Sync to webrtc branch-heads/69

https://webrtc.googlesource.com/src/+log/branch-heads/69

BUG=chromium:874787
TEST=emerge-eve webrtc-apm

Change-Id: If0f58568f15f0f419356474f631f6fcea1f3a0d2
Reviewed-on: https://chromium-review.googlesource.com/1174084
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Cheng-Yi Chiang <cychiang@chromium.org>
diff --git a/Makefile b/Makefile
index 0a23258..21bb278 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,8 @@
 	common_audio/libcommon_audio \
 	system_wrappers/source/libsystem_wrappers \
 	modules/audio_coding/libaudio_coding \
-	modules/audio_processing/libaudioproc_debug_proto
+	modules/audio_processing/libaudioproc_debug_proto \
+	absl
 
 CXX_LIBRARY(libwebrtc_apm.so): CPPFLAGS += \
 	$(call get_pc_cflags,$(webrtc_apm_PC_DEPS))
@@ -41,6 +42,7 @@
 	modules/audio_coding/libaudio_coding.pic.a \
 	rtc_base/librtc_base.pic.a \
 	libaudioproc_debug_proto.pic.a \
+	absl.pic.a \
 	$(call get_pc_libs,$(webrtc_apm_PC_DEPS))
 
 all: CXX_LIBRARY(libwebrtc_apm.so)
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
new file mode 100644
index 0000000..439addb
--- /dev/null
+++ b/absl/BUILD.bazel
@@ -0,0 +1,52 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+config_setting(
+    name = "llvm_compiler",
+    values = {
+        "compiler": "llvm",
+    },
+    visibility = [":__subpackages__"],
+)
+
+# following configs are based on mapping defined in: https://git.io/v5Ijz
+config_setting(
+    name = "ios",
+    values = {
+        "cpu": "darwin",
+    },
+    visibility = [":__subpackages__"],
+)
+
+config_setting(
+    name = "windows",
+    values = {
+        "cpu": "x64_windows",
+    },
+    visibility = [":__subpackages__"],
+)
+
+config_setting(
+    name = "ppc",
+    values = {
+        "cpu": "ppc",
+    },
+    visibility = [":__subpackages__"],
+)
diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt
new file mode 100644
index 0000000..689f64e
--- /dev/null
+++ b/absl/CMakeLists.txt
@@ -0,0 +1,30 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+
+
+add_subdirectory(base)
+add_subdirectory(algorithm)
+add_subdirectory(container)
+add_subdirectory(debugging)
+add_subdirectory(memory)
+add_subdirectory(meta)
+add_subdirectory(numeric)
+add_subdirectory(strings)
+add_subdirectory(synchronization)
+add_subdirectory(time)
+add_subdirectory(types)
+add_subdirectory(utility)
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
new file mode 100644
index 0000000..d04dc71
--- /dev/null
+++ b/absl/algorithm/BUILD.bazel
@@ -0,0 +1,81 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "algorithm",
+    hdrs = ["algorithm.h"],
+    copts = ABSL_DEFAULT_COPTS,
+)
+
+cc_test(
+    name = "algorithm_test",
+    size = "small",
+    srcs = ["algorithm_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":algorithm",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "algorithm_benchmark",
+    srcs = ["equal_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    deps = [
+        ":algorithm",
+        "//absl/base:core_headers",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "container",
+    hdrs = [
+        "container.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":algorithm",
+        "//absl/base:core_headers",
+        "//absl/meta:type_traits",
+    ],
+)
+
+cc_test(
+    name = "container_test",
+    srcs = ["container_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":container",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "//absl/types:span",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/algorithm/BUILD.gn b/absl/algorithm/BUILD.gn
new file mode 100644
index 0000000..37ec665
--- /dev/null
+++ b/absl/algorithm/BUILD.gn
@@ -0,0 +1,44 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("algorithm") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "algorithm.h",
+  ]
+}
+
+source_set("container") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "container.h",
+  ]
+  deps = [
+    ":algorithm",
+    "../base:core_headers",
+    "../meta:type_traits",
+  ]
+}
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt
new file mode 100644
index 0000000..fdf45c5
--- /dev/null
+++ b/absl/algorithm/CMakeLists.txt
@@ -0,0 +1,63 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND ALGORITHM_PUBLIC_HEADERS
+  "algorithm.h"
+  "container.h"
+)
+
+
+#
+## TESTS
+#
+
+# test algorithm_test
+list(APPEND ALGORITHM_TEST_SRC
+  "algorithm_test.cc"
+  ${ALGORITHM_PUBLIC_HEADERS}
+  ${ALGORITHM_INTERNAL_HEADERS}
+)
+
+absl_header_library(
+  TARGET
+    absl_algorithm
+  EXPORT_NAME
+    algorithm
+)
+
+absl_test(
+  TARGET
+    algorithm_test
+  SOURCES
+    ${ALGORITHM_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl::algorithm
+)
+
+
+
+
+# test container_test
+set(CONTAINER_TEST_SRC "container_test.cc")
+
+absl_test(
+  TARGET
+    container_test
+  SOURCES
+    ${CONTAINER_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl::algorithm
+)
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h
new file mode 100644
index 0000000..3d65864
--- /dev/null
+++ b/absl/algorithm/algorithm.h
@@ -0,0 +1,150 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: algorithm.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains Google extensions to the standard <algorithm> C++
+// header.
+
+#ifndef ABSL_ALGORITHM_ALGORITHM_H_
+#define ABSL_ALGORITHM_ALGORITHM_H_
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+
+namespace absl {
+
+namespace algorithm_internal {
+
+// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
+struct EqualTo {
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a == b;
+  }
+};
+
+template <typename InputIter1, typename InputIter2, typename Pred>
+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+               InputIter2 last2, Pred pred, std::input_iterator_tag,
+               std::input_iterator_tag) {
+  while (true) {
+    if (first1 == last1) return first2 == last2;
+    if (first2 == last2) return false;
+    if (!pred(*first1, *first2)) return false;
+    ++first1;
+    ++first2;
+  }
+}
+
+template <typename InputIter1, typename InputIter2, typename Pred>
+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+               InputIter2 last2, Pred&& pred, std::random_access_iterator_tag,
+               std::random_access_iterator_tag) {
+  return (last1 - first1 == last2 - first2) &&
+         std::equal(first1, last1, first2, std::forward<Pred>(pred));
+}
+
+// When we are using our own internal predicate that just applies operator==, we
+// forward to the non-predicate form of std::equal. This enables an optimization
+// in libstdc++ that can result in std::memcmp being used for integer types.
+template <typename InputIter1, typename InputIter2>
+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+               InputIter2 last2, algorithm_internal::EqualTo /* unused */,
+               std::random_access_iterator_tag,
+               std::random_access_iterator_tag) {
+  return (last1 - first1 == last2 - first2) &&
+         std::equal(first1, last1, first2);
+}
+
+template <typename It>
+It RotateImpl(It first, It middle, It last, std::true_type) {
+  return std::rotate(first, middle, last);
+}
+
+template <typename It>
+It RotateImpl(It first, It middle, It last, std::false_type) {
+  std::rotate(first, middle, last);
+  return std::next(first, std::distance(middle, last));
+}
+
+}  // namespace algorithm_internal
+
+// Compares the equality of two ranges specified by pairs of iterators, using
+// the given predicate, returning true iff for each corresponding iterator i1
+// and i2 in the first and second range respectively, pred(*i1, *i2) == true
+//
+// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`)
+// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are
+// both random-access iterators, and `last1` - `first1` != `last2` - `first2`,
+// then the predicate is never invoked and the function returns false.
+//
+// This is a C++11-compatible implementation of C++14 `std::equal`.  See
+// http://en.cppreference.com/w/cpp/algorithm/equal for more information.
+template <typename InputIter1, typename InputIter2, typename Pred>
+bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+           InputIter2 last2, Pred&& pred) {
+  return algorithm_internal::EqualImpl(
+      first1, last1, first2, last2, std::forward<Pred>(pred),
+      typename std::iterator_traits<InputIter1>::iterator_category{},
+      typename std::iterator_traits<InputIter2>::iterator_category{});
+}
+
+// Performs comparison of two ranges specified by pairs of iterators using
+// operator==.
+template <typename InputIter1, typename InputIter2>
+bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+           InputIter2 last2) {
+  return absl::equal(first1, last1, first2, last2,
+                     algorithm_internal::EqualTo{});
+}
+
+// Performs a linear search for `value` using the iterator `first` up to
+// but not including `last`, returning true if [`first`, `last`) contains an
+// element equal to `value`.
+//
+// A linear search is of O(n) complexity which is guaranteed to make at most
+// n = (`last` - `first`) comparisons. A linear search over short containers
+// may be faster than a binary search, even when the container is sorted.
+template <typename InputIterator, typename EqualityComparable>
+bool linear_search(InputIterator first, InputIterator last,
+                   const EqualityComparable& value) {
+  return std::find(first, last, value) != last;
+}
+
+// Performs a left rotation on a range of elements (`first`, `last`) such that
+// `middle` is now the first element. `rotate()` returns an iterator pointing to
+// the first element before rotation. This function is exactly the same as
+// `std::rotate`, but fixes a bug in gcc
+// <= 4.9 where `std::rotate` returns `void` instead of an iterator.
+//
+// The complexity of this algorithm is the same as that of `std::rotate`, but if
+// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
+// performs an additional pass over the range to construct the return value.
+
+template <typename ForwardIterator>
+ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
+                       ForwardIterator last) {
+  return algorithm_internal::RotateImpl(
+      first, middle, last,
+      std::is_same<decltype(std::rotate(first, middle, last)),
+                   ForwardIterator>());
+}
+
+}  // namespace absl
+
+#endif  // ABSL_ALGORITHM_ALGORITHM_H_
diff --git a/absl/algorithm/algorithm_test.cc b/absl/algorithm/algorithm_test.cc
new file mode 100644
index 0000000..e4322bc
--- /dev/null
+++ b/absl/algorithm/algorithm_test.cc
@@ -0,0 +1,182 @@
+// Copyright 2017 The Abseil 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 "absl/algorithm/algorithm.h"
+
+#include <algorithm>
+#include <list>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(EqualTest, DefaultComparisonRandomAccess) {
+  std::vector<int> v1{1, 2, 3};
+  std::vector<int> v2 = v1;
+  std::vector<int> v3 = {1, 2};
+  std::vector<int> v4 = {1, 2, 4};
+
+  EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end()));
+}
+
+TEST(EqualTest, DefaultComparison) {
+  std::list<int> lst1{1, 2, 3};
+  std::list<int> lst2 = lst1;
+  std::list<int> lst3{1, 2};
+  std::list<int> lst4{1, 2, 4};
+
+  EXPECT_TRUE(absl::equal(lst1.begin(), lst1.end(), lst2.begin(), lst2.end()));
+  EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst3.begin(), lst3.end()));
+  EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst4.begin(), lst4.end()));
+}
+
+TEST(EqualTest, EmptyRange) {
+  std::vector<int> v1{1, 2, 3};
+  std::vector<int> empty1;
+  std::vector<int> empty2;
+
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), empty1.begin(), empty1.end()));
+  EXPECT_FALSE(absl::equal(empty1.begin(), empty1.end(), v1.begin(), v1.end()));
+  EXPECT_TRUE(
+      absl::equal(empty1.begin(), empty1.end(), empty2.begin(), empty2.end()));
+}
+
+TEST(EqualTest, MixedIterTypes) {
+  std::vector<int> v1{1, 2, 3};
+  std::list<int> lst1{v1.begin(), v1.end()};
+  std::list<int> lst2{1, 2, 4};
+  std::list<int> lst3{1, 2};
+
+  EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), lst1.begin(), lst1.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst2.begin(), lst2.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst3.begin(), lst3.end()));
+}
+
+TEST(EqualTest, MixedValueTypes) {
+  std::vector<int> v1{1, 2, 3};
+  std::vector<char> v2{1, 2, 3};
+  std::vector<char> v3{1, 2};
+  std::vector<char> v4{1, 2, 4};
+
+  EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end()));
+}
+
+TEST(EqualTest, WeirdIterators) {
+  std::vector<bool> v1{true, false};
+  std::vector<bool> v2 = v1;
+  std::vector<bool> v3{true};
+  std::vector<bool> v4{true, true, true};
+
+  EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end()));
+}
+
+TEST(EqualTest, CustomComparison) {
+  int n[] = {1, 2, 3, 4};
+  std::vector<int*> v1{&n[0], &n[1], &n[2]};
+  std::vector<int*> v2 = v1;
+  std::vector<int*> v3{&n[0], &n[1], &n[3]};
+  std::vector<int*> v4{&n[0], &n[1]};
+
+  auto eq = [](int* a, int* b) { return *a == *b; };
+
+  EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), eq));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(), eq));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end(), eq));
+}
+
+TEST(EqualTest, MoveOnlyPredicate) {
+  std::vector<int> v1{1, 2, 3};
+  std::vector<int> v2{4, 5, 6};
+
+  // move-only equality predicate
+  struct Eq {
+    Eq() = default;
+    Eq(Eq &&) = default;
+    Eq(const Eq &) = delete;
+    Eq &operator=(const Eq &) = delete;
+    bool operator()(const int a, const int b) const { return a == b; }
+  };
+
+  EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v1.begin(), v1.end(), Eq()));
+  EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), Eq()));
+}
+
+struct CountingTrivialPred {
+  int* count;
+  bool operator()(int, int) const {
+    ++*count;
+    return true;
+  }
+};
+
+TEST(EqualTest, RandomAccessComplexity) {
+  std::vector<int> v1{1, 1, 3};
+  std::vector<int> v2 = v1;
+  std::vector<int> v3{1, 2};
+
+  do {
+    int count = 0;
+    absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(),
+                CountingTrivialPred{&count});
+    EXPECT_LE(count, 3);
+  } while (std::next_permutation(v2.begin(), v2.end()));
+
+  int count = 0;
+  absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(),
+              CountingTrivialPred{&count});
+  EXPECT_EQ(count, 0);
+}
+
+class LinearSearchTest : public testing::Test {
+ protected:
+  LinearSearchTest() : container_{1, 2, 3} {}
+
+  static bool Is3(int n) { return n == 3; }
+  static bool Is4(int n) { return n == 4; }
+
+  std::vector<int> container_;
+};
+
+TEST_F(LinearSearchTest, linear_search) {
+  EXPECT_TRUE(absl::linear_search(container_.begin(), container_.end(), 3));
+  EXPECT_FALSE(absl::linear_search(container_.begin(), container_.end(), 4));
+}
+
+TEST_F(LinearSearchTest, linear_searchConst) {
+  const std::vector<int> *const const_container = &container_;
+  EXPECT_TRUE(
+      absl::linear_search(const_container->begin(), const_container->end(), 3));
+  EXPECT_FALSE(
+      absl::linear_search(const_container->begin(), const_container->end(), 4));
+}
+
+TEST(RotateTest, Rotate) {
+  std::vector<int> v{0, 1, 2, 3, 4};
+  EXPECT_EQ(*absl::rotate(v.begin(), v.begin() + 2, v.end()), 0);
+  EXPECT_THAT(v, testing::ElementsAreArray({2, 3, 4, 0, 1}));
+
+  std::list<int> l{0, 1, 2, 3, 4};
+  EXPECT_EQ(*absl::rotate(l.begin(), std::next(l.begin(), 3), l.end()), 0);
+  EXPECT_THAT(l, testing::ElementsAreArray({3, 4, 0, 1, 2}));
+}
+
+}  // namespace
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
new file mode 100644
index 0000000..acddec4
--- /dev/null
+++ b/absl/algorithm/container.h
@@ -0,0 +1,1642 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: container.h
+// -----------------------------------------------------------------------------
+//
+// This header file provides Container-based versions of algorithmic functions
+// within the C++ standard library. The following standard library sets of
+// functions are covered within this file:
+//
+//   * Algorithmic <iterator> functions
+//   * Algorithmic <numeric> functions
+//   * <algorithm> functions
+//
+// The standard library functions operate on iterator ranges; the functions
+// within this API operate on containers, though many return iterator ranges.
+//
+// All functions within this API are named with a `c_` prefix. Calls such as
+// `absl::c_xx(container, ...) are equivalent to std:: functions such as
+// `std::xx(std::begin(cont), std::end(cont), ...)`. Functions that act on
+// iterators but not conceptually on iterator ranges (e.g. `std::iter_swap`)
+// have no equivalent here.
+//
+// For template parameter and variable naming, `C` indicates the container type
+// to which the function is applied, `Pred` indicates the predicate object type
+// to be used by the function and `T` indicates the applicable element type.
+//
+
+#ifndef ABSL_ALGORITHM_CONTAINER_H_
+#define ABSL_ALGORITHM_CONTAINER_H_
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+namespace container_algorithm_internal {
+
+// NOTE: it is important to defer to ADL lookup for building with C++ modules,
+// especially for headers like <valarray> which are not visible from this file
+// but specialize std::begin and std::end.
+using std::begin;
+using std::end;
+
+// The type of the iterator given by begin(c) (possibly std::begin(c)).
+// ContainerIter<const vector<T>> gives vector<T>::const_iterator,
+// while ContainerIter<vector<T>> gives vector<T>::iterator.
+template <typename C>
+using ContainerIter = decltype(begin(std::declval<C&>()));
+
+// An MSVC bug involving template parameter substitution requires us to use
+// decltype() here instead of just std::pair.
+template <typename C1, typename C2>
+using ContainerIterPairType =
+    decltype(std::make_pair(ContainerIter<C1>(), ContainerIter<C2>()));
+
+template <typename C>
+using ContainerDifferenceType =
+    decltype(std::distance(std::declval<ContainerIter<C>>(),
+                           std::declval<ContainerIter<C>>()));
+
+template <typename C>
+using ContainerPointerType =
+    typename std::iterator_traits<ContainerIter<C>>::pointer;
+
+// container_algorithm_internal::c_begin and
+// container_algorithm_internal::c_end are abbreviations for proper ADL
+// lookup of std::begin and std::end, i.e.
+//   using std::begin;
+//   using std::end;
+//   std::foo(begin(c), end(c);
+// becomes
+//   std::foo(container_algorithm_internal::begin(c),
+//   container_algorithm_internal::end(c));
+// These are meant for internal use only.
+
+template <typename C>
+ContainerIter<C> c_begin(C& c) { return begin(c); }
+
+template <typename C>
+ContainerIter<C> c_end(C& c) { return end(c); }
+
+}  // namespace container_algorithm_internal
+
+// PUBLIC API
+
+//------------------------------------------------------------------------------
+// Abseil algorithm.h functions
+//------------------------------------------------------------------------------
+
+// c_linear_search()
+//
+// Container-based version of absl::linear_search() for performing a linear
+// search within a container.
+template <typename C, typename EqualityComparable>
+bool c_linear_search(const C& c, EqualityComparable&& value) {
+  return linear_search(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c),
+                       std::forward<EqualityComparable>(value));
+}
+
+//------------------------------------------------------------------------------
+// <iterator> algorithms
+//------------------------------------------------------------------------------
+
+// c_distance()
+//
+// Container-based version of the <iterator> `std::distance()` function to
+// return the number of elements within a container.
+template <typename C>
+container_algorithm_internal::ContainerDifferenceType<const C> c_distance(
+    const C& c) {
+  return std::distance(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Non-modifying sequence operations
+//------------------------------------------------------------------------------
+
+// c_all_of()
+//
+// Container-based version of the <algorithm> `std::all_of()` function to
+// test a condition on all elements within a container.
+template <typename C, typename Pred>
+bool c_all_of(const C& c, Pred&& pred) {
+  return std::all_of(container_algorithm_internal::c_begin(c),
+                     container_algorithm_internal::c_end(c),
+                     std::forward<Pred>(pred));
+}
+
+// c_any_of()
+//
+// Container-based version of the <algorithm> `std::any_of()` function to
+// test if any element in a container fulfills a condition.
+template <typename C, typename Pred>
+bool c_any_of(const C& c, Pred&& pred) {
+  return std::any_of(container_algorithm_internal::c_begin(c),
+                     container_algorithm_internal::c_end(c),
+                     std::forward<Pred>(pred));
+}
+
+// c_none_of()
+//
+// Container-based version of the <algorithm> `std::none_of()` function to
+// test if no elements in a container fulfil a condition.
+template <typename C, typename Pred>
+bool c_none_of(const C& c, Pred&& pred) {
+  return std::none_of(container_algorithm_internal::c_begin(c),
+                      container_algorithm_internal::c_end(c),
+                      std::forward<Pred>(pred));
+}
+
+// c_for_each()
+//
+// Container-based version of the <algorithm> `std::for_each()` function to
+// apply a function to a container's elements.
+template <typename C, typename Function>
+decay_t<Function> c_for_each(C&& c, Function&& f) {
+  return std::for_each(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c),
+                       std::forward<Function>(f));
+}
+
+// c_find()
+//
+// Container-based version of the <algorithm> `std::find()` function to find
+// the first element containing the passed value within a container value.
+template <typename C, typename T>
+container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) {
+  return std::find(container_algorithm_internal::c_begin(c),
+                   container_algorithm_internal::c_end(c),
+                   std::forward<T>(value));
+}
+
+// c_find_if()
+//
+// Container-based version of the <algorithm> `std::find_if()` function to find
+// the first element in a container matching the given condition.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) {
+  return std::find_if(container_algorithm_internal::c_begin(c),
+                      container_algorithm_internal::c_end(c),
+                      std::forward<Pred>(pred));
+}
+
+// c_find_if_not()
+//
+// Container-based version of the <algorithm> `std::find_if_not()` function to
+// find the first element in a container not matching the given condition.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c,
+                                                             Pred&& pred) {
+  return std::find_if_not(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c),
+                          std::forward<Pred>(pred));
+}
+
+// c_find_end()
+//
+// Container-based version of the <algorithm> `std::find_end()` function to
+// find the last subsequence within a container.
+template <typename Sequence1, typename Sequence2>
+container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
+    Sequence1& sequence, Sequence2& subsequence) {
+  return std::find_end(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence),
+                       container_algorithm_internal::c_begin(subsequence),
+                       container_algorithm_internal::c_end(subsequence));
+}
+
+// Overload of c_find_end() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
+    Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+  return std::find_end(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence),
+                       container_algorithm_internal::c_begin(subsequence),
+                       container_algorithm_internal::c_end(subsequence),
+                       std::forward<BinaryPredicate>(pred));
+}
+
+// c_find_first_of()
+//
+// Container-based version of the <algorithm> `std::find_first_of()` function to
+// find the first elements in an ordered set within a container.
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
+                                                                C2& options) {
+  return std::find_first_of(container_algorithm_internal::c_begin(container),
+                            container_algorithm_internal::c_end(container),
+                            container_algorithm_internal::c_begin(options),
+                            container_algorithm_internal::c_end(options));
+}
+
+// Overload of c_find_first_of() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<C1> c_find_first_of(
+    C1& container, C2& options, BinaryPredicate&& pred) {
+  return std::find_first_of(container_algorithm_internal::c_begin(container),
+                            container_algorithm_internal::c_end(container),
+                            container_algorithm_internal::c_begin(options),
+                            container_algorithm_internal::c_end(options),
+                            std::forward<BinaryPredicate>(pred));
+}
+
+// c_adjacent_find()
+//
+// Container-based version of the <algorithm> `std::adjacent_find()` function to
+// find equal adjacent elements within a container.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
+    Sequence& sequence) {
+  return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_adjacent_find() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
+    Sequence& sequence, BinaryPredicate&& pred) {
+  return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<BinaryPredicate>(pred));
+}
+
+// c_count()
+//
+// Container-based version of the <algorithm> `std::count()` function to count
+// values that match within a container.
+template <typename C, typename T>
+container_algorithm_internal::ContainerDifferenceType<const C> c_count(
+    const C& c, T&& value) {
+  return std::count(container_algorithm_internal::c_begin(c),
+                    container_algorithm_internal::c_end(c),
+                    std::forward<T>(value));
+}
+
+// c_count_if()
+//
+// Container-based version of the <algorithm> `std::count_if()` function to
+// count values matching a condition within a container.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
+    const C& c, Pred&& pred) {
+  return std::count_if(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c),
+                       std::forward<Pred>(pred));
+}
+
+// c_mismatch()
+//
+// Container-based version of the <algorithm> `std::mismatchf()` function to
+// return the first element where two ordered containers differ.
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIterPairType<C1, C2>
+c_mismatch(C1& c1, C2& c2) {
+  return std::mismatch(container_algorithm_internal::c_begin(c1),
+                       container_algorithm_internal::c_end(c1),
+                       container_algorithm_internal::c_begin(c2));
+}
+
+// Overload of c_mismatch() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIterPairType<C1, C2>
+c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
+  return std::mismatch(container_algorithm_internal::c_begin(c1),
+                       container_algorithm_internal::c_end(c1),
+                       container_algorithm_internal::c_begin(c2),
+                       std::forward<BinaryPredicate>(pred));
+}
+
+// c_equal()
+//
+// Container-based version of the <algorithm> `std::equal()` function to
+// test whether two containers are equal.
+//
+// NOTE: the semantics of c_equal() are slightly different than those of
+// equal(): while the latter iterates over the second container only up to the
+// size of the first container, c_equal() also checks whether the container
+// sizes are equal.  This better matches expectations about c_equal() based on
+// its signature.
+//
+// Example:
+//   vector v1 = <1, 2, 3>;
+//   vector v2 = <1, 2, 3, 4>;
+//   equal(std::begin(v1), std::end(v1), std::begin(v2)) returns true
+//   c_equal(v1, v2) returns false
+
+template <typename C1, typename C2>
+bool c_equal(const C1& c1, const C2& c2) {
+  return ((c1.size() == c2.size()) &&
+          std::equal(container_algorithm_internal::c_begin(c1),
+                     container_algorithm_internal::c_end(c1),
+                     container_algorithm_internal::c_begin(c2)));
+}
+
+// Overload of c_equal() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+  return ((c1.size() == c2.size()) &&
+          std::equal(container_algorithm_internal::c_begin(c1),
+                     container_algorithm_internal::c_end(c1),
+                     container_algorithm_internal::c_begin(c2),
+                     std::forward<BinaryPredicate>(pred)));
+}
+
+// c_is_permutation()
+//
+// Container-based version of the <algorithm> `std::is_permutation()` function
+// to test whether a container is a permutation of another.
+template <typename C1, typename C2>
+bool c_is_permutation(const C1& c1, const C2& c2) {
+  using std::begin;
+  using std::end;
+  return c1.size() == c2.size() &&
+         std::is_permutation(begin(c1), end(c1), begin(c2));
+}
+
+// Overload of c_is_permutation() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+  using std::begin;
+  using std::end;
+  return c1.size() == c2.size() &&
+         std::is_permutation(begin(c1), end(c1), begin(c2),
+                             std::forward<BinaryPredicate>(pred));
+}
+
+// c_search()
+//
+// Container-based version of the <algorithm> `std::search()` function to search
+// a container for a subsequence.
+template <typename Sequence1, typename Sequence2>
+container_algorithm_internal::ContainerIter<Sequence1> c_search(
+    Sequence1& sequence, Sequence2& subsequence) {
+  return std::search(container_algorithm_internal::c_begin(sequence),
+                     container_algorithm_internal::c_end(sequence),
+                     container_algorithm_internal::c_begin(subsequence),
+                     container_algorithm_internal::c_end(subsequence));
+}
+
+// Overload of c_search() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence1> c_search(
+    Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+  return std::search(container_algorithm_internal::c_begin(sequence),
+                     container_algorithm_internal::c_end(sequence),
+                     container_algorithm_internal::c_begin(subsequence),
+                     container_algorithm_internal::c_end(subsequence),
+                     std::forward<BinaryPredicate>(pred));
+}
+
+// c_search_n()
+//
+// Container-based version of the <algorithm> `std::search_n()` function to
+// search a container for the first sequence of N elements.
+template <typename Sequence, typename Size, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_search_n(
+    Sequence& sequence, Size count, T&& value) {
+  return std::search_n(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence), count,
+                       std::forward<T>(value));
+}
+
+// Overload of c_search_n() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence, typename Size, typename T,
+          typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence> c_search_n(
+    Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) {
+  return std::search_n(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence), count,
+                       std::forward<T>(value),
+                       std::forward<BinaryPredicate>(pred));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Modifying sequence operations
+//------------------------------------------------------------------------------
+
+// c_copy()
+//
+// Container-based version of the <algorithm> `std::copy()` function to copy a
+// container's elements into an iterator.
+template <typename InputSequence, typename OutputIterator>
+OutputIterator c_copy(const InputSequence& input, OutputIterator output) {
+  return std::copy(container_algorithm_internal::c_begin(input),
+                   container_algorithm_internal::c_end(input), output);
+}
+
+// c_copy_n()
+//
+// Container-based version of the <algorithm> `std::copy_n()` function to copy a
+// container's first N elements into an iterator.
+template <typename C, typename Size, typename OutputIterator>
+OutputIterator c_copy_n(const C& input, Size n, OutputIterator output) {
+  return std::copy_n(container_algorithm_internal::c_begin(input), n, output);
+}
+
+// c_copy_if()
+//
+// Container-based version of the <algorithm> `std::copy_if()` function to copy
+// a container's elements satisfying some condition into an iterator.
+template <typename InputSequence, typename OutputIterator, typename Pred>
+OutputIterator c_copy_if(const InputSequence& input, OutputIterator output,
+                         Pred&& pred) {
+  return std::copy_if(container_algorithm_internal::c_begin(input),
+                      container_algorithm_internal::c_end(input), output,
+                      std::forward<Pred>(pred));
+}
+
+// c_copy_backward()
+//
+// Container-based version of the <algorithm> `std::copy_backward()` function to
+// copy a container's elements in reverse order into an iterator.
+template <typename C, typename BidirectionalIterator>
+BidirectionalIterator c_copy_backward(const C& src,
+                                      BidirectionalIterator dest) {
+  return std::copy_backward(container_algorithm_internal::c_begin(src),
+                            container_algorithm_internal::c_end(src), dest);
+}
+
+// c_move()
+//
+// Container-based version of the <algorithm> `std::move()` function to move
+// a container's elements into an iterator.
+template <typename C, typename OutputIterator>
+OutputIterator c_move(C& src, OutputIterator dest) {
+  return std::move(container_algorithm_internal::c_begin(src),
+                   container_algorithm_internal::c_end(src), dest);
+}
+
+// c_swap_ranges()
+//
+// Container-based version of the <algorithm> `std::swap_ranges()` function to
+// swap a container's elements with another container's elements.
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) {
+  return std::swap_ranges(container_algorithm_internal::c_begin(c1),
+                          container_algorithm_internal::c_end(c1),
+                          container_algorithm_internal::c_begin(c2));
+}
+
+// c_transform()
+//
+// Container-based version of the <algorithm> `std::transform()` function to
+// transform a container's elements using the unary operation, storing the
+// result in an iterator pointing to the last transformed element in the output
+// range.
+template <typename InputSequence, typename OutputIterator, typename UnaryOp>
+OutputIterator c_transform(const InputSequence& input, OutputIterator output,
+                           UnaryOp&& unary_op) {
+  return std::transform(container_algorithm_internal::c_begin(input),
+                        container_algorithm_internal::c_end(input), output,
+                        std::forward<UnaryOp>(unary_op));
+}
+
+// Overload of c_transform() for performing a transformation using a binary
+// predicate.
+template <typename InputSequence1, typename InputSequence2,
+          typename OutputIterator, typename BinaryOp>
+OutputIterator c_transform(const InputSequence1& input1,
+                           const InputSequence2& input2, OutputIterator output,
+                           BinaryOp&& binary_op) {
+  return std::transform(container_algorithm_internal::c_begin(input1),
+                        container_algorithm_internal::c_end(input1),
+                        container_algorithm_internal::c_begin(input2), output,
+                        std::forward<BinaryOp>(binary_op));
+}
+
+// c_replace()
+//
+// Container-based version of the <algorithm> `std::replace()` function to
+// replace a container's elements of some value with a new value. The container
+// is modified in place.
+template <typename Sequence, typename T>
+void c_replace(Sequence& sequence, const T& old_value, const T& new_value) {
+  std::replace(container_algorithm_internal::c_begin(sequence),
+               container_algorithm_internal::c_end(sequence), old_value,
+               new_value);
+}
+
+// c_replace_if()
+//
+// Container-based version of the <algorithm> `std::replace_if()` function to
+// replace a container's elements of some value with a new value based on some
+// condition. The container is modified in place.
+template <typename C, typename Pred, typename T>
+void c_replace_if(C& c, Pred&& pred, T&& new_value) {
+  std::replace_if(container_algorithm_internal::c_begin(c),
+                  container_algorithm_internal::c_end(c),
+                  std::forward<Pred>(pred), std::forward<T>(new_value));
+}
+
+// c_replace_copy()
+//
+// Container-based version of the <algorithm> `std::replace_copy()` function to
+// replace a container's elements of some value with a new value  and return the
+// results within an iterator.
+template <typename C, typename OutputIterator, typename T>
+OutputIterator c_replace_copy(const C& c, OutputIterator result, T&& old_value,
+                              T&& new_value) {
+  return std::replace_copy(container_algorithm_internal::c_begin(c),
+                           container_algorithm_internal::c_end(c), result,
+                           std::forward<T>(old_value),
+                           std::forward<T>(new_value));
+}
+
+// c_replace_copy_if()
+//
+// Container-based version of the <algorithm> `std::replace_copy_if()` function
+// to replace a container's elements of some value with a new value based on
+// some condition, and return the results within an iterator.
+template <typename C, typename OutputIterator, typename Pred, typename T>
+OutputIterator c_replace_copy_if(const C& c, OutputIterator result, Pred&& pred,
+                                 T&& new_value) {
+  return std::replace_copy_if(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c), result,
+                              std::forward<Pred>(pred),
+                              std::forward<T>(new_value));
+}
+
+// c_fill()
+//
+// Container-based version of the <algorithm> `std::fill()` function to fill a
+// container with some value.
+template <typename C, typename T>
+void c_fill(C& c, T&& value) {
+  std::fill(container_algorithm_internal::c_begin(c),
+            container_algorithm_internal::c_end(c), std::forward<T>(value));
+}
+
+// c_fill_n()
+//
+// Container-based version of the <algorithm> `std::fill_n()` function to fill
+// the first N elements in a container with some value.
+template <typename C, typename Size, typename T>
+void c_fill_n(C& c, Size n, T&& value) {
+  std::fill_n(container_algorithm_internal::c_begin(c), n,
+              std::forward<T>(value));
+}
+
+// c_generate()
+//
+// Container-based version of the <algorithm> `std::generate()` function to
+// assign a container's elements to the values provided by the given generator.
+template <typename C, typename Generator>
+void c_generate(C& c, Generator&& gen) {
+  std::generate(container_algorithm_internal::c_begin(c),
+                container_algorithm_internal::c_end(c),
+                std::forward<Generator>(gen));
+}
+
+// c_generate_n()
+//
+// Container-based version of the <algorithm> `std::generate_n()` function to
+// assign a container's first N elements to the values provided by the given
+// generator.
+template <typename C, typename Size, typename Generator>
+container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n,
+                                                            Generator&& gen) {
+  return std::generate_n(container_algorithm_internal::c_begin(c), n,
+                         std::forward<Generator>(gen));
+}
+
+// Note: `c_xx()` <algorithm> container versions for `remove()`, `remove_if()`,
+// and `unique()` are omitted, because it's not clear whether or not such
+// functions should call erase on their supplied sequences afterwards. Either
+// behavior would be surprising for a different set of users.
+//
+
+// c_remove_copy()
+//
+// Container-based version of the <algorithm> `std::remove_copy()` function to
+// copy a container's elements while removing any elements matching the given
+// `value`.
+template <typename C, typename OutputIterator, typename T>
+OutputIterator c_remove_copy(const C& c, OutputIterator result, T&& value) {
+  return std::remove_copy(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c), result,
+                          std::forward<T>(value));
+}
+
+// c_remove_copy_if()
+//
+// Container-based version of the <algorithm> `std::remove_copy_if()` function
+// to copy a container's elements while removing any elements matching the given
+// condition.
+template <typename C, typename OutputIterator, typename Pred>
+OutputIterator c_remove_copy_if(const C& c, OutputIterator result,
+                                Pred&& pred) {
+  return std::remove_copy_if(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c), result,
+                             std::forward<Pred>(pred));
+}
+
+// c_unique_copy()
+//
+// Container-based version of the <algorithm> `std::unique_copy()` function to
+// copy a container's elements while removing any elements containing duplicate
+// values.
+template <typename C, typename OutputIterator>
+OutputIterator c_unique_copy(const C& c, OutputIterator result) {
+  return std::unique_copy(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c), result);
+}
+
+// Overload of c_unique_copy() for using a predicate evaluation other than
+// `==` for comparing uniqueness of the element values.
+template <typename C, typename OutputIterator, typename BinaryPredicate>
+OutputIterator c_unique_copy(const C& c, OutputIterator result,
+                             BinaryPredicate&& pred) {
+  return std::unique_copy(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c), result,
+                          std::forward<BinaryPredicate>(pred));
+}
+
+// c_reverse()
+//
+// Container-based version of the <algorithm> `std::reverse()` function to
+// reverse a container's elements.
+template <typename Sequence>
+void c_reverse(Sequence& sequence) {
+  std::reverse(container_algorithm_internal::c_begin(sequence),
+               container_algorithm_internal::c_end(sequence));
+}
+
+// c_reverse_copy()
+//
+// Container-based version of the <algorithm> `std::reverse()` function to
+// reverse a container's elements and write them to an iterator range.
+template <typename C, typename OutputIterator>
+OutputIterator c_reverse_copy(const C& sequence, OutputIterator result) {
+  return std::reverse_copy(container_algorithm_internal::c_begin(sequence),
+                           container_algorithm_internal::c_end(sequence),
+                           result);
+}
+
+// c_rotate()
+//
+// Container-based version of the <algorithm> `std::rotate()` function to
+// shift a container's elements leftward such that the `middle` element becomes
+// the first element in the container.
+template <typename C,
+          typename Iterator = container_algorithm_internal::ContainerIter<C>>
+Iterator c_rotate(C& sequence, Iterator middle) {
+  return absl::rotate(container_algorithm_internal::c_begin(sequence), middle,
+                      container_algorithm_internal::c_end(sequence));
+}
+
+// c_rotate_copy()
+//
+// Container-based version of the <algorithm> `std::rotate_copy()` function to
+// shift a container's elements leftward such that the `middle` element becomes
+// the first element in a new iterator range.
+template <typename C, typename OutputIterator>
+OutputIterator c_rotate_copy(
+    const C& sequence,
+    container_algorithm_internal::ContainerIter<const C> middle,
+    OutputIterator result) {
+  return std::rotate_copy(container_algorithm_internal::c_begin(sequence),
+                          middle, container_algorithm_internal::c_end(sequence),
+                          result);
+}
+
+// c_shuffle()
+//
+// Container-based version of the <algorithm> `std::shuffle()` function to
+// randomly shuffle elements within the container using a `gen()` uniform random
+// number generator.
+template <typename RandomAccessContainer, typename UniformRandomBitGenerator>
+void c_shuffle(RandomAccessContainer& c, UniformRandomBitGenerator&& gen) {
+  std::shuffle(container_algorithm_internal::c_begin(c),
+               container_algorithm_internal::c_end(c),
+               std::forward<UniformRandomBitGenerator>(gen));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Partition functions
+//------------------------------------------------------------------------------
+
+// c_is_partitioned()
+//
+// Container-based version of the <algorithm> `std::is_partitioned()` function
+// to test whether all elements in the container for which `pred` returns `true`
+// precede those for which `pred` is `false`.
+template <typename C, typename Pred>
+bool c_is_partitioned(const C& c, Pred&& pred) {
+  return std::is_partitioned(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c),
+                             std::forward<Pred>(pred));
+}
+
+// c_partition()
+//
+// Container-based version of the <algorithm> `std::partition()` function
+// to rearrange all elements in a container in such a way that all elements for
+// which `pred` returns `true` precede all those for which it returns `false`,
+// returning an iterator to the first element of the second group.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_partition(C& c, Pred&& pred) {
+  return std::partition(container_algorithm_internal::c_begin(c),
+                        container_algorithm_internal::c_end(c),
+                        std::forward<Pred>(pred));
+}
+
+// c_stable_partition()
+//
+// Container-based version of the <algorithm> `std::stable_partition()` function
+// to rearrange all elements in a container in such a way that all elements for
+// which `pred` returns `true` precede all those for which it returns `false`,
+// preserving the relative ordering between the two groups. The function returns
+// an iterator to the first element of the second group.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_stable_partition(C& c,
+                                                                  Pred&& pred) {
+  return std::stable_partition(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c),
+                               std::forward<Pred>(pred));
+}
+
+// c_partition_copy()
+//
+// Container-based version of the <algorithm> `std::partition_copy()` function
+// to partition a container's elements and return them into two iterators: one
+// for which `pred` returns `true`, and one for which `pred` returns `false.`
+
+template <typename C, typename OutputIterator1, typename OutputIterator2,
+          typename Pred>
+std::pair<OutputIterator1, OutputIterator2> c_partition_copy(
+    const C& c, OutputIterator1 out_true, OutputIterator2 out_false,
+    Pred&& pred) {
+  return std::partition_copy(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c), out_true,
+                             out_false, std::forward<Pred>(pred));
+}
+
+// c_partition_point()
+//
+// Container-based version of the <algorithm> `std::partition_point()` function
+// to return the first element of an already partitioned container for which
+// the given `pred` is not `true`.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_partition_point(C& c,
+                                                                 Pred&& pred) {
+  return std::partition_point(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c),
+                              std::forward<Pred>(pred));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Sorting functions
+//------------------------------------------------------------------------------
+
+// c_sort()
+//
+// Container-based version of the <algorithm> `std::sort()` function
+// to sort elements in ascending order of their values.
+template <typename C>
+void c_sort(C& c) {
+  std::sort(container_algorithm_internal::c_begin(c),
+            container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_sort() for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+void c_sort(C& c, Compare&& comp) {
+  std::sort(container_algorithm_internal::c_begin(c),
+            container_algorithm_internal::c_end(c),
+            std::forward<Compare>(comp));
+}
+
+// c_stable_sort()
+//
+// Container-based version of the <algorithm> `std::stable_sort()` function
+// to sort elements in ascending order of their values, preserving the order
+// of equivalents.
+template <typename C>
+void c_stable_sort(C& c) {
+  std::stable_sort(container_algorithm_internal::c_begin(c),
+                   container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_stable_sort() for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+void c_stable_sort(C& c, Compare&& comp) {
+  std::stable_sort(container_algorithm_internal::c_begin(c),
+                   container_algorithm_internal::c_end(c),
+                   std::forward<Compare>(comp));
+}
+
+// c_is_sorted()
+//
+// Container-based version of the <algorithm> `std::is_sorted()` function
+// to evaluate whether the given container is sorted in ascending order.
+template <typename C>
+bool c_is_sorted(const C& c) {
+  return std::is_sorted(container_algorithm_internal::c_begin(c),
+                        container_algorithm_internal::c_end(c));
+}
+
+// c_is_sorted() overload for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+bool c_is_sorted(const C& c, Compare&& comp) {
+  return std::is_sorted(container_algorithm_internal::c_begin(c),
+                        container_algorithm_internal::c_end(c),
+                        std::forward<Compare>(comp));
+}
+
+// c_partial_sort()
+//
+// Container-based version of the <algorithm> `std::partial_sort()` function
+// to rearrange elements within a container such that elements before `middle`
+// are sorted in ascending order.
+template <typename RandomAccessContainer>
+void c_partial_sort(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> middle) {
+  std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
+                    container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_partial_sort() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_partial_sort(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
+    Compare&& comp) {
+  std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
+                    container_algorithm_internal::c_end(sequence),
+                    std::forward<Compare>(comp));
+}
+
+// c_partial_sort_copy()
+//
+// Container-based version of the <algorithm> `std::partial_sort_copy()`
+// function to sort elements within a container such that elements before
+// `middle` are sorted in ascending order, and return the result within an
+// iterator.
+template <typename C, typename RandomAccessContainer>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
+  return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
+                                container_algorithm_internal::c_end(sequence),
+                                container_algorithm_internal::c_begin(result),
+                                container_algorithm_internal::c_end(result));
+}
+
+// Overload of c_partial_sort_copy() for performing a `comp` comparison other
+// than the default `operator<`.
+template <typename C, typename RandomAccessContainer, typename Compare>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
+                    Compare&& comp) {
+  return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
+                                container_algorithm_internal::c_end(sequence),
+                                container_algorithm_internal::c_begin(result),
+                                container_algorithm_internal::c_end(result),
+                                std::forward<Compare>(comp));
+}
+
+// c_is_sorted_until()
+//
+// Container-based version of the <algorithm> `std::is_sorted_until()` function
+// to return the first element within a container that is not sorted in
+// ascending order as an iterator.
+template <typename C>
+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) {
+  return std::is_sorted_until(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_is_sorted_until() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename C, typename Compare>
+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(
+    C& c, Compare&& comp) {
+  return std::is_sorted_until(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c),
+                              std::forward<Compare>(comp));
+}
+
+// c_nth_element()
+//
+// Container-based version of the <algorithm> `std::nth_element()` function
+// to rearrange the elements within a container such that the `nth` element
+// would be in that position in an ordered sequence; other elements may be in
+// any order, except that all preceding `nth` will be less than that element,
+// and all following `nth` will be greater than that element.
+template <typename RandomAccessContainer>
+void c_nth_element(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> nth) {
+  std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
+                   container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_nth_element() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_nth_element(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> nth,
+    Compare&& comp) {
+  std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
+                   container_algorithm_internal::c_end(sequence),
+                   std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Binary Search
+//------------------------------------------------------------------------------
+
+// c_lower_bound()
+//
+// Container-based version of the <algorithm> `std::lower_bound()` function
+// to return an iterator pointing to the first element in a sorted container
+// which does not compare less than `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
+    Sequence& sequence, T&& value) {
+  return std::lower_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value));
+}
+
+// Overload of c_lower_bound() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
+    Sequence& sequence, T&& value, Compare&& comp) {
+  return std::lower_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_upper_bound()
+//
+// Container-based version of the <algorithm> `std::upper_bound()` function
+// to return an iterator pointing to the first element in a sorted container
+// which is greater than `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
+    Sequence& sequence, T&& value) {
+  return std::upper_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value));
+}
+
+// Overload of c_upper_bound() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
+    Sequence& sequence, T&& value, Compare&& comp) {
+  return std::upper_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_equal_range()
+//
+// Container-based version of the <algorithm> `std::equal_range()` function
+// to return an iterator pair pointing to the first and last elements in a
+// sorted container which compare equal to `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
+c_equal_range(Sequence& sequence, T&& value) {
+  return std::equal_range(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value));
+}
+
+// Overload of c_equal_range() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
+c_equal_range(Sequence& sequence, T&& value, Compare&& comp) {
+  return std::equal_range(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_binary_search()
+//
+// Container-based version of the <algorithm> `std::binary_search()` function
+// to test if any element in the sorted container contains a value equivalent to
+// 'value'.
+template <typename Sequence, typename T>
+bool c_binary_search(Sequence&& sequence, T&& value) {
+  return std::binary_search(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<T>(value));
+}
+
+// Overload of c_binary_search() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) {
+  return std::binary_search(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<T>(value),
+                            std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Merge functions
+//------------------------------------------------------------------------------
+
+// c_merge()
+//
+// Container-based version of the <algorithm> `std::merge()` function
+// to merge two sorted containers into a single sorted iterator.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) {
+  return std::merge(container_algorithm_internal::c_begin(c1),
+                    container_algorithm_internal::c_end(c1),
+                    container_algorithm_internal::c_begin(c2),
+                    container_algorithm_internal::c_end(c2), result);
+}
+
+// Overload of c_merge() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result,
+                       Compare&& comp) {
+  return std::merge(container_algorithm_internal::c_begin(c1),
+                    container_algorithm_internal::c_end(c1),
+                    container_algorithm_internal::c_begin(c2),
+                    container_algorithm_internal::c_end(c2), result,
+                    std::forward<Compare>(comp));
+}
+
+// c_inplace_merge()
+//
+// Container-based version of the <algorithm> `std::inplace_merge()` function
+// to merge a supplied iterator `middle` into a container.
+template <typename C>
+void c_inplace_merge(C& c,
+                     container_algorithm_internal::ContainerIter<C> middle) {
+  std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
+                     container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_inplace_merge() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C, typename Compare>
+void c_inplace_merge(C& c,
+                     container_algorithm_internal::ContainerIter<C> middle,
+                     Compare&& comp) {
+  std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
+                     container_algorithm_internal::c_end(c),
+                     std::forward<Compare>(comp));
+}
+
+// c_includes()
+//
+// Container-based version of the <algorithm> `std::includes()` function
+// to test whether a sorted container `c1` entirely contains another sorted
+// container `c2`.
+template <typename C1, typename C2>
+bool c_includes(const C1& c1, const C2& c2) {
+  return std::includes(container_algorithm_internal::c_begin(c1),
+                       container_algorithm_internal::c_end(c1),
+                       container_algorithm_internal::c_begin(c2),
+                       container_algorithm_internal::c_end(c2));
+}
+
+// Overload of c_includes() for performing a merge using a `comp` other than
+// `operator<`.
+template <typename C1, typename C2, typename Compare>
+bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
+  return std::includes(container_algorithm_internal::c_begin(c1),
+                       container_algorithm_internal::c_end(c1),
+                       container_algorithm_internal::c_begin(c2),
+                       container_algorithm_internal::c_end(c2),
+                       std::forward<Compare>(comp));
+}
+
+// c_set_union()
+//
+// Container-based version of the <algorithm> `std::set_union()` function
+// to return an iterator containing the union of two containers; duplicate
+// values are not copied into the output.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
+  return std::set_union(container_algorithm_internal::c_begin(c1),
+                        container_algorithm_internal::c_end(c1),
+                        container_algorithm_internal::c_begin(c2),
+                        container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_union() for performing a merge using a `comp` other than
+// `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
+                           Compare&& comp) {
+  return std::set_union(container_algorithm_internal::c_begin(c1),
+                        container_algorithm_internal::c_end(c1),
+                        container_algorithm_internal::c_begin(c2),
+                        container_algorithm_internal::c_end(c2), output,
+                        std::forward<Compare>(comp));
+}
+
+// c_set_intersection()
+//
+// Container-based version of the <algorithm> `std::set_intersection()` function
+// to return an iterator containing the intersection of two containers.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_intersection(const C1& c1, const C2& c2,
+                                  OutputIterator output) {
+  return std::set_intersection(container_algorithm_internal::c_begin(c1),
+                               container_algorithm_internal::c_end(c1),
+                               container_algorithm_internal::c_begin(c2),
+                               container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_intersection() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_intersection(const C1& c1, const C2& c2,
+                                  OutputIterator output, Compare&& comp) {
+  return std::set_intersection(container_algorithm_internal::c_begin(c1),
+                               container_algorithm_internal::c_end(c1),
+                               container_algorithm_internal::c_begin(c2),
+                               container_algorithm_internal::c_end(c2), output,
+                               std::forward<Compare>(comp));
+}
+
+// c_set_difference()
+//
+// Container-based version of the <algorithm> `std::set_difference()` function
+// to return an iterator containing elements present in the first container but
+// not in the second.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_difference(const C1& c1, const C2& c2,
+                                OutputIterator output) {
+  return std::set_difference(container_algorithm_internal::c_begin(c1),
+                             container_algorithm_internal::c_end(c1),
+                             container_algorithm_internal::c_begin(c2),
+                             container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_difference() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_difference(const C1& c1, const C2& c2,
+                                OutputIterator output, Compare&& comp) {
+  return std::set_difference(container_algorithm_internal::c_begin(c1),
+                             container_algorithm_internal::c_end(c1),
+                             container_algorithm_internal::c_begin(c2),
+                             container_algorithm_internal::c_end(c2), output,
+                             std::forward<Compare>(comp));
+}
+
+// c_set_symmetric_difference()
+//
+// Container-based version of the <algorithm> `std::set_symmetric_difference()`
+// function to return an iterator containing elements present in either one
+// container or the other, but not both.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
+                                          OutputIterator output) {
+  return std::set_symmetric_difference(
+      container_algorithm_internal::c_begin(c1),
+      container_algorithm_internal::c_end(c1),
+      container_algorithm_internal::c_begin(c2),
+      container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_symmetric_difference() for performing a merge using a
+// `comp` other than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
+                                          OutputIterator output,
+                                          Compare&& comp) {
+  return std::set_symmetric_difference(
+      container_algorithm_internal::c_begin(c1),
+      container_algorithm_internal::c_end(c1),
+      container_algorithm_internal::c_begin(c2),
+      container_algorithm_internal::c_end(c2), output,
+      std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Heap functions
+//------------------------------------------------------------------------------
+
+// c_push_heap()
+//
+// Container-based version of the <algorithm> `std::push_heap()` function
+// to push a value onto a container heap.
+template <typename RandomAccessContainer>
+void c_push_heap(RandomAccessContainer& sequence) {
+  std::push_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_push_heap() for performing a push operation on a heap using a
+// `comp` other than `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::push_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence),
+                 std::forward<Compare>(comp));
+}
+
+// c_pop_heap()
+//
+// Container-based version of the <algorithm> `std::pop_heap()` function
+// to pop a value from a heap container.
+template <typename RandomAccessContainer>
+void c_pop_heap(RandomAccessContainer& sequence) {
+  std::pop_heap(container_algorithm_internal::c_begin(sequence),
+                container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_pop_heap() for performing a pop operation on a heap using a
+// `comp` other than `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::pop_heap(container_algorithm_internal::c_begin(sequence),
+                container_algorithm_internal::c_end(sequence),
+                std::forward<Compare>(comp));
+}
+
+// c_make_heap()
+//
+// Container-based version of the <algorithm> `std::make_heap()` function
+// to make a container a heap.
+template <typename RandomAccessContainer>
+void c_make_heap(RandomAccessContainer& sequence) {
+  std::make_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_make_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::make_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence),
+                 std::forward<Compare>(comp));
+}
+
+// c_sort_heap()
+//
+// Container-based version of the <algorithm> `std::sort_heap()` function
+// to sort a heap into ascending order (after which it is no longer a heap).
+template <typename RandomAccessContainer>
+void c_sort_heap(RandomAccessContainer& sequence) {
+  std::sort_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_sort_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::sort_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence),
+                 std::forward<Compare>(comp));
+}
+
+// c_is_heap()
+//
+// Container-based version of the <algorithm> `std::is_heap()` function
+// to check whether the given container is a heap.
+template <typename RandomAccessContainer>
+bool c_is_heap(const RandomAccessContainer& sequence) {
+  return std::is_heap(container_algorithm_internal::c_begin(sequence),
+                      container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_is_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) {
+  return std::is_heap(container_algorithm_internal::c_begin(sequence),
+                      container_algorithm_internal::c_end(sequence),
+                      std::forward<Compare>(comp));
+}
+
+// c_is_heap_until()
+//
+// Container-based version of the <algorithm> `std::is_heap_until()` function
+// to find the first element in a given container which is not in heap order.
+template <typename RandomAccessContainer>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_is_heap_until(RandomAccessContainer& sequence) {
+  return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_is_heap_until() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) {
+  return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+//  <algorithm> Min/max
+//------------------------------------------------------------------------------
+
+// c_min_element()
+//
+// Container-based version of the <algorithm> `std::min_element()` function
+// to return an iterator pointing to the element with the smallest value, using
+// `operator<` to make the comparisons.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_min_element(
+    Sequence& sequence) {
+  return std::min_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_min_element() for performing a `comp` comparison other than
+// `operator<`.
+template <typename Sequence, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_min_element(
+    Sequence& sequence, Compare&& comp) {
+  return std::min_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<Compare>(comp));
+}
+
+// c_max_element()
+//
+// Container-based version of the <algorithm> `std::max_element()` function
+// to return an iterator pointing to the element with the largest value, using
+// `operator<` to make the comparisons.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_max_element(
+    Sequence& sequence) {
+  return std::max_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_max_element() for performing a `comp` comparison other than
+// `operator<`.
+template <typename Sequence, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_max_element(
+    Sequence& sequence, Compare&& comp) {
+  return std::max_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<Compare>(comp));
+}
+
+// c_minmax_element()
+//
+// Container-based version of the <algorithm> `std::minmax_element()` function
+// to return a pair of iterators pointing to the elements containing the
+// smallest and largest values, respectively, using `operator<` to make the
+// comparisons.
+template <typename C>
+container_algorithm_internal::ContainerIterPairType<C, C>
+c_minmax_element(C& c) {
+  return std::minmax_element(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_minmax_element() for performing `comp` comparisons other than
+// `operator<`.
+template <typename C, typename Compare>
+container_algorithm_internal::ContainerIterPairType<C, C>
+c_minmax_element(C& c, Compare&& comp) {
+  return std::minmax_element(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c),
+                             std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+//  <algorithm> Lexicographical Comparisons
+//------------------------------------------------------------------------------
+
+// c_lexicographical_compare()
+//
+// Container-based version of the <algorithm> `std::lexicographical_compare()`
+// function to lexicographically compare (e.g. sort words alphabetically) two
+// container sequences. The comparison is performed using `operator<`. Note
+// that capital letters ("A-Z") have ASCII values less than lowercase letters
+// ("a-z").
+template <typename Sequence1, typename Sequence2>
+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) {
+  return std::lexicographical_compare(
+      container_algorithm_internal::c_begin(sequence1),
+      container_algorithm_internal::c_end(sequence1),
+      container_algorithm_internal::c_begin(sequence2),
+      container_algorithm_internal::c_end(sequence2));
+}
+
+// Overload of c_lexicographical_compare() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename Sequence1, typename Sequence2, typename Compare>
+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2,
+                               Compare&& comp) {
+  return std::lexicographical_compare(
+      container_algorithm_internal::c_begin(sequence1),
+      container_algorithm_internal::c_end(sequence1),
+      container_algorithm_internal::c_begin(sequence2),
+      container_algorithm_internal::c_end(sequence2),
+      std::forward<Compare>(comp));
+}
+
+// c_next_permutation()
+//
+// Container-based version of the <algorithm> `std::next_permutation()` function
+// to rearrange a container's elements into the next lexicographically greater
+// permutation.
+template <typename C>
+bool c_next_permutation(C& c) {
+  return std::next_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_next_permutation() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename C, typename Compare>
+bool c_next_permutation(C& c, Compare&& comp) {
+  return std::next_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c),
+                               std::forward<Compare>(comp));
+}
+
+// c_prev_permutation()
+//
+// Container-based version of the <algorithm> `std::prev_permutation()` function
+// to rearrange a container's elements into the next lexicographically lesser
+// permutation.
+template <typename C>
+bool c_prev_permutation(C& c) {
+  return std::prev_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_prev_permutation() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename C, typename Compare>
+bool c_prev_permutation(C& c, Compare&& comp) {
+  return std::prev_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c),
+                               std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <numeric> algorithms
+//------------------------------------------------------------------------------
+
+// c_iota()
+//
+// Container-based version of the <algorithm> `std::iota()` function
+// to compute successive values of `value`, as if incremented with `++value`
+// after each element is written. and write them to the container.
+template <typename Sequence, typename T>
+void c_iota(Sequence& sequence, T&& value) {
+  std::iota(container_algorithm_internal::c_begin(sequence),
+            container_algorithm_internal::c_end(sequence),
+            std::forward<T>(value));
+}
+// c_accumulate()
+//
+// Container-based version of the <algorithm> `std::accumulate()` function
+// to accumulate the element values of a container to `init` and return that
+// accumulation by value.
+//
+// Note: Due to a language technicality this function has return type
+// absl::decay_t<T>. As a user of this function you can casually read
+// this as "returns T by value" and assume it does the right thing.
+template <typename Sequence, typename T>
+decay_t<T> c_accumulate(const Sequence& sequence, T&& init) {
+  return std::accumulate(container_algorithm_internal::c_begin(sequence),
+                         container_algorithm_internal::c_end(sequence),
+                         std::forward<T>(init));
+}
+
+// Overload of c_accumulate() for using a binary operations other than
+// addition for computing the accumulation.
+template <typename Sequence, typename T, typename BinaryOp>
+decay_t<T> c_accumulate(const Sequence& sequence, T&& init,
+                        BinaryOp&& binary_op) {
+  return std::accumulate(container_algorithm_internal::c_begin(sequence),
+                         container_algorithm_internal::c_end(sequence),
+                         std::forward<T>(init),
+                         std::forward<BinaryOp>(binary_op));
+}
+
+// c_inner_product()
+//
+// Container-based version of the <algorithm> `std::inner_product()` function
+// to compute the cumulative inner product of container element pairs.
+//
+// Note: Due to a language technicality this function has return type
+// absl::decay_t<T>. As a user of this function you can casually read
+// this as "returns T by value" and assume it does the right thing.
+template <typename Sequence1, typename Sequence2, typename T>
+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
+                           T&& sum) {
+  return std::inner_product(container_algorithm_internal::c_begin(factors1),
+                            container_algorithm_internal::c_end(factors1),
+                            container_algorithm_internal::c_begin(factors2),
+                            std::forward<T>(sum));
+}
+
+// Overload of c_inner_product() for using binary operations other than
+// `operator+` (for computing the accumulation) and `operator*` (for computing
+// the product between the two container's element pair).
+template <typename Sequence1, typename Sequence2, typename T,
+          typename BinaryOp1, typename BinaryOp2>
+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
+                           T&& sum, BinaryOp1&& op1, BinaryOp2&& op2) {
+  return std::inner_product(container_algorithm_internal::c_begin(factors1),
+                            container_algorithm_internal::c_end(factors1),
+                            container_algorithm_internal::c_begin(factors2),
+                            std::forward<T>(sum), std::forward<BinaryOp1>(op1),
+                            std::forward<BinaryOp2>(op2));
+}
+
+// c_adjacent_difference()
+//
+// Container-based version of the <algorithm> `std::adjacent_difference()`
+// function to compute the difference between each element and the one preceding
+// it and write it to an iterator.
+template <typename InputSequence, typename OutputIt>
+OutputIt c_adjacent_difference(const InputSequence& input,
+                               OutputIt output_first) {
+  return std::adjacent_difference(container_algorithm_internal::c_begin(input),
+                                  container_algorithm_internal::c_end(input),
+                                  output_first);
+}
+
+// Overload of c_adjacent_difference() for using a binary operation other than
+// subtraction to compute the adjacent difference.
+template <typename InputSequence, typename OutputIt, typename BinaryOp>
+OutputIt c_adjacent_difference(const InputSequence& input,
+                               OutputIt output_first, BinaryOp&& op) {
+  return std::adjacent_difference(container_algorithm_internal::c_begin(input),
+                                  container_algorithm_internal::c_end(input),
+                                  output_first, std::forward<BinaryOp>(op));
+}
+
+// c_partial_sum()
+//
+// Container-based version of the <algorithm> `std::partial_sum()` function
+// to compute the partial sum of the elements in a sequence and write them
+// to an iterator. The partial sum is the sum of all element values so far in
+// the sequence.
+template <typename InputSequence, typename OutputIt>
+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first) {
+  return std::partial_sum(container_algorithm_internal::c_begin(input),
+                          container_algorithm_internal::c_end(input),
+                          output_first);
+}
+
+// Overload of c_partial_sum() for using a binary operation other than addition
+// to compute the "partial sum".
+template <typename InputSequence, typename OutputIt, typename BinaryOp>
+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
+                       BinaryOp&& op) {
+  return std::partial_sum(container_algorithm_internal::c_begin(input),
+                          container_algorithm_internal::c_end(input),
+                          output_first, std::forward<BinaryOp>(op));
+}
+
+}  // namespace absl
+
+#endif  // ABSL_ALGORITHM_CONTAINER_H_
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
new file mode 100644
index 0000000..de66f14
--- /dev/null
+++ b/absl/algorithm/container_test.cc
@@ -0,0 +1,997 @@
+// Copyright 2017 The Abseil 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 "absl/algorithm/container.h"
+
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <list>
+#include <memory>
+#include <ostream>
+#include <random>
+#include <set>
+#include <unordered_set>
+#include <utility>
+#include <valarray>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/casts.h"
+#include "absl/base/macros.h"
+#include "absl/memory/memory.h"
+#include "absl/types/span.h"
+
+namespace {
+
+using ::testing::Each;
+using ::testing::ElementsAre;
+using ::testing::Gt;
+using ::testing::IsNull;
+using ::testing::Lt;
+using ::testing::Pointee;
+using ::testing::Truly;
+using ::testing::UnorderedElementsAre;
+
+// Most of these tests just check that the code compiles, not that it
+// does the right thing. That's fine since the functions just forward
+// to the STL implementation.
+class NonMutatingTest : public testing::Test {
+ protected:
+  std::unordered_set<int> container_ = {1, 2, 3};
+  std::list<int> sequence_ = {1, 2, 3};
+  std::vector<int> vector_ = {1, 2, 3};
+  int array_[3] = {1, 2, 3};
+};
+
+struct AccumulateCalls {
+  void operator()(int value) {
+    calls.push_back(value);
+  }
+  std::vector<int> calls;
+};
+
+bool Predicate(int value) { return value < 3; }
+bool BinPredicate(int v1, int v2) { return v1 < v2; }
+bool Equals(int v1, int v2) { return v1 == v2; }
+bool IsOdd(int x) { return x % 2 != 0; }
+
+
+TEST_F(NonMutatingTest, Distance) {
+  EXPECT_EQ(container_.size(), absl::c_distance(container_));
+  EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_));
+  EXPECT_EQ(vector_.size(), absl::c_distance(vector_));
+  EXPECT_EQ(ABSL_ARRAYSIZE(array_), absl::c_distance(array_));
+
+  // Works with a temporary argument.
+  EXPECT_EQ(vector_.size(), absl::c_distance(std::vector<int>(vector_)));
+}
+
+TEST_F(NonMutatingTest, Distance_OverloadedBeginEnd) {
+  // Works with classes which have custom ADL-selected overloads of std::begin
+  // and std::end.
+  std::initializer_list<int> a = {1, 2, 3};
+  std::valarray<int> b = {1, 2, 3};
+  EXPECT_EQ(3, absl::c_distance(a));
+  EXPECT_EQ(3, absl::c_distance(b));
+
+  // It is assumed that other c_* functions use the same mechanism for
+  // ADL-selecting begin/end overloads.
+}
+
+TEST_F(NonMutatingTest, ForEach) {
+  AccumulateCalls c = absl::c_for_each(container_, AccumulateCalls());
+  // Don't rely on the unordered_set's order.
+  std::sort(c.calls.begin(), c.calls.end());
+  EXPECT_EQ(vector_, c.calls);
+
+  // Works with temporary container, too.
+  AccumulateCalls c2 =
+      absl::c_for_each(std::unordered_set<int>(container_), AccumulateCalls());
+  std::sort(c2.calls.begin(), c2.calls.end());
+  EXPECT_EQ(vector_, c2.calls);
+}
+
+TEST_F(NonMutatingTest, FindReturnsCorrectType) {
+  auto it = absl::c_find(container_, 3);
+  EXPECT_EQ(3, *it);
+  absl::c_find(absl::implicit_cast<const std::list<int>&>(sequence_), 3);
+}
+
+TEST_F(NonMutatingTest, FindIf) { absl::c_find_if(container_, Predicate); }
+
+TEST_F(NonMutatingTest, FindIfNot) {
+  absl::c_find_if_not(container_, Predicate);
+}
+
+TEST_F(NonMutatingTest, FindEnd) {
+  absl::c_find_end(sequence_, vector_);
+  absl::c_find_end(vector_, sequence_);
+}
+
+TEST_F(NonMutatingTest, FindEndWithPredicate) {
+  absl::c_find_end(sequence_, vector_, BinPredicate);
+  absl::c_find_end(vector_, sequence_, BinPredicate);
+}
+
+TEST_F(NonMutatingTest, FindFirstOf) {
+  absl::c_find_first_of(container_, sequence_);
+  absl::c_find_first_of(sequence_, container_);
+}
+
+TEST_F(NonMutatingTest, FindFirstOfWithPredicate) {
+  absl::c_find_first_of(container_, sequence_, BinPredicate);
+  absl::c_find_first_of(sequence_, container_, BinPredicate);
+}
+
+TEST_F(NonMutatingTest, AdjacentFind) { absl::c_adjacent_find(sequence_); }
+
+TEST_F(NonMutatingTest, AdjacentFindWithPredicate) {
+  absl::c_adjacent_find(sequence_, BinPredicate);
+}
+
+TEST_F(NonMutatingTest, Count) { EXPECT_EQ(1, absl::c_count(container_, 3)); }
+
+TEST_F(NonMutatingTest, CountIf) {
+  EXPECT_EQ(2, absl::c_count_if(container_, Predicate));
+  const std::unordered_set<int>& const_container = container_;
+  EXPECT_EQ(2, absl::c_count_if(const_container, Predicate));
+}
+
+TEST_F(NonMutatingTest, Mismatch) {
+  absl::c_mismatch(container_, sequence_);
+  absl::c_mismatch(sequence_, container_);
+}
+
+TEST_F(NonMutatingTest, MismatchWithPredicate) {
+  absl::c_mismatch(container_, sequence_, BinPredicate);
+  absl::c_mismatch(sequence_, container_, BinPredicate);
+}
+
+TEST_F(NonMutatingTest, Equal) {
+  EXPECT_TRUE(absl::c_equal(vector_, sequence_));
+  EXPECT_TRUE(absl::c_equal(sequence_, vector_));
+
+  // Test that behavior appropriately differs from that of equal().
+  std::vector<int> vector_plus = {1, 2, 3};
+  vector_plus.push_back(4);
+  EXPECT_FALSE(absl::c_equal(vector_plus, sequence_));
+  EXPECT_FALSE(absl::c_equal(sequence_, vector_plus));
+}
+
+TEST_F(NonMutatingTest, EqualWithPredicate) {
+  EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals));
+  EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals));
+
+  // Test that behavior appropriately differs from that of equal().
+  std::vector<int> vector_plus = {1, 2, 3};
+  vector_plus.push_back(4);
+  EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals));
+  EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals));
+}
+
+TEST_F(NonMutatingTest, IsPermutation) {
+  auto vector_permut_ = vector_;
+  std::next_permutation(vector_permut_.begin(), vector_permut_.end());
+  EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_));
+  EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_));
+
+  // Test that behavior appropriately differs from that of is_permutation().
+  std::vector<int> vector_plus = {1, 2, 3};
+  vector_plus.push_back(4);
+  EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_));
+  EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus));
+}
+
+TEST_F(NonMutatingTest, IsPermutationWithPredicate) {
+  auto vector_permut_ = vector_;
+  std::next_permutation(vector_permut_.begin(), vector_permut_.end());
+  EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_, Equals));
+  EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_, Equals));
+
+  // Test that behavior appropriately differs from that of is_permutation().
+  std::vector<int> vector_plus = {1, 2, 3};
+  vector_plus.push_back(4);
+  EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_, Equals));
+  EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus, Equals));
+}
+
+TEST_F(NonMutatingTest, Search) {
+  absl::c_search(sequence_, vector_);
+  absl::c_search(vector_, sequence_);
+  absl::c_search(array_, sequence_);
+}
+
+TEST_F(NonMutatingTest, SearchWithPredicate) {
+  absl::c_search(sequence_, vector_, BinPredicate);
+  absl::c_search(vector_, sequence_, BinPredicate);
+}
+
+TEST_F(NonMutatingTest, SearchN) { absl::c_search_n(sequence_, 3, 1); }
+
+TEST_F(NonMutatingTest, SearchNWithPredicate) {
+  absl::c_search_n(sequence_, 3, 1, BinPredicate);
+}
+
+TEST_F(NonMutatingTest, LowerBound) {
+  std::list<int>::iterator i = absl::c_lower_bound(sequence_, 3);
+  ASSERT_TRUE(i != sequence_.end());
+  EXPECT_EQ(2, std::distance(sequence_.begin(), i));
+  EXPECT_EQ(3, *i);
+}
+
+TEST_F(NonMutatingTest, LowerBoundWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  std::vector<int>::iterator i = absl::c_lower_bound(v, 3, std::greater<int>());
+  EXPECT_TRUE(i == v.begin());
+  EXPECT_EQ(3, *i);
+}
+
+TEST_F(NonMutatingTest, UpperBound) {
+  std::list<int>::iterator i = absl::c_upper_bound(sequence_, 1);
+  ASSERT_TRUE(i != sequence_.end());
+  EXPECT_EQ(1, std::distance(sequence_.begin(), i));
+  EXPECT_EQ(2, *i);
+}
+
+TEST_F(NonMutatingTest, UpperBoundWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  std::vector<int>::iterator i = absl::c_upper_bound(v, 1, std::greater<int>());
+  EXPECT_EQ(3, i - v.begin());
+  EXPECT_TRUE(i == v.end());
+}
+
+TEST_F(NonMutatingTest, EqualRange) {
+  std::pair<std::list<int>::iterator, std::list<int>::iterator> p =
+      absl::c_equal_range(sequence_, 2);
+  EXPECT_EQ(1, std::distance(sequence_.begin(), p.first));
+  EXPECT_EQ(2, std::distance(sequence_.begin(), p.second));
+}
+
+TEST_F(NonMutatingTest, EqualRangeArray) {
+  auto p = absl::c_equal_range(array_, 2);
+  EXPECT_EQ(1, std::distance(std::begin(array_), p.first));
+  EXPECT_EQ(2, std::distance(std::begin(array_), p.second));
+}
+
+TEST_F(NonMutatingTest, EqualRangeWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p =
+      absl::c_equal_range(v, 2, std::greater<int>());
+  EXPECT_EQ(1, std::distance(v.begin(), p.first));
+  EXPECT_EQ(2, std::distance(v.begin(), p.second));
+}
+
+TEST_F(NonMutatingTest, BinarySearch) {
+  EXPECT_TRUE(absl::c_binary_search(vector_, 2));
+  EXPECT_TRUE(absl::c_binary_search(std::vector<int>(vector_), 2));
+}
+
+TEST_F(NonMutatingTest, BinarySearchWithPredicate) {
+  std::vector<int> v(vector_);
+  std::sort(v.begin(), v.end(), std::greater<int>());
+  EXPECT_TRUE(absl::c_binary_search(v, 2, std::greater<int>()));
+  EXPECT_TRUE(
+      absl::c_binary_search(std::vector<int>(v), 2, std::greater<int>()));
+}
+
+TEST_F(NonMutatingTest, MinElement) {
+  std::list<int>::iterator i = absl::c_min_element(sequence_);
+  ASSERT_TRUE(i != sequence_.end());
+  EXPECT_EQ(*i, 1);
+}
+
+TEST_F(NonMutatingTest, MinElementWithPredicate) {
+  std::list<int>::iterator i =
+      absl::c_min_element(sequence_, std::greater<int>());
+  ASSERT_TRUE(i != sequence_.end());
+  EXPECT_EQ(*i, 3);
+}
+
+TEST_F(NonMutatingTest, MaxElement) {
+  std::list<int>::iterator i = absl::c_max_element(sequence_);
+  ASSERT_TRUE(i != sequence_.end());
+  EXPECT_EQ(*i, 3);
+}
+
+TEST_F(NonMutatingTest, MaxElementWithPredicate) {
+  std::list<int>::iterator i =
+      absl::c_max_element(sequence_, std::greater<int>());
+  ASSERT_TRUE(i != sequence_.end());
+  EXPECT_EQ(*i, 1);
+}
+
+TEST_F(NonMutatingTest, LexicographicalCompare) {
+  EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_));
+
+  std::vector<int> v;
+  v.push_back(1);
+  v.push_back(2);
+  v.push_back(4);
+
+  EXPECT_TRUE(absl::c_lexicographical_compare(sequence_, v));
+  EXPECT_TRUE(absl::c_lexicographical_compare(std::list<int>(sequence_), v));
+}
+
+TEST_F(NonMutatingTest, LexicographicalCopmareWithPredicate) {
+  EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_,
+                                               std::greater<int>()));
+
+  std::vector<int> v;
+  v.push_back(1);
+  v.push_back(2);
+  v.push_back(4);
+
+  EXPECT_TRUE(
+      absl::c_lexicographical_compare(v, sequence_, std::greater<int>()));
+  EXPECT_TRUE(absl::c_lexicographical_compare(
+      std::vector<int>(v), std::list<int>(sequence_), std::greater<int>()));
+}
+
+TEST_F(NonMutatingTest, Includes) {
+  std::set<int> s(vector_.begin(), vector_.end());
+  s.insert(4);
+  EXPECT_TRUE(absl::c_includes(s, vector_));
+}
+
+TEST_F(NonMutatingTest, IncludesWithPredicate) {
+  std::vector<int> v = {3, 2, 1};
+  std::set<int, std::greater<int>> s(v.begin(), v.end());
+  s.insert(4);
+  EXPECT_TRUE(absl::c_includes(s, v, std::greater<int>()));
+}
+
+class NumericMutatingTest : public testing::Test {
+ protected:
+  std::list<int> list_ = {1, 2, 3};
+  std::vector<int> output_;
+};
+
+TEST_F(NumericMutatingTest, Iota) {
+  absl::c_iota(list_, 5);
+  std::list<int> expected{5, 6, 7};
+  EXPECT_EQ(list_, expected);
+}
+
+TEST_F(NonMutatingTest, Accumulate) {
+  EXPECT_EQ(absl::c_accumulate(sequence_, 4), 1 + 2 + 3 + 4);
+}
+
+TEST_F(NonMutatingTest, AccumulateWithBinaryOp) {
+  EXPECT_EQ(absl::c_accumulate(sequence_, 4, std::multiplies<int>()),
+            1 * 2 * 3 * 4);
+}
+
+TEST_F(NonMutatingTest, AccumulateLvalueInit) {
+  int lvalue = 4;
+  EXPECT_EQ(absl::c_accumulate(sequence_, lvalue), 1 + 2 + 3 + 4);
+}
+
+TEST_F(NonMutatingTest, AccumulateWithBinaryOpLvalueInit) {
+  int lvalue = 4;
+  EXPECT_EQ(absl::c_accumulate(sequence_, lvalue, std::multiplies<int>()),
+            1 * 2 * 3 * 4);
+}
+
+TEST_F(NonMutatingTest, InnerProduct) {
+  EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 1000),
+            1000 + 1 * 1 + 2 * 2 + 3 * 3);
+}
+
+TEST_F(NonMutatingTest, InnerProductWithBinaryOps) {
+  EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 10,
+                                  std::multiplies<int>(), std::plus<int>()),
+            10 * (1 + 1) * (2 + 2) * (3 + 3));
+}
+
+TEST_F(NonMutatingTest, InnerProductLvalueInit) {
+  int lvalue = 1000;
+  EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue),
+            1000 + 1 * 1 + 2 * 2 + 3 * 3);
+}
+
+TEST_F(NonMutatingTest, InnerProductWithBinaryOpsLvalueInit) {
+  int lvalue = 10;
+  EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue,
+                                  std::multiplies<int>(), std::plus<int>()),
+            10 * (1 + 1) * (2 + 2) * (3 + 3));
+}
+
+TEST_F(NumericMutatingTest, AdjacentDifference) {
+  auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_));
+  *last = 1000;
+  std::vector<int> expected{1, 2 - 1, 3 - 2, 1000};
+  EXPECT_EQ(output_, expected);
+}
+
+TEST_F(NumericMutatingTest, AdjacentDifferenceWithBinaryOp) {
+  auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_),
+                                          std::multiplies<int>());
+  *last = 1000;
+  std::vector<int> expected{1, 2 * 1, 3 * 2, 1000};
+  EXPECT_EQ(output_, expected);
+}
+
+TEST_F(NumericMutatingTest, PartialSum) {
+  auto last = absl::c_partial_sum(list_, std::back_inserter(output_));
+  *last = 1000;
+  std::vector<int> expected{1, 1 + 2, 1 + 2 + 3, 1000};
+  EXPECT_EQ(output_, expected);
+}
+
+TEST_F(NumericMutatingTest, PartialSumWithBinaryOp) {
+  auto last = absl::c_partial_sum(list_, std::back_inserter(output_),
+                                  std::multiplies<int>());
+  *last = 1000;
+  std::vector<int> expected{1, 1 * 2, 1 * 2 * 3, 1000};
+  EXPECT_EQ(output_, expected);
+}
+
+TEST_F(NonMutatingTest, LinearSearch) {
+  EXPECT_TRUE(absl::c_linear_search(container_, 3));
+  EXPECT_FALSE(absl::c_linear_search(container_, 4));
+}
+
+TEST_F(NonMutatingTest, AllOf) {
+  const std::vector<int>& v = vector_;
+  EXPECT_FALSE(absl::c_all_of(v, [](int x) { return x > 1; }));
+  EXPECT_TRUE(absl::c_all_of(v, [](int x) { return x > 0; }));
+}
+
+TEST_F(NonMutatingTest, AnyOf) {
+  const std::vector<int>& v = vector_;
+  EXPECT_TRUE(absl::c_any_of(v, [](int x) { return x > 2; }));
+  EXPECT_FALSE(absl::c_any_of(v, [](int x) { return x > 5; }));
+}
+
+TEST_F(NonMutatingTest, NoneOf) {
+  const std::vector<int>& v = vector_;
+  EXPECT_FALSE(absl::c_none_of(v, [](int x) { return x > 2; }));
+  EXPECT_TRUE(absl::c_none_of(v, [](int x) { return x > 5; }));
+}
+
+TEST_F(NonMutatingTest, MinMaxElementLess) {
+  std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator>
+      p = absl::c_minmax_element(vector_, std::less<int>());
+  EXPECT_TRUE(p.first == vector_.begin());
+  EXPECT_TRUE(p.second == vector_.begin() + 2);
+}
+
+TEST_F(NonMutatingTest, MinMaxElementGreater) {
+  std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator>
+      p = absl::c_minmax_element(vector_, std::greater<int>());
+  EXPECT_TRUE(p.first == vector_.begin() + 2);
+  EXPECT_TRUE(p.second == vector_.begin());
+}
+
+TEST_F(NonMutatingTest, MinMaxElementNoPredicate) {
+  std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator>
+      p = absl::c_minmax_element(vector_);
+  EXPECT_TRUE(p.first == vector_.begin());
+  EXPECT_TRUE(p.second == vector_.begin() + 2);
+}
+
+class SortingTest : public testing::Test {
+ protected:
+  std::list<int> sorted_ = {1, 2, 3, 4};
+  std::list<int> unsorted_ = {2, 4, 1, 3};
+  std::list<int> reversed_ = {4, 3, 2, 1};
+};
+
+TEST_F(SortingTest, IsSorted) {
+  EXPECT_TRUE(absl::c_is_sorted(sorted_));
+  EXPECT_FALSE(absl::c_is_sorted(unsorted_));
+  EXPECT_FALSE(absl::c_is_sorted(reversed_));
+}
+
+TEST_F(SortingTest, IsSortedWithPredicate) {
+  EXPECT_FALSE(absl::c_is_sorted(sorted_, std::greater<int>()));
+  EXPECT_FALSE(absl::c_is_sorted(unsorted_, std::greater<int>()));
+  EXPECT_TRUE(absl::c_is_sorted(reversed_, std::greater<int>()));
+}
+
+TEST_F(SortingTest, IsSortedUntil) {
+  EXPECT_EQ(1, *absl::c_is_sorted_until(unsorted_));
+  EXPECT_EQ(4, *absl::c_is_sorted_until(unsorted_, std::greater<int>()));
+}
+
+TEST_F(SortingTest, NthElement) {
+  std::vector<int> unsorted = {2, 4, 1, 3};
+  absl::c_nth_element(unsorted, unsorted.begin() + 2);
+  EXPECT_THAT(unsorted,
+              ElementsAre(Lt(3), Lt(3), 3, Gt(3)));
+  absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater<int>());
+  EXPECT_THAT(unsorted,
+              ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
+}
+
+TEST(MutatingTest, IsPartitioned) {
+  EXPECT_TRUE(
+      absl::c_is_partitioned(std::vector<int>{1, 3, 5, 2, 4, 6}, IsOdd));
+  EXPECT_FALSE(
+      absl::c_is_partitioned(std::vector<int>{1, 2, 3, 4, 5, 6}, IsOdd));
+  EXPECT_FALSE(
+      absl::c_is_partitioned(std::vector<int>{2, 4, 6, 1, 3, 5}, IsOdd));
+}
+
+TEST(MutatingTest, Partition) {
+  std::vector<int> actual = {1, 2, 3, 4, 5};
+  absl::c_partition(actual, IsOdd);
+  EXPECT_THAT(actual, Truly([](const std::vector<int>& c) {
+                return absl::c_is_partitioned(c, IsOdd);
+              }));
+}
+
+TEST(MutatingTest, StablePartition) {
+  std::vector<int> actual = {1, 2, 3, 4, 5};
+  absl::c_stable_partition(actual, IsOdd);
+  EXPECT_THAT(actual, ElementsAre(1, 3, 5, 2, 4));
+}
+
+TEST(MutatingTest, PartitionCopy) {
+  const std::vector<int> initial = {1, 2, 3, 4, 5};
+  std::vector<int> odds, evens;
+  auto ends = absl::c_partition_copy(initial, back_inserter(odds),
+                                     back_inserter(evens), IsOdd);
+  *ends.first = 7;
+  *ends.second = 6;
+  EXPECT_THAT(odds, ElementsAre(1, 3, 5, 7));
+  EXPECT_THAT(evens, ElementsAre(2, 4, 6));
+}
+
+TEST(MutatingTest, PartitionPoint) {
+  const std::vector<int> initial = {1, 3, 5, 2, 4};
+  auto middle = absl::c_partition_point(initial, IsOdd);
+  EXPECT_EQ(2, *middle);
+}
+
+TEST(MutatingTest, CopyMiddle) {
+  const std::vector<int> initial = {4, -1, -2, -3, 5};
+  const std::list<int> input = {1, 2, 3};
+  const std::vector<int> expected = {4, 1, 2, 3, 5};
+
+  std::list<int> test_list(initial.begin(), initial.end());
+  absl::c_copy(input, ++test_list.begin());
+  EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list);
+
+  std::vector<int> test_vector = initial;
+  absl::c_copy(input, test_vector.begin() + 1);
+  EXPECT_EQ(expected, test_vector);
+}
+
+TEST(MutatingTest, CopyFrontInserter) {
+  const std::list<int> initial = {4, 5};
+  const std::list<int> input = {1, 2, 3};
+  const std::list<int> expected = {3, 2, 1, 4, 5};
+
+  std::list<int> test_list = initial;
+  absl::c_copy(input, std::front_inserter(test_list));
+  EXPECT_EQ(expected, test_list);
+}
+
+TEST(MutatingTest, CopyBackInserter) {
+  const std::vector<int> initial = {4, 5};
+  const std::list<int> input = {1, 2, 3};
+  const std::vector<int> expected = {4, 5, 1, 2, 3};
+
+  std::list<int> test_list(initial.begin(), initial.end());
+  absl::c_copy(input, std::back_inserter(test_list));
+  EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list);
+
+  std::vector<int> test_vector = initial;
+  absl::c_copy(input, std::back_inserter(test_vector));
+  EXPECT_EQ(expected, test_vector);
+}
+
+TEST(MutatingTest, CopyN) {
+  const std::vector<int> initial = {1, 2, 3, 4, 5};
+  const std::vector<int> expected = {1, 2};
+  std::vector<int> actual;
+  absl::c_copy_n(initial, 2, back_inserter(actual));
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MutatingTest, CopyIf) {
+  const std::list<int> input = {1, 2, 3};
+  std::vector<int> output;
+  absl::c_copy_if(input, std::back_inserter(output),
+                  [](int i) { return i != 2; });
+  EXPECT_THAT(output, ElementsAre(1, 3));
+}
+
+TEST(MutatingTest, CopyBackward) {
+  std::vector<int> actual = {1, 2, 3, 4, 5};
+  std::vector<int> expected = {1, 2, 1, 2, 3};
+  absl::c_copy_backward(absl::MakeSpan(actual.data(), 3), actual.end());
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MutatingTest, Move) {
+  std::vector<std::unique_ptr<int>> src;
+  src.emplace_back(absl::make_unique<int>(1));
+  src.emplace_back(absl::make_unique<int>(2));
+  src.emplace_back(absl::make_unique<int>(3));
+  src.emplace_back(absl::make_unique<int>(4));
+  src.emplace_back(absl::make_unique<int>(5));
+
+  std::vector<std::unique_ptr<int>> dest = {};
+  absl::c_move(src, std::back_inserter(dest));
+  EXPECT_THAT(src, Each(IsNull()));
+  EXPECT_THAT(dest, ElementsAre(Pointee(1), Pointee(2), Pointee(3), Pointee(4),
+                                Pointee(5)));
+}
+
+TEST(MutatingTest, SwapRanges) {
+  std::vector<int> odds = {2, 4, 6};
+  std::vector<int> evens = {1, 3, 5};
+  absl::c_swap_ranges(odds, evens);
+  EXPECT_THAT(odds, ElementsAre(1, 3, 5));
+  EXPECT_THAT(evens, ElementsAre(2, 4, 6));
+}
+
+TEST_F(NonMutatingTest, Transform) {
+  std::vector<int> x{0, 2, 4}, y, z;
+  auto end = absl::c_transform(x, back_inserter(y), std::negate<int>());
+  EXPECT_EQ(std::vector<int>({0, -2, -4}), y);
+  *end = 7;
+  EXPECT_EQ(std::vector<int>({0, -2, -4, 7}), y);
+
+  y = {1, 3, 0};
+  end = absl::c_transform(x, y, back_inserter(z), std::plus<int>());
+  EXPECT_EQ(std::vector<int>({1, 5, 4}), z);
+  *end = 7;
+  EXPECT_EQ(std::vector<int>({1, 5, 4, 7}), z);
+}
+
+TEST(MutatingTest, Replace) {
+  const std::vector<int> initial = {1, 2, 3, 1, 4, 5};
+  const std::vector<int> expected = {4, 2, 3, 4, 4, 5};
+
+  std::vector<int> test_vector = initial;
+  absl::c_replace(test_vector, 1, 4);
+  EXPECT_EQ(expected, test_vector);
+
+  std::list<int> test_list(initial.begin(), initial.end());
+  absl::c_replace(test_list, 1, 4);
+  EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list);
+}
+
+TEST(MutatingTest, ReplaceIf) {
+  std::vector<int> actual = {1, 2, 3, 4, 5};
+  const std::vector<int> expected = {0, 2, 0, 4, 0};
+
+  absl::c_replace_if(actual, IsOdd, 0);
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MutatingTest, ReplaceCopy) {
+  const std::vector<int> initial = {1, 2, 3, 1, 4, 5};
+  const std::vector<int> expected = {4, 2, 3, 4, 4, 5};
+
+  std::vector<int> actual;
+  absl::c_replace_copy(initial, back_inserter(actual), 1, 4);
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MutatingTest, Sort) {
+  std::vector<int> test_vector = {2, 3, 1, 4};
+  absl::c_sort(test_vector);
+  EXPECT_THAT(test_vector, ElementsAre(1, 2, 3, 4));
+}
+
+TEST(MutatingTest, SortWithPredicate) {
+  std::vector<int> test_vector = {2, 3, 1, 4};
+  absl::c_sort(test_vector, std::greater<int>());
+  EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1));
+}
+
+// For absl::c_stable_sort tests. Needs an operator< that does not cover all
+// fields so that the test can check the sort preserves order of equal elements.
+struct Element {
+  int key;
+  int value;
+  friend bool operator<(const Element& e1, const Element& e2) {
+    return e1.key < e2.key;
+  }
+  // Make gmock print useful diagnostics.
+  friend std::ostream& operator<<(std::ostream& o, const Element& e) {
+    return o << "{" << e.key << ", " << e.value << "}";
+  }
+};
+
+MATCHER_P2(IsElement, key, value, "") {
+  return arg.key == key && arg.value == value;
+}
+
+TEST(MutatingTest, StableSort) {
+  std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}};
+  absl::c_stable_sort(test_vector);
+  EXPECT_THAT(
+      test_vector,
+      ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
+                  IsElement(2, 0), IsElement(2, 2)));
+}
+
+TEST(MutatingTest, StableSortWithPredicate) {
+  std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}};
+  absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) {
+    return e2 < e1;
+  });
+  EXPECT_THAT(
+      test_vector,
+      ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
+                  IsElement(1, 1), IsElement(1, 0)));
+}
+
+TEST(MutatingTest, ReplaceCopyIf) {
+  const std::vector<int> initial = {1, 2, 3, 4, 5};
+  const std::vector<int> expected = {0, 2, 0, 4, 0};
+
+  std::vector<int> actual;
+  absl::c_replace_copy_if(initial, back_inserter(actual), IsOdd, 0);
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MutatingTest, Fill) {
+  std::vector<int> actual(5);
+  absl::c_fill(actual, 1);
+  EXPECT_THAT(actual, ElementsAre(1, 1, 1, 1, 1));
+}
+
+TEST(MutatingTest, FillN) {
+  std::vector<int> actual(5, 0);
+  absl::c_fill_n(actual, 2, 1);
+  EXPECT_THAT(actual, ElementsAre(1, 1, 0, 0, 0));
+}
+
+TEST(MutatingTest, Generate) {
+  std::vector<int> actual(5);
+  int x = 0;
+  absl::c_generate(actual, [&x]() { return ++x; });
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
+}
+
+TEST(MutatingTest, GenerateN) {
+  std::vector<int> actual(5, 0);
+  int x = 0;
+  absl::c_generate_n(actual, 3, [&x]() { return ++x; });
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 0, 0));
+}
+
+TEST(MutatingTest, RemoveCopy) {
+  std::vector<int> actual;
+  absl::c_remove_copy(std::vector<int>{1, 2, 3}, back_inserter(actual), 2);
+  EXPECT_THAT(actual, ElementsAre(1, 3));
+}
+
+TEST(MutatingTest, RemoveCopyIf) {
+  std::vector<int> actual;
+  absl::c_remove_copy_if(std::vector<int>{1, 2, 3}, back_inserter(actual),
+                         IsOdd);
+  EXPECT_THAT(actual, ElementsAre(2));
+}
+
+TEST(MutatingTest, UniqueCopy) {
+  std::vector<int> actual;
+  absl::c_unique_copy(std::vector<int>{1, 2, 2, 2, 3, 3, 2},
+                      back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 2));
+}
+
+TEST(MutatingTest, UniqueCopyWithPredicate) {
+  std::vector<int> actual;
+  absl::c_unique_copy(std::vector<int>{1, 2, 3, -1, -2, -3, 1},
+                      back_inserter(actual),
+                      [](int x, int y) { return (x < 0) == (y < 0); });
+  EXPECT_THAT(actual, ElementsAre(1, -1, 1));
+}
+
+TEST(MutatingTest, Reverse) {
+  std::vector<int> test_vector = {1, 2, 3, 4};
+  absl::c_reverse(test_vector);
+  EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1));
+
+  std::list<int> test_list = {1, 2, 3, 4};
+  absl::c_reverse(test_list);
+  EXPECT_THAT(test_list, ElementsAre(4, 3, 2, 1));
+}
+
+TEST(MutatingTest, ReverseCopy) {
+  std::vector<int> actual;
+  absl::c_reverse_copy(std::vector<int>{1, 2, 3, 4}, back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(4, 3, 2, 1));
+}
+
+TEST(MutatingTest, Rotate) {
+  std::vector<int> actual = {1, 2, 3, 4};
+  auto it = absl::c_rotate(actual, actual.begin() + 2);
+  EXPECT_THAT(actual, testing::ElementsAreArray({3, 4, 1, 2}));
+  EXPECT_EQ(*it, 1);
+}
+
+TEST(MutatingTest, RotateCopy) {
+  std::vector<int> initial = {1, 2, 3, 4};
+  std::vector<int> actual;
+  auto end =
+      absl::c_rotate_copy(initial, initial.begin() + 2, back_inserter(actual));
+  *end = 5;
+  EXPECT_THAT(actual, ElementsAre(3, 4, 1, 2, 5));
+}
+
+TEST(MutatingTest, Shuffle) {
+  std::vector<int> actual = {1, 2, 3, 4, 5};
+  absl::c_shuffle(actual, std::random_device());
+  EXPECT_THAT(actual, UnorderedElementsAre(1, 2, 3, 4, 5));
+}
+
+TEST(MutatingTest, PartialSort) {
+  std::vector<int> sequence{5, 3, 42, 0};
+  absl::c_partial_sort(sequence, sequence.begin() + 2);
+  EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(0, 3));
+  absl::c_partial_sort(sequence, sequence.begin() + 2, std::greater<int>());
+  EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(42, 5));
+}
+
+TEST(MutatingTest, PartialSortCopy) {
+  const std::vector<int> initial = {5, 3, 42, 0};
+  std::vector<int> actual(2);
+  absl::c_partial_sort_copy(initial, actual);
+  EXPECT_THAT(actual, ElementsAre(0, 3));
+  absl::c_partial_sort_copy(initial, actual, std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(42, 5));
+}
+
+TEST(MutatingTest, Merge) {
+  std::vector<int> actual;
+  absl::c_merge(std::vector<int>{1, 3, 5}, std::vector<int>{2, 4},
+                back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
+}
+
+TEST(MutatingTest, MergeWithComparator) {
+  std::vector<int> actual;
+  absl::c_merge(std::vector<int>{5, 3, 1}, std::vector<int>{4, 2},
+                back_inserter(actual), std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1));
+}
+
+TEST(MutatingTest, InplaceMerge) {
+  std::vector<int> actual = {1, 3, 5, 2, 4};
+  absl::c_inplace_merge(actual, actual.begin() + 3);
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
+}
+
+TEST(MutatingTest, InplaceMergeWithComparator) {
+  std::vector<int> actual = {5, 3, 1, 4, 2};
+  absl::c_inplace_merge(actual, actual.begin() + 3, std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1));
+}
+
+class SetOperationsTest : public testing::Test {
+ protected:
+  std::vector<int> a_ = {1, 2, 3};
+  std::vector<int> b_ = {1, 3, 5};
+
+  std::vector<int> a_reversed_ = {3, 2, 1};
+  std::vector<int> b_reversed_ = {5, 3, 1};
+};
+
+TEST_F(SetOperationsTest, SetUnion) {
+  std::vector<int> actual;
+  absl::c_set_union(a_, b_, back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(1, 2, 3, 5));
+}
+
+TEST_F(SetOperationsTest, SetUnionWithComparator) {
+  std::vector<int> actual;
+  absl::c_set_union(a_reversed_, b_reversed_, back_inserter(actual),
+                    std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(5, 3, 2, 1));
+}
+
+TEST_F(SetOperationsTest, SetIntersection) {
+  std::vector<int> actual;
+  absl::c_set_intersection(a_, b_, back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(1, 3));
+}
+
+TEST_F(SetOperationsTest, SetIntersectionWithComparator) {
+  std::vector<int> actual;
+  absl::c_set_intersection(a_reversed_, b_reversed_, back_inserter(actual),
+                           std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(3, 1));
+}
+
+TEST_F(SetOperationsTest, SetDifference) {
+  std::vector<int> actual;
+  absl::c_set_difference(a_, b_, back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(2));
+}
+
+TEST_F(SetOperationsTest, SetDifferenceWithComparator) {
+  std::vector<int> actual;
+  absl::c_set_difference(a_reversed_, b_reversed_, back_inserter(actual),
+                         std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(2));
+}
+
+TEST_F(SetOperationsTest, SetSymmetricDifference) {
+  std::vector<int> actual;
+  absl::c_set_symmetric_difference(a_, b_, back_inserter(actual));
+  EXPECT_THAT(actual, ElementsAre(2, 5));
+}
+
+TEST_F(SetOperationsTest, SetSymmetricDifferenceWithComparator) {
+  std::vector<int> actual;
+  absl::c_set_symmetric_difference(a_reversed_, b_reversed_,
+                                   back_inserter(actual), std::greater<int>());
+  EXPECT_THAT(actual, ElementsAre(5, 2));
+}
+
+TEST(HeapOperationsTest, WithoutComparator) {
+  std::vector<int> heap = {1, 2, 3};
+  EXPECT_FALSE(absl::c_is_heap(heap));
+  absl::c_make_heap(heap);
+  EXPECT_TRUE(absl::c_is_heap(heap));
+  heap.push_back(4);
+  EXPECT_EQ(3, absl::c_is_heap_until(heap) - heap.begin());
+  absl::c_push_heap(heap);
+  EXPECT_EQ(4, heap[0]);
+  absl::c_pop_heap(heap);
+  EXPECT_EQ(4, heap[3]);
+  absl::c_make_heap(heap);
+  absl::c_sort_heap(heap);
+  EXPECT_THAT(heap, ElementsAre(1, 2, 3, 4));
+  EXPECT_FALSE(absl::c_is_heap(heap));
+}
+
+TEST(HeapOperationsTest, WithComparator) {
+  using greater = std::greater<int>;
+  std::vector<int> heap = {3, 2, 1};
+  EXPECT_FALSE(absl::c_is_heap(heap, greater()));
+  absl::c_make_heap(heap, greater());
+  EXPECT_TRUE(absl::c_is_heap(heap, greater()));
+  heap.push_back(0);
+  EXPECT_EQ(3, absl::c_is_heap_until(heap, greater()) - heap.begin());
+  absl::c_push_heap(heap, greater());
+  EXPECT_EQ(0, heap[0]);
+  absl::c_pop_heap(heap, greater());
+  EXPECT_EQ(0, heap[3]);
+  absl::c_make_heap(heap, greater());
+  absl::c_sort_heap(heap, greater());
+  EXPECT_THAT(heap, ElementsAre(3, 2, 1, 0));
+  EXPECT_FALSE(absl::c_is_heap(heap, greater()));
+}
+
+TEST(MutatingTest, PermutationOperations) {
+  std::vector<int> initial = {1, 2, 3, 4};
+  std::vector<int> permuted = initial;
+
+  absl::c_next_permutation(permuted);
+  EXPECT_TRUE(absl::c_is_permutation(initial, permuted));
+  EXPECT_TRUE(absl::c_is_permutation(initial, permuted, std::equal_to<int>()));
+
+  std::vector<int> permuted2 = initial;
+  absl::c_prev_permutation(permuted2, std::greater<int>());
+  EXPECT_EQ(permuted, permuted2);
+
+  absl::c_prev_permutation(permuted);
+  EXPECT_EQ(initial, permuted);
+}
+
+}  // namespace
diff --git a/absl/algorithm/equal_benchmark.cc b/absl/algorithm/equal_benchmark.cc
new file mode 100644
index 0000000..19c0780
--- /dev/null
+++ b/absl/algorithm/equal_benchmark.cc
@@ -0,0 +1,126 @@
+// Copyright 2017 The Abseil 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 <cstdint>
+#include <cstring>
+
+#include "benchmark/benchmark.h"
+#include "absl/algorithm/algorithm.h"
+
+namespace {
+
+// The range of sequence sizes to benchmark.
+constexpr int kMinBenchmarkSize = 1024;
+constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024;
+
+// A user-defined type for use in equality benchmarks. Note that we expect
+// std::memcmp to win for this type: libstdc++'s std::equal only defers to
+// memcmp for integral types. This is because it is not straightforward to
+// guarantee that std::memcmp would produce a result "as-if" compared by
+// operator== for other types (example gotchas: NaN floats, structs with
+// padding).
+struct EightBits {
+  explicit EightBits(int /* unused */) : data(0) {}
+  bool operator==(const EightBits& rhs) const { return data == rhs.data; }
+  uint8_t data;
+};
+
+template <typename T>
+void BM_absl_equal_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  std::vector<T> ys = xs;
+  while (state.KeepRunning()) {
+    const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end());
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+template <typename T>
+void BM_std_equal_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  std::vector<T> ys = xs;
+  while (state.KeepRunning()) {
+    const bool same = std::equal(xs.begin(), xs.end(), ys.begin());
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+template <typename T>
+void BM_memcmp_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  std::vector<T> ys = xs;
+  while (state.KeepRunning()) {
+    const bool same =
+        std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0;
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+// The expectation is that the compiler should be able to elide the equality
+// comparison altogether for sufficiently simple types.
+template <typename T>
+void BM_absl_equal_self_benchmark(benchmark::State& state) {
+  std::vector<T> xs(state.range(0), T(0));
+  while (state.KeepRunning()) {
+    const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end());
+    benchmark::DoNotOptimize(same);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits)
+    ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
+
+}  // namespace
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
new file mode 100644
index 0000000..35414a2
--- /dev/null
+++ b/absl/base/BUILD.bazel
@@ -0,0 +1,422 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+    "ABSL_EXCEPTIONS_FLAG",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "spinlock_wait",
+    srcs = [
+        "internal/spinlock_akaros.inc",
+        "internal/spinlock_posix.inc",
+        "internal/spinlock_wait.cc",
+        "internal/spinlock_win32.inc",
+    ],
+    hdrs = [
+        "internal/scheduling_mode.h",
+        "internal/spinlock_wait.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = [
+        "//absl/base:__pkg__",
+    ],
+    deps = [":core_headers"],
+)
+
+cc_library(
+    name = "config",
+    hdrs = [
+        "config.h",
+        "policy_checks.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+)
+
+cc_library(
+    name = "dynamic_annotations",
+    srcs = ["dynamic_annotations.cc"],
+    hdrs = ["dynamic_annotations.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
+)
+
+cc_library(
+    name = "core_headers",
+    hdrs = [
+        "attributes.h",
+        "macros.h",
+        "optimization.h",
+        "port.h",
+        "thread_annotations.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":config",
+        ":dynamic_annotations",
+    ],
+)
+
+cc_library(
+    name = "malloc_internal",
+    srcs = [
+        "internal/low_level_alloc.cc",
+    ],
+    hdrs = [
+        "internal/direct_mmap.h",
+        "internal/low_level_alloc.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":base",
+        ":config",
+        ":core_headers",
+        ":dynamic_annotations",
+        ":spinlock_wait",
+    ],
+)
+
+cc_library(
+    name = "base_internal",
+    hdrs = [
+        "internal/hide_ptr.h",
+        "internal/identity.h",
+        "internal/inline_variable.h",
+        "internal/invoke.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+)
+
+cc_library(
+    name = "base",
+    srcs = [
+        "internal/cycleclock.cc",
+        "internal/raw_logging.cc",
+        "internal/spinlock.cc",
+        "internal/sysinfo.cc",
+        "internal/thread_identity.cc",
+        "internal/unscaledcycleclock.cc",
+    ],
+    hdrs = [
+        "call_once.h",
+        "casts.h",
+        "internal/atomic_hook.h",
+        "internal/cycleclock.h",
+        "internal/low_level_scheduling.h",
+        "internal/per_thread_tls.h",
+        "internal/raw_logging.h",
+        "internal/spinlock.h",
+        "internal/sysinfo.h",
+        "internal/thread_identity.h",
+        "internal/tsan_mutex_interface.h",
+        "internal/unscaledcycleclock.h",
+        "log_severity.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":base_internal",
+        ":config",
+        ":core_headers",
+        ":dynamic_annotations",
+        ":spinlock_wait",
+    ],
+)
+
+cc_test(
+    name = "atomic_hook_test",
+    size = "small",
+    srcs = ["internal/atomic_hook_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "bit_cast_test",
+    size = "small",
+    srcs = [
+        "bit_cast_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "throw_delegate",
+    srcs = ["internal/throw_delegate.cc"],
+    hdrs = ["internal/throw_delegate.h"],
+    copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":base",
+        ":config",
+        ":core_headers",
+    ],
+)
+
+cc_test(
+    name = "throw_delegate_test",
+    srcs = ["throw_delegate_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":throw_delegate",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "exception_testing",
+    testonly = 1,
+    hdrs = ["internal/exception_testing.h"],
+    copts = ABSL_TEST_COPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":config",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_library(
+    name = "pretty_function",
+    hdrs = ["internal/pretty_function.h"],
+    visibility = ["//absl:__subpackages__"],
+)
+
+cc_library(
+    name = "exception_safety_testing",
+    testonly = 1,
+    srcs = ["internal/exception_safety_testing.cc"],
+    hdrs = ["internal/exception_safety_testing.h"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":base",
+        ":config",
+        ":pretty_function",
+        "//absl/memory",
+        "//absl/meta:type_traits",
+        "//absl/strings",
+        "//absl/types:optional",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_test(
+    name = "exception_safety_testing_test",
+    srcs = ["exception_safety_testing_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":exception_safety_testing",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "inline_variable_test",
+    size = "small",
+    srcs = [
+        "inline_variable_test.cc",
+        "inline_variable_test_a.cc",
+        "inline_variable_test_b.cc",
+        "internal/inline_variable_testing.h",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base_internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "invoke_test",
+    size = "small",
+    srcs = ["invoke_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base_internal",
+        "//absl/memory",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+# Common test library made available for use in non-absl code that overrides
+# AbslInternalSpinLockDelay and AbslInternalSpinLockWake.
+cc_library(
+    name = "spinlock_test_common",
+    testonly = 1,
+    srcs = ["spinlock_test_common.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":core_headers",
+        ":spinlock_wait",
+        "//absl/synchronization",
+        "@com_google_googletest//:gtest",
+    ],
+    alwayslink = 1,
+)
+
+cc_test(
+    name = "spinlock_test",
+    size = "medium",
+    srcs = ["spinlock_test_common.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":core_headers",
+        ":spinlock_wait",
+        "//absl/synchronization",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "endian",
+    hdrs = [
+        "internal/endian.h",
+        "internal/unaligned_access.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":config",
+        ":core_headers",
+    ],
+)
+
+cc_test(
+    name = "endian_test",
+    srcs = ["internal/endian_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":config",
+        ":endian",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "config_test",
+    srcs = ["config_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":config",
+        "//absl/synchronization:thread_pool",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "call_once_test",
+    srcs = ["call_once_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        ":core_headers",
+        "//absl/synchronization",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "raw_logging_test",
+    srcs = ["raw_logging_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "sysinfo_test",
+    size = "small",
+    srcs = ["internal/sysinfo_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":base",
+        "//absl/synchronization",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "low_level_alloc_test",
+    size = "small",
+    srcs = ["internal/low_level_alloc_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//absl:windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    tags = ["no_test_ios_x86_64"],
+    deps = [":malloc_internal"],
+)
+
+cc_test(
+    name = "thread_identity_test",
+    size = "small",
+    srcs = ["internal/thread_identity_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//absl:windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    deps = [
+        ":base",
+        ":core_headers",
+        "//absl/synchronization",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "thread_identity_benchmark",
+    srcs = ["internal/thread_identity_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":base",
+        "//absl/synchronization",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
diff --git a/absl/base/BUILD.gn b/absl/base/BUILD.gn
new file mode 100644
index 0000000..a714656
--- /dev/null
+++ b/absl/base/BUILD.gn
@@ -0,0 +1,298 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("spinlock_wait") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/spinlock_akaros.inc",
+    "internal/spinlock_posix.inc",
+    "internal/spinlock_wait.cc",
+    "internal/spinlock_win32.inc",
+  ]
+  public = [
+    "internal/scheduling_mode.h",
+    "internal/spinlock_wait.h",
+  ]
+  deps = [
+    ":core_headers",
+  ]
+  visibility = []
+  visibility += [ "../base:*" ]
+}
+
+source_set("config") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "config.h",
+    "policy_checks.h",
+  ]
+}
+
+config("clang_support_dynamic_annotations") {
+  cflags_cc = [ "-D__CLANG_SUPPORT_DYN_ANNOTATION__" ]
+}
+
+source_set("dynamic_annotations") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [
+    ":clang_support_dynamic_annotations",
+    "//third_party/abseil-cpp:absl_include_config",
+  ]
+  sources = [
+    "dynamic_annotations.cc",
+  ]
+  public = [
+    "dynamic_annotations.h",
+  ]
+  # Abseil's dynamic annotations are only visible inside Abseil because
+  # their usage is deprecated in Chromium (see README.chromium for more info).
+  visibility = []
+  visibility = [ "../*" ]
+}
+
+source_set("core_headers") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "attributes.h",
+    "macros.h",
+    "optimization.h",
+    "port.h",
+    "thread_annotations.h",
+  ]
+  deps = [
+    ":config",
+    ":dynamic_annotations",
+  ]
+}
+
+source_set("malloc_internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/low_level_alloc.cc",
+  ]
+  public = [
+    "internal/direct_mmap.h",
+    "internal/low_level_alloc.h",
+  ]
+  deps = [
+    ":base",
+    ":config",
+    ":core_headers",
+    ":dynamic_annotations",
+    ":spinlock_wait",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
+
+source_set("base_internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "internal/hide_ptr.h",
+    "internal/identity.h",
+    "internal/inline_variable.h",
+    "internal/invoke.h",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
+
+source_set("base") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/cycleclock.cc",
+    "internal/raw_logging.cc",
+    "internal/spinlock.cc",
+    "internal/sysinfo.cc",
+    "internal/thread_identity.cc",
+    "internal/unscaledcycleclock.cc",
+  ]
+  public = [
+    "call_once.h",
+    "casts.h",
+    "internal/atomic_hook.h",
+    "internal/cycleclock.h",
+    "internal/low_level_scheduling.h",
+    "internal/per_thread_tls.h",
+    "internal/raw_logging.h",
+    "internal/spinlock.h",
+    "internal/sysinfo.h",
+    "internal/thread_identity.h",
+    "internal/tsan_mutex_interface.h",
+    "internal/unscaledcycleclock.h",
+    "log_severity.h",
+  ]
+  deps = [
+    ":base_internal",
+    ":config",
+    ":core_headers",
+    ":dynamic_annotations",
+    ":spinlock_wait",
+  ]
+}
+
+source_set("throw_delegate") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/throw_delegate.cc",
+  ]
+  public = [
+    "internal/throw_delegate.h",
+  ]
+  deps = [
+    ":base",
+    ":config",
+    ":core_headers",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
+
+source_set("exception_testing") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_test_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "internal/exception_testing.h",
+  ]
+  deps = [
+    ":config",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
+
+source_set("pretty_function") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "internal/pretty_function.h",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
+
+# TODO(mbonadei): This target throws by design. We should probably
+# just remove it.
+# source_set("exception_safety_testing") {
+#   testonly = true
+#   configs -= [ "//build/config/compiler:chromium_code" ]
+#   configs += [
+#     "//build/config/compiler:no_chromium_code",
+#     "//third_party/abseil-cpp:absl_test_cflags_cc",
+#   ]
+#   public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+#   sources = [
+#     "internal/exception_safety_testing.cc",
+#   ]
+#   public = [
+#     "internal/exception_safety_testing.h",
+#   ]
+#   deps = [
+#     ":base",
+#     ":config",
+#     ":pretty_function",
+#     "../memory",
+#     "../meta:type_traits",
+#     "../strings",
+#     "../types:optional",
+#     "//testing/gtest",
+#   ]
+# }
+
+source_set("spinlock_test_common") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_test_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "spinlock_test_common.cc",
+  ]
+  deps = [
+    ":base",
+    ":core_headers",
+    ":spinlock_wait",
+    "../synchronization",
+    "//testing/gtest",
+  ]
+}
+
+source_set("endian") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "internal/endian.h",
+    "internal/unaligned_access.h",
+  ]
+  deps = [
+    ":config",
+    ":core_headers",
+  ]
+}
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
new file mode 100644
index 0000000..303533e
--- /dev/null
+++ b/absl/base/CMakeLists.txt
@@ -0,0 +1,386 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND BASE_PUBLIC_HEADERS
+  "attributes.h"
+  "call_once.h"
+  "casts.h"
+  "config.h"
+  "dynamic_annotations.h"
+  "log_severity.h"
+  "macros.h"
+  "optimization.h"
+  "policy_checks.h"
+  "port.h"
+  "thread_annotations.h"
+)
+
+
+list(APPEND BASE_INTERNAL_HEADERS
+  "internal/atomic_hook.h"
+  "internal/cycleclock.h"
+  "internal/direct_mmap.h"
+  "internal/endian.h"
+  "internal/exception_testing.h"
+  "internal/exception_safety_testing.h"
+  "internal/hide_ptr.h"
+  "internal/identity.h"
+  "internal/invoke.h"
+  "internal/inline_variable.h"
+  "internal/low_level_alloc.h"
+  "internal/low_level_scheduling.h"
+  "internal/per_thread_tls.h"
+  "internal/pretty_function.h"
+  "internal/raw_logging.h"
+  "internal/scheduling_mode.h"
+  "internal/spinlock.h"
+  "internal/spinlock_wait.h"
+  "internal/sysinfo.h"
+  "internal/thread_identity.h"
+  "internal/throw_delegate.h"
+  "internal/tsan_mutex_interface.h"
+  "internal/unaligned_access.h"
+  "internal/unscaledcycleclock.h"
+)
+
+
+# absl_base main library
+list(APPEND BASE_SRC
+  "internal/cycleclock.cc"
+  "internal/raw_logging.cc"
+  "internal/spinlock.cc"
+  "internal/sysinfo.cc"
+  "internal/thread_identity.cc"
+  "internal/unscaledcycleclock.cc"
+  "internal/low_level_alloc.cc"
+  ${BASE_PUBLIC_HEADERS}
+  ${BASE_INTERNAL_HEADERS}
+)
+
+absl_library(
+  TARGET
+    absl_base
+  SOURCES
+    ${BASE_SRC}
+  PUBLIC_LIBRARIES
+    absl_dynamic_annotations
+    absl_spinlock_wait
+  EXPORT_NAME
+    base
+)
+
+# throw delegate library
+set(THROW_DELEGATE_SRC "internal/throw_delegate.cc")
+
+absl_library(
+  TARGET
+    absl_throw_delegate
+  SOURCES
+    ${THROW_DELEGATE_SRC}
+  PUBLIC_LIBRARIES
+    ${THROW_DELEGATE_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+  EXPORT_NAME
+    throw_delegate
+)
+
+if(BUILD_TESTING)
+  # exception-safety testing library
+  set(EXCEPTION_SAFETY_TESTING_SRC
+    "internal/exception_safety_testing.h"
+    "internal/exception_safety_testing.cc"
+  )
+  set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
+    ${ABSL_TEST_COMMON_LIBRARIES}
+    absl::base
+    absl::memory
+    absl::meta
+    absl::strings
+    absl::optional
+    gtest
+  )
+
+absl_library(
+  TARGET
+    absl_base_internal_exception_safety_testing
+  SOURCES
+    ${EXCEPTION_SAFETY_TESTING_SRC}
+  PUBLIC_LIBRARIES
+    ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+endif()
+
+
+# dynamic_annotations library
+set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc")
+
+absl_library(
+  TARGET
+    absl_dynamic_annotations
+  SOURCES
+    ${DYNAMIC_ANNOTATIONS_SRC}
+)
+
+
+# spinlock_wait library
+set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc")
+
+absl_library(
+  TARGET
+    absl_spinlock_wait
+  SOURCES
+    ${SPINLOCK_WAIT_SRC}
+)
+
+
+# malloc_internal library
+list(APPEND MALLOC_INTERNAL_SRC
+  "internal/low_level_alloc.cc"
+)
+
+absl_library(
+  TARGET
+    absl_malloc_internal
+  SOURCES
+    ${MALLOC_INTERNAL_SRC}
+  PUBLIC_LIBRARIES
+    absl_dynamic_annotations
+)
+
+
+
+#
+## TESTS
+#
+
+# call once test
+set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc")
+set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base)
+
+absl_test(
+  TARGET
+    atomic_hook_test
+  SOURCES
+    ${ATOMIC_HOOK_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# call once test
+set(CALL_ONCE_TEST_SRC "call_once_test.cc")
+set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
+
+absl_test(
+  TARGET
+    call_once_test
+  SOURCES
+    ${CALL_ONCE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${CALL_ONCE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test bit_cast_test
+set(BIT_CAST_TEST_SRC "bit_cast_test.cc")
+
+absl_test(
+  TARGET
+    bit_cast_test
+  SOURCES
+    ${BIT_CAST_TEST_SRC}
+)
+
+
+# test absl_throw_delegate_test
+set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc")
+set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate)
+
+absl_test(
+  TARGET
+    throw_delegate_test
+  SOURCES
+    ${THROW_DELEGATE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test invoke_test
+set(INVOKE_TEST_SRC "invoke_test.cc")
+set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    invoke_test
+  SOURCES
+    ${INVOKE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${INVOKE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test inline_variable_test
+list(APPEND INLINE_VARIABLE_TEST_SRC
+  "internal/inline_variable_testing.h"
+  "inline_variable_test.cc"
+  "inline_variable_test_a.cc"
+  "inline_variable_test_b.cc"
+)
+
+set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base)
+
+absl_test(
+  TARGET
+    inline_variable_test
+  SOURCES
+    ${INLINE_VARIABLE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test spinlock_test_common
+set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc")
+set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization)
+
+absl_test(
+  TARGET
+    spinlock_test_common
+  SOURCES
+    ${SPINLOCK_TEST_COMMON_SRC}
+  PUBLIC_LIBRARIES
+    ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES}
+)
+
+
+# test spinlock_test
+set(SPINLOCK_TEST_SRC "spinlock_test_common.cc")
+set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
+
+absl_test(
+  TARGET
+    spinlock_test
+  SOURCES
+    ${SPINLOCK_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${SPINLOCK_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test endian_test
+set(ENDIAN_TEST_SRC "internal/endian_test.cc")
+
+absl_test(
+  TARGET
+    endian_test
+  SOURCES
+    ${ENDIAN_TEST_SRC}
+)
+
+
+# test config_test
+set(CONFIG_TEST_SRC "config_test.cc")
+set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
+absl_test(
+  TARGET
+    config_test
+  SOURCES
+    ${CONFIG_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${CONFIG_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test raw_logging_test
+set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc")
+set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base)
+
+absl_test(
+  TARGET
+    raw_logging_test
+  SOURCES
+    ${RAW_LOGGING_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${RAW_LOGGING_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test sysinfo_test
+set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc")
+set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
+
+absl_test(
+  TARGET
+    sysinfo_test
+  SOURCES
+    ${SYSINFO_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${SYSINFO_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test low_level_alloc_test
+set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc")
+set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base)
+
+absl_test(
+  TARGET
+    low_level_alloc_test
+  SOURCES
+    ${LOW_LEVEL_ALLOC_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test thread_identity_test
+set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc")
+set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
+
+absl_test(
+  TARGET
+    thread_identity_test
+  SOURCES
+    ${THREAD_IDENTITY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES}
+)
+
+#test exceptions_safety_testing_test
+set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
+set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES
+  absl::base
+  absl_base_internal_exception_safety_testing
+  absl::memory
+  absl::meta
+  absl::strings
+  absl::optional
+)
+
+absl_test(
+  TARGET
+    absl_exception_safety_testing_test
+  SOURCES
+    ${EXCEPTION_SAFETY_TESTING_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
new file mode 100644
index 0000000..b1883b6
--- /dev/null
+++ b/absl/base/attributes.h
@@ -0,0 +1,568 @@
+// Copyright 2017 The Abseil 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.
+//
+// This header file defines macros for declaring attributes for functions,
+// types, and variables.
+//
+// These macros are used within Abseil and allow the compiler to optimize, where
+// applicable, certain function calls.
+//
+// This file is used for both C and C++!
+//
+// Most macros here are exposing GCC or Clang features, and are stubbed out for
+// other compilers.
+//
+// GCC attributes documentation:
+//   https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
+//   https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
+//   https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
+//
+// Most attributes in this file are already supported by GCC 4.7. However, some
+// of them are not supported in older version of Clang. Thus, we check
+// `__has_attribute()` first. If the check fails, we check if we are on GCC and
+// assume the attribute exists on GCC (which is verified on GCC 4.7).
+//
+// -----------------------------------------------------------------------------
+// Sanitizer Attributes
+// -----------------------------------------------------------------------------
+//
+// Sanitizer-related attributes are not "defined" in this file (and indeed
+// are not defined as such in any file). To utilize the following
+// sanitizer-related attributes within your builds, define the following macros
+// within your build using a `-D` flag, along with the given value for
+// `-fsanitize`:
+//
+//   * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
+//   * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
+//   * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
+//   * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
+//   * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
+//
+// Example:
+//
+//   // Enable branches in the Abseil code that are tagged for ASan:
+//   $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
+//     --linkopt=-fsanitize=address *target*
+//
+// Since these macro names are only supported by GCC and Clang, we only check
+// for `__GNUC__` (GCC or Clang) and the above macros.
+#ifndef ABSL_BASE_ATTRIBUTES_H_
+#define ABSL_BASE_ATTRIBUTES_H_
+
+// ABSL_HAVE_ATTRIBUTE
+//
+// A function-like feature checking macro that is a wrapper around
+// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
+// nonzero constant integer if the attribute is supported or 0 if not.
+//
+// It evaluates to zero if `__has_attribute` is not defined by the compiler.
+//
+// GCC: https://gcc.gnu.org/gcc-5/changes.html
+// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
+#ifdef __has_attribute
+#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define ABSL_HAVE_ATTRIBUTE(x) 0
+#endif
+
+// ABSL_HAVE_CPP_ATTRIBUTE
+//
+// A function-like feature checking macro that accepts C++11 style attributes.
+// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
+// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
+// find `__has_cpp_attribute`, will evaluate to 0.
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+// NOTE: requiring __cplusplus above should not be necessary, but
+// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
+#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
+#endif
+
+// -----------------------------------------------------------------------------
+// Function Attributes
+// -----------------------------------------------------------------------------
+//
+// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+// Clang: https://clang.llvm.org/docs/AttributeReference.html
+
+// ABSL_PRINTF_ATTRIBUTE
+// ABSL_SCANF_ATTRIBUTE
+//
+// Tells the compiler to perform `printf` format std::string checking if the
+// compiler supports it; see the 'format' attribute in
+// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
+//
+// Note: As the GCC manual states, "[s]ince non-static C++ methods
+// have an implicit 'this' argument, the arguments of such methods
+// should be counted from two, not one."
+#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
+  __attribute__((__format__(__printf__, string_index, first_to_check)))
+#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
+  __attribute__((__format__(__scanf__, string_index, first_to_check)))
+#else
+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
+#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
+#endif
+
+// ABSL_ATTRIBUTE_ALWAYS_INLINE
+// ABSL_ATTRIBUTE_NOINLINE
+//
+// Forces functions to either inline or not inline. Introduced in gcc 3.1.
+#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
+#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
+#else
+#define ABSL_ATTRIBUTE_ALWAYS_INLINE
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
+#else
+#define ABSL_ATTRIBUTE_NOINLINE
+#endif
+
+// ABSL_ATTRIBUTE_NO_TAIL_CALL
+//
+// Prevents the compiler from optimizing away stack frames for functions which
+// end in a call to another function.
+#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
+#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
+#elif defined(__GNUC__) && !defined(__clang__)
+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
+#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
+  __attribute__((optimize("no-optimize-sibling-calls")))
+#else
+#define ABSL_ATTRIBUTE_NO_TAIL_CALL
+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
+#endif
+
+// ABSL_ATTRIBUTE_WEAK
+//
+// Tags a function as weak for the purposes of compilation and linking.
+#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))
+#undef ABSL_ATTRIBUTE_WEAK
+#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
+#define ABSL_HAVE_ATTRIBUTE_WEAK 1
+#else
+#define ABSL_ATTRIBUTE_WEAK
+#define ABSL_HAVE_ATTRIBUTE_WEAK 0
+#endif
+
+// ABSL_ATTRIBUTE_NONNULL
+//
+// Tells the compiler either (a) that a particular function parameter
+// should be a non-null pointer, or (b) that all pointer arguments should
+// be non-null.
+//
+// Note: As the GCC manual states, "[s]ince non-static C++ methods
+// have an implicit 'this' argument, the arguments of such methods
+// should be counted from two, not one."
+//
+// Args are indexed starting at 1.
+//
+// For non-static class member functions, the implicit `this` argument
+// is arg 1, and the first explicit argument is arg 2. For static class member
+// functions, there is no implicit `this`, and the first explicit argument is
+// arg 1.
+//
+// Example:
+//
+//   /* arg_a cannot be null, but arg_b can */
+//   void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
+//
+//   class C {
+//     /* arg_a cannot be null, but arg_b can */
+//     void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
+//
+//     /* arg_a cannot be null, but arg_b can */
+//     static void StaticMethod(void* arg_a, void* arg_b)
+//     ABSL_ATTRIBUTE_NONNULL(1);
+//   };
+//
+// If no arguments are provided, then all pointer arguments should be non-null.
+//
+//  /* No pointer arguments may be null. */
+//  void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
+//
+// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
+// ABSL_ATTRIBUTE_NONNULL does not.
+#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
+#else
+#define ABSL_ATTRIBUTE_NONNULL(...)
+#endif
+
+// ABSL_ATTRIBUTE_NORETURN
+//
+// Tells the compiler that a given function never returns.
+#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define ABSL_ATTRIBUTE_NORETURN
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
+//
+// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
+// function. Useful for cases when a function reads random locations on stack,
+// calls _exit from a cloned subprocess, deliberately accesses buffer
+// out of bounds or does other scary things with memory.
+// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
+// https://gcc.gnu.org/gcc-4.8/changes.html
+#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+//
+// Tells the  MemorySanitizer to relax the handling of a given function. All
+// "Use of uninitialized value" warnings from such functions will be suppressed,
+// and all values loaded from memory will be considered fully initialized.
+// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals
+// with initialized-ness rather than addressability issues.
+// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
+#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
+//
+// Tells the ThreadSanitizer to not instrument a given function.
+// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
+// https://gcc.gnu.org/gcc-4.8/changes.html
+#if defined(__GNUC__) && defined(THREAD_SANITIZER)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
+//
+// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
+// where certain behavior (eg. division by zero) is being used intentionally.
+// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
+// https://gcc.gnu.org/gcc-4.9/changes.html
+#if defined(__GNUC__) && \
+    (defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
+  __attribute__((no_sanitize("undefined")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
+//
+// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
+// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
+#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
+#endif
+
+// ABSL_ATTRIBUTE_RETURNS_NONNULL
+//
+// Tells the compiler that a particular function never returns a null pointer.
+#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \
+    (defined(__GNUC__) && \
+     (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
+     !defined(__clang__))
+#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define ABSL_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
+// ABSL_HAVE_ATTRIBUTE_SECTION
+//
+// Indicates whether labeled sections are supported. Labeled sections are not
+// supported on Darwin/iOS.
+#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
+#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
+#elif (ABSL_HAVE_ATTRIBUTE(section) ||                \
+       (defined(__GNUC__) && !defined(__clang__))) && \
+    !defined(__APPLE__)
+#define ABSL_HAVE_ATTRIBUTE_SECTION 1
+
+// ABSL_ATTRIBUTE_SECTION
+//
+// Tells the compiler/linker to put a given function into a section and define
+// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
+// This functionality is supported by GNU linker.  Any function annotated with
+// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
+// whatever section its caller is placed into.
+//
+#ifndef ABSL_ATTRIBUTE_SECTION
+#define ABSL_ATTRIBUTE_SECTION(name) \
+  __attribute__((section(#name))) __attribute__((noinline))
+#endif
+
+
+// ABSL_ATTRIBUTE_SECTION_VARIABLE
+//
+// Tells the compiler/linker to put a given variable into a section and define
+// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
+// This functionality is supported by GNU linker.
+#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
+#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
+#endif
+
+// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
+//
+// A weak section declaration to be used as a global declaration
+// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
+// even without functions with ABSL_ATTRIBUTE_SECTION(name).
+// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
+// a no-op on ELF but not on Mach-O.
+//
+#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
+#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
+  extern char __start_##name[] ABSL_ATTRIBUTE_WEAK;    \
+  extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
+#endif
+#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
+#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
+#endif
+
+// ABSL_ATTRIBUTE_SECTION_START
+//
+// Returns `void*` pointers to start/end of a section of code with
+// functions having ABSL_ATTRIBUTE_SECTION(name).
+// Returns 0 if no such functions exist.
+// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
+// link.
+//
+#define ABSL_ATTRIBUTE_SECTION_START(name) \
+  (reinterpret_cast<void *>(__start_##name))
+#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
+  (reinterpret_cast<void *>(__stop_##name))
+
+#else  // !ABSL_HAVE_ATTRIBUTE_SECTION
+
+#define ABSL_HAVE_ATTRIBUTE_SECTION 0
+
+// provide dummy definitions
+#define ABSL_ATTRIBUTE_SECTION(name)
+#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
+#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
+#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
+
+#endif  // ABSL_ATTRIBUTE_SECTION
+
+// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+//
+// Support for aligning the stack on 32-bit x86.
+#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#if defined(__i386__)
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
+  __attribute__((force_align_arg_pointer))
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
+#elif defined(__x86_64__)
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+#else  // !__i386__ && !__x86_64
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+#endif  // __i386__
+#else
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
+#endif
+
+// ABSL_MUST_USE_RESULT
+//
+// Tells the compiler to warn about unused return values for functions declared
+// with this macro. The macro must appear as the very first part of a function
+// declaration or definition:
+//
+// Example:
+//
+//   ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
+//
+// This placement has the broadest compatibility with GCC, Clang, and MSVC, with
+// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11
+// and C++17 attributes.
+//
+// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
+// warning. For that, warn_unused_result is used only for clang but not for gcc.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
+//
+// Note: past advice was to place the macro after the argument list.
+#if ABSL_HAVE_ATTRIBUTE(nodiscard)
+#define ABSL_MUST_USE_RESULT [[nodiscard]]
+#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
+#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
+#else
+#define ABSL_MUST_USE_RESULT
+#endif
+
+// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
+//
+// Tells GCC that a function is hot or cold. GCC can use this information to
+// improve static analysis, i.e. a conditional branch to a cold function
+// is likely to be not-taken.
+// This annotation is used for function declarations.
+//
+// Example:
+//
+//   int foo() ABSL_ATTRIBUTE_HOT;
+#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
+#else
+#define ABSL_ATTRIBUTE_HOT
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
+#else
+#define ABSL_ATTRIBUTE_COLD
+#endif
+
+// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
+//
+// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
+// macro used as an attribute to mark functions that must always or never be
+// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
+//
+// For reference on the LLVM XRay instrumentation, see
+// http://llvm.org/docs/XRay.html.
+//
+// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
+// will always get the XRay instrumentation sleds. These sleds may introduce
+// some binary size and runtime overhead and must be used sparingly.
+//
+// These attributes only take effect when the following conditions are met:
+//
+//   * The file/target is built in at least C++11 mode, with a Clang compiler
+//     that supports XRay attributes.
+//   * The file/target is built with the -fxray-instrument flag set for the
+//     Clang/LLVM compiler.
+//   * The function is defined in the translation unit (the compiler honors the
+//     attribute in either the definition or the declaration, and must match).
+//
+// There are cases when, even when building with XRay instrumentation, users
+// might want to control specifically which functions are instrumented for a
+// particular build using special-case lists provided to the compiler. These
+// special case lists are provided to Clang via the
+// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
+// attributes in source take precedence over these special-case lists.
+//
+// To disable the XRay attributes at build-time, users may define
+// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
+// packages/targets, as this may lead to conflicting definitions of functions at
+// link-time.
+//
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
+    !defined(ABSL_NO_XRAY_ATTRIBUTES)
+#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
+#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
+#define ABSL_XRAY_LOG_ARGS(N) \
+    [[clang::xray_always_instrument, clang::xray_log_args(N)]]
+#else
+#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
+#endif
+#else
+#define ABSL_XRAY_ALWAYS_INSTRUMENT
+#define ABSL_XRAY_NEVER_INSTRUMENT
+#define ABSL_XRAY_LOG_ARGS(N)
+#endif
+
+// -----------------------------------------------------------------------------
+// Variable Attributes
+// -----------------------------------------------------------------------------
+
+// ABSL_ATTRIBUTE_UNUSED
+//
+// Prevents the compiler from complaining about or optimizing away variables
+// that appear unused.
+#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
+#undef ABSL_ATTRIBUTE_UNUSED
+#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define ABSL_ATTRIBUTE_UNUSED
+#endif
+
+// ABSL_ATTRIBUTE_INITIAL_EXEC
+//
+// Tells the compiler to use "initial-exec" mode for a thread-local variable.
+// See http://people.redhat.com/drepper/tls.pdf for the gory details.
+#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
+#else
+#define ABSL_ATTRIBUTE_INITIAL_EXEC
+#endif
+
+// ABSL_ATTRIBUTE_PACKED
+//
+// Prevents the compiler from padding a structure to natural alignment
+#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
+#else
+#define ABSL_ATTRIBUTE_PACKED
+#endif
+
+// ABSL_ATTRIBUTE_FUNC_ALIGN
+//
+// Tells the compiler to align the function start at least to certain
+// alignment boundary
+#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
+#else
+#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
+#endif
+
+// ABSL_CONST_INIT
+//
+// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
+// not compile (on supported platforms) unless the variable has a constant
+// initializer. This is useful for variables with static and thread storage
+// duration, because it guarantees that they will not suffer from the so-called
+// "static init order fiasco".  Prefer to put this attribute on the most visible
+// declaration of the variable, if there's more than one, because code that
+// accesses the variable can then use the attribute for optimization.
+//
+// Example:
+//
+//   class MyClass {
+//    public:
+//     ABSL_CONST_INIT static MyType my_var;
+//   };
+//
+//   MyType MyClass::my_var = MakeMyType(...);
+//
+// Note that this attribute is redundant if the variable is declared constexpr.
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
+// NOLINTNEXTLINE(whitespace/braces)
+#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
+#else
+#define ABSL_CONST_INIT
+#endif  // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
+
+#endif  // ABSL_BASE_ATTRIBUTES_H_
diff --git a/absl/base/bit_cast_test.cc b/absl/base/bit_cast_test.cc
new file mode 100644
index 0000000..8cd878d
--- /dev/null
+++ b/absl/base/bit_cast_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2017 The Abseil 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.
+
+// Unit test for bit_cast template.
+
+#include <cstdint>
+#include <cstring>
+
+#include "gtest/gtest.h"
+#include "absl/base/casts.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+namespace {
+
+template <int N>
+struct marshall { char buf[N]; };
+
+template <typename T>
+void TestMarshall(const T values[], int num_values) {
+  for (int i = 0; i < num_values; ++i) {
+    T t0 = values[i];
+    marshall<sizeof(T)> m0 = absl::bit_cast<marshall<sizeof(T)> >(t0);
+    T t1 = absl::bit_cast<T>(m0);
+    marshall<sizeof(T)> m1 = absl::bit_cast<marshall<sizeof(T)> >(t1);
+    ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T)));
+    ASSERT_EQ(0, memcmp(&m0, &m1, sizeof(T)));
+  }
+}
+
+// Convert back and forth to an integral type.  The C++ standard does
+// not guarantee this will work, but we test that this works on all the
+// platforms we support.
+//
+// Likewise, we below make assumptions about sizeof(float) and
+// sizeof(double) which the standard does not guarantee, but which hold on the
+// platforms we support.
+
+template <typename T, typename I>
+void TestIntegral(const T values[], int num_values) {
+  for (int i = 0; i < num_values; ++i) {
+    T t0 = values[i];
+    I i0 = absl::bit_cast<I>(t0);
+    T t1 = absl::bit_cast<T>(i0);
+    I i1 = absl::bit_cast<I>(t1);
+    ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T)));
+    ASSERT_EQ(i0, i1);
+  }
+}
+
+TEST(BitCast, Bool) {
+  static const bool bool_list[] = { false, true };
+  TestMarshall<bool>(bool_list, ABSL_ARRAYSIZE(bool_list));
+}
+
+TEST(BitCast, Int32) {
+  static const int32_t int_list[] =
+    { 0, 1, 100, 2147483647, -1, -100, -2147483647, -2147483647-1 };
+  TestMarshall<int32_t>(int_list, ABSL_ARRAYSIZE(int_list));
+}
+
+TEST(BitCast, Int64) {
+  static const int64_t int64_list[] =
+    { 0, 1, 1LL << 40, -1, -(1LL<<40) };
+  TestMarshall<int64_t>(int64_list, ABSL_ARRAYSIZE(int64_list));
+}
+
+TEST(BitCast, Uint64) {
+  static const uint64_t uint64_list[] =
+    { 0, 1, 1LLU << 40, 1LLU << 63 };
+  TestMarshall<uint64_t>(uint64_list, ABSL_ARRAYSIZE(uint64_list));
+}
+
+TEST(BitCast, Float) {
+  static const float float_list[] =
+    { 0.0f, 1.0f, -1.0f, 10.0f, -10.0f,
+      1e10f, 1e20f, 1e-10f, 1e-20f,
+      2.71828f, 3.14159f };
+  TestMarshall<float>(float_list, ABSL_ARRAYSIZE(float_list));
+  TestIntegral<float, int>(float_list, ABSL_ARRAYSIZE(float_list));
+  TestIntegral<float, unsigned>(float_list, ABSL_ARRAYSIZE(float_list));
+}
+
+TEST(BitCast, Double) {
+  static const double double_list[] =
+    { 0.0, 1.0, -1.0, 10.0, -10.0,
+      1e10, 1e100, 1e-10, 1e-100,
+      2.718281828459045,
+      3.141592653589793238462643383279502884197169399375105820974944 };
+  TestMarshall<double>(double_list, ABSL_ARRAYSIZE(double_list));
+  TestIntegral<double, int64_t>(double_list, ABSL_ARRAYSIZE(double_list));
+  TestIntegral<double, uint64_t>(double_list, ABSL_ARRAYSIZE(double_list));
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
new file mode 100644
index 0000000..532ee2e
--- /dev/null
+++ b/absl/base/call_once.h
@@ -0,0 +1,216 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: call_once.h
+// -----------------------------------------------------------------------------
+//
+// This header file provides an Abseil version of `std::call_once` for invoking
+// a given function at most once, across all threads. This Abseil version is
+// faster than the C++11 version and incorporates the C++17 argument-passing
+// fix, so that (for example) non-const references may be passed to the invoked
+// function.
+
+#ifndef ABSL_BASE_CALL_ONCE_H_
+#define ABSL_BASE_CALL_ONCE_H_
+
+#include <algorithm>
+#include <atomic>
+#include <cstdint>
+#include <type_traits>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/spinlock_wait.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+class once_flag;
+
+namespace base_internal {
+std::atomic<uint32_t>* ControlWord(absl::once_flag* flag);
+}  // namespace base_internal
+
+// call_once()
+//
+// For all invocations using a given `once_flag`, invokes a given `fn` exactly
+// once across all threads. The first call to `call_once()` with a particular
+// `once_flag` argument (that does not throw an exception) will run the
+// specified function with the provided `args`; other calls with the same
+// `once_flag` argument will not run the function, but will wait
+// for the provided function to finish running (if it is still running).
+//
+// This mechanism provides a safe, simple, and fast mechanism for one-time
+// initialization in a multi-threaded process.
+//
+// Example:
+//
+// class MyInitClass {
+//  public:
+//  ...
+//  mutable absl::once_flag once_;
+//
+//  MyInitClass* init() const {
+//    absl::call_once(once_, &MyInitClass::Init, this);
+//    return ptr_;
+//  }
+//
+template <typename Callable, typename... Args>
+void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);
+
+// once_flag
+//
+// Objects of this type are used to distinguish calls to `call_once()` and
+// ensure the provided function is only invoked once across all threads. This
+// type is not copyable or movable. However, it has a `constexpr`
+// constructor, and is safe to use as a namespace-scoped global variable.
+class once_flag {
+ public:
+  constexpr once_flag() : control_(0) {}
+  once_flag(const once_flag&) = delete;
+  once_flag& operator=(const once_flag&) = delete;
+
+ private:
+  friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag);
+  std::atomic<uint32_t> control_;
+};
+
+//------------------------------------------------------------------------------
+// End of public interfaces.
+// Implementation details follow.
+//------------------------------------------------------------------------------
+
+namespace base_internal {
+
+// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
+// initialize entities used by the scheduler implementation.
+template <typename Callable, typename... Args>
+void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args);
+
+// Disables scheduling while on stack when scheduling mode is non-cooperative.
+// No effect for cooperative scheduling modes.
+class SchedulingHelper {
+ public:
+  explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) {
+    if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
+      guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
+    }
+  }
+
+  ~SchedulingHelper() {
+    if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
+      base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
+    }
+  }
+
+ private:
+  base_internal::SchedulingMode mode_;
+  bool guard_result_;
+};
+
+// Bit patterns for call_once state machine values.  Internal implementation
+// detail, not for use by clients.
+//
+// The bit patterns are arbitrarily chosen from unlikely values, to aid in
+// debugging.  However, kOnceInit must be 0, so that a zero-initialized
+// once_flag will be valid for immediate use.
+enum {
+  kOnceInit = 0,
+  kOnceRunning = 0x65C2937B,
+  kOnceWaiter = 0x05A308D2,
+  // A very small constant is chosen for kOnceDone so that it fit in a single
+  // compare with immediate instruction for most common ISAs.  This is verified
+  // for x86, POWER and ARM.
+  kOnceDone = 221,    // Random Number
+};
+
+template <typename Callable, typename... Args>
+void CallOnceImpl(std::atomic<uint32_t>* control,
+                  base_internal::SchedulingMode scheduling_mode, Callable&& fn,
+                  Args&&... args) {
+#ifndef NDEBUG
+  {
+    uint32_t old_control = control->load(std::memory_order_acquire);
+    if (old_control != kOnceInit &&
+        old_control != kOnceRunning &&
+        old_control != kOnceWaiter &&
+        old_control != kOnceDone) {
+      ABSL_RAW_LOG(
+          FATAL,
+          "Unexpected value for control word: %lx. Either the control word "
+          "has non-static storage duration (where GoogleOnceDynamic might "
+          "be appropriate), or there's been a memory corruption.",
+          static_cast<unsigned long>(old_control)); // NOLINT
+    }
+  }
+#endif  // NDEBUG
+  static const base_internal::SpinLockWaitTransition trans[] = {
+      {kOnceInit, kOnceRunning, true},
+      {kOnceRunning, kOnceWaiter, false},
+      {kOnceDone, kOnceDone, true}};
+
+  // Must do this before potentially modifying control word's state.
+  base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
+  // Short circuit the simplest case to avoid procedure call overhead.
+  uint32_t old_control = kOnceInit;
+  if (control->compare_exchange_strong(old_control, kOnceRunning,
+                                       std::memory_order_acquire,
+                                       std::memory_order_relaxed) ||
+      base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
+                                  scheduling_mode) == kOnceInit) {
+    base_internal::Invoke(std::forward<Callable>(fn),
+                          std::forward<Args>(args)...);
+    old_control = control->load(std::memory_order_relaxed);
+    control->store(base_internal::kOnceDone, std::memory_order_release);
+    if (old_control == base_internal::kOnceWaiter) {
+      base_internal::SpinLockWake(control, true);
+    }
+  }  // else *control is already kOnceDone
+}
+
+inline std::atomic<uint32_t>* ControlWord(once_flag* flag) {
+  return &flag->control_;
+}
+
+template <typename Callable, typename... Args>
+void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) {
+  std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
+  uint32_t s = once->load(std::memory_order_acquire);
+  if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
+    base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY,
+                                std::forward<Callable>(fn),
+                                std::forward<Args>(args)...);
+  }
+}
+
+}  // namespace base_internal
+
+template <typename Callable, typename... Args>
+void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
+  std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
+  uint32_t s = once->load(std::memory_order_acquire);
+  if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
+    base_internal::CallOnceImpl(
+        once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL,
+        std::forward<Callable>(fn), std::forward<Args>(args)...);
+  }
+}
+
+}  // namespace absl
+
+#endif  // ABSL_BASE_CALL_ONCE_H_
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc
new file mode 100644
index 0000000..cd58ee1
--- /dev/null
+++ b/absl/base/call_once_test.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 The Abseil 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 "absl/base/call_once.h"
+
+#include <thread>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace {
+
+absl::once_flag once;
+Mutex counters_mu;
+
+int running_thread_count GUARDED_BY(counters_mu) = 0;
+int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
+int call_once_finished_count GUARDED_BY(counters_mu) = 0;
+int call_once_return_count GUARDED_BY(counters_mu) = 0;
+bool done_blocking GUARDED_BY(counters_mu) = false;
+
+// Function to be called from absl::call_once.  Waits for a notification.
+void WaitAndIncrement() {
+  counters_mu.Lock();
+  ++call_once_invoke_count;
+  counters_mu.Unlock();
+
+  counters_mu.LockWhen(Condition(&done_blocking));
+  ++call_once_finished_count;
+  counters_mu.Unlock();
+}
+
+void ThreadBody() {
+  counters_mu.Lock();
+  ++running_thread_count;
+  counters_mu.Unlock();
+
+  absl::call_once(once, WaitAndIncrement);
+
+  counters_mu.Lock();
+  ++call_once_return_count;
+  counters_mu.Unlock();
+}
+
+// Returns true if all threads are set up for the test.
+bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
+  // All ten threads must be running, and WaitAndIncrement should be blocked.
+  return running_thread_count == 10 && call_once_invoke_count == 1;
+}
+
+TEST(CallOnceTest, ExecutionCount) {
+  std::vector<std::thread> threads;
+
+  // Start 10 threads all calling call_once on the same once_flag.
+  for (int i = 0; i < 10; ++i) {
+    threads.emplace_back(ThreadBody);
+  }
+
+
+  // Wait until all ten threads have started, and WaitAndIncrement has been
+  // invoked.
+  counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));
+
+  // WaitAndIncrement should have been invoked by exactly one call_once()
+  // instance.  That thread should be blocking on a notification, and all other
+  // call_once instances should be blocking as well.
+  EXPECT_EQ(call_once_invoke_count, 1);
+  EXPECT_EQ(call_once_finished_count, 0);
+  EXPECT_EQ(call_once_return_count, 0);
+
+  // Allow WaitAndIncrement to finish executing.  Once it does, the other
+  // call_once waiters will be unblocked.
+  done_blocking = true;
+  counters_mu.Unlock();
+
+  for (std::thread& thread : threads) {
+    thread.join();
+  }
+
+  counters_mu.Lock();
+  EXPECT_EQ(call_once_invoke_count, 1);
+  EXPECT_EQ(call_once_finished_count, 1);
+  EXPECT_EQ(call_once_return_count, 10);
+  counters_mu.Unlock();
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/base/casts.h b/absl/base/casts.h
new file mode 100644
index 0000000..20fd34d
--- /dev/null
+++ b/absl/base/casts.h
@@ -0,0 +1,189 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: casts.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines casting templates to fit use cases not covered by
+// the standard casts provided in the C++ standard. As with all cast operations,
+// use these with caution and only if alternatives do not exist.
+
+#ifndef ABSL_BASE_CASTS_H_
+#define ABSL_BASE_CASTS_H_
+
+#include <cstring>
+#include <memory>
+#include <type_traits>
+
+#include "absl/base/internal/identity.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+
+namespace internal_casts {
+
+// NOTE: Not a fully compliant implementation of `std::is_trivially_copyable`.
+// TODO(calabrese) Branch on implementations that directly provide
+// `std::is_trivially_copyable`, create a more rigorous workaround, and publicly
+// expose in meta/type_traits.
+template <class T>
+struct is_trivially_copyable
+    : std::integral_constant<
+          bool, std::is_destructible<T>::value&& __has_trivial_destructor(T) &&
+                    __has_trivial_copy(T) && __has_trivial_assign(T)> {};
+
+template <class Dest, class Source>
+struct is_bitcastable
+    : std::integral_constant<bool,
+                             sizeof(Dest) == sizeof(Source) &&
+                                 is_trivially_copyable<Source>::value &&
+                                 is_trivially_copyable<Dest>::value &&
+                                 std::is_default_constructible<Dest>::value> {};
+
+}  // namespace internal_casts
+
+// implicit_cast()
+//
+// Performs an implicit conversion between types following the language
+// rules for implicit conversion; if an implicit conversion is otherwise
+// allowed by the language in the given context, this function performs such an
+// implicit conversion.
+//
+// Example:
+//
+//   // If the context allows implicit conversion:
+//   From from;
+//   To to = from;
+//
+//   // Such code can be replaced by:
+//   implicit_cast<To>(from);
+//
+// An `implicit_cast()` may also be used to annotate numeric type conversions
+// that, although safe, may produce compiler warnings (such as `long` to `int`).
+// Additionally, an `implicit_cast()` is also useful within return statements to
+// indicate a specific implicit conversion is being undertaken.
+//
+// Example:
+//
+//   return implicit_cast<double>(size_in_bytes) / capacity_;
+//
+// Annotating code with `implicit_cast()` allows you to explicitly select
+// particular overloads and template instantiations, while providing a safer
+// cast than `reinterpret_cast()` or `static_cast()`.
+//
+// Additionally, an `implicit_cast()` can be used to allow upcasting within a
+// type hierarchy where incorrect use of `static_cast()` could accidentally
+// allow downcasting.
+//
+// Finally, an `implicit_cast()` can be used to perform implicit conversions
+// from unrelated types that otherwise couldn't be implicitly cast directly;
+// C++ will normally only implicitly cast "one step" in such conversions.
+//
+// That is, if C is a type which can be implicitly converted to B, with B being
+// a type that can be implicitly converted to A, an `implicit_cast()` can be
+// used to convert C to B (which the compiler can then implicitly convert to A
+// using language rules).
+//
+// Example:
+//
+//   // Assume an object C is convertible to B, which is implicitly convertible
+//   // to A
+//   A a = implicit_cast<B>(C);
+//
+// Such implicit cast chaining may be useful within template logic.
+template <typename To>
+inline To implicit_cast(typename absl::internal::identity_t<To> to) {
+  return to;
+}
+
+// bit_cast()
+//
+// Performs a bitwise cast on a type without changing the underlying bit
+// representation of that type's value. The two types must be of the same size
+// and both types must be trivially copyable. As with most casts, use with
+// caution. A `bit_cast()` might be needed when you need to temporarily treat a
+// type as some other type, such as in the following cases:
+//
+//    * Serialization (casting temporarily to `char *` for those purposes is
+//      always allowed by the C++ standard)
+//    * Managing the individual bits of a type within mathematical operations
+//      that are not normally accessible through that type
+//    * Casting non-pointer types to pointer types (casting the other way is
+//      allowed by `reinterpret_cast()` but round-trips cannot occur the other
+//      way).
+//
+// Example:
+//
+//   float f = 3.14159265358979;
+//   int i = bit_cast<int32_t>(f);
+//   // i = 0x40490fdb
+//
+// Casting non-pointer types to pointer types and then dereferencing them
+// traditionally produces undefined behavior.
+//
+// Example:
+//
+//   // WRONG
+//   float f = 3.14159265358979;            // WRONG
+//   int i = * reinterpret_cast<int*>(&f);  // WRONG
+//
+// The address-casting method produces undefined behavior according to the ISO
+// C++ specification section [basic.lval]. Roughly, this section says: if an
+// object in memory has one type, and a program accesses it with a different
+// type, the result is undefined behavior for most values of "different type".
+//
+// Such casting results in type punning: holding an object in memory of one type
+// and reading its bits back using a different type. A `bit_cast()` avoids this
+// issue by implementing its casts using `memcpy()`, which avoids introducing
+// this undefined behavior.
+//
+// NOTE: The requirements here are more strict than the bit_cast of standard
+// proposal p0476 due to the need for workarounds and lack of intrinsics.
+// Specifically, this implementation also requires `Dest` to be
+// default-constructible.
+template <
+    typename Dest, typename Source,
+    typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value,
+                            int>::type = 0>
+inline Dest bit_cast(const Source& source) {
+  Dest dest;
+  memcpy(static_cast<void*>(std::addressof(dest)),
+         static_cast<const void*>(std::addressof(source)), sizeof(dest));
+  return dest;
+}
+
+// NOTE: This overload is only picked if the requirements of bit_cast are not
+// met. It is therefore UB, but is provided temporarily as previous versions of
+// this function template were unchecked. Do not use this in new code.
+template <
+    typename Dest, typename Source,
+    typename std::enable_if<
+        !internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0>
+ABSL_DEPRECATED(
+    "absl::bit_cast type requirements were violated. Update the types being "
+    "used such that they are the same size and are both TriviallyCopyable.")
+inline Dest bit_cast(const Source& source) {
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "Source and destination types should have equal sizes.");
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_BASE_CASTS_H_
diff --git a/absl/base/config.h b/absl/base/config.h
new file mode 100644
index 0000000..2f5f159
--- /dev/null
+++ b/absl/base/config.h
@@ -0,0 +1,427 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: config.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a set of macros for checking the presence of
+// important compiler and platform features. Such macros can be used to
+// produce portable code by parameterizing compilation based on the presence or
+// lack of a given feature.
+//
+// We define a "feature" as some interface we wish to program to: for example,
+// a library function or system call. A value of `1` indicates support for
+// that feature; any other value indicates the feature support is undefined.
+//
+// Example:
+//
+// Suppose a programmer wants to write a program that uses the 'mmap()' system
+// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
+// selectively include the `mmap.h` header and bracket code using that feature
+// in the macro:
+//
+//   #include "absl/base/config.h"
+//
+//   #ifdef ABSL_HAVE_MMAP
+//   #include "sys/mman.h"
+//   #endif  //ABSL_HAVE_MMAP
+//
+//   ...
+//   #ifdef ABSL_HAVE_MMAP
+//   void *ptr = mmap(...);
+//   ...
+//   #endif  // ABSL_HAVE_MMAP
+
+#ifndef ABSL_BASE_CONFIG_H_
+#define ABSL_BASE_CONFIG_H_
+
+// Included for the __GLIBC__ macro (or similar macros on other systems).
+#include <limits.h>
+
+#ifdef __cplusplus
+// Included for __GLIBCXX__, _LIBCPP_VERSION
+#include <cstddef>
+#endif  // __cplusplus
+
+#if defined(__APPLE__)
+// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
+// __IPHONE_8_0.
+#include <Availability.h>
+#include <TargetConditionals.h>
+#endif
+
+#include "absl/base/policy_checks.h"
+
+// -----------------------------------------------------------------------------
+// Compiler Feature Checks
+// -----------------------------------------------------------------------------
+
+// ABSL_HAVE_BUILTIN()
+//
+// Checks whether the compiler supports a Clang Feature Checking Macro, and if
+// so, checks whether it supports the provided builtin function "x" where x
+// is one of the functions noted in
+// https://clang.llvm.org/docs/LanguageExtensions.html
+//
+// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
+// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
+#ifdef __has_builtin
+#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
+#else
+#define ABSL_HAVE_BUILTIN(x) 0
+#endif
+
+// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
+// We assume __thread is supported on Linux when compiled with Clang or compiled
+// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
+#ifdef ABSL_HAVE_TLS
+#error ABSL_HAVE_TLS cannot be directly set
+#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
+#define ABSL_HAVE_TLS 1
+#endif
+
+// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+//
+// Checks whether `std::is_trivially_destructible<T>` is supported.
+//
+// Notes: All supported compilers using libc++ support this feature, as does
+// gcc >= 4.8.1 using libstdc++, and Visual Studio.
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
+#elif defined(_LIBCPP_VERSION) ||                                        \
+    (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
+     (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) ||        \
+    defined(_MSC_VER)
+#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
+#endif
+
+// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+//
+// Checks whether `std::is_trivially_default_constructible<T>` and
+// `std::is_trivially_copy_constructible<T>` are supported.
+
+// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+//
+// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
+
+// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
+// either libc++ or libstdc++, and Visual Studio.
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
+#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
+#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
+#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
+#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) ||        \
+    (!defined(__clang__) && defined(__GNUC__) &&                 \
+     (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
+     (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) ||      \
+    defined(_MSC_VER)
+#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
+#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
+#endif
+
+// ABSL_HAVE_THREAD_LOCAL
+//
+// Checks whether C++11's `thread_local` storage duration specifier is
+// supported.
+#ifdef ABSL_HAVE_THREAD_LOCAL
+#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
+#elif defined(__APPLE__)
+// Notes: Xcode's clang did not support `thread_local` until version
+// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing
+// `thread_local` for 32-bit iOS simulator targeting iOS 9.x.
+// `__has_feature` is only supported by Clang so it has be inside
+// `defined(__APPLE__)` check.
+#if __has_feature(cxx_thread_local)
+#define ABSL_HAVE_THREAD_LOCAL 1
+#endif
+#else  // !defined(__APPLE__)
+#define ABSL_HAVE_THREAD_LOCAL 1
+#endif
+
+// There are platforms for which TLS should not be used even though the compiler
+// makes it seem like it's supported (Android NDK < r12b for example).
+// This is primarily because of linker problems and toolchain misconfiguration:
+// Abseil does not intend to support this indefinitely. Currently, the newest
+// toolchain that we intend to support that requires this behavior is the
+// r11 NDK - allowing for a 5 year support window on that means this option
+// is likely to be removed around June of 2021.
+// TLS isn't supported until NDK r12b per
+// https://developer.android.com/ndk/downloads/revision_history.html
+// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
+// <android/ndk-version.h>. For NDK < r16, users should define these macros,
+// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11.
+#if defined(__ANDROID__) && defined(__clang__)
+#if __has_include(<android/ndk-version.h>)
+#include <android/ndk-version.h>
+#endif  // __has_include(<android/ndk-version.h>)
+#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
+    defined(__NDK_MINOR__) &&                                               \
+    ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
+#undef ABSL_HAVE_TLS
+#undef ABSL_HAVE_THREAD_LOCAL
+#endif
+#endif  // defined(__ANDROID__) && defined(__clang__)
+
+// ABSL_HAVE_INTRINSIC_INT128
+//
+// Checks whether the __int128 compiler extension for a 128-bit integral type is
+// supported.
+//
+// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
+// supported, but we avoid using it in certain cases:
+// * On Clang:
+//   * Building using Clang for Windows, where the Clang runtime library has
+//     128-bit support only on LP64 architectures, but Windows is LLP64.
+//   * Building for aarch64, where __int128 exists but has exhibits a sporadic
+//     compiler crashing bug.
+// * On Nvidia's nvcc:
+//   * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
+//     actually support __int128.
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
+#elif defined(__SIZEOF_INT128__)
+#if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \
+    (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) ||                \
+    (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
+#define ABSL_HAVE_INTRINSIC_INT128 1
+#elif defined(__CUDACC__)
+// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
+// std::string explaining that it has been removed starting with CUDA 9. We use
+// nested #ifs because there is no short-circuiting in the preprocessor.
+// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
+#if __CUDACC_VER__ >= 70000
+#define ABSL_HAVE_INTRINSIC_INT128 1
+#endif  // __CUDACC_VER__ >= 70000
+#endif  // defined(__CUDACC__)
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+// ABSL_HAVE_EXCEPTIONS
+//
+// Checks whether the compiler both supports and enables exceptions. Many
+// compilers support a "no exceptions" mode that disables exceptions.
+//
+// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
+//
+// * Code using `throw` and `try` may not compile.
+// * The `noexcept` specifier will still compile and behave as normal.
+// * The `noexcept` operator may still return `false`.
+//
+// For further details, consult the compiler's documentation.
+#ifdef ABSL_HAVE_EXCEPTIONS
+#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
+
+#elif defined(__clang__)
+// TODO(calabrese)
+// Switch to using __cpp_exceptions when we no longer support versions < 3.6.
+// For details on this check, see:
+//   http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
+#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
+#define ABSL_HAVE_EXCEPTIONS 1
+#endif  // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
+
+// Handle remaining special cases and default to exceptions being supported.
+#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) &&    \
+    !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
+    !(defined(_MSC_VER) && !defined(_CPPUNWIND))
+#define ABSL_HAVE_EXCEPTIONS 1
+#endif
+
+// -----------------------------------------------------------------------------
+// Platform Feature Checks
+// -----------------------------------------------------------------------------
+
+// Currently supported operating systems and associated preprocessor
+// symbols:
+//
+//   Linux and Linux-derived           __linux__
+//   Android                           __ANDROID__ (implies __linux__)
+//   Linux (non-Android)               __linux__ && !__ANDROID__
+//   Darwin (Mac OS X and iOS)         __APPLE__
+//   Akaros (http://akaros.org)        __ros__
+//   Windows                           _WIN32
+//   NaCL                              __native_client__
+//   AsmJS                             __asmjs__
+//   WebAssembly                       __wasm__
+//   Fuchsia                           __Fuchsia__
+//
+// Note that since Android defines both __ANDROID__ and __linux__, one
+// may probe for either Linux or Android by simply testing for __linux__.
+
+// ABSL_HAVE_MMAP
+//
+// Checks whether the platform has an mmap(2) implementation as defined in
+// POSIX.1-2001.
+#ifdef ABSL_HAVE_MMAP
+#error ABSL_HAVE_MMAP cannot be directly set
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||   \
+    defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
+    defined(__wasm__) || defined(__Fuchsia__)
+#define ABSL_HAVE_MMAP 1
+#endif
+
+// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+//
+// Checks whether the platform implements the pthread_(get|set)schedparam(3)
+// functions as defined in POSIX.1-2001.
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
+    defined(__ros__)
+#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
+#endif
+
+// ABSL_HAVE_SCHED_YIELD
+//
+// Checks whether the platform implements sched_yield(2) as defined in
+// POSIX.1-2001.
+#ifdef ABSL_HAVE_SCHED_YIELD
+#error ABSL_HAVE_SCHED_YIELD cannot be directly set
+#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
+#define ABSL_HAVE_SCHED_YIELD 1
+#endif
+
+// ABSL_HAVE_SEMAPHORE_H
+//
+// Checks whether the platform supports the <semaphore.h> header and sem_open(3)
+// family of functions as standardized in POSIX.1-2001.
+//
+// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
+// explicitly deprecated and will cause build failures if enabled for those
+// platforms.  We side-step the issue by not defining it here for Apple
+// platforms.
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
+#elif defined(__linux__) || defined(__ros__)
+#define ABSL_HAVE_SEMAPHORE_H 1
+#endif
+
+// ABSL_HAVE_ALARM
+//
+// Checks whether the platform supports the <signal.h> header and alarm(2)
+// function as standardized in POSIX.1-2001.
+#ifdef ABSL_HAVE_ALARM
+#error ABSL_HAVE_ALARM cannot be directly set
+#elif defined(__GOOGLE_GRTE_VERSION__)
+// feature tests for Google's GRTE
+#define ABSL_HAVE_ALARM 1
+#elif defined(__GLIBC__)
+// feature test for glibc
+#define ABSL_HAVE_ALARM 1
+#elif defined(_MSC_VER)
+// feature tests for Microsoft's library
+#elif defined(__native_client__)
+#else
+// other standard libraries
+#define ABSL_HAVE_ALARM 1
+#endif
+
+// ABSL_IS_LITTLE_ENDIAN
+// ABSL_IS_BIG_ENDIAN
+//
+// Checks the endianness of the platform.
+//
+// Notes: uses the built in endian macros provided by GCC (since 4.6) and
+// Clang (since 3.2); see
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
+// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
+#if defined(ABSL_IS_BIG_ENDIAN)
+#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
+#endif
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
+#endif
+
+#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+     __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define ABSL_IS_LITTLE_ENDIAN 1
+#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
+    __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define ABSL_IS_BIG_ENDIAN 1
+#elif defined(_WIN32)
+#define ABSL_IS_LITTLE_ENDIAN 1
+#else
+#error "absl endian detection needs to be set up for your compiler"
+#endif
+
+// ABSL_HAVE_STD_ANY
+//
+// Checks whether C++17 std::any is available by checking whether <any> exists.
+#ifdef ABSL_HAVE_STD_ANY
+#error "ABSL_HAVE_STD_ANY cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<any>) && __cplusplus >= 201703L
+#define ABSL_HAVE_STD_ANY 1
+#endif
+#endif
+
+// ABSL_HAVE_STD_OPTIONAL
+//
+// Checks whether C++17 std::optional is available.
+#ifdef ABSL_HAVE_STD_OPTIONAL
+#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+#define ABSL_HAVE_STD_OPTIONAL 1
+#endif
+#endif
+
+// ABSL_HAVE_STD_VARIANT
+//
+// Checks whether C++17 std::variant is available.
+#ifdef ABSL_HAVE_STD_VARIANT
+#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<variant>) && __cplusplus >= 201703L
+#define ABSL_HAVE_STD_VARIANT 1
+#endif
+#endif
+
+// ABSL_HAVE_STD_STRING_VIEW
+//
+// Checks whether C++17 std::string_view is available.
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<string_view>) && __cplusplus >= 201703L
+#define ABSL_HAVE_STD_STRING_VIEW 1
+#endif
+#endif
+
+// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
+// the support for <optional>, <any>, <string_view>, <variant>. So we use
+// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
+// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
+// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
+// version.
+// TODO(zhangxy): fix tests before enabling aliasing for `std::any`,
+// `std::string_view`.
+#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
+    ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
+// #define ABSL_HAVE_STD_ANY 1
+#define ABSL_HAVE_STD_OPTIONAL 1
+#define ABSL_HAVE_STD_VARIANT 1
+// #define ABSL_HAVE_STD_STRING_VIEW 1
+#endif
+
+#endif  // ABSL_BASE_CONFIG_H_
diff --git a/absl/base/config_test.cc b/absl/base/config_test.cc
new file mode 100644
index 0000000..c839712
--- /dev/null
+++ b/absl/base/config_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2017 The Abseil 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 "absl/base/config.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+#include "absl/synchronization/internal/thread_pool.h"
+
+namespace {
+
+TEST(ConfigTest, Endianness) {
+  union {
+    uint32_t value;
+    uint8_t data[sizeof(uint32_t)];
+  } number;
+  number.data[0] = 0x00;
+  number.data[1] = 0x01;
+  number.data[2] = 0x02;
+  number.data[3] = 0x03;
+#if defined(ABSL_IS_LITTLE_ENDIAN) && defined(ABSL_IS_BIG_ENDIAN)
+#error Both ABSL_IS_LITTLE_ENDIAN and ABSL_IS_BIG_ENDIAN are defined
+#elif defined(ABSL_IS_LITTLE_ENDIAN)
+  EXPECT_EQ(UINT32_C(0x03020100), number.value);
+#elif defined(ABSL_IS_BIG_ENDIAN)
+  EXPECT_EQ(UINT32_C(0x00010203), number.value);
+#else
+#error Unknown endianness
+#endif
+}
+
+#if defined(ABSL_HAVE_THREAD_LOCAL)
+TEST(ConfigTest, ThreadLocal) {
+  static thread_local int mine_mine_mine = 16;
+  EXPECT_EQ(16, mine_mine_mine);
+  {
+    absl::synchronization_internal::ThreadPool pool(1);
+    pool.Schedule([&] {
+      EXPECT_EQ(16, mine_mine_mine);
+      mine_mine_mine = 32;
+      EXPECT_EQ(32, mine_mine_mine);
+    });
+  }
+  EXPECT_EQ(16, mine_mine_mine);
+}
+#endif
+
+}  // namespace
diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc
new file mode 100644
index 0000000..b97fa3a
--- /dev/null
+++ b/absl/base/dynamic_annotations.cc
@@ -0,0 +1,129 @@
+// Copyright 2017 The Abseil 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 <stdlib.h>
+#include <string.h>
+
+#include "absl/base/dynamic_annotations.h"
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+/* Compiler-based ThreadSanitizer defines
+   ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
+   and provides its own definitions of the functions. */
+
+#ifndef ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
+# define ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
+#endif
+
+/* Each function is empty and called (via a macro) only in debug mode.
+   The arguments are captured by dynamic tools at runtime. */
+
+#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
+
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void AbslAnnotateRWLockCreate(const char *, int,
+                          const volatile void *){}
+void AbslAnnotateRWLockDestroy(const char *, int,
+                           const volatile void *){}
+void AbslAnnotateRWLockAcquired(const char *, int,
+                            const volatile void *, long){}
+void AbslAnnotateRWLockReleased(const char *, int,
+                            const volatile void *, long){}
+void AbslAnnotateBenignRace(const char *, int,
+                        const volatile void *,
+                        const char *){}
+void AbslAnnotateBenignRaceSized(const char *, int,
+                             const volatile void *,
+                             size_t,
+                             const char *) {}
+void AbslAnnotateThreadName(const char *, int,
+                        const char *){}
+void AbslAnnotateIgnoreReadsBegin(const char *, int){}
+void AbslAnnotateIgnoreReadsEnd(const char *, int){}
+void AbslAnnotateIgnoreWritesBegin(const char *, int){}
+void AbslAnnotateIgnoreWritesEnd(const char *, int){}
+void AbslAnnotateEnableRaceDetection(const char *, int, int){}
+void AbslAnnotateMemoryIsInitialized(const char *, int,
+                                 const volatile void *mem, size_t size) {
+#if __has_feature(memory_sanitizer)
+  __msan_unpoison(mem, size);
+#else
+  (void)mem;
+  (void)size;
+#endif
+}
+
+void AbslAnnotateMemoryIsUninitialized(const char *, int,
+                                   const volatile void *mem, size_t size) {
+#if __has_feature(memory_sanitizer)
+  __msan_allocated_memory(mem, size);
+#else
+  (void)mem;
+  (void)size;
+#endif
+}
+
+static int AbslGetRunningOnValgrind(void) {
+#ifdef RUNNING_ON_VALGRIND
+  if (RUNNING_ON_VALGRIND) return 1;
+#endif
+  char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
+  if (running_on_valgrind_str) {
+    return strcmp(running_on_valgrind_str, "0") != 0;
+  }
+  return 0;
+}
+
+/* See the comments in dynamic_annotations.h */
+int AbslRunningOnValgrind(void) {
+  static volatile int running_on_valgrind = -1;
+  int local_running_on_valgrind = running_on_valgrind;
+  /* C doesn't have thread-safe initialization of statics, and we
+     don't want to depend on pthread_once here, so hack it. */
+  ABSL_ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
+  if (local_running_on_valgrind == -1)
+    running_on_valgrind = local_running_on_valgrind = AbslGetRunningOnValgrind();
+  return local_running_on_valgrind;
+}
+
+/* See the comments in dynamic_annotations.h */
+double AbslValgrindSlowdown(void) {
+  /* Same initialization hack as in AbslRunningOnValgrind(). */
+  static volatile double slowdown = 0.0;
+  double local_slowdown = slowdown;
+  ABSL_ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
+  if (AbslRunningOnValgrind() == 0) {
+    return 1.0;
+  }
+  if (local_slowdown == 0.0) {
+    char *env = getenv("VALGRIND_SLOWDOWN");
+    slowdown = local_slowdown = env ? atof(env) : 50.0;
+  }
+  return local_slowdown;
+}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+#endif  /* ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h
new file mode 100644
index 0000000..88048b0
--- /dev/null
+++ b/absl/base/dynamic_annotations.h
@@ -0,0 +1,388 @@
+/*
+ *  Copyright 2017 The Abseil 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.
+ */
+/* This file defines dynamic annotations for use with dynamic analysis
+   tool such as valgrind, PIN, etc.
+
+   Dynamic annotation is a source code annotation that affects
+   the generated code (that is, the annotation is not a comment).
+   Each such annotation is attached to a particular
+   instruction and/or to a particular object (address) in the program.
+
+   The annotations that should be used by users are macros in all upper-case
+   (e.g., ABSL_ANNOTATE_THREAD_NAME).
+
+   Actual implementation of these macros may differ depending on the
+   dynamic analysis tool being used.
+
+   This file supports the following configurations:
+   - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+     In this case, macros expand to functions implemented by Thread Sanitizer,
+     when building with TSan. When not provided an external implementation,
+     dynamic_annotations.cc provides no-op implementations.
+
+   - Static Clang thread-safety warnings enabled.
+     When building with a Clang compiler that supports thread-safety warnings,
+     a subset of annotations can be statically-checked at compile-time. We
+     expand these macros to static-inline functions that can be analyzed for
+     thread-safety, but afterwards elided when building the final binary.
+
+   - All annotations are disabled.
+     If neither Dynamic Annotations nor Clang thread-safety warnings are
+     enabled, then all annotation-macros expand to empty. */
+
+#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
+#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
+
+#ifndef ABSL_DYNAMIC_ANNOTATIONS_ENABLED
+# define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+  /* -------------------------------------------------------------
+     Annotations that suppress errors.  It is usually better to express the
+     program's synchronization using the other annotations, but these can
+     be used when all else fails. */
+
+  /* Report that we may have a benign race at "pointer", with size
+     "sizeof(*(pointer))". "pointer" must be a non-void* pointer.  Insert at the
+     point where "pointer" has been allocated, preferably close to the point
+     where the race happens.  See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. */
+  #define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
+    AbslAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
+                            sizeof(*(pointer)), description)
+
+  /* Same as ABSL_ANNOTATE_BENIGN_RACE(address, description), but applies to
+     the memory range [address, address+size). */
+  #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+    AbslAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
+
+  /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
+     This annotation could be useful if you want to skip expensive race analysis
+     during some period of program execution, e.g. during initialization. */
+  #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+    AbslAnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
+
+  /* -------------------------------------------------------------
+     Annotations useful for debugging. */
+
+  /* Report the current thread name to a race detector. */
+  #define ABSL_ANNOTATE_THREAD_NAME(name) \
+    AbslAnnotateThreadName(__FILE__, __LINE__, name)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing locks.  They are not
+     normally needed by modules that merely use locks.
+     The "lock" argument is a pointer to the lock object. */
+
+  /* Report that a lock has been created at address "lock". */
+  #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
+    AbslAnnotateRWLockCreate(__FILE__, __LINE__, lock)
+
+  /* Report that a linker initialized lock has been created at address "lock".
+   */
+#ifdef THREAD_SANITIZER
+  #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+    AbslAnnotateRWLockCreateStatic(__FILE__, __LINE__, lock)
+#else
+  #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) ABSL_ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+  /* Report that the lock at address "lock" is about to be destroyed. */
+  #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
+    AbslAnnotateRWLockDestroy(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" has been acquired.
+     is_w=1 for writer lock, is_w=0 for reader lock. */
+  #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+    AbslAnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
+
+  /* Report that the lock at address "lock" is about to be released. */
+  #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+    AbslAnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
+
+#else  /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+  #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */
+  #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+  #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+  #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+  #define ABSL_ANNOTATE_BENIGN_RACE(address, description) /* empty */
+  #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+  #define ABSL_ANNOTATE_THREAD_NAME(name) /* empty */
+  #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+
+#endif  /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* These annotations are also made available to LLVM's Memory Sanitizer */
+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
+  #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+    AbslAnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
+
+  #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+    AbslAnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
+#else
+  #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
+  #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
+#endif  /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
+/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
+   appropriate feature ID. */
+#if defined(__clang__) && (!defined(SWIG)) \
+    && defined(__CLANG_SUPPORT_DYN_ANNOTATION__)
+
+  #if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0
+    #define ABSL_ANNOTALYSIS_ENABLED
+  #endif
+
+  /* When running in opt-mode, GCC will issue a warning, if these attributes are
+     compiled. Only include them when compiling using Clang. */
+  #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN \
+      __attribute((exclusive_lock_function("*")))
+  #define ABSL_ATTRIBUTE_IGNORE_READS_END \
+      __attribute((unlock_function("*")))
+#else
+  #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN  /* empty */
+  #define ABSL_ATTRIBUTE_IGNORE_READS_END  /* empty */
+#endif  /* defined(__clang__) && ... */
+
+#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ABSL_ANNOTALYSIS_ENABLED)
+  #define ABSL_ANNOTATIONS_ENABLED
+#endif
+
+#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0)
+
+  /* Request the analysis tool to ignore all reads in the current thread
+     until ABSL_ANNOTATE_IGNORE_READS_END is called.
+     Useful to ignore intentional racey reads, while still checking
+     other reads and all writes.
+     See also ABSL_ANNOTATE_UNPROTECTED_READ. */
+  #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
+    AbslAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+
+  /* Stop ignoring reads. */
+  #define ABSL_ANNOTATE_IGNORE_READS_END() \
+    AbslAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+
+  /* Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
+  #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
+    AbslAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+  /* Stop ignoring writes. */
+  #define ABSL_ANNOTATE_IGNORE_WRITES_END() \
+    AbslAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+
+/* Clang provides limited support for static thread-safety analysis
+   through a feature called Annotalysis. We configure macro-definitions
+   according to whether Annotalysis support is available. */
+#elif defined(ABSL_ANNOTALYSIS_ENABLED)
+
+  #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
+    AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+
+  #define ABSL_ANNOTATE_IGNORE_READS_END() \
+    AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+
+  #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
+    AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+  #define ABSL_ANNOTATE_IGNORE_WRITES_END() \
+    AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+
+#else
+  #define ABSL_ANNOTATE_IGNORE_READS_BEGIN()  /* empty */
+  #define ABSL_ANNOTATE_IGNORE_READS_END()  /* empty */
+  #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN()  /* empty */
+  #define ABSL_ANNOTATE_IGNORE_WRITES_END()  /* empty */
+#endif
+
+/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+   primitive annotations defined above. */
+#if defined(ABSL_ANNOTATIONS_ENABLED)
+
+  /* Start ignoring all memory accesses (both reads and writes). */
+  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+    do {                                           \
+      ABSL_ANNOTATE_IGNORE_READS_BEGIN();               \
+      ABSL_ANNOTATE_IGNORE_WRITES_BEGIN();              \
+    }while (0)
+
+  /* Stop ignoring both reads and writes. */
+  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()   \
+    do {                                           \
+      ABSL_ANNOTATE_IGNORE_WRITES_END();                \
+      ABSL_ANNOTATE_IGNORE_READS_END();                 \
+    }while (0)
+
+#else
+  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  /* empty */
+  #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()  /* empty */
+#endif
+
+/* Use the macros above rather than using these functions directly. */
+#include <stddef.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AbslAnnotateRWLockCreate(const char *file, int line,
+                          const volatile void *lock);
+void AbslAnnotateRWLockCreateStatic(const char *file, int line,
+                          const volatile void *lock);
+void AbslAnnotateRWLockDestroy(const char *file, int line,
+                           const volatile void *lock);
+void AbslAnnotateRWLockAcquired(const char *file, int line,
+                            const volatile void *lock, long is_w);  /* NOLINT */
+void AbslAnnotateRWLockReleased(const char *file, int line,
+                            const volatile void *lock, long is_w);  /* NOLINT */
+void AbslAnnotateBenignRace(const char *file, int line,
+                        const volatile void *address,
+                        const char *description);
+void AbslAnnotateBenignRaceSized(const char *file, int line,
+                        const volatile void *address,
+                        size_t size,
+                        const char *description);
+void AbslAnnotateThreadName(const char *file, int line,
+                        const char *name);
+void AbslAnnotateEnableRaceDetection(const char *file, int line, int enable);
+void AbslAnnotateMemoryIsInitialized(const char *file, int line,
+                                 const volatile void *mem, size_t size);
+void AbslAnnotateMemoryIsUninitialized(const char *file, int line,
+                                   const volatile void *mem, size_t size);
+
+/* Annotations expand to these functions, when Dynamic Annotations are enabled.
+   These functions are either implemented as no-op calls, if no Sanitizer is
+   attached, or provided with externally-linked implementations by a library
+   like ThreadSanitizer. */
+void AbslAnnotateIgnoreReadsBegin(const char *file, int line)
+    ABSL_ATTRIBUTE_IGNORE_READS_BEGIN;
+void AbslAnnotateIgnoreReadsEnd(const char *file, int line)
+    ABSL_ATTRIBUTE_IGNORE_READS_END;
+void AbslAnnotateIgnoreWritesBegin(const char *file, int line);
+void AbslAnnotateIgnoreWritesEnd(const char *file, int line);
+
+#if defined(ABSL_ANNOTALYSIS_ENABLED)
+/* When Annotalysis is enabled without Dynamic Annotations, the use of
+   static-inline functions allows the annotations to be read at compile-time,
+   while still letting the compiler elide the functions from the final build.
+
+   TODO(delesley) -- The exclusive lock here ignores writes as well, but
+   allows IGNORE_READS_AND_WRITES to work properly. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line)
+    ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
+static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line)
+    ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
+static inline void AbslStaticAnnotateIgnoreWritesBegin(
+    const char *file, int line) { (void)file; (void)line; }
+static inline void AbslStaticAnnotateIgnoreWritesEnd(
+    const char *file, int line) { (void)file; (void)line; }
+#pragma GCC diagnostic pop
+#endif
+
+/* Return non-zero value if running under valgrind.
+
+  If "valgrind.h" is included into dynamic_annotations.cc,
+  the regular valgrind mechanism will be used.
+  See http://valgrind.org/docs/manual/manual-core-adv.html about
+  RUNNING_ON_VALGRIND and other valgrind "client requests".
+  The file "valgrind.h" may be obtained by doing
+     svn co svn://svn.valgrind.org/valgrind/trunk/include
+
+  If for some reason you can't use "valgrind.h" or want to fake valgrind,
+  there are two ways to make this function return non-zero:
+    - Use environment variable: export RUNNING_ON_VALGRIND=1
+    - Make your tool intercept the function AbslRunningOnValgrind() and
+      change its return value.
+ */
+int AbslRunningOnValgrind(void);
+
+/* AbslValgrindSlowdown returns:
+    * 1.0, if (AbslRunningOnValgrind() == 0)
+    * 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
+    * atof(getenv("VALGRIND_SLOWDOWN")) otherwise
+   This function can be used to scale timeout values:
+   EXAMPLE:
+   for (;;) {
+     DoExpensiveBackgroundTask();
+     SleepForSeconds(5 * AbslValgrindSlowdown());
+   }
+ */
+double AbslValgrindSlowdown(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+     Instead of doing
+        ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+        ... = x;
+        ABSL_ANNOTATE_IGNORE_READS_END();
+     one can use
+        ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); */
+#if defined(__cplusplus) && defined(ABSL_ANNOTATIONS_ENABLED)
+template <typename T>
+inline T ABSL_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
+  ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+  T res = x;
+  ABSL_ANNOTATE_IGNORE_READS_END();
+  return res;
+  }
+#else
+  #define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
+#endif
+
+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+  /* Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+  #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)        \
+    namespace {                                                       \
+      class static_var ## _annotator {                                \
+       public:                                                        \
+        static_var ## _annotator() {                                  \
+          ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var,                     \
+                                      sizeof(static_var),             \
+            # static_var ": " description);                           \
+        }                                                             \
+      };                                                              \
+      static static_var ## _annotator the ## static_var ## _annotator;\
+    }  // namespace
+#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+  #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)  /* empty */
+#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
+
+#ifdef ADDRESS_SANITIZER
+/* Describe the current state of a contiguous container such as e.g.
+ * std::vector or std::string. For more details see
+ * sanitizer/common_interface_defs.h, which is provided by the compiler. */
+#include <sanitizer/common_interface_defs.h>
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+  __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name)         \
+  struct { char x[8] __attribute__ ((aligned (8))); } name
+#else
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name)
+#endif  // ADDRESS_SANITIZER
+
+/* Undefine the macros intended only in this file. */
+#undef ABSL_ANNOTALYSIS_ENABLED
+#undef ABSL_ANNOTATIONS_ENABLED
+#undef ABSL_ATTRIBUTE_IGNORE_READS_BEGIN
+#undef ABSL_ATTRIBUTE_IGNORE_READS_END
+
+#endif  /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
new file mode 100644
index 0000000..97c8d6f
--- /dev/null
+++ b/absl/base/exception_safety_testing_test.cc
@@ -0,0 +1,942 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/exception_safety_testing.h"
+
+#include <cstddef>
+#include <exception>
+#include <iostream>
+#include <list>
+#include <type_traits>
+#include <vector>
+
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+#include "absl/memory/memory.h"
+
+namespace testing {
+
+namespace {
+
+using ::testing::exceptions_internal::SetCountdown;
+using ::testing::exceptions_internal::TestException;
+using ::testing::exceptions_internal::UnsetCountdown;
+
+// EXPECT_NO_THROW can't inspect the thrown inspection in general.
+template <typename F>
+void ExpectNoThrow(const F& f) {
+  try {
+    f();
+  } catch (TestException e) {
+    ADD_FAILURE() << "Unexpected exception thrown from " << e.what();
+  }
+}
+
+TEST(ThrowingValueTest, Throws) {
+  SetCountdown();
+  EXPECT_THROW(ThrowingValue<> bomb, TestException);
+
+  // It's not guaranteed that every operator only throws *once*.  The default
+  // ctor only throws once, though, so use it to make sure we only throw when
+  // the countdown hits 0
+  SetCountdown(2);
+  ExpectNoThrow([]() { ThrowingValue<> bomb; });
+  ExpectNoThrow([]() { ThrowingValue<> bomb; });
+  EXPECT_THROW(ThrowingValue<> bomb, TestException);
+
+  UnsetCountdown();
+}
+
+// Tests that an operation throws when the countdown is at 0, doesn't throw when
+// the countdown doesn't hit 0, and doesn't modify the state of the
+// ThrowingValue if it throws
+template <typename F>
+void TestOp(const F& f) {
+  ExpectNoThrow(f);
+
+  SetCountdown();
+  EXPECT_THROW(f(), TestException);
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, ThrowingCtors) {
+  ThrowingValue<> bomb;
+
+  TestOp([]() { ThrowingValue<> bomb(1); });
+  TestOp([&]() { ThrowingValue<> bomb1 = bomb; });
+  TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
+}
+
+TEST(ThrowingValueTest, ThrowingAssignment) {
+  ThrowingValue<> bomb, bomb1;
+
+  TestOp([&]() { bomb = bomb1; });
+  TestOp([&]() { bomb = std::move(bomb1); });
+
+  // Test that when assignment throws, the assignment should fail (lhs != rhs)
+  // and strong guarantee fails (lhs != lhs_copy).
+  {
+    ThrowingValue<> lhs(39), rhs(42);
+    ThrowingValue<> lhs_copy(lhs);
+    SetCountdown();
+    EXPECT_THROW(lhs = rhs, TestException);
+    UnsetCountdown();
+    EXPECT_NE(lhs, rhs);
+    EXPECT_NE(lhs_copy, lhs);
+  }
+  {
+    ThrowingValue<> lhs(39), rhs(42);
+    ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);
+    SetCountdown();
+    EXPECT_THROW(lhs = std::move(rhs), TestException);
+    UnsetCountdown();
+    EXPECT_NE(lhs, rhs_copy);
+    EXPECT_NE(lhs_copy, lhs);
+  }
+}
+
+TEST(ThrowingValueTest, ThrowingComparisons) {
+  ThrowingValue<> bomb1, bomb2;
+  TestOp([&]() { return bomb1 == bomb2; });
+  TestOp([&]() { return bomb1 != bomb2; });
+  TestOp([&]() { return bomb1 < bomb2; });
+  TestOp([&]() { return bomb1 <= bomb2; });
+  TestOp([&]() { return bomb1 > bomb2; });
+  TestOp([&]() { return bomb1 >= bomb2; });
+}
+
+TEST(ThrowingValueTest, ThrowingArithmeticOps) {
+  ThrowingValue<> bomb1(1), bomb2(2);
+
+  TestOp([&bomb1]() { +bomb1; });
+  TestOp([&bomb1]() { -bomb1; });
+  TestOp([&bomb1]() { ++bomb1; });
+  TestOp([&bomb1]() { bomb1++; });
+  TestOp([&bomb1]() { --bomb1; });
+  TestOp([&bomb1]() { bomb1--; });
+
+  TestOp([&]() { bomb1 + bomb2; });
+  TestOp([&]() { bomb1 - bomb2; });
+  TestOp([&]() { bomb1* bomb2; });
+  TestOp([&]() { bomb1 / bomb2; });
+  TestOp([&]() { bomb1 << 1; });
+  TestOp([&]() { bomb1 >> 1; });
+}
+
+TEST(ThrowingValueTest, ThrowingLogicalOps) {
+  ThrowingValue<> bomb1, bomb2;
+
+  TestOp([&bomb1]() { !bomb1; });
+  TestOp([&]() { bomb1&& bomb2; });
+  TestOp([&]() { bomb1 || bomb2; });
+}
+
+TEST(ThrowingValueTest, ThrowingBitwiseOps) {
+  ThrowingValue<> bomb1, bomb2;
+
+  TestOp([&bomb1]() { ~bomb1; });
+  TestOp([&]() { bomb1& bomb2; });
+  TestOp([&]() { bomb1 | bomb2; });
+  TestOp([&]() { bomb1 ^ bomb2; });
+}
+
+TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
+  ThrowingValue<> bomb1(1), bomb2(2);
+
+  TestOp([&]() { bomb1 += bomb2; });
+  TestOp([&]() { bomb1 -= bomb2; });
+  TestOp([&]() { bomb1 *= bomb2; });
+  TestOp([&]() { bomb1 /= bomb2; });
+  TestOp([&]() { bomb1 %= bomb2; });
+  TestOp([&]() { bomb1 &= bomb2; });
+  TestOp([&]() { bomb1 |= bomb2; });
+  TestOp([&]() { bomb1 ^= bomb2; });
+  TestOp([&]() { bomb1 *= bomb2; });
+}
+
+TEST(ThrowingValueTest, ThrowingStreamOps) {
+  ThrowingValue<> bomb;
+
+  TestOp([&]() {
+    std::istringstream stream;
+    stream >> bomb;
+  });
+  TestOp([&]() {
+    std::stringstream stream;
+    stream << bomb;
+  });
+}
+
+// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit
+// a nonfatal failure that contains the std::string representation of the Thrower
+TEST(ThrowingValueTest, StreamOpsOutput) {
+  using ::testing::TypeSpec;
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+
+  // Test default spec list (kEverythingThrows)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower = ThrowingValue<TypeSpec{}>;
+        auto thrower = Thrower(123);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<>(123)");
+
+  // Test with one item in spec list (kNoThrowCopy)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>;
+        auto thrower = Thrower(234);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<kNoThrowCopy>(234)");
+
+  // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower =
+            ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>;
+        auto thrower = Thrower(345);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<kNoThrowMove | kNoThrowNew>(345)");
+
+  // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>;
+        auto thrower = Thrower(456);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)");
+}
+
+template <typename F>
+void TestAllocatingOp(const F& f) {
+  ExpectNoThrow(f);
+
+  SetCountdown();
+  EXPECT_THROW(f(), exceptions_internal::TestBadAllocException);
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, ThrowingAllocatingOps) {
+  // make_unique calls unqualified operator new, so these exercise the
+  // ThrowingValue overloads.
+  TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
+  TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
+}
+
+TEST(ThrowingValueTest, NonThrowingMoveCtor) {
+  ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor;
+
+  SetCountdown();
+  ExpectNoThrow([&nothrow_ctor]() {
+    ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor);
+  });
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, NonThrowingMoveAssign) {
+  ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2;
+
+  SetCountdown();
+  ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
+    nothrow_assign1 = std::move(nothrow_assign2);
+  });
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, ThrowingCopyCtor) {
+  ThrowingValue<> tv;
+
+  TestOp([&]() { ThrowingValue<> tv_copy(tv); });
+}
+
+TEST(ThrowingValueTest, ThrowingCopyAssign) {
+  ThrowingValue<> tv1, tv2;
+
+  TestOp([&]() { tv1 = tv2; });
+}
+
+TEST(ThrowingValueTest, NonThrowingCopyCtor) {
+  ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor;
+
+  SetCountdown();
+  ExpectNoThrow([&nothrow_ctor]() {
+    ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor);
+  });
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, NonThrowingCopyAssign) {
+  ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2;
+
+  SetCountdown();
+  ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
+    nothrow_assign1 = nothrow_assign2;
+  });
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, ThrowingSwap) {
+  ThrowingValue<> bomb1, bomb2;
+  TestOp([&]() { std::swap(bomb1, bomb2); });
+}
+
+TEST(ThrowingValueTest, NonThrowingSwap) {
+  ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2;
+  ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
+}
+
+TEST(ThrowingValueTest, NonThrowingAllocation) {
+  ThrowingValue<TypeSpec::kNoThrowNew>* allocated;
+  ThrowingValue<TypeSpec::kNoThrowNew>* array;
+
+  ExpectNoThrow([&allocated]() {
+    allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1);
+    delete allocated;
+  });
+  ExpectNoThrow([&array]() {
+    array = new ThrowingValue<TypeSpec::kNoThrowNew>[2];
+    delete[] array;
+  });
+}
+
+TEST(ThrowingValueTest, NonThrowingDelete) {
+  auto* allocated = new ThrowingValue<>(1);
+  auto* array = new ThrowingValue<>[2];
+
+  SetCountdown();
+  ExpectNoThrow([allocated]() { delete allocated; });
+  SetCountdown();
+  ExpectNoThrow([array]() { delete[] array; });
+
+  UnsetCountdown();
+}
+
+using Storage =
+    absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
+
+TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
+  constexpr int kArrayLen = 2;
+  // We intentionally create extra space to store the tag allocated by placement
+  // new[].
+  constexpr int kStorageLen = 4;
+
+  Storage buf;
+  Storage array_buf[kStorageLen];
+  auto* placed = new (&buf) ThrowingValue<>(1);
+  auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];
+
+  SetCountdown();
+  ExpectNoThrow([placed, &buf]() {
+    placed->~ThrowingValue<>();
+    ThrowingValue<>::operator delete(placed, &buf);
+  });
+
+  SetCountdown();
+  ExpectNoThrow([&, placed_array]() {
+    for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
+    ThrowingValue<>::operator delete[](placed_array, &array_buf);
+  });
+
+  UnsetCountdown();
+}
+
+TEST(ThrowingValueTest, NonThrowingDestructor) {
+  auto* allocated = new ThrowingValue<>();
+
+  SetCountdown();
+  ExpectNoThrow([allocated]() { delete allocated; });
+  UnsetCountdown();
+}
+
+TEST(ThrowingBoolTest, ThrowingBool) {
+  ThrowingBool t = true;
+
+  // Test that it's contextually convertible to bool
+  if (t) {  // NOLINT(whitespace/empty_if_body)
+  }
+  EXPECT_TRUE(t);
+
+  TestOp([&]() { (void)!t; });
+}
+
+TEST(ThrowingAllocatorTest, MemoryManagement) {
+  // Just exercise the memory management capabilities under LSan to make sure we
+  // don't leak.
+  ThrowingAllocator<int> int_alloc;
+  int* ip = int_alloc.allocate(1);
+  int_alloc.deallocate(ip, 1);
+  int* i_array = int_alloc.allocate(2);
+  int_alloc.deallocate(i_array, 2);
+
+  ThrowingAllocator<ThrowingValue<>> tv_alloc;
+  ThrowingValue<>* ptr = tv_alloc.allocate(1);
+  tv_alloc.deallocate(ptr, 1);
+  ThrowingValue<>* tv_array = tv_alloc.allocate(2);
+  tv_alloc.deallocate(tv_array, 2);
+}
+
+TEST(ThrowingAllocatorTest, CallsGlobalNew) {
+  ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc;
+  ThrowingValue<>* ptr;
+
+  SetCountdown();
+  // This will only throw if ThrowingValue::new is called.
+  ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
+  nothrow_alloc.deallocate(ptr, 1);
+
+  UnsetCountdown();
+}
+
+TEST(ThrowingAllocatorTest, ThrowingConstructors) {
+  ThrowingAllocator<int> int_alloc;
+  int* ip = nullptr;
+
+  SetCountdown();
+  EXPECT_THROW(ip = int_alloc.allocate(1), TestException);
+  ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
+
+  *ip = 1;
+  SetCountdown();
+  EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
+  EXPECT_EQ(*ip, 1);
+  int_alloc.deallocate(ip, 1);
+
+  UnsetCountdown();
+}
+
+TEST(ThrowingAllocatorTest, NonThrowingConstruction) {
+  {
+    ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc;
+    int* ip = nullptr;
+
+    SetCountdown();
+    ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
+
+    SetCountdown();
+    ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
+
+    EXPECT_EQ(*ip, 2);
+    int_alloc.deallocate(ip, 1);
+
+    UnsetCountdown();
+  }
+
+  {
+    ThrowingAllocator<int> int_alloc;
+    int* ip = nullptr;
+    ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
+    ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
+    EXPECT_EQ(*ip, 2);
+    int_alloc.deallocate(ip, 1);
+  }
+
+  {
+    ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate>
+        nothrow_alloc;
+    ThrowingValue<>* ptr;
+
+    SetCountdown();
+    ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
+
+    SetCountdown();
+    ExpectNoThrow(
+        [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); });
+
+    EXPECT_EQ(ptr->Get(), 2);
+    nothrow_alloc.destroy(ptr);
+    nothrow_alloc.deallocate(ptr, 1);
+
+    UnsetCountdown();
+  }
+
+  {
+    ThrowingAllocator<int> a;
+
+    SetCountdown();
+    ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
+
+    SetCountdown();
+    ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
+
+    UnsetCountdown();
+  }
+}
+
+TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
+  ThrowingAllocator<int> a;
+  TestOp([]() { ThrowingAllocator<int> a; });
+  TestOp([&]() { a.select_on_container_copy_construction(); });
+}
+
+TEST(ThrowingAllocatorTest, State) {
+  ThrowingAllocator<int> a1, a2;
+  EXPECT_NE(a1, a2);
+
+  auto a3 = a1;
+  EXPECT_EQ(a3, a1);
+  int* ip = a1.allocate(1);
+  EXPECT_EQ(a3, a1);
+  a3.deallocate(ip, 1);
+  EXPECT_EQ(a3, a1);
+}
+
+TEST(ThrowingAllocatorTest, InVector) {
+  std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
+  for (int i = 0; i < 20; ++i) v.push_back({});
+  for (int i = 0; i < 20; ++i) v.pop_back();
+}
+
+TEST(ThrowingAllocatorTest, InList) {
+  std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
+  for (int i = 0; i < 20; ++i) l.push_back({});
+  for (int i = 0; i < 20; ++i) l.pop_back();
+  for (int i = 0; i < 20; ++i) l.push_front({});
+  for (int i = 0; i < 20; ++i) l.pop_front();
+}
+
+template <typename TesterInstance, typename = void>
+struct NullaryTestValidator : public std::false_type {};
+
+template <typename TesterInstance>
+struct NullaryTestValidator<
+    TesterInstance,
+    absl::void_t<decltype(std::declval<TesterInstance>().Test())>>
+    : public std::true_type {};
+
+template <typename TesterInstance>
+bool HasNullaryTest(const TesterInstance&) {
+  return NullaryTestValidator<TesterInstance>::value;
+}
+
+void DummyOp(void*) {}
+
+template <typename TesterInstance, typename = void>
+struct UnaryTestValidator : public std::false_type {};
+
+template <typename TesterInstance>
+struct UnaryTestValidator<
+    TesterInstance,
+    absl::void_t<decltype(std::declval<TesterInstance>().Test(DummyOp))>>
+    : public std::true_type {};
+
+template <typename TesterInstance>
+bool HasUnaryTest(const TesterInstance&) {
+  return UnaryTestValidator<TesterInstance>::value;
+}
+
+TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) {
+  using T = exceptions_internal::UninitializedT;
+  auto op = [](T* t) {};
+  auto inv = [](T*) { return testing::AssertionSuccess(); };
+  auto fac = []() { return absl::make_unique<T>(); };
+
+  // Test that providing operation and inveriants still does not allow for the
+  // the invocation of .Test() and .Test(op) because it lacks a factory
+  auto without_fac =
+      testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants(
+          inv, testing::strong_guarantee);
+  EXPECT_FALSE(HasNullaryTest(without_fac));
+  EXPECT_FALSE(HasUnaryTest(without_fac));
+
+  // Test that providing invariants and factory allows the invocation of
+  // .Test(op) but does not allow for .Test() because it lacks an operation
+  auto without_op = testing::MakeExceptionSafetyTester()
+                        .WithInvariants(inv, testing::strong_guarantee)
+                        .WithFactory(fac);
+  EXPECT_FALSE(HasNullaryTest(without_op));
+  EXPECT_TRUE(HasUnaryTest(without_op));
+
+  // Test that providing operation and factory still does not allow for the
+  // the invocation of .Test() and .Test(op) because it lacks invariants
+  auto without_inv =
+      testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
+  EXPECT_FALSE(HasNullaryTest(without_inv));
+  EXPECT_FALSE(HasUnaryTest(without_inv));
+}
+
+struct ExampleStruct {};
+
+std::unique_ptr<ExampleStruct> ExampleFunctionFactory() {
+  return absl::make_unique<ExampleStruct>();
+}
+
+void ExampleFunctionOperation(ExampleStruct*) {}
+
+testing::AssertionResult ExampleFunctionInvariant(ExampleStruct*) {
+  return testing::AssertionSuccess();
+}
+
+struct {
+  std::unique_ptr<ExampleStruct> operator()() const {
+    return ExampleFunctionFactory();
+  }
+} example_struct_factory;
+
+struct {
+  void operator()(ExampleStruct*) const {}
+} example_struct_operation;
+
+struct {
+  testing::AssertionResult operator()(ExampleStruct* example_struct) const {
+    return ExampleFunctionInvariant(example_struct);
+  }
+} example_struct_invariant;
+
+auto example_lambda_factory = []() { return ExampleFunctionFactory(); };
+
+auto example_lambda_operation = [](ExampleStruct*) {};
+
+auto example_lambda_invariant = [](ExampleStruct* example_struct) {
+  return ExampleFunctionInvariant(example_struct);
+};
+
+// Testing that function references, pointers, structs with operator() and
+// lambdas can all be used with ExceptionSafetyTester
+TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {
+  // function reference
+  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
+                  .WithFactory(ExampleFunctionFactory)
+                  .WithOperation(ExampleFunctionOperation)
+                  .WithInvariants(ExampleFunctionInvariant)
+                  .Test());
+
+  // function pointer
+  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
+                  .WithFactory(&ExampleFunctionFactory)
+                  .WithOperation(&ExampleFunctionOperation)
+                  .WithInvariants(&ExampleFunctionInvariant)
+                  .Test());
+
+  // struct
+  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
+                  .WithFactory(example_struct_factory)
+                  .WithOperation(example_struct_operation)
+                  .WithInvariants(example_struct_invariant)
+                  .Test());
+
+  // lambda
+  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
+                  .WithFactory(example_lambda_factory)
+                  .WithOperation(example_lambda_operation)
+                  .WithInvariants(example_lambda_invariant)
+                  .Test());
+}
+
+struct NonNegative {
+  bool operator==(const NonNegative& other) const { return i == other.i; }
+  int i;
+};
+
+testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) {
+  if (g->i >= 0) {
+    return testing::AssertionSuccess();
+  }
+  return testing::AssertionFailure()
+         << "i should be non-negative but is " << g->i;
+}
+
+struct {
+  template <typename T>
+  void operator()(T* t) const {
+    (*t)();
+  }
+} invoker;
+
+auto tester =
+    testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants(
+        CheckNonNegativeInvariants);
+auto strong_tester = tester.WithInvariants(testing::strong_guarantee);
+
+struct FailsBasicGuarantee : public NonNegative {
+  void operator()() {
+    --i;
+    ThrowingValue<> bomb;
+    ++i;
+  }
+};
+
+TEST(ExceptionCheckTest, BasicGuaranteeFailure) {
+  EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test());
+}
+
+struct FollowsBasicGuarantee : public NonNegative {
+  void operator()() {
+    ++i;
+    ThrowingValue<> bomb;
+  }
+};
+
+TEST(ExceptionCheckTest, BasicGuarantee) {
+  EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test());
+}
+
+TEST(ExceptionCheckTest, StrongGuaranteeFailure) {
+  EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test());
+  EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test());
+}
+
+struct BasicGuaranteeWithExtraInvariants : public NonNegative {
+  // After operator(), i is incremented.  If operator() throws, i is set to 9999
+  void operator()() {
+    int old_i = i;
+    i = kExceptionSentinel;
+    ThrowingValue<> bomb;
+    i = ++old_i;
+  }
+
+  static constexpr int kExceptionSentinel = 9999;
+};
+constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel;
+
+TEST(ExceptionCheckTest, BasicGuaranteeWithExtraInvariants) {
+  auto tester_with_val =
+      tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{});
+  EXPECT_TRUE(tester_with_val.Test());
+  EXPECT_TRUE(
+      tester_with_val
+          .WithInvariants([](BasicGuaranteeWithExtraInvariants* o) {
+            if (o->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) {
+              return testing::AssertionSuccess();
+            }
+            return testing::AssertionFailure()
+                   << "i should be "
+                   << BasicGuaranteeWithExtraInvariants::kExceptionSentinel
+                   << ", but is " << o->i;
+          })
+          .Test());
+}
+
+struct FollowsStrongGuarantee : public NonNegative {
+  void operator()() { ThrowingValue<> bomb; }
+};
+
+TEST(ExceptionCheckTest, StrongGuarantee) {
+  EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test());
+  EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test());
+}
+
+struct HasReset : public NonNegative {
+  void operator()() {
+    i = -1;
+    ThrowingValue<> bomb;
+    i = 1;
+  }
+
+  void reset() { i = 0; }
+};
+
+testing::AssertionResult CheckHasResetInvariants(HasReset* h) {
+  h->reset();
+  return testing::AssertionResult(h->i == 0);
+}
+
+TEST(ExceptionCheckTest, ModifyingChecker) {
+  auto set_to_1000 = [](FollowsBasicGuarantee* g) {
+    g->i = 1000;
+    return testing::AssertionSuccess();
+  };
+  auto is_1000 = [](FollowsBasicGuarantee* g) {
+    return testing::AssertionResult(g->i == 1000);
+  };
+  auto increment = [](FollowsStrongGuarantee* g) {
+    ++g->i;
+    return testing::AssertionSuccess();
+  };
+
+  EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{})
+                   .WithInvariants(set_to_1000, is_1000)
+                   .Test());
+  EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})
+                  .WithInvariants(increment)
+                  .Test());
+  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
+                  .WithInitialValue(HasReset{})
+                  .WithInvariants(CheckHasResetInvariants)
+                  .Test(invoker));
+}
+
+struct NonCopyable : public NonNegative {
+  NonCopyable(const NonCopyable&) = delete;
+  NonCopyable() : NonNegative{0} {}
+
+  void operator()() { ThrowingValue<> bomb; }
+};
+
+TEST(ExceptionCheckTest, NonCopyable) {
+  auto factory = []() { return absl::make_unique<NonCopyable>(); };
+  EXPECT_TRUE(tester.WithFactory(factory).Test());
+  EXPECT_TRUE(strong_tester.WithFactory(factory).Test());
+}
+
+struct NonEqualityComparable : public NonNegative {
+  void operator()() { ThrowingValue<> bomb; }
+
+  void ModifyOnThrow() {
+    ++i;
+    ThrowingValue<> bomb;
+    static_cast<void>(bomb);
+    --i;
+  }
+};
+
+TEST(ExceptionCheckTest, NonEqualityComparable) {
+  auto nec_is_strong = [](NonEqualityComparable* nec) {
+    return testing::AssertionResult(nec->i == NonEqualityComparable().i);
+  };
+  auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{})
+                               .WithInvariants(nec_is_strong);
+
+  EXPECT_TRUE(strong_nec_tester.Test());
+  EXPECT_FALSE(strong_nec_tester.Test(
+      [](NonEqualityComparable* n) { n->ModifyOnThrow(); }));
+}
+
+template <typename T>
+struct ExhaustivenessTester {
+  void operator()() {
+    successes |= 1;
+    T b1;
+    static_cast<void>(b1);
+    successes |= (1 << 1);
+    T b2;
+    static_cast<void>(b2);
+    successes |= (1 << 2);
+    T b3;
+    static_cast<void>(b3);
+    successes |= (1 << 3);
+  }
+
+  bool operator==(const ExhaustivenessTester<ThrowingValue<>>&) const {
+    return true;
+  }
+
+  static unsigned char successes;
+};
+
+struct {
+  template <typename T>
+  testing::AssertionResult operator()(ExhaustivenessTester<T>*) const {
+    return testing::AssertionSuccess();
+  }
+} CheckExhaustivenessTesterInvariants;
+
+template <typename T>
+unsigned char ExhaustivenessTester<T>::successes = 0;
+
+TEST(ExceptionCheckTest, Exhaustiveness) {
+  auto exhaust_tester = testing::MakeExceptionSafetyTester()
+                            .WithInvariants(CheckExhaustivenessTesterInvariants)
+                            .WithOperation(invoker);
+
+  EXPECT_TRUE(
+      exhaust_tester.WithInitialValue(ExhaustivenessTester<int>{}).Test());
+  EXPECT_EQ(ExhaustivenessTester<int>::successes, 0xF);
+
+  EXPECT_TRUE(
+      exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})
+          .WithInvariants(testing::strong_guarantee)
+          .Test());
+  EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);
+}
+
+struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {
+  LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) {
+    ++counter;
+    ThrowingValue<> v;
+    static_cast<void>(v);
+    --counter;
+  }
+  LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept
+      : TrackedObject(ABSL_PRETTY_FUNCTION) {}
+  static int counter;
+};
+int LeaksIfCtorThrows::counter = 0;
+
+TEST(ExceptionCheckTest, TestLeakyCtor) {
+  testing::TestThrowingCtor<LeaksIfCtorThrows>();
+  EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
+  LeaksIfCtorThrows::counter = 0;
+}
+
+struct Tracked : private exceptions_internal::TrackedObject {
+  Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
+};
+
+TEST(ConstructorTrackerTest, CreatedBefore) {
+  Tracked a, b, c;
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+}
+
+TEST(ConstructorTrackerTest, CreatedAfter) {
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+  Tracked a, b, c;
+}
+
+TEST(ConstructorTrackerTest, NotDestroyedAfter) {
+  absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
+  EXPECT_NONFATAL_FAILURE(
+      {
+        exceptions_internal::ConstructorTracker ct(
+            exceptions_internal::countdown);
+        new (&storage) Tracked;
+      },
+      "not destroyed");
+}
+
+TEST(ConstructorTrackerTest, DestroyedTwice) {
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+  EXPECT_NONFATAL_FAILURE(
+      {
+        Tracked t;
+        t.~Tracked();
+      },
+      "re-destroyed");
+}
+
+TEST(ConstructorTrackerTest, ConstructedTwice) {
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+  absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
+  EXPECT_NONFATAL_FAILURE(
+      {
+        new (&storage) Tracked;
+        new (&storage) Tracked;
+        reinterpret_cast<Tracked*>(&storage)->~Tracked();
+      },
+      "re-constructed");
+}
+
+TEST(ThrowingValueTraitsTest, RelationalOperators) {
+  ThrowingValue<> a, b;
+  EXPECT_TRUE((std::is_convertible<decltype(a == b), bool>::value));
+  EXPECT_TRUE((std::is_convertible<decltype(a != b), bool>::value));
+  EXPECT_TRUE((std::is_convertible<decltype(a < b), bool>::value));
+  EXPECT_TRUE((std::is_convertible<decltype(a <= b), bool>::value));
+  EXPECT_TRUE((std::is_convertible<decltype(a > b), bool>::value));
+  EXPECT_TRUE((std::is_convertible<decltype(a >= b), bool>::value));
+}
+
+TEST(ThrowingAllocatorTraitsTest, Assignablility) {
+  EXPECT_TRUE(std::is_move_assignable<ThrowingAllocator<int>>::value);
+  EXPECT_TRUE(std::is_copy_assignable<ThrowingAllocator<int>>::value);
+  EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value);
+  EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value);
+}
+
+}  // namespace
+
+}  // namespace testing
diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc
new file mode 100644
index 0000000..5499189
--- /dev/null
+++ b/absl/base/inline_variable_test.cc
@@ -0,0 +1,62 @@
+// Copyright 2017 The Abseil 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 <type_traits>
+
+#include "absl/base/internal/inline_variable.h"
+#include "absl/base/internal/inline_variable_testing.h"
+
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace inline_variable_testing_internal {
+namespace {
+
+TEST(InlineVariableTest, Constexpr) {
+  static_assert(inline_variable_foo.value == 5, "");
+  static_assert(other_inline_variable_foo.value == 5, "");
+  static_assert(inline_variable_int == 5, "");
+  static_assert(other_inline_variable_int == 5, "");
+}
+
+TEST(InlineVariableTest, DefaultConstructedIdentityEquality) {
+  EXPECT_EQ(get_foo_a().value, 5);
+  EXPECT_EQ(get_foo_b().value, 5);
+  EXPECT_EQ(&get_foo_a(), &get_foo_b());
+}
+
+TEST(InlineVariableTest, DefaultConstructedIdentityInequality) {
+  EXPECT_NE(&inline_variable_foo, &other_inline_variable_foo);
+}
+
+TEST(InlineVariableTest, InitializedIdentityEquality) {
+  EXPECT_EQ(get_int_a(), 5);
+  EXPECT_EQ(get_int_b(), 5);
+  EXPECT_EQ(&get_int_a(), &get_int_b());
+}
+
+TEST(InlineVariableTest, InitializedIdentityInequality) {
+  EXPECT_NE(&inline_variable_int, &other_inline_variable_int);
+}
+
+TEST(InlineVariableTest, FunPtrType) {
+  static_assert(
+      std::is_same<void(*)(),
+                   std::decay<decltype(inline_variable_fun_ptr)>::type>::value,
+      "");
+}
+
+}  // namespace
+}  // namespace inline_variable_testing_internal
+}  // namespace absl
diff --git a/absl/base/inline_variable_test_a.cc b/absl/base/inline_variable_test_a.cc
new file mode 100644
index 0000000..a3bf3b6
--- /dev/null
+++ b/absl/base/inline_variable_test_a.cc
@@ -0,0 +1,25 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/inline_variable_testing.h"
+
+namespace absl {
+namespace inline_variable_testing_internal {
+
+const Foo& get_foo_a() { return inline_variable_foo; }
+
+const int& get_int_a() { return inline_variable_int; }
+
+}  // namespace inline_variable_testing_internal
+}  // namespace absl
diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc
new file mode 100644
index 0000000..b4b9393
--- /dev/null
+++ b/absl/base/inline_variable_test_b.cc
@@ -0,0 +1,25 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/inline_variable_testing.h"
+
+namespace absl {
+namespace inline_variable_testing_internal {
+
+const Foo& get_foo_b() { return inline_variable_foo; }
+
+const int& get_int_b() { return inline_variable_int; }
+
+}  // namespace inline_variable_testing_internal
+}  // namespace absl
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h
new file mode 100644
index 0000000..b458511
--- /dev/null
+++ b/absl/base/internal/atomic_hook.h
@@ -0,0 +1,165 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
+#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+#ifdef _MSC_FULL_VER
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
+#else
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
+#endif
+
+namespace absl {
+namespace base_internal {
+
+template <typename T>
+class AtomicHook;
+
+// AtomicHook is a helper class, templatized on a raw function pointer type, for
+// implementing Abseil customization hooks.  It is a callable object that
+// dispatches to the registered hook.
+//
+// A default constructed object performs a no-op (and returns a default
+// constructed object) if no hook has been registered.
+//
+// Hooks can be pre-registered via constant initialization, for example,
+// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
+// and then changed at runtime via a call to Store().
+//
+// Reads and writes guarantee memory_order_acquire/memory_order_release
+// semantics.
+template <typename ReturnType, typename... Args>
+class AtomicHook<ReturnType (*)(Args...)> {
+ public:
+  using FnPtr = ReturnType (*)(Args...);
+
+  // Constructs an object that by default performs a no-op (and
+  // returns a default constructed object) when no hook as been registered.
+  constexpr AtomicHook() : AtomicHook(DummyFunction) {}
+
+  // Constructs an object that by default dispatches to/returns the
+  // pre-registered default_fn when no hook has been registered at runtime.
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : hook_(default_fn), default_fn_(default_fn) {}
+#else
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : hook_(kUninitialized), default_fn_(default_fn) {}
+#endif
+
+  // Stores the provided function pointer as the value for this hook.
+  //
+  // This is intended to be called once.  Multiple calls are legal only if the
+  // same function pointer is provided for each call.  The store is implemented
+  // as a memory_order_release operation, and read accesses are implemented as
+  // memory_order_acquire.
+  void Store(FnPtr fn) {
+    bool success = DoStore(fn);
+    static_cast<void>(success);
+    assert(success);
+  }
+
+  // Invokes the registered callback.  If no callback has yet been registered, a
+  // default-constructed object of the appropriate type is returned instead.
+  template <typename... CallArgs>
+  ReturnType operator()(CallArgs&&... args) const {
+    return DoLoad()(std::forward<CallArgs>(args)...);
+  }
+
+  // Returns the registered callback, or nullptr if none has been registered.
+  // Useful if client code needs to conditionalize behavior based on whether a
+  // callback was registered.
+  //
+  // Note that atomic_hook.Load()() and atomic_hook() have different semantics:
+  // operator()() will perform a no-op if no callback was registered, while
+  // Load()() will dereference a null function pointer.  Prefer operator()() to
+  // Load()() unless you must conditionalize behavior on whether a hook was
+  // registered.
+  FnPtr Load() const {
+    FnPtr ptr = DoLoad();
+    return (ptr == DummyFunction) ? nullptr : ptr;
+  }
+
+ private:
+  static ReturnType DummyFunction(Args...) {
+    return ReturnType();
+  }
+
+  // Current versions of MSVC (as of September 2017) have a broken
+  // implementation of std::atomic<T*>:  Its constructor attempts to do the
+  // equivalent of a reinterpret_cast in a constexpr context, which is not
+  // allowed.
+  //
+  // This causes an issue when building with LLVM under Windows.  To avoid this,
+  // we use a less-efficient, intptr_t-based implementation on Windows.
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER
+  // Return the stored value, or DummyFunction if no value has been stored.
+  FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
+
+  // Store the given value.  Returns false if a different value was already
+  // stored to this object.
+  bool DoStore(FnPtr fn) {
+    assert(fn);
+    FnPtr expected = default_fn_;
+    const bool store_succeeded = hook_.compare_exchange_strong(
+        expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
+    const bool same_value_already_stored = (expected == fn);
+    return store_succeeded || same_value_already_stored;
+  }
+
+  std::atomic<FnPtr> hook_;
+#else  // !ABSL_HAVE_WORKING_ATOMIC_POINTER
+  // Use a sentinel value unlikely to be the address of an actual function.
+  static constexpr intptr_t kUninitialized = 0;
+
+  static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
+                "intptr_t can't contain a function pointer");
+
+  FnPtr DoLoad() const {
+    const intptr_t value = hook_.load(std::memory_order_acquire);
+    if (value == kUninitialized) {
+      return default_fn_;
+    }
+    return reinterpret_cast<FnPtr>(value);
+  }
+
+  bool DoStore(FnPtr fn) {
+    assert(fn);
+    const auto value = reinterpret_cast<intptr_t>(fn);
+    intptr_t expected = kUninitialized;
+    const bool store_succeeded = hook_.compare_exchange_strong(
+        expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
+    const bool same_value_already_stored = (expected == value);
+    return store_succeeded || same_value_already_stored;
+  }
+
+  std::atomic<intptr_t> hook_;
+#endif
+
+  const FnPtr default_fn_;
+};
+
+#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
diff --git a/absl/base/internal/atomic_hook_test.cc b/absl/base/internal/atomic_hook_test.cc
new file mode 100644
index 0000000..cf74075
--- /dev/null
+++ b/absl/base/internal/atomic_hook_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2018 The Abseil 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 "absl/base/internal/atomic_hook.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+
+namespace {
+
+int value = 0;
+void TestHook(int x) { value = x; }
+
+TEST(AtomicHookTest, NoDefaultFunction) {
+  ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
+  value = 0;
+
+  // Test the default DummyFunction.
+  EXPECT_TRUE(hook.Load() == nullptr);
+  EXPECT_EQ(value, 0);
+  hook(1);
+  EXPECT_EQ(value, 0);
+
+  // Test a stored hook.
+  hook.Store(TestHook);
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 0);
+  hook(1);
+  EXPECT_EQ(value, 1);
+
+  // Calling Store() with the same hook should not crash.
+  hook.Store(TestHook);
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 1);
+  hook(2);
+  EXPECT_EQ(value, 2);
+}
+
+TEST(AtomicHookTest, WithDefaultFunction) {
+  // Set the default value to TestHook at compile-time.
+  ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
+      TestHook);
+  value = 0;
+
+  // Test the default value is TestHook.
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 0);
+  hook(1);
+  EXPECT_EQ(value, 1);
+
+  // Calling Store() with the same hook should not crash.
+  hook.Store(TestHook);
+  EXPECT_TRUE(hook.Load() == TestHook);
+  EXPECT_EQ(value, 1);
+  hook(2);
+  EXPECT_EQ(value, 2);
+}
+
+}  // namespace
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc
new file mode 100644
index 0000000..a742df0
--- /dev/null
+++ b/absl/base/internal/cycleclock.cc
@@ -0,0 +1,81 @@
+// Copyright 2017 The Abseil 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 implementation of CycleClock::Frequency.
+//
+// NOTE: only i386 and x86_64 have been well tested.
+// PPC, sparc, alpha, and ia64 are based on
+//    http://peter.kuscsik.com/wordpress/?p=14
+// with modifications by m3b.  See also
+//    https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
+
+#include "absl/base/internal/cycleclock.h"
+
+#include <chrono>  // NOLINT(build/c++11)
+
+#include "absl/base/internal/unscaledcycleclock.h"
+
+namespace absl {
+namespace base_internal {
+
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+
+namespace {
+
+#ifdef NDEBUG
+#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+// Not debug mode and the UnscaledCycleClock frequency is the CPU
+// frequency.  Scale the CycleClock to prevent overflow if someone
+// tries to represent the time as cycles since the Unix epoch.
+static constexpr int32_t kShift = 1;
+#else
+// Not debug mode and the UnscaledCycleClock isn't operating at the
+// raw CPU frequency. There is no need to do any scaling, so don't
+// needlessly sacrifice precision.
+static constexpr int32_t kShift = 0;
+#endif
+#else
+// In debug mode use a different shift to discourage depending on a
+// particular shift value.
+static constexpr int32_t kShift = 2;
+#endif
+
+static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
+
+}  // namespace
+
+int64_t CycleClock::Now() {
+  return base_internal::UnscaledCycleClock::Now() >> kShift;
+}
+
+double CycleClock::Frequency() {
+  return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
+}
+
+#else
+
+int64_t CycleClock::Now() {
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             std::chrono::steady_clock::now().time_since_epoch())
+      .count();
+}
+
+double CycleClock::Frequency() {
+  return 1e9;
+}
+
+#endif
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h
new file mode 100644
index 0000000..60e9715
--- /dev/null
+++ b/absl/base/internal/cycleclock.h
@@ -0,0 +1,77 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+
+// -----------------------------------------------------------------------------
+// File: cycleclock.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `CycleClock`, which yields the value and frequency
+// of a cycle counter that increments at a rate that is approximately constant.
+//
+// NOTE:
+//
+// The cycle counter frequency is not necessarily related to the core clock
+// frequency and should not be treated as such. That is, `CycleClock` cycles are
+// not necessarily "CPU cycles" and code should not rely on that behavior, even
+// if experimentally observed.
+//
+//
+// An arbitrary offset may have been added to the counter at power on.
+//
+// On some platforms, the rate and offset of the counter may differ
+// slightly when read from different CPUs of a multiprocessor. Usually,
+// we try to ensure that the operating system adjusts values periodically
+// so that values agree approximately.   If you need stronger guarantees,
+// consider using alternate interfaces.
+//
+// The CPU is not required to maintain the ordering of a cycle counter read
+// with respect to surrounding instructions.
+
+#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
+#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_
+
+#include <cstdint>
+
+namespace absl {
+namespace base_internal {
+
+// -----------------------------------------------------------------------------
+// CycleClock
+// -----------------------------------------------------------------------------
+class CycleClock {
+ public:
+  // CycleClock::Now()
+  //
+  // Returns the value of a cycle counter that counts at a rate that is
+  // approximately constant.
+  static int64_t Now();
+
+  // CycleClock::Frequency()
+  //
+  // Returns the amount by which `CycleClock::Now()` increases per second. Note
+  // that this value may not necessarily match the core CPU clock frequency.
+  static double Frequency();
+
+ private:
+  CycleClock() = delete;  // no instances
+  CycleClock(const CycleClock&) = delete;
+  CycleClock& operator=(const CycleClock&) = delete;
+};
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h
new file mode 100644
index 0000000..0426e11
--- /dev/null
+++ b/absl/base/internal/direct_mmap.h
@@ -0,0 +1,153 @@
+// Copyright 2017 The Abseil 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.
+//
+// Functions for directly invoking mmap() via syscall, avoiding the case where
+// mmap() has been locally overridden.
+
+#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
+#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
+
+#include "absl/base/config.h"
+
+#if ABSL_HAVE_MMAP
+
+#include <sys/mman.h>
+
+#ifdef __linux__
+
+#include <sys/types.h>
+#ifdef __BIONIC__
+#include <sys/syscall.h>
+#else
+#include <syscall.h>
+#endif
+
+#include <linux/unistd.h>
+#include <unistd.h>
+#include <cerrno>
+#include <cstdarg>
+#include <cstdint>
+
+#ifdef __mips__
+// Include definitions of the ABI currently in use.
+#ifdef __BIONIC__
+// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
+// definitions we need.
+#include <asm/sgidefs.h>
+#else
+#include <sgidefs.h>
+#endif  // __BIONIC__
+#endif  // __mips__
+
+// SYS_mmap and SYS_munmap are not defined in Android.
+#ifdef __BIONIC__
+extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
+#if defined(__NR_mmap) && !defined(SYS_mmap)
+#define SYS_mmap __NR_mmap
+#endif
+#ifndef SYS_munmap
+#define SYS_munmap __NR_munmap
+#endif
+#endif  // __BIONIC__
+
+namespace absl {
+namespace base_internal {
+
+// Platform specific logic extracted from
+// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
+inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
+                        off64_t offset) noexcept {
+#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
+    (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) ||                   \
+    (defined(__PPC__) && !defined(__PPC64__)) ||                             \
+    (defined(__s390__) && !defined(__s390x__))
+  // On these architectures, implement mmap with mmap2.
+  static int pagesize = 0;
+  if (pagesize == 0) {
+    pagesize = getpagesize();
+  }
+  if (offset < 0 || offset % pagesize != 0) {
+    errno = EINVAL;
+    return MAP_FAILED;
+  }
+#ifdef __BIONIC__
+  // SYS_mmap2 has problems on Android API level <= 16.
+  // Workaround by invoking __mmap2() instead.
+  return __mmap2(start, length, prot, flags, fd, offset / pagesize);
+#else
+  return reinterpret_cast<void*>(
+      syscall(SYS_mmap2, start, length, prot, flags, fd,
+              static_cast<off_t>(offset / pagesize)));
+#endif
+#elif defined(__s390x__)
+  // On s390x, mmap() arguments are passed in memory.
+  unsigned long buf[6] = {reinterpret_cast<unsigned long>(start),  // NOLINT
+                          static_cast<unsigned long>(length),      // NOLINT
+                          static_cast<unsigned long>(prot),        // NOLINT
+                          static_cast<unsigned long>(flags),       // NOLINT
+                          static_cast<unsigned long>(fd),          // NOLINT
+                          static_cast<unsigned long>(offset)};     // NOLINT
+  return reinterpret_cast<void*>(syscall(SYS_mmap, buf));
+#elif defined(__x86_64__)
+// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
+// We need to explicitly cast to an unsigned 64 bit type to avoid implicit
+// sign extension.  We can't cast pointers directly because those are
+// 32 bits, and gcc will dump ugly warnings about casting from a pointer
+// to an integer of a different size. We also need to make sure __off64_t
+// isn't truncated to 32-bits under x32.
+#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x))
+  return reinterpret_cast<void*>(
+      syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length),
+              MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags),
+              MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset)));
+#undef MMAP_SYSCALL_ARG
+#else  // Remaining 64-bit aritectures.
+  static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit");
+  return reinterpret_cast<void*>(
+      syscall(SYS_mmap, start, length, prot, flags, fd, offset));
+#endif
+}
+
+inline int DirectMunmap(void* start, size_t length) {
+  return static_cast<int>(syscall(SYS_munmap, start, length));
+}
+
+}  // namespace base_internal
+}  // namespace absl
+
+#else  // !__linux__
+
+// For non-linux platforms where we have mmap, just dispatch directly to the
+// actual mmap()/munmap() methods.
+
+namespace absl {
+namespace base_internal {
+
+inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
+                        off_t offset) {
+  return mmap(start, length, prot, flags, fd, offset);
+}
+
+inline int DirectMunmap(void* start, size_t length) {
+  return munmap(start, length);
+}
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // __linux__
+
+#endif  // ABSL_HAVE_MMAP
+
+#endif  // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h
new file mode 100644
index 0000000..edc10f1
--- /dev/null
+++ b/absl/base/internal/endian.h
@@ -0,0 +1,269 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_ENDIAN_H_
+#define ABSL_BASE_INTERNAL_ENDIAN_H_
+
+// The following guarantees declaration of the byte swap functions
+#ifdef _MSC_VER
+#include <stdlib.h>  // NOLINT(build/include)
+#elif defined(__APPLE__)
+// Mac OS X / Darwin features
+#include <libkern/OSByteOrder.h>
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#elif defined(__GLIBC__)
+#include <byteswap.h>  // IWYU pragma: export
+#endif
+
+#include <cstdint>
+#include "absl/base/config.h"
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+// Use compiler byte-swapping intrinsics if they are available.  32-bit
+// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
+// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
+// For simplicity, we enable them all only for GCC 4.8.0 or later.
+#if defined(__clang__) || \
+    (defined(__GNUC__) && \
+     ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
+inline uint64_t gbswap_64(uint64_t host_int) {
+  return __builtin_bswap64(host_int);
+}
+inline uint32_t gbswap_32(uint32_t host_int) {
+  return __builtin_bswap32(host_int);
+}
+inline uint16_t gbswap_16(uint16_t host_int) {
+  return __builtin_bswap16(host_int);
+}
+
+#elif defined(_MSC_VER)
+inline uint64_t gbswap_64(uint64_t host_int) {
+  return _byteswap_uint64(host_int);
+}
+inline uint32_t gbswap_32(uint32_t host_int) {
+  return _byteswap_ulong(host_int);
+}
+inline uint16_t gbswap_16(uint16_t host_int) {
+  return _byteswap_ushort(host_int);
+}
+
+#elif defined(__APPLE__)
+inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); }
+inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); }
+inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); }
+
+#else
+inline uint64_t gbswap_64(uint64_t host_int) {
+#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
+  // Adapted from /usr/include/byteswap.h.  Not available on Mac.
+  if (__builtin_constant_p(host_int)) {
+    return __bswap_constant_64(host_int);
+  } else {
+    register uint64_t result;
+    __asm__("bswap %0" : "=r"(result) : "0"(host_int));
+    return result;
+  }
+#elif defined(__GLIBC__)
+  return bswap_64(host_int);
+#else
+  return (((x & uint64_t{(0xFF}) << 56) |
+          ((x & uint64_t{(0xFF00}) << 40) |
+          ((x & uint64_t{(0xFF0000}) << 24) |
+          ((x & uint64_t{(0xFF000000}) << 8) |
+          ((x & uint64_t{(0xFF00000000}) >> 8) |
+          ((x & uint64_t{(0xFF0000000000}) >> 24) |
+          ((x & uint64_t{(0xFF000000000000}) >> 40) |
+          ((x & uint64_t{(0xFF00000000000000}) >> 56));
+#endif  // bswap_64
+}
+
+inline uint32_t gbswap_32(uint32_t host_int) {
+#if defined(__GLIBC__)
+  return bswap_32(host_int);
+#else
+  return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) |
+          ((x & 0xFF000000) >> 24));
+#endif
+}
+
+inline uint16_t gbswap_16(uint16_t host_int) {
+#if defined(__GLIBC__)
+  return bswap_16(host_int);
+#else
+  return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)};
+#endif
+}
+
+#endif  // intrinics available
+
+#ifdef ABSL_IS_LITTLE_ENDIAN
+
+// Definitions for ntohl etc. that don't require us to include
+// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
+// than just #defining them because in debug mode, gcc doesn't
+// correctly handle the (rather involved) definitions of bswap_32.
+// gcc guarantees that inline functions are as fast as macros, so
+// this isn't a performance hit.
+inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
+inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
+inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
+
+#elif defined ABSL_IS_BIG_ENDIAN
+
+// These definitions are simpler on big-endian machines
+// These are functions instead of macros to avoid self-assignment warnings
+// on calls such as "i = ghtnol(i);".  This also provides type checking.
+inline uint16_t ghtons(uint16_t x) { return x; }
+inline uint32_t ghtonl(uint32_t x) { return x; }
+inline uint64_t ghtonll(uint64_t x) { return x; }
+
+#else
+#error \
+    "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
+       "ABSL_IS_LITTLE_ENDIAN must be defined"
+#endif  // byte order
+
+inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
+inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
+inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
+
+// Utilities to convert numbers between the current hosts's native byte
+// order and little-endian byte order
+//
+// Load/Store methods are alignment safe
+namespace little_endian {
+// Conversion functions.
+#ifdef ABSL_IS_LITTLE_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return x; }
+inline uint16_t ToHost16(uint16_t x) { return x; }
+
+inline uint32_t FromHost32(uint32_t x) { return x; }
+inline uint32_t ToHost32(uint32_t x) { return x; }
+
+inline uint64_t FromHost64(uint64_t x) { return x; }
+inline uint64_t ToHost64(uint64_t x) { return x; }
+
+inline constexpr bool IsLittleEndian() { return true; }
+
+#elif defined ABSL_IS_BIG_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
+inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
+
+inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
+inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
+
+inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
+inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
+
+inline constexpr bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+// Functions to do unaligned loads and stores in little-endian order.
+inline uint16_t Load16(const void *p) {
+  return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
+}
+
+inline void Store16(void *p, uint16_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
+}
+
+inline uint32_t Load32(const void *p) {
+  return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
+}
+
+inline void Store32(void *p, uint32_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
+}
+
+inline uint64_t Load64(const void *p) {
+  return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
+}
+
+inline void Store64(void *p, uint64_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
+}
+
+}  // namespace little_endian
+
+// Utilities to convert numbers between the current hosts's native byte
+// order and big-endian byte order (same as network byte order)
+//
+// Load/Store methods are alignment safe
+namespace big_endian {
+#ifdef ABSL_IS_LITTLE_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
+inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
+
+inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
+inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
+
+inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
+inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
+
+inline constexpr bool IsLittleEndian() { return true; }
+
+#elif defined ABSL_IS_BIG_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return x; }
+inline uint16_t ToHost16(uint16_t x) { return x; }
+
+inline uint32_t FromHost32(uint32_t x) { return x; }
+inline uint32_t ToHost32(uint32_t x) { return x; }
+
+inline uint64_t FromHost64(uint64_t x) { return x; }
+inline uint64_t ToHost64(uint64_t x) { return x; }
+
+inline constexpr bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+// Functions to do unaligned loads and stores in big-endian order.
+inline uint16_t Load16(const void *p) {
+  return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
+}
+
+inline void Store16(void *p, uint16_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
+}
+
+inline uint32_t Load32(const void *p) {
+  return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
+}
+
+inline void Store32(void *p, uint32_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
+}
+
+inline uint64_t Load64(const void *p) {
+  return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
+}
+
+inline void Store64(void *p, uint64_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
+}
+
+}  // namespace big_endian
+
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_ENDIAN_H_
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc
new file mode 100644
index 0000000..f3ff4b3
--- /dev/null
+++ b/absl/base/internal/endian_test.cc
@@ -0,0 +1,279 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/endian.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+#include <random>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace absl {
+namespace {
+
+const uint64_t kInitialNumber{0x0123456789abcdef};
+const uint64_t k64Value{kInitialNumber};
+const uint32_t k32Value{0x01234567};
+const uint16_t k16Value{0x0123};
+const int kNumValuesToTest = 1000000;
+const int kRandomSeed = 12345;
+
+#ifdef ABSL_IS_BIG_ENDIAN
+const uint64_t kInitialInNetworkOrder{kInitialNumber};
+const uint64_t k64ValueLE{0xefcdab8967452301};
+const uint32_t k32ValueLE{0x67452301};
+const uint16_t k16ValueLE{0x2301};
+const uint8_t k8ValueLE{k8Value};
+const uint64_t k64IValueLE{0xefcdab89674523a1};
+const uint32_t k32IValueLE{0x67452391};
+const uint16_t k16IValueLE{0x85ff};
+const uint8_t k8IValueLE{0xff};
+const uint64_t kDoubleValueLE{0x6e861bf0f9210940};
+const uint32_t kFloatValueLE{0xd00f4940};
+const uint8_t kBoolValueLE{0x1};
+
+const uint64_t k64ValueBE{kInitialNumber};
+const uint32_t k32ValueBE{k32Value};
+const uint16_t k16ValueBE{k16Value};
+const uint8_t k8ValueBE{k8Value};
+const uint64_t k64IValueBE{0xa123456789abcdef};
+const uint32_t k32IValueBE{0x91234567};
+const uint16_t k16IValueBE{0xff85};
+const uint8_t k8IValueBE{0xff};
+const uint64_t kDoubleValueBE{0x400921f9f01b866e};
+const uint32_t kFloatValueBE{0x40490fd0};
+const uint8_t kBoolValueBE{0x1};
+#elif defined ABSL_IS_LITTLE_ENDIAN
+const uint64_t kInitialInNetworkOrder{0xefcdab8967452301};
+const uint64_t k64ValueLE{kInitialNumber};
+const uint32_t k32ValueLE{k32Value};
+const uint16_t k16ValueLE{k16Value};
+
+const uint64_t k64ValueBE{0xefcdab8967452301};
+const uint32_t k32ValueBE{0x67452301};
+const uint16_t k16ValueBE{0x2301};
+#endif
+
+template<typename T>
+std::vector<T> GenerateAllValuesForType() {
+  std::vector<T> result;
+  T next = std::numeric_limits<T>::min();
+  while (true) {
+    result.push_back(next);
+    if (next == std::numeric_limits<T>::max()) {
+      return result;
+    }
+    ++next;
+  }
+}
+
+template<typename T>
+std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) {
+  std::vector<T> result;
+  std::mt19937_64 rng(kRandomSeed);
+  for (size_t i = 0; i < numValuesToTest; ++i) {
+    result.push_back(rng());
+  }
+  return result;
+}
+
+void ManualByteSwap(char* bytes, int length) {
+  if (length == 1)
+    return;
+
+  EXPECT_EQ(0, length % 2);
+  for (int i = 0; i < length / 2; ++i) {
+    int j = (length - 1) - i;
+    using std::swap;
+    swap(bytes[i], bytes[j]);
+  }
+}
+
+template<typename T>
+inline T UnalignedLoad(const char* p) {
+  static_assert(
+      sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
+      "Unexpected type size");
+
+  switch (sizeof(T)) {
+    case 1: return *reinterpret_cast<const T*>(p);
+    case 2:
+      return ABSL_INTERNAL_UNALIGNED_LOAD16(p);
+    case 4:
+      return ABSL_INTERNAL_UNALIGNED_LOAD32(p);
+    case 8:
+      return ABSL_INTERNAL_UNALIGNED_LOAD64(p);
+    default:
+      // Suppresses invalid "not all control paths return a value" on MSVC
+      return {};
+  }
+}
+
+template <typename T, typename ByteSwapper>
+static void GBSwapHelper(const std::vector<T>& host_values_to_test,
+                         const ByteSwapper& byte_swapper) {
+  // Test byte_swapper against a manual byte swap.
+  for (typename std::vector<T>::const_iterator it = host_values_to_test.begin();
+       it != host_values_to_test.end(); ++it) {
+    T host_value = *it;
+
+    char actual_value[sizeof(host_value)];
+    memcpy(actual_value, &host_value, sizeof(host_value));
+    byte_swapper(actual_value);
+
+    char expected_value[sizeof(host_value)];
+    memcpy(expected_value, &host_value, sizeof(host_value));
+    ManualByteSwap(expected_value, sizeof(host_value));
+
+    ASSERT_EQ(0, memcmp(actual_value, expected_value, sizeof(host_value)))
+        << "Swap output for 0x" << std::hex << host_value << " does not match. "
+        << "Expected: 0x" << UnalignedLoad<T>(expected_value) << "; "
+        << "actual: 0x" <<  UnalignedLoad<T>(actual_value);
+  }
+}
+
+void Swap16(char* bytes) {
+  ABSL_INTERNAL_UNALIGNED_STORE16(
+      bytes, gbswap_16(ABSL_INTERNAL_UNALIGNED_LOAD16(bytes)));
+}
+
+void Swap32(char* bytes) {
+  ABSL_INTERNAL_UNALIGNED_STORE32(
+      bytes, gbswap_32(ABSL_INTERNAL_UNALIGNED_LOAD32(bytes)));
+}
+
+void Swap64(char* bytes) {
+  ABSL_INTERNAL_UNALIGNED_STORE64(
+      bytes, gbswap_64(ABSL_INTERNAL_UNALIGNED_LOAD64(bytes)));
+}
+
+TEST(EndianessTest, Uint16) {
+  GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16);
+}
+
+TEST(EndianessTest, Uint32) {
+  GBSwapHelper(GenerateRandomIntegers<uint32_t>(kNumValuesToTest), &Swap32);
+}
+
+TEST(EndianessTest, Uint64) {
+  GBSwapHelper(GenerateRandomIntegers<uint64_t>(kNumValuesToTest), &Swap64);
+}
+
+TEST(EndianessTest, ghtonll_gntohll) {
+  // Test that absl::ghtonl compiles correctly
+  uint32_t test = 0x01234567;
+  EXPECT_EQ(absl::gntohl(absl::ghtonl(test)), test);
+
+  uint64_t comp = absl::ghtonll(kInitialNumber);
+  EXPECT_EQ(comp, kInitialInNetworkOrder);
+  comp = absl::gntohll(kInitialInNetworkOrder);
+  EXPECT_EQ(comp, kInitialNumber);
+
+  // Test that htonll and ntohll are each others' inverse functions on a
+  // somewhat assorted batch of numbers. 37 is chosen to not be anything
+  // particularly nice base 2.
+  uint64_t value = 1;
+  for (int i = 0; i < 100; ++i) {
+    comp = absl::ghtonll(absl::gntohll(value));
+    EXPECT_EQ(value, comp);
+    comp = absl::gntohll(absl::ghtonll(value));
+    EXPECT_EQ(value, comp);
+    value *= 37;
+  }
+}
+
+TEST(EndianessTest, little_endian) {
+  // Check little_endian uint16_t.
+  uint64_t comp = little_endian::FromHost16(k16Value);
+  EXPECT_EQ(comp, k16ValueLE);
+  comp = little_endian::ToHost16(k16ValueLE);
+  EXPECT_EQ(comp, k16Value);
+
+  // Check little_endian uint32_t.
+  comp = little_endian::FromHost32(k32Value);
+  EXPECT_EQ(comp, k32ValueLE);
+  comp = little_endian::ToHost32(k32ValueLE);
+  EXPECT_EQ(comp, k32Value);
+
+  // Check little_endian uint64_t.
+  comp = little_endian::FromHost64(k64Value);
+  EXPECT_EQ(comp, k64ValueLE);
+  comp = little_endian::ToHost64(k64ValueLE);
+  EXPECT_EQ(comp, k64Value);
+
+  // Check little-endian Load and store functions.
+  uint16_t u16Buf;
+  uint32_t u32Buf;
+  uint64_t u64Buf;
+
+  little_endian::Store16(&u16Buf, k16Value);
+  EXPECT_EQ(u16Buf, k16ValueLE);
+  comp = little_endian::Load16(&u16Buf);
+  EXPECT_EQ(comp, k16Value);
+
+  little_endian::Store32(&u32Buf, k32Value);
+  EXPECT_EQ(u32Buf, k32ValueLE);
+  comp = little_endian::Load32(&u32Buf);
+  EXPECT_EQ(comp, k32Value);
+
+  little_endian::Store64(&u64Buf, k64Value);
+  EXPECT_EQ(u64Buf, k64ValueLE);
+  comp = little_endian::Load64(&u64Buf);
+  EXPECT_EQ(comp, k64Value);
+}
+
+TEST(EndianessTest, big_endian) {
+  // Check big-endian Load and store functions.
+  uint16_t u16Buf;
+  uint32_t u32Buf;
+  uint64_t u64Buf;
+
+  unsigned char buffer[10];
+  big_endian::Store16(&u16Buf, k16Value);
+  EXPECT_EQ(u16Buf, k16ValueBE);
+  uint64_t comp = big_endian::Load16(&u16Buf);
+  EXPECT_EQ(comp, k16Value);
+
+  big_endian::Store32(&u32Buf, k32Value);
+  EXPECT_EQ(u32Buf, k32ValueBE);
+  comp = big_endian::Load32(&u32Buf);
+  EXPECT_EQ(comp, k32Value);
+
+  big_endian::Store64(&u64Buf, k64Value);
+  EXPECT_EQ(u64Buf, k64ValueBE);
+  comp = big_endian::Load64(&u64Buf);
+  EXPECT_EQ(comp, k64Value);
+
+  big_endian::Store16(buffer + 1, k16Value);
+  EXPECT_EQ(u16Buf, k16ValueBE);
+  comp = big_endian::Load16(buffer + 1);
+  EXPECT_EQ(comp, k16Value);
+
+  big_endian::Store32(buffer + 1, k32Value);
+  EXPECT_EQ(u32Buf, k32ValueBE);
+  comp = big_endian::Load32(buffer + 1);
+  EXPECT_EQ(comp, k32Value);
+
+  big_endian::Store64(buffer + 1, k64Value);
+  EXPECT_EQ(u64Buf, k64ValueBE);
+  comp = big_endian::Load64(buffer + 1);
+  EXPECT_EQ(comp, k64Value);
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc
new file mode 100644
index 0000000..f1d081f
--- /dev/null
+++ b/absl/base/internal/exception_safety_testing.cc
@@ -0,0 +1,71 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/exception_safety_testing.h"
+
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+
+namespace testing {
+
+exceptions_internal::NoThrowTag nothrow_ctor;
+
+exceptions_internal::StrongGuaranteeTagType strong_guarantee;
+
+namespace exceptions_internal {
+
+int countdown = -1;
+
+ConstructorTracker* ConstructorTracker::current_tracker_instance_ = nullptr;
+
+void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) {
+  if (countdown-- == 0) {
+    if (throw_bad_alloc) throw TestBadAllocException(msg);
+    throw TestException(msg);
+  }
+}
+
+testing::AssertionResult FailureMessage(const TestException& e,
+                                        int countdown) noexcept {
+  return testing::AssertionFailure() << "Exception thrown from " << e.what();
+}
+
+std::string GetSpecString(TypeSpec spec) {
+  std::string out;
+  absl::string_view sep;
+  const auto append = [&](absl::string_view s) {
+    absl::StrAppend(&out, sep, s);
+    sep = " | ";
+  };
+  if (static_cast<bool>(TypeSpec::kNoThrowCopy & spec)) {
+    append("kNoThrowCopy");
+  }
+  if (static_cast<bool>(TypeSpec::kNoThrowMove & spec)) {
+    append("kNoThrowMove");
+  }
+  if (static_cast<bool>(TypeSpec::kNoThrowNew & spec)) {
+    append("kNoThrowNew");
+  }
+  return out;
+}
+
+std::string GetSpecString(AllocSpec spec) {
+  return static_cast<bool>(AllocSpec::kNoThrowAllocate & spec)
+             ? "kNoThrowAllocate"
+             : "";
+}
+
+}  // namespace exceptions_internal
+
+}  // namespace testing
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
new file mode 100644
index 0000000..8c2f509
--- /dev/null
+++ b/absl/base/internal/exception_safety_testing.h
@@ -0,0 +1,1109 @@
+// Copyright 2017 The Abseil 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.
+
+// Utilities for testing exception-safety
+
+#ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
+#define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <initializer_list>
+#include <iosfwd>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/pretty_function.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/substitute.h"
+#include "absl/types/optional.h"
+
+namespace testing {
+
+enum class TypeSpec;
+enum class AllocSpec;
+
+constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) {
+  using T = absl::underlying_type_t<TypeSpec>;
+  return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b));
+}
+
+constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) {
+  using T = absl::underlying_type_t<TypeSpec>;
+  return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b));
+}
+
+constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) {
+  using T = absl::underlying_type_t<AllocSpec>;
+  return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b));
+}
+
+constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
+  using T = absl::underlying_type_t<AllocSpec>;
+  return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b));
+}
+
+namespace exceptions_internal {
+
+std::string GetSpecString(TypeSpec);
+std::string GetSpecString(AllocSpec);
+
+struct NoThrowTag {};
+struct StrongGuaranteeTagType {};
+
+// A simple exception class.  We throw this so that test code can catch
+// exceptions specifically thrown by ThrowingValue.
+class TestException {
+ public:
+  explicit TestException(absl::string_view msg) : msg_(msg) {}
+  virtual ~TestException() {}
+  virtual const char* what() const noexcept { return msg_.c_str(); }
+
+ private:
+  std::string msg_;
+};
+
+// TestBadAllocException exists because allocation functions must throw an
+// exception which can be caught by a handler of std::bad_alloc.  We use a child
+// class of std::bad_alloc so we can customise the error message, and also
+// derive from TestException so we don't accidentally end up catching an actual
+// bad_alloc exception in TestExceptionSafety.
+class TestBadAllocException : public std::bad_alloc, public TestException {
+ public:
+  explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {}
+  using TestException::what;
+};
+
+extern int countdown;
+
+// Allows the countdown variable to be set manually (defaulting to the initial
+// value of 0)
+inline void SetCountdown(int i = 0) { countdown = i; }
+// Sets the countdown to the terminal value -1
+inline void UnsetCountdown() { SetCountdown(-1); }
+
+void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
+
+testing::AssertionResult FailureMessage(const TestException& e,
+                                        int countdown) noexcept;
+
+struct TrackedAddress {
+  bool is_alive;
+  std::string description;
+};
+
+// Inspects the constructions and destructions of anything inheriting from
+// TrackedObject. This allows us to safely "leak" TrackedObjects, as
+// ConstructorTracker will destroy everything left over in its destructor.
+class ConstructorTracker {
+ public:
+  explicit ConstructorTracker(int count) : countdown_(count) {
+    assert(current_tracker_instance_ == nullptr);
+    current_tracker_instance_ = this;
+  }
+
+  ~ConstructorTracker() {
+    assert(current_tracker_instance_ == this);
+    current_tracker_instance_ = nullptr;
+
+    for (auto& it : address_map_) {
+      void* address = it.first;
+      TrackedAddress& tracked_address = it.second;
+      if (tracked_address.is_alive) {
+        ADD_FAILURE() << "Object at address " << address
+                      << " with countdown of " << countdown_
+                      << " was not destroyed [" << tracked_address.description
+                      << "]";
+      }
+    }
+  }
+
+  static void ObjectConstructed(void* address, std::string description) {
+    if (!CurrentlyTracking()) return;
+
+    TrackedAddress& tracked_address =
+        current_tracker_instance_->address_map_[address];
+    if (tracked_address.is_alive) {
+      ADD_FAILURE() << "Object at address " << address << " with countdown of "
+                    << current_tracker_instance_->countdown_
+                    << " was re-constructed. Previously: ["
+                    << tracked_address.description << "] Now: [" << description
+                    << "]";
+    }
+    tracked_address = {true, std::move(description)};
+  }
+
+  static void ObjectDestructed(void* address) {
+    if (!CurrentlyTracking()) return;
+
+    auto it = current_tracker_instance_->address_map_.find(address);
+    // Not tracked. Ignore.
+    if (it == current_tracker_instance_->address_map_.end()) return;
+
+    TrackedAddress& tracked_address = it->second;
+    if (!tracked_address.is_alive) {
+      ADD_FAILURE() << "Object at address " << address << " with countdown of "
+                    << current_tracker_instance_->countdown_
+                    << " was re-destroyed or created prior to construction "
+                    << "tracking [" << tracked_address.description << "]";
+    }
+    tracked_address.is_alive = false;
+  }
+
+ private:
+  static bool CurrentlyTracking() {
+    return current_tracker_instance_ != nullptr;
+  }
+
+  std::unordered_map<void*, TrackedAddress> address_map_;
+  int countdown_;
+
+  static ConstructorTracker* current_tracker_instance_;
+};
+
+class TrackedObject {
+ public:
+  TrackedObject(const TrackedObject&) = delete;
+  TrackedObject(TrackedObject&&) = delete;
+
+ protected:
+  explicit TrackedObject(std::string description) {
+    ConstructorTracker::ObjectConstructed(this, std::move(description));
+  }
+
+  ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); }
+};
+
+template <typename Factory, typename Operation, typename Invariant>
+absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
+    const Factory& factory, const Operation& operation, int count,
+    const Invariant& invariant) {
+  auto t_ptr = factory();
+  absl::optional<testing::AssertionResult> current_res;
+  SetCountdown(count);
+  try {
+    operation(t_ptr.get());
+  } catch (const exceptions_internal::TestException& e) {
+    current_res.emplace(invariant(t_ptr.get()));
+    if (!current_res.value()) {
+      *current_res << e.what() << " failed invariant check";
+    }
+  }
+  UnsetCountdown();
+  return current_res;
+}
+
+template <typename Factory, typename Operation>
+absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
+    const Factory& factory, const Operation& operation, int count,
+    StrongGuaranteeTagType) {
+  using TPtr = typename decltype(factory())::pointer;
+  auto t_is_strong = [&](TPtr t) { return *t == *factory(); };
+  return TestSingleInvariantAtCountdownImpl(factory, operation, count,
+                                            t_is_strong);
+}
+
+template <typename Factory, typename Operation, typename Invariant>
+int TestSingleInvariantAtCountdown(
+    const Factory& factory, const Operation& operation, int count,
+    const Invariant& invariant,
+    absl::optional<testing::AssertionResult>* reduced_res) {
+  // If reduced_res is empty, it means the current call to
+  // TestSingleInvariantAtCountdown(...) is the first test being run so we do
+  // want to run it. Alternatively, if it's not empty (meaning a previous test
+  // has run) we want to check if it passed. If the previous test did pass, we
+  // want to contine running tests so we do want to run the current one. If it
+  // failed, we want to short circuit so as not to overwrite the AssertionResult
+  // output. If that's the case, we do not run the current test and instead we
+  // simply return.
+  if (!reduced_res->has_value() || reduced_res->value()) {
+    *reduced_res = TestSingleInvariantAtCountdownImpl(factory, operation, count,
+                                                      invariant);
+  }
+  return 0;
+}
+
+template <typename Factory, typename Operation, typename... Invariants>
+inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown(
+    const Factory& factory, const Operation& operation, int count,
+    const Invariants&... invariants) {
+  absl::optional<testing::AssertionResult> reduced_res;
+
+  // Run each checker, short circuiting after the first failure
+  int dummy[] = {
+      0, (TestSingleInvariantAtCountdown(factory, operation, count, invariants,
+                                         &reduced_res))...};
+  static_cast<void>(dummy);
+  return reduced_res;
+}
+
+}  // namespace exceptions_internal
+
+extern exceptions_internal::NoThrowTag nothrow_ctor;
+
+extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
+
+// A test class which is convertible to bool.  The conversion can be
+// instrumented to throw at a controlled time.
+class ThrowingBool {
+ public:
+  ThrowingBool(bool b) noexcept : b_(b) {}  // NOLINT(runtime/explicit)
+  operator bool() const {                   // NOLINT
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return b_;
+  }
+
+ private:
+  bool b_;
+};
+
+/*
+ * Configuration enum for the ThrowingValue type that defines behavior for the
+ * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer
+ * constructor from throwing.
+ *
+ * kEverythingThrows: Every operation can throw an exception
+ * kNoThrowCopy: Copy construction and copy assignment will not throw
+ * kNoThrowMove: Move construction and move assignment will not throw
+ * kNoThrowNew: Overloaded operators new and new[] will not throw
+ */
+enum class TypeSpec {
+  kEverythingThrows = 0,
+  kNoThrowCopy = 1,
+  kNoThrowMove = 1 << 1,
+  kNoThrowNew = 1 << 2,
+};
+
+/*
+ * A testing class instrumented to throw an exception at a controlled time.
+ *
+ * ThrowingValue implements a slightly relaxed version of the Regular concept --
+ * that is it's a value type with the expected semantics.  It also implements
+ * arithmetic operations.  It doesn't implement member and pointer operators
+ * like operator-> or operator[].
+ *
+ * ThrowingValue can be instrumented to have certain operations be noexcept by
+ * using compile-time bitfield template arguments.  That is, to make an
+ * ThrowingValue which has noexcept move construction/assignment and noexcept
+ * copy construction/assignment, use the following:
+ *   ThrowingValue<testing::kNoThrowMove | testing::kNoThrowCopy> my_thrwr{val};
+ */
+template <TypeSpec Spec = TypeSpec::kEverythingThrows>
+class ThrowingValue : private exceptions_internal::TrackedObject {
+  static constexpr bool IsSpecified(TypeSpec spec) {
+    return static_cast<bool>(Spec & spec);
+  }
+
+  static constexpr int kDefaultValue = 0;
+  static constexpr int kBadValue = 938550620;
+
+ public:
+  ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ = kDefaultValue;
+  }
+
+  ThrowingValue(const ThrowingValue& other) noexcept(
+      IsSpecified(TypeSpec::kNoThrowCopy))
+      : TrackedObject(GetInstanceString(other.dummy_)) {
+    if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
+      exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    }
+    dummy_ = other.dummy_;
+  }
+
+  ThrowingValue(ThrowingValue&& other) noexcept(
+      IsSpecified(TypeSpec::kNoThrowMove))
+      : TrackedObject(GetInstanceString(other.dummy_)) {
+    if (!IsSpecified(TypeSpec::kNoThrowMove)) {
+      exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    }
+    dummy_ = other.dummy_;
+  }
+
+  explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ = i;
+  }
+
+  ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept
+      : TrackedObject(GetInstanceString(i)), dummy_(i) {}
+
+  // absl expects nothrow destructors
+  ~ThrowingValue() noexcept = default;
+
+  ThrowingValue& operator=(const ThrowingValue& other) noexcept(
+      IsSpecified(TypeSpec::kNoThrowCopy)) {
+    dummy_ = kBadValue;
+    if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
+      exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    }
+    dummy_ = other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator=(ThrowingValue&& other) noexcept(
+      IsSpecified(TypeSpec::kNoThrowMove)) {
+    dummy_ = kBadValue;
+    if (!IsSpecified(TypeSpec::kNoThrowMove)) {
+      exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    }
+    dummy_ = other.dummy_;
+    return *this;
+  }
+
+  // Arithmetic Operators
+  ThrowingValue operator+(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator+() const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator-(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator-() const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(-dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue& operator++() {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    ++dummy_;
+    return *this;
+  }
+
+  ThrowingValue operator++(int) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    auto out = ThrowingValue(dummy_, nothrow_ctor);
+    ++dummy_;
+    return out;
+  }
+
+  ThrowingValue& operator--() {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    --dummy_;
+    return *this;
+  }
+
+  ThrowingValue operator--(int) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    auto out = ThrowingValue(dummy_, nothrow_ctor);
+    --dummy_;
+    return out;
+  }
+
+  ThrowingValue operator*(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator/(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator%(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator<<(int shift) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ << shift, nothrow_ctor);
+  }
+
+  ThrowingValue operator>>(int shift) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ >> shift, nothrow_ctor);
+  }
+
+  // Comparison Operators
+  // NOTE: We use `ThrowingBool` instead of `bool` because most STL
+  // types/containers requires T to be convertible to bool.
+  friend ThrowingBool operator==(const ThrowingValue& a,
+                                 const ThrowingValue& b) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return a.dummy_ == b.dummy_;
+  }
+  friend ThrowingBool operator!=(const ThrowingValue& a,
+                                 const ThrowingValue& b) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return a.dummy_ != b.dummy_;
+  }
+  friend ThrowingBool operator<(const ThrowingValue& a,
+                                const ThrowingValue& b) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return a.dummy_ < b.dummy_;
+  }
+  friend ThrowingBool operator<=(const ThrowingValue& a,
+                                 const ThrowingValue& b) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return a.dummy_ <= b.dummy_;
+  }
+  friend ThrowingBool operator>(const ThrowingValue& a,
+                                const ThrowingValue& b) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return a.dummy_ > b.dummy_;
+  }
+  friend ThrowingBool operator>=(const ThrowingValue& a,
+                                 const ThrowingValue& b) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return a.dummy_ >= b.dummy_;
+  }
+
+  // Logical Operators
+  ThrowingBool operator!() const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return !dummy_;
+  }
+
+  ThrowingBool operator&&(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return dummy_ && other.dummy_;
+  }
+
+  ThrowingBool operator||(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return dummy_ || other.dummy_;
+  }
+
+  // Bitwise Logical Operators
+  ThrowingValue operator~() const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(~dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator&(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator|(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
+  }
+
+  ThrowingValue operator^(const ThrowingValue& other) const {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
+  }
+
+  // Compound Assignment operators
+  ThrowingValue& operator+=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ += other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator-=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ -= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator*=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ *= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator/=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ /= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator%=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ %= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator&=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ &= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator|=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ |= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator^=(const ThrowingValue& other) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ ^= other.dummy_;
+    return *this;
+  }
+
+  ThrowingValue& operator<<=(int shift) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ <<= shift;
+    return *this;
+  }
+
+  ThrowingValue& operator>>=(int shift) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ >>= shift;
+    return *this;
+  }
+
+  // Pointer operators
+  void operator&() const = delete;  // NOLINT(runtime/operator)
+
+  // Stream operators
+  friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return os << GetInstanceString(tv.dummy_);
+  }
+
+  friend std::istream& operator>>(std::istream& is, const ThrowingValue&) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    return is;
+  }
+
+  // Memory management operators
+  // Args.. allows us to overload regular and placement new in one shot
+  template <typename... Args>
+  static void* operator new(size_t s, Args&&... args) noexcept(
+      IsSpecified(TypeSpec::kNoThrowNew)) {
+    if (!IsSpecified(TypeSpec::kNoThrowNew)) {
+      exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
+    }
+    return ::operator new(s, std::forward<Args>(args)...);
+  }
+
+  template <typename... Args>
+  static void* operator new[](size_t s, Args&&... args) noexcept(
+      IsSpecified(TypeSpec::kNoThrowNew)) {
+    if (!IsSpecified(TypeSpec::kNoThrowNew)) {
+      exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
+    }
+    return ::operator new[](s, std::forward<Args>(args)...);
+  }
+
+  // Abseil doesn't support throwing overloaded operator delete.  These are
+  // provided so a throwing operator-new can clean up after itself.
+  //
+  // We provide both regular and templated operator delete because if only the
+  // templated version is provided as we did with operator new, the compiler has
+  // no way of knowing which overload of operator delete to call. See
+  // http://en.cppreference.com/w/cpp/memory/new/operator_delete and
+  // http://en.cppreference.com/w/cpp/language/delete for the gory details.
+  void operator delete(void* p) noexcept { ::operator delete(p); }
+
+  template <typename... Args>
+  void operator delete(void* p, Args&&... args) noexcept {
+    ::operator delete(p, std::forward<Args>(args)...);
+  }
+
+  void operator delete[](void* p) noexcept { return ::operator delete[](p); }
+
+  template <typename... Args>
+  void operator delete[](void* p, Args&&... args) noexcept {
+    return ::operator delete[](p, std::forward<Args>(args)...);
+  }
+
+  // Non-standard access to the actual contained value.  No need for this to
+  // throw.
+  int& Get() noexcept { return dummy_; }
+  const int& Get() const noexcept { return dummy_; }
+
+ private:
+  static std::string GetInstanceString(int dummy) {
+    return absl::StrCat("ThrowingValue<",
+                        exceptions_internal::GetSpecString(Spec), ">(", dummy,
+                        ")");
+  }
+
+  int dummy_;
+};
+// While not having to do with exceptions, explicitly delete comma operator, to
+// make sure we don't use it on user-supplied types.
+template <TypeSpec Spec, typename T>
+void operator,(const ThrowingValue<Spec>&, T&&) = delete;
+template <TypeSpec Spec, typename T>
+void operator,(T&&, const ThrowingValue<Spec>&) = delete;
+
+/*
+ * Configuration enum for the ThrowingAllocator type that defines behavior for
+ * the lifetime of the instance.
+ *
+ * kEverythingThrows: Calls to the member functions may throw
+ * kNoThrowAllocate: Calls to the member functions will not throw
+ */
+enum class AllocSpec {
+  kEverythingThrows = 0,
+  kNoThrowAllocate = 1,
+};
+
+/*
+ * An allocator type which is instrumented to throw at a controlled time, or not
+ * to throw, using AllocSpec. The supported settings are the default of every
+ * function which is allowed to throw in a conforming allocator possibly
+ * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
+ * configuration macro.
+ */
+template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
+class ThrowingAllocator : private exceptions_internal::TrackedObject {
+  static constexpr bool IsSpecified(AllocSpec spec) {
+    return static_cast<bool>(Spec & spec);
+  }
+
+ public:
+  using pointer = T*;
+  using const_pointer = const T*;
+  using reference = T&;
+  using const_reference = const T&;
+  using void_pointer = void*;
+  using const_void_pointer = const void*;
+  using value_type = T;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  using is_nothrow =
+      std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
+  using propagate_on_container_copy_assignment = std::true_type;
+  using propagate_on_container_move_assignment = std::true_type;
+  using propagate_on_container_swap = std::true_type;
+  using is_always_equal = std::false_type;
+
+  ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
+    exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
+    dummy_ = std::make_shared<const int>(next_id_++);
+  }
+
+  template <typename U>
+  ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept  // NOLINT
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(other.State()) {}
+
+  // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
+  // allocator shall not exit via an exception, thus they are marked noexcept.
+  ThrowingAllocator(const ThrowingAllocator& other) noexcept
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(other.State()) {}
+
+  template <typename U>
+  ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept  // NOLINT
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(std::move(other.State())) {}
+
+  ThrowingAllocator(ThrowingAllocator&& other) noexcept
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(std::move(other.State())) {}
+
+  ~ThrowingAllocator() noexcept = default;
+
+  ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept {
+    dummy_ = other.State();
+    return *this;
+  }
+
+  template <typename U>
+  ThrowingAllocator& operator=(
+      const ThrowingAllocator<U, Spec>& other) noexcept {
+    dummy_ = other.State();
+    return *this;
+  }
+
+  template <typename U>
+  ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
+    dummy_ = std::move(other.State());
+    return *this;
+  }
+
+  template <typename U>
+  struct rebind {
+    using other = ThrowingAllocator<U, Spec>;
+  };
+
+  pointer allocate(size_type n) noexcept(
+      IsSpecified(AllocSpec::kNoThrowAllocate)) {
+    ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
+    return static_cast<pointer>(::operator new(n * sizeof(T)));
+  }
+
+  pointer allocate(size_type n, const_void_pointer) noexcept(
+      IsSpecified(AllocSpec::kNoThrowAllocate)) {
+    return allocate(n);
+  }
+
+  void deallocate(pointer ptr, size_type) noexcept {
+    ReadState();
+    ::operator delete(static_cast<void*>(ptr));
+  }
+
+  template <typename U, typename... Args>
+  void construct(U* ptr, Args&&... args) noexcept(
+      IsSpecified(AllocSpec::kNoThrowAllocate)) {
+    ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
+    ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
+  }
+
+  template <typename U>
+  void destroy(U* p) noexcept {
+    ReadState();
+    p->~U();
+  }
+
+  size_type max_size() const noexcept {
+    return std::numeric_limits<difference_type>::max() / sizeof(value_type);
+  }
+
+  ThrowingAllocator select_on_container_copy_construction() noexcept(
+      IsSpecified(AllocSpec::kNoThrowAllocate)) {
+    auto& out = *this;
+    ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
+    return out;
+  }
+
+  template <typename U>
+  bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
+    return dummy_ == other.dummy_;
+  }
+
+  template <typename U>
+  bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
+    return dummy_ != other.dummy_;
+  }
+
+  template <typename, AllocSpec>
+  friend class ThrowingAllocator;
+
+ private:
+  static std::string GetInstanceString(int dummy) {
+    return absl::StrCat("ThrowingAllocator<",
+                        exceptions_internal::GetSpecString(Spec), ">(", dummy,
+                        ")");
+  }
+
+  const std::shared_ptr<const int>& State() const { return dummy_; }
+  std::shared_ptr<const int>& State() { return dummy_; }
+
+  void ReadState() {
+    // we know that this will never be true, but the compiler doesn't, so this
+    // should safely force a read of the value.
+    if (*dummy_ < 0) std::abort();
+  }
+
+  void ReadStateAndMaybeThrow(absl::string_view msg) const {
+    if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
+      exceptions_internal::MaybeThrow(
+          absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
+    }
+  }
+
+  static int next_id_;
+  std::shared_ptr<const int> dummy_;
+};
+
+template <typename T, AllocSpec Spec>
+int ThrowingAllocator<T, Spec>::next_id_ = 0;
+
+// Tests for resource leaks by attempting to construct a T using args repeatedly
+// until successful, using the countdown method.  Side effects can then be
+// tested for resource leaks.
+template <typename T, typename... Args>
+void TestThrowingCtor(Args&&... args) {
+  struct Cleanup {
+    ~Cleanup() { exceptions_internal::UnsetCountdown(); }
+  } c;
+  for (int count = 0;; ++count) {
+    exceptions_internal::ConstructorTracker ct(count);
+    exceptions_internal::SetCountdown(count);
+    try {
+      T temp(std::forward<Args>(args)...);
+      static_cast<void>(temp);
+      break;
+    } catch (const exceptions_internal::TestException&) {
+    }
+  }
+}
+
+// Tests the nothrow guarantee of the provided nullary operation. If the an
+// exception is thrown, the result will be AssertionFailure(). Otherwise, it
+// will be AssertionSuccess().
+template <typename Operation>
+testing::AssertionResult TestNothrowOp(const Operation& operation) {
+  struct Cleanup {
+    Cleanup() { exceptions_internal::SetCountdown(); }
+    ~Cleanup() { exceptions_internal::UnsetCountdown(); }
+  } c;
+  try {
+    operation();
+    return testing::AssertionSuccess();
+  } catch (exceptions_internal::TestException) {
+    return testing::AssertionFailure()
+           << "TestException thrown during call to operation() when nothrow "
+              "guarantee was expected.";
+  } catch (...) {
+    return testing::AssertionFailure()
+           << "Unknown exception thrown during call to operation() when "
+              "nothrow guarantee was expected.";
+  }
+}
+
+namespace exceptions_internal {
+
+// Dummy struct for ExceptionSafetyTester<> partial state.
+struct UninitializedT {};
+
+template <typename T>
+class DefaultFactory {
+ public:
+  explicit DefaultFactory(const T& t) : t_(t) {}
+  std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); }
+
+ private:
+  T t_;
+};
+
+template <size_t LazyInvariantsCount, typename LazyFactory,
+          typename LazyOperation>
+using EnableIfTestable = typename absl::enable_if_t<
+    LazyInvariantsCount != 0 &&
+    !std::is_same<LazyFactory, UninitializedT>::value &&
+    !std::is_same<LazyOperation, UninitializedT>::value>;
+
+template <typename Factory = UninitializedT,
+          typename Operation = UninitializedT, typename... Invariants>
+class ExceptionSafetyTester;
+
+}  // namespace exceptions_internal
+
+exceptions_internal::ExceptionSafetyTester<> MakeExceptionSafetyTester();
+
+namespace exceptions_internal {
+
+/*
+ * Builds a tester object that tests if performing a operation on a T follows
+ * exception safety guarantees. Verification is done via invariant assertion
+ * callbacks applied to T instances post-throw.
+ *
+ * Template parameters for ExceptionSafetyTester:
+ *
+ * - Factory: The factory object (passed in via tester.WithFactory(...) or
+ *   tester.WithInitialValue(...)) must be invocable with the signature
+ *   `std::unique_ptr<T> operator()() const` where T is the type being tested.
+ *   It is used for reliably creating identical T instances to test on.
+ *
+ * - Operation: The operation object (passsed in via tester.WithOperation(...)
+ *   or tester.Test(...)) must be invocable with the signature
+ *   `void operator()(T*) const` where T is the type being tested. It is used
+ *   for performing steps on a T instance that may throw and that need to be
+ *   checked for exception safety. Each call to the operation will receive a
+ *   fresh T instance so it's free to modify and destroy the T instances as it
+ *   pleases.
+ *
+ * - Invariants...: The invariant assertion callback objects (passed in via
+ *   tester.WithInvariants(...)) must be invocable with the signature
+ *   `testing::AssertionResult operator()(T*) const` where T is the type being
+ *   tested. Invariant assertion callbacks are provided T instances post-throw.
+ *   They must return testing::AssertionSuccess when the type invariants of the
+ *   provided T instance hold. If the type invariants of the T instance do not
+ *   hold, they must return testing::AssertionFailure. Execution order of
+ *   Invariants... is unspecified. They will each individually get a fresh T
+ *   instance so they are free to modify and destroy the T instances as they
+ *   please.
+ */
+template <typename Factory, typename Operation, typename... Invariants>
+class ExceptionSafetyTester {
+ public:
+  /*
+   * Returns a new ExceptionSafetyTester with an included T factory based on the
+   * provided T instance. The existing factory will not be included in the newly
+   * created tester instance. The created factory returns a new T instance by
+   * copy-constructing the provided const T& t.
+   *
+   * Preconditions for tester.WithInitialValue(const T& t):
+   *
+   * - The const T& t object must be copy-constructible where T is the type
+   *   being tested. For non-copy-constructible objects, use the method
+   *   tester.WithFactory(...).
+   */
+  template <typename T>
+  ExceptionSafetyTester<DefaultFactory<T>, Operation, Invariants...>
+  WithInitialValue(const T& t) const {
+    return WithFactory(DefaultFactory<T>(t));
+  }
+
+  /*
+   * Returns a new ExceptionSafetyTester with the provided T factory included.
+   * The existing factory will not be included in the newly-created tester
+   * instance. This method is intended for use with types lacking a copy
+   * constructor. Types that can be copy-constructed should instead use the
+   * method tester.WithInitialValue(...).
+   */
+  template <typename NewFactory>
+  ExceptionSafetyTester<absl::decay_t<NewFactory>, Operation, Invariants...>
+  WithFactory(const NewFactory& new_factory) const {
+    return {new_factory, operation_, invariants_};
+  }
+
+  /*
+   * Returns a new ExceptionSafetyTester with the provided testable operation
+   * included. The existing operation will not be included in the newly created
+   * tester.
+   */
+  template <typename NewOperation>
+  ExceptionSafetyTester<Factory, absl::decay_t<NewOperation>, Invariants...>
+  WithOperation(const NewOperation& new_operation) const {
+    return {factory_, new_operation, invariants_};
+  }
+
+  /*
+   * Returns a new ExceptionSafetyTester with the provided MoreInvariants...
+   * combined with the Invariants... that were already included in the instance
+   * on which the method was called. Invariants... cannot be removed or replaced
+   * once added to an ExceptionSafetyTester instance. A fresh object must be
+   * created in order to get an empty Invariants... list.
+   *
+   * In addition to passing in custom invariant assertion callbacks, this method
+   * accepts `testing::strong_guarantee` as an argument which checks T instances
+   * post-throw against freshly created T instances via operator== to verify
+   * that any state changes made during the execution of the operation were
+   * properly rolled back.
+   */
+  template <typename... MoreInvariants>
+  ExceptionSafetyTester<Factory, Operation, Invariants...,
+                        absl::decay_t<MoreInvariants>...>
+  WithInvariants(const MoreInvariants&... more_invariants) const {
+    return {factory_, operation_,
+            std::tuple_cat(invariants_,
+                           std::tuple<absl::decay_t<MoreInvariants>...>(
+                               more_invariants...))};
+  }
+
+  /*
+   * Returns a testing::AssertionResult that is the reduced result of the
+   * exception safety algorithm. The algorithm short circuits and returns
+   * AssertionFailure after the first invariant callback returns an
+   * AssertionFailure. Otherwise, if all invariant callbacks return an
+   * AssertionSuccess, the reduced result is AssertionSuccess.
+   *
+   * The passed-in testable operation will not be saved in a new tester instance
+   * nor will it modify/replace the existing tester instance. This is useful
+   * when each operation being tested is unique and does not need to be reused.
+   *
+   * Preconditions for tester.Test(const NewOperation& new_operation):
+   *
+   * - May only be called after at least one invariant assertion callback and a
+   *   factory or initial value have been provided.
+   */
+  template <
+      typename NewOperation,
+      typename = EnableIfTestable<sizeof...(Invariants), Factory, NewOperation>>
+  testing::AssertionResult Test(const NewOperation& new_operation) const {
+    return TestImpl(new_operation, absl::index_sequence_for<Invariants...>());
+  }
+
+  /*
+   * Returns a testing::AssertionResult that is the reduced result of the
+   * exception safety algorithm. The algorithm short circuits and returns
+   * AssertionFailure after the first invariant callback returns an
+   * AssertionFailure. Otherwise, if all invariant callbacks return an
+   * AssertionSuccess, the reduced result is AssertionSuccess.
+   *
+   * Preconditions for tester.Test():
+   *
+   * - May only be called after at least one invariant assertion callback, a
+   *   factory or initial value and a testable operation have been provided.
+   */
+  template <typename LazyOperation = Operation,
+            typename =
+                EnableIfTestable<sizeof...(Invariants), Factory, LazyOperation>>
+  testing::AssertionResult Test() const {
+    return TestImpl(operation_, absl::index_sequence_for<Invariants...>());
+  }
+
+ private:
+  template <typename, typename, typename...>
+  friend class ExceptionSafetyTester;
+
+  friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester();
+
+  ExceptionSafetyTester() {}
+
+  ExceptionSafetyTester(const Factory& f, const Operation& o,
+                        const std::tuple<Invariants...>& i)
+      : factory_(f), operation_(o), invariants_(i) {}
+
+  template <typename SelectedOperation, size_t... Indices>
+  testing::AssertionResult TestImpl(const SelectedOperation& selected_operation,
+                                    absl::index_sequence<Indices...>) const {
+    // Starting from 0 and counting upwards until one of the exit conditions is
+    // hit...
+    for (int count = 0;; ++count) {
+      exceptions_internal::ConstructorTracker ct(count);
+
+      // Run the full exception safety test algorithm for the current countdown
+      auto reduced_res =
+          TestAllInvariantsAtCountdown(factory_, selected_operation, count,
+                                       std::get<Indices>(invariants_)...);
+      // If there is no value in the optional, no invariants were run because no
+      // exception was thrown. This means that the test is complete and the loop
+      // can exit successfully.
+      if (!reduced_res.has_value()) {
+        return testing::AssertionSuccess();
+      }
+      // If the optional is not empty and the value is falsy, an invariant check
+      // failed so the test must exit to propegate the failure.
+      if (!reduced_res.value()) {
+        return reduced_res.value();
+      }
+      // If the optional is not empty and the value is not falsy, it means
+      // exceptions were thrown but the invariants passed so the test must
+      // continue to run.
+    }
+  }
+
+  Factory factory_;
+  Operation operation_;
+  std::tuple<Invariants...> invariants_;
+};
+
+}  // namespace exceptions_internal
+
+/*
+ * Constructs an empty ExceptionSafetyTester. All ExceptionSafetyTester
+ * objects are immutable and all With[thing] mutation methods return new
+ * instances of ExceptionSafetyTester.
+ *
+ * In order to test a T for exception safety, a factory for that T, a testable
+ * operation, and at least one invariant callback returning an assertion
+ * result must be applied using the respective methods.
+ */
+inline exceptions_internal::ExceptionSafetyTester<>
+MakeExceptionSafetyTester() {
+  return {};
+}
+
+}  // namespace testing
+
+#endif  // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
diff --git a/absl/base/internal/exception_testing.h b/absl/base/internal/exception_testing.h
new file mode 100644
index 0000000..fd89a3f
--- /dev/null
+++ b/absl/base/internal/exception_testing.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Abseil 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.
+
+// Testing utilities for ABSL types which throw exceptions.
+
+#ifndef ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
+#define ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+// ABSL_BASE_INTERNAL_EXPECT_FAIL tests either for a specified thrown exception
+// if exceptions are enabled, or for death with a specified text in the error
+// message
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
+  EXPECT_THROW(expr, exception_t)
+
+#elif defined(__ANDROID__)
+// Android asserts do not log anywhere that gtest can currently inspect.
+// So we expect exit, but cannot match the message.
+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
+  EXPECT_DEATH(expr, ".*")
+#else
+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
+  EXPECT_DEATH(expr, text)
+
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
diff --git a/absl/base/internal/hide_ptr.h b/absl/base/internal/hide_ptr.h
new file mode 100644
index 0000000..45cf438
--- /dev/null
+++ b/absl/base/internal/hide_ptr.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Abseil 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 ABSL_BASE_INTERNAL_HIDE_PTR_H_
+#define ABSL_BASE_INTERNAL_HIDE_PTR_H_
+
+#include <cstdint>
+
+namespace absl {
+namespace base_internal {
+
+// Arbitrary value with high bits set. Xor'ing with it is unlikely
+// to map one valid pointer to another valid pointer.
+constexpr uintptr_t HideMask() {
+  return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU;
+}
+
+// Hide a pointer from the leak checker. For internal use only.
+// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr
+// and all objects reachable from ptr to be ignored by the leak checker.
+template <class T>
+inline uintptr_t HidePtr(T* ptr) {
+  return reinterpret_cast<uintptr_t>(ptr) ^ HideMask();
+}
+
+// Return a pointer that has been hidden from the leak checker.
+// For internal use only.
+template <class T>
+inline T* UnhidePtr(uintptr_t hidden) {
+  return reinterpret_cast<T*>(hidden ^ HideMask());
+}
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_HIDE_PTR_H_
diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h
new file mode 100644
index 0000000..a1a5d70
--- /dev/null
+++ b/absl/base/internal/identity.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_IDENTITY_H_
+#define ABSL_BASE_INTERNAL_IDENTITY_H_
+
+namespace absl {
+namespace internal {
+
+template <typename T>
+struct identity {
+  typedef T type;
+};
+
+template <typename T>
+using identity_t = typename identity<T>::type;
+
+}  // namespace internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_IDENTITY_H_
diff --git a/absl/base/internal/inline_variable.h b/absl/base/internal/inline_variable.h
new file mode 100644
index 0000000..f7bb8c5
--- /dev/null
+++ b/absl/base/internal/inline_variable.h
@@ -0,0 +1,107 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
+#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
+
+#include <type_traits>
+
+#include "absl/base/internal/identity.h"
+
+// File:
+//   This file define a macro that allows the creation of or emulation of C++17
+//   inline variables based on whether or not the feature is supported.
+
+////////////////////////////////////////////////////////////////////////////////
+// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
+//
+// Description:
+//   Expands to the equivalent of an inline constexpr instance of the specified
+//   `type` and `name`, initialized to the value `init`. If the compiler being
+//   used is detected as supporting actual inline variables as a language
+//   feature, then the macro expands to an actual inline variable definition.
+//
+// Requires:
+//   `type` is a type that is usable in an extern variable declaration.
+//
+// Requires: `name` is a valid identifier
+//
+// Requires:
+//   `init` is an expression that can be used in the following definition:
+//     constexpr type name = init;
+//
+// Usage:
+//
+//   // Equivalent to: `inline constexpr size_t variant_npos = -1;`
+//   ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+//
+// Differences in implementation:
+//   For a direct, language-level inline variable, decltype(name) will be the
+//   type that was specified along with const qualification, whereas for
+//   emulated inline variables, decltype(name) may be different (in practice
+//   it will likely be a reference type).
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cpp_inline_variables
+
+// Clang's -Wmissing-variable-declarations option erroneously warned that
+// inline constexpr objects need to be pre-declared. This has now been fixed,
+// but we will need to support this workaround for people building with older
+// versions of clang.
+//
+// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
+//
+// Note:
+//   identity_t is used here so that the const and name are in the
+//   appropriate place for pointer types, reference types, function pointer
+//   types, etc..
+#if defined(__clang__)
+#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
+  extern const ::absl::internal::identity_t<type> name;
+#else  // Otherwise, just define the macro to do nothing.
+#define ABSL_INTERNAL_EXTERN_DECL(type, name)
+#endif  // defined(__clang__)
+
+// See above comment at top of file for details.
+#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
+  ABSL_INTERNAL_EXTERN_DECL(type, name)                  \
+  inline constexpr ::absl::internal::identity_t<type> name = init
+
+#else
+
+// See above comment at top of file for details.
+//
+// Note:
+//   identity_t is used here so that the const and name are in the
+//   appropriate place for pointer types, reference types, function pointer
+//   types, etc..
+#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init)                  \
+  template <class /*AbslInternalDummy*/ = void>                               \
+  struct AbslInternalInlineVariableHolder##name {                             \
+    static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \
+  };                                                                          \
+                                                                              \
+  template <class AbslInternalDummy>                                          \
+  constexpr ::absl::internal::identity_t<var_type>                            \
+      AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance;   \
+                                                                              \
+  static constexpr const ::absl::internal::identity_t<var_type>&              \
+      name = /* NOLINT */                                                     \
+      AbslInternalInlineVariableHolder##name<>::kInstance;                    \
+  static_assert(sizeof(void (*)(decltype(name))) != 0,                        \
+                "Silence unused variable warnings.")
+
+#endif  // __cpp_inline_variables
+
+#endif  // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h
new file mode 100644
index 0000000..a0dd2bb
--- /dev/null
+++ b/absl/base/internal/inline_variable_testing.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INLINE_VARIABLE_TESTING_H_
+#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_
+
+#include "absl/base/internal/inline_variable.h"
+
+namespace absl {
+namespace inline_variable_testing_internal {
+
+struct Foo {
+  int value = 5;
+};
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {});
+ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {});
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5);
+ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5);
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr);
+
+const Foo& get_foo_a();
+const Foo& get_foo_b();
+
+const int& get_int_a();
+const int& get_int_b();
+
+}  // namespace inline_variable_testing_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INLINE_VARIABLE_TESTING_H_
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
new file mode 100644
index 0000000..8c3f4f6
--- /dev/null
+++ b/absl/base/internal/invoke.h
@@ -0,0 +1,188 @@
+// Copyright 2017 The Abseil 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.
+//
+// absl::base_internal::Invoke(f, args...) is an implementation of
+// INVOKE(f, args...) from section [func.require] of the C++ standard.
+//
+// [func.require]
+// Define INVOKE (f, t1, t2, ..., tN) as follows:
+// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
+//    and t1 is an object of type T or a reference to an object of type T or a
+//    reference to an object of a type derived from T;
+// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
+//    class T and t1 is not one of the types described in the previous item;
+// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
+//    an object of type T or a reference to an object of type T or a reference
+//    to an object of a type derived from T;
+// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
+//    is not one of the types described in the previous item;
+// 5. f(t1, t2, ..., tN) in all other cases.
+//
+// The implementation is SFINAE-friendly: substitution failure within Invoke()
+// isn't an error.
+
+#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
+#define ABSL_BASE_INTERNAL_INVOKE_H_
+
+#include <algorithm>
+#include <type_traits>
+#include <utility>
+
+// The following code is internal implementation detail.  See the comment at the
+// top of this file for the API documentation.
+
+namespace absl {
+namespace base_internal {
+
+// The five classes below each implement one of the clauses from the definition
+// of INVOKE. The inner class template Accept<F, Args...> checks whether the
+// clause is applicable; static function template Invoke(f, args...) does the
+// invocation.
+//
+// By separating the clause selection logic from invocation we make sure that
+// Invoke() does exactly what the standard says.
+
+template <typename Derived>
+struct StrippedAccept {
+  template <typename... Args>
+  struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
+                      typename std::remove_reference<Args>::type>::type...> {};
+};
+
+// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
+// and t1 is an object of type T or a reference to an object of type T or a
+// reference to an object of a type derived from T.
+struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename R, typename C, typename... Params, typename Obj,
+            typename... Args>
+  struct AcceptImpl<R (C::*)(Params...), Obj, Args...>
+      : std::is_base_of<C, Obj> {};
+
+  template <typename R, typename C, typename... Params, typename Obj,
+            typename... Args>
+  struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...>
+      : std::is_base_of<C, Obj> {};
+
+  template <typename MemFun, typename Obj, typename... Args>
+  static decltype((std::declval<Obj>().*
+                   std::declval<MemFun>())(std::declval<Args>()...))
+  Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
+    return (std::forward<Obj>(obj).*
+            std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
+  }
+};
+
+// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
+// class T and t1 is not one of the types described in the previous item.
+struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename R, typename C, typename... Params, typename Ptr,
+            typename... Args>
+  struct AcceptImpl<R (C::*)(Params...), Ptr, Args...>
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+
+  template <typename R, typename C, typename... Params, typename Ptr,
+            typename... Args>
+  struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...>
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+
+  template <typename MemFun, typename Ptr, typename... Args>
+  static decltype(((*std::declval<Ptr>()).*
+                   std::declval<MemFun>())(std::declval<Args>()...))
+  Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
+    return ((*std::forward<Ptr>(ptr)).*
+            std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
+  }
+};
+
+// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
+// an object of type T or a reference to an object of type T or a reference
+// to an object of a type derived from T.
+struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename R, typename C, typename Obj>
+  struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, Obj> {};
+
+  template <typename DataMem, typename Ref>
+  static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
+      DataMem&& data_mem, Ref&& ref) {
+    return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
+  }
+};
+
+// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
+// is not one of the types described in the previous item.
+struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename R, typename C, typename Ptr>
+  struct AcceptImpl<R C::*, Ptr>
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+
+  template <typename DataMem, typename Ptr>
+  static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
+      DataMem&& data_mem, Ptr&& ptr) {
+    return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
+  }
+};
+
+// f(t1, t2, ..., tN) in all other cases.
+struct Callable {
+  // Callable doesn't have Accept because it's the last clause that gets picked
+  // when none of the previous clauses are applicable.
+  template <typename F, typename... Args>
+  static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
+      F&& f, Args&&... args) {
+    return std::forward<F>(f)(std::forward<Args>(args)...);
+  }
+};
+
+// Resolves to the first matching clause.
+template <typename... Args>
+struct Invoker {
+  typedef typename std::conditional<
+      MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
+      typename std::conditional<
+          MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
+          typename std::conditional<
+              DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
+              typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
+                                        DataMemAndPtr, Callable>::type>::type>::
+          type>::type type;
+};
+
+// The result type of Invoke<F, Args...>.
+template <typename F, typename... Args>
+using InvokeT = decltype(Invoker<F, Args...>::type::Invoke(
+    std::declval<F>(), std::declval<Args>()...));
+
+// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
+// [func.require] of the C++ standard.
+template <typename F, typename... Args>
+InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
+  return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
+                                           std::forward<Args>(args)...);
+}
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_INVOKE_H_
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
new file mode 100644
index 0000000..0626cd5
--- /dev/null
+++ b/absl/base/internal/low_level_alloc.cc
@@ -0,0 +1,604 @@
+// Copyright 2017 The Abseil 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.
+
+// A low-level allocator that can be used by other low-level
+// modules without introducing dependency cycles.
+// This allocator is slow and wasteful of memory;
+// it should not be used when performance is key.
+
+#include "absl/base/internal/low_level_alloc.h"
+
+#include <type_traits>
+
+#include "absl/base/call_once.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/direct_mmap.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
+
+// LowLevelAlloc requires that the platform support low-level
+// allocation of virtual memory. Platforms lacking this cannot use
+// LowLevelAlloc.
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#ifndef _WIN32
+#include <pthread.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <cstddef>
+#include <new>                   // for placement-new
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+// MAP_ANONYMOUS
+#if defined(__APPLE__)
+// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is
+// deprecated. In Darwin, MAP_ANON is all there is.
+#if !defined MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif  // !MAP_ANONYMOUS
+#endif  // __APPLE__
+
+namespace absl {
+namespace base_internal {
+
+// A first-fit allocator with amortized logarithmic free() time.
+
+// ---------------------------------------------------------------------------
+static const int kMaxLevel = 30;
+
+namespace {
+// This struct describes one allocated block, or one free block.
+struct AllocList {
+  struct Header {
+    // Size of entire region, including this field. Must be
+    // first. Valid in both allocated and unallocated blocks.
+    uintptr_t size;
+
+    // kMagicAllocated or kMagicUnallocated xor this.
+    uintptr_t magic;
+
+    // Pointer to parent arena.
+    LowLevelAlloc::Arena *arena;
+
+    // Aligns regions to 0 mod 2*sizeof(void*).
+    void *dummy_for_alignment;
+  } header;
+
+  // Next two fields: in unallocated blocks: freelist skiplist data
+  //                  in allocated blocks: overlaps with client data
+
+  // Levels in skiplist used.
+  int levels;
+
+  // Actually has levels elements. The AllocList node may not have room
+  // for all kMaxLevel entries. See max_fit in LLA_SkiplistLevels().
+  AllocList *next[kMaxLevel];
+};
+}  // namespace
+
+// ---------------------------------------------------------------------------
+// A trivial skiplist implementation.  This is used to keep the freelist
+// in address order while taking only logarithmic time per insert and delete.
+
+// An integer approximation of log2(size/base)
+// Requires size >= base.
+static int IntLog2(size_t size, size_t base) {
+  int result = 0;
+  for (size_t i = size; i > base; i >>= 1) {  // i == floor(size/2**result)
+    result++;
+  }
+  //    floor(size / 2**result) <= base < floor(size / 2**(result-1))
+  // =>     log2(size/(base+1)) <= result < 1+log2(size/base)
+  // => result ~= log2(size/base)
+  return result;
+}
+
+// Return a random integer n:  p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1.
+static int Random(uint32_t *state) {
+  uint32_t r = *state;
+  int result = 1;
+  while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) {
+    result++;
+  }
+  *state = r;
+  return result;
+}
+
+// Return a number of skiplist levels for a node of size bytes, where
+// base is the minimum node size.  Compute level=log2(size / base)+n
+// where n is 1 if random is false and otherwise a random number generated with
+// the standard distribution for a skiplist:  See Random() above.
+// Bigger nodes tend to have more skiplist levels due to the log2(size / base)
+// term, so first-fit searches touch fewer nodes.  "level" is clipped so
+// level<kMaxLevel and next[level-1] will fit in the node.
+// 0 < LLA_SkiplistLevels(x,y,false) <= LLA_SkiplistLevels(x,y,true) < kMaxLevel
+static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) {
+  // max_fit is the maximum number of levels that will fit in a node for the
+  // given size.   We can't return more than max_fit, no matter what the
+  // random number generator says.
+  size_t max_fit = (size - offsetof(AllocList, next)) / sizeof(AllocList *);
+  int level = IntLog2(size, base) + (random != nullptr ? Random(random) : 1);
+  if (static_cast<size_t>(level) > max_fit) level = static_cast<int>(max_fit);
+  if (level > kMaxLevel-1) level = kMaxLevel - 1;
+  ABSL_RAW_CHECK(level >= 1, "block not big enough for even one level");
+  return level;
+}
+
+// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e.
+// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater
+// points to the last element at level i in the AllocList less than *e, or is
+// head if no such element exists.
+static AllocList *LLA_SkiplistSearch(AllocList *head,
+                                     AllocList *e, AllocList **prev) {
+  AllocList *p = head;
+  for (int level = head->levels - 1; level >= 0; level--) {
+    for (AllocList *n; (n = p->next[level]) != nullptr && n < e; p = n) {
+    }
+    prev[level] = p;
+  }
+  return (head->levels == 0) ? nullptr : prev[0]->next[0];
+}
+
+// Insert element *e into AllocList *head.  Set prev[] as LLA_SkiplistSearch.
+// Requires that e->levels be previously set by the caller (using
+// LLA_SkiplistLevels())
+static void LLA_SkiplistInsert(AllocList *head, AllocList *e,
+                               AllocList **prev) {
+  LLA_SkiplistSearch(head, e, prev);
+  for (; head->levels < e->levels; head->levels++) {  // extend prev pointers
+    prev[head->levels] = head;                        // to all *e's levels
+  }
+  for (int i = 0; i != e->levels; i++) {  // add element to list
+    e->next[i] = prev[i]->next[i];
+    prev[i]->next[i] = e;
+  }
+}
+
+// Remove element *e from AllocList *head.  Set prev[] as LLA_SkiplistSearch().
+// Requires that e->levels be previous set by the caller (using
+// LLA_SkiplistLevels())
+static void LLA_SkiplistDelete(AllocList *head, AllocList *e,
+                               AllocList **prev) {
+  AllocList *found = LLA_SkiplistSearch(head, e, prev);
+  ABSL_RAW_CHECK(e == found, "element not in freelist");
+  for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) {
+    prev[i]->next[i] = e->next[i];
+  }
+  while (head->levels > 0 && head->next[head->levels - 1] == nullptr) {
+    head->levels--;   // reduce head->levels if level unused
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Arena implementation
+
+// Metadata for an LowLevelAlloc arena instance.
+struct LowLevelAlloc::Arena {
+  // Constructs an arena with the given LowLevelAlloc flags.
+  explicit Arena(uint32_t flags_value);
+
+  base_internal::SpinLock mu;
+  // Head of free list, sorted by address
+  AllocList freelist GUARDED_BY(mu);
+  // Count of allocated blocks
+  int32_t allocation_count GUARDED_BY(mu);
+  // flags passed to NewArena
+  const uint32_t flags;
+  // Result of getpagesize()
+  const size_t pagesize;
+  // Lowest power of two >= max(16, sizeof(AllocList))
+  const size_t roundup;
+  // Smallest allocation block size
+  const size_t min_size;
+  // PRNG state
+  uint32_t random GUARDED_BY(mu);
+};
+
+namespace {
+using ArenaStorage = std::aligned_storage<sizeof(LowLevelAlloc::Arena),
+                                          alignof(LowLevelAlloc::Arena)>::type;
+
+// Static storage space for the lazily-constructed, default global arena
+// instances.  We require this space because the whole point of LowLevelAlloc
+// is to avoid relying on malloc/new.
+ArenaStorage default_arena_storage;
+ArenaStorage unhooked_arena_storage;
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+ArenaStorage unhooked_async_sig_safe_arena_storage;
+#endif
+
+// We must use LowLevelCallOnce here to construct the global arenas, rather than
+// using function-level statics, to avoid recursively invoking the scheduler.
+absl::once_flag create_globals_once;
+
+void CreateGlobalArenas() {
+  new (&default_arena_storage)
+      LowLevelAlloc::Arena(LowLevelAlloc::kCallMallocHook);
+  new (&unhooked_arena_storage) LowLevelAlloc::Arena(0);
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+  new (&unhooked_async_sig_safe_arena_storage)
+      LowLevelAlloc::Arena(LowLevelAlloc::kAsyncSignalSafe);
+#endif
+}
+
+// Returns a global arena that does not call into hooks.  Used by NewArena()
+// when kCallMallocHook is not set.
+LowLevelAlloc::Arena* UnhookedArena() {
+  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
+  return reinterpret_cast<LowLevelAlloc::Arena*>(&unhooked_arena_storage);
+}
+
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+// Returns a global arena that is async-signal safe.  Used by NewArena() when
+// kAsyncSignalSafe is set.
+LowLevelAlloc::Arena *UnhookedAsyncSigSafeArena() {
+  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
+  return reinterpret_cast<LowLevelAlloc::Arena *>(
+      &unhooked_async_sig_safe_arena_storage);
+}
+#endif
+
+}  // namespace
+
+// Returns the default arena, as used by LowLevelAlloc::Alloc() and friends.
+LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
+  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
+  return reinterpret_cast<LowLevelAlloc::Arena*>(&default_arena_storage);
+}
+
+// magic numbers to identify allocated and unallocated blocks
+static const uintptr_t kMagicAllocated = 0x4c833e95U;
+static const uintptr_t kMagicUnallocated = ~kMagicAllocated;
+
+namespace {
+class SCOPED_LOCKABLE ArenaLock {
+ public:
+  explicit ArenaLock(LowLevelAlloc::Arena *arena)
+      EXCLUSIVE_LOCK_FUNCTION(arena->mu)
+      : arena_(arena) {
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+      sigset_t all;
+      sigfillset(&all);
+      mask_valid_ = pthread_sigmask(SIG_BLOCK, &all, &mask_) == 0;
+    }
+#endif
+    arena_->mu.Lock();
+  }
+  ~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
+  void Leave() UNLOCK_FUNCTION() {
+    arena_->mu.Unlock();
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    if (mask_valid_) {
+      pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
+    }
+#endif
+    left_ = true;
+  }
+
+ private:
+  bool left_ = false;  // whether left region
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+  bool mask_valid_ = false;
+  sigset_t mask_;  // old mask of blocked signals
+#endif
+  LowLevelAlloc::Arena *arena_;
+  ArenaLock(const ArenaLock &) = delete;
+  ArenaLock &operator=(const ArenaLock &) = delete;
+};
+}  // namespace
+
+// create an appropriate magic number for an object at "ptr"
+// "magic" should be kMagicAllocated or kMagicUnallocated
+inline static uintptr_t Magic(uintptr_t magic, AllocList::Header *ptr) {
+  return magic ^ reinterpret_cast<uintptr_t>(ptr);
+}
+
+namespace {
+size_t GetPageSize() {
+#ifdef _WIN32
+  SYSTEM_INFO system_info;
+  GetSystemInfo(&system_info);
+  return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
+#else
+  return getpagesize();
+#endif
+}
+
+size_t RoundedUpBlockSize() {
+  // Round up block sizes to a power of two close to the header size.
+  size_t roundup = 16;
+  while (roundup < sizeof(AllocList::Header)) {
+    roundup += roundup;
+  }
+  return roundup;
+}
+
+}  // namespace
+
+LowLevelAlloc::Arena::Arena(uint32_t flags_value)
+    : mu(base_internal::SCHEDULE_KERNEL_ONLY),
+      allocation_count(0),
+      flags(flags_value),
+      pagesize(GetPageSize()),
+      roundup(RoundedUpBlockSize()),
+      min_size(2 * roundup),
+      random(0) {
+  freelist.header.size = 0;
+  freelist.header.magic =
+      Magic(kMagicUnallocated, &freelist.header);
+  freelist.header.arena = this;
+  freelist.levels = 0;
+  memset(freelist.next, 0, sizeof(freelist.next));
+}
+
+// L < meta_data_arena->mu
+LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32_t flags) {
+  Arena *meta_data_arena = DefaultArena();
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+  if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+    meta_data_arena = UnhookedAsyncSigSafeArena();
+  } else  // NOLINT(readability/braces)
+#endif
+      if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
+    meta_data_arena = UnhookedArena();
+  }
+  Arena *result =
+    new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(flags);
+  return result;
+}
+
+// L < arena->mu, L < arena->arena->mu
+bool LowLevelAlloc::DeleteArena(Arena *arena) {
+  ABSL_RAW_CHECK(
+      arena != nullptr && arena != DefaultArena() && arena != UnhookedArena(),
+      "may not delete default arena");
+  ArenaLock section(arena);
+  if (arena->allocation_count != 0) {
+    section.Leave();
+    return false;
+  }
+  while (arena->freelist.next[0] != nullptr) {
+    AllocList *region = arena->freelist.next[0];
+    size_t size = region->header.size;
+    arena->freelist.next[0] = region->next[0];
+    ABSL_RAW_CHECK(
+        region->header.magic == Magic(kMagicUnallocated, &region->header),
+        "bad magic number in DeleteArena()");
+    ABSL_RAW_CHECK(region->header.arena == arena,
+                   "bad arena pointer in DeleteArena()");
+    ABSL_RAW_CHECK(size % arena->pagesize == 0,
+                   "empty arena has non-page-aligned block size");
+    ABSL_RAW_CHECK(reinterpret_cast<uintptr_t>(region) % arena->pagesize == 0,
+                   "empty arena has non-page-aligned block");
+    int munmap_result;
+#ifdef _WIN32
+    munmap_result = VirtualFree(region, 0, MEM_RELEASE);
+    ABSL_RAW_CHECK(munmap_result != 0,
+                   "LowLevelAlloc::DeleteArena: VitualFree failed");
+#else
+    if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
+      munmap_result = munmap(region, size);
+    } else {
+      munmap_result = base_internal::DirectMunmap(region, size);
+    }
+    if (munmap_result != 0) {
+      ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d",
+                   errno);
+    }
+#endif
+  }
+  section.Leave();
+  arena->~Arena();
+  Free(arena);
+  return true;
+}
+
+// ---------------------------------------------------------------------------
+
+// Addition, checking for overflow.  The intent is to die if an external client
+// manages to push through a request that would cause arithmetic to fail.
+static inline uintptr_t CheckedAdd(uintptr_t a, uintptr_t b) {
+  uintptr_t sum = a + b;
+  ABSL_RAW_CHECK(sum >= a, "LowLevelAlloc arithmetic overflow");
+  return sum;
+}
+
+// Return value rounded up to next multiple of align.
+// align must be a power of two.
+static inline uintptr_t RoundUp(uintptr_t addr, uintptr_t align) {
+  return CheckedAdd(addr, align - 1) & ~(align - 1);
+}
+
+// Equivalent to "return prev->next[i]" but with sanity checking
+// that the freelist is in the correct order, that it
+// consists of regions marked "unallocated", and that no two regions
+// are adjacent in memory (they should have been coalesced).
+// L < arena->mu
+static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
+  ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()");
+  AllocList *next = prev->next[i];
+  if (next != nullptr) {
+    ABSL_RAW_CHECK(
+        next->header.magic == Magic(kMagicUnallocated, &next->header),
+        "bad magic number in Next()");
+    ABSL_RAW_CHECK(next->header.arena == arena, "bad arena pointer in Next()");
+    if (prev != &arena->freelist) {
+      ABSL_RAW_CHECK(prev < next, "unordered freelist");
+      ABSL_RAW_CHECK(reinterpret_cast<char *>(prev) + prev->header.size <
+                         reinterpret_cast<char *>(next),
+                     "malformed freelist");
+    }
+  }
+  return next;
+}
+
+// Coalesce list item "a" with its successor if they are adjacent.
+static void Coalesce(AllocList *a) {
+  AllocList *n = a->next[0];
+  if (n != nullptr && reinterpret_cast<char *>(a) + a->header.size ==
+                          reinterpret_cast<char *>(n)) {
+    LowLevelAlloc::Arena *arena = a->header.arena;
+    a->header.size += n->header.size;
+    n->header.magic = 0;
+    n->header.arena = nullptr;
+    AllocList *prev[kMaxLevel];
+    LLA_SkiplistDelete(&arena->freelist, n, prev);
+    LLA_SkiplistDelete(&arena->freelist, a, prev);
+    a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size,
+                                   &arena->random);
+    LLA_SkiplistInsert(&arena->freelist, a, prev);
+  }
+}
+
+// Adds block at location "v" to the free list
+// L >= arena->mu
+static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) {
+  AllocList *f = reinterpret_cast<AllocList *>(
+                        reinterpret_cast<char *>(v) - sizeof (f->header));
+  ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
+                 "bad magic number in AddToFreelist()");
+  ABSL_RAW_CHECK(f->header.arena == arena,
+                 "bad arena pointer in AddToFreelist()");
+  f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size,
+                                 &arena->random);
+  AllocList *prev[kMaxLevel];
+  LLA_SkiplistInsert(&arena->freelist, f, prev);
+  f->header.magic = Magic(kMagicUnallocated, &f->header);
+  Coalesce(f);                  // maybe coalesce with successor
+  Coalesce(prev[0]);            // maybe coalesce with predecessor
+}
+
+// Frees storage allocated by LowLevelAlloc::Alloc().
+// L < arena->mu
+void LowLevelAlloc::Free(void *v) {
+  if (v != nullptr) {
+    AllocList *f = reinterpret_cast<AllocList *>(
+                        reinterpret_cast<char *>(v) - sizeof (f->header));
+    ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
+                   "bad magic number in Free()");
+    LowLevelAlloc::Arena *arena = f->header.arena;
+    ArenaLock section(arena);
+    AddToFreelist(v, arena);
+    ABSL_RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
+    arena->allocation_count--;
+    section.Leave();
+  }
+}
+
+// allocates and returns a block of size bytes, to be freed with Free()
+// L < arena->mu
+static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
+  void *result = nullptr;
+  if (request != 0) {
+    AllocList *s;       // will point to region that satisfies request
+    ArenaLock section(arena);
+    // round up with header
+    size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)),
+                             arena->roundup);
+    for (;;) {      // loop until we find a suitable region
+      // find the minimum levels that a block of this size must have
+      int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1;
+      if (i < arena->freelist.levels) {   // potential blocks exist
+        AllocList *before = &arena->freelist;  // predecessor of s
+        while ((s = Next(i, before, arena)) != nullptr &&
+               s->header.size < req_rnd) {
+          before = s;
+        }
+        if (s != nullptr) {       // we found a region
+          break;
+        }
+      }
+      // we unlock before mmap() both because mmap() may call a callback hook,
+      // and because it may be slow.
+      arena->mu.Unlock();
+      // mmap generous 64K chunks to decrease
+      // the chances/impact of fragmentation:
+      size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
+      void *new_pages;
+#ifdef _WIN32
+      new_pages = VirtualAlloc(0, new_pages_size,
+                               MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+      ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed");
+#else
+      if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+        new_pages = base_internal::DirectMmap(nullptr, new_pages_size,
+            PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+      } else {
+        new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
+                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+      }
+      if (new_pages == MAP_FAILED) {
+        ABSL_RAW_LOG(FATAL, "mmap error: %d", errno);
+      }
+#endif
+      arena->mu.Lock();
+      s = reinterpret_cast<AllocList *>(new_pages);
+      s->header.size = new_pages_size;
+      // Pretend the block is allocated; call AddToFreelist() to free it.
+      s->header.magic = Magic(kMagicAllocated, &s->header);
+      s->header.arena = arena;
+      AddToFreelist(&s->levels, arena);  // insert new region into free list
+    }
+    AllocList *prev[kMaxLevel];
+    LLA_SkiplistDelete(&arena->freelist, s, prev);    // remove from free list
+    // s points to the first free region that's big enough
+    if (CheckedAdd(req_rnd, arena->min_size) <= s->header.size) {
+      // big enough to split
+      AllocList *n = reinterpret_cast<AllocList *>
+                        (req_rnd + reinterpret_cast<char *>(s));
+      n->header.size = s->header.size - req_rnd;
+      n->header.magic = Magic(kMagicAllocated, &n->header);
+      n->header.arena = arena;
+      s->header.size = req_rnd;
+      AddToFreelist(&n->levels, arena);
+    }
+    s->header.magic = Magic(kMagicAllocated, &s->header);
+    ABSL_RAW_CHECK(s->header.arena == arena, "");
+    arena->allocation_count++;
+    section.Leave();
+    result = &s->levels;
+  }
+  ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
+  return result;
+}
+
+void *LowLevelAlloc::Alloc(size_t request) {
+  void *result = DoAllocWithArena(request, DefaultArena());
+  return result;
+}
+
+void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
+  ABSL_RAW_CHECK(arena != nullptr, "must pass a valid arena");
+  void *result = DoAllocWithArena(request, arena);
+  return result;
+}
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h
new file mode 100644
index 0000000..3c15605
--- /dev/null
+++ b/absl/base/internal/low_level_alloc.h
@@ -0,0 +1,119 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
+#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
+
+// A simple thread-safe memory allocator that does not depend on
+// mutexes or thread-specific data.  It is intended to be used
+// sparingly, and only when malloc() would introduce an unwanted
+// dependency, such as inside the heap-checker, or the Mutex
+// implementation.
+
+// IWYU pragma: private, include "base/low_level_alloc.h"
+
+#include <sys/types.h>
+#include <cstdint>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+// LowLevelAlloc requires that the platform support low-level
+// allocation of virtual memory. Platforms lacking this cannot use
+// LowLevelAlloc.
+#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
+#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
+#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
+#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
+#endif
+
+// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows.
+#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
+#elif defined(_WIN32)
+#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
+#endif
+
+#include <cstddef>
+
+#include "absl/base/port.h"
+
+namespace absl {
+namespace base_internal {
+
+class LowLevelAlloc {
+ public:
+  struct Arena;       // an arena from which memory may be allocated
+
+  // Returns a pointer to a block of at least "request" bytes
+  // that have been newly allocated from the specific arena.
+  // for Alloc() call the DefaultArena() is used.
+  // Returns 0 if passed request==0.
+  // Does not return 0 under other circumstances; it crashes if memory
+  // is not available.
+  static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
+  static void *AllocWithArena(size_t request, Arena *arena)
+      ABSL_ATTRIBUTE_SECTION(malloc_hook);
+
+  // Deallocates a region of memory that was previously allocated with
+  // Alloc().   Does nothing if passed 0.   "s" must be either 0,
+  // or must have been returned from a call to Alloc() and not yet passed to
+  // Free() since that call to Alloc().  The space is returned to the arena
+  // from which it was allocated.
+  static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook);
+
+  // ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
+  // are to put all callers of MallocHook::Invoke* in this module
+  // into special section,
+  // so that MallocHook::GetCallerStackTrace can function accurately.
+
+  // Create a new arena.
+  // The root metadata for the new arena is allocated in the
+  // meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
+  // These values may be ored into flags:
+  enum {
+    // Report calls to Alloc() and Free() via the MallocHook interface.
+    // Set in the DefaultArena.
+    kCallMallocHook = 0x0001,
+
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    // Make calls to Alloc(), Free() be async-signal-safe. Not set in
+    // DefaultArena(). Not supported on all platforms.
+    kAsyncSignalSafe = 0x0002,
+#endif
+  };
+  // Construct a new arena.  The allocation of the underlying metadata honors
+  // the provided flags.  For example, the call NewArena(kAsyncSignalSafe)
+  // is itself async-signal-safe, as well as generatating an arena that provides
+  // async-signal-safe Alloc/Free.
+  static Arena *NewArena(int32_t flags);
+
+  // Destroys an arena allocated by NewArena and returns true,
+  // provided no allocated blocks remain in the arena.
+  // If allocated blocks remain in the arena, does nothing and
+  // returns false.
+  // It is illegal to attempt to destroy the DefaultArena().
+  static bool DeleteArena(Arena *arena);
+
+  // The default arena that always exists.
+  static Arena *DefaultArena();
+
+ private:
+  LowLevelAlloc();      // no instances
+};
+
+}  // namespace base_internal
+}  // namespace absl
+#endif  // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc
new file mode 100644
index 0000000..cf2b363
--- /dev/null
+++ b/absl/base/internal/low_level_alloc_test.cc
@@ -0,0 +1,157 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/low_level_alloc.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <thread>  // NOLINT(build/c++11)
+#include <unordered_map>
+#include <utility>
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+// This test doesn't use gtest since it needs to test that everything
+// works before main().
+#define TEST_ASSERT(x)                                           \
+  if (!(x)) {                                                    \
+    printf("TEST_ASSERT(%s) FAILED ON LINE %d\n", #x, __LINE__); \
+    abort();                                                     \
+  }
+
+// a block of memory obtained from the allocator
+struct BlockDesc {
+  char *ptr;      // pointer to memory
+  int len;        // number of bytes
+  int fill;       // filled with data starting with this
+};
+
+// Check that the pattern placed in the block d
+// by RandomizeBlockDesc is still there.
+static void CheckBlockDesc(const BlockDesc &d) {
+  for (int i = 0; i != d.len; i++) {
+    TEST_ASSERT((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff));
+  }
+}
+
+// Fill the block "*d" with a pattern
+// starting with a random byte.
+static void RandomizeBlockDesc(BlockDesc *d) {
+  d->fill = rand() & 0xff;
+  for (int i = 0; i != d->len; i++) {
+    d->ptr[i] = (d->fill + i) & 0xff;
+  }
+}
+
+// Use to indicate to the malloc hooks that
+// this calls is from LowLevelAlloc.
+static bool using_low_level_alloc = false;
+
+// n times, toss a coin, and based on the outcome
+// either allocate a new block or deallocate an old block.
+// New blocks are placed in a std::unordered_map with a random key
+// and initialized with RandomizeBlockDesc().
+// If keys conflict, the older block is freed.
+// Old blocks are always checked with CheckBlockDesc()
+// before being freed.  At the end of the run,
+// all remaining allocated blocks are freed.
+// If use_new_arena is true, use a fresh arena, and then delete it.
+// If call_malloc_hook is true and user_arena is true,
+// allocations and deallocations are reported via the MallocHook
+// interface.
+static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
+  typedef std::unordered_map<int, BlockDesc> AllocMap;
+  AllocMap allocated;
+  AllocMap::iterator it;
+  BlockDesc block_desc;
+  int rnd;
+  LowLevelAlloc::Arena *arena = 0;
+  if (use_new_arena) {
+    int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0;
+    arena = LowLevelAlloc::NewArena(flags);
+  }
+  for (int i = 0; i != n; i++) {
+    if (i != 0 && i % 10000 == 0) {
+      printf(".");
+      fflush(stdout);
+    }
+
+    switch (rand() & 1) {      // toss a coin
+    case 0:     // coin came up heads: add a block
+      using_low_level_alloc = true;
+      block_desc.len = rand() & 0x3fff;
+      block_desc.ptr =
+        reinterpret_cast<char *>(
+                        arena == 0
+                        ? LowLevelAlloc::Alloc(block_desc.len)
+                        : LowLevelAlloc::AllocWithArena(block_desc.len, arena));
+      using_low_level_alloc = false;
+      RandomizeBlockDesc(&block_desc);
+      rnd = rand();
+      it = allocated.find(rnd);
+      if (it != allocated.end()) {
+        CheckBlockDesc(it->second);
+        using_low_level_alloc = true;
+        LowLevelAlloc::Free(it->second.ptr);
+        using_low_level_alloc = false;
+        it->second = block_desc;
+      } else {
+        allocated[rnd] = block_desc;
+      }
+      break;
+    case 1:     // coin came up tails: remove a block
+      it = allocated.begin();
+      if (it != allocated.end()) {
+        CheckBlockDesc(it->second);
+        using_low_level_alloc = true;
+        LowLevelAlloc::Free(it->second.ptr);
+        using_low_level_alloc = false;
+        allocated.erase(it);
+      }
+      break;
+    }
+  }
+  // remove all remaining blocks
+  while ((it = allocated.begin()) != allocated.end()) {
+    CheckBlockDesc(it->second);
+    using_low_level_alloc = true;
+    LowLevelAlloc::Free(it->second.ptr);
+    using_low_level_alloc = false;
+    allocated.erase(it);
+  }
+  if (use_new_arena) {
+    TEST_ASSERT(LowLevelAlloc::DeleteArena(arena));
+  }
+}
+// LowLevelAlloc is designed to be safe to call before main().
+static struct BeforeMain {
+  BeforeMain() {
+    Test(false, false, 50000);
+    Test(true, false, 50000);
+    Test(true, true, 50000);
+  }
+} before_main;
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
+
+int main(int argc, char *argv[]) {
+  // The actual test runs in the global constructor of `before_main`.
+  printf("PASS\n");
+  return 0;
+}
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h
new file mode 100644
index 0000000..e716f2b
--- /dev/null
+++ b/absl/base/internal/low_level_scheduling.h
@@ -0,0 +1,104 @@
+// Copyright 2017 The Abseil 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.
+//
+// Core interfaces and definitions used by by low-level interfaces such as
+// SpinLock.
+
+#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
+#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
+
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/macros.h"
+
+// The following two declarations exist so SchedulingGuard may friend them with
+// the appropriate language linkage.  These callbacks allow libc internals, such
+// as function level statics, to schedule cooperatively when locking.
+extern "C" bool __google_disable_rescheduling(void);
+extern "C" void __google_enable_rescheduling(bool disable_result);
+
+namespace absl {
+namespace base_internal {
+
+class SchedulingHelper;  // To allow use of SchedulingGuard.
+class SpinLock;          // To allow use of SchedulingGuard.
+
+// SchedulingGuard
+// Provides guard semantics that may be used to disable cooperative rescheduling
+// of the calling thread within specific program blocks.  This is used to
+// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
+// scheduling depends on.
+//
+// Domain implementations capable of rescheduling in reaction to involuntary
+// kernel thread actions (e.g blocking due to a pagefault or syscall) must
+// guarantee that an annotated thread is not allowed to (cooperatively)
+// reschedule until the annotated region is complete.
+//
+// It is an error to attempt to use a cooperatively scheduled resource (e.g.
+// Mutex) within a rescheduling-disabled region.
+//
+// All methods are async-signal safe.
+class SchedulingGuard {
+ public:
+  // Returns true iff the calling thread may be cooperatively rescheduled.
+  static bool ReschedulingIsAllowed();
+
+ private:
+  // Disable cooperative rescheduling of the calling thread.  It may still
+  // initiate scheduling operations (e.g. wake-ups), however, it may not itself
+  // reschedule.  Nestable.  The returned result is opaque, clients should not
+  // attempt to interpret it.
+  // REQUIRES: Result must be passed to a pairing EnableScheduling().
+  static bool DisableRescheduling();
+
+  // Marks the end of a rescheduling disabled region, previously started by
+  // DisableRescheduling().
+  // REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
+  static void EnableRescheduling(bool disable_result);
+
+  // A scoped helper for {Disable, Enable}Rescheduling().
+  // REQUIRES: destructor must run in same thread as constructor.
+  struct ScopedDisable {
+    ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); }
+    ~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); }
+
+    bool disabled;
+  };
+
+  // Access to SchedulingGuard is explicitly white-listed.
+  friend class SchedulingHelper;
+  friend class SpinLock;
+
+  SchedulingGuard(const SchedulingGuard&) = delete;
+  SchedulingGuard& operator=(const SchedulingGuard&) = delete;
+};
+
+//------------------------------------------------------------------------------
+// End of public interfaces.
+//------------------------------------------------------------------------------
+inline bool SchedulingGuard::ReschedulingIsAllowed() {
+  return false;
+}
+
+inline bool SchedulingGuard::DisableRescheduling() {
+  return false;
+}
+
+inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
+  return;
+}
+
+
+}  // namespace base_internal
+}  // namespace absl
+#endif  // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/absl/base/internal/module.mk b/absl/base/internal/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/absl/base/internal/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/absl/base/internal/per_thread_tls.h b/absl/base/internal/per_thread_tls.h
new file mode 100644
index 0000000..2428bdc
--- /dev/null
+++ b/absl/base/internal/per_thread_tls.h
@@ -0,0 +1,48 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
+#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
+
+// This header defines two macros:
+// If the platform supports thread-local storage:
+//   ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
+//   thread-local variable ABSL_PER_THREAD_TLS is 1
+//
+// Otherwise:
+//   ABSL_PER_THREAD_TLS_KEYWORD is empty
+//   ABSL_PER_THREAD_TLS is 0
+//
+// Microsoft C supports thread-local storage.
+// GCC supports it if the appropriate version of glibc is available,
+// which the programmer can indicate by defining ABSL_HAVE_TLS
+
+#include "absl/base/port.h"  // For ABSL_HAVE_TLS
+
+#if defined(ABSL_PER_THREAD_TLS)
+#error ABSL_PER_THREAD_TLS cannot be directly set
+#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
+#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
+#elif defined(ABSL_HAVE_TLS)
+#define ABSL_PER_THREAD_TLS_KEYWORD __thread
+#define ABSL_PER_THREAD_TLS 1
+#elif defined(_MSC_VER)
+#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
+#define ABSL_PER_THREAD_TLS 1
+#else
+#define ABSL_PER_THREAD_TLS_KEYWORD
+#define ABSL_PER_THREAD_TLS 0
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
diff --git a/absl/base/internal/pretty_function.h b/absl/base/internal/pretty_function.h
new file mode 100644
index 0000000..01b0547
--- /dev/null
+++ b/absl/base/internal/pretty_function.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
+#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
+
+// ABSL_PRETTY_FUNCTION
+//
+// In C++11, __func__ gives the undecorated name of the current function.  That
+// is, "main", not "int main()".  Various compilers give extra macros to get the
+// decorated function name, including return type and arguments, to
+// differentiate between overload sets.  ABSL_PRETTY_FUNCTION is a portable
+// version of these macros which forwards to the correct macro on each compiler.
+#if defined(_MSC_VER)
+#define ABSL_PRETTY_FUNCTION __FUNCSIG__
+#elif defined(__GNUC__)
+#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#error "Unsupported compiler"
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
new file mode 100644
index 0000000..1ce1388
--- /dev/null
+++ b/absl/base/internal/raw_logging.cc
@@ -0,0 +1,218 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/raw_logging.h"
+
+#include <stddef.h>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/log_severity.h"
+
+// We know how to perform low-level writes to stderr in POSIX and Windows.  For
+// these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED.
+// Much of raw_logging.cc becomes a no-op when we can't output messages,
+// although a FATAL ABSL_RAW_LOG message will still abort the process.
+
+// ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write()
+// (as from unistd.h)
+//
+// This preprocessor token is also defined in raw_io.cc.  If you need to copy
+// this, consider moving both to config.h instead.
+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
+    defined(__Fuchsia__) || defined(__native_client__)
+#include <unistd.h>
+
+
+#define ABSL_HAVE_POSIX_WRITE 1
+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
+#else
+#undef ABSL_HAVE_POSIX_WRITE
+#endif
+
+// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
+//   syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
+// for low level operations that want to avoid libc.
+#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
+#include <sys/syscall.h>
+#define ABSL_HAVE_SYSCALL_WRITE 1
+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
+#else
+#undef ABSL_HAVE_SYSCALL_WRITE
+#endif
+
+#ifdef _WIN32
+#include <io.h>
+
+#define ABSL_HAVE_RAW_IO 1
+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
+#else
+#undef ABSL_HAVE_RAW_IO
+#endif
+
+// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
+// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
+// whitelisted set of platforms for which we expect not to be able to raw log.
+
+ABSL_CONST_INIT static absl::base_internal::AtomicHook<
+    absl::raw_logging_internal::LogPrefixHook> log_prefix_hook;
+ABSL_CONST_INIT static absl::base_internal::AtomicHook<
+    absl::raw_logging_internal::AbortHook> abort_hook;
+
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+static const char kTruncated[] = " ... (message truncated)\n";
+
+// sprintf the format to the buffer, adjusting *buf and *size to reflect the
+// consumed bytes, and return whether the message fit without truncation.  If
+// truncation occurred, if possible leave room in the buffer for the message
+// kTruncated[].
+inline static bool VADoRawLog(char** buf, int* size, const char* format,
+                              va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
+inline static bool VADoRawLog(char** buf, int* size,
+                              const char* format, va_list ap) {
+  int n = vsnprintf(*buf, *size, format, ap);
+  bool result = true;
+  if (n < 0 || n > *size) {
+    result = false;
+    if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
+      n = *size - sizeof(kTruncated);  // room for truncation message
+    } else {
+      n = 0;                           // no room for truncation message
+    }
+  }
+  *size -= n;
+  *buf += n;
+  return result;
+}
+#endif  // ABSL_LOW_LEVEL_WRITE_SUPPORTED
+
+static constexpr int kLogBufSize = 3000;
+
+namespace {
+
+// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
+// that invoke malloc() and getenv() that might acquire some locks.
+
+// Helper for RawLog below.
+// *DoRawLog writes to *buf of *size and move them past the written portion.
+// It returns true iff there was no overflow or error.
+bool DoRawLog(char** buf, int* size, const char* format, ...)
+    ABSL_PRINTF_ATTRIBUTE(3, 4);
+bool DoRawLog(char** buf, int* size, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  int n = vsnprintf(*buf, *size, format, ap);
+  va_end(ap);
+  if (n < 0 || n > *size) return false;
+  *size -= n;
+  *buf += n;
+  return true;
+}
+
+void RawLogVA(absl::LogSeverity severity, const char* file, int line,
+              const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
+void RawLogVA(absl::LogSeverity severity, const char* file, int line,
+              const char* format, va_list ap) {
+  char buffer[kLogBufSize];
+  char* buf = buffer;
+  int size = sizeof(buffer);
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  bool enabled = true;
+#else
+  bool enabled = false;
+#endif
+
+#ifdef ABSL_MIN_LOG_LEVEL
+  if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL &&
+      severity < absl::LogSeverity::kFatal) {
+    enabled = false;
+  }
+#endif
+
+  auto log_prefix_hook_ptr = log_prefix_hook.Load();
+  if (log_prefix_hook_ptr) {
+    enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size);
+  } else {
+    if (enabled) {
+      DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line);
+    }
+  }
+  const char* const prefix_end = buf;
+
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  if (enabled) {
+    bool no_chop = VADoRawLog(&buf, &size, format, ap);
+    if (no_chop) {
+      DoRawLog(&buf, &size, "\n");
+    } else {
+      DoRawLog(&buf, &size, "%s", kTruncated);
+    }
+    absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
+  }
+#else
+  static_cast<void>(format);
+  static_cast<void>(ap);
+#endif
+
+  // Abort the process after logging a FATAL message, even if the output itself
+  // was suppressed.
+  if (severity == absl::LogSeverity::kFatal) {
+    abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize);
+    abort();
+  }
+}
+
+}  // namespace
+
+namespace absl {
+namespace raw_logging_internal {
+void SafeWriteToStderr(const char *s, size_t len) {
+#if defined(ABSL_HAVE_SYSCALL_WRITE)
+  syscall(SYS_write, STDERR_FILENO, s, len);
+#elif defined(ABSL_HAVE_POSIX_WRITE)
+  write(STDERR_FILENO, s, len);
+#elif defined(ABSL_HAVE_RAW_IO)
+  _write(/* stderr */ 2, s, len);
+#else
+  // stderr logging unsupported on this platform
+  (void) s;
+  (void) len;
+#endif
+}
+
+void RawLog(absl::LogSeverity severity, const char* file, int line,
+            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
+void RawLog(absl::LogSeverity severity, const char* file, int line,
+            const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  RawLogVA(severity, file, line, format, ap);
+  va_end(ap);
+}
+
+bool RawLoggingFullySupported() {
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  return true;
+#else  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  return false;
+#endif  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
+}
+
+}  // namespace raw_logging_internal
+}  // namespace absl
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
new file mode 100644
index 0000000..a2b7207
--- /dev/null
+++ b/absl/base/internal/raw_logging.h
@@ -0,0 +1,137 @@
+// Copyright 2017 The Abseil 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.
+//
+// Thread-safe logging routines that do not allocate any memory or
+// acquire any locks, and can therefore be used by low-level memory
+// allocation, synchronization, and signal-handling code.
+
+#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
+#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/log_severity.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+// This is similar to LOG(severity) << format..., but
+// * it is to be used ONLY by low-level modules that can't use normal LOG()
+// * it is designed to be a low-level logger that does not allocate any
+//   memory and does not need any locks, hence:
+// * it logs straight and ONLY to STDERR w/o buffering
+// * it uses an explicit printf-format and arguments list
+// * it will silently chop off really long message strings
+// Usage example:
+//   ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
+// This will print an almost standard log line like this to stderr only:
+//   E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+#define ABSL_RAW_LOG(severity, ...)                                            \
+  do {                                                                         \
+    constexpr const char* absl_raw_logging_internal_basename =                 \
+        ::absl::raw_logging_internal::Basename(__FILE__,                       \
+                                               sizeof(__FILE__) - 1);          \
+    ::absl::raw_logging_internal::RawLog(ABSL_RAW_LOGGING_INTERNAL_##severity, \
+                                         absl_raw_logging_internal_basename,   \
+                                         __LINE__, __VA_ARGS__);               \
+  } while (0)
+
+// Similar to CHECK(condition) << message, but for low-level modules:
+// we use only ABSL_RAW_LOG that does not allocate memory.
+// We do not want to provide args list here to encourage this usage:
+//   if (!cond)  ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
+// so that the args are not computed when not needed.
+#define ABSL_RAW_CHECK(condition, message)                             \
+  do {                                                                 \
+    if (ABSL_PREDICT_FALSE(!(condition))) {                            \
+      ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
+    }                                                                  \
+  } while (0)
+
+#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
+#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
+#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
+#define ABSL_RAW_LOGGING_INTERNAL_FATAL ::absl::LogSeverity::kFatal
+#define ABSL_RAW_LOGGING_INTERNAL_LEVEL(severity) \
+  ::absl::NormalizeLogSeverity(severity)
+
+namespace absl {
+namespace raw_logging_internal {
+
+// Helper function to implement ABSL_RAW_LOG
+// Logs format... at "severity" level, reporting it
+// as called from file:line.
+// This does not allocate memory or acquire locks.
+void RawLog(absl::LogSeverity severity, const char* file, int line,
+            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
+
+// Writes the provided buffer directly to stderr, in a safe, low-level manner.
+//
+// In POSIX this means calling write(), which is async-signal safe and does
+// not malloc.  If the platform supports the SYS_write syscall, we invoke that
+// directly to side-step any libc interception.
+void SafeWriteToStderr(const char *s, size_t len);
+
+// compile-time function to get the "base" filename, that is, the part of
+// a filename after the last "/" or "\" path separator.  The search starts at
+// the end of the std::string; the second parameter is the length of the std::string.
+constexpr const char* Basename(const char* fname, int offset) {
+  return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
+             ? fname + offset
+             : Basename(fname, offset - 1);
+}
+
+// For testing only.
+// Returns true if raw logging is fully supported. When it is not
+// fully supported, no messages will be emitted, but a log at FATAL
+// severity will cause an abort.
+//
+// TODO(gfalcon): Come up with a better name for this method.
+bool RawLoggingFullySupported();
+
+// Function type for a raw_logging customization hook for suppressing messages
+// by severity, and for writing custom prefixes on non-suppressed messages.
+//
+// The installed hook is called for every raw log invocation.  The message will
+// be logged to stderr only if the hook returns true.  FATAL errors will cause
+// the process to abort, even if writing to stderr is suppressed.  The hook is
+// also provided with an output buffer, where it can write a custom log message
+// prefix.
+//
+// The raw_logging system does not allocate memory or grab locks.  User-provided
+// hooks must avoid these operations, and must not throw exceptions.
+//
+// 'severity' is the severity level of the message being written.
+// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
+// was located.
+// 'buffer' and 'buf_size' are pointers to the buffer and buffer size.  If the
+// hook writes a prefix, it must increment *buffer and decrement *buf_size
+// accordingly.
+using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file,
+                               int line, char** buffer, int* buf_size);
+
+// Function type for a raw_logging customization hook called to abort a process
+// when a FATAL message is logged.  If the provided AbortHook() returns, the
+// logging system will call abort().
+//
+// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
+// was located.
+// The null-terminated logged message lives in the buffer between 'buf_start'
+// and 'buf_end'.  'prefix_end' points to the first non-prefix character of the
+// buffer (as written by the LogPrefixHook.)
+using AbortHook = void (*)(const char* file, int line, const char* buf_start,
+                           const char* prefix_end, const char* buf_end);
+
+}  // namespace raw_logging_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
diff --git a/absl/base/internal/scheduling_mode.h b/absl/base/internal/scheduling_mode.h
new file mode 100644
index 0000000..1b6497a
--- /dev/null
+++ b/absl/base/internal/scheduling_mode.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Abseil 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.
+//
+// Core interfaces and definitions used by by low-level interfaces such as
+// SpinLock.
+
+#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
+#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
+
+namespace absl {
+namespace base_internal {
+
+// Used to describe how a thread may be scheduled.  Typically associated with
+// the declaration of a resource supporting synchronized access.
+//
+// SCHEDULE_COOPERATIVE_AND_KERNEL:
+// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
+// reschedule (using base::scheduling semantics); allowing other cooperative
+// threads to proceed.
+//
+// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
+// Specifies that no cooperative scheduling semantics may be used, even if the
+// current thread is itself cooperatively scheduled.  This means that
+// cooperative threads will NOT allow other cooperative threads to execute in
+// their place while waiting for a resource of this type.  Host operating system
+// semantics (e.g. a futex) may still be used.
+//
+// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
+// by default.  SCHEDULE_KERNEL_ONLY should only be used for resources on which
+// base::scheduling (e.g. the implementation of a Scheduler) may depend.
+//
+// NOTE: Cooperative resources may not be nested below non-cooperative ones.
+// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
+// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
+enum SchedulingMode {
+  SCHEDULE_KERNEL_ONLY = 0,         // Allow scheduling only the host OS.
+  SCHEDULE_COOPERATIVE_AND_KERNEL,  // Also allow cooperative scheduling.
+};
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
new file mode 100644
index 0000000..1b97efb
--- /dev/null
+++ b/absl/base/internal/spinlock.cc
@@ -0,0 +1,228 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/spinlock.h"
+
+#include <algorithm>
+#include <atomic>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/spinlock_wait.h"
+#include "absl/base/internal/sysinfo.h" /* For NumCPUs() */
+#include "absl/base/call_once.h"
+
+// Description of lock-word:
+//  31..00: [............................3][2][1][0]
+//
+//     [0]: kSpinLockHeld
+//     [1]: kSpinLockCooperative
+//     [2]: kSpinLockDisabledScheduling
+// [31..3]: ONLY kSpinLockSleeper OR
+//          Wait time in cycles >> PROFILE_TIMESTAMP_SHIFT
+//
+// Detailed descriptions:
+//
+// Bit [0]: The lock is considered held iff kSpinLockHeld is set.
+//
+// Bit [1]: Eligible waiters (e.g. Fibers) may co-operatively reschedule when
+//          contended iff kSpinLockCooperative is set.
+//
+// Bit [2]: This bit is exclusive from bit [1].  It is used only by a
+//          non-cooperative lock.  When set, indicates that scheduling was
+//          successfully disabled when the lock was acquired.  May be unset,
+//          even if non-cooperative, if a ThreadIdentity did not yet exist at
+//          time of acquisition.
+//
+// Bit [3]: If this is the only upper bit ([31..3]) set then this lock was
+//          acquired without contention, however, at least one waiter exists.
+//
+//          Otherwise, bits [31..3] represent the time spent by the current lock
+//          holder to acquire the lock.  There may be outstanding waiter(s).
+
+namespace absl {
+namespace base_internal {
+
+ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
+                                                          int64_t wait_cycles)>
+    submit_profile_data;
+
+void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
+                                         int64_t wait_cycles)) {
+  submit_profile_data.Store(fn);
+}
+
+// Uncommon constructors.
+SpinLock::SpinLock(base_internal::SchedulingMode mode)
+    : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
+  ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+}
+
+SpinLock::SpinLock(base_internal::LinkerInitialized,
+                   base_internal::SchedulingMode mode) {
+  ABSL_TSAN_MUTEX_CREATE(this, 0);
+  if (IsCooperative(mode)) {
+    InitLinkerInitializedAndCooperative();
+  }
+  // Otherwise, lockword_ is already initialized.
+}
+
+// Static (linker initialized) spinlocks always start life as functional
+// non-cooperative locks.  When their static constructor does run, it will call
+// this initializer to augment the lockword with the cooperative bit.  By
+// actually taking the lock when we do this we avoid the need for an atomic
+// operation in the regular unlock path.
+//
+// SlowLock() must be careful to re-test for this bit so that any outstanding
+// waiters may be upgraded to cooperative status.
+void SpinLock::InitLinkerInitializedAndCooperative() {
+  Lock();
+  lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
+  Unlock();
+}
+
+// Monitor the lock to see if its value changes within some time period
+// (adaptive_spin_count loop iterations).  A timestamp indicating
+// when the thread initially started waiting for the lock is passed in via
+// the initial_wait_timestamp value.  The total wait time in cycles for the
+// lock is returned in the wait_cycles parameter.  The last value read
+// from the lock is returned from the method.
+uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
+                            uint32_t *wait_cycles) {
+  // We are already in the slow path of SpinLock, initialize the
+  // adaptive_spin_count here.
+  ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
+  ABSL_CONST_INIT static int adaptive_spin_count = 0;
+  base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() {
+    adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1;
+  });
+
+  int c = adaptive_spin_count;
+  uint32_t lock_value;
+  do {
+    lock_value = lockword_.load(std::memory_order_relaxed);
+  } while ((lock_value & kSpinLockHeld) != 0 && --c > 0);
+  uint32_t spin_loop_wait_cycles =
+      EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now());
+  *wait_cycles = spin_loop_wait_cycles;
+
+  return TryLockInternal(lock_value, spin_loop_wait_cycles);
+}
+
+void SpinLock::SlowLock() {
+  // The lock was not obtained initially, so this thread needs to wait for
+  // it.  Record the current timestamp in the local variable wait_start_time
+  // so the total wait time can be stored in the lockword once this thread
+  // obtains the lock.
+  int64_t wait_start_time = CycleClock::Now();
+  uint32_t wait_cycles;
+  uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles);
+
+  int lock_wait_call_count = 0;
+  while ((lock_value & kSpinLockHeld) != 0) {
+    // If the lock is currently held, but not marked as having a sleeper, mark
+    // it as having a sleeper.
+    if ((lock_value & kWaitTimeMask) == 0) {
+      // Here, just "mark" that the thread is going to sleep.  Don't store the
+      // lock wait time in the lock as that will cause the current lock
+      // owner to think it experienced contention.
+      if (lockword_.compare_exchange_strong(
+              lock_value, lock_value | kSpinLockSleeper,
+              std::memory_order_acquire, std::memory_order_relaxed)) {
+        // Successfully transitioned to kSpinLockSleeper.  Pass
+        // kSpinLockSleeper to the SpinLockWait routine to properly indicate
+        // the last lock_value observed.
+        lock_value |= kSpinLockSleeper;
+      } else if ((lock_value & kSpinLockHeld) == 0) {
+        // Lock is free again, so try and acquire it before sleeping.  The
+        // new lock state will be the number of cycles this thread waited if
+        // this thread obtains the lock.
+        lock_value = TryLockInternal(lock_value, wait_cycles);
+        continue;   // Skip the delay at the end of the loop.
+      }
+    }
+
+    base_internal::SchedulingMode scheduling_mode;
+    if ((lock_value & kSpinLockCooperative) != 0) {
+      scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+    } else {
+      scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
+    }
+    // SpinLockDelay() calls into fiber scheduler, we need to see
+    // synchronization there to avoid false positives.
+    ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+    // Wait for an OS specific delay.
+    base_internal::SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count,
+                                 scheduling_mode);
+    ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+    // Spin again after returning from the wait routine to give this thread
+    // some chance of obtaining the lock.
+    lock_value = SpinLoop(wait_start_time, &wait_cycles);
+  }
+}
+
+void SpinLock::SlowUnlock(uint32_t lock_value) {
+  base_internal::SpinLockWake(&lockword_,
+                              false);  // wake waiter if necessary
+
+  // If our acquisition was contended, collect contentionz profile info.  We
+  // reserve a unitary wait time to represent that a waiter exists without our
+  // own acquisition having been contended.
+  if ((lock_value & kWaitTimeMask) != kSpinLockSleeper) {
+    const uint64_t wait_cycles = DecodeWaitCycles(lock_value);
+    ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+    submit_profile_data(this, wait_cycles);
+    ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+  }
+}
+
+// We use the upper 29 bits of the lock word to store the time spent waiting to
+// acquire this lock.  This is reported by contentionz profiling.  Since the
+// lower bits of the cycle counter wrap very quickly on high-frequency
+// processors we divide to reduce the granularity to 2^PROFILE_TIMESTAMP_SHIFT
+// sized units.  On a 4Ghz machine this will lose track of wait times greater
+// than (2^29/4 Ghz)*128 =~ 17.2 seconds.  Such waits should be extremely rare.
+enum { PROFILE_TIMESTAMP_SHIFT = 7 };
+enum { LOCKWORD_RESERVED_SHIFT = 3 };  // We currently reserve the lower 3 bits.
+
+uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
+                                    int64_t wait_end_time) {
+  static const int64_t kMaxWaitTime =
+      std::numeric_limits<uint32_t>::max() >> LOCKWORD_RESERVED_SHIFT;
+  int64_t scaled_wait_time =
+      (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
+
+  // Return a representation of the time spent waiting that can be stored in
+  // the lock word's upper bits.  bit_cast is required as Atomic32 is signed.
+  const uint32_t clamped = static_cast<uint32_t>(
+      std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT);
+
+  // bump up value if necessary to avoid returning kSpinLockSleeper.
+  const uint32_t after_spinlock_sleeper =
+     kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
+  return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped;
+}
+
+uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
+  // Cast to uint32_t first to ensure bits [63:32] are cleared.
+  const uint64_t scaled_wait_time =
+      static_cast<uint32_t>(lock_value & kWaitTimeMask);
+  return scaled_wait_time
+      << (PROFILE_TIMESTAMP_SHIFT - LOCKWORD_RESERVED_SHIFT);
+}
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
new file mode 100644
index 0000000..212abc6
--- /dev/null
+++ b/absl/base/internal/spinlock.h
@@ -0,0 +1,239 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+
+//  Most users requiring mutual exclusion should use Mutex.
+//  SpinLock is provided for use in three situations:
+//   - for use in code that Mutex itself depends on
+//   - to get a faster fast-path release under low contention (without an
+//     atomic read-modify-write) In return, SpinLock has worse behaviour under
+//     contention, which is why Mutex is preferred in most situations.
+//   - for async signal safety (see below)
+
+// SpinLock is async signal safe.  If a spinlock is used within a signal
+// handler, all code that acquires the lock must ensure that the signal cannot
+// arrive while they are holding the lock.  Typically, this is done by blocking
+// the signal.
+
+#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
+#define ABSL_BASE_INTERNAL_SPINLOCK_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+
+namespace absl {
+namespace base_internal {
+
+class LOCKABLE SpinLock {
+ public:
+  SpinLock() : lockword_(kSpinLockCooperative) {
+    ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+  }
+
+  // Special constructor for use with static SpinLock objects.  E.g.,
+  //
+  //    static SpinLock lock(base_internal::kLinkerInitialized);
+  //
+  // When intialized using this constructor, we depend on the fact
+  // that the linker has already initialized the memory appropriately.
+  // A SpinLock constructed like this can be freely used from global
+  // initializers without worrying about the order in which global
+  // initializers run.
+  explicit SpinLock(base_internal::LinkerInitialized) {
+    // Does nothing; lockword_ is already initialized
+    ABSL_TSAN_MUTEX_CREATE(this, 0);
+  }
+
+  // Constructors that allow non-cooperative spinlocks to be created for use
+  // inside thread schedulers.  Normal clients should not use these.
+  explicit SpinLock(base_internal::SchedulingMode mode);
+  SpinLock(base_internal::LinkerInitialized,
+           base_internal::SchedulingMode mode);
+
+  ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
+
+  // Acquire this SpinLock.
+  inline void Lock() EXCLUSIVE_LOCK_FUNCTION() {
+    ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+    if (!TryLockImpl()) {
+      SlowLock();
+    }
+    ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+  }
+
+  // Try to acquire this SpinLock without blocking and return true if the
+  // acquisition was successful.  If the lock was not acquired, false is
+  // returned.  If this SpinLock is free at the time of the call, TryLock
+  // will return true with high probability.
+  inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
+    bool res = TryLockImpl();
+    ABSL_TSAN_MUTEX_POST_LOCK(
+        this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
+        0);
+    return res;
+  }
+
+  // Release this SpinLock, which must be held by the calling thread.
+  inline void Unlock() UNLOCK_FUNCTION() {
+    ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
+    uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
+    lockword_.store(lock_value & kSpinLockCooperative,
+                    std::memory_order_release);
+
+    if ((lock_value & kSpinLockDisabledScheduling) != 0) {
+      base_internal::SchedulingGuard::EnableRescheduling(true);
+    }
+    if ((lock_value & kWaitTimeMask) != 0) {
+      // Collect contentionz profile info, and speed the wakeup of any waiter.
+      // The wait_cycles value indicates how long this thread spent waiting
+      // for the lock.
+      SlowUnlock(lock_value);
+    }
+    ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
+  }
+
+  // Determine if the lock is held.  When the lock is held by the invoking
+  // thread, true will always be returned. Intended to be used as
+  // CHECK(lock.IsHeld()).
+  inline bool IsHeld() const {
+    return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
+  }
+
+ protected:
+  // These should not be exported except for testing.
+
+  // Store number of cycles between wait_start_time and wait_end_time in a
+  // lock value.
+  static uint32_t EncodeWaitCycles(int64_t wait_start_time,
+                                   int64_t wait_end_time);
+
+  // Extract number of wait cycles in a lock value.
+  static uint64_t DecodeWaitCycles(uint32_t lock_value);
+
+  // Provide access to protected method above.  Use for testing only.
+  friend struct SpinLockTest;
+
+ private:
+  // lockword_ is used to store the following:
+  //
+  // bit[0] encodes whether a lock is being held.
+  // bit[1] encodes whether a lock uses cooperative scheduling.
+  // bit[2] encodes whether a lock disables scheduling.
+  // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
+  enum { kSpinLockHeld = 1 };
+  enum { kSpinLockCooperative = 2 };
+  enum { kSpinLockDisabledScheduling = 4 };
+  enum { kSpinLockSleeper = 8 };
+  enum { kWaitTimeMask =                      // Includes kSpinLockSleeper.
+    ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling) };
+
+  // Returns true if the provided scheduling mode is cooperative.
+  static constexpr bool IsCooperative(
+      base_internal::SchedulingMode scheduling_mode) {
+    return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+  }
+
+  uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
+  void InitLinkerInitializedAndCooperative();
+  void SlowLock() ABSL_ATTRIBUTE_COLD;
+  void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
+  uint32_t SpinLoop(int64_t initial_wait_timestamp, uint32_t* wait_cycles);
+
+  inline bool TryLockImpl() {
+    uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
+    return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
+  }
+
+  std::atomic<uint32_t> lockword_;
+
+  SpinLock(const SpinLock&) = delete;
+  SpinLock& operator=(const SpinLock&) = delete;
+};
+
+// Corresponding locker object that arranges to acquire a spinlock for
+// the duration of a C++ scope.
+class SCOPED_LOCKABLE SpinLockHolder {
+ public:
+  inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
+      : lock_(l) {
+    l->Lock();
+  }
+  inline ~SpinLockHolder() UNLOCK_FUNCTION() { lock_->Unlock(); }
+
+  SpinLockHolder(const SpinLockHolder&) = delete;
+  SpinLockHolder& operator=(const SpinLockHolder&) = delete;
+
+ private:
+  SpinLock* lock_;
+};
+
+// Register a hook for profiling support.
+//
+// The function pointer registered here will be called whenever a spinlock is
+// contended.  The callback is given an opaque handle to the contended spinlock
+// and the number of wait cycles.  This is thread-safe, but only a single
+// profiler can be registered.  It is an error to call this function multiple
+// times with different arguments.
+void RegisterSpinLockProfiler(void (*fn)(const void* lock,
+                                         int64_t wait_cycles));
+
+//------------------------------------------------------------------------------
+// Public interface ends here.
+//------------------------------------------------------------------------------
+
+// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
+// Otherwise, returns last observed value for lockword_.
+inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
+                                          uint32_t wait_cycles) {
+  if ((lock_value & kSpinLockHeld) != 0) {
+    return lock_value;
+  }
+
+  uint32_t sched_disabled_bit = 0;
+  if ((lock_value & kSpinLockCooperative) == 0) {
+    // For non-cooperative locks we must make sure we mark ourselves as
+    // non-reschedulable before we attempt to CompareAndSwap.
+    if (base_internal::SchedulingGuard::DisableRescheduling()) {
+      sched_disabled_bit = kSpinLockDisabledScheduling;
+    }
+  }
+
+  if (lockword_.compare_exchange_strong(
+          lock_value,
+          kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
+          std::memory_order_acquire, std::memory_order_relaxed)) {
+  } else {
+    base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
+  }
+
+  return lock_value;
+}
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SPINLOCK_H_
diff --git a/absl/base/internal/spinlock_akaros.inc b/absl/base/internal/spinlock_akaros.inc
new file mode 100644
index 0000000..051c8cf
--- /dev/null
+++ b/absl/base/internal/spinlock_akaros.inc
@@ -0,0 +1,35 @@
+// Copyright 2017 The Abseil 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.
+//
+// This file is an Akaros-specific part of spinlock_wait.cc
+
+#include <atomic>
+
+#include "absl/base/internal/scheduling_mode.h"
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
+    int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
+  // In Akaros, one must take care not to call anything that could cause a
+  // malloc(), a blocking system call, or a uthread_yield() while holding a
+  // spinlock. Our callers assume will not call into libraries or other
+  // arbitrary code.
+}
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
+
+}  // extern "C"
diff --git a/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc
new file mode 100644
index 0000000..0098c1c
--- /dev/null
+++ b/absl/base/internal/spinlock_posix.inc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Abseil 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.
+//
+// This file is a Posix-specific part of spinlock_wait.cc
+
+#include <sched.h>
+#include <atomic>
+#include <ctime>
+#include <cerrno>
+
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/port.h"
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
+    absl::base_internal::SchedulingMode /* mode */) {
+  int save_errno = errno;
+  if (loop == 0) {
+  } else if (loop == 1) {
+    sched_yield();
+  } else {
+    struct timespec tm;
+    tm.tv_sec = 0;
+    tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
+    nanosleep(&tm, nullptr);
+  }
+  errno = save_errno;
+}
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
+
+}  // extern "C"
diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc
new file mode 100644
index 0000000..9f6e991
--- /dev/null
+++ b/absl/base/internal/spinlock_wait.cc
@@ -0,0 +1,79 @@
+// Copyright 2017 The Abseil 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 OS-specific header included below must provide two calls:
+// base::subtle::SpinLockDelay() and base::subtle::SpinLockWake().
+// See spinlock_wait.h for the specs.
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/internal/spinlock_wait.h"
+
+#if defined(_WIN32)
+#include "absl/base/internal/spinlock_win32.inc"
+#elif defined(__akaros__)
+#include "absl/base/internal/spinlock_akaros.inc"
+#else
+#include "absl/base/internal/spinlock_posix.inc"
+#endif
+
+namespace absl {
+namespace base_internal {
+
+// See spinlock_wait.h for spec.
+uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
+                      const SpinLockWaitTransition trans[],
+                      base_internal::SchedulingMode scheduling_mode) {
+  for (int loop = 0; ; loop++) {
+    uint32_t v = w->load(std::memory_order_acquire);
+    int i;
+    for (i = 0; i != n && v != trans[i].from; i++) {
+    }
+    if (i == n) {
+      SpinLockDelay(w, v, loop, scheduling_mode);  // no matching transition
+    } else if (trans[i].to == v ||                 // null transition
+               w->compare_exchange_strong(v, trans[i].to,
+                                          std::memory_order_acquire,
+                                          std::memory_order_relaxed)) {
+      if (trans[i].done) return v;
+    }
+  }
+}
+
+static std::atomic<uint64_t> delay_rand;
+
+// Return a suggested delay in nanoseconds for iteration number "loop"
+int SpinLockSuggestedDelayNS(int loop) {
+  // Weak pseudo-random number generator to get some spread between threads
+  // when many are spinning.
+  uint64_t r = delay_rand.load(std::memory_order_relaxed);
+  r = 0x5deece66dLL * r + 0xb;   // numbers from nrand48()
+  delay_rand.store(r, std::memory_order_relaxed);
+
+  r <<= 16;   // 48-bit random number now in top 48-bits.
+  if (loop < 0 || loop > 32) {   // limit loop to 0..32
+    loop = 32;
+  }
+  // loop>>3 cannot exceed 4 because loop cannot exceed 32.
+  // Select top 20..24 bits of lower 48 bits,
+  // giving approximately 0ms to 16ms.
+  // Mean is exponential in loop for first 32 iterations, then 8ms.
+  // The futex path multiplies this by 16, since we expect explicit wakeups
+  // almost always on that path.
+  return static_cast<int>(r >> (44 - (loop >> 3)));
+}
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h
new file mode 100644
index 0000000..5c6cc7f
--- /dev/null
+++ b/absl/base/internal/spinlock_wait.h
@@ -0,0 +1,91 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
+#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
+
+// Operations to make atomic transitions on a word, and to allow
+// waiting for those transitions to become possible.
+
+#include <stdint.h>
+#include <atomic>
+
+#include "absl/base/internal/scheduling_mode.h"
+
+namespace absl {
+namespace base_internal {
+
+// SpinLockWait() waits until it can perform one of several transitions from
+// "from" to "to".  It returns when it performs a transition where done==true.
+struct SpinLockWaitTransition {
+  uint32_t from;
+  uint32_t to;
+  bool done;
+};
+
+// Wait until *w can transition from trans[i].from to trans[i].to for some i
+// satisfying 0<=i<n && trans[i].done, atomically make the transition,
+// then return the old value of *w.   Make any other atomic transitions
+// where !trans[i].done, but continue waiting.
+uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
+                      const SpinLockWaitTransition trans[],
+                      SchedulingMode scheduling_mode);
+
+// If possible, wake some thread that has called SpinLockDelay(w, ...). If
+// "all" is true, wake all such threads.  This call is a hint, and on some
+// systems it may be a no-op; threads calling SpinLockDelay() will always wake
+// eventually even if SpinLockWake() is never called.
+void SpinLockWake(std::atomic<uint32_t> *w, bool all);
+
+// Wait for an appropriate spin delay on iteration "loop" of a
+// spin loop on location *w, whose previously observed value was "value".
+// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
+// or may wait for a delay that can be truncated by a call to SpinLockWake(w).
+// In all cases, it must return in bounded time even if SpinLockWake() is not
+// called.
+void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
+                   base_internal::SchedulingMode scheduling_mode);
+
+// Helper used by AbslInternalSpinLockDelay.
+// Returns a suggested delay in nanoseconds for iteration number "loop".
+int SpinLockSuggestedDelayNS(int loop);
+
+}  // namespace base_internal
+}  // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all);
+void AbslInternalSpinLockDelay(
+    std::atomic<uint32_t> *w, uint32_t value, int loop,
+    absl::base_internal::SchedulingMode scheduling_mode);
+}
+
+inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
+                                              bool all) {
+  AbslInternalSpinLockWake(w, all);
+}
+
+inline void absl::base_internal::SpinLockDelay(
+    std::atomic<uint32_t> *w, uint32_t value, int loop,
+    absl::base_internal::SchedulingMode scheduling_mode) {
+  AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
+}
+
+#endif  // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
diff --git a/absl/base/internal/spinlock_win32.inc b/absl/base/internal/spinlock_win32.inc
new file mode 100644
index 0000000..32c8fc0
--- /dev/null
+++ b/absl/base/internal/spinlock_win32.inc
@@ -0,0 +1,37 @@
+// Copyright 2017 The Abseil 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.
+//
+// This file is a Win32-specific part of spinlock_wait.cc
+
+#include <windows.h>
+#include <atomic>
+#include "absl/base/internal/scheduling_mode.h"
+
+extern "C" {
+
+void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
+                               uint32_t /* value */, int loop,
+                               absl::base_internal::SchedulingMode /* mode */) {
+  if (loop == 0) {
+  } else if (loop == 1) {
+    Sleep(0);
+  } else {
+    Sleep(absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000);
+  }
+}
+
+void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */,
+                              bool /* all */) {}
+
+}  // extern "C"
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
new file mode 100644
index 0000000..db41bac
--- /dev/null
+++ b/absl/base/internal/sysinfo.cc
@@ -0,0 +1,404 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/sysinfo.h"
+
+#include "absl/base/attributes.h"
+
+#ifdef _WIN32
+#include <shlwapi.h>
+#include <windows.h>
+#else
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <sys/syscall.h>
+#endif
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+
+#if defined(__myriad2__)
+#include <rtems.h>
+#endif
+
+#include <string.h>
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <limits>
+#include <thread>  // NOLINT(build/c++11)
+#include <utility>
+#include <vector>
+
+#include "absl/base/call_once.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/unscaledcycleclock.h"
+
+namespace absl {
+namespace base_internal {
+
+static once_flag init_system_info_once;
+static int num_cpus = 0;
+static double nominal_cpu_frequency = 1.0;  // 0.0 might be dangerous.
+
+static int GetNumCPUs() {
+#if defined(__myriad2__)
+  return 1;
+#else
+  // Other possibilities:
+  //  - Read /sys/devices/system/cpu/online and use cpumask_parse()
+  //  - sysconf(_SC_NPROCESSORS_ONLN)
+  return std::thread::hardware_concurrency();
+#endif
+}
+
+#if defined(_WIN32)
+
+static double GetNominalCPUFrequency() {
+  DWORD data;
+  DWORD data_size = sizeof(data);
+  #pragma comment(lib, "shlwapi.lib")  // For SHGetValue().
+  if (SUCCEEDED(
+          SHGetValueA(HKEY_LOCAL_MACHINE,
+                      "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
+                      "~MHz", nullptr, &data, &data_size))) {
+    return data * 1e6;  // Value is MHz.
+  }
+  return 1.0;
+}
+
+#elif defined(CTL_HW) && defined(HW_CPU_FREQ)
+
+static double GetNominalCPUFrequency() {
+  unsigned freq;
+  size_t size = sizeof(freq);
+  int mib[2] = {CTL_HW, HW_CPU_FREQ};
+  if (sysctl(mib, 2, &freq, &size, nullptr, 0) == 0) {
+    return static_cast<double>(freq);
+  }
+  return 1.0;
+}
+
+#else
+
+// Helper function for reading a long from a file. Returns true if successful
+// and the memory location pointed to by value is set to the value read.
+static bool ReadLongFromFile(const char *file, long *value) {
+  bool ret = false;
+  int fd = open(file, O_RDONLY);
+  if (fd != -1) {
+    char line[1024];
+    char *err;
+    memset(line, '\0', sizeof(line));
+    int len = read(fd, line, sizeof(line) - 1);
+    if (len <= 0) {
+      ret = false;
+    } else {
+      const long temp_value = strtol(line, &err, 10);
+      if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
+        *value = temp_value;
+        ret = true;
+      }
+    }
+    close(fd);
+  }
+  return ret;
+}
+
+#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
+
+// Reads a monotonic time source and returns a value in
+// nanoseconds. The returned value uses an arbitrary epoch, not the
+// Unix epoch.
+static int64_t ReadMonotonicClockNanos() {
+  struct timespec t;
+#ifdef CLOCK_MONOTONIC_RAW
+  int rc = clock_gettime(CLOCK_MONOTONIC_RAW, &t);
+#else
+  int rc = clock_gettime(CLOCK_MONOTONIC, &t);
+#endif
+  if (rc != 0) {
+    perror("clock_gettime() failed");
+    abort();
+  }
+  return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec;
+}
+
+class UnscaledCycleClockWrapperForInitializeFrequency {
+ public:
+  static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
+};
+
+struct TimeTscPair {
+  int64_t time;  // From ReadMonotonicClockNanos().
+  int64_t tsc;   // From UnscaledCycleClock::Now().
+};
+
+// Returns a pair of values (monotonic kernel time, TSC ticks) that
+// approximately correspond to each other.  This is accomplished by
+// doing several reads and picking the reading with the lowest
+// latency.  This approach is used to minimize the probability that
+// our thread was preempted between clock reads.
+static TimeTscPair GetTimeTscPair() {
+  int64_t best_latency = std::numeric_limits<int64_t>::max();
+  TimeTscPair best;
+  for (int i = 0; i < 10; ++i) {
+    int64_t t0 = ReadMonotonicClockNanos();
+    int64_t tsc = UnscaledCycleClockWrapperForInitializeFrequency::Now();
+    int64_t t1 = ReadMonotonicClockNanos();
+    int64_t latency = t1 - t0;
+    if (latency < best_latency) {
+      best_latency = latency;
+      best.time = t0;
+      best.tsc = tsc;
+    }
+  }
+  return best;
+}
+
+// Measures and returns the TSC frequency by taking a pair of
+// measurements approximately `sleep_nanoseconds` apart.
+static double MeasureTscFrequencyWithSleep(int sleep_nanoseconds) {
+  auto t0 = GetTimeTscPair();
+  struct timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = sleep_nanoseconds;
+  while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {}
+  auto t1 = GetTimeTscPair();
+  double elapsed_ticks = t1.tsc - t0.tsc;
+  double elapsed_time = (t1.time - t0.time) * 1e-9;
+  return elapsed_ticks / elapsed_time;
+}
+
+// Measures and returns the TSC frequency by calling
+// MeasureTscFrequencyWithSleep(), doubling the sleep interval until the
+// frequency measurement stabilizes.
+static double MeasureTscFrequency() {
+  double last_measurement = -1.0;
+  int sleep_nanoseconds = 1000000;  // 1 millisecond.
+  for (int i = 0; i < 8; ++i) {
+    double measurement = MeasureTscFrequencyWithSleep(sleep_nanoseconds);
+    if (measurement * 0.99 < last_measurement &&
+        last_measurement < measurement * 1.01) {
+      // Use the current measurement if it is within 1% of the
+      // previous measurement.
+      return measurement;
+    }
+    last_measurement = measurement;
+    sleep_nanoseconds *= 2;
+  }
+  return last_measurement;
+}
+
+#endif  // ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+
+static double GetNominalCPUFrequency() {
+  long freq = 0;
+
+  // Google's production kernel has a patch to export the TSC
+  // frequency through sysfs. If the kernel is exporting the TSC
+  // frequency use that. There are issues where cpuinfo_max_freq
+  // cannot be relied on because the BIOS may be exporting an invalid
+  // p-state (on x86) or p-states may be used to put the processor in
+  // a new mode (turbo mode). Essentially, those frequencies cannot
+  // always be relied upon. The same reasons apply to /proc/cpuinfo as
+  // well.
+  if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {
+    return freq * 1e3;  // Value is kHz.
+  }
+
+#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
+  // On these platforms, the TSC frequency is the nominal CPU
+  // frequency.  But without having the kernel export it directly
+  // though /sys/devices/system/cpu/cpu0/tsc_freq_khz, there is no
+  // other way to reliably get the TSC frequency, so we have to
+  // measure it ourselves.  Some CPUs abuse cpuinfo_max_freq by
+  // exporting "fake" frequencies for implementing new features. For
+  // example, Intel's turbo mode is enabled by exposing a p-state
+  // value with a higher frequency than that of the real TSC
+  // rate. Because of this, we prefer to measure the TSC rate
+  // ourselves on i386 and x86-64.
+  return MeasureTscFrequency();
+#else
+
+  // If CPU scaling is in effect, we want to use the *maximum*
+  // frequency, not whatever CPU speed some random processor happens
+  // to be using now.
+  if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
+                       &freq)) {
+    return freq * 1e3;  // Value is kHz.
+  }
+
+  return 1.0;
+#endif  // !ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+}
+
+#endif
+
+// InitializeSystemInfo() may be called before main() and before
+// malloc is properly initialized, therefore this must not allocate
+// memory.
+static void InitializeSystemInfo() {
+  num_cpus = GetNumCPUs();
+  nominal_cpu_frequency = GetNominalCPUFrequency();
+}
+
+int NumCPUs() {
+  base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
+  return num_cpus;
+}
+
+double NominalCPUFrequency() {
+  base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
+  return nominal_cpu_frequency;
+}
+
+#if defined(_WIN32)
+
+pid_t GetTID() {
+  return GetCurrentThreadId();
+}
+
+#elif defined(__linux__)
+
+#ifndef SYS_gettid
+#define SYS_gettid __NR_gettid
+#endif
+
+pid_t GetTID() {
+  return syscall(SYS_gettid);
+}
+
+#elif defined(__akaros__)
+
+pid_t GetTID() {
+  // Akaros has a concept of "vcore context", which is the state the program
+  // is forced into when we need to make a user-level scheduling decision, or
+  // run a signal handler.  This is analogous to the interrupt context that a
+  // CPU might enter if it encounters some kind of exception.
+  //
+  // There is no current thread context in vcore context, but we need to give
+  // a reasonable answer if asked for a thread ID (e.g., in a signal handler).
+  // Thread 0 always exists, so if we are in vcore context, we return that.
+  //
+  // Otherwise, we know (since we are using pthreads) that the uthread struct
+  // current_uthread is pointing to is the first element of a
+  // struct pthread_tcb, so we extract and return the thread ID from that.
+  //
+  // TODO(dcross): Akaros anticipates moving the thread ID to the uthread
+  // structure at some point. We should modify this code to remove the cast
+  // when that happens.
+  if (in_vcore_context())
+    return 0;
+  return reinterpret_cast<struct pthread_tcb *>(current_uthread)->id;
+}
+
+#elif defined(__myriad2__)
+
+pid_t GetTID() {
+  uint32_t tid;
+  rtems_task_ident(RTEMS_SELF, 0, &tid);
+  return tid;
+}
+
+#else
+
+// Fallback implementation of GetTID using pthread_getspecific.
+static once_flag tid_once;
+static pthread_key_t tid_key;
+static absl::base_internal::SpinLock tid_lock(
+    absl::base_internal::kLinkerInitialized);
+
+// We set a bit per thread in this array to indicate that an ID is in
+// use. ID 0 is unused because it is the default value returned by
+// pthread_getspecific().
+static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr;
+static constexpr int kBitsPerWord = 32;  // tid_array is uint32_t.
+
+// Returns the TID to tid_array.
+static void FreeTID(void *v) {
+  intptr_t tid = reinterpret_cast<intptr_t>(v);
+  int word = tid / kBitsPerWord;
+  uint32_t mask = ~(1u << (tid % kBitsPerWord));
+  absl::base_internal::SpinLockHolder lock(&tid_lock);
+  assert(0 <= word && static_cast<size_t>(word) < tid_array->size());
+  (*tid_array)[word] &= mask;
+}
+
+static void InitGetTID() {
+  if (pthread_key_create(&tid_key, FreeTID) != 0) {
+    // The logging system calls GetTID() so it can't be used here.
+    perror("pthread_key_create failed");
+    abort();
+  }
+
+  // Initialize tid_array.
+  absl::base_internal::SpinLockHolder lock(&tid_lock);
+  tid_array = new std::vector<uint32_t>(1);
+  (*tid_array)[0] = 1;  // ID 0 is never-allocated.
+}
+
+// Return a per-thread small integer ID from pthread's thread-specific data.
+pid_t GetTID() {
+  absl::call_once(tid_once, InitGetTID);
+
+  intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key));
+  if (tid != 0) {
+    return tid;
+  }
+
+  int bit;  // tid_array[word] = 1u << bit;
+  size_t word;
+  {
+    // Search for the first unused ID.
+    absl::base_internal::SpinLockHolder lock(&tid_lock);
+    // First search for a word in the array that is not all ones.
+    word = 0;
+    while (word < tid_array->size() && ~(*tid_array)[word] == 0) {
+      ++word;
+    }
+    if (word == tid_array->size()) {
+      tid_array->push_back(0);  // No space left, add kBitsPerWord more IDs.
+    }
+    // Search for a zero bit in the word.
+    bit = 0;
+    while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) {
+      ++bit;
+    }
+    tid = (word * kBitsPerWord) + bit;
+    (*tid_array)[word] |= 1u << bit;  // Mark the TID as allocated.
+  }
+
+  if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) {
+    perror("pthread_setspecific failed");
+    abort();
+  }
+
+  return static_cast<pid_t>(tid);
+}
+
+#endif
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h
new file mode 100644
index 0000000..5bd1c50
--- /dev/null
+++ b/absl/base/internal/sysinfo.h
@@ -0,0 +1,63 @@
+// Copyright 2017 The Abseil 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.
+//
+// This file includes routines to find out characteristics
+// of the machine a program is running on.  It is undoubtedly
+// system-dependent.
+
+// Functions listed here that accept a pid_t as an argument act on the
+// current process if the pid_t argument is 0
+// All functions here are thread-hostile due to file caching unless
+// commented otherwise.
+
+#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_
+#define ABSL_BASE_INTERNAL_SYSINFO_H_
+
+#ifndef _WIN32
+#include <sys/types.h>
+#else
+#include <intsafe.h>
+#endif
+
+#include "absl/base/port.h"
+
+namespace absl {
+namespace base_internal {
+
+// Nominal core processor cycles per second of each processor.   This is _not_
+// necessarily the frequency of the CycleClock counter (see cycleclock.h)
+// Thread-safe.
+double NominalCPUFrequency();
+
+// Number of logical processors (hyperthreads) in system. Thread-safe.
+int NumCPUs();
+
+// Return the thread id of the current thread, as told by the system.
+// No two currently-live threads implemented by the OS shall have the same ID.
+// Thread ids of exited threads may be reused.   Multiple user-level threads
+// may have the same thread ID if multiplexed on the same OS thread.
+//
+// On Linux, you may send a signal to the resulting ID with kill().  However,
+// it is recommended for portability that you use pthread_kill() instead.
+#ifdef _WIN32
+// On Windows, process id and thread id are of the same type according to
+// the return types of GetProcessId() and GetThreadId() are both DWORD.
+using pid_t = DWORD;
+#endif
+pid_t GetTID();
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SYSINFO_H_
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
new file mode 100644
index 0000000..e0d9aab
--- /dev/null
+++ b/absl/base/internal/sysinfo_test.cc
@@ -0,0 +1,98 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/sysinfo.h"
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <thread>  // NOLINT(build/c++11)
+#include <unordered_set>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/synchronization/barrier.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+TEST(SysinfoTest, NumCPUs) {
+  EXPECT_NE(NumCPUs(), 0)
+      << "NumCPUs() should not have the default value of 0";
+}
+
+TEST(SysinfoTest, NominalCPUFrequency) {
+#if !(defined(__aarch64__) && defined(__linux__))
+  EXPECT_GE(NominalCPUFrequency(), 1000.0)
+      << "NominalCPUFrequency() did not return a reasonable value";
+#else
+  // TODO(absl-team): Aarch64 cannot read the CPU frequency from sysfs, so we
+  // get back 1.0. Fix once the value is available.
+  EXPECT_EQ(NominalCPUFrequency(), 1.0)
+      << "CPU frequency detection was fixed! Please update unittest.";
+#endif
+}
+
+TEST(SysinfoTest, GetTID) {
+  EXPECT_EQ(GetTID(), GetTID());  // Basic compile and equality test.
+#ifdef __native_client__
+  // Native Client has a race condition bug that leads to memory
+  // exaustion when repeatedly creating and joining threads.
+  // https://bugs.chromium.org/p/nativeclient/issues/detail?id=1027
+  return;
+#endif
+  // Test that TIDs are unique to each thread.
+  // Uses a few loops to exercise implementations that reallocate IDs.
+  for (int i = 0; i < 32; ++i) {
+    constexpr int kNumThreads = 64;
+    Barrier all_threads_done(kNumThreads);
+    std::vector<std::thread> threads;
+
+    Mutex mutex;
+    std::unordered_set<pid_t> tids;
+
+    for (int j = 0; j < kNumThreads; ++j) {
+      threads.push_back(std::thread([&]() {
+        pid_t id = GetTID();
+        {
+          MutexLock lock(&mutex);
+          ASSERT_TRUE(tids.find(id) == tids.end());
+          tids.insert(id);
+        }
+        // We can't simply join the threads here. The threads need to
+        // be alive otherwise the TID might have been reallocated to
+        // another live thread.
+        all_threads_done.Block();
+      }));
+    }
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+}
+
+#ifdef __linux__
+TEST(SysinfoTest, LinuxGetTID) {
+  // On Linux, for the main thread, GetTID()==getpid() is guaranteed by the API.
+  EXPECT_EQ(GetTID(), getpid());
+}
+#endif
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc
new file mode 100644
index 0000000..678e856
--- /dev/null
+++ b/absl/base/internal/thread_identity.cc
@@ -0,0 +1,123 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/thread_identity.h"
+
+#ifndef _WIN32
+#include <pthread.h>
+#include <signal.h>
+#endif
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "absl/base/call_once.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+namespace absl {
+namespace base_internal {
+
+#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+namespace {
+// Used to co-ordinate one-time creation of our pthread_key
+absl::once_flag init_thread_identity_key_once;
+pthread_key_t thread_identity_pthread_key;
+std::atomic<bool> pthread_key_initialized(false);
+
+void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
+  pthread_key_create(&thread_identity_pthread_key, reclaimer);
+  pthread_key_initialized.store(true, std::memory_order_release);
+}
+}  // namespace
+#endif
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+// The actual TLS storage for a thread's currently associated ThreadIdentity.
+// This is referenced by inline accessors in the header.
+// "protected" visibility ensures that if multiple instances of Abseil code
+// exist within a process (via dlopen() or similar), references to
+// thread_identity_ptr from each instance of the code will refer to
+// *different* instances of this ptr.
+#ifdef __GNUC__
+__attribute__((visibility("protected")))
+#endif  // __GNUC__
+  ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
+#endif  // TLS or CPP11
+
+void SetCurrentThreadIdentity(
+    ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) {
+  assert(CurrentThreadIdentityIfPresent() == nullptr);
+  // Associate our destructor.
+  // NOTE: This call to pthread_setspecific is currently the only immovable
+  // barrier to CurrentThreadIdentity() always being async signal safe.
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+  // NOTE: Not async-safe.  But can be open-coded.
+  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
+                  reclaimer);
+  // We must mask signals around the call to setspecific as with current glibc,
+  // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent())
+  // may zero our value.
+  //
+  // While not officially async-signal safe, getspecific within a signal handler
+  // is otherwise OK.
+  sigset_t all_signals;
+  sigset_t curr_signals;
+  sigfillset(&all_signals);
+  pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals);
+  pthread_setspecific(thread_identity_pthread_key,
+                      reinterpret_cast<void*>(identity));
+  pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
+#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
+  // NOTE: Not async-safe.  But can be open-coded.
+  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
+                  reclaimer);
+  pthread_setspecific(thread_identity_pthread_key,
+                      reinterpret_cast<void*>(identity));
+  thread_identity_ptr = identity;
+#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+  thread_local std::unique_ptr<ThreadIdentity, ThreadIdentityReclaimerFunction>
+      holder(identity, reclaimer);
+  thread_identity_ptr = identity;
+#else
+#error Unimplemented ABSL_THREAD_IDENTITY_MODE
+#endif
+}
+
+void ClearCurrentThreadIdentity() {
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+  thread_identity_ptr = nullptr;
+#elif ABSL_THREAD_IDENTITY_MODE == \
+      ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+  // pthread_setspecific expected to clear value on destruction
+  assert(CurrentThreadIdentityIfPresent() == nullptr);
+#endif
+}
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+ThreadIdentity* CurrentThreadIdentityIfPresent() {
+  bool initialized = pthread_key_initialized.load(std::memory_order_acquire);
+  if (!initialized) {
+    return nullptr;
+  }
+  return reinterpret_cast<ThreadIdentity*>(
+      pthread_getspecific(thread_identity_pthread_key));
+}
+#endif
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
new file mode 100644
index 0000000..a51722f
--- /dev/null
+++ b/absl/base/internal/thread_identity.h
@@ -0,0 +1,240 @@
+// Copyright 2017 The Abseil 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.
+//
+// Each active thread has an ThreadIdentity that may represent the thread in
+// various level interfaces.  ThreadIdentity objects are never deallocated.
+// When a thread terminates, its ThreadIdentity object may be reused for a
+// thread created later.
+
+#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
+#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
+
+#ifndef _WIN32
+#include <pthread.h>
+// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
+// supported.
+#include <unistd.h>
+#endif
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/internal/per_thread_tls.h"
+
+namespace absl {
+
+struct SynchLocksHeld;
+struct SynchWaitParams;
+
+namespace base_internal {
+
+class SpinLock;
+struct ThreadIdentity;
+
+// Used by the implementation of base::Mutex and base::CondVar.
+struct PerThreadSynch {
+  // The internal representation of base::Mutex and base::CondVar rely
+  // on the alignment of PerThreadSynch. Both store the address of the
+  // PerThreadSynch in the high-order bits of their internal state,
+  // which means the low kLowZeroBits of the address of PerThreadSynch
+  // must be zero.
+  static constexpr int kLowZeroBits = 8;
+  static constexpr int kAlignment = 1 << kLowZeroBits;
+
+  // Returns the associated ThreadIdentity.
+  // This can be implemented as a cast because we guarantee
+  // PerThreadSynch is the first element of ThreadIdentity.
+  ThreadIdentity* thread_identity() {
+    return reinterpret_cast<ThreadIdentity*>(this);
+  }
+
+  PerThreadSynch *next;  // Circular waiter queue; initialized to 0.
+  PerThreadSynch *skip;  // If non-zero, all entries in Mutex queue
+                         // up to and including "skip" have same
+                         // condition as this, and will be woken later
+  bool may_skip;         // if false while on mutex queue, a mutex unlocker
+                         // is using this PerThreadSynch as a terminator.  Its
+                         // skip field must not be filled in because the loop
+                         // might then skip over the terminator.
+
+  // The wait parameters of the current wait.  waitp is null if the
+  // thread is not waiting. Transitions from null to non-null must
+  // occur before the enqueue commit point (state = kQueued in
+  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
+  // null must occur after the wait is finished (state = kAvailable in
+  // Mutex::Block() and CondVar::WaitCommon()). This field may be
+  // changed only by the thread that describes this PerThreadSynch.  A
+  // special case is Fer(), which calls Enqueue() on another thread,
+  // but with an identical SynchWaitParams pointer, thus leaving the
+  // pointer unchanged.
+  SynchWaitParams *waitp;
+
+  bool suppress_fatal_errors;  // If true, try to proceed even in the face of
+                               // broken invariants.  This is used within fatal
+                               // signal handlers to improve the chances of
+                               // debug logging information being output
+                               // successfully.
+
+  intptr_t readers;     // Number of readers in mutex.
+  int priority;         // Priority of thread (updated every so often).
+
+  // When priority will next be read (cycles).
+  int64_t next_priority_read_cycles;
+
+  // State values:
+  //   kAvailable: This PerThreadSynch is available.
+  //   kQueued: This PerThreadSynch is unavailable, it's currently queued on a
+  //            Mutex or CondVar waistlist.
+  //
+  // Transitions from kQueued to kAvailable require a release
+  // barrier. This is needed as a waiter may use "state" to
+  // independently observe that it's no longer queued.
+  //
+  // Transitions from kAvailable to kQueued require no barrier, they
+  // are externally ordered by the Mutex.
+  enum State {
+    kAvailable,
+    kQueued
+  };
+  std::atomic<State> state;
+
+  bool maybe_unlocking;  // Valid at head of Mutex waiter queue;
+                         // true if UnlockSlow could be searching
+                         // for a waiter to wake.  Used for an optimization
+                         // in Enqueue().  true is always a valid value.
+                         // Can be reset to false when the unlocker or any
+                         // writer releases the lock, or a reader fully releases
+                         // the lock.  It may not be set to false by a reader
+                         // that decrements the count to non-zero.
+                         // protected by mutex spinlock
+
+  bool wake;  // This thread is to be woken from a Mutex.
+
+  // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
+  // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
+  //
+  // The value of "x->cond_waiter" is meaningless if "x" is not on a
+  // Mutex waiter list.
+  bool cond_waiter;
+
+  // Locks held; used during deadlock detection.
+  // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
+  SynchLocksHeld *all_locks;
+};
+
+struct ThreadIdentity {
+  // Must be the first member.  The Mutex implementation requires that
+  // the PerThreadSynch object associated with each thread is
+  // PerThreadSynch::kAlignment aligned.  We provide this alignment on
+  // ThreadIdentity itself.
+  PerThreadSynch per_thread_synch;
+
+  // Private: Reserved for absl::synchronization_internal::Waiter.
+  struct WaiterState {
+    char data[128];
+  } waiter_state;
+
+  // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
+  std::atomic<int>* blocked_count_ptr;
+
+  // The following variables are mostly read/written just by the
+  // thread itself.  The only exception is that these are read by
+  // a ticker thread as a hint.
+  std::atomic<int> ticker;      // Tick counter, incremented once per second.
+  std::atomic<int> wait_start;  // Ticker value when thread started waiting.
+  std::atomic<bool> is_idle;    // Has thread become idle yet?
+
+  ThreadIdentity* next;
+};
+
+// Returns the ThreadIdentity object representing the calling thread; guaranteed
+// to be unique for its lifetime.  The returned object will remain valid for the
+// program's lifetime; although it may be re-assigned to a subsequent thread.
+// If one does not exist, return nullptr instead.
+//
+// Does not malloc(*), and is async-signal safe.
+// [*] Technically pthread_setspecific() does malloc on first use; however this
+// is handled internally within tcmalloc's initialization already.
+//
+// New ThreadIdentity objects can be constructed and associated with a thread
+// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
+ThreadIdentity* CurrentThreadIdentityIfPresent();
+
+using ThreadIdentityReclaimerFunction = void (*)(void*);
+
+// Sets the current thread identity to the given value.  'reclaimer' is a
+// pointer to the global function for cleaning up instances on thread
+// destruction.
+void SetCurrentThreadIdentity(ThreadIdentity* identity,
+                              ThreadIdentityReclaimerFunction reclaimer);
+
+// Removes the currently associated ThreadIdentity from the running thread.
+// This must be called from inside the ThreadIdentityReclaimerFunction, and only
+// from that function.
+void ClearCurrentThreadIdentity();
+
+// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
+// index>
+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set
+#else
+#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
+#endif
+
+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
+#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set
+#else
+#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
+#endif
+
+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set
+#else
+#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
+#endif
+
+#ifdef ABSL_THREAD_IDENTITY_MODE
+#error ABSL_THREAD_IDENTITY_MODE cannot be direcly set
+#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
+#elif defined(_WIN32)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
+    (__GOOGLE_GRTE_VERSION__ >= 20140228L)
+// Support for async-safe TLS was specifically added in GRTEv4.  It's not
+// present in the upstream eglibc.
+// Note:  Current default for production systems.
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
+#else
+#define ABSL_THREAD_IDENTITY_MODE \
+  ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+#endif
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+
+extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
+
+inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
+  return thread_identity_ptr;
+}
+
+#elif ABSL_THREAD_IDENTITY_MODE != \
+    ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+#error Unknown ABSL_THREAD_IDENTITY_MODE
+#endif
+
+}  // namespace base_internal
+}  // namespace absl
+#endif  // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc
new file mode 100644
index 0000000..242522b
--- /dev/null
+++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 The Abseil 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 "benchmark/benchmark.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+namespace {
+
+void BM_SafeCurrentThreadIdentity(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::synchronization_internal::GetOrCreateCurrentThreadIdentity());
+  }
+}
+BENCHMARK(BM_SafeCurrentThreadIdentity);
+
+void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::base_internal::CurrentThreadIdentityIfPresent());
+  }
+}
+BENCHMARK(BM_UnsafeCurrentThreadIdentity);
+
+}  // namespace
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
new file mode 100644
index 0000000..ecb8af6
--- /dev/null
+++ b/absl/base/internal/thread_identity_test.cc
@@ -0,0 +1,126 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/thread_identity.h"
+
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/macros.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+// protects num_identities_reused
+static absl::base_internal::SpinLock map_lock(
+    absl::base_internal::kLinkerInitialized);
+static int num_identities_reused;
+
+static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
+
+static void TestThreadIdentityCurrent(const void* assert_no_identity) {
+  ThreadIdentity* identity;
+
+  // We have to test this conditionally, because if the test framework relies
+  // on Abseil, then some previous action may have already allocated an
+  // identity.
+  if (assert_no_identity == kCheckNoIdentity) {
+    identity = CurrentThreadIdentityIfPresent();
+    EXPECT_TRUE(identity == nullptr);
+  }
+
+  identity = synchronization_internal::GetOrCreateCurrentThreadIdentity();
+  EXPECT_TRUE(identity != nullptr);
+  ThreadIdentity* identity_no_init;
+  identity_no_init = CurrentThreadIdentityIfPresent();
+  EXPECT_TRUE(identity == identity_no_init);
+
+  // Check that per_thread_synch is correctly aligned.
+  EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
+                   PerThreadSynch::kAlignment);
+  EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
+
+  absl::base_internal::SpinLockHolder l(&map_lock);
+  num_identities_reused++;
+}
+
+TEST(ThreadIdentityTest, BasicIdentityWorks) {
+  // This tests for the main() thread.
+  TestThreadIdentityCurrent(nullptr);
+}
+
+TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
+  // Now try the same basic test with multiple threads being created and
+  // destroyed.  This makes sure that:
+  // - New threads are created without a ThreadIdentity.
+  // - We re-allocate ThreadIdentity objects from the free-list.
+  // - If a thread implementation chooses to recycle threads, that
+  //   correct re-initialization occurs.
+  static const int kNumLoops = 3;
+  static const int kNumThreads = 400;
+  for (int iter = 0; iter < kNumLoops; iter++) {
+    std::vector<std::thread> threads;
+    for (int i = 0; i < kNumThreads; ++i) {
+      threads.push_back(
+          std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
+    }
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+
+  // We should have recycled ThreadIdentity objects above; while (external)
+  // library threads allocating their own identities may preclude some
+  // reuse, we should have sufficient repetitions to exclude this.
+  EXPECT_LT(kNumThreads, num_identities_reused);
+}
+
+TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
+  // This test repeatly creates and joins a series of threads, each of
+  // which acquires and releases shared Mutex locks. This verifies
+  // Mutex operations work correctly under a reused
+  // ThreadIdentity. Note that the most likely failure mode of this
+  // test is a crash or deadlock.
+  static const int kNumLoops = 10;
+  static const int kNumThreads = 12;
+  static const int kNumMutexes = 3;
+  static const int kNumLockLoops = 5;
+
+  Mutex mutexes[kNumMutexes];
+  for (int iter = 0; iter < kNumLoops; ++iter) {
+    std::vector<std::thread> threads;
+    for (int thread = 0; thread < kNumThreads; ++thread) {
+      threads.push_back(std::thread([&]() {
+        for (int l = 0; l < kNumLockLoops; ++l) {
+          for (int m = 0; m < kNumMutexes; ++m) {
+            MutexLock lock(&mutexes[m]);
+          }
+        }
+      }));
+    }
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+}
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc
new file mode 100644
index 0000000..46dc573
--- /dev/null
+++ b/absl/base/internal/throw_delegate.cc
@@ -0,0 +1,106 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/throw_delegate.h"
+
+#include <cstdlib>
+#include <functional>
+#include <new>
+#include <stdexcept>
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace base_internal {
+
+namespace {
+template <typename T>
+[[noreturn]] void Throw(const T& error) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw error;
+#else
+  ABSL_RAW_LOG(ERROR, "%s", error.what());
+  abort();
+#endif
+}
+}  // namespace
+
+void ThrowStdLogicError(const std::string& what_arg) {
+  Throw(std::logic_error(what_arg));
+}
+void ThrowStdLogicError(const char* what_arg) {
+  Throw(std::logic_error(what_arg));
+}
+void ThrowStdInvalidArgument(const std::string& what_arg) {
+  Throw(std::invalid_argument(what_arg));
+}
+void ThrowStdInvalidArgument(const char* what_arg) {
+  Throw(std::invalid_argument(what_arg));
+}
+
+void ThrowStdDomainError(const std::string& what_arg) {
+  Throw(std::domain_error(what_arg));
+}
+void ThrowStdDomainError(const char* what_arg) {
+  Throw(std::domain_error(what_arg));
+}
+
+void ThrowStdLengthError(const std::string& what_arg) {
+  Throw(std::length_error(what_arg));
+}
+void ThrowStdLengthError(const char* what_arg) {
+  Throw(std::length_error(what_arg));
+}
+
+void ThrowStdOutOfRange(const std::string& what_arg) {
+  Throw(std::out_of_range(what_arg));
+}
+void ThrowStdOutOfRange(const char* what_arg) {
+  Throw(std::out_of_range(what_arg));
+}
+
+void ThrowStdRuntimeError(const std::string& what_arg) {
+  Throw(std::runtime_error(what_arg));
+}
+void ThrowStdRuntimeError(const char* what_arg) {
+  Throw(std::runtime_error(what_arg));
+}
+
+void ThrowStdRangeError(const std::string& what_arg) {
+  Throw(std::range_error(what_arg));
+}
+void ThrowStdRangeError(const char* what_arg) {
+  Throw(std::range_error(what_arg));
+}
+
+void ThrowStdOverflowError(const std::string& what_arg) {
+  Throw(std::overflow_error(what_arg));
+}
+void ThrowStdOverflowError(const char* what_arg) {
+  Throw(std::overflow_error(what_arg));
+}
+
+void ThrowStdUnderflowError(const std::string& what_arg) {
+  Throw(std::underflow_error(what_arg));
+}
+void ThrowStdUnderflowError(const char* what_arg) {
+  Throw(std::underflow_error(what_arg));
+}
+
+void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
+
+void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/throw_delegate.h b/absl/base/internal/throw_delegate.h
new file mode 100644
index 0000000..70e2d77
--- /dev/null
+++ b/absl/base/internal/throw_delegate.h
@@ -0,0 +1,71 @@
+//
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
+#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
+
+#include <string>
+
+namespace absl {
+namespace base_internal {
+
+// Helper functions that allow throwing exceptions consistently from anywhere.
+// The main use case is for header-based libraries (eg templates), as they will
+// be built by many different targets with their own compiler options.
+// In particular, this will allow a safe way to throw exceptions even if the
+// caller is compiled with -fno-exceptions.  This is intended for implementing
+// things like map<>::at(), which the standard documents as throwing an
+// exception on error.
+//
+// Using other techniques like #if tricks could lead to ODR violations.
+//
+// You shouldn't use it unless you're writing code that you know will be built
+// both with and without exceptions and you need to conform to an interface
+// that uses exceptions.
+
+[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
+[[noreturn]] void ThrowStdLogicError(const char* what_arg);
+[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
+[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
+[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
+[[noreturn]] void ThrowStdDomainError(const char* what_arg);
+[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
+[[noreturn]] void ThrowStdLengthError(const char* what_arg);
+[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
+[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
+[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
+[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
+[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
+[[noreturn]] void ThrowStdRangeError(const char* what_arg);
+[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
+[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
+[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
+[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);
+
+[[noreturn]] void ThrowStdBadFunctionCall();
+[[noreturn]] void ThrowStdBadAlloc();
+
+// ThrowStdBadArrayNewLength() cannot be consistently supported because
+// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
+// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
+// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
+// libcxx (as of 3.2) and msvc (as of 2015) both have it.
+// [[noreturn]] void ThrowStdBadArrayNewLength();
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
diff --git a/absl/base/internal/tsan_mutex_interface.h b/absl/base/internal/tsan_mutex_interface.h
new file mode 100644
index 0000000..6bb4fae
--- /dev/null
+++ b/absl/base/internal/tsan_mutex_interface.h
@@ -0,0 +1,66 @@
+// Copyright 2017 The Abseil 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.
+//
+// This file is intended solely for spinlock.h.
+// It provides ThreadSanitizer annotations for custom mutexes.
+// See <sanitizer/tsan_interface.h> for meaning of these annotations.
+
+#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
+#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
+
+// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+// Macro intended only for internal use.
+//
+// Checks whether LLVM Thread Sanitizer interfaces are available.
+// First made available in LLVM 5.0 (Sep 2017).
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
+#endif
+
+#if defined(THREAD_SANITIZER) && defined(__has_include)
+#if __has_include(<sanitizer/tsan_interface.h>)
+#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
+#endif
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+#include <sanitizer/tsan_interface.h>
+
+#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
+#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
+#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
+#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
+#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
+#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
+#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
+#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
+#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
+#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert
+
+#else
+
+#define ABSL_TSAN_MUTEX_CREATE(...)
+#define ABSL_TSAN_MUTEX_DESTROY(...)
+#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
+#define ABSL_TSAN_MUTEX_POST_LOCK(...)
+#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
+#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
+#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
+#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
+#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
+#define ABSL_TSAN_MUTEX_POST_DIVERT(...)
+
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h
new file mode 100644
index 0000000..c572436
--- /dev/null
+++ b/absl/base/internal/unaligned_access.h
@@ -0,0 +1,256 @@
+//
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
+#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
+
+#include <string.h>
+#include <cstdint>
+
+#include "absl/base/attributes.h"
+
+// unaligned APIs
+
+// Portable handling of unaligned loads, stores, and copies.
+// On some platforms, like ARM, the copy functions can be more efficient
+// then a load and a store.
+//
+// It is possible to implement all of these these using constant-length memcpy
+// calls, which is portable and will usually be inlined into simple loads and
+// stores if the architecture supports it. However, such inlining usually
+// happens in a pass that's quite late in compilation, which means the resulting
+// loads and stores cannot participate in many other optimizations, leading to
+// overall worse code.
+
+// The unaligned API is C++ only.  The declarations use C++ features
+// (namespaces, inline) which are absent or incompatible in C.
+#if defined(__cplusplus)
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
+    defined(MEMORY_SANITIZER)
+// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
+// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
+// will miss a bug if 08 is the first unaddressable byte.
+// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
+// miss a race between this access and some other accesses to 08.
+// MemorySanitizer will correctly propagate the shadow on unaligned stores
+// and correctly report bugs on unaligned loads, but it may not properly
+// update and report the origin of the uninitialized memory.
+// For all three tools, replacing an unaligned access with a tool-specific
+// callback solves the problem.
+
+// Make sure uint16_t/uint32_t/uint64_t are defined.
+#include <stdint.h>
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(const void *p);
+uint32_t __sanitizer_unaligned_load32(const void *p);
+uint64_t __sanitizer_unaligned_load64(const void *p);
+void __sanitizer_unaligned_store16(void *p, uint16_t v);
+void __sanitizer_unaligned_store32(void *p, uint32_t v);
+void __sanitizer_unaligned_store64(void *p, uint64_t v);
+}  // extern "C"
+
+namespace absl {
+
+inline uint16_t UnalignedLoad16(const void *p) {
+  return __sanitizer_unaligned_load16(p);
+}
+
+inline uint32_t UnalignedLoad32(const void *p) {
+  return __sanitizer_unaligned_load32(p);
+}
+
+inline uint64_t UnalignedLoad64(const void *p) {
+  return __sanitizer_unaligned_load64(p);
+}
+
+inline void UnalignedStore16(void *p, uint16_t v) {
+  __sanitizer_unaligned_store16(p, v);
+}
+
+inline void UnalignedStore32(void *p, uint32_t v) {
+  __sanitizer_unaligned_store32(p, v);
+}
+
+inline void UnalignedStore64(void *p, uint64_t v) {
+  __sanitizer_unaligned_store64(p, v);
+}
+
+}  // namespace absl
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
+
+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
+  (absl::UnalignedStore16(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
+  (absl::UnalignedStore32(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
+  (absl::UnalignedStore64(_p, _val))
+
+#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
+    defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) ||    \
+    defined(__ppc64__) || defined(__PPC64__)
+
+// x86 and x86-64 can perform unaligned loads/stores directly;
+// modern PowerPC hardware can also do unaligned integer loads and stores;
+// but note: the FPU still sends unaligned loads and stores to a trap handler!
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
+  (*reinterpret_cast<const uint16_t *>(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
+  (*reinterpret_cast<const uint32_t *>(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
+  (*reinterpret_cast<const uint64_t *>(_p))
+
+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
+  (*reinterpret_cast<uint16_t *>(_p) = (_val))
+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
+  (*reinterpret_cast<uint32_t *>(_p) = (_val))
+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
+  (*reinterpret_cast<uint64_t *>(_p) = (_val))
+
+#elif defined(__arm__) && \
+      !defined(__ARM_ARCH_5__) && \
+      !defined(__ARM_ARCH_5T__) && \
+      !defined(__ARM_ARCH_5TE__) && \
+      !defined(__ARM_ARCH_5TEJ__) && \
+      !defined(__ARM_ARCH_6__) && \
+      !defined(__ARM_ARCH_6J__) && \
+      !defined(__ARM_ARCH_6K__) && \
+      !defined(__ARM_ARCH_6Z__) && \
+      !defined(__ARM_ARCH_6ZK__) && \
+      !defined(__ARM_ARCH_6T2__)
+
+
+// ARMv7 and newer support native unaligned accesses, but only of 16-bit
+// and 32-bit values (not 64-bit); older versions either raise a fatal signal,
+// do an unaligned read and rotate the words around a bit, or do the reads very
+// slowly (trip through kernel mode). There's no simple #define that says just
+// "ARMv7 or higher", so we have to filter away all ARMv5 and ARMv6
+// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define,
+// so in time, maybe we can move on to that.
+//
+// This is a mess, but there's not much we can do about it.
+//
+// To further complicate matters, only LDR instructions (single reads) are
+// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we
+// explicitly tell the compiler that these accesses can be unaligned, it can and
+// will combine accesses. On armcc, the way to signal this is done by accessing
+// through the type (uint32_t __packed *), but GCC has no such attribute
+// (it ignores __attribute__((packed)) on individual variables). However,
+// we can tell it that a _struct_ is unaligned, which has the same effect,
+// so we do that.
+
+namespace absl {
+namespace internal {
+
+struct Unaligned16Struct {
+  uint16_t value;
+  uint8_t dummy;  // To make the size non-power-of-two.
+} ABSL_ATTRIBUTE_PACKED;
+
+struct Unaligned32Struct {
+  uint32_t value;
+  uint8_t dummy;  // To make the size non-power-of-two.
+} ABSL_ATTRIBUTE_PACKED;
+
+}  // namespace internal
+}  // namespace absl
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
+  ((reinterpret_cast<const ::absl::internal::Unaligned16Struct *>(_p))->value)
+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
+  ((reinterpret_cast<const ::absl::internal::Unaligned32Struct *>(_p))->value)
+
+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val)                          \
+  ((reinterpret_cast< ::absl::internal::Unaligned16Struct *>(_p))->value = \
+       (_val))
+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val)                          \
+  ((reinterpret_cast< ::absl::internal::Unaligned32Struct *>(_p))->value = \
+       (_val))
+
+namespace absl {
+
+inline uint64_t UnalignedLoad64(const void *p) {
+  uint64_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
+
+}  // namespace absl
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
+  (absl::UnalignedStore64(_p, _val))
+
+#else
+
+// ABSL_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform
+// doesn't support unaligned access.
+#define ABSL_INTERNAL_NEED_ALIGNED_LOADS
+
+// These functions are provided for architectures that don't support
+// unaligned loads and stores.
+
+namespace absl {
+
+inline uint16_t UnalignedLoad16(const void *p) {
+  uint16_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32_t UnalignedLoad32(const void *p) {
+  uint32_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64_t UnalignedLoad64(const void *p) {
+  uint64_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
+
+inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
+
+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
+
+}  // namespace absl
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
+
+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
+  (absl::UnalignedStore16(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
+  (absl::UnalignedStore32(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
+  (absl::UnalignedStore64(_p, _val))
+
+#endif
+
+#endif  // defined(__cplusplus), end of unaligned API
+
+#endif  // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
new file mode 100644
index 0000000..a12d68b
--- /dev/null
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -0,0 +1,101 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/unscaledcycleclock.h"
+
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+
+#if defined(_WIN32)
+#include <intrin.h>
+#endif
+
+#if defined(__powerpc__) || defined(__ppc__)
+#include <sys/platform/ppc.h>
+#endif
+
+#include "absl/base/internal/sysinfo.h"
+
+namespace absl {
+namespace base_internal {
+
+#if defined(__i386__)
+
+int64_t UnscaledCycleClock::Now() {
+  int64_t ret;
+  __asm__ volatile("rdtsc" : "=A"(ret));
+  return ret;
+}
+
+double UnscaledCycleClock::Frequency() {
+  return base_internal::NominalCPUFrequency();
+}
+
+#elif defined(__x86_64__)
+
+int64_t UnscaledCycleClock::Now() {
+  uint64_t low, high;
+  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
+  return (high << 32) | low;
+}
+
+double UnscaledCycleClock::Frequency() {
+  return base_internal::NominalCPUFrequency();
+}
+
+#elif defined(__powerpc__) || defined(__ppc__)
+
+int64_t UnscaledCycleClock::Now() {
+  return __ppc_get_timebase();
+}
+
+double UnscaledCycleClock::Frequency() {
+  return __ppc_get_timebase_freq();
+}
+
+#elif defined(__aarch64__)
+
+// System timer of ARMv8 runs at a different frequency than the CPU's.
+// The frequency is fixed, typically in the range 1-50MHz.  It can be
+// read at CNTFRQ special register.  We assume the OS has set up
+// the virtual timer properly.
+int64_t UnscaledCycleClock::Now() {
+  int64_t virtual_timer_value;
+  asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
+  return virtual_timer_value;
+}
+
+double UnscaledCycleClock::Frequency() {
+  uint64_t aarch64_timer_frequency;
+  asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency));
+  return aarch64_timer_frequency;
+}
+
+#elif defined(_M_IX86) || defined(_M_X64)
+
+#pragma intrinsic(__rdtsc)
+
+int64_t UnscaledCycleClock::Now() {
+  return __rdtsc();
+}
+
+double UnscaledCycleClock::Frequency() {
+  return base_internal::NominalCPUFrequency();
+}
+
+#endif
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_USE_UNSCALED_CYCLECLOCK
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h
new file mode 100644
index 0000000..049f1ca
--- /dev/null
+++ b/absl/base/internal/unscaledcycleclock.h
@@ -0,0 +1,119 @@
+// Copyright 2017 The Abseil 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.
+//
+// UnscaledCycleClock
+//    An UnscaledCycleClock yields the value and frequency of a cycle counter
+//    that increments at a rate that is approximately constant.
+//    This class is for internal / whitelisted use only, you should consider
+//    using CycleClock instead.
+//
+// Notes:
+// The cycle counter frequency is not necessarily the core clock frequency.
+// That is, CycleCounter cycles are not necessarily "CPU cycles".
+//
+// An arbitrary offset may have been added to the counter at power on.
+//
+// On some platforms, the rate and offset of the counter may differ
+// slightly when read from different CPUs of a multiprocessor.  Usually,
+// we try to ensure that the operating system adjusts values periodically
+// so that values agree approximately.   If you need stronger guarantees,
+// consider using alternate interfaces.
+//
+// The CPU is not required to maintain the ordering of a cycle counter read
+// with respect to surrounding instructions.
+
+#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
+#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
+
+#include <cstdint>
+
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#endif
+
+#include "absl/base/port.h"
+
+// The following platforms have an implementation of a hardware counter.
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
+  defined(__powerpc__) || defined(__ppc__) || \
+  defined(_M_IX86) || defined(_M_X64)
+#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
+#else
+#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
+#endif
+
+// The following platforms often disable access to the hardware
+// counter (through a sandbox) even if the underlying hardware has a
+// usable counter. The CycleTimer interface also requires a *scaled*
+// CycleClock that runs at atleast 1 MHz. We've found some Android
+// ARM64 devices where this is not the case, so we disable it by
+// default on Android ARM64.
+#if defined(__native_client__) || TARGET_OS_IPHONE || \
+    (defined(__ANDROID__) && defined(__aarch64__))
+#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
+#else
+#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1
+#endif
+
+// UnscaledCycleClock is an optional internal feature.
+// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence.
+// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1
+#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK)
+#define ABSL_USE_UNSCALED_CYCLECLOCK               \
+  (ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \
+   ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT)
+#endif
+
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+
+// This macro can be used to test if UnscaledCycleClock::Frequency()
+// is NominalCPUFrequency() on a particular platform.
+#if  (defined(__i386__) || defined(__x86_64__) || \
+      defined(_M_IX86) || defined(_M_X64))
+#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+#endif
+namespace absl {
+namespace time_internal {
+class UnscaledCycleClockWrapperForGetCurrentTime;
+}  // namespace time_internal
+
+namespace base_internal {
+class CycleClock;
+class UnscaledCycleClockWrapperForInitializeFrequency;
+
+class UnscaledCycleClock {
+ private:
+  UnscaledCycleClock() = delete;
+
+  // Return the value of a cycle counter that counts at a rate that is
+  // approximately constant.
+  static int64_t Now();
+
+  // Return the how much UnscaledCycleClock::Now() increases per second.
+  // This is not necessarily the core CPU clock frequency.
+  // It may be the nominal value report by the kernel, rather than a measured
+  // value.
+  static double Frequency();
+
+  // Whitelisted friends.
+  friend class base_internal::CycleClock;
+  friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
+  friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
+};
+
+}  // namespace base_internal
+}  // namespace absl
+#endif  // ABSL_USE_UNSCALED_CYCLECLOCK
+
+#endif  // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
new file mode 100644
index 0000000..466bf11
--- /dev/null
+++ b/absl/base/invoke_test.cc
@@ -0,0 +1,200 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/invoke.h"
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+int Function(int a, int b) { return a - b; }
+
+int Sink(std::unique_ptr<int> p) {
+  return *p;
+}
+
+std::unique_ptr<int> Factory(int n) {
+  return make_unique<int>(n);
+}
+
+void NoOp() {}
+
+struct ConstFunctor {
+  int operator()(int a, int b) const { return a - b; }
+};
+
+struct MutableFunctor {
+  int operator()(int a, int b) { return a - b; }
+};
+
+struct EphemeralFunctor {
+  int operator()(int a, int b) && { return a - b; }
+};
+
+struct OverloadedFunctor {
+  template <typename... Args>
+  std::string operator()(const Args&... args) & {
+    return StrCat("&", args...);
+  }
+  template <typename... Args>
+  std::string operator()(const Args&... args) const& {
+    return StrCat("const&", args...);
+  }
+  template <typename... Args>
+  std::string operator()(const Args&... args) && {
+    return StrCat("&&", args...);
+  }
+};
+
+struct Class {
+  int Method(int a, int b) { return a - b; }
+  int ConstMethod(int a, int b) const { return a - b; }
+
+  int member;
+};
+
+struct FlipFlop {
+  int ConstMethod() const { return member; }
+  FlipFlop operator*() const { return {-member}; }
+
+  int member;
+};
+
+// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
+// on which one is valid.
+template <typename F>
+decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) {
+  return Invoke(f);
+}
+
+template <typename F>
+decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
+  return Invoke(f, 42);
+}
+
+TEST(InvokeTest, Function) {
+  EXPECT_EQ(1, Invoke(Function, 3, 2));
+  EXPECT_EQ(1, Invoke(&Function, 3, 2));
+}
+
+TEST(InvokeTest, NonCopyableArgument) {
+  EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
+}
+
+TEST(InvokeTest, NonCopyableResult) {
+  EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
+}
+
+TEST(InvokeTest, VoidResult) {
+  Invoke(NoOp);
+}
+
+TEST(InvokeTest, ConstFunctor) {
+  EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
+}
+
+TEST(InvokeTest, MutableFunctor) {
+  MutableFunctor f;
+  EXPECT_EQ(1, Invoke(f, 3, 2));
+  EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
+}
+
+TEST(InvokeTest, EphemeralFunctor) {
+  EphemeralFunctor f;
+  EXPECT_EQ(1, Invoke(std::move(f), 3, 2));
+  EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2));
+}
+
+TEST(InvokeTest, OverloadedFunctor) {
+  OverloadedFunctor f;
+  const OverloadedFunctor& cf = f;
+
+  EXPECT_EQ("&", Invoke(f));
+  EXPECT_EQ("& 42", Invoke(f, " 42"));
+
+  EXPECT_EQ("const&", Invoke(cf));
+  EXPECT_EQ("const& 42", Invoke(cf, " 42"));
+
+  EXPECT_EQ("&&", Invoke(std::move(f)));
+  EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
+}
+
+TEST(InvokeTest, ReferenceWrapper) {
+  ConstFunctor cf;
+  MutableFunctor mf;
+  EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2));
+  EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2));
+  EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2));
+}
+
+TEST(InvokeTest, MemberFunction) {
+  std::unique_ptr<Class> p(new Class);
+  std::unique_ptr<const Class> cp(new Class);
+  EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
+
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2));
+
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
+
+  EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
+  EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
+}
+
+TEST(InvokeTest, DataMember) {
+  std::unique_ptr<Class> p(new Class{42});
+  std::unique_ptr<const Class> cp(new Class{42});
+  EXPECT_EQ(42, Invoke(&Class::member, p));
+  EXPECT_EQ(42, Invoke(&Class::member, *p));
+  EXPECT_EQ(42, Invoke(&Class::member, p.get()));
+
+  Invoke(&Class::member, p) = 42;
+  Invoke(&Class::member, p.get()) = 42;
+
+  EXPECT_EQ(42, Invoke(&Class::member, cp));
+  EXPECT_EQ(42, Invoke(&Class::member, *cp));
+  EXPECT_EQ(42, Invoke(&Class::member, cp.get()));
+}
+
+TEST(InvokeTest, FlipFlop) {
+  FlipFlop obj = {42};
+  // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
+  // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
+  EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj));
+  EXPECT_EQ(42, Invoke(&FlipFlop::member, obj));
+}
+
+TEST(InvokeTest, SfinaeFriendly) {
+  CallMaybeWithArg(NoOp);
+  EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42));
+}
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h
new file mode 100644
index 0000000..e2931c3
--- /dev/null
+++ b/absl/base/log_severity.h
@@ -0,0 +1,67 @@
+// Copyright 2017 The Abseil 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 ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+
+#include <array>
+
+#include "absl/base/attributes.h"
+
+namespace absl {
+
+// Four severity levels are defined.  Logging APIs should terminate the program
+// when a message is logged at severity `kFatal`; the other levels have no
+// special semantics.
+enum class LogSeverity : int {
+  kInfo = 0,
+  kWarning = 1,
+  kError = 2,
+  kFatal = 3,
+};
+
+// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
+// least to most severe.
+constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
+  return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
+           absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
+}
+
+// Returns the all-caps std::string representation (e.g. "INFO") of the specified
+// severity level if it is one of the normal levels and "UNKNOWN" otherwise.
+constexpr const char* LogSeverityName(absl::LogSeverity s) {
+  return s == absl::LogSeverity::kInfo
+             ? "INFO"
+             : s == absl::LogSeverity::kWarning
+                   ? "WARNING"
+                   : s == absl::LogSeverity::kError
+                         ? "ERROR"
+                         : s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN";
+}
+
+// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
+// normalize to `kError` (**NOT** `kFatal`).
+constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
+  return s < absl::LogSeverity::kInfo
+             ? absl::LogSeverity::kInfo
+             : s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError : s;
+}
+constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
+  return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
+}
+
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
diff --git a/absl/base/macros.h b/absl/base/macros.h
new file mode 100644
index 0000000..ca3d5ed
--- /dev/null
+++ b/absl/base/macros.h
@@ -0,0 +1,202 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: macros.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the set of language macros used within Abseil code.
+// For the set of macros used to determine supported compilers and platforms,
+// see absl/base/config.h instead.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems.  Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+
+#ifndef ABSL_BASE_MACROS_H_
+#define ABSL_BASE_MACROS_H_
+
+#include <cassert>
+#include <cstddef>
+
+#include "absl/base/port.h"
+
+// ABSL_ARRAYSIZE()
+//
+// Returns the number of elements in an array as a compile-time constant, which
+// can be used in defining new arrays. If you use this macro on a pointer by
+// mistake, you will get a compile-time error.
+#define ABSL_ARRAYSIZE(array) \
+  (sizeof(::absl::macros_internal::ArraySizeHelper(array)))
+
+namespace absl {
+namespace macros_internal {
+// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
+// The function doesn't need a definition, as we only use its type.
+template <typename T, size_t N>
+auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
+}  // namespace macros_internal
+}  // namespace absl
+
+// kLinkerInitialized
+//
+// An enum used only as a constructor argument to indicate that a variable has
+// static storage duration, and that the constructor should do nothing to its
+// state. Use of this macro indicates to the reader that it is legal to
+// declare a static instance of the class, provided the constructor is given
+// the absl::base_internal::kLinkerInitialized argument.
+//
+// Normally, it is unsafe to declare a static variable that has a constructor or
+// a destructor because invocation order is undefined. However, if the type can
+// be zero-initialized (which the loader does for static variables) into a valid
+// state and the type's destructor does not affect storage, then a constructor
+// for static initialization can be declared.
+//
+// Example:
+//       // Declaration
+//       explicit MyClass(absl::base_internal:LinkerInitialized x) {}
+//
+//       // Invocation
+//       static MyClass my_global(absl::base_internal::kLinkerInitialized);
+namespace absl {
+namespace base_internal {
+enum LinkerInitialized {
+  kLinkerInitialized = 0,
+};
+}  // namespace base_internal
+}  // namespace absl
+
+// ABSL_FALLTHROUGH_INTENDED
+//
+// Annotates implicit fall-through between switch labels, allowing a case to
+// indicate intentional fallthrough and turn off warnings about any lack of a
+// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
+// a semicolon and can be used in most places where `break` can, provided that
+// no statements exist between it and the next switch label.
+//
+// Example:
+//
+//  switch (x) {
+//    case 40:
+//    case 41:
+//      if (truth_is_out_there) {
+//        ++x;
+//        ABSL_FALLTHROUGH_INTENDED;  // Use instead of/along with annotations
+//                                    // in comments
+//      } else {
+//        return x;
+//      }
+//    case 42:
+//      ...
+//
+// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
+// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
+// when  performing switch labels fall-through diagnostic
+// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
+// for details:
+// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
+//
+// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
+// has no effect on diagnostics. In any case this macro has no effect on runtime
+// behavior and performance of code.
+#ifdef ABSL_FALLTHROUGH_INTENDED
+#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
+#endif
+
+// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
+#endif
+#elif defined(__GNUC__) && __GNUC__ >= 7
+#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
+#endif
+
+#ifndef ABSL_FALLTHROUGH_INTENDED
+#define ABSL_FALLTHROUGH_INTENDED \
+  do {                            \
+  } while (0)
+#endif
+
+// ABSL_DEPRECATED()
+//
+// Marks a deprecated class, struct, enum, function, method and variable
+// declarations. The macro argument is used as a custom diagnostic message (e.g.
+// suggestion of a better alternative).
+//
+// Example:
+//
+//   class ABSL_DEPRECATED("Use Bar instead") Foo {...};
+//   ABSL_DEPRECATED("Use Baz instead") void Bar() {...}
+//
+// Every usage of a deprecated entity will trigger a warning when compiled with
+// clang's `-Wdeprecated-declarations` option. This option is turned off by
+// default, but the warnings will be reported by clang-tidy.
+#if defined(__clang__) && __cplusplus >= 201103L
+#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+
+#ifndef ABSL_DEPRECATED
+#define ABSL_DEPRECATED(message)
+#endif
+
+// ABSL_BAD_CALL_IF()
+//
+// Used on a function overload to trap bad calls: any call that matches the
+// overload will cause a compile-time error. This macro uses a clang-specific
+// "enable_if" attribute, as described at
+// http://clang.llvm.org/docs/AttributeReference.html#enable-if
+//
+// Overloads which use this macro should be bracketed by
+// `#ifdef ABSL_BAD_CALL_IF`.
+//
+// Example:
+//
+//   int isdigit(int c);
+//   #ifdef ABSL_BAD_CALL_IF
+//   int isdigit(int c)
+//     ABSL_BAD_CALL_IF(c <= -1 || c > 255,
+//                       "'c' must have the value of an unsigned char or EOF");
+//   #endif // ABSL_BAD_CALL_IF
+
+#if defined(__clang__)
+# if __has_attribute(enable_if)
+#  define ABSL_BAD_CALL_IF(expr, msg) \
+    __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
+# endif
+#endif
+
+// ABSL_ASSERT()
+//
+// In C++11, `assert` can't be used portably within constexpr functions.
+// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
+// functions.  Example:
+//
+// constexpr double Divide(double a, double b) {
+//   return ABSL_ASSERT(b != 0), a / b;
+// }
+//
+// This macro is inspired by
+// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
+#if defined(NDEBUG)
+#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
+#else
+#define ABSL_ASSERT(expr)              \
+  (ABSL_PREDICT_TRUE((expr)) ? (void)0 \
+                             : [] { assert(false && #expr); }())  // NOLINT
+#endif
+
+#endif  // ABSL_BASE_MACROS_H_
diff --git a/absl/base/module.mk b/absl/base/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/absl/base/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
new file mode 100644
index 0000000..2fddfc8
--- /dev/null
+++ b/absl/base/optimization.h
@@ -0,0 +1,165 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: optimization.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines portable macros for performance optimization.
+
+#ifndef ABSL_BASE_OPTIMIZATION_H_
+#define ABSL_BASE_OPTIMIZATION_H_
+
+#include "absl/base/config.h"
+
+// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
+//
+// Instructs the compiler to avoid optimizing tail-call recursion. Use of this
+// macro is useful when you wish to preserve the existing function order within
+// a stack trace for logging, debugging, or profiling purposes.
+//
+// Example:
+//
+//   int f() {
+//     int result = g();
+//     ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+//     return result;
+//   }
+#if defined(__pnacl__)
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
+#elif defined(__clang__)
+// Clang will not tail call given inline volatile assembly.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
+#elif defined(__GNUC__)
+// GCC will not tail call given inline volatile assembly.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
+#elif defined(_MSC_VER)
+#include <intrin.h>
+// The __nop() intrinsic blocks the optimisation.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
+#else
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
+#endif
+
+// ABSL_CACHELINE_SIZE
+//
+// Explicitly defines the size of the L1 cache for purposes of alignment.
+// Setting the cacheline size allows you to specify that certain objects be
+// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
+// (See below.)
+//
+// NOTE: this macro should be replaced with the following C++17 features, when
+// those are generally available:
+//
+//   * `std::hardware_constructive_interference_size`
+//   * `std::hardware_destructive_interference_size`
+//
+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
+// for more information.
+#if defined(__GNUC__)
+// Cache line alignment
+#if defined(__i386__) || defined(__x86_64__)
+#define ABSL_CACHELINE_SIZE 64
+#elif defined(__powerpc64__)
+#define ABSL_CACHELINE_SIZE 128
+#elif defined(__aarch64__)
+// We would need to read special register ctr_el0 to find out L1 dcache size.
+// This value is a good estimate based on a real aarch64 machine.
+#define ABSL_CACHELINE_SIZE 64
+#elif defined(__arm__)
+// Cache line sizes for ARM: These values are not strictly correct since
+// cache line sizes depend on implementations, not architectures.  There
+// are even implementations with cache line sizes configurable at boot
+// time.
+#if defined(__ARM_ARCH_5T__)
+#define ABSL_CACHELINE_SIZE 32
+#elif defined(__ARM_ARCH_7A__)
+#define ABSL_CACHELINE_SIZE 64
+#endif
+#endif
+
+#ifndef ABSL_CACHELINE_SIZE
+// A reasonable default guess.  Note that overestimates tend to waste more
+// space, while underestimates tend to waste more time.
+#define ABSL_CACHELINE_SIZE 64
+#endif
+
+// ABSL_CACHELINE_ALIGNED
+//
+// Indicates that the declared object be cache aligned using
+// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
+// load a set of related objects in the L1 cache for performance improvements.
+// Cacheline aligning objects properly allows constructive memory sharing and
+// prevents destructive (or "false") memory sharing.
+//
+// NOTE: this macro should be replaced with usage of `alignas()` using
+// `std::hardware_constructive_interference_size` and/or
+// `std::hardware_destructive_interference_size` when available within C++17.
+//
+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
+// for more information.
+//
+// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to
+// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is
+// not known to work, the macro expands to nothing.
+//
+// No further guarantees are made here. The result of applying the macro
+// to variables and types is always implementation-defined.
+//
+// WARNING: It is easy to use this attribute incorrectly, even to the point
+// of causing bugs that are difficult to diagnose, crash, etc. It does not
+// of itself guarantee that objects are aligned to a cache line.
+//
+// Recommendations:
+//
+// 1) Consult compiler documentation; this comment is not kept in sync as
+//    toolchains evolve.
+// 2) Verify your use has the intended effect. This often requires inspecting
+//    the generated machine code.
+// 3) Prefer applying this attribute to individual variables. Avoid
+//    applying it to types. This tends to localize the effect.
+#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
+
+#else  // not GCC
+#define ABSL_CACHELINE_SIZE 64
+#define ABSL_CACHELINE_ALIGNED
+#endif
+
+// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
+//
+// Enables the compiler to prioritize compilation using static analysis for
+// likely paths within a boolean branch.
+//
+// Example:
+//
+//   if (ABSL_PREDICT_TRUE(expression)) {
+//     return result;                        // Faster if more likely
+//   } else {
+//     return 0;
+//   }
+//
+// Compilers can use the information that a certain branch is not likely to be
+// taken (for instance, a CHECK failure) to optimize for the common case in
+// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
+#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#else
+#define ABSL_PREDICT_FALSE(x) (x)
+#define ABSL_PREDICT_TRUE(x) (x)
+#endif
+
+#endif  // ABSL_BASE_OPTIMIZATION_H_
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
new file mode 100644
index 0000000..0a07fc0
--- /dev/null
+++ b/absl/base/policy_checks.h
@@ -0,0 +1,121 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: policy_checks.h
+// -----------------------------------------------------------------------------
+//
+// This header enforces a minimum set of policies at build time, such as the
+// supported compiler and library versions. Unsupported configurations are
+// reported with `#error`. This enforcement is best effort, so successfully
+// compiling this header does not guarantee a supported configuration.
+
+#ifndef ABSL_BASE_POLICY_CHECKS_H_
+#define ABSL_BASE_POLICY_CHECKS_H_
+
+// Included for the __GLIBC_PREREQ macro used below.
+#include <limits.h>
+
+// Included for the _STLPORT_VERSION macro used below.
+#if defined(__cplusplus)
+#include <cstddef>
+#endif
+
+// -----------------------------------------------------------------------------
+// Operating System Check
+// -----------------------------------------------------------------------------
+
+#if defined(__CYGWIN__)
+#error "Cygwin is not supported."
+#endif
+
+// -----------------------------------------------------------------------------
+// Compiler Check
+// -----------------------------------------------------------------------------
+
+// We support MSVC++ 14.0 update 2 and later.
+// This minimum will go up.
+#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
+#error "This package requires Visual Studio 2015 Update 2 or higher."
+#endif
+
+// We support gcc 4.7 and later.
+// This minimum will go up.
+#if defined(__GNUC__) && !defined(__clang__)
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
+#error "This package requires gcc 4.7 or higher."
+#endif
+#endif
+
+// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
+// This corresponds to Apple Xcode version 4.5.
+// This minimum will go up.
+#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
+#error "This package requires __apple_build_version__ of 4211165 or higher."
+#endif
+
+// -----------------------------------------------------------------------------
+// C++ Version Check
+// -----------------------------------------------------------------------------
+
+// Enforce C++11 as the minimum.  Note that Visual Studio has not
+// advanced __cplusplus despite being good enough for our purposes, so
+// so we exempt it from the check.
+#if defined(__cplusplus) && !defined(_MSC_VER)
+#if __cplusplus < 201103L
+#error "C++ versions less than C++11 are not supported."
+#endif
+#endif
+
+// -----------------------------------------------------------------------------
+// Standard Library Check
+// -----------------------------------------------------------------------------
+
+// We have chosen glibc 2.12 as the minimum as it was tagged for release
+// in May, 2010 and includes some functionality used in Google software
+// (for instance pthread_setname_np):
+// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
+#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+#if !__GLIBC_PREREQ(2, 12)
+#error "Minimum required version of glibc is 2.12."
+#endif
+#endif
+
+#if defined(_STLPORT_VERSION)
+#error "STLPort is not supported."
+#endif
+
+// -----------------------------------------------------------------------------
+// `char` Size Check
+// -----------------------------------------------------------------------------
+
+// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a
+// platform where this is not the case, please provide us with the details about
+// your platform so we can consider relaxing this requirement.
+#if CHAR_BIT != 8
+#error "Abseil assumes CHAR_BIT == 8."
+#endif
+
+// -----------------------------------------------------------------------------
+// `int` Size Check
+// -----------------------------------------------------------------------------
+
+// Abseil currently assumes that an int is 4 bytes. If you would like to use
+// Abseil on a platform where this is not the case, please provide us with the
+// details about your platform so we can consider relaxing this requirement.
+#if INT_MAX < 2147483647
+#error "Abseil assumes that int is at least 4 bytes. "
+#endif
+
+#endif  // ABSL_BASE_POLICY_CHECKS_H_
diff --git a/absl/base/port.h b/absl/base/port.h
new file mode 100644
index 0000000..1c67257
--- /dev/null
+++ b/absl/base/port.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Abseil 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.
+//
+// This files is a forwarding header for other headers containing various
+// portability macros and functions.
+// This file is used for both C and C++!
+
+#ifndef ABSL_BASE_PORT_H_
+#define ABSL_BASE_PORT_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+
+#endif  // ABSL_BASE_PORT_H_
diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc
new file mode 100644
index 0000000..dae4b35
--- /dev/null
+++ b/absl/base/raw_logging_test.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 The Abseil 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.
+
+// This test serves primarily as a compilation test for base/raw_logging.h.
+// Raw logging testing is covered by logging_unittest.cc, which is not as
+// portable as this test.
+
+#include "absl/base/internal/raw_logging.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(RawLoggingCompilationTest, Log) {
+  ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1);
+  ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1);
+}
+
+TEST(RawLoggingCompilationTest, PassingCheck) {
+  ABSL_RAW_CHECK(true, "RAW CHECK");
+}
+
+// Not all platforms support output from raw log, so we don't verify any
+// particular output for RAW check failures (expecting the empty std::string
+// accomplishes this).  This test is primarily a compilation test, but we
+// are verifying process death when EXPECT_DEATH works for a platform.
+const char kExpectedDeathOutput[] = "";
+
+TEST(RawLoggingDeathTest, FailingCheck) {
+  EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_CHECK(1 == 0, "explanation"),
+                            kExpectedDeathOutput);
+}
+
+TEST(RawLoggingDeathTest, LogFatal) {
+  EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_LOG(FATAL, "my dog has fleas"),
+                            kExpectedDeathOutput);
+}
+
+}  // namespace
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
new file mode 100644
index 0000000..1b50884
--- /dev/null
+++ b/absl/base/spinlock_test_common.cc
@@ -0,0 +1,266 @@
+// Copyright 2017 The Abseil 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.
+
+// A bunch of threads repeatedly hash an array of ints protected by a
+// spinlock.  If the spinlock is working properly, all elements of the
+// array should be equal at the end of the test.
+
+#include <cstdint>
+#include <limits>
+#include <random>
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/base/macros.h"
+#include "absl/synchronization/blocking_counter.h"
+#include "absl/synchronization/notification.h"
+
+constexpr int32_t kNumThreads = 10;
+constexpr int32_t kIters = 1000;
+
+namespace absl {
+namespace base_internal {
+
+// This is defined outside of anonymous namespace so that it can be
+// a friend of SpinLock to access protected methods for testing.
+struct SpinLockTest {
+  static uint32_t EncodeWaitCycles(int64_t wait_start_time,
+                                   int64_t wait_end_time) {
+    return SpinLock::EncodeWaitCycles(wait_start_time, wait_end_time);
+  }
+  static uint64_t DecodeWaitCycles(uint32_t lock_value) {
+    return SpinLock::DecodeWaitCycles(lock_value);
+  }
+};
+
+namespace {
+
+static constexpr int kArrayLength = 10;
+static uint32_t values[kArrayLength];
+static SpinLock static_spinlock(base_internal::kLinkerInitialized);
+static SpinLock static_cooperative_spinlock(
+    base_internal::kLinkerInitialized,
+    base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+static SpinLock static_noncooperative_spinlock(
+    base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
+
+
+// Simple integer hash function based on the public domain lookup2 hash.
+// http://burtleburtle.net/bob/c/lookup2.c
+static uint32_t Hash32(uint32_t a, uint32_t c) {
+  uint32_t b = 0x9e3779b9UL;  // The golden ratio; an arbitrary value.
+  a -= b; a -= c; a ^= (c >> 13);
+  b -= c; b -= a; b ^= (a << 8);
+  c -= a; c -= b; c ^= (b >> 13);
+  a -= b; a -= c; a ^= (c >> 12);
+  b -= c; b -= a; b ^= (a << 16);
+  c -= a; c -= b; c ^= (b >> 5);
+  a -= b; a -= c; a ^= (c >> 3);
+  b -= c; b -= a; b ^= (a << 10);
+  c -= a; c -= b; c ^= (b >> 15);
+  return c;
+}
+
+static void TestFunction(int thread_salt, SpinLock* spinlock) {
+  for (int i = 0; i < kIters; i++) {
+    SpinLockHolder h(spinlock);
+    for (int j = 0; j < kArrayLength; j++) {
+      const int index = (j + thread_salt) % kArrayLength;
+      values[index] = Hash32(values[index], thread_salt);
+      std::this_thread::yield();
+    }
+  }
+}
+
+static void ThreadedTest(SpinLock* spinlock) {
+  std::vector<std::thread> threads;
+  for (int i = 0; i < kNumThreads; ++i) {
+    threads.push_back(std::thread(TestFunction, i, spinlock));
+  }
+  for (auto& thread : threads) {
+    thread.join();
+  }
+
+  SpinLockHolder h(spinlock);
+  for (int i = 1; i < kArrayLength; i++) {
+    EXPECT_EQ(values[0], values[i]);
+  }
+}
+
+TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
+  SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
+  spinlock.Lock();
+  EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed());
+  spinlock.Unlock();
+}
+
+TEST(SpinLock, StaticNonCooperativeDisablesScheduling) {
+  static_noncooperative_spinlock.Lock();
+  EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed());
+  static_noncooperative_spinlock.Unlock();
+}
+
+TEST(SpinLock, WaitCyclesEncoding) {
+  // These are implementation details not exported by SpinLock.
+  const int kProfileTimestampShift = 7;
+  const int kLockwordReservedShift = 3;
+  const uint32_t kSpinLockSleeper = 8;
+
+  // We should be able to encode up to (1^kMaxCycleBits - 1) without clamping
+  // but the lower kProfileTimestampShift will be dropped.
+  const int kMaxCyclesShift =
+    32 - kLockwordReservedShift + kProfileTimestampShift;
+  const uint64_t kMaxCycles = (int64_t{1} << kMaxCyclesShift) - 1;
+
+  // These bits should be zero after encoding.
+  const uint32_t kLockwordReservedMask = (1 << kLockwordReservedShift) - 1;
+
+  // These bits are dropped when wait cycles are encoded.
+  const uint64_t kProfileTimestampMask = (1 << kProfileTimestampShift) - 1;
+
+  // Test a bunch of random values
+  std::default_random_engine generator;
+  // Shift to avoid overflow below.
+  std::uniform_int_distribution<uint64_t> time_distribution(
+      0, std::numeric_limits<uint64_t>::max() >> 4);
+  std::uniform_int_distribution<uint64_t> cycle_distribution(0, kMaxCycles);
+
+  for (int i = 0; i < 100; i++) {
+    int64_t start_time = time_distribution(generator);
+    int64_t cycles = cycle_distribution(generator);
+    int64_t end_time = start_time + cycles;
+    uint32_t lock_value = SpinLockTest::EncodeWaitCycles(start_time, end_time);
+    EXPECT_EQ(0, lock_value & kLockwordReservedMask);
+    uint64_t decoded = SpinLockTest::DecodeWaitCycles(lock_value);
+    EXPECT_EQ(0, decoded & kProfileTimestampMask);
+    EXPECT_EQ(cycles & ~kProfileTimestampMask, decoded);
+  }
+
+  // Test corner cases
+  int64_t start_time = time_distribution(generator);
+  EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time));
+  EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0));
+  EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask));
+  EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask,
+            SpinLockTest::DecodeWaitCycles(~kLockwordReservedMask));
+
+  // Check that we cannot produce kSpinLockSleeper during encoding.
+  int64_t sleeper_cycles =
+      kSpinLockSleeper << (kProfileTimestampShift - kLockwordReservedShift);
+  uint32_t sleeper_value =
+      SpinLockTest::EncodeWaitCycles(start_time, start_time + sleeper_cycles);
+  EXPECT_NE(sleeper_value, kSpinLockSleeper);
+
+  // Test clamping
+  uint32_t max_value =
+    SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles);
+  uint64_t max_value_decoded = SpinLockTest::DecodeWaitCycles(max_value);
+  uint64_t expected_max_value_decoded = kMaxCycles & ~kProfileTimestampMask;
+  EXPECT_EQ(expected_max_value_decoded, max_value_decoded);
+
+  const int64_t step = (1 << kProfileTimestampShift);
+  uint32_t after_max_value =
+    SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles + step);
+  uint64_t after_max_value_decoded =
+      SpinLockTest::DecodeWaitCycles(after_max_value);
+  EXPECT_EQ(expected_max_value_decoded, after_max_value_decoded);
+
+  uint32_t before_max_value = SpinLockTest::EncodeWaitCycles(
+      start_time, start_time + kMaxCycles - step);
+  uint64_t before_max_value_decoded =
+    SpinLockTest::DecodeWaitCycles(before_max_value);
+  EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
+}
+TEST(SpinLockWithThreads, StaticSpinLock) {
+  ThreadedTest(&static_spinlock);
+}
+TEST(SpinLockWithThreads, StackSpinLock) {
+  SpinLock spinlock;
+  ThreadedTest(&spinlock);
+}
+
+TEST(SpinLockWithThreads, StackCooperativeSpinLock) {
+  SpinLock spinlock(base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+  ThreadedTest(&spinlock);
+}
+
+TEST(SpinLockWithThreads, StackNonCooperativeSpinLock) {
+  SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
+  ThreadedTest(&spinlock);
+}
+
+TEST(SpinLockWithThreads, StaticCooperativeSpinLock) {
+  ThreadedTest(&static_cooperative_spinlock);
+}
+
+TEST(SpinLockWithThreads, StaticNonCooperativeSpinLock) {
+  ThreadedTest(&static_noncooperative_spinlock);
+}
+
+TEST(SpinLockWithThreads, DoesNotDeadlock) {
+  struct Helper {
+    static void NotifyThenLock(Notification* locked, SpinLock* spinlock,
+                               BlockingCounter* b) {
+      locked->WaitForNotification();  // Wait for LockThenWait() to hold "s".
+      b->DecrementCount();
+      SpinLockHolder l(spinlock);
+    }
+
+    static void LockThenWait(Notification* locked, SpinLock* spinlock,
+                             BlockingCounter* b) {
+      SpinLockHolder l(spinlock);
+      locked->Notify();
+      b->Wait();
+    }
+
+    static void DeadlockTest(SpinLock* spinlock, int num_spinners) {
+      Notification locked;
+      BlockingCounter counter(num_spinners);
+      std::vector<std::thread> threads;
+
+      threads.push_back(
+          std::thread(Helper::LockThenWait, &locked, spinlock, &counter));
+      for (int i = 0; i < num_spinners; ++i) {
+        threads.push_back(
+            std::thread(Helper::NotifyThenLock, &locked, spinlock, &counter));
+      }
+
+      for (auto& thread : threads) {
+        thread.join();
+      }
+    }
+  };
+
+  SpinLock stack_cooperative_spinlock(
+      base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+  SpinLock stack_noncooperative_spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
+  Helper::DeadlockTest(&stack_cooperative_spinlock,
+                       base_internal::NumCPUs() * 2);
+  Helper::DeadlockTest(&stack_noncooperative_spinlock,
+                       base_internal::NumCPUs() * 2);
+  Helper::DeadlockTest(&static_cooperative_spinlock,
+                       base_internal::NumCPUs() * 2);
+  Helper::DeadlockTest(&static_noncooperative_spinlock,
+                       base_internal::NumCPUs() * 2);
+}
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
new file mode 100644
index 0000000..fbb2797
--- /dev/null
+++ b/absl/base/thread_annotations.h
@@ -0,0 +1,257 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: thread_annotations.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains macro definitions for thread safety annotations
+// that allow developers to document the locking policies of multi-threaded
+// code. The annotations can also help program analysis tools to identify
+// potential thread safety issues.
+//
+//
+// These annotations are implemented using compiler attributes. Using the macros
+// defined here instead of raw attributes allow for portability and future
+// compatibility.
+//
+// When referring to mutexes in the arguments of the attributes, you should
+// use variable names or more complex expressions (e.g. my_object->mutex_)
+// that evaluate to a concrete mutex object whenever possible. If the mutex
+// you want to refer to is not in scope, you may use a member pointer
+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
+
+#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
+#define ABSL_BASE_THREAD_ANNOTATIONS_H_
+#if defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
+#endif
+
+// GUARDED_BY()
+//
+// Documents if a shared field or global variable needs to be protected by a
+// mutex. GUARDED_BY() allows the user to specify a particular mutex that
+// should be held when accessing the annotated variable.
+//
+// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// local variables, a local variable and its associated mutex can often be
+// combined into a small class or struct, thereby allowing the annotation.
+//
+// Example:
+//
+//   class Foo {
+//     Mutex mu_;
+//     int p1_ GUARDED_BY(mu_);
+//     ...
+//   };
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+// PT_GUARDED_BY()
+//
+// Documents if the memory location pointed to by a pointer should be guarded
+// by a mutex when dereferencing the pointer.
+//
+// Example:
+//   class Foo {
+//     Mutex mu_;
+//     int *p1_ PT_GUARDED_BY(mu_);
+//     ...
+//   };
+//
+// Note that a pointer variable to a shared memory location could itself be a
+// shared variable.
+//
+// Example:
+//
+//   // `q_`, guarded by `mu1_`, points to a shared memory location that is
+//   // guarded by `mu2_`:
+//   int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+//
+// Documents the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
+// and ACQUIRED_BEFORE.)
+//
+// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// fields or global variables.
+//
+// Example:
+//
+//   Mutex m1_;
+//   Mutex m2_ ACQUIRED_AFTER(m1_);
+#define ACQUIRED_AFTER(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define ACQUIRED_BEFORE(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+//
+// Documents a function that expects a mutex to be held prior to entry.
+// The mutex is expected to be held both on entry to, and exit from, the
+// function.
+//
+// Example:
+//
+//   Mutex mu1, mu2;
+//   int a GUARDED_BY(mu1);
+//   int b GUARDED_BY(mu2);
+//
+//   void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... };
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+#define SHARED_LOCKS_REQUIRED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// LOCKS_EXCLUDED()
+//
+// Documents the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as Abseil's `Mutex` locks are
+// non-reentrant).
+#define LOCKS_EXCLUDED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// LOCK_RETURNED()
+//
+// Documents a function that returns a mutex without acquiring it.  For example,
+// a public getter method that returns a pointer to a private mutex should
+// be annotated with LOCK_RETURNED.
+#define LOCK_RETURNED(x) \
+  THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+// LOCKABLE
+//
+// Documents if a class/type is a lockable type (such as the `Mutex` class).
+#define LOCKABLE \
+  THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// SCOPED_LOCKABLE
+//
+// Documents if a class does RAII locking (such as the `MutexLock` class).
+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// arguments; the analysis will assume that the destructor unlocks whatever the
+// constructor locked.
+#define SCOPED_LOCKABLE \
+  THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// EXCLUSIVE_LOCK_FUNCTION()
+//
+// Documents functions that acquire a lock in the body of a function, and do
+// not release it.
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+// SHARED_LOCK_FUNCTION()
+//
+// Documents functions that acquire a shared (reader) lock in the body of a
+// function, and do not release it.
+#define SHARED_LOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+// UNLOCK_FUNCTION()
+//
+// Documents functions that expect a lock to be held on entry to the function,
+// and release it in the body of the function.
+#define UNLOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+//
+// Documents functions that try to acquire a lock, and return success or failure
+// (or a non-boolean value that can be interpreted as a boolean).
+// The first argument should be `true` for functions that return `true` on
+// success, or `false` for functions that return `false` on success. The second
+// argument specifies the mutex that is locked on success. If unspecified, this
+// mutex is assumed to be `this`.
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+//
+// Documents functions that dynamically check to see if a lock is held, and fail
+// if it is not held.
+#define ASSERT_EXCLUSIVE_LOCK(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+#define ASSERT_SHARED_LOCK(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+// NO_THREAD_SAFETY_ANALYSIS
+//
+// Turns off thread safety checking within the body of a particular function.
+// This annotation is used to mark functions that are known to be correct, but
+// the locking behavior is more complicated than the analyzer can handle.
+#define NO_THREAD_SAFETY_ANALYSIS \
+  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+//------------------------------------------------------------------------------
+// Tool-Supplied Annotations
+//------------------------------------------------------------------------------
+
+// TS_UNCHECKED should be placed around lock expressions that are not valid
+// C++ syntax, but which are present for documentation purposes.  These
+// annotations will be ignored by the analysis.
+#define TS_UNCHECKED(x) ""
+
+// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// It is used by automated tools to mark and disable invalid expressions.
+// The annotation should either be fixed, or changed to TS_UNCHECKED.
+#define TS_FIXME(x) ""
+
+// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
+// a particular function.  However, this attribute is used to mark functions
+// that are incorrect and need to be fixed.  It is used by automated tools to
+// avoid breaking the build when the analysis is updated.
+// Code owners are expected to eventually fix the routine.
+#define NO_THREAD_SAFETY_ANALYSIS_FIXME  NO_THREAD_SAFETY_ANALYSIS
+
+// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
+// annotation that needs to be fixed, because it is producing thread safety
+// warning.  It disables the GUARDED_BY.
+#define GUARDED_BY_FIXME(x)
+
+// Disables warnings for a single read operation.  This can be used to avoid
+// warnings when it is known that the read is not actually involved in a race,
+// but the compiler cannot confirm that.
+#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
+
+
+namespace thread_safety_analysis {
+
+// Takes a reference to a guarded data member, and returns an unguarded
+// reference.
+template <typename T>
+inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+  return v;
+}
+
+template <typename T>
+inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+  return v;
+}
+
+}  // namespace thread_safety_analysis
+
+#endif  // ABSL_BASE_THREAD_ANNOTATIONS_H_
diff --git a/absl/base/throw_delegate_test.cc b/absl/base/throw_delegate_test.cc
new file mode 100644
index 0000000..0f15df0
--- /dev/null
+++ b/absl/base/throw_delegate_test.cc
@@ -0,0 +1,94 @@
+// Copyright 2017 The Abseil 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 "absl/base/internal/throw_delegate.h"
+
+#include <functional>
+#include <new>
+#include <stdexcept>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::base_internal::ThrowStdLogicError;
+using absl::base_internal::ThrowStdInvalidArgument;
+using absl::base_internal::ThrowStdDomainError;
+using absl::base_internal::ThrowStdLengthError;
+using absl::base_internal::ThrowStdOutOfRange;
+using absl::base_internal::ThrowStdRuntimeError;
+using absl::base_internal::ThrowStdRangeError;
+using absl::base_internal::ThrowStdOverflowError;
+using absl::base_internal::ThrowStdUnderflowError;
+using absl::base_internal::ThrowStdBadFunctionCall;
+using absl::base_internal::ThrowStdBadAlloc;
+
+constexpr const char* what_arg = "The quick brown fox jumps over the lazy dog";
+
+template <typename E>
+void ExpectThrowChar(void (*f)(const char*)) {
+  try {
+    f(what_arg);
+    FAIL() << "Didn't throw";
+  } catch (const E& e) {
+    EXPECT_STREQ(e.what(), what_arg);
+  }
+}
+
+template <typename E>
+void ExpectThrowString(void (*f)(const std::string&)) {
+  try {
+    f(what_arg);
+    FAIL() << "Didn't throw";
+  } catch (const E& e) {
+    EXPECT_STREQ(e.what(), what_arg);
+  }
+}
+
+template <typename E>
+void ExpectThrowNoWhat(void (*f)()) {
+  try {
+    f();
+    FAIL() << "Didn't throw";
+  } catch (const E& e) {
+  }
+}
+
+TEST(ThrowHelper, Test) {
+  // Not using EXPECT_THROW because we want to check the .what() message too.
+  ExpectThrowChar<std::logic_error>(ThrowStdLogicError);
+  ExpectThrowChar<std::invalid_argument>(ThrowStdInvalidArgument);
+  ExpectThrowChar<std::domain_error>(ThrowStdDomainError);
+  ExpectThrowChar<std::length_error>(ThrowStdLengthError);
+  ExpectThrowChar<std::out_of_range>(ThrowStdOutOfRange);
+  ExpectThrowChar<std::runtime_error>(ThrowStdRuntimeError);
+  ExpectThrowChar<std::range_error>(ThrowStdRangeError);
+  ExpectThrowChar<std::overflow_error>(ThrowStdOverflowError);
+  ExpectThrowChar<std::underflow_error>(ThrowStdUnderflowError);
+
+  ExpectThrowString<std::logic_error>(ThrowStdLogicError);
+  ExpectThrowString<std::invalid_argument>(ThrowStdInvalidArgument);
+  ExpectThrowString<std::domain_error>(ThrowStdDomainError);
+  ExpectThrowString<std::length_error>(ThrowStdLengthError);
+  ExpectThrowString<std::out_of_range>(ThrowStdOutOfRange);
+  ExpectThrowString<std::runtime_error>(ThrowStdRuntimeError);
+  ExpectThrowString<std::range_error>(ThrowStdRangeError);
+  ExpectThrowString<std::overflow_error>(ThrowStdOverflowError);
+  ExpectThrowString<std::underflow_error>(ThrowStdUnderflowError);
+
+  ExpectThrowNoWhat<std::bad_function_call>(ThrowStdBadFunctionCall);
+  ExpectThrowNoWhat<std::bad_alloc>(ThrowStdBadAlloc);
+}
+
+}  // namespace
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
new file mode 100644
index 0000000..07df367
--- /dev/null
+++ b/absl/container/BUILD.bazel
@@ -0,0 +1,163 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+    "ABSL_EXCEPTIONS_FLAG",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "fixed_array",
+    hdrs = ["fixed_array.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/algorithm",
+        "//absl/base:core_headers",
+        "//absl/base:dynamic_annotations",
+        "//absl/base:throw_delegate",
+        "//absl/memory",
+    ],
+)
+
+cc_test(
+    name = "fixed_array_test",
+    srcs = ["fixed_array_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":fixed_array",
+        "//absl/base:exception_testing",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "fixed_array_test_noexceptions",
+    srcs = ["fixed_array_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":fixed_array",
+        "//absl/base:exception_testing",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "fixed_array_exception_safety_test",
+    srcs = ["fixed_array_exception_safety_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":fixed_array",
+        "//absl/base:exception_safety_testing",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "fixed_array_benchmark",
+    srcs = ["fixed_array_benchmark.cc"],
+    copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"],
+    tags = ["benchmark"],
+    deps = [
+        ":fixed_array",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "inlined_vector",
+    hdrs = ["inlined_vector.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/algorithm",
+        "//absl/base:core_headers",
+        "//absl/base:throw_delegate",
+        "//absl/memory",
+    ],
+)
+
+cc_test(
+    name = "inlined_vector_test",
+    srcs = ["inlined_vector_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":inlined_vector",
+        ":test_instance_tracker",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/base:exception_testing",
+        "//absl/memory",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "inlined_vector_test_noexceptions",
+    srcs = ["inlined_vector_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":inlined_vector",
+        ":test_instance_tracker",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/base:exception_testing",
+        "//absl/memory",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "inlined_vector_benchmark",
+    srcs = ["inlined_vector_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    deps = [
+        ":inlined_vector",
+        "//absl/base",
+        "//absl/strings",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "test_instance_tracker",
+    testonly = 1,
+    srcs = ["internal/test_instance_tracker.cc"],
+    hdrs = ["internal/test_instance_tracker.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+)
+
+cc_test(
+    name = "test_instance_tracker_test",
+    srcs = ["internal/test_instance_tracker_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":test_instance_tracker",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/container/BUILD.gn b/absl/container/BUILD.gn
new file mode 100644
index 0000000..a00eaf4
--- /dev/null
+++ b/absl/container/BUILD.gn
@@ -0,0 +1,70 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("fixed_array") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "fixed_array.h",
+  ]
+  deps = [
+    "../algorithm",
+    "../base:core_headers",
+    "../base:dynamic_annotations",
+    "../base:throw_delegate",
+    "../memory",
+  ]
+}
+
+source_set("inlined_vector") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "inlined_vector.h",
+  ]
+  deps = [
+    "../algorithm",
+    "../base:core_headers",
+    "../base:throw_delegate",
+    "../memory",
+  ]
+}
+
+source_set("test_instance_tracker") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/test_instance_tracker.cc",
+  ]
+  public = [
+    "internal/test_instance_tracker.h",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
new file mode 100644
index 0000000..d580b48
--- /dev/null
+++ b/absl/container/CMakeLists.txt
@@ -0,0 +1,145 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+
+list(APPEND CONTAINER_PUBLIC_HEADERS
+  "fixed_array.h"
+  "inlined_vector.h"
+)
+
+
+list(APPEND CONTAINER_INTERNAL_HEADERS
+  "internal/test_instance_tracker.h"
+)
+
+
+absl_header_library(
+  TARGET
+    absl_container
+  EXPORT_NAME
+    container
+)
+
+
+#
+## TESTS
+#
+
+list(APPEND TEST_INSTANCE_TRACKER_LIB_SRC
+  "internal/test_instance_tracker.cc"
+  ${CONTAINER_PUBLIC_HEADERS}
+  ${CONTAINER_INTERNAL_HEADERS}
+)
+
+
+absl_library(
+  TARGET
+    test_instance_tracker_lib
+  SOURCES
+    ${TEST_INSTANCE_TRACKER_LIB_SRC}
+  PUBLIC_LIBRARIES
+    absl::container
+  DISABLE_INSTALL
+)
+
+
+
+# test fixed_array_test
+set(FIXED_ARRAY_TEST_SRC "fixed_array_test.cc")
+set(FIXED_ARRAY_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib)
+
+absl_test(
+  TARGET
+    fixed_array_test
+  SOURCES
+    ${FIXED_ARRAY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
+
+
+absl_test(
+  TARGET
+    fixed_array_test_noexceptions
+  SOURCES
+    ${FIXED_ARRAY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test fixed_array_exception_safety_test
+set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC "fixed_array_exception_safety_test.cc")
+set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
+  absl::container
+  absl_base_internal_exception_safety_testing
+)
+
+absl_test(
+  TARGET
+    fixed_array_exception_safety_test
+  SOURCES
+    ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
+
+# test inlined_vector_test
+set(INLINED_VECTOR_TEST_SRC "inlined_vector_test.cc")
+set(INLINED_VECTOR_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib)
+
+absl_test(
+  TARGET
+    inlined_vector_test
+  SOURCES
+    ${INLINED_VECTOR_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES}
+)
+
+absl_test(
+  TARGET
+    inlined_vector_test_noexceptions
+  SOURCES
+    ${INLINED_VECTOR_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_NOEXCEPTION_CXXFLAGS}
+)
+
+
+# test test_instance_tracker_test
+set(TEST_INSTANCE_TRACKER_TEST_SRC "internal/test_instance_tracker_test.cc")
+set(TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib)
+
+
+absl_test(
+  TARGET
+    test_instance_tracker_test
+  SOURCES
+    ${TEST_INSTANCE_TRACKER_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES}
+)
+
+
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
new file mode 100644
index 0000000..708c615
--- /dev/null
+++ b/absl/container/fixed_array.h
@@ -0,0 +1,478 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: fixed_array.h
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
+// the array can be determined at run-time. It is a good replacement for
+// non-standard and deprecated uses of `alloca()` and variable length arrays
+// within the GCC extension. (See
+// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
+//
+// `FixedArray` allocates small arrays inline, keeping performance fast by
+// avoiding heap operations. It also helps reduce the chances of
+// accidentally overflowing your stack if large input is passed to
+// your function.
+
+#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
+#define ABSL_CONTAINER_FIXED_ARRAY_H_
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+
+constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
+
+// -----------------------------------------------------------------------------
+// FixedArray
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray` provides a run-time fixed-size array, allocating a small array
+// inline for efficiency.
+//
+// Most users should not specify an `inline_elements` argument and let
+// `FixedArray` automatically determine the number of elements
+// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
+// `FixedArray` implementation will use inline storage for arrays with a
+// length <= `inline_elements`.
+//
+// Note that a `FixedArray` constructed with a `size_type` argument will
+// default-initialize its values by leaving trivially constructible types
+// uninitialized (e.g. int, int[4], double), and others default-constructed.
+// This matches the behavior of c-style arrays and `std::array`, but not
+// `std::vector`.
+//
+// Note that `FixedArray` does not provide a public allocator; if it requires a
+// heap allocation, it will do so with global `::operator new[]()` and
+// `::operator delete[]()`, even if T provides class-scope overrides for these
+// operators.
+template <typename T, size_t inlined = kFixedArrayUseDefault>
+class FixedArray {
+  static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
+                "Arrays with unknown bounds cannot be used with FixedArray.");
+  static constexpr size_t kInlineBytesDefault = 256;
+
+  // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
+  // but this seems to be mostly pedantic.
+  template <typename Iterator>
+  using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
+      typename std::iterator_traits<Iterator>::iterator_category,
+      std::forward_iterator_tag>::value>;
+
+ public:
+  using value_type = T;
+  using iterator = T*;
+  using const_iterator = const T*;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using reference = T&;
+  using const_reference = const T&;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using difference_type = ptrdiff_t;
+  using size_type = size_t;
+
+  static constexpr size_type inline_elements =
+      inlined == kFixedArrayUseDefault
+          ? kInlineBytesDefault / sizeof(value_type)
+          : inlined;
+
+  FixedArray(const FixedArray& other)
+      : FixedArray(other.begin(), other.end()) {}
+
+  FixedArray(FixedArray&& other) noexcept(
+      absl::conjunction<absl::allocator_is_nothrow<std::allocator<value_type>>,
+                        std::is_nothrow_move_constructible<value_type>>::value)
+      : FixedArray(std::make_move_iterator(other.begin()),
+                   std::make_move_iterator(other.end())) {}
+
+  // Creates an array object that can store `n` elements.
+  // Note that trivially constructible elements will be uninitialized.
+  explicit FixedArray(size_type n) : storage_(n) {
+    absl::memory_internal::uninitialized_default_construct_n(storage_.begin(),
+                                                             size());
+  }
+
+  // Creates an array initialized with `n` copies of `val`.
+  FixedArray(size_type n, const value_type& val) : storage_(n) {
+    std::uninitialized_fill_n(data(), size(), val);
+  }
+
+  // Creates an array initialized with the elements from the input
+  // range. The array's size will always be `std::distance(first, last)`.
+  // REQUIRES: Iterator must be a forward_iterator or better.
+  template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
+  FixedArray(Iterator first, Iterator last)
+      : storage_(std::distance(first, last)) {
+    std::uninitialized_copy(first, last, data());
+  }
+
+  FixedArray(std::initializer_list<value_type> init_list)
+      : FixedArray(init_list.begin(), init_list.end()) {}
+
+  ~FixedArray() noexcept {
+    for (const StorageElement& cur : storage_) {
+      cur.~StorageElement();
+    }
+  }
+
+  // Assignments are deleted because they break the invariant that the size of a
+  // `FixedArray` never changes.
+  void operator=(FixedArray&&) = delete;
+  void operator=(const FixedArray&) = delete;
+
+  // FixedArray::size()
+  //
+  // Returns the length of the fixed array.
+  size_type size() const { return storage_.size(); }
+
+  // FixedArray::max_size()
+  //
+  // Returns the largest possible value of `std::distance(begin(), end())` for a
+  // `FixedArray<T>`. This is equivalent to the most possible addressable bytes
+  // over the number of bytes taken by T.
+  constexpr size_type max_size() const {
+    return std::numeric_limits<difference_type>::max() / sizeof(value_type);
+  }
+
+  // FixedArray::empty()
+  //
+  // Returns whether or not the fixed array is empty.
+  bool empty() const { return size() == 0; }
+
+  // FixedArray::memsize()
+  //
+  // Returns the memory size of the fixed array in bytes.
+  size_t memsize() const { return size() * sizeof(value_type); }
+
+  // FixedArray::data()
+  //
+  // Returns a const T* pointer to elements of the `FixedArray`. This pointer
+  // can be used to access (but not modify) the contained elements.
+  const_pointer data() const { return AsValueType(storage_.begin()); }
+
+  // Overload of FixedArray::data() to return a T* pointer to elements of the
+  // fixed array. This pointer can be used to access and modify the contained
+  // elements.
+  pointer data() { return AsValueType(storage_.begin()); }
+
+  // FixedArray::operator[]
+  //
+  // Returns a reference the ith element of the fixed array.
+  // REQUIRES: 0 <= i < size()
+  reference operator[](size_type i) {
+    assert(i < size());
+    return data()[i];
+  }
+
+  // Overload of FixedArray::operator()[] to return a const reference to the
+  // ith element of the fixed array.
+  // REQUIRES: 0 <= i < size()
+  const_reference operator[](size_type i) const {
+    assert(i < size());
+    return data()[i];
+  }
+
+  // FixedArray::at
+  //
+  // Bounds-checked access.  Returns a reference to the ith element of the
+  // fiexed array, or throws std::out_of_range
+  reference at(size_type i) {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // Overload of FixedArray::at() to return a const reference to the ith element
+  // of the fixed array.
+  const_reference at(size_type i) const {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // FixedArray::front()
+  //
+  // Returns a reference to the first element of the fixed array.
+  reference front() { return *begin(); }
+
+  // Overload of FixedArray::front() to return a reference to the first element
+  // of a fixed array of const values.
+  const_reference front() const { return *begin(); }
+
+  // FixedArray::back()
+  //
+  // Returns a reference to the last element of the fixed array.
+  reference back() { return *(end() - 1); }
+
+  // Overload of FixedArray::back() to return a reference to the last element
+  // of a fixed array of const values.
+  const_reference back() const { return *(end() - 1); }
+
+  // FixedArray::begin()
+  //
+  // Returns an iterator to the beginning of the fixed array.
+  iterator begin() { return data(); }
+
+  // Overload of FixedArray::begin() to return a const iterator to the
+  // beginning of the fixed array.
+  const_iterator begin() const { return data(); }
+
+  // FixedArray::cbegin()
+  //
+  // Returns a const iterator to the beginning of the fixed array.
+  const_iterator cbegin() const { return begin(); }
+
+  // FixedArray::end()
+  //
+  // Returns an iterator to the end of the fixed array.
+  iterator end() { return data() + size(); }
+
+  // Overload of FixedArray::end() to return a const iterator to the end of the
+  // fixed array.
+  const_iterator end() const { return data() + size(); }
+
+  // FixedArray::cend()
+  //
+  // Returns a const iterator to the end of the fixed array.
+  const_iterator cend() const { return end(); }
+
+  // FixedArray::rbegin()
+  //
+  // Returns a reverse iterator from the end of the fixed array.
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+
+  // Overload of FixedArray::rbegin() to return a const reverse iterator from
+  // the end of the fixed array.
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+
+  // FixedArray::crbegin()
+  //
+  // Returns a const reverse iterator from the end of the fixed array.
+  const_reverse_iterator crbegin() const { return rbegin(); }
+
+  // FixedArray::rend()
+  //
+  // Returns a reverse iterator from the beginning of the fixed array.
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+
+  // Overload of FixedArray::rend() for returning a const reverse iterator
+  // from the beginning of the fixed array.
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // FixedArray::crend()
+  //
+  // Returns a reverse iterator from the beginning of the fixed array.
+  const_reverse_iterator crend() const { return rend(); }
+
+  // FixedArray::fill()
+  //
+  // Assigns the given `value` to all elements in the fixed array.
+  void fill(const value_type& val) { std::fill(begin(), end(), val); }
+
+  // Relational operators. Equality operators are elementwise using
+  // `operator==`, while order operators order FixedArrays lexicographically.
+  friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
+    return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+  }
+
+  friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
+    return !(lhs == rhs);
+  }
+
+  friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
+                                        rhs.end());
+  }
+
+  friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
+    return rhs < lhs;
+  }
+
+  friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
+    return !(rhs < lhs);
+  }
+
+  friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
+    return !(lhs < rhs);
+  }
+
+ private:
+  // StorageElement
+  //
+  // For FixedArrays with a C-style-array value_type, StorageElement is a POD
+  // wrapper struct called StorageElementWrapper that holds the value_type
+  // instance inside. This is needed for construction and destruction of the
+  // entire array regardless of how many dimensions it has. For all other cases,
+  // StorageElement is just an alias of value_type.
+  //
+  // Maintainer's Note: The simpler solution would be to simply wrap value_type
+  // in a struct whether it's an array or not. That causes some paranoid
+  // diagnostics to misfire, believing that 'data()' returns a pointer to a
+  // single element, rather than the packed array that it really is.
+  // e.g.:
+  //
+  //     FixedArray<char> buf(1);
+  //     sprintf(buf.data(), "foo");
+  //
+  //     error: call to int __builtin___sprintf_chk(etc...)
+  //     will always overflow destination buffer [-Werror]
+  //
+  template <typename OuterT = value_type,
+            typename InnerT = absl::remove_extent_t<OuterT>,
+            size_t InnerN = std::extent<OuterT>::value>
+  struct StorageElementWrapper {
+    InnerT array[InnerN];
+  };
+
+  using StorageElement =
+      absl::conditional_t<std::is_array<value_type>::value,
+                          StorageElementWrapper<value_type>, value_type>;
+
+  static pointer AsValueType(pointer ptr) { return ptr; }
+  static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
+    return std::addressof(ptr->array);
+  }
+
+  static_assert(sizeof(StorageElement) == sizeof(value_type), "");
+  static_assert(alignof(StorageElement) == alignof(value_type), "");
+
+  struct NonEmptyInlinedStorage {
+    using StorageElementBuffer =
+        absl::aligned_storage_t<sizeof(StorageElement),
+                                alignof(StorageElement)>;
+    StorageElement* data() {
+      return reinterpret_cast<StorageElement*>(inlined_storage_.data());
+    }
+
+#ifdef ADDRESS_SANITIZER
+    void* RedzoneBegin() { return &redzone_begin_; }
+    void* RedzoneEnd() { return &redzone_end_ + 1; }
+#endif  // ADDRESS_SANITIZER
+
+    void AnnotateConstruct(size_t);
+    void AnnotateDestruct(size_t);
+
+    ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
+    std::array<StorageElementBuffer, inline_elements> inlined_storage_;
+    ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
+  };
+
+  struct EmptyInlinedStorage {
+    StorageElement* data() { return nullptr; }
+    void AnnotateConstruct(size_t) {}
+    void AnnotateDestruct(size_t) {}
+  };
+
+  using InlinedStorage =
+      absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
+                          NonEmptyInlinedStorage>;
+
+  // Storage
+  //
+  // An instance of Storage manages the inline and out-of-line memory for
+  // instances of FixedArray. This guarantees that even when construction of
+  // individual elements fails in the FixedArray constructor body, the
+  // destructor for Storage will still be called and out-of-line memory will be
+  // properly deallocated.
+  //
+  class Storage : public InlinedStorage {
+   public:
+    explicit Storage(size_type n) : data_(CreateStorage(n)), size_(n) {}
+    ~Storage() noexcept {
+      if (UsingInlinedStorage(size())) {
+        this->AnnotateDestruct(size());
+      } else {
+        std::allocator<StorageElement>().deallocate(begin(), size());
+      }
+    }
+
+    size_type size() const { return size_; }
+    StorageElement* begin() const { return data_; }
+    StorageElement* end() const { return begin() + size(); }
+
+   private:
+    static bool UsingInlinedStorage(size_type n) {
+      return n <= inline_elements;
+    }
+
+    StorageElement* CreateStorage(size_type n) {
+      if (UsingInlinedStorage(n)) {
+        this->AnnotateConstruct(n);
+        return InlinedStorage::data();
+      } else {
+        return std::allocator<StorageElement>().allocate(n);
+      }
+    }
+
+    StorageElement* const data_;
+    const size_type size_;
+  };
+
+  const Storage storage_;
+};
+
+template <typename T, size_t N>
+constexpr size_t FixedArray<T, N>::inline_elements;
+
+template <typename T, size_t N>
+constexpr size_t FixedArray<T, N>::kInlineBytesDefault;
+
+template <typename T, size_t N>
+void FixedArray<T, N>::NonEmptyInlinedStorage::AnnotateConstruct(size_t n) {
+#ifdef ADDRESS_SANITIZER
+  if (!n) return;
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin());
+#endif                   // ADDRESS_SANITIZER
+  static_cast<void>(n);  // Mark used when not in asan mode
+}
+
+template <typename T, size_t N>
+void FixedArray<T, N>::NonEmptyInlinedStorage::AnnotateDestruct(size_t n) {
+#ifdef ADDRESS_SANITIZER
+  if (!n) return;
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data());
+#endif                   // ADDRESS_SANITIZER
+  static_cast<void>(n);  // Mark used when not in asan mode
+}
+
+}  // namespace absl
+#endif  // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/absl/container/fixed_array_benchmark.cc b/absl/container/fixed_array_benchmark.cc
new file mode 100644
index 0000000..b4f0cf2
--- /dev/null
+++ b/absl/container/fixed_array_benchmark.cc
@@ -0,0 +1,66 @@
+// Copyright 2017 The Abseil 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 "absl/container/fixed_array.h"
+
+#include <stddef.h>
+#include <string>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// For benchmarking -- simple class with constructor and destructor that
+// set an int to a constant..
+class SimpleClass {
+ public:
+  SimpleClass() : i(3) { }
+  ~SimpleClass() { i = 0; }
+ private:
+  int i;
+};
+
+template <typename C, size_t stack_size>
+void BM_FixedArray(benchmark::State& state) {
+  const int size = state.range(0);
+  for (auto _ : state) {
+    absl::FixedArray<C, stack_size> fa(size);
+    benchmark::DoNotOptimize(fa.data());
+  }
+}
+BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault)
+    ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16);
+
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault)
+    ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16);
+
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault)
+    ->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16);
+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16);
+
+}  // namespace
diff --git a/absl/container/fixed_array_exception_safety_test.cc b/absl/container/fixed_array_exception_safety_test.cc
new file mode 100644
index 0000000..c123c2a
--- /dev/null
+++ b/absl/container/fixed_array_exception_safety_test.cc
@@ -0,0 +1,117 @@
+// Copyright 2017 The Abseil 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 <initializer_list>
+
+#include "absl/container/fixed_array.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+
+namespace absl {
+
+namespace {
+
+constexpr size_t kInlined = 25;
+constexpr size_t kSmallSize = kInlined / 2;
+constexpr size_t kLargeSize = kInlined * 2;
+
+constexpr int kInitialValue = 5;
+constexpr int kUpdatedValue = 10;
+
+using ::testing::TestThrowingCtor;
+
+using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
+using FixedArr = absl::FixedArray<Thrower, kInlined>;
+
+using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using MoveFixedArr = absl::FixedArray<MoveThrower, kInlined>;
+
+TEST(FixedArrayExceptionSafety, CopyConstructor) {
+  auto small = FixedArr(kSmallSize);
+  TestThrowingCtor<FixedArr>(small);
+
+  auto large = FixedArr(kLargeSize);
+  TestThrowingCtor<FixedArr>(large);
+}
+
+TEST(FixedArrayExceptionSafety, MoveConstructor) {
+  TestThrowingCtor<FixedArr>(FixedArr(kSmallSize));
+  TestThrowingCtor<FixedArr>(FixedArr(kLargeSize));
+
+  // TypeSpec::kNoThrowMove
+  TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kSmallSize));
+  TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kLargeSize));
+}
+
+TEST(FixedArrayExceptionSafety, SizeConstructor) {
+  TestThrowingCtor<FixedArr>(kSmallSize);
+  TestThrowingCtor<FixedArr>(kLargeSize);
+}
+
+TEST(FixedArrayExceptionSafety, SizeValueConstructor) {
+  TestThrowingCtor<FixedArr>(kSmallSize, Thrower());
+  TestThrowingCtor<FixedArr>(kLargeSize, Thrower());
+}
+
+TEST(FixedArrayExceptionSafety, IteratorConstructor) {
+  auto small = FixedArr(kSmallSize);
+  TestThrowingCtor<FixedArr>(small.begin(), small.end());
+
+  auto large = FixedArr(kLargeSize);
+  TestThrowingCtor<FixedArr>(large.begin(), large.end());
+}
+
+TEST(FixedArrayExceptionSafety, InitListConstructor) {
+  constexpr int small_inlined = 3;
+  using SmallFixedArr = absl::FixedArray<Thrower, small_inlined>;
+
+  TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{});
+  // Test inlined allocation
+  TestThrowingCtor<SmallFixedArr>(
+      std::initializer_list<Thrower>{Thrower{}, Thrower{}});
+  // Test out of line allocation
+  TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{
+      Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
+}
+
+testing::AssertionResult ReadMemory(FixedArr* fixed_arr) {
+  // Marked volatile to prevent optimization. Used for running asan tests.
+  volatile int sum = 0;
+  for (const auto& thrower : *fixed_arr) {
+    sum += thrower.Get();
+  }
+  return testing::AssertionSuccess() << "Values sum to [" << sum << "]";
+}
+
+TEST(FixedArrayExceptionSafety, Fill) {
+  auto test_fill = testing::MakeExceptionSafetyTester()
+                       .WithInvariants(ReadMemory)
+                       .WithOperation([&](FixedArr* fixed_arr_ptr) {
+                         auto thrower =
+                             Thrower(kUpdatedValue, testing::nothrow_ctor);
+                         fixed_arr_ptr->fill(thrower);
+                       });
+
+  EXPECT_TRUE(
+      test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue)))
+          .Test());
+  EXPECT_TRUE(
+      test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue)))
+          .Test());
+}
+
+}  // namespace
+
+}  // namespace absl
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
new file mode 100644
index 0000000..2142132
--- /dev/null
+++ b/absl/container/fixed_array_test.cc
@@ -0,0 +1,659 @@
+// Copyright 2017 The Abseil 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 "absl/container/fixed_array.h"
+
+#include <stdio.h>
+#include <list>
+#include <memory>
+#include <numeric>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/memory/memory.h"
+
+using ::testing::ElementsAreArray;
+
+namespace {
+
+// Helper routine to determine if a absl::FixedArray used stack allocation.
+template <typename ArrayType>
+static bool IsOnStack(const ArrayType& a) {
+  return a.size() <= ArrayType::inline_elements;
+}
+
+class ConstructionTester {
+ public:
+  ConstructionTester()
+      : self_ptr_(this),
+        value_(0) {
+    constructions++;
+  }
+  ~ConstructionTester() {
+    assert(self_ptr_ == this);
+    self_ptr_ = nullptr;
+    destructions++;
+  }
+
+  // These are incremented as elements are constructed and destructed so we can
+  // be sure all elements are properly cleaned up.
+  static int constructions;
+  static int destructions;
+
+  void CheckConstructed() {
+    assert(self_ptr_ == this);
+  }
+
+  void set(int value) { value_ = value; }
+  int get() { return value_; }
+
+ private:
+  // self_ptr_ should always point to 'this' -- that's how we can be sure the
+  // constructor has been called.
+  ConstructionTester* self_ptr_;
+  int value_;
+};
+
+int ConstructionTester::constructions = 0;
+int ConstructionTester::destructions = 0;
+
+// ThreeInts will initialize its three ints to the value stored in
+// ThreeInts::counter. The constructor increments counter so that each object
+// in an array of ThreeInts will have different values.
+class ThreeInts {
+ public:
+  ThreeInts() {
+    x_ = counter;
+    y_ = counter;
+    z_ = counter;
+    ++counter;
+  }
+
+  static int counter;
+
+  int x_, y_, z_;
+};
+
+int ThreeInts::counter = 0;
+
+TEST(FixedArrayTest, CopyCtor) {
+  absl::FixedArray<int, 10> on_stack(5);
+  std::iota(on_stack.begin(), on_stack.end(), 0);
+  absl::FixedArray<int, 10> stack_copy = on_stack;
+  EXPECT_THAT(stack_copy, ElementsAreArray(on_stack));
+  EXPECT_TRUE(IsOnStack(stack_copy));
+
+  absl::FixedArray<int, 10> allocated(15);
+  std::iota(allocated.begin(), allocated.end(), 0);
+  absl::FixedArray<int, 10> alloced_copy = allocated;
+  EXPECT_THAT(alloced_copy, ElementsAreArray(allocated));
+  EXPECT_FALSE(IsOnStack(alloced_copy));
+}
+
+TEST(FixedArrayTest, MoveCtor) {
+  absl::FixedArray<std::unique_ptr<int>, 10> on_stack(5);
+  for (int i = 0; i < 5; ++i) {
+    on_stack[i] = absl::make_unique<int>(i);
+  }
+
+  absl::FixedArray<std::unique_ptr<int>, 10> stack_copy = std::move(on_stack);
+  for (int i = 0; i < 5; ++i) EXPECT_EQ(*(stack_copy[i]), i);
+  EXPECT_EQ(stack_copy.size(), on_stack.size());
+
+  absl::FixedArray<std::unique_ptr<int>, 10> allocated(15);
+  for (int i = 0; i < 15; ++i) {
+    allocated[i] = absl::make_unique<int>(i);
+  }
+
+  absl::FixedArray<std::unique_ptr<int>, 10> alloced_copy =
+      std::move(allocated);
+  for (int i = 0; i < 15; ++i) EXPECT_EQ(*(alloced_copy[i]), i);
+  EXPECT_EQ(allocated.size(), alloced_copy.size());
+}
+
+TEST(FixedArrayTest, SmallObjects) {
+  // Small object arrays
+  {
+    // Short arrays should be on the stack
+    absl::FixedArray<int> array(4);
+    EXPECT_TRUE(IsOnStack(array));
+  }
+
+  {
+    // Large arrays should be on the heap
+    absl::FixedArray<int> array(1048576);
+    EXPECT_FALSE(IsOnStack(array));
+  }
+
+  {
+    // Arrays of <= default size should be on the stack
+    absl::FixedArray<int, 100> array(100);
+    EXPECT_TRUE(IsOnStack(array));
+  }
+
+  {
+    // Arrays of > default size should be on the stack
+    absl::FixedArray<int, 100> array(101);
+    EXPECT_FALSE(IsOnStack(array));
+  }
+
+  {
+    // Arrays with different size elements should use approximately
+    // same amount of stack space
+    absl::FixedArray<int> array1(0);
+    absl::FixedArray<char> array2(0);
+    EXPECT_LE(sizeof(array1), sizeof(array2)+100);
+    EXPECT_LE(sizeof(array2), sizeof(array1)+100);
+  }
+
+  {
+    // Ensure that vectors are properly constructed inside a fixed array.
+    absl::FixedArray<std::vector<int> > array(2);
+    EXPECT_EQ(0, array[0].size());
+    EXPECT_EQ(0, array[1].size());
+  }
+
+  {
+    // Regardless of absl::FixedArray implementation, check that a type with a
+    // low alignment requirement and a non power-of-two size is initialized
+    // correctly.
+    ThreeInts::counter = 1;
+    absl::FixedArray<ThreeInts> array(2);
+    EXPECT_EQ(1, array[0].x_);
+    EXPECT_EQ(1, array[0].y_);
+    EXPECT_EQ(1, array[0].z_);
+    EXPECT_EQ(2, array[1].x_);
+    EXPECT_EQ(2, array[1].y_);
+    EXPECT_EQ(2, array[1].z_);
+  }
+}
+
+TEST(FixedArrayTest, AtThrows) {
+  absl::FixedArray<int> a = {1, 2, 3};
+  EXPECT_EQ(a.at(2), 3);
+  ABSL_BASE_INTERNAL_EXPECT_FAIL(a.at(3), std::out_of_range,
+                                 "failed bounds check");
+}
+
+TEST(FixedArrayRelationalsTest, EqualArrays) {
+  for (int i = 0; i < 10; ++i) {
+    absl::FixedArray<int, 5> a1(i);
+    std::iota(a1.begin(), a1.end(), 0);
+    absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
+
+    EXPECT_TRUE(a1 == a2);
+    EXPECT_FALSE(a1 != a2);
+    EXPECT_TRUE(a2 == a1);
+    EXPECT_FALSE(a2 != a1);
+    EXPECT_FALSE(a1 < a2);
+    EXPECT_FALSE(a1 > a2);
+    EXPECT_FALSE(a2 < a1);
+    EXPECT_FALSE(a2 > a1);
+    EXPECT_TRUE(a1 <= a2);
+    EXPECT_TRUE(a1 >= a2);
+    EXPECT_TRUE(a2 <= a1);
+    EXPECT_TRUE(a2 >= a1);
+  }
+}
+
+TEST(FixedArrayRelationalsTest, UnequalArrays) {
+  for (int i = 1; i < 10; ++i) {
+    absl::FixedArray<int, 5> a1(i);
+    std::iota(a1.begin(), a1.end(), 0);
+    absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
+    --a2[i / 2];
+
+    EXPECT_FALSE(a1 == a2);
+    EXPECT_TRUE(a1 != a2);
+    EXPECT_FALSE(a2 == a1);
+    EXPECT_TRUE(a2 != a1);
+    EXPECT_FALSE(a1 < a2);
+    EXPECT_TRUE(a1 > a2);
+    EXPECT_TRUE(a2 < a1);
+    EXPECT_FALSE(a2 > a1);
+    EXPECT_FALSE(a1 <= a2);
+    EXPECT_TRUE(a1 >= a2);
+    EXPECT_TRUE(a2 <= a1);
+    EXPECT_FALSE(a2 >= a1);
+  }
+}
+
+template <int stack_elements>
+static void TestArray(int n) {
+  SCOPED_TRACE(n);
+  SCOPED_TRACE(stack_elements);
+  ConstructionTester::constructions = 0;
+  ConstructionTester::destructions = 0;
+  {
+    absl::FixedArray<ConstructionTester, stack_elements> array(n);
+
+    EXPECT_THAT(array.size(), n);
+    EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n);
+    EXPECT_THAT(array.begin() + n, array.end());
+
+    // Check that all elements were constructed
+    for (int i = 0; i < n; i++) {
+      array[i].CheckConstructed();
+    }
+    // Check that no other elements were constructed
+    EXPECT_THAT(ConstructionTester::constructions, n);
+
+    // Test operator[]
+    for (int i = 0; i < n; i++) {
+      array[i].set(i);
+    }
+    for (int i = 0; i < n; i++) {
+      EXPECT_THAT(array[i].get(), i);
+      EXPECT_THAT(array.data()[i].get(), i);
+    }
+
+    // Test data()
+    for (int i = 0; i < n; i++) {
+      array.data()[i].set(i + 1);
+    }
+    for (int i = 0; i < n; i++) {
+      EXPECT_THAT(array[i].get(), i+1);
+      EXPECT_THAT(array.data()[i].get(), i+1);
+    }
+  }  // Close scope containing 'array'.
+
+  // Check that all constructed elements were destructed.
+  EXPECT_EQ(ConstructionTester::constructions,
+            ConstructionTester::destructions);
+}
+
+template <int elements_per_inner_array, int inline_elements>
+static void TestArrayOfArrays(int n) {
+  SCOPED_TRACE(n);
+  SCOPED_TRACE(inline_elements);
+  SCOPED_TRACE(elements_per_inner_array);
+  ConstructionTester::constructions = 0;
+  ConstructionTester::destructions = 0;
+  {
+    using InnerArray = ConstructionTester[elements_per_inner_array];
+    // Heap-allocate the FixedArray to avoid blowing the stack frame.
+    auto array_ptr =
+        absl::make_unique<absl::FixedArray<InnerArray, inline_elements>>(n);
+    auto& array = *array_ptr;
+
+    ASSERT_EQ(array.size(), n);
+    ASSERT_EQ(array.memsize(),
+             sizeof(ConstructionTester) * elements_per_inner_array * n);
+    ASSERT_EQ(array.begin() + n, array.end());
+
+    // Check that all elements were constructed
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < elements_per_inner_array; j++) {
+        (array[i])[j].CheckConstructed();
+      }
+    }
+    // Check that no other elements were constructed
+    ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array);
+
+    // Test operator[]
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < elements_per_inner_array; j++) {
+        (array[i])[j].set(i * elements_per_inner_array + j);
+      }
+    }
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < elements_per_inner_array; j++) {
+        ASSERT_EQ((array[i])[j].get(),  i * elements_per_inner_array + j);
+        ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
+      }
+    }
+
+    // Test data()
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < elements_per_inner_array; j++) {
+        (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j);
+      }
+    }
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < elements_per_inner_array; j++) {
+        ASSERT_EQ((array[i])[j].get(),
+                  (i + 1) * elements_per_inner_array + j);
+        ASSERT_EQ((array.data()[i])[j].get(),
+                  (i + 1) * elements_per_inner_array + j);
+      }
+    }
+  }  // Close scope containing 'array'.
+
+  // Check that all constructed elements were destructed.
+  EXPECT_EQ(ConstructionTester::constructions,
+            ConstructionTester::destructions);
+}
+
+TEST(IteratorConstructorTest, NonInline) {
+  int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+  absl::FixedArray<int, ABSL_ARRAYSIZE(kInput) - 1> const fixed(
+      kInput, kInput + ABSL_ARRAYSIZE(kInput));
+  ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
+    ASSERT_EQ(kInput[i], fixed[i]);
+  }
+}
+
+TEST(IteratorConstructorTest, Inline) {
+  int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+  absl::FixedArray<int, ABSL_ARRAYSIZE(kInput)> const fixed(
+      kInput, kInput + ABSL_ARRAYSIZE(kInput));
+  ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
+    ASSERT_EQ(kInput[i], fixed[i]);
+  }
+}
+
+TEST(IteratorConstructorTest, NonPod) {
+  char const* kInput[] =
+      { "red", "orange", "yellow", "green", "blue", "indigo", "violet" };
+  absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+  ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
+    ASSERT_EQ(kInput[i], fixed[i]);
+  }
+}
+
+TEST(IteratorConstructorTest, FromEmptyVector) {
+  std::vector<int> const empty;
+  absl::FixedArray<int> const fixed(empty.begin(), empty.end());
+  EXPECT_EQ(0, fixed.size());
+  EXPECT_EQ(empty.size(), fixed.size());
+}
+
+TEST(IteratorConstructorTest, FromNonEmptyVector) {
+  int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+  std::vector<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+  absl::FixedArray<int> const fixed(items.begin(), items.end());
+  ASSERT_EQ(items.size(), fixed.size());
+  for (size_t i = 0; i < items.size(); ++i) {
+    ASSERT_EQ(items[i], fixed[i]);
+  }
+}
+
+TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
+  int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+  std::list<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+  absl::FixedArray<int> const fixed(items.begin(), items.end());
+  EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
+}
+
+TEST(InitListConstructorTest, InitListConstruction) {
+  absl::FixedArray<int> fixed = {1, 2, 3};
+  EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
+}
+
+TEST(FillConstructorTest, NonEmptyArrays) {
+  absl::FixedArray<int> stack_array(4, 1);
+  EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
+
+  absl::FixedArray<int, 0> heap_array(4, 1);
+  EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
+}
+
+TEST(FillConstructorTest, EmptyArray) {
+  absl::FixedArray<int> empty_fill(0, 1);
+  absl::FixedArray<int> empty_size(0);
+  EXPECT_EQ(empty_fill, empty_size);
+}
+
+TEST(FillConstructorTest, NotTriviallyCopyable) {
+  std::string str = "abcd";
+  absl::FixedArray<std::string> strings = {str, str, str, str};
+
+  absl::FixedArray<std::string> array(4, str);
+  EXPECT_EQ(array, strings);
+}
+
+TEST(FillConstructorTest, Disambiguation) {
+  absl::FixedArray<size_t> a(1, 2);
+  EXPECT_THAT(a, testing::ElementsAre(2));
+}
+
+TEST(FixedArrayTest, ManySizedArrays) {
+  std::vector<int> sizes;
+  for (int i = 1; i < 100; i++) sizes.push_back(i);
+  for (int i = 100; i <= 1000; i += 100) sizes.push_back(i);
+  for (int n : sizes) {
+    TestArray<0>(n);
+    TestArray<1>(n);
+    TestArray<64>(n);
+    TestArray<1000>(n);
+  }
+}
+
+TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) {
+  for (int n = 1; n < 1000; n++) {
+    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n)));
+    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n)));
+    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n)));
+    ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n)));
+  }
+}
+
+TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) {
+  for (int n = 1; n < 1000; n++) {
+    TestArrayOfArrays<2, 0>(n);
+    TestArrayOfArrays<2, 1>(n);
+    TestArrayOfArrays<2, 64>(n);
+    TestArrayOfArrays<2, 1000>(n);
+  }
+}
+
+// If value_type is put inside of a struct container,
+// we might evoke this error in a hardened build unless data() is carefully
+// written, so check on that.
+//     error: call to int __builtin___sprintf_chk(etc...)
+//     will always overflow destination buffer [-Werror]
+TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
+  absl::FixedArray<char, 32> buf(32);
+  sprintf(buf.data(), "foo");  // NOLINT(runtime/printf)
+}
+
+TEST(FixedArrayTest, TooBigInlinedSpace) {
+  struct TooBig {
+    char c[1 << 20];
+  };  // too big for even one on the stack
+
+  // Simulate the data members of absl::FixedArray, a pointer and a size_t.
+  struct Data {
+    TooBig* p;
+    size_t size;
+  };
+
+  // Make sure TooBig objects are not inlined for 0 or default size.
+  static_assert(sizeof(absl::FixedArray<TooBig, 0>) == sizeof(Data),
+                "0-sized absl::FixedArray should have same size as Data.");
+  static_assert(alignof(absl::FixedArray<TooBig, 0>) == alignof(Data),
+                "0-sized absl::FixedArray should have same alignment as Data.");
+  static_assert(sizeof(absl::FixedArray<TooBig>) == sizeof(Data),
+                "default-sized absl::FixedArray should have same size as Data");
+  static_assert(
+      alignof(absl::FixedArray<TooBig>) == alignof(Data),
+      "default-sized absl::FixedArray should have same alignment as Data.");
+}
+
+// PickyDelete EXPECTs its class-scope deallocation funcs are unused.
+struct PickyDelete {
+  PickyDelete() {}
+  ~PickyDelete() {}
+  void operator delete(void* p) {
+    EXPECT_TRUE(false) << __FUNCTION__;
+    ::operator delete(p);
+  }
+  void operator delete[](void* p) {
+    EXPECT_TRUE(false) << __FUNCTION__;
+    ::operator delete[](p);
+  }
+};
+
+TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); }
+
+
+TEST(FixedArrayTest, Data) {
+  static const int kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+  absl::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
+  EXPECT_EQ(fa.data(), &*fa.begin());
+  EXPECT_EQ(fa.data(), &fa[0]);
+
+  const absl::FixedArray<int>& cfa = fa;
+  EXPECT_EQ(cfa.data(), &*cfa.begin());
+  EXPECT_EQ(cfa.data(), &cfa[0]);
+}
+
+TEST(FixedArrayTest, Empty) {
+  absl::FixedArray<int> empty(0);
+  absl::FixedArray<int> inline_filled(1);
+  absl::FixedArray<int, 0> heap_filled(1);
+  EXPECT_TRUE(empty.empty());
+  EXPECT_FALSE(inline_filled.empty());
+  EXPECT_FALSE(heap_filled.empty());
+}
+
+TEST(FixedArrayTest, FrontAndBack) {
+  absl::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3};
+  EXPECT_EQ(inlined.front(), 1);
+  EXPECT_EQ(inlined.back(), 3);
+
+  absl::FixedArray<int, 0> allocated = {1, 2, 3};
+  EXPECT_EQ(allocated.front(), 1);
+  EXPECT_EQ(allocated.back(), 3);
+
+  absl::FixedArray<int> one_element = {1};
+  EXPECT_EQ(one_element.front(), one_element.back());
+}
+
+TEST(FixedArrayTest, ReverseIteratorInlined) {
+  absl::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4};
+
+  int counter = 5;
+  for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
+       iter != a.rend(); ++iter) {
+    counter--;
+    EXPECT_EQ(counter, *iter);
+  }
+  EXPECT_EQ(counter, 0);
+
+  counter = 5;
+  for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
+       iter != a.rend(); ++iter) {
+    counter--;
+    EXPECT_EQ(counter, *iter);
+  }
+  EXPECT_EQ(counter, 0);
+
+  counter = 5;
+  for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
+    counter--;
+    EXPECT_EQ(counter, *iter);
+  }
+  EXPECT_EQ(counter, 0);
+}
+
+TEST(FixedArrayTest, ReverseIteratorAllocated) {
+  absl::FixedArray<int, 0> a = {0, 1, 2, 3, 4};
+
+  int counter = 5;
+  for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
+       iter != a.rend(); ++iter) {
+    counter--;
+    EXPECT_EQ(counter, *iter);
+  }
+  EXPECT_EQ(counter, 0);
+
+  counter = 5;
+  for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
+       iter != a.rend(); ++iter) {
+    counter--;
+    EXPECT_EQ(counter, *iter);
+  }
+  EXPECT_EQ(counter, 0);
+
+  counter = 5;
+  for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
+    counter--;
+    EXPECT_EQ(counter, *iter);
+  }
+  EXPECT_EQ(counter, 0);
+}
+
+TEST(FixedArrayTest, Fill) {
+  absl::FixedArray<int, 5 * sizeof(int)> inlined(5);
+  int fill_val = 42;
+  inlined.fill(fill_val);
+  for (int i : inlined) EXPECT_EQ(i, fill_val);
+
+  absl::FixedArray<int, 0> allocated(5);
+  allocated.fill(fill_val);
+  for (int i : allocated) EXPECT_EQ(i, fill_val);
+
+  // It doesn't do anything, just make sure this compiles.
+  absl::FixedArray<int> empty(0);
+  empty.fill(fill_val);
+}
+
+#ifdef ADDRESS_SANITIZER
+TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
+  absl::FixedArray<int, 32> a(10);
+  int *raw = a.data();
+  raw[0] = 0;
+  raw[9] = 0;
+  EXPECT_DEATH(raw[-2] = 0, "container-overflow");
+  EXPECT_DEATH(raw[-1] = 0, "container-overflow");
+  EXPECT_DEATH(raw[10] = 0, "container-overflow");
+  EXPECT_DEATH(raw[31] = 0, "container-overflow");
+}
+
+TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
+  absl::FixedArray<char, 17> a(12);
+  char *raw = a.data();
+  raw[0] = 0;
+  raw[11] = 0;
+  EXPECT_DEATH(raw[-7] = 0, "container-overflow");
+  EXPECT_DEATH(raw[-1] = 0, "container-overflow");
+  EXPECT_DEATH(raw[12] = 0, "container-overflow");
+  EXPECT_DEATH(raw[17] = 0, "container-overflow");
+}
+
+TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
+  absl::FixedArray<uint64_t, 20> a(20);
+  uint64_t *raw = a.data();
+  raw[0] = 0;
+  raw[19] = 0;
+  EXPECT_DEATH(raw[-1] = 0, "container-overflow");
+  EXPECT_DEATH(raw[20] = 0, "container-overflow");
+}
+
+TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
+  absl::FixedArray<ThreeInts> a(10);
+  ThreeInts *raw = a.data();
+  raw[0] = ThreeInts();
+  raw[9] = ThreeInts();
+  // Note: raw[-1] is pointing to 12 bytes before the container range. However,
+  // there is only a 8-byte red zone before the container range, so we only
+  // access the last 4 bytes of the struct to make sure it stays within the red
+  // zone.
+  EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow");
+  EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow");
+  // The actual size of storage is kDefaultBytes=256, 21*12 = 252,
+  // so reading raw[21] should still trigger the correct warning.
+  EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow");
+}
+#endif  // ADDRESS_SANITIZER
+
+}  // namespace
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
new file mode 100644
index 0000000..03660f1
--- /dev/null
+++ b/absl/container/inlined_vector.h
@@ -0,0 +1,1379 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: inlined_vector.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains the declaration and definition of an "inlined
+// vector" which behaves in an equivalent fashion to a `std::vector`, except
+// that storage for small sequences of the vector are provided inline without
+// requiring any heap allocation.
+
+// An `absl::InlinedVector<T,N>` specifies the size N at which to inline as one
+// of its template parameters. Vectors of length <= N are provided inline.
+// Typically N is very small (e.g., 4) so that sequences that are expected to be
+// short do not require allocations.
+
+// An `absl::InlinedVector` does not usually require a specific allocator; if
+// the inlined vector grows beyond its initial constraints, it will need to
+// allocate (as any normal `std::vector` would) and it will generally use the
+// default allocator in that case; optionally, a custom allocator may be
+// specified using an `absl::InlinedVector<T,N,A>` construction.
+
+#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
+#define ABSL_CONTAINER_INLINED_VECTOR_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// InlinedVector
+// -----------------------------------------------------------------------------
+//
+// An `absl::InlinedVector` is designed to be a drop-in replacement for
+// `std::vector` for use cases where the vector's size is sufficiently small
+// that it can be inlined. If the inlined vector does grow beyond its estimated
+// size, it will trigger an initial allocation on the heap, and will behave as a
+// `std:vector`. The API of the `absl::InlinedVector` within this file is
+// designed to cover the same API footprint as covered by `std::vector`.
+template <typename T, size_t N, typename A = std::allocator<T> >
+class InlinedVector {
+  using AllocatorTraits = std::allocator_traits<A>;
+
+ public:
+  using allocator_type = A;
+  using value_type = typename allocator_type::value_type;
+  using pointer = typename allocator_type::pointer;
+  using const_pointer = typename allocator_type::const_pointer;
+  using reference = typename allocator_type::reference;
+  using const_reference = typename allocator_type::const_reference;
+  using size_type = typename allocator_type::size_type;
+  using difference_type = typename allocator_type::difference_type;
+  using iterator = pointer;
+  using const_iterator = const_pointer;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  InlinedVector() noexcept(noexcept(allocator_type()))
+      : allocator_and_tag_(allocator_type()) {}
+
+  explicit InlinedVector(const allocator_type& alloc) noexcept
+      : allocator_and_tag_(alloc) {}
+
+  // Create a vector with n copies of value_type().
+  explicit InlinedVector(size_type n,
+                         const allocator_type& alloc = allocator_type())
+      : allocator_and_tag_(alloc) {
+    InitAssign(n);
+  }
+
+  // Create a vector with n copies of elem
+  InlinedVector(size_type n, const value_type& elem,
+                const allocator_type& alloc = allocator_type())
+      : allocator_and_tag_(alloc) {
+    InitAssign(n, elem);
+  }
+
+  // Create and initialize with the elements [first .. last).
+  // The unused enable_if argument restricts this constructor so that it is
+  // elided when value_type is an integral type.  This prevents ambiguous
+  // interpretation between a call to this constructor with two integral
+  // arguments and a call to the preceding (n, elem) constructor.
+  template <typename InputIterator>
+  InlinedVector(
+      InputIterator first, InputIterator last,
+      const allocator_type& alloc = allocator_type(),
+      typename std::enable_if<!std::is_integral<InputIterator>::value>::type* =
+          nullptr)
+      : allocator_and_tag_(alloc) {
+    AppendRange(first, last);
+  }
+
+  InlinedVector(std::initializer_list<value_type> init,
+                const allocator_type& alloc = allocator_type())
+      : allocator_and_tag_(alloc) {
+    AppendRange(init.begin(), init.end());
+  }
+
+  InlinedVector(const InlinedVector& v);
+  InlinedVector(const InlinedVector& v, const allocator_type& alloc);
+
+  // This move constructor does not allocate and only moves the underlying
+  // objects, so its `noexcept` specification depends on whether moving the
+  // underlying objects can throw or not. We assume
+  //  a) move constructors should only throw due to allocation failure and
+  //  b) if `value_type`'s move constructor allocates, it uses the same
+  //     allocation function as the `InlinedVector`'s allocator, so the move
+  //     constructor is non-throwing if the allocator is non-throwing or
+  //     `value_type`'s move constructor is specified as `noexcept`.
+  InlinedVector(InlinedVector&& v) noexcept(
+      absl::allocator_is_nothrow<allocator_type>::value ||
+      std::is_nothrow_move_constructible<value_type>::value);
+
+  // This move constructor allocates and also moves the underlying objects, so
+  // its `noexcept` specification depends on whether the allocation can throw
+  // and whether moving the underlying objects can throw. Based on the same
+  // assumptions above, the `noexcept` specification is dominated by whether the
+  // allocation can throw regardless of whether `value_type`'s move constructor
+  // is specified as `noexcept`.
+  InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept(
+      absl::allocator_is_nothrow<allocator_type>::value);
+
+  ~InlinedVector() { clear(); }
+
+  InlinedVector& operator=(const InlinedVector& v) {
+    if (this == &v) {
+      return *this;
+    }
+    // Optimized to avoid reallocation.
+    // Prefer reassignment to copy construction for elements.
+    if (size() < v.size()) {  // grow
+      reserve(v.size());
+      std::copy(v.begin(), v.begin() + size(), begin());
+      std::copy(v.begin() + size(), v.end(), std::back_inserter(*this));
+    } else {  // maybe shrink
+      erase(begin() + v.size(), end());
+      std::copy(v.begin(), v.end(), begin());
+    }
+    return *this;
+  }
+
+  InlinedVector& operator=(InlinedVector&& v) {
+    if (this == &v) {
+      return *this;
+    }
+    if (v.allocated()) {
+      clear();
+      tag().set_allocated_size(v.size());
+      init_allocation(v.allocation());
+      v.tag() = Tag();
+    } else {
+      if (allocated()) clear();
+      // Both are inlined now.
+      if (size() < v.size()) {
+        auto mid = std::make_move_iterator(v.begin() + size());
+        std::copy(std::make_move_iterator(v.begin()), mid, begin());
+        UninitializedCopy(mid, std::make_move_iterator(v.end()), end());
+      } else {
+        auto new_end = std::copy(std::make_move_iterator(v.begin()),
+                                 std::make_move_iterator(v.end()), begin());
+        Destroy(new_end, end());
+      }
+      tag().set_inline_size(v.size());
+    }
+    return *this;
+  }
+
+  InlinedVector& operator=(std::initializer_list<value_type> init) {
+    AssignRange(init.begin(), init.end());
+    return *this;
+  }
+
+  // InlinedVector::assign()
+  //
+  // Replaces the contents of the inlined vector with copies of those in the
+  // iterator range [first, last).
+  template <typename InputIterator>
+  void assign(
+      InputIterator first, InputIterator last,
+      typename std::enable_if<!std::is_integral<InputIterator>::value>::type* =
+          nullptr) {
+    AssignRange(first, last);
+  }
+
+  // Overload of `InlinedVector::assign()` to take values from elements of an
+  // initializer list
+  void assign(std::initializer_list<value_type> init) {
+    AssignRange(init.begin(), init.end());
+  }
+
+  // Overload of `InlinedVector::assign()` to replace the first `n` elements of
+  // the inlined vector with `elem` values.
+  void assign(size_type n, const value_type& elem) {
+    if (n <= size()) {  // Possibly shrink
+      std::fill_n(begin(), n, elem);
+      erase(begin() + n, end());
+      return;
+    }
+    // Grow
+    reserve(n);
+    std::fill_n(begin(), size(), elem);
+    if (allocated()) {
+      UninitializedFill(allocated_space() + size(), allocated_space() + n,
+                        elem);
+      tag().set_allocated_size(n);
+    } else {
+      UninitializedFill(inlined_space() + size(), inlined_space() + n, elem);
+      tag().set_inline_size(n);
+    }
+  }
+
+  // InlinedVector::size()
+  //
+  // Returns the number of elements in the inlined vector.
+  size_type size() const noexcept { return tag().size(); }
+
+  // InlinedVector::empty()
+  //
+  // Checks if the inlined vector has no elements.
+  bool empty() const noexcept { return (size() == 0); }
+
+  // InlinedVector::capacity()
+  //
+  // Returns the number of elements that can be stored in an inlined vector
+  // without requiring a reallocation of underlying memory. Note that for
+  // most inlined vectors, `capacity()` should equal its initial size `N`; for
+  // inlined vectors which exceed this capacity, they will no longer be inlined,
+  // and `capacity()` will equal its capacity on the allocated heap.
+  size_type capacity() const noexcept {
+    return allocated() ? allocation().capacity() : N;
+  }
+
+  // InlinedVector::max_size()
+  //
+  // Returns the maximum number of elements the vector can hold.
+  size_type max_size() const noexcept {
+    // One bit of the size storage is used to indicate whether the inlined
+    // vector is allocated; as a result, the maximum size of the container that
+    // we can express is half of the max for our size type.
+    return std::numeric_limits<size_type>::max() / 2;
+  }
+
+  // InlinedVector::data()
+  //
+  // Returns a const T* pointer to elements of the inlined vector. This pointer
+  // can be used to access (but not modify) the contained elements.
+  // Only results within the range `[0,size())` are defined.
+  const_pointer data() const noexcept {
+    return allocated() ? allocated_space() : inlined_space();
+  }
+
+  // Overload of InlinedVector::data() to return a T* pointer to elements of the
+  // inlined vector. This pointer can be used to access and modify the contained
+  // elements.
+  pointer data() noexcept {
+    return allocated() ? allocated_space() : inlined_space();
+  }
+
+  // InlinedVector::clear()
+  //
+  // Removes all elements from the inlined vector.
+  void clear() noexcept {
+    size_type s = size();
+    if (allocated()) {
+      Destroy(allocated_space(), allocated_space() + s);
+      allocation().Dealloc(allocator());
+    } else if (s != 0) {  // do nothing for empty vectors
+      Destroy(inlined_space(), inlined_space() + s);
+    }
+    tag() = Tag();
+  }
+
+  // InlinedVector::at()
+  //
+  // Returns the ith element of an inlined vector.
+  const value_type& at(size_type i) const {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange(
+          "InlinedVector::at failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // InlinedVector::operator[]
+  //
+  // Returns the ith element of an inlined vector using the array operator.
+  const value_type& operator[](size_type i) const {
+    assert(i < size());
+    return data()[i];
+  }
+
+  // Overload of InlinedVector::at() to return the ith element of an inlined
+  // vector.
+  value_type& at(size_type i) {
+    if (i >= size()) {
+      base_internal::ThrowStdOutOfRange(
+          "InlinedVector::at failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // Overload of InlinedVector::operator[] to return the ith element of an
+  // inlined vector.
+  value_type& operator[](size_type i) {
+    assert(i < size());
+    return data()[i];
+  }
+
+  // InlinedVector::back()
+  //
+  // Returns a reference to the last element of an inlined vector.
+  value_type& back() {
+    assert(!empty());
+    return at(size() - 1);
+  }
+
+  // Overload of InlinedVector::back() returns a reference to the last element
+  // of an inlined vector of const values.
+  const value_type& back() const {
+    assert(!empty());
+    return at(size() - 1);
+  }
+
+  // InlinedVector::front()
+  //
+  // Returns a reference to the first element of an inlined vector.
+  value_type& front() {
+    assert(!empty());
+    return at(0);
+  }
+
+  // Overload of InlinedVector::front() returns a reference to the first element
+  // of an inlined vector of const values.
+  const value_type& front() const {
+    assert(!empty());
+    return at(0);
+  }
+
+  // InlinedVector::emplace_back()
+  //
+  // Constructs and appends an object to the inlined vector.
+  //
+  // Returns a reference to the inserted element.
+  template <typename... Args>
+  value_type& emplace_back(Args&&... args) {
+    size_type s = size();
+    assert(s <= capacity());
+    if (ABSL_PREDICT_FALSE(s == capacity())) {
+      return GrowAndEmplaceBack(std::forward<Args>(args)...);
+    }
+    assert(s < capacity());
+
+    value_type* space;
+    if (allocated()) {
+      tag().set_allocated_size(s + 1);
+      space = allocated_space();
+    } else {
+      tag().set_inline_size(s + 1);
+      space = inlined_space();
+    }
+    return Construct(space + s, std::forward<Args>(args)...);
+  }
+
+  // InlinedVector::push_back()
+  //
+  // Appends a const element to the inlined vector.
+  void push_back(const value_type& t) { emplace_back(t); }
+
+  // Overload of InlinedVector::push_back() to append a move-only element to the
+  // inlined vector.
+  void push_back(value_type&& t) { emplace_back(std::move(t)); }
+
+  // InlinedVector::pop_back()
+  //
+  // Removes the last element (which is destroyed) in the inlined vector.
+  void pop_back() {
+    assert(!empty());
+    size_type s = size();
+    if (allocated()) {
+      Destroy(allocated_space() + s - 1, allocated_space() + s);
+      tag().set_allocated_size(s - 1);
+    } else {
+      Destroy(inlined_space() + s - 1, inlined_space() + s);
+      tag().set_inline_size(s - 1);
+    }
+  }
+
+  // InlinedVector::resize()
+  //
+  // Resizes the inlined vector to contain `n` elements. If `n` is smaller than
+  // the inlined vector's current size, extra elements are destroyed. If `n` is
+  // larger than the initial size, new elements are value-initialized.
+  void resize(size_type n);
+
+  // Overload of InlinedVector::resize() to resize the inlined vector to contain
+  // `n` elements. If `n` is larger than the current size, enough copies of
+  // `elem` are appended to increase its size to `n`.
+  void resize(size_type n, const value_type& elem);
+
+  // InlinedVector::begin()
+  //
+  // Returns an iterator to the beginning of the inlined vector.
+  iterator begin() noexcept { return data(); }
+
+  // Overload of InlinedVector::begin() for returning a const iterator to the
+  // beginning of the inlined vector.
+  const_iterator begin() const noexcept { return data(); }
+
+  // InlinedVector::cbegin()
+  //
+  // Returns a const iterator to the beginning of the inlined vector.
+  const_iterator cbegin() const noexcept { return begin(); }
+
+  // InlinedVector::end()
+  //
+  // Returns an iterator to the end of the inlined vector.
+  iterator end() noexcept { return data() + size(); }
+
+  // Overload of InlinedVector::end() for returning a const iterator to the end
+  // of the inlined vector.
+  const_iterator end() const noexcept { return data() + size(); }
+
+  // InlinedVector::cend()
+  //
+  // Returns a const iterator to the end of the inlined vector.
+  const_iterator cend() const noexcept { return end(); }
+
+  // InlinedVector::rbegin()
+  //
+  // Returns a reverse iterator from the end of the inlined vector.
+  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+
+  // Overload of InlinedVector::rbegin() for returning a const reverse iterator
+  // from the end of the inlined vector.
+  const_reverse_iterator rbegin() const noexcept {
+    return const_reverse_iterator(end());
+  }
+
+  // InlinedVector::crbegin()
+  //
+  // Returns a const reverse iterator from the end of the inlined vector.
+  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+  // InlinedVector::rend()
+  //
+  // Returns a reverse iterator from the beginning of the inlined vector.
+  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+
+  // Overload of InlinedVector::rend() for returning a const reverse iterator
+  // from the beginning of the inlined vector.
+  const_reverse_iterator rend() const noexcept {
+    return const_reverse_iterator(begin());
+  }
+
+  // InlinedVector::crend()
+  //
+  // Returns a reverse iterator from the beginning of the inlined vector.
+  const_reverse_iterator crend() const noexcept { return rend(); }
+
+  // InlinedVector::emplace()
+  //
+  // Constructs and inserts an object to the inlined vector at the given
+  // `position`, returning an iterator pointing to the newly emplaced element.
+  template <typename... Args>
+  iterator emplace(const_iterator position, Args&&... args);
+
+  // InlinedVector::insert()
+  //
+  // Inserts an element of the specified value at `position`, returning an
+  // iterator pointing to the newly inserted element.
+  iterator insert(const_iterator position, const value_type& v) {
+    return emplace(position, v);
+  }
+
+  // Overload of InlinedVector::insert() for inserting an element of the
+  // specified rvalue, returning an iterator pointing to the newly inserted
+  // element.
+  iterator insert(const_iterator position, value_type&& v) {
+    return emplace(position, std::move(v));
+  }
+
+  // Overload of InlinedVector::insert() for inserting `n` elements of the
+  // specified value at `position`, returning an iterator pointing to the first
+  // of the newly inserted elements.
+  iterator insert(const_iterator position, size_type n, const value_type& v) {
+    return InsertWithCount(position, n, v);
+  }
+
+  // Overload of `InlinedVector::insert()` to disambiguate the two
+  // three-argument overloads of `insert()`, returning an iterator pointing to
+  // the first of the newly inserted elements.
+  template <typename InputIterator,
+            typename = typename std::enable_if<std::is_convertible<
+                typename std::iterator_traits<InputIterator>::iterator_category,
+                std::input_iterator_tag>::value>::type>
+  iterator insert(const_iterator position, InputIterator first,
+                  InputIterator last) {
+    using IterType =
+        typename std::iterator_traits<InputIterator>::iterator_category;
+    return InsertWithRange(position, first, last, IterType());
+  }
+
+  // Overload of InlinedVector::insert() for inserting a list of elements at
+  // `position`, returning an iterator pointing to the first of the newly
+  // inserted elements.
+  iterator insert(const_iterator position,
+                  std::initializer_list<value_type> init) {
+    return insert(position, init.begin(), init.end());
+  }
+
+  // InlinedVector::erase()
+  //
+  // Erases the element at `position` of the inlined vector, returning an
+  // iterator pointing to the following element or the container's end if the
+  // last element was erased.
+  iterator erase(const_iterator position) {
+    assert(position >= begin());
+    assert(position < end());
+
+    iterator pos = const_cast<iterator>(position);
+    std::move(pos + 1, end(), pos);
+    pop_back();
+    return pos;
+  }
+
+  // Overload of InlinedVector::erase() for erasing all elements in the
+  // iterator range [first, last) in the inlined vector, returning an iterator
+  // pointing to the first element following the range erased, or the
+  // container's end if range included the container's last element.
+  iterator erase(const_iterator first, const_iterator last);
+
+  // InlinedVector::reserve()
+  //
+  // Enlarges the underlying representation of the inlined vector so it can hold
+  // at least `n` elements. This method does not change `size()` or the actual
+  // contents of the vector.
+  //
+  // Note that if `n` does not exceed the inlined vector's initial size `N`,
+  // `reserve()` will have no effect; if it does exceed its initial size,
+  // `reserve()` will trigger an initial allocation and move the inlined vector
+  // onto the heap. If the vector already exists on the heap and the requested
+  // size exceeds it, a reallocation will be performed.
+  void reserve(size_type n) {
+    if (n > capacity()) {
+      // Make room for new elements
+      EnlargeBy(n - size());
+    }
+  }
+
+  // InlinedVector::shrink_to_fit()
+  //
+  // Reduces memory usage by freeing unused memory.
+  // After this call `capacity()` will be equal to `max(N, size())`.
+  //
+  // If `size() <= N` and the elements are currently stored on the heap, they
+  // will be moved to the inlined storage and the heap memory deallocated.
+  // If `size() > N` and `size() < capacity()` the elements will be moved to
+  // a reallocated storage on heap.
+  void shrink_to_fit() {
+    const auto s = size();
+    if (!allocated() || s == capacity()) {
+      // There's nothing to deallocate.
+      return;
+    }
+
+    if (s <= N) {
+      // Move the elements to the inlined storage.
+      // We have to do this using a temporary, because inlined_storage and
+      // allocation_storage are in a union field.
+      auto temp = std::move(*this);
+      assign(std::make_move_iterator(temp.begin()),
+             std::make_move_iterator(temp.end()));
+      return;
+    }
+
+    // Reallocate storage and move elements.
+    // We can't simply use the same approach as above, because assign() would
+    // call into reserve() internally and reserve larger capacity than we need.
+    Allocation new_allocation(allocator(), s);
+    UninitializedCopy(std::make_move_iterator(allocated_space()),
+                      std::make_move_iterator(allocated_space() + s),
+                      new_allocation.buffer());
+    ResetAllocation(new_allocation, s);
+  }
+
+  // InlinedVector::swap()
+  //
+  // Swaps the contents of this inlined vector with the contents of `other`.
+  void swap(InlinedVector& other);
+
+  // InlinedVector::get_allocator()
+  //
+  // Returns the allocator of this inlined vector.
+  allocator_type get_allocator() const { return allocator(); }
+
+ private:
+  static_assert(N > 0, "inlined vector with nonpositive size");
+
+  // It holds whether the vector is allocated or not in the lowest bit.
+  // The size is held in the high bits:
+  //   size_ = (size << 1) | is_allocated;
+  class Tag {
+   public:
+    Tag() : size_(0) {}
+    size_type size() const { return size_ >> 1; }
+    void add_size(size_type n) { size_ += n << 1; }
+    void set_inline_size(size_type n) { size_ = n << 1; }
+    void set_allocated_size(size_type n) { size_ = (n << 1) | 1; }
+    bool allocated() const { return size_ & 1; }
+
+   private:
+    size_type size_;
+  };
+
+  // Derives from allocator_type to use the empty base class optimization.
+  // If the allocator_type is stateless, we can 'store'
+  // our instance of it for free.
+  class AllocatorAndTag : private allocator_type {
+   public:
+    explicit AllocatorAndTag(const allocator_type& a, Tag t = Tag())
+        : allocator_type(a), tag_(t) {}
+    Tag& tag() { return tag_; }
+    const Tag& tag() const { return tag_; }
+    allocator_type& allocator() { return *this; }
+    const allocator_type& allocator() const { return *this; }
+
+   private:
+    Tag tag_;
+  };
+
+  class Allocation {
+   public:
+    Allocation(allocator_type& a,  // NOLINT(runtime/references)
+               size_type capacity)
+        : capacity_(capacity),
+          buffer_(AllocatorTraits::allocate(a, capacity_)) {}
+
+    void Dealloc(allocator_type& a) {  // NOLINT(runtime/references)
+      AllocatorTraits::deallocate(a, buffer(), capacity());
+    }
+
+    size_type capacity() const { return capacity_; }
+    const value_type* buffer() const { return buffer_; }
+    value_type* buffer() { return buffer_; }
+
+   private:
+    size_type capacity_;
+    value_type* buffer_;
+  };
+
+  const Tag& tag() const { return allocator_and_tag_.tag(); }
+  Tag& tag() { return allocator_and_tag_.tag(); }
+
+  Allocation& allocation() {
+    return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation);
+  }
+  const Allocation& allocation() const {
+    return reinterpret_cast<const Allocation&>(
+        rep_.allocation_storage.allocation);
+  }
+  void init_allocation(const Allocation& allocation) {
+    new (&rep_.allocation_storage.allocation) Allocation(allocation);
+  }
+
+  value_type* inlined_space() {
+    return reinterpret_cast<value_type*>(&rep_.inlined_storage.inlined);
+  }
+  const value_type* inlined_space() const {
+    return reinterpret_cast<const value_type*>(&rep_.inlined_storage.inlined);
+  }
+
+  value_type* allocated_space() { return allocation().buffer(); }
+  const value_type* allocated_space() const { return allocation().buffer(); }
+
+  const allocator_type& allocator() const {
+    return allocator_and_tag_.allocator();
+  }
+  allocator_type& allocator() { return allocator_and_tag_.allocator(); }
+
+  bool allocated() const { return tag().allocated(); }
+
+  // Enlarge the underlying representation so we can store size_ + delta elems.
+  // The size is not changed, and any newly added memory is not initialized.
+  void EnlargeBy(size_type delta);
+
+  // Shift all elements from position to end() n places to the right.
+  // If the vector needs to be enlarged, memory will be allocated.
+  // Returns iterators pointing to the start of the previously-initialized
+  // portion and the start of the uninitialized portion of the created gap.
+  // The number of initialized spots is pair.second - pair.first;
+  // the number of raw spots is n - (pair.second - pair.first).
+  //
+  // Updates the size of the InlinedVector internally.
+  std::pair<iterator, iterator> ShiftRight(const_iterator position,
+                                           size_type n);
+
+  void ResetAllocation(Allocation new_allocation, size_type new_size) {
+    if (allocated()) {
+      Destroy(allocated_space(), allocated_space() + size());
+      assert(begin() == allocated_space());
+      allocation().Dealloc(allocator());
+      allocation() = new_allocation;
+    } else {
+      Destroy(inlined_space(), inlined_space() + size());
+      init_allocation(new_allocation);  // bug: only init once
+    }
+    tag().set_allocated_size(new_size);
+  }
+
+  template <typename... Args>
+  value_type& GrowAndEmplaceBack(Args&&... args) {
+    assert(size() == capacity());
+    const size_type s = size();
+
+    Allocation new_allocation(allocator(), 2 * capacity());
+
+    value_type& new_element =
+        Construct(new_allocation.buffer() + s, std::forward<Args>(args)...);
+    UninitializedCopy(std::make_move_iterator(data()),
+                      std::make_move_iterator(data() + s),
+                      new_allocation.buffer());
+
+    ResetAllocation(new_allocation, s + 1);
+
+    return new_element;
+  }
+
+  void InitAssign(size_type n);
+  void InitAssign(size_type n, const value_type& t);
+
+  template <typename... Args>
+  value_type& Construct(pointer p, Args&&... args) {
+    AllocatorTraits::construct(allocator(), p, std::forward<Args>(args)...);
+    return *p;
+  }
+
+  template <typename Iter>
+  void UninitializedCopy(Iter src, Iter src_last, value_type* dst) {
+    for (; src != src_last; ++dst, ++src) Construct(dst, *src);
+  }
+
+  template <typename... Args>
+  void UninitializedFill(value_type* dst, value_type* dst_last,
+                         const Args&... args) {
+    for (; dst != dst_last; ++dst) Construct(dst, args...);
+  }
+
+  // Destroy [ptr, ptr_last) in place.
+  void Destroy(value_type* ptr, value_type* ptr_last);
+
+  template <typename Iter>
+  void AppendRange(Iter first, Iter last, std::input_iterator_tag) {
+    std::copy(first, last, std::back_inserter(*this));
+  }
+
+  // Faster path for forward iterators.
+  template <typename Iter>
+  void AppendRange(Iter first, Iter last, std::forward_iterator_tag);
+
+  template <typename Iter>
+  void AppendRange(Iter first, Iter last) {
+    using IterTag = typename std::iterator_traits<Iter>::iterator_category;
+    AppendRange(first, last, IterTag());
+  }
+
+  template <typename Iter>
+  void AssignRange(Iter first, Iter last, std::input_iterator_tag);
+
+  // Faster path for forward iterators.
+  template <typename Iter>
+  void AssignRange(Iter first, Iter last, std::forward_iterator_tag);
+
+  template <typename Iter>
+  void AssignRange(Iter first, Iter last) {
+    using IterTag = typename std::iterator_traits<Iter>::iterator_category;
+    AssignRange(first, last, IterTag());
+  }
+
+  iterator InsertWithCount(const_iterator position, size_type n,
+                           const value_type& v);
+
+  template <typename InputIter>
+  iterator InsertWithRange(const_iterator position, InputIter first,
+                           InputIter last, std::input_iterator_tag);
+  template <typename ForwardIter>
+  iterator InsertWithRange(const_iterator position, ForwardIter first,
+                           ForwardIter last, std::forward_iterator_tag);
+
+  AllocatorAndTag allocator_and_tag_;
+
+  // Either the inlined or allocated representation
+  union Rep {
+    // Use struct to perform indirection that solves a bizarre compilation
+    // error on Visual Studio (all known versions).
+    struct {
+      typename std::aligned_storage<sizeof(value_type),
+                                    alignof(value_type)>::type inlined[N];
+    } inlined_storage;
+    struct {
+      typename std::aligned_storage<sizeof(Allocation),
+                                    alignof(Allocation)>::type allocation;
+    } allocation_storage;
+  } rep_;
+};
+
+// -----------------------------------------------------------------------------
+// InlinedVector Non-Member Functions
+// -----------------------------------------------------------------------------
+
+// swap()
+//
+// Swaps the contents of two inlined vectors. This convenience function
+// simply calls InlinedVector::swap(other_inlined_vector).
+template <typename T, size_t N, typename A>
+void swap(InlinedVector<T, N, A>& a,
+          InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
+  a.swap(b);
+}
+
+// operator==()
+//
+// Tests the equivalency of the contents of two inlined vectors.
+template <typename T, size_t N, typename A>
+bool operator==(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) {
+  return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// operator!=()
+//
+// Tests the inequality of the contents of two inlined vectors.
+template <typename T, size_t N, typename A>
+bool operator!=(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) {
+  return !(a == b);
+}
+
+// operator<()
+//
+// Tests whether the contents of one inlined vector are less than the contents
+// of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator<(const InlinedVector<T, N, A>& a,
+               const InlinedVector<T, N, A>& b) {
+  return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// operator>()
+//
+// Tests whether the contents of one inlined vector are greater than the
+// contents of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator>(const InlinedVector<T, N, A>& a,
+               const InlinedVector<T, N, A>& b) {
+  return b < a;
+}
+
+// operator<=()
+//
+// Tests whether the contents of one inlined vector are less than or equal to
+// the contents of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator<=(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) {
+  return !(b < a);
+}
+
+// operator>=()
+//
+// Tests whether the contents of one inlined vector are greater than or equal to
+// the contents of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator>=(const InlinedVector<T, N, A>& a,
+                const InlinedVector<T, N, A>& b) {
+  return !(a < b);
+}
+
+// -----------------------------------------------------------------------------
+// Implementation of InlinedVector
+// -----------------------------------------------------------------------------
+//
+// Do not depend on any implementation details below this line.
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v)
+    : allocator_and_tag_(v.allocator()) {
+  reserve(v.size());
+  if (allocated()) {
+    UninitializedCopy(v.begin(), v.end(), allocated_space());
+    tag().set_allocated_size(v.size());
+  } else {
+    UninitializedCopy(v.begin(), v.end(), inlined_space());
+    tag().set_inline_size(v.size());
+  }
+}
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v,
+                                      const allocator_type& alloc)
+    : allocator_and_tag_(alloc) {
+  reserve(v.size());
+  if (allocated()) {
+    UninitializedCopy(v.begin(), v.end(), allocated_space());
+    tag().set_allocated_size(v.size());
+  } else {
+    UninitializedCopy(v.begin(), v.end(), inlined_space());
+    tag().set_inline_size(v.size());
+  }
+}
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(InlinedVector&& v) noexcept(
+    absl::allocator_is_nothrow<allocator_type>::value ||
+    std::is_nothrow_move_constructible<value_type>::value)
+    : allocator_and_tag_(v.allocator_and_tag_) {
+  if (v.allocated()) {
+    // We can just steal the underlying buffer from the source.
+    // That leaves the source empty, so we clear its size.
+    init_allocation(v.allocation());
+    v.tag() = Tag();
+  } else {
+    UninitializedCopy(std::make_move_iterator(v.inlined_space()),
+                      std::make_move_iterator(v.inlined_space() + v.size()),
+                      inlined_space());
+  }
+}
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(
+    InlinedVector&& v,
+    const allocator_type&
+        alloc) noexcept(absl::allocator_is_nothrow<allocator_type>::value)
+    : allocator_and_tag_(alloc) {
+  if (v.allocated()) {
+    if (alloc == v.allocator()) {
+      // We can just steal the allocation from the source.
+      tag() = v.tag();
+      init_allocation(v.allocation());
+      v.tag() = Tag();
+    } else {
+      // We need to use our own allocator
+      reserve(v.size());
+      UninitializedCopy(std::make_move_iterator(v.begin()),
+                        std::make_move_iterator(v.end()), allocated_space());
+      tag().set_allocated_size(v.size());
+    }
+  } else {
+    UninitializedCopy(std::make_move_iterator(v.inlined_space()),
+                      std::make_move_iterator(v.inlined_space() + v.size()),
+                      inlined_space());
+    tag().set_inline_size(v.size());
+  }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::InitAssign(size_type n, const value_type& t) {
+  if (n > static_cast<size_type>(N)) {
+    Allocation new_allocation(allocator(), n);
+    init_allocation(new_allocation);
+    UninitializedFill(allocated_space(), allocated_space() + n, t);
+    tag().set_allocated_size(n);
+  } else {
+    UninitializedFill(inlined_space(), inlined_space() + n, t);
+    tag().set_inline_size(n);
+  }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::InitAssign(size_type n) {
+  if (n > static_cast<size_type>(N)) {
+    Allocation new_allocation(allocator(), n);
+    init_allocation(new_allocation);
+    UninitializedFill(allocated_space(), allocated_space() + n);
+    tag().set_allocated_size(n);
+  } else {
+    UninitializedFill(inlined_space(), inlined_space() + n);
+    tag().set_inline_size(n);
+  }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::resize(size_type n) {
+  size_type s = size();
+  if (n < s) {
+    erase(begin() + n, end());
+    return;
+  }
+  reserve(n);
+  assert(capacity() >= n);
+
+  // Fill new space with elements constructed in-place.
+  if (allocated()) {
+    UninitializedFill(allocated_space() + s, allocated_space() + n);
+    tag().set_allocated_size(n);
+  } else {
+    UninitializedFill(inlined_space() + s, inlined_space() + n);
+    tag().set_inline_size(n);
+  }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::resize(size_type n, const value_type& elem) {
+  size_type s = size();
+  if (n < s) {
+    erase(begin() + n, end());
+    return;
+  }
+  reserve(n);
+  assert(capacity() >= n);
+
+  // Fill new space with copies of 'elem'.
+  if (allocated()) {
+    UninitializedFill(allocated_space() + s, allocated_space() + n, elem);
+    tag().set_allocated_size(n);
+  } else {
+    UninitializedFill(inlined_space() + s, inlined_space() + n, elem);
+    tag().set_inline_size(n);
+  }
+}
+
+template <typename T, size_t N, typename A>
+template <typename... Args>
+typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::emplace(
+    const_iterator position, Args&&... args) {
+  assert(position >= begin());
+  assert(position <= end());
+  if (position == end()) {
+    emplace_back(std::forward<Args>(args)...);
+    return end() - 1;
+  }
+
+  T new_t = T(std::forward<Args>(args)...);
+
+  auto range = ShiftRight(position, 1);
+  if (range.first == range.second) {
+    // constructing into uninitialized memory
+    Construct(range.first, std::move(new_t));
+  } else {
+    // assigning into moved-from object
+    *range.first = T(std::move(new_t));
+  }
+
+  return range.first;
+}
+
+template <typename T, size_t N, typename A>
+typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::erase(
+    const_iterator first, const_iterator last) {
+  assert(begin() <= first);
+  assert(first <= last);
+  assert(last <= end());
+
+  iterator range_start = const_cast<iterator>(first);
+  iterator range_end = const_cast<iterator>(last);
+
+  size_type s = size();
+  ptrdiff_t erase_gap = std::distance(range_start, range_end);
+  if (erase_gap > 0) {
+    pointer space;
+    if (allocated()) {
+      space = allocated_space();
+      tag().set_allocated_size(s - erase_gap);
+    } else {
+      space = inlined_space();
+      tag().set_inline_size(s - erase_gap);
+    }
+    std::move(range_end, space + s, range_start);
+    Destroy(space + s - erase_gap, space + s);
+  }
+  return range_start;
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::swap(InlinedVector& other) {
+  using std::swap;  // Augment ADL with std::swap.
+  if (&other == this) {
+    return;
+  }
+  if (allocated() && other.allocated()) {
+    // Both out of line, so just swap the tag, allocation, and allocator.
+    swap(tag(), other.tag());
+    swap(allocation(), other.allocation());
+    swap(allocator(), other.allocator());
+    return;
+  }
+  if (!allocated() && !other.allocated()) {
+    // Both inlined: swap up to smaller size, then move remaining elements.
+    InlinedVector* a = this;
+    InlinedVector* b = &other;
+    if (size() < other.size()) {
+      swap(a, b);
+    }
+
+    const size_type a_size = a->size();
+    const size_type b_size = b->size();
+    assert(a_size >= b_size);
+    // 'a' is larger. Swap the elements up to the smaller array size.
+    std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size,
+                     b->inlined_space());
+
+    // Move the remaining elements: A[b_size,a_size) -> B[b_size,a_size)
+    b->UninitializedCopy(a->inlined_space() + b_size,
+                         a->inlined_space() + a_size,
+                         b->inlined_space() + b_size);
+    a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size);
+
+    swap(a->tag(), b->tag());
+    swap(a->allocator(), b->allocator());
+    assert(b->size() == a_size);
+    assert(a->size() == b_size);
+    return;
+  }
+  // One is out of line, one is inline.
+  // We first move the elements from the inlined vector into the
+  // inlined space in the other vector.  We then put the other vector's
+  // pointer/capacity into the originally inlined vector and swap
+  // the tags.
+  InlinedVector* a = this;
+  InlinedVector* b = &other;
+  if (a->allocated()) {
+    swap(a, b);
+  }
+  assert(!a->allocated());
+  assert(b->allocated());
+  const size_type a_size = a->size();
+  const size_type b_size = b->size();
+  // In an optimized build, b_size would be unused.
+  (void)b_size;
+
+  // Made Local copies of size(), don't need tag() accurate anymore
+  swap(a->tag(), b->tag());
+
+  // Copy b_allocation out before b's union gets clobbered by inline_space.
+  Allocation b_allocation = b->allocation();
+
+  b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size,
+                       b->inlined_space());
+  a->Destroy(a->inlined_space(), a->inlined_space() + a_size);
+
+  a->allocation() = b_allocation;
+
+  if (a->allocator() != b->allocator()) {
+    swap(a->allocator(), b->allocator());
+  }
+
+  assert(b->size() == a_size);
+  assert(a->size() == b_size);
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::EnlargeBy(size_type delta) {
+  const size_type s = size();
+  assert(s <= capacity());
+
+  size_type target = std::max(static_cast<size_type>(N), s + delta);
+
+  // Compute new capacity by repeatedly doubling current capacity
+  // TODO(psrc): Check and avoid overflow?
+  size_type new_capacity = capacity();
+  while (new_capacity < target) {
+    new_capacity <<= 1;
+  }
+
+  Allocation new_allocation(allocator(), new_capacity);
+
+  UninitializedCopy(std::make_move_iterator(data()),
+                    std::make_move_iterator(data() + s),
+                    new_allocation.buffer());
+
+  ResetAllocation(new_allocation, s);
+}
+
+template <typename T, size_t N, typename A>
+auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n)
+    -> std::pair<iterator, iterator> {
+  iterator start_used = const_cast<iterator>(position);
+  iterator start_raw = const_cast<iterator>(position);
+  size_type s = size();
+  size_type required_size = s + n;
+
+  if (required_size > capacity()) {
+    // Compute new capacity by repeatedly doubling current capacity
+    size_type new_capacity = capacity();
+    while (new_capacity < required_size) {
+      new_capacity <<= 1;
+    }
+    // Move everyone into the new allocation, leaving a gap of n for the
+    // requested shift.
+    Allocation new_allocation(allocator(), new_capacity);
+    size_type index = position - begin();
+    UninitializedCopy(std::make_move_iterator(data()),
+                      std::make_move_iterator(data() + index),
+                      new_allocation.buffer());
+    UninitializedCopy(std::make_move_iterator(data() + index),
+                      std::make_move_iterator(data() + s),
+                      new_allocation.buffer() + index + n);
+    ResetAllocation(new_allocation, s);
+
+    // New allocation means our iterator is invalid, so we'll recalculate.
+    // Since the entire gap is in new space, there's no used space to reuse.
+    start_raw = begin() + index;
+    start_used = start_raw;
+  } else {
+    // If we had enough space, it's a two-part move. Elements going into
+    // previously-unoccupied space need an UninitializedCopy. Elements
+    // going into a previously-occupied space are just a move.
+    iterator pos = const_cast<iterator>(position);
+    iterator raw_space = end();
+    size_type slots_in_used_space = raw_space - pos;
+    size_type new_elements_in_used_space = std::min(n, slots_in_used_space);
+    size_type new_elements_in_raw_space = n - new_elements_in_used_space;
+    size_type old_elements_in_used_space =
+        slots_in_used_space - new_elements_in_used_space;
+
+    UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space),
+                      std::make_move_iterator(raw_space),
+                      raw_space + new_elements_in_raw_space);
+    std::move_backward(pos, pos + old_elements_in_used_space, raw_space);
+
+    // If the gap is entirely in raw space, the used space starts where the raw
+    // space starts, leaving no elements in used space. If the gap is entirely
+    // in used space, the raw space starts at the end of the gap, leaving all
+    // elements accounted for within the used space.
+    start_used = pos;
+    start_raw = pos + new_elements_in_used_space;
+  }
+  tag().add_size(n);
+  return std::make_pair(start_used, start_raw);
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::Destroy(value_type* ptr, value_type* ptr_last) {
+  for (value_type* p = ptr; p != ptr_last; ++p) {
+    AllocatorTraits::destroy(allocator(), p);
+  }
+
+  // Overwrite unused memory with 0xab so we can catch uninitialized usage.
+  // Cast to void* to tell the compiler that we don't care that we might be
+  // scribbling on a vtable pointer.
+#ifndef NDEBUG
+  if (ptr != ptr_last) {
+    memset(reinterpret_cast<void*>(ptr), 0xab, sizeof(*ptr) * (ptr_last - ptr));
+  }
+#endif
+}
+
+template <typename T, size_t N, typename A>
+template <typename Iter>
+void InlinedVector<T, N, A>::AppendRange(Iter first, Iter last,
+                                         std::forward_iterator_tag) {
+  using Length = typename std::iterator_traits<Iter>::difference_type;
+  Length length = std::distance(first, last);
+  reserve(size() + length);
+  if (allocated()) {
+    UninitializedCopy(first, last, allocated_space() + size());
+    tag().set_allocated_size(size() + length);
+  } else {
+    UninitializedCopy(first, last, inlined_space() + size());
+    tag().set_inline_size(size() + length);
+  }
+}
+
+template <typename T, size_t N, typename A>
+template <typename Iter>
+void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last,
+                                         std::input_iterator_tag) {
+  // Optimized to avoid reallocation.
+  // Prefer reassignment to copy construction for elements.
+  iterator out = begin();
+  for (; first != last && out != end(); ++first, ++out) {
+    *out = *first;
+  }
+  erase(out, end());
+  std::copy(first, last, std::back_inserter(*this));
+}
+
+template <typename T, size_t N, typename A>
+template <typename Iter>
+void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last,
+                                         std::forward_iterator_tag) {
+  using Length = typename std::iterator_traits<Iter>::difference_type;
+  Length length = std::distance(first, last);
+  // Prefer reassignment to copy construction for elements.
+  if (static_cast<size_type>(length) <= size()) {
+    erase(std::copy(first, last, begin()), end());
+    return;
+  }
+  reserve(length);
+  iterator out = begin();
+  for (; out != end(); ++first, ++out) *out = *first;
+  if (allocated()) {
+    UninitializedCopy(first, last, out);
+    tag().set_allocated_size(length);
+  } else {
+    UninitializedCopy(first, last, out);
+    tag().set_inline_size(length);
+  }
+}
+
+template <typename T, size_t N, typename A>
+auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
+                                             size_type n, const value_type& v)
+    -> iterator {
+  assert(position >= begin() && position <= end());
+  if (n == 0) return const_cast<iterator>(position);
+
+  value_type copy = v;
+  std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
+  std::fill(it_pair.first, it_pair.second, copy);
+  UninitializedFill(it_pair.second, it_pair.first + n, copy);
+
+  return it_pair.first;
+}
+
+template <typename T, size_t N, typename A>
+template <typename InputIter>
+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
+                                             InputIter first, InputIter last,
+                                             std::input_iterator_tag)
+    -> iterator {
+  assert(position >= begin() && position <= end());
+  size_type index = position - cbegin();
+  size_type i = index;
+  while (first != last) insert(begin() + i++, *first++);
+  return begin() + index;
+}
+
+// Overload of InlinedVector::InsertWithRange()
+template <typename T, size_t N, typename A>
+template <typename ForwardIter>
+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
+                                             ForwardIter first,
+                                             ForwardIter last,
+                                             std::forward_iterator_tag)
+    -> iterator {
+  assert(position >= begin() && position <= end());
+  if (first == last) {
+    return const_cast<iterator>(position);
+  }
+  using Length = typename std::iterator_traits<ForwardIter>::difference_type;
+  Length n = std::distance(first, last);
+  std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
+  size_type used_spots = it_pair.second - it_pair.first;
+  ForwardIter open_spot = std::next(first, used_spots);
+  std::copy(first, open_spot, it_pair.first);
+  UninitializedCopy(open_spot, last, it_pair.second);
+  return it_pair.first;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
new file mode 100644
index 0000000..24f2174
--- /dev/null
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -0,0 +1,385 @@
+// Copyright 2017 The Abseil 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 "absl/container/inlined_vector.h"
+
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+using IntVec = absl::InlinedVector<int, 8>;
+
+void BM_InlinedVectorFill(benchmark::State& state) {
+  const int len = state.range(0);
+  for (auto _ : state) {
+    IntVec v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(i);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
+
+void BM_InlinedVectorFillRange(benchmark::State& state) {
+  const int len = state.range(0);
+  std::unique_ptr<int[]> ia(new int[len]);
+  for (int i = 0; i < len; i++) {
+    ia[i] = i;
+  }
+  for (auto _ : state) {
+    IntVec v(ia.get(), ia.get() + len);
+    benchmark::DoNotOptimize(v);
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
+
+void BM_StdVectorFill(benchmark::State& state) {
+  const int len = state.range(0);
+  for (auto _ : state) {
+    std::vector<int> v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(i);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
+
+// The purpose of the next two benchmarks is to verify that
+// absl::InlinedVector is efficient when moving is more efficent than
+// copying. To do so, we use strings that are larger than the short
+// std::string optimization.
+bool StringRepresentedInline(std::string s) {
+  const char* chars = s.data();
+  std::string s1 = std::move(s);
+  return s1.data() != chars;
+}
+
+int GetNonShortStringOptimizationSize() {
+  for (int i = 24; i <= 192; i *= 2) {
+    if (!StringRepresentedInline(std::string(i, 'A'))) {
+      return i;
+    }
+  }
+  ABSL_RAW_LOG(
+      FATAL,
+      "Failed to find a std::string larger than the short std::string optimization");
+  return -1;
+}
+
+void BM_InlinedVectorFillString(benchmark::State& state) {
+  const int len = state.range(0);
+  const int no_sso = GetNonShortStringOptimizationSize();
+  std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
+                       std::string(no_sso, 'C'), std::string(no_sso, 'D')};
+
+  for (auto _ : state) {
+    absl::InlinedVector<std::string, 8> v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(strings[i & 3]);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024);
+
+void BM_StdVectorFillString(benchmark::State& state) {
+  const int len = state.range(0);
+  const int no_sso = GetNonShortStringOptimizationSize();
+  std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
+                       std::string(no_sso, 'C'), std::string(no_sso, 'D')};
+
+  for (auto _ : state) {
+    std::vector<std::string> v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(strings[i & 3]);
+    }
+  }
+  state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
+}
+BENCHMARK(BM_StdVectorFillString)->Range(0, 1024);
+
+struct Buffer {  // some arbitrary structure for benchmarking.
+  char* base;
+  int length;
+  int capacity;
+  void* user_data;
+};
+
+void BM_InlinedVectorTenAssignments(benchmark::State& state) {
+  const int len = state.range(0);
+  using BufferVec = absl::InlinedVector<Buffer, 2>;
+
+  BufferVec src;
+  src.resize(len);
+
+  BufferVec dst;
+  for (auto _ : state) {
+    for (int i = 0; i < 10; ++i) {
+      dst = src;
+    }
+  }
+}
+BENCHMARK(BM_InlinedVectorTenAssignments)
+    ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20);
+
+void BM_CreateFromContainer(benchmark::State& state) {
+  for (auto _ : state) {
+    absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3});
+    benchmark::DoNotOptimize(x);
+  }
+}
+BENCHMARK(BM_CreateFromContainer);
+
+struct LargeCopyableOnly {
+  LargeCopyableOnly() : d(1024, 17) {}
+  LargeCopyableOnly(const LargeCopyableOnly& o) = default;
+  LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default;
+
+  std::vector<int> d;
+};
+
+struct LargeCopyableSwappable {
+  LargeCopyableSwappable() : d(1024, 17) {}
+  LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
+  LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
+
+  LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
+    using std::swap;
+    swap(*this, o);
+    return *this;
+  }
+  LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
+
+  friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
+    using std::swap;
+    swap(a.d, b.d);
+  }
+
+  std::vector<int> d;
+};
+
+struct LargeCopyableMovable {
+  LargeCopyableMovable() : d(1024, 17) {}
+  // Use implicitly defined copy and move.
+
+  std::vector<int> d;
+};
+
+struct LargeCopyableMovableSwappable {
+  LargeCopyableMovableSwappable() : d(1024, 17) {}
+  LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) =
+      default;
+  LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default;
+
+  LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) {
+    using std::swap;
+    swap(*this, o);
+    return *this;
+  }
+  LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) =
+      default;
+
+  friend void swap(LargeCopyableMovableSwappable& a,
+                   LargeCopyableMovableSwappable& b) {
+    using std::swap;
+    swap(a.d, b.d);
+  }
+
+  std::vector<int> d;
+};
+
+template <typename ElementType>
+void BM_SwapElements(benchmark::State& state) {
+  const int len = state.range(0);
+  using Vec = absl::InlinedVector<ElementType, 32>;
+  Vec a(len);
+  Vec b;
+  for (auto _ : state) {
+    using std::swap;
+    swap(a, b);
+  }
+}
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024);
+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable)
+    ->Range(0, 1024);
+
+// The following benchmark is meant to track the efficiency of the vector size
+// as a function of stored type via the benchmark label. It is not meant to
+// output useful sizeof operator performance. The loop is a dummy operation
+// to fulfill the requirement of running the benchmark.
+template <typename VecType>
+void BM_Sizeof(benchmark::State& state) {
+  int size = 0;
+  for (auto _ : state) {
+    VecType vec;
+    size = sizeof(vec);
+  }
+  state.SetLabel(absl::StrCat("sz=", size));
+}
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>);
+
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>);
+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>);
+
+void BM_InlinedVectorIndexInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    for (int i = 0; i < 1000; ++i) {
+      benchmark::DoNotOptimize(v);
+      benchmark::DoNotOptimize(v[4]);
+    }
+  }
+  state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorIndexInlined);
+
+void BM_InlinedVectorIndexExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    for (int i = 0; i < 1000; ++i) {
+      benchmark::DoNotOptimize(v);
+      benchmark::DoNotOptimize(v[4]);
+    }
+  }
+  state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorIndexExternal);
+
+void BM_StdVectorIndex(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    for (int i = 0; i < 1000; ++i) {
+      benchmark::DoNotOptimize(v);
+      benchmark::DoNotOptimize(v[4]);
+    }
+  }
+  state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorIndex);
+
+#define UNROLL_2(x)            \
+  benchmark::DoNotOptimize(x); \
+  benchmark::DoNotOptimize(x);
+
+#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x)
+#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x)
+#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x);
+
+void BM_InlinedVectorDataInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    UNROLL_16(v.data());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorDataInlined);
+
+void BM_InlinedVectorDataExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.data());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorDataExternal);
+
+void BM_StdVectorData(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.data());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorData);
+
+void BM_InlinedVectorSizeInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    UNROLL_16(v.size());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorSizeInlined);
+
+void BM_InlinedVectorSizeExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.size());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorSizeExternal);
+
+void BM_StdVectorSize(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.size());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorSize);
+
+void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
+  for (auto _ : state) {
+    UNROLL_16(v.empty());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorEmptyInlined);
+
+void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
+  absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.empty());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_InlinedVectorEmptyExternal);
+
+void BM_StdVectorEmpty(benchmark::State& state) {
+  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  for (auto _ : state) {
+    UNROLL_16(v.empty());
+  }
+  state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
+}
+BENCHMARK(BM_StdVectorEmpty);
+
+}  // namespace
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
new file mode 100644
index 0000000..f81fad5
--- /dev/null
+++ b/absl/container/inlined_vector_test.cc
@@ -0,0 +1,1792 @@
+// Copyright 2017 The Abseil 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 "absl/container/inlined_vector.h"
+
+#include <algorithm>
+#include <forward_list>
+#include <list>
+#include <memory>
+#include <scoped_allocator>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+using absl::test_internal::CopyableMovableInstance;
+using absl::test_internal::CopyableOnlyInstance;
+using absl::test_internal::InstanceTracker;
+using testing::AllOf;
+using testing::Each;
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::Eq;
+using testing::Gt;
+using testing::PrintToString;
+
+using IntVec = absl::InlinedVector<int, 8>;
+
+MATCHER_P(SizeIs, n, "") {
+  return testing::ExplainMatchResult(n, arg.size(), result_listener);
+}
+
+MATCHER_P(CapacityIs, n, "") {
+  return testing::ExplainMatchResult(n, arg.capacity(), result_listener);
+}
+
+MATCHER_P(ValueIs, e, "") {
+  return testing::ExplainMatchResult(e, arg.value(), result_listener);
+}
+
+// TODO(bsamwel): Add support for movable-only types.
+
+// Test fixture for typed tests on BaseCountedInstance derived classes, see
+// test_instance_tracker.h.
+template <typename T>
+class InstanceTest : public ::testing::Test {};
+TYPED_TEST_CASE_P(InstanceTest);
+
+// A simple reference counted class to make sure that the proper elements are
+// destroyed in the erase(begin, end) test.
+class RefCounted {
+ public:
+  RefCounted(int value, int* count) : value_(value), count_(count) {
+    Ref();
+  }
+
+  RefCounted(const RefCounted& v)
+      : value_(v.value_), count_(v.count_) {
+    Ref();
+  }
+
+  ~RefCounted() {
+    Unref();
+    count_ = nullptr;
+  }
+
+  friend void swap(RefCounted& a, RefCounted& b) {
+    using std::swap;
+    swap(a.value_, b.value_);
+    swap(a.count_, b.count_);
+  }
+
+  RefCounted& operator=(RefCounted v) {
+    using std::swap;
+    swap(*this, v);
+    return *this;
+  }
+
+  void Ref() const {
+    ABSL_RAW_CHECK(count_ != nullptr, "");
+    ++(*count_);
+  }
+
+  void Unref() const {
+    --(*count_);
+    ABSL_RAW_CHECK(*count_ >= 0, "");
+  }
+
+  int value_;
+  int* count_;
+};
+
+using RefCountedVec = absl::InlinedVector<RefCounted, 8>;
+
+// A class with a vtable pointer
+class Dynamic {
+ public:
+  virtual ~Dynamic() {}
+};
+
+using DynamicVec = absl::InlinedVector<Dynamic, 8>;
+
+// Append 0..len-1 to *v
+template <typename Container>
+static void Fill(Container* v, int len, int offset = 0) {
+  for (int i = 0; i < len; i++) {
+    v->push_back(i + offset);
+  }
+}
+
+static IntVec Fill(int len, int offset = 0) {
+  IntVec v;
+  Fill(&v, len, offset);
+  return v;
+}
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator : public std::allocator<T> {
+ public:
+  using Alloc = std::allocator<T>;
+  using pointer = typename Alloc::pointer;
+  using size_type = typename Alloc::size_type;
+
+  CountingAllocator() : bytes_used_(nullptr) {}
+  explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
+
+  template <typename U>
+  CountingAllocator(const CountingAllocator<U>& x)
+      : Alloc(x), bytes_used_(x.bytes_used_) {}
+
+  pointer allocate(size_type n,
+                   std::allocator<void>::const_pointer hint = nullptr) {
+    assert(bytes_used_ != nullptr);
+    *bytes_used_ += n * sizeof(T);
+    return Alloc::allocate(n, hint);
+  }
+
+  void deallocate(pointer p, size_type n) {
+    Alloc::deallocate(p, n);
+    assert(bytes_used_ != nullptr);
+    *bytes_used_ -= n * sizeof(T);
+  }
+
+  template<typename U>
+  class rebind {
+   public:
+    using other = CountingAllocator<U>;
+  };
+
+  friend bool operator==(const CountingAllocator& a,
+                         const CountingAllocator& b) {
+    return a.bytes_used_ == b.bytes_used_;
+  }
+
+  friend bool operator!=(const CountingAllocator& a,
+                         const CountingAllocator& b) {
+    return !(a == b);
+  }
+
+  int64_t* bytes_used_;
+};
+
+TEST(IntVec, SimpleOps) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v;
+    const IntVec& cv = v;  // const alias
+
+    Fill(&v, len);
+    EXPECT_EQ(len, v.size());
+    EXPECT_LE(len, v.capacity());
+
+    for (int i = 0; i < len; i++) {
+      EXPECT_EQ(i, v[i]);
+      EXPECT_EQ(i, v.at(i));
+    }
+    EXPECT_EQ(v.begin(), v.data());
+    EXPECT_EQ(cv.begin(), cv.data());
+
+    int counter = 0;
+    for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) {
+      EXPECT_EQ(counter, *iter);
+      counter++;
+    }
+    EXPECT_EQ(counter, len);
+
+    counter = 0;
+    for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) {
+      EXPECT_EQ(counter, *iter);
+      counter++;
+    }
+    EXPECT_EQ(counter, len);
+
+    counter = 0;
+    for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) {
+      EXPECT_EQ(counter, *iter);
+      counter++;
+    }
+    EXPECT_EQ(counter, len);
+
+    if (len > 0) {
+      EXPECT_EQ(0, v.front());
+      EXPECT_EQ(len - 1, v.back());
+      v.pop_back();
+      EXPECT_EQ(len - 1, v.size());
+      for (int i = 0; i < v.size(); ++i) {
+        EXPECT_EQ(i, v[i]);
+        EXPECT_EQ(i, v.at(i));
+      }
+    }
+  }
+}
+
+TEST(IntVec, AtThrows) {
+  IntVec v = {1, 2, 3};
+  EXPECT_EQ(v.at(2), 3);
+  ABSL_BASE_INTERNAL_EXPECT_FAIL(v.at(3), std::out_of_range,
+                                 "failed bounds check");
+}
+
+TEST(IntVec, ReverseIterator) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v;
+    Fill(&v, len);
+
+    int counter = len;
+    for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) {
+      counter--;
+      EXPECT_EQ(counter, *iter);
+    }
+    EXPECT_EQ(counter, 0);
+
+    counter = len;
+    for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend();
+         ++iter) {
+      counter--;
+      EXPECT_EQ(counter, *iter);
+    }
+    EXPECT_EQ(counter, 0);
+
+    counter = len;
+    for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend();
+         ++iter) {
+      counter--;
+      EXPECT_EQ(counter, *iter);
+    }
+    EXPECT_EQ(counter, 0);
+  }
+}
+
+TEST(IntVec, Erase) {
+  for (int len = 1; len < 20; len++) {
+    for (int i = 0; i < len; ++i) {
+      IntVec v;
+      Fill(&v, len);
+      v.erase(v.begin() + i);
+      EXPECT_EQ(len - 1, v.size());
+      for (int j = 0; j < i; ++j) {
+        EXPECT_EQ(j, v[j]);
+      }
+      for (int j = i; j < len - 1; ++j) {
+        EXPECT_EQ(j + 1, v[j]);
+      }
+    }
+  }
+}
+
+// At the end of this test loop, the elements between [erase_begin, erase_end)
+// should have reference counts == 0, and all others elements should have
+// reference counts == 1.
+TEST(RefCountedVec, EraseBeginEnd) {
+  for (int len = 1; len < 20; ++len) {
+    for (int erase_begin = 0; erase_begin < len; ++erase_begin) {
+      for (int erase_end = erase_begin; erase_end <= len; ++erase_end) {
+        std::vector<int> counts(len, 0);
+        RefCountedVec v;
+        for (int i = 0; i < len; ++i) {
+          v.push_back(RefCounted(i, &counts[i]));
+        }
+
+        int erase_len = erase_end - erase_begin;
+
+        v.erase(v.begin() + erase_begin, v.begin() + erase_end);
+
+        EXPECT_EQ(len - erase_len, v.size());
+
+        // Check the elements before the first element erased.
+        for (int i = 0; i < erase_begin; ++i) {
+          EXPECT_EQ(i, v[i].value_);
+        }
+
+        // Check the elements after the first element erased.
+        for (int i = erase_begin; i < v.size(); ++i) {
+          EXPECT_EQ(i + erase_len, v[i].value_);
+        }
+
+        // Check that the elements at the beginning are preserved.
+        for (int i = 0; i < erase_begin; ++i) {
+          EXPECT_EQ(1, counts[i]);
+        }
+
+        // Check that the erased elements are destroyed
+        for (int i = erase_begin; i < erase_end; ++i) {
+          EXPECT_EQ(0, counts[i]);
+        }
+
+        // Check that the elements at the end are preserved.
+        for (int i = erase_end; i< len; ++i) {
+          EXPECT_EQ(1, counts[i]);
+        }
+      }
+    }
+  }
+}
+
+struct NoDefaultCtor {
+  explicit NoDefaultCtor(int) {}
+};
+struct NoCopy {
+  NoCopy() {}
+  NoCopy(const NoCopy&) = delete;
+};
+struct NoAssign {
+  NoAssign() {}
+  NoAssign& operator=(const NoAssign&) = delete;
+};
+struct MoveOnly {
+  MoveOnly() {}
+  MoveOnly(MoveOnly&&) = default;
+  MoveOnly& operator=(MoveOnly&&) = default;
+};
+TEST(InlinedVectorTest, NoDefaultCtor) {
+  absl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2));
+  (void)v;
+}
+TEST(InlinedVectorTest, NoCopy) {
+  absl::InlinedVector<NoCopy, 1> v(10);
+  (void)v;
+}
+TEST(InlinedVectorTest, NoAssign) {
+  absl::InlinedVector<NoAssign, 1> v(10);
+  (void)v;
+}
+TEST(InlinedVectorTest, MoveOnly) {
+  absl::InlinedVector<MoveOnly, 2> v;
+  v.push_back(MoveOnly{});
+  v.push_back(MoveOnly{});
+  v.push_back(MoveOnly{});
+  v.erase(v.begin());
+  v.push_back(MoveOnly{});
+  v.erase(v.begin(), v.begin() + 1);
+  v.insert(v.begin(), MoveOnly{});
+  v.emplace(v.begin());
+  v.emplace(v.begin(), MoveOnly{});
+}
+TEST(InlinedVectorTest, Noexcept) {
+  EXPECT_TRUE(std::is_nothrow_move_constructible<IntVec>::value);
+  EXPECT_TRUE((std::is_nothrow_move_constructible<
+               absl::InlinedVector<MoveOnly, 2>>::value));
+
+  struct MoveCanThrow {
+    MoveCanThrow(MoveCanThrow&&) {}
+  };
+  EXPECT_EQ(absl::default_allocator_is_nothrow::value,
+            (std::is_nothrow_move_constructible<
+                absl::InlinedVector<MoveCanThrow, 2>>::value));
+}
+
+TEST(InlinedVectorTest, EmplaceBack) {
+  absl::InlinedVector<std::pair<std::string, int>, 1> v;
+
+  auto& inlined_element = v.emplace_back("answer", 42);
+  EXPECT_EQ(&inlined_element, &v[0]);
+  EXPECT_EQ(inlined_element.first, "answer");
+  EXPECT_EQ(inlined_element.second, 42);
+
+  auto& allocated_element = v.emplace_back("taxicab", 1729);
+  EXPECT_EQ(&allocated_element, &v[1]);
+  EXPECT_EQ(allocated_element.first, "taxicab");
+  EXPECT_EQ(allocated_element.second, 1729);
+}
+
+TEST(InlinedVectorTest, ShrinkToFitGrowingVector) {
+  absl::InlinedVector<std::pair<std::string, int>, 1> v;
+
+  v.shrink_to_fit();
+  EXPECT_EQ(v.capacity(), 1);
+
+  v.emplace_back("answer", 42);
+  v.shrink_to_fit();
+  EXPECT_EQ(v.capacity(), 1);
+
+  v.emplace_back("taxicab", 1729);
+  EXPECT_GE(v.capacity(), 2);
+  v.shrink_to_fit();
+  EXPECT_EQ(v.capacity(), 2);
+
+  v.reserve(100);
+  EXPECT_GE(v.capacity(), 100);
+  v.shrink_to_fit();
+  EXPECT_EQ(v.capacity(), 2);
+}
+
+TEST(InlinedVectorTest, ShrinkToFitEdgeCases) {
+  {
+    absl::InlinedVector<std::pair<std::string, int>, 1> v;
+    v.emplace_back("answer", 42);
+    v.emplace_back("taxicab", 1729);
+    EXPECT_GE(v.capacity(), 2);
+    v.pop_back();
+    v.shrink_to_fit();
+    EXPECT_EQ(v.capacity(), 1);
+    EXPECT_EQ(v[0].first, "answer");
+    EXPECT_EQ(v[0].second, 42);
+  }
+
+  {
+    absl::InlinedVector<std::string, 2> v(100);
+    v.resize(0);
+    v.shrink_to_fit();
+    EXPECT_EQ(v.capacity(), 2);  // inlined capacity
+  }
+
+  {
+    absl::InlinedVector<std::string, 2> v(100);
+    v.resize(1);
+    v.shrink_to_fit();
+    EXPECT_EQ(v.capacity(), 2);  // inlined capacity
+  }
+
+  {
+    absl::InlinedVector<std::string, 2> v(100);
+    v.resize(2);
+    v.shrink_to_fit();
+    EXPECT_EQ(v.capacity(), 2);
+  }
+
+  {
+    absl::InlinedVector<std::string, 2> v(100);
+    v.resize(3);
+    v.shrink_to_fit();
+    EXPECT_EQ(v.capacity(), 3);
+  }
+}
+
+TEST(IntVec, Insert) {
+  for (int len = 0; len < 20; len++) {
+    for (int pos = 0; pos <= len; pos++) {
+      {
+        // Single element
+        std::vector<int> std_v;
+        Fill(&std_v, len);
+        IntVec v;
+        Fill(&v, len);
+
+        std_v.insert(std_v.begin() + pos, 9999);
+        IntVec::iterator it = v.insert(v.cbegin() + pos, 9999);
+        EXPECT_THAT(v, ElementsAreArray(std_v));
+        EXPECT_EQ(it, v.cbegin() + pos);
+      }
+      {
+        // n elements
+        std::vector<int> std_v;
+        Fill(&std_v, len);
+        IntVec v;
+        Fill(&v, len);
+
+        IntVec::size_type n = 5;
+        std_v.insert(std_v.begin() + pos, n, 9999);
+        IntVec::iterator it = v.insert(v.cbegin() + pos, n, 9999);
+        EXPECT_THAT(v, ElementsAreArray(std_v));
+        EXPECT_EQ(it, v.cbegin() + pos);
+      }
+      {
+        // Iterator range (random access iterator)
+        std::vector<int> std_v;
+        Fill(&std_v, len);
+        IntVec v;
+        Fill(&v, len);
+
+        const std::vector<int> input = {9999, 8888, 7777};
+        std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
+        IntVec::iterator it =
+            v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
+        EXPECT_THAT(v, ElementsAreArray(std_v));
+        EXPECT_EQ(it, v.cbegin() + pos);
+      }
+      {
+        // Iterator range (forward iterator)
+        std::vector<int> std_v;
+        Fill(&std_v, len);
+        IntVec v;
+        Fill(&v, len);
+
+        const std::forward_list<int> input = {9999, 8888, 7777};
+        std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
+        IntVec::iterator it =
+            v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
+        EXPECT_THAT(v, ElementsAreArray(std_v));
+        EXPECT_EQ(it, v.cbegin() + pos);
+      }
+      {
+        // Iterator range (input iterator)
+        std::vector<int> std_v;
+        Fill(&std_v, len);
+        IntVec v;
+        Fill(&v, len);
+
+        std_v.insert(std_v.begin() + pos, {9999, 8888, 7777});
+        std::istringstream input("9999 8888 7777");
+        IntVec::iterator it =
+            v.insert(v.cbegin() + pos, std::istream_iterator<int>(input),
+                     std::istream_iterator<int>());
+        EXPECT_THAT(v, ElementsAreArray(std_v));
+        EXPECT_EQ(it, v.cbegin() + pos);
+      }
+      {
+        // Initializer list
+        std::vector<int> std_v;
+        Fill(&std_v, len);
+        IntVec v;
+        Fill(&v, len);
+
+        std_v.insert(std_v.begin() + pos, {9999, 8888});
+        IntVec::iterator it = v.insert(v.cbegin() + pos, {9999, 8888});
+        EXPECT_THAT(v, ElementsAreArray(std_v));
+        EXPECT_EQ(it, v.cbegin() + pos);
+      }
+    }
+  }
+}
+
+TEST(RefCountedVec, InsertConstructorDestructor) {
+  // Make sure the proper construction/destruction happen during insert
+  // operations.
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    for (int pos = 0; pos <= len; pos++) {
+      SCOPED_TRACE(pos);
+      std::vector<int> counts(len, 0);
+      int inserted_count = 0;
+      RefCountedVec v;
+      for (int i = 0; i < len; ++i) {
+        SCOPED_TRACE(i);
+        v.push_back(RefCounted(i, &counts[i]));
+      }
+
+      EXPECT_THAT(counts, Each(Eq(1)));
+
+      RefCounted insert_element(9999, &inserted_count);
+      EXPECT_EQ(1, inserted_count);
+      v.insert(v.begin() + pos, insert_element);
+      EXPECT_EQ(2, inserted_count);
+      // Check that the elements at the end are preserved.
+      EXPECT_THAT(counts, Each(Eq(1)));
+      EXPECT_EQ(2, inserted_count);
+    }
+  }
+}
+
+TEST(IntVec, Resize) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v;
+    Fill(&v, len);
+
+    // Try resizing up and down by k elements
+    static const int kResizeElem = 1000000;
+    for (int k = 0; k < 10; k++) {
+      // Enlarging resize
+      v.resize(len+k, kResizeElem);
+      EXPECT_EQ(len+k, v.size());
+      EXPECT_LE(len+k, v.capacity());
+      for (int i = 0; i < len+k; i++) {
+        if (i < len) {
+          EXPECT_EQ(i, v[i]);
+        } else {
+          EXPECT_EQ(kResizeElem, v[i]);
+        }
+      }
+
+      // Shrinking resize
+      v.resize(len, kResizeElem);
+      EXPECT_EQ(len, v.size());
+      EXPECT_LE(len, v.capacity());
+      for (int i = 0; i < len; i++) {
+        EXPECT_EQ(i, v[i]);
+      }
+    }
+  }
+}
+
+TEST(IntVec, InitWithLength) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v(len, 7);
+    EXPECT_EQ(len, v.size());
+    EXPECT_LE(len, v.capacity());
+    for (int i = 0; i < len; i++) {
+      EXPECT_EQ(7, v[i]);
+    }
+  }
+}
+
+TEST(IntVec, CopyConstructorAndAssignment) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v;
+    Fill(&v, len);
+    EXPECT_EQ(len, v.size());
+    EXPECT_LE(len, v.capacity());
+
+    IntVec v2(v);
+    EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2);
+
+    for (int start_len = 0; start_len < 20; start_len++) {
+      IntVec v3;
+      Fill(&v3, start_len, 99);  // Add dummy elements that should go away
+      v3 = v;
+      EXPECT_TRUE(v == v3) << PrintToString(v) << PrintToString(v3);
+    }
+  }
+}
+
+TEST(IntVec, AliasingCopyAssignment) {
+  for (int len = 0; len < 20; ++len) {
+    IntVec original;
+    Fill(&original, len);
+    IntVec dup = original;
+    dup = *&dup;
+    EXPECT_EQ(dup, original);
+  }
+}
+
+TEST(IntVec, MoveConstructorAndAssignment) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v_in;
+    const int inlined_capacity = v_in.capacity();
+    Fill(&v_in, len);
+    EXPECT_EQ(len, v_in.size());
+    EXPECT_LE(len, v_in.capacity());
+
+    {
+      IntVec v_temp(v_in);
+      auto* old_data = v_temp.data();
+      IntVec v_out(std::move(v_temp));
+      EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
+      if (v_in.size() > inlined_capacity) {
+        // Allocation is moved as a whole, data stays in place.
+        EXPECT_TRUE(v_out.data() == old_data);
+      } else {
+        EXPECT_FALSE(v_out.data() == old_data);
+      }
+    }
+    for (int start_len = 0; start_len < 20; start_len++) {
+      IntVec v_out;
+      Fill(&v_out, start_len, 99);  // Add dummy elements that should go away
+      IntVec v_temp(v_in);
+      auto* old_data = v_temp.data();
+      v_out = std::move(v_temp);
+      EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
+      if (v_in.size() > inlined_capacity) {
+        // Allocation is moved as a whole, data stays in place.
+        EXPECT_TRUE(v_out.data() == old_data);
+      } else {
+        EXPECT_FALSE(v_out.data() == old_data);
+      }
+    }
+  }
+}
+
+class NotTriviallyDestructible {
+ public:
+  NotTriviallyDestructible() : p_(new int(1)) {}
+  explicit NotTriviallyDestructible(int i) : p_(new int(i)) {}
+
+  NotTriviallyDestructible(const NotTriviallyDestructible& other)
+      : p_(new int(*other.p_)) {}
+
+  NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) {
+    p_ = absl::make_unique<int>(*other.p_);
+    return *this;
+  }
+
+  bool operator==(const NotTriviallyDestructible& other) const {
+    return *p_ == *other.p_;
+  }
+
+ private:
+  std::unique_ptr<int> p_;
+};
+
+TEST(AliasingTest, Emplace) {
+  for (int i = 2; i < 20; ++i) {
+    absl::InlinedVector<NotTriviallyDestructible, 10> vec;
+    for (int j = 0; j < i; ++j) {
+      vec.push_back(NotTriviallyDestructible(j));
+    }
+    vec.emplace(vec.begin(), vec[0]);
+    EXPECT_EQ(vec[0], vec[1]);
+    vec.emplace(vec.begin() + i / 2, vec[i / 2]);
+    EXPECT_EQ(vec[i / 2], vec[i / 2 + 1]);
+    vec.emplace(vec.end() - 1, vec.back());
+    EXPECT_EQ(vec[vec.size() - 2], vec.back());
+  }
+}
+
+TEST(AliasingTest, InsertWithCount) {
+  for (int i = 1; i < 20; ++i) {
+    absl::InlinedVector<NotTriviallyDestructible, 10> vec;
+    for (int j = 0; j < i; ++j) {
+      vec.push_back(NotTriviallyDestructible(j));
+    }
+    for (int n = 0; n < 5; ++n) {
+      // We use back where we can because it's guaranteed to become invalidated
+      vec.insert(vec.begin(), n, vec.back());
+      auto b = vec.begin();
+      EXPECT_TRUE(
+          std::all_of(b, b + n, [&vec](const NotTriviallyDestructible& x) {
+            return x == vec.back();
+          }));
+
+      auto m_idx = vec.size() / 2;
+      vec.insert(vec.begin() + m_idx, n, vec.back());
+      auto m = vec.begin() + m_idx;
+      EXPECT_TRUE(
+          std::all_of(m, m + n, [&vec](const NotTriviallyDestructible& x) {
+            return x == vec.back();
+          }));
+
+      // We want distinct values so the equality test is meaningful,
+      // vec[vec.size() - 1] is also almost always invalidated.
+      auto old_e = vec.size() - 1;
+      auto val = vec[old_e];
+      vec.insert(vec.end(), n, vec[old_e]);
+      auto e = vec.begin() + old_e;
+      EXPECT_TRUE(std::all_of(
+          e, e + n,
+          [&val](const NotTriviallyDestructible& x) { return x == val; }));
+    }
+  }
+}
+
+TEST(OverheadTest, Storage) {
+  // Check for size overhead.
+  // In particular, ensure that std::allocator doesn't cost anything to store.
+  // The union should be absorbing some of the allocation bookkeeping overhead
+  // in the larger vectors, leaving only the size_ field as overhead.
+  EXPECT_EQ(2 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*));
+  EXPECT_EQ(1 * sizeof(int*),
+            sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*));
+}
+
+TEST(IntVec, Clear) {
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    IntVec v;
+    Fill(&v, len);
+    v.clear();
+    EXPECT_EQ(0, v.size());
+    EXPECT_EQ(v.begin(), v.end());
+  }
+}
+
+TEST(IntVec, Reserve) {
+  for (int len = 0; len < 20; len++) {
+    IntVec v;
+    Fill(&v, len);
+
+    for (int newlen = 0; newlen < 100; newlen++) {
+      const int* start_rep = v.data();
+      v.reserve(newlen);
+      const int* final_rep = v.data();
+      if (newlen <= len) {
+        EXPECT_EQ(start_rep, final_rep);
+      }
+      EXPECT_LE(newlen, v.capacity());
+
+      // Filling up to newlen should not change rep
+      while (v.size() < newlen) {
+        v.push_back(0);
+      }
+      EXPECT_EQ(final_rep, v.data());
+    }
+  }
+}
+
+TEST(StringVec, SelfRefPushBack) {
+  std::vector<std::string> std_v;
+  absl::InlinedVector<std::string, 4> v;
+  const std::string s = "A quite long std::string to ensure heap.";
+  std_v.push_back(s);
+  v.push_back(s);
+  for (int i = 0; i < 20; ++i) {
+    EXPECT_THAT(v, ElementsAreArray(std_v));
+
+    v.push_back(v.back());
+    std_v.push_back(std_v.back());
+  }
+  EXPECT_THAT(v, ElementsAreArray(std_v));
+}
+
+TEST(StringVec, SelfRefPushBackWithMove) {
+  std::vector<std::string> std_v;
+  absl::InlinedVector<std::string, 4> v;
+  const std::string s = "A quite long std::string to ensure heap.";
+  std_v.push_back(s);
+  v.push_back(s);
+  for (int i = 0; i < 20; ++i) {
+    EXPECT_EQ(v.back(), std_v.back());
+
+    v.push_back(std::move(v.back()));
+    std_v.push_back(std::move(std_v.back()));
+  }
+  EXPECT_EQ(v.back(), std_v.back());
+}
+
+TEST(StringVec, SelfMove) {
+  const std::string s = "A quite long std::string to ensure heap.";
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    absl::InlinedVector<std::string, 8> v;
+    for (int i = 0; i < len; ++i) {
+      SCOPED_TRACE(i);
+      v.push_back(s);
+    }
+    // Indirection necessary to avoid compiler warning.
+    v = std::move(*(&v));
+    // Ensure that the inlined vector is still in a valid state by copying it.
+    // We don't expect specific contents since a self-move results in an
+    // unspecified valid state.
+    std::vector<std::string> copy(v.begin(), v.end());
+  }
+}
+
+TEST(IntVec, Swap) {
+  for (int l1 = 0; l1 < 20; l1++) {
+    SCOPED_TRACE(l1);
+    for (int l2 = 0; l2 < 20; l2++) {
+      SCOPED_TRACE(l2);
+      IntVec a = Fill(l1, 0);
+      IntVec b = Fill(l2, 100);
+      {
+        using std::swap;
+        swap(a, b);
+      }
+      EXPECT_EQ(l1, b.size());
+      EXPECT_EQ(l2, a.size());
+      for (int i = 0; i < l1; i++) {
+        SCOPED_TRACE(i);
+        EXPECT_EQ(i, b[i]);
+      }
+      for (int i = 0; i < l2; i++) {
+        SCOPED_TRACE(i);
+        EXPECT_EQ(100 + i, a[i]);
+      }
+    }
+  }
+}
+
+TYPED_TEST_P(InstanceTest, Swap) {
+  using Instance = TypeParam;
+  using InstanceVec = absl::InlinedVector<Instance, 8>;
+  for (int l1 = 0; l1 < 20; l1++) {
+    SCOPED_TRACE(l1);
+    for (int l2 = 0; l2 < 20; l2++) {
+      SCOPED_TRACE(l2);
+      InstanceTracker tracker;
+      InstanceVec a, b;
+      const size_t inlined_capacity = a.capacity();
+      for (int i = 0; i < l1; i++) a.push_back(Instance(i));
+      for (int i = 0; i < l2; i++) b.push_back(Instance(100+i));
+      EXPECT_EQ(tracker.instances(), l1 + l2);
+      tracker.ResetCopiesMovesSwaps();
+      {
+        using std::swap;
+        swap(a, b);
+      }
+      EXPECT_EQ(tracker.instances(), l1 + l2);
+      if (a.size() > inlined_capacity && b.size() > inlined_capacity) {
+        EXPECT_EQ(tracker.swaps(), 0);  // Allocations are swapped.
+        EXPECT_EQ(tracker.moves(), 0);
+      } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
+        EXPECT_EQ(tracker.swaps(), std::min(l1, l2));
+        // TODO(bsamwel): This should use moves when the type is movable.
+        EXPECT_EQ(tracker.copies(), std::max(l1, l2) - std::min(l1, l2));
+      } else {
+        // One is allocated and the other isn't. The allocation is transferred
+        // without copying elements, and the inlined instances are copied/moved.
+        EXPECT_EQ(tracker.swaps(), 0);
+        // TODO(bsamwel): This should use moves when the type is movable.
+        EXPECT_EQ(tracker.copies(), std::min(l1, l2));
+      }
+
+      EXPECT_EQ(l1, b.size());
+      EXPECT_EQ(l2, a.size());
+      for (int i = 0; i < l1; i++) {
+        EXPECT_EQ(i, b[i].value());
+      }
+      for (int i = 0; i < l2; i++) {
+        EXPECT_EQ(100 + i, a[i].value());
+      }
+    }
+  }
+}
+
+TEST(IntVec, EqualAndNotEqual) {
+  IntVec a, b;
+  EXPECT_TRUE(a == b);
+  EXPECT_FALSE(a != b);
+
+  a.push_back(3);
+  EXPECT_FALSE(a == b);
+  EXPECT_TRUE(a != b);
+
+  b.push_back(3);
+  EXPECT_TRUE(a == b);
+  EXPECT_FALSE(a != b);
+
+  b.push_back(7);
+  EXPECT_FALSE(a == b);
+  EXPECT_TRUE(a != b);
+
+  a.push_back(6);
+  EXPECT_FALSE(a == b);
+  EXPECT_TRUE(a != b);
+
+  a.clear();
+  b.clear();
+  for (int i = 0; i < 100; i++) {
+    a.push_back(i);
+    b.push_back(i);
+    EXPECT_TRUE(a == b);
+    EXPECT_FALSE(a != b);
+
+    b[i] = b[i] + 1;
+    EXPECT_FALSE(a == b);
+    EXPECT_TRUE(a != b);
+
+    b[i] = b[i] - 1;    // Back to before
+    EXPECT_TRUE(a == b);
+    EXPECT_FALSE(a != b);
+  }
+}
+
+TEST(IntVec, RelationalOps) {
+  IntVec a, b;
+  EXPECT_FALSE(a < b);
+  EXPECT_FALSE(b < a);
+  EXPECT_FALSE(a > b);
+  EXPECT_FALSE(b > a);
+  EXPECT_TRUE(a <= b);
+  EXPECT_TRUE(b <= a);
+  EXPECT_TRUE(a >= b);
+  EXPECT_TRUE(b >= a);
+  b.push_back(3);
+  EXPECT_TRUE(a < b);
+  EXPECT_FALSE(b < a);
+  EXPECT_FALSE(a > b);
+  EXPECT_TRUE(b > a);
+  EXPECT_TRUE(a <= b);
+  EXPECT_FALSE(b <= a);
+  EXPECT_FALSE(a >= b);
+  EXPECT_TRUE(b >= a);
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) {
+  using Instance = TypeParam;
+  using InstanceVec = absl::InlinedVector<Instance, 8>;
+  InstanceTracker tracker;
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    tracker.ResetCopiesMovesSwaps();
+
+    InstanceVec v;
+    const size_t inlined_capacity = v.capacity();
+    for (int i = 0; i < len; i++) {
+      v.push_back(Instance(i));
+    }
+    EXPECT_EQ(tracker.instances(), len);
+    EXPECT_GE(tracker.copies() + tracker.moves(),
+              len);  // More due to reallocation.
+    tracker.ResetCopiesMovesSwaps();
+
+    // Enlarging resize() must construct some objects
+    tracker.ResetCopiesMovesSwaps();
+    v.resize(len + 10, Instance(100));
+    EXPECT_EQ(tracker.instances(), len + 10);
+    if (len <= inlined_capacity && len + 10 > inlined_capacity) {
+      EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len);
+    } else {
+      // Only specify a minimum number of copies + moves. We don't want to
+      // depend on the reallocation policy here.
+      EXPECT_GE(tracker.copies() + tracker.moves(),
+                10);  // More due to reallocation.
+    }
+
+    // Shrinking resize() must destroy some objects
+    tracker.ResetCopiesMovesSwaps();
+    v.resize(len, Instance(100));
+    EXPECT_EQ(tracker.instances(), len);
+    EXPECT_EQ(tracker.copies(), 0);
+    EXPECT_EQ(tracker.moves(), 0);
+
+    // reserve() must not increase the number of initialized objects
+    SCOPED_TRACE("reserve");
+    v.reserve(len+1000);
+    EXPECT_EQ(tracker.instances(), len);
+    EXPECT_EQ(tracker.copies() + tracker.moves(), len);
+
+    // pop_back() and erase() must destroy one object
+    if (len > 0) {
+      tracker.ResetCopiesMovesSwaps();
+      v.pop_back();
+      EXPECT_EQ(tracker.instances(), len - 1);
+      EXPECT_EQ(tracker.copies(), 0);
+      EXPECT_EQ(tracker.moves(), 0);
+
+      if (!v.empty()) {
+        tracker.ResetCopiesMovesSwaps();
+        v.erase(v.begin());
+        EXPECT_EQ(tracker.instances(), len - 2);
+        EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2);
+      }
+    }
+
+    tracker.ResetCopiesMovesSwaps();
+    int instances_before_empty_erase = tracker.instances();
+    v.erase(v.begin(), v.begin());
+    EXPECT_EQ(tracker.instances(), instances_before_empty_erase);
+    EXPECT_EQ(tracker.copies() + tracker.moves(), 0);
+  }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) {
+  using Instance = TypeParam;
+  using InstanceVec = absl::InlinedVector<Instance, 8>;
+  InstanceTracker tracker;
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    tracker.ResetCopiesMovesSwaps();
+
+    InstanceVec v;
+    for (int i = 0; i < len; i++) {
+      v.push_back(Instance(i));
+    }
+    EXPECT_EQ(tracker.instances(), len);
+    EXPECT_GE(tracker.copies() + tracker.moves(),
+              len);  // More due to reallocation.
+    tracker.ResetCopiesMovesSwaps();
+    {  // Copy constructor should create 'len' more instances.
+      InstanceVec v_copy(v);
+      EXPECT_EQ(tracker.instances(), len + len);
+      EXPECT_EQ(tracker.copies(), len);
+      EXPECT_EQ(tracker.moves(), 0);
+    }
+    EXPECT_EQ(tracker.instances(), len);
+  }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) {
+  using Instance = TypeParam;
+  using InstanceVec = absl::InlinedVector<Instance, 8>;
+  InstanceTracker tracker;
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    tracker.ResetCopiesMovesSwaps();
+
+    InstanceVec v;
+    const size_t inlined_capacity = v.capacity();
+    for (int i = 0; i < len; i++) {
+      v.push_back(Instance(i));
+    }
+    EXPECT_EQ(tracker.instances(), len);
+    EXPECT_GE(tracker.copies() + tracker.moves(),
+              len);  // More due to reallocation.
+    tracker.ResetCopiesMovesSwaps();
+    {
+      InstanceVec v_copy(std::move(v));
+      if (len > inlined_capacity) {
+        // Allocation is moved as a whole.
+        EXPECT_EQ(tracker.instances(), len);
+        EXPECT_EQ(tracker.live_instances(), len);
+        // Tests an implementation detail, don't rely on this in your code.
+        EXPECT_EQ(v.size(), 0);  // NOLINT misc-use-after-move
+        EXPECT_EQ(tracker.copies(), 0);
+        EXPECT_EQ(tracker.moves(), 0);
+      } else {
+        EXPECT_EQ(tracker.instances(), len + len);
+        if (Instance::supports_move()) {
+          EXPECT_EQ(tracker.live_instances(), len);
+          EXPECT_EQ(tracker.copies(), 0);
+          EXPECT_EQ(tracker.moves(), len);
+        } else {
+          EXPECT_EQ(tracker.live_instances(), len + len);
+          EXPECT_EQ(tracker.copies(), len);
+          EXPECT_EQ(tracker.moves(), 0);
+        }
+      }
+      EXPECT_EQ(tracker.swaps(), 0);
+    }
+  }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) {
+  using Instance = TypeParam;
+  using InstanceVec = absl::InlinedVector<Instance, 8>;
+  InstanceTracker tracker;
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    for (int longorshort = 0; longorshort <= 1; ++longorshort) {
+      SCOPED_TRACE(longorshort);
+      tracker.ResetCopiesMovesSwaps();
+
+      InstanceVec longer, shorter;
+      for (int i = 0; i < len; i++) {
+        longer.push_back(Instance(i));
+        shorter.push_back(Instance(i));
+      }
+      longer.push_back(Instance(len));
+      EXPECT_EQ(tracker.instances(), len + len + 1);
+      EXPECT_GE(tracker.copies() + tracker.moves(),
+                len + len + 1);  // More due to reallocation.
+
+      tracker.ResetCopiesMovesSwaps();
+      if (longorshort) {
+        shorter = longer;
+        EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1));
+        EXPECT_GE(tracker.copies() + tracker.moves(),
+                  len + 1);  // More due to reallocation.
+      } else {
+        longer = shorter;
+        EXPECT_EQ(tracker.instances(), len + len);
+        EXPECT_EQ(tracker.copies() + tracker.moves(), len);
+      }
+    }
+  }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) {
+  using Instance = TypeParam;
+  using InstanceVec = absl::InlinedVector<Instance, 8>;
+  InstanceTracker tracker;
+  for (int len = 0; len < 20; len++) {
+    SCOPED_TRACE(len);
+    for (int longorshort = 0; longorshort <= 1; ++longorshort) {
+      SCOPED_TRACE(longorshort);
+      tracker.ResetCopiesMovesSwaps();
+
+      InstanceVec longer, shorter;
+      const int inlined_capacity = longer.capacity();
+      for (int i = 0; i < len; i++) {
+        longer.push_back(Instance(i));
+        shorter.push_back(Instance(i));
+      }
+      longer.push_back(Instance(len));
+      EXPECT_EQ(tracker.instances(), len + len + 1);
+      EXPECT_GE(tracker.copies() + tracker.moves(),
+                len + len + 1);  // More due to reallocation.
+
+      tracker.ResetCopiesMovesSwaps();
+      int src_len;
+      if (longorshort) {
+        src_len = len + 1;
+        shorter = std::move(longer);
+      } else {
+        src_len = len;
+        longer = std::move(shorter);
+      }
+      if (src_len > inlined_capacity) {
+        // Allocation moved as a whole.
+        EXPECT_EQ(tracker.instances(), src_len);
+        EXPECT_EQ(tracker.live_instances(), src_len);
+        EXPECT_EQ(tracker.copies(), 0);
+        EXPECT_EQ(tracker.moves(), 0);
+      } else {
+        // Elements are all copied.
+        EXPECT_EQ(tracker.instances(), src_len + src_len);
+        if (Instance::supports_move()) {
+          EXPECT_EQ(tracker.copies(), 0);
+          EXPECT_EQ(tracker.moves(), src_len);
+          EXPECT_EQ(tracker.live_instances(), src_len);
+        } else {
+          EXPECT_EQ(tracker.copies(), src_len);
+          EXPECT_EQ(tracker.moves(), 0);
+          EXPECT_EQ(tracker.live_instances(), src_len + src_len);
+        }
+      }
+      EXPECT_EQ(tracker.swaps(), 0);
+    }
+  }
+}
+
+TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
+  for (size_t original_size = 0; original_size <= 5; ++original_size) {
+    SCOPED_TRACE(original_size);
+    // Original contents are [12345, 12345, ...]
+    std::vector<int> original_contents(original_size, 12345);
+
+    absl::InlinedVector<int, 2> v(original_contents.begin(),
+                                  original_contents.end());
+    v.assign(2, 123);
+    EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123)));
+    if (original_size <= 2) {
+      // If the original had inline backing, it should stay inline.
+      EXPECT_EQ(2, v.capacity());
+    }
+  }
+}
+
+TEST(CountElemAssign, SimpleTypeWithAllocation) {
+  for (size_t original_size = 0; original_size <= 5; ++original_size) {
+    SCOPED_TRACE(original_size);
+    // Original contents are [12345, 12345, ...]
+    std::vector<int> original_contents(original_size, 12345);
+
+    absl::InlinedVector<int, 2> v(original_contents.begin(),
+                                  original_contents.end());
+    v.assign(3, 123);
+    EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123)));
+    EXPECT_LE(v.size(), v.capacity());
+  }
+}
+
+TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) {
+  using Instance = TypeParam;
+  for (size_t original_size = 0; original_size <= 5; ++original_size) {
+    SCOPED_TRACE(original_size);
+    // Original contents are [12345, 12345, ...]
+    std::vector<Instance> original_contents(original_size, Instance(12345));
+
+    absl::InlinedVector<Instance, 2> v(original_contents.begin(),
+                                       original_contents.end());
+    v.assign(2, Instance(123));
+    EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123))));
+    if (original_size <= 2) {
+      // If the original had inline backing, it should stay inline.
+      EXPECT_EQ(2, v.capacity());
+    }
+  }
+}
+
+template <typename Instance>
+void InstanceCountElemAssignWithAllocationTest() {
+  for (size_t original_size = 0; original_size <= 5; ++original_size) {
+    SCOPED_TRACE(original_size);
+    // Original contents are [12345, 12345, ...]
+    std::vector<Instance> original_contents(original_size, Instance(12345));
+
+    absl::InlinedVector<Instance, 2> v(original_contents.begin(),
+                                       original_contents.end());
+    v.assign(3, Instance(123));
+    EXPECT_THAT(v,
+                AllOf(SizeIs(3),
+                      ElementsAre(ValueIs(123), ValueIs(123), ValueIs(123))));
+    EXPECT_LE(v.size(), v.capacity());
+  }
+}
+TEST(CountElemAssign, WithAllocationCopyableInstance) {
+  InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>();
+}
+TEST(CountElemAssign, WithAllocationCopyableMovableInstance) {
+  InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>();
+}
+
+TEST(RangedConstructor, SimpleType) {
+  std::vector<int> source_v = {4, 5, 6};
+  // First try to fit in inline backing
+  absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end());
+  EXPECT_EQ(3, v.size());
+  EXPECT_EQ(4, v.capacity());  // Indication that we're still on inlined storage
+  EXPECT_EQ(4, v[0]);
+  EXPECT_EQ(5, v[1]);
+  EXPECT_EQ(6, v[2]);
+
+  // Now, force a re-allocate
+  absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end());
+  EXPECT_EQ(3, realloc_v.size());
+  EXPECT_LT(2, realloc_v.capacity());
+  EXPECT_EQ(4, realloc_v[0]);
+  EXPECT_EQ(5, realloc_v[1]);
+  EXPECT_EQ(6, realloc_v[2]);
+}
+
+// Test for ranged constructors using Instance as the element type and
+// SourceContainer as the source container type.
+template <typename Instance, typename SourceContainer, int inlined_capacity>
+void InstanceRangedConstructorTestForContainer() {
+  InstanceTracker tracker;
+  SourceContainer source_v = {Instance(0), Instance(1)};
+  tracker.ResetCopiesMovesSwaps();
+  absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(),
+                                                    source_v.end());
+  EXPECT_EQ(2, v.size());
+  EXPECT_LT(1, v.capacity());
+  EXPECT_EQ(0, v[0].value());
+  EXPECT_EQ(1, v[1].value());
+  EXPECT_EQ(tracker.copies(), 2);
+  EXPECT_EQ(tracker.moves(), 0);
+}
+
+template <typename Instance, int inlined_capacity>
+void InstanceRangedConstructorTestWithCapacity() {
+  // Test with const and non-const, random access and non-random-access sources.
+  // TODO(bsamwel): Test with an input iterator source.
+  {
+    SCOPED_TRACE("std::list");
+    InstanceRangedConstructorTestForContainer<Instance, std::list<Instance>,
+                                              inlined_capacity>();
+    {
+      SCOPED_TRACE("const std::list");
+      InstanceRangedConstructorTestForContainer<
+          Instance, const std::list<Instance>, inlined_capacity>();
+    }
+    {
+      SCOPED_TRACE("std::vector");
+      InstanceRangedConstructorTestForContainer<Instance, std::vector<Instance>,
+                                                inlined_capacity>();
+    }
+    {
+      SCOPED_TRACE("const std::vector");
+      InstanceRangedConstructorTestForContainer<
+          Instance, const std::vector<Instance>, inlined_capacity>();
+    }
+  }
+}
+
+TYPED_TEST_P(InstanceTest, RangedConstructor) {
+  using Instance = TypeParam;
+  SCOPED_TRACE("capacity=1");
+  InstanceRangedConstructorTestWithCapacity<Instance, 1>();
+  SCOPED_TRACE("capacity=2");
+  InstanceRangedConstructorTestWithCapacity<Instance, 2>();
+}
+
+TEST(RangedConstructor, ElementsAreConstructed) {
+  std::vector<std::string> source_v = {"cat", "dog"};
+
+  // Force expansion and re-allocation of v.  Ensures that when the vector is
+  // expanded that new elements are constructed.
+  absl::InlinedVector<std::string, 1> v(source_v.begin(), source_v.end());
+  EXPECT_EQ("cat", v[0]);
+  EXPECT_EQ("dog", v[1]);
+}
+
+TEST(RangedAssign, SimpleType) {
+  // Test for all combinations of original sizes (empty and non-empty inline,
+  // and out of line) and target sizes.
+  for (size_t original_size = 0; original_size <= 5; ++original_size) {
+    SCOPED_TRACE(original_size);
+    // Original contents are [12345, 12345, ...]
+    std::vector<int> original_contents(original_size, 12345);
+
+    for (size_t target_size = 0; target_size <= 5; ++target_size) {
+      SCOPED_TRACE(target_size);
+
+      // New contents are [3, 4, ...]
+      std::vector<int> new_contents;
+      for (size_t i = 0; i < target_size; ++i) {
+        new_contents.push_back(i + 3);
+      }
+
+      absl::InlinedVector<int, 3> v(original_contents.begin(),
+                                    original_contents.end());
+      v.assign(new_contents.begin(), new_contents.end());
+
+      EXPECT_EQ(new_contents.size(), v.size());
+      EXPECT_LE(new_contents.size(), v.capacity());
+      if (target_size <= 3 && original_size <= 3) {
+        // Storage should stay inline when target size is small.
+        EXPECT_EQ(3, v.capacity());
+      }
+      EXPECT_THAT(v, ElementsAreArray(new_contents));
+    }
+  }
+}
+
+// Returns true if lhs and rhs have the same value.
+template <typename Instance>
+static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) {
+  return lhs.value() == rhs.value();
+}
+
+// Test for ranged assign() using Instance as the element type and
+// SourceContainer as the source container type.
+template <typename Instance, typename SourceContainer>
+void InstanceRangedAssignTestForContainer() {
+  // Test for all combinations of original sizes (empty and non-empty inline,
+  // and out of line) and target sizes.
+  for (size_t original_size = 0; original_size <= 5; ++original_size) {
+    SCOPED_TRACE(original_size);
+    // Original contents are [12345, 12345, ...]
+    std::vector<Instance> original_contents(original_size, Instance(12345));
+
+    for (size_t target_size = 0; target_size <= 5; ++target_size) {
+      SCOPED_TRACE(target_size);
+
+      // New contents are [3, 4, ...]
+      // Generate data using a non-const container, because SourceContainer
+      // itself may be const.
+      // TODO(bsamwel): Test with an input iterator.
+      std::vector<Instance> new_contents_in;
+      for (size_t i = 0; i < target_size; ++i) {
+        new_contents_in.push_back(Instance(i + 3));
+      }
+      SourceContainer new_contents(new_contents_in.begin(),
+                                   new_contents_in.end());
+
+      absl::InlinedVector<Instance, 3> v(original_contents.begin(),
+                                         original_contents.end());
+      v.assign(new_contents.begin(), new_contents.end());
+
+      EXPECT_EQ(new_contents.size(), v.size());
+      EXPECT_LE(new_contents.size(), v.capacity());
+      if (target_size <= 3 && original_size <= 3) {
+        // Storage should stay inline when target size is small.
+        EXPECT_EQ(3, v.capacity());
+      }
+      EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(),
+                             InstanceValuesEqual<Instance>));
+    }
+  }
+}
+
+TYPED_TEST_P(InstanceTest, RangedAssign) {
+  using Instance = TypeParam;
+  // Test with const and non-const, random access and non-random-access sources.
+  // TODO(bsamwel): Test with an input iterator source.
+  SCOPED_TRACE("std::list");
+  InstanceRangedAssignTestForContainer<Instance, std::list<Instance>>();
+  SCOPED_TRACE("const std::list");
+  InstanceRangedAssignTestForContainer<Instance, const std::list<Instance>>();
+  SCOPED_TRACE("std::vector");
+  InstanceRangedAssignTestForContainer<Instance, std::vector<Instance>>();
+  SCOPED_TRACE("const std::vector");
+  InstanceRangedAssignTestForContainer<Instance, const std::vector<Instance>>();
+}
+
+TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) {
+  EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}),
+              AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6)));
+}
+
+TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) {
+  EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}),
+              AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6)));
+}
+
+TEST(InitializerListConstructor, DisparateTypesInList) {
+  EXPECT_THAT((absl::InlinedVector<int, 2>{-7, 8ULL}), ElementsAre(-7, 8));
+
+  EXPECT_THAT((absl::InlinedVector<std::string, 2>{"foo", std::string("bar")}),
+              ElementsAre("foo", "bar"));
+}
+
+TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
+  EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
+                  CopyableMovableInstance(0)}),
+              AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0))));
+}
+
+TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) {
+  EXPECT_THAT(
+      (absl::InlinedVector<CopyableMovableInstance, 1>{
+          CopyableMovableInstance(0), CopyableMovableInstance(1)}),
+      AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1))));
+}
+
+TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) {
+  for (size_t original_size = 0; original_size <= 4; ++original_size) {
+    SCOPED_TRACE(original_size);
+
+    absl::InlinedVector<int, 2> v1(original_size, 12345);
+    const size_t original_capacity_v1 = v1.capacity();
+    v1.assign({3});
+    EXPECT_THAT(
+        v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3)));
+
+    absl::InlinedVector<int, 2> v2(original_size, 12345);
+    const size_t original_capacity_v2 = v2.capacity();
+    v2 = {3};
+    EXPECT_THAT(
+        v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3)));
+  }
+}
+
+TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) {
+  for (size_t original_size = 0; original_size <= 4; ++original_size) {
+    SCOPED_TRACE(original_size);
+    absl::InlinedVector<int, 2> v1(original_size, 12345);
+    v1.assign({3, 4, 5});
+    EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
+    EXPECT_LE(3, v1.capacity());
+
+    absl::InlinedVector<int, 2> v2(original_size, 12345);
+    v2 = {3, 4, 5};
+    EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
+    EXPECT_LE(3, v2.capacity());
+  }
+}
+
+TEST(InitializerListAssign, DisparateTypesInList) {
+  absl::InlinedVector<int, 2> v_int1;
+  v_int1.assign({-7, 8ULL});
+  EXPECT_THAT(v_int1, ElementsAre(-7, 8));
+
+  absl::InlinedVector<int, 2> v_int2;
+  v_int2 = {-7, 8ULL};
+  EXPECT_THAT(v_int2, ElementsAre(-7, 8));
+
+  absl::InlinedVector<std::string, 2> v_string1;
+  v_string1.assign({"foo", std::string("bar")});
+  EXPECT_THAT(v_string1, ElementsAre("foo", "bar"));
+
+  absl::InlinedVector<std::string, 2> v_string2;
+  v_string2 = {"foo", std::string("bar")};
+  EXPECT_THAT(v_string2, ElementsAre("foo", "bar"));
+}
+
+TYPED_TEST_P(InstanceTest, InitializerListAssign) {
+  using Instance = TypeParam;
+  for (size_t original_size = 0; original_size <= 4; ++original_size) {
+    SCOPED_TRACE(original_size);
+    absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
+    const size_t original_capacity = v.capacity();
+    v.assign({Instance(3)});
+    EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity),
+                         ElementsAre(ValueIs(3))));
+  }
+  for (size_t original_size = 0; original_size <= 4; ++original_size) {
+    SCOPED_TRACE(original_size);
+    absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
+    v.assign({Instance(3), Instance(4), Instance(5)});
+    EXPECT_THAT(v, AllOf(SizeIs(3),
+                         ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
+    EXPECT_LE(3, v.capacity());
+  }
+}
+
+REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors,
+                           CountConstructorsDestructorsOnCopyConstruction,
+                           CountConstructorsDestructorsOnMoveConstruction,
+                           CountConstructorsDestructorsOnAssignment,
+                           CountConstructorsDestructorsOnMoveAssignment,
+                           CountElemAssignInlineBacking, RangedConstructor,
+                           RangedAssign, InitializerListAssign);
+
+using InstanceTypes =
+    ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>;
+INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes);
+
+TEST(DynamicVec, DynamicVecCompiles) {
+  DynamicVec v;
+  (void)v;
+}
+
+TEST(AllocatorSupportTest, Constructors) {
+  using MyAlloc = CountingAllocator<int>;
+  using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+  const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+  int64_t allocated = 0;
+  MyAlloc alloc(&allocated);
+  { AllocVec ABSL_ATTRIBUTE_UNUSED v; }
+  { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); }
+  { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); }
+  { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); }
+
+  AllocVec v2;
+  { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); }
+  { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); }
+}
+
+TEST(AllocatorSupportTest, CountAllocations) {
+  using MyAlloc = CountingAllocator<int>;
+  using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+  const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+  int64_t allocated = 0;
+  MyAlloc alloc(&allocated);
+  {
+    AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
+    EXPECT_THAT(allocated, 0);
+  }
+  EXPECT_THAT(allocated, 0);
+  {
+    AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
+    EXPECT_THAT(allocated, v.size() * sizeof(int));
+  }
+  EXPECT_THAT(allocated, 0);
+  {
+    AllocVec v(4, 1, alloc);
+    EXPECT_THAT(allocated, 0);
+
+    int64_t allocated2 = 0;
+    MyAlloc alloc2(&allocated2);
+    AllocVec v2(v, alloc2);
+    EXPECT_THAT(allocated2, 0);
+
+    int64_t allocated3 = 0;
+    MyAlloc alloc3(&allocated3);
+    AllocVec v3(std::move(v), alloc3);
+    EXPECT_THAT(allocated3, 0);
+  }
+  EXPECT_THAT(allocated, 0);
+  {
+    AllocVec v(8, 2, alloc);
+    EXPECT_THAT(allocated, v.size() * sizeof(int));
+
+    int64_t allocated2 = 0;
+    MyAlloc alloc2(&allocated2);
+    AllocVec v2(v, alloc2);
+    EXPECT_THAT(allocated2, v2.size() * sizeof(int));
+
+    int64_t allocated3 = 0;
+    MyAlloc alloc3(&allocated3);
+    AllocVec v3(std::move(v), alloc3);
+    EXPECT_THAT(allocated3, v3.size() * sizeof(int));
+  }
+  EXPECT_EQ(allocated, 0);
+  {
+    // Test shrink_to_fit deallocations.
+    AllocVec v(8, 2, alloc);
+    EXPECT_EQ(allocated, 8 * sizeof(int));
+    v.resize(5);
+    EXPECT_EQ(allocated, 8 * sizeof(int));
+    v.shrink_to_fit();
+    EXPECT_EQ(allocated, 5 * sizeof(int));
+    v.resize(4);
+    EXPECT_EQ(allocated, 5 * sizeof(int));
+    v.shrink_to_fit();
+    EXPECT_EQ(allocated, 0);
+  }
+}
+
+TEST(AllocatorSupportTest, SwapBothAllocated) {
+  using MyAlloc = CountingAllocator<int>;
+  using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+  int64_t allocated1 = 0;
+  int64_t allocated2 = 0;
+  {
+    const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+    const int ia2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+    MyAlloc a1(&allocated1);
+    MyAlloc a2(&allocated2);
+    AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
+    AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
+    EXPECT_LT(v1.capacity(), v2.capacity());
+    EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
+    EXPECT_THAT(allocated2, v2.capacity() * sizeof(int));
+    v1.swap(v2);
+    EXPECT_THAT(v1, ElementsAreArray(ia2));
+    EXPECT_THAT(v2, ElementsAreArray(ia1));
+    EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
+    EXPECT_THAT(allocated2, v1.capacity() * sizeof(int));
+  }
+  EXPECT_THAT(allocated1, 0);
+  EXPECT_THAT(allocated2, 0);
+}
+
+TEST(AllocatorSupportTest, SwapOneAllocated) {
+  using MyAlloc = CountingAllocator<int>;
+  using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+  int64_t allocated1 = 0;
+  int64_t allocated2 = 0;
+  {
+    const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+    const int ia2[] = { 0, 1, 2, 3 };
+    MyAlloc a1(&allocated1);
+    MyAlloc a2(&allocated2);
+    AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
+    AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
+    EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
+    EXPECT_THAT(allocated2, 0);
+    v1.swap(v2);
+    EXPECT_THAT(v1, ElementsAreArray(ia2));
+    EXPECT_THAT(v2, ElementsAreArray(ia1));
+    EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
+    EXPECT_THAT(allocated2, 0);
+    EXPECT_TRUE(v2.get_allocator() == a1);
+    EXPECT_TRUE(v1.get_allocator() == a2);
+  }
+  EXPECT_THAT(allocated1, 0);
+  EXPECT_THAT(allocated2, 0);
+}
+
+TEST(AllocatorSupportTest, ScopedAllocatorWorks) {
+  using StdVector = std::vector<int, CountingAllocator<int>>;
+  using MyAlloc =
+      std::scoped_allocator_adaptor<CountingAllocator<StdVector>>;
+  using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>;
+
+  int64_t allocated = 0;
+  AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}});
+  EXPECT_EQ(allocated, 0);
+
+  // This default constructs a vector<int>, but the allocator should pass itself
+  // into the vector<int>.
+  // The absl::InlinedVector does not allocate any memory.
+  // The vector<int> does not allocate any memory.
+  vec.resize(1);
+  EXPECT_EQ(allocated, 0);
+
+  // We make vector<int> allocate memory.
+  // It must go through the allocator even though we didn't construct the
+  // vector directly.
+  vec[0].push_back(1);
+  EXPECT_EQ(allocated, sizeof(int) * 1);
+
+  // Another allocating vector.
+  vec.push_back(vec[0]);
+  EXPECT_EQ(allocated, sizeof(int) * 2);
+
+  // Overflow the inlined memory.
+  // The absl::InlinedVector will now allocate.
+  vec.resize(5);
+  EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8);
+
+  // Adding one more in external mode should also work.
+  vec.push_back(vec[0]);
+  EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8);
+
+  // And extending these should still work.
+  vec[0].push_back(1);
+  EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8);
+
+  vec.clear();
+  EXPECT_EQ(allocated, 0);
+}
+
+TEST(AllocatorSupportTest, SizeAllocConstructor) {
+  constexpr int inlined_size = 4;
+  using Alloc = CountingAllocator<int>;
+  using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>;
+
+  {
+    auto len = inlined_size / 2;
+    int64_t allocated = 0;
+    auto v = AllocVec(len, Alloc(&allocated));
+
+    // Inline storage used; allocator should not be invoked
+    EXPECT_THAT(allocated, 0);
+    EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
+  }
+
+  {
+    auto len = inlined_size * 2;
+    int64_t allocated = 0;
+    auto v = AllocVec(len, Alloc(&allocated));
+
+    // Out of line storage used; allocation of 8 elements expected
+    EXPECT_THAT(allocated, len * sizeof(int));
+    EXPECT_THAT(v, AllOf(SizeIs(len), Each(0)));
+  }
+}
+
+}  // anonymous namespace
diff --git a/absl/container/internal/test_instance_tracker.cc b/absl/container/internal/test_instance_tracker.cc
new file mode 100644
index 0000000..fe00aca
--- /dev/null
+++ b/absl/container/internal/test_instance_tracker.cc
@@ -0,0 +1,26 @@
+// Copyright 2017 The Abseil 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 "absl/container/internal/test_instance_tracker.h"
+
+namespace absl {
+namespace test_internal {
+int BaseCountedInstance::num_instances_ = 0;
+int BaseCountedInstance::num_live_instances_ = 0;
+int BaseCountedInstance::num_moves_ = 0;
+int BaseCountedInstance::num_copies_ = 0;
+int BaseCountedInstance::num_swaps_ = 0;
+
+}  // namespace test_internal
+}  // namespace absl
diff --git a/absl/container/internal/test_instance_tracker.h b/absl/container/internal/test_instance_tracker.h
new file mode 100644
index 0000000..cf8f3a5
--- /dev/null
+++ b/absl/container/internal/test_instance_tracker.h
@@ -0,0 +1,220 @@
+// Copyright 2017 The Abseil 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 ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
+#define ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
+
+#include <cstdlib>
+#include <ostream>
+
+namespace absl {
+namespace test_internal {
+
+// A type that counts number of occurences of the type, the live occurrences of
+// the type, as well as the number of copies, moves, and swaps that have
+// occurred on the type. This is used as a base class for the copyable,
+// copyable+movable, and movable types below that are used in actual tests. Use
+// InstanceTracker in tests to track the number of instances.
+class BaseCountedInstance {
+ public:
+  explicit BaseCountedInstance(int x) : value_(x) {
+    ++num_instances_;
+    ++num_live_instances_;
+  }
+  BaseCountedInstance(const BaseCountedInstance& x)
+      : value_(x.value_), is_live_(x.is_live_) {
+    ++num_instances_;
+    if (is_live_) ++num_live_instances_;
+    ++num_copies_;
+  }
+  BaseCountedInstance(BaseCountedInstance&& x)
+      : value_(x.value_), is_live_(x.is_live_) {
+    x.is_live_ = false;
+    ++num_instances_;
+    ++num_moves_;
+  }
+  ~BaseCountedInstance() {
+    --num_instances_;
+    if (is_live_) --num_live_instances_;
+  }
+
+  BaseCountedInstance& operator=(const BaseCountedInstance& x) {
+    value_ = x.value_;
+    if (is_live_) --num_live_instances_;
+    is_live_ = x.is_live_;
+    if (is_live_) ++num_live_instances_;
+    ++num_copies_;
+    return *this;
+  }
+  BaseCountedInstance& operator=(BaseCountedInstance&& x) {
+    value_ = x.value_;
+    if (is_live_) --num_live_instances_;
+    is_live_ = x.is_live_;
+    x.is_live_ = false;
+    ++num_moves_;
+    return *this;
+  }
+
+  int value() const {
+    if (!is_live_) std::abort();
+    return value_;
+  }
+
+  friend std::ostream& operator<<(std::ostream& o,
+                                  const BaseCountedInstance& v) {
+    return o << "[value:" << v.value() << "]";
+  }
+
+  // Implementation of efficient swap() that counts swaps.
+  static void SwapImpl(
+      BaseCountedInstance& lhs,    // NOLINT(runtime/references)
+      BaseCountedInstance& rhs) {  // NOLINT(runtime/references)
+    using std::swap;
+    swap(lhs.value_, rhs.value_);
+    swap(lhs.is_live_, rhs.is_live_);
+    ++BaseCountedInstance::num_swaps_;
+  }
+
+ private:
+  friend class InstanceTracker;
+
+  int value_;
+
+  // Indicates if the value is live, ie it hasn't been moved away from.
+  bool is_live_ = true;
+
+  // Number of instances.
+  static int num_instances_;
+
+  // Number of live instances (those that have not been moved away from.)
+  static int num_live_instances_;
+
+  // Number of times that BaseCountedInstance objects were moved.
+  static int num_moves_;
+
+  // Number of times that BaseCountedInstance objects were copied.
+  static int num_copies_;
+
+  // Number of times that BaseCountedInstance objects were swapped.
+  static int num_swaps_;
+};
+
+// Helper to track the BaseCountedInstance instance counters. Expects that the
+// number of instances and live_instances are the same when it is constructed
+// and when it is destructed.
+class InstanceTracker {
+ public:
+  InstanceTracker()
+      : start_instances_(BaseCountedInstance::num_instances_),
+        start_live_instances_(BaseCountedInstance::num_live_instances_) {
+    ResetCopiesMovesSwaps();
+  }
+  ~InstanceTracker() {
+    if (instances() != 0) std::abort();
+    if (live_instances() != 0) std::abort();
+  }
+
+  // Returns the number of BaseCountedInstance instances both containing valid
+  // values and those moved away from compared to when the InstanceTracker was
+  // constructed
+  int instances() const {
+    return BaseCountedInstance::num_instances_ - start_instances_;
+  }
+
+  // Returns the number of live BaseCountedInstance instances compared to when
+  // the InstanceTracker was constructed
+  int live_instances() const {
+    return BaseCountedInstance::num_live_instances_ - start_live_instances_;
+  }
+
+  // Returns the number of moves on BaseCountedInstance objects since
+  // construction or since the last call to ResetCopiesMovesSwaps().
+  int moves() const { return BaseCountedInstance::num_moves_ - start_moves_; }
+
+  // Returns the number of copies on BaseCountedInstance objects since
+  // construction or the last call to ResetCopiesMovesSwaps().
+  int copies() const {
+    return BaseCountedInstance::num_copies_ - start_copies_;
+  }
+
+  // Returns the number of swaps on BaseCountedInstance objects since
+  // construction or the last call to ResetCopiesMovesSwaps().
+  int swaps() const { return BaseCountedInstance::num_swaps_ - start_swaps_; }
+
+  // Resets the base values for moves, copies and swaps to the current values,
+  // so that subsequent Get*() calls for moves, copies and swaps will compare to
+  // the situation at the point of this call.
+  void ResetCopiesMovesSwaps() {
+    start_moves_ = BaseCountedInstance::num_moves_;
+    start_copies_ = BaseCountedInstance::num_copies_;
+    start_swaps_ = BaseCountedInstance::num_swaps_;
+  }
+
+ private:
+  int start_instances_;
+  int start_live_instances_;
+  int start_moves_;
+  int start_copies_;
+  int start_swaps_;
+};
+
+// Copyable, not movable.
+class CopyableOnlyInstance : public BaseCountedInstance {
+ public:
+  explicit CopyableOnlyInstance(int x) : BaseCountedInstance(x) {}
+  CopyableOnlyInstance(const CopyableOnlyInstance& rhs) = default;
+  CopyableOnlyInstance& operator=(const CopyableOnlyInstance& rhs) = default;
+
+  friend void swap(CopyableOnlyInstance& lhs, CopyableOnlyInstance& rhs) {
+    BaseCountedInstance::SwapImpl(lhs, rhs);
+  }
+
+  static bool supports_move() { return false; }
+};
+
+// Copyable and movable.
+class CopyableMovableInstance : public BaseCountedInstance {
+ public:
+  explicit CopyableMovableInstance(int x) : BaseCountedInstance(x) {}
+  CopyableMovableInstance(const CopyableMovableInstance& rhs) = default;
+  CopyableMovableInstance(CopyableMovableInstance&& rhs) = default;
+  CopyableMovableInstance& operator=(const CopyableMovableInstance& rhs) =
+      default;
+  CopyableMovableInstance& operator=(CopyableMovableInstance&& rhs) = default;
+
+  friend void swap(CopyableMovableInstance& lhs, CopyableMovableInstance& rhs) {
+    BaseCountedInstance::SwapImpl(lhs, rhs);
+  }
+
+  static bool supports_move() { return true; }
+};
+
+// Only movable, not default-constructible.
+class MovableOnlyInstance : public BaseCountedInstance {
+ public:
+  explicit MovableOnlyInstance(int x) : BaseCountedInstance(x) {}
+  MovableOnlyInstance(MovableOnlyInstance&& other) = default;
+  MovableOnlyInstance& operator=(MovableOnlyInstance&& other) = default;
+
+  friend void swap(MovableOnlyInstance& lhs, MovableOnlyInstance& rhs) {
+    BaseCountedInstance::SwapImpl(lhs, rhs);
+  }
+
+  static bool supports_move() { return true; }
+};
+
+}  // namespace test_internal
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
diff --git a/absl/container/internal/test_instance_tracker_test.cc b/absl/container/internal/test_instance_tracker_test.cc
new file mode 100644
index 0000000..9efb677
--- /dev/null
+++ b/absl/container/internal/test_instance_tracker_test.cc
@@ -0,0 +1,160 @@
+// Copyright 2017 The Abseil 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 "absl/container/internal/test_instance_tracker.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::test_internal::CopyableMovableInstance;
+using absl::test_internal::CopyableOnlyInstance;
+using absl::test_internal::InstanceTracker;
+using absl::test_internal::MovableOnlyInstance;
+
+TEST(TestInstanceTracker, CopyableMovable) {
+  InstanceTracker tracker;
+  CopyableMovableInstance src(1);
+  EXPECT_EQ(1, src.value()) << src;
+  CopyableMovableInstance copy(src);
+  CopyableMovableInstance move(std::move(src));
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(1, tracker.moves());
+  EXPECT_EQ(0, tracker.swaps());
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(2, tracker.live_instances());
+  tracker.ResetCopiesMovesSwaps();
+
+  CopyableMovableInstance copy_assign(1);
+  copy_assign = copy;
+  CopyableMovableInstance move_assign(1);
+  move_assign = std::move(move);
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(1, tracker.moves());
+  EXPECT_EQ(0, tracker.swaps());
+  EXPECT_EQ(5, tracker.instances());
+  EXPECT_EQ(3, tracker.live_instances());
+  tracker.ResetCopiesMovesSwaps();
+
+  {
+    using std::swap;
+    swap(move_assign, copy);
+    swap(copy, move_assign);
+    EXPECT_EQ(2, tracker.swaps());
+    EXPECT_EQ(0, tracker.copies());
+    EXPECT_EQ(0, tracker.moves());
+    EXPECT_EQ(5, tracker.instances());
+    EXPECT_EQ(3, tracker.live_instances());
+  }
+}
+
+TEST(TestInstanceTracker, CopyableOnly) {
+  InstanceTracker tracker;
+  CopyableOnlyInstance src(1);
+  EXPECT_EQ(1, src.value()) << src;
+  CopyableOnlyInstance copy(src);
+  CopyableOnlyInstance copy2(std::move(src));  // NOLINT
+  EXPECT_EQ(2, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(3, tracker.live_instances());
+  tracker.ResetCopiesMovesSwaps();
+
+  CopyableOnlyInstance copy_assign(1);
+  copy_assign = copy;
+  CopyableOnlyInstance copy_assign2(1);
+  copy_assign2 = std::move(copy2);  // NOLINT
+  EXPECT_EQ(2, tracker.copies());
+  EXPECT_EQ(0, tracker.moves());
+  EXPECT_EQ(5, tracker.instances());
+  EXPECT_EQ(5, tracker.live_instances());
+  tracker.ResetCopiesMovesSwaps();
+
+  {
+    using std::swap;
+    swap(src, copy);
+    swap(copy, src);
+    EXPECT_EQ(2, tracker.swaps());
+    EXPECT_EQ(0, tracker.copies());
+    EXPECT_EQ(0, tracker.moves());
+    EXPECT_EQ(5, tracker.instances());
+    EXPECT_EQ(5, tracker.live_instances());
+  }
+}
+
+TEST(TestInstanceTracker, MovableOnly) {
+  InstanceTracker tracker;
+  MovableOnlyInstance src(1);
+  EXPECT_EQ(1, src.value()) << src;
+  MovableOnlyInstance move(std::move(src));
+  MovableOnlyInstance move_assign(2);
+  move_assign = std::move(move);
+  EXPECT_EQ(3, tracker.instances());
+  EXPECT_EQ(1, tracker.live_instances());
+  EXPECT_EQ(2, tracker.moves());
+  EXPECT_EQ(0, tracker.copies());
+  tracker.ResetCopiesMovesSwaps();
+
+  {
+    using std::swap;
+    MovableOnlyInstance other(2);
+    swap(move_assign, other);
+    swap(other, move_assign);
+    EXPECT_EQ(2, tracker.swaps());
+    EXPECT_EQ(0, tracker.copies());
+    EXPECT_EQ(0, tracker.moves());
+    EXPECT_EQ(4, tracker.instances());
+    EXPECT_EQ(2, tracker.live_instances());
+  }
+}
+
+TEST(TestInstanceTracker, ExistingInstances) {
+  CopyableMovableInstance uncounted_instance(1);
+  CopyableMovableInstance uncounted_live_instance(
+      std::move(uncounted_instance));
+  InstanceTracker tracker;
+  EXPECT_EQ(0, tracker.instances());
+  EXPECT_EQ(0, tracker.live_instances());
+  EXPECT_EQ(0, tracker.copies());
+  {
+    CopyableMovableInstance instance1(1);
+    EXPECT_EQ(1, tracker.instances());
+    EXPECT_EQ(1, tracker.live_instances());
+    EXPECT_EQ(0, tracker.copies());
+    EXPECT_EQ(0, tracker.moves());
+    {
+      InstanceTracker tracker2;
+      CopyableMovableInstance instance2(instance1);
+      CopyableMovableInstance instance3(std::move(instance2));
+      EXPECT_EQ(3, tracker.instances());
+      EXPECT_EQ(2, tracker.live_instances());
+      EXPECT_EQ(1, tracker.copies());
+      EXPECT_EQ(1, tracker.moves());
+      EXPECT_EQ(2, tracker2.instances());
+      EXPECT_EQ(1, tracker2.live_instances());
+      EXPECT_EQ(1, tracker2.copies());
+      EXPECT_EQ(1, tracker2.moves());
+    }
+    EXPECT_EQ(1, tracker.instances());
+    EXPECT_EQ(1, tracker.live_instances());
+    EXPECT_EQ(1, tracker.copies());
+    EXPECT_EQ(1, tracker.moves());
+  }
+  EXPECT_EQ(0, tracker.instances());
+  EXPECT_EQ(0, tracker.live_instances());
+  EXPECT_EQ(1, tracker.copies());
+  EXPECT_EQ(1, tracker.moves());
+}
+
+}  // namespace
diff --git a/absl/copts.bzl b/absl/copts.bzl
new file mode 100644
index 0000000..20c9b61
--- /dev/null
+++ b/absl/copts.bzl
@@ -0,0 +1,155 @@
+"""absl specific copts.
+
+Flags specified here must not impact ABI. Code compiled with and without these
+opts will be linked together, and in some cases headers compiled with and
+without these options will be part of the same program.
+"""
+GCC_FLAGS = [
+    "-Wall",
+    "-Wextra",
+    "-Wcast-qual",
+    "-Wconversion-null",
+    "-Wmissing-declarations",
+    "-Woverlength-strings",
+    "-Wpointer-arith",
+    "-Wunused-local-typedefs",
+    "-Wunused-result",
+    "-Wvarargs",
+    "-Wvla",  # variable-length array
+    "-Wwrite-strings",
+    # Google style does not use unsigned integers, though STL containers
+    # have unsigned types.
+    "-Wno-sign-compare",
+]
+
+GCC_TEST_FLAGS = [
+    "-Wno-conversion-null",
+    "-Wno-missing-declarations",
+    "-Wno-sign-compare",
+    "-Wno-unused-function",
+    "-Wno-unused-parameter",
+    "-Wno-unused-private-field",
+]
+
+
+# Docs on single flags is preceded by a comment.
+# Docs on groups of flags is preceded by ###.
+
+LLVM_FLAGS = [
+    # All warnings are treated as errors by implicit -Werror flag
+    "-Wall",
+    "-Wextra",
+    "-Weverything",
+    # Abseil does not support C++98
+    "-Wno-c++98-compat-pedantic",
+    # Turns off all implicit conversion warnings. Most are re-enabled below.
+    "-Wno-conversion",
+    "-Wno-covered-switch-default",
+    "-Wno-deprecated",
+    "-Wno-disabled-macro-expansion",
+    "-Wno-double-promotion",
+    ###
+    # Turned off as they include valid C++ code.
+    "-Wno-comma",
+    "-Wno-extra-semi",
+    "-Wno-packed",
+    "-Wno-padded",
+    ###
+    "-Wno-float-conversion",
+    "-Wno-float-equal",
+    "-Wno-format-nonliteral",
+    # Too aggressive: warns on Clang extensions enclosed in Clang-only
+    # compilation paths.
+    "-Wno-gcc-compat",
+    ###
+    # Some internal globals are necessary. Don't do this at home.
+    "-Wno-global-constructors",
+    "-Wno-exit-time-destructors",
+    ###
+    "-Wno-nested-anon-types",
+    "-Wno-non-modular-include-in-module",
+    "-Wno-old-style-cast",
+    # Warns on preferred usage of non-POD types such as string_view
+    "-Wno-range-loop-analysis",
+    "-Wno-reserved-id-macro",
+    "-Wno-shorten-64-to-32",
+    "-Wno-switch-enum",
+    "-Wno-thread-safety-negative",
+    "-Wno-undef",
+    "-Wno-unknown-warning-option",
+    "-Wno-unreachable-code",
+    # Causes warnings on include guards
+    "-Wno-unused-macros",
+    "-Wno-weak-vtables",
+    ###
+    # Implicit conversion warnings turned off by -Wno-conversion
+    # which are re-enabled below.
+    "-Wbitfield-enum-conversion",
+    "-Wbool-conversion",
+    "-Wconstant-conversion",
+    "-Wenum-conversion",
+    "-Wint-conversion",
+    "-Wliteral-conversion",
+    "-Wnon-literal-null-conversion",
+    "-Wnull-conversion",
+    "-Wobjc-literal-conversion",
+    "-Wno-sign-conversion",
+    "-Wstring-conversion",
+    ###
+]
+
+LLVM_TEST_FLAGS = [
+    "-Wno-c99-extensions",
+    "-Wno-missing-noreturn",
+    "-Wno-missing-prototypes",
+    "-Wno-null-conversion",
+    "-Wno-shadow",
+    "-Wno-shift-sign-overflow",
+    "-Wno-sign-compare",
+    "-Wno-unused-function",
+    "-Wno-unused-member-function",
+    "-Wno-unused-parameter",
+    "-Wno-unused-private-field",
+    "-Wno-unused-template",
+    "-Wno-used-but-marked-unused",
+    "-Wno-zero-as-null-pointer-constant",
+]
+
+MSVC_FLAGS = [
+    "/W3",
+    "/WX",
+    "/wd4005",  # macro-redefinition
+    "/wd4068",  # unknown pragma
+    "/wd4244",  # conversion from 'type1' to 'type2', possible loss of data
+    "/wd4267",  # conversion from 'size_t' to 'type', possible loss of data
+    "/wd4800",  # forcing value to bool 'true' or 'false' (performance warning)
+    "/DNOMINMAX",  # Don't define min and max macros (windows.h)
+    "/DWIN32_LEAN_AND_MEAN",  # Don't bloat namespace with incompatible winsock versions.
+    "/D_CRT_SECURE_NO_WARNINGS",  # Don't warn about usage of insecure C functions
+]
+
+MSVC_TEST_FLAGS = [
+    "/wd4018",  # signed/unsigned mismatch
+    "/wd4101",  # unreferenced local variable
+    "/wd4503",  # decorated name length exceeded, name was truncated
+]
+
+# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
+ABSL_DEFAULT_COPTS = select({
+    "//absl:windows": MSVC_FLAGS,
+    "//absl:llvm_compiler": LLVM_FLAGS,
+    "//conditions:default": GCC_FLAGS,
+})
+
+# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
+# to their (included header) dependencies and fail to build outside absl
+ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
+    "//absl:windows": MSVC_TEST_FLAGS,
+    "//absl:llvm_compiler": LLVM_TEST_FLAGS,
+    "//conditions:default": GCC_TEST_FLAGS,
+})
+
+ABSL_EXCEPTIONS_FLAG = select({
+    "//absl:windows": ["/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"],
+    "//conditions:default": ["-fexceptions"],
+})
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
new file mode 100644
index 0000000..e1e7fce
--- /dev/null
+++ b/absl/debugging/BUILD.bazel
@@ -0,0 +1,305 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "stacktrace",
+    srcs = [
+        "stacktrace.cc",
+    ],
+    hdrs = ["stacktrace.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":debugging_internal",
+        "//absl/base",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_library(
+    name = "symbolize",
+    srcs = [
+        "symbolize.cc",
+        "symbolize_elf.inc",
+        "symbolize_unimplemented.inc",
+        "symbolize_win32.inc",
+    ],
+    hdrs = [
+        "internal/symbolize.h",
+        "symbolize.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":debugging_internal",
+        ":demangle_internal",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/base:malloc_internal",
+    ],
+)
+
+cc_test(
+    name = "symbolize_test",
+    srcs = ["symbolize_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":stack_consumption",
+        ":symbolize",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_library(
+    name = "examine_stack",
+    srcs = [
+        "internal/examine_stack.cc",
+    ],
+    hdrs = [
+        "internal/examine_stack.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":stacktrace",
+        ":symbolize",
+        "//absl/base",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_library(
+    name = "failure_signal_handler",
+    srcs = ["failure_signal_handler.cc"],
+    hdrs = ["failure_signal_handler.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":examine_stack",
+        ":stacktrace",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "failure_signal_handler_test",
+    srcs = ["failure_signal_handler_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//absl:windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    deps = [
+        ":failure_signal_handler",
+        ":stacktrace",
+        ":symbolize",
+        "//absl/base",
+        "//absl/strings",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_library(
+    name = "debugging_internal",
+    srcs = [
+        "internal/address_is_readable.cc",
+        "internal/elf_mem_image.cc",
+        "internal/vdso_support.cc",
+    ],
+    hdrs = [
+        "internal/address_is_readable.h",
+        "internal/elf_mem_image.h",
+        "internal/stacktrace_aarch64-inl.inc",
+        "internal/stacktrace_arm-inl.inc",
+        "internal/stacktrace_config.h",
+        "internal/stacktrace_generic-inl.inc",
+        "internal/stacktrace_powerpc-inl.inc",
+        "internal/stacktrace_unimplemented-inl.inc",
+        "internal/stacktrace_win32-inl.inc",
+        "internal/stacktrace_x86-inl.inc",
+        "internal/vdso_support.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base",
+        "//absl/base:dynamic_annotations",
+    ],
+)
+
+cc_library(
+    name = "demangle_internal",
+    srcs = ["internal/demangle.cc"],
+    hdrs = ["internal/demangle.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "demangle_test",
+    srcs = ["internal/demangle_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":demangle_internal",
+        ":stack_consumption",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "leak_check",
+    srcs = select({
+        # The leak checking interface depends on weak function
+        # declarations that may not necessarily have definitions.
+        # Windows doesn't support this, and ios requires
+        # guaranteed definitions for weak symbols.
+        "//absl:ios": [],
+        "//absl:windows": [],
+        "//conditions:default": [
+            "leak_check.cc",
+        ],
+    }),
+    hdrs = select({
+        "//absl:ios": [],
+        "//absl:windows": [],
+        "//conditions:default": ["leak_check.h"],
+    }),
+    deps = ["//absl/base:core_headers"],
+)
+
+# Adding a dependency to leak_check_disable will disable
+# sanitizer leak checking (asan/lsan) in a test without
+# the need to mess around with build features.
+cc_library(
+    name = "leak_check_disable",
+    srcs = ["leak_check_disable.cc"],
+    linkstatic = 1,
+    alwayslink = 1,
+)
+
+# These targets exists for use in tests only, explicitly configuring the
+# LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan.
+ABSL_LSAN_LINKOPTS = select({
+    "//absl:llvm_compiler": ["-fsanitize=leak"],
+    "//conditions:default": [],
+})
+
+cc_library(
+    name = "leak_check_api_enabled_for_testing",
+    testonly = 1,
+    srcs = ["leak_check.cc"],
+    hdrs = ["leak_check.h"],
+    copts = select({
+        "//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
+        "//conditions:default": [],
+    }),
+    visibility = ["//visibility:private"],
+)
+
+cc_library(
+    name = "leak_check_api_disabled_for_testing",
+    testonly = 1,
+    srcs = ["leak_check.cc"],
+    hdrs = ["leak_check.h"],
+    copts = ["-ULEAK_SANITIZER"],
+    visibility = ["//visibility:private"],
+)
+
+cc_test(
+    name = "leak_check_test",
+    srcs = ["leak_check_test.cc"],
+    copts = select({
+        "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
+        "//conditions:default": [],
+    }),
+    linkopts = ABSL_LSAN_LINKOPTS,
+    deps = [
+        ":leak_check_api_enabled_for_testing",
+        "//absl/base",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "leak_check_no_lsan_test",
+    srcs = ["leak_check_test.cc"],
+    copts = ["-UABSL_EXPECT_LEAK_SANITIZER"],
+    deps = [
+        ":leak_check_api_disabled_for_testing",
+        "//absl/base",  # for raw_logging
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+# Test that leak checking is skipped when lsan is enabled but
+# ":leak_check_disable" is linked in.
+#
+# This test should fail in the absence of a dependency on ":leak_check_disable"
+cc_test(
+    name = "disabled_leak_check_test",
+    srcs = ["leak_check_fail_test.cc"],
+    linkopts = ABSL_LSAN_LINKOPTS,
+    deps = [
+        ":leak_check_api_enabled_for_testing",
+        ":leak_check_disable",
+        "//absl/base",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "stack_consumption",
+    testonly = 1,
+    srcs = ["internal/stack_consumption.cc"],
+    hdrs = ["internal/stack_consumption.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        "//absl/base",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "stack_consumption_test",
+    srcs = ["internal/stack_consumption_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":stack_consumption",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/debugging/BUILD.gn b/absl/debugging/BUILD.gn
new file mode 100644
index 0000000..b50b0a6
--- /dev/null
+++ b/absl/debugging/BUILD.gn
@@ -0,0 +1,245 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("stacktrace") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "stacktrace.cc",
+  ]
+  public = [
+    "stacktrace.h",
+  ]
+  deps = [
+    ":debugging_internal",
+    "../base",
+    "../base:core_headers",
+  ]
+}
+
+source_set("symbolize") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "symbolize.cc",
+    "symbolize_elf.inc",
+    "symbolize_unimplemented.inc",
+    "symbolize_win32.inc",
+  ]
+  public = [
+    "internal/symbolize.h",
+    "symbolize.h",
+  ]
+  deps = [
+    ":debugging_internal",
+    ":demangle_internal",
+    "../base",
+    "../base:core_headers",
+    "../base:malloc_internal",
+  ]
+}
+
+source_set("examine_stack") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/examine_stack.cc",
+  ]
+  public = [
+    "internal/examine_stack.h",
+  ]
+  visibility = []
+  visibility += [ ":*" ]
+  deps = [
+    ":stacktrace",
+    ":symbolize",
+    "../base",
+    "../base:core_headers",
+  ]
+}
+
+source_set("failure_signal_handler") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "failure_signal_handler.cc"
+  ]
+  public = [
+    "failure_signal_handler.h"
+  ]
+  deps = [
+    ":examine_stack",
+    ":stacktrace",
+    "../base",
+    "../base:config",
+    "../base:core_headers",
+  ]
+}
+
+source_set("debugging_internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/address_is_readable.cc",
+    "internal/elf_mem_image.cc",
+    "internal/vdso_support.cc",
+  ]
+  public = [
+    "internal/address_is_readable.h",
+    "internal/elf_mem_image.h",
+    "internal/stacktrace_config.h",
+    "internal/vdso_support.h",
+  ]
+  deps = [
+    "../base",
+    "../base:dynamic_annotations",
+  ]
+}
+
+source_set("demangle_internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/demangle.cc",
+  ]
+  public = [
+    "internal/demangle.h",
+  ]
+  deps = [
+    "../base",
+    "../base:core_headers",
+  ]
+}
+
+source_set("leak_check") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  if (is_ios || is_win) {
+    sources = []
+    public = []
+  } else {
+    sources = [
+      "leak_check.cc",
+    ]
+    public = [
+      "leak_check.h",
+    ]
+  }
+  deps = [
+    "../base:core_headers",
+  ]
+}
+
+source_set("leak_check_disable") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "leak_check_disable.cc",
+  ]
+}
+
+if (is_lsan) {
+  source_set("leak_check_api_enabled_for_testing") {
+    testonly = true
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      "//build/config/compiler:no_chromium_code",
+      "//third_party/abseil-cpp:absl_default_cflags_cc",
+    ]
+    public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+    sources = [
+      "leak_check.cc",
+    ]
+    public = [
+      "leak_check.h",
+    ]
+    visibility = []
+    visibility += [ ":*" ]
+  }
+} else {
+  source_set("leak_check_api_disabled_for_testing") {
+    testonly = true
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      "//build/config/compiler:no_chromium_code",
+      "//third_party/abseil-cpp:absl_default_cflags_cc",
+    ]
+    public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+    sources = [
+      "leak_check.cc",
+    ]
+    public = [
+      "leak_check.h",
+    ]
+    visibility = []
+    visibility += [ ":*" ]
+  }
+}
+
+source_set("stack_consumption") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/stack_consumption.cc",
+  ]
+  public = [
+    "internal/stack_consumption.h",
+  ]
+  deps = [
+    "../base",
+    "../base:core_headers",
+  ]
+  visibility = []
+  visibility += [ ":*" ]
+}
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
new file mode 100644
index 0000000..4af2ec8
--- /dev/null
+++ b/absl/debugging/CMakeLists.txt
@@ -0,0 +1,217 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND DEBUGGING_PUBLIC_HEADERS
+  "failure_signal_handler.h"
+  "leak_check.h"
+  "stacktrace.h"
+  "symbolize.h"
+)
+
+# TODO(cohenjon) The below is all kinds of wrong.  Make this match what we do in
+# Bazel
+list(APPEND DEBUGGING_INTERNAL_HEADERS
+  "internal/address_is_readable.h"
+  "internal/demangle.h"
+  "internal/elf_mem_image.h"
+  "internal/examine_stack.h"
+  "internal/stacktrace_config.h"
+  "internal/symbolize.h"
+  "internal/vdso_support.h"
+)
+
+list(APPEND DEBUGGING_INTERNAL_SRC
+  "internal/address_is_readable.cc"
+  "internal/elf_mem_image.cc"
+  "internal/vdso_support.cc"
+)
+
+
+list(APPEND STACKTRACE_SRC
+  "stacktrace.cc"
+  ${DEBUGGING_INTERNAL_SRC}
+  ${DEBUGGING_PUBLIC_HEADERS}
+  ${DEBUGGING_INTERNAL_HEADERS}
+)
+
+list(APPEND SYMBOLIZE_SRC
+  "symbolize.cc"
+  "symbolize_elf.inc"
+  "symbolize_unimplemented.inc"
+  "symbolize_win32.inc"
+  "internal/demangle.cc"
+  ${DEBUGGING_PUBLIC_HEADERS}
+  ${DEBUGGING_INTERNAL_HEADERS}
+  ${DEBUGGING_INTERNAL_SRC}
+)
+
+list(APPEND FAILURE_SIGNAL_HANDLER_SRC
+  "failure_signal_handler.cc"
+  ${DEBUGGING_PUBLIC_HEADERS}
+)
+
+list(APPEND EXAMINE_STACK_SRC
+  "internal/examine_stack.cc"
+  ${DEBUGGING_PUBLIC_HEADERS}
+  ${DEBUGGING_INTERNAL_HEADERS}
+)
+
+absl_library(
+  TARGET
+    absl_stacktrace
+  SOURCES
+    ${STACKTRACE_SRC}
+  EXPORT_NAME
+    stacktrace
+)
+
+absl_library(
+  TARGET
+    absl_symbolize
+  SOURCES
+    ${SYMBOLIZE_SRC}
+  PUBLIC_LIBRARIES
+    absl::base
+    absl_malloc_internal
+  EXPORT_NAME
+    symbolize
+)
+
+absl_library(
+  TARGET
+    absl_failure_signal_handler
+  SOURCES
+    ${FAILURE_SIGNAL_HANDLER_SRC}
+  PUBLIC_LIBRARIES
+    absl_base absl::examine_stack absl::stacktrace absl_synchronization
+  EXPORT_NAME
+    failure_signal_handler
+)
+
+# Internal-only. Projects external to Abseil should not depend
+# directly on this library.
+absl_library(
+  TARGET
+    absl_examine_stack
+  SOURCES
+    ${EXAMINE_STACK_SRC}
+  EXPORT_NAME
+    examine_stack
+)
+
+list(APPEND LEAK_CHECK_SRC
+  "leak_check.cc"
+)
+
+
+# leak_check library
+absl_library(
+  TARGET
+    absl_leak_check
+  SOURCES
+    ${LEAK_CHECK_SRC}
+  PUBLIC_LIBRARIES
+    absl_base
+  EXPORT_NAME
+    leak_check
+)
+
+
+# component target
+absl_header_library(
+  TARGET
+    absl_debugging
+  PUBLIC_LIBRARIES
+    absl_stacktrace absl_leak_check
+  EXPORT_NAME
+    debugging
+)
+
+#
+## TESTS
+#
+
+list(APPEND STACK_CONSUMPTION_SRC
+  "internal/stack_consumption.cc"
+  "internal/stack_consumption.h"
+)
+
+absl_library(
+  TARGET
+    absl_stack_consumption
+  SOURCES
+    ${STACK_CONSUMPTION_SRC}
+)
+
+absl_test(
+  TARGET
+    absl_stack_consumption_test
+  SOURCES
+    "internal/stack_consumption_test.cc"
+  PUBLIC_LIBRARIES
+    absl_stack_consumption
+    absl::base
+)
+
+list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc")
+
+absl_test(
+  TARGET
+    demangle_test
+  SOURCES
+    ${DEMANGLE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl_symbolize absl_stack_consumption
+)
+
+list(APPEND SYMBOLIZE_TEST_SRC "symbolize_test.cc")
+
+absl_test(
+  TARGET
+    symbolize_test
+  SOURCES
+    ${SYMBOLIZE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl::base absl::memory absl_symbolize absl_stack_consumption
+)
+
+list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc")
+
+absl_test(
+  TARGET
+    failure_signal_handler_test
+  SOURCES
+    ${FAILURE_SIGNAL_HANDLER_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl_examine_stack
+    absl_failure_signal_handler
+    absl_stacktrace
+    absl_symbolize
+    absl::base
+    absl::strings
+)
+
+# test leak_check_test
+list(APPEND LEAK_CHECK_TEST_SRC "leak_check_test.cc")
+
+absl_test(
+  TARGET
+    leak_check_test
+  SOURCES
+    ${LEAK_CHECK_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl_leak_check
+)
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
new file mode 100644
index 0000000..4c131fe
--- /dev/null
+++ b/absl/debugging/failure_signal_handler.cc
@@ -0,0 +1,356 @@
+//
+// Copyright 2018 The Abseil 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 "absl/debugging/failure_signal_handler.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifdef ABSL_HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <csignal>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/debugging/internal/examine_stack.h"
+#include "absl/debugging/stacktrace.h"
+
+#ifndef _WIN32
+#define ABSL_HAVE_SIGACTION
+#endif
+
+namespace absl {
+
+ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
+
+// Resets the signal handler for signo to the default action for that
+// signal, then raises the signal.
+static void RaiseToDefaultHandler(int signo) {
+  signal(signo, SIG_DFL);
+  raise(signo);
+}
+
+struct FailureSignalData {
+  const int signo;
+  const char* const as_string;
+#ifdef ABSL_HAVE_SIGACTION
+  struct sigaction previous_action;
+  // StructSigaction is used to silence -Wmissing-field-initializers.
+  using StructSigaction = struct sigaction;
+  #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
+#else
+  void (*previous_handler)(int);
+  #define FSD_PREVIOUS_INIT SIG_DFL
+#endif
+};
+
+ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = {
+    {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
+    {SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
+    {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
+    {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
+    {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
+#ifndef _WIN32
+    {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
+    {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
+#endif
+};
+
+#undef FSD_PREVIOUS_INIT
+
+static void RaiseToPreviousHandler(int signo) {
+  // Search for the previous handler.
+  for (const auto& it : failure_signal_data) {
+    if (it.signo == signo) {
+#ifdef ABSL_HAVE_SIGACTION
+      sigaction(signo, &it.previous_action, nullptr);
+#else
+      signal(signo, it.previous_handler);
+#endif
+      raise(signo);
+      return;
+    }
+  }
+
+  // Not found, use the default handler.
+  RaiseToDefaultHandler(signo);
+}
+
+namespace debugging_internal {
+
+const char* FailureSignalToString(int signo) {
+  for (const auto& it : failure_signal_data) {
+    if (it.signo == signo) {
+      return it.as_string;
+    }
+  }
+  return "";
+}
+
+}  // namespace debugging_internal
+
+#ifndef _WIN32
+
+static bool SetupAlternateStackOnce() {
+  const size_t page_mask = getpagesize() - 1;
+  size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER)
+  // Account for sanitizer instrumentation requiring additional stack space.
+  stack_size *= 5;
+#endif
+
+  stack_t sigstk;
+  memset(&sigstk, 0, sizeof(sigstk));
+  sigstk.ss_size = stack_size;
+
+#ifdef ABSL_HAVE_MMAP
+#ifndef MAP_STACK
+#define MAP_STACK 0
+#endif
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+  sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
+                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+  if (sigstk.ss_sp == MAP_FAILED) {
+    ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
+  }
+#else
+  sigstk.ss_sp = malloc(sigstk.ss_size);
+  if (sigstk.ss_sp == nullptr) {
+    ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
+  }
+#endif
+
+  if (sigaltstack(&sigstk, nullptr) != 0) {
+    ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
+  }
+  return true;
+}
+
+#endif
+
+#ifdef ABSL_HAVE_SIGACTION
+
+// Sets up an alternate stack for signal handlers once.
+// Returns the appropriate flag for sig_action.sa_flags
+// if the system supports using an alternate stack.
+static int MaybeSetupAlternateStack() {
+#ifndef _WIN32
+  ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
+  return SA_ONSTACK;
+#else
+  return 0;
+#endif
+}
+
+static void InstallOneFailureHandler(FailureSignalData* data,
+                                     void (*handler)(int, siginfo_t*, void*)) {
+  struct sigaction act;
+  memset(&act, 0, sizeof(act));
+  sigemptyset(&act.sa_mask);
+  act.sa_flags |= SA_SIGINFO;
+  // SA_NODEFER is required to handle SIGABRT from
+  // ImmediateAbortSignalHandler().
+  act.sa_flags |= SA_NODEFER;
+  if (fsh_options.use_alternate_stack) {
+    act.sa_flags |= MaybeSetupAlternateStack();
+  }
+  act.sa_sigaction = handler;
+  ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
+                 "sigaction() failed");
+}
+
+#else
+
+static void InstallOneFailureHandler(FailureSignalData* data,
+                                     void (*handler)(int)) {
+  data->previous_handler = signal(data->signo, handler);
+  ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
+}
+
+#endif
+
+static void WriteToStderr(const char* data) {
+  int old_errno = errno;
+  absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
+  errno = old_errno;
+}
+
+static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
+  char buf[64];
+  const char* const signal_string =
+      debugging_internal::FailureSignalToString(signo);
+  if (signal_string != nullptr && signal_string[0] != '\0') {
+    snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n",
+             signal_string,
+             static_cast<long>(time(nullptr)));  // NOLINT(runtime/int)
+  } else {
+    snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n",
+             signo, static_cast<long>(time(nullptr)));  // NOLINT(runtime/int)
+  }
+  writerfn(buf);
+}
+
+// `void*` might not be big enough to store `void(*)(const char*)`.
+struct WriterFnStruct {
+  void (*writerfn)(const char*);
+};
+
+// Many of the absl::debugging_internal::Dump* functions in
+// examine_stack.h take a writer function pointer that has a void* arg
+// for historical reasons. failure_signal_handler_writer only takes a
+// data pointer. This function converts between these types.
+static void WriterFnWrapper(const char* data, void* arg) {
+  static_cast<WriterFnStruct*>(arg)->writerfn(data);
+}
+
+// Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
+// handlers. "noinline" so that GetStackFrames() skips the top-most stack
+// frame for this function.
+ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace(
+    void* ucontext, bool symbolize_stacktrace,
+    void (*writerfn)(const char*, void*), void* writerfn_arg) {
+  constexpr int kNumStackFrames = 32;
+  void* stack[kNumStackFrames];
+  int frame_sizes[kNumStackFrames];
+  int min_dropped_frames;
+  int depth = absl::GetStackFramesWithContext(
+      stack, frame_sizes, kNumStackFrames,
+      1,  // Do not include this function in stack trace.
+      ucontext, &min_dropped_frames);
+  absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace(
+      absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
+      depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
+}
+
+// Called by FailureSignalHandler() to write the failure info. It is
+// called once with writerfn set to WriteToStderr() and then possibly
+// with writerfn set to the user provided function.
+static void WriteFailureInfo(int signo, void* ucontext,
+                             void (*writerfn)(const char*)) {
+  WriterFnStruct writerfn_struct{writerfn};
+  WriteSignalMessage(signo, writerfn);
+  WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
+                  &writerfn_struct);
+}
+
+// absl::SleepFor() can't be used here since AbslInternalSleepFor()
+// may be overridden to do something that isn't async-signal-safe on
+// some platforms.
+static void PortableSleepForSeconds(int seconds) {
+#ifdef _WIN32
+  Sleep(seconds * 1000);
+#else
+  struct timespec sleep_time;
+  sleep_time.tv_sec = seconds;
+  sleep_time.tv_nsec = 0;
+  while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {}
+#endif
+}
+
+#ifdef ABSL_HAVE_ALARM
+// FailureSignalHandler() installs this as a signal handler for
+// SIGALRM, then sets an alarm to be delivered to the program after a
+// set amount of time. If FailureSignalHandler() hangs for more than
+// the alarm timeout, ImmediateAbortSignalHandler() will abort the
+// program.
+static void ImmediateAbortSignalHandler(int) {
+  RaiseToDefaultHandler(SIGABRT);
+}
+#endif
+
+// absl::base_internal::GetTID() returns pid_t on most platforms, but
+// returns absl::base_internal::pid_t on Windows.
+using GetTidType = decltype(absl::base_internal::GetTID());
+ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
+
+#ifndef ABSL_HAVE_SIGACTION
+static void FailureSignalHandler(int signo) {
+  void* ucontext = nullptr;
+#else
+static void FailureSignalHandler(int signo, siginfo_t*,
+                                 void* ucontext) {
+#endif
+
+  const GetTidType this_tid = absl::base_internal::GetTID();
+  GetTidType previous_failed_tid = 0;
+  if (!failed_tid.compare_exchange_strong(
+          previous_failed_tid, static_cast<intptr_t>(this_tid),
+          std::memory_order_acq_rel, std::memory_order_relaxed)) {
+    ABSL_RAW_LOG(
+        ERROR,
+        "Signal %d raised at PC=%p while already in FailureSignalHandler()",
+        signo, absl::debugging_internal::GetProgramCounter(ucontext));
+    if (this_tid != previous_failed_tid) {
+      // Another thread is already in FailureSignalHandler(), so wait
+      // a bit for it to finish. If the other thread doesn't kill us,
+      // we do so after sleeping.
+      PortableSleepForSeconds(3);
+      RaiseToDefaultHandler(signo);
+      // The recursively raised signal may be blocked until we return.
+      return;
+    }
+  }
+
+#ifdef ABSL_HAVE_ALARM
+  // Set an alarm to abort the program in case this code hangs or deadlocks.
+  if (fsh_options.alarm_on_failure_secs > 0) {
+    alarm(0);  // Cancel any existing alarms.
+    signal(SIGALRM, ImmediateAbortSignalHandler);
+    alarm(fsh_options.alarm_on_failure_secs);
+  }
+#endif
+
+  // First write to stderr.
+  WriteFailureInfo(signo, ucontext, WriteToStderr);
+
+  // Riskier code (because it is less likely to be async-signal-safe)
+  // goes after this point.
+  if (fsh_options.writerfn != nullptr) {
+    WriteFailureInfo(signo, ucontext, fsh_options.writerfn);
+  }
+
+  if (fsh_options.call_previous_handler) {
+    RaiseToPreviousHandler(signo);
+  } else {
+    RaiseToDefaultHandler(signo);
+  }
+}
+
+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
+  fsh_options = options;
+  for (auto& it : failure_signal_data) {
+    InstallOneFailureHandler(&it, FailureSignalHandler);
+  }
+}
+
+}  // namespace absl
diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h
new file mode 100644
index 0000000..c57954e
--- /dev/null
+++ b/absl/debugging/failure_signal_handler.h
@@ -0,0 +1,117 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: failure_signal_handler.h
+// -----------------------------------------------------------------------------
+//
+// This file configures the Abseil *failure signal handler* to capture and dump
+// useful debugging information (such as a stacktrace) upon program failure.
+//
+// To use the failure signal handler, call `absl::InstallFailureSignalHandler()`
+// very early in your program, usually in the first few lines of main():
+//
+// int main(int argc, char** argv) {
+//   // Initialize the symbolizer to get a human-readable stack trace
+//   absl::InitializeSymbolizer(argv[0]);
+//
+//   absl::FailureSignalHandlerOptions options;
+//   absl::InstallFailureSignalHandler(options);
+//   DoSomethingInteresting();
+//   return 0;
+// }
+//
+// Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`,
+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the
+// installed failure signal handler and provide debugging information to stderr.
+//
+// Note that you should *not* install the Abseil failure signal handler more
+// than once. You may, of course, have another (non-Abseil) failure signal
+// handler installed (which would be triggered if Abseil's failure signal
+// handler sets `call_previous_handler` to `true`).
+
+#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+
+namespace absl {
+
+// FailureSignalHandlerOptions
+//
+// Struct for holding `absl::InstallFailureSignalHandler()` configuration
+// options.
+struct FailureSignalHandlerOptions {
+  // If true, try to symbolize the stacktrace emitted on failure, provided that
+  // you have initialized a symbolizer for that purpose. (See symbolize.h for
+  // more information.)
+  bool symbolize_stacktrace = true;
+
+  // If true, try to run signal handlers on an alternate stack (if supported on
+  // the given platform). An alternate stack is useful for program crashes due
+  // to a stack overflow; by running on a alternate stack, the signal handler
+  // may run even when normal stack space has been exausted. The downside of
+  // using an alternate stack is that extra memory for the alternate stack needs
+  // to be pre-allocated.
+  bool use_alternate_stack = true;
+
+  // If positive, indicates the number of seconds after which the failure signal
+  // handler is invoked to abort the program. Setting such an alarm is useful in
+  // cases where the failure signal handler itself may become hung or
+  // deadlocked.
+  int alarm_on_failure_secs = 3;
+
+  // If true, call the previously registered signal handler for the signal that
+  // was received (if one was registered) after the existing signal handler
+  // runs. This mechanism can be used to chain signal handlers together.
+  //
+  // If false, the signal is raised to the default handler for that signal
+  // (which normally terminates the program).
+  //
+  // IMPORTANT: If true, the chained fatal signal handlers must not try to
+  // recover from the fatal signal. Instead, they should terminate the program
+  // via some mechanism, like raising the default handler for the signal, or by
+  // calling `_exit()`. Note that the failure signal handler may put parts of
+  // the Abseil library into a state from which they cannot recover.
+  bool call_previous_handler = false;
+
+  // If non-null, indicates a pointer to a callback function that will be called
+  // upon failure, with a std::string argument containing failure data. This function
+  // may be used as a hook to write failure data to a secondary location, such
+  // as a log file. This function may also be called with null data, as a hint
+  // to flush any buffered data before the program may be terminated. Consider
+  // flushing any buffered data in all calls to this function.
+  //
+  // Since this function runs within a signal handler, it should be
+  // async-signal-safe if possible.
+  // See http://man7.org/linux/man-pages/man7/signal-safety.7.html
+  void (*writerfn)(const char*) = nullptr;
+};
+
+// InstallFailureSignalHandler()
+//
+// Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`,
+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist
+// on the given platform). The failure signal handler dumps program failure data
+// useful for debugging in an unspecified format to stderr. This data may
+// include the program counter, a stacktrace, and register information on some
+// systems; do not rely on an exact format for the output, as it is subject to
+// change.
+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options);
+
+namespace debugging_internal {
+const char* FailureSignalToString(int signo);
+}  // namespace debugging_internal
+
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc
new file mode 100644
index 0000000..ba52091
--- /dev/null
+++ b/absl/debugging/failure_signal_handler_test.cc
@@ -0,0 +1,155 @@
+//
+// Copyright 2018 The Abseil 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 "absl/debugging/failure_signal_handler.h"
+
+#include <csignal>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+#if GTEST_HAS_DEATH_TEST
+
+// For the parameterized death tests. GetParam() returns the signal number.
+using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>;
+
+// This function runs in a fork()ed process on most systems.
+void InstallHandlerAndRaise(int signo) {
+  absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions());
+  raise(signo);
+}
+
+TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) {
+  const int signo = GetParam();
+  std::string exit_regex = absl::StrCat(
+      "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
+      " received at time=");
+#ifndef _WIN32
+  EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo),
+              exit_regex);
+#else
+  // Windows doesn't have testing::KilledBySignal().
+  EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex);
+#endif
+}
+
+ABSL_CONST_INIT FILE* error_file = nullptr;
+
+void WriteToErrorFile(const char* msg) {
+  if (msg != nullptr) {
+    ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1,
+                   "fwrite() failed");
+  }
+  ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed");
+}
+
+std::string GetTmpDir() {
+  // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel.
+  static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP",
+                                            "TEMPDIR", "TMP"};
+  for (const char* const var : kTmpEnvVars) {
+    const char* tmp_dir = std::getenv(var);
+    if (tmp_dir != nullptr) {
+      return tmp_dir;
+    }
+  }
+
+  // Try something reasonable.
+  return "/tmp";
+}
+
+// This function runs in a fork()ed process on most systems.
+void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) {
+  error_file = fopen(file, "w");
+  ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file");
+  absl::FailureSignalHandlerOptions options;
+  options.writerfn = WriteToErrorFile;
+  absl::InstallFailureSignalHandler(options);
+  raise(signo);
+}
+
+TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) {
+  const int signo = GetParam();
+  std::string tmp_dir = GetTmpDir();
+  std::string file = absl::StrCat(tmp_dir, "/signo_", signo);
+
+  std::string exit_regex = absl::StrCat(
+      "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
+      " received at time=");
+#ifndef _WIN32
+  EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
+              testing::KilledBySignal(signo), exit_regex);
+#else
+  // Windows doesn't have testing::KilledBySignal().
+  EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
+               exit_regex);
+#endif
+
+  // Open the file in this process and check its contents.
+  std::fstream error_output(file);
+  ASSERT_TRUE(error_output.is_open()) << file;
+  std::string error_line;
+  std::getline(error_output, error_line);
+  EXPECT_TRUE(absl::StartsWith(
+      error_line,
+      absl::StrCat("*** ",
+                   absl::debugging_internal::FailureSignalToString(signo),
+                   " received at ")));
+
+  if (absl::debugging_internal::StackTraceWorksForTest()) {
+    std::getline(error_output, error_line);
+    EXPECT_TRUE(absl::StartsWith(error_line, "PC: "));
+  }
+}
+
+constexpr int kFailureSignals[] = {
+    SIGSEGV, SIGILL,  SIGFPE, SIGABRT, SIGTERM,
+#ifndef _WIN32
+    SIGBUS,  SIGTRAP,
+#endif
+};
+
+std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
+  std::string result = absl::debugging_internal::FailureSignalToString(info.param);
+  if (result.empty()) {
+    result = absl::StrCat(info.param);
+  }
+  return result;
+}
+
+INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
+                        ::testing::ValuesIn(kFailureSignals),
+                        SignalParamToString);
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  absl::InitializeSymbolizer(argv[0]);
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc
new file mode 100644
index 0000000..7455aa0
--- /dev/null
+++ b/absl/debugging/internal/address_is_readable.cc
@@ -0,0 +1,133 @@
+// Copyright 2017 The Abseil 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.
+
+// base::AddressIsReadable() probes an address to see whether it is readable,
+// without faulting.
+
+#include "absl/debugging/internal/address_is_readable.h"
+
+#if !defined(__linux__) || defined(__ANDROID__)
+
+namespace absl {
+namespace debugging_internal {
+
+// On platforms other than Linux, just return true.
+bool AddressIsReadable(const void* /* addr */) { return true; }
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#else
+
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <atomic>
+#include <cerrno>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace debugging_internal {
+
+// Pack a pid and two file descriptors into a 64-bit word,
+// using 16, 24, and 24 bits for each respectively.
+static uint64_t Pack(uint64_t pid, uint64_t read_fd, uint64_t write_fd) {
+  ABSL_RAW_CHECK((read_fd >> 24) == 0 && (write_fd >> 24) == 0,
+                 "fd out of range");
+  return (pid << 48) | ((read_fd & 0xffffff) << 24) | (write_fd & 0xffffff);
+}
+
+// Unpack x into a pid and two file descriptors, where x was created with
+// Pack().
+static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) {
+  *pid = x >> 48;
+  *read_fd = (x >> 24) & 0xffffff;
+  *write_fd = x & 0xffffff;
+}
+
+// Return whether the byte at *addr is readable, without faulting.
+// Save and restores errno.   Returns true on systems where
+// unimplemented.
+// This is a namespace-scoped variable for correct zero-initialization.
+static std::atomic<uint64_t> pid_and_fds;  // initially 0, an invalid pid.
+bool AddressIsReadable(const void *addr) {
+  int save_errno = errno;
+  // We test whether a byte is readable by using write().  Normally, this would
+  // be done via a cached file descriptor to /dev/null, but linux fails to
+  // check whether the byte is readable when the destination is /dev/null, so
+  // we use a cached pipe.  We store the pid of the process that created the
+  // pipe to handle the case where a process forks, and the child closes all
+  // the file descriptors and then calls this routine.  This is not perfect:
+  // the child could use the routine, then close all file descriptors and then
+  // use this routine again.  But the likely use of this routine is when
+  // crashing, to test the validity of pages when dumping the stack.  Beware
+  // that we may leak file descriptors, but we're unlikely to leak many.
+  int bytes_written;
+  int current_pid = getpid() & 0xffff;   // we use only the low order 16 bits
+  do {  // until we do not get EBADF trying to use file descriptors
+    int pid;
+    int read_fd;
+    int write_fd;
+    uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+    Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
+    while (current_pid != pid) {
+      int p[2];
+      // new pipe
+      if (pipe(p) != 0) {
+        ABSL_RAW_LOG(FATAL, "Failed to create pipe, errno=%d", errno);
+      }
+      fcntl(p[0], F_SETFD, FD_CLOEXEC);
+      fcntl(p[1], F_SETFD, FD_CLOEXEC);
+      uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]);
+      if (pid_and_fds.compare_exchange_strong(
+              local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed,
+              std::memory_order_relaxed)) {
+        local_pid_and_fds = new_pid_and_fds;  // fds exposed to other threads
+      } else {  // fds not exposed to other threads; we can close them.
+        close(p[0]);
+        close(p[1]);
+        local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+      }
+      Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
+    }
+    errno = 0;
+    // Use syscall(SYS_write, ...) instead of write() to prevent ASAN
+    // and other checkers from complaining about accesses to arbitrary
+    // memory.
+    do {
+      bytes_written = syscall(SYS_write, write_fd, addr, 1);
+    } while (bytes_written == -1 && errno == EINTR);
+    if (bytes_written == 1) {   // remove the byte from the pipe
+      char c;
+      while (read(read_fd, &c, 1) == -1 && errno == EINTR) {
+      }
+    }
+    if (errno == EBADF) {  // Descriptors invalid.
+      // If pid_and_fds contains the problematic file descriptors we just used,
+      // this call will forget them, and the loop will try again.
+      pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0,
+                                          std::memory_order_relaxed,
+                                          std::memory_order_relaxed);
+    }
+  } while (errno == EBADF);
+  errno = save_errno;
+  return bytes_written == 1;
+}
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif
diff --git a/absl/debugging/internal/address_is_readable.h b/absl/debugging/internal/address_is_readable.h
new file mode 100644
index 0000000..9d48030
--- /dev/null
+++ b/absl/debugging/internal/address_is_readable.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Abseil 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 ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+
+namespace absl {
+namespace debugging_internal {
+
+// Return whether the byte at *addr is readable, without faulting.
+// Save and restores errno.
+bool AddressIsReadable(const void *addr);
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
new file mode 100644
index 0000000..c9ca2f3
--- /dev/null
+++ b/absl/debugging/internal/demangle.cc
@@ -0,0 +1,1862 @@
+// Copyright 2018 The Abseil 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.
+
+// For reference check out:
+// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
+//
+// Note that we only have partial C++11 support yet.
+
+#include "absl/debugging/internal/demangle.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <limits>
+
+namespace absl {
+namespace debugging_internal {
+
+typedef struct {
+  const char *abbrev;
+  const char *real_name;
+  // Number of arguments in <expression> context, or 0 if disallowed.
+  int arity;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+    // New has special syntax (not currently supported).
+    {"nw", "new", 0},
+    {"na", "new[]", 0},
+
+    // Works except that the 'gs' prefix is not supported.
+    {"dl", "delete", 1},
+    {"da", "delete[]", 1},
+
+    {"ps", "+", 1},  // "positive"
+    {"ng", "-", 1},  // "negative"
+    {"ad", "&", 1},  // "address-of"
+    {"de", "*", 1},  // "dereference"
+    {"co", "~", 1},
+
+    {"pl", "+", 2},
+    {"mi", "-", 2},
+    {"ml", "*", 2},
+    {"dv", "/", 2},
+    {"rm", "%", 2},
+    {"an", "&", 2},
+    {"or", "|", 2},
+    {"eo", "^", 2},
+    {"aS", "=", 2},
+    {"pL", "+=", 2},
+    {"mI", "-=", 2},
+    {"mL", "*=", 2},
+    {"dV", "/=", 2},
+    {"rM", "%=", 2},
+    {"aN", "&=", 2},
+    {"oR", "|=", 2},
+    {"eO", "^=", 2},
+    {"ls", "<<", 2},
+    {"rs", ">>", 2},
+    {"lS", "<<=", 2},
+    {"rS", ">>=", 2},
+    {"eq", "==", 2},
+    {"ne", "!=", 2},
+    {"lt", "<", 2},
+    {"gt", ">", 2},
+    {"le", "<=", 2},
+    {"ge", ">=", 2},
+    {"nt", "!", 1},
+    {"aa", "&&", 2},
+    {"oo", "||", 2},
+    {"pp", "++", 1},
+    {"mm", "--", 1},
+    {"cm", ",", 2},
+    {"pm", "->*", 2},
+    {"pt", "->", 0},  // Special syntax
+    {"cl", "()", 0},  // Special syntax
+    {"ix", "[]", 2},
+    {"qu", "?", 3},
+    {"st", "sizeof", 0},  // Special syntax
+    {"sz", "sizeof", 1},  // Not a real operator name, but used in expressions.
+    {nullptr, nullptr, 0},
+};
+
+// List of builtin types from Itanium C++ ABI.
+static const AbbrevPair kBuiltinTypeList[] = {
+    {"v", "void", 0},
+    {"w", "wchar_t", 0},
+    {"b", "bool", 0},
+    {"c", "char", 0},
+    {"a", "signed char", 0},
+    {"h", "unsigned char", 0},
+    {"s", "short", 0},
+    {"t", "unsigned short", 0},
+    {"i", "int", 0},
+    {"j", "unsigned int", 0},
+    {"l", "long", 0},
+    {"m", "unsigned long", 0},
+    {"x", "long long", 0},
+    {"y", "unsigned long long", 0},
+    {"n", "__int128", 0},
+    {"o", "unsigned __int128", 0},
+    {"f", "float", 0},
+    {"d", "double", 0},
+    {"e", "long double", 0},
+    {"g", "__float128", 0},
+    {"z", "ellipsis", 0},
+    {nullptr, nullptr, 0},
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+    {"St", "", 0},
+    {"Sa", "allocator", 0},
+    {"Sb", "basic_string", 0},
+    // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+    {"Ss", "string", 0},
+    // std::basic_istream<char, std::char_traits<char> >
+    {"Si", "istream", 0},
+    // std::basic_ostream<char, std::char_traits<char> >
+    {"So", "ostream", 0},
+    // std::basic_iostream<char, std::char_traits<char> >
+    {"Sd", "iostream", 0},
+    {nullptr, nullptr, 0},
+};
+
+// State needed for demangling.  This struct is copied in almost every stack
+// frame, so every byte counts.
+typedef struct {
+  int mangled_idx;                   // Cursor of mangled name.
+  int out_cur_idx;                   // Cursor of output std::string.
+  int prev_name_idx;                 // For constructors/destructors.
+  signed int prev_name_length : 16;  // For constructors/destructors.
+  signed int nest_level : 15;        // For nested names.
+  unsigned int append : 1;           // Append flag.
+  // Note: for some reason MSVC can't pack "bool append : 1" into the same int
+  // with the above two fields, so we use an int instead.  Amusingly it can pack
+  // "signed bool" as expected, but relying on that to continue to be a legal
+  // type seems ill-advised (as it's illegal in at least clang).
+} ParseState;
+
+static_assert(sizeof(ParseState) == 4 * sizeof(int),
+              "unexpected size of ParseState");
+
+// One-off state for demangling that's not subject to backtracking -- either
+// constant data, data that's intentionally immune to backtracking (steps), or
+// data that would never be changed by backtracking anyway (recursion_depth).
+//
+// Only one copy of this exists for each call to Demangle, so the size of this
+// struct is nearly inconsequential.
+typedef struct {
+  const char *mangled_begin;  // Beginning of input std::string.
+  char *out;                  // Beginning of output std::string.
+  int out_end_idx;            // One past last allowed output character.
+  int recursion_depth;        // For stack exhaustion prevention.
+  int steps;               // Cap how much work we'll do, regardless of depth.
+  ParseState parse_state;  // Backtrackable state copied for most frames.
+} State;
+
+namespace {
+// Prevent deep recursion / stack exhaustion.
+// Also prevent unbounded handling of complex inputs.
+class ComplexityGuard {
+ public:
+  explicit ComplexityGuard(State *state) : state_(state) {
+    ++state->recursion_depth;
+    ++state->steps;
+  }
+  ~ComplexityGuard() { --state_->recursion_depth; }
+
+  // 256 levels of recursion seems like a reasonable upper limit on depth.
+  // 128 is not enough to demagle synthetic tests from demangle_unittest.txt:
+  // "_ZaaZZZZ..." and "_ZaaZcvZcvZ..."
+  static constexpr int kRecursionDepthLimit = 256;
+
+  // We're trying to pick a charitable upper-limit on how many parse steps are
+  // necessary to handle something that a human could actually make use of.
+  // This is mostly in place as a bound on how much work we'll do if we are
+  // asked to demangle an mangled name from an untrusted source, so it should be
+  // much larger than the largest expected symbol, but much smaller than the
+  // amount of work we can do in, e.g., a second.
+  //
+  // Some real-world symbols from an arbitrary binary started failing between
+  // 2^12 and 2^13, so we multiply the latter by an extra factor of 16 to set
+  // the limit.
+  //
+  // Spending one second on 2^17 parse steps would require each step to take
+  // 7.6us, or ~30000 clock cycles, so it's safe to say this can be done in
+  // under a second.
+  static constexpr int kParseStepsLimit = 1 << 17;
+
+  bool IsTooComplex() const {
+    return state_->recursion_depth > kRecursionDepthLimit ||
+           state_->steps > kParseStepsLimit;
+  }
+
+ private:
+  State *state_;
+};
+}  // namespace
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+  size_t len = 0;
+  while (*str != '\0') {
+    ++str;
+    ++len;
+  }
+  return len;
+}
+
+// Returns true if "str" has at least "n" characters remaining.
+static bool AtLeastNumCharsRemaining(const char *str, int n) {
+  for (int i = 0; i < n; ++i) {
+    if (str[i] == '\0') {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+  size_t i = 0;
+  while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) {
+    ++i;
+  }
+  return prefix[i] == '\0';  // Consumed everything in "prefix".
+}
+
+static void InitState(State *state, const char *mangled, char *out,
+                      int out_size) {
+  state->mangled_begin = mangled;
+  state->out = out;
+  state->out_end_idx = out_size;
+  state->recursion_depth = 0;
+  state->steps = 0;
+
+  state->parse_state.mangled_idx = 0;
+  state->parse_state.out_cur_idx = 0;
+  state->parse_state.prev_name_idx = 0;
+  state->parse_state.prev_name_length = -1;
+  state->parse_state.nest_level = -1;
+  state->parse_state.append = true;
+}
+
+static inline const char *RemainingInput(State *state) {
+  return &state->mangled_begin[state->parse_state.mangled_idx];
+}
+
+// Returns true and advances "mangled_idx" if we find "one_char_token"
+// at "mangled_idx" position.  It is assumed that "one_char_token" does
+// not contain '\0'.
+static bool ParseOneCharToken(State *state, const char one_char_token) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (RemainingInput(state)[0] == one_char_token) {
+    ++state->parse_state.mangled_idx;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find "two_char_token"
+// at "mangled_cur" position.  It is assumed that "two_char_token" does
+// not contain '\0'.
+static bool ParseTwoCharToken(State *state, const char *two_char_token) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (RemainingInput(state)[0] == two_char_token[0] &&
+      RemainingInput(state)[1] == two_char_token[1]) {
+    state->parse_state.mangled_idx += 2;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find any character in
+// "char_class" at "mangled_cur" position.
+static bool ParseCharClass(State *state, const char *char_class) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (RemainingInput(state)[0] == '\0') {
+    return false;
+  }
+  const char *p = char_class;
+  for (; *p != '\0'; ++p) {
+    if (RemainingInput(state)[0] == *p) {
+      ++state->parse_state.mangled_idx;
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool ParseDigit(State *state, int *digit) {
+  char c = RemainingInput(state)[0];
+  if (ParseCharClass(state, "0123456789")) {
+    if (digit != nullptr) {
+      *digit = c - '0';
+    }
+    return true;
+  }
+  return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool /*status*/) { return true; }
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+  if (parse_func(state)) {
+    while (parse_func(state)) {
+    }
+    return true;
+  }
+  return false;
+}
+
+// This function is used for handling <non-terminal>* syntax. The function
+// always returns true and must be followed by a termination token or a
+// terminating sequence not handled by parse_func (e.g.
+// ParseOneCharToken(state, 'E')).
+static bool ZeroOrMore(ParseFunc parse_func, State *state) {
+  while (parse_func(state)) {
+  }
+  return true;
+}
+
+// Append "str" at "out_cur_idx".  If there is an overflow, out_cur_idx is
+// set to out_end_idx+1.  The output std::string is ensured to
+// always terminate with '\0' as long as there is no overflow.
+static void Append(State *state, const char *const str, const int length) {
+  for (int i = 0; i < length; ++i) {
+    if (state->parse_state.out_cur_idx + 1 <
+        state->out_end_idx) {  // +1 for '\0'
+      state->out[state->parse_state.out_cur_idx++] = str[i];
+    } else {
+      // signal overflow
+      state->parse_state.out_cur_idx = state->out_end_idx + 1;
+      break;
+    }
+  }
+  if (state->parse_state.out_cur_idx < state->out_end_idx) {
+    state->out[state->parse_state.out_cur_idx] =
+        '\0';  // Terminate it with '\0'
+  }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) { return c >= 'a' && c <= 'z'; }
+
+static bool IsAlpha(char c) {
+  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+static bool IsDigit(char c) { return c >= '0' && c <= '9'; }
+
+// Returns true if "str" is a function clone suffix.  These suffixes are used
+// by GCC 4.5.x and later versions (and our locally-modified version of GCC
+// 4.4.x) to indicate functions which have been cloned during optimization.
+// We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix.
+static bool IsFunctionCloneSuffix(const char *str) {
+  size_t i = 0;
+  while (str[i] != '\0') {
+    // Consume a single .<alpha>+.<digit>+ sequence.
+    if (str[i] != '.' || !IsAlpha(str[i + 1])) {
+      return false;
+    }
+    i += 2;
+    while (IsAlpha(str[i])) {
+      ++i;
+    }
+    if (str[i] != '.' || !IsDigit(str[i + 1])) {
+      return false;
+    }
+    i += 2;
+    while (IsDigit(str[i])) {
+      ++i;
+    }
+  }
+  return true;  // Consumed everything in "str".
+}
+
+static bool EndsWith(State *state, const char chr) {
+  return state->parse_state.out_cur_idx > 0 &&
+         chr == state->out[state->parse_state.out_cur_idx - 1];
+}
+
+// Append "str" with some tweaks, iff "append" state is true.
+static void MaybeAppendWithLength(State *state, const char *const str,
+                                  const int length) {
+  if (state->parse_state.append && length > 0) {
+    // Append a space if the output buffer ends with '<' and "str"
+    // starts with '<' to avoid <<<.
+    if (str[0] == '<' && EndsWith(state, '<')) {
+      Append(state, " ", 1);
+    }
+    // Remember the last identifier name for ctors/dtors.
+    if (IsAlpha(str[0]) || str[0] == '_') {
+      state->parse_state.prev_name_idx = state->parse_state.out_cur_idx;
+      state->parse_state.prev_name_length = length;
+    }
+    Append(state, str, length);
+  }
+}
+
+// Appends a positive decimal number to the output if appending is enabled.
+static bool MaybeAppendDecimal(State *state, unsigned int val) {
+  // Max {32-64}-bit unsigned int is 20 digits.
+  constexpr size_t kMaxLength = 20;
+  char buf[kMaxLength];
+
+  // We can't use itoa or sprintf as neither is specified to be
+  // async-signal-safe.
+  if (state->parse_state.append) {
+    // We can't have a one-before-the-beginning pointer, so instead start with
+    // one-past-the-end and manipulate one character before the pointer.
+    char *p = &buf[kMaxLength];
+    do {  // val=0 is the only input that should write a leading zero digit.
+      *--p = (val % 10) + '0';
+      val /= 10;
+    } while (p > buf && val != 0);
+
+    // 'p' landed on the last character we set.  How convenient.
+    Append(state, p, kMaxLength - (p - buf));
+  }
+
+  return true;
+}
+
+// A convenient wrapper around MaybeAppendWithLength().
+// Returns true so that it can be placed in "if" conditions.
+static bool MaybeAppend(State *state, const char *const str) {
+  if (state->parse_state.append) {
+    int length = StrLen(str);
+    MaybeAppendWithLength(state, str, length);
+  }
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+  state->parse_state.nest_level = 0;
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, int16_t prev_value) {
+  state->parse_state.nest_level = prev_value;
+  return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+  state->parse_state.append = false;
+  return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+  state->parse_state.append = prev_value;
+  return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+  if (state->parse_state.nest_level > -1) {
+    ++state->parse_state.nest_level;
+  }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+  if (state->parse_state.nest_level >= 1) {
+    MaybeAppend(state, "::");
+  }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+  if (state->parse_state.nest_level >= 1 && state->parse_state.append &&
+      state->parse_state.out_cur_idx >= 2) {
+    state->parse_state.out_cur_idx -= 2;
+    state->out[state->parse_state.out_cur_idx] = '\0';
+  }
+}
+
+// Returns true if the identifier of the given length pointed to by
+// "mangled_cur" is anonymous namespace.
+static bool IdentifierIsAnonymousNamespace(State *state, int length) {
+  // Returns true if "anon_prefix" is a proper prefix of "mangled_cur".
+  static const char anon_prefix[] = "_GLOBAL__N_";
+  return (length > static_cast<int>(sizeof(anon_prefix) - 1) &&
+          StrPrefix(RemainingInput(state), anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseNestedName(State *state);
+static bool ParsePrefix(State *state);
+static bool ParseUnqualifiedName(State *state);
+static bool ParseSourceName(State *state);
+static bool ParseLocalSourceName(State *state);
+static bool ParseUnnamedTypeName(State *state);
+static bool ParseNumber(State *state, int *number_out);
+static bool ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state, int length);
+static bool ParseOperatorName(State *state, int *arity);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseDecltype(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseBaseUnresolvedName(State *state);
+static bool ParseUnresolvedName(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseExprCastValue(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseLocalNameSuffix(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state, bool accept_std);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+//   We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the parse state and returns true on
+// success, or returns false and doesn't change the parse state (note:
+// the parse-steps counter increases regardless of success or failure).
+// To ensure that the parse state isn't changed in the latter case, we
+// save the original state before we call multiple parsing functions
+// consecutively with &&, and restore it if unsuccessful.  See
+// ParseEncoding() as an example of this convention.  We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments.  Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+//   <https://mentorembedded.github.io/cxx-abi/abi.html#mangling>
+
+// <mangled-name> ::= _Z <encoding>
+static bool ParseMangledName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+//            ::= <(data) name>
+//            ::= <special-name>
+static bool ParseEncoding(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  // Implementing the first two productions together as <name>
+  // [<bare-function-type>] avoids exponential blowup of backtracking.
+  //
+  // Since Optional(...) can't fail, there's no need to copy the state for
+  // backtracking.
+  if (ParseName(state) && Optional(ParseBareFunctionType(state))) {
+    return true;
+  }
+
+  if (ParseSpecialName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <name> ::= <nested-name>
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//        ::= <local-name>
+static bool ParseName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseNestedName(state) || ParseLocalName(state)) {
+    return true;
+  }
+
+  // We reorganize the productions to avoid re-parsing unscoped names.
+  // - Inline <unscoped-template-name> productions:
+  //   <name> ::= <substitution> <template-args>
+  //          ::= <unscoped-name> <template-args>
+  //          ::= <unscoped-name>
+  // - Merge the two productions that start with unscoped-name:
+  //   <name> ::= <unscoped-name> [<template-args>]
+
+  ParseState copy = state->parse_state;
+  // "std<...>" isn't a valid name.
+  if (ParseSubstitution(state, /*accept_std=*/false) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Note there's no need to restore state after this since only the first
+  // subparser can fail.
+  return ParseUnscopedName(state) && Optional(ParseTemplateArgs(state));
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseUnqualifiedName(state)) {
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <ref-qualifer> ::= R // lvalue method reference qualifier
+//                ::= O // rvalue method reference qualifier
+static inline bool ParseRefQualifier(State *state) {
+  return ParseCharClass(state, "OR");
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix>
+//                   <unqualified-name> E
+//               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
+//                   <template-args> E
+static bool ParseNestedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'N') && EnterNestedName(state) &&
+      Optional(ParseCVQualifiers(state)) &&
+      Optional(ParseRefQualifier(state)) && ParsePrefix(state) &&
+      LeaveNestedName(state, copy.nest_level) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// This part is tricky.  If we literally translate them to code, we'll
+// end up infinite loop.  Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <substitution>
+//          ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+static bool ParsePrefix(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  bool has_something = false;
+  while (true) {
+    MaybeAppendSeparator(state);
+    if (ParseTemplateParam(state) ||
+        ParseSubstitution(state, /*accept_std=*/true) ||
+        ParseUnscopedName(state) ||
+        (ParseOneCharToken(state, 'M') && ParseUnnamedTypeName(state))) {
+      has_something = true;
+      MaybeIncreaseNestLevel(state);
+      continue;
+    }
+    MaybeCancelLastSeparator(state);
+    if (has_something && ParseTemplateArgs(state)) {
+      return ParsePrefix(state);
+    } else {
+      break;
+    }
+  }
+  return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <local-source-name> // GCC extension; see below.
+//                    ::= <unnamed-type-name>
+static bool ParseUnqualifiedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return (ParseOperatorName(state, nullptr) || ParseCtorDtorName(state) ||
+          ParseSourceName(state) || ParseLocalSourceName(state) ||
+          ParseUnnamedTypeName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  int length = -1;
+  if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+//   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+//   http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <unnamed-type-name> ::= Ut [<(nonnegative) number>] _
+//                     ::= <closure-type-name>
+// <closure-type-name> ::= Ul <lambda-sig> E [<(nonnegative) number>] _
+// <lambda-sig>        ::= <(parameter) type>+
+static bool ParseUnnamedTypeName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  // Type's 1-based index n is encoded as { "", n == 1; itoa(n-2), otherwise }.
+  // Optionally parse the encoded value into 'which' and add 2 to get the index.
+  int which = -1;
+
+  // Unnamed type local to function or class.
+  if (ParseTwoCharToken(state, "Ut") && Optional(ParseNumber(state, &which)) &&
+      which <= std::numeric_limits<int>::max() - 2 &&  // Don't overflow.
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "{unnamed type#");
+    MaybeAppendDecimal(state, 2 + which);
+    MaybeAppend(state, "}");
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Closure type.
+  which = -1;
+  if (ParseTwoCharToken(state, "Ul") && DisableAppend(state) &&
+      OneOrMore(ParseType, state) && RestoreAppend(state, copy.append) &&
+      ParseOneCharToken(state, 'E') && Optional(ParseNumber(state, &which)) &&
+      which <= std::numeric_limits<int>::max() - 2 &&  // Don't overflow.
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "{lambda()#");
+    MaybeAppendDecimal(state, 2 + which);
+    MaybeAppend(state, "}");
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+// If "number_out" is non-null, then *number_out is set to the value of the
+// parsed number on success.
+static bool ParseNumber(State *state, int *number_out) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  bool negative = false;
+  if (ParseOneCharToken(state, 'n')) {
+    negative = true;
+  }
+  const char *p = RemainingInput(state);
+  uint64_t number = 0;
+  for (; *p != '\0'; ++p) {
+    if (IsDigit(*p)) {
+      number = number * 10 + (*p - '0');
+    } else {
+      break;
+    }
+  }
+  // Apply the sign with uint64_t arithmetic so overflows aren't UB.  Gives
+  // "incorrect" results for out-of-range inputs, but negative values only
+  // appear for literals, which aren't printed.
+  if (negative) {
+    number = ~number + 1;
+  }
+  if (p != RemainingInput(state)) {  // Conversion succeeded.
+    state->parse_state.mangled_idx += p - RemainingInput(state);
+    if (number_out != nullptr) {
+      // Note: possibly truncate "number".
+      *number_out = number;
+    }
+    return true;
+  }
+  return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// hexadecimal std::string.
+static bool ParseFloatNumber(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  const char *p = RemainingInput(state);
+  for (; *p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
+      break;
+    }
+  }
+  if (p != RemainingInput(state)) {  // Conversion succeeded.
+    state->parse_state.mangled_idx += p - RemainingInput(state);
+    return true;
+  }
+  return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// using digits and upper case letters
+static bool ParseSeqId(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  const char *p = RemainingInput(state);
+  for (; *p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
+      break;
+    }
+  }
+  if (p != RemainingInput(state)) {  // Conversion succeeded.
+    state->parse_state.mangled_idx += p - RemainingInput(state);
+    return true;
+  }
+  return false;
+}
+
+// <identifier> ::= <unqualified source code identifier> (of given length)
+static bool ParseIdentifier(State *state, int length) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (length < 0 || !AtLeastNumCharsRemaining(RemainingInput(state), length)) {
+    return false;
+  }
+  if (IdentifierIsAnonymousNamespace(state, length)) {
+    MaybeAppend(state, "(anonymous namespace)");
+  } else {
+    MaybeAppendWithLength(state, RemainingInput(state), length);
+  }
+  state->parse_state.mangled_idx += length;
+  return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+//                 ::= cv <type>  # (cast)
+//                 ::= v  <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state, int *arity) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (!AtLeastNumCharsRemaining(RemainingInput(state), 2)) {
+    return false;
+  }
+  // First check with "cv" (cast) case.
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") &&
+      EnterNestedName(state) && ParseType(state) &&
+      LeaveNestedName(state, copy.nest_level)) {
+    if (arity != nullptr) {
+      *arity = 1;
+    }
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Then vendor extended operators.
+  if (ParseOneCharToken(state, 'v') && ParseDigit(state, arity) &&
+      ParseSourceName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Other operator names should start with a lower alphabet followed
+  // by a lower/upper alphabet.
+  if (!(IsLower(RemainingInput(state)[0]) &&
+        IsAlpha(RemainingInput(state)[1]))) {
+    return false;
+  }
+  // We may want to perform a binary search if we really need speed.
+  const AbbrevPair *p;
+  for (p = kOperatorList; p->abbrev != nullptr; ++p) {
+    if (RemainingInput(state)[0] == p->abbrev[0] &&
+        RemainingInput(state)[1] == p->abbrev[1]) {
+      if (arity != nullptr) {
+        *arity = p->arity;
+      }
+      MaybeAppend(state, "operator");
+      if (IsLower(*p->real_name)) {  // new, delete, etc.
+        MaybeAppend(state, " ");
+      }
+      MaybeAppend(state, p->real_name);
+      state->parse_state.mangled_idx += 2;
+      return true;
+    }
+  }
+  return false;
+}
+
+// <special-name> ::= TV <type>
+//                ::= TT <type>
+//                ::= TI <type>
+//                ::= TS <type>
+//                ::= Tc <call-offset> <call-offset> <(base) encoding>
+//                ::= GV <(object) name>
+//                ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+//                ::= TC <type> <(offset) number> _ <(base) type>
+//                ::= TF <type>
+//                ::= TJ <type>
+//                ::= GR <name>
+//                ::= GA <encoding>
+//                ::= Th <call-offset> <(base) encoding>
+//                ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces.  The are special data.
+static bool ParseSpecialName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
+      ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "GV") && ParseName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
+      ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // G++ extensions
+  if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
+      ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
+      DisableAppend(state) && ParseType(state)) {
+    RestoreAppend(state, copy.append);
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
+      ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) &&
+      ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'v') && ParseVOffset(state) &&
+      ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return ParseNumber(state, nullptr);
+}
+
+// <v-offset>  ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
+      ParseNumber(state, nullptr)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3
+//                  ::= D0 | D1 | D2
+// # GCC extensions: "unified" constructor/destructor.  See
+// # https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
+//                  ::= C4 | D4
+static bool ParseCtorDtorName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "1234")) {
+    const char *const prev_name = state->out + state->parse_state.prev_name_idx;
+    MaybeAppendWithLength(state, prev_name,
+                          state->parse_state.prev_name_length);
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "0124")) {
+    const char *const prev_name = state->out + state->parse_state.prev_name_idx;
+    MaybeAppend(state, "~");
+    MaybeAppendWithLength(state, prev_name,
+                          state->parse_state.prev_name_length);
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <decltype> ::= Dt <expression> E  # decltype of an id-expression or class
+//                                   # member access (C++0x)
+//            ::= DT <expression> E  # decltype of an expression (C++0x)
+static bool ParseDecltype(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
+      ParseExpression(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+//        ::= P <type>   # pointer-to
+//        ::= R <type>   # reference-to
+//        ::= O <type>   # rvalue reference-to (C++0x)
+//        ::= C <type>   # complex pair (C 2000)
+//        ::= G <type>   # imaginary (C 2000)
+//        ::= U <source-name> <type>  # vendor extended type qualifier
+//        ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>  # note: just an alias for <name>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-template-param> <template-args>
+//        ::= <template-param>
+//        ::= <decltype>
+//        ::= <substitution>
+//        ::= Dp <type>          # pack expansion of (C++0x)
+//
+static bool ParseType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+
+  // We should check CV-qualifers, and PRGC things first.
+  //
+  // CV-qualifiers overlap with some operator names, but an operator name is not
+  // valid as a type.  To avoid an ambiguity that can lead to exponential time
+  // complexity, refuse to backtrack the CV-qualifiers.
+  //
+  // _Z4aoeuIrMvvE
+  //  => _Z 4aoeuI        rM  v     v   E
+  //         aoeu<operator%=, void, void>
+  //  => _Z 4aoeuI r Mv v              E
+  //         aoeu<void void::* restrict>
+  //
+  // By consuming the CV-qualifiers first, the former parse is disabled.
+  if (ParseCVQualifiers(state)) {
+    const bool result = ParseType(state);
+    if (!result) state->parse_state = copy;
+    return result;
+  }
+  state->parse_state = copy;
+
+  // Similarly, these tag characters can overlap with other <name>s resulting in
+  // two different parse prefixes that land on <template-args> in the same
+  // place, such as "C3r1xI...".  So, disable the "ctor-name = C3" parse by
+  // refusing to backtrack the tag characters.
+  if (ParseCharClass(state, "OPRCG")) {
+    const bool result = ParseType(state);
+    if (!result) state->parse_state = copy;
+    return result;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseBuiltinType(state) || ParseFunctionType(state) ||
+      ParseClassEnumType(state) || ParseArrayType(state) ||
+      ParsePointerToMemberType(state) || ParseDecltype(state) ||
+      // "std" on its own isn't a type.
+      ParseSubstitution(state, /*accept_std=*/false)) {
+    return true;
+  }
+
+  if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Less greedy than <template-template-param> <template-args>.
+  if (ParseTemplateParam(state)) {
+    return true;
+  }
+
+  return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// ParseType().
+static bool ParseCVQualifiers(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  int num_cv_qualifiers = 0;
+  num_cv_qualifiers += ParseOneCharToken(state, 'r');
+  num_cv_qualifiers += ParseOneCharToken(state, 'V');
+  num_cv_qualifiers += ParseOneCharToken(state, 'K');
+  return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.
+//                ::= u <source-name>
+static bool ParseBuiltinType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  const AbbrevPair *p;
+  for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
+    if (RemainingInput(state)[0] == p->abbrev[0]) {
+      MaybeAppend(state, p->real_name);
+      ++state->parse_state.mangled_idx;
+      return true;
+    }
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <function-type> ::= F [Y] <bare-function-type> E
+static bool ParseFunctionType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'F') &&
+      Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  DisableAppend(state);
+  if (OneOrMore(ParseType, state)) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "()");
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+//              ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <template-param> ::= T_
+//                  ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseTwoCharToken(state, "T_")) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <template-template-param> ::= <template-param>
+//                           ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return (ParseTemplateParam(state) ||
+          // "std" on its own isn't a template.
+          ParseSubstitution(state, /*accept_std=*/false));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  DisableAppend(state);
+  if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "<>");
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <template-arg>  ::= <type>
+//                 ::= <expr-primary>
+//                 ::= J <template-arg>* E        # argument pack
+//                 ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'J') && ZeroOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // There can be significant overlap between the following leading to
+  // exponential backtracking:
+  //
+  //   <expr-primary> ::= L <type> <expr-cast-value> E
+  //                 e.g. L 2xxIvE 1                 E
+  //   <type>         ==> <local-source-name> <template-args>
+  //                 e.g. L 2xx               IvE
+  //
+  // This means parsing an entire <type> twice, and <type> can contain
+  // <template-arg>, so this can generate exponential backtracking.  There is
+  // only overlap when the remaining input starts with "L <source-name>", so
+  // parse all cases that can start this way jointly to share the common prefix.
+  //
+  // We have:
+  //
+  //   <template-arg> ::= <type>
+  //                  ::= <expr-primary>
+  //
+  // First, drop all the productions of <type> that must start with something
+  // other than 'L'.  All that's left is <class-enum-type>; inline it.
+  //
+  //   <type> ::= <nested-name> # starts with 'N'
+  //          ::= <unscoped-name>
+  //          ::= <unscoped-template-name> <template-args>
+  //          ::= <local-name> # starts with 'Z'
+  //
+  // Drop and inline again:
+  //
+  //   <type> ::= <unscoped-name>
+  //          ::= <unscoped-name> <template-args>
+  //          ::= <substitution> <template-args> # starts with 'S'
+  //
+  // Merge the first two, inline <unscoped-name>, drop last:
+  //
+  //   <type> ::= <unqualified-name> [<template-args>]
+  //          ::= St <unqualified-name> [<template-args>] # starts with 'S'
+  //
+  // Drop and inline:
+  //
+  //   <type> ::= <operator-name> [<template-args>] # starts with lowercase
+  //          ::= <ctor-dtor-name> [<template-args>] # starts with 'C' or 'D'
+  //          ::= <source-name> [<template-args>] # starts with digit
+  //          ::= <local-source-name> [<template-args>]
+  //          ::= <unnamed-type-name> [<template-args>] # starts with 'U'
+  //
+  // One more time:
+  //
+  //   <type> ::= L <source-name> [<template-args>]
+  //
+  // Likewise with <expr-primary>:
+  //
+  //   <expr-primary> ::= L <type> <expr-cast-value> E
+  //                  ::= LZ <encoding> E # cannot overlap; drop
+  //                  ::= L <mangled_name> E # cannot overlap; drop
+  //
+  // By similar reasoning as shown above, the only <type>s starting with
+  // <source-name> are "<source-name> [<template-args>]".  Inline this.
+  //
+  //   <expr-primary> ::= L <source-name> [<template-args>] <expr-cast-value> E
+  //
+  // Now inline both of these into <template-arg>:
+  //
+  //   <template-arg> ::= L <source-name> [<template-args>]
+  //                  ::= L <source-name> [<template-args>] <expr-cast-value> E
+  //
+  // Merge them and we're done:
+  //   <template-arg>
+  //     ::= L <source-name> [<template-args>] [<expr-cast-value> E]
+  if (ParseLocalSourceName(state) && Optional(ParseTemplateArgs(state))) {
+    copy = state->parse_state;
+    if (ParseExprCastValue(state) && ParseOneCharToken(state, 'E')) {
+      return true;
+    }
+    state->parse_state = copy;
+    return true;
+  }
+
+  // Now that the overlapping cases can't reach this code, we can safely call
+  // both of these.
+  if (ParseType(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <unresolved-type> ::= <template-param> [<template-args>]
+//                   ::= <decltype>
+//                   ::= <substitution>
+static inline bool ParseUnresolvedType(State *state) {
+  // No ComplexityGuard because we don't copy the state in this stack frame.
+  return (ParseTemplateParam(state) && Optional(ParseTemplateArgs(state))) ||
+         ParseDecltype(state) || ParseSubstitution(state, /*accept_std=*/false);
+}
+
+// <simple-id> ::= <source-name> [<template-args>]
+static inline bool ParseSimpleId(State *state) {
+  // No ComplexityGuard because we don't copy the state in this stack frame.
+
+  // Note: <simple-id> cannot be followed by a parameter pack; see comment in
+  // ParseUnresolvedType.
+  return ParseSourceName(state) && Optional(ParseTemplateArgs(state));
+}
+
+// <base-unresolved-name> ::= <source-name> [<template-args>]
+//                        ::= on <operator-name> [<template-args>]
+//                        ::= dn <destructor-name>
+static bool ParseBaseUnresolvedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  if (ParseSimpleId(state)) {
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "on") && ParseOperatorName(state, nullptr) &&
+      Optional(ParseTemplateArgs(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "dn") &&
+      (ParseUnresolvedType(state) || ParseSimpleId(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <unresolved-name> ::= [gs] <base-unresolved-name>
+//                   ::= sr <unresolved-type> <base-unresolved-name>
+//                   ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
+//                         <base-unresolved-name>
+//                   ::= [gs] sr <unresolved-qualifier-level>+ E
+//                         <base-unresolved-name>
+static bool ParseUnresolvedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  ParseState copy = state->parse_state;
+  if (Optional(ParseTwoCharToken(state, "gs")) &&
+      ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseUnresolvedType(state) &&
+      ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseOneCharToken(state, 'N') &&
+      ParseUnresolvedType(state) &&
+      OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) &&
+      ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (Optional(ParseTwoCharToken(state, "gs")) &&
+      ParseTwoCharToken(state, "sr") &&
+      OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) &&
+      ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <expression> ::= <1-ary operator-name> <expression>
+//              ::= <2-ary operator-name> <expression> <expression>
+//              ::= <3-ary operator-name> <expression> <expression> <expression>
+//              ::= cl <expression>+ E
+//              ::= cv <type> <expression>      # type (expression)
+//              ::= cv <type> _ <expression>* E # type (expr-list)
+//              ::= st <type>
+//              ::= <template-param>
+//              ::= <function-param>
+//              ::= <expr-primary>
+//              ::= dt <expression> <unresolved-name> # expr.name
+//              ::= pt <expression> <unresolved-name> # expr->name
+//              ::= sp <expression>         # argument pack expansion
+//              ::= sr <type> <unqualified-name> <template-args>
+//              ::= sr <type> <unqualified-name>
+// <function-param> ::= fp <(top-level) CV-qualifiers> _
+//                  ::= fp <(top-level) CV-qualifiers> <number> _
+//                  ::= fL <number> p <(top-level) CV-qualifiers> _
+//                  ::= fL <number> p <(top-level) CV-qualifiers> <number> _
+static bool ParseExpression(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+
+  // Object/function call expression.
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Function-param expression (level 0).
+  if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) &&
+      Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Function-param expression (level 1+).
+  if (ParseTwoCharToken(state, "fL") && Optional(ParseNumber(state, nullptr)) &&
+      ParseOneCharToken(state, 'p') && Optional(ParseCVQualifiers(state)) &&
+      Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Parse the conversion expressions jointly to avoid re-parsing the <type> in
+  // their common prefix.  Parsed as:
+  // <expression> ::= cv <type> <conversion-args>
+  // <conversion-args> ::= _ <expression>* E
+  //                   ::= <expression>
+  //
+  // Also don't try ParseOperatorName after seeing "cv", since ParseOperatorName
+  // also needs to accept "cv <type>" in other contexts.
+  if (ParseTwoCharToken(state, "cv")) {
+    if (ParseType(state)) {
+      ParseState copy2 = state->parse_state;
+      if (ParseOneCharToken(state, '_') && ZeroOrMore(ParseExpression, state) &&
+          ParseOneCharToken(state, 'E')) {
+        return true;
+      }
+      state->parse_state = copy2;
+      if (ParseExpression(state)) {
+        return true;
+      }
+    }
+  } else {
+    // Parse unary, binary, and ternary operator expressions jointly, taking
+    // care not to re-parse subexpressions repeatedly. Parse like:
+    //   <expression> ::= <operator-name> <expression>
+    //                    [<one-to-two-expressions>]
+    //   <one-to-two-expressions> ::= <expression> [<expression>]
+    int arity = -1;
+    if (ParseOperatorName(state, &arity) &&
+        arity > 0 &&  // 0 arity => disabled.
+        (arity < 3 || ParseExpression(state)) &&
+        (arity < 2 || ParseExpression(state)) &&
+        (arity < 1 || ParseExpression(state))) {
+      return true;
+    }
+  }
+  state->parse_state = copy;
+
+  // sizeof type
+  if (ParseTwoCharToken(state, "st") && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Object and pointer member access expressions.
+  if ((ParseTwoCharToken(state, "dt") || ParseTwoCharToken(state, "pt")) &&
+      ParseExpression(state) && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Parameter pack expansion
+  if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return ParseUnresolvedName(state);
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+//                ::= L <type> <(value) float> E
+//                ::= L <mangled-name> E
+//                // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+//                ::= LZ <encoding> E
+//
+// Warning, subtle: the "bug" LZ production above is ambiguous with the first
+// production where <type> starts with <local-name>, which can lead to
+// exponential backtracking in two scenarios:
+//
+// - When whatever follows the E in the <local-name> in the first production is
+//   not a name, we backtrack the whole <encoding> and re-parse the whole thing.
+//
+// - When whatever follows the <local-name> in the first production is not a
+//   number and this <expr-primary> may be followed by a name, we backtrack the
+//   <name> and re-parse it.
+//
+// Moreover this ambiguity isn't always resolved -- for example, the following
+// has two different parses:
+//
+//   _ZaaILZ4aoeuE1x1EvE
+//   => operator&&<aoeu, x, E, void>
+//   => operator&&<(aoeu::x)(1), void>
+//
+// To resolve this, we just do what GCC's demangler does, and refuse to parse
+// casts to <local-name> types.
+static bool ParseExprPrimary(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+
+  // The "LZ" special case: if we see LZ, we commit to accept "LZ <encoding> E"
+  // or fail, no backtracking.
+  if (ParseTwoCharToken(state, "LZ")) {
+    if (ParseEncoding(state) && ParseOneCharToken(state, 'E')) {
+      return true;
+    }
+
+    state->parse_state = copy;
+    return false;
+  }
+
+  // The merged cast production.
+  if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+      ParseExprCastValue(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <number> or <float>, followed by 'E', as described above ParseExprPrimary.
+static bool ParseExprCastValue(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  // We have to be able to backtrack after accepting a number because we could
+  // have e.g. "7fffE", which will accept "7" as a number but then fail to find
+  // the 'E'.
+  ParseState copy = state->parse_state;
+  if (ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+//              ::= Z <(function) encoding> E s [<discriminator>]
+//
+// Parsing a common prefix of these two productions together avoids an
+// exponential blowup of backtracking.  Parse like:
+//   <local-name> := Z <encoding> E <local-name-suffix>
+//   <local-name-suffix> ::= s [<discriminator>]
+//                       ::= <name> [<discriminator>]
+
+static bool ParseLocalNameSuffix(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  if (MaybeAppend(state, "::") && ParseName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+
+  // Since we're not going to overwrite the above "::" by re-parsing the
+  // <encoding> (whose trailing '\0' byte was in the byte now holding the
+  // first ':'), we have to rollback the "::" if the <name> parse failed.
+  if (state->parse_state.append) {
+    state->out[state->parse_state.out_cur_idx - 2] = '\0';
+  }
+
+  return ParseOneCharToken(state, 's') && Optional(ParseDiscriminator(state));
+}
+
+static bool ParseLocalName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+      ParseOneCharToken(state, 'E') && ParseLocalNameSuffix(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <substitution> ::= S_
+//                ::= S <seq-id> _
+//                ::= St, etc.
+//
+// "St" is special in that it's not valid as a standalone name, and it *is*
+// allowed to precede a name without being wrapped in "N...E".  This means that
+// if we accept it on its own, we can accept "St1a" and try to parse
+// template-args, then fail and backtrack, accept "St" on its own, then "1a" as
+// an unqualified name and re-parse the same template-args.  To block this
+// exponential backtracking, we disable it with 'accept_std=false' in
+// problematic contexts.
+static bool ParseSubstitution(State *state, bool accept_std) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseTwoCharToken(state, "S_")) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Expand abbreviations like "St" => "std".
+  if (ParseOneCharToken(state, 'S')) {
+    const AbbrevPair *p;
+    for (p = kSubstitutionList; p->abbrev != nullptr; ++p) {
+      if (RemainingInput(state)[0] == p->abbrev[1] &&
+          (accept_std || p->abbrev[1] != 't')) {
+        MaybeAppend(state, "std");
+        if (p->real_name[0] != '\0') {
+          MaybeAppend(state, "::");
+          MaybeAppend(state, p->real_name);
+        }
+        ++state->parse_state.mangled_idx;
+        return true;
+      }
+    }
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// Parse <mangled-name>, optionally followed by either a function-clone suffix
+// or version suffix.  Returns true only if all of "mangled_cur" was consumed.
+static bool ParseTopLevelMangledName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseMangledName(state)) {
+    if (RemainingInput(state)[0] != '\0') {
+      // Drop trailing function clone suffix, if any.
+      if (IsFunctionCloneSuffix(RemainingInput(state))) {
+        return true;
+      }
+      // Append trailing version suffix if any.
+      // ex. _Z3foo@@GLIBCXX_3.4
+      if (RemainingInput(state)[0] == '@') {
+        MaybeAppend(state, RemainingInput(state));
+        return true;
+      }
+      return false;  // Unconsumed suffix.
+    }
+    return true;
+  }
+  return false;
+}
+
+static bool Overflowed(const State *state) {
+  return state->parse_state.out_cur_idx >= state->out_end_idx;
+}
+
+// The demangler entry point.
+bool Demangle(const char *mangled, char *out, int out_size) {
+  State state;
+  InitState(&state, mangled, out, out_size);
+  return ParseTopLevelMangledName(&state) && !Overflowed(&state);
+}
+
+}  // namespace debugging_internal
+}  // namespace absl
diff --git a/absl/debugging/internal/demangle.h b/absl/debugging/internal/demangle.h
new file mode 100644
index 0000000..2e75564
--- /dev/null
+++ b/absl/debugging/internal/demangle.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Abseil 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.
+
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+//
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces.  We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling.  More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments.  It just skips them.  However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name  | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv         | f()           | f()
+// | _Z1fi         | f()           | f(int)
+// | _Z3foo3bar    | foo()         | foo(bar)
+// | _Z1fIiEvi     | f<>()         | void f<int>(int)
+// | _ZN1N1fE      | N::f          | N::f
+// | _ZN3Foo3BarEv | Foo::Bar()    | Foo::Bar()
+// | _Zrm1XS_"     | operator%()   | operator%(X, X)
+// | _ZN3FooC1Ev   | Foo::Foo()    | Foo::Foo()
+// | _Z1fSs        | f()           | f(std::basic_string<char,
+// |               |               |   std::char_traits<char>,
+// |               |               |   std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
+#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
+
+namespace absl {
+namespace debugging_internal {
+
+// Demangle `mangled`.  On success, return true and write the
+// demangled symbol name to `out`.  Otherwise, return false.
+// `out` is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
new file mode 100644
index 0000000..b9d9008
--- /dev/null
+++ b/absl/debugging/internal/demangle_test.cc
@@ -0,0 +1,191 @@
+// Copyright 2018 The Abseil 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 "absl/debugging/internal/demangle.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/internal/stack_consumption.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+namespace debugging_internal {
+namespace {
+
+// A wrapper function for Demangle() to make the unit test simple.
+static const char *DemangleIt(const char * const mangled) {
+  static char demangled[4096];
+  if (Demangle(mangled, demangled, sizeof(demangled))) {
+    return demangled;
+  } else {
+    return mangled;
+  }
+}
+
+// Test corner cases of bounary conditions.
+TEST(Demangle, CornerCases) {
+  char tmp[10];
+  EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp)));
+  // sizeof("foobar()") == 9
+  EXPECT_STREQ("foobar()", tmp);
+  EXPECT_TRUE(Demangle("_Z6foobarv", tmp, 9));
+  EXPECT_STREQ("foobar()", tmp);
+  EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 8));  // Not enough.
+  EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 1));
+  EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 0));
+  EXPECT_FALSE(Demangle("_Z6foobarv", nullptr, 0));  // Should not cause SEGV.
+  EXPECT_FALSE(Demangle("_Z1000000", tmp, 9));
+}
+
+// Test handling of functions suffixed with .clone.N, which is used
+// by GCC 4.5.x (and our locally-modified version of GCC 4.4.x), and
+// .constprop.N and .isra.N, which are used by GCC 4.6.x.  These
+// suffixes are used to indicate functions which have been cloned
+// during optimization.  We ignore these suffixes.
+TEST(Demangle, Clones) {
+  char tmp[20];
+  EXPECT_TRUE(Demangle("_ZL3Foov", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  EXPECT_TRUE(Demangle("_ZL3Foov.clone.3", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  EXPECT_TRUE(Demangle("_ZL3Foov.constprop.80", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  EXPECT_TRUE(Demangle("_ZL3Foov.isra.18", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp)));
+  EXPECT_STREQ("Foo()", tmp);
+  // Invalid (truncated), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
+  // Invalid (.clone. not followed by number), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
+  // Invalid (.clone. followed by non-number), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
+  // Invalid (.constprop. not followed by number), should not demangle.
+  EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
+}
+
+// Tests that verify that Demangle footprint is within some limit.
+// They are not to be run under sanitizers as the sanitizers increase
+// stack consumption by about 4x.
+#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
+    !ADDRESS_SANITIZER && !MEMORY_SANITIZER && !THREAD_SANITIZER
+
+static const char *g_mangled;
+static char g_demangle_buffer[4096];
+static char *g_demangle_result;
+
+static void DemangleSignalHandler(int signo) {
+  if (Demangle(g_mangled, g_demangle_buffer, sizeof(g_demangle_buffer))) {
+    g_demangle_result = g_demangle_buffer;
+  } else {
+    g_demangle_result = nullptr;
+  }
+}
+
+// Call Demangle and figure out the stack footprint of this call.
+static const char *DemangleStackConsumption(const char *mangled,
+                                            int *stack_consumed) {
+  g_mangled = mangled;
+  *stack_consumed = GetSignalHandlerStackConsumption(DemangleSignalHandler);
+  ABSL_RAW_LOG(INFO, "Stack consumption of Demangle: %d", *stack_consumed);
+  return g_demangle_result;
+}
+
+// Demangle stack consumption should be within 8kB for simple mangled names
+// with some level of nesting. With alternate signal stack we have 64K,
+// but some signal handlers run on thread stack, and could have arbitrarily
+// little space left (so we don't want to make this number too large).
+const int kStackConsumptionUpperLimit = 8192;
+
+// Returns a mangled name nested to the given depth.
+static std::string NestedMangledName(int depth) {
+  std::string mangled_name = "_Z1a";
+  if (depth > 0) {
+    mangled_name += "IXL";
+    mangled_name += NestedMangledName(depth - 1);
+    mangled_name += "EEE";
+  }
+  return mangled_name;
+}
+
+TEST(Demangle, DemangleStackConsumption) {
+  // Measure stack consumption of Demangle for nested mangled names of varying
+  // depth.  Since Demangle is implemented as a recursive descent parser,
+  // stack consumption will grow as the nesting depth increases.  By measuring
+  // the stack consumption for increasing depths, we can see the growing
+  // impact of any stack-saving changes made to the code for Demangle.
+  int stack_consumed = 0;
+
+  const char *demangled =
+      DemangleStackConsumption("_Z6foobarv", &stack_consumed);
+  EXPECT_STREQ("foobar()", demangled);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
+
+  const std::string nested_mangled_name0 = NestedMangledName(0);
+  demangled = DemangleStackConsumption(nested_mangled_name0.c_str(),
+                                       &stack_consumed);
+  EXPECT_STREQ("a", demangled);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
+
+  const std::string nested_mangled_name1 = NestedMangledName(1);
+  demangled = DemangleStackConsumption(nested_mangled_name1.c_str(),
+                                       &stack_consumed);
+  EXPECT_STREQ("a<>", demangled);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
+
+  const std::string nested_mangled_name2 = NestedMangledName(2);
+  demangled = DemangleStackConsumption(nested_mangled_name2.c_str(),
+                                       &stack_consumed);
+  EXPECT_STREQ("a<>", demangled);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
+
+  const std::string nested_mangled_name3 = NestedMangledName(3);
+  demangled = DemangleStackConsumption(nested_mangled_name3.c_str(),
+                                       &stack_consumed);
+  EXPECT_STREQ("a<>", demangled);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
+}
+
+#endif  // Stack consumption tests
+
+static void TestOnInput(const char* input) {
+  static const int kOutSize = 1048576;
+  auto out = absl::make_unique<char[]>(kOutSize);
+  Demangle(input, out.get(), kOutSize);
+}
+
+TEST(DemangleRegression, NegativeLength) {
+  TestOnInput("_ZZn4");
+}
+TEST(DemangleRegression, DeeplyNestedArrayType) {
+  const int depth = 100000;
+  std::string data = "_ZStI";
+  data.reserve(data.size() + 3 * depth + 1);
+  for (int i = 0; i < depth; i++) {
+    data += "A1_";
+  }
+  TestOnInput(data.c_str());
+}
+
+}  // namespace
+}  // namespace debugging_internal
+}  // namespace absl
diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc
new file mode 100644
index 0000000..3f747e7
--- /dev/null
+++ b/absl/debugging/internal/elf_mem_image.cc
@@ -0,0 +1,380 @@
+// Copyright 2017 The Abseil 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.
+
+// Allow dynamic symbol lookup in an in-memory Elf image.
+//
+
+#include "absl/debugging/internal/elf_mem_image.h"
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE  // defined in elf_mem_image.h
+
+#include <string.h>
+#include <cassert>
+#include <cstddef>
+#include "absl/base/internal/raw_logging.h"
+
+// From binutils/include/elf/common.h (this doesn't appear to be documented
+// anywhere else).
+//
+//   /* This flag appears in a Versym structure.  It means that the symbol
+//      is hidden, and is only visible with an explicit version number.
+//      This is a GNU extension.  */
+//   #define VERSYM_HIDDEN           0x8000
+//
+//   /* This is the mask for the rest of the Versym information.  */
+//   #define VERSYM_VERSION          0x7fff
+
+#define VERSYM_VERSION 0x7fff
+
+namespace absl {
+namespace debugging_internal {
+
+namespace {
+
+#if __WORDSIZE == 32
+const int kElfClass = ELFCLASS32;
+int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); }
+int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); }
+#elif __WORDSIZE == 64
+const int kElfClass = ELFCLASS64;
+int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); }
+int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); }
+#else
+const int kElfClass = -1;
+int ElfBind(const ElfW(Sym) *) {
+  ABSL_RAW_LOG(FATAL, "Unexpected word size");
+  return 0;
+}
+int ElfType(const ElfW(Sym) *) {
+  ABSL_RAW_LOG(FATAL, "Unexpected word size");
+  return 0;
+}
+#endif
+
+// Extract an element from one of the ELF tables, cast it to desired type.
+// This is just a simple arithmetic and a glorified cast.
+// Callers are responsible for bounds checking.
+template <typename T>
+const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset,
+                         ElfW(Word) element_size, size_t index) {
+  return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
+                                    + table_offset
+                                    + index * element_size);
+}
+
+}  // namespace
+
+// The value of this variable doesn't matter; it's used only for its
+// unique address.
+const int ElfMemImage::kInvalidBaseSentinel = 0;
+
+ElfMemImage::ElfMemImage(const void *base) {
+  ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer");
+  Init(base);
+}
+
+int ElfMemImage::GetNumSymbols() const {
+  if (!hash_) {
+    return 0;
+  }
+  // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
+  return hash_[1];
+}
+
+const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
+  ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
+  return dynsym_ + index;
+}
+
+const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
+  ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
+  return versym_ + index;
+}
+
+const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
+  ABSL_RAW_CHECK(index < ehdr_->e_phnum, "index out of range");
+  return GetTableElement<ElfW(Phdr)>(ehdr_,
+                                     ehdr_->e_phoff,
+                                     ehdr_->e_phentsize,
+                                     index);
+}
+
+const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
+  ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
+  return dynstr_ + offset;
+}
+
+const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
+  if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
+    // Symbol corresponds to "special" (e.g. SHN_ABS) section.
+    return reinterpret_cast<const void *>(sym->st_value);
+  }
+  ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
+  return GetTableElement<char>(ehdr_, 0, 1, sym->st_value - link_base_);
+}
+
+const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
+  ABSL_RAW_CHECK(0 <= index && static_cast<size_t>(index) <= verdefnum_,
+                 "index out of range");
+  const ElfW(Verdef) *version_definition = verdef_;
+  while (version_definition->vd_ndx < index && version_definition->vd_next) {
+    const char *const version_definition_as_char =
+        reinterpret_cast<const char *>(version_definition);
+    version_definition =
+        reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
+                                               version_definition->vd_next);
+  }
+  return version_definition->vd_ndx == index ? version_definition : nullptr;
+}
+
+const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
+    const ElfW(Verdef) *verdef) const {
+  return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
+}
+
+const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
+  ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
+  return dynstr_ + offset;
+}
+
+void ElfMemImage::Init(const void *base) {
+  ehdr_      = nullptr;
+  dynsym_    = nullptr;
+  dynstr_    = nullptr;
+  versym_    = nullptr;
+  verdef_    = nullptr;
+  hash_      = nullptr;
+  strsize_   = 0;
+  verdefnum_ = 0;
+  link_base_ = ~0L;  // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
+  if (!base) {
+    return;
+  }
+  const char *const base_as_char = reinterpret_cast<const char *>(base);
+  if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
+      base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
+    assert(false);
+    return;
+  }
+  int elf_class = base_as_char[EI_CLASS];
+  if (elf_class != kElfClass) {
+    assert(false);
+    return;
+  }
+  switch (base_as_char[EI_DATA]) {
+    case ELFDATA2LSB: {
+      if (__LITTLE_ENDIAN != __BYTE_ORDER) {
+        assert(false);
+        return;
+      }
+      break;
+    }
+    case ELFDATA2MSB: {
+      if (__BIG_ENDIAN != __BYTE_ORDER) {
+        assert(false);
+        return;
+      }
+      break;
+    }
+    default: {
+      assert(false);
+      return;
+    }
+  }
+
+  ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
+  const ElfW(Phdr) *dynamic_program_header = nullptr;
+  for (int i = 0; i < ehdr_->e_phnum; ++i) {
+    const ElfW(Phdr) *const program_header = GetPhdr(i);
+    switch (program_header->p_type) {
+      case PT_LOAD:
+        if (!~link_base_) {
+          link_base_ = program_header->p_vaddr;
+        }
+        break;
+      case PT_DYNAMIC:
+        dynamic_program_header = program_header;
+        break;
+    }
+  }
+  if (!~link_base_ || !dynamic_program_header) {
+    assert(false);
+    // Mark this image as not present. Can not recur infinitely.
+    Init(nullptr);
+    return;
+  }
+  ptrdiff_t relocation =
+      base_as_char - reinterpret_cast<const char *>(link_base_);
+  ElfW(Dyn) *dynamic_entry =
+      reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
+                                    relocation);
+  for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
+    const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation;
+    switch (dynamic_entry->d_tag) {
+      case DT_HASH:
+        hash_ = reinterpret_cast<ElfW(Word) *>(value);
+        break;
+      case DT_SYMTAB:
+        dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
+        break;
+      case DT_STRTAB:
+        dynstr_ = reinterpret_cast<const char *>(value);
+        break;
+      case DT_VERSYM:
+        versym_ = reinterpret_cast<ElfW(Versym) *>(value);
+        break;
+      case DT_VERDEF:
+        verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
+        break;
+      case DT_VERDEFNUM:
+        verdefnum_ = dynamic_entry->d_un.d_val;
+        break;
+      case DT_STRSZ:
+        strsize_ = dynamic_entry->d_un.d_val;
+        break;
+      default:
+        // Unrecognized entries explicitly ignored.
+        break;
+    }
+  }
+  if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
+      !verdef_ || !verdefnum_ || !strsize_) {
+    assert(false);  // invalid VDSO
+    // Mark this image as not present. Can not recur infinitely.
+    Init(nullptr);
+    return;
+  }
+}
+
+bool ElfMemImage::LookupSymbol(const char *name,
+                               const char *version,
+                               int type,
+                               SymbolInfo *info_out) const {
+  for (const SymbolInfo& info : *this) {
+    if (strcmp(info.name, name) == 0 && strcmp(info.version, version) == 0 &&
+        ElfType(info.symbol) == type) {
+      if (info_out) {
+        *info_out = info;
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ElfMemImage::LookupSymbolByAddress(const void *address,
+                                        SymbolInfo *info_out) const {
+  for (const SymbolInfo& info : *this) {
+    const char *const symbol_start =
+        reinterpret_cast<const char *>(info.address);
+    const char *const symbol_end = symbol_start + info.symbol->st_size;
+    if (symbol_start <= address && address < symbol_end) {
+      if (info_out) {
+        // Client wants to know details for that symbol (the usual case).
+        if (ElfBind(info.symbol) == STB_GLOBAL) {
+          // Strong symbol; just return it.
+          *info_out = info;
+          return true;
+        } else {
+          // Weak or local. Record it, but keep looking for a strong one.
+          *info_out = info;
+        }
+      } else {
+        // Client only cares if there is an overlapping symbol.
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
+    : index_(index), image_(image) {
+}
+
+const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
+  return &info_;
+}
+
+const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
+  return info_;
+}
+
+bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
+  return this->image_ == rhs.image_ && this->index_ == rhs.index_;
+}
+
+bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
+  return !(*this == rhs);
+}
+
+ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
+  this->Update(1);
+  return *this;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::begin() const {
+  SymbolIterator it(this, 0);
+  it.Update(0);
+  return it;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::end() const {
+  return SymbolIterator(this, GetNumSymbols());
+}
+
+void ElfMemImage::SymbolIterator::Update(int increment) {
+  const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
+  ABSL_RAW_CHECK(image->IsPresent() || increment == 0, "");
+  if (!image->IsPresent()) {
+    return;
+  }
+  index_ += increment;
+  if (index_ >= image->GetNumSymbols()) {
+    index_ = image->GetNumSymbols();
+    return;
+  }
+  const ElfW(Sym)    *symbol = image->GetDynsym(index_);
+  const ElfW(Versym) *version_symbol = image->GetVersym(index_);
+  ABSL_RAW_CHECK(symbol && version_symbol, "");
+  const char *const symbol_name = image->GetDynstr(symbol->st_name);
+  const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
+  const ElfW(Verdef) *version_definition = nullptr;
+  const char *version_name = "";
+  if (symbol->st_shndx == SHN_UNDEF) {
+    // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
+    // version_index could well be greater than verdefnum_, so calling
+    // GetVerdef(version_index) may trigger assertion.
+  } else {
+    version_definition = image->GetVerdef(version_index);
+  }
+  if (version_definition) {
+    // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
+    // optional 2nd if the version has a parent.
+    ABSL_RAW_CHECK(
+        version_definition->vd_cnt == 1 || version_definition->vd_cnt == 2,
+        "wrong number of entries");
+    const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
+    version_name = image->GetVerstr(version_aux->vda_name);
+  }
+  info_.name    = symbol_name;
+  info_.version = version_name;
+  info_.address = image->GetSymAddr(symbol);
+  info_.symbol  = symbol;
+}
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
new file mode 100644
index 0000000..3b57726
--- /dev/null
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2017 The Abseil 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.
+ */
+
+// Allow dynamic symbol lookup for in-memory Elf images.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
+#define ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
+
+// Including this will define the __GLIBC__ macro if glibc is being
+// used.
+#include <climits>
+
+// Maybe one day we can rewrite this file not to require the elf
+// symbol extensions in glibc, but for right now we need them.
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+#error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set
+#endif
+
+#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
+    !defined(__asmjs__) && !defined(__wasm__)
+#define ABSL_HAVE_ELF_MEM_IMAGE 1
+#endif
+
+#if ABSL_HAVE_ELF_MEM_IMAGE
+
+#include <link.h>  // for ElfW
+
+namespace absl {
+namespace debugging_internal {
+
+// An in-memory ELF image (may not exist on disk).
+class ElfMemImage {
+ private:
+  // Sentinel: there could never be an elf image at &kInvalidBaseSentinel.
+  static const int kInvalidBaseSentinel;
+
+ public:
+  // Sentinel: there could never be an elf image at this address.
+  static constexpr const void *const kInvalidBase =
+    static_cast<const void*>(&kInvalidBaseSentinel);
+
+  // Information about a single vdso symbol.
+  // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
+  // Do not free() them or modify through them.
+  struct SymbolInfo {
+    const char      *name;      // E.g. "__vdso_getcpu"
+    const char      *version;   // E.g. "LINUX_2.6", could be ""
+                                // for unversioned symbol.
+    const void      *address;   // Relocated symbol address.
+    const ElfW(Sym) *symbol;    // Symbol in the dynamic symbol table.
+  };
+
+  // Supports iteration over all dynamic symbols.
+  class SymbolIterator {
+   public:
+    friend class ElfMemImage;
+    const SymbolInfo *operator->() const;
+    const SymbolInfo &operator*() const;
+    SymbolIterator& operator++();
+    bool operator!=(const SymbolIterator &rhs) const;
+    bool operator==(const SymbolIterator &rhs) const;
+   private:
+    SymbolIterator(const void *const image, int index);
+    void Update(int incr);
+    SymbolInfo info_;
+    int index_;
+    const void *const image_;
+  };
+
+
+  explicit ElfMemImage(const void *base);
+  void                 Init(const void *base);
+  bool                 IsPresent() const { return ehdr_ != nullptr; }
+  const ElfW(Phdr)*    GetPhdr(int index) const;
+  const ElfW(Sym)*     GetDynsym(int index) const;
+  const ElfW(Versym)*  GetVersym(int index) const;
+  const ElfW(Verdef)*  GetVerdef(int index) const;
+  const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
+  const char*          GetDynstr(ElfW(Word) offset) const;
+  const void*          GetSymAddr(const ElfW(Sym) *sym) const;
+  const char*          GetVerstr(ElfW(Word) offset) const;
+  int                  GetNumSymbols() const;
+
+  SymbolIterator begin() const;
+  SymbolIterator end() const;
+
+  // Look up versioned dynamic symbol in the image.
+  // Returns false if image is not present, or doesn't contain given
+  // symbol/version/type combination.
+  // If info_out is non-null, additional details are filled in.
+  bool LookupSymbol(const char *name, const char *version,
+                    int symbol_type, SymbolInfo *info_out) const;
+
+  // Find info about symbol (if any) which overlaps given address.
+  // Returns true if symbol was found; false if image isn't present
+  // or doesn't have a symbol overlapping given address.
+  // If info_out is non-null, additional details are filled in.
+  bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+ private:
+  const ElfW(Ehdr) *ehdr_;
+  const ElfW(Sym) *dynsym_;
+  const ElfW(Versym) *versym_;
+  const ElfW(Verdef) *verdef_;
+  const ElfW(Word) *hash_;
+  const char *dynstr_;
+  size_t strsize_;
+  size_t verdefnum_;
+  ElfW(Addr) link_base_;     // Link-time base (p_vaddr of first PT_LOAD).
+};
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_ELF_MEM_IMAGE
+
+#endif  // ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
new file mode 100644
index 0000000..8434709
--- /dev/null
+++ b/absl/debugging/internal/examine_stack.cc
@@ -0,0 +1,149 @@
+//
+// Copyright 2018 The Abseil 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 "absl/debugging/internal/examine_stack.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include <csignal>
+#include <cstdio>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+
+namespace absl {
+namespace debugging_internal {
+
+// Returns the program counter from signal context, nullptr if
+// unknown. vuc is a ucontext_t*. We use void* to avoid the use of
+// ucontext_t on non-POSIX systems.
+void* GetProgramCounter(void* vuc) {
+#ifdef __linux__
+  if (vuc != nullptr) {
+    ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__arm__)
+    return reinterpret_cast<void*>(context->uc_mcontext.arm_pc);
+#elif defined(__i386__)
+    if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
+      return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]);
+#elif defined(__mips__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__powerpc64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
+#elif defined(__powerpc__)
+    return reinterpret_cast<void*>(context->uc_mcontext.regs->nip);
+#elif defined(__x86_64__)
+    if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
+      return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
+#else
+#error "Undefined Architecture."
+#endif
+  }
+#elif defined(__akaros__)
+  auto* ctx = reinterpret_cast<struct user_context*>(vuc);
+  return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
+#endif
+  static_cast<void>(vuc);
+  return nullptr;
+}
+
+// The %p field width for printf() functions is two characters per byte,
+// and two extra for the leading "0x".
+static constexpr int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
+
+// Print a program counter, its stack frame size, and its symbol name.
+// Note that there is a separate symbolize_pc argument. Return addresses may be
+// at the end of the function, and this allows the caller to back up from pc if
+// appropriate.
+static void DumpPCAndFrameSizeAndSymbol(void (*writerfn)(const char*, void*),
+                                        void* writerfn_arg, void* pc,
+                                        void* symbolize_pc, int framesize,
+                                        const char* const prefix) {
+  char tmp[1024];
+  const char* symbol = "(unknown)";
+  if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp))) {
+    symbol = tmp;
+  }
+  char buf[1024];
+  if (framesize <= 0) {
+    snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)  %s\n", prefix,
+             kPrintfPointerFieldWidth, pc, symbol);
+  } else {
+    snprintf(buf, sizeof(buf), "%s@ %*p  %9d  %s\n", prefix,
+             kPrintfPointerFieldWidth, pc, framesize, symbol);
+  }
+  writerfn(buf, writerfn_arg);
+}
+
+// Print a program counter and the corresponding stack frame size.
+static void DumpPCAndFrameSize(void (*writerfn)(const char*, void*),
+                               void* writerfn_arg, void* pc, int framesize,
+                               const char* const prefix) {
+  char buf[100];
+  if (framesize <= 0) {
+    snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)\n", prefix,
+             kPrintfPointerFieldWidth, pc);
+  } else {
+    snprintf(buf, sizeof(buf), "%s@ %*p  %9d\n", prefix,
+             kPrintfPointerFieldWidth, pc, framesize);
+  }
+  writerfn(buf, writerfn_arg);
+}
+
+void DumpPCAndFrameSizesAndStackTrace(
+    void* pc, void* const stack[], int frame_sizes[], int depth,
+    int min_dropped_frames, bool symbolize_stacktrace,
+    void (*writerfn)(const char*, void*), void* writerfn_arg) {
+  if (pc != nullptr) {
+    // We don't know the stack frame size for PC, use 0.
+    if (symbolize_stacktrace) {
+      DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, pc, pc, 0, "PC: ");
+    } else {
+      DumpPCAndFrameSize(writerfn, writerfn_arg, pc, 0, "PC: ");
+    }
+  }
+  for (int i = 0; i < depth; i++) {
+    if (symbolize_stacktrace) {
+      // Pass the previous address of pc as the symbol address because pc is a
+      // return address, and an overrun may occur when the function ends with a
+      // call to a function annotated noreturn (e.g. CHECK). Note that we don't
+      // do this for pc above, as the adjustment is only correct for return
+      // addresses.
+      DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, stack[i],
+                                  reinterpret_cast<char*>(stack[i]) - 1,
+                                  frame_sizes[i], "    ");
+    } else {
+      DumpPCAndFrameSize(writerfn, writerfn_arg, stack[i], frame_sizes[i],
+                         "    ");
+    }
+  }
+  if (min_dropped_frames > 0) {
+    char buf[100];
+    snprintf(buf, sizeof(buf), "    @ ... and at least %d more frames\n",
+             min_dropped_frames);
+    writerfn(buf, writerfn_arg);
+  }
+}
+
+}  // namespace debugging_internal
+}  // namespace absl
diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h
new file mode 100644
index 0000000..a16c03b
--- /dev/null
+++ b/absl/debugging/internal/examine_stack.h
@@ -0,0 +1,38 @@
+//
+// Copyright 2018 The Abseil 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 ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
+#define ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
+
+namespace absl {
+namespace debugging_internal {
+
+// Returns the program counter from signal context, or nullptr if
+// unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of
+// ucontext_t on non-POSIX systems.
+void* GetProgramCounter(void* vuc);
+
+// Uses `writerfn` to dump the program counter, stack trace, and stack
+// frame sizes.
+void DumpPCAndFrameSizesAndStackTrace(
+    void* pc, void* const stack[], int frame_sizes[], int depth,
+    int min_dropped_frames, bool symbolize_stacktrace,
+    void (*writerfn)(const char*, void*), void* writerfn_arg);
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc
new file mode 100644
index 0000000..2b3b972
--- /dev/null
+++ b/absl/debugging/internal/stack_consumption.cc
@@ -0,0 +1,172 @@
+//
+// Copyright 2018 The Abseil 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 "absl/debugging/internal/stack_consumption.h"
+
+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+#include <signal.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace debugging_internal {
+namespace {
+
+// This code requires that we know the direction in which the stack
+// grows. It is commonly believed that this can be detected by putting
+// a variable on the stack and then passing its address to a function
+// that compares the address of this variable to the address of a
+// variable on the function's own stack. However, this is unspecified
+// behavior in C++: If two pointers p and q of the same type point to
+// different objects that are not members of the same object or
+// elements of the same array or to different functions, or if only
+// one of them is null, the results of p<q, p>q, p<=q, and p>=q are
+// unspecified. Therefore, instead we hardcode the direction of the
+// stack on platforms we know about.
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__)
+constexpr bool kStackGrowsDown = true;
+#else
+#error Need to define kStackGrowsDown
+#endif
+
+// To measure the stack footprint of some code, we create a signal handler
+// (for SIGUSR2 say) that exercises this code on an alternate stack. This
+// alternate stack is initialized to some known pattern (0x55, 0x55, 0x55,
+// ...). We then self-send this signal, and after the signal handler returns,
+// look at the alternate stack buffer to see what portion has been touched.
+//
+// This trick gives us the the stack footprint of the signal handler.  But the
+// signal handler, even before the code for it is exercised, consumes some
+// stack already. We however only want the stack usage of the code inside the
+// signal handler. To measure this accurately, we install two signal handlers:
+// one that does nothing and just returns, and the user-provided signal
+// handler. The difference between the stack consumption of these two signals
+// handlers should give us the stack foorprint of interest.
+
+void EmptySignalHandler(int) {}
+
+// This is arbitrary value, and could be increase further, at the cost of
+// memset()ting it all to known sentinel value.
+constexpr int kAlternateStackSize = 64 << 10;  // 64KiB
+
+constexpr int kSafetyMargin = 32;
+constexpr char kAlternateStackFillValue = 0x55;
+
+// These helper functions look at the alternate stack buffer, and figure
+// out what portion of this buffer has been touched - this is the stack
+// consumption of the signal handler running on this alternate stack.
+// This function will return -1 if the alternate stack buffer has not been
+// touched. It will abort the program if the buffer has overflowed or is about
+// to overflow.
+int GetStackConsumption(const void* const altstack) {
+  const char* begin;
+  int increment;
+  if (kStackGrowsDown) {
+    begin = reinterpret_cast<const char*>(altstack);
+    increment = 1;
+  } else {
+    begin = reinterpret_cast<const char*>(altstack) + kAlternateStackSize - 1;
+    increment = -1;
+  }
+
+  for (int usage_count = kAlternateStackSize; usage_count > 0; --usage_count) {
+    if (*begin != kAlternateStackFillValue) {
+      ABSL_RAW_CHECK(usage_count <= kAlternateStackSize - kSafetyMargin,
+                     "Buffer has overflowed or is about to overflow");
+      return usage_count;
+    }
+    begin += increment;
+  }
+
+  ABSL_RAW_LOG(FATAL, "Unreachable code");
+  return -1;
+}
+
+}  // namespace
+
+int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
+  // The alt-signal-stack cannot be heap allocated because there is a
+  // bug in glibc-2.2 where some signal handler setup code looks at the
+  // current stack pointer to figure out what thread is currently running.
+  // Therefore, the alternate stack must be allocated from the main stack
+  // itself.
+  void* altstack = mmap(nullptr, kAlternateStackSize, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ABSL_RAW_CHECK(altstack != MAP_FAILED, "mmap() failed");
+
+  // Set up the alt-signal-stack (and save the older one).
+  stack_t sigstk;
+  memset(&sigstk, 0, sizeof(sigstk));
+  stack_t old_sigstk;
+  sigstk.ss_sp = altstack;
+  sigstk.ss_size = kAlternateStackSize;
+  sigstk.ss_flags = 0;
+  ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
+                 "sigaltstack() failed");
+
+  // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  struct sigaction old_sa1, old_sa2;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_ONSTACK;
+
+  // SIGUSR1 maps to EmptySignalHandler.
+  sa.sa_handler = EmptySignalHandler;
+  ABSL_RAW_CHECK(sigaction(SIGUSR1, &sa, &old_sa1) == 0, "sigaction() failed");
+
+  // SIGUSR2 maps to signal_handler.
+  sa.sa_handler = signal_handler;
+  ABSL_RAW_CHECK(sigaction(SIGUSR2, &sa, &old_sa2) == 0, "sigaction() failed");
+
+  // Send SIGUSR1 signal and measure the stack consumption of the empty
+  // signal handler.
+  // The first signal might use more stack space. Run once and ignore the
+  // results to get that out of the way.
+  ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
+
+  memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
+  ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
+  int base_stack_consumption = GetStackConsumption(altstack);
+
+  // Send SIGUSR2 signal and measure the stack consumption of signal_handler.
+  ABSL_RAW_CHECK(kill(getpid(), SIGUSR2) == 0, "kill() failed");
+  int signal_handler_stack_consumption = GetStackConsumption(altstack);
+
+  // Now restore the old alt-signal-stack and signal handlers.
+  ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
+                 "sigaltstack() failed");
+  ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
+                 "sigaction() failed");
+  ABSL_RAW_CHECK(sigaction(SIGUSR2, &old_sa2, nullptr) == 0,
+                 "sigaction() failed");
+
+  ABSL_RAW_CHECK(munmap(altstack, kAlternateStackSize) == 0, "munmap() failed");
+  if (signal_handler_stack_consumption != -1 && base_stack_consumption != -1) {
+    return signal_handler_stack_consumption - base_stack_consumption;
+  }
+  return -1;
+}
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h
new file mode 100644
index 0000000..4c5fa0f
--- /dev/null
+++ b/absl/debugging/internal/stack_consumption.h
@@ -0,0 +1,45 @@
+//
+// Copyright 2018 The Abseil 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.
+
+// Helper function for measuring stack consumption of signal handlers.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
+#define ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
+
+// The code in this module is not portable.
+// Use this feature test macro to detect its availability.
+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+#error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
+#elif !defined(__APPLE__) && !defined(_WIN32) && \
+    (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))
+#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
+
+namespace absl {
+namespace debugging_internal {
+
+// Returns the stack consumption in bytes for the code exercised by
+// signal_handler.  To measure stack consumption, signal_handler is registered
+// as a signal handler, so the code that it exercises must be async-signal
+// safe.  The argument of signal_handler is an implementation detail of signal
+// handlers and should ignored by the code for signal_handler.  Use global
+// variables to pass information between your test code and signal_handler.
+int GetSignalHandlerStackConsumption(void (*signal_handler)(int));
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
diff --git a/absl/debugging/internal/stack_consumption_test.cc b/absl/debugging/internal/stack_consumption_test.cc
new file mode 100644
index 0000000..5ce3846
--- /dev/null
+++ b/absl/debugging/internal/stack_consumption_test.cc
@@ -0,0 +1,48 @@
+//
+// Copyright 2018 The Abseil 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 "absl/debugging/internal/stack_consumption.h"
+
+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+#include <string.h>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace debugging_internal {
+namespace {
+
+static void SimpleSignalHandler(int signo) {
+  char buf[100];
+  memset(buf, 'a', sizeof(buf));
+
+  // Never true, but prevents compiler from optimizing buf out.
+  if (signo == 0) {
+    ABSL_RAW_LOG(INFO, "%p", static_cast<void*>(buf));
+  }
+}
+
+TEST(SignalHandlerStackConsumptionTest, MeasuresStackConsumption) {
+  // Our handler should consume reasonable number of bytes.
+  EXPECT_GE(GetSignalHandlerStackConsumption(SimpleSignalHandler), 100);
+}
+
+}  // namespace
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
new file mode 100644
index 0000000..7ed6b3e
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -0,0 +1,190 @@
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
+
+// Generate stack tracer for aarch64
+
+#if defined(__linux__)
+#include <sys/mman.h>
+#include <ucontext.h>
+#include <unistd.h>
+#endif
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include <iostream>
+
+#include "absl/base/attributes.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h"  // a no-op on non-elf or non-glibc systems
+#include "absl/debugging/stacktrace.h"
+
+static const uintptr_t kUnknownFrameSize = 0;
+
+#if defined(__linux__)
+// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
+static const unsigned char* GetKernelRtSigreturnAddress() {
+  constexpr uintptr_t kImpossibleAddress = 1;
+  ABSL_CONST_INIT static std::atomic<uintptr_t> memoized{kImpossibleAddress};
+  uintptr_t address = memoized.load(std::memory_order_relaxed);
+  if (address != kImpossibleAddress) {
+    return reinterpret_cast<const unsigned char*>(address);
+  }
+
+  address = reinterpret_cast<uintptr_t>(nullptr);
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+  absl::debugging_internal::VDSOSupport vdso;
+  if (vdso.IsPresent()) {
+    absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
+    if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
+                           &symbol_info) ||
+        symbol_info.address == nullptr) {
+      // Unexpected: VDSO is present, yet the expected symbol is missing
+      // or null.
+      assert(false && "VDSO is present, but doesn't have expected symbol");
+    } else {
+      if (reinterpret_cast<uintptr_t>(symbol_info.address) !=
+          kImpossibleAddress) {
+        address = reinterpret_cast<uintptr_t>(symbol_info.address);
+      } else {
+        assert(false && "VDSO returned invalid address");
+      }
+    }
+  }
+#endif
+
+  memoized.store(address, std::memory_order_relaxed);
+  return reinterpret_cast<const unsigned char*>(address);
+}
+#endif  // __linux__
+
+// Compute the size of a stack frame in [low..high).  We assume that
+// low < high.  Return size of kUnknownFrameSize.
+template<typename T>
+static inline uintptr_t ComputeStackFrameSize(const T* low,
+                                              const T* high) {
+  const char* low_char_ptr = reinterpret_cast<const char *>(low);
+  const char* high_char_ptr = reinterpret_cast<const char *>(high);
+  return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize;
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
+static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
+  void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
+  bool check_frame_size = true;
+
+#if defined(__linux__)
+  if (WITH_CONTEXT && uc != nullptr) {
+    // Check to see if next frame's return address is __kernel_rt_sigreturn.
+    if (old_frame_pointer[1] == GetKernelRtSigreturnAddress()) {
+      const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+      // old_frame_pointer[0] is not suitable for unwinding, look at
+      // ucontext to discover frame pointer before signal.
+      void **const pre_signal_frame_pointer =
+          reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]);
+
+      // Check that alleged frame pointer is actually readable. This is to
+      // prevent "double fault" in case we hit the first fault due to e.g.
+      // stack corruption.
+      if (!absl::debugging_internal::AddressIsReadable(
+              pre_signal_frame_pointer))
+        return nullptr;
+
+      // Alleged frame pointer is readable, use it for further unwinding.
+      new_frame_pointer = pre_signal_frame_pointer;
+
+      // Skip frame size check if we return from a signal. We may be using a
+      // an alternate stack for signals.
+      check_frame_size = false;
+    }
+  }
+#endif
+
+  // aarch64 ABI requires stack pointer to be 16-byte-aligned.
+  if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 15) != 0)
+    return nullptr;
+
+  // Check frame size.  In strict mode, we assume frames to be under
+  // 100,000 bytes.  In non-strict mode, we relax the limit to 1MB.
+  if (check_frame_size) {
+    const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
+    const uintptr_t frame_size =
+        ComputeStackFrameSize(old_frame_pointer, new_frame_pointer);
+    if (frame_size == kUnknownFrameSize || frame_size > max_size)
+      return nullptr;
+  }
+
+  return new_frame_pointer;
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+#ifdef __GNUC__
+  void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0));
+#else
+# error reading stack point not yet supported on this platform.
+#endif
+
+  skip_count++;    // Skip the frame for this function.
+  int n = 0;
+
+  // The frame pointer points to low address of a frame.  The first 64-bit
+  // word of a frame points to the next frame up the call chain, which normally
+  // is just after the high address of the current frame.  The second word of
+  // a frame contains return adress of to the caller.   To find a pc value
+  // associated with the current frame, we need to go down a level in the call
+  // chain.  So we remember return the address of the last frame seen.  This
+  // does not work for the first stack frame, which belongs to UnwindImp() but
+  // we skip the frame for UnwindImp() anyway.
+  void* prev_return_address = nullptr;
+
+  while (frame_pointer && n < max_depth) {
+    // The absl::GetStackFrames routine is called when we are in some
+    // informational context (the failure signal handler for example).
+    // Use the non-strict unwinding rules to produce a stack trace
+    // that is as complete as possible (even if it contains a few bogus
+    // entries in some rare cases).
+    void **next_frame_pointer =
+        NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
+
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = prev_return_address;
+      if (IS_STACK_FRAMES) {
+        sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
+      }
+      n++;
+    }
+    prev_return_address = frame_pointer[1];
+    frame_pointer = next_frame_pointer;
+  }
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 200;
+    int j = 0;
+    for (; frame_pointer != nullptr && j < kMaxUnwind; j++) {
+      frame_pointer =
+          NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc
new file mode 100644
index 0000000..c840833
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -0,0 +1,123 @@
+// Copyright 2011 and onwards Google Inc.
+// All rights reserved.
+//
+// Author: Doug Kwan
+// This is inspired by Craig Silverstein's PowerPC stacktrace code.
+//
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
+
+#include <cstdint>
+
+#include "absl/debugging/stacktrace.h"
+
+// WARNING:
+// This only works if all your code is in either ARM or THUMB mode.  With
+// interworking, the frame pointer of the caller can either be in r11 (ARM
+// mode) or r7 (THUMB mode).  A callee only saves the frame pointer of its
+// mode in a fixed location on its stack frame.  If the caller is a different
+// mode, there is no easy way to find the frame pointer.  It can either be
+// still in the designated register or saved on stack along with other callee
+// saved registers.
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return nullptr if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
+static void **NextStackFrame(void **old_sp) {
+  void **new_sp = (void**) old_sp[-1];
+
+  // Check that the transition from frame pointer old_sp to frame
+  // pointer new_sp isn't clearly bogus
+  if (STRICT_UNWINDING) {
+    // With the stack growing downwards, older stack frame must be
+    // at a greater address that the current one.
+    if (new_sp <= old_sp) return nullptr;
+    // Assume stack frames larger than 100,000 bytes are bogus.
+    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
+  } else {
+    // In the non-strict mode, allow discontiguous stack frames.
+    // (alternate-signal-stacks for example).
+    if (new_sp == old_sp) return nullptr;
+    // And allow frames upto about 1MB.
+    if ((new_sp > old_sp)
+        && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
+  }
+  if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
+  return new_sp;
+}
+
+// This ensures that absl::GetStackTrace sets up the Link Register properly.
+#ifdef __GNUC__
+void StacktraceArmDummyFunction() __attribute__((noinline));
+void StacktraceArmDummyFunction() { __asm__ volatile(""); }
+#else
+# error StacktraceArmDummyFunction() needs to be ported to this platform.
+#endif
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void * /* ucp */, int *min_dropped_frames) {
+#ifdef __GNUC__
+  void **sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+#else
+# error reading stack point not yet supported on this platform.
+#endif
+
+  // On ARM, the return address is stored in the link register (r14).
+  // This is not saved on the stack frame of a leaf function.  To
+  // simplify code that reads return addresses, we call a dummy
+  // function so that the return address of this function is also
+  // stored in the stack frame.  This works at least for gcc.
+  StacktraceArmDummyFunction();
+
+  int n = 0;
+  while (sp && n < max_depth) {
+    // The absl::GetStackFrames routine is called when we are in some
+    // informational context (the failure signal handler for example).
+    // Use the non-strict unwinding rules to produce a stack trace
+    // that is as complete as possible (even if it contains a few bogus
+    // entries in some rare cases).
+    void **next_sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
+
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = *sp;
+
+      if (IS_STACK_FRAMES) {
+        if (next_sp > sp) {
+          sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+        } else {
+          // A frame-size of 0 is used to indicate unknown frame size.
+          sizes[n] = 0;
+        }
+      }
+      n++;
+    }
+    sp = next_sp;
+  }
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 200;
+    int j = 0;
+    for (; sp != nullptr && j < kMaxUnwind; j++) {
+      sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return false;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
new file mode 100644
index 0000000..48adfcc
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 The Abseil 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.
+
+ * Defines ABSL_STACKTRACE_INL_HEADER to the *-inl.h containing
+ * actual unwinder implementation.
+ * This header is "private" to stacktrace.cc.
+ * DO NOT include it into any other files.
+*/
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+
+// First, test platforms which only support a stub.
+#if ABSL_STACKTRACE_INL_HEADER
+#error ABSL_STACKTRACE_INL_HEADER cannot be directly set
+#elif defined(__native_client__) || defined(__APPLE__) || \
+    defined(__FreeBSD__) || defined(__ANDROID__) || defined(__myriad2__) || \
+    defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+
+// Next, test for Mips and Windows.
+// TODO(marmstrong): Mips case, remove the check for ABSL_STACKTRACE_INL_HEADER
+#elif defined(__mips__) && !defined(ABSL_STACKTRACE_INL_HEADER)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+#elif defined(_WIN32)  // windows
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_win32-inl.inc"
+
+// Finally, test NO_FRAME_POINTER.
+#elif !defined(NO_FRAME_POINTER)
+# if defined(__i386__) || defined(__x86_64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_x86-inl.inc"
+# elif defined(__ppc__) || defined(__PPC__)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+# elif defined(__aarch64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+# elif defined(__arm__)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_arm-inl.inc"
+# endif
+#else  // defined(NO_FRAME_POINTER)
+# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+# elif defined(__ppc__) || defined(__PPC__)
+//  Use glibc's backtrace.
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_generic-inl.inc"
+# elif defined(__arm__)
+#   error stacktrace without frame pointer is not supported on ARM
+# endif
+#endif  // NO_FRAME_POINTER
+
+#if !defined(ABSL_STACKTRACE_INL_HEADER)
+#error Not supported yet
+#endif
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
new file mode 100644
index 0000000..2c9ca41
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -0,0 +1,59 @@
+// Copyright 2000 - 2007 Google Inc.
+// All rights reserved.
+//
+// Author: Sanjay Ghemawat
+//
+// Portable implementation - just use glibc
+//
+// Note:  The glibc implementation may cause a call to malloc.
+// This can cause a deadlock in HeapProfiler.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+
+#include <execinfo.h>
+#include <cstring>
+
+#include "absl/debugging/stacktrace.h"
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  static const int kStackLength = 64;
+  void * stack[kStackLength];
+  int size;
+
+  size = backtrace(stack, kStackLength);
+  skip_count++;  // we want to skip the current frame as well
+  int result_count = size - skip_count;
+  if (result_count < 0)
+    result_count = 0;
+  if (result_count > max_depth)
+    result_count = max_depth;
+  for (int i = 0; i < result_count; i++)
+    result[i] = stack[i + skip_count];
+
+  if (IS_STACK_FRAMES) {
+    // No implementation for finding out the stack frame sizes yet.
+    memset(sizes, 0, sizeof(*sizes) * result_count);
+  }
+  if (min_dropped_frames != nullptr) {
+    if (size - skip_count - max_depth > 0) {
+      *min_dropped_frames = size - skip_count - max_depth;
+    } else {
+      *min_dropped_frames = 0;
+    }
+  }
+
+  return result_count;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
new file mode 100644
index 0000000..297bdad
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -0,0 +1,243 @@
+// Copyright 2017 The Abseil 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.
+//
+// Produce stack trace.  I'm guessing (hoping!) the code is much like
+// for x86.  For apple machines, at least, it seems to be; see
+//    http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
+//    http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
+// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+
+#if defined(__linux__)
+#include <asm/ptrace.h>   // for PT_NIP.
+#include <ucontext.h>     // for ucontext_t
+#endif
+
+#include <unistd.h>
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+
+#include "absl/base/port.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h"  // a no-op on non-elf or non-glibc systems
+
+// Given a stack pointer, return the saved link register value.
+// Note that this is the link register for a callee.
+static inline void *StacktracePowerPCGetLR(void **sp) {
+  // PowerPC has 3 main ABIs, which say where in the stack the
+  // Link Register is.  For DARWIN and AIX (used by apple and
+  // linux ppc64), it's in sp[2].  For SYSV (used by linux ppc),
+  // it's in sp[1].
+#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
+  return *(sp+2);
+#elif defined(_CALL_SYSV)
+  return *(sp+1);
+#elif defined(__APPLE__) || defined(__FreeBSD__) || \
+    (defined(__linux__) && defined(__PPC64__))
+  // This check is in case the compiler doesn't define _CALL_AIX/etc.
+  return *(sp+2);
+#elif defined(__linux)
+  // This check is in case the compiler doesn't define _CALL_SYSV.
+  return *(sp+1);
+#else
+#error Need to specify the PPC ABI for your archiecture.
+#endif
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static void **NextStackFrame(void **old_sp, const void *uc) {
+  void **new_sp = (void **) *old_sp;
+  enum { kStackAlignment = 16 };
+
+  // Check that the transition from frame pointer old_sp to frame
+  // pointer new_sp isn't clearly bogus
+  if (STRICT_UNWINDING) {
+    // With the stack growing downwards, older stack frame must be
+    // at a greater address that the current one.
+    if (new_sp <= old_sp) return nullptr;
+    // Assume stack frames larger than 100,000 bytes are bogus.
+    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
+  } else {
+    // In the non-strict mode, allow discontiguous stack frames.
+    // (alternate-signal-stacks for example).
+    if (new_sp == old_sp) return nullptr;
+    // And allow frames upto about 1MB.
+    if ((new_sp > old_sp)
+        && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
+  }
+  if ((uintptr_t)new_sp % kStackAlignment != 0) return nullptr;
+
+#if defined(__linux__)
+  enum StackTraceKernelSymbolStatus {
+      kNotInitialized = 0, kAddressValid, kAddressInvalid };
+
+  if (IS_WITH_CONTEXT && uc != nullptr) {
+    static StackTraceKernelSymbolStatus kernel_symbol_status =
+        kNotInitialized;  // Sentinel: not computed yet.
+    // Initialize with sentinel value: __kernel_rt_sigtramp_rt64 can not
+    // possibly be there.
+    static const unsigned char *kernel_sigtramp_rt64_address = nullptr;
+    if (kernel_symbol_status == kNotInitialized) {
+      absl::debugging_internal::VDSOSupport vdso;
+      if (vdso.IsPresent()) {
+        absl::debugging_internal::VDSOSupport::SymbolInfo
+            sigtramp_rt64_symbol_info;
+        if (!vdso.LookupSymbol(
+                "__kernel_sigtramp_rt64", "LINUX_2.6.15",
+                absl::debugging_internal::VDSOSupport::kVDSOSymbolType,
+                &sigtramp_rt64_symbol_info) ||
+            sigtramp_rt64_symbol_info.address == nullptr) {
+          // Unexpected: VDSO is present, yet the expected symbol is missing
+          // or null.
+          assert(false && "VDSO is present, but doesn't have expected symbol");
+          kernel_symbol_status = kAddressInvalid;
+        } else {
+          kernel_sigtramp_rt64_address =
+              reinterpret_cast<const unsigned char *>(
+                  sigtramp_rt64_symbol_info.address);
+          kernel_symbol_status = kAddressValid;
+        }
+      } else {
+        kernel_symbol_status = kAddressInvalid;
+      }
+    }
+
+    if (new_sp != nullptr &&
+        kernel_symbol_status == kAddressValid &&
+        StacktracePowerPCGetLR(new_sp) == kernel_sigtramp_rt64_address) {
+      const ucontext_t* signal_context =
+          reinterpret_cast<const ucontext_t*>(uc);
+      void **const sp_before_signal =
+          reinterpret_cast<void**>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+      // Check that alleged sp before signal is nonnull and is reasonably
+      // aligned.
+      if (sp_before_signal != nullptr &&
+          ((uintptr_t)sp_before_signal % kStackAlignment) == 0) {
+        // Check that alleged stack pointer is actually readable. This is to
+        // prevent a "double fault" in case we hit the first fault due to e.g.
+        // a stack corruption.
+        if (absl::debugging_internal::AddressIsReadable(sp_before_signal)) {
+          // Alleged stack pointer is readable, use it for further unwinding.
+          new_sp = sp_before_signal;
+        }
+      }
+    }
+  }
+#endif
+
+  return new_sp;
+}
+
+// This ensures that absl::GetStackTrace sets up the Link Register properly.
+void StacktracePowerPCDummyFunction() __attribute__((noinline));
+void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  void **sp;
+  // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+  // and Darwin 8.8.1 (Tiger) use as 1.38.  This means we have to use a
+  // different asm syntax.  I don't know quite the best way to discriminate
+  // systems using the old as from the new one; I've gone with __APPLE__.
+#ifdef __APPLE__
+  __asm__ volatile ("mr %0,r1" : "=r" (sp));
+#else
+  __asm__ volatile ("mr %0,1" : "=r" (sp));
+#endif
+
+  // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
+  // entry that holds the return address of the subroutine call (what
+  // instruction we run after our function finishes).  This is the
+  // same as the stack-pointer of our parent routine, which is what we
+  // want here.  While the compiler will always(?) set up LR for
+  // subroutine calls, it may not for leaf functions (such as this one).
+  // This routine forces the compiler (at least gcc) to push it anyway.
+  StacktracePowerPCDummyFunction();
+
+  // The LR save area is used by the callee, so the top entry is bogus.
+  skip_count++;
+
+  int n = 0;
+
+  // Unlike ABIs of X86 and ARM, PowerPC ABIs say that return address (in
+  // the link register) of a function call is stored in the caller's stack
+  // frame instead of the callee's.  When we look for the return address
+  // associated with a stack frame, we need to make sure that there is a
+  // caller frame before it.  So we call NextStackFrame before entering the
+  // loop below and check next_sp instead of sp for loop termination.
+  // The outermost frame is set up by runtimes and it does not have a
+  // caller frame, so it is skipped.
+
+  // The absl::GetStackFrames routine is called when we are in some
+  // informational context (the failure signal handler for example).
+  // Use the non-strict unwinding rules to produce a stack trace
+  // that is as complete as possible (even if it contains a few
+  // bogus entries in some rare cases).
+  void **next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
+
+  while (next_sp && n < max_depth) {
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = StacktracePowerPCGetLR(sp);
+      if (IS_STACK_FRAMES) {
+        if (next_sp > sp) {
+          sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+        } else {
+          // A frame-size of 0 is used to indicate unknown frame size.
+          sizes[n] = 0;
+        }
+      }
+      n++;
+    }
+
+    sp = next_sp;
+    next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
+  }
+
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 1000;
+    int j = 0;
+    for (; next_sp != nullptr && j < kMaxUnwind; j++) {
+      next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(next_sp, ucp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
new file mode 100644
index 0000000..e256fdd
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
@@ -0,0 +1,22 @@
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** /* result */, int* /* sizes */,
+                      int /* max_depth */, int /* skip_count */,
+                      const void* /* ucp */, int *min_dropped_frames) {
+  if (min_dropped_frames != nullptr) {
+    *min_dropped_frames = 0;
+  }
+  return 0;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return false;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
new file mode 100644
index 0000000..a8f8a56
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -0,0 +1,83 @@
+// Copyright 2017 The Abseil 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.
+//
+// Produces a stack trace for Windows.  Normally, one could use
+// stacktrace_x86-inl.h or stacktrace_x86_64-inl.h -- and indeed, that
+// should work for binaries compiled using MSVC in "debug" mode.
+// However, in "release" mode, Windows uses frame-pointer
+// optimization, which makes getting a stack trace very difficult.
+//
+// There are several approaches one can take.  One is to use Windows
+// intrinsics like StackWalk64.  These can work, but have restrictions
+// on how successful they can be.  Another attempt is to write a
+// version of stacktrace_x86-inl.h that has heuristic support for
+// dealing with FPO, similar to what WinDbg does (see
+// http://www.nynaeve.net/?p=97).  There are (non-working) examples of
+// these approaches, complete with TODOs, in stacktrace_win32-inl.h#1
+//
+// The solution we've ended up doing is to call the undocumented
+// windows function RtlCaptureStackBackTrace, which probably doesn't
+// work with FPO but at least is fast, and doesn't require a symbol
+// server.
+//
+// This code is inspired by a patch from David Vitek:
+//   http://code.google.com/p/google-perftools/issues/detail?id=83
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
+
+#include <windows.h>    // for GetProcAddress and GetModuleHandle
+#include <cassert>
+
+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
+    IN ULONG frames_to_skip,
+    IN ULONG frames_to_capture,
+    OUT PVOID *backtrace,
+    OUT PULONG backtrace_hash);
+
+// Load the function we need at static init time, where we don't have
+// to worry about someone else holding the loader's lock.
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+   (RtlCaptureStackBackTrace_Function*)
+   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  int n = 0;
+  if (!RtlCaptureStackBackTrace_fn) {
+    // can't find a stacktrace with no function to call
+  } else {
+    n = (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, 0);
+  }
+  if (IS_STACK_FRAMES) {
+    // No implementation for finding out the stack frame sizes yet.
+    memset(sizes, 0, sizeof(*sizes) * n);
+  }
+  if (min_dropped_frames != nullptr) {
+    // Not implemented.
+    *min_dropped_frames = 0;
+  }
+  return n;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return false;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
new file mode 100644
index 0000000..ac85b92
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -0,0 +1,337 @@
+// Copyright 2017 The Abseil 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.
+//
+// Produce stack trace
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
+
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+#include <ucontext.h>  // for ucontext_t
+#endif
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+
+#include <cassert>
+#include <cstdint>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h"  // a no-op on non-elf or non-glibc systems
+#include "absl/debugging/stacktrace.h"
+#include "absl/base/internal/raw_logging.h"
+
+#if defined(__linux__) && defined(__i386__)
+// Count "push %reg" instructions in VDSO __kernel_vsyscall(),
+// preceeding "syscall" or "sysenter".
+// If __kernel_vsyscall uses frame pointer, answer 0.
+//
+// kMaxBytes tells how many instruction bytes of __kernel_vsyscall
+// to analyze before giving up. Up to kMaxBytes+1 bytes of
+// instructions could be accessed.
+//
+// Here are known __kernel_vsyscall instruction sequences:
+//
+// SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S).
+// Used on Intel.
+//  0xffffe400 <__kernel_vsyscall+0>:       push   %ecx
+//  0xffffe401 <__kernel_vsyscall+1>:       push   %edx
+//  0xffffe402 <__kernel_vsyscall+2>:       push   %ebp
+//  0xffffe403 <__kernel_vsyscall+3>:       mov    %esp,%ebp
+//  0xffffe405 <__kernel_vsyscall+5>:       sysenter
+//
+// SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S).
+// Used on AMD.
+//  0xffffe400 <__kernel_vsyscall+0>:       push   %ebp
+//  0xffffe401 <__kernel_vsyscall+1>:       mov    %ecx,%ebp
+//  0xffffe403 <__kernel_vsyscall+3>:       syscall
+//
+
+// The sequence below isn't actually expected in Google fleet,
+// here only for completeness. Remove this comment from OSS release.
+
+// i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S)
+//  0xffffe400 <__kernel_vsyscall+0>:       int $0x80
+//  0xffffe401 <__kernel_vsyscall+1>:       ret
+//
+static const int kMaxBytes = 10;
+
+// We use assert()s instead of DCHECK()s -- this is too low level
+// for DCHECK().
+
+static int CountPushInstructions(const unsigned char *const addr) {
+  int result = 0;
+  for (int i = 0; i < kMaxBytes; ++i) {
+    if (addr[i] == 0x89) {
+      // "mov reg,reg"
+      if (addr[i + 1] == 0xE5) {
+        // Found "mov %esp,%ebp".
+        return 0;  
+      }
+      ++i;  // Skip register encoding byte.
+    } else if (addr[i] == 0x0F &&
+               (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) {
+      // Found "sysenter" or "syscall".
+      return result;
+    } else if ((addr[i] & 0xF0) == 0x50) {
+      // Found "push %reg".
+      ++result;
+    } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) {
+      // Found "int $0x80"
+      assert(result == 0);
+      return 0;
+    } else {
+      // Unexpected instruction.
+      assert(false && "unexpected instruction in __kernel_vsyscall");
+      return 0;
+    }
+  }
+  // Unexpected: didn't find SYSENTER or SYSCALL in
+  // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval.
+  assert(false && "did not find SYSENTER or SYSCALL in __kernel_vsyscall");
+  return 0;
+}
+#endif
+
+// Assume stack frames larger than 100,000 bytes are bogus.
+static const int kMaxFrameBytes = 100000;
+
+// Returns the stack frame pointer from signal context, 0 if unknown.
+// vuc is a ucontext_t *.  We use void* to avoid the use
+// of ucontext_t on non-POSIX systems.
+static uintptr_t GetFP(const void *vuc) {
+#if !defined(__linux__)
+  static_cast<void>(vuc);  // Avoid an unused argument compiler warning.
+#else
+  if (vuc != nullptr) {
+    auto *uc = reinterpret_cast<const ucontext_t *>(vuc);
+#if defined(__i386__)
+    const auto bp = uc->uc_mcontext.gregs[REG_EBP];
+    const auto sp = uc->uc_mcontext.gregs[REG_ESP];
+#elif defined(__x86_64__)
+    const auto bp = uc->uc_mcontext.gregs[REG_RBP];
+    const auto sp = uc->uc_mcontext.gregs[REG_RSP];
+#else
+    const uintptr_t bp = 0;
+    const uintptr_t sp = 0;
+#endif
+    // Sanity-check that the base pointer is valid.  It should be as long as
+    // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in
+    // the process is compiled with --copt=-fomit-frame-pointer or
+    // --copt=-momit-leaf-frame-pointer.
+    //
+    // TODO(bcmills): -momit-leaf-frame-pointer is currently the default
+    // behavior when building with clang.  Talk to the C++ toolchain team about
+    // fixing that.
+    if (bp >= sp && bp - sp <= kMaxFrameBytes) return bp;
+
+    // If bp isn't a plausible frame pointer, return the stack pointer instead.
+    // If we're lucky, it points to the start of a stack frame; otherwise, we'll
+    // get one frame of garbage in the stack trace and fail the sanity check on
+    // the next iteration.
+    return sp;
+  }
+#endif
+  return 0;
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template <bool STRICT_UNWINDING, bool WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static void **NextStackFrame(void **old_fp, const void *uc) {
+  void **new_fp = (void **)*old_fp;
+
+#if defined(__linux__) && defined(__i386__)
+  if (WITH_CONTEXT && uc != nullptr) {
+    // How many "push %reg" instructions are there at __kernel_vsyscall?
+    // This is constant for a given kernel and processor, so compute
+    // it only once.
+    static int num_push_instructions = -1;  // Sentinel: not computed yet.
+    // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly
+    // be there.
+    static const unsigned char *kernel_rt_sigreturn_address = nullptr;
+    static const unsigned char *kernel_vsyscall_address = nullptr;
+    if (num_push_instructions == -1) {
+      absl::debugging_internal::VDSOSupport vdso;
+      if (vdso.IsPresent()) {
+        absl::debugging_internal::VDSOSupport::SymbolInfo
+            rt_sigreturn_symbol_info;
+        absl::debugging_internal::VDSOSupport::SymbolInfo vsyscall_symbol_info;
+        if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC,
+                               &rt_sigreturn_symbol_info) ||
+            !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC,
+                               &vsyscall_symbol_info) ||
+            rt_sigreturn_symbol_info.address == nullptr ||
+            vsyscall_symbol_info.address == nullptr) {
+          // Unexpected: 32-bit VDSO is present, yet one of the expected
+          // symbols is missing or null.
+          assert(false && "VDSO is present, but doesn't have expected symbols");
+          num_push_instructions = 0;
+        } else {
+          kernel_rt_sigreturn_address =
+              reinterpret_cast<const unsigned char *>(
+                  rt_sigreturn_symbol_info.address);
+          kernel_vsyscall_address =
+              reinterpret_cast<const unsigned char *>(
+                  vsyscall_symbol_info.address);
+          num_push_instructions =
+              CountPushInstructions(kernel_vsyscall_address);
+        }
+      } else {
+        num_push_instructions = 0;
+      }
+    }
+    if (num_push_instructions != 0 && kernel_rt_sigreturn_address != nullptr &&
+        old_fp[1] == kernel_rt_sigreturn_address) {
+      const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+      // This kernel does not use frame pointer in its VDSO code,
+      // and so %ebp is not suitable for unwinding.
+      void **const reg_ebp =
+          reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_EBP]);
+      const unsigned char *const reg_eip =
+          reinterpret_cast<unsigned char *>(ucv->uc_mcontext.gregs[REG_EIP]);
+      if (new_fp == reg_ebp && kernel_vsyscall_address <= reg_eip &&
+          reg_eip - kernel_vsyscall_address < kMaxBytes) {
+        // We "stepped up" to __kernel_vsyscall, but %ebp is not usable.
+        // Restore from 'ucv' instead.
+        void **const reg_esp =
+            reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_ESP]);
+        // Check that alleged %esp is not null and is reasonably aligned.
+        if (reg_esp &&
+            ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) {
+          // Check that alleged %esp is actually readable. This is to prevent
+          // "double fault" in case we hit the first fault due to e.g. stack
+          // corruption.
+          void *const reg_esp2 = reg_esp[num_push_instructions - 1];
+          if (absl::debugging_internal::AddressIsReadable(reg_esp2)) {
+            // Alleged %esp is readable, use it for further unwinding.
+            new_fp = reinterpret_cast<void **>(reg_esp2);
+          }
+        }
+      }
+    }
+  }
+#endif
+
+  const uintptr_t old_fp_u = reinterpret_cast<uintptr_t>(old_fp);
+  const uintptr_t new_fp_u = reinterpret_cast<uintptr_t>(new_fp);
+
+  // Check that the transition from frame pointer old_fp to frame
+  // pointer new_fp isn't clearly bogus.  Skip the checks if new_fp
+  // matches the signal context, so that we don't skip out early when
+  // using an alternate signal stack.
+  //
+  // TODO(bcmills): The GetFP call should be completely unnecessary when
+  // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's
+  // stack by this point), but it is empirically still needed (e.g. when the
+  // stack includes a call to abort).  unw_get_reg returns UNW_EBADREG for some
+  // frames.  Figure out why GetValidFrameAddr and/or libunwind isn't doing what
+  // it's supposed to.
+  if (STRICT_UNWINDING &&
+      (!WITH_CONTEXT || uc == nullptr || new_fp_u != GetFP(uc))) {
+    // With the stack growing downwards, older stack frame must be
+    // at a greater address that the current one.
+    if (new_fp_u <= old_fp_u) return nullptr;
+    if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr;
+  } else {
+    if (new_fp == nullptr) return nullptr;  // skip AddressIsReadable() below
+    // In the non-strict mode, allow discontiguous stack frames.
+    // (alternate-signal-stacks for example).
+    if (new_fp == old_fp) return nullptr;
+  }
+
+  if (new_fp_u & (sizeof(void *) - 1)) return nullptr;
+#ifdef __i386__
+  // On 32-bit machines, the stack pointer can be very close to
+  // 0xffffffff, so we explicitly check for a pointer into the
+  // last two pages in the address space
+  if (new_fp_u >= 0xffffe000) return nullptr;
+#endif
+#if !defined(_WIN32)
+  if (!STRICT_UNWINDING) {
+    // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
+    // on AMD-based machines with VDSO-enabled kernels.
+    // Make an extra sanity check to insure new_fp is readable.
+    // Note: NextStackFrame<false>() is only called while the program
+    //       is already on its last leg, so it's ok to be slow here.
+
+    if (!absl::debugging_internal::AddressIsReadable(new_fp)) {
+      return nullptr;
+    }
+  }
+#endif
+  return new_fp;
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+ABSL_ATTRIBUTE_NOINLINE
+static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  int n = 0;
+  void **fp = reinterpret_cast<void **>(__builtin_frame_address(0));
+
+  while (fp && n < max_depth) {
+    if (*(fp + 1) == reinterpret_cast<void *>(0)) {
+      // In 64-bit code, we often see a frame that
+      // points to itself and has a return address of 0.
+      break;
+    }
+    void **next_fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp);
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = *(fp + 1);
+      if (IS_STACK_FRAMES) {
+        if (next_fp > fp) {
+          sizes[n] = (uintptr_t)next_fp - (uintptr_t)fp;
+        } else {
+          // A frame-size of 0 is used to indicate unknown frame size.
+          sizes[n] = 0;
+        }
+      }
+      n++;
+    }
+    fp = next_fp;
+  }
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 1000;
+    int j = 0;
+    for (; fp != nullptr && j < kMaxUnwind; j++) {
+      fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
new file mode 100644
index 0000000..8d926fe
--- /dev/null
+++ b/absl/debugging/internal/symbolize.h
@@ -0,0 +1,123 @@
+// Copyright 2018 The Abseil 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.
+
+// This file contains internal parts of the Abseil symbolizer.
+// Do not depend on the anything in this file, it may change at anytime.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
+#define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
+
+#include <cstddef>
+#include <cstdint>
+#include "absl/base/port.h"  // Needed for string vs std::string
+
+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
+#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
+    !defined(__asmjs__) && !defined(__wasm__)
+#define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1
+
+#include <elf.h>
+#include <link.h>  // For ElfW() macro.
+#include <functional>
+#include <string>
+
+namespace absl {
+namespace debugging_internal {
+
+// Iterates over all sections, invoking callback on each with the section name
+// and the section header.
+//
+// Returns true on success; otherwise returns false in case of errors.
+//
+// This is not async-signal-safe.
+bool ForEachSection(
+    int fd, const std::function<bool(const std::string& name, const ElfW(Shdr) &)>&
+                callback);
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out);
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+
+namespace absl {
+namespace debugging_internal {
+
+struct SymbolDecoratorArgs {
+  // The program counter we are getting symbolic name for.
+  const void *pc;
+  // 0 for main executable, load address for shared libraries.
+  ptrdiff_t relocation;
+  // Read-only file descriptor for ELF image covering "pc",
+  // or -1 if no such ELF image exists in /proc/self/maps.
+  int fd;
+  // Output buffer, size.
+  // Note: the buffer may not be empty -- default symbolizer may have already
+  // produced some output, and earlier decorators may have adorned it in
+  // some way. You are free to replace or augment the contents (within the
+  // symbol_buf_size limit).
+  char *const symbol_buf;
+  size_t symbol_buf_size;
+  // Temporary scratch space, size.
+  // Use that space in preference to allocating your own stack buffer to
+  // conserve stack.
+  char *const tmp_buf;
+  size_t tmp_buf_size;
+  // User-provided argument
+  void* arg;
+};
+using SymbolDecorator = void (*)(const SymbolDecoratorArgs *);
+
+// Installs a function-pointer as a decorator. Returns a value less than zero
+// if the system cannot install the decorator. Otherwise, returns a unique
+// identifier corresponding to the decorator. This identifier can be used to
+// uninstall the decorator - See RemoveSymbolDecorator() below.
+int InstallSymbolDecorator(SymbolDecorator decorator, void* arg);
+
+// Removes a previously installed function-pointer decorator. Parameter "ticket"
+// is the return-value from calling InstallSymbolDecorator().
+bool RemoveSymbolDecorator(int ticket);
+
+// Remove all installed decorators.  Returns true if successful, false if
+// symbolization is currently in progress.
+bool RemoveAllSymbolDecorators(void);
+
+// Registers an address range to a file mapping.
+//
+// Preconditions:
+//   start <= end
+//   filename != nullptr
+//
+// Returns true if the file was successfully registered.
+bool RegisterFileMappingHint(
+    const void* start, const void* end, uint64_t offset, const char* filename);
+
+// Looks up the file mapping registered by RegisterFileMappingHint for an
+// address range. If there is one, the file name is stored in *filename and
+// *start and *end are modified to reflect the registered mapping. Returns
+// whether any hint was found.
+bool GetFileMappingHint(const void** start,
+                        const void** end,
+                        uint64_t    *  offset,
+                        const char** filename);
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
new file mode 100644
index 0000000..e8129e8
--- /dev/null
+++ b/absl/debugging/internal/vdso_support.cc
@@ -0,0 +1,192 @@
+// Copyright 2017 The Abseil 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.
+
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+
+#include "absl/debugging/internal/vdso_support.h"
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT     // defined in vdso_support.h
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#if __GLIBC_PREREQ(2, 16)  // GLIBC-2.16 implements getauxval.
+#include <sys/auxv.h>
+#endif
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/port.h"
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33  // for crosstoolv10
+#endif
+
+namespace absl {
+namespace debugging_internal {
+
+ABSL_CONST_INIT
+std::atomic<const void *> VDSOSupport::vdso_base_(
+    debugging_internal::ElfMemImage::kInvalidBase);
+
+std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
+VDSOSupport::VDSOSupport()
+    // If vdso_base_ is still set to kInvalidBase, we got here
+    // before VDSOSupport::Init has been called. Call it now.
+    : image_(vdso_base_.load(std::memory_order_relaxed) ==
+                     debugging_internal::ElfMemImage::kInvalidBase
+                 ? Init()
+                 : vdso_base_.load(std::memory_order_relaxed)) {}
+
+// NOTE: we can't use GoogleOnceInit() below, because we can be
+// called by tcmalloc, and none of the *once* stuff may be functional yet.
+//
+// In addition, we hope that the VDSOSupportHelper constructor
+// causes this code to run before there are any threads, and before
+// InitGoogle() has executed any chroot or setuid calls.
+//
+// Finally, even if there is a race here, it is harmless, because
+// the operation should be idempotent.
+const void *VDSOSupport::Init() {
+  const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase;
+#if __GLIBC_PREREQ(2, 16)
+  if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+    errno = 0;
+    const void *const sysinfo_ehdr =
+        reinterpret_cast<const void *>(getauxval(AT_SYSINFO_EHDR));
+    if (errno == 0) {
+      vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed);
+    }
+  }
+#endif  // __GLIBC_PREREQ(2, 16)
+  if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+    // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
+    // on stack, and so glibc works as if VDSO was not present.
+    // But going directly to kernel via /proc/self/auxv below bypasses
+    // Valgrind zapping. So we check for Valgrind separately.
+    if (AbslRunningOnValgrind()) {
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+      getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+      return nullptr;
+    }
+    int fd = open("/proc/self/auxv", O_RDONLY);
+    if (fd == -1) {
+      // Kernel too old to have a VDSO.
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+      getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+      return nullptr;
+    }
+    ElfW(auxv_t) aux;
+    while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
+      if (aux.a_type == AT_SYSINFO_EHDR) {
+        vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
+                         std::memory_order_relaxed);
+        break;
+      }
+    }
+    close(fd);
+    if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+      // Didn't find AT_SYSINFO_EHDR in auxv[].
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+    }
+  }
+  GetCpuFn fn = &GetCPUViaSyscall;  // default if VDSO not present.
+  if (vdso_base_.load(std::memory_order_relaxed)) {
+    VDSOSupport vdso;
+    SymbolInfo info;
+    if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+      fn = reinterpret_cast<GetCpuFn>(const_cast<void *>(info.address));
+    }
+  }
+  // Subtle: this code runs outside of any locks; prevent compiler
+  // from assigning to getcpu_fn_ more than once.
+  getcpu_fn_.store(fn, std::memory_order_relaxed);
+  return vdso_base_.load(std::memory_order_relaxed);
+}
+
+const void *VDSOSupport::SetBase(const void *base) {
+  ABSL_RAW_CHECK(base != debugging_internal::ElfMemImage::kInvalidBase,
+                 "internal error");
+  const void *old_base = vdso_base_.load(std::memory_order_relaxed);
+  vdso_base_.store(base, std::memory_order_relaxed);
+  image_.Init(base);
+  // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO.
+  getcpu_fn_.store(&InitAndGetCPU, std::memory_order_relaxed);
+  return old_base;
+}
+
+bool VDSOSupport::LookupSymbol(const char *name,
+                               const char *version,
+                               int type,
+                               SymbolInfo *info) const {
+  return image_.LookupSymbol(name, version, type, info);
+}
+
+bool VDSOSupport::LookupSymbolByAddress(const void *address,
+                                        SymbolInfo *info_out) const {
+  return image_.LookupSymbolByAddress(address, info_out);
+}
+
+// NOLINT on 'long' because this routine mimics kernel api.
+long VDSOSupport::GetCPUViaSyscall(unsigned *cpu,  // NOLINT(runtime/int)
+                                   void *, void *) {
+#ifdef SYS_getcpu
+  return syscall(SYS_getcpu, cpu, nullptr, nullptr);
+#else
+  // x86_64 never implemented sys_getcpu(), except as a VDSO call.
+  static_cast<void>(cpu);  // Avoid an unused argument compiler warning.
+  errno = ENOSYS;
+  return -1;
+#endif
+}
+
+// Use fast __vdso_getcpu if available.
+long VDSOSupport::InitAndGetCPU(unsigned *cpu,  // NOLINT(runtime/int)
+                                void *x, void *y) {
+  Init();
+  GetCpuFn fn = getcpu_fn_.load(std::memory_order_relaxed);
+  ABSL_RAW_CHECK(fn != &InitAndGetCPU, "Init() did not set getcpu_fn_");
+  return (*fn)(cpu, x, y);
+}
+
+// This function must be very fast, and may be called from very
+// low level (e.g. tcmalloc). Hence I avoid things like
+// GoogleOnceInit() and ::operator new.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+int GetCPU() {
+  unsigned cpu;
+  int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, nullptr, nullptr);
+  return ret_code == 0 ? cpu : ret_code;
+}
+
+// We need to make sure VDSOSupport::Init() is called before
+// InitGoogle() does any setuid or chroot calls.  If VDSOSupport
+// is used in any global constructor, this will happen, since
+// VDSOSupport's constructor calls Init.  But if not, we need to
+// ensure it here, with a global constructor of our own.  This
+// is an allowed exception to the normal rule against non-trivial
+// global constructors.
+static class VDSOInitHelper {
+ public:
+  VDSOInitHelper() { VDSOSupport::Init(); }
+} vdso_init_helper;
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_VDSO_SUPPORT
diff --git a/absl/debugging/internal/vdso_support.h b/absl/debugging/internal/vdso_support.h
new file mode 100644
index 0000000..8002c74
--- /dev/null
+++ b/absl/debugging/internal/vdso_support.h
@@ -0,0 +1,156 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSO stands for "Virtual Dynamic Shared Object" -- a page of
+// executable code, which looks like a shared library, but doesn't
+// necessarily exist anywhere on disk, and which gets mmap()ed into
+// every process by kernels which support VDSO, such as 2.6.x for 32-bit
+// executables, and 2.6.24 and above for 64-bit executables.
+//
+// More details could be found here:
+// http://www.trilithium.com/johan/2005/08/linux-gate/
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+//
+// Example usage:
+//  VDSOSupport vdso;
+//  VDSOSupport::SymbolInfo info;
+//  typedef (*FN)(unsigned *, void *, void *);
+//  FN fn = nullptr;
+//  if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+//     fn = reinterpret_cast<FN>(info.address);
+//  }
+
+#ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
+#define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/debugging/internal/elf_mem_image.h"
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+#error ABSL_HAVE_VDSO_SUPPORT cannot be directly set
+#else
+#define ABSL_HAVE_VDSO_SUPPORT 1
+#endif
+
+namespace absl {
+namespace debugging_internal {
+
+// NOTE: this class may be used from within tcmalloc, and can not
+// use any memory allocation routines.
+class VDSOSupport {
+ public:
+  VDSOSupport();
+
+  typedef ElfMemImage::SymbolInfo SymbolInfo;
+  typedef ElfMemImage::SymbolIterator SymbolIterator;
+
+  // On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE
+  // depending on how the kernel is built.  The kernel is normally built with
+  // STT_NOTYPE type VDSO symbols.  Let's make things simpler first by using a
+  // compile-time constant.
+#ifdef __powerpc64__
+  enum { kVDSOSymbolType = STT_NOTYPE };
+#else
+  enum { kVDSOSymbolType = STT_FUNC };
+#endif
+
+  // Answers whether we have a vdso at all.
+  bool IsPresent() const { return image_.IsPresent(); }
+
+  // Allow to iterate over all VDSO symbols.
+  SymbolIterator begin() const { return image_.begin(); }
+  SymbolIterator end() const { return image_.end(); }
+
+  // Look up versioned dynamic symbol in the kernel VDSO.
+  // Returns false if VDSO is not present, or doesn't contain given
+  // symbol/version/type combination.
+  // If info_out != nullptr, additional details are filled in.
+  bool LookupSymbol(const char *name, const char *version,
+                    int symbol_type, SymbolInfo *info_out) const;
+
+  // Find info about symbol (if any) which overlaps given address.
+  // Returns true if symbol was found; false if VDSO isn't present
+  // or doesn't have a symbol overlapping given address.
+  // If info_out != nullptr, additional details are filled in.
+  bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+  // Used only for testing. Replace real VDSO base with a mock.
+  // Returns previous value of vdso_base_. After you are done testing,
+  // you are expected to call SetBase() with previous value, in order to
+  // reset state to the way it was.
+  const void *SetBase(const void *s);
+
+  // Computes vdso_base_ and returns it. Should be called as early as
+  // possible; before any thread creation, chroot or setuid.
+  static const void *Init();
+
+ private:
+  // image_ represents VDSO ELF image in memory.
+  // image_.ehdr_ == nullptr implies there is no VDSO.
+  ElfMemImage image_;
+
+  // Cached value of auxv AT_SYSINFO_EHDR, computed once.
+  // This is a tri-state:
+  //   kInvalidBase   => value hasn't been determined yet.
+  //              0   => there is no VDSO.
+  //           else   => vma of VDSO Elf{32,64}_Ehdr.
+  //
+  // When testing with mock VDSO, low bit is set.
+  // The low bit is always available because vdso_base_ is
+  // page-aligned.
+  static std::atomic<const void *> vdso_base_;
+
+  // NOLINT on 'long' because these routines mimic kernel api.
+  // The 'cache' parameter may be used by some versions of the kernel,
+  // and should be nullptr or point to a static buffer containing at
+  // least two 'long's.
+  static long InitAndGetCPU(unsigned *cpu, void *cache,     // NOLINT 'long'.
+                            void *unused);
+  static long GetCPUViaSyscall(unsigned *cpu, void *cache,  // NOLINT 'long'.
+                               void *unused);
+  typedef long (*GetCpuFn)(unsigned *cpu, void *cache,      // NOLINT 'long'.
+                           void *unused);
+
+  // This function pointer may point to InitAndGetCPU,
+  // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
+  ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_;
+
+  friend int GetCPU(void);  // Needs access to getcpu_fn_.
+
+  VDSOSupport(const VDSOSupport&) = delete;
+  VDSOSupport& operator=(const VDSOSupport&) = delete;
+};
+
+// Same as sched_getcpu() on later glibc versions.
+// Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
+// otherwise use syscall(SYS_getcpu,...).
+// May return -1 with errno == ENOSYS if the kernel doesn't
+// support SYS_getcpu.
+int GetCPU();
+
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_ELF_MEM_IMAGE
+
+#endif  // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
new file mode 100644
index 0000000..e01e5f8
--- /dev/null
+++ b/absl/debugging/leak_check.cc
@@ -0,0 +1,48 @@
+// Copyright 2017 The Abseil 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.
+// Wrappers around lsan_interface functions.
+// When lsan is not linked in, these functions are not available,
+// therefore Abseil code which depends on these functions is conditioned on the
+// definition of LEAK_SANITIZER.
+#include "absl/debugging/leak_check.h"
+
+#ifndef LEAK_SANITIZER
+
+namespace absl {
+bool HaveLeakSanitizer() { return false; }
+void DoIgnoreLeak(const void*) { }
+void RegisterLivePointers(const void*, size_t) { }
+void UnRegisterLivePointers(const void*, size_t) { }
+LeakCheckDisabler::LeakCheckDisabler() { }
+LeakCheckDisabler::~LeakCheckDisabler() { }
+}  // namespace absl
+
+#else
+
+#include <sanitizer/lsan_interface.h>
+
+namespace absl {
+bool HaveLeakSanitizer() { return true; }
+void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
+void RegisterLivePointers(const void* ptr, size_t size) {
+  __lsan_register_root_region(ptr, size);
+}
+void UnRegisterLivePointers(const void* ptr, size_t size) {
+  __lsan_unregister_root_region(ptr, size);
+}
+LeakCheckDisabler::LeakCheckDisabler() { __lsan_disable(); }
+LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); }
+}  // namespace absl
+
+#endif  // LEAK_SANITIZER
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h
new file mode 100644
index 0000000..c930684
--- /dev/null
+++ b/absl/debugging/leak_check.h
@@ -0,0 +1,109 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: leak_check.h
+// -----------------------------------------------------------------------------
+//
+// This file contains functions that affect leak checking behavior within
+// targets built with the LeakSanitizer (LSan), a memory leak detector that is
+// integrated within the AddressSanitizer (ASan) as an additional component, or
+// which can be used standalone. LSan and ASan are included (or can be provided)
+// as additional components for most compilers such as Clang, gcc and MSVC.
+// Note: this leak checking API is not yet supported in MSVC.
+// Leak checking is enabled by default in all ASan builds.
+//
+// See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
+//
+// -----------------------------------------------------------------------------
+#ifndef ABSL_DEBUGGING_LEAK_CHECK_H_
+#define ABSL_DEBUGGING_LEAK_CHECK_H_
+
+#include <cstddef>
+
+namespace absl {
+
+// HaveLeakSanitizer()
+//
+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is
+// currently built into this target.
+bool HaveLeakSanitizer();
+
+// DoIgnoreLeak()
+//
+// Implements `IgnoreLeak()` below. This function should usually
+// not be called directly; calling `IgnoreLeak()` is preferred.
+void DoIgnoreLeak(const void* ptr);
+
+// IgnoreLeak()
+//
+// Instruct the leak sanitizer to ignore leak warnings on the object referenced
+// by the passed pointer, as well as all heap objects transitively referenced
+// by it. The passed object pointer can point to either the beginning of the
+// object or anywhere within it.
+//
+// Example:
+//
+//   static T* obj = IgnoreLeak(new T(...));
+//
+// If the passed `ptr` does not point to an actively allocated object at the
+// time `IgnoreLeak()` is called, the call is a no-op; if it is actively
+// allocated, the object must not get deallocated later.
+//
+template <typename T>
+T* IgnoreLeak(T* ptr) {
+  DoIgnoreLeak(ptr);
+  return ptr;
+}
+
+// LeakCheckDisabler
+//
+// This helper class indicates that any heap allocations done in the code block
+// covered by the scoped object, which should be allocated on the stack, will
+// not be reported as leaks. Leak check disabling will occur within the code
+// block and any nested function calls within the code block.
+//
+// Example:
+//
+//   void Foo() {
+//     LeakCheckDisabler disabler;
+//     ... code that allocates objects whose leaks should be ignored ...
+//   }
+//
+// REQUIRES: Destructor runs in same thread as constructor
+class LeakCheckDisabler {
+ public:
+  LeakCheckDisabler();
+  LeakCheckDisabler(const LeakCheckDisabler&) = delete;
+  LeakCheckDisabler& operator=(const LeakCheckDisabler&) = delete;
+  ~LeakCheckDisabler();
+};
+
+// RegisterLivePointers()
+//
+// Registers `ptr[0,size-1]` as pointers to memory that is still actively being
+// referenced and for which leak checking should be ignored. This function is
+// useful if you store pointers in mapped memory, for memory ranges that we know
+// are correct but for which normal analysis would flag as leaked code.
+void RegisterLivePointers(const void* ptr, size_t size);
+
+// UnRegisterLivePointers()
+//
+// Deregisters the pointers previously marked as active in
+// `RegisterLivePointers()`, enabling leak checking of those pointers.
+void UnRegisterLivePointers(const void* ptr, size_t size);
+
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_LEAK_CHECK_H_
diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc
new file mode 100644
index 0000000..df22c1c
--- /dev/null
+++ b/absl/debugging/leak_check_disable.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Abseil 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.
+
+// Disable LeakSanitizer when this file is linked in.
+// This function overrides __lsan_is_turned_off from sanitizer/lsan_interface.h
+extern "C" int __lsan_is_turned_off();
+extern "C" int __lsan_is_turned_off() {
+  return 1;
+}
diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc
new file mode 100644
index 0000000..bf541fe
--- /dev/null
+++ b/absl/debugging/leak_check_fail_test.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 The Abseil 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 <memory>
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/leak_check.h"
+
+namespace {
+
+TEST(LeakCheckTest, LeakMemory) {
+  // This test is expected to cause lsan failures on program exit. Therefore the
+  // test will be run only by leak_check_test.sh, which will verify a
+  // failed exit code.
+
+  char* foo = strdup("lsan should complain about this leaked string");
+  ABSL_RAW_LOG(INFO, "Should detect leaked std::string %s", foo);
+}
+
+TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) {
+  // This test is expected to cause lsan failures on program exit. Therefore the
+  // test will be run only by external_leak_check_test.sh, which will verify a
+  // failed exit code.
+  { absl::LeakCheckDisabler disabler; }
+  char* foo = strdup("lsan should also complain about this leaked string");
+  ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked std::string %s",
+               foo);
+}
+
+}  // namespace
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc
new file mode 100644
index 0000000..febd1ee
--- /dev/null
+++ b/absl/debugging/leak_check_test.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 The Abseil 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 <string>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/leak_check.h"
+
+namespace {
+
+TEST(LeakCheckTest, DetectLeakSanitizer) {
+#ifdef ABSL_EXPECT_LEAK_SANITIZER
+  EXPECT_TRUE(absl::HaveLeakSanitizer());
+#else
+  EXPECT_FALSE(absl::HaveLeakSanitizer());
+#endif
+}
+
+TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) {
+  auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string"));
+  ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str());
+}
+
+TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) {
+  absl::LeakCheckDisabler disabler;
+  auto foo = new std::string("some std::string leaked while checks are disabled");
+  ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str());
+}
+
+}  // namespace
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
new file mode 100644
index 0000000..61fee61
--- /dev/null
+++ b/absl/debugging/stacktrace.cc
@@ -0,0 +1,133 @@
+// Copyright 2017 The Abseil 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.
+
+// Produce stack trace.
+//
+// There are three different ways we can try to get the stack trace:
+//
+// 1) Our hand-coded stack-unwinder.  This depends on a certain stack
+//    layout, which is used by gcc (and those systems using a
+//    gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
+//    It uses the frame pointer to do its work.
+//
+// 2) The libunwind library.  This is still in development, and as a
+//    separate library adds a new dependency, but doesn't need a frame
+//    pointer.  It also doesn't call malloc.
+//
+// 3) The gdb unwinder -- also the one used by the c++ exception code.
+//    It's obviously well-tested, but has a fatal flaw: it can call
+//    malloc() from the unwinder.  This is a problem because we're
+//    trying to use the unwinder to instrument malloc().
+//
+// Note: if you add a new implementation here, make sure it works
+// correctly when absl::GetStackTrace() is called with max_depth == 0.
+// Some code may do that.
+
+#include "absl/debugging/stacktrace.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/stacktrace_config.h"
+
+#if defined(ABSL_STACKTRACE_INL_HEADER)
+#include ABSL_STACKTRACE_INL_HEADER
+#else
+# error Cannot calculate stack trace: will need to write for your environment
+# include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+# include "absl/debugging/internal/stacktrace_arm-inl.inc"
+# include "absl/debugging/internal/stacktrace_generic-inl.inc"
+# include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+# include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+# include "absl/debugging/internal/stacktrace_win32-inl.inc"
+# include "absl/debugging/internal/stacktrace_x86-inl.inc"
+#endif
+
+namespace absl {
+namespace {
+
+typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
+std::atomic<Unwinder> custom;
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
+                                               int max_depth, int skip_count,
+                                               const void* uc,
+                                               int* min_dropped_frames) {
+  Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
+  Unwinder g = custom.load(std::memory_order_acquire);
+  if (g != nullptr) f = g;
+
+  // Add 1 to skip count for the unwinder function itself
+  int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
+                  min_dropped_frames);
+  // To disable tail call to (*f)(...)
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+  return size;
+}
+
+}  // anonymous namespace
+
+int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count) {
+  return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
+                             nullptr);
+}
+
+int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+                              int skip_count, const void* uc,
+                              int* min_dropped_frames) {
+  return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
+                            min_dropped_frames);
+}
+
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+  return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
+                              nullptr);
+}
+
+int GetStackTraceWithContext(void** result, int max_depth, int skip_count,
+                             const void* uc, int* min_dropped_frames) {
+  return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
+                             min_dropped_frames);
+}
+
+void SetStackUnwinder(Unwinder w) {
+  custom.store(w, std::memory_order_release);
+}
+
+int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
+                         const void* uc, int* min_dropped_frames) {
+  skip++;  // For this function
+  Unwinder f = nullptr;
+  if (sizes == nullptr) {
+    if (uc == nullptr) {
+      f = &UnwindImpl<false, false>;
+    } else {
+      f = &UnwindImpl<false, true>;
+    }
+  } else {
+    if (uc == nullptr) {
+      f = &UnwindImpl<true, false>;
+    } else {
+      f = &UnwindImpl<true, true>;
+    }
+  }
+  volatile int x = 0;
+  int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
+  x = 1; (void) x;  // To disable tail call to (*f)(...)
+  return n;
+}
+
+}  // namespace absl
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
new file mode 100644
index 0000000..8b831e2
--- /dev/null
+++ b/absl/debugging/stacktrace.h
@@ -0,0 +1,225 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: stacktrace.h
+// -----------------------------------------------------------------------------
+//
+// This file contains routines to extract the current stack trace and associated
+// stack frames. These functions are thread-safe and async-signal-safe.
+//
+// Note that stack trace functionality is platform dependent and requires
+// additional support from the compiler/build system in most cases. (That is,
+// this functionality generally only works on platforms/builds that have been
+// specifically configured to support it.)
+//
+// Note: stack traces in Abseil that do not utilize a symbolizer will result in
+// frames consisting of function addresses rather than human-readable function
+// names. (See symbolize.h for information on symbolizing these values.)
+
+#ifndef ABSL_DEBUGGING_STACKTRACE_H_
+#define ABSL_DEBUGGING_STACKTRACE_H_
+
+namespace absl {
+
+// GetStackFrames()
+//
+// Records program counter values for up to `max_depth` frames, skipping the
+// most recent `skip_count` stack frames, and stores their corresponding values
+// and sizes in `results` and `sizes` buffers. (Note that the frame generated
+// for the `absl::GetStackFrames()` routine itself is also skipped.)
+// routine itself.
+//
+// Example:
+//
+//      main() { foo(); }
+//      foo() { bar(); }
+//      bar() {
+//        void* result[10];
+//        int sizes[10];
+//        int depth = absl::GetStackFrames(result, sizes, 10, 1);
+//      }
+//
+// The current stack frame would consist of three function calls: `bar()`,
+// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
+// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
+// invoked function call. It will therefore return two program counters and will
+// produce values that map to the following function calls:
+//
+//      result[0]       foo()
+//      result[1]       main()
+//
+// (Note: in practice, a few more entries after `main()` may be added to account
+// for startup processes.)
+//
+// Corresponding stack frame sizes will also be recorded:
+//
+//    sizes[0]       16
+//    sizes[1]       16
+//
+// (Stack frame sizes of `16` above are just for illustration purposes.)
+//
+// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
+// be identified.
+//
+// This routine may return fewer stack frame entries than are
+// available. Also note that `result` and `sizes` must both be non-null.
+extern int GetStackFrames(void** result, int* sizes, int max_depth,
+                          int skip_count);
+
+// GetStackFramesWithContext()
+//
+// Records program counter values obtained from a signal handler. Records
+// program counter values for up to `max_depth` frames, skipping the most recent
+// `skip_count` stack frames, and stores their corresponding values and sizes in
+// `results` and `sizes` buffers. (Note that the frame generated for the
+// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+//
+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
+// passed to a signal handler registered via the `sa_sigaction` field of a
+// `sigaction` struct. (See
+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
+// help a stack unwinder to provide a better stack trace under certain
+// conditions. `uc` may safely be null.
+//
+// The `min_dropped_frames` output parameter, if non-null, points to the
+// location to note any dropped stack frames, if any, due to buffer limitations
+// or other reasons. (This value will be set to `0` if no frames were dropped.)
+// The number of total stack frames is guaranteed to be >= skip_count +
+// max_depth + *min_dropped_frames.
+extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+                                     int skip_count, const void* uc,
+                                     int* min_dropped_frames);
+
+// GetStackTrace()
+//
+// Records program counter values for up to `max_depth` frames, skipping the
+// most recent `skip_count` stack frames, and stores their corresponding values
+// in `results`. Note that this function is similar to `absl::GetStackFrames()`
+// except that it returns the stack trace only, and not stack frame sizes.
+//
+// Example:
+//
+//      main() { foo(); }
+//      foo() { bar(); }
+//      bar() {
+//        void* result[10];
+//        int depth = absl::GetStackTrace(result, 10, 1);
+//      }
+//
+// This produces:
+//
+//      result[0]       foo
+//      result[1]       main
+//           ....       ...
+//
+// `result` must not be null.
+extern int GetStackTrace(void** result, int max_depth, int skip_count);
+
+// GetStackTraceWithContext()
+//
+// Records program counter values obtained from a signal handler. Records
+// program counter values for up to `max_depth` frames, skipping the most recent
+// `skip_count` stack frames, and stores their corresponding values in
+// `results`. (Note that the frame generated for the
+// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+//
+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
+// passed to a signal handler registered via the `sa_sigaction` field of a
+// `sigaction` struct. (See
+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
+// help a stack unwinder to provide a better stack trace under certain
+// conditions. `uc` may safely be null.
+//
+// The `min_dropped_frames` output parameter, if non-null, points to the
+// location to note any dropped stack frames, if any, due to buffer limitations
+// or other reasons. (This value will be set to `0` if no frames were dropped.)
+// The number of total stack frames is guaranteed to be >= skip_count +
+// max_depth + *min_dropped_frames.
+extern int GetStackTraceWithContext(void** result, int max_depth,
+                                    int skip_count, const void* uc,
+                                    int* min_dropped_frames);
+
+// SetStackUnwinder()
+//
+// Provides a custom function for unwinding stack frames that will be used in
+// place of the default stack unwinder when invoking the static
+// GetStack{Frames,Trace}{,WithContext}() functions above.
+//
+// The arguments passed to the unwinder function will match the
+// arguments passed to `absl::GetStackFramesWithContext()` except that sizes
+// will be non-null iff the caller is interested in frame sizes.
+//
+// If unwinder is set to null, we revert to the default stack-tracing behavior.
+//
+// *****************************************************************************
+// WARNING
+// *****************************************************************************
+//
+// absl::SetStackUnwinder is not suitable for general purpose use.  It is
+// provided for custom runtimes.
+// Some things to watch out for when calling `absl::SetStackUnwinder()`:
+//
+// (a) The unwinder may be called from within signal handlers and
+// therefore must be async-signal-safe.
+//
+// (b) Even after a custom stack unwinder has been unregistered, other
+// threads may still be in the process of using that unwinder.
+// Therefore do not clean up any state that may be needed by an old
+// unwinder.
+// *****************************************************************************
+extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes,
+                                             int max_depth, int skip_count,
+                                             const void* uc,
+                                             int* min_dropped_frames));
+
+// DefaultStackUnwinder()
+//
+// Records program counter values of up to `max_depth` frames, skipping the most
+// recent `skip_count` stack frames, and stores their corresponding values in
+// `pcs`. (Note that the frame generated for this call itself is also skipped.)
+// This function acts as a generic stack-unwinder; prefer usage of the more
+// specific `GetStack{Trace,Frames}{,WithContext}()` functions above.
+//
+// If you have set your own stack unwinder (with the `SetStackUnwinder()`
+// function above, you can still get the default stack unwinder by calling
+// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder
+// and use the default one instead.
+//
+// Because this function is generic, only `pcs` is guaranteed to be non-null
+// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all
+// be null when called.
+//
+// The semantics are the same as the corresponding `GetStack*()` function in the
+// case where `absl::SetStackUnwinder()` was never called. Equivalents are:
+//
+//                       null sizes         |        non-nullptr sizes
+//             |==========================================================|
+//     null uc | GetStackTrace()            | GetStackFrames()            |
+// non-null uc | GetStackTraceWithContext() | GetStackFramesWithContext() |
+//             |==========================================================|
+extern int DefaultStackUnwinder(void** pcs, int* sizes, int max_depth,
+                                int skip_count, const void* uc,
+                                int* min_dropped_frames);
+
+namespace debugging_internal {
+// Returns true for platforms which are expected to have functioning stack trace
+// implementations. Intended to be used for tests which want to exclude
+// verification of logic known to be broken because stack traces are not
+// working.
+extern bool StackTraceWorksForTest();
+}  // namespace debugging_internal
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_STACKTRACE_H_
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
new file mode 100644
index 0000000..a35e24c
--- /dev/null
+++ b/absl/debugging/symbolize.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Abseil 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 "absl/debugging/symbolize.h"
+
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
+#include "absl/debugging/symbolize_elf.inc"
+#elif defined(_WIN32) && defined(_DEBUG)
+// The Windows Symbolizer only works in debug mode. Note that _DEBUG
+// is the macro that defines whether or not MS C-Runtime debug info is
+// available. Note that the PDB files containing the debug info must
+// also be available to the program at runtime for the symbolizer to
+// work.
+#include "absl/debugging/symbolize_win32.inc"
+#else
+#include "absl/debugging/symbolize_unimplemented.inc"
+#endif
diff --git a/absl/debugging/symbolize.h b/absl/debugging/symbolize.h
new file mode 100644
index 0000000..24e6e64
--- /dev/null
+++ b/absl/debugging/symbolize.h
@@ -0,0 +1,97 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: symbolize.h
+// -----------------------------------------------------------------------------
+//
+// This file configures the Abseil symbolizer for use in converting instruction
+// pointer addresses (program counters) into human-readable names (function
+// calls, etc.) within Abseil code.
+//
+// The symbolizer may be invoked from several sources:
+//
+//   * Implicitly, through the installation of an Abseil failure signal handler.
+//     (See failure_signal_handler.h for more information.)
+//   * By calling `Symbolize()` directly on a program counter you obtain through
+//     `absl::GetStackTrace()` or `absl::GetStackFrames()`. (See stacktrace.h
+//     for more information.
+//   * By calling `Symbolize()` directly on a program counter you obtain through
+//     other means (which would be platform-dependent).
+//
+// In all of the above cases, the symbolizer must first be initialized before
+// any program counter values can be symbolized. If you are installing a failure
+// signal handler, initialize the symbolizer before you do so.
+//
+// Example:
+//
+//   int main(int argc, char** argv) {
+//     // Initialize the Symbolizer before installing the failure signal handler
+//     absl::InitializeSymbolizer(argv[0]);
+//
+//     // Now you may install the failure signal handler
+//     absl::FailureSignalHandlerOptions options;
+//     absl::InstallFailureSignalHandler(options);
+//
+//     // Start running your main program
+//     ...
+//     return 0;
+//  }
+//
+#ifndef ABSL_DEBUGGING_SYMBOLIZE_H_
+#define ABSL_DEBUGGING_SYMBOLIZE_H_
+
+#include "absl/debugging/internal/symbolize.h"
+
+namespace absl {
+
+// InitializeSymbolizer()
+//
+// Initializes the program counter symbolizer, given the path of the program
+// (typically obtained through `main()`s `argv[0]`). The Abseil symbolizer
+// allows you to read program counters (instruction pointer values) using their
+// human-readable names within output such as stack traces.
+//
+// Example:
+//
+// int main(int argc, char *argv[]) {
+//   absl::InitializeSymbolizer(argv[0]);
+//   // Now you can use the symbolizer
+// }
+void InitializeSymbolizer(const char* argv0);
+
+// Symbolize()
+//
+// Symbolizes a program counter (instruction pointer value) `pc` and, on
+// success, writes the name to `out`. The symbol name is demangled, if possible.
+// Note that the symbolized name may be truncated and will be NUL-terminated.
+// Demangling is supported for symbols generated by GCC 3.x or newer). Returns
+// `false` on failure.
+//
+// Example:
+//
+//   // Print a program counter and its symbol name.
+//   static void DumpPCAndSymbol(void *pc) {
+//     char tmp[1024];
+//     const char *symbol = "(unknown)";
+//     if (absl::Symbolize(pc, tmp, sizeof(tmp))) {
+//       symbol = tmp;
+//     }
+//     absl::PrintF("%*p  %s\n", pc, symbol);
+//  }
+bool Symbolize(const void *pc, char *out, int out_size);
+
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_SYMBOLIZE_H_
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
new file mode 100644
index 0000000..b16a42a
--- /dev/null
+++ b/absl/debugging/symbolize_elf.inc
@@ -0,0 +1,1473 @@
+// Copyright 2018 The Abseil 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.
+
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+//   1. Go through a list of maps in /proc/self/maps and find the map
+//   containing the program counter.
+//
+//   2. Open the mapped file and find a regular symbol table inside.
+//   Iterate over symbols in the symbol table and look for the symbol
+//   containing the program counter.  If such a symbol is found,
+//   obtain the symbol name, and demangle the symbol if possible.
+//   If the symbol isn't found in the regular symbol table (binary is
+//   stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// signal handlers, hence it doesn't use malloc() and other unsafe
+// operations.  It should be both thread-safe and async-signal-safe.
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks.  We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym)  = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym)  = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses some
+// functions which are not guaranteed to be so, such as memchr() and
+// memmove().  We assume they are async-signal-safe.
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <link.h>  // For ElfW() macro.
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <cinttypes>
+#include <climits>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "absl/base/casts.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/debugging/internal/vdso_support.h"
+
+namespace absl {
+
+// Value of argv[0]. Used by MaybeInitializeObjFile().
+static char *argv0_value = nullptr;
+
+void InitializeSymbolizer(const char *argv0) {
+  if (argv0_value != nullptr) {
+    free(argv0_value);
+    argv0_value = nullptr;
+  }
+  if (argv0 != nullptr && argv0[0] != '\0') {
+    argv0_value = strdup(argv0);
+  }
+}
+
+namespace debugging_internal {
+namespace {
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn) \
+  do {              \
+  } while ((fn) < 0 && errno == EINTR)
+
+// On Linux, ELF_ST_* are defined in <linux/elf.h>.  To make this portable
+// we define our own ELF_ST_BIND and ELF_ST_TYPE if not available.
+#ifndef ELF_ST_BIND
+#define ELF_ST_BIND(info) (((unsigned char)(info)) >> 4)
+#endif
+
+#ifndef ELF_ST_TYPE
+#define ELF_ST_TYPE(info) (((unsigned char)(info)) & 0xF)
+#endif
+
+// Some platforms use a special .opd section to store function pointers.
+const char kOpdSectionName[] = ".opd";
+
+#if (defined(__powerpc__) && !(_CALL_ELF > 1)) || defined(__ia64)
+// Use opd section for function descriptors on these platforms, the function
+// address is the first word of the descriptor.
+enum { kPlatformUsesOPDSections = 1 };
+#else  // not PPC or IA64
+enum { kPlatformUsesOPDSections = 0 };
+#endif
+
+// This works for PowerPC & IA64 only.  A function descriptor consist of two
+// pointers and the first one is the function's entry.
+const size_t kFunctionDescriptorSize = sizeof(void *) * 2;
+
+const int kMaxDecorators = 10;  // Seems like a reasonable upper limit.
+
+struct InstalledSymbolDecorator {
+  SymbolDecorator fn;
+  void *arg;
+  int ticket;
+};
+
+int g_num_decorators;
+InstalledSymbolDecorator g_decorators[kMaxDecorators];
+
+struct FileMappingHint {
+  const void *start;
+  const void *end;
+  uint64_t offset;
+  const char *filename;
+};
+
+// Protects g_decorators.
+// We are using SpinLock and not a Mutex here, because we may be called
+// from inside Mutex::Lock itself, and it prohibits recursive calls.
+// This happens in e.g. base/stacktrace_syscall_unittest.
+// Moreover, we are using only TryLock(), if the decorator list
+// is being modified (is busy), we skip all decorators, and possibly
+// loose some info. Sorry, that's the best we could do.
+base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized);
+
+const int kMaxFileMappingHints = 8;
+int g_num_file_mapping_hints;
+FileMappingHint g_file_mapping_hints[kMaxFileMappingHints];
+// Protects g_file_mapping_hints.
+base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized);
+
+// Async-signal-safe function to zero a buffer.
+// memset() is not guaranteed to be async-signal-safe.
+static void SafeMemZero(void* p, size_t size) {
+  unsigned char *c = static_cast<unsigned char *>(p);
+  while (size--) {
+    *c++ = 0;
+  }
+}
+
+struct ObjFile {
+  ObjFile()
+      : filename(nullptr),
+        start_addr(nullptr),
+        end_addr(nullptr),
+        offset(0),
+        fd(-1),
+        elf_type(-1) {
+    SafeMemZero(&elf_header, sizeof(elf_header));
+  }
+
+  char *filename;
+  const void *start_addr;
+  const void *end_addr;
+  uint64_t offset;
+
+  // The following fields are initialized on the first access to the
+  // object file.
+  int fd;
+  int elf_type;
+  ElfW(Ehdr) elf_header;
+};
+
+// Build 4-way associative cache for symbols. Within each cache line, symbols
+// are replaced in LRU order.
+enum {
+  ASSOCIATIVITY = 4,
+};
+struct SymbolCacheLine {
+  const void *pc[ASSOCIATIVITY];
+  char *name[ASSOCIATIVITY];
+
+  // age[i] is incremented when a line is accessed. it's reset to zero if the
+  // i'th entry is read.
+  uint32_t age[ASSOCIATIVITY];
+};
+
+// ---------------------------------------------------------------
+// An async-signal-safe arena for LowLevelAlloc
+static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
+
+static base_internal::LowLevelAlloc::Arena *SigSafeArena() {
+  return g_sig_safe_arena.load(std::memory_order_acquire);
+}
+
+static void InitSigSafeArena() {
+  if (SigSafeArena() == nullptr) {
+    base_internal::LowLevelAlloc::Arena *new_arena =
+        base_internal::LowLevelAlloc::NewArena(
+            base_internal::LowLevelAlloc::kAsyncSignalSafe);
+    base_internal::LowLevelAlloc::Arena *old_value = nullptr;
+    if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
+                                                  std::memory_order_release,
+                                                  std::memory_order_relaxed)) {
+      // We lost a race to allocate an arena; deallocate.
+      base_internal::LowLevelAlloc::DeleteArena(new_arena);
+    }
+  }
+}
+
+// ---------------------------------------------------------------
+// An AddrMap is a vector of ObjFile, using SigSafeArena() for allocation.
+
+class AddrMap {
+ public:
+  AddrMap() : size_(0), allocated_(0), obj_(nullptr) {}
+  ~AddrMap() { base_internal::LowLevelAlloc::Free(obj_); }
+  int Size() const { return size_; }
+  ObjFile *At(int i) { return &obj_[i]; }
+  ObjFile *Add();
+  void Clear();
+
+ private:
+  int size_;       // count of valid elements (<= allocated_)
+  int allocated_;  // count of allocated elements
+  ObjFile *obj_;   // array of allocated_ elements
+  AddrMap(const AddrMap &) = delete;
+  AddrMap &operator=(const AddrMap &) = delete;
+};
+
+void AddrMap::Clear() {
+  for (int i = 0; i != size_; i++) {
+    At(i)->~ObjFile();
+  }
+  size_ = 0;
+}
+
+ObjFile *AddrMap::Add() {
+  if (size_ == allocated_) {
+    int new_allocated = allocated_ * 2 + 50;
+    ObjFile *new_obj_ =
+        static_cast<ObjFile *>(base_internal::LowLevelAlloc::AllocWithArena(
+            new_allocated * sizeof(*new_obj_), SigSafeArena()));
+    if (obj_) {
+      memcpy(new_obj_, obj_, allocated_ * sizeof(*new_obj_));
+      base_internal::LowLevelAlloc::Free(obj_);
+    }
+    obj_ = new_obj_;
+    allocated_ = new_allocated;
+  }
+  return new (&obj_[size_++]) ObjFile;
+}
+
+// ---------------------------------------------------------------
+
+enum FindSymbolResult { SYMBOL_NOT_FOUND = 1, SYMBOL_TRUNCATED, SYMBOL_FOUND };
+
+class Symbolizer {
+ public:
+  Symbolizer();
+  ~Symbolizer();
+  const char *GetSymbol(const void *const pc);
+
+ private:
+  char *CopyString(const char *s) {
+    int len = strlen(s);
+    char *dst = static_cast<char *>(
+        base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
+    ABSL_RAW_CHECK(dst != nullptr, "out of memory");
+    memcpy(dst, s, len + 1);
+    return dst;
+  }
+  ObjFile *FindObjFile(const void *const start,
+                       size_t size) ABSL_ATTRIBUTE_NOINLINE;
+  static bool RegisterObjFile(const char *filename,
+                              const void *const start_addr,
+                              const void *const end_addr, uint64_t offset,
+                              void *arg);
+  SymbolCacheLine *GetCacheLine(const void *const pc);
+  const char *FindSymbolInCache(const void *const pc);
+  const char *InsertSymbolInCache(const void *const pc, const char *name);
+  void AgeSymbols(SymbolCacheLine *line);
+  void ClearAddrMap();
+  FindSymbolResult GetSymbolFromObjectFile(const ObjFile &obj,
+                                           const void *const pc,
+                                           const ptrdiff_t relocation,
+                                           char *out, int out_size,
+                                           char *tmp_buf, int tmp_buf_size);
+
+  enum {
+    SYMBOL_BUF_SIZE = 2048,
+    TMP_BUF_SIZE = 1024,
+    SYMBOL_CACHE_LINES = 128,
+  };
+
+  AddrMap addr_map_;
+
+  bool ok_;
+  bool addr_map_read_;
+
+  char symbol_buf_[SYMBOL_BUF_SIZE];
+
+  // tmp_buf_ will be used to store arrays of ElfW(Shdr) and ElfW(Sym)
+  // so we ensure that tmp_buf_ is properly aligned to store either.
+  alignas(16) char tmp_buf_[TMP_BUF_SIZE];
+  static_assert(alignof(ElfW(Shdr)) <= 16,
+                "alignment of tmp buf too small for Shdr");
+  static_assert(alignof(ElfW(Sym)) <= 16,
+                "alignment of tmp buf too small for Sym");
+
+  SymbolCacheLine symbol_cache_[SYMBOL_CACHE_LINES];
+};
+
+static std::atomic<Symbolizer *> g_cached_symbolizer;
+
+}  // namespace
+
+static int SymbolizerSize() {
+  int pagesize = getpagesize();
+  return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize;
+}
+
+// Return (and set null) g_cached_symbolized_state if it is not null.
+// Otherwise return a new symbolizer.
+static Symbolizer *AllocateSymbolizer() {
+  InitSigSafeArena();
+  Symbolizer *symbolizer =
+      g_cached_symbolizer.exchange(nullptr, std::memory_order_acquire);
+  if (symbolizer != nullptr) {
+    return symbolizer;
+  }
+  return new (base_internal::LowLevelAlloc::AllocWithArena(
+      SymbolizerSize(), SigSafeArena())) Symbolizer();
+}
+
+// Set g_cached_symbolize_state to s if it is null, otherwise
+// delete s.
+static void FreeSymbolizer(Symbolizer *s) {
+  Symbolizer *old_cached_symbolizer = nullptr;
+  if (!g_cached_symbolizer.compare_exchange_strong(old_cached_symbolizer, s,
+                                                   std::memory_order_release,
+                                                   std::memory_order_relaxed)) {
+    s->~Symbolizer();
+    base_internal::LowLevelAlloc::Free(s);
+  }
+}
+
+Symbolizer::Symbolizer() : ok_(true), addr_map_read_(false) {
+  for (SymbolCacheLine &symbol_cache_line : symbol_cache_) {
+    for (size_t j = 0; j < ABSL_ARRAYSIZE(symbol_cache_line.name); ++j) {
+      symbol_cache_line.pc[j] = nullptr;
+      symbol_cache_line.name[j] = nullptr;
+      symbol_cache_line.age[j] = 0;
+    }
+  }
+}
+
+Symbolizer::~Symbolizer() {
+  for (SymbolCacheLine &symbol_cache_line : symbol_cache_) {
+    for (char *s : symbol_cache_line.name) {
+      base_internal::LowLevelAlloc::Free(s);
+    }
+  }
+  ClearAddrMap();
+}
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe.  Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+#define SAFE_ASSERT(expr) ((expr) ? static_cast<void>(0) : abort())
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR.  On
+// success, return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadPersistent(int fd, void *buf, size_t count) {
+  SAFE_ASSERT(fd >= 0);
+  SAFE_ASSERT(count <= SSIZE_MAX);
+  char *buf0 = reinterpret_cast<char *>(buf);
+  size_t num_bytes = 0;
+  while (num_bytes < count) {
+    ssize_t len;
+    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+    if (len < 0) {  // There was an error other than EINTR.
+      ABSL_RAW_LOG(WARNING, "read failed: errno=%d", errno);
+      return -1;
+    }
+    if (len == 0) {  // Reached EOF.
+      break;
+    }
+    num_bytes += len;
+  }
+  SAFE_ASSERT(num_bytes <= count);
+  return static_cast<ssize_t>(num_bytes);
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf".  On success,
+// return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
+                              const off_t offset) {
+  off_t off = lseek(fd, offset, SEEK_SET);
+  if (off == (off_t)-1) {
+    ABSL_RAW_LOG(WARNING, "lseek(%d, %ju, SEEK_SET) failed: errno=%d", fd,
+                 static_cast<uintmax_t>(offset), errno);
+    return -1;
+  }
+  return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR.  On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf, const size_t count,
+                                const off_t offset) {
+  ssize_t len = ReadFromOffset(fd, buf, count, offset);
+  return len >= 0 && static_cast<size_t>(len) == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return -1;
+  }
+  if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+    return -1;
+  }
+  return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(
+    const int fd, ElfW(Half) sh_num, const off_t sh_offset, ElfW(Word) type,
+    ElfW(Shdr) * out, char *tmp_buf, int tmp_buf_size) {
+  ElfW(Shdr) *buf = reinterpret_cast<ElfW(Shdr) *>(tmp_buf);
+  const int buf_entries = tmp_buf_size / sizeof(buf[0]);
+  const int buf_bytes = buf_entries * sizeof(buf[0]);
+
+  for (int i = 0; i < sh_num;) {
+    const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+    const ssize_t num_bytes_to_read =
+        (buf_bytes > num_bytes_left) ? num_bytes_left : buf_bytes;
+    const off_t offset = sh_offset + i * sizeof(buf[0]);
+    const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read, offset);
+    if (len % sizeof(buf[0]) != 0) {
+      ABSL_RAW_LOG(
+          WARNING,
+          "Reading %zd bytes from offset %ju returned %zd which is not a "
+          "multiple of %zu.",
+          num_bytes_to_read, static_cast<uintmax_t>(offset), len,
+          sizeof(buf[0]));
+      return false;
+    }
+    const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_headers_in_buf <= buf_entries);
+    for (int j = 0; j < num_headers_in_buf; ++j) {
+      if (buf[j].sh_type == type) {
+        *out = buf[j];
+        return true;
+      }
+    }
+    i += num_headers_in_buf;
+  }
+  return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+bool ForEachSection(int fd,
+                    const std::function<bool(const std::string &name,
+                                             const ElfW(Shdr) &)> &callback) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset =
+      (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    ElfW(Shdr) out;
+    off_t section_header_offset =
+        (elf_header.e_shoff + elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, &out, sizeof(out), section_header_offset)) {
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out.sh_name;
+    char header_name[kMaxSectionNameLen + 1];
+    ssize_t n_read =
+        ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset);
+    if (n_read == -1) {
+      return false;
+    } else if (n_read > kMaxSectionNameLen) {
+      // Long read?
+      return false;
+    }
+    header_name[n_read] = '\0';
+
+    std::string name(header_name);
+    if (!callback(name, out)) {
+      break;
+    }
+  }
+  return true;
+}
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) * out) {
+  char header_name[kMaxSectionNameLen];
+  if (sizeof(header_name) < name_len) {
+    ABSL_RAW_LOG(WARNING,
+                 "Section name '%s' is too long (%zu); "
+                 "section will not be found (even if present).",
+                 name, name_len);
+    // No point in even trying.
+    return false;
+  }
+
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset =
+      (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    off_t section_header_offset =
+        (elf_header.e_shoff + elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out->sh_name;
+    ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+    if (n_read < 0) {
+      return false;
+    } else if (static_cast<size_t>(n_read) != name_len) {
+      // Short read -- name could be at end of file.
+      continue;
+    }
+    if (memcmp(header_name, name, name_len) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Compare symbols at in the same address.
+// Return true if we should pick symbol1.
+static bool ShouldPickFirstSymbol(const ElfW(Sym) & symbol1,
+                                  const ElfW(Sym) & symbol2) {
+  // If one of the symbols is weak and the other is not, pick the one
+  // this is not a weak symbol.
+  char bind1 = ELF_ST_BIND(symbol1.st_info);
+  char bind2 = ELF_ST_BIND(symbol1.st_info);
+  if (bind1 == STB_WEAK && bind2 != STB_WEAK) return false;
+  if (bind2 == STB_WEAK && bind1 != STB_WEAK) return true;
+
+  // If one of the symbols has zero size and the other is not, pick the
+  // one that has non-zero size.
+  if (symbol1.st_size != 0 && symbol2.st_size == 0) {
+    return true;
+  }
+  if (symbol1.st_size == 0 && symbol2.st_size != 0) {
+    return false;
+  }
+
+  // If one of the symbols has no type and the other is not, pick the
+  // one that has a type.
+  char type1 = ELF_ST_TYPE(symbol1.st_info);
+  char type2 = ELF_ST_TYPE(symbol1.st_info);
+  if (type1 != STT_NOTYPE && type2 == STT_NOTYPE) {
+    return true;
+  }
+  if (type1 == STT_NOTYPE && type2 != STT_NOTYPE) {
+    return false;
+  }
+
+  // Pick the first one, if we still cannot decide.
+  return true;
+}
+
+// Return true if an address is inside a section.
+static bool InSection(const void *address, const ElfW(Shdr) * section) {
+  const char *start = reinterpret_cast<const char *>(section->sh_addr);
+  size_t size = static_cast<size_t>(section->sh_size);
+  return start <= address && address < (start + size);
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc".  If the symbol is found, and its name fits in
+// out_size, the name is written into out and SYMBOL_FOUND is returned.
+// If the name does not fit, truncated name is written into out,
+// and SYMBOL_TRUNCATED is returned. Out is NUL-terminated.
+// If the symbol is not found, SYMBOL_NOT_FOUND is returned;
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
+    const void *const pc, const int fd, char *out, int out_size,
+    ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab,
+    const ElfW(Shdr) * opd, char *tmp_buf, int tmp_buf_size) {
+  if (symtab == nullptr) {
+    return SYMBOL_NOT_FOUND;
+  }
+
+  // Read multiple symbols at once to save read() calls.
+  ElfW(Sym) *buf = reinterpret_cast<ElfW(Sym) *>(tmp_buf);
+  const int buf_entries = tmp_buf_size / sizeof(buf[0]);
+
+  const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+
+  // On platforms using an .opd section (PowerPC & IA64), a function symbol
+  // has the address of a function descriptor, which contains the real
+  // starting address.  However, we do not always want to use the real
+  // starting address because we sometimes want to symbolize a function
+  // pointer into the .opd section, e.g. FindSymbol(&foo,...).
+  const bool pc_in_opd =
+      kPlatformUsesOPDSections && opd != nullptr && InSection(pc, opd);
+  const bool deref_function_descriptor_pointer =
+      kPlatformUsesOPDSections && opd != nullptr && !pc_in_opd;
+
+  ElfW(Sym) best_match;
+  SafeMemZero(&best_match, sizeof(best_match));
+  bool found_match = false;
+  for (int i = 0; i < num_symbols;) {
+    off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+    const int num_remaining_symbols = num_symbols - i;
+    const int entries_in_chunk = std::min(num_remaining_symbols, buf_entries);
+    const int bytes_in_chunk = entries_in_chunk * sizeof(buf[0]);
+    const ssize_t len = ReadFromOffset(fd, buf, bytes_in_chunk, offset);
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_symbols_in_buf <= entries_in_chunk);
+    for (int j = 0; j < num_symbols_in_buf; ++j) {
+      const ElfW(Sym) &symbol = buf[j];
+
+      // For a DSO, a symbol address is relocated by the loading address.
+      // We keep the original address for opd redirection below.
+      const char *const original_start_address =
+          reinterpret_cast<const char *>(symbol.st_value);
+      const char *start_address = original_start_address + relocation;
+
+      if (deref_function_descriptor_pointer &&
+          InSection(original_start_address, opd)) {
+        // The opd section is mapped into memory.  Just dereference
+        // start_address to get the first double word, which points to the
+        // function entry.
+        start_address = *reinterpret_cast<const char *const *>(start_address);
+      }
+
+      // If pc is inside the .opd section, it points to a function descriptor.
+      const size_t size = pc_in_opd ? kFunctionDescriptorSize : symbol.st_size;
+      const void *const end_address =
+          reinterpret_cast<const char *>(start_address) + size;
+      if (symbol.st_value != 0 &&  // Skip null value symbols.
+          symbol.st_shndx != 0 &&  // Skip undefined symbols.
+#ifdef STT_TLS
+          ELF_ST_TYPE(symbol.st_info) != STT_TLS &&  // Skip thread-local data.
+#endif                                               // STT_TLS
+          ((start_address <= pc && pc < end_address) ||
+           (start_address == pc && pc == end_address))) {
+        if (!found_match || ShouldPickFirstSymbol(symbol, best_match)) {
+          found_match = true;
+          best_match = symbol;
+        }
+      }
+    }
+    i += num_symbols_in_buf;
+  }
+
+  if (found_match) {
+    const size_t off = strtab->sh_offset + best_match.st_name;
+    const ssize_t n_read = ReadFromOffset(fd, out, out_size, off);
+    if (n_read <= 0) {
+      // This should never happen.
+      ABSL_RAW_LOG(WARNING,
+                   "Unable to read from fd %d at offset %zu: n_read = %zd", fd,
+                   off, n_read);
+      return SYMBOL_NOT_FOUND;
+    }
+    ABSL_RAW_CHECK(n_read <= out_size, "ReadFromOffset read too much data.");
+
+    // strtab->sh_offset points into .strtab-like section that contains
+    // NUL-terminated strings: '\0foo\0barbaz\0...".
+    //
+    // sh_offset+st_name points to the start of symbol name, but we don't know
+    // how long the symbol is, so we try to read as much as we have space for,
+    // and usually over-read (i.e. there is a NUL somewhere before n_read).
+    if (memchr(out, '\0', n_read) == nullptr) {
+      // Either out_size was too small (n_read == out_size and no NUL), or
+      // we tried to read past the EOF (n_read < out_size) and .strtab is
+      // corrupt (missing terminating NUL; should never happen for valid ELF).
+      out[n_read - 1] = '\0';
+      return SYMBOL_TRUNCATED;
+    }
+    return SYMBOL_FOUND;
+  }
+
+  return SYMBOL_NOT_FOUND;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd".  Process
+// both regular and dynamic symbol tables if necessary.
+// See FindSymbol() comment for description of return value.
+FindSymbolResult Symbolizer::GetSymbolFromObjectFile(
+    const ObjFile &obj, const void *const pc, const ptrdiff_t relocation,
+    char *out, int out_size, char *tmp_buf, int tmp_buf_size) {
+  ElfW(Shdr) symtab;
+  ElfW(Shdr) strtab;
+  ElfW(Shdr) opd;
+  ElfW(Shdr) *opd_ptr = nullptr;
+
+  // On platforms using an .opd sections for function descriptor, read
+  // the section header.  The .opd section is in data segment and should be
+  // loaded but we check that it is mapped just to be extra careful.
+  if (kPlatformUsesOPDSections) {
+    if (GetSectionHeaderByName(obj.fd, kOpdSectionName,
+                               sizeof(kOpdSectionName) - 1, &opd) &&
+        FindObjFile(reinterpret_cast<const char *>(opd.sh_addr) + relocation,
+                    opd.sh_size) != nullptr) {
+      opd_ptr = &opd;
+    } else {
+      return SYMBOL_NOT_FOUND;
+    }
+  }
+
+  // Consult a regular symbol table first.
+  if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
+                              obj.elf_header.e_shoff, SHT_SYMTAB, &symtab,
+                              tmp_buf, tmp_buf_size)) {
+    return SYMBOL_NOT_FOUND;
+  }
+  if (!ReadFromOffsetExact(
+          obj.fd, &strtab, sizeof(strtab),
+          obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
+    return SYMBOL_NOT_FOUND;
+  }
+  const FindSymbolResult rc =
+      FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab,
+                 opd_ptr, tmp_buf, tmp_buf_size);
+  if (rc != SYMBOL_NOT_FOUND) {
+    return rc;  // Found the symbol in a regular symbol table.
+  }
+
+  // If the symbol is not found, then consult a dynamic symbol table.
+  if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
+                              obj.elf_header.e_shoff, SHT_DYNSYM, &symtab,
+                              tmp_buf, tmp_buf_size)) {
+    return SYMBOL_NOT_FOUND;
+  }
+  if (!ReadFromOffsetExact(
+          obj.fd, &strtab, sizeof(strtab),
+          obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
+    return SYMBOL_NOT_FOUND;
+  }
+  return FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab,
+                    opd_ptr, tmp_buf, tmp_buf_size);
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+class FileDescriptor {
+ public:
+  explicit FileDescriptor(int fd) : fd_(fd) {}
+  FileDescriptor(const FileDescriptor &) = delete;
+  FileDescriptor &operator=(const FileDescriptor &) = delete;
+
+  ~FileDescriptor() {
+    if (fd_ >= 0) {
+      NO_INTR(close(fd_));
+    }
+  }
+
+  int get() const { return fd_; }
+
+ private:
+  const int fd_;
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+  explicit LineReader(int fd, char *buf, int buf_len)
+      : fd_(fd),
+        buf_len_(buf_len),
+        buf_(buf),
+        bol_(buf),
+        eol_(buf),
+        eod_(buf) {}
+
+  LineReader(const LineReader &) = delete;
+  LineReader &operator=(const LineReader &) = delete;
+
+  // Read '\n'-terminated line from file.  On success, modify "bol"
+  // and "eol", then return true.  Otherwise, return false.
+  //
+  // Note: if the last line doesn't end with '\n', the line will be
+  // dropped.  It's an intentional behavior to make the code simple.
+  bool ReadLine(const char **bol, const char **eol) {
+    if (BufferIsEmpty()) {  // First time.
+      const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+      if (num_bytes <= 0) {  // EOF or error.
+        return false;
+      }
+      eod_ = buf_ + num_bytes;
+      bol_ = buf_;
+    } else {
+      bol_ = eol_ + 1;            // Advance to the next line in the buffer.
+      SAFE_ASSERT(bol_ <= eod_);  // "bol_" can point to "eod_".
+      if (!HasCompleteLine()) {
+        const int incomplete_line_length = eod_ - bol_;
+        // Move the trailing incomplete line to the beginning.
+        memmove(buf_, bol_, incomplete_line_length);
+        // Read text from file and append it.
+        char *const append_pos = buf_ + incomplete_line_length;
+        const int capacity_left = buf_len_ - incomplete_line_length;
+        const ssize_t num_bytes =
+            ReadPersistent(fd_, append_pos, capacity_left);
+        if (num_bytes <= 0) {  // EOF or error.
+          return false;
+        }
+        eod_ = append_pos + num_bytes;
+        bol_ = buf_;
+      }
+    }
+    eol_ = FindLineFeed();
+    if (eol_ == nullptr) {  // '\n' not found.  Malformed line.
+      return false;
+    }
+    *eol_ = '\0';  // Replace '\n' with '\0'.
+
+    *bol = bol_;
+    *eol = eol_;
+    return true;
+  }
+
+ private:
+  char *FindLineFeed() const {
+    return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+  }
+
+  bool BufferIsEmpty() const { return buf_ == eod_; }
+
+  bool HasCompleteLine() const {
+    return !BufferIsEmpty() && FindLineFeed() != nullptr;
+  }
+
+  const int fd_;
+  const int buf_len_;
+  char *const buf_;
+  char *bol_;
+  char *eol_;
+  const char *eod_;  // End of data in "buf_".
+};
+}  // namespace
+
+// Place the hex number read from "start" into "*hex".  The pointer to
+// the first non-hex character or "end" is returned.
+static const char *GetHex(const char *start, const char *end,
+                          uint64_t *const value) {
+  uint64_t hex = 0;
+  const char *p;
+  for (p = start; p < end; ++p) {
+    int ch = *p;
+    if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
+        (ch >= 'a' && ch <= 'f')) {
+      hex = (hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+    } else {  // Encountered the first non-hex character.
+      break;
+    }
+  }
+  SAFE_ASSERT(p <= end);
+  *value = hex;
+  return p;
+}
+
+static const char *GetHex(const char *start, const char *end,
+                          const void **const addr) {
+  uint64_t hex = 0;
+  const char *p = GetHex(start, end, &hex);
+  *addr = reinterpret_cast<void *>(hex);
+  return p;
+}
+
+// Read /proc/self/maps and run "callback" for each mmapped file found.  If
+// "callback" returns false, stop scanning and return true. Else continue
+// scanning /proc/self/maps. Return true if no parse error is found.
+static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap(
+    bool (*callback)(const char *filename, const void *const start_addr,
+                     const void *const end_addr, uint64_t offset, void *arg),
+    void *arg, void *tmp_buf, int tmp_buf_size) {
+  // Use /proc/self/task/<pid>/maps instead of /proc/self/maps. The latter
+  // requires kernel to stop all threads, and is significantly slower when there
+  // are 1000s of threads.
+  char maps_path[80];
+  snprintf(maps_path, sizeof(maps_path), "/proc/self/task/%d/maps", getpid());
+
+  int maps_fd;
+  NO_INTR(maps_fd = open(maps_path, O_RDONLY));
+  FileDescriptor wrapped_maps_fd(maps_fd);
+  if (wrapped_maps_fd.get() < 0) {
+    ABSL_RAW_LOG(WARNING, "%s: errno=%d", maps_path, errno);
+    return false;
+  }
+
+  // Iterate over maps and look for the map containing the pc.  Then
+  // look into the symbol tables inside.
+  LineReader reader(wrapped_maps_fd.get(), static_cast<char *>(tmp_buf),
+                    tmp_buf_size);
+  while (true) {
+    const char *cursor;
+    const char *eol;
+    if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.
+      break;
+    }
+
+    const char *line = cursor;
+    const void *start_address;
+    // Start parsing line in /proc/self/maps.  Here is an example:
+    //
+    // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat
+    //
+    // We want start address (08048000), end address (0804c000), flags
+    // (r-xp) and file name (/bin/cat).
+
+    // Read start address.
+    cursor = GetHex(cursor, eol, &start_address);
+    if (cursor == eol || *cursor != '-') {
+      ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps line: %s", line);
+      return false;
+    }
+    ++cursor;  // Skip '-'.
+
+    // Read end address.
+    const void *end_address;
+    cursor = GetHex(cursor, eol, &end_address);
+    if (cursor == eol || *cursor != ' ') {
+      ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps line: %s", line);
+      return false;
+    }
+    ++cursor;  // Skip ' '.
+
+    // Read flags.  Skip flags until we encounter a space or eol.
+    const char *const flags_start = cursor;
+    while (cursor < eol && *cursor != ' ') {
+      ++cursor;
+    }
+    // We expect at least four letters for flags (ex. "r-xp").
+    if (cursor == eol || cursor < flags_start + 4) {
+      ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps: %s", line);
+      return false;
+    }
+
+    // Check flags.  Normally we are only interested in "r-x" maps.  On
+    // the PowerPC, function pointers point to descriptors in the .opd
+    // section.  The descriptors themselves are not executable code.  So
+    // we need to relax the check below to "r**".
+    if (memcmp(flags_start, "r-x", 3) != 0 &&  // Not a "r-x" map.
+        !(kPlatformUsesOPDSections && flags_start[0] == 'r')) {
+      continue;  // We skip this map.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Read file offset.
+    uint64_t offset;
+    cursor = GetHex(cursor, eol, &offset);
+    ++cursor;  // Skip ' '.
+
+    // Skip to file name.  "cursor" now points to dev.  We need to skip at least
+    // two spaces for dev and inode.
+    int num_spaces = 0;
+    while (cursor < eol) {
+      if (*cursor == ' ') {
+        ++num_spaces;
+      } else if (num_spaces >= 2) {
+        // The first non-space character after  skipping two spaces
+        // is the beginning of the file name.
+        break;
+      }
+      ++cursor;
+    }
+
+    // Check whether this entry corresponds to our hint table for the true
+    // filename.
+    bool hinted =
+        GetFileMappingHint(&start_address, &end_address, &offset, &cursor);
+    if (!hinted && (cursor == eol || cursor[0] == '[')) {
+      // not an object file, typically [vdso] or [vsyscall]
+      continue;
+    }
+    if (!callback(cursor, start_address, end_address, offset, arg)) break;
+  }
+  return true;
+}
+
+// Find the objfile mapped in address region containing [addr, addr + len).
+ObjFile *Symbolizer::FindObjFile(const void *const addr, size_t len) {
+  for (int i = 0; i < 2; ++i) {
+    if (!ok_) return nullptr;
+
+    // Read /proc/self/maps if necessary
+    if (!addr_map_read_) {
+      addr_map_read_ = true;
+      if (!ReadAddrMap(RegisterObjFile, this, tmp_buf_, TMP_BUF_SIZE)) {
+        ok_ = false;
+        return nullptr;
+      }
+    }
+
+    int lo = 0;
+    int hi = addr_map_.Size();
+    while (lo < hi) {
+      int mid = (lo + hi) / 2;
+      if (addr < addr_map_.At(mid)->end_addr) {
+        hi = mid;
+      } else {
+        lo = mid + 1;
+      }
+    }
+    if (lo != addr_map_.Size()) {
+      ObjFile *obj = addr_map_.At(lo);
+      SAFE_ASSERT(obj->end_addr > addr);
+      if (addr >= obj->start_addr &&
+          reinterpret_cast<const char *>(addr) + len <= obj->end_addr)
+        return obj;
+    }
+
+    // The address mapping may have changed since it was last read.  Retry.
+    ClearAddrMap();
+  }
+  return nullptr;
+}
+
+void Symbolizer::ClearAddrMap() {
+  for (int i = 0; i != addr_map_.Size(); i++) {
+    ObjFile *o = addr_map_.At(i);
+    base_internal::LowLevelAlloc::Free(o->filename);
+    if (o->fd >= 0) {
+      NO_INTR(close(o->fd));
+    }
+  }
+  addr_map_.Clear();
+  addr_map_read_ = false;
+}
+
+// Callback for ReadAddrMap to register objfiles in an in-memory table.
+bool Symbolizer::RegisterObjFile(const char *filename,
+                                 const void *const start_addr,
+                                 const void *const end_addr, uint64_t offset,
+                                 void *arg) {
+  Symbolizer *impl = static_cast<Symbolizer *>(arg);
+
+  // Files are supposed to be added in the increasing address order.  Make
+  // sure that's the case.
+  int addr_map_size = impl->addr_map_.Size();
+  if (addr_map_size != 0) {
+    ObjFile *old = impl->addr_map_.At(addr_map_size - 1);
+    if (old->end_addr > end_addr) {
+      ABSL_RAW_LOG(ERROR,
+                   "Unsorted addr map entry: 0x%" PRIxPTR ": %s <-> 0x%" PRIxPTR
+                   ": %s",
+                   reinterpret_cast<uintptr_t>(end_addr), filename,
+                   reinterpret_cast<uintptr_t>(old->end_addr), old->filename);
+      return true;
+    } else if (old->end_addr == end_addr) {
+      // The same entry appears twice. This sometimes happens for [vdso].
+      if (old->start_addr != start_addr ||
+          strcmp(old->filename, filename) != 0) {
+        ABSL_RAW_LOG(ERROR,
+                     "Duplicate addr 0x%" PRIxPTR ": %s <-> 0x%" PRIxPTR ": %s",
+                     reinterpret_cast<uintptr_t>(end_addr), filename,
+                     reinterpret_cast<uintptr_t>(old->end_addr), old->filename);
+      }
+      return true;
+    }
+  }
+  ObjFile *obj = impl->addr_map_.Add();
+  obj->filename = impl->CopyString(filename);
+  obj->start_addr = start_addr;
+  obj->end_addr = end_addr;
+  obj->offset = offset;
+  obj->elf_type = -1;  // filled on demand
+  obj->fd = -1;        // opened on demand
+  return true;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size,
+                                                    char *tmp_buf,
+                                                    int tmp_buf_size) {
+  if (Demangle(out, tmp_buf, tmp_buf_size)) {
+    // Demangling succeeded. Copy to out if the space allows.
+    int len = strlen(tmp_buf);
+    if (len + 1 <= out_size) {  // +1 for '\0'.
+      SAFE_ASSERT(len < tmp_buf_size);
+      memmove(out, tmp_buf, len + 1);
+    }
+  }
+}
+
+SymbolCacheLine *Symbolizer::GetCacheLine(const void *const pc) {
+  uintptr_t pc0 = reinterpret_cast<uintptr_t>(pc);
+  pc0 >>= 3;  // drop the low 3 bits
+
+  // Shuffle bits.
+  pc0 ^= (pc0 >> 6) ^ (pc0 >> 12) ^ (pc0 >> 18);
+  return &symbol_cache_[pc0 % SYMBOL_CACHE_LINES];
+}
+
+void Symbolizer::AgeSymbols(SymbolCacheLine *line) {
+  for (uint32_t &age : line->age) {
+    ++age;
+  }
+}
+
+const char *Symbolizer::FindSymbolInCache(const void *const pc) {
+  if (pc == nullptr) return nullptr;
+
+  SymbolCacheLine *line = GetCacheLine(pc);
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) {
+    if (line->pc[i] == pc) {
+      AgeSymbols(line);
+      line->age[i] = 0;
+      return line->name[i];
+    }
+  }
+  return nullptr;
+}
+
+const char *Symbolizer::InsertSymbolInCache(const void *const pc,
+                                            const char *name) {
+  SAFE_ASSERT(pc != nullptr);
+
+  SymbolCacheLine *line = GetCacheLine(pc);
+  uint32_t max_age = 0;
+  int oldest_index = -1;
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) {
+    if (line->pc[i] == nullptr) {
+      AgeSymbols(line);
+      line->pc[i] = pc;
+      line->name[i] = CopyString(name);
+      line->age[i] = 0;
+      return line->name[i];
+    }
+    if (line->age[i] >= max_age) {
+      max_age = line->age[i];
+      oldest_index = i;
+    }
+  }
+
+  AgeSymbols(line);
+  ABSL_RAW_CHECK(oldest_index >= 0, "Corrupt cache");
+  base_internal::LowLevelAlloc::Free(line->name[oldest_index]);
+  line->pc[oldest_index] = pc;
+  line->name[oldest_index] = CopyString(name);
+  line->age[oldest_index] = 0;
+  return line->name[oldest_index];
+}
+
+static void MaybeOpenFdFromSelfExe(ObjFile *obj) {
+  if (memcmp(obj->start_addr, ELFMAG, SELFMAG) != 0) {
+    return;
+  }
+  int fd = open("/proc/self/exe", O_RDONLY);
+  if (fd == -1) {
+    return;
+  }
+  // Verify that contents of /proc/self/exe matches in-memory image of
+  // the binary. This can fail if the "deleted" binary is in fact not
+  // the main executable, or for binaries that have the first PT_LOAD
+  // segment smaller than 4K. We do it in four steps so that the
+  // buffer is smaller and we don't consume too much stack space.
+  const char *mem = reinterpret_cast<const char *>(obj->start_addr);
+  for (int i = 0; i < 4; ++i) {
+    char buf[1024];
+    ssize_t n = read(fd, buf, sizeof(buf));
+    if (n != sizeof(buf) || memcmp(buf, mem, sizeof(buf)) != 0) {
+      close(fd);
+      return;
+    }
+    mem += sizeof(buf);
+  }
+  obj->fd = fd;
+}
+
+static bool MaybeInitializeObjFile(ObjFile *obj) {
+  if (obj->fd < 0) {
+    obj->fd = open(obj->filename, O_RDONLY);
+
+    if (obj->fd < 0) {
+      // Getting /proc/self/exe here means that we were hinted.
+      if (strcmp(obj->filename, "/proc/self/exe") == 0) {
+        // /proc/self/exe may be inaccessible (due to setuid, etc.), so try
+        // accessing the binary via argv0.
+        if (argv0_value != nullptr) {
+          obj->fd = open(argv0_value, O_RDONLY);
+        }
+      } else {
+        MaybeOpenFdFromSelfExe(obj);
+      }
+    }
+
+    if (obj->fd < 0) {
+      ABSL_RAW_LOG(WARNING, "%s: open failed: errno=%d", obj->filename, errno);
+      return false;
+    }
+    obj->elf_type = FileGetElfType(obj->fd);
+    if (obj->elf_type < 0) {
+      ABSL_RAW_LOG(WARNING, "%s: wrong elf type: %d", obj->filename,
+                   obj->elf_type);
+      return false;
+    }
+
+    if (!ReadFromOffsetExact(obj->fd, &obj->elf_header, sizeof(obj->elf_header),
+                             0)) {
+      ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename);
+      return false;
+    }
+  }
+  return true;
+}
+
+// The implementation of our symbolization routine.  If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns pointer to that symbol. Otherwise, returns nullptr.
+// If any symbol decorators have been installed via InstallSymbolDecorator(),
+// they are called here as well.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+const char *Symbolizer::GetSymbol(const void *const pc) {
+  const char *entry = FindSymbolInCache(pc);
+  if (entry != nullptr) {
+    return entry;
+  }
+  symbol_buf_[0] = '\0';
+
+  ObjFile *const obj = FindObjFile(pc, 1);
+  ptrdiff_t relocation = 0;
+  int fd = -1;
+  if (obj != nullptr) {
+    if (MaybeInitializeObjFile(obj)) {
+      if (obj->elf_type == ET_DYN &&
+          reinterpret_cast<uint64_t>(obj->start_addr) >= obj->offset) {
+        // This object was relocated.
+        //
+        // For obj->offset > 0, adjust the relocation since a mapping at offset
+        // X in the file will have a start address of [true relocation]+X.
+        relocation = reinterpret_cast<ptrdiff_t>(obj->start_addr) - obj->offset;
+      }
+
+      fd = obj->fd;
+    }
+    if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
+                                sizeof(symbol_buf_), tmp_buf_,
+                                sizeof(tmp_buf_)) == SYMBOL_FOUND) {
+      // Only try to demangle the symbol name if it fit into symbol_buf_.
+      DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
+                      sizeof(tmp_buf_));
+    }
+  } else {
+#if ABSL_HAVE_VDSO_SUPPORT
+    VDSOSupport vdso;
+    if (vdso.IsPresent()) {
+      VDSOSupport::SymbolInfo symbol_info;
+      if (vdso.LookupSymbolByAddress(pc, &symbol_info)) {
+        // All VDSO symbols are known to be short.
+        size_t len = strlen(symbol_info.name);
+        ABSL_RAW_CHECK(len + 1 < sizeof(symbol_buf_),
+                       "VDSO symbol unexpectedly long");
+        memcpy(symbol_buf_, symbol_info.name, len + 1);
+      }
+    }
+#endif
+  }
+
+  if (g_decorators_mu.TryLock()) {
+    if (g_num_decorators > 0) {
+      SymbolDecoratorArgs decorator_args = {
+          pc,       relocation,       fd,     symbol_buf_, sizeof(symbol_buf_),
+          tmp_buf_, sizeof(tmp_buf_), nullptr};
+      for (int i = 0; i < g_num_decorators; ++i) {
+        decorator_args.arg = g_decorators[i].arg;
+        g_decorators[i].fn(&decorator_args);
+      }
+    }
+    g_decorators_mu.Unlock();
+  }
+  if (symbol_buf_[0] == '\0') {
+    return nullptr;
+  }
+  symbol_buf_[sizeof(symbol_buf_) - 1] = '\0';  // Paranoia.
+  return InsertSymbolInCache(pc, symbol_buf_);
+}
+
+bool RemoveAllSymbolDecorators(void) {
+  if (!g_decorators_mu.TryLock()) {
+    // Someone else is using decorators. Get out.
+    return false;
+  }
+  g_num_decorators = 0;
+  g_decorators_mu.Unlock();
+  return true;
+}
+
+bool RemoveSymbolDecorator(int ticket) {
+  if (!g_decorators_mu.TryLock()) {
+    // Someone else is using decorators. Get out.
+    return false;
+  }
+  for (int i = 0; i < g_num_decorators; ++i) {
+    if (g_decorators[i].ticket == ticket) {
+      while (i < g_num_decorators - 1) {
+        g_decorators[i] = g_decorators[i + 1];
+        ++i;
+      }
+      g_num_decorators = i;
+      break;
+    }
+  }
+  g_decorators_mu.Unlock();
+  return true;  // Decorator is known to be removed.
+}
+
+int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) {
+  static int ticket = 0;
+
+  if (!g_decorators_mu.TryLock()) {
+    // Someone else is using decorators. Get out.
+    return false;
+  }
+  int ret = ticket;
+  if (g_num_decorators >= kMaxDecorators) {
+    ret = -1;
+  } else {
+    g_decorators[g_num_decorators] = {decorator, arg, ticket++};
+    ++g_num_decorators;
+  }
+  g_decorators_mu.Unlock();
+  return ret;
+}
+
+bool RegisterFileMappingHint(const void *start, const void *end, uint64_t offset,
+                             const char *filename) {
+  SAFE_ASSERT(start <= end);
+  SAFE_ASSERT(filename != nullptr);
+
+  InitSigSafeArena();
+
+  if (!g_file_mapping_mu.TryLock()) {
+    return false;
+  }
+
+  bool ret = true;
+  if (g_num_file_mapping_hints >= kMaxFileMappingHints) {
+    ret = false;
+  } else {
+    // TODO(ckennelly): Move this into a std::string copy routine.
+    int len = strlen(filename);
+    char *dst = static_cast<char *>(
+        base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
+    ABSL_RAW_CHECK(dst != nullptr, "out of memory");
+    memcpy(dst, filename, len + 1);
+
+    auto &hint = g_file_mapping_hints[g_num_file_mapping_hints++];
+    hint.start = start;
+    hint.end = end;
+    hint.offset = offset;
+    hint.filename = dst;
+  }
+
+  g_file_mapping_mu.Unlock();
+  return ret;
+}
+
+bool GetFileMappingHint(const void **start, const void **end, uint64_t *offset,
+                        const char **filename) {
+  if (!g_file_mapping_mu.TryLock()) {
+    return false;
+  }
+  bool found = false;
+  for (int i = 0; i < g_num_file_mapping_hints; i++) {
+    if (g_file_mapping_hints[i].start <= *start &&
+        *end <= g_file_mapping_hints[i].end) {
+      // We assume that the start_address for the mapping is the base
+      // address of the ELF section, but when [start_address,end_address) is
+      // not strictly equal to [hint.start, hint.end), that assumption is
+      // invalid.
+      //
+      // This uses the hint's start address (even though hint.start is not
+      // necessarily equal to start_address) to ensure the correct
+      // relocation is computed later.
+      *start = g_file_mapping_hints[i].start;
+      *end = g_file_mapping_hints[i].end;
+      *offset = g_file_mapping_hints[i].offset;
+      *filename = g_file_mapping_hints[i].filename;
+      found = true;
+      break;
+    }
+  }
+  g_file_mapping_mu.Unlock();
+  return found;
+}
+
+}  // namespace debugging_internal
+
+bool Symbolize(const void *pc, char *out, int out_size) {
+  // Symbolization is very slow under tsan.
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+  SAFE_ASSERT(out_size >= 0);
+  debugging_internal::Symbolizer *s = debugging_internal::AllocateSymbolizer();
+  const char *name = s->GetSymbol(pc);
+  bool ok = false;
+  if (name != nullptr && out_size > 0) {
+    strncpy(out, name, out_size);
+    ok = true;
+    if (out[out_size - 1] != '\0') {
+      // strncpy() does not '\0' terminate when it truncates.  Do so, with
+      // trailing ellipsis.
+      static constexpr char kEllipsis[] = "...";
+      int ellipsis_size =
+          std::min(implicit_cast<int>(strlen(kEllipsis)), out_size - 1);
+      memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+      out[out_size - 1] = '\0';
+    }
+  }
+  debugging_internal::FreeSymbolizer(s);
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
+  return ok;
+}
+
+}  // namespace absl
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
new file mode 100644
index 0000000..5f2af47
--- /dev/null
+++ b/absl/debugging/symbolize_test.cc
@@ -0,0 +1,517 @@
+// Copyright 2018 The Abseil 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 "absl/debugging/symbolize.h"
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <sys/mman.h>
+#endif
+
+#include <cstring>
+#include <iostream>
+#include <memory>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/casts.h"
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/optimization.h"
+#include "absl/debugging/internal/stack_consumption.h"
+#include "absl/memory/memory.h"
+
+using testing::Contains;
+
+// Functions to symbolize. Use C linkage to avoid mangled names.
+extern "C" {
+void nonstatic_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); }
+static void static_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); }
+}  // extern "C"
+
+struct Foo {
+  static void func(int x);
+};
+
+// A C++ method that should have a mangled name.
+void ABSL_ATTRIBUTE_NOINLINE Foo::func(int) {
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+// Create functions that will remain in different text sections in the
+// final binary when linker option "-z,keep-text-section-prefix" is used.
+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.unlikely) unlikely_func() {
+  return 0;
+}
+
+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() {
+  return 0;
+}
+
+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() {
+  return 0;
+}
+
+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() {
+  return 0;
+}
+
+int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() {
+  return 0;
+}
+
+// Thread-local data may confuse the symbolizer, ensure that it does not.
+// Variable sizes and order are important.
+#if ABSL_PER_THREAD_TLS
+static ABSL_PER_THREAD_TLS_KEYWORD char symbolize_test_thread_small[1];
+static ABSL_PER_THREAD_TLS_KEYWORD char
+    symbolize_test_thread_big[2 * 1024 * 1024];
+#endif
+
+// Used below to hopefully inhibit some compiler/linker optimizations
+// that may remove kHpageTextPadding, kPadding0, and kPadding1 from
+// the binary.
+static volatile bool volatile_bool = false;
+
+// Force the binary to be large enough that a THP .text remap will succeed.
+static constexpr size_t kHpageSize = 1 << 21;
+const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
+    .text) = "";
+
+static char try_symbolize_buffer[4096];
+
+// A wrapper function for absl::Symbolize() to make the unit test simple.  The
+// limit must be < sizeof(try_symbolize_buffer).  Returns null if
+// absl::Symbolize() returns false, otherwise returns try_symbolize_buffer with
+// the result of absl::Symbolize().
+static const char *TrySymbolizeWithLimit(void *pc, int limit) {
+  ABSL_RAW_CHECK(limit <= sizeof(try_symbolize_buffer),
+                 "try_symbolize_buffer is too small");
+
+  // Use the heap to facilitate heap and buffer sanitizer tools.
+  auto heap_buffer = absl::make_unique<char[]>(sizeof(try_symbolize_buffer));
+  bool found = absl::Symbolize(pc, heap_buffer.get(), limit);
+  if (found) {
+    ABSL_RAW_CHECK(strnlen(heap_buffer.get(), limit) < limit,
+                   "absl::Symbolize() did not properly terminate the string");
+    strncpy(try_symbolize_buffer, heap_buffer.get(),
+            sizeof(try_symbolize_buffer));
+  }
+
+  return found ? try_symbolize_buffer : nullptr;
+}
+
+// A wrapper for TrySymbolizeWithLimit(), with a large limit.
+static const char *TrySymbolize(void *pc) {
+  return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
+}
+
+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+
+TEST(Symbolize, Cached) {
+  // Compilers should give us pointers to them.
+  EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
+
+  // The name of an internal linkage symbol is not specified; allow either a
+  // mangled or an unmangled name here.
+  const char *static_func_symbol = TrySymbolize((void *)(&static_func));
+  EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
+              strcmp("static_func()", static_func_symbol) == 0);
+
+  EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
+}
+
+TEST(Symbolize, Truncation) {
+  constexpr char kNonStaticFunc[] = "nonstatic_func";
+  EXPECT_STREQ("nonstatic_func",
+               TrySymbolizeWithLimit((void *)(&nonstatic_func),
+                                     strlen(kNonStaticFunc) + 1));
+  EXPECT_STREQ("nonstatic_...",
+               TrySymbolizeWithLimit((void *)(&nonstatic_func),
+                                     strlen(kNonStaticFunc) + 0));
+  EXPECT_STREQ("nonstatic...",
+               TrySymbolizeWithLimit((void *)(&nonstatic_func),
+                                     strlen(kNonStaticFunc) - 1));
+  EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
+  EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
+  EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
+  EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
+  EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
+  EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
+}
+
+TEST(Symbolize, SymbolizeWithDemangling) {
+  Foo::func(100);
+  EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
+}
+
+TEST(Symbolize, SymbolizeSplitTextSections) {
+  EXPECT_STREQ("unlikely_func()", TrySymbolize((void *)(&unlikely_func)));
+  EXPECT_STREQ("hot_func()", TrySymbolize((void *)(&hot_func)));
+  EXPECT_STREQ("startup_func()", TrySymbolize((void *)(&startup_func)));
+  EXPECT_STREQ("exit_func()", TrySymbolize((void *)(&exit_func)));
+  EXPECT_STREQ("regular_func()", TrySymbolize((void *)(&regular_func)));
+}
+
+// Tests that verify that Symbolize stack footprint is within some limit.
+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+static void *g_pc_to_symbolize;
+static char g_symbolize_buffer[4096];
+static char *g_symbolize_result;
+
+static void SymbolizeSignalHandler(int signo) {
+  if (absl::Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
+                      sizeof(g_symbolize_buffer))) {
+    g_symbolize_result = g_symbolize_buffer;
+  } else {
+    g_symbolize_result = nullptr;
+  }
+}
+
+// Call Symbolize and figure out the stack footprint of this call.
+static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
+  g_pc_to_symbolize = pc;
+  *stack_consumed = absl::debugging_internal::GetSignalHandlerStackConsumption(
+      SymbolizeSignalHandler);
+  return g_symbolize_result;
+}
+
+static int GetStackConsumptionUpperLimit() {
+  // Symbolize stack consumption should be within 2kB.
+  int stack_consumption_upper_limit = 2048;
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER)
+  // Account for sanitizer instrumentation requiring additional stack space.
+  stack_consumption_upper_limit *= 5;
+#endif
+  return stack_consumption_upper_limit;
+}
+
+TEST(Symbolize, SymbolizeStackConsumption) {
+  int stack_consumed = 0;
+
+  const char *symbol =
+      SymbolizeStackConsumption((void *)(&nonstatic_func), &stack_consumed);
+  EXPECT_STREQ("nonstatic_func", symbol);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
+
+  // The name of an internal linkage symbol is not specified; allow either a
+  // mangled or an unmangled name here.
+  symbol = SymbolizeStackConsumption((void *)(&static_func), &stack_consumed);
+  EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
+              strcmp("static_func()", symbol) == 0);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
+}
+
+TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
+  Foo::func(100);
+  int stack_consumed = 0;
+
+  const char *symbol =
+      SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed);
+
+  EXPECT_STREQ("Foo::func()", symbol);
+  EXPECT_GT(stack_consumed, 0);
+  EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit());
+}
+
+#endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+// Use a 64K page size for PPC.
+const size_t kPageSize = 64 << 10;
+// We place a read-only symbols into the .text section and verify that we can
+// symbolize them and other symbols after remapping them.
+const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
+    "";
+const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
+    "";
+
+static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) {
+  for (int i = 0; i < info->dlpi_phnum; i++) {
+    if (info->dlpi_phdr[i].p_type == PT_LOAD &&
+        info->dlpi_phdr[i].p_flags == (PF_R | PF_X)) {
+      const void *const vaddr =
+          absl::bit_cast<void *>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+      const auto segsize = info->dlpi_phdr[i].p_memsz;
+
+      const char *self_exe;
+      if (info->dlpi_name != nullptr && info->dlpi_name[0] != '\0') {
+        self_exe = info->dlpi_name;
+      } else {
+        self_exe = "/proc/self/exe";
+      }
+
+      absl::debugging_internal::RegisterFileMappingHint(
+          vaddr, reinterpret_cast<const char *>(vaddr) + segsize,
+          info->dlpi_phdr[i].p_offset, self_exe);
+
+      return 1;
+    }
+  }
+
+  return 1;
+}
+
+TEST(Symbolize, SymbolizeWithMultipleMaps) {
+  // Force kPadding0 and kPadding1 to be linked in.
+  if (volatile_bool) {
+    ABSL_RAW_LOG(INFO, "%s", kPadding0);
+    ABSL_RAW_LOG(INFO, "%s", kPadding1);
+  }
+
+  // Verify we can symbolize everything.
+  char buf[512];
+  memset(buf, 0, sizeof(buf));
+  absl::Symbolize(kPadding0, buf, sizeof(buf));
+  EXPECT_STREQ("kPadding0", buf);
+
+  memset(buf, 0, sizeof(buf));
+  absl::Symbolize(kPadding1, buf, sizeof(buf));
+  EXPECT_STREQ("kPadding1", buf);
+
+  // Specify a hint for the executable segment.
+  dl_iterate_phdr(FilterElfHeader, nullptr);
+
+  // Reload at least one page out of kPadding0, kPadding1
+  const char *ptrs[] = {kPadding0, kPadding1};
+
+  for (const char *ptr : ptrs) {
+    const int kMapFlags = MAP_ANONYMOUS | MAP_PRIVATE;
+    void *addr = mmap(nullptr, kPageSize, PROT_READ, kMapFlags, 0, 0);
+    ASSERT_NE(addr, MAP_FAILED);
+
+    // kPadding[0-1] is full of zeroes, so we can remap anywhere within it, but
+    // we ensure there is at least a full page of padding.
+    void *remapped = reinterpret_cast<void *>(
+        reinterpret_cast<uintptr_t>(ptr + kPageSize) & ~(kPageSize - 1ULL));
+
+    const int kMremapFlags = (MREMAP_MAYMOVE | MREMAP_FIXED);
+    void *ret = mremap(addr, kPageSize, kPageSize, kMremapFlags, remapped);
+    ASSERT_NE(ret, MAP_FAILED);
+  }
+
+  // Invalidate the symbolization cache so we are forced to rely on the hint.
+  absl::Symbolize(nullptr, buf, sizeof(buf));
+
+  // Verify we can still symbolize.
+  const char *expected[] = {"kPadding0", "kPadding1"};
+  const size_t offsets[] = {0, kPageSize, 2 * kPageSize, 3 * kPageSize};
+
+  for (int i = 0; i < 2; i++) {
+    for (size_t offset : offsets) {
+      memset(buf, 0, sizeof(buf));
+      absl::Symbolize(ptrs[i] + offset, buf, sizeof(buf));
+      EXPECT_STREQ(expected[i], buf);
+    }
+  }
+}
+
+// Appends std::string(*args->arg) to args->symbol_buf.
+static void DummySymbolDecorator(
+    const absl::debugging_internal::SymbolDecoratorArgs *args) {
+  std::string *message = static_cast<std::string *>(args->arg);
+  strncat(args->symbol_buf, message->c_str(),
+          args->symbol_buf_size - strlen(args->symbol_buf) - 1);
+}
+
+TEST(Symbolize, InstallAndRemoveSymbolDecorators) {
+  int ticket_a;
+  std::string a_message("a");
+  EXPECT_GE(ticket_a = absl::debugging_internal::InstallSymbolDecorator(
+                DummySymbolDecorator, &a_message),
+            0);
+
+  int ticket_b;
+  std::string b_message("b");
+  EXPECT_GE(ticket_b = absl::debugging_internal::InstallSymbolDecorator(
+                DummySymbolDecorator, &b_message),
+            0);
+
+  int ticket_c;
+  std::string c_message("c");
+  EXPECT_GE(ticket_c = absl::debugging_internal::InstallSymbolDecorator(
+                DummySymbolDecorator, &c_message),
+            0);
+
+  char *address = reinterpret_cast<char *>(1);
+  EXPECT_STREQ("abc", TrySymbolize(address++));
+
+  EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_b));
+
+  EXPECT_STREQ("ac", TrySymbolize(address++));
+
+  // Cleanup: remove all remaining decorators so other stack traces don't
+  // get mystery "ac" decoration.
+  EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_a));
+  EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_c));
+}
+
+// Some versions of Clang with optimizations enabled seem to be able
+// to optimize away the .data section if no variables live in the
+// section. This variable should get placed in the .data section, and
+// the test below checks for the existence of a .data section.
+static int in_data_section = 1;
+
+TEST(Symbolize, ForEachSection) {
+  int fd = TEMP_FAILURE_RETRY(open("/proc/self/exe", O_RDONLY));
+  ASSERT_NE(fd, -1);
+
+  std::vector<std::string> sections;
+  ASSERT_TRUE(absl::debugging_internal::ForEachSection(
+      fd, [&sections](const std::string &name, const ElfW(Shdr) &) {
+        sections.push_back(name);
+        return true;
+      }));
+
+  // Check for the presence of common section names.
+  EXPECT_THAT(sections, Contains(".text"));
+  EXPECT_THAT(sections, Contains(".rodata"));
+  EXPECT_THAT(sections, Contains(".bss"));
+  ++in_data_section;
+  EXPECT_THAT(sections, Contains(".data"));
+
+  close(fd);
+}
+
+// x86 specific tests.  Uses some inline assembler.
+extern "C" {
+inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
+  void *pc = nullptr;
+#if defined(__i386__) || defined(__x86_64__)
+  __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#endif
+  return pc;
+}
+
+void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
+  void *pc = nullptr;
+#if defined(__i386__) || defined(__x86_64__)
+  __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#endif
+  return pc;
+}
+
+void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
+#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) && \
+    (defined(__i386__) || defined(__x86_64__))
+  void *pc = non_inline_func();
+  const char *symbol = TrySymbolize(pc);
+  ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideNonInlineFunction failed");
+  ABSL_RAW_CHECK(strcmp(symbol, "non_inline_func") == 0,
+                 "TestWithPCInsideNonInlineFunction failed");
+  std::cout << "TestWithPCInsideNonInlineFunction passed" << std::endl;
+#endif
+}
+
+void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
+#if defined(ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE) && \
+    (defined(__i386__) || defined(__x86_64__))
+  void *pc = inline_func();  // Must be inlined.
+  const char *symbol = TrySymbolize(pc);
+  ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideInlineFunction failed");
+  ABSL_RAW_CHECK(strcmp(symbol, __FUNCTION__) == 0,
+                 "TestWithPCInsideInlineFunction failed");
+  std::cout << "TestWithPCInsideInlineFunction passed" << std::endl;
+#endif
+}
+}
+
+// Test with a return address.
+void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
+#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE)
+  void *return_address = __builtin_return_address(0);
+  const char *symbol = TrySymbolize(return_address);
+  ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed");
+  ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed");
+  std::cout << "TestWithReturnAddress passed" << std::endl;
+#endif
+}
+
+#elif defined(_WIN32) && defined(_DEBUG)
+
+TEST(Symbolize, Basics) {
+  EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
+
+  // The name of an internal linkage symbol is not specified; allow either a
+  // mangled or an unmangled name here.
+  const char* static_func_symbol = TrySymbolize((void *)(&static_func));
+  ASSERT_TRUE(static_func_symbol != nullptr);
+  EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
+
+  EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
+}
+
+TEST(Symbolize, Truncation) {
+  constexpr char kNonStaticFunc[] = "nonstatic_func";
+  EXPECT_STREQ("nonstatic_func",
+               TrySymbolizeWithLimit((void *)(&nonstatic_func),
+                                     strlen(kNonStaticFunc) + 1));
+  EXPECT_STREQ("nonstatic_...",
+               TrySymbolizeWithLimit((void *)(&nonstatic_func),
+                                     strlen(kNonStaticFunc) + 0));
+  EXPECT_STREQ("nonstatic...",
+               TrySymbolizeWithLimit((void *)(&nonstatic_func),
+                                     strlen(kNonStaticFunc) - 1));
+  EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
+  EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
+  EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
+  EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
+  EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
+  EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
+}
+
+TEST(Symbolize, SymbolizeWithDemangling) {
+  const char* result = TrySymbolize((void *)(&Foo::func));
+  ASSERT_TRUE(result != nullptr);
+  EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
+}
+
+#else  // Symbolizer unimplemented
+
+TEST(Symbolize, Unimplemented) {
+  char buf[64];
+  EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf)));
+  EXPECT_FALSE(absl::Symbolize((void *)(&static_func), buf, sizeof(buf)));
+  EXPECT_FALSE(absl::Symbolize((void *)(&Foo::func), buf, sizeof(buf)));
+}
+
+#endif
+
+int main(int argc, char **argv) {
+  // Make sure kHpageTextPadding is linked into the binary.
+  if (volatile_bool) {
+    ABSL_RAW_LOG(INFO, "%s", kHpageTextPadding);
+  }
+
+#if ABSL_PER_THREAD_TLS
+  // Touch the per-thread variables.
+  symbolize_test_thread_small[0] = 0;
+  symbolize_test_thread_big[0] = 0;
+#endif
+
+  absl::InitializeSymbolizer(argv[0]);
+  testing::InitGoogleTest(&argc, argv);
+
+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+  TestWithPCInsideInlineFunction();
+  TestWithPCInsideNonInlineFunction();
+  TestWithReturnAddress();
+#endif
+
+  return RUN_ALL_TESTS();
+}
diff --git a/absl/debugging/symbolize_unimplemented.inc b/absl/debugging/symbolize_unimplemented.inc
new file mode 100644
index 0000000..2a3f4ac
--- /dev/null
+++ b/absl/debugging/symbolize_unimplemented.inc
@@ -0,0 +1,35 @@
+// Copyright 2018 The Abseil 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 <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+namespace debugging_internal {
+
+int InstallSymbolDecorator(SymbolDecorator, void*) { return -1; }
+bool RemoveSymbolDecorator(int) { return false; }
+bool RemoveAllSymbolDecorators(void) { return false; }
+bool RegisterFileMappingHint(const void *, const void *, uint64_t, const char *) {
+  return false;
+}
+
+}  // namespace debugging_internal
+
+void InitializeSymbolizer(const char*) {}
+bool Symbolize(const void *, char *, int) { return false; }
+
+}  // namespace absl
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
new file mode 100644
index 0000000..e3fff74
--- /dev/null
+++ b/absl/debugging/symbolize_win32.inc
@@ -0,0 +1,74 @@
+// Copyright 2018 The Abseil 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.
+
+// See "Retrieving Symbol Information by Address":
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
+
+#include <windows.h>
+#include <DbgHelp.h>
+#pragma comment(lib, "DbgHelp")
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+static HANDLE process = NULL;
+
+void InitializeSymbolizer(const char *argv0) {
+  if (process != nullptr) {
+    return;
+  }
+  process = GetCurrentProcess();
+
+  // Symbols are not loaded until a reference is made requiring the
+  // symbols be loaded. This is the fastest, most efficient way to use
+  // the symbol handler.
+  SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
+  if (!SymInitialize(process, nullptr, true)) {
+    // GetLastError() returns a Win32 DWORD, but we assign to
+    // unsigned long long to simplify the ABSL_RAW_LOG case below.  The uniform
+    // initialization guarantees this is not a narrowing conversion.
+    const unsigned long long error{GetLastError()};  // NOLINT(runtime/int)
+    ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
+  }
+}
+
+bool Symbolize(const void *pc, char *out, int out_size) {
+  if (out_size <= 0) {
+    return false;
+  }
+  std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME,
+                       alignof(SYMBOL_INFO)>::type buf;
+  SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf);
+  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+  symbol->MaxNameLen = MAX_SYM_NAME;
+  if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
+    return false;
+  }
+  strncpy(out, symbol->Name, out_size);
+  if (out[out_size - 1] != '\0') {
+    // strncpy() does not '\0' terminate when it truncates.
+    static constexpr char kEllipsis[] = "...";
+    int ellipsis_size =
+        std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+    memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+    out[out_size - 1] = '\0';
+  }
+  return true;
+}
+
+}  // namespace absl
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
new file mode 100644
index 0000000..46f47b1
--- /dev/null
+++ b/absl/memory/BUILD.bazel
@@ -0,0 +1,61 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+    "ABSL_EXCEPTIONS_FLAG",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "memory",
+    hdrs = ["memory.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base:core_headers",
+        "//absl/meta:type_traits",
+    ],
+)
+
+cc_test(
+    name = "memory_test",
+    srcs = ["memory_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":memory",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "memory_exception_safety_test",
+    srcs = [
+        "memory_exception_safety_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":memory",
+        "//absl/base:exception_safety_testing",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/memory/BUILD.gn b/absl/memory/BUILD.gn
new file mode 100644
index 0000000..30224c6
--- /dev/null
+++ b/absl/memory/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("memory") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "memory.h",
+  ]
+  deps = [
+    "../base:core_headers",
+    "../meta:type_traits",
+  ]
+}
diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt
new file mode 100644
index 0000000..5958f5c
--- /dev/null
+++ b/absl/memory/CMakeLists.txt
@@ -0,0 +1,71 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND MEMORY_PUBLIC_HEADERS
+  "memory.h"
+)
+
+
+absl_header_library(
+  TARGET
+    absl_memory
+  EXPORT_NAME
+    memory
+)
+
+#
+## TESTS
+#
+
+# test memory_test
+list(APPEND MEMORY_TEST_SRC
+  "memory_test.cc"
+  ${MEMORY_PUBLIC_HEADERS}
+)
+set(MEMORY_TEST_PUBLIC_LIBRARIES absl::base absl::memory)
+
+
+
+absl_test(
+  TARGET
+    memory_test
+  SOURCES
+    ${MEMORY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${MEMORY_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test memory_exception_safety_test
+set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc")
+set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
+  absl::memory
+  absl_base_internal_exception_safety_testing
+)
+
+absl_test(
+  TARGET
+    memory_exception_safety_test
+  SOURCES
+    ${MEMORY_EXCEPTION_SAFETY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
+
+
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
new file mode 100644
index 0000000..c43e156
--- /dev/null
+++ b/absl/memory/memory.h
@@ -0,0 +1,674 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: memory.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for managing the creation and
+// conversion of smart pointers. This file is an extension to the C++
+// standard <memory> library header file.
+
+#ifndef ABSL_MEMORY_MEMORY_H_
+#define ABSL_MEMORY_MEMORY_H_
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Function Template: WrapUnique()
+// -----------------------------------------------------------------------------
+//
+//  Adopts ownership from a raw pointer and transfers it to the returned
+//  `std::unique_ptr`, whose type is deduced. DO NOT specify the template type T
+//  when calling WrapUnique.
+//
+// Example:
+//   X* NewX(int, int);
+//   auto x = WrapUnique(NewX(1, 2));  // 'x' is std::unique_ptr<X>.
+//
+// `absl::WrapUnique` is useful for capturing the output of a raw pointer
+// factory. However, prefer 'absl::make_unique<T>(args...) over
+// 'absl::WrapUnique(new T(args...))'.
+//
+//   auto x = WrapUnique(new X(1, 2));  // works, but nonideal.
+//   auto x = make_unique<X>(1, 2);     // safer, standard, avoids raw 'new'.
+//
+// Note that `absl::WrapUnique(p)` is valid only if `delete p` is a valid
+// expression. In particular, `absl::WrapUnique()` cannot wrap pointers to
+// arrays, functions or void, and it must not be used to capture pointers
+// obtained from array-new expressions (even though that would compile!).
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+  static_assert(!std::is_array<T>::value, "array types are unsupported");
+  static_assert(std::is_object<T>::value, "non-object types are unsupported");
+  return std::unique_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// Traits to select proper overload and return type for `absl::make_unique<>`.
+template <typename T>
+struct MakeUniqueResult {
+  using scalar = std::unique_ptr<T>;
+};
+template <typename T>
+struct MakeUniqueResult<T[]> {
+  using array = std::unique_ptr<T[]>;
+};
+template <typename T, size_t N>
+struct MakeUniqueResult<T[N]> {
+  using invalid = void;
+};
+
+}  // namespace memory_internal
+
+#if __cplusplus >= 201402L || defined(_MSC_VER)
+using std::make_unique;
+#else
+// -----------------------------------------------------------------------------
+// Function Template: make_unique<T>()
+// -----------------------------------------------------------------------------
+//
+// Creates a `std::unique_ptr<>`, while avoiding issues creating temporaries
+// during the construction process. `absl::make_unique<>` also avoids redundant
+// type declarations, by avoiding the need to explicitly use the `new` operator.
+//
+// This implementation of `absl::make_unique<>` is designed for C++11 code and
+// will be replaced in C++14 by the equivalent `std::make_unique<>` abstraction.
+// `absl::make_unique<>` is designed to be 100% compatible with
+// `std::make_unique<>` so that the eventual migration will involve a simple
+// rename operation.
+//
+// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic,
+// see Herb Sutter's explanation on
+// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/].
+// (In general, reviewers should treat `new T(a,b)` with scrutiny.)
+//
+// Example usage:
+//
+//    auto p = make_unique<X>(args...);  // 'p'  is a std::unique_ptr<X>
+//    auto pa = make_unique<X[]>(5);     // 'pa' is a std::unique_ptr<X[]>
+//
+// Three overloads of `absl::make_unique` are required:
+//
+//   - For non-array T:
+//
+//       Allocates a T with `new T(std::forward<Args> args...)`,
+//       forwarding all `args` to T's constructor.
+//       Returns a `std::unique_ptr<T>` owning that object.
+//
+//   - For an array of unknown bounds T[]:
+//
+//       `absl::make_unique<>` will allocate an array T of type U[] with
+//       `new U[n]()` and return a `std::unique_ptr<U[]>` owning that array.
+//
+//       Note that 'U[n]()' is different from 'U[n]', and elements will be
+//       value-initialized. Note as well that `std::unique_ptr` will perform its
+//       own destruction of the array elements upon leaving scope, even though
+//       the array [] does not have a default destructor.
+//
+//       NOTE: an array of unknown bounds T[] may still be (and often will be)
+//       initialized to have a size, and will still use this overload. E.g:
+//
+//         auto my_array = absl::make_unique<int[]>(10);
+//
+//   - For an array of known bounds T[N]:
+//
+//       `absl::make_unique<>` is deleted (like with `std::make_unique<>`) as
+//       this overload is not useful.
+//
+//       NOTE: an array of known bounds T[N] is not considered a useful
+//       construction, and may cause undefined behavior in templates. E.g:
+//
+//         auto my_array = absl::make_unique<int[10]>();
+//
+//       In those cases, of course, you can still use the overload above and
+//       simply initialize it to its desired size:
+//
+//         auto my_array = absl::make_unique<int[]>(10);
+
+// `absl::make_unique` overload for non-array types.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::scalar make_unique(
+    Args&&... args) {
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+// `absl::make_unique` overload for an array T[] of unknown bounds.
+// The array allocation needs to use the `new T[size]` form and cannot take
+// element constructor arguments. The `std::unique_ptr` will manage destructing
+// these array elements.
+template <typename T>
+typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) {
+  return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]());
+}
+
+// `absl::make_unique` overload for an array T[N] of known bounds.
+// This construction will be rejected.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::invalid make_unique(
+    Args&&... /* args */) = delete;
+#endif
+
+// -----------------------------------------------------------------------------
+// Function Template: RawPtr()
+// -----------------------------------------------------------------------------
+//
+// Extracts the raw pointer from a pointer-like value `ptr`. `absl::RawPtr` is
+// useful within templates that need to handle a complement of raw pointers,
+// `std::nullptr_t`, and smart pointers.
+template <typename T>
+auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr)) {
+  // ptr is a forwarding reference to support Ts with non-const operators.
+  return (ptr != nullptr) ? std::addressof(*ptr) : nullptr;
+}
+inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; }
+
+// -----------------------------------------------------------------------------
+// Function Template: ShareUniquePtr()
+// -----------------------------------------------------------------------------
+//
+// Adopts a `std::unique_ptr` rvalue and returns a `std::shared_ptr` of deduced
+// type. Ownership (if any) of the held value is transferred to the returned
+// shared pointer.
+//
+// Example:
+//
+//     auto up = absl::make_unique<int>(10);
+//     auto sp = absl::ShareUniquePtr(std::move(up));  // shared_ptr<int>
+//     CHECK_EQ(*sp, 10);
+//     CHECK(up == nullptr);
+//
+// Note that this conversion is correct even when T is an array type, and more
+// generally it works for *any* deleter of the `unique_ptr` (single-object
+// deleter, array deleter, or any custom deleter), since the deleter is adopted
+// by the shared pointer as well. The deleter is copied (unless it is a
+// reference).
+//
+// Implements the resolution of [LWG 2415](http://wg21.link/lwg2415), by which a
+// null shared pointer does not attempt to call the deleter.
+template <typename T, typename D>
+std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) {
+  return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>();
+}
+
+// -----------------------------------------------------------------------------
+// Function Template: WeakenPtr()
+// -----------------------------------------------------------------------------
+//
+// Creates a weak pointer associated with a given shared pointer. The returned
+// value is a `std::weak_ptr` of deduced type.
+//
+// Example:
+//
+//    auto sp = std::make_shared<int>(10);
+//    auto wp = absl::WeakenPtr(sp);
+//    CHECK_EQ(sp.get(), wp.lock().get());
+//    sp.reset();
+//    CHECK(wp.lock() == nullptr);
+//
+template <typename T>
+std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) {
+  return std::weak_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D.
+template <template <typename> class Extract, typename Obj, typename Default,
+          typename>
+struct ExtractOr {
+  using type = Default;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> {
+  using type = Extract<Obj>;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type;
+
+// Extractors for the features of allocators.
+template <typename T>
+using GetPointer = typename T::pointer;
+
+template <typename T>
+using GetConstPointer = typename T::const_pointer;
+
+template <typename T>
+using GetVoidPointer = typename T::void_pointer;
+
+template <typename T>
+using GetConstVoidPointer = typename T::const_void_pointer;
+
+template <typename T>
+using GetDifferenceType = typename T::difference_type;
+
+template <typename T>
+using GetSizeType = typename T::size_type;
+
+template <typename T>
+using GetPropagateOnContainerCopyAssignment =
+    typename T::propagate_on_container_copy_assignment;
+
+template <typename T>
+using GetPropagateOnContainerMoveAssignment =
+    typename T::propagate_on_container_move_assignment;
+
+template <typename T>
+using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap;
+
+template <typename T>
+using GetIsAlwaysEqual = typename T::is_always_equal;
+
+template <typename T>
+struct GetFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args>
+struct GetFirstArg<Class<T, Args...>> {
+  using type = T;
+};
+
+template <typename Ptr, typename = void>
+struct ElementType {
+  using type = typename GetFirstArg<Ptr>::type;
+};
+
+template <typename T>
+struct ElementType<T, void_t<typename T::element_type>> {
+  using type = typename T::element_type;
+};
+
+template <typename T, typename U>
+struct RebindFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args,
+          typename U>
+struct RebindFirstArg<Class<T, Args...>, U> {
+  using type = Class<U, Args...>;
+};
+
+template <typename T, typename U, typename = void>
+struct RebindPtr {
+  using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> {
+  using type = typename T::template rebind<U>;
+};
+
+template <typename T, typename U>
+constexpr bool HasRebindAlloc(...) {
+  return false;
+}
+
+template <typename T, typename U>
+constexpr bool HasRebindAlloc(typename T::template rebind<U>::other*) {
+  return true;
+}
+
+template <typename T, typename U, bool = HasRebindAlloc<T, U>(nullptr)>
+struct RebindAlloc {
+  using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindAlloc<T, U, true> {
+  using type = typename T::template rebind<U>::other;
+};
+
+}  // namespace memory_internal
+
+// -----------------------------------------------------------------------------
+// Class Template: pointer_traits
+// -----------------------------------------------------------------------------
+//
+// An implementation of C++11's std::pointer_traits.
+//
+// Provided for portability on toolchains that have a working C++11 compiler,
+// but the standard library is lacking in C++11 support. For example, some
+// version of the Android NDK.
+//
+
+template <typename Ptr>
+struct pointer_traits {
+  using pointer = Ptr;
+
+  // element_type:
+  // Ptr::element_type if present. Otherwise T if Ptr is a template
+  // instantiation Template<T, Args...>
+  using element_type = typename memory_internal::ElementType<Ptr>::type;
+
+  // difference_type:
+  // Ptr::difference_type if present, otherwise std::ptrdiff_t
+  using difference_type =
+      memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr,
+                                  std::ptrdiff_t>;
+
+  // rebind:
+  // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a
+  // template instantiation Template<T, Args...>
+  template <typename U>
+  using rebind = typename memory_internal::RebindPtr<Ptr, U>::type;
+
+  // pointer_to:
+  // Calls Ptr::pointer_to(r)
+  static pointer pointer_to(element_type& r) {  // NOLINT(runtime/references)
+    return Ptr::pointer_to(r);
+  }
+};
+
+// Specialization for T*.
+template <typename T>
+struct pointer_traits<T*> {
+  using pointer = T*;
+  using element_type = T;
+  using difference_type = std::ptrdiff_t;
+
+  template <typename U>
+  using rebind = U*;
+
+  // pointer_to:
+  // Calls std::addressof(r)
+  static pointer pointer_to(
+      element_type& r) noexcept {  // NOLINT(runtime/references)
+    return std::addressof(r);
+  }
+};
+
+// -----------------------------------------------------------------------------
+// Class Template: allocator_traits
+// -----------------------------------------------------------------------------
+//
+// A C++11 compatible implementation of C++17's std::allocator_traits.
+//
+template <typename Alloc>
+struct allocator_traits {
+  using allocator_type = Alloc;
+
+  // value_type:
+  // Alloc::value_type
+  using value_type = typename Alloc::value_type;
+
+  // pointer:
+  // Alloc::pointer if present, otherwise value_type*
+  using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer,
+                                              Alloc, value_type*>;
+
+  // const_pointer:
+  // Alloc::const_pointer if present, otherwise
+  // absl::pointer_traits<pointer>::rebind<const value_type>
+  using const_pointer =
+      memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc,
+                                  typename absl::pointer_traits<pointer>::
+                                      template rebind<const value_type>>;
+
+  // void_pointer:
+  // Alloc::void_pointer if present, otherwise
+  // absl::pointer_traits<pointer>::rebind<void>
+  using void_pointer = memory_internal::ExtractOrT<
+      memory_internal::GetVoidPointer, Alloc,
+      typename absl::pointer_traits<pointer>::template rebind<void>>;
+
+  // const_void_pointer:
+  // Alloc::const_void_pointer if present, otherwise
+  // absl::pointer_traits<pointer>::rebind<const void>
+  using const_void_pointer = memory_internal::ExtractOrT<
+      memory_internal::GetConstVoidPointer, Alloc,
+      typename absl::pointer_traits<pointer>::template rebind<const void>>;
+
+  // difference_type:
+  // Alloc::difference_type if present, otherwise
+  // absl::pointer_traits<pointer>::difference_type
+  using difference_type = memory_internal::ExtractOrT<
+      memory_internal::GetDifferenceType, Alloc,
+      typename absl::pointer_traits<pointer>::difference_type>;
+
+  // size_type:
+  // Alloc::size_type if present, otherwise
+  // std::make_unsigned<difference_type>::type
+  using size_type = memory_internal::ExtractOrT<
+      memory_internal::GetSizeType, Alloc,
+      typename std::make_unsigned<difference_type>::type>;
+
+  // propagate_on_container_copy_assignment:
+  // Alloc::propagate_on_container_copy_assignment if present, otherwise
+  // std::false_type
+  using propagate_on_container_copy_assignment = memory_internal::ExtractOrT<
+      memory_internal::GetPropagateOnContainerCopyAssignment, Alloc,
+      std::false_type>;
+
+  // propagate_on_container_move_assignment:
+  // Alloc::propagate_on_container_move_assignment if present, otherwise
+  // std::false_type
+  using propagate_on_container_move_assignment = memory_internal::ExtractOrT<
+      memory_internal::GetPropagateOnContainerMoveAssignment, Alloc,
+      std::false_type>;
+
+  // propagate_on_container_swap:
+  // Alloc::propagate_on_container_swap if present, otherwise std::false_type
+  using propagate_on_container_swap =
+      memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap,
+                                  Alloc, std::false_type>;
+
+  // is_always_equal:
+  // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
+  using is_always_equal =
+      memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc,
+                                  typename std::is_empty<Alloc>::type>;
+
+  // rebind_alloc:
+  // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc
+  // is Alloc<U, Args>
+  template <typename T>
+  using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type;
+
+  // rebind_traits:
+  // absl::allocator_traits<rebind_alloc<T>>
+  template <typename T>
+  using rebind_traits = absl::allocator_traits<rebind_alloc<T>>;
+
+  // allocate(Alloc& a, size_type n):
+  // Calls a.allocate(n)
+  static pointer allocate(Alloc& a,  // NOLINT(runtime/references)
+                          size_type n) {
+    return a.allocate(n);
+  }
+
+  // allocate(Alloc& a, size_type n, const_void_pointer hint):
+  // Calls a.allocate(n, hint) if possible.
+  // If not possible, calls a.allocate(n)
+  static pointer allocate(Alloc& a, size_type n,  // NOLINT(runtime/references)
+                          const_void_pointer hint) {
+    return allocate_impl(0, a, n, hint);
+  }
+
+  // deallocate(Alloc& a, pointer p, size_type n):
+  // Calls a.deallocate(p, n)
+  static void deallocate(Alloc& a, pointer p,  // NOLINT(runtime/references)
+                         size_type n) {
+    a.deallocate(p, n);
+  }
+
+  // construct(Alloc& a, T* p, Args&&... args):
+  // Calls a.construct(p, std::forward<Args>(args)...) if possible.
+  // If not possible, calls
+  //   ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
+  template <typename T, typename... Args>
+  static void construct(Alloc& a, T* p,  // NOLINT(runtime/references)
+                        Args&&... args) {
+    construct_impl(0, a, p, std::forward<Args>(args)...);
+  }
+
+  // destroy(Alloc& a, T* p):
+  // Calls a.destroy(p) if possible. If not possible, calls p->~T().
+  template <typename T>
+  static void destroy(Alloc& a, T* p) {  // NOLINT(runtime/references)
+    destroy_impl(0, a, p);
+  }
+
+  // max_size(const Alloc& a):
+  // Returns a.max_size() if possible. If not possible, returns
+  //   std::numeric_limits<size_type>::max() / sizeof(value_type)
+  static size_type max_size(const Alloc& a) { return max_size_impl(0, a); }
+
+  // select_on_container_copy_construction(const Alloc& a):
+  // Returns a.select_on_container_copy_construction() if possible.
+  // If not possible, returns a.
+  static Alloc select_on_container_copy_construction(const Alloc& a) {
+    return select_on_container_copy_construction_impl(0, a);
+  }
+
+ private:
+  template <typename A>
+  static auto allocate_impl(int, A& a,  // NOLINT(runtime/references)
+                            size_type n, const_void_pointer hint)
+      -> decltype(a.allocate(n, hint)) {
+    return a.allocate(n, hint);
+  }
+  static pointer allocate_impl(char, Alloc& a,  // NOLINT(runtime/references)
+                               size_type n, const_void_pointer) {
+    return a.allocate(n);
+  }
+
+  template <typename A, typename... Args>
+  static auto construct_impl(int, A& a,  // NOLINT(runtime/references)
+                             Args&&... args)
+      -> decltype(a.construct(std::forward<Args>(args)...)) {
+    a.construct(std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  static void construct_impl(char, Alloc&, T* p, Args&&... args) {
+    ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+  }
+
+  template <typename A, typename T>
+  static auto destroy_impl(int, A& a,  // NOLINT(runtime/references)
+                           T* p) -> decltype(a.destroy(p)) {
+    a.destroy(p);
+  }
+  template <typename T>
+  static void destroy_impl(char, Alloc&, T* p) {
+    p->~T();
+  }
+
+  template <typename A>
+  static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) {
+    return a.max_size();
+  }
+  static size_type max_size_impl(char, const Alloc&) {
+    return std::numeric_limits<size_type>::max() / sizeof(value_type);
+  }
+
+  template <typename A>
+  static auto select_on_container_copy_construction_impl(int, const A& a)
+      -> decltype(a.select_on_container_copy_construction()) {
+    return a.select_on_container_copy_construction();
+  }
+  static Alloc select_on_container_copy_construction_impl(char,
+                                                          const Alloc& a) {
+    return a;
+  }
+};
+
+namespace memory_internal {
+
+// This template alias transforms Alloc::is_nothrow into a metafunction with
+// Alloc as a parameter so it can be used with ExtractOrT<>.
+template <typename Alloc>
+using GetIsNothrow = typename Alloc::is_nothrow;
+
+}  // namespace memory_internal
+
+// ABSL_ALLOCATOR_NOTHROW is a build time configuration macro for user to
+// specify whether the default allocation function can throw or never throws.
+// If the allocation function never throws, user should define it to a non-zero
+// value (e.g. via `-DABSL_ALLOCATOR_NOTHROW`).
+// If the allocation function can throw, user should leave it undefined or
+// define it to zero.
+//
+// allocator_is_nothrow<Alloc> is a traits class that derives from
+// Alloc::is_nothrow if present, otherwise std::false_type. It's specialized
+// for Alloc = std::allocator<T> for any type T according to the state of
+// ABSL_ALLOCATOR_NOTHROW.
+//
+// default_allocator_is_nothrow is a class that derives from std::true_type
+// when the default allocator (global operator new) never throws, and
+// std::false_type when it can throw. It is a convenience shorthand for writing
+// allocator_is_nothrow<std::allocator<T>> (T can be any type).
+// NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from
+// the same type for all T, because users should specialize neither
+// allocator_is_nothrow nor std::allocator.
+template <typename Alloc>
+struct allocator_is_nothrow
+    : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
+                                  std::false_type> {};
+
+#if ABSL_ALLOCATOR_NOTHROW
+template <typename T>
+struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
+struct default_allocator_is_nothrow : std::true_type {};
+#else
+struct default_allocator_is_nothrow : std::false_type {};
+#endif
+
+namespace memory_internal {
+// TODO(b110200014): Implement proper backports
+template <typename ForwardIt>
+void DefaultConstruct(ForwardIt it) {
+  using value_type = typename std::iterator_traits<ForwardIt>::value_type;
+  ::new (static_cast<void*>(std::addressof(*it))) value_type;
+}  // namespace memory_internal
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+template <typename ForwardIt, typename Size>
+void uninitialized_default_construct_n(ForwardIt first, Size size) {
+  for (ForwardIt cur = first; size > 0; static_cast<void>(++cur), --size) {
+    try {
+      absl::memory_internal::DefaultConstruct(cur);
+    } catch (...) {
+      using value_type = typename std::iterator_traits<ForwardIt>::value_type;
+      for (; first != cur; ++first) {
+        first->~value_type();
+      }
+      throw;
+    }
+  }
+}
+#else   // ABSL_HAVE_EXCEPTIONS
+template <typename ForwardIt, typename Size>
+void uninitialized_default_construct_n(ForwardIt first, Size size) {
+  for (; size > 0; static_cast<void>(++first), --size) {
+    absl::memory_internal::DefaultConstruct(first);
+  }
+}
+#endif  // ABSL_HAVE_EXCEPTIONS
+}  // namespace memory_internal
+
+}  // namespace absl
+
+#endif  // ABSL_MEMORY_MEMORY_H_
diff --git a/absl/memory/memory_exception_safety_test.cc b/absl/memory/memory_exception_safety_test.cc
new file mode 100644
index 0000000..fb8b561
--- /dev/null
+++ b/absl/memory/memory_exception_safety_test.cc
@@ -0,0 +1,63 @@
+// Copyright 2018 The Abseil 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 "absl/memory/memory.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+
+namespace absl {
+namespace {
+
+constexpr int kLength = 50;
+using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
+using ThrowerStorage =
+    absl::aligned_storage_t<sizeof(Thrower), alignof(Thrower)>;
+using ThrowerList = std::array<ThrowerStorage, kLength>;
+
+TEST(MakeUnique, CheckForLeaks) {
+  constexpr int kValue = 321;
+  auto tester = testing::MakeExceptionSafetyTester()
+                    .WithInitialValue(Thrower(kValue))
+                    // Ensures make_unique does not modify the input. The real
+                    // test, though, is ConstructorTracker checking for leaks.
+                    .WithInvariants(testing::strong_guarantee);
+
+  EXPECT_TRUE(tester.Test([](Thrower* thrower) {
+    static_cast<void>(absl::make_unique<Thrower>(*thrower));
+  }));
+
+  EXPECT_TRUE(tester.Test([](Thrower* thrower) {
+    static_cast<void>(absl::make_unique<Thrower>(std::move(*thrower)));
+  }));
+
+  // Test T[n] overload
+  EXPECT_TRUE(tester.Test([&](Thrower*) {
+    static_cast<void>(absl::make_unique<Thrower[]>(kLength));
+  }));
+}
+
+TEST(MemoryInternal, UninitDefaultConstructNNonTrivial) {
+  EXPECT_TRUE(testing::MakeExceptionSafetyTester()
+                  .WithInitialValue(ThrowerList{})
+                  .WithOperation([&](ThrowerList* list_ptr) {
+                    absl::memory_internal::uninitialized_default_construct_n(
+                        list_ptr->data(), kLength);
+                  })
+                  .WithInvariants([&](...) { return true; })
+                  .Test());
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
new file mode 100644
index 0000000..8ff1945
--- /dev/null
+++ b/absl/memory/memory_test.cc
@@ -0,0 +1,657 @@
+// Copyright 2017 The Abseil 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.
+
+// Tests for pointer utilities.
+
+#include "absl/memory/memory.h"
+
+#include <sys/types.h>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Return;
+
+// This class creates observable behavior to verify that a destructor has
+// been called, via the instance_count variable.
+class DestructorVerifier {
+ public:
+  DestructorVerifier() { ++instance_count_;  }
+  DestructorVerifier(const DestructorVerifier&) = delete;
+  DestructorVerifier& operator=(const DestructorVerifier&) = delete;
+  ~DestructorVerifier() {  --instance_count_; }
+
+  // The number of instances of this class currently active.
+  static int instance_count() { return instance_count_; }
+
+ private:
+  // The number of instances of this class currently active.
+  static int instance_count_;
+};
+
+int DestructorVerifier::instance_count_ = 0;
+
+TEST(WrapUniqueTest, WrapUnique) {
+  // Test that the unique_ptr is constructed properly by verifying that the
+  // destructor for its payload gets called at the proper time.
+  {
+    auto dv = new DestructorVerifier;
+    EXPECT_EQ(1, DestructorVerifier::instance_count());
+    std::unique_ptr<DestructorVerifier> ptr = absl::WrapUnique(dv);
+    EXPECT_EQ(1, DestructorVerifier::instance_count());
+  }
+  EXPECT_EQ(0, DestructorVerifier::instance_count());
+}
+TEST(MakeUniqueTest, Basic) {
+  std::unique_ptr<std::string> p = absl::make_unique<std::string>();
+  EXPECT_EQ("", *p);
+  p = absl::make_unique<std::string>("hi");
+  EXPECT_EQ("hi", *p);
+}
+
+struct MoveOnly {
+  MoveOnly() = default;
+  explicit MoveOnly(int i1) : ip1{new int{i1}} {}
+  MoveOnly(int i1, int i2) : ip1{new int{i1}}, ip2{new int{i2}} {}
+  std::unique_ptr<int> ip1;
+  std::unique_ptr<int> ip2;
+};
+
+struct AcceptMoveOnly {
+  explicit AcceptMoveOnly(MoveOnly m) : m_(std::move(m)) {}
+  MoveOnly m_;
+};
+
+TEST(MakeUniqueTest, MoveOnlyTypeAndValue) {
+  using ExpectedType = std::unique_ptr<MoveOnly>;
+  {
+    auto p = absl::make_unique<MoveOnly>();
+    static_assert(std::is_same<decltype(p), ExpectedType>::value,
+                  "unexpected return type");
+    EXPECT_TRUE(!p->ip1);
+    EXPECT_TRUE(!p->ip2);
+  }
+  {
+    auto p = absl::make_unique<MoveOnly>(1);
+    static_assert(std::is_same<decltype(p), ExpectedType>::value,
+                  "unexpected return type");
+    EXPECT_TRUE(p->ip1 && *p->ip1 == 1);
+    EXPECT_TRUE(!p->ip2);
+  }
+  {
+    auto p = absl::make_unique<MoveOnly>(1, 2);
+    static_assert(std::is_same<decltype(p), ExpectedType>::value,
+                  "unexpected return type");
+    EXPECT_TRUE(p->ip1 && *p->ip1 == 1);
+    EXPECT_TRUE(p->ip2 && *p->ip2 == 2);
+  }
+}
+
+TEST(MakeUniqueTest, AcceptMoveOnly) {
+  auto p = absl::make_unique<AcceptMoveOnly>(MoveOnly());
+  p = std::unique_ptr<AcceptMoveOnly>(new AcceptMoveOnly(MoveOnly()));
+}
+
+struct ArrayWatch {
+  void* operator new[](size_t n) {
+    allocs().push_back(n);
+    return ::operator new[](n);
+  }
+  void operator delete[](void* p) {
+    return ::operator delete[](p);
+  }
+  static std::vector<size_t>& allocs() {
+    static auto& v = *new std::vector<size_t>;
+    return v;
+  }
+};
+
+TEST(Make_UniqueTest, Array) {
+  // Ensure state is clean before we start so that these tests
+  // are order-agnostic.
+  ArrayWatch::allocs().clear();
+
+  auto p = absl::make_unique<ArrayWatch[]>(5);
+  static_assert(std::is_same<decltype(p),
+                             std::unique_ptr<ArrayWatch[]>>::value,
+                "unexpected return type");
+  EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch)));
+}
+
+TEST(Make_UniqueTest, NotAmbiguousWithStdMakeUnique) {
+  // Ensure that absl::make_unique is not ambiguous with std::make_unique.
+  // In C++14 mode, the below call to make_unique has both types as candidates.
+  struct TakesStdType {
+    explicit TakesStdType(const std::vector<int> &vec) {}
+  };
+  using absl::make_unique;
+  make_unique<TakesStdType>(std::vector<int>());
+}
+
+#if 0
+// TODO(billydonahue): Make a proper NC test.
+// These tests shouldn't compile.
+TEST(MakeUniqueTestNC, AcceptMoveOnlyLvalue) {
+  auto m = MoveOnly();
+  auto p = absl::make_unique<AcceptMoveOnly>(m);
+}
+TEST(MakeUniqueTestNC, KnownBoundArray) {
+  auto p = absl::make_unique<ArrayWatch[5]>();
+}
+#endif
+
+TEST(RawPtrTest, RawPointer) {
+  int i = 5;
+  EXPECT_EQ(&i, absl::RawPtr(&i));
+}
+
+TEST(RawPtrTest, SmartPointer) {
+  int* o = new int(5);
+  std::unique_ptr<int> p(o);
+  EXPECT_EQ(o, absl::RawPtr(p));
+}
+
+class IntPointerNonConstDeref {
+ public:
+  explicit IntPointerNonConstDeref(int* p) : p_(p) {}
+  friend bool operator!=(const IntPointerNonConstDeref& a, std::nullptr_t) {
+    return a.p_ != nullptr;
+  }
+  int& operator*() { return *p_; }
+
+ private:
+  std::unique_ptr<int> p_;
+};
+
+TEST(RawPtrTest, SmartPointerNonConstDereference) {
+  int* o = new int(5);
+  IntPointerNonConstDeref p(o);
+  EXPECT_EQ(o, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, NullValuedRawPointer) {
+  int* p = nullptr;
+  EXPECT_EQ(nullptr, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, NullValuedSmartPointer) {
+  std::unique_ptr<int> p;
+  EXPECT_EQ(nullptr, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, Nullptr) {
+  auto p = absl::RawPtr(nullptr);
+  EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+  EXPECT_EQ(nullptr, p);
+}
+
+TEST(RawPtrTest, Null) {
+  auto p = absl::RawPtr(nullptr);
+  EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+  EXPECT_EQ(nullptr, p);
+}
+
+TEST(RawPtrTest, Zero) {
+  auto p = absl::RawPtr(nullptr);
+  EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+  EXPECT_EQ(nullptr, p);
+}
+
+TEST(ShareUniquePtrTest, Share) {
+  auto up = absl::make_unique<int>();
+  int* rp = up.get();
+  auto sp = absl::ShareUniquePtr(std::move(up));
+  EXPECT_EQ(sp.get(), rp);
+}
+
+TEST(ShareUniquePtrTest, ShareNull) {
+  struct NeverDie {
+    using pointer = void*;
+    void operator()(pointer) {
+      ASSERT_TRUE(false) << "Deleter should not have been called.";
+    }
+  };
+
+  std::unique_ptr<void, NeverDie> up;
+  auto sp = absl::ShareUniquePtr(std::move(up));
+}
+
+TEST(WeakenPtrTest, Weak) {
+  auto sp = std::make_shared<int>();
+  auto wp = absl::WeakenPtr(sp);
+  EXPECT_EQ(sp.get(), wp.lock().get());
+  sp.reset();
+  EXPECT_TRUE(wp.expired());
+}
+
+// Should not compile.
+/*
+TEST(RawPtrTest, NotAPointer) {
+  absl::RawPtr(1.5);
+}
+*/
+
+template <typename T>
+struct SmartPointer {
+  using difference_type = char;
+};
+
+struct PointerWith {
+  using element_type = int32_t;
+  using difference_type = int16_t;
+  template <typename U>
+  using rebind = SmartPointer<U>;
+
+  static PointerWith pointer_to(
+      element_type& r) {  // NOLINT(runtime/references)
+    return PointerWith{&r};
+  }
+
+  element_type* ptr;
+};
+
+template <typename... Args>
+struct PointerWithout {};
+
+TEST(PointerTraits, Types) {
+  using TraitsWith = absl::pointer_traits<PointerWith>;
+  EXPECT_TRUE((std::is_same<TraitsWith::pointer, PointerWith>::value));
+  EXPECT_TRUE((std::is_same<TraitsWith::element_type, int32_t>::value));
+  EXPECT_TRUE((std::is_same<TraitsWith::difference_type, int16_t>::value));
+  EXPECT_TRUE((
+      std::is_same<TraitsWith::rebind<int64_t>, SmartPointer<int64_t>>::value));
+
+  using TraitsWithout = absl::pointer_traits<PointerWithout<double, int>>;
+  EXPECT_TRUE((std::is_same<TraitsWithout::pointer,
+                            PointerWithout<double, int>>::value));
+  EXPECT_TRUE((std::is_same<TraitsWithout::element_type, double>::value));
+  EXPECT_TRUE(
+      (std::is_same<TraitsWithout ::difference_type, std::ptrdiff_t>::value));
+  EXPECT_TRUE((std::is_same<TraitsWithout::rebind<int64_t>,
+                            PointerWithout<int64_t, int>>::value));
+
+  using TraitsRawPtr = absl::pointer_traits<char*>;
+  EXPECT_TRUE((std::is_same<TraitsRawPtr::pointer, char*>::value));
+  EXPECT_TRUE((std::is_same<TraitsRawPtr::element_type, char>::value));
+  EXPECT_TRUE(
+      (std::is_same<TraitsRawPtr::difference_type, std::ptrdiff_t>::value));
+  EXPECT_TRUE((std::is_same<TraitsRawPtr::rebind<int64_t>, int64_t*>::value));
+}
+
+TEST(PointerTraits, Functions) {
+  int i;
+  EXPECT_EQ(&i, absl::pointer_traits<PointerWith>::pointer_to(i).ptr);
+  EXPECT_EQ(&i, absl::pointer_traits<int*>::pointer_to(i));
+}
+
+TEST(AllocatorTraits, Typedefs) {
+  struct A {
+    struct value_type {};
+  };
+  EXPECT_TRUE((
+      std::is_same<A,
+                   typename absl::allocator_traits<A>::allocator_type>::value));
+  EXPECT_TRUE(
+      (std::is_same<A::value_type,
+                    typename absl::allocator_traits<A>::value_type>::value));
+
+  struct X {};
+  struct HasPointer {
+    using value_type = X;
+    using pointer = SmartPointer<X>;
+  };
+  EXPECT_TRUE((std::is_same<SmartPointer<X>, typename absl::allocator_traits<
+                                                 HasPointer>::pointer>::value));
+  EXPECT_TRUE(
+      (std::is_same<A::value_type*,
+                    typename absl::allocator_traits<A>::pointer>::value));
+
+  EXPECT_TRUE(
+      (std::is_same<
+          SmartPointer<const X>,
+          typename absl::allocator_traits<HasPointer>::const_pointer>::value));
+  EXPECT_TRUE(
+      (std::is_same<const A::value_type*,
+                    typename absl::allocator_traits<A>::const_pointer>::value));
+
+  struct HasVoidPointer {
+    using value_type = X;
+    struct void_pointer {};
+  };
+
+  EXPECT_TRUE((std::is_same<HasVoidPointer::void_pointer,
+                            typename absl::allocator_traits<
+                                HasVoidPointer>::void_pointer>::value));
+  EXPECT_TRUE(
+      (std::is_same<SmartPointer<void>, typename absl::allocator_traits<
+                                            HasPointer>::void_pointer>::value));
+
+  struct HasConstVoidPointer {
+    using value_type = X;
+    struct const_void_pointer {};
+  };
+
+  EXPECT_TRUE(
+      (std::is_same<HasConstVoidPointer::const_void_pointer,
+                    typename absl::allocator_traits<
+                        HasConstVoidPointer>::const_void_pointer>::value));
+  EXPECT_TRUE((std::is_same<SmartPointer<const void>,
+                            typename absl::allocator_traits<
+                                HasPointer>::const_void_pointer>::value));
+
+  struct HasDifferenceType {
+    using value_type = X;
+    using difference_type = int;
+  };
+  EXPECT_TRUE(
+      (std::is_same<int, typename absl::allocator_traits<
+                             HasDifferenceType>::difference_type>::value));
+  EXPECT_TRUE((std::is_same<char, typename absl::allocator_traits<
+                                      HasPointer>::difference_type>::value));
+
+  struct HasSizeType {
+    using value_type = X;
+    using size_type = unsigned int;
+  };
+  EXPECT_TRUE((std::is_same<unsigned int, typename absl::allocator_traits<
+                                              HasSizeType>::size_type>::value));
+  EXPECT_TRUE((std::is_same<unsigned char, typename absl::allocator_traits<
+                                               HasPointer>::size_type>::value));
+
+  struct HasPropagateOnCopy {
+    using value_type = X;
+    struct propagate_on_container_copy_assignment {};
+  };
+
+  EXPECT_TRUE(
+      (std::is_same<HasPropagateOnCopy::propagate_on_container_copy_assignment,
+                    typename absl::allocator_traits<HasPropagateOnCopy>::
+                        propagate_on_container_copy_assignment>::value));
+  EXPECT_TRUE(
+      (std::is_same<std::false_type,
+                    typename absl::allocator_traits<
+                        A>::propagate_on_container_copy_assignment>::value));
+
+  struct HasPropagateOnMove {
+    using value_type = X;
+    struct propagate_on_container_move_assignment {};
+  };
+
+  EXPECT_TRUE(
+      (std::is_same<HasPropagateOnMove::propagate_on_container_move_assignment,
+                    typename absl::allocator_traits<HasPropagateOnMove>::
+                        propagate_on_container_move_assignment>::value));
+  EXPECT_TRUE(
+      (std::is_same<std::false_type,
+                    typename absl::allocator_traits<
+                        A>::propagate_on_container_move_assignment>::value));
+
+  struct HasPropagateOnSwap {
+    using value_type = X;
+    struct propagate_on_container_swap {};
+  };
+
+  EXPECT_TRUE(
+      (std::is_same<HasPropagateOnSwap::propagate_on_container_swap,
+                    typename absl::allocator_traits<HasPropagateOnSwap>::
+                        propagate_on_container_swap>::value));
+  EXPECT_TRUE(
+      (std::is_same<std::false_type, typename absl::allocator_traits<A>::
+                                         propagate_on_container_swap>::value));
+
+  struct HasIsAlwaysEqual {
+    using value_type = X;
+    struct is_always_equal {};
+  };
+
+  EXPECT_TRUE((std::is_same<HasIsAlwaysEqual::is_always_equal,
+                            typename absl::allocator_traits<
+                                HasIsAlwaysEqual>::is_always_equal>::value));
+  EXPECT_TRUE((std::is_same<std::true_type, typename absl::allocator_traits<
+                                                A>::is_always_equal>::value));
+  struct NonEmpty {
+    using value_type = X;
+    int i;
+  };
+  EXPECT_TRUE(
+      (std::is_same<std::false_type,
+                    absl::allocator_traits<NonEmpty>::is_always_equal>::value));
+}
+
+template <typename T>
+struct AllocWithPrivateInheritance : private std::allocator<T> {
+  using value_type = T;
+};
+
+TEST(AllocatorTraits, RebindWithPrivateInheritance) {
+  // Regression test for some versions of gcc that do not like the sfinae we
+  // used in combination with private inheritance.
+  EXPECT_TRUE(
+      (std::is_same<AllocWithPrivateInheritance<int>,
+                    absl::allocator_traits<AllocWithPrivateInheritance<char>>::
+                        rebind_alloc<int>>::value));
+}
+
+template <typename T>
+struct Rebound {};
+
+struct AllocWithRebind {
+  using value_type = int;
+  template <typename T>
+  struct rebind {
+    using other = Rebound<T>;
+  };
+};
+
+template <typename T, typename U>
+struct AllocWithoutRebind {
+  using value_type = int;
+};
+
+TEST(AllocatorTraits, Rebind) {
+  EXPECT_TRUE(
+      (std::is_same<Rebound<int>,
+                    typename absl::allocator_traits<
+                        AllocWithRebind>::template rebind_alloc<int>>::value));
+  EXPECT_TRUE(
+      (std::is_same<absl::allocator_traits<Rebound<int>>,
+                    typename absl::allocator_traits<
+                        AllocWithRebind>::template rebind_traits<int>>::value));
+
+  EXPECT_TRUE(
+      (std::is_same<AllocWithoutRebind<double, char>,
+                    typename absl::allocator_traits<AllocWithoutRebind<
+                        int, char>>::template rebind_alloc<double>>::value));
+  EXPECT_TRUE(
+      (std::is_same<absl::allocator_traits<AllocWithoutRebind<double, char>>,
+                    typename absl::allocator_traits<AllocWithoutRebind<
+                        int, char>>::template rebind_traits<double>>::value));
+}
+
+struct TestValue {
+  TestValue() {}
+  explicit TestValue(int* trace) : trace(trace) { ++*trace; }
+  ~TestValue() {
+    if (trace) --*trace;
+  }
+  int* trace = nullptr;
+};
+
+struct MinimalMockAllocator {
+  MinimalMockAllocator() : value(0) {}
+  explicit MinimalMockAllocator(int value) : value(value) {}
+  MinimalMockAllocator(const MinimalMockAllocator& other)
+      : value(other.value) {}
+  using value_type = TestValue;
+  MOCK_METHOD1(allocate, value_type*(size_t));
+  MOCK_METHOD2(deallocate, void(value_type*, size_t));
+
+  int value;
+};
+
+TEST(AllocatorTraits, FunctionsMinimal) {
+  int trace = 0;
+  int hint;
+  TestValue x(&trace);
+  MinimalMockAllocator mock;
+  using Traits = absl::allocator_traits<MinimalMockAllocator>;
+  EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
+  EXPECT_CALL(mock, deallocate(&x, 7));
+
+  EXPECT_EQ(&x, Traits::allocate(mock, 7));
+  Traits::allocate(mock, 7, static_cast<const void*>(&hint));
+  EXPECT_EQ(&x, Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
+  Traits::deallocate(mock, &x, 7);
+
+  EXPECT_EQ(1, trace);
+  Traits::construct(mock, &x, &trace);
+  EXPECT_EQ(2, trace);
+  Traits::destroy(mock, &x);
+  EXPECT_EQ(1, trace);
+
+  EXPECT_EQ(std::numeric_limits<size_t>::max() / sizeof(TestValue),
+            Traits::max_size(mock));
+
+  EXPECT_EQ(0, mock.value);
+  EXPECT_EQ(0, Traits::select_on_container_copy_construction(mock).value);
+}
+
+struct FullMockAllocator {
+  FullMockAllocator() : value(0) {}
+  explicit FullMockAllocator(int value) : value(value) {}
+  FullMockAllocator(const FullMockAllocator& other) : value(other.value) {}
+  using value_type = TestValue;
+  MOCK_METHOD1(allocate, value_type*(size_t));
+  MOCK_METHOD2(allocate, value_type*(size_t, const void*));
+  MOCK_METHOD2(construct, void(value_type*, int*));
+  MOCK_METHOD1(destroy, void(value_type*));
+  MOCK_CONST_METHOD0(max_size, size_t());
+  MOCK_CONST_METHOD0(select_on_container_copy_construction,
+                     FullMockAllocator());
+
+  int value;
+};
+
+TEST(AllocatorTraits, FunctionsFull) {
+  int trace = 0;
+  int hint;
+  TestValue x(&trace), y;
+  FullMockAllocator mock;
+  using Traits = absl::allocator_traits<FullMockAllocator>;
+  EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
+  EXPECT_CALL(mock, allocate(13, &hint)).WillRepeatedly(Return(&y));
+  EXPECT_CALL(mock, construct(&x, &trace));
+  EXPECT_CALL(mock, destroy(&x));
+  EXPECT_CALL(mock, max_size()).WillRepeatedly(Return(17));
+  EXPECT_CALL(mock, select_on_container_copy_construction())
+      .WillRepeatedly(Return(FullMockAllocator(23)));
+
+  EXPECT_EQ(&x, Traits::allocate(mock, 7));
+  EXPECT_EQ(&y, Traits::allocate(mock, 13, static_cast<const void*>(&hint)));
+
+  EXPECT_EQ(1, trace);
+  Traits::construct(mock, &x, &trace);
+  EXPECT_EQ(1, trace);
+  Traits::destroy(mock, &x);
+  EXPECT_EQ(1, trace);
+
+  EXPECT_EQ(17, Traits::max_size(mock));
+
+  EXPECT_EQ(0, mock.value);
+  EXPECT_EQ(23, Traits::select_on_container_copy_construction(mock).value);
+}
+
+TEST(AllocatorNoThrowTest, DefaultAllocator) {
+#if ABSL_ALLOCATOR_NOTHROW
+  EXPECT_TRUE(absl::default_allocator_is_nothrow::value);
+#else
+  EXPECT_FALSE(absl::default_allocator_is_nothrow::value);
+#endif
+}
+
+TEST(AllocatorNoThrowTest, StdAllocator) {
+#if ABSL_ALLOCATOR_NOTHROW
+  EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value);
+#else
+  EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value);
+#endif
+}
+
+TEST(AllocatorNoThrowTest, CustomAllocator) {
+  struct NoThrowAllocator {
+    using is_nothrow = std::true_type;
+  };
+  struct CanThrowAllocator {
+    using is_nothrow = std::false_type;
+  };
+  struct UnspecifiedAllocator {
+  };
+  EXPECT_TRUE(absl::allocator_is_nothrow<NoThrowAllocator>::value);
+  EXPECT_FALSE(absl::allocator_is_nothrow<CanThrowAllocator>::value);
+  EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value);
+}
+
+TEST(MemoryInternal, UninitDefaultConstructNTrivial) {
+  constexpr int kInitialValue = 123;
+  constexpr int kExpectedValue = kInitialValue;  // Expect no-op behavior
+  constexpr int len = 5;
+
+  struct TestObj {
+    int val;
+  };
+  static_assert(absl::is_trivially_default_constructible<TestObj>::value, "");
+  static_assert(absl::is_trivially_destructible<TestObj>::value, "");
+
+  TestObj objs[len];
+  for (auto& obj : objs) {
+    obj.val = kInitialValue;
+  }
+
+  absl::memory_internal::uninitialized_default_construct_n(objs, len);
+  for (auto& obj : objs) {
+    EXPECT_EQ(obj.val, kExpectedValue);
+  }
+}
+
+TEST(MemoryInternal, UninitDefaultConstructNNonTrivial) {
+  constexpr int kInitialValue = 123;
+  constexpr int kExpectedValue = 0;  // Expect value-construction behavior
+  constexpr int len = 5;
+
+  struct TestObj {
+    int val{kExpectedValue};
+  };
+  static_assert(absl::is_trivially_destructible<TestObj>::value, "");
+
+  TestObj objs[len];
+  for (auto& obj : objs) {
+    obj.val = kInitialValue;
+  }
+
+  absl::memory_internal::uninitialized_default_construct_n(objs, len);
+  for (auto& obj : objs) {
+    EXPECT_EQ(obj.val, kExpectedValue);
+  }
+}
+
+}  // namespace
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
new file mode 100644
index 0000000..dbc9717
--- /dev/null
+++ b/absl/meta/BUILD.bazel
@@ -0,0 +1,29 @@
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "type_traits",
+    hdrs = ["type_traits.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base:config",
+    ],
+)
+
+cc_test(
+    name = "type_traits_test",
+    srcs = ["type_traits_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":type_traits",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/meta/BUILD.gn b/absl/meta/BUILD.gn
new file mode 100644
index 0000000..6757219
--- /dev/null
+++ b/absl/meta/BUILD.gn
@@ -0,0 +1,30 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("type_traits") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "type_traits.h",
+  ]
+  deps = [
+    "../base:config",
+  ]
+}
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
new file mode 100644
index 0000000..adb0ceb
--- /dev/null
+++ b/absl/meta/CMakeLists.txt
@@ -0,0 +1,52 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND META_PUBLIC_HEADERS
+  "type_traits.h"
+)
+
+
+#
+## TESTS
+#
+
+# test type_traits_test
+list(APPEND TYPE_TRAITS_TEST_SRC
+  "type_traits_test.cc"
+  ${META_PUBLIC_HEADERS}
+)
+
+absl_header_library(
+  TARGET
+    absl_meta
+  PUBLIC_LIBRARIES
+    absl::base
+  EXPORT_NAME
+    meta
+ )
+
+absl_test(
+  TARGET
+    type_traits_test
+  SOURCES
+    ${TYPE_TRAITS_TEST_SRC}
+  PUBLIC_LIBRARIES
+    absl::base
+    absl::meta
+)
+
+
+
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
new file mode 100644
index 0000000..c3e01fe
--- /dev/null
+++ b/absl/meta/type_traits.h
@@ -0,0 +1,374 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// type_traits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains C++11-compatible versions of standard <type_traits> API
+// functions for determining the characteristics of types. Such traits can
+// support type inference, classification, and transformation, as well as
+// make it easier to write templates based on generic type behavior.
+//
+// See http://en.cppreference.com/w/cpp/header/type_traits
+//
+// WARNING: use of many of the constructs in this header will count as "complex
+// template metaprogramming", so before proceeding, please carefully consider
+// https://google.github.io/styleguide/cppguide.html#Template_metaprogramming
+//
+// WARNING: using template metaprogramming to detect or depend on API
+// features is brittle and not guaranteed. Neither the standard library nor
+// Abseil provides any guarantee that APIs are stable in the face of template
+// metaprogramming. Use with caution.
+#ifndef ABSL_META_TYPE_TRAITS_H_
+#define ABSL_META_TYPE_TRAITS_H_
+
+#include <stddef.h>
+#include <functional>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+
+namespace type_traits_internal {
+template <typename... Ts>
+struct VoidTImpl {
+  using type = void;
+};
+
+// This trick to retrieve a default alignment is necessary for our
+// implementation of aligned_storage_t to be consistent with any implementation
+// of std::aligned_storage.
+template <size_t Len, typename T = std::aligned_storage<Len>>
+struct default_alignment_of_aligned_storage;
+
+template <size_t Len, size_t Align>
+struct default_alignment_of_aligned_storage<Len,
+                                            std::aligned_storage<Len, Align>> {
+  static constexpr size_t value = Align;
+};
+
+}  // namespace type_traits_internal
+
+// void_t()
+//
+// Ignores the type of any its arguments and returns `void`. In general, this
+// metafunction allows you to create a general case that maps to `void` while
+// allowing specializations that map to specific types.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::void_t` metafunction.
+//
+// NOTE: `absl::void_t` does not use the standard-specified implementation so
+// that it can remain compatible with gcc < 5.1. This can introduce slightly
+// different behavior, such as when ordering partial specializations.
+template <typename... Ts>
+using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
+
+// conjunction
+//
+// Performs a compile-time logical AND operation on the passed types (which
+// must have  `::value` members convertible to `bool`. Short-circuits if it
+// encounters any `false` members (and does not compare the `::value` members
+// of any remaining arguments).
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::conjunction` metafunction.
+template <typename... Ts>
+struct conjunction;
+
+template <typename T, typename... Ts>
+struct conjunction<T, Ts...>
+    : std::conditional<T::value, conjunction<Ts...>, T>::type {};
+
+template <typename T>
+struct conjunction<T> : T {};
+
+template <>
+struct conjunction<> : std::true_type {};
+
+// disjunction
+//
+// Performs a compile-time logical OR operation on the passed types (which
+// must have  `::value` members convertible to `bool`. Short-circuits if it
+// encounters any `true` members (and does not compare the `::value` members
+// of any remaining arguments).
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::disjunction` metafunction.
+template <typename... Ts>
+struct disjunction;
+
+template <typename T, typename... Ts>
+struct disjunction<T, Ts...> :
+      std::conditional<T::value, T, disjunction<Ts...>>::type {};
+
+template <typename T>
+struct disjunction<T> : T {};
+
+template <>
+struct disjunction<> : std::false_type {};
+
+// negation
+//
+// Performs a compile-time logical NOT operation on the passed type (which
+// must have  `::value` members convertible to `bool`.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::negation` metafunction.
+template <typename T>
+struct negation : std::integral_constant<bool, !T::value> {};
+
+// is_trivially_destructible()
+//
+// Determines whether the passed type `T` is trivially destructable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_destructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: the extensions (__has_trivial_xxx) are implemented in gcc (version >=
+// 4.3) and clang. Since we are supporting libstdc++ > 4.7, they should always
+// be present. These  extensions are documented at
+// https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html#Type-Traits.
+template <typename T>
+struct is_trivially_destructible
+    : std::integral_constant<bool, __has_trivial_destructor(T) &&
+                                   std::is_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+ private:
+  static constexpr bool compliant = std::is_trivially_destructible<T>::value ==
+                                    is_trivially_destructible::value;
+  static_assert(compliant || std::is_trivially_destructible<T>::value,
+                "Not compliant with std::is_trivially_destructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_destructible<T>::value,
+                "Not compliant with std::is_trivially_destructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+};
+
+// is_trivially_default_constructible()
+//
+// Determines whether the passed type `T` is trivially default constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_default_constructible()` metafunction for platforms that
+// have incomplete C++11 support (such as libstdc++ 4.x). On any platforms that
+// do fully support C++11, we check whether this yields the same result as the
+// std implementation.
+//
+// NOTE: according to the C++ standard, Section: 20.15.4.3 [meta.unary.prop]
+// "The predicate condition for a template specialization is_constructible<T,
+// Args...> shall be satisfied if and only if the following variable
+// definition would be well-formed for some invented variable t:
+//
+// T t(declval<Args>()...);
+//
+// is_trivially_constructible<T, Args...> additionally requires that the
+// variable definition does not call any operation that is not trivial.
+// For the purposes of this check, the call to std::declval is considered
+// trivial."
+//
+// Notes from http://en.cppreference.com/w/cpp/types/is_constructible:
+// In many implementations, is_nothrow_constructible also checks if the
+// destructor throws because it is effectively noexcept(T(arg)). Same
+// applies to is_trivially_constructible, which, in these implementations, also
+// requires that the destructor is trivial.
+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116.
+//
+// "T obj();" need to be well-formed and not call any nontrivial operation.
+// Nontrivially destructible types will cause the expression to be nontrivial.
+template <typename T>
+struct is_trivially_default_constructible
+    : std::integral_constant<bool, __has_trivial_constructor(T) &&
+                                   std::is_default_constructible<T>::value &&
+                                   is_trivially_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_default_constructible<T>::value ==
+      is_trivially_default_constructible::value;
+  static_assert(compliant || std::is_trivially_default_constructible<T>::value,
+                "Not compliant with std::is_trivially_default_constructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_default_constructible<T>::value,
+                "Not compliant with std::is_trivially_default_constructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_copy_constructible()
+//
+// Determines whether the passed type `T` is trivially copy constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_copy_constructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `T obj(declval<const T&>());` needs to be well-formed and not call any
+// nontrivial operation.  Nontrivially destructible types will cause the
+// expression to be nontrivial.
+template <typename T>
+struct is_trivially_copy_constructible
+    : std::integral_constant<bool, __has_trivial_copy(T) &&
+                                   std::is_copy_constructible<T>::value &&
+                                   is_trivially_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_copy_constructible<T>::value ==
+      is_trivially_copy_constructible::value;
+  static_assert(compliant || std::is_trivially_copy_constructible<T>::value,
+                "Not compliant with std::is_trivially_copy_constructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_copy_constructible<T>::value,
+                "Not compliant with std::is_trivially_copy_constructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_copy_assignable()
+//
+// Determines whether the passed type `T` is trivially copy assignable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_copy_assignable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `is_assignable<T, U>::value` is `true` if the expression
+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
+// `is_trivially_assignable<T&, const T&>`.
+template <typename T>
+struct is_trivially_copy_assignable
+    : std::integral_constant<bool, __has_trivial_assign(T) &&
+                                   std::is_copy_assignable<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_copy_assignable<T>::value ==
+      is_trivially_copy_assignable::value;
+  static_assert(compliant || std::is_trivially_copy_assignable<T>::value,
+                "Not compliant with std::is_trivially_copy_assignable; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_copy_assignable<T>::value,
+                "Not compliant with std::is_trivially_copy_assignable; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+};
+
+// -----------------------------------------------------------------------------
+// C++14 "_t" trait aliases
+// -----------------------------------------------------------------------------
+
+template <typename T>
+using remove_cv_t = typename std::remove_cv<T>::type;
+
+template <typename T>
+using remove_const_t = typename std::remove_const<T>::type;
+
+template <typename T>
+using remove_volatile_t = typename std::remove_volatile<T>::type;
+
+template <typename T>
+using add_cv_t = typename std::add_cv<T>::type;
+
+template <typename T>
+using add_const_t = typename std::add_const<T>::type;
+
+template <typename T>
+using add_volatile_t = typename std::add_volatile<T>::type;
+
+template <typename T>
+using remove_reference_t = typename std::remove_reference<T>::type;
+
+template <typename T>
+using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
+
+template <typename T>
+using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
+
+template <typename T>
+using remove_pointer_t = typename std::remove_pointer<T>::type;
+
+template <typename T>
+using add_pointer_t = typename std::add_pointer<T>::type;
+
+template <typename T>
+using make_signed_t = typename std::make_signed<T>::type;
+
+template <typename T>
+using make_unsigned_t = typename std::make_unsigned<T>::type;
+
+template <typename T>
+using remove_extent_t = typename std::remove_extent<T>::type;
+
+template <typename T>
+using remove_all_extents_t = typename std::remove_all_extents<T>::type;
+
+template <size_t Len, size_t Align = type_traits_internal::
+                          default_alignment_of_aligned_storage<Len>::value>
+using aligned_storage_t = typename std::aligned_storage<Len, Align>::type;
+
+template <typename T>
+using decay_t = typename std::decay<T>::type;
+
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+template <bool B, typename T, typename F>
+using conditional_t = typename std::conditional<B, T, F>::type;
+
+template <typename... T>
+using common_type_t = typename std::common_type<T...>::type;
+
+template <typename T>
+using underlying_type_t = typename std::underlying_type<T>::type;
+
+template <typename T>
+using result_of_t = typename std::result_of<T>::type;
+
+namespace type_traits_internal {
+template <typename Key, typename = size_t>
+struct IsHashable : std::false_type {};
+
+template <typename Key>
+struct IsHashable<Key,
+                  decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))>
+    : std::true_type {};
+
+template <typename Key>
+struct IsHashEnabled
+    : absl::conjunction<std::is_default_constructible<std::hash<Key>>,
+                        std::is_copy_constructible<std::hash<Key>>,
+                        std::is_destructible<std::hash<Key>>,
+                        std::is_copy_assignable<std::hash<Key>>,
+                        IsHashable<Key>> {};
+}  // namespace type_traits_internal
+
+}  // namespace absl
+
+
+#endif  // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
new file mode 100644
index 0000000..c44d1c5
--- /dev/null
+++ b/absl/meta/type_traits_test.cc
@@ -0,0 +1,799 @@
+// Copyright 2017 The Abseil 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 "absl/meta/type_traits.h"
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using ::testing::StaticAssertTypeEq;
+
+template <class T, class U>
+struct simple_pair {
+  T first;
+  U second;
+};
+
+struct Dummy {};
+
+TEST(VoidTTest, BasicUsage) {
+  StaticAssertTypeEq<void, absl::void_t<Dummy>>();
+  StaticAssertTypeEq<void, absl::void_t<Dummy, Dummy, Dummy>>();
+}
+
+TEST(ConjunctionTest, BasicBooleanLogic) {
+  EXPECT_TRUE(absl::conjunction<>::value);
+  EXPECT_TRUE(absl::conjunction<std::true_type>::value);
+  EXPECT_TRUE((absl::conjunction<std::true_type, std::true_type>::value));
+  EXPECT_FALSE((absl::conjunction<std::true_type, std::false_type>::value));
+  EXPECT_FALSE((absl::conjunction<std::false_type, std::true_type>::value));
+  EXPECT_FALSE((absl::conjunction<std::false_type, std::false_type>::value));
+}
+
+struct MyTrueType {
+  static constexpr bool value = true;
+};
+
+struct MyFalseType {
+  static constexpr bool value = false;
+};
+
+TEST(ConjunctionTest, ShortCircuiting) {
+  EXPECT_FALSE(
+      (absl::conjunction<std::true_type, std::false_type, Dummy>::value));
+  EXPECT_TRUE((std::is_base_of<MyFalseType,
+                               absl::conjunction<std::true_type, MyFalseType,
+                                                 std::false_type>>::value));
+  EXPECT_TRUE(
+      (std::is_base_of<MyTrueType,
+                       absl::conjunction<std::true_type, MyTrueType>>::value));
+}
+
+TEST(DisjunctionTest, BasicBooleanLogic) {
+  EXPECT_FALSE(absl::disjunction<>::value);
+  EXPECT_FALSE(absl::disjunction<std::false_type>::value);
+  EXPECT_TRUE((absl::disjunction<std::true_type, std::true_type>::value));
+  EXPECT_TRUE((absl::disjunction<std::true_type, std::false_type>::value));
+  EXPECT_TRUE((absl::disjunction<std::false_type, std::true_type>::value));
+  EXPECT_FALSE((absl::disjunction<std::false_type, std::false_type>::value));
+}
+
+TEST(DisjunctionTest, ShortCircuiting) {
+  EXPECT_TRUE(
+      (absl::disjunction<std::false_type, std::true_type, Dummy>::value));
+  EXPECT_TRUE((
+      std::is_base_of<MyTrueType, absl::disjunction<std::false_type, MyTrueType,
+                                                    std::true_type>>::value));
+  EXPECT_TRUE((
+      std::is_base_of<MyFalseType,
+                      absl::disjunction<std::false_type, MyFalseType>>::value));
+}
+
+TEST(NegationTest, BasicBooleanLogic) {
+  EXPECT_FALSE(absl::negation<std::true_type>::value);
+  EXPECT_FALSE(absl::negation<MyTrueType>::value);
+  EXPECT_TRUE(absl::negation<std::false_type>::value);
+  EXPECT_TRUE(absl::negation<MyFalseType>::value);
+}
+
+// all member functions are trivial
+class Trivial {
+  int n_;
+};
+
+struct TrivialDestructor {
+  ~TrivialDestructor() = default;
+};
+
+struct NontrivialDestructor {
+  ~NontrivialDestructor() {}
+};
+
+struct DeletedDestructor {
+  ~DeletedDestructor() = delete;
+};
+
+class TrivialDefaultCtor {
+ public:
+  TrivialDefaultCtor() = default;
+  explicit TrivialDefaultCtor(int n) : n_(n) {}
+
+ private:
+  int n_;
+};
+
+class NontrivialDefaultCtor {
+ public:
+  NontrivialDefaultCtor() : n_(1) {}
+
+ private:
+  int n_;
+};
+
+class DeletedDefaultCtor {
+ public:
+  DeletedDefaultCtor() = delete;
+  explicit DeletedDefaultCtor(int n) : n_(n) {}
+
+ private:
+  int n_;
+};
+
+class TrivialCopyCtor {
+ public:
+  explicit TrivialCopyCtor(int n) : n_(n) {}
+  TrivialCopyCtor(const TrivialCopyCtor&) = default;
+  TrivialCopyCtor& operator=(const TrivialCopyCtor& t) {
+    n_ = t.n_;
+    return *this;
+  }
+
+ private:
+  int n_;
+};
+
+class NontrivialCopyCtor {
+ public:
+  explicit NontrivialCopyCtor(int n) : n_(n) {}
+  NontrivialCopyCtor(const NontrivialCopyCtor& t) : n_(t.n_) {}
+  NontrivialCopyCtor& operator=(const NontrivialCopyCtor&) = default;
+
+ private:
+  int n_;
+};
+
+class DeletedCopyCtor {
+ public:
+  explicit DeletedCopyCtor(int n) : n_(n) {}
+  DeletedCopyCtor(const DeletedCopyCtor&) = delete;
+  DeletedCopyCtor& operator=(const DeletedCopyCtor&) = default;
+
+ private:
+  int n_;
+};
+
+class TrivialCopyAssign {
+ public:
+  explicit TrivialCopyAssign(int n) : n_(n) {}
+  TrivialCopyAssign(const TrivialCopyAssign& t) : n_(t.n_) {}
+  TrivialCopyAssign& operator=(const TrivialCopyAssign& t) = default;
+  ~TrivialCopyAssign() {}  // can have nontrivial destructor
+ private:
+  int n_;
+};
+
+class NontrivialCopyAssign {
+ public:
+  explicit NontrivialCopyAssign(int n) : n_(n) {}
+  NontrivialCopyAssign(const NontrivialCopyAssign&) = default;
+  NontrivialCopyAssign& operator=(const NontrivialCopyAssign& t) {
+    n_ = t.n_;
+    return *this;
+  }
+
+ private:
+  int n_;
+};
+
+class DeletedCopyAssign {
+ public:
+  explicit DeletedCopyAssign(int n) : n_(n) {}
+  DeletedCopyAssign(const DeletedCopyAssign&) = default;
+  DeletedCopyAssign& operator=(const DeletedCopyAssign&) = delete;
+
+ private:
+  int n_;
+};
+
+struct NonCopyable {
+  NonCopyable() = default;
+  NonCopyable(const NonCopyable&) = delete;
+  NonCopyable& operator=(const NonCopyable&) = delete;
+};
+
+class Base {
+ public:
+  virtual ~Base() {}
+};
+
+// In GCC/Clang, std::is_trivially_constructible requires that the destructor is
+// trivial. However, MSVC doesn't require that. This results in different
+// behavior when checking is_trivially_constructible on any type with
+// nontrivial destructor. Since absl::is_trivially_default_constructible and
+// absl::is_trivially_copy_constructible both follows Clang/GCC's interpretation
+// and check is_trivially_destructible, it results in inconsistency with
+// std::is_trivially_xxx_constructible on MSVC. This macro is used to work
+// around this issue in test. In practice, a trivially constructible type
+// should also be trivially destructible.
+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116
+#ifndef _MSC_VER
+#define ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE 1
+#endif
+
+// Old versions of libc++, around Clang 3.5 to 3.6, consider deleted destructors
+// as also being trivial. With the resolution of CWG 1928 and CWG 1734, this
+// is no longer considered true and has thus been amended.
+// Compiler Explorer: https://godbolt.org/g/zT59ZL
+// CWG issue 1734: http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1734
+// CWG issue 1928: http://open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1928
+#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 3700
+#define ABSL_TRIVIALLY_DESTRUCTIBLE_CONSIDER_DELETED_DESTRUCTOR_NOT_TRIVIAL 1
+#endif
+
+// As of the moment, GCC versions >5.1 have a problem compiling for
+// std::is_trivially_default_constructible<NontrivialDestructor[10]>, where
+// NontrivialDestructor is a struct with a custom nontrivial destructor. Note
+// that this problem only occurs for arrays of a known size, so something like
+// std::is_trivially_default_constructible<NontrivialDestructor[]> does not
+// have any problems.
+// Compiler Explorer: https://godbolt.org/g/dXRbdK
+// GCC bug 83689: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83689
+#if defined(__clang__) || defined(_MSC_VER) || \
+    (defined(__GNUC__) && __GNUC__ < 5)
+#define ABSL_GCC_BUG_TRIVIALLY_CONSTRUCTIBLE_ON_ARRAY_OF_NONTRIVIAL 1
+#endif
+
+TEST(TypeTraitsTest, TestTrivialDestructor) {
+  // Verify that arithmetic types and pointers have trivial destructors.
+  EXPECT_TRUE(absl::is_trivially_destructible<bool>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<char>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<unsigned char>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<signed char>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<wchar_t>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<int>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<unsigned int>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<int16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<uint16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<int64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<uint64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<float>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<double>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<long double>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<const std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<const Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<std::string**>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<Trivial**>::value);
+
+  // classes with destructors
+  EXPECT_TRUE(absl::is_trivially_destructible<Trivial>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<TrivialDestructor>::value);
+
+  // Verify that types with a nontrivial or deleted destructor
+  // are marked as such.
+  EXPECT_FALSE(absl::is_trivially_destructible<NontrivialDestructor>::value);
+#ifdef ABSL_TRIVIALLY_DESTRUCTIBLE_CONSIDER_DELETED_DESTRUCTOR_NOT_TRIVIAL
+  EXPECT_FALSE(absl::is_trivially_destructible<DeletedDestructor>::value);
+#endif
+
+  // simple_pair of such types is trivial
+  EXPECT_TRUE((absl::is_trivially_destructible<simple_pair<int, int>>::value));
+  EXPECT_TRUE((absl::is_trivially_destructible<
+               simple_pair<Trivial, TrivialDestructor>>::value));
+
+  // Verify that types without trivial destructors are correctly marked as such.
+  EXPECT_FALSE(absl::is_trivially_destructible<std::string>::value);
+  EXPECT_FALSE(absl::is_trivially_destructible<std::vector<int>>::value);
+
+  // Verify that simple_pairs of types without trivial destructors
+  // are not marked as trivial.
+  EXPECT_FALSE((absl::is_trivially_destructible<
+                simple_pair<int, std::string>>::value));
+  EXPECT_FALSE((absl::is_trivially_destructible<
+                simple_pair<std::string, int>>::value));
+
+  // array of such types is trivial
+  using int10 = int[10];
+  EXPECT_TRUE(absl::is_trivially_destructible<int10>::value);
+  using Trivial10 = Trivial[10];
+  EXPECT_TRUE(absl::is_trivially_destructible<Trivial10>::value);
+  using TrivialDestructor10 = TrivialDestructor[10];
+  EXPECT_TRUE(absl::is_trivially_destructible<TrivialDestructor10>::value);
+
+  // Conversely, the opposite also holds.
+  using NontrivialDestructor10 = NontrivialDestructor[10];
+  EXPECT_FALSE(absl::is_trivially_destructible<NontrivialDestructor10>::value);
+}
+
+TEST(TypeTraitsTest, TestTrivialDefaultCtor) {
+  // arithmetic types and pointers have trivial default constructors.
+  EXPECT_TRUE(absl::is_trivially_default_constructible<bool>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<char>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<unsigned char>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<signed char>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<wchar_t>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<int>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<unsigned int>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<int16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<uint16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<int64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<uint64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<float>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<double>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<long double>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial*>::value);
+  EXPECT_TRUE(
+      absl::is_trivially_default_constructible<const std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<const Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<std::string**>::value);
+  EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial**>::value);
+
+  // types with compiler generated default ctors
+  EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial>::value);
+  EXPECT_TRUE(
+      absl::is_trivially_default_constructible<TrivialDefaultCtor>::value);
+
+  // Verify that types without them are not.
+  EXPECT_FALSE(
+      absl::is_trivially_default_constructible<NontrivialDefaultCtor>::value);
+  EXPECT_FALSE(
+      absl::is_trivially_default_constructible<DeletedDefaultCtor>::value);
+
+#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
+  // types with nontrivial destructor are nontrivial
+  EXPECT_FALSE(
+      absl::is_trivially_default_constructible<NontrivialDestructor>::value);
+#endif
+
+  // types with vtables
+  EXPECT_FALSE(absl::is_trivially_default_constructible<Base>::value);
+
+  // Verify that simple_pair has trivial constructors where applicable.
+  EXPECT_TRUE((absl::is_trivially_default_constructible<
+               simple_pair<int, char*>>::value));
+  EXPECT_TRUE((absl::is_trivially_default_constructible<
+               simple_pair<int, Trivial>>::value));
+  EXPECT_TRUE((absl::is_trivially_default_constructible<
+               simple_pair<int, TrivialDefaultCtor>>::value));
+
+  // Verify that types without trivial constructors are
+  // correctly marked as such.
+  EXPECT_FALSE(absl::is_trivially_default_constructible<std::string>::value);
+  EXPECT_FALSE(
+      absl::is_trivially_default_constructible<std::vector<int>>::value);
+
+  // Verify that simple_pairs of types without trivial constructors
+  // are not marked as trivial.
+  EXPECT_FALSE((absl::is_trivially_default_constructible<
+                simple_pair<int, std::string>>::value));
+  EXPECT_FALSE((absl::is_trivially_default_constructible<
+                simple_pair<std::string, int>>::value));
+
+  // Verify that arrays of such types are trivially default constructible
+  using int10 = int[10];
+  EXPECT_TRUE(absl::is_trivially_default_constructible<int10>::value);
+  using Trivial10 = Trivial[10];
+  EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial10>::value);
+  using TrivialDefaultCtor10 = TrivialDefaultCtor[10];
+  EXPECT_TRUE(
+      absl::is_trivially_default_constructible<TrivialDefaultCtor10>::value);
+
+  // Conversely, the opposite also holds.
+#ifdef ABSL_GCC_BUG_TRIVIALLY_CONSTRUCTIBLE_ON_ARRAY_OF_NONTRIVIAL
+  using NontrivialDefaultCtor10 = NontrivialDefaultCtor[10];
+  EXPECT_FALSE(
+      absl::is_trivially_default_constructible<NontrivialDefaultCtor10>::value);
+#endif
+}
+
+TEST(TypeTraitsTest, TestTrivialCopyCtor) {
+  // Verify that arithmetic types and pointers have trivial copy
+  // constructors.
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<bool>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<char>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<unsigned char>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<signed char>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<wchar_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<int>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<unsigned int>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<int16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<uint16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<int64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<uint64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<float>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<double>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<long double>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<const std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<const Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string**>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial**>::value);
+
+  // types with compiler generated copy ctors
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivialCopyCtor>::value);
+
+  // Verify that types without them (i.e. nontrivial or deleted) are not.
+  EXPECT_FALSE(
+      absl::is_trivially_copy_constructible<NontrivialCopyCtor>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_constructible<DeletedCopyCtor>::value);
+  EXPECT_FALSE(
+      absl::is_trivially_copy_constructible<NonCopyable>::value);
+
+#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
+  // type with nontrivial destructor are nontrivial copy construbtible
+  EXPECT_FALSE(
+      absl::is_trivially_copy_constructible<NontrivialDestructor>::value);
+#endif
+
+  // types with vtables
+  EXPECT_FALSE(absl::is_trivially_copy_constructible<Base>::value);
+
+  // Verify that simple_pair of such types is trivially copy constructible
+  EXPECT_TRUE(
+      (absl::is_trivially_copy_constructible<simple_pair<int, char*>>::value));
+  EXPECT_TRUE((
+      absl::is_trivially_copy_constructible<simple_pair<int, Trivial>>::value));
+  EXPECT_TRUE((absl::is_trivially_copy_constructible<
+               simple_pair<int, TrivialCopyCtor>>::value));
+
+  // Verify that types without trivial copy constructors are
+  // correctly marked as such.
+  EXPECT_FALSE(absl::is_trivially_copy_constructible<std::string>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_constructible<std::vector<int>>::value);
+
+  // Verify that simple_pairs of types without trivial copy constructors
+  // are not marked as trivial.
+  EXPECT_FALSE((absl::is_trivially_copy_constructible<
+                simple_pair<int, std::string>>::value));
+  EXPECT_FALSE((absl::is_trivially_copy_constructible<
+                simple_pair<std::string, int>>::value));
+
+  // Verify that arrays are not
+  using int10 = int[10];
+  EXPECT_FALSE(absl::is_trivially_copy_constructible<int10>::value);
+}
+
+TEST(TypeTraitsTest, TestTrivialCopyAssign) {
+  // Verify that arithmetic types and pointers have trivial copy
+  // assignment operators.
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<bool>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<char>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<unsigned char>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<signed char>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<wchar_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<unsigned int>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<int16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<uint16_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<int64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<uint64_t>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<float>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<double>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<long double>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<const std::string*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<const Trivial*>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<std::string**>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial**>::value);
+
+  // const qualified types are not assignable
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<const int>::value);
+
+  // types with compiler generated copy assignment
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivialCopyAssign>::value);
+
+  // Verify that types without them (i.e. nontrivial or deleted) are not.
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<NontrivialCopyAssign>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<DeletedCopyAssign>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyable>::value);
+
+  // types with vtables
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<Base>::value);
+
+  // Verify that simple_pair is trivially assignable
+  EXPECT_TRUE(
+      (absl::is_trivially_copy_assignable<simple_pair<int, char*>>::value));
+  EXPECT_TRUE(
+      (absl::is_trivially_copy_assignable<simple_pair<int, Trivial>>::value));
+  EXPECT_TRUE((absl::is_trivially_copy_assignable<
+               simple_pair<int, TrivialCopyAssign>>::value));
+
+  // Verify that types not trivially copy assignable are
+  // correctly marked as such.
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<std::string>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<std::vector<int>>::value);
+
+  // Verify that simple_pairs of types not trivially copy assignable
+  // are not marked as trivial.
+  EXPECT_FALSE((absl::is_trivially_copy_assignable<
+                simple_pair<int, std::string>>::value));
+  EXPECT_FALSE((absl::is_trivially_copy_assignable<
+                simple_pair<std::string, int>>::value));
+
+  // Verify that arrays are not trivially copy assignable
+  using int10 = int[10];
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<int10>::value);
+}
+
+#define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...)          \
+  EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \
+                            absl::trait_name##_t<__VA_ARGS__>>::value))
+
+TEST(TypeTraitsTest, TestRemoveCVAliases) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const volatile int);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const volatile int);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const volatile int);
+}
+
+TEST(TypeTraitsTest, TestAddCVAliases) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const volatile int);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const volatile int);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const volatile int);
+}
+
+TEST(TypeTraitsTest, TestReferenceAliases) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&&);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&&);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&&);
+}
+
+TEST(TypeTraitsTest, TestPointerAliases) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, int*);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, volatile int*);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, volatile int);
+}
+
+TEST(TypeTraitsTest, TestSignednessAliases) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, unsigned);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile unsigned);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, unsigned);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile unsigned);
+}
+
+TEST(TypeTraitsTest, TestExtentAliases) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1][1]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[][1]);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1][1]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[][1]);
+}
+
+TEST(TypeTraitsTest, TestAlignedStorageAlias) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32, 128);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33, 128);
+}
+
+TEST(TypeTraitsTest, TestDecay) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1][1]);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int());
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float));
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...));
+}
+
+struct TypeA {};
+struct TypeB {};
+struct TypeC {};
+struct TypeD {};
+
+template <typename T>
+struct Wrap {};
+
+enum class TypeEnum { A, B, C, D };
+
+struct GetTypeT {
+  template <typename T,
+            absl::enable_if_t<std::is_same<T, TypeA>::value, int> = 0>
+  TypeEnum operator()(Wrap<T>) const {
+    return TypeEnum::A;
+  }
+
+  template <typename T,
+            absl::enable_if_t<std::is_same<T, TypeB>::value, int> = 0>
+  TypeEnum operator()(Wrap<T>) const {
+    return TypeEnum::B;
+  }
+
+  template <typename T,
+            absl::enable_if_t<std::is_same<T, TypeC>::value, int> = 0>
+  TypeEnum operator()(Wrap<T>) const {
+    return TypeEnum::C;
+  }
+
+  // NOTE: TypeD is intentionally not handled
+} constexpr GetType = {};
+
+TEST(TypeTraitsTest, TestEnableIf) {
+  EXPECT_EQ(TypeEnum::A, GetType(Wrap<TypeA>()));
+  EXPECT_EQ(TypeEnum::B, GetType(Wrap<TypeB>()));
+  EXPECT_EQ(TypeEnum::C, GetType(Wrap<TypeC>()));
+}
+
+TEST(TypeTraitsTest, TestConditional) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, true, int, char);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, false, int, char);
+}
+
+// TODO(calabrese) Check with specialized std::common_type
+TEST(TypeTraitsTest, TestCommonType) {
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int);
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char&);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int&);
+}
+
+TEST(TypeTraitsTest, TestUnderlyingType) {
+  enum class enum_char : char {};
+  enum class enum_long_long : long long {};  // NOLINT(runtime/int)
+
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_char);
+  ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_long_long);
+}
+
+struct GetTypeExtT {
+  template <typename T>
+  absl::result_of_t<const GetTypeT&(T)> operator()(T&& arg) const {
+    return GetType(std::forward<T>(arg));
+  }
+
+  TypeEnum operator()(Wrap<TypeD>) const { return TypeEnum::D; }
+} constexpr GetTypeExt = {};
+
+TEST(TypeTraitsTest, TestResultOf) {
+  EXPECT_EQ(TypeEnum::A, GetTypeExt(Wrap<TypeA>()));
+  EXPECT_EQ(TypeEnum::B, GetTypeExt(Wrap<TypeB>()));
+  EXPECT_EQ(TypeEnum::C, GetTypeExt(Wrap<TypeC>()));
+  EXPECT_EQ(TypeEnum::D, GetTypeExt(Wrap<TypeD>()));
+}
+
+}  // namespace
diff --git a/absl/module.mk b/absl/module.mk
new file mode 100644
index 0000000..262d8e4
--- /dev/null
+++ b/absl/module.mk
@@ -0,0 +1,21 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
+
+absl_CXX_OBJECTS = \
+	absl/base/internal/raw_logging.o \
+	absl/types/bad_optional_access.o
+
+# CXX_STATIC_LIBRARY(absl.pic.a): \
+# 	CPPFLAGS+= -DWEBRTC_POSIX -DWEBRTC_LINUX
+
+CXX_STATIC_LIBRARY(absl.pic.a): \
+	$(absl_CXX_OBJECTS)
+
+absl: CXX_STATIC_LIBRARY(absl.pic.a)
+
+clean: CLEAN(absl.pic.a)
+
+.PHONY: absl
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
new file mode 100644
index 0000000..f49571e
--- /dev/null
+++ b/absl/numeric/BUILD.bazel
@@ -0,0 +1,67 @@
+# Copyright 2018 The Abseil 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.
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "int128",
+    srcs = [
+        "int128.cc",
+        "int128_have_intrinsic.inc",
+        "int128_no_intrinsic.inc",
+    ],
+    hdrs = ["int128.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base:config",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "int128_test",
+    size = "small",
+    srcs = [
+        "int128_stream_test.cc",
+        "int128_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":int128",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/meta:type_traits",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "int128_benchmark",
+    srcs = ["int128_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    deps = [
+        ":int128",
+        "//absl/base:config",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
diff --git a/absl/numeric/BUILD.gn b/absl/numeric/BUILD.gn
new file mode 100644
index 0000000..fdfa2e2
--- /dev/null
+++ b/absl/numeric/BUILD.gn
@@ -0,0 +1,36 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("int128") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "int128.cc",
+    "int128_have_intrinsic.inc",
+    "int128_no_intrinsic.inc",
+  ]
+  public = [
+    "int128.h",
+  ]
+  deps = [
+    "../base:config",
+    "../base:core_headers",
+  ]
+}
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
new file mode 100644
index 0000000..3360b2e
--- /dev/null
+++ b/absl/numeric/CMakeLists.txt
@@ -0,0 +1,62 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND NUMERIC_PUBLIC_HEADERS
+  "int128.h"
+)
+
+
+# library 128
+list(APPEND INT128_SRC
+  "int128.cc"
+  ${NUMERIC_PUBLIC_HEADERS}
+)
+absl_library(
+  TARGET
+    absl_int128
+  SOURCES
+    ${INT128_SRC}
+  PUBLIC_LIBRARIES
+    ${INT128_PUBLIC_LIBRARIES}
+  EXPORT_NAME
+    int128
+)
+
+
+absl_header_library(
+  TARGET
+    absl_numeric
+  PUBLIC_LIBRARIES
+    absl::int128
+  EXPORT_NAME
+    numeric
+)
+
+# test int128_test
+set(INT128_TEST_SRC "int128_test.cc")
+set(INT128_TEST_PUBLIC_LIBRARIES absl::numeric absl::base)
+
+absl_test(
+  TARGET
+    int128_test
+  SOURCES
+    ${INT128_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${INT128_TEST_PUBLIC_LIBRARIES}
+)
+
+
+
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
new file mode 100644
index 0000000..cd79534
--- /dev/null
+++ b/absl/numeric/int128.cc
@@ -0,0 +1,251 @@
+// Copyright 2017 The Abseil 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 "absl/numeric/int128.h"
+
+#include <stddef.h>
+#include <cassert>
+#include <iomanip>
+#include <iostream>  // NOLINT(readability/streams)
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+namespace absl {
+
+const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(),
+                                        std::numeric_limits<uint64_t>::max());
+
+namespace {
+
+// Returns the 0-based position of the last set bit (i.e., most significant bit)
+// in the given uint64_t. The argument may not be 0.
+//
+// For example:
+//   Given: 5 (decimal) == 101 (binary)
+//   Returns: 2
+#define STEP(T, n, pos, sh)                   \
+  do {                                        \
+    if ((n) >= (static_cast<T>(1) << (sh))) { \
+      (n) = (n) >> (sh);                      \
+      (pos) |= (sh);                          \
+    }                                         \
+  } while (0)
+static inline int Fls64(uint64_t n) {
+  assert(n != 0);
+  int pos = 0;
+  STEP(uint64_t, n, pos, 0x20);
+  uint32_t n32 = static_cast<uint32_t>(n);
+  STEP(uint32_t, n32, pos, 0x10);
+  STEP(uint32_t, n32, pos, 0x08);
+  STEP(uint32_t, n32, pos, 0x04);
+  return pos + ((uint64_t{0x3333333322221100} >> (n32 << 2)) & 0x3);
+}
+#undef STEP
+
+// Like Fls64() above, but returns the 0-based position of the last set bit
+// (i.e., most significant bit) in the given uint128. The argument may not be 0.
+static inline int Fls128(uint128 n) {
+  if (uint64_t hi = Uint128High64(n)) {
+    return Fls64(hi) + 64;
+  }
+  return Fls64(Uint128Low64(n));
+}
+
+// Long division/modulo for uint128 implemented using the shift-subtract
+// division algorithm adapted from:
+// http://stackoverflow.com/questions/5386377/division-without-using
+void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
+                uint128* remainder_ret) {
+  assert(divisor != 0);
+
+  if (divisor > dividend) {
+    *quotient_ret = 0;
+    *remainder_ret = dividend;
+    return;
+  }
+
+  if (divisor == dividend) {
+    *quotient_ret = 1;
+    *remainder_ret = 0;
+    return;
+  }
+
+  uint128 denominator = divisor;
+  uint128 quotient = 0;
+
+  // Left aligns the MSB of the denominator and the dividend.
+  const int shift = Fls128(dividend) - Fls128(denominator);
+  denominator <<= shift;
+
+  // Uses shift-subtract algorithm to divide dividend by denominator. The
+  // remainder will be left in dividend.
+  for (int i = 0; i <= shift; ++i) {
+    quotient <<= 1;
+    if (dividend >= denominator) {
+      dividend -= denominator;
+      quotient |= 1;
+    }
+    denominator >>= 1;
+  }
+
+  *quotient_ret = quotient;
+  *remainder_ret = dividend;
+}
+
+template <typename T>
+uint128 MakeUint128FromFloat(T v) {
+  static_assert(std::is_floating_point<T>::value, "");
+
+  // Rounding behavior is towards zero, same as for built-in types.
+
+  // Undefined behavior if v is NaN or cannot fit into uint128.
+  assert(std::isfinite(v) && v > -1 &&
+         (std::numeric_limits<T>::max_exponent <= 128 ||
+          v < std::ldexp(static_cast<T>(1), 128)));
+
+  if (v >= std::ldexp(static_cast<T>(1), 64)) {
+    uint64_t hi = static_cast<uint64_t>(std::ldexp(v, -64));
+    uint64_t lo = static_cast<uint64_t>(v - std::ldexp(static_cast<T>(hi), 64));
+    return MakeUint128(hi, lo);
+  }
+
+  return MakeUint128(0, static_cast<uint64_t>(v));
+}
+}  // namespace
+
+uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
+uint128::uint128(double v) : uint128(MakeUint128FromFloat(v)) {}
+uint128::uint128(long double v) : uint128(MakeUint128FromFloat(v)) {}
+
+uint128 operator/(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  return static_cast<unsigned __int128>(lhs) /
+         static_cast<unsigned __int128>(rhs);
+#else  // ABSL_HAVE_INTRINSIC_INT128
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(lhs, rhs, &quotient, &remainder);
+  return quotient;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+}
+uint128 operator%(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  return static_cast<unsigned __int128>(lhs) %
+         static_cast<unsigned __int128>(rhs);
+#else  // ABSL_HAVE_INTRINSIC_INT128
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(lhs, rhs, &quotient, &remainder);
+  return remainder;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+}
+
+namespace {
+
+std::string Uint128ToFormattedString(uint128 v, std::ios_base::fmtflags flags) {
+  // Select a divisor which is the largest power of the base < 2^64.
+  uint128 div;
+  int div_base_log;
+  switch (flags & std::ios::basefield) {
+    case std::ios::hex:
+      div = 0x1000000000000000;  // 16^15
+      div_base_log = 15;
+      break;
+    case std::ios::oct:
+      div = 01000000000000000000000;  // 8^21
+      div_base_log = 21;
+      break;
+    default:  // std::ios::dec
+      div = 10000000000000000000u;  // 10^19
+      div_base_log = 19;
+      break;
+  }
+
+  // Now piece together the uint128 representation from three chunks of the
+  // original value, each less than "div" and therefore representable as a
+  // uint64_t.
+  std::ostringstream os;
+  std::ios_base::fmtflags copy_mask =
+      std::ios::basefield | std::ios::showbase | std::ios::uppercase;
+  os.setf(flags & copy_mask, copy_mask);
+  uint128 high = v;
+  uint128 low;
+  DivModImpl(high, div, &high, &low);
+  uint128 mid;
+  DivModImpl(high, div, &high, &mid);
+  if (Uint128Low64(high) != 0) {
+    os << Uint128Low64(high);
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+    os << Uint128Low64(mid);
+    os << std::setw(div_base_log);
+  } else if (Uint128Low64(mid) != 0) {
+    os << Uint128Low64(mid);
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+  }
+  os << Uint128Low64(low);
+  return os.str();
+}
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& os, uint128 v) {
+  std::ios_base::fmtflags flags = os.flags();
+  std::string rep = Uint128ToFormattedString(v, flags);
+
+  // Add the requisite padding.
+  std::streamsize width = os.width(0);
+  if (static_cast<size_t>(width) > rep.size()) {
+    std::ios::fmtflags adjustfield = flags & std::ios::adjustfield;
+    if (adjustfield == std::ios::left) {
+      rep.append(width - rep.size(), os.fill());
+    } else if (adjustfield == std::ios::internal &&
+               (flags & std::ios::showbase) &&
+               (flags & std::ios::basefield) == std::ios::hex && v != 0) {
+      rep.insert(2, width - rep.size(), os.fill());
+    } else {
+      rep.insert(0, width - rep.size(), os.fill());
+    }
+  }
+
+  return os << rep;
+}
+
+}  // namespace absl
+
+namespace std {
+constexpr bool numeric_limits<absl::uint128>::is_specialized;
+constexpr bool numeric_limits<absl::uint128>::is_signed;
+constexpr bool numeric_limits<absl::uint128>::is_integer;
+constexpr bool numeric_limits<absl::uint128>::is_exact;
+constexpr bool numeric_limits<absl::uint128>::has_infinity;
+constexpr bool numeric_limits<absl::uint128>::has_quiet_NaN;
+constexpr bool numeric_limits<absl::uint128>::has_signaling_NaN;
+constexpr float_denorm_style numeric_limits<absl::uint128>::has_denorm;
+constexpr bool numeric_limits<absl::uint128>::has_denorm_loss;
+constexpr float_round_style numeric_limits<absl::uint128>::round_style;
+constexpr bool numeric_limits<absl::uint128>::is_iec559;
+constexpr bool numeric_limits<absl::uint128>::is_bounded;
+constexpr bool numeric_limits<absl::uint128>::is_modulo;
+constexpr int numeric_limits<absl::uint128>::digits;
+constexpr int numeric_limits<absl::uint128>::digits10;
+constexpr int numeric_limits<absl::uint128>::max_digits10;
+constexpr int numeric_limits<absl::uint128>::radix;
+constexpr int numeric_limits<absl::uint128>::min_exponent;
+constexpr int numeric_limits<absl::uint128>::min_exponent10;
+constexpr int numeric_limits<absl::uint128>::max_exponent;
+constexpr int numeric_limits<absl::uint128>::max_exponent10;
+constexpr bool numeric_limits<absl::uint128>::traps;
+constexpr bool numeric_limits<absl::uint128>::tinyness_before;
+}  // namespace std
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
new file mode 100644
index 0000000..e4f39c3
--- /dev/null
+++ b/absl/numeric/int128.h
@@ -0,0 +1,704 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: int128.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines 128-bit integer types.
+//
+// Currently, this file defines `uint128`, an unsigned 128-bit integer; a signed
+// 128-bit integer is forthcoming.
+
+#ifndef ABSL_NUMERIC_INT128_H_
+#define ABSL_NUMERIC_INT128_H_
+
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <limits>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+
+// uint128
+//
+// An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type
+// as closely as is practical, including exhibiting undefined behavior in
+// analogous cases (e.g. division by zero). This type is intended to be a
+// drop-in replacement once C++ supports an intrinsic `uint128_t` type; when
+// that occurs, existing well-behaved uses of `uint128` will continue to work
+// using that new type.
+//
+// Note: code written with this type will continue to compile once `uint128_t`
+// is introduced, provided the replacement helper functions
+// `Uint128(Low|High)64()` and `MakeUint128()` are made.
+//
+// A `uint128` supports the following:
+//
+//   * Implicit construction from integral types
+//   * Explicit conversion to integral types
+//
+// Additionally, if your compiler supports `__int128`, `uint128` is
+// interoperable with that type. (Abseil checks for this compatibility through
+// the `ABSL_HAVE_INTRINSIC_INT128` macro.)
+//
+// However, a `uint128` differs from intrinsic integral types in the following
+// ways:
+//
+//   * Errors on implicit conversions that do not preserve value (such as
+//     loss of precision when converting to float values).
+//   * Requires explicit construction from and conversion to floating point
+//     types.
+//   * Conversion to integral types requires an explicit static_cast() to
+//     mimic use of the `-Wnarrowing` compiler flag.
+//   * The alignment requirement of `uint128` may differ from that of an
+//     intrinsic 128-bit integer type depending on platform and build
+//     configuration.
+//
+// Example:
+//
+//     float y = absl::Uint128Max();  // Error. uint128 cannot be implicitly
+//                                    // converted to float.
+//
+//     absl::uint128 v;
+//     uint64_t i = v;                         // Error
+//     uint64_t i = static_cast<uint64_t>(v);  // OK
+//
+class
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+    alignas(unsigned __int128)
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+        uint128 {
+ public:
+  uint128() = default;
+
+  // Constructors from arithmetic types
+  constexpr uint128(int v);                 // NOLINT(runtime/explicit)
+  constexpr uint128(unsigned int v);        // NOLINT(runtime/explicit)
+  constexpr uint128(long v);                // NOLINT(runtime/int)
+  constexpr uint128(unsigned long v);       // NOLINT(runtime/int)
+  constexpr uint128(long long v);           // NOLINT(runtime/int)
+  constexpr uint128(unsigned long long v);  // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr uint128(__int128 v);           // NOLINT(runtime/explicit)
+  constexpr uint128(unsigned __int128 v);  // NOLINT(runtime/explicit)
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  explicit uint128(float v);
+  explicit uint128(double v);
+  explicit uint128(long double v);
+
+  // Assignment operators from arithmetic types
+  uint128& operator=(int v);
+  uint128& operator=(unsigned int v);
+  uint128& operator=(long v);                // NOLINT(runtime/int)
+  uint128& operator=(unsigned long v);       // NOLINT(runtime/int)
+  uint128& operator=(long long v);           // NOLINT(runtime/int)
+  uint128& operator=(unsigned long long v);  // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  uint128& operator=(__int128 v);
+  uint128& operator=(unsigned __int128 v);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+  // Conversion operators to other arithmetic types
+  constexpr explicit operator bool() const;
+  constexpr explicit operator char() const;
+  constexpr explicit operator signed char() const;
+  constexpr explicit operator unsigned char() const;
+  constexpr explicit operator char16_t() const;
+  constexpr explicit operator char32_t() const;
+  constexpr explicit operator wchar_t() const;
+  constexpr explicit operator short() const;  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned short() const;
+  constexpr explicit operator int() const;
+  constexpr explicit operator unsigned int() const;
+  constexpr explicit operator long() const;  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned long() const;
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator long long() const;
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned long long() const;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr explicit operator __int128() const;
+  constexpr explicit operator unsigned __int128() const;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  explicit operator float() const;
+  explicit operator double() const;
+  explicit operator long double() const;
+
+  // Trivial copy constructor, assignment operator and destructor.
+
+  // Arithmetic operators.
+  uint128& operator+=(uint128 other);
+  uint128& operator-=(uint128 other);
+  uint128& operator*=(uint128 other);
+  // Long division/modulo for uint128.
+  uint128& operator/=(uint128 other);
+  uint128& operator%=(uint128 other);
+  uint128 operator++(int);
+  uint128 operator--(int);
+  uint128& operator<<=(int);
+  uint128& operator>>=(int);
+  uint128& operator&=(uint128 other);
+  uint128& operator|=(uint128 other);
+  uint128& operator^=(uint128 other);
+  uint128& operator++();
+  uint128& operator--();
+
+  // Uint128Low64()
+  //
+  // Returns the lower 64-bit value of a `uint128` value.
+  friend constexpr uint64_t Uint128Low64(uint128 v);
+
+  // Uint128High64()
+  //
+  // Returns the higher 64-bit value of a `uint128` value.
+  friend constexpr uint64_t Uint128High64(uint128 v);
+
+  // MakeUInt128()
+  //
+  // Constructs a `uint128` numeric value from two 64-bit unsigned integers.
+  // Note that this factory function is the only way to construct a `uint128`
+  // from integer values greater than 2^64.
+  //
+  // Example:
+  //
+  //   absl::uint128 big = absl::MakeUint128(1, 0);
+  friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low);
+
+  // Uint128Max()
+  //
+  // Returns the highest value for a 128-bit unsigned integer.
+  friend constexpr uint128 Uint128Max();
+
+ private:
+  constexpr uint128(uint64_t high, uint64_t low);
+
+  // TODO(strel) Update implementation to use __int128 once all users of
+  // uint128 are fixed to not depend on alignof(uint128) == 8. Also add
+  // alignas(16) to class definition to keep alignment consistent across
+  // platforms.
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+  uint64_t lo_;
+  uint64_t hi_;
+#elif defined(ABSL_IS_BIG_ENDIAN)
+  uint64_t hi_;
+  uint64_t lo_;
+#else  // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif  // byte order
+};
+
+// Prefer to use the constexpr `Uint128Max()`.
+//
+// TODO(absl-team) deprecate kuint128max once migration tool is released.
+extern const uint128 kuint128max;
+
+// allow uint128 to be logged
+std::ostream& operator<<(std::ostream& os, uint128 v);
+
+// TODO(strel) add operator>>(std::istream&, uint128)
+
+constexpr uint128 Uint128Max() {
+  return uint128(std::numeric_limits<uint64_t>::max(),
+                 std::numeric_limits<uint64_t>::max());
+}
+
+}  // namespace absl
+
+// Specialized numeric_limits for uint128.
+namespace std {
+template <>
+class numeric_limits<absl::uint128> {
+ public:
+  static constexpr bool is_specialized = true;
+  static constexpr bool is_signed = false;
+  static constexpr bool is_integer = true;
+  static constexpr bool is_exact = true;
+  static constexpr bool has_infinity = false;
+  static constexpr bool has_quiet_NaN = false;
+  static constexpr bool has_signaling_NaN = false;
+  static constexpr float_denorm_style has_denorm = denorm_absent;
+  static constexpr bool has_denorm_loss = false;
+  static constexpr float_round_style round_style = round_toward_zero;
+  static constexpr bool is_iec559 = false;
+  static constexpr bool is_bounded = true;
+  static constexpr bool is_modulo = true;
+  static constexpr int digits = 128;
+  static constexpr int digits10 = 38;
+  static constexpr int max_digits10 = 0;
+  static constexpr int radix = 2;
+  static constexpr int min_exponent = 0;
+  static constexpr int min_exponent10 = 0;
+  static constexpr int max_exponent = 0;
+  static constexpr int max_exponent10 = 0;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool traps = numeric_limits<unsigned __int128>::traps;
+#else   // ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool traps = numeric_limits<uint64_t>::traps;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool tinyness_before = false;
+
+  static constexpr absl::uint128 min() { return 0; }
+  static constexpr absl::uint128 lowest() { return 0; }
+  static constexpr absl::uint128 max() { return absl::Uint128Max(); }
+  static constexpr absl::uint128 epsilon() { return 0; }
+  static constexpr absl::uint128 round_error() { return 0; }
+  static constexpr absl::uint128 infinity() { return 0; }
+  static constexpr absl::uint128 quiet_NaN() { return 0; }
+  static constexpr absl::uint128 signaling_NaN() { return 0; }
+  static constexpr absl::uint128 denorm_min() { return 0; }
+};
+}  // namespace std
+
+// TODO(absl-team): Implement signed 128-bit type
+
+// --------------------------------------------------------------------------
+//                      Implementation details follow
+// --------------------------------------------------------------------------
+namespace absl {
+
+constexpr uint128 MakeUint128(uint64_t high, uint64_t low) {
+  return uint128(high, low);
+}
+
+// Assignment from integer types.
+
+inline uint128& uint128::operator=(int v) { return *this = uint128(v); }
+
+inline uint128& uint128::operator=(unsigned int v) {
+  return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(long v) {  // NOLINT(runtime/int)
+  return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(unsigned long v) {
+  return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(long long v) {
+  return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(unsigned long long v) {
+  return *this = uint128(v);
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+inline uint128& uint128::operator=(__int128 v) {
+  return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(unsigned __int128 v) {
+  return *this = uint128(v);
+}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+// Arithmetic operators.
+
+uint128 operator<<(uint128 lhs, int amount);
+uint128 operator>>(uint128 lhs, int amount);
+uint128 operator+(uint128 lhs, uint128 rhs);
+uint128 operator-(uint128 lhs, uint128 rhs);
+uint128 operator*(uint128 lhs, uint128 rhs);
+uint128 operator/(uint128 lhs, uint128 rhs);
+uint128 operator%(uint128 lhs, uint128 rhs);
+
+inline uint128& uint128::operator<<=(int amount) {
+  *this = *this << amount;
+  return *this;
+}
+
+inline uint128& uint128::operator>>=(int amount) {
+  *this = *this >> amount;
+  return *this;
+}
+
+inline uint128& uint128::operator+=(uint128 other) {
+  *this = *this + other;
+  return *this;
+}
+
+inline uint128& uint128::operator-=(uint128 other) {
+  *this = *this - other;
+  return *this;
+}
+
+inline uint128& uint128::operator*=(uint128 other) {
+  *this = *this * other;
+  return *this;
+}
+
+inline uint128& uint128::operator/=(uint128 other) {
+  *this = *this / other;
+  return *this;
+}
+
+inline uint128& uint128::operator%=(uint128 other) {
+  *this = *this % other;
+  return *this;
+}
+
+constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; }
+
+constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; }
+
+// Constructors from integer types.
+
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+
+constexpr uint128::uint128(uint64_t high, uint64_t low)
+    : lo_{low}, hi_{high} {}
+
+constexpr uint128::uint128(int v)
+    : lo_{static_cast<uint64_t>(v)},
+      hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {}
+constexpr uint128::uint128(long v)  // NOLINT(runtime/int)
+    : lo_{static_cast<uint64_t>(v)},
+      hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {}
+constexpr uint128::uint128(long long v)  // NOLINT(runtime/int)
+    : lo_{static_cast<uint64_t>(v)},
+      hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {}
+
+constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long long v) : lo_{v}, hi_{0} {}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::uint128(__int128 v)
+    : lo_{static_cast<uint64_t>(v & ~uint64_t{0})},
+      hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)} {}
+constexpr uint128::uint128(unsigned __int128 v)
+    : lo_{static_cast<uint64_t>(v & ~uint64_t{0})},
+      hi_{static_cast<uint64_t>(v >> 64)} {}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+#elif defined(ABSL_IS_BIG_ENDIAN)
+
+constexpr uint128::uint128(uint64_t high, uint64_t low)
+    : hi_{high}, lo_{low} {}
+
+constexpr uint128::uint128(int v)
+    : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0},
+      lo_{static_cast<uint64_t>(v)} {}
+constexpr uint128::uint128(long v)  // NOLINT(runtime/int)
+    : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0},
+      lo_{static_cast<uint64_t>(v)} {}
+constexpr uint128::uint128(long long v)  // NOLINT(runtime/int)
+    : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0},
+      lo_{static_cast<uint64_t>(v)} {}
+
+constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long long v) : hi_{0}, lo_{v} {}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::uint128(__int128 v)
+    : hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)},
+      lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {}
+constexpr uint128::uint128(unsigned __int128 v)
+    : hi_{static_cast<uint64_t>(v >> 64)},
+      lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+#else  // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif  // byte order
+
+// Conversion operators to integer types.
+
+constexpr uint128::operator bool() const { return lo_ || hi_; }
+
+constexpr uint128::operator char() const { return static_cast<char>(lo_); }
+
+constexpr uint128::operator signed char() const {
+  return static_cast<signed char>(lo_);
+}
+
+constexpr uint128::operator unsigned char() const {
+  return static_cast<unsigned char>(lo_);
+}
+
+constexpr uint128::operator char16_t() const {
+  return static_cast<char16_t>(lo_);
+}
+
+constexpr uint128::operator char32_t() const {
+  return static_cast<char32_t>(lo_);
+}
+
+constexpr uint128::operator wchar_t() const {
+  return static_cast<wchar_t>(lo_);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::operator short() const { return static_cast<short>(lo_); }
+
+constexpr uint128::operator unsigned short() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned short>(lo_);            // NOLINT(runtime/int)
+}
+
+constexpr uint128::operator int() const { return static_cast<int>(lo_); }
+
+constexpr uint128::operator unsigned int() const {
+  return static_cast<unsigned int>(lo_);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::operator long() const { return static_cast<long>(lo_); }
+
+constexpr uint128::operator unsigned long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long>(lo_);            // NOLINT(runtime/int)
+}
+
+constexpr uint128::operator long long() const {  // NOLINT(runtime/int)
+  return static_cast<long long>(lo_);            // NOLINT(runtime/int)
+}
+
+constexpr uint128::operator unsigned long long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long long>(lo_);            // NOLINT(runtime/int)
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::operator __int128() const {
+  return (static_cast<__int128>(hi_) << 64) + lo_;
+}
+
+constexpr uint128::operator unsigned __int128() const {
+  return (static_cast<unsigned __int128>(hi_) << 64) + lo_;
+}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+// Conversion operators to floating point types.
+
+inline uint128::operator float() const {
+  return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64);
+}
+
+inline uint128::operator double() const {
+  return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64);
+}
+
+inline uint128::operator long double() const {
+  return static_cast<long double>(lo_) +
+         std::ldexp(static_cast<long double>(hi_), 64);
+}
+
+// Comparison operators.
+
+inline bool operator==(uint128 lhs, uint128 rhs) {
+  return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
+          Uint128High64(lhs) == Uint128High64(rhs));
+}
+
+inline bool operator!=(uint128 lhs, uint128 rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator<(uint128 lhs, uint128 rhs) {
+  return (Uint128High64(lhs) == Uint128High64(rhs))
+             ? (Uint128Low64(lhs) < Uint128Low64(rhs))
+             : (Uint128High64(lhs) < Uint128High64(rhs));
+}
+
+inline bool operator>(uint128 lhs, uint128 rhs) {
+  return (Uint128High64(lhs) == Uint128High64(rhs))
+             ? (Uint128Low64(lhs) > Uint128Low64(rhs))
+             : (Uint128High64(lhs) > Uint128High64(rhs));
+}
+
+inline bool operator<=(uint128 lhs, uint128 rhs) {
+  return (Uint128High64(lhs) == Uint128High64(rhs))
+             ? (Uint128Low64(lhs) <= Uint128Low64(rhs))
+             : (Uint128High64(lhs) <= Uint128High64(rhs));
+}
+
+inline bool operator>=(uint128 lhs, uint128 rhs) {
+  return (Uint128High64(lhs) == Uint128High64(rhs))
+             ? (Uint128Low64(lhs) >= Uint128Low64(rhs))
+             : (Uint128High64(lhs) >= Uint128High64(rhs));
+}
+
+// Unary operators.
+
+inline uint128 operator-(uint128 val) {
+  uint64_t hi = ~Uint128High64(val);
+  uint64_t lo = ~Uint128Low64(val) + 1;
+  if (lo == 0) ++hi;  // carry
+  return MakeUint128(hi, lo);
+}
+
+inline bool operator!(uint128 val) {
+  return !Uint128High64(val) && !Uint128Low64(val);
+}
+
+// Logical operators.
+
+inline uint128 operator~(uint128 val) {
+  return MakeUint128(~Uint128High64(val), ~Uint128Low64(val));
+}
+
+inline uint128 operator|(uint128 lhs, uint128 rhs) {
+  return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs),
+                           Uint128Low64(lhs) | Uint128Low64(rhs));
+}
+
+inline uint128 operator&(uint128 lhs, uint128 rhs) {
+  return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs),
+                           Uint128Low64(lhs) & Uint128Low64(rhs));
+}
+
+inline uint128 operator^(uint128 lhs, uint128 rhs) {
+  return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs),
+                           Uint128Low64(lhs) ^ Uint128Low64(rhs));
+}
+
+inline uint128& uint128::operator|=(uint128 other) {
+  hi_ |= other.hi_;
+  lo_ |= other.lo_;
+  return *this;
+}
+
+inline uint128& uint128::operator&=(uint128 other) {
+  hi_ &= other.hi_;
+  lo_ &= other.lo_;
+  return *this;
+}
+
+inline uint128& uint128::operator^=(uint128 other) {
+  hi_ ^= other.hi_;
+  lo_ ^= other.lo_;
+  return *this;
+}
+
+// Arithmetic operators.
+
+inline uint128 operator<<(uint128 lhs, int amount) {
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      return MakeUint128(
+          (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)),
+          Uint128Low64(lhs) << amount);
+    }
+    return lhs;
+  }
+  return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0);
+}
+
+inline uint128 operator>>(uint128 lhs, int amount) {
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      return MakeUint128(Uint128High64(lhs) >> amount,
+                         (Uint128Low64(lhs) >> amount) |
+                             (Uint128High64(lhs) << (64 - amount)));
+    }
+    return lhs;
+  }
+  return MakeUint128(0, Uint128High64(lhs) >> (amount - 64));
+}
+
+inline uint128 operator+(uint128 lhs, uint128 rhs) {
+  uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs),
+                               Uint128Low64(lhs) + Uint128Low64(rhs));
+  if (Uint128Low64(result) < Uint128Low64(lhs)) {  // check for carry
+    return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result));
+  }
+  return result;
+}
+
+inline uint128 operator-(uint128 lhs, uint128 rhs) {
+  uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs),
+                               Uint128Low64(lhs) - Uint128Low64(rhs));
+  if (Uint128Low64(lhs) < Uint128Low64(rhs)) {  // check for carry
+    return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result));
+  }
+  return result;
+}
+
+inline uint128 operator*(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  // TODO(strel) Remove once alignment issues are resolved and unsigned __int128
+  // can be used for uint128 storage.
+  return static_cast<unsigned __int128>(lhs) *
+         static_cast<unsigned __int128>(rhs);
+#else   // ABSL_HAVE_INTRINSIC128
+  uint64_t a32 = Uint128Low64(lhs) >> 32;
+  uint64_t a00 = Uint128Low64(lhs) & 0xffffffff;
+  uint64_t b32 = Uint128Low64(rhs) >> 32;
+  uint64_t b00 = Uint128Low64(rhs) & 0xffffffff;
+  uint128 result =
+      MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) +
+                      Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32,
+                  a00 * b00);
+  result += uint128(a32 * b00) << 32;
+  result += uint128(a00 * b32) << 32;
+  return result;
+#endif  // ABSL_HAVE_INTRINSIC128
+}
+
+// Increment/decrement operators.
+
+inline uint128 uint128::operator++(int) {
+  uint128 tmp(*this);
+  *this += 1;
+  return tmp;
+}
+
+inline uint128 uint128::operator--(int) {
+  uint128 tmp(*this);
+  *this -= 1;
+  return tmp;
+}
+
+inline uint128& uint128::operator++() {
+  *this += 1;
+  return *this;
+}
+
+inline uint128& uint128::operator--() {
+  *this -= 1;
+  return *this;
+}
+
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+#include "absl/numeric/int128_have_intrinsic.inc"
+#else  // ABSL_HAVE_INTRINSIC_INT128
+#include "absl/numeric/int128_no_intrinsic.inc"
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INT128_H_
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc
new file mode 100644
index 0000000..1cb7d0e
--- /dev/null
+++ b/absl/numeric/int128_benchmark.cc
@@ -0,0 +1,221 @@
+// Copyright 2017 The Abseil 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 "absl/numeric/int128.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/config.h"
+
+namespace {
+
+constexpr size_t kSampleSize = 1000000;
+
+std::mt19937 MakeRandomEngine() {
+  std::random_device r;
+  std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
+  return std::mt19937(seed);
+}
+
+std::vector<std::pair<absl::uint128, absl::uint128>>
+GetRandomClass128SampleUniformDivisor() {
+  std::vector<std::pair<absl::uint128, absl::uint128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    absl::uint128 a =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    absl::uint128 b =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    values.emplace_back(std::max(a, b),
+                        std::max(absl::uint128(2), std::min(a, b)));
+  }
+  return values;
+}
+
+void BM_DivideClass128UniformDivisor(benchmark::State& state) {
+  auto values = GetRandomClass128SampleUniformDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideClass128UniformDivisor);
+
+std::vector<std::pair<absl::uint128, uint64_t>>
+GetRandomClass128SampleSmallDivisor() {
+  std::vector<std::pair<absl::uint128, uint64_t>> values;
+  std::mt19937 random = MakeRandomEngine();
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    absl::uint128 a =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
+    values.emplace_back(std::max(a, absl::uint128(b)), b);
+  }
+  return values;
+}
+
+void BM_DivideClass128SmallDivisor(benchmark::State& state) {
+  auto values = GetRandomClass128SampleSmallDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideClass128SmallDivisor);
+
+std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
+  std::vector<std::pair<absl::uint128, absl::uint128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    values.emplace_back(
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
+  }
+  return values;
+}
+
+void BM_MultiplyClass128(benchmark::State& state) {
+  auto values = GetRandomClass128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first * pair.second);
+    }
+  }
+}
+BENCHMARK(BM_MultiplyClass128);
+
+void BM_AddClass128(benchmark::State& state) {
+  auto values = GetRandomClass128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first + pair.second);
+    }
+  }
+}
+BENCHMARK(BM_AddClass128);
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+
+// Some implementations of <random> do not support __int128 when it is
+// available, so we make our own uniform_int_distribution-like type.
+class UniformIntDistribution128 {
+ public:
+  // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
+  unsigned __int128 operator()(std::mt19937& generator) {
+    return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
+           dist64_(generator);
+  }
+
+ private:
+  std::uniform_int_distribution<uint64_t> dist64_;
+};
+
+std::vector<std::pair<unsigned __int128, unsigned __int128>>
+GetRandomIntrinsic128SampleUniformDivisor() {
+  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  UniformIntDistribution128 uniform_uint128;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    unsigned __int128 a = uniform_uint128(random);
+    unsigned __int128 b = uniform_uint128(random);
+    values.emplace_back(
+        std::max(a, b),
+        std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
+  }
+  return values;
+}
+
+void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128SampleUniformDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
+
+std::vector<std::pair<unsigned __int128, uint64_t>>
+GetRandomIntrinsic128SampleSmallDivisor() {
+  std::vector<std::pair<unsigned __int128, uint64_t>> values;
+  std::mt19937 random = MakeRandomEngine();
+  UniformIntDistribution128 uniform_uint128;
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    unsigned __int128 a = uniform_uint128(random);
+    uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
+    values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
+  }
+  return values;
+}
+
+void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128SampleSmallDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
+
+std::vector<std::pair<unsigned __int128, unsigned __int128>>
+      GetRandomIntrinsic128Sample() {
+  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  UniformIntDistribution128 uniform_uint128;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    values.emplace_back(uniform_uint128(random), uniform_uint128(random));
+  }
+  return values;
+}
+
+void BM_MultiplyIntrinsic128(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first * pair.second);
+    }
+  }
+}
+BENCHMARK(BM_MultiplyIntrinsic128);
+
+void BM_AddIntrinsic128(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first + pair.second);
+    }
+  }
+}
+BENCHMARK(BM_AddIntrinsic128);
+
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+}  // namespace
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
new file mode 100644
index 0000000..ee2a093
--- /dev/null
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -0,0 +1,18 @@
+//
+// Copyright 2017 The Abseil 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.
+
+// This file contains :int128 implementation details that depend on internal
+// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is
+// included by int128.h.
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
new file mode 100644
index 0000000..0d0b3cf
--- /dev/null
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -0,0 +1,18 @@
+//
+// Copyright 2017 The Abseil 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.
+
+// This file contains :int128 implementation details that depend on internal
+// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
+// is included by int128.h.
diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc
new file mode 100644
index 0000000..09efaad
--- /dev/null
+++ b/absl/numeric/int128_stream_test.cc
@@ -0,0 +1,666 @@
+// Copyright 2017 The Abseil 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 "absl/numeric/int128.h"
+
+#include <sstream>
+#include <string>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+struct Uint128TestCase {
+  absl::uint128 value;
+  std::ios_base::fmtflags flags;
+  std::streamsize width;
+  const char* expected;
+};
+
+constexpr char kFill = '_';
+
+std::string StreamFormatToString(std::ios_base::fmtflags flags,
+                                 std::streamsize width) {
+  std::vector<const char*> flagstr;
+  switch (flags & std::ios::basefield) {
+    case std::ios::dec:
+      flagstr.push_back("std::ios::dec");
+      break;
+    case std::ios::oct:
+      flagstr.push_back("std::ios::oct");
+      break;
+    case std::ios::hex:
+      flagstr.push_back("std::ios::hex");
+      break;
+    default:  // basefield not specified
+      break;
+  }
+  switch (flags & std::ios::adjustfield) {
+    case std::ios::left:
+      flagstr.push_back("std::ios::left");
+      break;
+    case std::ios::internal:
+      flagstr.push_back("std::ios::internal");
+      break;
+    case std::ios::right:
+      flagstr.push_back("std::ios::right");
+      break;
+    default:  // adjustfield not specified
+      break;
+  }
+  if (flags & std::ios::uppercase) flagstr.push_back("std::ios::uppercase");
+  if (flags & std::ios::showbase) flagstr.push_back("std::ios::showbase");
+  if (flags & std::ios::showpos) flagstr.push_back("std::ios::showpos");
+
+  std::ostringstream msg;
+  msg << "\n  StreamFormatToString(test_case.flags, test_case.width)\n    "
+         "flags: ";
+  if (!flagstr.empty()) {
+    for (size_t i = 0; i < flagstr.size() - 1; ++i) msg << flagstr[i] << " | ";
+    msg << flagstr.back();
+  } else {
+    msg << "(default)";
+  }
+  msg << "\n    width: " << width << "\n    fill: '" << kFill << "'";
+  return msg.str();
+}
+
+void CheckUint128Case(const Uint128TestCase& test_case) {
+  std::ostringstream os;
+  os.flags(test_case.flags);
+  os.width(test_case.width);
+  os.fill(kFill);
+  os << test_case.value;
+  SCOPED_TRACE(StreamFormatToString(test_case.flags, test_case.width));
+  EXPECT_EQ(test_case.expected, os.str());
+}
+
+constexpr std::ios::fmtflags kDec = std::ios::dec;
+constexpr std::ios::fmtflags kOct = std::ios::oct;
+constexpr std::ios::fmtflags kHex = std::ios::hex;
+constexpr std::ios::fmtflags kLeft = std::ios::left;
+constexpr std::ios::fmtflags kInt = std::ios::internal;
+constexpr std::ios::fmtflags kRight = std::ios::right;
+constexpr std::ios::fmtflags kUpper = std::ios::uppercase;
+constexpr std::ios::fmtflags kBase = std::ios::showbase;
+constexpr std::ios::fmtflags kPos = std::ios::showpos;
+
+TEST(Uint128, OStreamValueTest) {
+  CheckUint128Case({1, kDec, /*width = */ 0, "1"});
+  CheckUint128Case({1, kOct, /*width = */ 0, "1"});
+  CheckUint128Case({1, kHex, /*width = */ 0, "1"});
+  CheckUint128Case({9, kDec, /*width = */ 0, "9"});
+  CheckUint128Case({9, kOct, /*width = */ 0, "11"});
+  CheckUint128Case({9, kHex, /*width = */ 0, "9"});
+  CheckUint128Case({12345, kDec, /*width = */ 0, "12345"});
+  CheckUint128Case({12345, kOct, /*width = */ 0, "30071"});
+  CheckUint128Case({12345, kHex, /*width = */ 0, "3039"});
+  CheckUint128Case(
+      {0x8000000000000000, kDec, /*width = */ 0, "9223372036854775808"});
+  CheckUint128Case(
+      {0x8000000000000000, kOct, /*width = */ 0, "1000000000000000000000"});
+  CheckUint128Case(
+      {0x8000000000000000, kHex, /*width = */ 0, "8000000000000000"});
+  CheckUint128Case({std::numeric_limits<uint64_t>::max(), kDec,
+                    /*width = */ 0, "18446744073709551615"});
+  CheckUint128Case({std::numeric_limits<uint64_t>::max(), kOct,
+                    /*width = */ 0, "1777777777777777777777"});
+  CheckUint128Case({std::numeric_limits<uint64_t>::max(), kHex,
+                    /*width = */ 0, "ffffffffffffffff"});
+  CheckUint128Case(
+      {absl::MakeUint128(1, 0), kDec, /*width = */ 0, "18446744073709551616"});
+  CheckUint128Case({absl::MakeUint128(1, 0), kOct, /*width = */ 0,
+                    "2000000000000000000000"});
+  CheckUint128Case(
+      {absl::MakeUint128(1, 0), kHex, /*width = */ 0, "10000000000000000"});
+  CheckUint128Case({absl::MakeUint128(0x8000000000000000, 0), kDec,
+                    /*width = */ 0, "170141183460469231731687303715884105728"});
+  CheckUint128Case({absl::MakeUint128(0x8000000000000000, 0), kOct,
+                    /*width = */ 0,
+                    "2000000000000000000000000000000000000000000"});
+  CheckUint128Case({absl::MakeUint128(0x8000000000000000, 0), kHex,
+                    /*width = */ 0, "80000000000000000000000000000000"});
+  CheckUint128Case({absl::kuint128max, kDec, /*width = */ 0,
+                    "340282366920938463463374607431768211455"});
+  CheckUint128Case({absl::kuint128max, kOct, /*width = */ 0,
+                    "3777777777777777777777777777777777777777777"});
+  CheckUint128Case({absl::kuint128max, kHex, /*width = */ 0,
+                    "ffffffffffffffffffffffffffffffff"});
+}
+
+std::vector<Uint128TestCase> GetUint128FormatCases();
+
+TEST(Uint128, OStreamFormatTest) {
+  for (const Uint128TestCase& test_case : GetUint128FormatCases()) {
+    CheckUint128Case(test_case);
+  }
+}
+
+std::vector<Uint128TestCase> GetUint128FormatCases() {
+  return {
+      {0, std::ios_base::fmtflags(), /*width = */ 0, "0"},
+      {0, std::ios_base::fmtflags(), /*width = */ 6, "_____0"},
+      {0, kPos, /*width = */ 0, "0"},
+      {0, kPos, /*width = */ 6, "_____0"},
+      {0, kBase, /*width = */ 0, "0"},
+      {0, kBase, /*width = */ 6, "_____0"},
+      {0, kBase | kPos, /*width = */ 0, "0"},
+      {0, kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kUpper, /*width = */ 0, "0"},
+      {0, kUpper, /*width = */ 6, "_____0"},
+      {0, kUpper | kPos, /*width = */ 0, "0"},
+      {0, kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kUpper | kBase, /*width = */ 0, "0"},
+      {0, kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kLeft, /*width = */ 0, "0"},
+      {0, kLeft, /*width = */ 6, "0_____"},
+      {0, kLeft | kPos, /*width = */ 0, "0"},
+      {0, kLeft | kPos, /*width = */ 6, "0_____"},
+      {0, kLeft | kBase, /*width = */ 0, "0"},
+      {0, kLeft | kBase, /*width = */ 6, "0_____"},
+      {0, kLeft | kBase | kPos, /*width = */ 0, "0"},
+      {0, kLeft | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kLeft | kUpper, /*width = */ 0, "0"},
+      {0, kLeft | kUpper, /*width = */ 6, "0_____"},
+      {0, kLeft | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kLeft | kUpper | kPos, /*width = */ 6, "0_____"},
+      {0, kLeft | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+      {0, kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kInt, /*width = */ 0, "0"},
+      {0, kInt, /*width = */ 6, "_____0"},
+      {0, kInt | kPos, /*width = */ 0, "0"},
+      {0, kInt | kPos, /*width = */ 6, "_____0"},
+      {0, kInt | kBase, /*width = */ 0, "0"},
+      {0, kInt | kBase, /*width = */ 6, "_____0"},
+      {0, kInt | kBase | kPos, /*width = */ 0, "0"},
+      {0, kInt | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kInt | kUpper, /*width = */ 0, "0"},
+      {0, kInt | kUpper, /*width = */ 6, "_____0"},
+      {0, kInt | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kInt | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kInt | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kInt | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kRight, /*width = */ 0, "0"},
+      {0, kRight, /*width = */ 6, "_____0"},
+      {0, kRight | kPos, /*width = */ 0, "0"},
+      {0, kRight | kPos, /*width = */ 6, "_____0"},
+      {0, kRight | kBase, /*width = */ 0, "0"},
+      {0, kRight | kBase, /*width = */ 6, "_____0"},
+      {0, kRight | kBase | kPos, /*width = */ 0, "0"},
+      {0, kRight | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kRight | kUpper, /*width = */ 0, "0"},
+      {0, kRight | kUpper, /*width = */ 6, "_____0"},
+      {0, kRight | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kRight | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kRight | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kRight | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kDec, /*width = */ 0, "0"},
+      {0, kDec, /*width = */ 6, "_____0"},
+      {0, kDec | kPos, /*width = */ 0, "0"},
+      {0, kDec | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kBase, /*width = */ 0, "0"},
+      {0, kDec | kBase, /*width = */ 6, "_____0"},
+      {0, kDec | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kUpper, /*width = */ 0, "0"},
+      {0, kDec | kUpper, /*width = */ 6, "_____0"},
+      {0, kDec | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kDec | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kDec | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kDec | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kLeft, /*width = */ 0, "0"},
+      {0, kDec | kLeft, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kPos, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kPos, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kBase, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kBase, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kUpper, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kUpper, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kUpper | kPos, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+      {0, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kDec | kInt, /*width = */ 0, "0"},
+      {0, kDec | kInt, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kPos, /*width = */ 0, "0"},
+      {0, kDec | kInt | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kBase, /*width = */ 0, "0"},
+      {0, kDec | kInt | kBase, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kInt | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kUpper, /*width = */ 0, "0"},
+      {0, kDec | kInt | kUpper, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kDec | kInt | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kDec | kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kRight, /*width = */ 0, "0"},
+      {0, kDec | kRight, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kPos, /*width = */ 0, "0"},
+      {0, kDec | kRight | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kBase, /*width = */ 0, "0"},
+      {0, kDec | kRight | kBase, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kRight | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kUpper, /*width = */ 0, "0"},
+      {0, kDec | kRight | kUpper, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kDec | kRight | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kDec | kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kOct, /*width = */ 0, "0"},
+      {0, kOct, /*width = */ 6, "_____0"},
+      {0, kOct | kPos, /*width = */ 0, "0"},
+      {0, kOct | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kBase, /*width = */ 0, "0"},
+      {0, kOct | kBase, /*width = */ 6, "_____0"},
+      {0, kOct | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kUpper, /*width = */ 0, "0"},
+      {0, kOct | kUpper, /*width = */ 6, "_____0"},
+      {0, kOct | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kOct | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kOct | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kOct | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kLeft, /*width = */ 0, "0"},
+      {0, kOct | kLeft, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kPos, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kPos, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kBase, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kBase, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kUpper, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kUpper, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kUpper | kPos, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+      {0, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kOct | kInt, /*width = */ 0, "0"},
+      {0, kOct | kInt, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kPos, /*width = */ 0, "0"},
+      {0, kOct | kInt | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kBase, /*width = */ 0, "0"},
+      {0, kOct | kInt | kBase, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kInt | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kUpper, /*width = */ 0, "0"},
+      {0, kOct | kInt | kUpper, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kOct | kInt | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kOct | kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kOct | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kRight, /*width = */ 0, "0"},
+      {0, kOct | kRight, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kPos, /*width = */ 0, "0"},
+      {0, kOct | kRight | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kBase, /*width = */ 0, "0"},
+      {0, kOct | kRight | kBase, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kRight | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kUpper, /*width = */ 0, "0"},
+      {0, kOct | kRight | kUpper, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kOct | kRight | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kOct | kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kOct | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kOct | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kHex, /*width = */ 0, "0"},
+      {0, kHex, /*width = */ 6, "_____0"},
+      {0, kHex | kPos, /*width = */ 0, "0"},
+      {0, kHex | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kBase, /*width = */ 0, "0"},
+      {0, kHex | kBase, /*width = */ 6, "_____0"},
+      {0, kHex | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kUpper, /*width = */ 0, "0"},
+      {0, kHex | kUpper, /*width = */ 6, "_____0"},
+      {0, kHex | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kHex | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kHex | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kHex | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kLeft, /*width = */ 0, "0"},
+      {0, kHex | kLeft, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kPos, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kPos, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kBase, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kBase, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kUpper, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kUpper, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kUpper | kPos, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+      {0, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"},
+      {0, kHex | kInt, /*width = */ 0, "0"},
+      {0, kHex | kInt, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kPos, /*width = */ 0, "0"},
+      {0, kHex | kInt | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kBase, /*width = */ 0, "0"},
+      {0, kHex | kInt | kBase, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kInt | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kUpper, /*width = */ 0, "0"},
+      {0, kHex | kInt | kUpper, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kHex | kInt | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kHex | kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kHex | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kRight, /*width = */ 0, "0"},
+      {0, kHex | kRight, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kPos, /*width = */ 0, "0"},
+      {0, kHex | kRight | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kBase, /*width = */ 0, "0"},
+      {0, kHex | kRight | kBase, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kRight | kBase | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kUpper, /*width = */ 0, "0"},
+      {0, kHex | kRight | kUpper, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kUpper | kPos, /*width = */ 0, "0"},
+      {0, kHex | kRight | kUpper | kPos, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kUpper | kBase, /*width = */ 0, "0"},
+      {0, kHex | kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+      {0, kHex | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"},
+      {0, kHex | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+      {37, std::ios_base::fmtflags(), /*width = */ 0, "37"},
+      {37, std::ios_base::fmtflags(), /*width = */ 6, "____37"},
+      {37, kPos, /*width = */ 0, "37"},
+      {37, kPos, /*width = */ 6, "____37"},
+      {37, kBase, /*width = */ 0, "37"},
+      {37, kBase, /*width = */ 6, "____37"},
+      {37, kBase | kPos, /*width = */ 0, "37"},
+      {37, kBase | kPos, /*width = */ 6, "____37"},
+      {37, kUpper, /*width = */ 0, "37"},
+      {37, kUpper, /*width = */ 6, "____37"},
+      {37, kUpper | kPos, /*width = */ 0, "37"},
+      {37, kUpper | kPos, /*width = */ 6, "____37"},
+      {37, kUpper | kBase, /*width = */ 0, "37"},
+      {37, kUpper | kBase, /*width = */ 6, "____37"},
+      {37, kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kUpper | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kLeft, /*width = */ 0, "37"},
+      {37, kLeft, /*width = */ 6, "37____"},
+      {37, kLeft | kPos, /*width = */ 0, "37"},
+      {37, kLeft | kPos, /*width = */ 6, "37____"},
+      {37, kLeft | kBase, /*width = */ 0, "37"},
+      {37, kLeft | kBase, /*width = */ 6, "37____"},
+      {37, kLeft | kBase | kPos, /*width = */ 0, "37"},
+      {37, kLeft | kBase | kPos, /*width = */ 6, "37____"},
+      {37, kLeft | kUpper, /*width = */ 0, "37"},
+      {37, kLeft | kUpper, /*width = */ 6, "37____"},
+      {37, kLeft | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kLeft | kUpper | kPos, /*width = */ 6, "37____"},
+      {37, kLeft | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kLeft | kUpper | kBase, /*width = */ 6, "37____"},
+      {37, kLeft | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kLeft | kUpper | kBase | kPos, /*width = */ 6, "37____"},
+      {37, kInt, /*width = */ 0, "37"},
+      {37, kInt, /*width = */ 6, "____37"},
+      {37, kInt | kPos, /*width = */ 0, "37"},
+      {37, kInt | kPos, /*width = */ 6, "____37"},
+      {37, kInt | kBase, /*width = */ 0, "37"},
+      {37, kInt | kBase, /*width = */ 6, "____37"},
+      {37, kInt | kBase | kPos, /*width = */ 0, "37"},
+      {37, kInt | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kInt | kUpper, /*width = */ 0, "37"},
+      {37, kInt | kUpper, /*width = */ 6, "____37"},
+      {37, kInt | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kInt | kUpper | kPos, /*width = */ 6, "____37"},
+      {37, kInt | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kInt | kUpper | kBase, /*width = */ 6, "____37"},
+      {37, kInt | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kInt | kUpper | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kRight, /*width = */ 0, "37"},
+      {37, kRight, /*width = */ 6, "____37"},
+      {37, kRight | kPos, /*width = */ 0, "37"},
+      {37, kRight | kPos, /*width = */ 6, "____37"},
+      {37, kRight | kBase, /*width = */ 0, "37"},
+      {37, kRight | kBase, /*width = */ 6, "____37"},
+      {37, kRight | kBase | kPos, /*width = */ 0, "37"},
+      {37, kRight | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kRight | kUpper, /*width = */ 0, "37"},
+      {37, kRight | kUpper, /*width = */ 6, "____37"},
+      {37, kRight | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kRight | kUpper | kPos, /*width = */ 6, "____37"},
+      {37, kRight | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kRight | kUpper | kBase, /*width = */ 6, "____37"},
+      {37, kRight | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kRight | kUpper | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kDec, /*width = */ 0, "37"},
+      {37, kDec, /*width = */ 6, "____37"},
+      {37, kDec | kPos, /*width = */ 0, "37"},
+      {37, kDec | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kBase, /*width = */ 0, "37"},
+      {37, kDec | kBase, /*width = */ 6, "____37"},
+      {37, kDec | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kUpper, /*width = */ 0, "37"},
+      {37, kDec | kUpper, /*width = */ 6, "____37"},
+      {37, kDec | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kDec | kUpper | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kDec | kUpper | kBase, /*width = */ 6, "____37"},
+      {37, kDec | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kUpper | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kLeft, /*width = */ 0, "37"},
+      {37, kDec | kLeft, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kPos, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kPos, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kBase, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kBase, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kBase | kPos, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kUpper, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kUpper, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kUpper | kPos, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kUpper | kBase, /*width = */ 6, "37____"},
+      {37, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "37____"},
+      {37, kDec | kInt, /*width = */ 0, "37"},
+      {37, kDec | kInt, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kPos, /*width = */ 0, "37"},
+      {37, kDec | kInt | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kBase, /*width = */ 0, "37"},
+      {37, kDec | kInt | kBase, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kInt | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kUpper, /*width = */ 0, "37"},
+      {37, kDec | kInt | kUpper, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kDec | kInt | kUpper | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kDec | kInt | kUpper | kBase, /*width = */ 6, "____37"},
+      {37, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kRight, /*width = */ 0, "37"},
+      {37, kDec | kRight, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kPos, /*width = */ 0, "37"},
+      {37, kDec | kRight | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kBase, /*width = */ 0, "37"},
+      {37, kDec | kRight | kBase, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kRight | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kUpper, /*width = */ 0, "37"},
+      {37, kDec | kRight | kUpper, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kUpper | kPos, /*width = */ 0, "37"},
+      {37, kDec | kRight | kUpper | kPos, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kUpper | kBase, /*width = */ 0, "37"},
+      {37, kDec | kRight | kUpper | kBase, /*width = */ 6, "____37"},
+      {37, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "37"},
+      {37, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "____37"},
+      {37, kOct, /*width = */ 0, "45"},
+      {37, kOct, /*width = */ 6, "____45"},
+      {37, kOct | kPos, /*width = */ 0, "45"},
+      {37, kOct | kPos, /*width = */ 6, "____45"},
+      {37, kOct | kBase, /*width = */ 0, "045"},
+      {37, kOct | kBase, /*width = */ 6, "___045"},
+      {37, kOct | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kBase | kPos, /*width = */ 6, "___045"},
+      {37, kOct | kUpper, /*width = */ 0, "45"},
+      {37, kOct | kUpper, /*width = */ 6, "____45"},
+      {37, kOct | kUpper | kPos, /*width = */ 0, "45"},
+      {37, kOct | kUpper | kPos, /*width = */ 6, "____45"},
+      {37, kOct | kUpper | kBase, /*width = */ 0, "045"},
+      {37, kOct | kUpper | kBase, /*width = */ 6, "___045"},
+      {37, kOct | kUpper | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kUpper | kBase | kPos, /*width = */ 6, "___045"},
+      {37, kOct | kLeft, /*width = */ 0, "45"},
+      {37, kOct | kLeft, /*width = */ 6, "45____"},
+      {37, kOct | kLeft | kPos, /*width = */ 0, "45"},
+      {37, kOct | kLeft | kPos, /*width = */ 6, "45____"},
+      {37, kOct | kLeft | kBase, /*width = */ 0, "045"},
+      {37, kOct | kLeft | kBase, /*width = */ 6, "045___"},
+      {37, kOct | kLeft | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kLeft | kBase | kPos, /*width = */ 6, "045___"},
+      {37, kOct | kLeft | kUpper, /*width = */ 0, "45"},
+      {37, kOct | kLeft | kUpper, /*width = */ 6, "45____"},
+      {37, kOct | kLeft | kUpper | kPos, /*width = */ 0, "45"},
+      {37, kOct | kLeft | kUpper | kPos, /*width = */ 6, "45____"},
+      {37, kOct | kLeft | kUpper | kBase, /*width = */ 0, "045"},
+      {37, kOct | kLeft | kUpper | kBase, /*width = */ 6, "045___"},
+      {37, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 6, "045___"},
+      {37, kOct | kInt, /*width = */ 0, "45"},
+      {37, kOct | kInt, /*width = */ 6, "____45"},
+      {37, kOct | kInt | kPos, /*width = */ 0, "45"},
+      {37, kOct | kInt | kPos, /*width = */ 6, "____45"},
+      {37, kOct | kInt | kBase, /*width = */ 0, "045"},
+      {37, kOct | kInt | kBase, /*width = */ 6, "___045"},
+      {37, kOct | kInt | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kInt | kBase | kPos, /*width = */ 6, "___045"},
+      {37, kOct | kInt | kUpper, /*width = */ 0, "45"},
+      {37, kOct | kInt | kUpper, /*width = */ 6, "____45"},
+      {37, kOct | kInt | kUpper | kPos, /*width = */ 0, "45"},
+      {37, kOct | kInt | kUpper | kPos, /*width = */ 6, "____45"},
+      {37, kOct | kInt | kUpper | kBase, /*width = */ 0, "045"},
+      {37, kOct | kInt | kUpper | kBase, /*width = */ 6, "___045"},
+      {37, kOct | kInt | kUpper | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kInt | kUpper | kBase | kPos, /*width = */ 6, "___045"},
+      {37, kOct | kRight, /*width = */ 0, "45"},
+      {37, kOct | kRight, /*width = */ 6, "____45"},
+      {37, kOct | kRight | kPos, /*width = */ 0, "45"},
+      {37, kOct | kRight | kPos, /*width = */ 6, "____45"},
+      {37, kOct | kRight | kBase, /*width = */ 0, "045"},
+      {37, kOct | kRight | kBase, /*width = */ 6, "___045"},
+      {37, kOct | kRight | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kRight | kBase | kPos, /*width = */ 6, "___045"},
+      {37, kOct | kRight | kUpper, /*width = */ 0, "45"},
+      {37, kOct | kRight | kUpper, /*width = */ 6, "____45"},
+      {37, kOct | kRight | kUpper | kPos, /*width = */ 0, "45"},
+      {37, kOct | kRight | kUpper | kPos, /*width = */ 6, "____45"},
+      {37, kOct | kRight | kUpper | kBase, /*width = */ 0, "045"},
+      {37, kOct | kRight | kUpper | kBase, /*width = */ 6, "___045"},
+      {37, kOct | kRight | kUpper | kBase | kPos, /*width = */ 0, "045"},
+      {37, kOct | kRight | kUpper | kBase | kPos, /*width = */ 6, "___045"},
+      {37, kHex, /*width = */ 0, "25"},
+      {37, kHex, /*width = */ 6, "____25"},
+      {37, kHex | kPos, /*width = */ 0, "25"},
+      {37, kHex | kPos, /*width = */ 6, "____25"},
+      {37, kHex | kBase, /*width = */ 0, "0x25"},
+      {37, kHex | kBase, /*width = */ 6, "__0x25"},
+      {37, kHex | kBase | kPos, /*width = */ 0, "0x25"},
+      {37, kHex | kBase | kPos, /*width = */ 6, "__0x25"},
+      {37, kHex | kUpper, /*width = */ 0, "25"},
+      {37, kHex | kUpper, /*width = */ 6, "____25"},
+      {37, kHex | kUpper | kPos, /*width = */ 0, "25"},
+      {37, kHex | kUpper | kPos, /*width = */ 6, "____25"},
+      {37, kHex | kUpper | kBase, /*width = */ 0, "0X25"},
+      {37, kHex | kUpper | kBase, /*width = */ 6, "__0X25"},
+      {37, kHex | kUpper | kBase | kPos, /*width = */ 0, "0X25"},
+      {37, kHex | kUpper | kBase | kPos, /*width = */ 6, "__0X25"},
+      {37, kHex | kLeft, /*width = */ 0, "25"},
+      {37, kHex | kLeft, /*width = */ 6, "25____"},
+      {37, kHex | kLeft | kPos, /*width = */ 0, "25"},
+      {37, kHex | kLeft | kPos, /*width = */ 6, "25____"},
+      {37, kHex | kLeft | kBase, /*width = */ 0, "0x25"},
+      {37, kHex | kLeft | kBase, /*width = */ 6, "0x25__"},
+      {37, kHex | kLeft | kBase | kPos, /*width = */ 0, "0x25"},
+      {37, kHex | kLeft | kBase | kPos, /*width = */ 6, "0x25__"},
+      {37, kHex | kLeft | kUpper, /*width = */ 0, "25"},
+      {37, kHex | kLeft | kUpper, /*width = */ 6, "25____"},
+      {37, kHex | kLeft | kUpper | kPos, /*width = */ 0, "25"},
+      {37, kHex | kLeft | kUpper | kPos, /*width = */ 6, "25____"},
+      {37, kHex | kLeft | kUpper | kBase, /*width = */ 0, "0X25"},
+      {37, kHex | kLeft | kUpper | kBase, /*width = */ 6, "0X25__"},
+      {37, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0X25"},
+      {37, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0X25__"},
+      {37, kHex | kInt, /*width = */ 0, "25"},
+      {37, kHex | kInt, /*width = */ 6, "____25"},
+      {37, kHex | kInt | kPos, /*width = */ 0, "25"},
+      {37, kHex | kInt | kPos, /*width = */ 6, "____25"},
+      {37, kHex | kInt | kBase, /*width = */ 0, "0x25"},
+      {37, kHex | kInt | kBase, /*width = */ 6, "0x__25"},
+      {37, kHex | kInt | kBase | kPos, /*width = */ 0, "0x25"},
+      {37, kHex | kInt | kBase | kPos, /*width = */ 6, "0x__25"},
+      {37, kHex | kInt | kUpper, /*width = */ 0, "25"},
+      {37, kHex | kInt | kUpper, /*width = */ 6, "____25"},
+      {37, kHex | kInt | kUpper | kPos, /*width = */ 0, "25"},
+      {37, kHex | kInt | kUpper | kPos, /*width = */ 6, "____25"},
+      {37, kHex | kInt | kUpper | kBase, /*width = */ 0, "0X25"},
+      {37, kHex | kInt | kUpper | kBase, /*width = */ 6, "0X__25"},
+      {37, kHex | kInt | kUpper | kBase | kPos, /*width = */ 0, "0X25"},
+      {37, kHex | kInt | kUpper | kBase | kPos, /*width = */ 6, "0X__25"},
+      {37, kHex | kRight, /*width = */ 0, "25"},
+      {37, kHex | kRight, /*width = */ 6, "____25"},
+      {37, kHex | kRight | kPos, /*width = */ 0, "25"},
+      {37, kHex | kRight | kPos, /*width = */ 6, "____25"},
+      {37, kHex | kRight | kBase, /*width = */ 0, "0x25"},
+      {37, kHex | kRight | kBase, /*width = */ 6, "__0x25"},
+      {37, kHex | kRight | kBase | kPos, /*width = */ 0, "0x25"},
+      {37, kHex | kRight | kBase | kPos, /*width = */ 6, "__0x25"},
+      {37, kHex | kRight | kUpper, /*width = */ 0, "25"},
+      {37, kHex | kRight | kUpper, /*width = */ 6, "____25"},
+      {37, kHex | kRight | kUpper | kPos, /*width = */ 0, "25"},
+      {37, kHex | kRight | kUpper | kPos, /*width = */ 6, "____25"},
+      {37, kHex | kRight | kUpper | kBase, /*width = */ 0, "0X25"},
+      {37, kHex | kRight | kUpper | kBase, /*width = */ 6, "__0X25"},
+      {37, kHex | kRight | kUpper | kBase | kPos, /*width = */ 0, "0X25"},
+      {37, kHex | kRight | kUpper | kBase | kPos, /*width = */ 6, "__0X25"}};
+}
+
+}  // namespace
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
new file mode 100644
index 0000000..1eb3e0e
--- /dev/null
+++ b/absl/numeric/int128_test.cc
@@ -0,0 +1,442 @@
+// Copyright 2017 The Abseil 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 "absl/numeric/int128.h"
+
+#include <algorithm>
+#include <limits>
+#include <random>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/meta/type_traits.h"
+
+#if defined(_MSC_VER) && _MSC_VER == 1900
+// Disable "unary minus operator applied to unsigned type" warnings in Microsoft
+// Visual C++ 14 (2015).
+#pragma warning(disable:4146)
+#endif
+
+namespace {
+
+template <typename T>
+class Uint128IntegerTraitsTest : public ::testing::Test {};
+typedef ::testing::Types<bool, char, signed char, unsigned char, char16_t,
+                         char32_t, wchar_t,
+                         short,           // NOLINT(runtime/int)
+                         unsigned short,  // NOLINT(runtime/int)
+                         int, unsigned int,
+                         long,                // NOLINT(runtime/int)
+                         unsigned long,       // NOLINT(runtime/int)
+                         long long,           // NOLINT(runtime/int)
+                         unsigned long long>  // NOLINT(runtime/int)
+    IntegerTypes;
+
+template <typename T>
+class Uint128FloatTraitsTest : public ::testing::Test {};
+typedef ::testing::Types<float, double, long double> FloatingPointTypes;
+
+TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes);
+
+TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) {
+  static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
+                "absl::uint128 must be constructible from TypeParam");
+  static_assert(std::is_assignable<absl::uint128&, TypeParam>::value,
+                "absl::uint128 must be assignable from TypeParam");
+  static_assert(!std::is_assignable<TypeParam&, absl::uint128>::value,
+                "TypeParam must not be assignable from absl::uint128");
+}
+
+TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes);
+
+TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) {
+  static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
+                "absl::uint128 must be constructible from TypeParam");
+  static_assert(!std::is_assignable<absl::uint128&, TypeParam>::value,
+                "absl::uint128 must not be assignable from TypeParam");
+  static_assert(!std::is_assignable<TypeParam&, absl::uint128>::value,
+                "TypeParam must not be assignable from absl::uint128");
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+// These type traits done separately as TYPED_TEST requires typeinfo, and not
+// all platforms have this for __int128 even though they define the type.
+TEST(Uint128, IntrinsicTypeTraitsTest) {
+  static_assert(std::is_constructible<absl::uint128, __int128>::value,
+                "absl::uint128 must be constructible from __int128");
+  static_assert(std::is_assignable<absl::uint128&, __int128>::value,
+                "absl::uint128 must be assignable from __int128");
+  static_assert(!std::is_assignable<__int128&, absl::uint128>::value,
+                "__int128 must not be assignable from absl::uint128");
+
+  static_assert(std::is_constructible<absl::uint128, unsigned __int128>::value,
+                "absl::uint128 must be constructible from unsigned __int128");
+  static_assert(std::is_assignable<absl::uint128&, unsigned __int128>::value,
+                "absl::uint128 must be assignable from unsigned __int128");
+  static_assert(!std::is_assignable<unsigned __int128&, absl::uint128>::value,
+                "unsigned __int128 must not be assignable from absl::uint128");
+}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+TEST(Uint128, TrivialTraitsTest) {
+  static_assert(absl::is_trivially_default_constructible<absl::uint128>::value,
+                "");
+  static_assert(absl::is_trivially_copy_constructible<absl::uint128>::value,
+                "");
+  static_assert(absl::is_trivially_copy_assignable<absl::uint128>::value, "");
+  static_assert(std::is_trivially_destructible<absl::uint128>::value, "");
+}
+
+TEST(Uint128, AllTests) {
+  absl::uint128 zero = 0;
+  absl::uint128 one = 1;
+  absl::uint128 one_2arg = absl::MakeUint128(0, 1);
+  absl::uint128 two = 2;
+  absl::uint128 three = 3;
+  absl::uint128 big = absl::MakeUint128(2000, 2);
+  absl::uint128 big_minus_one = absl::MakeUint128(2000, 1);
+  absl::uint128 bigger = absl::MakeUint128(2001, 1);
+  absl::uint128 biggest = absl::Uint128Max();
+  absl::uint128 high_low = absl::MakeUint128(1, 0);
+  absl::uint128 low_high =
+      absl::MakeUint128(0, std::numeric_limits<uint64_t>::max());
+  EXPECT_LT(one, two);
+  EXPECT_GT(two, one);
+  EXPECT_LT(one, big);
+  EXPECT_LT(one, big);
+  EXPECT_EQ(one, one_2arg);
+  EXPECT_NE(one, two);
+  EXPECT_GT(big, one);
+  EXPECT_GE(big, two);
+  EXPECT_GE(big, big_minus_one);
+  EXPECT_GT(big, big_minus_one);
+  EXPECT_LT(big_minus_one, big);
+  EXPECT_LE(big_minus_one, big);
+  EXPECT_NE(big_minus_one, big);
+  EXPECT_LT(big, biggest);
+  EXPECT_LE(big, biggest);
+  EXPECT_GT(biggest, big);
+  EXPECT_GE(biggest, big);
+  EXPECT_EQ(big, ~~big);
+  EXPECT_EQ(one, one | one);
+  EXPECT_EQ(big, big | big);
+  EXPECT_EQ(one, one | zero);
+  EXPECT_EQ(one, one & one);
+  EXPECT_EQ(big, big & big);
+  EXPECT_EQ(zero, one & zero);
+  EXPECT_EQ(zero, big & ~big);
+  EXPECT_EQ(zero, one ^ one);
+  EXPECT_EQ(zero, big ^ big);
+  EXPECT_EQ(one, one ^ zero);
+
+  // Shift operators.
+  EXPECT_EQ(big, big << 0);
+  EXPECT_EQ(big, big >> 0);
+  EXPECT_GT(big << 1, big);
+  EXPECT_LT(big >> 1, big);
+  EXPECT_EQ(big, (big << 10) >> 10);
+  EXPECT_EQ(big, (big >> 1) << 1);
+  EXPECT_EQ(one, (one << 80) >> 80);
+  EXPECT_EQ(zero, (one >> 80) << 80);
+
+  // Shift assignments.
+  absl::uint128 big_copy = big;
+  EXPECT_EQ(big << 0, big_copy <<= 0);
+  big_copy = big;
+  EXPECT_EQ(big >> 0, big_copy >>= 0);
+  big_copy = big;
+  EXPECT_EQ(big << 1, big_copy <<= 1);
+  big_copy = big;
+  EXPECT_EQ(big >> 1, big_copy >>= 1);
+  big_copy = big;
+  EXPECT_EQ(big << 10, big_copy <<= 10);
+  big_copy = big;
+  EXPECT_EQ(big >> 10, big_copy >>= 10);
+  big_copy = big;
+  EXPECT_EQ(big << 64, big_copy <<= 64);
+  big_copy = big;
+  EXPECT_EQ(big >> 64, big_copy >>= 64);
+  big_copy = big;
+  EXPECT_EQ(big << 73, big_copy <<= 73);
+  big_copy = big;
+  EXPECT_EQ(big >> 73, big_copy >>= 73);
+
+  EXPECT_EQ(absl::Uint128High64(biggest), std::numeric_limits<uint64_t>::max());
+  EXPECT_EQ(absl::Uint128Low64(biggest), std::numeric_limits<uint64_t>::max());
+  EXPECT_EQ(zero + one, one);
+  EXPECT_EQ(one + one, two);
+  EXPECT_EQ(big_minus_one + one, big);
+  EXPECT_EQ(one - one, zero);
+  EXPECT_EQ(one - zero, one);
+  EXPECT_EQ(zero - one, biggest);
+  EXPECT_EQ(big - big, zero);
+  EXPECT_EQ(big - one, big_minus_one);
+  EXPECT_EQ(big + std::numeric_limits<uint64_t>::max(), bigger);
+  EXPECT_EQ(biggest + 1, zero);
+  EXPECT_EQ(zero - 1, biggest);
+  EXPECT_EQ(high_low - one, low_high);
+  EXPECT_EQ(low_high + one, high_low);
+  EXPECT_EQ(absl::Uint128High64((absl::uint128(1) << 64) - 1), 0);
+  EXPECT_EQ(absl::Uint128Low64((absl::uint128(1) << 64) - 1),
+            std::numeric_limits<uint64_t>::max());
+  EXPECT_TRUE(!!one);
+  EXPECT_TRUE(!!high_low);
+  EXPECT_FALSE(!!zero);
+  EXPECT_FALSE(!one);
+  EXPECT_FALSE(!high_low);
+  EXPECT_TRUE(!zero);
+  EXPECT_TRUE(zero == 0);       // NOLINT(readability/check)
+  EXPECT_FALSE(zero != 0);      // NOLINT(readability/check)
+  EXPECT_FALSE(one == 0);       // NOLINT(readability/check)
+  EXPECT_TRUE(one != 0);        // NOLINT(readability/check)
+  EXPECT_FALSE(high_low == 0);  // NOLINT(readability/check)
+  EXPECT_TRUE(high_low != 0);   // NOLINT(readability/check)
+
+  absl::uint128 test = zero;
+  EXPECT_EQ(++test, one);
+  EXPECT_EQ(test, one);
+  EXPECT_EQ(test++, one);
+  EXPECT_EQ(test, two);
+  EXPECT_EQ(test -= 2, zero);
+  EXPECT_EQ(test, zero);
+  EXPECT_EQ(test += 2, two);
+  EXPECT_EQ(test, two);
+  EXPECT_EQ(--test, one);
+  EXPECT_EQ(test, one);
+  EXPECT_EQ(test--, one);
+  EXPECT_EQ(test, zero);
+  EXPECT_EQ(test |= three, three);
+  EXPECT_EQ(test &= one, one);
+  EXPECT_EQ(test ^= three, two);
+  EXPECT_EQ(test >>= 1, one);
+  EXPECT_EQ(test <<= 1, two);
+
+  EXPECT_EQ(big, -(-big));
+  EXPECT_EQ(two, -((-one) - 1));
+  EXPECT_EQ(absl::Uint128Max(), -one);
+  EXPECT_EQ(zero, -zero);
+
+  EXPECT_EQ(absl::Uint128Max(), absl::kuint128max);
+}
+
+TEST(Uint128, ConversionTests) {
+  EXPECT_TRUE(absl::MakeUint128(1, 0));
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  unsigned __int128 intrinsic =
+      (static_cast<unsigned __int128>(0x3a5b76c209de76f6) << 64) +
+      0x1f25e1d63a2b46c5;
+  absl::uint128 custom =
+      absl::MakeUint128(0x3a5b76c209de76f6, 0x1f25e1d63a2b46c5);
+
+  EXPECT_EQ(custom, absl::uint128(intrinsic));
+  EXPECT_EQ(custom, absl::uint128(static_cast<__int128>(intrinsic)));
+  EXPECT_EQ(intrinsic, static_cast<unsigned __int128>(custom));
+  EXPECT_EQ(intrinsic, static_cast<__int128>(custom));
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+  // verify that an integer greater than 2**64 that can be stored precisely
+  // inside a double is converted to a absl::uint128 without loss of
+  // information.
+  double precise_double = 0x530e * std::pow(2.0, 64.0) + 0xda74000000000000;
+  absl::uint128 from_precise_double(precise_double);
+  absl::uint128 from_precise_ints =
+      absl::MakeUint128(0x530e, 0xda74000000000000);
+  EXPECT_EQ(from_precise_double, from_precise_ints);
+  EXPECT_DOUBLE_EQ(static_cast<double>(from_precise_ints), precise_double);
+
+  double approx_double = 0xffffeeeeddddcccc * std::pow(2.0, 64.0) +
+                         0xbbbbaaaa99998888;
+  absl::uint128 from_approx_double(approx_double);
+  EXPECT_DOUBLE_EQ(static_cast<double>(from_approx_double), approx_double);
+
+  double round_to_zero = 0.7;
+  double round_to_five = 5.8;
+  double round_to_nine = 9.3;
+  EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0);
+  EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5);
+  EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9);
+}
+
+TEST(Uint128, OperatorAssignReturnRef) {
+  absl::uint128 v(1);
+  (v += 4) -= 3;
+  EXPECT_EQ(2, v);
+}
+
+TEST(Uint128, Multiply) {
+  absl::uint128 a, b, c;
+
+  // Zero test.
+  a = 0;
+  b = 0;
+  c = a * b;
+  EXPECT_EQ(0, c);
+
+  // Max carries.
+  a = absl::uint128(0) - 1;
+  b = absl::uint128(0) - 1;
+  c = a * b;
+  EXPECT_EQ(1, c);
+
+  // Self-operation with max carries.
+  c = absl::uint128(0) - 1;
+  c *= c;
+  EXPECT_EQ(1, c);
+
+  // 1-bit x 1-bit.
+  for (int i = 0; i < 64; ++i) {
+    for (int j = 0; j < 64; ++j) {
+      a = absl::uint128(1) << i;
+      b = absl::uint128(1) << j;
+      c = a * b;
+      EXPECT_EQ(absl::uint128(1) << (i + j), c);
+    }
+  }
+
+  // Verified with dc.
+  a = absl::MakeUint128(0xffffeeeeddddcccc, 0xbbbbaaaa99998888);
+  b = absl::MakeUint128(0x7777666655554444, 0x3333222211110000);
+  c = a * b;
+  EXPECT_EQ(absl::MakeUint128(0x530EDA741C71D4C3, 0xBF25975319080000), c);
+  EXPECT_EQ(0, c - b * a);
+  EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+
+  // Verified with dc.
+  a = absl::MakeUint128(0x0123456789abcdef, 0xfedcba9876543210);
+  b = absl::MakeUint128(0x02468ace13579bdf, 0xfdb97531eca86420);
+  c = a * b;
+  EXPECT_EQ(absl::MakeUint128(0x97a87f4f261ba3f2, 0x342d0bbf48948200), c);
+  EXPECT_EQ(0, c - b * a);
+  EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+}
+
+TEST(Uint128, AliasTests) {
+  absl::uint128 x1 = absl::MakeUint128(1, 2);
+  absl::uint128 x2 = absl::MakeUint128(2, 4);
+  x1 += x1;
+  EXPECT_EQ(x2, x1);
+
+  absl::uint128 x3 = absl::MakeUint128(1, static_cast<uint64_t>(1) << 63);
+  absl::uint128 x4 = absl::MakeUint128(3, 0);
+  x3 += x3;
+  EXPECT_EQ(x4, x3);
+}
+
+TEST(Uint128, DivideAndMod) {
+  using std::swap;
+
+  // a := q * b + r
+  absl::uint128 a, b, q, r;
+
+  // Zero test.
+  a = 0;
+  b = 123;
+  q = a / b;
+  r = a % b;
+  EXPECT_EQ(0, q);
+  EXPECT_EQ(0, r);
+
+  a = absl::MakeUint128(0x530eda741c71d4c3, 0xbf25975319080000);
+  q = absl::MakeUint128(0x4de2cab081, 0x14c34ab4676e4bab);
+  b = absl::uint128(0x1110001);
+  r = absl::uint128(0x3eb455);
+  ASSERT_EQ(a, q * b + r);  // Sanity-check.
+
+  absl::uint128 result_q, result_r;
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(q, result_q);
+  EXPECT_EQ(r, result_r);
+
+  // Try the other way around.
+  swap(q, b);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(q, result_q);
+  EXPECT_EQ(r, result_r);
+  // Restore.
+  swap(b, q);
+
+  // Dividend < divisor; result should be q:0 r:<dividend>.
+  swap(a, b);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(0, result_q);
+  EXPECT_EQ(a, result_r);
+  // Try the other way around.
+  swap(a, q);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(0, result_q);
+  EXPECT_EQ(a, result_r);
+  // Restore.
+  swap(q, a);
+  swap(b, a);
+
+  // Try a large remainder.
+  b = a / 2 + 1;
+  absl::uint128 expected_r =
+      absl::MakeUint128(0x29876d3a0e38ea61, 0xdf92cba98c83ffff);
+  // Sanity checks.
+  ASSERT_EQ(a / 2 - 1, expected_r);
+  ASSERT_EQ(a, b + expected_r);
+  result_q = a / b;
+  result_r = a % b;
+  EXPECT_EQ(1, result_q);
+  EXPECT_EQ(expected_r, result_r);
+}
+
+TEST(Uint128, DivideAndModRandomInputs) {
+  const int kNumIters = 1 << 18;
+  std::minstd_rand random(testing::UnitTest::GetInstance()->random_seed());
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  for (int i = 0; i < kNumIters; ++i) {
+    const absl::uint128 a =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    const absl::uint128 b =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    if (b == 0) {
+      continue;  // Avoid a div-by-zero.
+    }
+    const absl::uint128 q = a / b;
+    const absl::uint128 r = a % b;
+    ASSERT_EQ(a, b * q + r);
+  }
+}
+
+TEST(Uint128, ConstexprTest) {
+  constexpr absl::uint128 zero = absl::uint128();
+  constexpr absl::uint128 one = 1;
+  constexpr absl::uint128 minus_two = -2;
+  EXPECT_EQ(zero, absl::uint128(0));
+  EXPECT_EQ(one, absl::uint128(1));
+  EXPECT_EQ(minus_two, absl::MakeUint128(-1, -2));
+}
+
+TEST(Uint128, NumericLimitsTest) {
+  static_assert(std::numeric_limits<absl::uint128>::is_specialized, "");
+  static_assert(!std::numeric_limits<absl::uint128>::is_signed, "");
+  static_assert(std::numeric_limits<absl::uint128>::is_integer, "");
+  EXPECT_EQ(static_cast<int>(128 * std::log10(2)),
+            std::numeric_limits<absl::uint128>::digits10);
+  EXPECT_EQ(0, std::numeric_limits<absl::uint128>::min());
+  EXPECT_EQ(0, std::numeric_limits<absl::uint128>::lowest());
+  EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max());
+}
+
+}  // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
new file mode 100644
index 0000000..3b1e067
--- /dev/null
+++ b/absl/strings/BUILD.bazel
@@ -0,0 +1,649 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+    "ABSL_EXCEPTIONS_FLAG",
+)
+
+package(
+    default_visibility = ["//visibility:public"],
+    features = ["parse_headers"],
+)
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "strings",
+    srcs = [
+        "ascii.cc",
+        "charconv.cc",
+        "escaping.cc",
+        "internal/charconv_bigint.cc",
+        "internal/charconv_bigint.h",
+        "internal/charconv_parse.cc",
+        "internal/charconv_parse.h",
+        "internal/memutil.cc",
+        "internal/memutil.h",
+        "internal/stl_type_traits.h",
+        "internal/str_join_internal.h",
+        "internal/str_split_internal.h",
+        "match.cc",
+        "numbers.cc",
+        "str_cat.cc",
+        "str_replace.cc",
+        "str_split.cc",
+        "string_view.cc",
+        "substitute.cc",
+    ],
+    hdrs = [
+        "ascii.h",
+        "charconv.h",
+        "escaping.h",
+        "match.h",
+        "numbers.h",
+        "str_cat.h",
+        "str_join.h",
+        "str_replace.h",
+        "str_split.h",
+        "string_view.h",
+        "strip.h",
+        "substitute.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":internal",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:endian",
+        "//absl/base:throw_delegate",
+        "//absl/memory",
+        "//absl/meta:type_traits",
+        "//absl/numeric:int128",
+    ],
+)
+
+cc_library(
+    name = "internal",
+    srcs = [
+        "internal/ostringstream.cc",
+        "internal/utf8.cc",
+    ],
+    hdrs = [
+        "internal/bits.h",
+        "internal/char_map.h",
+        "internal/ostringstream.h",
+        "internal/resize_uninitialized.h",
+        "internal/utf8.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base:core_headers",
+        "//absl/base:endian",
+        "//absl/meta:type_traits",
+    ],
+)
+
+cc_test(
+    name = "match_test",
+    size = "small",
+    srcs = ["match_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "escaping_test",
+    size = "small",
+    srcs = [
+        "escaping_test.cc",
+        "internal/escaping_test_common.h",
+    ],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "//absl/container:fixed_array",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "escaping_benchmark",
+    srcs = [
+        "escaping_benchmark.cc",
+        "internal/escaping_test_common.h",
+    ],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "ascii_test",
+    size = "small",
+    srcs = ["ascii_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "memutil_benchmark",
+    srcs = [
+        "internal/memutil.h",
+        "internal/memutil_benchmark.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "memutil_test",
+    size = "small",
+    srcs = [
+        "internal/memutil.h",
+        "internal/memutil_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "utf8_test",
+    size = "small",
+    srcs = [
+        "internal/utf8_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":internal",
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "string_view_benchmark",
+    srcs = ["string_view_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "string_view_test",
+    size = "small",
+    srcs = ["string_view_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:dynamic_annotations",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "substitute_test",
+    size = "small",
+    srcs = ["substitute_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_replace_benchmark",
+    srcs = ["str_replace_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "str_replace_test",
+    size = "small",
+    srcs = ["str_replace_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_split_test",
+    srcs = ["str_split_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "//absl/base:dynamic_annotations",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_split_benchmark",
+    srcs = ["str_split_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "ostringstream_test",
+    size = "small",
+    srcs = ["internal/ostringstream_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "ostringstream_benchmark",
+    srcs = ["internal/ostringstream_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":internal",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "resize_uninitialized_test",
+    size = "small",
+    srcs = [
+        "internal/resize_uninitialized.h",
+        "internal/resize_uninitialized_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        "//absl/base:core_headers",
+        "//absl/meta:type_traits",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_join_test",
+    size = "small",
+    srcs = ["str_join_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_join_benchmark",
+    srcs = ["str_join_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/memory",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "str_cat_test",
+    size = "small",
+    srcs = ["str_cat_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_cat_benchmark",
+    srcs = ["str_cat_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "numbers_test",
+    size = "small",
+    srcs = [
+        "internal/numbers_test_common.h",
+        "numbers_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "numbers_benchmark",
+    srcs = ["numbers_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "strip_test",
+    size = "small",
+    srcs = ["strip_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "char_map_test",
+    srcs = ["internal/char_map_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "char_map_benchmark",
+    srcs = ["internal/char_map_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    deps = [
+        ":internal",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "charconv_test",
+    srcs = ["charconv_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "charconv_parse_test",
+    srcs = [
+        "internal/charconv_parse.h",
+        "internal/charconv_parse_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "charconv_bigint_test",
+    srcs = [
+        "internal/charconv_bigint.h",
+        "internal/charconv_bigint_test.cc",
+        "internal/charconv_parse.h",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "charconv_benchmark",
+    srcs = [
+        "charconv_benchmark.cc",
+    ],
+    tags = [
+        "benchmark",
+    ],
+    deps = [
+        ":strings",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "str_format",
+    hdrs = [
+        "str_format.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":str_format_internal",
+    ],
+)
+
+cc_library(
+    name = "str_format_internal",
+    srcs = [
+        "internal/str_format/arg.cc",
+        "internal/str_format/bind.cc",
+        "internal/str_format/extension.cc",
+        "internal/str_format/float_conversion.cc",
+        "internal/str_format/output.cc",
+        "internal/str_format/parser.cc",
+    ],
+    hdrs = [
+        "internal/str_format/arg.h",
+        "internal/str_format/bind.h",
+        "internal/str_format/checker.h",
+        "internal/str_format/extension.h",
+        "internal/str_format/float_conversion.h",
+        "internal/str_format/output.h",
+        "internal/str_format/parser.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "//absl/container:inlined_vector",
+        "//absl/meta:type_traits",
+        "//absl/numeric:int128",
+        "//absl/types:span",
+    ],
+)
+
+cc_test(
+    name = "str_format_test",
+    srcs = ["str_format_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format",
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_extension_test",
+    srcs = [
+        "internal/str_format/extension_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format",
+        ":str_format_internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_arg_test",
+    srcs = ["internal/str_format/arg_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format",
+        ":str_format_internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_bind_test",
+    srcs = ["internal/str_format/bind_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format_internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_checker_test",
+    srcs = ["internal/str_format/checker_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_convert_test",
+    size = "small",
+    srcs = ["internal/str_format/convert_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format_internal",
+        "//absl/numeric:int128",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_output_test",
+    srcs = ["internal/str_format/output_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format_internal",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "str_format_parser_test",
+    srcs = ["internal/str_format/parser_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":str_format_internal",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/strings/BUILD.gn b/absl/strings/BUILD.gn
new file mode 100644
index 0000000..9a8a10d
--- /dev/null
+++ b/absl/strings/BUILD.gn
@@ -0,0 +1,146 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("strings") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "ascii.cc",
+    "charconv.cc",
+    "escaping.cc",
+    "internal/charconv_bigint.cc",
+    "internal/charconv_bigint.h",
+    "internal/charconv_parse.cc",
+    "internal/charconv_parse.h",
+    "internal/memutil.cc",
+    "internal/memutil.h",
+    "internal/stl_type_traits.h",
+    "internal/str_join_internal.h",
+    "internal/str_split_internal.h",
+    "match.cc",
+    "numbers.cc",
+    "str_cat.cc",
+    "str_replace.cc",
+    "str_split.cc",
+    "string_view.cc",
+    "substitute.cc",
+  ]
+  public = [
+    "ascii.h",
+    "charconv.h",
+    "escaping.h",
+    "match.h",
+    "numbers.h",
+    "str_cat.h",
+    "str_join.h",
+    "str_replace.h",
+    "str_split.h",
+    "string_view.h",
+    "strip.h",
+    "substitute.h",
+  ]
+  deps = [
+    ":internal",
+    "../base",
+    "../base:config",
+    "../base:core_headers",
+    "../base:endian",
+    "../base:throw_delegate",
+    "../memory",
+    "../meta:type_traits",
+    "../numeric:int128",
+  ]
+}
+
+source_set("internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/ostringstream.cc",
+    "internal/utf8.cc",
+  ]
+  public = [
+    "internal/bits.h",
+    "internal/char_map.h",
+    "internal/ostringstream.h",
+    "internal/resize_uninitialized.h",
+    "internal/utf8.h",
+  ]
+  deps = [
+    "../base:core_headers",
+    "../base:endian",
+    "../meta:type_traits",
+  ]
+}
+
+source_set("str_format") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "str_format.h",
+  ]
+  deps = [
+    ":str_format_internal",
+  ]
+}
+
+source_set("str_format_internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/str_format/arg.cc",
+    "internal/str_format/bind.cc",
+    "internal/str_format/extension.cc",
+    "internal/str_format/float_conversion.cc",
+    "internal/str_format/output.cc",
+    "internal/str_format/parser.cc",
+  ]
+  public = [
+    "internal/str_format/arg.h",
+    "internal/str_format/bind.h",
+    "internal/str_format/checker.h",
+    "internal/str_format/extension.h",
+    "internal/str_format/float_conversion.h",
+    "internal/str_format/output.h",
+    "internal/str_format/parser.h",
+  ]
+  visibility = []
+  visibility += [ ":*" ]
+  deps = [
+    ":strings",
+    "../base:core_headers",
+    "../container:inlined_vector",
+    "../meta:type_traits",
+    "../numeric:int128",
+    "../types:span",
+  ]
+}
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
new file mode 100644
index 0000000..cd12213
--- /dev/null
+++ b/absl/strings/CMakeLists.txt
@@ -0,0 +1,464 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+
+list(APPEND STRINGS_PUBLIC_HEADERS
+  "ascii.h"
+  "charconv.h"
+  "escaping.h"
+  "match.h"
+  "numbers.h"
+  "str_cat.h"
+  "string_view.h"
+  "strip.h"
+  "str_join.h"
+  "str_replace.h"
+  "str_split.h"
+  "substitute.h"
+)
+
+
+list(APPEND STRINGS_INTERNAL_HEADERS
+  "internal/bits.h"
+  "internal/char_map.h"
+  "internal/charconv_bigint.h"
+  "internal/charconv_parse.h"
+  "internal/memutil.h"
+  "internal/ostringstream.h"
+  "internal/resize_uninitialized.h"
+  "internal/stl_type_traits.h"
+  "internal/str_join_internal.h"
+  "internal/str_split_internal.h"
+  "internal/utf8.h"
+)
+
+
+
+# add string library
+list(APPEND STRINGS_SRC
+  "ascii.cc"
+  "charconv.cc"
+  "escaping.cc"
+  "internal/charconv_bigint.cc"
+  "internal/charconv_parse.cc"
+  "internal/memutil.cc"
+  "internal/memutil.h"
+  "internal/utf8.cc"
+  "internal/ostringstream.cc"
+  "match.cc"
+  "numbers.cc"
+  "str_cat.cc"
+  "str_replace.cc"
+  "str_split.cc"
+  "string_view.cc"
+  "substitute.cc"
+  ${STRINGS_PUBLIC_HEADERS}
+  ${STRINGS_INTERNAL_HEADERS}
+)
+set(STRINGS_PUBLIC_LIBRARIES absl::base absl_throw_delegate)
+
+absl_library(
+  TARGET
+    absl_strings
+  SOURCES
+    ${STRINGS_SRC}
+  PUBLIC_LIBRARIES
+    ${STRINGS_PUBLIC_LIBRARIES}
+  EXPORT_NAME
+    strings
+)
+
+# add str_format library
+absl_header_library(
+  TARGET
+    absl_str_format
+  PUBLIC_LIBRARIES
+    str_format_internal
+  EXPORT_NAME
+    str_format
+)
+
+# str_format_internal
+absl_library(
+  TARGET
+    str_format_internal
+  SOURCES
+    "internal/str_format/arg.cc"
+    "internal/str_format/bind.cc"
+    "internal/str_format/extension.cc"
+    "internal/str_format/float_conversion.cc"
+    "internal/str_format/output.cc"
+    "internal/str_format/parser.cc"
+    "internal/str_format/arg.h"
+    "internal/str_format/bind.h"
+    "internal/str_format/checker.h"
+    "internal/str_format/extension.h"
+    "internal/str_format/float_conversion.h"
+    "internal/str_format/output.h"
+    "internal/str_format/parser.h"
+  PUBLIC_LIBRARIES
+    str_format_extension_internal
+    absl::strings
+    absl::base
+    absl::numeric
+    absl::container
+    absl::span
+)
+
+# str_format_extension_internal
+absl_library(
+  TARGET
+    str_format_extension_internal
+  SOURCES
+    "internal/str_format/extension.cc"
+    "internal/str_format/extension.h"
+    "internal/str_format/output.cc"
+    "internal/str_format/output.h"
+  PUBLIC_LIBRARIES
+    absl::base
+    absl::strings
+)
+
+#
+## TESTS
+#
+
+# test match_test
+set(MATCH_TEST_SRC "match_test.cc")
+set(MATCH_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    match_test
+  SOURCES
+    ${MATCH_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${MATCH_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test escaping_test
+set(ESCAPING_TEST_SRC "escaping_test.cc")
+set(ESCAPING_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
+
+absl_test(
+  TARGET
+    escaping_test
+  SOURCES
+    ${ESCAPING_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ESCAPING_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test ascii_test
+set(ASCII_TEST_SRC "ascii_test.cc")
+set(ASCII_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    ascii_test
+  SOURCES
+    ${ASCII_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ASCII_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test memutil_test
+set(MEMUTIL_TEST_SRC "internal/memutil_test.cc")
+set(MEMUTIL_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    memutil_test
+  SOURCES
+    ${MEMUTIL_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${MEMUTIL_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test utf8_test
+set(UTF8_TEST_SRC "internal/utf8_test.cc")
+set(UTF8_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
+
+absl_test(
+  TARGET
+    utf8_test
+  SOURCES
+    ${UTF8_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${UTF8_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test string_view_test
+set(STRING_VIEW_TEST_SRC "string_view_test.cc")
+set(STRING_VIEW_TEST_PUBLIC_LIBRARIES absl::strings absl_throw_delegate absl::base)
+
+absl_test(
+  TARGET
+    string_view_test
+  SOURCES
+    ${STRING_VIEW_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${STRING_VIEW_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test substitute_test
+set(SUBSTITUTE_TEST_SRC "substitute_test.cc")
+set(SUBSTITUTE_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
+
+absl_test(
+  TARGET
+    substitute_test
+  SOURCES
+    ${SUBSTITUTE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${SUBSTITUTE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test str_replace_test
+set(STR_REPLACE_TEST_SRC "str_replace_test.cc")
+set(STR_REPLACE_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate)
+
+absl_test(
+  TARGET
+    str_replace_test
+  SOURCES
+    ${STR_REPLACE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${STR_REPLACE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test str_split_test
+set(STR_SPLIT_TEST_SRC "str_split_test.cc")
+set(STR_SPLIT_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate)
+
+absl_test(
+  TARGET
+    str_split_test
+  SOURCES
+    ${STR_SPLIT_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${STR_SPLIT_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test ostringstream_test
+set(OSTRINGSTREAM_TEST_SRC "internal/ostringstream_test.cc")
+set(OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    ostringstream_test
+  SOURCES
+    ${OSTRINGSTREAM_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test resize_uninitialized_test
+set(RESIZE_UNINITIALIZED_TEST_SRC "internal/resize_uninitialized_test.cc")
+
+absl_test(
+  TARGET
+    resize_uninitialized_test
+  SOURCES
+    ${RESIZE_UNINITIALIZED_TEST_SRC}
+)
+
+
+# test str_join_test
+set(STR_JOIN_TEST_SRC "str_join_test.cc")
+set(STR_JOIN_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    str_join_test
+  SOURCES
+    ${STR_JOIN_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${STR_JOIN_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test str_cat_test
+set(STR_CAT_TEST_SRC "str_cat_test.cc")
+set(STR_CAT_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    str_cat_test
+  SOURCES
+    ${STR_CAT_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${STR_CAT_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test numbers_test
+set(NUMBERS_TEST_SRC "numbers_test.cc")
+set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    numbers_test
+  SOURCES
+    ${NUMBERS_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${NUMBERS_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test strip_test
+set(STRIP_TEST_SRC "strip_test.cc")
+set(STRIP_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    strip_test
+  SOURCES
+    ${STRIP_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${STRIP_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test char_map_test
+set(CHAR_MAP_TEST_SRC "internal/char_map_test.cc")
+set(CHAR_MAP_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    char_map_test
+  SOURCES
+    ${CHAR_MAP_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${CHAR_MAP_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test charconv_test
+set(CHARCONV_TEST_SRC "charconv_test.cc")
+set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    charconv_test
+  SOURCES
+    ${CHARCONV_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${CHARCONV_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test charconv_parse_test
+set(CHARCONV_PARSE_TEST_SRC "internal/charconv_parse_test.cc")
+set(CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    charconv_parse_test
+  SOURCES
+    ${CHARCONV_PARSE_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test charconv_bigint_test
+set(CHARCONV_BIGINT_TEST_SRC "internal/charconv_bigint_test.cc")
+set(CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES absl::strings)
+
+absl_test(
+  TARGET
+    charconv_bigint_test
+  SOURCES
+    ${CHARCONV_BIGINT_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES}
+)
+# test str_format_test
+absl_test(
+  TARGET
+    str_format_test
+  SOURCES
+    "str_format_test.cc"
+  PUBLIC_LIBRARIES
+    absl::base
+    absl::str_format
+    absl::strings
+)
+
+# test str_format_bind_test
+absl_test(
+  TARGET
+    str_format_bind_test
+  SOURCES
+    "internal/str_format/bind_test.cc"
+  PUBLIC_LIBRARIES
+    str_format_internal
+)
+
+# test str_format_checker_test
+absl_test(
+  TARGET
+    str_format_checker_test
+  SOURCES
+    "internal/str_format/checker_test.cc"
+  PUBLIC_LIBRARIES
+    absl::str_format
+)
+
+# test str_format_convert_test
+absl_test(
+  TARGET
+    str_format_convert_test
+  SOURCES
+    "internal/str_format/convert_test.cc"
+  PUBLIC_LIBRARIES
+    str_format_internal
+    absl::numeric
+)
+
+# test str_format_output_test
+absl_test(
+  TARGET
+    str_format_output_test
+  SOURCES
+    "internal/str_format/output_test.cc"
+  PUBLIC_LIBRARIES
+    str_format_extension_internal
+)
+
+# test str_format_parser_test
+absl_test(
+  TARGET
+    str_format_parser_test
+  SOURCES
+    "internal/str_format/parser_test.cc"
+  PUBLIC_LIBRARIES
+    str_format_internal
+    absl::base
+)
+
+
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
new file mode 100644
index 0000000..c9481e8
--- /dev/null
+++ b/absl/strings/ascii.cc
@@ -0,0 +1,198 @@
+// Copyright 2017 The Abseil 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 "absl/strings/ascii.h"
+
+namespace absl {
+namespace ascii_internal {
+
+// # Table generated by this Python code (bit 0x02 is currently unused):
+// TODO(mbar) Move Python code for generation of table to BUILD and link here.
+
+// NOTE: The kAsciiPropertyBits table used within this code was generated by
+// Python code of the following form. (Bit 0x02 is currently unused and
+// available.)
+//
+// def Hex2(n):
+//   return '0x' + hex(n/16)[2:] + hex(n%16)[2:]
+// def IsPunct(ch):
+//   return (ord(ch) >= 32 and ord(ch) < 127 and
+//           not ch.isspace() and not ch.isalnum())
+// def IsBlank(ch):
+//   return ch in ' \t'
+// def IsCntrl(ch):
+//   return ord(ch) < 32 or ord(ch) == 127
+// def IsXDigit(ch):
+//   return ch.isdigit() or ch.lower() in 'abcdef'
+// for i in range(128):
+//   ch = chr(i)
+//   mask = ((ch.isalpha() and 0x01 or 0) |
+//           (ch.isalnum() and 0x04 or 0) |
+//           (ch.isspace() and 0x08 or 0) |
+//           (IsPunct(ch) and 0x10 or 0) |
+//           (IsBlank(ch) and 0x20 or 0) |
+//           (IsCntrl(ch) and 0x40 or 0) |
+//           (IsXDigit(ch) and 0x80 or 0))
+//   print Hex2(mask) + ',',
+//   if i % 16 == 7:
+//     print ' //', Hex2(i & 0x78)
+//   elif i % 16 == 15:
+//     print
+
+// clang-format off
+// Array of bitfields holding character information. Each bit value corresponds
+// to a particular character feature. For readability, and because the value
+// of these bits is tightly coupled to this implementation, the individual bits
+// are not named. Note that bitfields for all characters above ASCII 127 are
+// zero-initialized.
+const unsigned char kPropertyBits[256] = {
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x00
+    0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x10
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  // 0x20
+    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+    0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,  // 0x30
+    0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+    0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05,  // 0x40
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,  // 0x50
+    0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
+    0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05,  // 0x60
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,  // 0x70
+    0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
+};
+
+// Array of characters for the ascii_tolower() function. For values 'A'
+// through 'Z', return the lower-case character; otherwise, return the
+// identity of the passed character.
+const char kToLower[256] = {
+  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
+  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+  '\x40',    'a',    'b',    'c',    'd',    'e',    'f',    'g',
+     'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
+     'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
+     'x',    'y',    'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
+  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
+  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
+  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+  '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+  '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+  '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+  '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+  '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+  '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+  '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+  '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+  '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+  '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+  '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+  '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+  '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+  '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
+};
+
+// Array of characters for the ascii_toupper() function. For values 'a'
+// through 'z', return the upper-case character; otherwise, return the
+// identity of the passed character.
+const char kToUpper[256] = {
+  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
+  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
+  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
+  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
+  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+  '\x60',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+     'X',    'Y',    'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+  '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+  '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+  '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+  '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+  '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+  '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+  '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+  '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+  '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+  '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+  '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+  '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+  '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+  '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
+};
+// clang-format on
+
+}  // namespace ascii_internal
+
+void AsciiStrToLower(std::string* s) {
+  for (auto& ch : *s) {
+    ch = absl::ascii_tolower(ch);
+  }
+}
+
+void AsciiStrToUpper(std::string* s) {
+  for (auto& ch : *s) {
+    ch = absl::ascii_toupper(ch);
+  }
+}
+
+void RemoveExtraAsciiWhitespace(std::string* str) {
+  auto stripped = StripAsciiWhitespace(*str);
+
+  if (stripped.empty()) {
+    str->clear();
+    return;
+  }
+
+  auto input_it = stripped.begin();
+  auto input_end = stripped.end();
+  auto output_it = &(*str)[0];
+  bool is_ws = false;
+
+  for (; input_it < input_end; ++input_it) {
+    if (is_ws) {
+      // Consecutive whitespace?  Keep only the last.
+      is_ws = absl::ascii_isspace(*input_it);
+      if (is_ws) --output_it;
+    } else {
+      is_ws = absl::ascii_isspace(*input_it);
+    }
+
+    *output_it = *input_it;
+    ++output_it;
+  }
+
+  str->erase(output_it - &(*str)[0]);
+}
+
+}  // namespace absl
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
new file mode 100644
index 0000000..96a6454
--- /dev/null
+++ b/absl/strings/ascii.h
@@ -0,0 +1,239 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: ascii.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions operating on characters and strings
+// restricted to standard ASCII. These include character classification
+// functions analogous to those found in the ANSI C Standard Library <ctype.h>
+// header file.
+//
+// C++ implementations provide <ctype.h> functionality based on their
+// C environment locale. In general, reliance on such a locale is not ideal, as
+// the locale standard is problematic (and may not return invariant information
+// for the same character set, for example). These `ascii_*()` functions are
+// hard-wired for standard ASCII, much faster, and guaranteed to behave
+// consistently.  They will never be overloaded, nor will their function
+// signature change.
+//
+// `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`,
+// `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`,
+// `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`,
+// `ascii_isxdigit()`
+//   Analogous to the <ctype.h> functions with similar names, these
+//   functions take an unsigned char and return a bool, based on whether the
+//   character matches the condition specified.
+//
+//   If the input character has a numerical value greater than 127, these
+//   functions return `false`.
+//
+// `ascii_tolower()`, `ascii_toupper()`
+//   Analogous to the <ctype.h> functions with similar names, these functions
+//   take an unsigned char and return a char.
+//
+//   If the input character is not an ASCII {lower,upper}-case letter (including
+//   numerical values greater than 127) then the functions return the same value
+//   as the input character.
+
+#ifndef ABSL_STRINGS_ASCII_H_
+#define ABSL_STRINGS_ASCII_H_
+
+#include <algorithm>
+#include <string>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace ascii_internal {
+
+// Declaration for an array of bitfields holding character information.
+extern const unsigned char kPropertyBits[256];
+
+// Declaration for the array of characters to upper-case characters.
+extern const char kToUpper[256];
+
+// Declaration for the array of characters to lower-case characters.
+extern const char kToLower[256];
+
+}  // namespace ascii_internal
+
+// ascii_isalpha()
+//
+// Determines whether the given character is an alphabetic character.
+inline bool ascii_isalpha(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x01) != 0;
+}
+
+// ascii_isalnum()
+//
+// Determines whether the given character is an alphanumeric character.
+inline bool ascii_isalnum(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x04) != 0;
+}
+
+// ascii_isspace()
+//
+// Determines whether the given character is a whitespace character (space,
+// tab, vertical tab, formfeed, linefeed, or carriage return).
+inline bool ascii_isspace(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x08) != 0;
+}
+
+// ascii_ispunct()
+//
+// Determines whether the given character is a punctuation character.
+inline bool ascii_ispunct(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x10) != 0;
+}
+
+// ascii_isblank()
+//
+// Determines whether the given character is a blank character (tab or space).
+inline bool ascii_isblank(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x20) != 0;
+}
+
+// ascii_iscntrl()
+//
+// Determines whether the given character is a control character.
+inline bool ascii_iscntrl(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x40) != 0;
+}
+
+// ascii_isxdigit()
+//
+// Determines whether the given character can be represented as a hexadecimal
+// digit character (i.e. {0-9} or {A-F}).
+inline bool ascii_isxdigit(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x80) != 0;
+}
+
+// ascii_isdigit()
+//
+// Determines whether the given character can be represented as a decimal
+// digit character (i.e. {0-9}).
+inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; }
+
+// ascii_isprint()
+//
+// Determines whether the given character is printable, including whitespace.
+inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; }
+
+// ascii_isgraph()
+//
+// Determines whether the given character has a graphical representation.
+inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; }
+
+// ascii_isupper()
+//
+// Determines whether the given character is uppercase.
+inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; }
+
+// ascii_islower()
+//
+// Determines whether the given character is lowercase.
+inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; }
+
+// ascii_isascii()
+//
+// Determines whether the given character is ASCII.
+inline bool ascii_isascii(unsigned char c) { return c < 128; }
+
+// ascii_tolower()
+//
+// Returns an ASCII character, converting to lowercase if uppercase is
+// passed. Note that character values > 127 are simply returned.
+inline char ascii_tolower(unsigned char c) {
+  return ascii_internal::kToLower[c];
+}
+
+// Converts the characters in `s` to lowercase, changing the contents of `s`.
+void AsciiStrToLower(std::string* s);
+
+// Creates a lowercase std::string from a given absl::string_view.
+ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) {
+  std::string result(s);
+  absl::AsciiStrToLower(&result);
+  return result;
+}
+
+// ascii_toupper()
+//
+// Returns the ASCII character, converting to upper-case if lower-case is
+// passed. Note that characters values > 127 are simply returned.
+inline char ascii_toupper(unsigned char c) {
+  return ascii_internal::kToUpper[c];
+}
+
+// Converts the characters in `s` to uppercase, changing the contents of `s`.
+void AsciiStrToUpper(std::string* s);
+
+// Creates an uppercase std::string from a given absl::string_view.
+ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) {
+  std::string result(s);
+  absl::AsciiStrToUpper(&result);
+  return result;
+}
+
+// Returns absl::string_view with whitespace stripped from the beginning of the
+// given string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace(
+    absl::string_view str) {
+  auto it = std::find_if_not(str.begin(), str.end(), absl::ascii_isspace);
+  return absl::string_view(it, str.end() - it);
+}
+
+// Strips in place whitespace from the beginning of the given std::string.
+inline void StripLeadingAsciiWhitespace(std::string* str) {
+  auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace);
+  str->erase(str->begin(), it);
+}
+
+// Returns absl::string_view with whitespace stripped from the end of the given
+// string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace(
+    absl::string_view str) {
+  auto it = std::find_if_not(str.rbegin(), str.rend(), absl::ascii_isspace);
+  return absl::string_view(str.begin(), str.rend() - it);
+}
+
+// Strips in place whitespace from the end of the given std::string
+inline void StripTrailingAsciiWhitespace(std::string* str) {
+  auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace);
+  str->erase(str->rend() - it);
+}
+
+// Returns absl::string_view with whitespace stripped from both ends of the
+// given string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace(
+    absl::string_view str) {
+  return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str));
+}
+
+// Strips in place whitespace from both ends of the given std::string
+inline void StripAsciiWhitespace(std::string* str) {
+  StripTrailingAsciiWhitespace(str);
+  StripLeadingAsciiWhitespace(str);
+}
+
+// Removes leading, trailing, and consecutive internal whitespace.
+void RemoveExtraAsciiWhitespace(std::string*);
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_ASCII_H_
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
new file mode 100644
index 0000000..9903b04
--- /dev/null
+++ b/absl/strings/ascii_test.cc
@@ -0,0 +1,361 @@
+// Copyright 2017 The Abseil 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 "absl/strings/ascii.h"
+
+#include <cctype>
+#include <clocale>
+#include <cstring>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace {
+
+TEST(AsciiIsFoo, All) {
+  for (int i = 0; i < 256; i++) {
+    if ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z'))
+      EXPECT_TRUE(absl::ascii_isalpha(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isalpha(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if ((i >= '0' && i <= '9'))
+      EXPECT_TRUE(absl::ascii_isdigit(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isdigit(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (absl::ascii_isalpha(i) || absl::ascii_isdigit(i))
+      EXPECT_TRUE(absl::ascii_isalnum(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isalnum(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i != '\0' && strchr(" \r\n\t\v\f", i))
+      EXPECT_TRUE(absl::ascii_isspace(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isspace(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i >= 32 && i < 127)
+      EXPECT_TRUE(absl::ascii_isprint(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isprint(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (absl::ascii_isprint(i) && !absl::ascii_isspace(i) &&
+        !absl::ascii_isalnum(i))
+      EXPECT_TRUE(absl::ascii_ispunct(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_ispunct(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i == ' ' || i == '\t')
+      EXPECT_TRUE(absl::ascii_isblank(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isblank(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i < 32 || i == 127)
+      EXPECT_TRUE(absl::ascii_iscntrl(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_iscntrl(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (absl::ascii_isdigit(i) || (i >= 'A' && i <= 'F') ||
+        (i >= 'a' && i <= 'f'))
+      EXPECT_TRUE(absl::ascii_isxdigit(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isxdigit(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i > 32 && i < 127)
+      EXPECT_TRUE(absl::ascii_isgraph(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isgraph(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i >= 'A' && i <= 'Z')
+      EXPECT_TRUE(absl::ascii_isupper(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_isupper(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 256; i++) {
+    if (i >= 'a' && i <= 'z')
+      EXPECT_TRUE(absl::ascii_islower(i)) << ": failed on " << i;
+    else
+      EXPECT_TRUE(!absl::ascii_islower(i)) << ": failed on " << i;
+  }
+  for (int i = 0; i < 128; i++) {
+    EXPECT_TRUE(absl::ascii_isascii(i)) << ": failed on " << i;
+  }
+  for (int i = 128; i < 256; i++) {
+    EXPECT_TRUE(!absl::ascii_isascii(i)) << ": failed on " << i;
+  }
+
+  // The official is* functions don't accept negative signed chars, but
+  // our absl::ascii_is* functions do.
+  for (int i = 0; i < 256; i++) {
+    signed char sc = static_cast<signed char>(static_cast<unsigned char>(i));
+    EXPECT_EQ(absl::ascii_isalpha(i), absl::ascii_isalpha(sc)) << i;
+    EXPECT_EQ(absl::ascii_isdigit(i), absl::ascii_isdigit(sc)) << i;
+    EXPECT_EQ(absl::ascii_isalnum(i), absl::ascii_isalnum(sc)) << i;
+    EXPECT_EQ(absl::ascii_isspace(i), absl::ascii_isspace(sc)) << i;
+    EXPECT_EQ(absl::ascii_ispunct(i), absl::ascii_ispunct(sc)) << i;
+    EXPECT_EQ(absl::ascii_isblank(i), absl::ascii_isblank(sc)) << i;
+    EXPECT_EQ(absl::ascii_iscntrl(i), absl::ascii_iscntrl(sc)) << i;
+    EXPECT_EQ(absl::ascii_isxdigit(i), absl::ascii_isxdigit(sc)) << i;
+    EXPECT_EQ(absl::ascii_isprint(i), absl::ascii_isprint(sc)) << i;
+    EXPECT_EQ(absl::ascii_isgraph(i), absl::ascii_isgraph(sc)) << i;
+    EXPECT_EQ(absl::ascii_isupper(i), absl::ascii_isupper(sc)) << i;
+    EXPECT_EQ(absl::ascii_islower(i), absl::ascii_islower(sc)) << i;
+    EXPECT_EQ(absl::ascii_isascii(i), absl::ascii_isascii(sc)) << i;
+  }
+}
+
+// Checks that absl::ascii_isfoo returns the same value as isfoo in the C
+// locale.
+TEST(AsciiIsFoo, SameAsIsFoo) {
+#ifndef __ANDROID__
+  // temporarily change locale to C. It should already be C, but just for safety
+  const char* old_locale = setlocale(LC_CTYPE, "C");
+  ASSERT_TRUE(old_locale != nullptr);
+#endif
+
+  for (int i = 0; i < 256; i++) {
+    EXPECT_EQ(isalpha(i) != 0, absl::ascii_isalpha(i)) << i;
+    EXPECT_EQ(isdigit(i) != 0, absl::ascii_isdigit(i)) << i;
+    EXPECT_EQ(isalnum(i) != 0, absl::ascii_isalnum(i)) << i;
+    EXPECT_EQ(isspace(i) != 0, absl::ascii_isspace(i)) << i;
+    EXPECT_EQ(ispunct(i) != 0, absl::ascii_ispunct(i)) << i;
+    EXPECT_EQ(isblank(i) != 0, absl::ascii_isblank(i)) << i;
+    EXPECT_EQ(iscntrl(i) != 0, absl::ascii_iscntrl(i)) << i;
+    EXPECT_EQ(isxdigit(i) != 0, absl::ascii_isxdigit(i)) << i;
+    EXPECT_EQ(isprint(i) != 0, absl::ascii_isprint(i)) << i;
+    EXPECT_EQ(isgraph(i) != 0, absl::ascii_isgraph(i)) << i;
+    EXPECT_EQ(isupper(i) != 0, absl::ascii_isupper(i)) << i;
+    EXPECT_EQ(islower(i) != 0, absl::ascii_islower(i)) << i;
+    EXPECT_EQ(isascii(i) != 0, absl::ascii_isascii(i)) << i;
+  }
+
+#ifndef __ANDROID__
+  // restore the old locale.
+  ASSERT_TRUE(setlocale(LC_CTYPE, old_locale));
+#endif
+}
+
+TEST(AsciiToFoo, All) {
+#ifndef __ANDROID__
+  // temporarily change locale to C. It should already be C, but just for safety
+  const char* old_locale = setlocale(LC_CTYPE, "C");
+  ASSERT_TRUE(old_locale != nullptr);
+#endif
+
+  for (int i = 0; i < 256; i++) {
+    if (absl::ascii_islower(i))
+      EXPECT_EQ(absl::ascii_toupper(i), 'A' + (i - 'a')) << i;
+    else
+      EXPECT_EQ(absl::ascii_toupper(i), static_cast<char>(i)) << i;
+
+    if (absl::ascii_isupper(i))
+      EXPECT_EQ(absl::ascii_tolower(i), 'a' + (i - 'A')) << i;
+    else
+      EXPECT_EQ(absl::ascii_tolower(i), static_cast<char>(i)) << i;
+
+    // These CHECKs only hold in a C locale.
+    EXPECT_EQ(static_cast<char>(tolower(i)), absl::ascii_tolower(i)) << i;
+    EXPECT_EQ(static_cast<char>(toupper(i)), absl::ascii_toupper(i)) << i;
+
+    // The official to* functions don't accept negative signed chars, but
+    // our absl::ascii_to* functions do.
+    signed char sc = static_cast<signed char>(static_cast<unsigned char>(i));
+    EXPECT_EQ(absl::ascii_tolower(i), absl::ascii_tolower(sc)) << i;
+    EXPECT_EQ(absl::ascii_toupper(i), absl::ascii_toupper(sc)) << i;
+  }
+#ifndef __ANDROID__
+  // restore the old locale.
+  ASSERT_TRUE(setlocale(LC_CTYPE, old_locale));
+#endif
+}
+
+TEST(AsciiStrTo, Lower) {
+  const char buf[] = "ABCDEF";
+  const std::string str("GHIJKL");
+  const std::string str2("MNOPQR");
+  const absl::string_view sp(str2);
+
+  EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
+  EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
+  EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
+
+  char mutable_buf[] = "Mutable";
+  std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
+                 mutable_buf, absl::ascii_tolower);
+  EXPECT_STREQ("mutable", mutable_buf);
+}
+
+TEST(AsciiStrTo, Upper) {
+  const char buf[] = "abcdef";
+  const std::string str("ghijkl");
+  const std::string str2("mnopqr");
+  const absl::string_view sp(str2);
+
+  EXPECT_EQ("ABCDEF", absl::AsciiStrToUpper(buf));
+  EXPECT_EQ("GHIJKL", absl::AsciiStrToUpper(str));
+  EXPECT_EQ("MNOPQR", absl::AsciiStrToUpper(sp));
+
+  char mutable_buf[] = "Mutable";
+  std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
+                 mutable_buf, absl::ascii_toupper);
+  EXPECT_STREQ("MUTABLE", mutable_buf);
+}
+
+TEST(StripLeadingAsciiWhitespace, FromStringView) {
+  EXPECT_EQ(absl::string_view{},
+            absl::StripLeadingAsciiWhitespace(absl::string_view{}));
+  EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"foo"}));
+  EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"\t  \n\f\r\n\vfoo"}));
+  EXPECT_EQ("foo foo\n ",
+            absl::StripLeadingAsciiWhitespace({"\t  \n\f\r\n\vfoo foo\n "}));
+  EXPECT_EQ(absl::string_view{}, absl::StripLeadingAsciiWhitespace(
+                                     {"\t  \n\f\r\v\n\t  \n\f\r\v\n"}));
+}
+
+TEST(StripLeadingAsciiWhitespace, InPlace) {
+  std::string str;
+
+  absl::StripLeadingAsciiWhitespace(&str);
+  EXPECT_EQ("", str);
+
+  str = "foo";
+  absl::StripLeadingAsciiWhitespace(&str);
+  EXPECT_EQ("foo", str);
+
+  str = "\t  \n\f\r\n\vfoo";
+  absl::StripLeadingAsciiWhitespace(&str);
+  EXPECT_EQ("foo", str);
+
+  str = "\t  \n\f\r\n\vfoo foo\n ";
+  absl::StripLeadingAsciiWhitespace(&str);
+  EXPECT_EQ("foo foo\n ", str);
+
+  str = "\t  \n\f\r\v\n\t  \n\f\r\v\n";
+  absl::StripLeadingAsciiWhitespace(&str);
+  EXPECT_EQ(absl::string_view{}, str);
+}
+
+TEST(StripTrailingAsciiWhitespace, FromStringView) {
+  EXPECT_EQ(absl::string_view{},
+            absl::StripTrailingAsciiWhitespace(absl::string_view{}));
+  EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo"}));
+  EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo\t  \n\f\r\n\v"}));
+  EXPECT_EQ(" \nfoo foo",
+            absl::StripTrailingAsciiWhitespace({" \nfoo foo\t  \n\f\r\n\v"}));
+  EXPECT_EQ(absl::string_view{}, absl::StripTrailingAsciiWhitespace(
+                                     {"\t  \n\f\r\v\n\t  \n\f\r\v\n"}));
+}
+
+TEST(StripTrailingAsciiWhitespace, InPlace) {
+  std::string str;
+
+  absl::StripTrailingAsciiWhitespace(&str);
+  EXPECT_EQ("", str);
+
+  str = "foo";
+  absl::StripTrailingAsciiWhitespace(&str);
+  EXPECT_EQ("foo", str);
+
+  str = "foo\t  \n\f\r\n\v";
+  absl::StripTrailingAsciiWhitespace(&str);
+  EXPECT_EQ("foo", str);
+
+  str = " \nfoo foo\t  \n\f\r\n\v";
+  absl::StripTrailingAsciiWhitespace(&str);
+  EXPECT_EQ(" \nfoo foo", str);
+
+  str = "\t  \n\f\r\v\n\t  \n\f\r\v\n";
+  absl::StripTrailingAsciiWhitespace(&str);
+  EXPECT_EQ(absl::string_view{}, str);
+}
+
+TEST(StripAsciiWhitespace, FromStringView) {
+  EXPECT_EQ(absl::string_view{},
+            absl::StripAsciiWhitespace(absl::string_view{}));
+  EXPECT_EQ("foo", absl::StripAsciiWhitespace({"foo"}));
+  EXPECT_EQ("foo",
+            absl::StripAsciiWhitespace({"\t  \n\f\r\n\vfoo\t  \n\f\r\n\v"}));
+  EXPECT_EQ("foo foo", absl::StripAsciiWhitespace(
+                           {"\t  \n\f\r\n\vfoo foo\t  \n\f\r\n\v"}));
+  EXPECT_EQ(absl::string_view{},
+            absl::StripAsciiWhitespace({"\t  \n\f\r\v\n\t  \n\f\r\v\n"}));
+}
+
+TEST(StripAsciiWhitespace, InPlace) {
+  std::string str;
+
+  absl::StripAsciiWhitespace(&str);
+  EXPECT_EQ("", str);
+
+  str = "foo";
+  absl::StripAsciiWhitespace(&str);
+  EXPECT_EQ("foo", str);
+
+  str = "\t  \n\f\r\n\vfoo\t  \n\f\r\n\v";
+  absl::StripAsciiWhitespace(&str);
+  EXPECT_EQ("foo", str);
+
+  str = "\t  \n\f\r\n\vfoo foo\t  \n\f\r\n\v";
+  absl::StripAsciiWhitespace(&str);
+  EXPECT_EQ("foo foo", str);
+
+  str = "\t  \n\f\r\v\n\t  \n\f\r\v\n";
+  absl::StripAsciiWhitespace(&str);
+  EXPECT_EQ(absl::string_view{}, str);
+}
+
+TEST(RemoveExtraAsciiWhitespace, InPlace) {
+  const char* inputs[] = {"No extra space",
+                          "  Leading whitespace",
+                          "Trailing whitespace  ",
+                          "  Leading and trailing  ",
+                          " Whitespace \t  in\v   middle  ",
+                          "'Eeeeep!  \n Newlines!\n",
+                          "nospaces",
+                          "",
+                          "\n\t a\t\n\nb \t\n"};
+
+  const char* outputs[] = {
+      "No extra space",
+      "Leading whitespace",
+      "Trailing whitespace",
+      "Leading and trailing",
+      "Whitespace in middle",
+      "'Eeeeep! Newlines!",
+      "nospaces",
+      "",
+      "a\nb",
+  };
+  const int NUM_TESTS = ABSL_ARRAYSIZE(inputs);
+
+  for (int i = 0; i < NUM_TESTS; i++) {
+    std::string s(inputs[i]);
+    absl::RemoveExtraAsciiWhitespace(&s);
+    EXPECT_EQ(outputs[i], s);
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc
new file mode 100644
index 0000000..08c3947
--- /dev/null
+++ b/absl/strings/charconv.cc
@@ -0,0 +1,982 @@
+// Copyright 2018 The Abseil 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 "absl/strings/charconv.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstring>
+
+#include "absl/base/casts.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/internal/bits.h"
+#include "absl/strings/internal/charconv_bigint.h"
+#include "absl/strings/internal/charconv_parse.h"
+
+// The macro ABSL_BIT_PACK_FLOATS is defined on x86-64, where IEEE floating
+// point numbers have the same endianness in memory as a bitfield struct
+// containing the corresponding parts.
+//
+// When set, we replace calls to ldexp() with manual bit packing, which is
+// faster and is unaffected by floating point environment.
+#ifdef ABSL_BIT_PACK_FLOATS
+#error ABSL_BIT_PACK_FLOATS cannot be directly set
+#elif defined(__x86_64__) || defined(_M_X64)
+#define ABSL_BIT_PACK_FLOATS 1
+#endif
+
+// A note about subnormals:
+//
+// The code below talks about "normals" and "subnormals".  A normal IEEE float
+// has a fixed-width mantissa and power of two exponent.  For example, a normal
+// `double` has a 53-bit mantissa.  Because the high bit is always 1, it is not
+// stored in the representation.  The implicit bit buys an extra bit of
+// resolution in the datatype.
+//
+// The downside of this scheme is that there is a large gap between DBL_MIN and
+// zero.  (Large, at least, relative to the different between DBL_MIN and the
+// next representable number).  This gap is softened by the "subnormal" numbers,
+// which have the same power-of-two exponent as DBL_MIN, but no implicit 53rd
+// bit.  An all-bits-zero exponent in the encoding represents subnormals.  (Zero
+// is represented as a subnormal with an all-bits-zero mantissa.)
+//
+// The code below, in calculations, represents the mantissa as a uint64_t.  The
+// end result normally has the 53rd bit set.  It represents subnormals by using
+// narrower mantissas.
+
+namespace absl {
+namespace {
+
+template <typename FloatType>
+struct FloatTraits;
+
+template <>
+struct FloatTraits<double> {
+  // The number of mantissa bits in the given float type.  This includes the
+  // implied high bit.
+  static constexpr int kTargetMantissaBits = 53;
+
+  // The largest supported IEEE exponent, in our integral mantissa
+  // representation.
+  //
+  // If `m` is the largest possible int kTargetMantissaBits bits wide, then
+  // m * 2**kMaxExponent is exactly equal to DBL_MAX.
+  static constexpr int kMaxExponent = 971;
+
+  // The smallest supported IEEE normal exponent, in our integral mantissa
+  // representation.
+  //
+  // If `m` is the smallest possible int kTargetMantissaBits bits wide, then
+  // m * 2**kMinNormalExponent is exactly equal to DBL_MIN.
+  static constexpr int kMinNormalExponent = -1074;
+
+  static double MakeNan(const char* tagp) {
+    // Support nan no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return nan(tagp);
+  }
+
+  // Builds a nonzero floating point number out of the provided parts.
+  //
+  // This is intended to do the same operation as ldexp(mantissa, exponent),
+  // but using purely integer math, to avoid -ffastmath and floating
+  // point environment issues.  Using type punning is also faster. We fall back
+  // to ldexp on a per-platform basis for portability.
+  //
+  // `exponent` must be between kMinNormalExponent and kMaxExponent.
+  //
+  // `mantissa` must either be exactly kTargetMantissaBits wide, in which case
+  // a normal value is made, or it must be less narrow than that, in which case
+  // `exponent` must be exactly kMinNormalExponent, and a subnormal value is
+  // made.
+  static double Make(uint64_t mantissa, int exponent, bool sign) {
+#ifndef ABSL_BIT_PACK_FLOATS
+    // Support ldexp no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return sign ? -ldexp(mantissa, exponent) : ldexp(mantissa, exponent);
+#else
+    constexpr uint64_t kMantissaMask =
+        (uint64_t(1) << (kTargetMantissaBits - 1)) - 1;
+    uint64_t dbl = static_cast<uint64_t>(sign) << 63;
+    if (mantissa > kMantissaMask) {
+      // Normal value.
+      // Adjust by 1023 for the exponent representation bias, and an additional
+      // 52 due to the implied decimal point in the IEEE mantissa represenation.
+      dbl += uint64_t{exponent + 1023u + kTargetMantissaBits - 1} << 52;
+      mantissa &= kMantissaMask;
+    } else {
+      // subnormal value
+      assert(exponent == kMinNormalExponent);
+    }
+    dbl += mantissa;
+    return absl::bit_cast<double>(dbl);
+#endif  // ABSL_BIT_PACK_FLOATS
+  }
+};
+
+// Specialization of floating point traits for the `float` type.  See the
+// FloatTraits<double> specialization above for meaning of each of the following
+// members and methods.
+template <>
+struct FloatTraits<float> {
+  static constexpr int kTargetMantissaBits = 24;
+  static constexpr int kMaxExponent = 104;
+  static constexpr int kMinNormalExponent = -149;
+  static float MakeNan(const char* tagp) {
+    // Support nanf no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return nanf(tagp);
+  }
+  static float Make(uint32_t mantissa, int exponent, bool sign) {
+#ifndef ABSL_BIT_PACK_FLOATS
+    // Support ldexpf no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return sign ? -ldexpf(mantissa, exponent) : ldexpf(mantissa, exponent);
+#else
+    constexpr uint32_t kMantissaMask =
+        (uint32_t(1) << (kTargetMantissaBits - 1)) - 1;
+    uint32_t flt = static_cast<uint32_t>(sign) << 31;
+    if (mantissa > kMantissaMask) {
+      // Normal value.
+      // Adjust by 127 for the exponent representation bias, and an additional
+      // 23 due to the implied decimal point in the IEEE mantissa represenation.
+      flt += uint32_t{exponent + 127u + kTargetMantissaBits - 1} << 23;
+      mantissa &= kMantissaMask;
+    } else {
+      // subnormal value
+      assert(exponent == kMinNormalExponent);
+    }
+    flt += mantissa;
+    return absl::bit_cast<float>(flt);
+#endif  // ABSL_BIT_PACK_FLOATS
+  }
+};
+
+// Decimal-to-binary conversions require coercing powers of 10 into a mantissa
+// and a power of 2.  The two helper functions Power10Mantissa(n) and
+// Power10Exponent(n) perform this task.  Together, these represent a hand-
+// rolled floating point value which is equal to or just less than 10**n.
+//
+// The return values satisfy two range guarantees:
+//
+//   Power10Mantissa(n) * 2**Power10Exponent(n) <= 10**n
+//     < (Power10Mantissa(n) + 1) * 2**Power10Exponent(n)
+//
+//   2**63 <= Power10Mantissa(n) < 2**64.
+//
+// Lookups into the power-of-10 table must first check the Power10Overflow() and
+// Power10Underflow() functions, to avoid out-of-bounds table access.
+//
+// Indexes into these tables are biased by -kPower10TableMin, and the table has
+// values in the range [kPower10TableMin, kPower10TableMax].
+extern const uint64_t kPower10MantissaTable[];
+extern const int16_t kPower10ExponentTable[];
+
+// The smallest allowed value for use with the Power10Mantissa() and
+// Power10Exponent() functions below.  (If a smaller exponent is needed in
+// calculations, the end result is guaranteed to underflow.)
+constexpr int kPower10TableMin = -342;
+
+// The largest allowed value for use with the Power10Mantissa() and
+// Power10Exponent() functions below.  (If a smaller exponent is needed in
+// calculations, the end result is guaranteed to overflow.)
+constexpr int kPower10TableMax = 308;
+
+uint64_t Power10Mantissa(int n) {
+  return kPower10MantissaTable[n - kPower10TableMin];
+}
+
+int Power10Exponent(int n) {
+  return kPower10ExponentTable[n - kPower10TableMin];
+}
+
+// Returns true if n is large enough that 10**n always results in an IEEE
+// overflow.
+bool Power10Overflow(int n) { return n > kPower10TableMax; }
+
+// Returns true if n is small enough that 10**n times a ParsedFloat mantissa
+// always results in an IEEE underflow.
+bool Power10Underflow(int n) { return n < kPower10TableMin; }
+
+// Returns true if Power10Mantissa(n) * 2**Power10Exponent(n) is exactly equal
+// to 10**n numerically.  Put another way, this returns true if there is no
+// truncation error in Power10Mantissa(n).
+bool Power10Exact(int n) { return n >= 0 && n <= 27; }
+
+// Sentinel exponent values for representing numbers too large or too close to
+// zero to represent in a double.
+constexpr int kOverflow = 99999;
+constexpr int kUnderflow = -99999;
+
+// Struct representing the calculated conversion result of a positive (nonzero)
+// floating point number.
+//
+// The calculated number is mantissa * 2**exponent (mantissa is treated as an
+// integer.)  `mantissa` is chosen to be the correct width for the IEEE float
+// representation being calculated.  (`mantissa` will always have the same bit
+// width for normal values, and narrower bit widths for subnormals.)
+//
+// If the result of conversion was an underflow or overflow, exponent is set
+// to kUnderflow or kOverflow.
+struct CalculatedFloat {
+  uint64_t mantissa = 0;
+  int exponent = 0;
+};
+
+// Returns the bit width of the given uint128.  (Equivalently, returns 128
+// minus the number of leading zero bits.)
+int BitWidth(uint128 value) {
+  if (Uint128High64(value) == 0) {
+    return 64 - strings_internal::CountLeadingZeros64(Uint128Low64(value));
+  }
+  return 128 - strings_internal::CountLeadingZeros64(Uint128High64(value));
+}
+
+// Calculates how far to the right a mantissa needs to be shifted to create a
+// properly adjusted mantissa for an IEEE floating point number.
+//
+// `mantissa_width` is the bit width of the mantissa to be shifted, and
+// `binary_exponent` is the exponent of the number before the shift.
+//
+// This accounts for subnormal values, and will return a larger-than-normal
+// shift if binary_exponent would otherwise be too low.
+template <typename FloatType>
+int NormalizedShiftSize(int mantissa_width, int binary_exponent) {
+  const int normal_shift =
+      mantissa_width - FloatTraits<FloatType>::kTargetMantissaBits;
+  const int minimum_shift =
+      FloatTraits<FloatType>::kMinNormalExponent - binary_exponent;
+  return std::max(normal_shift, minimum_shift);
+}
+
+// Right shifts a uint128 so that it has the requested bit width.  (The
+// resulting value will have 128 - bit_width leading zeroes.)  The initial
+// `value` must be wider than the requested bit width.
+//
+// Returns the number of bits shifted.
+int TruncateToBitWidth(int bit_width, uint128* value) {
+  const int current_bit_width = BitWidth(*value);
+  const int shift = current_bit_width - bit_width;
+  *value >>= shift;
+  return shift;
+}
+
+// Checks if the given ParsedFloat represents one of the edge cases that are
+// not dependent on number base: zero, infinity, or NaN.  If so, sets *value
+// the appropriate double, and returns true.
+template <typename FloatType>
+bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative,
+                    FloatType* value) {
+  if (input.type == strings_internal::FloatType::kNan) {
+    // A bug in both clang and gcc would cause the compiler to optimize away the
+    // buffer we are building below.  Declaring the buffer volatile avoids the
+    // issue, and has no measurable performance impact in microbenchmarks.
+    //
+    // https://bugs.llvm.org/show_bug.cgi?id=37778
+    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113
+    constexpr ptrdiff_t kNanBufferSize = 128;
+    volatile char n_char_sequence[kNanBufferSize];
+    if (input.subrange_begin == nullptr) {
+      n_char_sequence[0] = '\0';
+    } else {
+      ptrdiff_t nan_size = input.subrange_end - input.subrange_begin;
+      nan_size = std::min(nan_size, kNanBufferSize - 1);
+      std::copy_n(input.subrange_begin, nan_size, n_char_sequence);
+      n_char_sequence[nan_size] = '\0';
+    }
+    char* nan_argument = const_cast<char*>(n_char_sequence);
+    *value = negative ? -FloatTraits<FloatType>::MakeNan(nan_argument)
+                      : FloatTraits<FloatType>::MakeNan(nan_argument);
+    return true;
+  }
+  if (input.type == strings_internal::FloatType::kInfinity) {
+    *value = negative ? -std::numeric_limits<FloatType>::infinity()
+                      : std::numeric_limits<FloatType>::infinity();
+    return true;
+  }
+  if (input.mantissa == 0) {
+    *value = negative ? -0.0 : 0.0;
+    return true;
+  }
+  return false;
+}
+
+// Given a CalculatedFloat result of a from_chars conversion, generate the
+// correct output values.
+//
+// CalculatedFloat can represent an underflow or overflow, in which case the
+// error code in *result is set.  Otherwise, the calculated floating point
+// number is stored in *value.
+template <typename FloatType>
+void EncodeResult(const CalculatedFloat& calculated, bool negative,
+                  absl::from_chars_result* result, FloatType* value) {
+  if (calculated.exponent == kOverflow) {
+    result->ec = std::errc::result_out_of_range;
+    *value = negative ? -std::numeric_limits<FloatType>::max()
+                      : std::numeric_limits<FloatType>::max();
+    return;
+  } else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) {
+    result->ec = std::errc::result_out_of_range;
+    *value = negative ? -0.0 : 0.0;
+    return;
+  }
+  *value = FloatTraits<FloatType>::Make(calculated.mantissa,
+                                        calculated.exponent, negative);
+}
+
+// Returns the given uint128 shifted to the right by `shift` bits, and rounds
+// the remaining bits using round_to_nearest logic.  The value is returned as a
+// uint64_t, since this is the type used by this library for storing calculated
+// floating point mantissas.
+//
+// It is expected that the width of the input value shifted by `shift` will
+// be the correct bit-width for the target mantissa, which is strictly narrower
+// than a uint64_t.
+//
+// If `input_exact` is false, then a nonzero error epsilon is assumed.  For
+// rounding purposes, the true value being rounded is strictly greater than the
+// input value.  The error may represent a single lost carry bit.
+//
+// When input_exact, shifted bits of the form 1000000... represent a tie, which
+// is broken by rounding to even -- the rounding direction is chosen so the low
+// bit of the returned value is 0.
+//
+// When !input_exact, shifted bits of the form 10000000... represent a value
+// strictly greater than one half (due to the error epsilon), and so ties are
+// always broken by rounding up.
+//
+// When !input_exact, shifted bits of the form 01111111... are uncertain;
+// the true value may or may not be greater than 10000000..., due to the
+// possible lost carry bit.  The correct rounding direction is unknown.  In this
+// case, the result is rounded down, and `output_exact` is set to false.
+//
+// Zero and negative values of `shift` are accepted, in which case the word is
+// shifted left, as necessary.
+uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact,
+                            bool* output_exact) {
+  if (shift <= 0) {
+    *output_exact = input_exact;
+    return static_cast<uint64_t>(value << -shift);
+  }
+  if (shift >= 128) {
+    // Exponent is so small that we are shifting away all significant bits.
+    // Answer will not be representable, even as a subnormal, so return a zero
+    // mantissa (which represents underflow).
+    *output_exact = true;
+    return 0;
+  }
+
+  *output_exact = true;
+  const uint128 shift_mask = (uint128(1) << shift) - 1;
+  const uint128 halfway_point = uint128(1) << (shift - 1);
+
+  const uint128 shifted_bits = value & shift_mask;
+  value >>= shift;
+  if (shifted_bits > halfway_point) {
+    // Shifted bits greater than 10000... require rounding up.
+    return static_cast<uint64_t>(value + 1);
+  }
+  if (shifted_bits == halfway_point) {
+    // In exact mode, shifted bits of 10000... mean we're exactly halfway
+    // between two numbers, and we must round to even.  So only round up if
+    // the low bit of `value` is set.
+    //
+    // In inexact mode, the nonzero error means the actual value is greater
+    // than the halfway point and we must alway round up.
+    if ((value & 1) == 1 || !input_exact) {
+      ++value;
+    }
+    return static_cast<uint64_t>(value);
+  }
+  if (!input_exact && shifted_bits == halfway_point - 1) {
+    // Rounding direction is unclear, due to error.
+    *output_exact = false;
+  }
+  // Otherwise, round down.
+  return static_cast<uint64_t>(value);
+}
+
+// Checks if a floating point guess needs to be rounded up, using high precision
+// math.
+//
+// `guess_mantissa` and `guess_exponent` represent a candidate guess for the
+// number represented by `parsed_decimal`.
+//
+// The exact number represented by `parsed_decimal` must lie between the two
+// numbers:
+//   A = `guess_mantissa * 2**guess_exponent`
+//   B = `(guess_mantissa + 1) * 2**guess_exponent`
+//
+// This function returns false if `A` is the better guess, and true if `B` is
+// the better guess, with rounding ties broken by rounding to even.
+bool MustRoundUp(uint64_t guess_mantissa, int guess_exponent,
+                 const strings_internal::ParsedFloat& parsed_decimal) {
+  // 768 is the number of digits needed in the worst case.  We could determine a
+  // better limit dynamically based on the value of parsed_decimal.exponent.
+  // This would optimize pathological input cases only.  (Sane inputs won't have
+  // hundreds of digits of mantissa.)
+  absl::strings_internal::BigUnsigned<84> exact_mantissa;
+  int exact_exponent = exact_mantissa.ReadFloatMantissa(parsed_decimal, 768);
+
+  // Adjust the `guess` arguments to be halfway between A and B.
+  guess_mantissa = guess_mantissa * 2 + 1;
+  guess_exponent -= 1;
+
+  // In our comparison:
+  // lhs = exact = exact_mantissa * 10**exact_exponent
+  //             = exact_mantissa * 5**exact_exponent * 2**exact_exponent
+  // rhs = guess = guess_mantissa * 2**guess_exponent
+  //
+  // Because we are doing integer math, we can't directly deal with negative
+  // exponents.  We instead move these to the other side of the inequality.
+  absl::strings_internal::BigUnsigned<84>& lhs = exact_mantissa;
+  int comparison;
+  if (exact_exponent >= 0) {
+    lhs.MultiplyByFiveToTheNth(exact_exponent);
+    absl::strings_internal::BigUnsigned<84> rhs(guess_mantissa);
+    // There are powers of 2 on both sides of the inequality; reduce this to
+    // a single bit-shift.
+    if (exact_exponent > guess_exponent) {
+      lhs.ShiftLeft(exact_exponent - guess_exponent);
+    } else {
+      rhs.ShiftLeft(guess_exponent - exact_exponent);
+    }
+    comparison = Compare(lhs, rhs);
+  } else {
+    // Move the power of 5 to the other side of the equation, giving us:
+    // lhs = exact_mantissa * 2**exact_exponent
+    // rhs = guess_mantissa * 5**(-exact_exponent) * 2**guess_exponent
+    absl::strings_internal::BigUnsigned<84> rhs =
+        absl::strings_internal::BigUnsigned<84>::FiveToTheNth(-exact_exponent);
+    rhs.MultiplyBy(guess_mantissa);
+    if (exact_exponent > guess_exponent) {
+      lhs.ShiftLeft(exact_exponent - guess_exponent);
+    } else {
+      rhs.ShiftLeft(guess_exponent - exact_exponent);
+    }
+    comparison = Compare(lhs, rhs);
+  }
+  if (comparison < 0) {
+    return false;
+  } else if (comparison > 0) {
+    return true;
+  } else {
+    // When lhs == rhs, the decimal input is exactly between A and B.
+    // Round towards even -- round up only if the low bit of the initial
+    // `guess_mantissa` was a 1.  We shifted guess_mantissa left 1 bit at
+    // the beginning of this function, so test the 2nd bit here.
+    return (guess_mantissa & 2) == 2;
+  }
+}
+
+// Constructs a CalculatedFloat from a given mantissa and exponent, but
+// with the following normalizations applied:
+//
+// If rounding has caused mantissa to increase just past the allowed bit
+// width, shift and adjust exponent.
+//
+// If exponent is too high, sets kOverflow.
+//
+// If mantissa is zero (representing a non-zero value not representable, even
+// as a subnormal), sets kUnderflow.
+template <typename FloatType>
+CalculatedFloat CalculatedFloatFromRawValues(uint64_t mantissa, int exponent) {
+  CalculatedFloat result;
+  if (mantissa == uint64_t(1) << FloatTraits<FloatType>::kTargetMantissaBits) {
+    mantissa >>= 1;
+    exponent += 1;
+  }
+  if (exponent > FloatTraits<FloatType>::kMaxExponent) {
+    result.exponent = kOverflow;
+  } else if (mantissa == 0) {
+    result.exponent = kUnderflow;
+  } else {
+    result.exponent = exponent;
+    result.mantissa = mantissa;
+  }
+  return result;
+}
+
+template <typename FloatType>
+CalculatedFloat CalculateFromParsedHexadecimal(
+    const strings_internal::ParsedFloat& parsed_hex) {
+  uint64_t mantissa = parsed_hex.mantissa;
+  int exponent = parsed_hex.exponent;
+  int mantissa_width = 64 - strings_internal::CountLeadingZeros64(mantissa);
+  const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent);
+  bool result_exact;
+  exponent += shift;
+  mantissa = ShiftRightAndRound(mantissa, shift,
+                                /* input exact= */ true, &result_exact);
+  // ParseFloat handles rounding in the hexadecimal case, so we don't have to
+  // check `result_exact` here.
+  return CalculatedFloatFromRawValues<FloatType>(mantissa, exponent);
+}
+
+template <typename FloatType>
+CalculatedFloat CalculateFromParsedDecimal(
+    const strings_internal::ParsedFloat& parsed_decimal) {
+  CalculatedFloat result;
+
+  // Large or small enough decimal exponents will always result in overflow
+  // or underflow.
+  if (Power10Underflow(parsed_decimal.exponent)) {
+    result.exponent = kUnderflow;
+    return result;
+  } else if (Power10Overflow(parsed_decimal.exponent)) {
+    result.exponent = kOverflow;
+    return result;
+  }
+
+  // Otherwise convert our power of 10 into a power of 2 times an integer
+  // mantissa, and multiply this by our parsed decimal mantissa.
+  uint128 wide_binary_mantissa = parsed_decimal.mantissa;
+  wide_binary_mantissa *= Power10Mantissa(parsed_decimal.exponent);
+  int binary_exponent = Power10Exponent(parsed_decimal.exponent);
+
+  // Discard bits that are inaccurate due to truncation error.  The magic
+  // `mantissa_width` constants below are justified in charconv_algorithm.md.
+  // They represent the number of bits in `wide_binary_mantissa` that are
+  // guaranteed to be unaffected by error propagation.
+  bool mantissa_exact;
+  int mantissa_width;
+  if (parsed_decimal.subrange_begin) {
+    // Truncated mantissa
+    mantissa_width = 58;
+    mantissa_exact = false;
+    binary_exponent +=
+        TruncateToBitWidth(mantissa_width, &wide_binary_mantissa);
+  } else if (!Power10Exact(parsed_decimal.exponent)) {
+    // Exact mantissa, truncated power of ten
+    mantissa_width = 63;
+    mantissa_exact = false;
+    binary_exponent +=
+        TruncateToBitWidth(mantissa_width, &wide_binary_mantissa);
+  } else {
+    // Product is exact
+    mantissa_width = BitWidth(wide_binary_mantissa);
+    mantissa_exact = true;
+  }
+
+  // Shift into an FloatType-sized mantissa, and round to nearest.
+  const int shift =
+      NormalizedShiftSize<FloatType>(mantissa_width, binary_exponent);
+  bool result_exact;
+  binary_exponent += shift;
+  uint64_t binary_mantissa = ShiftRightAndRound(wide_binary_mantissa, shift,
+                                                mantissa_exact, &result_exact);
+  if (!result_exact) {
+    // We could not determine the rounding direction using int128 math.  Use
+    // full resolution math instead.
+    if (MustRoundUp(binary_mantissa, binary_exponent, parsed_decimal)) {
+      binary_mantissa += 1;
+    }
+  }
+
+  return CalculatedFloatFromRawValues<FloatType>(binary_mantissa,
+                                                 binary_exponent);
+}
+
+template <typename FloatType>
+from_chars_result FromCharsImpl(const char* first, const char* last,
+                                FloatType& value, chars_format fmt_flags) {
+  from_chars_result result;
+  result.ptr = first;  // overwritten on successful parse
+  result.ec = std::errc();
+
+  bool negative = false;
+  if (first != last && *first == '-') {
+    ++first;
+    negative = true;
+  }
+  // If the `hex` flag is *not* set, then we will accept a 0x prefix and try
+  // to parse a hexadecimal float.
+  if ((fmt_flags & chars_format::hex) == chars_format{} && last - first >= 2 &&
+      *first == '0' && (first[1] == 'x' || first[1] == 'X')) {
+    const char* hex_first = first + 2;
+    strings_internal::ParsedFloat hex_parse =
+        strings_internal::ParseFloat<16>(hex_first, last, fmt_flags);
+    if (hex_parse.end == nullptr ||
+        hex_parse.type != strings_internal::FloatType::kNumber) {
+      // Either we failed to parse a hex float after the "0x", or we read
+      // "0xinf" or "0xnan" which we don't want to match.
+      //
+      // However, a std::string that begins with "0x" also begins with "0", which
+      // is normally a valid match for the number zero.  So we want these
+      // strings to match zero unless fmt_flags is `scientific`.  (This flag
+      // means an exponent is required, which the std::string "0" does not have.)
+      if (fmt_flags == chars_format::scientific) {
+        result.ec = std::errc::invalid_argument;
+      } else {
+        result.ptr = first + 1;
+        value = negative ? -0.0 : 0.0;
+      }
+      return result;
+    }
+    // We matched a value.
+    result.ptr = hex_parse.end;
+    if (HandleEdgeCase(hex_parse, negative, &value)) {
+      return result;
+    }
+    CalculatedFloat calculated =
+        CalculateFromParsedHexadecimal<FloatType>(hex_parse);
+    EncodeResult(calculated, negative, &result, &value);
+    return result;
+  }
+  // Otherwise, we choose the number base based on the flags.
+  if ((fmt_flags & chars_format::hex) == chars_format::hex) {
+    strings_internal::ParsedFloat hex_parse =
+        strings_internal::ParseFloat<16>(first, last, fmt_flags);
+    if (hex_parse.end == nullptr) {
+      result.ec = std::errc::invalid_argument;
+      return result;
+    }
+    result.ptr = hex_parse.end;
+    if (HandleEdgeCase(hex_parse, negative, &value)) {
+      return result;
+    }
+    CalculatedFloat calculated =
+        CalculateFromParsedHexadecimal<FloatType>(hex_parse);
+    EncodeResult(calculated, negative, &result, &value);
+    return result;
+  } else {
+    strings_internal::ParsedFloat decimal_parse =
+        strings_internal::ParseFloat<10>(first, last, fmt_flags);
+    if (decimal_parse.end == nullptr) {
+      result.ec = std::errc::invalid_argument;
+      return result;
+    }
+    result.ptr = decimal_parse.end;
+    if (HandleEdgeCase(decimal_parse, negative, &value)) {
+      return result;
+    }
+    CalculatedFloat calculated =
+        CalculateFromParsedDecimal<FloatType>(decimal_parse);
+    EncodeResult(calculated, negative, &result, &value);
+    return result;
+  }
+  return result;
+}
+}  // namespace
+
+from_chars_result from_chars(const char* first, const char* last, double& value,
+                             chars_format fmt) {
+  return FromCharsImpl(first, last, value, fmt);
+}
+
+from_chars_result from_chars(const char* first, const char* last, float& value,
+                             chars_format fmt) {
+  return FromCharsImpl(first, last, value, fmt);
+}
+
+namespace {
+
+// Table of powers of 10, from kPower10TableMin to kPower10TableMax.
+//
+// kPower10MantissaTable[i - kPower10TableMin] stores the 64-bit mantissa (high
+// bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores the
+// power-of-two exponent.  For a given number i, this gives the unique mantissa
+// and exponent such that mantissa * 2**exponent <= 10**i < (mantissa + 1) *
+// 2**exponent.
+
+const uint64_t kPower10MantissaTable[] = {
+    0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U,
+    0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U,
+    0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU,
+    0xde8b2b66b3bc4723U, 0x8b16fb203055ac76U, 0xaddcb9e83c6b1793U,
+    0xd953e8624b85dd78U, 0x87d4713d6f33aa6bU, 0xa9c98d8ccb009506U,
+    0xd43bf0effdc0ba48U, 0x84a57695fe98746dU, 0xa5ced43b7e3e9188U,
+    0xcf42894a5dce35eaU, 0x818995ce7aa0e1b2U, 0xa1ebfb4219491a1fU,
+    0xca66fa129f9b60a6U, 0xfd00b897478238d0U, 0x9e20735e8cb16382U,
+    0xc5a890362fddbc62U, 0xf712b443bbd52b7bU, 0x9a6bb0aa55653b2dU,
+    0xc1069cd4eabe89f8U, 0xf148440a256e2c76U, 0x96cd2a865764dbcaU,
+    0xbc807527ed3e12bcU, 0xeba09271e88d976bU, 0x93445b8731587ea3U,
+    0xb8157268fdae9e4cU, 0xe61acf033d1a45dfU, 0x8fd0c16206306babU,
+    0xb3c4f1ba87bc8696U, 0xe0b62e2929aba83cU, 0x8c71dcd9ba0b4925U,
+    0xaf8e5410288e1b6fU, 0xdb71e91432b1a24aU, 0x892731ac9faf056eU,
+    0xab70fe17c79ac6caU, 0xd64d3d9db981787dU, 0x85f0468293f0eb4eU,
+    0xa76c582338ed2621U, 0xd1476e2c07286faaU, 0x82cca4db847945caU,
+    0xa37fce126597973cU, 0xcc5fc196fefd7d0cU, 0xff77b1fcbebcdc4fU,
+    0x9faacf3df73609b1U, 0xc795830d75038c1dU, 0xf97ae3d0d2446f25U,
+    0x9becce62836ac577U, 0xc2e801fb244576d5U, 0xf3a20279ed56d48aU,
+    0x9845418c345644d6U, 0xbe5691ef416bd60cU, 0xedec366b11c6cb8fU,
+    0x94b3a202eb1c3f39U, 0xb9e08a83a5e34f07U, 0xe858ad248f5c22c9U,
+    0x91376c36d99995beU, 0xb58547448ffffb2dU, 0xe2e69915b3fff9f9U,
+    0x8dd01fad907ffc3bU, 0xb1442798f49ffb4aU, 0xdd95317f31c7fa1dU,
+    0x8a7d3eef7f1cfc52U, 0xad1c8eab5ee43b66U, 0xd863b256369d4a40U,
+    0x873e4f75e2224e68U, 0xa90de3535aaae202U, 0xd3515c2831559a83U,
+    0x8412d9991ed58091U, 0xa5178fff668ae0b6U, 0xce5d73ff402d98e3U,
+    0x80fa687f881c7f8eU, 0xa139029f6a239f72U, 0xc987434744ac874eU,
+    0xfbe9141915d7a922U, 0x9d71ac8fada6c9b5U, 0xc4ce17b399107c22U,
+    0xf6019da07f549b2bU, 0x99c102844f94e0fbU, 0xc0314325637a1939U,
+    0xf03d93eebc589f88U, 0x96267c7535b763b5U, 0xbbb01b9283253ca2U,
+    0xea9c227723ee8bcbU, 0x92a1958a7675175fU, 0xb749faed14125d36U,
+    0xe51c79a85916f484U, 0x8f31cc0937ae58d2U, 0xb2fe3f0b8599ef07U,
+    0xdfbdcece67006ac9U, 0x8bd6a141006042bdU, 0xaecc49914078536dU,
+    0xda7f5bf590966848U, 0x888f99797a5e012dU, 0xaab37fd7d8f58178U,
+    0xd5605fcdcf32e1d6U, 0x855c3be0a17fcd26U, 0xa6b34ad8c9dfc06fU,
+    0xd0601d8efc57b08bU, 0x823c12795db6ce57U, 0xa2cb1717b52481edU,
+    0xcb7ddcdda26da268U, 0xfe5d54150b090b02U, 0x9efa548d26e5a6e1U,
+    0xc6b8e9b0709f109aU, 0xf867241c8cc6d4c0U, 0x9b407691d7fc44f8U,
+    0xc21094364dfb5636U, 0xf294b943e17a2bc4U, 0x979cf3ca6cec5b5aU,
+    0xbd8430bd08277231U, 0xece53cec4a314ebdU, 0x940f4613ae5ed136U,
+    0xb913179899f68584U, 0xe757dd7ec07426e5U, 0x9096ea6f3848984fU,
+    0xb4bca50b065abe63U, 0xe1ebce4dc7f16dfbU, 0x8d3360f09cf6e4bdU,
+    0xb080392cc4349decU, 0xdca04777f541c567U, 0x89e42caaf9491b60U,
+    0xac5d37d5b79b6239U, 0xd77485cb25823ac7U, 0x86a8d39ef77164bcU,
+    0xa8530886b54dbdebU, 0xd267caa862a12d66U, 0x8380dea93da4bc60U,
+    0xa46116538d0deb78U, 0xcd795be870516656U, 0x806bd9714632dff6U,
+    0xa086cfcd97bf97f3U, 0xc8a883c0fdaf7df0U, 0xfad2a4b13d1b5d6cU,
+    0x9cc3a6eec6311a63U, 0xc3f490aa77bd60fcU, 0xf4f1b4d515acb93bU,
+    0x991711052d8bf3c5U, 0xbf5cd54678eef0b6U, 0xef340a98172aace4U,
+    0x9580869f0e7aac0eU, 0xbae0a846d2195712U, 0xe998d258869facd7U,
+    0x91ff83775423cc06U, 0xb67f6455292cbf08U, 0xe41f3d6a7377eecaU,
+    0x8e938662882af53eU, 0xb23867fb2a35b28dU, 0xdec681f9f4c31f31U,
+    0x8b3c113c38f9f37eU, 0xae0b158b4738705eU, 0xd98ddaee19068c76U,
+    0x87f8a8d4cfa417c9U, 0xa9f6d30a038d1dbcU, 0xd47487cc8470652bU,
+    0x84c8d4dfd2c63f3bU, 0xa5fb0a17c777cf09U, 0xcf79cc9db955c2ccU,
+    0x81ac1fe293d599bfU, 0xa21727db38cb002fU, 0xca9cf1d206fdc03bU,
+    0xfd442e4688bd304aU, 0x9e4a9cec15763e2eU, 0xc5dd44271ad3cdbaU,
+    0xf7549530e188c128U, 0x9a94dd3e8cf578b9U, 0xc13a148e3032d6e7U,
+    0xf18899b1bc3f8ca1U, 0x96f5600f15a7b7e5U, 0xbcb2b812db11a5deU,
+    0xebdf661791d60f56U, 0x936b9fcebb25c995U, 0xb84687c269ef3bfbU,
+    0xe65829b3046b0afaU, 0x8ff71a0fe2c2e6dcU, 0xb3f4e093db73a093U,
+    0xe0f218b8d25088b8U, 0x8c974f7383725573U, 0xafbd2350644eeacfU,
+    0xdbac6c247d62a583U, 0x894bc396ce5da772U, 0xab9eb47c81f5114fU,
+    0xd686619ba27255a2U, 0x8613fd0145877585U, 0xa798fc4196e952e7U,
+    0xd17f3b51fca3a7a0U, 0x82ef85133de648c4U, 0xa3ab66580d5fdaf5U,
+    0xcc963fee10b7d1b3U, 0xffbbcfe994e5c61fU, 0x9fd561f1fd0f9bd3U,
+    0xc7caba6e7c5382c8U, 0xf9bd690a1b68637bU, 0x9c1661a651213e2dU,
+    0xc31bfa0fe5698db8U, 0xf3e2f893dec3f126U, 0x986ddb5c6b3a76b7U,
+    0xbe89523386091465U, 0xee2ba6c0678b597fU, 0x94db483840b717efU,
+    0xba121a4650e4ddebU, 0xe896a0d7e51e1566U, 0x915e2486ef32cd60U,
+    0xb5b5ada8aaff80b8U, 0xe3231912d5bf60e6U, 0x8df5efabc5979c8fU,
+    0xb1736b96b6fd83b3U, 0xddd0467c64bce4a0U, 0x8aa22c0dbef60ee4U,
+    0xad4ab7112eb3929dU, 0xd89d64d57a607744U, 0x87625f056c7c4a8bU,
+    0xa93af6c6c79b5d2dU, 0xd389b47879823479U, 0x843610cb4bf160cbU,
+    0xa54394fe1eedb8feU, 0xce947a3da6a9273eU, 0x811ccc668829b887U,
+    0xa163ff802a3426a8U, 0xc9bcff6034c13052U, 0xfc2c3f3841f17c67U,
+    0x9d9ba7832936edc0U, 0xc5029163f384a931U, 0xf64335bcf065d37dU,
+    0x99ea0196163fa42eU, 0xc06481fb9bcf8d39U, 0xf07da27a82c37088U,
+    0x964e858c91ba2655U, 0xbbe226efb628afeaU, 0xeadab0aba3b2dbe5U,
+    0x92c8ae6b464fc96fU, 0xb77ada0617e3bbcbU, 0xe55990879ddcaabdU,
+    0x8f57fa54c2a9eab6U, 0xb32df8e9f3546564U, 0xdff9772470297ebdU,
+    0x8bfbea76c619ef36U, 0xaefae51477a06b03U, 0xdab99e59958885c4U,
+    0x88b402f7fd75539bU, 0xaae103b5fcd2a881U, 0xd59944a37c0752a2U,
+    0x857fcae62d8493a5U, 0xa6dfbd9fb8e5b88eU, 0xd097ad07a71f26b2U,
+    0x825ecc24c873782fU, 0xa2f67f2dfa90563bU, 0xcbb41ef979346bcaU,
+    0xfea126b7d78186bcU, 0x9f24b832e6b0f436U, 0xc6ede63fa05d3143U,
+    0xf8a95fcf88747d94U, 0x9b69dbe1b548ce7cU, 0xc24452da229b021bU,
+    0xf2d56790ab41c2a2U, 0x97c560ba6b0919a5U, 0xbdb6b8e905cb600fU,
+    0xed246723473e3813U, 0x9436c0760c86e30bU, 0xb94470938fa89bceU,
+    0xe7958cb87392c2c2U, 0x90bd77f3483bb9b9U, 0xb4ecd5f01a4aa828U,
+    0xe2280b6c20dd5232U, 0x8d590723948a535fU, 0xb0af48ec79ace837U,
+    0xdcdb1b2798182244U, 0x8a08f0f8bf0f156bU, 0xac8b2d36eed2dac5U,
+    0xd7adf884aa879177U, 0x86ccbb52ea94baeaU, 0xa87fea27a539e9a5U,
+    0xd29fe4b18e88640eU, 0x83a3eeeef9153e89U, 0xa48ceaaab75a8e2bU,
+    0xcdb02555653131b6U, 0x808e17555f3ebf11U, 0xa0b19d2ab70e6ed6U,
+    0xc8de047564d20a8bU, 0xfb158592be068d2eU, 0x9ced737bb6c4183dU,
+    0xc428d05aa4751e4cU, 0xf53304714d9265dfU, 0x993fe2c6d07b7fabU,
+    0xbf8fdb78849a5f96U, 0xef73d256a5c0f77cU, 0x95a8637627989aadU,
+    0xbb127c53b17ec159U, 0xe9d71b689dde71afU, 0x9226712162ab070dU,
+    0xb6b00d69bb55c8d1U, 0xe45c10c42a2b3b05U, 0x8eb98a7a9a5b04e3U,
+    0xb267ed1940f1c61cU, 0xdf01e85f912e37a3U, 0x8b61313bbabce2c6U,
+    0xae397d8aa96c1b77U, 0xd9c7dced53c72255U, 0x881cea14545c7575U,
+    0xaa242499697392d2U, 0xd4ad2dbfc3d07787U, 0x84ec3c97da624ab4U,
+    0xa6274bbdd0fadd61U, 0xcfb11ead453994baU, 0x81ceb32c4b43fcf4U,
+    0xa2425ff75e14fc31U, 0xcad2f7f5359a3b3eU, 0xfd87b5f28300ca0dU,
+    0x9e74d1b791e07e48U, 0xc612062576589ddaU, 0xf79687aed3eec551U,
+    0x9abe14cd44753b52U, 0xc16d9a0095928a27U, 0xf1c90080baf72cb1U,
+    0x971da05074da7beeU, 0xbce5086492111aeaU, 0xec1e4a7db69561a5U,
+    0x9392ee8e921d5d07U, 0xb877aa3236a4b449U, 0xe69594bec44de15bU,
+    0x901d7cf73ab0acd9U, 0xb424dc35095cd80fU, 0xe12e13424bb40e13U,
+    0x8cbccc096f5088cbU, 0xafebff0bcb24aafeU, 0xdbe6fecebdedd5beU,
+    0x89705f4136b4a597U, 0xabcc77118461cefcU, 0xd6bf94d5e57a42bcU,
+    0x8637bd05af6c69b5U, 0xa7c5ac471b478423U, 0xd1b71758e219652bU,
+    0x83126e978d4fdf3bU, 0xa3d70a3d70a3d70aU, 0xccccccccccccccccU,
+    0x8000000000000000U, 0xa000000000000000U, 0xc800000000000000U,
+    0xfa00000000000000U, 0x9c40000000000000U, 0xc350000000000000U,
+    0xf424000000000000U, 0x9896800000000000U, 0xbebc200000000000U,
+    0xee6b280000000000U, 0x9502f90000000000U, 0xba43b74000000000U,
+    0xe8d4a51000000000U, 0x9184e72a00000000U, 0xb5e620f480000000U,
+    0xe35fa931a0000000U, 0x8e1bc9bf04000000U, 0xb1a2bc2ec5000000U,
+    0xde0b6b3a76400000U, 0x8ac7230489e80000U, 0xad78ebc5ac620000U,
+    0xd8d726b7177a8000U, 0x878678326eac9000U, 0xa968163f0a57b400U,
+    0xd3c21bcecceda100U, 0x84595161401484a0U, 0xa56fa5b99019a5c8U,
+    0xcecb8f27f4200f3aU, 0x813f3978f8940984U, 0xa18f07d736b90be5U,
+    0xc9f2c9cd04674edeU, 0xfc6f7c4045812296U, 0x9dc5ada82b70b59dU,
+    0xc5371912364ce305U, 0xf684df56c3e01bc6U, 0x9a130b963a6c115cU,
+    0xc097ce7bc90715b3U, 0xf0bdc21abb48db20U, 0x96769950b50d88f4U,
+    0xbc143fa4e250eb31U, 0xeb194f8e1ae525fdU, 0x92efd1b8d0cf37beU,
+    0xb7abc627050305adU, 0xe596b7b0c643c719U, 0x8f7e32ce7bea5c6fU,
+    0xb35dbf821ae4f38bU, 0xe0352f62a19e306eU, 0x8c213d9da502de45U,
+    0xaf298d050e4395d6U, 0xdaf3f04651d47b4cU, 0x88d8762bf324cd0fU,
+    0xab0e93b6efee0053U, 0xd5d238a4abe98068U, 0x85a36366eb71f041U,
+    0xa70c3c40a64e6c51U, 0xd0cf4b50cfe20765U, 0x82818f1281ed449fU,
+    0xa321f2d7226895c7U, 0xcbea6f8ceb02bb39U, 0xfee50b7025c36a08U,
+    0x9f4f2726179a2245U, 0xc722f0ef9d80aad6U, 0xf8ebad2b84e0d58bU,
+    0x9b934c3b330c8577U, 0xc2781f49ffcfa6d5U, 0xf316271c7fc3908aU,
+    0x97edd871cfda3a56U, 0xbde94e8e43d0c8ecU, 0xed63a231d4c4fb27U,
+    0x945e455f24fb1cf8U, 0xb975d6b6ee39e436U, 0xe7d34c64a9c85d44U,
+    0x90e40fbeea1d3a4aU, 0xb51d13aea4a488ddU, 0xe264589a4dcdab14U,
+    0x8d7eb76070a08aecU, 0xb0de65388cc8ada8U, 0xdd15fe86affad912U,
+    0x8a2dbf142dfcc7abU, 0xacb92ed9397bf996U, 0xd7e77a8f87daf7fbU,
+    0x86f0ac99b4e8dafdU, 0xa8acd7c0222311bcU, 0xd2d80db02aabd62bU,
+    0x83c7088e1aab65dbU, 0xa4b8cab1a1563f52U, 0xcde6fd5e09abcf26U,
+    0x80b05e5ac60b6178U, 0xa0dc75f1778e39d6U, 0xc913936dd571c84cU,
+    0xfb5878494ace3a5fU, 0x9d174b2dcec0e47bU, 0xc45d1df942711d9aU,
+    0xf5746577930d6500U, 0x9968bf6abbe85f20U, 0xbfc2ef456ae276e8U,
+    0xefb3ab16c59b14a2U, 0x95d04aee3b80ece5U, 0xbb445da9ca61281fU,
+    0xea1575143cf97226U, 0x924d692ca61be758U, 0xb6e0c377cfa2e12eU,
+    0xe498f455c38b997aU, 0x8edf98b59a373fecU, 0xb2977ee300c50fe7U,
+    0xdf3d5e9bc0f653e1U, 0x8b865b215899f46cU, 0xae67f1e9aec07187U,
+    0xda01ee641a708de9U, 0x884134fe908658b2U, 0xaa51823e34a7eedeU,
+    0xd4e5e2cdc1d1ea96U, 0x850fadc09923329eU, 0xa6539930bf6bff45U,
+    0xcfe87f7cef46ff16U, 0x81f14fae158c5f6eU, 0xa26da3999aef7749U,
+    0xcb090c8001ab551cU, 0xfdcb4fa002162a63U, 0x9e9f11c4014dda7eU,
+    0xc646d63501a1511dU, 0xf7d88bc24209a565U, 0x9ae757596946075fU,
+    0xc1a12d2fc3978937U, 0xf209787bb47d6b84U, 0x9745eb4d50ce6332U,
+    0xbd176620a501fbffU, 0xec5d3fa8ce427affU, 0x93ba47c980e98cdfU,
+    0xb8a8d9bbe123f017U, 0xe6d3102ad96cec1dU, 0x9043ea1ac7e41392U,
+    0xb454e4a179dd1877U, 0xe16a1dc9d8545e94U, 0x8ce2529e2734bb1dU,
+    0xb01ae745b101e9e4U, 0xdc21a1171d42645dU, 0x899504ae72497ebaU,
+    0xabfa45da0edbde69U, 0xd6f8d7509292d603U, 0x865b86925b9bc5c2U,
+    0xa7f26836f282b732U, 0xd1ef0244af2364ffU, 0x8335616aed761f1fU,
+    0xa402b9c5a8d3a6e7U, 0xcd036837130890a1U, 0x802221226be55a64U,
+    0xa02aa96b06deb0fdU, 0xc83553c5c8965d3dU, 0xfa42a8b73abbf48cU,
+    0x9c69a97284b578d7U, 0xc38413cf25e2d70dU, 0xf46518c2ef5b8cd1U,
+    0x98bf2f79d5993802U, 0xbeeefb584aff8603U, 0xeeaaba2e5dbf6784U,
+    0x952ab45cfa97a0b2U, 0xba756174393d88dfU, 0xe912b9d1478ceb17U,
+    0x91abb422ccb812eeU, 0xb616a12b7fe617aaU, 0xe39c49765fdf9d94U,
+    0x8e41ade9fbebc27dU, 0xb1d219647ae6b31cU, 0xde469fbd99a05fe3U,
+    0x8aec23d680043beeU, 0xada72ccc20054ae9U, 0xd910f7ff28069da4U,
+    0x87aa9aff79042286U, 0xa99541bf57452b28U, 0xd3fa922f2d1675f2U,
+    0x847c9b5d7c2e09b7U, 0xa59bc234db398c25U, 0xcf02b2c21207ef2eU,
+    0x8161afb94b44f57dU, 0xa1ba1ba79e1632dcU, 0xca28a291859bbf93U,
+    0xfcb2cb35e702af78U, 0x9defbf01b061adabU, 0xc56baec21c7a1916U,
+    0xf6c69a72a3989f5bU, 0x9a3c2087a63f6399U, 0xc0cb28a98fcf3c7fU,
+    0xf0fdf2d3f3c30b9fU, 0x969eb7c47859e743U, 0xbc4665b596706114U,
+    0xeb57ff22fc0c7959U, 0x9316ff75dd87cbd8U, 0xb7dcbf5354e9beceU,
+    0xe5d3ef282a242e81U, 0x8fa475791a569d10U, 0xb38d92d760ec4455U,
+    0xe070f78d3927556aU, 0x8c469ab843b89562U, 0xaf58416654a6babbU,
+    0xdb2e51bfe9d0696aU, 0x88fcf317f22241e2U, 0xab3c2fddeeaad25aU,
+    0xd60b3bd56a5586f1U, 0x85c7056562757456U, 0xa738c6bebb12d16cU,
+    0xd106f86e69d785c7U, 0x82a45b450226b39cU, 0xa34d721642b06084U,
+    0xcc20ce9bd35c78a5U, 0xff290242c83396ceU, 0x9f79a169bd203e41U,
+    0xc75809c42c684dd1U, 0xf92e0c3537826145U, 0x9bbcc7a142b17ccbU,
+    0xc2abf989935ddbfeU, 0xf356f7ebf83552feU, 0x98165af37b2153deU,
+    0xbe1bf1b059e9a8d6U, 0xeda2ee1c7064130cU, 0x9485d4d1c63e8be7U,
+    0xb9a74a0637ce2ee1U, 0xe8111c87c5c1ba99U, 0x910ab1d4db9914a0U,
+    0xb54d5e4a127f59c8U, 0xe2a0b5dc971f303aU, 0x8da471a9de737e24U,
+    0xb10d8e1456105dadU, 0xdd50f1996b947518U, 0x8a5296ffe33cc92fU,
+    0xace73cbfdc0bfb7bU, 0xd8210befd30efa5aU, 0x8714a775e3e95c78U,
+    0xa8d9d1535ce3b396U, 0xd31045a8341ca07cU, 0x83ea2b892091e44dU,
+    0xa4e4b66b68b65d60U, 0xce1de40642e3f4b9U, 0x80d2ae83e9ce78f3U,
+    0xa1075a24e4421730U, 0xc94930ae1d529cfcU, 0xfb9b7cd9a4a7443cU,
+    0x9d412e0806e88aa5U, 0xc491798a08a2ad4eU, 0xf5b5d7ec8acb58a2U,
+    0x9991a6f3d6bf1765U, 0xbff610b0cc6edd3fU, 0xeff394dcff8a948eU,
+    0x95f83d0a1fb69cd9U, 0xbb764c4ca7a4440fU, 0xea53df5fd18d5513U,
+    0x92746b9be2f8552cU, 0xb7118682dbb66a77U, 0xe4d5e82392a40515U,
+    0x8f05b1163ba6832dU, 0xb2c71d5bca9023f8U, 0xdf78e4b2bd342cf6U,
+    0x8bab8eefb6409c1aU, 0xae9672aba3d0c320U, 0xda3c0f568cc4f3e8U,
+    0x8865899617fb1871U, 0xaa7eebfb9df9de8dU, 0xd51ea6fa85785631U,
+    0x8533285c936b35deU, 0xa67ff273b8460356U, 0xd01fef10a657842cU,
+    0x8213f56a67f6b29bU, 0xa298f2c501f45f42U, 0xcb3f2f7642717713U,
+    0xfe0efb53d30dd4d7U, 0x9ec95d1463e8a506U, 0xc67bb4597ce2ce48U,
+    0xf81aa16fdc1b81daU, 0x9b10a4e5e9913128U, 0xc1d4ce1f63f57d72U,
+    0xf24a01a73cf2dccfU, 0x976e41088617ca01U, 0xbd49d14aa79dbc82U,
+    0xec9c459d51852ba2U, 0x93e1ab8252f33b45U, 0xb8da1662e7b00a17U,
+    0xe7109bfba19c0c9dU, 0x906a617d450187e2U, 0xb484f9dc9641e9daU,
+    0xe1a63853bbd26451U, 0x8d07e33455637eb2U, 0xb049dc016abc5e5fU,
+    0xdc5c5301c56b75f7U, 0x89b9b3e11b6329baU, 0xac2820d9623bf429U,
+    0xd732290fbacaf133U, 0x867f59a9d4bed6c0U, 0xa81f301449ee8c70U,
+    0xd226fc195c6a2f8cU, 0x83585d8fd9c25db7U, 0xa42e74f3d032f525U,
+    0xcd3a1230c43fb26fU, 0x80444b5e7aa7cf85U, 0xa0555e361951c366U,
+    0xc86ab5c39fa63440U, 0xfa856334878fc150U, 0x9c935e00d4b9d8d2U,
+    0xc3b8358109e84f07U, 0xf4a642e14c6262c8U, 0x98e7e9cccfbd7dbdU,
+    0xbf21e44003acdd2cU, 0xeeea5d5004981478U, 0x95527a5202df0ccbU,
+    0xbaa718e68396cffdU, 0xe950df20247c83fdU, 0x91d28b7416cdd27eU,
+    0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU,
+};
+
+const int16_t kPower10ExponentTable[] = {
+    -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166,
+    -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130,
+    -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093,
+    -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057,
+    -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020,
+    -1017, -1014, -1010, -1007, -1004, -1000, -997,  -994,  -990,  -987,  -984,
+    -980,  -977,  -974,  -970,  -967,  -964,  -960,  -957,  -954,  -950,  -947,
+    -944,  -940,  -937,  -934,  -931,  -927,  -924,  -921,  -917,  -914,  -911,
+    -907,  -904,  -901,  -897,  -894,  -891,  -887,  -884,  -881,  -877,  -874,
+    -871,  -867,  -864,  -861,  -857,  -854,  -851,  -847,  -844,  -841,  -838,
+    -834,  -831,  -828,  -824,  -821,  -818,  -814,  -811,  -808,  -804,  -801,
+    -798,  -794,  -791,  -788,  -784,  -781,  -778,  -774,  -771,  -768,  -764,
+    -761,  -758,  -754,  -751,  -748,  -744,  -741,  -738,  -735,  -731,  -728,
+    -725,  -721,  -718,  -715,  -711,  -708,  -705,  -701,  -698,  -695,  -691,
+    -688,  -685,  -681,  -678,  -675,  -671,  -668,  -665,  -661,  -658,  -655,
+    -651,  -648,  -645,  -642,  -638,  -635,  -632,  -628,  -625,  -622,  -618,
+    -615,  -612,  -608,  -605,  -602,  -598,  -595,  -592,  -588,  -585,  -582,
+    -578,  -575,  -572,  -568,  -565,  -562,  -558,  -555,  -552,  -549,  -545,
+    -542,  -539,  -535,  -532,  -529,  -525,  -522,  -519,  -515,  -512,  -509,
+    -505,  -502,  -499,  -495,  -492,  -489,  -485,  -482,  -479,  -475,  -472,
+    -469,  -465,  -462,  -459,  -455,  -452,  -449,  -446,  -442,  -439,  -436,
+    -432,  -429,  -426,  -422,  -419,  -416,  -412,  -409,  -406,  -402,  -399,
+    -396,  -392,  -389,  -386,  -382,  -379,  -376,  -372,  -369,  -366,  -362,
+    -359,  -356,  -353,  -349,  -346,  -343,  -339,  -336,  -333,  -329,  -326,
+    -323,  -319,  -316,  -313,  -309,  -306,  -303,  -299,  -296,  -293,  -289,
+    -286,  -283,  -279,  -276,  -273,  -269,  -266,  -263,  -259,  -256,  -253,
+    -250,  -246,  -243,  -240,  -236,  -233,  -230,  -226,  -223,  -220,  -216,
+    -213,  -210,  -206,  -203,  -200,  -196,  -193,  -190,  -186,  -183,  -180,
+    -176,  -173,  -170,  -166,  -163,  -160,  -157,  -153,  -150,  -147,  -143,
+    -140,  -137,  -133,  -130,  -127,  -123,  -120,  -117,  -113,  -110,  -107,
+    -103,  -100,  -97,   -93,   -90,   -87,   -83,   -80,   -77,   -73,   -70,
+    -67,   -63,   -60,   -57,   -54,   -50,   -47,   -44,   -40,   -37,   -34,
+    -30,   -27,   -24,   -20,   -17,   -14,   -10,   -7,    -4,    0,     3,
+    6,     10,    13,    16,    20,    23,    26,    30,    33,    36,    39,
+    43,    46,    49,    53,    56,    59,    63,    66,    69,    73,    76,
+    79,    83,    86,    89,    93,    96,    99,    103,   106,   109,   113,
+    116,   119,   123,   126,   129,   132,   136,   139,   142,   146,   149,
+    152,   156,   159,   162,   166,   169,   172,   176,   179,   182,   186,
+    189,   192,   196,   199,   202,   206,   209,   212,   216,   219,   222,
+    226,   229,   232,   235,   239,   242,   245,   249,   252,   255,   259,
+    262,   265,   269,   272,   275,   279,   282,   285,   289,   292,   295,
+    299,   302,   305,   309,   312,   315,   319,   322,   325,   328,   332,
+    335,   338,   342,   345,   348,   352,   355,   358,   362,   365,   368,
+    372,   375,   378,   382,   385,   388,   392,   395,   398,   402,   405,
+    408,   412,   415,   418,   422,   425,   428,   431,   435,   438,   441,
+    445,   448,   451,   455,   458,   461,   465,   468,   471,   475,   478,
+    481,   485,   488,   491,   495,   498,   501,   505,   508,   511,   515,
+    518,   521,   524,   528,   531,   534,   538,   541,   544,   548,   551,
+    554,   558,   561,   564,   568,   571,   574,   578,   581,   584,   588,
+    591,   594,   598,   601,   604,   608,   611,   614,   617,   621,   624,
+    627,   631,   634,   637,   641,   644,   647,   651,   654,   657,   661,
+    664,   667,   671,   674,   677,   681,   684,   687,   691,   694,   697,
+    701,   704,   707,   711,   714,   717,   720,   724,   727,   730,   734,
+    737,   740,   744,   747,   750,   754,   757,   760,   764,   767,   770,
+    774,   777,   780,   784,   787,   790,   794,   797,   800,   804,   807,
+    810,   813,   817,   820,   823,   827,   830,   833,   837,   840,   843,
+    847,   850,   853,   857,   860,   863,   867,   870,   873,   877,   880,
+    883,   887,   890,   893,   897,   900,   903,   907,   910,   913,   916,
+    920,   923,   926,   930,   933,   936,   940,   943,   946,   950,   953,
+    956,   960,
+};
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h
new file mode 100644
index 0000000..3e31367
--- /dev/null
+++ b/absl/strings/charconv.h
@@ -0,0 +1,115 @@
+// Copyright 2018 The Abseil 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 ABSL_STRINGS_CHARCONV_H_
+#define ABSL_STRINGS_CHARCONV_H_
+
+#include <system_error>  // NOLINT(build/c++11)
+
+namespace absl {
+
+// Workalike compatibilty version of std::chars_format from C++17.
+//
+// This is an bitfield enumerator which can be passed to absl::from_chars to
+// configure the std::string-to-float conversion.
+enum class chars_format {
+  scientific = 1,
+  fixed = 2,
+  hex = 4,
+  general = fixed | scientific,
+};
+
+// The return result of a std::string-to-number conversion.
+//
+// `ec` will be set to `invalid_argument` if a well-formed number was not found
+// at the start of the input range, `result_out_of_range` if a well-formed
+// number was found, but it was out of the representable range of the requested
+// type, or to std::errc() otherwise.
+//
+// If a well-formed number was found, `ptr` is set to one past the sequence of
+// characters that were successfully parsed.  If none was found, `ptr` is set
+// to the `first` argument to from_chars.
+struct from_chars_result {
+  const char* ptr;
+  std::errc ec;
+};
+
+// Workalike compatibilty version of std::from_chars from C++17.  Currently
+// this only supports the `double` and `float` types.
+//
+// This interface incorporates the proposed resolutions for library issues
+// DR 3800 and DR 3801.  If these are adopted with different wording,
+// Abseil's behavior will change to match the standard.  (The behavior most
+// likely to change is for DR 3801, which says what `value` will be set to in
+// the case of overflow and underflow.  Code that wants to avoid possible
+// breaking changes in this area should not depend on `value` when the returned
+// from_chars_result indicates a range error.)
+//
+// Searches the range [first, last) for the longest matching pattern beginning
+// at `first` that represents a floating point number.  If one is found, store
+// the result in `value`.
+//
+// The matching pattern format is almost the same as that of strtod(), except
+// that C locale is not respected, and an initial '+' character in the input
+// range will never be matched.
+//
+// If `fmt` is set, it must be one of the enumerator values of the chars_format.
+// (This is despite the fact that chars_format is a bitmask type.)  If set to
+// `scientific`, a matching number must contain an exponent.  If set to `fixed`,
+// then an exponent will never match.  (For example, the std::string "1e5" will be
+// parsed as "1".)  If set to `hex`, then a hexadecimal float is parsed in the
+// format that strtod() accepts, except that a "0x" prefix is NOT matched.
+// (In particular, in `hex` mode, the input "0xff" results in the largest
+// matching pattern "0".)
+absl::from_chars_result from_chars(const char* first, const char* last,
+                                   double& value,  // NOLINT
+                                   chars_format fmt = chars_format::general);
+
+absl::from_chars_result from_chars(const char* first, const char* last,
+                                   float& value,  // NOLINT
+                                   chars_format fmt = chars_format::general);
+
+// std::chars_format is specified as a bitmask type, which means the following
+// operations must be provided:
+inline constexpr chars_format operator&(chars_format lhs, chars_format rhs) {
+  return static_cast<chars_format>(static_cast<int>(lhs) &
+                                   static_cast<int>(rhs));
+}
+inline constexpr chars_format operator|(chars_format lhs, chars_format rhs) {
+  return static_cast<chars_format>(static_cast<int>(lhs) |
+                                   static_cast<int>(rhs));
+}
+inline constexpr chars_format operator^(chars_format lhs, chars_format rhs) {
+  return static_cast<chars_format>(static_cast<int>(lhs) ^
+                                   static_cast<int>(rhs));
+}
+inline constexpr chars_format operator~(chars_format arg) {
+  return static_cast<chars_format>(~static_cast<int>(arg));
+}
+inline chars_format& operator&=(chars_format& lhs, chars_format rhs) {
+  lhs = lhs & rhs;
+  return lhs;
+}
+inline chars_format& operator|=(chars_format& lhs, chars_format rhs) {
+  lhs = lhs | rhs;
+  return lhs;
+}
+inline chars_format& operator^=(chars_format& lhs, chars_format rhs) {
+  lhs = lhs ^ rhs;
+  return lhs;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_CHARCONV_H_
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc
new file mode 100644
index 0000000..fd83f44
--- /dev/null
+++ b/absl/strings/charconv_benchmark.cc
@@ -0,0 +1,204 @@
+// Copyright 2018 The Abseil 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 "absl/strings/charconv.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_Strtod_Pi(benchmark::State& state) {
+  const char* pi = "3.14159";
+  for (auto s : state) {
+    benchmark::DoNotOptimize(pi);
+    benchmark::DoNotOptimize(strtod(pi, nullptr));
+  }
+}
+BENCHMARK(BM_Strtod_Pi);
+
+void BM_Absl_Pi(benchmark::State& state) {
+  const char* pi = "3.14159";
+  const char* pi_end = pi + strlen(pi);
+  for (auto s : state) {
+    benchmark::DoNotOptimize(pi);
+    double v;
+    absl::from_chars(pi, pi_end, v);
+    benchmark::DoNotOptimize(v);
+  }
+}
+BENCHMARK(BM_Absl_Pi);
+
+void BM_Strtod_Pi_float(benchmark::State& state) {
+  const char* pi = "3.14159";
+  for (auto s : state) {
+    benchmark::DoNotOptimize(pi);
+    benchmark::DoNotOptimize(strtof(pi, nullptr));
+  }
+}
+BENCHMARK(BM_Strtod_Pi_float);
+
+void BM_Absl_Pi_float(benchmark::State& state) {
+  const char* pi = "3.14159";
+  const char* pi_end = pi + strlen(pi);
+  for (auto s : state) {
+    benchmark::DoNotOptimize(pi);
+    float v;
+    absl::from_chars(pi, pi_end, v);
+    benchmark::DoNotOptimize(v);
+  }
+}
+BENCHMARK(BM_Absl_Pi_float);
+
+void BM_Strtod_HardLarge(benchmark::State& state) {
+  const char* num = "272104041512242479.e200";
+  for (auto s : state) {
+    benchmark::DoNotOptimize(num);
+    benchmark::DoNotOptimize(strtod(num, nullptr));
+  }
+}
+BENCHMARK(BM_Strtod_HardLarge);
+
+void BM_Absl_HardLarge(benchmark::State& state) {
+  const char* numstr = "272104041512242479.e200";
+  const char* numstr_end = numstr + strlen(numstr);
+  for (auto s : state) {
+    benchmark::DoNotOptimize(numstr);
+    double v;
+    absl::from_chars(numstr, numstr_end, v);
+    benchmark::DoNotOptimize(v);
+  }
+}
+BENCHMARK(BM_Absl_HardLarge);
+
+void BM_Strtod_HardSmall(benchmark::State& state) {
+  const char* num = "94080055902682397.e-242";
+  for (auto s : state) {
+    benchmark::DoNotOptimize(num);
+    benchmark::DoNotOptimize(strtod(num, nullptr));
+  }
+}
+BENCHMARK(BM_Strtod_HardSmall);
+
+void BM_Absl_HardSmall(benchmark::State& state) {
+  const char* numstr = "94080055902682397.e-242";
+  const char* numstr_end = numstr + strlen(numstr);
+  for (auto s : state) {
+    benchmark::DoNotOptimize(numstr);
+    double v;
+    absl::from_chars(numstr, numstr_end, v);
+    benchmark::DoNotOptimize(v);
+  }
+}
+BENCHMARK(BM_Absl_HardSmall);
+
+void BM_Strtod_HugeMantissa(benchmark::State& state) {
+  std::string huge(200, '3');
+  const char* num = huge.c_str();
+  for (auto s : state) {
+    benchmark::DoNotOptimize(num);
+    benchmark::DoNotOptimize(strtod(num, nullptr));
+  }
+}
+BENCHMARK(BM_Strtod_HugeMantissa);
+
+void BM_Absl_HugeMantissa(benchmark::State& state) {
+  std::string huge(200, '3');
+  const char* num = huge.c_str();
+  const char* num_end = num + 200;
+  for (auto s : state) {
+    benchmark::DoNotOptimize(num);
+    double v;
+    absl::from_chars(num, num_end, v);
+    benchmark::DoNotOptimize(v);
+  }
+}
+BENCHMARK(BM_Absl_HugeMantissa);
+
+std::string MakeHardCase(int length) {
+  // The number 1.1521...e-297 is exactly halfway between 12345 * 2**-1000 and
+  // the next larger representable number.  The digits of this number are in
+  // the std::string below.
+  const std::string digits =
+      "1."
+      "152113937042223790993097181572444900347587985074226836242307364987727724"
+      "831384300183638649152607195040591791364113930628852279348613864894524591"
+      "272746490313676832900762939595690019745859128071117417798540258114233761"
+      "012939937017879509401007964861774960297319002612457273148497158989073482"
+      "171377406078223015359818300988676687994537274548940612510414856761641652"
+      "513434981938564294004070500716200446656421722229202383105446378511678258"
+      "370570631774499359748259931676320916632111681001853983492795053244971606"
+      "922718923011680846577744433974087653954904214152517799883551075537146316"
+      "168973685866425605046988661997658648354773076621610279716804960009043764"
+      "038392994055171112475093876476783502487512538082706095923790634572014823"
+      "78877699375152587890625" +
+      std::string(5000, '0');
+  // generate the hard cases on either side for the given length.
+  // Lengths between 3 and 1000 are reasonable.
+  return digits.substr(0, length) + "1e-297";
+}
+
+void BM_Strtod_Big_And_Difficult(benchmark::State& state) {
+  std::string testcase = MakeHardCase(state.range(0));
+  const char* begin = testcase.c_str();
+  for (auto s : state) {
+    benchmark::DoNotOptimize(begin);
+    benchmark::DoNotOptimize(strtod(begin, nullptr));
+  }
+}
+BENCHMARK(BM_Strtod_Big_And_Difficult)->Range(3, 5000);
+
+void BM_Absl_Big_And_Difficult(benchmark::State& state) {
+  std::string testcase = MakeHardCase(state.range(0));
+  const char* begin = testcase.c_str();
+  const char* end = begin + testcase.size();
+  for (auto s : state) {
+    benchmark::DoNotOptimize(begin);
+    double v;
+    absl::from_chars(begin, end, v);
+    benchmark::DoNotOptimize(v);
+  }
+}
+BENCHMARK(BM_Absl_Big_And_Difficult)->Range(3, 5000);
+
+}  // namespace
+
+// ------------------------------------------------------------------------
+// Benchmark                                 Time           CPU Iterations
+// ------------------------------------------------------------------------
+// BM_Strtod_Pi                             96 ns         96 ns    6337454
+// BM_Absl_Pi                               35 ns         35 ns   20031996
+// BM_Strtod_Pi_float                       91 ns         91 ns    7745851
+// BM_Absl_Pi_float                         35 ns         35 ns   20430298
+// BM_Strtod_HardLarge                     133 ns        133 ns    5288341
+// BM_Absl_HardLarge                       181 ns        181 ns    3855615
+// BM_Strtod_HardSmall                     279 ns        279 ns    2517243
+// BM_Absl_HardSmall                       287 ns        287 ns    2458744
+// BM_Strtod_HugeMantissa                  433 ns        433 ns    1604293
+// BM_Absl_HugeMantissa                    160 ns        160 ns    4403671
+// BM_Strtod_Big_And_Difficult/3           236 ns        236 ns    2942496
+// BM_Strtod_Big_And_Difficult/8           232 ns        232 ns    2983796
+// BM_Strtod_Big_And_Difficult/64          437 ns        437 ns    1591951
+// BM_Strtod_Big_And_Difficult/512        1738 ns       1738 ns     402519
+// BM_Strtod_Big_And_Difficult/4096       3943 ns       3943 ns     176128
+// BM_Strtod_Big_And_Difficult/5000       4397 ns       4397 ns     157878
+// BM_Absl_Big_And_Difficult/3              39 ns         39 ns   17799583
+// BM_Absl_Big_And_Difficult/8              43 ns         43 ns   16096859
+// BM_Absl_Big_And_Difficult/64            550 ns        550 ns    1259717
+// BM_Absl_Big_And_Difficult/512          4167 ns       4167 ns     171414
+// BM_Absl_Big_And_Difficult/4096         9160 ns       9159 ns      76297
+// BM_Absl_Big_And_Difficult/5000         9738 ns       9738 ns      70140
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
new file mode 100644
index 0000000..f8d71cc
--- /dev/null
+++ b/absl/strings/charconv_test.cc
@@ -0,0 +1,766 @@
+// Copyright 2018 The Abseil 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 "absl/strings/charconv.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+
+#ifdef _MSC_FULL_VER
+#define ABSL_COMPILER_DOES_EXACT_ROUNDING 0
+#define ABSL_STRTOD_HANDLES_NAN_CORRECTLY 0
+#else
+#define ABSL_COMPILER_DOES_EXACT_ROUNDING 1
+#define ABSL_STRTOD_HANDLES_NAN_CORRECTLY 1
+#endif
+
+namespace {
+
+#if ABSL_COMPILER_DOES_EXACT_ROUNDING
+
+// Tests that the given std::string is accepted by absl::from_chars, and that it
+// converts exactly equal to the given number.
+void TestDoubleParse(absl::string_view str, double expected_number) {
+  SCOPED_TRACE(str);
+  double actual_number = 0.0;
+  absl::from_chars_result result =
+      absl::from_chars(str.data(), str.data() + str.length(), actual_number);
+  EXPECT_EQ(result.ec, std::errc());
+  EXPECT_EQ(result.ptr, str.data() + str.length());
+  EXPECT_EQ(actual_number, expected_number);
+}
+
+void TestFloatParse(absl::string_view str, float expected_number) {
+  SCOPED_TRACE(str);
+  float actual_number = 0.0;
+  absl::from_chars_result result =
+      absl::from_chars(str.data(), str.data() + str.length(), actual_number);
+  EXPECT_EQ(result.ec, std::errc());
+  EXPECT_EQ(result.ptr, str.data() + str.length());
+  EXPECT_EQ(actual_number, expected_number);
+}
+
+// Tests that the given double or single precision floating point literal is
+// parsed correctly by absl::from_chars.
+//
+// These convenience macros assume that the C++ compiler being used also does
+// fully correct decimal-to-binary conversions.
+#define FROM_CHARS_TEST_DOUBLE(number)     \
+  {                                        \
+    TestDoubleParse(#number, number);      \
+    TestDoubleParse("-" #number, -number); \
+  }
+
+#define FROM_CHARS_TEST_FLOAT(number)        \
+  {                                          \
+    TestFloatParse(#number, number##f);      \
+    TestFloatParse("-" #number, -number##f); \
+  }
+
+TEST(FromChars, NearRoundingCases) {
+  // Cases from "A Program for Testing IEEE Decimal-Binary Conversion"
+  // by Vern Paxson.
+
+  // Forms that should round towards zero.  (These are the hardest cases for
+  // each decimal mantissa size.)
+  FROM_CHARS_TEST_DOUBLE(5.e125);
+  FROM_CHARS_TEST_DOUBLE(69.e267);
+  FROM_CHARS_TEST_DOUBLE(999.e-026);
+  FROM_CHARS_TEST_DOUBLE(7861.e-034);
+  FROM_CHARS_TEST_DOUBLE(75569.e-254);
+  FROM_CHARS_TEST_DOUBLE(928609.e-261);
+  FROM_CHARS_TEST_DOUBLE(9210917.e080);
+  FROM_CHARS_TEST_DOUBLE(84863171.e114);
+  FROM_CHARS_TEST_DOUBLE(653777767.e273);
+  FROM_CHARS_TEST_DOUBLE(5232604057.e-298);
+  FROM_CHARS_TEST_DOUBLE(27235667517.e-109);
+  FROM_CHARS_TEST_DOUBLE(653532977297.e-123);
+  FROM_CHARS_TEST_DOUBLE(3142213164987.e-294);
+  FROM_CHARS_TEST_DOUBLE(46202199371337.e-072);
+  FROM_CHARS_TEST_DOUBLE(231010996856685.e-073);
+  FROM_CHARS_TEST_DOUBLE(9324754620109615.e212);
+  FROM_CHARS_TEST_DOUBLE(78459735791271921.e049);
+  FROM_CHARS_TEST_DOUBLE(272104041512242479.e200);
+  FROM_CHARS_TEST_DOUBLE(6802601037806061975.e198);
+  FROM_CHARS_TEST_DOUBLE(20505426358836677347.e-221);
+  FROM_CHARS_TEST_DOUBLE(836168422905420598437.e-234);
+  FROM_CHARS_TEST_DOUBLE(4891559871276714924261.e222);
+  FROM_CHARS_TEST_FLOAT(5.e-20);
+  FROM_CHARS_TEST_FLOAT(67.e14);
+  FROM_CHARS_TEST_FLOAT(985.e15);
+  FROM_CHARS_TEST_FLOAT(7693.e-42);
+  FROM_CHARS_TEST_FLOAT(55895.e-16);
+  FROM_CHARS_TEST_FLOAT(996622.e-44);
+  FROM_CHARS_TEST_FLOAT(7038531.e-32);
+  FROM_CHARS_TEST_FLOAT(60419369.e-46);
+  FROM_CHARS_TEST_FLOAT(702990899.e-20);
+  FROM_CHARS_TEST_FLOAT(6930161142.e-48);
+  FROM_CHARS_TEST_FLOAT(25933168707.e-13);
+  FROM_CHARS_TEST_FLOAT(596428896559.e20);
+
+  // Similarly, forms that should round away from zero.
+  FROM_CHARS_TEST_DOUBLE(9.e-265);
+  FROM_CHARS_TEST_DOUBLE(85.e-037);
+  FROM_CHARS_TEST_DOUBLE(623.e100);
+  FROM_CHARS_TEST_DOUBLE(3571.e263);
+  FROM_CHARS_TEST_DOUBLE(81661.e153);
+  FROM_CHARS_TEST_DOUBLE(920657.e-023);
+  FROM_CHARS_TEST_DOUBLE(4603285.e-024);
+  FROM_CHARS_TEST_DOUBLE(87575437.e-309);
+  FROM_CHARS_TEST_DOUBLE(245540327.e122);
+  FROM_CHARS_TEST_DOUBLE(6138508175.e120);
+  FROM_CHARS_TEST_DOUBLE(83356057653.e193);
+  FROM_CHARS_TEST_DOUBLE(619534293513.e124);
+  FROM_CHARS_TEST_DOUBLE(2335141086879.e218);
+  FROM_CHARS_TEST_DOUBLE(36167929443327.e-159);
+  FROM_CHARS_TEST_DOUBLE(609610927149051.e-255);
+  FROM_CHARS_TEST_DOUBLE(3743626360493413.e-165);
+  FROM_CHARS_TEST_DOUBLE(94080055902682397.e-242);
+  FROM_CHARS_TEST_DOUBLE(899810892172646163.e283);
+  FROM_CHARS_TEST_DOUBLE(7120190517612959703.e120);
+  FROM_CHARS_TEST_DOUBLE(25188282901709339043.e-252);
+  FROM_CHARS_TEST_DOUBLE(308984926168550152811.e-052);
+  FROM_CHARS_TEST_DOUBLE(6372891218502368041059.e064);
+  FROM_CHARS_TEST_FLOAT(3.e-23);
+  FROM_CHARS_TEST_FLOAT(57.e18);
+  FROM_CHARS_TEST_FLOAT(789.e-35);
+  FROM_CHARS_TEST_FLOAT(2539.e-18);
+  FROM_CHARS_TEST_FLOAT(76173.e28);
+  FROM_CHARS_TEST_FLOAT(887745.e-11);
+  FROM_CHARS_TEST_FLOAT(5382571.e-37);
+  FROM_CHARS_TEST_FLOAT(82381273.e-35);
+  FROM_CHARS_TEST_FLOAT(750486563.e-38);
+  FROM_CHARS_TEST_FLOAT(3752432815.e-39);
+  FROM_CHARS_TEST_FLOAT(75224575729.e-45);
+  FROM_CHARS_TEST_FLOAT(459926601011.e15);
+}
+
+#undef FROM_CHARS_TEST_DOUBLE
+#undef FROM_CHARS_TEST_FLOAT
+#endif
+
+float ToFloat(absl::string_view s) {
+  float f;
+  absl::from_chars(s.data(), s.data() + s.size(), f);
+  return f;
+}
+
+double ToDouble(absl::string_view s) {
+  double d;
+  absl::from_chars(s.data(), s.data() + s.size(), d);
+  return d;
+}
+
+// A duplication of the test cases in "NearRoundingCases" above, but with
+// expected values expressed with integers, using ldexp/ldexpf.  These test
+// cases will work even on compilers that do not accurately round floating point
+// literals.
+TEST(FromChars, NearRoundingCasesExplicit) {
+  EXPECT_EQ(ToDouble("5.e125"), ldexp(6653062250012735, 365));
+  EXPECT_EQ(ToDouble("69.e267"), ldexp(4705683757438170, 841));
+  EXPECT_EQ(ToDouble("999.e-026"), ldexp(6798841691080350, -129));
+  EXPECT_EQ(ToDouble("7861.e-034"), ldexp(8975675289889240, -153));
+  EXPECT_EQ(ToDouble("75569.e-254"), ldexp(6091718967192243, -880));
+  EXPECT_EQ(ToDouble("928609.e-261"), ldexp(7849264900213743, -900));
+  EXPECT_EQ(ToDouble("9210917.e080"), ldexp(8341110837370930, 236));
+  EXPECT_EQ(ToDouble("84863171.e114"), ldexp(4625202867375927, 353));
+  EXPECT_EQ(ToDouble("653777767.e273"), ldexp(5068902999763073, 884));
+  EXPECT_EQ(ToDouble("5232604057.e-298"), ldexp(5741343011915040, -1010));
+  EXPECT_EQ(ToDouble("27235667517.e-109"), ldexp(6707124626673586, -380));
+  EXPECT_EQ(ToDouble("653532977297.e-123"), ldexp(7078246407265384, -422));
+  EXPECT_EQ(ToDouble("3142213164987.e-294"), ldexp(8219991337640559, -988));
+  EXPECT_EQ(ToDouble("46202199371337.e-072"), ldexp(5224462102115359, -246));
+  EXPECT_EQ(ToDouble("231010996856685.e-073"), ldexp(5224462102115359, -247));
+  EXPECT_EQ(ToDouble("9324754620109615.e212"), ldexp(5539753864394442, 705));
+  EXPECT_EQ(ToDouble("78459735791271921.e049"), ldexp(8388176519442766, 166));
+  EXPECT_EQ(ToDouble("272104041512242479.e200"), ldexp(5554409530847367, 670));
+  EXPECT_EQ(ToDouble("6802601037806061975.e198"), ldexp(5554409530847367, 668));
+  EXPECT_EQ(ToDouble("20505426358836677347.e-221"),
+            ldexp(4524032052079546, -722));
+  EXPECT_EQ(ToDouble("836168422905420598437.e-234"),
+            ldexp(5070963299887562, -760));
+  EXPECT_EQ(ToDouble("4891559871276714924261.e222"),
+            ldexp(6452687840519111, 757));
+  EXPECT_EQ(ToFloat("5.e-20"), ldexpf(15474250, -88));
+  EXPECT_EQ(ToFloat("67.e14"), ldexpf(12479722, 29));
+  EXPECT_EQ(ToFloat("985.e15"), ldexpf(14333636, 36));
+  EXPECT_EQ(ToFloat("7693.e-42"), ldexpf(10979816, -150));
+  EXPECT_EQ(ToFloat("55895.e-16"), ldexpf(12888509, -61));
+  EXPECT_EQ(ToFloat("996622.e-44"), ldexpf(14224264, -150));
+  EXPECT_EQ(ToFloat("7038531.e-32"), ldexpf(11420669, -107));
+  EXPECT_EQ(ToFloat("60419369.e-46"), ldexpf(8623340, -150));
+  EXPECT_EQ(ToFloat("702990899.e-20"), ldexpf(16209866, -61));
+  EXPECT_EQ(ToFloat("6930161142.e-48"), ldexpf(9891056, -150));
+  EXPECT_EQ(ToFloat("25933168707.e-13"), ldexpf(11138211, -32));
+  EXPECT_EQ(ToFloat("596428896559.e20"), ldexpf(12333860, 82));
+
+
+  EXPECT_EQ(ToDouble("9.e-265"), ldexp(8168427841980010, -930));
+  EXPECT_EQ(ToDouble("85.e-037"), ldexp(6360455125664090, -169));
+  EXPECT_EQ(ToDouble("623.e100"), ldexp(6263531988747231, 289));
+  EXPECT_EQ(ToDouble("3571.e263"), ldexp(6234526311072170, 833));
+  EXPECT_EQ(ToDouble("81661.e153"), ldexp(6696636728760206, 472));
+  EXPECT_EQ(ToDouble("920657.e-023"), ldexp(5975405561110124, -109));
+  EXPECT_EQ(ToDouble("4603285.e-024"), ldexp(5975405561110124, -110));
+  EXPECT_EQ(ToDouble("87575437.e-309"), ldexp(8452160731874668, -1053));
+  EXPECT_EQ(ToDouble("245540327.e122"), ldexp(4985336549131723, 381));
+  EXPECT_EQ(ToDouble("6138508175.e120"), ldexp(4985336549131723, 379));
+  EXPECT_EQ(ToDouble("83356057653.e193"), ldexp(5986732817132056, 625));
+  EXPECT_EQ(ToDouble("619534293513.e124"), ldexp(4798406992060657, 399));
+  EXPECT_EQ(ToDouble("2335141086879.e218"), ldexp(5419088166961646, 713));
+  EXPECT_EQ(ToDouble("36167929443327.e-159"), ldexp(8135819834632444, -536));
+  EXPECT_EQ(ToDouble("609610927149051.e-255"), ldexp(4576664294594737, -850));
+  EXPECT_EQ(ToDouble("3743626360493413.e-165"), ldexp(6898586531774201, -549));
+  EXPECT_EQ(ToDouble("94080055902682397.e-242"), ldexp(6273271706052298, -800));
+  EXPECT_EQ(ToDouble("899810892172646163.e283"), ldexp(7563892574477827, 947));
+  EXPECT_EQ(ToDouble("7120190517612959703.e120"), ldexp(5385467232557565, 409));
+  EXPECT_EQ(ToDouble("25188282901709339043.e-252"),
+            ldexp(5635662608542340, -825));
+  EXPECT_EQ(ToDouble("308984926168550152811.e-052"),
+            ldexp(5644774693823803, -157));
+  EXPECT_EQ(ToDouble("6372891218502368041059.e064"),
+            ldexp(4616868614322430, 233));
+
+  EXPECT_EQ(ToFloat("3.e-23"), ldexpf(9507380, -98));
+  EXPECT_EQ(ToFloat("57.e18"), ldexpf(12960300, 42));
+  EXPECT_EQ(ToFloat("789.e-35"), ldexpf(10739312, -130));
+  EXPECT_EQ(ToFloat("2539.e-18"), ldexpf(11990089, -72));
+  EXPECT_EQ(ToFloat("76173.e28"), ldexpf(9845130, 86));
+  EXPECT_EQ(ToFloat("887745.e-11"), ldexpf(9760860, -40));
+  EXPECT_EQ(ToFloat("5382571.e-37"), ldexpf(11447463, -124));
+  EXPECT_EQ(ToFloat("82381273.e-35"), ldexpf(8554961, -113));
+  EXPECT_EQ(ToFloat("750486563.e-38"), ldexpf(9975678, -120));
+  EXPECT_EQ(ToFloat("3752432815.e-39"), ldexpf(9975678, -121));
+  EXPECT_EQ(ToFloat("75224575729.e-45"), ldexpf(13105970, -137));
+  EXPECT_EQ(ToFloat("459926601011.e15"), ldexpf(12466336, 65));
+}
+
+// Common test logic for converting a std::string which lies exactly halfway between
+// two target floats.
+//
+// mantissa and exponent represent the precise value between two floating point
+// numbers, `expected_low` and `expected_high`.  The floating point
+// representation to parse in `StrCat(mantissa, "e", exponent)`.
+//
+// This function checks that an input just slightly less than the exact value
+// is rounded down to `expected_low`, and an input just slightly greater than
+// the exact value is rounded up to `expected_high`.
+//
+// The exact value should round to `expected_half`, which must be either
+// `expected_low` or `expected_high`.
+template <typename FloatType>
+void TestHalfwayValue(const std::string& mantissa, int exponent,
+                      FloatType expected_low, FloatType expected_high,
+                      FloatType expected_half) {
+  std::string low_rep = mantissa;
+  low_rep[low_rep.size() - 1] -= 1;
+  absl::StrAppend(&low_rep, std::string(1000, '9'), "e", exponent);
+
+  FloatType actual_low = 0;
+  absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low);
+  EXPECT_EQ(expected_low, actual_low);
+
+  std::string high_rep = absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent);
+  FloatType actual_high = 0;
+  absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(),
+                   actual_high);
+  EXPECT_EQ(expected_high, actual_high);
+
+  std::string halfway_rep = absl::StrCat(mantissa, "e", exponent);
+  FloatType actual_half = 0;
+  absl::from_chars(halfway_rep.data(), halfway_rep.data() + halfway_rep.size(),
+                   actual_half);
+  EXPECT_EQ(expected_half, actual_half);
+}
+
+TEST(FromChars, DoubleRounding) {
+  const double zero = 0.0;
+  const double first_subnormal = nextafter(zero, 1.0);
+  const double second_subnormal = nextafter(first_subnormal, 1.0);
+
+  const double first_normal = DBL_MIN;
+  const double last_subnormal = nextafter(first_normal, 0.0);
+  const double second_normal = nextafter(first_normal, 1.0);
+
+  const double last_normal = DBL_MAX;
+  const double penultimate_normal = nextafter(last_normal, 0.0);
+
+  // Various test cases for numbers between two representable floats.  Each
+  // call to TestHalfwayValue tests a number just below and just above the
+  // halfway point, as well as the number exactly between them.
+
+  // Test between zero and first_subnormal.  Round-to-even tie rounds down.
+  TestHalfwayValue(
+      "2."
+      "470328229206232720882843964341106861825299013071623822127928412503377536"
+      "351043759326499181808179961898982823477228588654633283551779698981993873"
+      "980053909390631503565951557022639229085839244910518443593180284993653615"
+      "250031937045767824921936562366986365848075700158576926990370631192827955"
+      "855133292783433840935197801553124659726357957462276646527282722005637400"
+      "648549997709659947045402082816622623785739345073633900796776193057750674"
+      "017632467360096895134053553745851666113422376667860416215968046191446729"
+      "184030053005753084904876539171138659164623952491262365388187963623937328"
+      "042389101867234849766823508986338858792562830275599565752445550725518931"
+      "369083625477918694866799496832404970582102851318545139621383772282614543"
+      "7693412532098591327667236328125",
+      -324, zero, first_subnormal, zero);
+
+  // first_subnormal and second_subnormal.  Round-to-even tie rounds up.
+  TestHalfwayValue(
+      "7."
+      "410984687618698162648531893023320585475897039214871466383785237510132609"
+      "053131277979497545424539885696948470431685765963899850655339096945981621"
+      "940161728171894510697854671067917687257517734731555330779540854980960845"
+      "750095811137303474765809687100959097544227100475730780971111893578483867"
+      "565399878350301522805593404659373979179073872386829939581848166016912201"
+      "945649993128979841136206248449867871357218035220901702390328579173252022"
+      "052897402080290685402160661237554998340267130003581248647904138574340187"
+      "552090159017259254714629617513415977493871857473787096164563890871811984"
+      "127167305601704549300470526959016576377688490826798697257336652176556794"
+      "107250876433756084600398490497214911746308553955635418864151316847843631"
+      "3080237596295773983001708984375",
+      -324, first_subnormal, second_subnormal, second_subnormal);
+
+  // last_subnormal and first_normal.  Round-to-even tie rounds up.
+  TestHalfwayValue(
+      "2."
+      "225073858507201136057409796709131975934819546351645648023426109724822222"
+      "021076945516529523908135087914149158913039621106870086438694594645527657"
+      "207407820621743379988141063267329253552286881372149012981122451451889849"
+      "057222307285255133155755015914397476397983411801999323962548289017107081"
+      "850690630666655994938275772572015763062690663332647565300009245888316433"
+      "037779791869612049497390377829704905051080609940730262937128958950003583"
+      "799967207254304360284078895771796150945516748243471030702609144621572289"
+      "880258182545180325707018860872113128079512233426288368622321503775666622"
+      "503982534335974568884423900265498198385487948292206894721689831099698365"
+      "846814022854243330660339850886445804001034933970427567186443383770486037"
+      "86162277173854562306587467901408672332763671875",
+      -308, last_subnormal, first_normal, first_normal);
+
+  // first_normal and second_normal.  Round-to-even tie rounds down.
+  TestHalfwayValue(
+      "2."
+      "225073858507201630123055637955676152503612414573018013083228724049586647"
+      "606759446192036794116886953213985520549032000903434781884412325572184367"
+      "563347617020518175998922941393629966742598285899994830148971433555578567"
+      "693279306015978183162142425067962460785295885199272493577688320732492479"
+      "924816869232247165964934329258783950102250973957579510571600738343645738"
+      "494324192997092179207389919761694314131497173265255020084997973676783743"
+      "155205818804439163810572367791175177756227497413804253387084478193655533"
+      "073867420834526162513029462022730109054820067654020201547112002028139700"
+      "141575259123440177362244273712468151750189745559978653234255886219611516"
+      "335924167958029604477064946470184777360934300451421683607013647479513962"
+      "13837722826145437693412532098591327667236328125",
+      -308, first_normal, second_normal, first_normal);
+
+  // penultimate_normal and last_normal.  Round-to-even rounds down.
+  TestHalfwayValue(
+      "1."
+      "797693134862315608353258760581052985162070023416521662616611746258695532"
+      "672923265745300992879465492467506314903358770175220871059269879629062776"
+      "047355692132901909191523941804762171253349609463563872612866401980290377"
+      "995141836029815117562837277714038305214839639239356331336428021390916694"
+      "57927874464075218944",
+      308, penultimate_normal, last_normal, penultimate_normal);
+}
+
+// Same test cases as DoubleRounding, now with new and improved Much Smaller
+// Precision!
+TEST(FromChars, FloatRounding) {
+  const float zero = 0.0;
+  const float first_subnormal = nextafterf(zero, 1.0);
+  const float second_subnormal = nextafterf(first_subnormal, 1.0);
+
+  const float first_normal = FLT_MIN;
+  const float last_subnormal = nextafterf(first_normal, 0.0);
+  const float second_normal = nextafterf(first_normal, 1.0);
+
+  const float last_normal = FLT_MAX;
+  const float penultimate_normal = nextafterf(last_normal, 0.0);
+
+  // Test between zero and first_subnormal.  Round-to-even tie rounds down.
+  TestHalfwayValue(
+      "7."
+      "006492321624085354618647916449580656401309709382578858785341419448955413"
+      "42930300743319094181060791015625",
+      -46, zero, first_subnormal, zero);
+
+  // first_subnormal and second_subnormal.  Round-to-even tie rounds up.
+  TestHalfwayValue(
+      "2."
+      "101947696487225606385594374934874196920392912814773657635602425834686624"
+      "028790902229957282543182373046875",
+      -45, first_subnormal, second_subnormal, second_subnormal);
+
+  // last_subnormal and first_normal.  Round-to-even tie rounds up.
+  TestHalfwayValue(
+      "1."
+      "175494280757364291727882991035766513322858992758990427682963118425003064"
+      "9651730385585324256680905818939208984375",
+      -38, last_subnormal, first_normal, first_normal);
+
+  // first_normal and second_normal.  Round-to-even tie rounds down.
+  TestHalfwayValue(
+      "1."
+      "175494420887210724209590083408724842314472120785184615334540294131831453"
+      "9442813071445925743319094181060791015625",
+      -38, first_normal, second_normal, first_normal);
+
+  // penultimate_normal and last_normal.  Round-to-even rounds down.
+  TestHalfwayValue("3.40282336497324057985868971510891282432", 38,
+                   penultimate_normal, last_normal, penultimate_normal);
+}
+
+TEST(FromChars, Underflow) {
+  // Check that underflow is handled correctly, according to the specification
+  // in DR 3081.
+  double d;
+  float f;
+  absl::from_chars_result result;
+
+  std::string negative_underflow = "-1e-1000";
+  const char* begin = negative_underflow.data();
+  const char* end = begin + negative_underflow.size();
+  d = 100.0;
+  result = absl::from_chars(begin, end, d);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_TRUE(std::signbit(d));  // negative
+  EXPECT_GE(d, -std::numeric_limits<double>::min());
+  f = 100.0;
+  result = absl::from_chars(begin, end, f);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_TRUE(std::signbit(f));  // negative
+  EXPECT_GE(f, -std::numeric_limits<float>::min());
+
+  std::string positive_underflow = "1e-1000";
+  begin = positive_underflow.data();
+  end = begin + positive_underflow.size();
+  d = -100.0;
+  result = absl::from_chars(begin, end, d);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_FALSE(std::signbit(d));  // positive
+  EXPECT_LE(d, std::numeric_limits<double>::min());
+  f = -100.0;
+  result = absl::from_chars(begin, end, f);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_FALSE(std::signbit(f));  // positive
+  EXPECT_LE(f, std::numeric_limits<float>::min());
+}
+
+TEST(FromChars, Overflow) {
+  // Check that overflow is handled correctly, according to the specification
+  // in DR 3081.
+  double d;
+  float f;
+  absl::from_chars_result result;
+
+  std::string negative_overflow = "-1e1000";
+  const char* begin = negative_overflow.data();
+  const char* end = begin + negative_overflow.size();
+  d = 100.0;
+  result = absl::from_chars(begin, end, d);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_TRUE(std::signbit(d));  // negative
+  EXPECT_EQ(d, -std::numeric_limits<double>::max());
+  f = 100.0;
+  result = absl::from_chars(begin, end, f);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_TRUE(std::signbit(f));  // negative
+  EXPECT_EQ(f, -std::numeric_limits<float>::max());
+
+  std::string positive_overflow = "1e1000";
+  begin = positive_overflow.data();
+  end = begin + positive_overflow.size();
+  d = -100.0;
+  result = absl::from_chars(begin, end, d);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_FALSE(std::signbit(d));  // positive
+  EXPECT_EQ(d, std::numeric_limits<double>::max());
+  f = -100.0;
+  result = absl::from_chars(begin, end, f);
+  EXPECT_EQ(result.ptr, end);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_FALSE(std::signbit(f));  // positive
+  EXPECT_EQ(f, std::numeric_limits<float>::max());
+}
+
+TEST(FromChars, ReturnValuePtr) {
+  // Check that `ptr` points one past the number scanned, even if that number
+  // is not representable.
+  double d;
+  absl::from_chars_result result;
+
+  std::string normal = "3.14@#$%@#$%";
+  result = absl::from_chars(normal.data(), normal.data() + normal.size(), d);
+  EXPECT_EQ(result.ec, std::errc());
+  EXPECT_EQ(result.ptr - normal.data(), 4);
+
+  std::string overflow = "1e1000@#$%@#$%";
+  result = absl::from_chars(overflow.data(),
+                            overflow.data() + overflow.size(), d);
+  EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+  EXPECT_EQ(result.ptr - overflow.data(), 6);
+
+  std::string garbage = "#$%@#$%";
+  result = absl::from_chars(garbage.data(),
+                            garbage.data() + garbage.size(), d);
+  EXPECT_EQ(result.ec, std::errc::invalid_argument);
+  EXPECT_EQ(result.ptr - garbage.data(), 0);
+}
+
+// Check for a wide range of inputs that strtod() and absl::from_chars() exactly
+// agree on the conversion amount.
+//
+// This test assumes the platform's strtod() uses perfect round_to_nearest
+// rounding.
+TEST(FromChars, TestVersusStrtod) {
+  for (int mantissa = 1000000; mantissa <= 9999999; mantissa += 501) {
+    for (int exponent = -300; exponent < 300; ++exponent) {
+      std::string candidate = absl::StrCat(mantissa, "e", exponent);
+      double strtod_value = strtod(candidate.c_str(), nullptr);
+      double absl_value = 0;
+      absl::from_chars(candidate.data(), candidate.data() + candidate.size(),
+                       absl_value);
+      ASSERT_EQ(strtod_value, absl_value) << candidate;
+    }
+  }
+}
+
+// Check for a wide range of inputs that strtof() and absl::from_chars() exactly
+// agree on the conversion amount.
+//
+// This test assumes the platform's strtof() uses perfect round_to_nearest
+// rounding.
+TEST(FromChars, TestVersusStrtof) {
+  for (int mantissa = 1000000; mantissa <= 9999999; mantissa += 501) {
+    for (int exponent = -43; exponent < 32; ++exponent) {
+      std::string candidate = absl::StrCat(mantissa, "e", exponent);
+      float strtod_value = strtof(candidate.c_str(), nullptr);
+      float absl_value = 0;
+      absl::from_chars(candidate.data(), candidate.data() + candidate.size(),
+                       absl_value);
+      ASSERT_EQ(strtod_value, absl_value) << candidate;
+    }
+  }
+}
+
+// Tests if two floating point values have identical bit layouts.  (EXPECT_EQ
+// is not suitable for NaN testing, since NaNs are never equal.)
+template <typename Float>
+bool Identical(Float a, Float b) {
+  return 0 == memcmp(&a, &b, sizeof(Float));
+}
+
+// Check that NaNs are parsed correctly.  The spec requires that
+// std::from_chars on "NaN(123abc)" return the same value as std::nan("123abc").
+// How such an n-char-sequence affects the generated NaN is unspecified, so we
+// just test for symmetry with std::nan and strtod here.
+//
+// (In Linux, this parses the value as a number and stuffs that number into the
+// free bits of a quiet NaN.)
+TEST(FromChars, NaNDoubles) {
+  for (std::string n_char_sequence :
+       {"", "1", "2", "3", "fff", "FFF", "200000", "400000", "4000000000000",
+        "8000000000000", "abc123", "legal_but_unexpected",
+        "99999999999999999999999", "_"}) {
+    std::string input = absl::StrCat("nan(", n_char_sequence, ")");
+    SCOPED_TRACE(input);
+    double from_chars_double;
+    absl::from_chars(input.data(), input.data() + input.size(),
+                     from_chars_double);
+    double std_nan_double = std::nan(n_char_sequence.c_str());
+    EXPECT_TRUE(Identical(from_chars_double, std_nan_double));
+
+    // Also check that we match strtod()'s behavior.  This test assumes that the
+    // platform has a compliant strtod().
+#if ABSL_STRTOD_HANDLES_NAN_CORRECTLY
+    double strtod_double = strtod(input.c_str(), nullptr);
+    EXPECT_TRUE(Identical(from_chars_double, strtod_double));
+#endif  // ABSL_STRTOD_HANDLES_NAN_CORRECTLY
+
+    // Check that we can parse a negative NaN
+    std::string negative_input = "-" + input;
+    double negative_from_chars_double;
+    absl::from_chars(negative_input.data(),
+                     negative_input.data() + negative_input.size(),
+                     negative_from_chars_double);
+    EXPECT_TRUE(std::signbit(negative_from_chars_double));
+    EXPECT_FALSE(Identical(negative_from_chars_double, from_chars_double));
+    from_chars_double = std::copysign(from_chars_double, -1.0);
+    EXPECT_TRUE(Identical(negative_from_chars_double, from_chars_double));
+  }
+}
+
+TEST(FromChars, NaNFloats) {
+  for (std::string n_char_sequence :
+       {"", "1", "2", "3", "fff", "FFF", "200000", "400000", "4000000000000",
+        "8000000000000", "abc123", "legal_but_unexpected",
+        "99999999999999999999999", "_"}) {
+    std::string input = absl::StrCat("nan(", n_char_sequence, ")");
+    SCOPED_TRACE(input);
+    float from_chars_float;
+    absl::from_chars(input.data(), input.data() + input.size(),
+                     from_chars_float);
+    float std_nan_float = std::nanf(n_char_sequence.c_str());
+    EXPECT_TRUE(Identical(from_chars_float, std_nan_float));
+
+    // Also check that we match strtof()'s behavior.  This test assumes that the
+    // platform has a compliant strtof().
+#if ABSL_STRTOD_HANDLES_NAN_CORRECTLY
+    float strtof_float = strtof(input.c_str(), nullptr);
+    EXPECT_TRUE(Identical(from_chars_float, strtof_float));
+#endif  // ABSL_STRTOD_HANDLES_NAN_CORRECTLY
+
+    // Check that we can parse a negative NaN
+    std::string negative_input = "-" + input;
+    float negative_from_chars_float;
+    absl::from_chars(negative_input.data(),
+                     negative_input.data() + negative_input.size(),
+                     negative_from_chars_float);
+    EXPECT_TRUE(std::signbit(negative_from_chars_float));
+    EXPECT_FALSE(Identical(negative_from_chars_float, from_chars_float));
+    from_chars_float = std::copysign(from_chars_float, -1.0);
+    EXPECT_TRUE(Identical(negative_from_chars_float, from_chars_float));
+  }
+}
+
+// Returns an integer larger than step.  The values grow exponentially.
+int NextStep(int step) {
+  return step + (step >> 2) + 1;
+}
+
+// Test a conversion on a family of input strings, checking that the calculation
+// is correct for in-bounds values, and that overflow and underflow are done
+// correctly for out-of-bounds values.
+//
+// input_generator maps from an integer index to a std::string to test.
+// expected_generator maps from an integer index to an expected Float value.
+// from_chars conversion of input_generator(i) should result in
+// expected_generator(i).
+//
+// lower_bound and upper_bound denote the smallest and largest values for which
+// the conversion is expected to succeed.
+template <typename Float>
+void TestOverflowAndUnderflow(
+    const std::function<std::string(int)>& input_generator,
+    const std::function<Float(int)>& expected_generator, int lower_bound,
+    int upper_bound) {
+  // test legal values near lower_bound
+  int index, step;
+  for (index = lower_bound, step = 1; index < upper_bound;
+       index += step, step = NextStep(step)) {
+    std::string input = input_generator(index);
+    SCOPED_TRACE(input);
+    Float expected = expected_generator(index);
+    Float actual;
+    auto result =
+        absl::from_chars(input.data(), input.data() + input.size(), actual);
+    EXPECT_EQ(result.ec, std::errc());
+    EXPECT_EQ(expected, actual);
+  }
+  // test legal values near upper_bound
+  for (index = upper_bound, step = 1; index > lower_bound;
+       index -= step, step = NextStep(step)) {
+    std::string input = input_generator(index);
+    SCOPED_TRACE(input);
+    Float expected = expected_generator(index);
+    Float actual;
+    auto result =
+        absl::from_chars(input.data(), input.data() + input.size(), actual);
+    EXPECT_EQ(result.ec, std::errc());
+    EXPECT_EQ(expected, actual);
+  }
+  // Test underflow values below lower_bound
+  for (index = lower_bound - 1, step = 1; index > -1000000;
+       index -= step, step = NextStep(step)) {
+    std::string input = input_generator(index);
+    SCOPED_TRACE(input);
+    Float actual;
+    auto result =
+        absl::from_chars(input.data(), input.data() + input.size(), actual);
+    EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+    EXPECT_LT(actual, 1.0);  // check for underflow
+  }
+  // Test overflow values above upper_bound
+  for (index = upper_bound + 1, step = 1; index < 1000000;
+       index += step, step = NextStep(step)) {
+    std::string input = input_generator(index);
+    SCOPED_TRACE(input);
+    Float actual;
+    auto result =
+        absl::from_chars(input.data(), input.data() + input.size(), actual);
+    EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+    EXPECT_GT(actual, 1.0);  // check for overflow
+  }
+}
+
+// Check that overflow and underflow are caught correctly for hex doubles.
+//
+// The largest representable double is 0x1.fffffffffffffp+1023, and the
+// smallest representable subnormal is 0x0.0000000000001p-1022, which equals
+// 0x1p-1074.  Therefore 1023 and -1074 are the limits of acceptable exponents
+// in this test.
+TEST(FromChars, HexdecimalDoubleLimits) {
+  auto input_gen = [](int index) { return absl::StrCat("0x1.0p", index); };
+  auto expected_gen = [](int index) { return std::ldexp(1.0, index); };
+  TestOverflowAndUnderflow<double>(input_gen, expected_gen, -1074, 1023);
+}
+
+// Check that overflow and underflow are caught correctly for hex floats.
+//
+// The largest representable float is 0x1.fffffep+127, and the smallest
+// representable subnormal is 0x0.000002p-126, which equals 0x1p-149.
+// Therefore 127 and -149 are the limits of acceptable exponents in this test.
+TEST(FromChars, HexdecimalFloatLimits) {
+  auto input_gen = [](int index) { return absl::StrCat("0x1.0p", index); };
+  auto expected_gen = [](int index) { return std::ldexp(1.0f, index); };
+  TestOverflowAndUnderflow<float>(input_gen, expected_gen, -149, 127);
+}
+
+// Check that overflow and underflow are caught correctly for decimal doubles.
+//
+// The largest representable double is about 1.8e308, and the smallest
+// representable subnormal is about 5e-324.  '1e-324' therefore rounds away from
+// the smallest representable positive value.  -323 and 308 are the limits of
+// acceptable exponents in this test.
+TEST(FromChars, DecimalDoubleLimits) {
+  auto input_gen = [](int index) { return absl::StrCat("1.0e", index); };
+  auto expected_gen = [](int index) { return std::pow(10.0, index); };
+  TestOverflowAndUnderflow<double>(input_gen, expected_gen, -323, 308);
+}
+
+// Check that overflow and underflow are caught correctly for decimal floats.
+//
+// The largest representable float is about 3.4e38, and the smallest
+// representable subnormal is about 1.45e-45.  '1e-45' therefore rounds towards
+// the smallest representable positive value.  -45 and 38 are the limits of
+// acceptable exponents in this test.
+TEST(FromChars, DecimalFloatLimits) {
+  auto input_gen = [](int index) { return absl::StrCat("1.0e", index); };
+  auto expected_gen = [](int index) { return std::pow(10.0, index); };
+  TestOverflowAndUnderflow<float>(input_gen, expected_gen, -45, 38);
+}
+
+}  // namespace
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
new file mode 100644
index 0000000..fbc9f75
--- /dev/null
+++ b/absl/strings/escaping.cc
@@ -0,0 +1,1109 @@
+// Copyright 2017 The Abseil 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 "absl/strings/escaping.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <string>
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/strings/internal/char_map.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/utf8.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace {
+
+// Digit conversion.
+constexpr char kHexChar[] = "0123456789abcdef";
+
+constexpr char kHexTable[513] =
+    "000102030405060708090a0b0c0d0e0f"
+    "101112131415161718191a1b1c1d1e1f"
+    "202122232425262728292a2b2c2d2e2f"
+    "303132333435363738393a3b3c3d3e3f"
+    "404142434445464748494a4b4c4d4e4f"
+    "505152535455565758595a5b5c5d5e5f"
+    "606162636465666768696a6b6c6d6e6f"
+    "707172737475767778797a7b7c7d7e7f"
+    "808182838485868788898a8b8c8d8e8f"
+    "909192939495969798999a9b9c9d9e9f"
+    "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+    "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+    "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+    "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+    "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+    "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+// These are used for the leave_nulls_escaped argument to CUnescapeInternal().
+constexpr bool kUnescapeNulls = false;
+
+inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); }
+
+inline int hex_digit_to_int(char c) {
+  static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61,
+                "Character set must be ASCII.");
+  assert(absl::ascii_isxdigit(c));
+  int x = static_cast<unsigned char>(c);
+  if (x > '9') {
+    x += 9;
+  }
+  return x & 0xf;
+}
+
+inline bool IsSurrogate(char32_t c, absl::string_view src, std::string* error) {
+  if (c >= 0xD800 && c <= 0xDFFF) {
+    if (error) {
+      *error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\",
+                            src);
+    }
+    return true;
+  }
+  return false;
+}
+
+// ----------------------------------------------------------------------
+// CUnescapeInternal()
+//    Implements both CUnescape() and CUnescapeForNullTerminatedString().
+//
+//    Unescapes C escape sequences and is the reverse of CEscape().
+//
+//    If 'source' is valid, stores the unescaped std::string and its size in
+//    'dest' and 'dest_len' respectively, and returns true. Otherwise
+//    returns false and optionally stores the error description in
+//    'error'. Set 'error' to nullptr to disable error reporting.
+//
+//    'dest' should point to a buffer that is at least as big as 'source'.
+//    'source' and 'dest' may be the same.
+//
+//     NOTE: any changes to this function must also be reflected in the older
+//     UnescapeCEscapeSequences().
+// ----------------------------------------------------------------------
+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
+                       char* dest, ptrdiff_t* dest_len, std::string* error) {
+  char* d = dest;
+  const char* p = source.data();
+  const char* end = source.end();
+  const char* last_byte = end - 1;
+
+  // Small optimization for case where source = dest and there's no escaping
+  while (p == d && p < end && *p != '\\') p++, d++;
+
+  while (p < end) {
+    if (*p != '\\') {
+      *d++ = *p++;
+    } else {
+      if (++p > last_byte) {  // skip past the '\\'
+        if (error) *error = "String cannot end with \\";
+        return false;
+      }
+      switch (*p) {
+        case 'a':  *d++ = '\a';  break;
+        case 'b':  *d++ = '\b';  break;
+        case 'f':  *d++ = '\f';  break;
+        case 'n':  *d++ = '\n';  break;
+        case 'r':  *d++ = '\r';  break;
+        case 't':  *d++ = '\t';  break;
+        case 'v':  *d++ = '\v';  break;
+        case '\\': *d++ = '\\';  break;
+        case '?':  *d++ = '\?';  break;    // \?  Who knew?
+        case '\'': *d++ = '\'';  break;
+        case '"':  *d++ = '\"';  break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7': {
+          // octal digit: 1 to 3 digits
+          const char* octal_start = p;
+          unsigned int ch = *p - '0';
+          if (p < last_byte && is_octal_digit(p[1])) ch = ch * 8 + *++p - '0';
+          if (p < last_byte && is_octal_digit(p[1]))
+            ch = ch * 8 + *++p - '0';      // now points at last digit
+          if (ch > 0xff) {
+            if (error) {
+              *error = "Value of \\" +
+                       std::string(octal_start, p + 1 - octal_start) +
+                       " exceeds 0xff";
+            }
+            return false;
+          }
+          if ((ch == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            const ptrdiff_t octal_size = p + 1 - octal_start;
+            *d++ = '\\';
+            memcpy(d, octal_start, octal_size);
+            d += octal_size;
+            break;
+          }
+          *d++ = ch;
+          break;
+        }
+        case 'x':
+        case 'X': {
+          if (p >= last_byte) {
+            if (error) *error = "String cannot end with \\x";
+            return false;
+          } else if (!absl::ascii_isxdigit(p[1])) {
+            if (error) *error = "\\x cannot be followed by a non-hex digit";
+            return false;
+          }
+          unsigned int ch = 0;
+          const char* hex_start = p;
+          while (p < last_byte && absl::ascii_isxdigit(p[1]))
+            // Arbitrarily many hex digits
+            ch = (ch << 4) + hex_digit_to_int(*++p);
+          if (ch > 0xFF) {
+            if (error) {
+              *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) +
+                       " exceeds 0xff";
+            }
+            return false;
+          }
+          if ((ch == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            const ptrdiff_t hex_size = p + 1 - hex_start;
+            *d++ = '\\';
+            memcpy(d, hex_start, hex_size);
+            d += hex_size;
+            break;
+          }
+          *d++ = ch;
+          break;
+        }
+        case 'u': {
+          // \uhhhh => convert 4 hex digits to UTF-8
+          char32_t rune = 0;
+          const char* hex_start = p;
+          if (p + 4 >= end) {
+            if (error) {
+              *error = "\\u must be followed by 4 hex digits: \\" +
+                       std::string(hex_start, p + 1 - hex_start);
+            }
+            return false;
+          }
+          for (int i = 0; i < 4; ++i) {
+            // Look one char ahead.
+            if (absl::ascii_isxdigit(p[1])) {
+              rune = (rune << 4) + hex_digit_to_int(*++p);  // Advance p.
+            } else {
+              if (error) {
+                *error = "\\u must be followed by 4 hex digits: \\" +
+                         std::string(hex_start, p + 1 - hex_start);
+              }
+              return false;
+            }
+          }
+          if ((rune == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            *d++ = '\\';
+            memcpy(d, hex_start, 5);  // u0000
+            d += 5;
+            break;
+          }
+          if (IsSurrogate(rune, absl::string_view(hex_start, 5), error)) {
+            return false;
+          }
+          d += strings_internal::EncodeUTF8Char(d, rune);
+          break;
+        }
+        case 'U': {
+          // \Uhhhhhhhh => convert 8 hex digits to UTF-8
+          char32_t rune = 0;
+          const char* hex_start = p;
+          if (p + 8 >= end) {
+            if (error) {
+              *error = "\\U must be followed by 8 hex digits: \\" +
+                       std::string(hex_start, p + 1 - hex_start);
+            }
+            return false;
+          }
+          for (int i = 0; i < 8; ++i) {
+            // Look one char ahead.
+            if (absl::ascii_isxdigit(p[1])) {
+              // Don't change rune until we're sure this
+              // is within the Unicode limit, but do advance p.
+              uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p);
+              if (newrune > 0x10FFFF) {
+                if (error) {
+                  *error = "Value of \\" +
+                           std::string(hex_start, p + 1 - hex_start) +
+                           " exceeds Unicode limit (0x10FFFF)";
+                }
+                return false;
+              } else {
+                rune = newrune;
+              }
+            } else {
+              if (error) {
+                *error = "\\U must be followed by 8 hex digits: \\" +
+                         std::string(hex_start, p + 1 - hex_start);
+              }
+              return false;
+            }
+          }
+          if ((rune == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            *d++ = '\\';
+            memcpy(d, hex_start, 9);  // U00000000
+            d += 9;
+            break;
+          }
+          if (IsSurrogate(rune, absl::string_view(hex_start, 9), error)) {
+            return false;
+          }
+          d += strings_internal::EncodeUTF8Char(d, rune);
+          break;
+        }
+        default: {
+          if (error) *error = std::string("Unknown escape sequence: \\") + *p;
+          return false;
+        }
+      }
+      p++;                                 // read past letter we escaped
+    }
+  }
+  *dest_len = d - dest;
+  return true;
+}
+
+// ----------------------------------------------------------------------
+// CUnescapeInternal()
+//
+//    Same as above but uses a C++ std::string for output. 'source' and 'dest'
+//    may be the same.
+// ----------------------------------------------------------------------
+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
+                       std::string* dest, std::string* error) {
+  strings_internal::STLStringResizeUninitialized(dest, source.size());
+
+  ptrdiff_t dest_size;
+  if (!CUnescapeInternal(source,
+                         leave_nulls_escaped,
+                         const_cast<char*>(dest->data()),
+                         &dest_size,
+                         error)) {
+    return false;
+  }
+  dest->erase(dest_size);
+  return true;
+}
+
+// ----------------------------------------------------------------------
+// CEscape()
+// CHexEscape()
+// Utf8SafeCEscape()
+// Utf8SafeCHexEscape()
+//    Escapes 'src' using C-style escape sequences.  This is useful for
+//    preparing query flags.  The 'Hex' version uses hexadecimal rather than
+//    octal sequences.  The 'Utf8Safe' version does not touch UTF-8 bytes.
+//
+//    Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
+// ----------------------------------------------------------------------
+std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) {
+  std::string dest;
+  bool last_hex_escape = false;  // true if last output char was \xNN.
+
+  for (unsigned char c : src) {
+    bool is_hex_escape = false;
+    switch (c) {
+      case '\n': dest.append("\\" "n"); break;
+      case '\r': dest.append("\\" "r"); break;
+      case '\t': dest.append("\\" "t"); break;
+      case '\"': dest.append("\\" "\""); break;
+      case '\'': dest.append("\\" "'"); break;
+      case '\\': dest.append("\\" "\\"); break;
+      default:
+        // Note that if we emit \xNN and the src character after that is a hex
+        // digit then that digit must be escaped too to prevent it being
+        // interpreted as part of the character code by C.
+        if ((!utf8_safe || c < 0x80) &&
+            (!absl::ascii_isprint(c) ||
+             (last_hex_escape && absl::ascii_isxdigit(c)))) {
+          if (use_hex) {
+            dest.append("\\" "x");
+            dest.push_back(kHexChar[c / 16]);
+            dest.push_back(kHexChar[c % 16]);
+            is_hex_escape = true;
+          } else {
+            dest.append("\\");
+            dest.push_back(kHexChar[c / 64]);
+            dest.push_back(kHexChar[(c % 64) / 8]);
+            dest.push_back(kHexChar[c % 8]);
+          }
+        } else {
+          dest.push_back(c);
+          break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+
+  return dest;
+}
+
+/* clang-format off */
+constexpr char c_escaped_len[256] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4,  // \t, \n, \r
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,  // ", '
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+/* clang-format on */
+
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+inline size_t CEscapedLength(absl::string_view src) {
+  size_t escaped_len = 0;
+  for (unsigned char c : src) escaped_len += c_escaped_len[c];
+  return escaped_len;
+}
+
+void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
+  size_t escaped_len = CEscapedLength(src);
+  if (escaped_len == src.size()) {
+    dest->append(src.data(), src.size());
+    return;
+  }
+
+  size_t cur_dest_len = dest->size();
+  strings_internal::STLStringResizeUninitialized(dest,
+                                                 cur_dest_len + escaped_len);
+  char* append_ptr = &(*dest)[cur_dest_len];
+
+  for (unsigned char c : src) {
+    int char_len = c_escaped_len[c];
+    if (char_len == 1) {
+      *append_ptr++ = c;
+    } else if (char_len == 2) {
+      switch (c) {
+        case '\n':
+          *append_ptr++ = '\\';
+          *append_ptr++ = 'n';
+          break;
+        case '\r':
+          *append_ptr++ = '\\';
+          *append_ptr++ = 'r';
+          break;
+        case '\t':
+          *append_ptr++ = '\\';
+          *append_ptr++ = 't';
+          break;
+        case '\"':
+          *append_ptr++ = '\\';
+          *append_ptr++ = '\"';
+          break;
+        case '\'':
+          *append_ptr++ = '\\';
+          *append_ptr++ = '\'';
+          break;
+        case '\\':
+          *append_ptr++ = '\\';
+          *append_ptr++ = '\\';
+          break;
+      }
+    } else {
+      *append_ptr++ = '\\';
+      *append_ptr++ = '0' + c / 64;
+      *append_ptr++ = '0' + (c % 64) / 8;
+      *append_ptr++ = '0' + c % 8;
+    }
+  }
+}
+
+bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest,
+                            size_t szdest, const signed char* unbase64,
+                            size_t* len) {
+  static const char kPad64Equals = '=';
+  static const char kPad64Dot = '.';
+
+  size_t destidx = 0;
+  int decode = 0;
+  int state = 0;
+  unsigned int ch = 0;
+  unsigned int temp = 0;
+
+  // If "char" is signed by default, using *src as an array index results in
+  // accessing negative array elements. Treat the input as a pointer to
+  // unsigned char to avoid this.
+  const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param);
+
+  // The GET_INPUT macro gets the next input character, skipping
+  // over any whitespace, and stopping when we reach the end of the
+  // std::string or when we read any non-data character.  The arguments are
+  // an arbitrary identifier (used as a label for goto) and the number
+  // of data bytes that must remain in the input to avoid aborting the
+  // loop.
+#define GET_INPUT(label, remain)                                \
+  label:                                                        \
+  --szsrc;                                                      \
+  ch = *src++;                                                  \
+  decode = unbase64[ch];                                        \
+  if (decode < 0) {                                             \
+    if (absl::ascii_isspace(ch) && szsrc >= remain) goto label; \
+    state = 4 - remain;                                         \
+    break;                                                      \
+  }
+
+  // if dest is null, we're just checking to see if it's legal input
+  // rather than producing output.  (I suspect this could just be done
+  // with a regexp...).  We duplicate the loop so this test can be
+  // outside it instead of in every iteration.
+
+  if (dest) {
+    // This loop consumes 4 input bytes and produces 3 output bytes
+    // per iteration.  We can't know at the start that there is enough
+    // data left in the std::string for a full iteration, so the loop may
+    // break out in the middle; if so 'state' will be set to the
+    // number of input bytes read.
+
+    while (szsrc >= 4) {
+      // We'll start by optimistically assuming that the next four
+      // bytes of the std::string (src[0..3]) are four good data bytes
+      // (that is, no nulls, whitespace, padding chars, or illegal
+      // chars).  We need to test src[0..2] for nulls individually
+      // before constructing temp to preserve the property that we
+      // never read past a null in the std::string (no matter how long
+      // szsrc claims the std::string is).
+
+      if (!src[0] || !src[1] || !src[2] ||
+          ((temp = ((unsigned(unbase64[src[0]]) << 18) |
+                    (unsigned(unbase64[src[1]]) << 12) |
+                    (unsigned(unbase64[src[2]]) << 6) |
+                    (unsigned(unbase64[src[3]])))) &
+           0x80000000)) {
+        // Iff any of those four characters was bad (null, illegal,
+        // whitespace, padding), then temp's high bit will be set
+        // (because unbase64[] is -1 for all bad characters).
+        //
+        // We'll back up and resort to the slower decoder, which knows
+        // how to handle those cases.
+
+        GET_INPUT(first, 4);
+        temp = decode;
+        GET_INPUT(second, 3);
+        temp = (temp << 6) | decode;
+        GET_INPUT(third, 2);
+        temp = (temp << 6) | decode;
+        GET_INPUT(fourth, 1);
+        temp = (temp << 6) | decode;
+      } else {
+        // We really did have four good data bytes, so advance four
+        // characters in the std::string.
+
+        szsrc -= 4;
+        src += 4;
+      }
+
+      // temp has 24 bits of input, so write that out as three bytes.
+
+      if (destidx + 3 > szdest) return false;
+      dest[destidx + 2] = temp;
+      temp >>= 8;
+      dest[destidx + 1] = temp;
+      temp >>= 8;
+      dest[destidx] = temp;
+      destidx += 3;
+    }
+  } else {
+    while (szsrc >= 4) {
+      if (!src[0] || !src[1] || !src[2] ||
+          ((temp = ((unsigned(unbase64[src[0]]) << 18) |
+                    (unsigned(unbase64[src[1]]) << 12) |
+                    (unsigned(unbase64[src[2]]) << 6) |
+                    (unsigned(unbase64[src[3]])))) &
+           0x80000000)) {
+        GET_INPUT(first_no_dest, 4);
+        GET_INPUT(second_no_dest, 3);
+        GET_INPUT(third_no_dest, 2);
+        GET_INPUT(fourth_no_dest, 1);
+      } else {
+        szsrc -= 4;
+        src += 4;
+      }
+      destidx += 3;
+    }
+  }
+
+#undef GET_INPUT
+
+  // if the loop terminated because we read a bad character, return
+  // now.
+  if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot &&
+      !absl::ascii_isspace(ch))
+    return false;
+
+  if (ch == kPad64Equals || ch == kPad64Dot) {
+    // if we stopped by hitting an '=' or '.', un-read that character -- we'll
+    // look at it again when we count to check for the proper number of
+    // equals signs at the end.
+    ++szsrc;
+    --src;
+  } else {
+    // This loop consumes 1 input byte per iteration.  It's used to
+    // clean up the 0-3 input bytes remaining when the first, faster
+    // loop finishes.  'temp' contains the data from 'state' input
+    // characters read by the first loop.
+    while (szsrc > 0) {
+      --szsrc;
+      ch = *src++;
+      decode = unbase64[ch];
+      if (decode < 0) {
+        if (absl::ascii_isspace(ch)) {
+          continue;
+        } else if (ch == kPad64Equals || ch == kPad64Dot) {
+          // back up one character; we'll read it again when we check
+          // for the correct number of pad characters at the end.
+          ++szsrc;
+          --src;
+          break;
+        } else {
+          return false;
+        }
+      }
+
+      // Each input character gives us six bits of output.
+      temp = (temp << 6) | decode;
+      ++state;
+      if (state == 4) {
+        // If we've accumulated 24 bits of output, write that out as
+        // three bytes.
+        if (dest) {
+          if (destidx + 3 > szdest) return false;
+          dest[destidx + 2] = temp;
+          temp >>= 8;
+          dest[destidx + 1] = temp;
+          temp >>= 8;
+          dest[destidx] = temp;
+        }
+        destidx += 3;
+        state = 0;
+        temp = 0;
+      }
+    }
+  }
+
+  // Process the leftover data contained in 'temp' at the end of the input.
+  int expected_equals = 0;
+  switch (state) {
+    case 0:
+      // Nothing left over; output is a multiple of 3 bytes.
+      break;
+
+    case 1:
+      // Bad input; we have 6 bits left over.
+      return false;
+
+    case 2:
+      // Produce one more output byte from the 12 input bits we have left.
+      if (dest) {
+        if (destidx + 1 > szdest) return false;
+        temp >>= 4;
+        dest[destidx] = temp;
+      }
+      ++destidx;
+      expected_equals = 2;
+      break;
+
+    case 3:
+      // Produce two more output bytes from the 18 input bits we have left.
+      if (dest) {
+        if (destidx + 2 > szdest) return false;
+        temp >>= 2;
+        dest[destidx + 1] = temp;
+        temp >>= 8;
+        dest[destidx] = temp;
+      }
+      destidx += 2;
+      expected_equals = 1;
+      break;
+
+    default:
+      // state should have no other values at this point.
+      ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d",
+                   state);
+  }
+
+  // The remainder of the std::string should be all whitespace, mixed with
+  // exactly 0 equals signs, or exactly 'expected_equals' equals
+  // signs.  (Always accepting 0 equals signs is an Abseil extension
+  // not covered in the RFC, as is accepting dot as the pad character.)
+
+  int equals = 0;
+  while (szsrc > 0) {
+    if (*src == kPad64Equals || *src == kPad64Dot)
+      ++equals;
+    else if (!absl::ascii_isspace(*src))
+      return false;
+    --szsrc;
+    ++src;
+  }
+
+  const bool ok = (equals == 0 || equals == expected_equals);
+  if (ok) *len = destidx;
+  return ok;
+}
+
+// The arrays below were generated by the following code
+// #include <sys/time.h>
+// #include <stdlib.h>
+// #include <std::string.h>
+// main()
+// {
+//   static const char Base64[] =
+//     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+//   char* pos;
+//   int idx, i, j;
+//   printf("    ");
+//   for (i = 0; i < 255; i += 8) {
+//     for (j = i; j < i + 8; j++) {
+//       pos = strchr(Base64, j);
+//       if ((pos == nullptr) || (j == 0))
+//         idx = -1;
+//       else
+//         idx = pos - Base64;
+//       if (idx == -1)
+//         printf(" %2d,     ", idx);
+//       else
+//         printf(" %2d/*%c*/,", idx, j);
+//     }
+//     printf("\n    ");
+//   }
+// }
+//
+// where the value of "Base64[]" was replaced by one of the base-64 conversion
+// tables from the functions below.
+/* clang-format off */
+constexpr signed char kUnBase64[] = {
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+    60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+    -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+    07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+    23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+    -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+    49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+constexpr signed char kUnWebSafeBase64[] = {
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      62/*-*/, -1,      -1,
+    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+    60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+    -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+    07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+    23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      63/*_*/,
+    -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+    49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+/* clang-format on */
+
+size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
+  // Base64 encodes three bytes of input at a time. If the input is not
+  // divisible by three, we pad as appropriate.
+  //
+  // (from http://tools.ietf.org/html/rfc3548)
+  // Special processing is performed if fewer than 24 bits are available
+  // at the end of the data being encoded.  A full encoding quantum is
+  // always completed at the end of a quantity.  When fewer than 24 input
+  // bits are available in an input group, zero bits are added (on the
+  // right) to form an integral number of 6-bit groups.  Padding at the
+  // end of the data is performed using the '=' character.  Since all base
+  // 64 input is an integral number of octets, only the following cases
+  // can arise:
+
+  // Base64 encodes each three bytes of input into four bytes of output.
+  size_t len = (input_len / 3) * 4;
+
+  if (input_len % 3 == 0) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (1) the final quantum of encoding input is an integral multiple of 24
+    // bits; here, the final unit of encoded output will be an integral
+    // multiple of 4 characters with no "=" padding,
+  } else if (input_len % 3 == 1) {
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (2) the final quantum of encoding input is exactly 8 bits; here, the
+    // final unit of encoded output will be two characters followed by two
+    // "=" padding characters, or
+    len += 2;
+    if (do_padding) {
+      len += 2;
+    }
+  } else {  // (input_len % 3 == 2)
+    // (from http://tools.ietf.org/html/rfc3548)
+    // (3) the final quantum of encoding input is exactly 16 bits; here, the
+    // final unit of encoded output will be three characters followed by one
+    // "=" padding character.
+    len += 3;
+    if (do_padding) {
+      len += 1;
+    }
+  }
+
+  assert(len >= input_len);  // make sure we didn't overflow
+  return len;
+}
+
+size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
+                            size_t szdest, const char* base64,
+                            bool do_padding) {
+  static const char kPad64 = '=';
+
+  if (szsrc * 4 > szdest * 3) return 0;
+
+  char* cur_dest = dest;
+  const unsigned char* cur_src = src;
+
+  char* const limit_dest = dest + szdest;
+  const unsigned char* const limit_src = src + szsrc;
+
+  // Three bytes of data encodes to four characters of cyphertext.
+  // So we can pump through three-byte chunks atomically.
+  if (szsrc >= 3) {  // "limit_src - 3" is UB if szsrc < 3
+    while (cur_src < limit_src - 3) {  // as long as we have >= 32 bits
+      uint32_t in = absl::big_endian::Load32(cur_src) >> 8;
+
+      cur_dest[0] = base64[in >> 18];
+      in &= 0x3FFFF;
+      cur_dest[1] = base64[in >> 12];
+      in &= 0xFFF;
+      cur_dest[2] = base64[in >> 6];
+      in &= 0x3F;
+      cur_dest[3] = base64[in];
+
+      cur_dest += 4;
+      cur_src += 3;
+    }
+  }
+  // To save time, we didn't update szdest or szsrc in the loop.  So do it now.
+  szdest = limit_dest - cur_dest;
+  szsrc = limit_src - cur_src;
+
+  /* now deal with the tail (<=3 bytes) */
+  switch (szsrc) {
+    case 0:
+      // Nothing left; nothing more to do.
+      break;
+    case 1: {
+      // One byte left: this encodes to two characters, and (optionally)
+      // two pad characters to round out the four-character cypherblock.
+      if (szdest < 2) return 0;
+      uint32_t in = cur_src[0];
+      cur_dest[0] = base64[in >> 2];
+      in &= 0x3;
+      cur_dest[1] = base64[in << 4];
+      cur_dest += 2;
+      szdest -= 2;
+      if (do_padding) {
+        if (szdest < 2) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest[1] = kPad64;
+        cur_dest += 2;
+        szdest -= 2;
+      }
+      break;
+    }
+    case 2: {
+      // Two bytes left: this encodes to three characters, and (optionally)
+      // one pad character to round out the four-character cypherblock.
+      if (szdest < 3) return 0;
+      uint32_t in = absl::big_endian::Load16(cur_src);
+      cur_dest[0] = base64[in >> 10];
+      in &= 0x3FF;
+      cur_dest[1] = base64[in >> 4];
+      in &= 0x00F;
+      cur_dest[2] = base64[in << 2];
+      cur_dest += 3;
+      szdest -= 3;
+      if (do_padding) {
+        if (szdest < 1) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest += 1;
+        szdest -= 1;
+      }
+      break;
+    }
+    case 3: {
+      // Three bytes left: same as in the big loop above.  We can't do this in
+      // the loop because the loop above always reads 4 bytes, and the fourth
+      // byte is past the end of the input.
+      if (szdest < 4) return 0;
+      uint32_t in = (cur_src[0] << 16) + absl::big_endian::Load16(cur_src + 1);
+      cur_dest[0] = base64[in >> 18];
+      in &= 0x3FFFF;
+      cur_dest[1] = base64[in >> 12];
+      in &= 0xFFF;
+      cur_dest[2] = base64[in >> 6];
+      in &= 0x3F;
+      cur_dest[3] = base64[in];
+      cur_dest += 4;
+      szdest -= 4;
+      break;
+    }
+    default:
+      // Should not be reached: blocks of 4 bytes are handled
+      // in the while loop before this switch statement.
+      ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc);
+      break;
+  }
+  return (cur_dest - dest);
+}
+
+constexpr char kBase64Chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+constexpr char kWebSafeBase64Chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+void Base64EscapeInternal(const unsigned char* src, size_t szsrc, std::string* dest,
+                          bool do_padding, const char* base64_chars) {
+  const size_t calc_escaped_size =
+      CalculateBase64EscapedLenInternal(szsrc, do_padding);
+  strings_internal::STLStringResizeUninitialized(dest, calc_escaped_size);
+
+  const size_t escaped_len = Base64EscapeInternal(
+      src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding);
+  assert(calc_escaped_size == escaped_len);
+  dest->erase(escaped_len);
+}
+
+bool Base64UnescapeInternal(const char* src, size_t slen, std::string* dest,
+                            const signed char* unbase64) {
+  // Determine the size of the output std::string.  Base64 encodes every 3 bytes into
+  // 4 characters.  any leftover chars are added directly for good measure.
+  // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
+  const size_t dest_len = 3 * (slen / 4) + (slen % 4);
+
+  strings_internal::STLStringResizeUninitialized(dest, dest_len);
+
+  // We are getting the destination buffer by getting the beginning of the
+  // std::string and converting it into a char *.
+  size_t len;
+  const bool ok =
+      Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
+  if (!ok) {
+    dest->clear();
+    return false;
+  }
+
+  // could be shorter if there was padding
+  assert(len <= dest_len);
+  dest->erase(len);
+
+  return true;
+}
+
+/* clang-format off */
+constexpr char kHexValue[256] = {
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  1,  2,  3,  4,  5,  6, 7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+/* clang-format on */
+
+// This is a templated function so that T can be either a char*
+// or a std::string.  This works because we use the [] operator to access
+// individual characters at a time.
+template <typename T>
+void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) {
+  for (int i = 0; i < num; i++) {
+    to[i] = (kHexValue[from[i * 2] & 0xFF] << 4) +
+            (kHexValue[from[i * 2 + 1] & 0xFF]);
+  }
+}
+
+// This is a templated function so that T can be either a char* or a std::string.
+template <typename T>
+void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) {
+  auto dest_ptr = &dest[0];
+  for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
+    const char* hex_p = &kHexTable[*src_ptr * 2];
+    std::copy(hex_p, hex_p + 2, dest_ptr);
+  }
+}
+
+}  // namespace
+
+// ----------------------------------------------------------------------
+// CUnescape()
+//
+// See CUnescapeInternal() for implementation details.
+// ----------------------------------------------------------------------
+bool CUnescape(absl::string_view source, std::string* dest, std::string* error) {
+  return CUnescapeInternal(source, kUnescapeNulls, dest, error);
+}
+
+std::string CEscape(absl::string_view src) {
+  std::string dest;
+  CEscapeAndAppendInternal(src, &dest);
+  return dest;
+}
+
+std::string CHexEscape(absl::string_view src) {
+  return CEscapeInternal(src, true, false);
+}
+
+std::string Utf8SafeCEscape(absl::string_view src) {
+  return CEscapeInternal(src, false, true);
+}
+
+std::string Utf8SafeCHexEscape(absl::string_view src) {
+  return CEscapeInternal(src, true, true);
+}
+
+// ----------------------------------------------------------------------
+// ptrdiff_t Base64Unescape() - base64 decoder
+// ptrdiff_t Base64Escape() - base64 encoder
+// ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder
+// ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://tools.ietf.org/html/rfc2045 for formal description, but what we
+// care about is that...
+//   Take the encoded stuff in groups of 4 characters and turn each
+//   character into a code 0 to 63 thus:
+//           A-Z map to 0 to 25
+//           a-z map to 26 to 51
+//           0-9 map to 52 to 61
+//           +(- for WebSafe) maps to 62
+//           /(_ for WebSafe) maps to 63
+//   There will be four numbers, all less than 64 which can be represented
+//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+//   Arrange the 6 digit binary numbers into three bytes as such:
+//   aaaaaabb bbbbcccc ccdddddd
+//   Equals signs (one or two) are used at the end of the encoded block to
+//   indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+bool Base64Unescape(absl::string_view src, std::string* dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
+}
+
+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
+}
+
+void Base64Escape(absl::string_view src, std::string* dest) {
+  Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
+                       src.size(), dest, true, kBase64Chars);
+}
+
+void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
+  Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
+                       src.size(), dest, false, kWebSafeBase64Chars);
+}
+
+std::string HexStringToBytes(absl::string_view from) {
+  std::string result;
+  const auto num = from.size() / 2;
+  strings_internal::STLStringResizeUninitialized(&result, num);
+  absl::HexStringToBytesInternal<std::string&>(from.data(), result, num);
+  return result;
+}
+
+std::string BytesToHexString(absl::string_view from) {
+  std::string result;
+  strings_internal::STLStringResizeUninitialized(&result, 2 * from.size());
+  absl::BytesToHexStringInternal<std::string&>(
+      reinterpret_cast<const unsigned char*>(from.data()), result, from.size());
+  return result;
+}
+
+}  // namespace absl
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h
new file mode 100644
index 0000000..1af0afa
--- /dev/null
+++ b/absl/strings/escaping.h
@@ -0,0 +1,161 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: escaping.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains std::string utilities involved in escaping and
+// unescaping strings in various ways.
+//
+
+#ifndef ABSL_STRINGS_ESCAPING_H_
+#define ABSL_STRINGS_ESCAPING_H_
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// CUnescape()
+//
+// Unescapes a `source` std::string and copies it into `dest`, rewriting C-style
+// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into
+// their proper code point equivalents, returning `true` if successful.
+//
+// The following unescape sequences can be handled:
+//
+//   * ASCII escape sequences ('\n','\r','\\', etc.) to their ASCII equivalents
+//   * Octal escape sequences ('\nnn') to byte nnn. The unescaped value must
+//     resolve to a single byte or an error will occur. E.g. values greater than
+//     0xff will produce an error.
+//   * Hexadecimal escape sequences ('\xnn') to byte nn. While an arbitrary
+//     number of following digits are allowed, the unescaped value must resolve
+//     to a single byte or an error will occur. E.g. '\x0045' is equivalent to
+//     '\x45', but '\x1234' will produce an error.
+//   * Unicode escape sequences ('\unnnn' for exactly four hex digits or
+//     '\Unnnnnnnn' for exactly eight hex digits, which will be encoded in
+//     UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and
+//     0x99).
+//
+//
+// If any errors are encountered, this function returns `false` and stores the
+// first encountered error in `error`. To disable error reporting, set `error`
+// to `nullptr` or use the overload with no error reporting below.
+//
+// Example:
+//
+//   std::string s = "foo\\rbar\\nbaz\\t";
+//   std::string unescaped_s;
+//   if (!absl::CUnescape(s, &unescaped_s) {
+//     ...
+//   }
+//   EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t");
+bool CUnescape(absl::string_view source, std::string* dest, std::string* error);
+
+// Overload of `CUnescape()` with no error reporting.
+inline bool CUnescape(absl::string_view source, std::string* dest) {
+  return CUnescape(source, dest, nullptr);
+}
+
+// CEscape()
+//
+// Escapes a 'src' std::string using C-style escapes sequences
+// (http://en.cppreference.com/w/cpp/language/escape), escaping other
+// non-printable/non-whitespace bytes as octal sequences (e.g. "\377").
+//
+// Example:
+//
+//   std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n";
+//   std::string escaped_s = absl::CEscape(s);
+//   EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\010\\t\\n\\013\\014\\r\\n");
+std::string CEscape(absl::string_view src);
+
+// CHexEscape()
+//
+// Escapes a 'src' std::string using C-style escape sequences, escaping
+// other non-printable/non-whitespace bytes as hexadecimal sequences (e.g.
+// "\xFF").
+//
+// Example:
+//
+//   std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n";
+//   std::string escaped_s = absl::CHexEscape(s);
+//   EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\x08\\t\\n\\x0b\\x0c\\r\\n");
+std::string CHexEscape(absl::string_view src);
+
+// Utf8SafeCEscape()
+//
+// Escapes a 'src' std::string using C-style escape sequences, escaping bytes as
+// octal sequences, and passing through UTF-8 characters without conversion.
+// I.e., when encountering any bytes with their high bit set, this function
+// will not escape those values, whether or not they are valid UTF-8.
+std::string Utf8SafeCEscape(absl::string_view src);
+
+// Utf8SafeCHexEscape()
+//
+// Escapes a 'src' std::string using C-style escape sequences, escaping bytes as
+// hexadecimal sequences, and passing through UTF-8 characters without
+// conversion.
+std::string Utf8SafeCHexEscape(absl::string_view src);
+
+// Base64Unescape()
+//
+// Converts a `src` std::string encoded in Base64 to its binary equivalent, writing
+// it to a `dest` buffer, returning `true` on success. If `src` contains invalid
+// characters, `dest` is cleared and returns `false`.
+bool Base64Unescape(absl::string_view src, std::string* dest);
+
+// WebSafeBase64Unescape(absl::string_view, std::string*)
+//
+// Converts a `src` std::string encoded in Base64 to its binary equivalent, writing
+// it to a `dest` buffer, but using '-' instead of '+', and '_' instead of '/'.
+// If `src` contains invalid characters, `dest` is cleared and returns `false`.
+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest);
+
+// Base64Escape()
+//
+// Encodes a `src` std::string into a `dest` buffer using base64 encoding, with
+// padding characters. This function conforms with RFC 4648 section 4 (base64).
+void Base64Escape(absl::string_view src, std::string* dest);
+
+// WebSafeBase64Escape()
+//
+// Encodes a `src` std::string into a `dest` buffer using uses '-' instead of '+' and
+// '_' instead of '/', and without padding. This function conforms with RFC 4648
+// section 5 (base64url).
+void WebSafeBase64Escape(absl::string_view src, std::string* dest);
+
+// HexStringToBytes()
+//
+// Converts an ASCII hex std::string into bytes, returning binary data of length
+// `from.size()/2`.
+std::string HexStringToBytes(absl::string_view from);
+
+// BytesToHexString()
+//
+// Converts binary data into an ASCII text std::string, returning a std::string of size
+// `2*from.size()`.
+std::string BytesToHexString(absl::string_view from);
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_ESCAPING_H_
diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc
new file mode 100644
index 0000000..0f791f4
--- /dev/null
+++ b/absl/strings/escaping_benchmark.cc
@@ -0,0 +1,94 @@
+// Copyright 2018 The Abseil 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 "absl/strings/escaping.h"
+
+#include <cstdio>
+#include <cstring>
+#include <random>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/internal/escaping_test_common.h"
+
+namespace {
+
+void BM_CUnescapeHexString(benchmark::State& state) {
+  std::string src;
+  for (int i = 0; i < 50; i++) {
+    src += "\\x55";
+  }
+  std::string dest;
+  for (auto _ : state) {
+    absl::CUnescape(src, &dest);
+  }
+}
+BENCHMARK(BM_CUnescapeHexString);
+
+void BM_WebSafeBase64Escape_string(benchmark::State& state) {
+  std::string raw;
+  for (int i = 0; i < 10; ++i) {
+    for (const auto& test_set : absl::strings_internal::base64_strings()) {
+      raw += std::string(test_set.plaintext);
+    }
+  }
+
+  // The actual benchmark loop is tiny...
+  std::string escaped;
+  for (auto _ : state) {
+    absl::WebSafeBase64Escape(raw, &escaped);
+  }
+
+  // We want to be sure the compiler doesn't throw away the loop above,
+  // and the easiest way to ensure that is to round-trip the results and verify
+  // them.
+  std::string round_trip;
+  absl::WebSafeBase64Unescape(escaped, &round_trip);
+  ABSL_RAW_CHECK(round_trip == raw, "");
+}
+BENCHMARK(BM_WebSafeBase64Escape_string);
+
+// Used for the CEscape benchmarks
+const char kStringValueNoEscape[] = "1234567890";
+const char kStringValueSomeEscaped[] = "123\n56789\xA1";
+const char kStringValueMostEscaped[] = "\xA1\xA2\ny\xA4\xA5\xA6z\b\r";
+
+void CEscapeBenchmarkHelper(benchmark::State& state, const char* string_value,
+                            int max_len) {
+  std::string src;
+  while (src.size() < max_len) {
+    absl::StrAppend(&src, string_value);
+  }
+
+  for (auto _ : state) {
+    absl::CEscape(src);
+  }
+}
+
+void BM_CEscape_NoEscape(benchmark::State& state) {
+  CEscapeBenchmarkHelper(state, kStringValueNoEscape, state.range(0));
+}
+BENCHMARK(BM_CEscape_NoEscape)->Range(1, 1 << 14);
+
+void BM_CEscape_SomeEscaped(benchmark::State& state) {
+  CEscapeBenchmarkHelper(state, kStringValueSomeEscaped, state.range(0));
+}
+BENCHMARK(BM_CEscape_SomeEscaped)->Range(1, 1 << 14);
+
+void BM_CEscape_MostEscaped(benchmark::State& state) {
+  CEscapeBenchmarkHelper(state, kStringValueMostEscaped, state.range(0));
+}
+BENCHMARK(BM_CEscape_MostEscaped)->Range(1, 1 << 14);
+
+}  // namespace
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
new file mode 100644
index 0000000..3f65ec1
--- /dev/null
+++ b/absl/strings/escaping_test.cc
@@ -0,0 +1,641 @@
+// Copyright 2017 The Abseil 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 "absl/strings/escaping.h"
+
+#include <array>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/container/fixed_array.h"
+#include "absl/strings/str_cat.h"
+
+#include "absl/strings/internal/escaping_test_common.h"
+
+namespace {
+
+struct epair {
+  std::string escaped;
+  std::string unescaped;
+};
+
+TEST(CEscape, EscapeAndUnescape) {
+  const std::string inputs[] = {
+    std::string("foo\nxx\r\b\0023"),
+    std::string(""),
+    std::string("abc"),
+    std::string("\1chad_rules"),
+    std::string("\1arnar_drools"),
+    std::string("xxxx\r\t'\"\\"),
+    std::string("\0xx\0", 4),
+    std::string("\x01\x31"),
+    std::string("abc\xb\x42\141bc"),
+    std::string("123\1\x31\x32\x33"),
+    std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
+    std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
+  };
+  // Do this twice, once for octal escapes and once for hex escapes.
+  for (int kind = 0; kind < 4; kind++) {
+    for (const std::string& original : inputs) {
+      std::string escaped;
+      switch (kind) {
+        case 0:
+          escaped = absl::CEscape(original);
+          break;
+        case 1:
+          escaped = absl::CHexEscape(original);
+          break;
+        case 2:
+          escaped = absl::Utf8SafeCEscape(original);
+          break;
+        case 3:
+          escaped = absl::Utf8SafeCHexEscape(original);
+          break;
+      }
+      std::string unescaped_str;
+      EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str));
+      EXPECT_EQ(unescaped_str, original);
+
+      // Check in-place unescaping
+      std::string s = escaped;
+      EXPECT_TRUE(absl::CUnescape(s, &s));
+      ASSERT_EQ(s, original);
+    }
+  }
+  // Check that all possible two character strings can be escaped then
+  // unescaped successfully.
+  for (int char0 = 0; char0 < 256; char0++) {
+    for (int char1 = 0; char1 < 256; char1++) {
+      char chars[2];
+      chars[0] = char0;
+      chars[1] = char1;
+      std::string s(chars, 2);
+      std::string escaped = absl::CHexEscape(s);
+      std::string unescaped;
+      EXPECT_TRUE(absl::CUnescape(escaped, &unescaped));
+      EXPECT_EQ(s, unescaped);
+    }
+  }
+}
+
+TEST(CEscape, BasicEscaping) {
+  epair oct_values[] = {
+      {"foo\\rbar\\nbaz\\t", "foo\rbar\nbaz\t"},
+      {"\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
+       "'full of \"sound\" and \"fury\"'"},
+      {"signi\\\\fying\\\\ nothing\\\\", "signi\\fying\\ nothing\\"},
+      {"\\010\\t\\n\\013\\014\\r", "\010\011\012\013\014\015"}
+  };
+  epair hex_values[] = {
+      {"ubik\\rubik\\nubik\\t", "ubik\rubik\nubik\t"},
+      {"I\\\'ve just seen a \\\"face\\\"",
+       "I've just seen a \"face\""},
+      {"hel\\\\ter\\\\skel\\\\ter\\\\", "hel\\ter\\skel\\ter\\"},
+      {"\\x08\\t\\n\\x0b\\x0c\\r", "\010\011\012\013\014\015"}
+  };
+  epair utf8_oct_values[] = {
+      {"\xe8\xb0\xb7\xe6\xad\x8c\\r\xe8\xb0\xb7\xe6\xad\x8c\\nbaz\\t",
+       "\xe8\xb0\xb7\xe6\xad\x8c\r\xe8\xb0\xb7\xe6\xad\x8c\nbaz\t"},
+      {"\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name",
+       "\"\xe8\xb0\xb7\xe6\xad\x8c\" is Google\'s Chinese name"},
+      {"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\\\are\\\\Japanese\\\\chars\\\\",
+       "\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\are\\Japanese\\chars\\"},
+      {"\xed\x81\xac\xeb\xa1\xac\\010\\t\\n\\013\\014\\r",
+       "\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"}
+  };
+  epair utf8_hex_values[] = {
+      {"\x20\xe4\xbd\xa0\\t\xe5\xa5\xbd,\\r!\\n",
+       "\x20\xe4\xbd\xa0\t\xe5\xa5\xbd,\r!\n"},
+      {"\xe8\xa9\xa6\xe9\xa8\x93\\\' means \\\"test\\\"",
+       "\xe8\xa9\xa6\xe9\xa8\x93\' means \"test\""},
+      {"\\\\\xe6\x88\x91\\\\:\\\\\xe6\x9d\xa8\xe6\xac\xa2\\\\",
+       "\\\xe6\x88\x91\\:\\\xe6\x9d\xa8\xe6\xac\xa2\\"},
+      {"\xed\x81\xac\xeb\xa1\xac\\x08\\t\\n\\x0b\\x0c\\r",
+       "\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"}
+  };
+
+  for (const epair& val : oct_values) {
+    std::string escaped = absl::CEscape(val.unescaped);
+    EXPECT_EQ(escaped, val.escaped);
+  }
+  for (const epair& val : hex_values) {
+    std::string escaped = absl::CHexEscape(val.unescaped);
+    EXPECT_EQ(escaped, val.escaped);
+  }
+  for (const epair& val : utf8_oct_values) {
+    std::string escaped = absl::Utf8SafeCEscape(val.unescaped);
+    EXPECT_EQ(escaped, val.escaped);
+  }
+  for (const epair& val : utf8_hex_values) {
+    std::string escaped = absl::Utf8SafeCHexEscape(val.unescaped);
+    EXPECT_EQ(escaped, val.escaped);
+  }
+}
+
+TEST(Unescape, BasicFunction) {
+  epair tests[] =
+    {{"\\u0030", "0"},
+     {"\\u00A3", "\xC2\xA3"},
+     {"\\u22FD", "\xE2\x8B\xBD"},
+     {"\\U00010000", "\xF0\x90\x80\x80"},
+     {"\\U0010FFFD", "\xF4\x8F\xBF\xBD"}};
+  for (const epair& val : tests) {
+    std::string out;
+    EXPECT_TRUE(absl::CUnescape(val.escaped, &out));
+    EXPECT_EQ(out, val.unescaped);
+  }
+  std::string bad[] =
+     {"\\u1",         // too short
+      "\\U1",         // too short
+      "\\Uffffff",    // exceeds 0x10ffff (largest Unicode)
+      "\\U00110000",  // exceeds 0x10ffff (largest Unicode)
+      "\\uD835",      // surrogate character (D800-DFFF)
+      "\\U0000DD04",  // surrogate character (D800-DFFF)
+      "\\777",        // exceeds 0xff
+      "\\xABCD"};     // exceeds 0xff
+  for (const std::string& e : bad) {
+    std::string error;
+    std::string out;
+    EXPECT_FALSE(absl::CUnescape(e, &out, &error));
+    EXPECT_FALSE(error.empty());
+  }
+}
+
+class CUnescapeTest : public testing::Test {
+ protected:
+  static const char kStringWithMultipleOctalNulls[];
+  static const char kStringWithMultipleHexNulls[];
+  static const char kStringWithMultipleUnicodeNulls[];
+
+  std::string result_string_;
+};
+
+const char CUnescapeTest::kStringWithMultipleOctalNulls[] =
+    "\\0\\n"    // null escape \0 plus newline
+    "0\\n"      // just a number 0 (not a null escape) plus newline
+    "\\00\\12"  // null escape \00 plus octal newline code
+    "\\000";    // null escape \000
+
+// This has the same ingredients as kStringWithMultipleOctalNulls
+// but with \x hex escapes instead of octal escapes.
+const char CUnescapeTest::kStringWithMultipleHexNulls[] =
+    "\\x0\\n"
+    "0\\n"
+    "\\x00\\xa"
+    "\\x000";
+
+const char CUnescapeTest::kStringWithMultipleUnicodeNulls[] =
+    "\\u0000\\n"    // short-form (4-digit) null escape plus newline
+    "0\\n"          // just a number 0 (not a null escape) plus newline
+    "\\U00000000";  // long-form (8-digit) null escape
+
+TEST_F(CUnescapeTest, Unescapes1CharOctalNull) {
+  std::string original_string = "\\0";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes2CharOctalNull) {
+  std::string original_string = "\\00";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes3CharOctalNull) {
+  std::string original_string = "\\000";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes1CharHexNull) {
+  std::string original_string = "\\x0";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes2CharHexNull) {
+  std::string original_string = "\\x00";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes3CharHexNull) {
+  std::string original_string = "\\x000";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes4CharUnicodeNull) {
+  std::string original_string = "\\u0000";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes8CharUnicodeNull) {
+  std::string original_string = "\\U00000000";
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) {
+  std::string original_string(kStringWithMultipleOctalNulls);
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  // All escapes, including newlines and null escapes, should have been
+  // converted to the equivalent characters.
+  EXPECT_EQ(std::string("\0\n"
+                   "0\n"
+                   "\0\n"
+                   "\0", 7), result_string_);
+}
+
+
+TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) {
+  std::string original_string(kStringWithMultipleHexNulls);
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0\n"
+                   "0\n"
+                   "\0\n"
+                   "\0", 7), result_string_);
+}
+
+TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) {
+  std::string original_string(kStringWithMultipleUnicodeNulls);
+  EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+  EXPECT_EQ(std::string("\0\n"
+                   "0\n"
+                   "\0", 5), result_string_);
+}
+
+static struct {
+  absl::string_view plaintext;
+  absl::string_view cyphertext;
+} const base64_tests[] = {
+    // Empty std::string.
+    {{"", 0}, {"", 0}},
+    {{nullptr, 0},
+     {"", 0}},  // if length is zero, plaintext ptr must be ignored!
+
+    // Basic bit patterns;
+    // values obtained with "echo -n '...' | uuencode -m test"
+
+    {{"\000", 1}, "AA=="},
+    {{"\001", 1}, "AQ=="},
+    {{"\002", 1}, "Ag=="},
+    {{"\004", 1}, "BA=="},
+    {{"\010", 1}, "CA=="},
+    {{"\020", 1}, "EA=="},
+    {{"\040", 1}, "IA=="},
+    {{"\100", 1}, "QA=="},
+    {{"\200", 1}, "gA=="},
+
+    {{"\377", 1}, "/w=="},
+    {{"\376", 1}, "/g=="},
+    {{"\375", 1}, "/Q=="},
+    {{"\373", 1}, "+w=="},
+    {{"\367", 1}, "9w=="},
+    {{"\357", 1}, "7w=="},
+    {{"\337", 1}, "3w=="},
+    {{"\277", 1}, "vw=="},
+    {{"\177", 1}, "fw=="},
+    {{"\000\000", 2}, "AAA="},
+    {{"\000\001", 2}, "AAE="},
+    {{"\000\002", 2}, "AAI="},
+    {{"\000\004", 2}, "AAQ="},
+    {{"\000\010", 2}, "AAg="},
+    {{"\000\020", 2}, "ABA="},
+    {{"\000\040", 2}, "ACA="},
+    {{"\000\100", 2}, "AEA="},
+    {{"\000\200", 2}, "AIA="},
+    {{"\001\000", 2}, "AQA="},
+    {{"\002\000", 2}, "AgA="},
+    {{"\004\000", 2}, "BAA="},
+    {{"\010\000", 2}, "CAA="},
+    {{"\020\000", 2}, "EAA="},
+    {{"\040\000", 2}, "IAA="},
+    {{"\100\000", 2}, "QAA="},
+    {{"\200\000", 2}, "gAA="},
+
+    {{"\377\377", 2}, "//8="},
+    {{"\377\376", 2}, "//4="},
+    {{"\377\375", 2}, "//0="},
+    {{"\377\373", 2}, "//s="},
+    {{"\377\367", 2}, "//c="},
+    {{"\377\357", 2}, "/+8="},
+    {{"\377\337", 2}, "/98="},
+    {{"\377\277", 2}, "/78="},
+    {{"\377\177", 2}, "/38="},
+    {{"\376\377", 2}, "/v8="},
+    {{"\375\377", 2}, "/f8="},
+    {{"\373\377", 2}, "+/8="},
+    {{"\367\377", 2}, "9/8="},
+    {{"\357\377", 2}, "7/8="},
+    {{"\337\377", 2}, "3/8="},
+    {{"\277\377", 2}, "v/8="},
+    {{"\177\377", 2}, "f/8="},
+
+    {{"\000\000\000", 3}, "AAAA"},
+    {{"\000\000\001", 3}, "AAAB"},
+    {{"\000\000\002", 3}, "AAAC"},
+    {{"\000\000\004", 3}, "AAAE"},
+    {{"\000\000\010", 3}, "AAAI"},
+    {{"\000\000\020", 3}, "AAAQ"},
+    {{"\000\000\040", 3}, "AAAg"},
+    {{"\000\000\100", 3}, "AABA"},
+    {{"\000\000\200", 3}, "AACA"},
+    {{"\000\001\000", 3}, "AAEA"},
+    {{"\000\002\000", 3}, "AAIA"},
+    {{"\000\004\000", 3}, "AAQA"},
+    {{"\000\010\000", 3}, "AAgA"},
+    {{"\000\020\000", 3}, "ABAA"},
+    {{"\000\040\000", 3}, "ACAA"},
+    {{"\000\100\000", 3}, "AEAA"},
+    {{"\000\200\000", 3}, "AIAA"},
+    {{"\001\000\000", 3}, "AQAA"},
+    {{"\002\000\000", 3}, "AgAA"},
+    {{"\004\000\000", 3}, "BAAA"},
+    {{"\010\000\000", 3}, "CAAA"},
+    {{"\020\000\000", 3}, "EAAA"},
+    {{"\040\000\000", 3}, "IAAA"},
+    {{"\100\000\000", 3}, "QAAA"},
+    {{"\200\000\000", 3}, "gAAA"},
+
+    {{"\377\377\377", 3}, "////"},
+    {{"\377\377\376", 3}, "///+"},
+    {{"\377\377\375", 3}, "///9"},
+    {{"\377\377\373", 3}, "///7"},
+    {{"\377\377\367", 3}, "///3"},
+    {{"\377\377\357", 3}, "///v"},
+    {{"\377\377\337", 3}, "///f"},
+    {{"\377\377\277", 3}, "//+/"},
+    {{"\377\377\177", 3}, "//9/"},
+    {{"\377\376\377", 3}, "//7/"},
+    {{"\377\375\377", 3}, "//3/"},
+    {{"\377\373\377", 3}, "//v/"},
+    {{"\377\367\377", 3}, "//f/"},
+    {{"\377\357\377", 3}, "/+//"},
+    {{"\377\337\377", 3}, "/9//"},
+    {{"\377\277\377", 3}, "/7//"},
+    {{"\377\177\377", 3}, "/3//"},
+    {{"\376\377\377", 3}, "/v//"},
+    {{"\375\377\377", 3}, "/f//"},
+    {{"\373\377\377", 3}, "+///"},
+    {{"\367\377\377", 3}, "9///"},
+    {{"\357\377\377", 3}, "7///"},
+    {{"\337\377\377", 3}, "3///"},
+    {{"\277\377\377", 3}, "v///"},
+    {{"\177\377\377", 3}, "f///"},
+
+    // Random numbers: values obtained with
+    //
+    //  #! /bin/bash
+    //  dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
+    //  od -N $1 -t o1 /tmp/bar.random
+    //  uuencode -m test < /tmp/bar.random
+    //
+    // where $1 is the number of bytes (2, 3)
+
+    {{"\243\361", 2}, "o/E="},
+    {{"\024\167", 2}, "FHc="},
+    {{"\313\252", 2}, "y6o="},
+    {{"\046\041", 2}, "JiE="},
+    {{"\145\236", 2}, "ZZ4="},
+    {{"\254\325", 2}, "rNU="},
+    {{"\061\330", 2}, "Mdg="},
+    {{"\245\032", 2}, "pRo="},
+    {{"\006\000", 2}, "BgA="},
+    {{"\375\131", 2}, "/Vk="},
+    {{"\303\210", 2}, "w4g="},
+    {{"\040\037", 2}, "IB8="},
+    {{"\261\372", 2}, "sfo="},
+    {{"\335\014", 2}, "3Qw="},
+    {{"\233\217", 2}, "m48="},
+    {{"\373\056", 2}, "+y4="},
+    {{"\247\232", 2}, "p5o="},
+    {{"\107\053", 2}, "Rys="},
+    {{"\204\077", 2}, "hD8="},
+    {{"\276\211", 2}, "vok="},
+    {{"\313\110", 2}, "y0g="},
+    {{"\363\376", 2}, "8/4="},
+    {{"\251\234", 2}, "qZw="},
+    {{"\103\262", 2}, "Q7I="},
+    {{"\142\312", 2}, "Yso="},
+    {{"\067\211", 2}, "N4k="},
+    {{"\220\001", 2}, "kAE="},
+    {{"\152\240", 2}, "aqA="},
+    {{"\367\061", 2}, "9zE="},
+    {{"\133\255", 2}, "W60="},
+    {{"\176\035", 2}, "fh0="},
+    {{"\032\231", 2}, "Gpk="},
+
+    {{"\013\007\144", 3}, "Cwdk"},
+    {{"\030\112\106", 3}, "GEpG"},
+    {{"\047\325\046", 3}, "J9Um"},
+    {{"\310\160\022", 3}, "yHAS"},
+    {{"\131\100\237", 3}, "WUCf"},
+    {{"\064\342\134", 3}, "NOJc"},
+    {{"\010\177\004", 3}, "CH8E"},
+    {{"\345\147\205", 3}, "5WeF"},
+    {{"\300\343\360", 3}, "wOPw"},
+    {{"\061\240\201", 3}, "MaCB"},
+    {{"\225\333\044", 3}, "ldsk"},
+    {{"\215\137\352", 3}, "jV/q"},
+    {{"\371\147\160", 3}, "+Wdw"},
+    {{"\030\320\051", 3}, "GNAp"},
+    {{"\044\174\241", 3}, "JHyh"},
+    {{"\260\127\037", 3}, "sFcf"},
+    {{"\111\045\033", 3}, "SSUb"},
+    {{"\202\114\107", 3}, "gkxH"},
+    {{"\057\371\042", 3}, "L/ki"},
+    {{"\223\247\244", 3}, "k6ek"},
+    {{"\047\216\144", 3}, "J45k"},
+    {{"\203\070\327", 3}, "gzjX"},
+    {{"\247\140\072", 3}, "p2A6"},
+    {{"\124\115\116", 3}, "VE1O"},
+    {{"\157\162\050", 3}, "b3Io"},
+    {{"\357\223\004", 3}, "75ME"},
+    {{"\052\117\156", 3}, "Kk9u"},
+    {{"\347\154\000", 3}, "52wA"},
+    {{"\303\012\142", 3}, "wwpi"},
+    {{"\060\035\362", 3}, "MB3y"},
+    {{"\130\226\361", 3}, "WJbx"},
+    {{"\173\013\071", 3}, "ews5"},
+    {{"\336\004\027", 3}, "3gQX"},
+    {{"\357\366\234", 3}, "7/ac"},
+    {{"\353\304\111", 3}, "68RJ"},
+    {{"\024\264\131", 3}, "FLRZ"},
+    {{"\075\114\251", 3}, "PUyp"},
+    {{"\315\031\225", 3}, "zRmV"},
+    {{"\154\201\276", 3}, "bIG+"},
+    {{"\200\066\072", 3}, "gDY6"},
+    {{"\142\350\267", 3}, "Yui3"},
+    {{"\033\000\166", 3}, "GwB2"},
+    {{"\210\055\077", 3}, "iC0/"},
+    {{"\341\037\124", 3}, "4R9U"},
+    {{"\161\103\152", 3}, "cUNq"},
+    {{"\270\142\131", 3}, "uGJZ"},
+    {{"\337\076\074", 3}, "3z48"},
+    {{"\375\106\362", 3}, "/Uby"},
+    {{"\227\301\127", 3}, "l8FX"},
+    {{"\340\002\234", 3}, "4AKc"},
+    {{"\121\064\033", 3}, "UTQb"},
+    {{"\157\134\143", 3}, "b1xj"},
+    {{"\247\055\327", 3}, "py3X"},
+    {{"\340\142\005", 3}, "4GIF"},
+    {{"\060\260\143", 3}, "MLBj"},
+    {{"\075\203\170", 3}, "PYN4"},
+    {{"\143\160\016", 3}, "Y3AO"},
+    {{"\313\013\063", 3}, "ywsz"},
+    {{"\174\236\135", 3}, "fJ5d"},
+    {{"\103\047\026", 3}, "QycW"},
+    {{"\365\005\343", 3}, "9QXj"},
+    {{"\271\160\223", 3}, "uXCT"},
+    {{"\362\255\172", 3}, "8q16"},
+    {{"\113\012\015", 3}, "SwoN"},
+
+    // various lengths, generated by this python script:
+    //
+    // from std::string import lowercase as lc
+    // for i in range(27):
+    //   print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
+    //                                     lc[:i].encode('base64').strip())
+
+    {{"", 0}, {"", 0}},
+    {"a", "YQ=="},
+    {"ab", "YWI="},
+    {"abc", "YWJj"},
+    {"abcd", "YWJjZA=="},
+    {"abcde", "YWJjZGU="},
+    {"abcdef", "YWJjZGVm"},
+    {"abcdefg", "YWJjZGVmZw=="},
+    {"abcdefgh", "YWJjZGVmZ2g="},
+    {"abcdefghi", "YWJjZGVmZ2hp"},
+    {"abcdefghij", "YWJjZGVmZ2hpag=="},
+    {"abcdefghijk", "YWJjZGVmZ2hpams="},
+    {"abcdefghijkl", "YWJjZGVmZ2hpamts"},
+    {"abcdefghijklm", "YWJjZGVmZ2hpamtsbQ=="},
+    {"abcdefghijklmn", "YWJjZGVmZ2hpamtsbW4="},
+    {"abcdefghijklmno", "YWJjZGVmZ2hpamtsbW5v"},
+    {"abcdefghijklmnop", "YWJjZGVmZ2hpamtsbW5vcA=="},
+    {"abcdefghijklmnopq", "YWJjZGVmZ2hpamtsbW5vcHE="},
+    {"abcdefghijklmnopqr", "YWJjZGVmZ2hpamtsbW5vcHFy"},
+    {"abcdefghijklmnopqrs", "YWJjZGVmZ2hpamtsbW5vcHFycw=="},
+    {"abcdefghijklmnopqrst", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q="},
+    {"abcdefghijklmnopqrstu", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1"},
+    {"abcdefghijklmnopqrstuv", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg=="},
+    {"abcdefghijklmnopqrstuvw", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc="},
+    {"abcdefghijklmnopqrstuvwx", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"},
+    {"abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="},
+    {"abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="},
+};
+
+TEST(Base64, EscapeAndUnescape) {
+  // Check the short strings; this tests the math (and boundaries)
+  for (const auto& tc : base64_tests) {
+    std::string encoded("this junk should be ignored");
+    absl::Base64Escape(tc.plaintext, &encoded);
+    EXPECT_EQ(encoded, tc.cyphertext);
+
+    std::string decoded("this junk should be ignored");
+    EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded));
+    EXPECT_EQ(decoded, tc.plaintext);
+
+    std::string websafe(tc.cyphertext);
+    for (int c = 0; c < websafe.size(); ++c) {
+      if ('+' == websafe[c]) websafe[c] = '-';
+      if ('/' == websafe[c]) websafe[c] = '_';
+      if ('=' == websafe[c]) {
+        websafe.resize(c);
+        break;
+      }
+    }
+
+    encoded = "this junk should be ignored";
+    absl::WebSafeBase64Escape(tc.plaintext, &encoded);
+    EXPECT_EQ(encoded, websafe);
+
+    // Let's try the std::string version of the decoder
+    decoded = "this junk should be ignored";
+    EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded));
+    EXPECT_EQ(decoded, tc.plaintext);
+  }
+
+  // Now try the long strings, this tests the streaming
+  for (const auto& tc : absl::strings_internal::base64_strings()) {
+    std::string buffer;
+    absl::WebSafeBase64Escape(tc.plaintext, &buffer);
+    EXPECT_EQ(tc.cyphertext, buffer);
+  }
+
+  // Verify the behavior when decoding bad data
+  {
+    absl::string_view data_set[] = {"ab-/", absl::string_view("\0bcd", 4),
+                                    absl::string_view("abc.\0", 5)};
+    for (absl::string_view bad_data : data_set) {
+      std::string buf;
+      EXPECT_FALSE(absl::Base64Unescape(bad_data, &buf));
+      EXPECT_FALSE(absl::WebSafeBase64Unescape(bad_data, &buf));
+      EXPECT_TRUE(buf.empty());
+    }
+  }
+}
+
+TEST(Base64, DISABLED_HugeData) {
+  const size_t kSize = size_t(3) * 1000 * 1000 * 1000;
+  static_assert(kSize % 3 == 0, "kSize must be divisible by 3");
+  const std::string huge(kSize, 'x');
+
+  std::string escaped;
+  absl::Base64Escape(huge, &escaped);
+
+  // Generates the std::string that should match a base64 encoded "xxx..." std::string.
+  // "xxx" in base64 is "eHh4".
+  std::string expected_encoding;
+  expected_encoding.reserve(kSize / 3 * 4);
+  for (size_t i = 0; i < kSize / 3; ++i) {
+    expected_encoding.append("eHh4");
+  }
+  EXPECT_EQ(expected_encoding, escaped);
+
+  std::string unescaped;
+  EXPECT_TRUE(absl::Base64Unescape(escaped, &unescaped));
+  EXPECT_EQ(huge, unescaped);
+}
+
+TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) {
+  std::string hex_mixed = "0123456789abcdefABCDEF";
+  std::string bytes_expected = "\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF";
+  std::string hex_only_lower = "0123456789abcdefabcdef";
+
+  std::string bytes_result = absl::HexStringToBytes(hex_mixed);
+  EXPECT_EQ(bytes_expected, bytes_result);
+
+  std::string prefix_valid = hex_mixed + "?";
+  std::string prefix_valid_result = absl::HexStringToBytes(
+      absl::string_view(prefix_valid.data(), prefix_valid.size() - 1));
+  EXPECT_EQ(bytes_expected, prefix_valid_result);
+
+  std::string infix_valid = "?" + hex_mixed + "???";
+  std::string infix_valid_result = absl::HexStringToBytes(
+      absl::string_view(infix_valid.data() + 1, hex_mixed.size()));
+  EXPECT_EQ(bytes_expected, infix_valid_result);
+
+  std::string hex_result = absl::BytesToHexString(bytes_expected);
+  EXPECT_EQ(hex_only_lower, hex_result);
+}
+
+}  // namespace
diff --git a/absl/strings/internal/bits.h b/absl/strings/internal/bits.h
new file mode 100644
index 0000000..901082c
--- /dev/null
+++ b/absl/strings/internal/bits.h
@@ -0,0 +1,53 @@
+// Copyright 2018 The Abseil 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 ABSL_STRINGS_INTERNAL_BITS_H_
+#define ABSL_STRINGS_INTERNAL_BITS_H_
+
+#include <cstdint>
+
+#if defined(_MSC_VER) && defined(_M_X64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#endif
+
+namespace absl {
+namespace strings_internal {
+
+// Returns the number of leading 0 bits in a 64-bit value.
+inline int CountLeadingZeros64(uint64_t n) {
+#if defined(__GNUC__)
+  static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
+                "__builtin_clzll does not take 64bit arg");
+  return n == 0 ? 64 : __builtin_clzll(n);
+#elif defined(_MSC_VER) && defined(_M_X64)
+  unsigned long result;  // NOLINT(runtime/int)
+  if (_BitScanReverse64(&result, n)) {
+    return 63 - result;
+  }
+  return 64;
+#else
+  int zeroes = 60;
+  if (n >> 32) zeroes -= 32, n >>= 32;
+  if (n >> 16) zeroes -= 16, n >>= 16;
+  if (n >> 8) zeroes -= 8, n >>= 8;
+  if (n >> 4) zeroes -= 4, n >>= 4;
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes;
+#endif
+}
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_BITS_H_
diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h
new file mode 100644
index 0000000..8d92963
--- /dev/null
+++ b/absl/strings/internal/char_map.h
@@ -0,0 +1,154 @@
+// Copyright 2017 The Abseil 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.
+//
+// Character Map Class
+//
+// A fast, bit-vector map for 8-bit unsigned characters.
+// This class is useful for non-character purposes as well.
+
+#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
+#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace strings_internal {
+
+class Charmap {
+ public:
+  constexpr Charmap() : m_() {}
+
+  // Initializes with a given char*.  Note that NUL is not treated as
+  // a terminator, but rather a char to be flicked.
+  Charmap(const char* str, int len) : m_() {
+    while (len--) SetChar(*str++);
+  }
+
+  // Initializes with a given char*.  NUL is treated as a terminator
+  // and will not be in the charmap.
+  explicit Charmap(const char* str) : m_() {
+    while (*str) SetChar(*str++);
+  }
+
+  constexpr bool contains(unsigned char c) const {
+    return (m_[c / 64] >> (c % 64)) & 0x1;
+  }
+
+  // Returns true if and only if a character exists in both maps.
+  bool IntersectsWith(const Charmap& c) const {
+    for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) {
+      if ((m_[i] & c.m_[i]) != 0) return true;
+    }
+    return false;
+  }
+
+  bool IsZero() const {
+    for (uint64_t c : m_) {
+      if (c != 0) return false;
+    }
+    return true;
+  }
+
+  // Containing only a single specified char.
+  static constexpr Charmap Char(char x) {
+    return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1),
+                   CharMaskForWord(x, 2), CharMaskForWord(x, 3));
+  }
+
+  // Containing all the chars in the C-std::string 's'.
+  // Note that this is expensively recursive because of the C++11 constexpr
+  // formulation. Use only in constexpr initializers.
+  static constexpr Charmap FromString(const char* s) {
+    return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1));
+  }
+
+  // Containing all the chars in the closed interval [lo,hi].
+  static constexpr Charmap Range(char lo, char hi) {
+    return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1),
+                   RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3));
+  }
+
+  friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) {
+    return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2],
+                   a.m_[3] & b.m_[3]);
+  }
+
+  friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) {
+    return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2],
+                   a.m_[3] | b.m_[3]);
+  }
+
+  friend constexpr Charmap operator~(const Charmap& a) {
+    return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]);
+  }
+
+ private:
+  constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3)
+      : m_{b0, b1, b2, b3} {}
+
+  static constexpr uint64_t RangeForWord(unsigned char lo, unsigned char hi,
+                                         uint64_t word) {
+    return OpenRangeFromZeroForWord(hi + 1, word) &
+           ~OpenRangeFromZeroForWord(lo, word);
+  }
+
+  // All the chars in the specified word of the range [0, upper).
+  static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper,
+                                                     uint64_t word) {
+    return (upper <= 64 * word)
+               ? 0
+               : (upper >= 64 * (word + 1))
+                     ? ~static_cast<uint64_t>(0)
+                     : (~static_cast<uint64_t>(0) >> (64 - upper % 64));
+  }
+
+  static constexpr uint64_t CharMaskForWord(unsigned char x, uint64_t word) {
+    return (x / 64 == word) ? (static_cast<uint64_t>(1) << (x % 64)) : 0;
+  }
+
+ private:
+  void SetChar(unsigned char c) {
+    m_[c / 64] |= static_cast<uint64_t>(1) << (c % 64);
+  }
+
+  uint64_t m_[4];
+};
+
+// Mirror the char-classifying predicates in <cctype>
+constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); }
+constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); }
+constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); }
+constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); }
+constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); }
+constexpr Charmap XDigitCharmap() {
+  return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f');
+}
+constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); }
+constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); }
+constexpr Charmap CntrlCharmap() {
+  return Charmap::Range(0, 0x7f) & ~PrintCharmap();
+}
+constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); }
+constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); }
+constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); }
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/internal/char_map_benchmark.cc
new file mode 100644
index 0000000..c45f315
--- /dev/null
+++ b/absl/strings/internal/char_map_benchmark.cc
@@ -0,0 +1,61 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/char_map.h"
+
+#include <cstdint>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+absl::strings_internal::Charmap MakeBenchmarkMap() {
+  absl::strings_internal::Charmap m;
+  uint32_t x[] = {0x0, 0x1, 0x2, 0x3, 0xf, 0xe, 0xd, 0xc};
+  for (uint32_t& t : x) t *= static_cast<uint32_t>(0x11111111UL);
+  for (uint32_t i = 0; i < 256; ++i) {
+    if ((x[i / 32] >> (i % 32)) & 1)
+      m = m | absl::strings_internal::Charmap::Char(i);
+  }
+  return m;
+}
+
+// Micro-benchmark for Charmap::contains.
+void BM_Contains(benchmark::State& state) {
+  // Loop-body replicated 10 times to increase time per iteration.
+  // Argument continuously changed to avoid generating common subexpressions.
+  const absl::strings_internal::Charmap benchmark_map = MakeBenchmarkMap();
+  unsigned char c = 0;
+  int ops = 0;
+  for (auto _ : state) {
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+    ops += benchmark_map.contains(c++);
+  }
+  benchmark::DoNotOptimize(ops);
+}
+BENCHMARK(BM_Contains);
+
+// We don't bother benchmarking Charmap::IsZero or Charmap::IntersectsWith;
+// their running time is data-dependent and it is not worth characterizing
+// "typical" data.
+
+}  // namespace
diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc
new file mode 100644
index 0000000..c3601e1
--- /dev/null
+++ b/absl/strings/internal/char_map_test.cc
@@ -0,0 +1,172 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/char_map.h"
+
+#include <cctype>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+constexpr absl::strings_internal::Charmap everything_map =
+    ~absl::strings_internal::Charmap();
+constexpr absl::strings_internal::Charmap nothing_map{};
+
+TEST(Charmap, AllTests) {
+  const absl::strings_internal::Charmap also_nothing_map("", 0);
+  ASSERT_TRUE(everything_map.contains('\0'));
+  ASSERT_TRUE(!nothing_map.contains('\0'));
+  ASSERT_TRUE(!also_nothing_map.contains('\0'));
+  for (unsigned char ch = 1; ch != 0; ++ch) {
+    ASSERT_TRUE(everything_map.contains(ch));
+    ASSERT_TRUE(!nothing_map.contains(ch));
+    ASSERT_TRUE(!also_nothing_map.contains(ch));
+  }
+
+  const absl::strings_internal::Charmap symbols("&@#@^!@?", 5);
+  ASSERT_TRUE(symbols.contains('&'));
+  ASSERT_TRUE(symbols.contains('@'));
+  ASSERT_TRUE(symbols.contains('#'));
+  ASSERT_TRUE(symbols.contains('^'));
+  ASSERT_TRUE(!symbols.contains('!'));
+  ASSERT_TRUE(!symbols.contains('?'));
+  int cnt = 0;
+  for (unsigned char ch = 1; ch != 0; ++ch)
+    cnt += symbols.contains(ch);
+  ASSERT_EQ(cnt, 4);
+
+  const absl::strings_internal::Charmap lets("^abcde", 3);
+  const absl::strings_internal::Charmap lets2("fghij\0klmnop", 10);
+  const absl::strings_internal::Charmap lets3("fghij\0klmnop");
+  ASSERT_TRUE(lets2.contains('k'));
+  ASSERT_TRUE(!lets3.contains('k'));
+
+  ASSERT_TRUE(symbols.IntersectsWith(lets));
+  ASSERT_TRUE(!lets2.IntersectsWith(lets));
+  ASSERT_TRUE(lets.IntersectsWith(symbols));
+  ASSERT_TRUE(!lets.IntersectsWith(lets2));
+
+  ASSERT_TRUE(nothing_map.IsZero());
+  ASSERT_TRUE(!lets.IsZero());
+}
+
+namespace {
+std::string Members(const absl::strings_internal::Charmap& m) {
+  std::string r;
+  for (size_t i = 0; i < 256; ++i)
+    if (m.contains(i)) r.push_back(i);
+  return r;
+}
+
+std::string ClosedRangeString(unsigned char lo, unsigned char hi) {
+  // Don't depend on lo<hi. Just increment until lo==hi.
+  std::string s;
+  while (true) {
+    s.push_back(lo);
+    if (lo == hi) break;
+    ++lo;
+  }
+  return s;
+}
+
+}  // namespace
+
+TEST(Charmap, Constexpr) {
+  constexpr absl::strings_internal::Charmap kEmpty = nothing_map;
+  EXPECT_THAT(Members(kEmpty), "");
+  constexpr absl::strings_internal::Charmap kA =
+      absl::strings_internal::Charmap::Char('A');
+  EXPECT_THAT(Members(kA), "A");
+  constexpr absl::strings_internal::Charmap kAZ =
+      absl::strings_internal::Charmap::Range('A', 'Z');
+  EXPECT_THAT(Members(kAZ), "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+  constexpr absl::strings_internal::Charmap kIdentifier =
+      absl::strings_internal::Charmap::Range('0', '9') |
+      absl::strings_internal::Charmap::Range('A', 'Z') |
+      absl::strings_internal::Charmap::Range('a', 'z') |
+      absl::strings_internal::Charmap::Char('_');
+  EXPECT_THAT(Members(kIdentifier),
+              "0123456789"
+              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+              "_"
+              "abcdefghijklmnopqrstuvwxyz");
+  constexpr absl::strings_internal::Charmap kAll = everything_map;
+  for (size_t i = 0; i < 256; ++i) {
+    EXPECT_TRUE(kAll.contains(i)) << i;
+  }
+  constexpr absl::strings_internal::Charmap kHello =
+      absl::strings_internal::Charmap::FromString("Hello, world!");
+  EXPECT_THAT(Members(kHello), " !,Hdelorw");
+
+  // test negation and intersection
+  constexpr absl::strings_internal::Charmap kABC =
+      absl::strings_internal::Charmap::Range('A', 'Z') &
+      ~absl::strings_internal::Charmap::Range('D', 'Z');
+  EXPECT_THAT(Members(kABC), "ABC");
+}
+
+TEST(Charmap, Range) {
+  // Exhaustive testing takes too long, so test some of the boundaries that
+  // are perhaps going to cause trouble.
+  std::vector<size_t> poi = {0,   1,   2,   3,   4,   7,   8,   9,  15,
+                             16,  17,  30,  31,  32,  33,  63,  64, 65,
+                             127, 128, 129, 223, 224, 225, 254, 255};
+  for (auto lo = poi.begin(); lo != poi.end(); ++lo) {
+    SCOPED_TRACE(*lo);
+    for (auto hi = lo; hi != poi.end(); ++hi) {
+      SCOPED_TRACE(*hi);
+      EXPECT_THAT(Members(absl::strings_internal::Charmap::Range(*lo, *hi)),
+                  ClosedRangeString(*lo, *hi));
+    }
+  }
+}
+
+bool AsBool(int x) { return static_cast<bool>(x); }
+
+TEST(CharmapCtype, Match) {
+  for (int c = 0; c < 256; ++c) {
+    SCOPED_TRACE(c);
+    SCOPED_TRACE(static_cast<char>(c));
+    EXPECT_EQ(AsBool(std::isupper(c)),
+              absl::strings_internal::UpperCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::islower(c)),
+              absl::strings_internal::LowerCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isdigit(c)),
+              absl::strings_internal::DigitCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isalpha(c)),
+              absl::strings_internal::AlphaCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isalnum(c)),
+              absl::strings_internal::AlnumCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isxdigit(c)),
+              absl::strings_internal::XDigitCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isprint(c)),
+              absl::strings_internal::PrintCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isspace(c)),
+              absl::strings_internal::SpaceCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::iscntrl(c)),
+              absl::strings_internal::CntrlCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isblank(c)),
+              absl::strings_internal::BlankCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::isgraph(c)),
+              absl::strings_internal::GraphCharmap().contains(c));
+    EXPECT_EQ(AsBool(std::ispunct(c)),
+              absl::strings_internal::PunctCharmap().contains(c));
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc
new file mode 100644
index 0000000..3e7296e
--- /dev/null
+++ b/absl/strings/internal/charconv_bigint.cc
@@ -0,0 +1,357 @@
+// Copyright 2018 The Abseil 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 "absl/strings/internal/charconv_bigint.h"
+
+#include <algorithm>
+#include <cassert>
+#include <string>
+
+namespace absl {
+namespace strings_internal {
+
+namespace {
+
+// Table containing some large powers of 5, for fast computation.
+
+// Constant step size for entries in the kLargePowersOfFive table.  Each entry
+// is larger than the previous entry by a factor of 5**kLargePowerOfFiveStep
+// (or 5**27).
+//
+// In other words, the Nth entry in the table is 5**(27*N).
+//
+// 5**27 is the largest power of 5 that fits in 64 bits.
+constexpr int kLargePowerOfFiveStep = 27;
+
+// The largest legal index into the kLargePowersOfFive table.
+//
+// In other words, the largest precomputed power of 5 is 5**(27*20).
+constexpr int kLargestPowerOfFiveIndex = 20;
+
+// Table of powers of (5**27), up to (5**27)**20 == 5**540.
+//
+// Used to generate large powers of 5 while limiting the number of repeated
+// multiplications required.
+//
+// clang-format off
+const uint32_t kLargePowersOfFive[] = {
+// 5**27 (i=1), start=0, end=2
+  0xfa10079dU, 0x6765c793U,
+// 5**54 (i=2), start=2, end=6
+  0x97d9f649U, 0x6664242dU, 0x29939b14U, 0x29c30f10U,
+// 5**81 (i=3), start=6, end=12
+  0xc4f809c5U, 0x7bf3f22aU, 0x67bdae34U, 0xad340517U, 0x369d1b5fU, 0x10de1593U,
+// 5**108 (i=4), start=12, end=20
+  0x92b260d1U, 0x9efff7c7U, 0x81de0ec6U, 0xaeba5d56U, 0x410664a4U, 0x4f40737aU,
+  0x20d3846fU, 0x06d00f73U,
+// 5**135 (i=5), start=20, end=30
+  0xff1b172dU, 0x13a1d71cU, 0xefa07617U, 0x7f682d3dU, 0xff8c90c0U, 0x3f0131e7U,
+  0x3fdcb9feU, 0x917b0177U, 0x16c407a7U, 0x02c06b9dU,
+// 5**162 (i=6), start=30, end=42
+  0x960f7199U, 0x056667ecU, 0xe07aefd8U, 0x80f2b9ccU, 0x8273f5e3U, 0xeb9a214aU,
+  0x40b38005U, 0x0e477ad4U, 0x277d08e6U, 0xfa28b11eU, 0xd3f7d784U, 0x011c835bU,
+// 5**189 (i=7), start=42, end=56
+  0xf723d9d5U, 0x3282d3f3U, 0xe00857d1U, 0x69659d25U, 0x2cf117cfU, 0x24da6d07U,
+  0x954d1417U, 0x3e5d8cedU, 0x7a8bb766U, 0xfd785ae6U, 0x645436d2U, 0x40c78b34U,
+  0x94151217U, 0x0072e9f7U,
+// 5**216 (i=8), start=56, end=72
+  0x2b416aa1U, 0x7893c5a7U, 0xe37dc6d4U, 0x2bad2beaU, 0xf0fc846cU, 0x7575ae4bU,
+  0x62587b14U, 0x83b67a34U, 0x02110cdbU, 0xf7992f55U, 0x00deb022U, 0xa4a23becU,
+  0x8af5c5cdU, 0xb85b654fU, 0x818df38bU, 0x002e69d2U,
+// 5**243 (i=9), start=72, end=90
+  0x3518cbbdU, 0x20b0c15fU, 0x38756c2fU, 0xfb5dc3ddU, 0x22ad2d94U, 0xbf35a952U,
+  0xa699192aU, 0x9a613326U, 0xad2a9cedU, 0xd7f48968U, 0xe87dfb54U, 0xc8f05db6U,
+  0x5ef67531U, 0x31c1ab49U, 0xe202ac9fU, 0x9b2957b5U, 0xa143f6d3U, 0x0012bf07U,
+// 5**270 (i=10), start=90, end=110
+  0x8b971de9U, 0x21aba2e1U, 0x63944362U, 0x57172336U, 0xd9544225U, 0xfb534166U,
+  0x08c563eeU, 0x14640ee2U, 0x24e40d31U, 0x02b06537U, 0x03887f14U, 0x0285e533U,
+  0xb744ef26U, 0x8be3a6c4U, 0x266979b4U, 0x6761ece2U, 0xd9cb39e4U, 0xe67de319U,
+  0x0d39e796U, 0x00079250U,
+// 5**297 (i=11), start=110, end=132
+  0x260eb6e5U, 0xf414a796U, 0xee1a7491U, 0xdb9368ebU, 0xf50c105bU, 0x59157750U,
+  0x9ed2fb5cU, 0xf6e56d8bU, 0xeaee8d23U, 0x0f319f75U, 0x2aa134d6U, 0xac2908e9U,
+  0xd4413298U, 0x02f02a55U, 0x989d5a7aU, 0x70dde184U, 0xba8040a7U, 0x03200981U,
+  0xbe03b11cU, 0x3c1c2a18U, 0xd60427a1U, 0x00030ee0U,
+// 5**324 (i=12), start=132, end=156
+  0xce566d71U, 0xf1c4aa25U, 0x4e93ca53U, 0xa72283d0U, 0x551a73eaU, 0x3d0538e2U,
+  0x8da4303fU, 0x6a58de60U, 0x0e660221U, 0x49cf61a6U, 0x8d058fc1U, 0xb9d1a14cU,
+  0x4bab157dU, 0xc85c6932U, 0x518c8b9eU, 0x9b92b8d0U, 0x0d8a0e21U, 0xbd855df9U,
+  0xb3ea59a1U, 0x8da29289U, 0x4584d506U, 0x3752d80fU, 0xb72569c6U, 0x00013c33U,
+// 5**351 (i=13), start=156, end=182
+  0x190f354dU, 0x83695cfeU, 0xe5a4d0c7U, 0xb60fb7e8U, 0xee5bbcc4U, 0xb922054cU,
+  0xbb4f0d85U, 0x48394028U, 0x1d8957dbU, 0x0d7edb14U, 0x4ecc7587U, 0x505e9e02U,
+  0x4c87f36bU, 0x99e66bd6U, 0x44b9ed35U, 0x753037d4U, 0xe5fe5f27U, 0x2742c203U,
+  0x13b2ed2bU, 0xdc525d2cU, 0xe6fde59aU, 0x77ffb18fU, 0x13c5752cU, 0x08a84bccU,
+  0x859a4940U, 0x00007fb6U,
+// 5**378 (i=14), start=182, end=210
+  0x4f98cb39U, 0xa60edbbcU, 0x83b5872eU, 0xa501acffU, 0x9cc76f78U, 0xbadd4c73U,
+  0x43e989faU, 0xca7acf80U, 0x2e0c824fU, 0xb19f4ffcU, 0x092fd81cU, 0xe4eb645bU,
+  0xa1ff84c2U, 0x8a5a83baU, 0xa8a1fae9U, 0x1db43609U, 0xb0fed50bU, 0x0dd7d2bdU,
+  0x7d7accd8U, 0x91fa640fU, 0x37dcc6c5U, 0x1c417fd5U, 0xe4d462adU, 0xe8a43399U,
+  0x131bf9a5U, 0x8df54d29U, 0x36547dc1U, 0x00003395U,
+// 5**405 (i=15), start=210, end=240
+  0x5bd330f5U, 0x77d21967U, 0x1ac481b7U, 0x6be2f7ceU, 0x7f4792a9U, 0xe84c2c52U,
+  0x84592228U, 0x9dcaf829U, 0xdab44ce1U, 0x3d0c311bU, 0x532e297dU, 0x4704e8b4U,
+  0x9cdc32beU, 0x41e64d9dU, 0x7717bea1U, 0xa824c00dU, 0x08f50b27U, 0x0f198d77U,
+  0x49bbfdf0U, 0x025c6c69U, 0xd4e55cd3U, 0xf083602bU, 0xb9f0fecdU, 0xc0864aeaU,
+  0x9cb98681U, 0xaaf620e9U, 0xacb6df30U, 0x4faafe66U, 0x8af13c3bU, 0x000014d5U,
+// 5**432 (i=16), start=240, end=272
+  0x682bb941U, 0x89a9f297U, 0xcba75d7bU, 0x404217b1U, 0xb4e519e9U, 0xa1bc162bU,
+  0xf7f5910aU, 0x98715af5U, 0x2ff53e57U, 0xe3ef118cU, 0x490c4543U, 0xbc9b1734U,
+  0x2affbe4dU, 0x4cedcb4cU, 0xfb14e99eU, 0x35e34212U, 0xece39c24U, 0x07673ab3U,
+  0xe73115ddU, 0xd15d38e7U, 0x093eed3bU, 0xf8e7eac5U, 0x78a8cc80U, 0x25227aacU,
+  0x3f590551U, 0x413da1cbU, 0xdf643a55U, 0xab65ad44U, 0xd70b23d7U, 0xc672cd76U,
+  0x3364ea62U, 0x0000086aU,
+// 5**459 (i=17), start=272, end=306
+  0x22f163ddU, 0x23cf07acU, 0xbe2af6c2U, 0xf412f6f6U, 0xc3ff541eU, 0x6eeaf7deU,
+  0xa47047e0U, 0x408cda92U, 0x0f0eeb08U, 0x56deba9dU, 0xcfc6b090U, 0x8bbbdf04U,
+  0x3933cdb3U, 0x9e7bb67dU, 0x9f297035U, 0x38946244U, 0xee1d37bbU, 0xde898174U,
+  0x63f3559dU, 0x705b72fbU, 0x138d27d9U, 0xf8603a78U, 0x735eec44U, 0xe30987d5U,
+  0xc6d38070U, 0x9cfe548eU, 0x9ff01422U, 0x7c564aa8U, 0x91cc60baU, 0xcbc3565dU,
+  0x7550a50bU, 0x6909aeadU, 0x13234c45U, 0x00000366U,
+// 5**486 (i=18), start=306, end=342
+  0x17954989U, 0x3a7d7709U, 0x98042de5U, 0xa9011443U, 0x45e723c2U, 0x269ffd6fU,
+  0x58852a46U, 0xaaa1042aU, 0x2eee8153U, 0xb2b6c39eU, 0xaf845b65U, 0xf6c365d7U,
+  0xe4cffb2bU, 0xc840e90cU, 0xabea8abbU, 0x5c58f8d2U, 0x5c19fa3aU, 0x4670910aU,
+  0x4449f21cU, 0xefa645b3U, 0xcc427decU, 0x083c3d73U, 0x467cb413U, 0x6fe10ae4U,
+  0x3caffc72U, 0x9f8da55eU, 0x5e5c8ea7U, 0x490594bbU, 0xf0871b0bU, 0xdd89816cU,
+  0x8e931df8U, 0xe85ce1c9U, 0xcca090a5U, 0x575fa16bU, 0x6b9f106cU, 0x0000015fU,
+// 5**513 (i=19), start=342, end=380
+  0xee20d805U, 0x57bc3c07U, 0xcdea624eU, 0xd3f0f52dU, 0x9924b4f4U, 0xcf968640U,
+  0x61d41962U, 0xe87fb464U, 0xeaaf51c7U, 0x564c8b60U, 0xccda4028U, 0x529428bbU,
+  0x313a1fa8U, 0x96bd0f94U, 0x7a82ebaaU, 0xad99e7e9U, 0xf2668cd4U, 0xbe33a45eU,
+  0xfd0db669U, 0x87ee369fU, 0xd3ec20edU, 0x9c4d7db7U, 0xdedcf0d8U, 0x7cd2ca64U,
+  0xe25a6577U, 0x61003fd4U, 0xe56f54ccU, 0x10b7c748U, 0x40526e5eU, 0x7300ae87U,
+  0x5c439261U, 0x2c0ff469U, 0xbf723f12U, 0xb2379b61U, 0xbf59b4f5U, 0xc91b1c3fU,
+  0xf0046d27U, 0x0000008dU,
+// 5**540 (i=20), start=380, end=420
+  0x525c9e11U, 0xf4e0eb41U, 0xebb2895dU, 0x5da512f9U, 0x7d9b29d4U, 0x452f4edcU,
+  0x0b90bc37U, 0x341777cbU, 0x63d269afU, 0x1da77929U, 0x0a5c1826U, 0x77991898U,
+  0x5aeddf86U, 0xf853a877U, 0x538c31ccU, 0xe84896daU, 0xb7a0010bU, 0x17ef4de5U,
+  0xa52a2adeU, 0x029fd81cU, 0x987ce701U, 0x27fefd77U, 0xdb46c66fU, 0x5d301900U,
+  0x496998c0U, 0xbb6598b9U, 0x5eebb607U, 0xe547354aU, 0xdf4a2f7eU, 0xf06c4955U,
+  0x96242ffaU, 0x1775fb27U, 0xbecc58ceU, 0xebf2a53bU, 0x3eaad82aU, 0xf41137baU,
+  0x573e6fbaU, 0xfb4866b8U, 0x54002148U, 0x00000039U,
+};
+// clang-format on
+
+// Returns a pointer to the big integer data for (5**27)**i.  i must be
+// between 1 and 20, inclusive.
+const uint32_t* LargePowerOfFiveData(int i) {
+  return kLargePowersOfFive + i * (i - 1);
+}
+
+// Returns the size of the big integer data for (5**27)**i, in words.  i must be
+// between 1 and 20, inclusive.
+int LargePowerOfFiveSize(int i) { return 2 * i; }
+}  // namespace
+
+const uint32_t kFiveToNth[14] = {
+    1,     5,      25,      125,     625,      3125,      15625,
+    78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125,
+};
+
+const uint32_t kTenToNth[10] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
+};
+
+template <int max_words>
+int BigUnsigned<max_words>::ReadFloatMantissa(const ParsedFloat& fp,
+                                              int significant_digits) {
+  SetToZero();
+  assert(fp.type == FloatType::kNumber);
+
+  if (fp.subrange_begin == nullptr) {
+    // We already exactly parsed the mantissa, so no more work is necessary.
+    words_[0] = fp.mantissa & 0xffffffffu;
+    words_[1] = fp.mantissa >> 32;
+    if (words_[1]) {
+      size_ = 2;
+    } else if (words_[0]) {
+      size_ = 1;
+    }
+    return fp.exponent;
+  }
+  int exponent_adjust =
+      ReadDigits(fp.subrange_begin, fp.subrange_end, significant_digits);
+  return fp.literal_exponent + exponent_adjust;
+}
+
+template <int max_words>
+int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end,
+                                       int significant_digits) {
+  assert(significant_digits <= Digits10() + 1);
+  SetToZero();
+
+  bool after_decimal_point = false;
+  // Discard any leading zeroes before the decimal point
+  while (begin < end && *begin == '0') {
+    ++begin;
+  }
+  int dropped_digits = 0;
+  // Discard any trailing zeroes.  These may or may not be after the decimal
+  // point.
+  while (begin < end && *std::prev(end) == '0') {
+    --end;
+    ++dropped_digits;
+  }
+  if (begin < end && *std::prev(end) == '.') {
+    // If the std::string ends in '.', either before or after dropping zeroes, then
+    // drop the decimal point and look for more digits to drop.
+    dropped_digits = 0;
+    --end;
+    while (begin < end && *std::prev(end) == '0') {
+      --end;
+      ++dropped_digits;
+    }
+  } else if (dropped_digits) {
+    // We dropped digits, and aren't sure if they're before or after the decimal
+    // point.  Figure that out now.
+    const char* dp = std::find(begin, end, '.');
+    if (dp != end) {
+      // The dropped trailing digits were after the decimal point, so don't
+      // count them.
+      dropped_digits = 0;
+    }
+  }
+  // Any non-fraction digits we dropped need to be accounted for in our exponent
+  // adjustment.
+  int exponent_adjust = dropped_digits;
+
+  uint32_t queued = 0;
+  int digits_queued = 0;
+  for (; begin != end && significant_digits > 0; ++begin) {
+    if (*begin == '.') {
+      after_decimal_point = true;
+      continue;
+    }
+    if (after_decimal_point) {
+      // For each fractional digit we emit in our parsed integer, adjust our
+      // decimal exponent to compensate.
+      --exponent_adjust;
+    }
+    int digit = (*begin - '0');
+    --significant_digits;
+    if (significant_digits == 0 && std::next(begin) != end &&
+        (digit == 0 || digit == 5)) {
+      // If this is the very last significant digit, but insignificant digits
+      // remain, we know that the last of those remaining significant digits is
+      // nonzero.  (If it wasn't, we would have stripped it before we got here.)
+      // So if this final digit is a 0 or 5, adjust it upward by 1.
+      //
+      // This adjustment is what allows incredibly large mantissas ending in
+      // 500000...000000000001 to correctly round up, rather than to nearest.
+      ++digit;
+    }
+    queued = 10 * queued + digit;
+    ++digits_queued;
+    if (digits_queued == kMaxSmallPowerOfTen) {
+      MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]);
+      AddWithCarry(0, queued);
+      queued = digits_queued = 0;
+    }
+  }
+  // Encode any remaining digits.
+  if (digits_queued) {
+    MultiplyBy(kTenToNth[digits_queued]);
+    AddWithCarry(0, queued);
+  }
+
+  // If any insignificant digits remain, we will drop them.  But if we have not
+  // yet read the decimal point, then we have to adjust the exponent to account
+  // for the dropped digits.
+  if (begin < end && !after_decimal_point) {
+    // This call to std::find will result in a pointer either to the decimal
+    // point, or to the end of our buffer if there was none.
+    //
+    // Either way, [begin, decimal_point) will contain the set of dropped digits
+    // that require an exponent adjustment.
+    const char* decimal_point = std::find(begin, end, '.');
+    exponent_adjust += (decimal_point - begin);
+  }
+  return exponent_adjust;
+}
+
+template <int max_words>
+/* static */ BigUnsigned<max_words> BigUnsigned<max_words>::FiveToTheNth(
+    int n) {
+  BigUnsigned answer(1u);
+
+  // Seed from the table of large powers, if possible.
+  bool first_pass = true;
+  while (n >= kLargePowerOfFiveStep) {
+    int big_power =
+        std::min(n / kLargePowerOfFiveStep, kLargestPowerOfFiveIndex);
+    if (first_pass) {
+      // just copy, rather than multiplying by 1
+      std::copy(
+          LargePowerOfFiveData(big_power),
+          LargePowerOfFiveData(big_power) + LargePowerOfFiveSize(big_power),
+          answer.words_);
+      answer.size_ = LargePowerOfFiveSize(big_power);
+      first_pass = false;
+    } else {
+      answer.MultiplyBy(LargePowerOfFiveSize(big_power),
+                        LargePowerOfFiveData(big_power));
+    }
+    n -= kLargePowerOfFiveStep * big_power;
+  }
+  answer.MultiplyByFiveToTheNth(n);
+  return answer;
+}
+
+template <int max_words>
+void BigUnsigned<max_words>::MultiplyStep(int original_size,
+                                          const uint32_t* other_words,
+                                          int other_size, int step) {
+  int this_i = std::min(original_size - 1, step);
+  int other_i = step - this_i;
+
+  uint64_t this_word = 0;
+  uint64_t carry = 0;
+  for (; this_i >= 0 && other_i < other_size; --this_i, ++other_i) {
+    uint64_t product = words_[this_i];
+    product *= other_words[other_i];
+    this_word += product;
+    carry += (this_word >> 32);
+    this_word &= 0xffffffff;
+  }
+  AddWithCarry(step + 1, carry);
+  words_[step] = this_word & 0xffffffff;
+  if (this_word > 0 && size_ <= step) {
+    size_ = step + 1;
+  }
+}
+
+template <int max_words>
+std::string BigUnsigned<max_words>::ToString() const {
+  BigUnsigned<max_words> copy = *this;
+  std::string result;
+  // Build result in reverse order
+  while (copy.size() > 0) {
+    int next_digit = copy.DivMod<10>();
+    result.push_back('0' + next_digit);
+  }
+  if (result.empty()) {
+    result.push_back('0');
+  }
+  std::reverse(result.begin(), result.end());
+  return result;
+}
+
+template class BigUnsigned<4>;
+template class BigUnsigned<84>;
+
+}  // namespace strings_internal
+}  // namespace absl
diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h
new file mode 100644
index 0000000..aa70af2
--- /dev/null
+++ b/absl/strings/internal/charconv_bigint.h
@@ -0,0 +1,426 @@
+// Copyright 2018 The Abseil 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 ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
+#define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <string>
+
+#include "absl/strings/ascii.h"
+#include "absl/strings/internal/charconv_parse.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace strings_internal {
+
+// The largest power that 5 that can be raised to, and still fit in a uint32_t.
+constexpr int kMaxSmallPowerOfFive = 13;
+// The largest power that 10 that can be raised to, and still fit in a uint32_t.
+constexpr int kMaxSmallPowerOfTen = 9;
+
+extern const uint32_t kFiveToNth[kMaxSmallPowerOfFive + 1];
+extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1];
+
+// Large, fixed-width unsigned integer.
+//
+// Exact rounding for decimal-to-binary floating point conversion requires very
+// large integer math, but a design goal of absl::from_chars is to avoid
+// allocating memory.  The integer precision needed for decimal-to-binary
+// conversions is large but bounded, so a huge fixed-width integer class
+// suffices.
+//
+// This is an intentionally limited big integer class.  Only needed operations
+// are implemented.  All storage lives in an array data member, and all
+// arithmetic is done in-place, to avoid requiring separate storage for operand
+// and result.
+//
+// This is an internal class.  Some methods live in the .cc file, and are
+// instantiated only for the values of max_words we need.
+template <int max_words>
+class BigUnsigned {
+ public:
+  static_assert(max_words == 4 || max_words == 84,
+                "unsupported max_words value");
+
+  BigUnsigned() : size_(0), words_{} {}
+  explicit BigUnsigned(uint32_t v) : size_(v > 0 ? 1 : 0), words_{v} {}
+  explicit BigUnsigned(uint64_t v)
+      : size_(0),
+        words_{static_cast<uint32_t>(v & 0xffffffff),
+               static_cast<uint32_t>(v >> 32)} {
+    if (words_[1]) {
+      size_ = 2;
+    } else if (words_[0]) {
+      size_ = 1;
+    }
+  }
+
+  // Constructs a BigUnsigned from the given string_view containing a decimal
+  // value.  If the input std::string is not a decimal integer, constructs a 0
+  // instead.
+  explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} {
+    // Check for valid input, returning a 0 otherwise.  This is reasonable
+    // behavior only because this constructor is for unit tests.
+    if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() ||
+        sv.empty()) {
+      return;
+    }
+    int exponent_adjust =
+        ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1);
+    if (exponent_adjust > 0) {
+      MultiplyByTenToTheNth(exponent_adjust);
+    }
+  }
+
+  // Loads the mantissa value of a previously-parsed float.
+  //
+  // Returns the associated decimal exponent.  The value of the parsed float is
+  // exactly *this * 10**exponent.
+  int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits);
+
+  // Returns the number of decimal digits of precision this type provides.  All
+  // numbers with this many decimal digits or fewer are representable by this
+  // type.
+  //
+  // Analagous to std::numeric_limits<BigUnsigned>::digits10.
+  static constexpr int Digits10() {
+    // 9975007/1035508 is very slightly less than log10(2**32).
+    return static_cast<uint64_t>(max_words) * 9975007 / 1035508;
+  }
+
+  // Shifts left by the given number of bits.
+  void ShiftLeft(int count) {
+    if (count > 0) {
+      const int word_shift = count / 32;
+      if (word_shift >= max_words) {
+        SetToZero();
+        return;
+      }
+      size_ = std::min(size_ + word_shift, max_words);
+      count %= 32;
+      if (count == 0) {
+        std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_);
+      } else {
+        for (int i = std::min(size_, max_words - 1); i > word_shift; --i) {
+          words_[i] = (words_[i - word_shift] << count) |
+                      (words_[i - word_shift - 1] >> (32 - count));
+        }
+        words_[word_shift] = words_[0] << count;
+        // Grow size_ if necessary.
+        if (size_ < max_words && words_[size_]) {
+          ++size_;
+        }
+      }
+      std::fill(words_, words_ + word_shift, 0u);
+    }
+  }
+
+
+  // Multiplies by v in-place.
+  void MultiplyBy(uint32_t v) {
+    if (size_ == 0 || v == 1) {
+      return;
+    }
+    if (v == 0) {
+      SetToZero();
+      return;
+    }
+    const uint64_t factor = v;
+    uint64_t window = 0;
+    for (int i = 0; i < size_; ++i) {
+      window += factor * words_[i];
+      words_[i] = window & 0xffffffff;
+      window >>= 32;
+    }
+    // If carry bits remain and there's space for them, grow size_.
+    if (window && size_ < max_words) {
+      words_[size_] = window & 0xffffffff;
+      ++size_;
+    }
+  }
+
+  void MultiplyBy(uint64_t v) {
+    uint32_t words[2];
+    words[0] = static_cast<uint32_t>(v);
+    words[1] = static_cast<uint32_t>(v >> 32);
+    if (words[1] == 0) {
+      MultiplyBy(words[0]);
+    } else {
+      MultiplyBy(2, words);
+    }
+  }
+
+  // Multiplies in place by 5 to the power of n.  n must be non-negative.
+  void MultiplyByFiveToTheNth(int n) {
+    while (n >= kMaxSmallPowerOfFive) {
+      MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]);
+      n -= kMaxSmallPowerOfFive;
+    }
+    if (n > 0) {
+      MultiplyBy(kFiveToNth[n]);
+    }
+  }
+
+  // Multiplies in place by 10 to the power of n.  n must be non-negative.
+  void MultiplyByTenToTheNth(int n) {
+    if (n > kMaxSmallPowerOfTen) {
+      // For large n, raise to a power of 5, then shift left by the same amount.
+      // (10**n == 5**n * 2**n.)  This requires fewer multiplications overall.
+      MultiplyByFiveToTheNth(n);
+      ShiftLeft(n);
+    } else if (n > 0) {
+      // We can do this more quickly for very small N by using a single
+      // multiplication.
+      MultiplyBy(kTenToNth[n]);
+    }
+  }
+
+  // Returns the value of 5**n, for non-negative n.  This implementation uses
+  // a lookup table, and is faster then seeding a BigUnsigned with 1 and calling
+  // MultiplyByFiveToTheNth().
+  static BigUnsigned FiveToTheNth(int n);
+
+  // Multiplies by another BigUnsigned, in-place.
+  template <int M>
+  void MultiplyBy(const BigUnsigned<M>& other) {
+    MultiplyBy(other.size(), other.words());
+  }
+
+  void SetToZero() {
+    std::fill(words_, words_ + size_, 0u);
+    size_ = 0;
+  }
+
+  // Returns the value of the nth word of this BigUnsigned.  This is
+  // range-checked, and returns 0 on out-of-bounds accesses.
+  uint32_t GetWord(int index) const {
+    if (index < 0 || index >= size_) {
+      return 0;
+    }
+    return words_[index];
+  }
+
+  // Returns this integer as a decimal std::string.  This is not used in the decimal-
+  // to-binary conversion; it is intended to aid in testing.
+  std::string ToString() const;
+
+  int size() const { return size_; }
+  const uint32_t* words() const { return words_; }
+
+ private:
+  // Reads the number between [begin, end), possibly containing a decimal point,
+  // into this BigUnsigned.
+  //
+  // Callers are required to ensure [begin, end) contains a valid number, with
+  // one or more decimal digits and at most one decimal point.  This routine
+  // will behave unpredictably if these preconditions are not met.
+  //
+  // Only the first `significant_digits` digits are read.  Digits beyond this
+  // limit are "sticky": If the final significant digit is 0 or 5, and if any
+  // dropped digit is nonzero, then that final significant digit is adjusted up
+  // to 1 or 6.  This adjustment allows for precise rounding.
+  //
+  // Returns `exponent_adjustment`, a power-of-ten exponent adjustment to
+  // account for the decimal point and for dropped significant digits.  After
+  // this function returns,
+  //   actual_value_of_parsed_string ~= *this * 10**exponent_adjustment.
+  int ReadDigits(const char* begin, const char* end, int significant_digits);
+
+  // Performs a step of big integer multiplication.  This computes the full
+  // (64-bit-wide) values that should be added at the given index (step), and
+  // adds to that location in-place.
+  //
+  // Because our math all occurs in place, we must multiply starting from the
+  // highest word working downward.  (This is a bit more expensive due to the
+  // extra carries involved.)
+  //
+  // This must be called in steps, for each word to be calculated, starting from
+  // the high end and working down to 0.  The first value of `step` should be
+  //   `std::min(original_size + other.size_ - 2, max_words - 1)`.
+  // The reason for this expression is that multiplying the i'th word from one
+  // multiplicand and the j'th word of another multiplicand creates a
+  // two-word-wide value to be stored at the (i+j)'th element.  The highest
+  // word indices we will access are `original_size - 1` from this object, and
+  // `other.size_ - 1` from our operand.  Therefore,
+  // `original_size + other.size_ - 2` is the first step we should calculate,
+  // but limited on an upper bound by max_words.
+
+  // Working from high-to-low ensures that we do not overwrite the portions of
+  // the initial value of *this which are still needed for later steps.
+  //
+  // Once called with step == 0, *this contains the result of the
+  // multiplication.
+  //
+  // `original_size` is the size_ of *this before the first call to
+  // MultiplyStep().  `other_words` and `other_size` are the contents of our
+  // operand.  `step` is the step to perform, as described above.
+  void MultiplyStep(int original_size, const uint32_t* other_words,
+                    int other_size, int step);
+
+  void MultiplyBy(int other_size, const uint32_t* other_words) {
+    const int original_size = size_;
+    const int first_step =
+        std::min(original_size + other_size - 2, max_words - 1);
+    for (int step = first_step; step >= 0; --step) {
+      MultiplyStep(original_size, other_words, other_size, step);
+    }
+  }
+
+  // Adds a 32-bit value to the index'th word, with carry.
+  void AddWithCarry(int index, uint32_t value) {
+    if (value) {
+      while (index < max_words && value > 0) {
+        words_[index] += value;
+        // carry if we overflowed in this word:
+        if (value > words_[index]) {
+          value = 1;
+          ++index;
+        } else {
+          value = 0;
+        }
+      }
+      size_ = std::min(max_words, std::max(index + 1, size_));
+    }
+  }
+
+  void AddWithCarry(int index, uint64_t value) {
+    if (value && index < max_words) {
+      uint32_t high = value >> 32;
+      uint32_t low = value & 0xffffffff;
+      words_[index] += low;
+      if (words_[index] < low) {
+        ++high;
+        if (high == 0) {
+          // Carry from the low word caused our high word to overflow.
+          // Short circuit here to do the right thing.
+          AddWithCarry(index + 2, static_cast<uint32_t>(1));
+          return;
+        }
+      }
+      if (high > 0) {
+        AddWithCarry(index + 1, high);
+      } else {
+        // Normally 32-bit AddWithCarry() sets size_, but since we don't call
+        // it when `high` is 0, do it ourselves here.
+        size_ = std::min(max_words, std::max(index + 1, size_));
+      }
+    }
+  }
+
+  // Divide this in place by a constant divisor.  Returns the remainder of the
+  // division.
+  template <uint32_t divisor>
+  uint32_t DivMod() {
+    uint64_t accumulator = 0;
+    for (int i = size_ - 1; i >= 0; --i) {
+      accumulator <<= 32;
+      accumulator += words_[i];
+      // accumulator / divisor will never overflow an int32_t in this loop
+      words_[i] = static_cast<uint32_t>(accumulator / divisor);
+      accumulator = accumulator % divisor;
+    }
+    while (size_ > 0 && words_[size_ - 1] == 0) {
+      --size_;
+    }
+    return static_cast<uint32_t>(accumulator);
+  }
+
+  // The number of elements in words_ that may carry significant values.
+  // All elements beyond this point are 0.
+  //
+  // When size_ is 0, this BigUnsigned stores the value 0.
+  // When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is
+  // nonzero.  This can occur due to overflow truncation.
+  // In particular, x.size_ != y.size_ does *not* imply x != y.
+  int size_;
+  uint32_t words_[max_words];
+};
+
+// Compares two big integer instances.
+//
+// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs.
+template <int N, int M>
+int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  int limit = std::max(lhs.size(), rhs.size());
+  for (int i = limit - 1; i >= 0; --i) {
+    const uint32_t lhs_word = lhs.GetWord(i);
+    const uint32_t rhs_word = rhs.GetWord(i);
+    if (lhs_word < rhs_word) {
+      return -1;
+    } else if (lhs_word > rhs_word) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+template <int N, int M>
+bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  int limit = std::max(lhs.size(), rhs.size());
+  for (int i = 0; i < limit; ++i) {
+    if (lhs.GetWord(i) != rhs.GetWord(i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <int N, int M>
+bool operator!=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return !(lhs == rhs);
+}
+
+template <int N, int M>
+bool operator<(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return Compare(lhs, rhs) == -1;
+}
+
+template <int N, int M>
+bool operator>(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return rhs < lhs;
+}
+template <int N, int M>
+bool operator<=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return !(rhs < lhs);
+}
+template <int N, int M>
+bool operator>=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return !(lhs < rhs);
+}
+
+// Output operator for BigUnsigned, for testing purposes only.
+template <int N>
+std::ostream& operator<<(std::ostream& os, const BigUnsigned<N>& num) {
+  return os << num.ToString();
+}
+
+// Explicit instantiation declarations for the sizes of BigUnsigned that we
+// are using.
+//
+// For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is
+// still bigger than an int128, and 84 is a large value we will want to use
+// in the from_chars implementation.
+//
+// Comments justifying the use of 84 belong in the from_chars implementation,
+// and will be added in a follow-up CL.
+extern template class BigUnsigned<4>;
+extern template class BigUnsigned<84>;
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc
new file mode 100644
index 0000000..9b63578
--- /dev/null
+++ b/absl/strings/internal/charconv_bigint_test.cc
@@ -0,0 +1,203 @@
+// Copyright 2018 The Abseil 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 "absl/strings/internal/charconv_bigint.h"
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace strings_internal {
+
+TEST(BigUnsigned, ShiftLeft) {
+  {
+    // Check that 3 * 2**100 is calculated correctly
+    BigUnsigned<4> num(3u);
+    num.ShiftLeft(100);
+    EXPECT_EQ(num, BigUnsigned<4>("3802951800684688204490109616128"));
+  }
+  {
+    // Test that overflow is truncated properly.
+    // 15 is 4 bits long, and BigUnsigned<4> is a 128-bit bigint.
+    // Shifting left by 125 bits should truncate off the high bit, so that
+    //   15 << 125 == 7 << 125
+    // after truncation.
+    BigUnsigned<4> a(15u);
+    BigUnsigned<4> b(7u);
+    BigUnsigned<4> c(3u);
+    a.ShiftLeft(125);
+    b.ShiftLeft(125);
+    c.ShiftLeft(125);
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+  }
+  {
+    // Same test, larger bigint:
+    BigUnsigned<84> a(15u);
+    BigUnsigned<84> b(7u);
+    BigUnsigned<84> c(3u);
+    a.ShiftLeft(84 * 32 - 3);
+    b.ShiftLeft(84 * 32 - 3);
+    c.ShiftLeft(84 * 32 - 3);
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+  }
+  {
+    // Check that incrementally shifting has the same result as doing it all at
+    // once (attempting to capture corner cases.)
+    const std::string seed = "1234567890123456789012345678901234567890";
+    BigUnsigned<84> a(seed);
+    for (int i = 1; i <= 84 * 32; ++i) {
+      a.ShiftLeft(1);
+      BigUnsigned<84> b(seed);
+      b.ShiftLeft(i);
+      EXPECT_EQ(a, b);
+    }
+    // And we should have fully rotated all bits off by now:
+    EXPECT_EQ(a, BigUnsigned<84>(0u));
+  }
+}
+
+TEST(BigUnsigned, MultiplyByUint32) {
+  const BigUnsigned<84> factorial_100(
+      "933262154439441526816992388562667004907159682643816214685929638952175999"
+      "932299156089414639761565182862536979208272237582511852109168640000000000"
+      "00000000000000");
+  BigUnsigned<84> a(1u);
+  for (uint32_t i = 1; i <= 100; ++i) {
+    a.MultiplyBy(i);
+  }
+  EXPECT_EQ(a, BigUnsigned<84>(factorial_100));
+}
+
+TEST(BigUnsigned, MultiplyByBigUnsigned) {
+  {
+    // Put the terms of factorial_200 into two bigints, and multiply them
+    // together.
+    const BigUnsigned<84> factorial_200(
+        "7886578673647905035523632139321850622951359776871732632947425332443594"
+        "4996340334292030428401198462390417721213891963883025764279024263710506"
+        "1926624952829931113462857270763317237396988943922445621451664240254033"
+        "2918641312274282948532775242424075739032403212574055795686602260319041"
+        "7032406235170085879617892222278962370389737472000000000000000000000000"
+        "0000000000000000000000000");
+    BigUnsigned<84> evens(1u);
+    BigUnsigned<84> odds(1u);
+    for (uint32_t i = 1; i < 200; i += 2) {
+      odds.MultiplyBy(i);
+      evens.MultiplyBy(i + 1);
+    }
+    evens.MultiplyBy(odds);
+    EXPECT_EQ(evens, factorial_200);
+  }
+  {
+    // Multiply various powers of 10 together.
+    for (int a = 0 ; a < 700; a += 25) {
+      SCOPED_TRACE(a);
+      BigUnsigned<84> a_value("3" + std::string(a, '0'));
+      for (int b = 0; b < (700 - a); b += 25) {
+        SCOPED_TRACE(b);
+        BigUnsigned<84> b_value("2" + std::string(b, '0'));
+        BigUnsigned<84> expected_product("6" + std::string(a + b, '0'));
+        b_value.MultiplyBy(a_value);
+        EXPECT_EQ(b_value, expected_product);
+      }
+    }
+  }
+}
+
+TEST(BigUnsigned, MultiplyByOverflow) {
+  {
+    // Check that multiplcation overflow predictably truncates.
+
+    // A big int with all bits on.
+    BigUnsigned<4> all_bits_on("340282366920938463463374607431768211455");
+    // Modulo 2**128, this is equal to -1.  Therefore the square of this,
+    // modulo 2**128, should be 1.
+    all_bits_on.MultiplyBy(all_bits_on);
+    EXPECT_EQ(all_bits_on, BigUnsigned<4>(1u));
+  }
+  {
+    // Try multiplying a large bigint by 2**50, and compare the result to
+    // shifting.
+    BigUnsigned<4> value_1("12345678901234567890123456789012345678");
+    BigUnsigned<4> value_2("12345678901234567890123456789012345678");
+    BigUnsigned<4> two_to_fiftieth(1u);
+    two_to_fiftieth.ShiftLeft(50);
+
+    value_1.ShiftLeft(50);
+    value_2.MultiplyBy(two_to_fiftieth);
+    EXPECT_EQ(value_1, value_2);
+  }
+}
+
+TEST(BigUnsigned, FiveToTheNth) {
+  {
+    // Sanity check that MultiplyByFiveToTheNth gives consistent answers, up to
+    // and including overflow.
+    for (int i = 0; i < 1160; ++i) {
+      SCOPED_TRACE(i);
+      BigUnsigned<84> value_1(123u);
+      BigUnsigned<84> value_2(123u);
+      value_1.MultiplyByFiveToTheNth(i);
+      for (int j = 0; j < i; j++) {
+        value_2.MultiplyBy(5u);
+      }
+      EXPECT_EQ(value_1, value_2);
+    }
+  }
+  {
+    // Check that the faster, table-lookup-based static method returns the same
+    // result that multiplying in-place would return, up to and including
+    // overflow.
+    for (int i = 0; i < 1160; ++i) {
+      SCOPED_TRACE(i);
+      BigUnsigned<84> value_1(1u);
+      value_1.MultiplyByFiveToTheNth(i);
+      BigUnsigned<84> value_2 = BigUnsigned<84>::FiveToTheNth(i);
+      EXPECT_EQ(value_1, value_2);
+    }
+  }
+}
+
+TEST(BigUnsigned, TenToTheNth) {
+  {
+    // Sanity check MultiplyByTenToTheNth.
+    for (int i = 0; i < 800; ++i) {
+      SCOPED_TRACE(i);
+      BigUnsigned<84> value_1(123u);
+      BigUnsigned<84> value_2(123u);
+      value_1.MultiplyByTenToTheNth(i);
+      for (int j = 0; j < i; j++) {
+        value_2.MultiplyBy(10u);
+      }
+      EXPECT_EQ(value_1, value_2);
+    }
+  }
+  {
+    // Alternate testing approach, taking advantage of the decimal parser.
+    for (int i = 0; i < 200; ++i) {
+      SCOPED_TRACE(i);
+      BigUnsigned<84> value_1(135u);
+      value_1.MultiplyByTenToTheNth(i);
+      BigUnsigned<84> value_2("135" + std::string(i, '0'));
+      EXPECT_EQ(value_1, value_2);
+    }
+  }
+}
+
+
+}  // namespace strings_internal
+}  // namespace absl
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc
new file mode 100644
index 0000000..a04cc67
--- /dev/null
+++ b/absl/strings/internal/charconv_parse.cc
@@ -0,0 +1,496 @@
+// Copyright 2018 The Abseil 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 "absl/strings/internal/charconv_parse.h"
+#include "absl/strings/charconv.h"
+
+#include <cassert>
+#include <cstdint>
+#include <limits>
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+namespace {
+
+// ParseFloat<10> will read the first 19 significant digits of the mantissa.
+// This number was chosen for multiple reasons.
+//
+// (a) First, for whatever integer type we choose to represent the mantissa, we
+// want to choose the largest possible number of decimal digits for that integer
+// type.  We are using uint64_t, which can express any 19-digit unsigned
+// integer.
+//
+// (b) Second, we need to parse enough digits that the binary value of any
+// mantissa we capture has more bits of resolution than the mantissa
+// representation in the target float.  Our algorithm requires at least 3 bits
+// of headway, but 19 decimal digits give a little more than that.
+//
+// The following static assertions verify the above comments:
+constexpr int kDecimalMantissaDigitsMax = 19;
+
+static_assert(std::numeric_limits<uint64_t>::digits10 ==
+                  kDecimalMantissaDigitsMax,
+              "(a) above");
+
+// IEEE doubles, which we assume in Abseil, have 53 binary bits of mantissa.
+static_assert(std::numeric_limits<double>::is_iec559, "IEEE double assumed");
+static_assert(std::numeric_limits<double>::radix == 2, "IEEE double fact");
+static_assert(std::numeric_limits<double>::digits == 53, "IEEE double fact");
+
+// The lowest valued 19-digit decimal mantissa we can read still contains
+// sufficient information to reconstruct a binary mantissa.
+static_assert(1000000000000000000u > (uint64_t(1) << (53 + 3)), "(b) above");
+
+// ParseFloat<16> will read the first 15 significant digits of the mantissa.
+//
+// Because a base-16-to-base-2 conversion can be done exactly, we do not need
+// to maximize the number of scanned hex digits to improve our conversion.  What
+// is required is to scan two more bits than the mantissa can represent, so that
+// we always round correctly.
+//
+// (One extra bit does not suffice to perform correct rounding, since a number
+// exactly halfway between two representable floats has unique rounding rules,
+// so we need to differentiate between a "halfway between" number and a "closer
+// to the larger value" number.)
+constexpr int kHexadecimalMantissaDigitsMax = 15;
+
+// The minimum number of significant bits that will be read from
+// kHexadecimalMantissaDigitsMax hex digits.  We must subtract by three, since
+// the most significant digit can be a "1", which only contributes a single
+// significant bit.
+constexpr int kGuaranteedHexadecimalMantissaBitPrecision =
+    4 * kHexadecimalMantissaDigitsMax - 3;
+
+static_assert(kGuaranteedHexadecimalMantissaBitPrecision >
+                  std::numeric_limits<double>::digits + 2,
+              "kHexadecimalMantissaDigitsMax too small");
+
+// We also impose a limit on the number of significant digits we will read from
+// an exponent, to avoid having to deal with integer overflow.  We use 9 for
+// this purpose.
+//
+// If we read a 9 digit exponent, the end result of the conversion will
+// necessarily be infinity or zero, depending on the sign of the exponent.
+// Therefore we can just drop extra digits on the floor without any extra
+// logic.
+constexpr int kDecimalExponentDigitsMax = 9;
+static_assert(std::numeric_limits<int>::digits10 >= kDecimalExponentDigitsMax,
+              "int type too small");
+
+// To avoid incredibly large inputs causing integer overflow for our exponent,
+// we impose an arbitrary but very large limit on the number of significant
+// digits we will accept.  The implementation refuses to match a std::string with
+// more consecutive significant mantissa digits than this.
+constexpr int kDecimalDigitLimit = 50000000;
+
+// Corresponding limit for hexadecimal digit inputs.  This is one fourth the
+// amount of kDecimalDigitLimit, since each dropped hexadecimal digit requires
+// a binary exponent adjustment of 4.
+constexpr int kHexadecimalDigitLimit = kDecimalDigitLimit / 4;
+
+// The largest exponent we can read is 999999999 (per
+// kDecimalExponentDigitsMax), and the largest exponent adjustment we can get
+// from dropped mantissa digits is 2 * kDecimalDigitLimit, and the sum of these
+// comfortably fits in an integer.
+//
+// We count kDecimalDigitLimit twice because there are independent limits for
+// numbers before and after the decimal point.  (In the case where there are no
+// significant digits before the decimal point, there are independent limits for
+// post-decimal-point leading zeroes and for significant digits.)
+static_assert(999999999 + 2 * kDecimalDigitLimit <
+                  std::numeric_limits<int>::max(),
+              "int type too small");
+static_assert(999999999 + 2 * (4 * kHexadecimalDigitLimit) <
+                  std::numeric_limits<int>::max(),
+              "int type too small");
+
+// Returns true if the provided bitfield allows parsing an exponent value
+// (e.g., "1.5e100").
+bool AllowExponent(chars_format flags) {
+  bool fixed = (flags & chars_format::fixed) == chars_format::fixed;
+  bool scientific =
+      (flags & chars_format::scientific) == chars_format::scientific;
+  return scientific || !fixed;
+}
+
+// Returns true if the provided bitfield requires an exponent value be present.
+bool RequireExponent(chars_format flags) {
+  bool fixed = (flags & chars_format::fixed) == chars_format::fixed;
+  bool scientific =
+      (flags & chars_format::scientific) == chars_format::scientific;
+  return scientific && !fixed;
+}
+
+const int8_t kAsciiToInt[256] = {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0,  1,  2,  3,  4,  5,  6,  7,  8,
+    9,  -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+// Returns true if `ch` is a digit in the given base
+template <int base>
+bool IsDigit(char ch);
+
+// Converts a valid `ch` to its digit value in the given base.
+template <int base>
+unsigned ToDigit(char ch);
+
+// Returns true if `ch` is the exponent delimiter for the given base.
+template <int base>
+bool IsExponentCharacter(char ch);
+
+// Returns the maximum number of significant digits we will read for a float
+// in the given base.
+template <int base>
+constexpr int MantissaDigitsMax();
+
+// Returns the largest consecutive run of digits we will accept when parsing a
+// number in the given base.
+template <int base>
+constexpr int DigitLimit();
+
+// Returns the amount the exponent must be adjusted by for each dropped digit.
+// (For decimal this is 1, since the digits are in base 10 and the exponent base
+// is also 10, but for hexadecimal this is 4, since the digits are base 16 but
+// the exponent base is 2.)
+template <int base>
+constexpr int DigitMagnitude();
+
+template <>
+bool IsDigit<10>(char ch) {
+  return ch >= '0' && ch <= '9';
+}
+template <>
+bool IsDigit<16>(char ch) {
+  return kAsciiToInt[static_cast<unsigned char>(ch)] >= 0;
+}
+
+template <>
+unsigned ToDigit<10>(char ch) {
+  return ch - '0';
+}
+template <>
+unsigned ToDigit<16>(char ch) {
+  return kAsciiToInt[static_cast<unsigned char>(ch)];
+}
+
+template <>
+bool IsExponentCharacter<10>(char ch) {
+  return ch == 'e' || ch == 'E';
+}
+
+template <>
+bool IsExponentCharacter<16>(char ch) {
+  return ch == 'p' || ch == 'P';
+}
+
+template <>
+constexpr int MantissaDigitsMax<10>() {
+  return kDecimalMantissaDigitsMax;
+}
+template <>
+constexpr int MantissaDigitsMax<16>() {
+  return kHexadecimalMantissaDigitsMax;
+}
+
+template <>
+constexpr int DigitLimit<10>() {
+  return kDecimalDigitLimit;
+}
+template <>
+constexpr int DigitLimit<16>() {
+  return kHexadecimalDigitLimit;
+}
+
+template <>
+constexpr int DigitMagnitude<10>() {
+  return 1;
+}
+template <>
+constexpr int DigitMagnitude<16>() {
+  return 4;
+}
+
+// Reads decimal digits from [begin, end) into *out.  Returns the number of
+// digits consumed.
+//
+// After max_digits has been read, keeps consuming characters, but no longer
+// adjusts *out.  If a nonzero digit is dropped this way, *dropped_nonzero_digit
+// is set; otherwise, it is left unmodified.
+//
+// If no digits are matched, returns 0 and leaves *out unchanged.
+//
+// ConsumeDigits does not protect against overflow on *out; max_digits must
+// be chosen with respect to type T to avoid the possibility of overflow.
+template <int base, typename T>
+std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
+                          T* out, bool* dropped_nonzero_digit) {
+  if (base == 10) {
+    assert(max_digits <= std::numeric_limits<T>::digits10);
+  } else if (base == 16) {
+    assert(max_digits * 4 <= std::numeric_limits<T>::digits);
+  }
+  const char* const original_begin = begin;
+  T accumulator = *out;
+  const char* significant_digits_end =
+      (end - begin > max_digits) ? begin + max_digits : end;
+  while (begin < significant_digits_end && IsDigit<base>(*begin)) {
+    // Do not guard against *out overflow; max_digits was chosen to avoid this.
+    // Do assert against it, to detect problems in debug builds.
+    auto digit = static_cast<T>(ToDigit<base>(*begin));
+    assert(accumulator * base >= accumulator);
+    accumulator *= base;
+    assert(accumulator + digit >= accumulator);
+    accumulator += digit;
+    ++begin;
+  }
+  bool dropped_nonzero = false;
+  while (begin < end && IsDigit<base>(*begin)) {
+    dropped_nonzero = dropped_nonzero || (*begin != '0');
+    ++begin;
+  }
+  if (dropped_nonzero && dropped_nonzero_digit != nullptr) {
+    *dropped_nonzero_digit = true;
+  }
+  *out = accumulator;
+  return begin - original_begin;
+}
+
+// Returns true if `v` is one of the chars allowed inside parentheses following
+// a NaN.
+bool IsNanChar(char v) {
+  return (v == '_') || (v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') ||
+         (v >= 'A' && v <= 'Z');
+}
+
+// Checks the range [begin, end) for a strtod()-formatted infinity or NaN.  If
+// one is found, sets `out` appropriately and returns true.
+bool ParseInfinityOrNan(const char* begin, const char* end,
+                        strings_internal::ParsedFloat* out) {
+  if (end - begin < 3) {
+    return false;
+  }
+  switch (*begin) {
+    case 'i':
+    case 'I': {
+      // An infinity std::string consists of the characters "inf" or "infinity",
+      // case insensitive.
+      if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) {
+        return false;
+      }
+      out->type = strings_internal::FloatType::kInfinity;
+      if (end - begin >= 8 &&
+          strings_internal::memcasecmp(begin + 3, "inity", 5) == 0) {
+        out->end = begin + 8;
+      } else {
+        out->end = begin + 3;
+      }
+      return true;
+    }
+    case 'n':
+    case 'N': {
+      // A NaN consists of the characters "nan", case insensitive, optionally
+      // followed by a parenthesized sequence of zero or more alphanumeric
+      // characters and/or underscores.
+      if (strings_internal::memcasecmp(begin + 1, "an", 2) != 0) {
+        return false;
+      }
+      out->type = strings_internal::FloatType::kNan;
+      out->end = begin + 3;
+      // NaN is allowed to be followed by a parenthesized std::string, consisting of
+      // only the characters [a-zA-Z0-9_].  Match that if it's present.
+      begin += 3;
+      if (begin < end && *begin == '(') {
+        const char* nan_begin = begin + 1;
+        while (nan_begin < end && IsNanChar(*nan_begin)) {
+          ++nan_begin;
+        }
+        if (nan_begin < end && *nan_begin == ')') {
+          // We found an extra NaN specifier range
+          out->subrange_begin = begin + 1;
+          out->subrange_end = nan_begin;
+          out->end = nan_begin + 1;
+        }
+      }
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+}  // namespace
+
+namespace strings_internal {
+
+template <int base>
+strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end,
+                                         chars_format format_flags) {
+  strings_internal::ParsedFloat result;
+
+  // Exit early if we're given an empty range.
+  if (begin == end) return result;
+
+  // Handle the infinity and NaN cases.
+  if (ParseInfinityOrNan(begin, end, &result)) {
+    return result;
+  }
+
+  const char* const mantissa_begin = begin;
+  while (begin < end && *begin == '0') {
+    ++begin;  // skip leading zeros
+  }
+  uint64_t mantissa = 0;
+
+  int exponent_adjustment = 0;
+  bool mantissa_is_inexact = false;
+  std::size_t pre_decimal_digits = ConsumeDigits<base>(
+      begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
+  begin += pre_decimal_digits;
+  int digits_left;
+  if (pre_decimal_digits >= DigitLimit<base>()) {
+    // refuse to parse pathological inputs
+    return result;
+  } else if (pre_decimal_digits > MantissaDigitsMax<base>()) {
+    // We dropped some non-fraction digits on the floor.  Adjust our exponent
+    // to compensate.
+    exponent_adjustment =
+        static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>());
+    digits_left = 0;
+  } else {
+    digits_left =
+        static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits);
+  }
+  if (begin < end && *begin == '.') {
+    ++begin;
+    if (mantissa == 0) {
+      // If we haven't seen any nonzero digits yet, keep skipping zeros.  We
+      // have to adjust the exponent to reflect the changed place value.
+      const char* begin_zeros = begin;
+      while (begin < end && *begin == '0') {
+        ++begin;
+      }
+      std::size_t zeros_skipped = begin - begin_zeros;
+      if (zeros_skipped >= DigitLimit<base>()) {
+        // refuse to parse pathological inputs
+        return result;
+      }
+      exponent_adjustment -= static_cast<int>(zeros_skipped);
+    }
+    std::size_t post_decimal_digits = ConsumeDigits<base>(
+        begin, end, digits_left, &mantissa, &mantissa_is_inexact);
+    begin += post_decimal_digits;
+
+    // Since `mantissa` is an integer, each significant digit we read after
+    // the decimal point requires an adjustment to the exponent. "1.23e0" will
+    // be stored as `mantissa` == 123 and `exponent` == -2 (that is,
+    // "123e-2").
+    if (post_decimal_digits >= DigitLimit<base>()) {
+      // refuse to parse pathological inputs
+      return result;
+    } else if (post_decimal_digits > digits_left) {
+      exponent_adjustment -= digits_left;
+    } else {
+      exponent_adjustment -= post_decimal_digits;
+    }
+  }
+  // If we've found no mantissa whatsoever, this isn't a number.
+  if (mantissa_begin == begin) {
+    return result;
+  }
+  // A bare "." doesn't count as a mantissa either.
+  if (begin - mantissa_begin == 1 && *mantissa_begin == '.') {
+    return result;
+  }
+
+  if (mantissa_is_inexact) {
+    // We dropped significant digits on the floor.  Handle this appropriately.
+    if (base == 10) {
+      // If we truncated significant decimal digits, store the full range of the
+      // mantissa for future big integer math for exact rounding.
+      result.subrange_begin = mantissa_begin;
+      result.subrange_end = begin;
+    } else if (base == 16) {
+      // If we truncated hex digits, reflect this fact by setting the low
+      // ("sticky") bit.  This allows for correct rounding in all cases.
+      mantissa |= 1;
+    }
+  }
+  result.mantissa = mantissa;
+
+  const char* const exponent_begin = begin;
+  result.literal_exponent = 0;
+  bool found_exponent = false;
+  if (AllowExponent(format_flags) && begin < end &&
+      IsExponentCharacter<base>(*begin)) {
+    bool negative_exponent = false;
+    ++begin;
+    if (begin < end && *begin == '-') {
+      negative_exponent = true;
+      ++begin;
+    } else if (begin < end && *begin == '+') {
+      ++begin;
+    }
+    const char* const exponent_digits_begin = begin;
+    // Exponent is always expressed in decimal, even for hexadecimal floats.
+    begin += ConsumeDigits<10>(begin, end, kDecimalExponentDigitsMax,
+                               &result.literal_exponent, nullptr);
+    if (begin == exponent_digits_begin) {
+      // there were no digits where we expected an exponent.  We failed to read
+      // an exponent and should not consume the 'e' after all.  Rewind 'begin'.
+      found_exponent = false;
+      begin = exponent_begin;
+    } else {
+      found_exponent = true;
+      if (negative_exponent) {
+        result.literal_exponent = -result.literal_exponent;
+      }
+    }
+  }
+
+  if (!found_exponent && RequireExponent(format_flags)) {
+    // Provided flags required an exponent, but none was found.  This results
+    // in a failure to scan.
+    return result;
+  }
+
+  // Success!
+  result.type = strings_internal::FloatType::kNumber;
+  if (result.mantissa > 0) {
+    result.exponent = result.literal_exponent +
+                      (DigitMagnitude<base>() * exponent_adjustment);
+  } else {
+    result.exponent = 0;
+  }
+  result.end = begin;
+  return result;
+}
+
+template ParsedFloat ParseFloat<10>(const char* begin, const char* end,
+                                    chars_format format_flags);
+template ParsedFloat ParseFloat<16>(const char* begin, const char* end,
+                                    chars_format format_flags);
+
+}  // namespace strings_internal
+}  // namespace absl
diff --git a/absl/strings/internal/charconv_parse.h b/absl/strings/internal/charconv_parse.h
new file mode 100644
index 0000000..7a5c087
--- /dev/null
+++ b/absl/strings/internal/charconv_parse.h
@@ -0,0 +1,96 @@
+// Copyright 2018 The Abseil 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 ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
+#define ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
+
+#include <cstdint>
+
+#include "absl/strings/charconv.h"
+
+namespace absl {
+namespace strings_internal {
+
+// Enum indicating whether a parsed float is a number or special value.
+enum class FloatType { kNumber, kInfinity, kNan };
+
+// The decomposed parts of a parsed `float` or `double`.
+struct ParsedFloat {
+  // Representation of the parsed mantissa, with the decimal point adjusted to
+  // make it an integer.
+  //
+  // During decimal scanning, this contains 19 significant digits worth of
+  // mantissa value.  If digits beyond this point are found, they
+  // are truncated, and if any of these dropped digits are nonzero, then
+  // `mantissa` is inexact, and the full mantissa is stored in [subrange_begin,
+  // subrange_end).
+  //
+  // During hexadecimal scanning, this contains 15 significant hex digits worth
+  // of mantissa value.  Digits beyond this point are sticky -- they are
+  // truncated, but if any dropped digits are nonzero, the low bit of mantissa
+  // will be set.  (This allows for precise rounding, and avoids the need
+  // to store the full mantissa in [subrange_begin, subrange_end).)
+  uint64_t mantissa = 0;
+
+  // Floating point expontent.  This reflects any decimal point adjustments and
+  // any truncated digits from the mantissa.  The absolute value of the parsed
+  // number is represented by mantissa * (base ** exponent), where base==10 for
+  // decimal floats, and base==2 for hexadecimal floats.
+  int exponent = 0;
+
+  // The literal exponent value scanned from the input, or 0 if none was
+  // present.  This does not reflect any adjustments applied to mantissa.
+  int literal_exponent = 0;
+
+  // The type of number scanned.
+  FloatType type = FloatType::kNumber;
+
+  // When non-null, [subrange_begin, subrange_end) marks a range of characters
+  // that require further processing.  The meaning is dependent on float type.
+  // If type == kNumber and this is set, this is a "wide input": the input
+  // mantissa contained more than 19 digits.  The range contains the full
+  // mantissa.  It plus `literal_exponent` need to be examined to find the best
+  // floating point match.
+  // If type == kNan and this is set, the range marks the contents of a
+  // matched parenthesized character region after the NaN.
+  const char* subrange_begin = nullptr;
+  const char* subrange_end = nullptr;
+
+  // One-past-the-end of the successfully parsed region, or nullptr if no
+  // matching pattern was found.
+  const char* end = nullptr;
+};
+
+// Read the floating point number in the provided range, and populate
+// ParsedFloat accordingly.
+//
+// format_flags is a bitmask value specifying what patterns this API will match.
+// `scientific` and `fixed`  are honored per std::from_chars rules
+// ([utility.from.chars], C++17): if exactly one of these bits is set, then an
+// exponent is required, or dislallowed, respectively.
+//
+// Template parameter `base` must be either 10 or 16.  For base 16, a "0x" is
+// *not* consumed.  The `hex` bit from format_flags is ignored by ParseFloat.
+template <int base>
+ParsedFloat ParseFloat(const char* begin, const char* end,
+                       absl::chars_format format_flags);
+
+extern template ParsedFloat ParseFloat<10>(const char* begin, const char* end,
+                                           absl::chars_format format_flags);
+extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end,
+                                           absl::chars_format format_flags);
+
+}  // namespace strings_internal
+}  // namespace absl
+#endif  // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc
new file mode 100644
index 0000000..1ff8600
--- /dev/null
+++ b/absl/strings/internal/charconv_parse_test.cc
@@ -0,0 +1,357 @@
+// Copyright 2018 The Abseil 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 "absl/strings/internal/charconv_parse.h"
+
+#include <string>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_cat.h"
+
+using absl::chars_format;
+using absl::strings_internal::FloatType;
+using absl::strings_internal::ParsedFloat;
+using absl::strings_internal::ParseFloat;
+
+namespace {
+
+// Check that a given std::string input is parsed to the expected mantissa and
+// exponent.
+//
+// Input std::string `s` must contain a '$' character.  It marks the end of the
+// characters that should be consumed by the match.  It is stripped from the
+// input to ParseFloat.
+//
+// If input std::string `s` contains '[' and ']' characters, these mark the region
+// of characters that should be marked as the "subrange".  For NaNs, this is
+// the location of the extended NaN std::string.  For numbers, this is the location
+// of the full, over-large mantissa.
+template <int base>
+void ExpectParsedFloat(std::string s, absl::chars_format format_flags,
+                       FloatType expected_type, uint64_t expected_mantissa,
+                       int expected_exponent,
+                       int expected_literal_exponent = -999) {
+  SCOPED_TRACE(s);
+
+  int begin_subrange = -1;
+  int end_subrange = -1;
+  // If s contains '[' and ']', then strip these characters and set the subrange
+  // indices appropriately.
+  std::string::size_type open_bracket_pos = s.find('[');
+  if (open_bracket_pos != std::string::npos) {
+    begin_subrange = static_cast<int>(open_bracket_pos);
+    s.replace(open_bracket_pos, 1, "");
+    std::string::size_type close_bracket_pos = s.find(']');
+    ABSL_RAW_CHECK(close_bracket_pos != absl::string_view::npos,
+                   "Test input contains [ without matching ]");
+    end_subrange = static_cast<int>(close_bracket_pos);
+    s.replace(close_bracket_pos, 1, "");
+  }
+  const std::string::size_type expected_characters_matched = s.find('$');
+  ABSL_RAW_CHECK(expected_characters_matched != std::string::npos,
+                 "Input std::string must contain $");
+  s.replace(expected_characters_matched, 1, "");
+
+  ParsedFloat parsed =
+      ParseFloat<base>(s.data(), s.data() + s.size(), format_flags);
+
+  EXPECT_NE(parsed.end, nullptr);
+  if (parsed.end == nullptr) {
+    return;  // The following tests are not useful if we fully failed to parse
+  }
+  EXPECT_EQ(parsed.type, expected_type);
+  if (begin_subrange == -1) {
+    EXPECT_EQ(parsed.subrange_begin, nullptr);
+    EXPECT_EQ(parsed.subrange_end, nullptr);
+  } else {
+    EXPECT_EQ(parsed.subrange_begin, s.data() + begin_subrange);
+    EXPECT_EQ(parsed.subrange_end, s.data() + end_subrange);
+  }
+  if (parsed.type == FloatType::kNumber) {
+    EXPECT_EQ(parsed.mantissa, expected_mantissa);
+    EXPECT_EQ(parsed.exponent, expected_exponent);
+    if (expected_literal_exponent != -999) {
+      EXPECT_EQ(parsed.literal_exponent, expected_literal_exponent);
+    }
+  }
+  auto characters_matched = static_cast<int>(parsed.end - s.data());
+  EXPECT_EQ(characters_matched, expected_characters_matched);
+}
+
+// Check that a given std::string input is parsed to the expected mantissa and
+// exponent.
+//
+// Input std::string `s` must contain a '$' character.  It marks the end of the
+// characters that were consumed by the match.
+template <int base>
+void ExpectNumber(std::string s, absl::chars_format format_flags,
+                  uint64_t expected_mantissa, int expected_exponent,
+                  int expected_literal_exponent = -999) {
+  ExpectParsedFloat<base>(std::move(s), format_flags, FloatType::kNumber,
+                          expected_mantissa, expected_exponent,
+                          expected_literal_exponent);
+}
+
+// Check that a given std::string input is parsed to the given special value.
+//
+// This tests against both number bases, since infinities and NaNs have
+// identical representations in both modes.
+void ExpectSpecial(const std::string& s, absl::chars_format format_flags,
+                   FloatType type) {
+  ExpectParsedFloat<10>(s, format_flags, type, 0, 0);
+  ExpectParsedFloat<16>(s, format_flags, type, 0, 0);
+}
+
+// Check that a given input std::string is not matched by Float.
+template <int base>
+void ExpectFailedParse(absl::string_view s, absl::chars_format format_flags) {
+  ParsedFloat parsed =
+      ParseFloat<base>(s.data(), s.data() + s.size(), format_flags);
+  EXPECT_EQ(parsed.end, nullptr);
+}
+
+TEST(ParseFloat, SimpleValue) {
+  // Test that various forms of floating point numbers all parse correctly.
+  ExpectNumber<10>("1.23456789e5$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789e+5$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789E5$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789e05$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("123.456789e3$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("0.000123456789e9$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("123456.789$", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("123456789e-3$", chars_format::general, 123456789, -3);
+
+  ExpectNumber<16>("1.234abcdefp28$", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("1.234abcdefp+28$", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("1.234ABCDEFp28$", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("1.234AbCdEfP0028$", chars_format::general, 0x1234abcdef,
+                   -8);
+  ExpectNumber<16>("123.4abcdefp20$", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("0.0001234abcdefp44$", chars_format::general, 0x1234abcdef,
+                   -8);
+  ExpectNumber<16>("1234abcd.ef$", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("1234abcdefp-8$", chars_format::general, 0x1234abcdef, -8);
+
+  // ExpectNumber does not attempt to drop trailing zeroes.
+  ExpectNumber<10>("0001.2345678900e005$", chars_format::general, 12345678900,
+                   -5);
+  ExpectNumber<16>("0001.234abcdef000p28$", chars_format::general,
+                   0x1234abcdef000, -20);
+
+  // Ensure non-matching characters after a number are ignored, even when they
+  // look like potentially matching characters.
+  ExpectNumber<10>("1.23456789e5$   ", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789e5$e5e5", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789e5$.25", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789e5$-", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("1.23456789e5$PUPPERS!!!", chars_format::general, 123456789,
+                   -3);
+  ExpectNumber<10>("123456.789$efghij", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("123456.789$e", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("123456.789$p5", chars_format::general, 123456789, -3);
+  ExpectNumber<10>("123456.789$.10", chars_format::general, 123456789, -3);
+
+  ExpectNumber<16>("1.234abcdefp28$   ", chars_format::general, 0x1234abcdef,
+                   -8);
+  ExpectNumber<16>("1.234abcdefp28$p28", chars_format::general, 0x1234abcdef,
+                   -8);
+  ExpectNumber<16>("1.234abcdefp28$.125", chars_format::general, 0x1234abcdef,
+                   -8);
+  ExpectNumber<16>("1.234abcdefp28$-", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("1.234abcdefp28$KITTEHS!!!", chars_format::general,
+                   0x1234abcdef, -8);
+  ExpectNumber<16>("1234abcd.ef$ghijk", chars_format::general, 0x1234abcdef,
+                   -8);
+  ExpectNumber<16>("1234abcd.ef$p", chars_format::general, 0x1234abcdef, -8);
+  ExpectNumber<16>("1234abcd.ef$.10", chars_format::general, 0x1234abcdef, -8);
+
+  // Ensure we can read a full resolution mantissa without overflow.
+  ExpectNumber<10>("9999999999999999999$", chars_format::general,
+                   9999999999999999999u, 0);
+  ExpectNumber<16>("fffffffffffffff$", chars_format::general,
+                   0xfffffffffffffffu, 0);
+
+  // Check that zero is consistently read.
+  ExpectNumber<10>("0$", chars_format::general, 0, 0);
+  ExpectNumber<16>("0$", chars_format::general, 0, 0);
+  ExpectNumber<10>("000000000000000000000000000000000000000$",
+                   chars_format::general, 0, 0);
+  ExpectNumber<16>("000000000000000000000000000000000000000$",
+                   chars_format::general, 0, 0);
+  ExpectNumber<10>("0000000000000000000000.000000000000000000$",
+                   chars_format::general, 0, 0);
+  ExpectNumber<16>("0000000000000000000000.000000000000000000$",
+                   chars_format::general, 0, 0);
+  ExpectNumber<10>("0.00000000000000000000000000000000e123456$",
+                   chars_format::general, 0, 0);
+  ExpectNumber<16>("0.00000000000000000000000000000000p123456$",
+                   chars_format::general, 0, 0);
+}
+
+TEST(ParseFloat, LargeDecimalMantissa) {
+  // After 19 significant decimal digits in the mantissa, ParsedFloat will
+  // truncate additional digits.  We need to test that:
+  //   1) the truncation to 19 digits happens
+  //   2) the returned exponent reflects the dropped significant digits
+  //   3) a correct literal_exponent is set
+  //
+  // If and only if a significant digit is found after 19 digits, then the
+  // entirety of the mantissa in case the exact value is needed to make a
+  // rounding decision.  The [ and ] characters below denote where such a
+  // subregion was marked by by ParseFloat.  They are not part of the input.
+
+  // Mark a capture group only if a dropped digit is significant (nonzero).
+  ExpectNumber<10>("100000000000000000000000000$", chars_format::general,
+                   1000000000000000000,
+                   /* adjusted exponent */ 8);
+
+  ExpectNumber<10>("123456789123456789100000000$", chars_format::general,
+                   1234567891234567891,
+                   /* adjusted exponent */ 8);
+
+  ExpectNumber<10>("[123456789123456789123456789]$", chars_format::general,
+                   1234567891234567891,
+                   /* adjusted exponent */ 8,
+                   /* literal exponent */ 0);
+
+  ExpectNumber<10>("[123456789123456789100000009]$", chars_format::general,
+                   1234567891234567891,
+                   /* adjusted exponent */ 8,
+                   /* literal exponent */ 0);
+
+  ExpectNumber<10>("[123456789123456789120000000]$", chars_format::general,
+                   1234567891234567891,
+                   /* adjusted exponent */ 8,
+                   /* literal exponent */ 0);
+
+  // Leading zeroes should not count towards the 19 significant digit limit
+  ExpectNumber<10>("[00000000123456789123456789123456789]$",
+                   chars_format::general, 1234567891234567891,
+                   /* adjusted exponent */ 8,
+                   /* literal exponent */ 0);
+
+  ExpectNumber<10>("00000000123456789123456789100000000$",
+                   chars_format::general, 1234567891234567891,
+                   /* adjusted exponent */ 8);
+
+  // Truncated digits after the decimal point should not cause a further
+  // exponent adjustment.
+  ExpectNumber<10>("1.234567891234567891e123$", chars_format::general,
+                   1234567891234567891, 105);
+  ExpectNumber<10>("[1.23456789123456789123456789]e123$", chars_format::general,
+                   1234567891234567891,
+                   /* adjusted exponent */ 105,
+                   /* literal exponent */ 123);
+
+  // Ensure we truncate, and not round.  (The from_chars algorithm we use
+  // depends on our guess missing low, if it misses, so we need the rounding
+  // error to be downward.)
+  ExpectNumber<10>("[1999999999999999999999]$", chars_format::general,
+                   1999999999999999999,
+                   /* adjusted exponent */ 3,
+                   /* literal exponent */ 0);
+}
+
+TEST(ParseFloat, LargeHexadecimalMantissa) {
+  // After 15 significant hex digits in the mantissa, ParsedFloat will treat
+  // additional digits as sticky,  We need to test that:
+  //   1) The truncation to 15 digits happens
+  //   2) The returned exponent reflects the dropped significant digits
+  //   3) If a nonzero digit is dropped, the low bit of mantissa is set.
+
+  ExpectNumber<16>("123456789abcdef123456789abcdef$", chars_format::general,
+                   0x123456789abcdef, 60);
+
+  // Leading zeroes should not count towards the 15 significant digit limit
+  ExpectNumber<16>("000000123456789abcdef123456789abcdef$",
+                   chars_format::general, 0x123456789abcdef, 60);
+
+  // Truncated digits after the radix point should not cause a further
+  // exponent adjustment.
+  ExpectNumber<16>("1.23456789abcdefp100$", chars_format::general,
+                   0x123456789abcdef, 44);
+  ExpectNumber<16>("1.23456789abcdef123456789abcdefp100$",
+                   chars_format::general, 0x123456789abcdef, 44);
+
+  // test sticky digit behavior.  The low bit should be set iff any dropped
+  // digit is nonzero.
+  ExpectNumber<16>("123456789abcdee123456789abcdee$", chars_format::general,
+                   0x123456789abcdef, 60);
+  ExpectNumber<16>("123456789abcdee000000000000001$", chars_format::general,
+                   0x123456789abcdef, 60);
+  ExpectNumber<16>("123456789abcdee000000000000000$", chars_format::general,
+                   0x123456789abcdee, 60);
+}
+
+TEST(ParseFloat, ScientificVsFixed) {
+  // In fixed mode, an exponent is never matched (but the remainder of the
+  // number will be matched.)
+  ExpectNumber<10>("1.23456789$e5", chars_format::fixed, 123456789, -8);
+  ExpectNumber<10>("123456.789$", chars_format::fixed, 123456789, -3);
+  ExpectNumber<16>("1.234abcdef$p28", chars_format::fixed, 0x1234abcdef, -36);
+  ExpectNumber<16>("1234abcd.ef$", chars_format::fixed, 0x1234abcdef, -8);
+
+  // In scientific mode, numbers don't match *unless* they have an exponent.
+  ExpectNumber<10>("1.23456789e5$", chars_format::scientific, 123456789, -3);
+  ExpectFailedParse<10>("-123456.789$", chars_format::scientific);
+  ExpectNumber<16>("1.234abcdefp28$", chars_format::scientific, 0x1234abcdef,
+                   -8);
+  ExpectFailedParse<16>("1234abcd.ef$", chars_format::scientific);
+}
+
+TEST(ParseFloat, Infinity) {
+  ExpectFailedParse<10>("in", chars_format::general);
+  ExpectFailedParse<16>("in", chars_format::general);
+  ExpectFailedParse<10>("inx", chars_format::general);
+  ExpectFailedParse<16>("inx", chars_format::general);
+  ExpectSpecial("inf$", chars_format::general, FloatType::kInfinity);
+  ExpectSpecial("Inf$", chars_format::general, FloatType::kInfinity);
+  ExpectSpecial("INF$", chars_format::general, FloatType::kInfinity);
+  ExpectSpecial("inf$inite", chars_format::general, FloatType::kInfinity);
+  ExpectSpecial("iNfInItY$", chars_format::general, FloatType::kInfinity);
+  ExpectSpecial("infinity$!!!", chars_format::general, FloatType::kInfinity);
+}
+
+TEST(ParseFloat, NaN) {
+  ExpectFailedParse<10>("na", chars_format::general);
+  ExpectFailedParse<16>("na", chars_format::general);
+  ExpectFailedParse<10>("nah", chars_format::general);
+  ExpectFailedParse<16>("nah", chars_format::general);
+  ExpectSpecial("nan$", chars_format::general, FloatType::kNan);
+  ExpectSpecial("NaN$", chars_format::general, FloatType::kNan);
+  ExpectSpecial("nAn$", chars_format::general, FloatType::kNan);
+  ExpectSpecial("NAN$", chars_format::general, FloatType::kNan);
+  ExpectSpecial("NaN$aNaNaNaNaBatman!", chars_format::general, FloatType::kNan);
+
+  // A parenthesized sequence of the characters [a-zA-Z0-9_] is allowed to
+  // appear after an NaN.  Check that this is allowed, and that the correct
+  // characters are grouped.
+  //
+  // (The characters [ and ] in the pattern below delimit the expected matched
+  // subgroup; they are not part of the input passed to ParseFloat.)
+  ExpectSpecial("nan([0xabcdef])$", chars_format::general, FloatType::kNan);
+  ExpectSpecial("nan([0xabcdef])$...", chars_format::general, FloatType::kNan);
+  ExpectSpecial("nan([0xabcdef])$)...", chars_format::general, FloatType::kNan);
+  ExpectSpecial("nan([])$", chars_format::general, FloatType::kNan);
+  ExpectSpecial("nan([aAzZ09_])$", chars_format::general, FloatType::kNan);
+  // If the subgroup contains illegal characters, don't match it at all.
+  ExpectSpecial("nan$(bad-char)", chars_format::general, FloatType::kNan);
+  // Also cope with a missing close paren.
+  ExpectSpecial("nan$(0xabcdef", chars_format::general, FloatType::kNan);
+}
+
+}  // namespace
diff --git a/absl/strings/internal/escaping_test_common.h b/absl/strings/internal/escaping_test_common.h
new file mode 100644
index 0000000..cc41f43
--- /dev/null
+++ b/absl/strings/internal/escaping_test_common.h
@@ -0,0 +1,131 @@
+// Copyright 2017 The Abseil 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.
+//
+// This test contains common things needed by both escaping_test.cc and
+// escaping_benchmark.cc.
+
+#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_
+#define ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_
+
+#include <array>
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace strings_internal {
+
+struct base64_testcase {
+  absl::string_view plaintext;
+  absl::string_view cyphertext;
+};
+
+inline const std::array<base64_testcase, 5>& base64_strings() {
+  static const std::array<base64_testcase, 5> testcase{{
+      // Some google quotes
+      // Cyphertext created with "uuencode (GNU sharutils) 4.6.3"
+      // (Note that we're testing the websafe encoding, though, so if
+      // you add messages, be sure to run "tr -- '+/' '-_'" on the output)
+      { "I was always good at math and science, and I never realized "
+        "that was unusual or somehow undesirable. So one of the things "
+        "I care a lot about is helping to remove that stigma, "
+        "to show girls that you can be feminine, you can like the things "
+        "that girls like, but you can also be really good at technology. "
+        "You can be really good at building things."
+        " - Marissa Meyer, Newsweek, 2010-12-22" "\n",
+
+        "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg"
+        "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu"
+        "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg"
+        "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo"
+        "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp"
+        "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs"
+        "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy"
+        "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll"
+        "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" },
+
+      { "Typical first year for a new cluster: "
+        "~0.5 overheating "
+        "~1 PDU failure "
+        "~1 rack-move "
+        "~1 network rewiring "
+        "~20 rack failures "
+        "~5 racks go wonky "
+        "~8 network maintenances "
+        "~12 router reloads "
+        "~3 router failures "
+        "~dozens of minor 30-second blips for dns "
+        "~1000 individual machine failures "
+        "~thousands of hard drive failures "
+        "slow disks, bad memory, misconfigured machines, flaky machines, etc."
+        " - Jeff Dean, The Joys of Real Hardware" "\n",
+
+        "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92"
+        "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3"
+        "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv"
+        "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk"
+        "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv"
+        "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp"
+        "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg"
+        "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs"
+        "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS"
+        "ZWFsIEhhcmR3YXJlCg" },
+
+      { "I'm the head of the webspam team at Google.  "
+        "That means that if you type your name into Google and get porn back, "
+        "it's my fault. Unless you're a porn star, in which case porn is a "
+        "completely reasonable response."
+        " - Matt Cutts, Google Plus" "\n",
+
+        "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg"
+        "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv"
+        "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz"
+        "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg"
+        "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs"
+        "IEdvb2dsZSBQbHVzCg" },
+
+      { "It will still be a long time before machines approach human "
+        "intelligence. "
+        "But luckily, machines don't actually have to be intelligent; "
+        "they just have to fake it. Access to a wealth of information, "
+        "combined with a rudimentary decision-making capacity, "
+        "can often be almost as useful. Of course, the results are better yet "
+        "when coupled with intelligence. A reference librarian with access to "
+        "a good search engine is a formidable tool."
+        " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004"
+        "\n",
+
+        "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg"
+        "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj"
+        "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg"
+        "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo"
+        "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg"
+        "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0"
+        "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy"
+        "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl"
+        "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu"
+        "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp"
+        "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw"
+        "NAo" },
+
+      // Degenerate edge case
+      { "",
+        "" },
+  }};
+
+  return testcase;
+}
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_
diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc
new file mode 100644
index 0000000..a0de70d
--- /dev/null
+++ b/absl/strings/internal/memutil.cc
@@ -0,0 +1,110 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/memutil.h"
+
+#include <cstdlib>
+
+namespace absl {
+namespace strings_internal {
+
+int memcasecmp(const char* s1, const char* s2, size_t len) {
+  const unsigned char* us1 = reinterpret_cast<const unsigned char*>(s1);
+  const unsigned char* us2 = reinterpret_cast<const unsigned char*>(s2);
+
+  for (size_t i = 0; i < len; i++) {
+    const int diff =
+        int{static_cast<unsigned char>(absl::ascii_tolower(us1[i]))} -
+        int{static_cast<unsigned char>(absl::ascii_tolower(us2[i]))};
+    if (diff != 0) return diff;
+  }
+  return 0;
+}
+
+char* memdup(const char* s, size_t slen) {
+  void* copy;
+  if ((copy = malloc(slen)) == nullptr) return nullptr;
+  memcpy(copy, s, slen);
+  return reinterpret_cast<char*>(copy);
+}
+
+char* memrchr(const char* s, int c, size_t slen) {
+  for (const char* e = s + slen - 1; e >= s; e--) {
+    if (*e == c) return const_cast<char*>(e);
+  }
+  return nullptr;
+}
+
+size_t memspn(const char* s, size_t slen, const char* accept) {
+  const char* p = s;
+  const char* spanp;
+  char c, sc;
+
+cont:
+  c = *p++;
+  if (slen-- == 0) return p - 1 - s;
+  for (spanp = accept; (sc = *spanp++) != '\0';)
+    if (sc == c) goto cont;
+  return p - 1 - s;
+}
+
+size_t memcspn(const char* s, size_t slen, const char* reject) {
+  const char* p = s;
+  const char* spanp;
+  char c, sc;
+
+  while (slen-- != 0) {
+    c = *p++;
+    for (spanp = reject; (sc = *spanp++) != '\0';)
+      if (sc == c) return p - 1 - s;
+  }
+  return p - s;
+}
+
+char* mempbrk(const char* s, size_t slen, const char* accept) {
+  const char* scanp;
+  int sc;
+
+  for (; slen; ++s, --slen) {
+    for (scanp = accept; (sc = *scanp++) != '\0';)
+      if (sc == *s) return const_cast<char*>(s);
+  }
+  return nullptr;
+}
+
+// This is significantly faster for case-sensitive matches with very
+// few possible matches.  See unit test for benchmarks.
+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
+                     size_t neelen) {
+  if (0 == neelen) {
+    return phaystack;  // even if haylen is 0
+  }
+  if (haylen < neelen) return nullptr;
+
+  const char* match;
+  const char* hayend = phaystack + haylen - neelen + 1;
+  // A static cast is used here to work around the fact that memchr returns
+  // a void* on Posix-compliant systems and const void* on Windows.
+  while ((match = static_cast<const char*>(
+              memchr(phaystack, pneedle[0], hayend - phaystack)))) {
+    if (memcmp(match, pneedle, neelen) == 0)
+      return match;
+    else
+      phaystack = match + 1;
+  }
+  return nullptr;
+}
+
+}  // namespace strings_internal
+}  // namespace absl
diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h
new file mode 100644
index 0000000..a6f1c69
--- /dev/null
+++ b/absl/strings/internal/memutil.h
@@ -0,0 +1,146 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+
+// These routines provide mem versions of standard C std::string routines,
+// such as strpbrk.  They function exactly the same as the str versions,
+// so if you wonder what they are, replace the word "mem" by
+// "str" and check out the man page.  I could return void*, as the
+// strutil.h mem*() routines tend to do, but I return char* instead
+// since this is by far the most common way these functions are called.
+//
+// The difference between the mem and str versions is the mem version
+// takes a pointer and a length, rather than a '\0'-terminated std::string.
+// The memcase* routines defined here assume the locale is "C"
+// (they use absl::ascii_tolower instead of tolower).
+//
+// These routines are based on the BSD library.
+//
+// Here's a list of routines from std::string.h, and their mem analogues.
+// Functions in lowercase are defined in std::string.h; those in UPPERCASE
+// are defined here:
+//
+// strlen                  --
+// strcat strncat          MEMCAT
+// strcpy strncpy          memcpy
+// --                      memccpy   (very cool function, btw)
+// --                      memmove
+// --                      memset
+// strcmp strncmp          memcmp
+// strcasecmp strncasecmp  MEMCASECMP
+// strchr                  memchr
+// strcoll                 --
+// strxfrm                 --
+// strdup strndup          MEMDUP
+// strrchr                 MEMRCHR
+// strspn                  MEMSPN
+// strcspn                 MEMCSPN
+// strpbrk                 MEMPBRK
+// strstr                  MEMSTR MEMMEM
+// (g)strcasestr           MEMCASESTR MEMCASEMEM
+// strtok                  --
+// strprefix               MEMPREFIX      (strprefix is from strutil.h)
+// strcaseprefix           MEMCASEPREFIX  (strcaseprefix is from strutil.h)
+// strsuffix               MEMSUFFIX      (strsuffix is from strutil.h)
+// strcasesuffix           MEMCASESUFFIX  (strcasesuffix is from strutil.h)
+// --                      MEMIS
+// --                      MEMCASEIS
+// strcount                MEMCOUNT       (strcount is from strutil.h)
+
+#ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_
+#define ABSL_STRINGS_INTERNAL_MEMUTIL_H_
+
+#include <cstddef>
+#include <cstring>
+
+#include "absl/base/port.h"  // disable some warnings on Windows
+#include "absl/strings/ascii.h"  // for absl::ascii_tolower
+
+namespace absl {
+namespace strings_internal {
+
+inline char* memcat(char* dest, size_t destlen, const char* src,
+                    size_t srclen) {
+  return reinterpret_cast<char*>(memcpy(dest + destlen, src, srclen));
+}
+
+int memcasecmp(const char* s1, const char* s2, size_t len);
+char* memdup(const char* s, size_t slen);
+char* memrchr(const char* s, int c, size_t slen);
+size_t memspn(const char* s, size_t slen, const char* accept);
+size_t memcspn(const char* s, size_t slen, const char* reject);
+char* mempbrk(const char* s, size_t slen, const char* accept);
+
+// This is for internal use only.  Don't call this directly
+template <bool case_sensitive>
+const char* int_memmatch(const char* haystack, size_t haylen,
+                         const char* needle, size_t neelen) {
+  if (0 == neelen) {
+    return haystack;  // even if haylen is 0
+  }
+  const char* hayend = haystack + haylen;
+  const char* needlestart = needle;
+  const char* needleend = needlestart + neelen;
+
+  for (; haystack < hayend; ++haystack) {
+    char hay = case_sensitive
+                   ? *haystack
+                   : absl::ascii_tolower(static_cast<unsigned char>(*haystack));
+    char nee = case_sensitive
+                   ? *needle
+                   : absl::ascii_tolower(static_cast<unsigned char>(*needle));
+    if (hay == nee) {
+      if (++needle == needleend) {
+        return haystack + 1 - neelen;
+      }
+    } else if (needle != needlestart) {
+      // must back up haystack in case a prefix matched (find "aab" in "aaab")
+      haystack -= needle - needlestart;  // for loop will advance one more
+      needle = needlestart;
+    }
+  }
+  return nullptr;
+}
+
+// These are the guys you can call directly
+inline const char* memstr(const char* phaystack, size_t haylen,
+                          const char* pneedle) {
+  return int_memmatch<true>(phaystack, haylen, pneedle, strlen(pneedle));
+}
+
+inline const char* memcasestr(const char* phaystack, size_t haylen,
+                              const char* pneedle) {
+  return int_memmatch<false>(phaystack, haylen, pneedle, strlen(pneedle));
+}
+
+inline const char* memmem(const char* phaystack, size_t haylen,
+                          const char* pneedle, size_t needlelen) {
+  return int_memmatch<true>(phaystack, haylen, pneedle, needlelen);
+}
+
+inline const char* memcasemem(const char* phaystack, size_t haylen,
+                              const char* pneedle, size_t needlelen) {
+  return int_memmatch<false>(phaystack, haylen, pneedle, needlelen);
+}
+
+// This is significantly faster for case-sensitive matches with very
+// few possible matches.  See unit test for benchmarks.
+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
+                     size_t neelen);
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_MEMUTIL_H_
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc
new file mode 100644
index 0000000..77915ad
--- /dev/null
+++ b/absl/strings/internal/memutil_benchmark.cc
@@ -0,0 +1,323 @@
+// Copyright 2018 The Abseil 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 "absl/strings/internal/memutil.h"
+
+#include <algorithm>
+#include <cstdlib>
+
+#include "benchmark/benchmark.h"
+#include "absl/strings/ascii.h"
+
+// We fill the haystack with aaaaaaaaaaaaaaaaaa...aaaab.
+// That gives us:
+// - an easy search: 'b'
+// - a medium search: 'ab'.  That means every letter is a possible match.
+// - a pathological search: 'aaaaaa.......aaaaab' (half as many a's as haytack)
+// We benchmark case-sensitive and case-insensitive versions of
+// three memmem implementations:
+// - memmem() from memutil.h
+// - search() from STL
+// - memmatch(), a custom implementation using memchr and memcmp.
+// Here are sample results:
+//
+// Run on (12 X 3800 MHz CPU s)
+// CPU Caches:
+//   L1 Data 32K (x6)
+//   L1 Instruction 32K (x6)
+//   L2 Unified 256K (x6)
+//   L3 Unified 15360K (x1)
+// ----------------------------------------------------------------
+// Benchmark                           Time          CPU Iterations
+// ----------------------------------------------------------------
+// BM_Memmem                        3583 ns      3582 ns     196469  2.59966GB/s
+// BM_MemmemMedium                 13743 ns     13742 ns      50901  693.986MB/s
+// BM_MemmemPathological        13695030 ns  13693977 ns         51  713.133kB/s
+// BM_Memcasemem                    3299 ns      3299 ns     212942  2.82309GB/s
+// BM_MemcasememMedium             16407 ns     16406 ns      42170  581.309MB/s
+// BM_MemcasememPathological    17267745 ns  17266030 ns         41  565.598kB/s
+// BM_Search                        1610 ns      1609 ns     431321  5.78672GB/s
+// BM_SearchMedium                 11111 ns     11110 ns      63001  858.414MB/s
+// BM_SearchPathological        12117390 ns  12116397 ns         58  805.984kB/s
+// BM_Searchcase                    3081 ns      3081 ns     229949  3.02313GB/s
+// BM_SearchcaseMedium             16003 ns     16001 ns      44170  595.998MB/s
+// BM_SearchcasePathological    15823413 ns  15821909 ns         44  617.222kB/s
+// BM_Memmatch                       197 ns       197 ns    3584225  47.2951GB/s
+// BM_MemmatchMedium               52333 ns     52329 ns      13280  182.244MB/s
+// BM_MemmatchPathological        659799 ns    659727 ns       1058  14.4556MB/s
+// BM_Memcasematch                  5460 ns      5460 ns     127606  1.70586GB/s
+// BM_MemcasematchMedium           32861 ns     32857 ns      21258  290.248MB/s
+// BM_MemcasematchPathological  15154243 ns  15153089 ns         46  644.464kB/s
+// BM_MemmemStartup                    5 ns         5 ns  150821500
+// BM_SearchStartup                    5 ns         5 ns  150644203
+// BM_MemmatchStartup                  7 ns         7 ns   97068802
+//
+// Conclusions:
+//
+// The following recommendations are based on the sample results above. However,
+// we have found that the performance of STL search can vary significantly
+// depending on compiler and standard library implementation. We recommend you
+// run the benchmarks for yourself on relevant platforms.
+//
+// If you need case-insensitive, STL search is slightly better than memmem for
+// all cases.
+//
+// Case-sensitive is more subtle:
+// Custom memmatch is _very_ fast at scanning, so if you have very few possible
+// matches in your haystack, that's the way to go. Performance drops
+// significantly with more matches.
+//
+// STL search is slightly faster than memmem in the medium and pathological
+// benchmarks. However, the performance of memmem is currently more dependable
+// across platforms and build configurations.
+
+namespace {
+
+constexpr int kHaystackSize = 10000;
+constexpr int64_t kHaystackSize64 = kHaystackSize;
+const char* MakeHaystack() {
+  char* haystack = new char[kHaystackSize];
+  for (int i = 0; i < kHaystackSize - 1; ++i) haystack[i] = 'a';
+  haystack[kHaystackSize - 1] = 'b';
+  return haystack;
+}
+const char* const kHaystack = MakeHaystack();
+
+void BM_Memmem(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmem(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memmem);
+
+void BM_MemmemMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmem(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmemMedium);
+
+void BM_MemmemPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmem(
+        kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2,
+        kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmemPathological);
+
+void BM_Memcasemem(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memcasemem);
+
+void BM_MemcasememMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasememMedium);
+
+void BM_MemcasememPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memcasemem(
+        kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2,
+        kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasememPathological);
+
+bool case_eq(const char a, const char b) {
+  return absl::ascii_tolower(a) == absl::ascii_tolower(b);
+}
+
+void BM_Search(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 1,
+                                         kHaystack + kHaystackSize));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Search);
+
+void BM_SearchMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 2,
+                                         kHaystack + kHaystackSize));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchMedium);
+
+void BM_SearchPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize / 2,
+                                         kHaystack + kHaystackSize));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchPathological);
+
+void BM_Searchcase(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 1,
+                                         kHaystack + kHaystackSize, case_eq));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Searchcase);
+
+void BM_SearchcaseMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 2,
+                                         kHaystack + kHaystackSize, case_eq));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchcaseMedium);
+
+void BM_SearchcasePathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize / 2,
+                                         kHaystack + kHaystackSize, case_eq));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchcasePathological);
+
+char* memcasechr(const char* s, int c, size_t slen) {
+  c = absl::ascii_tolower(c);
+  for (; slen; ++s, --slen) {
+    if (absl::ascii_tolower(*s) == c) return const_cast<char*>(s);
+  }
+  return nullptr;
+}
+
+const char* memcasematch(const char* phaystack, size_t haylen,
+                         const char* pneedle, size_t neelen) {
+  if (0 == neelen) {
+    return phaystack;  // even if haylen is 0
+  }
+  if (haylen < neelen) return nullptr;
+
+  const char* match;
+  const char* hayend = phaystack + haylen - neelen + 1;
+  while ((match = static_cast<char*>(
+              memcasechr(phaystack, pneedle[0], hayend - phaystack)))) {
+    if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0)
+      return match;
+    else
+      phaystack = match + 1;
+  }
+  return nullptr;
+}
+
+void BM_Memmatch(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmatch(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memmatch);
+
+void BM_MemmatchMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmatch(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmatchMedium);
+
+void BM_MemmatchPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmatch(
+        kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2,
+        kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmatchPathological);
+
+void BM_Memcasematch(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memcasematch);
+
+void BM_MemcasematchMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasematchMedium);
+
+void BM_MemcasematchPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize,
+                                          kHaystack + kHaystackSize / 2,
+                                          kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasematchPathological);
+
+void BM_MemmemStartup(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmem(
+        kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1));
+  }
+}
+BENCHMARK(BM_MemmemStartup);
+
+void BM_SearchStartup(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        std::search(kHaystack + kHaystackSize - 10, kHaystack + kHaystackSize,
+                    kHaystack + kHaystackSize - 1, kHaystack + kHaystackSize));
+  }
+}
+BENCHMARK(BM_SearchStartup);
+
+void BM_MemmatchStartup(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmatch(
+        kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1));
+  }
+}
+BENCHMARK(BM_MemmatchStartup);
+
+}  // namespace
diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc
new file mode 100644
index 0000000..09424de
--- /dev/null
+++ b/absl/strings/internal/memutil_test.cc
@@ -0,0 +1,179 @@
+// Copyright 2017 The Abseil 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.
+
+// Unit test for memutil.cc
+
+#include "absl/strings/internal/memutil.h"
+
+#include <cstdlib>
+
+#include "gtest/gtest.h"
+#include "absl/strings/ascii.h"
+
+namespace {
+
+static char* memcasechr(const char* s, int c, size_t slen) {
+  c = absl::ascii_tolower(c);
+  for (; slen; ++s, --slen) {
+    if (absl::ascii_tolower(*s) == c) return const_cast<char*>(s);
+  }
+  return nullptr;
+}
+
+static const char* memcasematch(const char* phaystack, size_t haylen,
+                                const char* pneedle, size_t neelen) {
+  if (0 == neelen) {
+    return phaystack;  // even if haylen is 0
+  }
+  if (haylen < neelen) return nullptr;
+
+  const char* match;
+  const char* hayend = phaystack + haylen - neelen + 1;
+  while ((match = static_cast<char*>(
+              memcasechr(phaystack, pneedle[0], hayend - phaystack)))) {
+    if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0)
+      return match;
+    else
+      phaystack = match + 1;
+  }
+  return nullptr;
+}
+
+TEST(MemUtilTest, AllTests) {
+  // check memutil functions
+  char a[1000];
+  absl::strings_internal::memcat(a, 0, "hello", sizeof("hello") - 1);
+  absl::strings_internal::memcat(a, 5, " there", sizeof(" there") - 1);
+
+  EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO there",
+                                               sizeof("hello there") - 1),
+            0);
+  EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO therf",
+                                               sizeof("hello there") - 1),
+            -1);
+  EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO therf",
+                                               sizeof("hello there") - 2),
+            0);
+  EXPECT_EQ(absl::strings_internal::memcasecmp(a, "whatever", 0), 0);
+
+  char* p = absl::strings_internal::memdup("hello", 5);
+  free(p);
+
+  p = absl::strings_internal::memrchr("hello there", 'e',
+                                      sizeof("hello there") - 1);
+  EXPECT_TRUE(p && p[-1] == 'r');
+  p = absl::strings_internal::memrchr("hello there", 'e',
+                                      sizeof("hello there") - 2);
+  EXPECT_TRUE(p && p[-1] == 'h');
+  p = absl::strings_internal::memrchr("hello there", 'u',
+                                      sizeof("hello there") - 1);
+  EXPECT_TRUE(p == nullptr);
+
+  int len = absl::strings_internal::memspn("hello there",
+                                           sizeof("hello there") - 1, "hole");
+  EXPECT_EQ(len, sizeof("hello") - 1);
+  len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1,
+                                       "u");
+  EXPECT_EQ(len, 0);
+  len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1,
+                                       "");
+  EXPECT_EQ(len, 0);
+  len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1,
+                                       "trole h");
+  EXPECT_EQ(len, sizeof("hello there") - 1);
+  len = absl::strings_internal::memspn("hello there!",
+                                       sizeof("hello there!") - 1, "trole h");
+  EXPECT_EQ(len, sizeof("hello there") - 1);
+  len = absl::strings_internal::memspn("hello there!",
+                                       sizeof("hello there!") - 2, "trole h!");
+  EXPECT_EQ(len, sizeof("hello there!") - 2);
+
+  len = absl::strings_internal::memcspn("hello there",
+                                        sizeof("hello there") - 1, "leho");
+  EXPECT_EQ(len, 0);
+  len = absl::strings_internal::memcspn("hello there",
+                                        sizeof("hello there") - 1, "u");
+  EXPECT_EQ(len, sizeof("hello there") - 1);
+  len = absl::strings_internal::memcspn("hello there",
+                                        sizeof("hello there") - 1, "");
+  EXPECT_EQ(len, sizeof("hello there") - 1);
+  len = absl::strings_internal::memcspn("hello there",
+                                        sizeof("hello there") - 1, " ");
+  EXPECT_EQ(len, 5);
+
+  p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1,
+                                      "leho");
+  EXPECT_TRUE(p && p[1] == 'e' && p[2] == 'l');
+  p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1,
+                                      "nu");
+  EXPECT_TRUE(p == nullptr);
+  p = absl::strings_internal::mempbrk("hello there!",
+                                      sizeof("hello there!") - 2, "!");
+  EXPECT_TRUE(p == nullptr);
+  p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1,
+                                      " t ");
+  EXPECT_TRUE(p && p[-1] == 'o' && p[1] == 't');
+
+  {
+    const char kHaystack[] = "0123456789";
+    EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 0, "", 0), kHaystack);
+    EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "012", 3),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "0xx", 1),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "789", 3),
+              kHaystack + 7);
+    EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "9xx", 1),
+              kHaystack + 9);
+    EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "9xx", 3) ==
+                nullptr);
+    EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "xxx", 1) ==
+                nullptr);
+  }
+  {
+    const char kHaystack[] = "aBcDeFgHiJ";
+    EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 0, "", 0),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Abc", 3),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Axx", 1),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "hIj", 3),
+              kHaystack + 7);
+    EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 1),
+              kHaystack + 9);
+    EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 3) ==
+                nullptr);
+    EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "xxx", 1) ==
+                nullptr);
+  }
+  {
+    const char kHaystack[] = "0123456789";
+    EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 0, "", 0), kHaystack);
+    EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "012", 3),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "0xx", 1),
+              kHaystack);
+    EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "789", 3),
+              kHaystack + 7);
+    EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 1),
+              kHaystack + 9);
+    EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 3) ==
+                nullptr);
+    EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "xxx", 1) ==
+                nullptr);
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h
new file mode 100644
index 0000000..20e3af5
--- /dev/null
+++ b/absl/strings/internal/numbers_test_common.h
@@ -0,0 +1,178 @@
+// Copyright 2017 The Abseil 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.
+//
+// This file contains common things needed by numbers_test.cc,
+// numbers_legacy_test.cc and numbers_benchmark.cc.
+
+#ifndef ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_
+#define ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_
+
+#include <array>
+#include <cstdint>
+#include <limits>
+#include <string>
+
+namespace absl {
+namespace strings_internal {
+
+template <typename IntType>
+inline bool Itoa(IntType value, int base, std::string* destination) {
+  destination->clear();
+  if (base <= 1 || base > 36) {
+    return false;
+  }
+
+  if (value == 0) {
+    destination->push_back('0');
+    return true;
+  }
+
+  bool negative = value < 0;
+  while (value != 0) {
+    const IntType next_value = value / base;
+    // Can't use std::abs here because of problems when IntType is unsigned.
+    int remainder = value > next_value * base ? value - next_value * base
+                                              : next_value * base - value;
+    char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10;
+    destination->insert(0, 1, c);
+    value = next_value;
+  }
+
+  if (negative) {
+    destination->insert(0, 1, '-');
+  }
+  return true;
+}
+
+struct uint32_test_case {
+  const char* str;
+  bool expect_ok;
+  int base;  // base to pass to the conversion function
+  uint32_t expected;
+};
+
+inline const std::array<uint32_test_case, 27>& strtouint32_test_cases() {
+  static const std::array<uint32_test_case, 27> test_cases{{
+      {"0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()},
+      {"0x34234324", true, 16, 0x34234324},
+      {"34234324", true, 16, 0x34234324},
+      {"0", true, 16, 0},
+      {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()},
+      {" \f\v 46", true, 10, 46},  // must accept weird whitespace
+      {" \t\n 72717222", true, 8, 072717222},
+      {" \t\n 072717222", true, 8, 072717222},
+      {" \t\n 072717228", false, 8, 07271722},
+      {"0", true, 0, 0},
+
+      // Base-10 version.
+      {"34234324", true, 0, 34234324},
+      {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()},
+      {"34234324 \n\t", true, 10, 34234324},
+
+      // Unusual base
+      {"0", true, 3, 0},
+      {"2", true, 3, 2},
+      {"11", true, 3, 4},
+
+      // Invalid uints.
+      {"", false, 0, 0},
+      {"  ", false, 0, 0},
+      {"abc", false, 0, 0},  // would be valid hex, but prefix is missing
+      {"34234324a", false, 0, 34234324},
+      {"34234.3", false, 0, 34234},
+      {"-1", false, 0, 0},
+      {"   -123", false, 0, 0},
+      {" \t\n -123", false, 0, 0},
+
+      // Out of bounds.
+      {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()},
+      {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()},
+      {nullptr, false, 0, 0},
+  }};
+  return test_cases;
+}
+
+struct uint64_test_case {
+  const char* str;
+  bool expect_ok;
+  int base;
+  uint64_t expected;
+};
+
+inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() {
+  static const std::array<uint64_test_case, 34> test_cases{{
+      {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}},
+      {"3423432448783446", true, 16, int64_t{0x3423432448783446}},
+
+      {"0", true, 16, 0},
+      {"000", true, 0, 0},
+      {"0", true, 0, 0},
+      {" \t\n 0xffffffffffffffff", true, 16,
+       std::numeric_limits<uint64_t>::max()},
+
+      {"012345670123456701234", true, 8, int64_t{012345670123456701234}},
+      {"12345670123456701234", true, 8, int64_t{012345670123456701234}},
+
+      {"12845670123456701234", false, 8, 0},
+
+      // Base-10 version.
+      {"34234324487834466", true, 0, int64_t{34234324487834466}},
+
+      {" \t\n 18446744073709551615", true, 0,
+       std::numeric_limits<uint64_t>::max()},
+
+      {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}},
+
+      {" \f\v 46", true, 10, 46},  // must accept weird whitespace
+
+      // Unusual base
+      {"0", true, 3, 0},
+      {"2", true, 3, 2},
+      {"11", true, 3, 4},
+
+      {"0", true, 0, 0},
+
+      // Invalid uints.
+      {"", false, 0, 0},
+      {"  ", false, 0, 0},
+      {"abc", false, 0, 0},
+      {"34234324487834466a", false, 0, 0},
+      {"34234487834466.3", false, 0, 0},
+      {"-1", false, 0, 0},
+      {"   -123", false, 0, 0},
+      {" \t\n -123", false, 0, 0},
+
+      // Out of bounds.
+      {"18446744073709551616", false, 10, 0},
+      {"18446744073709551616", false, 0, 0},
+      {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()},
+      {"0X10000000000000000", false, 16,
+       std::numeric_limits<uint64_t>::max()},  // 0X versus 0x.
+      {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()},
+      {"0X10000000000000000", false, 0,
+       std::numeric_limits<uint64_t>::max()},  // 0X versus 0x.
+
+      {"0x1234", true, 16, 0x1234},
+
+      // Base-10 std::string version.
+      {"1234", true, 0, 1234},
+      {nullptr, false, 0, 0},
+  }};
+  return test_cases;
+}
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_
diff --git a/absl/strings/internal/ostringstream.cc b/absl/strings/internal/ostringstream.cc
new file mode 100644
index 0000000..6ee2b10
--- /dev/null
+++ b/absl/strings/internal/ostringstream.cc
@@ -0,0 +1,34 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/ostringstream.h"
+
+namespace absl {
+namespace strings_internal {
+
+OStringStream::Buf::int_type OStringStream::overflow(int c) {
+  assert(s_);
+  if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof()))
+    s_->push_back(static_cast<char>(c));
+  return 1;
+}
+
+std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) {
+  assert(s_);
+  s_->append(s, n);
+  return n;
+}
+
+}  // namespace strings_internal
+}  // namespace absl
diff --git a/absl/strings/internal/ostringstream.h b/absl/strings/internal/ostringstream.h
new file mode 100644
index 0000000..6e1325b
--- /dev/null
+++ b/absl/strings/internal/ostringstream.h
@@ -0,0 +1,87 @@
+// Copyright 2017 The Abseil 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 ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
+#define ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
+
+#include <cassert>
+#include <ostream>
+#include <streambuf>
+#include <string>
+
+#include "absl/base/port.h"
+
+namespace absl {
+namespace strings_internal {
+
+// The same as std::ostringstream but appends to a user-specified std::string,
+// and is faster. It is ~70% faster to create, ~50% faster to write to, and
+// completely free to extract the result std::string.
+//
+//   std::string s;
+//   OStringStream strm(&s);
+//   strm << 42 << ' ' << 3.14;  // appends to `s`
+//
+// The stream object doesn't have to be named. Starting from C++11 operator<<
+// works with rvalues of std::ostream.
+//
+//   std::string s;
+//   OStringStream(&s) << 42 << ' ' << 3.14;  // appends to `s`
+//
+// OStringStream is faster to create than std::ostringstream but it's still
+// relatively slow. Avoid creating multiple streams where a single stream will
+// do.
+//
+// Creates unnecessary instances of OStringStream: slow.
+//
+//   std::string s;
+//   OStringStream(&s) << 42;
+//   OStringStream(&s) << ' ';
+//   OStringStream(&s) << 3.14;
+//
+// Creates a single instance of OStringStream and reuses it: fast.
+//
+//   std::string s;
+//   OStringStream strm(&s);
+//   strm << 42;
+//   strm << ' ';
+//   strm << 3.14;
+//
+// Note: flush() has no effect. No reason to call it.
+class OStringStream : private std::basic_streambuf<char>, public std::ostream {
+ public:
+  // The argument can be null, in which case you'll need to call str(p) with a
+  // non-null argument before you can write to the stream.
+  //
+  // The destructor of OStringStream doesn't use the std::string. It's OK to destroy
+  // the std::string before the stream.
+  explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {}
+
+  std::string* str() { return s_; }
+  const std::string* str() const { return s_; }
+  void str(std::string* s) { s_ = s; }
+
+ private:
+  using Buf = std::basic_streambuf<char>;
+
+  Buf::int_type overflow(int c) override;
+  std::streamsize xsputn(const char* s, std::streamsize n) override;
+
+  std::string* s_;
+};
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc
new file mode 100644
index 0000000..c93f969
--- /dev/null
+++ b/absl/strings/internal/ostringstream_benchmark.cc
@@ -0,0 +1,106 @@
+// Copyright 2018 The Abseil 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 "absl/strings/internal/ostringstream.h"
+
+#include <sstream>
+#include <string>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+enum StringType {
+  kNone,
+  kStdString,
+};
+
+// Benchmarks for std::ostringstream.
+template <StringType kOutput>
+void BM_StdStream(benchmark::State& state) {
+  const int num_writes = state.range(0);
+  const int bytes_per_write = state.range(1);
+  const std::string payload(bytes_per_write, 'x');
+  for (auto _ : state) {
+    std::ostringstream strm;
+    benchmark::DoNotOptimize(strm);
+    for (int i = 0; i != num_writes; ++i) {
+      strm << payload;
+    }
+    switch (kOutput) {
+      case kNone: {
+        break;
+      }
+      case kStdString: {
+        std::string s = strm.str();
+        benchmark::DoNotOptimize(s);
+        break;
+      }
+    }
+  }
+}
+
+// Create the stream, optionally write to it, then destroy it.
+BENCHMARK_TEMPLATE(BM_StdStream, kNone)
+    ->ArgPair(0, 0)
+    ->ArgPair(1, 16)   // 16 bytes is small enough for SSO
+    ->ArgPair(1, 256)  // 256 bytes requires heap allocation
+    ->ArgPair(1024, 256);
+// Create the stream, write to it, get std::string out, then destroy.
+BENCHMARK_TEMPLATE(BM_StdStream, kStdString)
+    ->ArgPair(1, 16)   // 16 bytes is small enough for SSO
+    ->ArgPair(1, 256)  // 256 bytes requires heap allocation
+    ->ArgPair(1024, 256);
+
+// Benchmarks for OStringStream.
+template <StringType kOutput>
+void BM_CustomStream(benchmark::State& state) {
+  const int num_writes = state.range(0);
+  const int bytes_per_write = state.range(1);
+  const std::string payload(bytes_per_write, 'x');
+  for (auto _ : state) {
+    std::string out;
+    absl::strings_internal::OStringStream strm(&out);
+    benchmark::DoNotOptimize(strm);
+    for (int i = 0; i != num_writes; ++i) {
+      strm << payload;
+    }
+    switch (kOutput) {
+      case kNone: {
+        break;
+      }
+      case kStdString: {
+        std::string s = out;
+        benchmark::DoNotOptimize(s);
+        break;
+      }
+    }
+  }
+}
+
+// Create the stream, optionally write to it, then destroy it.
+BENCHMARK_TEMPLATE(BM_CustomStream, kNone)
+    ->ArgPair(0, 0)
+    ->ArgPair(1, 16)   // 16 bytes is small enough for SSO
+    ->ArgPair(1, 256)  // 256 bytes requires heap allocation
+    ->ArgPair(1024, 256);
+// Create the stream, write to it, get std::string out, then destroy.
+// It's not useful in practice to extract std::string from OStringStream; we
+// measure it for completeness.
+BENCHMARK_TEMPLATE(BM_CustomStream, kStdString)
+    ->ArgPair(1, 16)   // 16 bytes is small enough for SSO
+    ->ArgPair(1, 256)  // 256 bytes requires heap allocation
+    ->ArgPair(1024, 256);
+
+}  // namespace
diff --git a/absl/strings/internal/ostringstream_test.cc b/absl/strings/internal/ostringstream_test.cc
new file mode 100644
index 0000000..069a0e1
--- /dev/null
+++ b/absl/strings/internal/ostringstream_test.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/ostringstream.h"
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(OStringStream, IsOStream) {
+  static_assert(
+      std::is_base_of<std::ostream, absl::strings_internal::OStringStream>(),
+      "");
+}
+
+TEST(OStringStream, ConstructDestroy) {
+  {
+    absl::strings_internal::OStringStream strm(nullptr);
+    EXPECT_EQ(nullptr, strm.str());
+  }
+  {
+    std::string s = "abc";
+    {
+      absl::strings_internal::OStringStream strm(&s);
+      EXPECT_EQ(&s, strm.str());
+    }
+    EXPECT_EQ("abc", s);
+  }
+  {
+    std::unique_ptr<std::string> s(new std::string);
+    absl::strings_internal::OStringStream strm(s.get());
+    s.reset();
+  }
+}
+
+TEST(OStringStream, Str) {
+  std::string s1;
+  absl::strings_internal::OStringStream strm(&s1);
+  const absl::strings_internal::OStringStream& c_strm(strm);
+
+  static_assert(std::is_same<decltype(strm.str()), std::string*>(), "");
+  static_assert(std::is_same<decltype(c_strm.str()), const std::string*>(), "");
+
+  EXPECT_EQ(&s1, strm.str());
+  EXPECT_EQ(&s1, c_strm.str());
+
+  strm.str(&s1);
+  EXPECT_EQ(&s1, strm.str());
+  EXPECT_EQ(&s1, c_strm.str());
+
+  std::string s2;
+  strm.str(&s2);
+  EXPECT_EQ(&s2, strm.str());
+  EXPECT_EQ(&s2, c_strm.str());
+
+  strm.str(nullptr);
+  EXPECT_EQ(nullptr, strm.str());
+  EXPECT_EQ(nullptr, c_strm.str());
+}
+
+TEST(OStreamStream, WriteToLValue) {
+  std::string s = "abc";
+  {
+    absl::strings_internal::OStringStream strm(&s);
+    EXPECT_EQ("abc", s);
+    strm << "";
+    EXPECT_EQ("abc", s);
+    strm << 42;
+    EXPECT_EQ("abc42", s);
+    strm << 'x' << 'y';
+    EXPECT_EQ("abc42xy", s);
+  }
+  EXPECT_EQ("abc42xy", s);
+}
+
+TEST(OStreamStream, WriteToRValue) {
+  std::string s = "abc";
+  absl::strings_internal::OStringStream(&s) << "";
+  EXPECT_EQ("abc", s);
+  absl::strings_internal::OStringStream(&s) << 42;
+  EXPECT_EQ("abc42", s);
+  absl::strings_internal::OStringStream(&s) << 'x' << 'y';
+  EXPECT_EQ("abc42xy", s);
+}
+
+}  // namespace
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h
new file mode 100644
index 0000000..0157ca0
--- /dev/null
+++ b/absl/strings/internal/resize_uninitialized.h
@@ -0,0 +1,69 @@
+//
+// Copyright 2017 The Abseil 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 ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
+#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
+
+#include <string>
+#include <utility>
+
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"  //  for void_t
+
+namespace absl {
+namespace strings_internal {
+
+// Is a subclass of true_type or false_type, depending on whether or not
+// T has a resize_uninitialized member.
+template <typename T, typename = void>
+struct HasResizeUninitialized : std::false_type {};
+template <typename T>
+struct HasResizeUninitialized<
+    T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>>
+    : std::true_type {};
+
+template <typename string_type>
+void ResizeUninit(string_type* s, size_t new_size, std::true_type) {
+  s->resize_uninitialized(new_size);
+}
+template <typename string_type>
+void ResizeUninit(string_type* s, size_t new_size, std::false_type) {
+  s->resize(new_size);
+}
+
+// Returns true if the std::string implementation supports a resize where
+// the new characters added to the std::string are left untouched.
+//
+// (A better name might be "STLStringSupportsUninitializedResize", alluding to
+// the previous function.)
+template <typename string_type>
+inline constexpr bool STLStringSupportsNontrashingResize(string_type*) {
+  return HasResizeUninitialized<string_type>();
+}
+
+// Like str->resize(new_size), except any new characters added to "*str" as a
+// result of resizing may be left uninitialized, rather than being filled with
+// '0' bytes. Typically used when code is then going to overwrite the backing
+// store of the std::string with known data. Uses a Google extension to std::string.
+template <typename string_type, typename = void>
+inline void STLStringResizeUninitialized(string_type* s, size_t new_size) {
+  ResizeUninit(s, new_size, HasResizeUninitialized<string_type>());
+}
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
diff --git a/absl/strings/internal/resize_uninitialized_test.cc b/absl/strings/internal/resize_uninitialized_test.cc
new file mode 100644
index 0000000..ad282ef
--- /dev/null
+++ b/absl/strings/internal/resize_uninitialized_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/resize_uninitialized.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+int resize_call_count = 0;
+
+struct resizable_string {
+  void resize(size_t) { resize_call_count += 1; }
+};
+
+int resize_uninitialized_call_count = 0;
+
+struct resize_uninitializable_string {
+  void resize(size_t) { resize_call_count += 1; }
+  void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; }
+};
+
+TEST(ResizeUninit, WithAndWithout) {
+  resize_call_count = 0;
+  resize_uninitialized_call_count = 0;
+  {
+    resizable_string rs;
+
+    EXPECT_EQ(resize_call_count, 0);
+    EXPECT_EQ(resize_uninitialized_call_count, 0);
+    EXPECT_FALSE(
+        absl::strings_internal::STLStringSupportsNontrashingResize(&rs));
+    EXPECT_EQ(resize_call_count, 0);
+    EXPECT_EQ(resize_uninitialized_call_count, 0);
+    absl::strings_internal::STLStringResizeUninitialized(&rs, 237);
+    EXPECT_EQ(resize_call_count, 1);
+    EXPECT_EQ(resize_uninitialized_call_count, 0);
+  }
+
+  resize_call_count = 0;
+  resize_uninitialized_call_count = 0;
+  {
+    resize_uninitializable_string rus;
+
+    EXPECT_EQ(resize_call_count, 0);
+    EXPECT_EQ(resize_uninitialized_call_count, 0);
+    EXPECT_TRUE(
+        absl::strings_internal::STLStringSupportsNontrashingResize(&rus));
+    EXPECT_EQ(resize_call_count, 0);
+    EXPECT_EQ(resize_uninitialized_call_count, 0);
+    absl::strings_internal::STLStringResizeUninitialized(&rus, 237);
+    EXPECT_EQ(resize_call_count, 0);
+    EXPECT_EQ(resize_uninitialized_call_count, 1);
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/internal/stl_type_traits.h b/absl/strings/internal/stl_type_traits.h
new file mode 100644
index 0000000..04c4a53
--- /dev/null
+++ b/absl/strings/internal/stl_type_traits.h
@@ -0,0 +1,246 @@
+// Copyright 2017 The Abseil 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.
+//
+
+// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type
+// trait metafunction to assist in working with the _GLIBCXX_DEBUG debug
+// wrappers of STL containers.
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_split.h.
+//
+// IWYU pragma: private, include "absl/strings/str_split.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
+#define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
+
+#include <array>
+#include <bitset>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <set>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+namespace strings_internal {
+
+template <typename C, template <typename...> class T>
+struct IsSpecializationImpl : std::false_type {};
+template <template <typename...> class T, typename... Args>
+struct IsSpecializationImpl<T<Args...>, T> : std::true_type {};
+template <typename C, template <typename...> class T>
+using IsSpecialization = IsSpecializationImpl<absl::decay_t<C>, T>;
+
+template <typename C>
+struct IsArrayImpl : std::false_type {};
+template <template <typename, size_t> class A, typename T, size_t N>
+struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {};
+template <typename C>
+using IsArray = IsArrayImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsBitsetImpl : std::false_type {};
+template <template <size_t> class B, size_t N>
+struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {};
+template <typename C>
+using IsBitset = IsBitsetImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsSTLContainer
+    : absl::disjunction<
+          IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>,
+          IsSpecialization<C, std::forward_list>,
+          IsSpecialization<C, std::list>, IsSpecialization<C, std::map>,
+          IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>,
+          IsSpecialization<C, std::multiset>,
+          IsSpecialization<C, std::unordered_map>,
+          IsSpecialization<C, std::unordered_multimap>,
+          IsSpecialization<C, std::unordered_set>,
+          IsSpecialization<C, std::unordered_multiset>,
+          IsSpecialization<C, std::vector>> {};
+
+template <typename C, template <typename...> class T, typename = void>
+struct IsBaseOfSpecializationImpl : std::false_type {};
+// IsBaseOfSpecializationImpl needs multiple partial specializations to SFINAE
+// on the existence of container dependent types and plug them into the STL
+// template.
+template <typename C, template <typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T, absl::void_t<typename C::value_type, typename C::allocator_type>>
+    : std::is_base_of<C,
+                      T<typename C::value_type, typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::key_compare,
+                 typename C::allocator_type>>
+    : std::is_base_of<C, T<typename C::key_type, typename C::key_compare,
+                           typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::key_compare, typename C::allocator_type>>
+    : std::is_base_of<C,
+                      T<typename C::key_type, typename C::mapped_type,
+                        typename C::key_compare, typename C::allocator_type>> {
+};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::hasher,
+                 typename C::key_equal, typename C::allocator_type>>
+    : std::is_base_of<C, T<typename C::key_type, typename C::hasher,
+                           typename C::key_equal, typename C::allocator_type>> {
+};
+template <typename C,
+          template <typename, typename, typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::hasher, typename C::key_equal,
+                 typename C::allocator_type>>
+    : std::is_base_of<C, T<typename C::key_type, typename C::mapped_type,
+                           typename C::hasher, typename C::key_equal,
+                           typename C::allocator_type>> {};
+template <typename C, template <typename...> class T>
+using IsBaseOfSpecialization = IsBaseOfSpecializationImpl<absl::decay_t<C>, T>;
+
+template <typename C>
+struct IsBaseOfArrayImpl : std::false_type {};
+template <template <typename, size_t> class A, typename T, size_t N>
+struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> {
+};
+template <typename C>
+using IsBaseOfArray = IsBaseOfArrayImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsBaseOfBitsetImpl : std::false_type {};
+template <template <size_t> class B, size_t N>
+struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {};
+template <typename C>
+using IsBaseOfBitset = IsBaseOfBitsetImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsBaseOfSTLContainer
+    : absl::disjunction<IsBaseOfArray<C>, IsBaseOfBitset<C>,
+                        IsBaseOfSpecialization<C, std::deque>,
+                        IsBaseOfSpecialization<C, std::forward_list>,
+                        IsBaseOfSpecialization<C, std::list>,
+                        IsBaseOfSpecialization<C, std::map>,
+                        IsBaseOfSpecialization<C, std::multimap>,
+                        IsBaseOfSpecialization<C, std::set>,
+                        IsBaseOfSpecialization<C, std::multiset>,
+                        IsBaseOfSpecialization<C, std::unordered_map>,
+                        IsBaseOfSpecialization<C, std::unordered_multimap>,
+                        IsBaseOfSpecialization<C, std::unordered_set>,
+                        IsBaseOfSpecialization<C, std::unordered_multiset>,
+                        IsBaseOfSpecialization<C, std::vector>> {};
+
+template <typename C, template <typename...> class T, typename = void>
+struct IsConvertibleToSpecializationImpl : std::false_type {};
+// IsConvertibleToSpecializationImpl needs multiple partial specializations to
+// SFINAE on the existence of container dependent types and plug them into the
+// STL template.
+template <typename C, template <typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T, absl::void_t<typename C::value_type, typename C::allocator_type>>
+    : std::is_convertible<
+          C, T<typename C::value_type, typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::key_compare,
+                 typename C::allocator_type>>
+    : std::is_convertible<C, T<typename C::key_type, typename C::key_compare,
+                               typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::key_compare, typename C::allocator_type>>
+    : std::is_convertible<
+          C, T<typename C::key_type, typename C::mapped_type,
+               typename C::key_compare, typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::hasher,
+                 typename C::key_equal, typename C::allocator_type>>
+    : std::is_convertible<
+          C, T<typename C::key_type, typename C::hasher, typename C::key_equal,
+               typename C::allocator_type>> {};
+template <typename C,
+          template <typename, typename, typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::hasher, typename C::key_equal,
+                 typename C::allocator_type>>
+    : std::is_convertible<C, T<typename C::key_type, typename C::mapped_type,
+                               typename C::hasher, typename C::key_equal,
+                               typename C::allocator_type>> {};
+template <typename C, template <typename...> class T>
+using IsConvertibleToSpecialization =
+    IsConvertibleToSpecializationImpl<absl::decay_t<C>, T>;
+
+template <typename C>
+struct IsConvertibleToArrayImpl : std::false_type {};
+template <template <typename, size_t> class A, typename T, size_t N>
+struct IsConvertibleToArrayImpl<A<T, N>>
+    : std::is_convertible<A<T, N>, std::array<T, N>> {};
+template <typename C>
+using IsConvertibleToArray = IsConvertibleToArrayImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsConvertibleToBitsetImpl : std::false_type {};
+template <template <size_t> class B, size_t N>
+struct IsConvertibleToBitsetImpl<B<N>>
+    : std::is_convertible<B<N>, std::bitset<N>> {};
+template <typename C>
+using IsConvertibleToBitset = IsConvertibleToBitsetImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsConvertibleToSTLContainer
+    : absl::disjunction<
+          IsConvertibleToArray<C>, IsConvertibleToBitset<C>,
+          IsConvertibleToSpecialization<C, std::deque>,
+          IsConvertibleToSpecialization<C, std::forward_list>,
+          IsConvertibleToSpecialization<C, std::list>,
+          IsConvertibleToSpecialization<C, std::map>,
+          IsConvertibleToSpecialization<C, std::multimap>,
+          IsConvertibleToSpecialization<C, std::set>,
+          IsConvertibleToSpecialization<C, std::multiset>,
+          IsConvertibleToSpecialization<C, std::unordered_map>,
+          IsConvertibleToSpecialization<C, std::unordered_multimap>,
+          IsConvertibleToSpecialization<C, std::unordered_set>,
+          IsConvertibleToSpecialization<C, std::unordered_multiset>,
+          IsConvertibleToSpecialization<C, std::vector>> {};
+
+template <typename C>
+struct IsStrictlyBaseOfAndConvertibleToSTLContainer
+    : absl::conjunction<absl::negation<IsSTLContainer<C>>,
+                        IsBaseOfSTLContainer<C>,
+                        IsConvertibleToSTLContainer<C>> {};
+
+}  // namespace strings_internal
+}  // namespace absl
+#endif  // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
new file mode 100644
index 0000000..eafb068
--- /dev/null
+++ b/absl/strings/internal/str_format/arg.cc
@@ -0,0 +1,399 @@
+//
+// POSIX spec:
+//   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
+//
+#include "absl/strings/internal/str_format/arg.h"
+
+#include <cassert>
+#include <cerrno>
+#include <cstdlib>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/strings/internal/str_format/float_conversion.h"
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+
+const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
+
+// Reduce *capacity by s.size(), clipped to a 0 minimum.
+void ReducePadding(string_view s, size_t *capacity) {
+  *capacity = Excess(s.size(), *capacity);
+}
+
+// Reduce *capacity by n, clipped to a 0 minimum.
+void ReducePadding(size_t n, size_t *capacity) {
+  *capacity = Excess(n, *capacity);
+}
+
+template <typename T>
+struct MakeUnsigned : std::make_unsigned<T> {};
+template <>
+struct MakeUnsigned<absl::uint128> {
+  using type = absl::uint128;
+};
+
+template <typename T>
+struct IsSigned : std::is_signed<T> {};
+template <>
+struct IsSigned<absl::uint128> : std::false_type {};
+
+class ConvertedIntInfo {
+ public:
+  template <typename T>
+  ConvertedIntInfo(T v, ConversionChar conv) {
+    using Unsigned = typename MakeUnsigned<T>::type;
+    auto u = static_cast<Unsigned>(v);
+    if (IsNeg(v)) {
+      is_neg_ = true;
+      u = Unsigned{} - u;
+    } else {
+      is_neg_ = false;
+    }
+    UnsignedToStringRight(u, conv);
+  }
+
+  string_view digits() const {
+    return {end() - size_, static_cast<size_t>(size_)};
+  }
+  bool is_neg() const { return is_neg_; }
+
+ private:
+  template <typename T, bool IsSigned>
+  struct IsNegImpl {
+    static bool Eval(T v) { return v < 0; }
+  };
+  template <typename T>
+  struct IsNegImpl<T, false> {
+    static bool Eval(T) {
+      return false;
+    }
+  };
+
+  template <typename T>
+  bool IsNeg(T v) {
+    return IsNegImpl<T, IsSigned<T>::value>::Eval(v);
+  }
+
+  template <typename T>
+  void UnsignedToStringRight(T u, ConversionChar conv) {
+    char *p = end();
+    switch (conv.radix()) {
+      default:
+      case 10:
+        for (; u; u /= 10)
+          *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));
+        break;
+      case 8:
+        for (; u; u /= 8)
+          *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
+        break;
+      case 16: {
+        const char *digits = kDigit[conv.upper() ? 1 : 0];
+        for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
+        break;
+      }
+    }
+    size_ = static_cast<int>(end() - p);
+  }
+
+  const char *end() const { return storage_ + sizeof(storage_); }
+  char *end() { return storage_ + sizeof(storage_); }
+
+  bool is_neg_;
+  int size_;
+  // Max size: 128 bit value as octal -> 43 digits
+  char storage_[128 / 3 + 1];
+};
+
+// Note: 'o' conversions do not have a base indicator, it's just that
+// the '#' flag is specified to modify the precision for 'o' conversions.
+string_view BaseIndicator(const ConvertedIntInfo &info,
+                          const ConversionSpec &conv) {
+  bool alt = conv.flags().alt;
+  int radix = conv.conv().radix();
+  if (conv.conv().id() == ConversionChar::p)
+    alt = true;  // always show 0x for %p.
+  // From the POSIX description of '#' flag:
+  //   "For x or X conversion specifiers, a non-zero result shall have
+  //   0x (or 0X) prefixed to it."
+  if (alt && radix == 16 && !info.digits().empty()) {
+    if (conv.conv().upper()) return "0X";
+    return "0x";
+  }
+  return {};
+}
+
+string_view SignColumn(bool neg, const ConversionSpec &conv) {
+  if (conv.conv().is_signed()) {
+    if (neg) return "-";
+    if (conv.flags().show_pos) return "+";
+    if (conv.flags().sign_col) return " ";
+  }
+  return {};
+}
+
+bool ConvertCharImpl(unsigned char v, const ConversionSpec &conv,
+                     FormatSinkImpl *sink) {
+  size_t fill = 0;
+  if (conv.width() >= 0) fill = conv.width();
+  ReducePadding(1, &fill);
+  if (!conv.flags().left) sink->Append(fill, ' ');
+  sink->Append(1, v);
+  if (conv.flags().left) sink->Append(fill, ' ');
+  return true;
+}
+
+bool ConvertIntImplInner(const ConvertedIntInfo &info,
+                         const ConversionSpec &conv, FormatSinkImpl *sink) {
+  // Print as a sequence of Substrings:
+  //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
+  size_t fill = 0;
+  if (conv.width() >= 0) fill = conv.width();
+
+  string_view formatted = info.digits();
+  ReducePadding(formatted, &fill);
+
+  string_view sign = SignColumn(info.is_neg(), conv);
+  ReducePadding(sign, &fill);
+
+  string_view base_indicator = BaseIndicator(info, conv);
+  ReducePadding(base_indicator, &fill);
+
+  int precision = conv.precision();
+  bool precision_specified = precision >= 0;
+  if (!precision_specified)
+    precision = 1;
+
+  if (conv.flags().alt && conv.conv().id() == ConversionChar::o) {
+    // From POSIX description of the '#' (alt) flag:
+    //   "For o conversion, it increases the precision (if necessary) to
+    //   force the first digit of the result to be zero."
+    if (formatted.empty() || *formatted.begin() != '0') {
+      int needed = static_cast<int>(formatted.size()) + 1;
+      precision = std::max(precision, needed);
+    }
+  }
+
+  size_t num_zeroes = Excess(formatted.size(), precision);
+  ReducePadding(num_zeroes, &fill);
+
+  size_t num_left_spaces = !conv.flags().left ? fill : 0;
+  size_t num_right_spaces = conv.flags().left ? fill : 0;
+
+  // From POSIX description of the '0' (zero) flag:
+  //   "For d, i, o, u, x, and X conversion specifiers, if a precision
+  //   is specified, the '0' flag is ignored."
+  if (!precision_specified && conv.flags().zero) {
+    num_zeroes += num_left_spaces;
+    num_left_spaces = 0;
+  }
+
+  sink->Append(num_left_spaces, ' ');
+  sink->Append(sign);
+  sink->Append(base_indicator);
+  sink->Append(num_zeroes, '0');
+  sink->Append(formatted);
+  sink->Append(num_right_spaces, ' ');
+  return true;
+}
+
+template <typename T>
+bool ConvertIntImplInner(T v, const ConversionSpec &conv,
+                         FormatSinkImpl *sink) {
+  ConvertedIntInfo info(v, conv.conv());
+  if (conv.flags().basic && conv.conv().id() != ConversionChar::p) {
+    if (info.is_neg()) sink->Append(1, '-');
+    if (info.digits().empty()) {
+      sink->Append(1, '0');
+    } else {
+      sink->Append(info.digits());
+    }
+    return true;
+  }
+  return ConvertIntImplInner(info, conv, sink);
+}
+
+template <typename T>
+bool ConvertIntArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) {
+  if (conv.conv().is_float()) {
+    return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
+  }
+  if (conv.conv().id() == ConversionChar::c)
+    return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
+  if (!conv.conv().is_integral())
+    return false;
+  if (!conv.conv().is_signed() && IsSigned<T>::value) {
+    using U = typename MakeUnsigned<T>::type;
+    return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
+  }
+  return ConvertIntImplInner(v, conv, sink);
+}
+
+template <typename T>
+bool ConvertFloatArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) {
+  return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink);
+}
+
+inline bool ConvertStringArg(string_view v, const ConversionSpec &conv,
+                             FormatSinkImpl *sink) {
+  if (conv.conv().id() != ConversionChar::s)
+    return false;
+  if (conv.flags().basic) {
+    sink->Append(v);
+    return true;
+  }
+  return sink->PutPaddedString(v, conv.width(), conv.precision(),
+                               conv.flags().left);
+}
+
+}  // namespace
+
+// ==================== Strings ====================
+ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,
+                                         const ConversionSpec &conv,
+                                         FormatSinkImpl *sink) {
+  return {ConvertStringArg(v, conv, sink)};
+}
+
+ConvertResult<Conv::s> FormatConvertImpl(string_view v,
+                                         const ConversionSpec &conv,
+                                         FormatSinkImpl *sink) {
+  return {ConvertStringArg(v, conv, sink)};
+}
+
+ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
+                                                   const ConversionSpec &conv,
+                                                   FormatSinkImpl *sink) {
+  if (conv.conv().id() == ConversionChar::p)
+    return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
+  size_t len;
+  if (v == nullptr) {
+    len = 0;
+  } else if (conv.precision() < 0) {
+    len = std::strlen(v);
+  } else {
+    // If precision is set, we look for the null terminator on the valid range.
+    len = std::find(v, v + conv.precision(), '\0') - v;
+  }
+  return {ConvertStringArg(string_view(v, len), conv, sink)};
+}
+
+// ==================== Raw pointers ====================
+ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec &conv,
+                                         FormatSinkImpl *sink) {
+  if (conv.conv().id() != ConversionChar::p)
+    return {false};
+  if (!v.value) {
+    sink->Append("(nil)");
+    return {true};
+  }
+  return {ConvertIntImplInner(v.value, conv, sink)};
+}
+
+// ==================== Floats ====================
+FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertFloatArg(v, conv, sink)};
+}
+FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertFloatArg(v, conv, sink)};
+}
+FloatingConvertResult FormatConvertImpl(long double v,
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertFloatArg(v, conv, sink)};
+}
+
+// ==================== Chars ====================
+IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(signed char v,
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+
+// ==================== Ints ====================
+IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(absl::uint128 v,
+                                        const ConversionSpec &conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+
+template struct FormatArgImpl::TypedVTable<str_format_internal::VoidPtr>;
+
+template struct FormatArgImpl::TypedVTable<bool>;
+template struct FormatArgImpl::TypedVTable<char>;
+template struct FormatArgImpl::TypedVTable<signed char>;
+template struct FormatArgImpl::TypedVTable<unsigned char>;
+template struct FormatArgImpl::TypedVTable<short>;           // NOLINT
+template struct FormatArgImpl::TypedVTable<unsigned short>;  // NOLINT
+template struct FormatArgImpl::TypedVTable<int>;
+template struct FormatArgImpl::TypedVTable<unsigned>;
+template struct FormatArgImpl::TypedVTable<long>;                // NOLINT
+template struct FormatArgImpl::TypedVTable<unsigned long>;       // NOLINT
+template struct FormatArgImpl::TypedVTable<long long>;           // NOLINT
+template struct FormatArgImpl::TypedVTable<unsigned long long>;  // NOLINT
+template struct FormatArgImpl::TypedVTable<absl::uint128>;
+
+template struct FormatArgImpl::TypedVTable<float>;
+template struct FormatArgImpl::TypedVTable<double>;
+template struct FormatArgImpl::TypedVTable<long double>;
+
+template struct FormatArgImpl::TypedVTable<const char *>;
+template struct FormatArgImpl::TypedVTable<std::string>;
+template struct FormatArgImpl::TypedVTable<string_view>;
+
+}  // namespace str_format_internal
+
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
new file mode 100644
index 0000000..a956218
--- /dev/null
+++ b/absl/strings/internal/str_format/arg.h
@@ -0,0 +1,434 @@
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
+
+#include <string.h>
+#include <wchar.h>
+
+#include <cstdio>
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/internal/str_format/extension.h"
+#include "absl/strings/string_view.h"
+
+class Cord;
+class CordReader;
+
+namespace absl {
+
+class FormatCountCapture;
+class FormatSink;
+
+namespace str_format_internal {
+
+template <typename T, typename = void>
+struct HasUserDefinedConvert : std::false_type {};
+
+template <typename T>
+struct HasUserDefinedConvert<
+    T, void_t<decltype(AbslFormatConvert(
+           std::declval<const T&>(), std::declval<const ConversionSpec&>(),
+           std::declval<FormatSink*>()))>> : std::true_type {};
+template <typename T>
+class StreamedWrapper;
+
+// If 'v' can be converted (in the printf sense) according to 'conv',
+// then convert it, appending to `sink` and return `true`.
+// Otherwise fail and return `false`.
+// Raw pointers.
+struct VoidPtr {
+  VoidPtr() = default;
+  template <typename T,
+            decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
+  VoidPtr(T* ptr)  // NOLINT
+      : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
+  uintptr_t value;
+};
+ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec& conv,
+                                         FormatSinkImpl* sink);
+
+// Strings.
+ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
+                                         const ConversionSpec& conv,
+                                         FormatSinkImpl* sink);
+ConvertResult<Conv::s> FormatConvertImpl(string_view v,
+                                         const ConversionSpec& conv,
+                                         FormatSinkImpl* sink);
+ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
+                                                   const ConversionSpec& conv,
+                                                   FormatSinkImpl* sink);
+template <class AbslCord,
+          typename std::enable_if<
+              std::is_same<AbslCord, ::Cord>::value>::type* = nullptr,
+          class AbslCordReader = ::CordReader>
+ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
+                                         const ConversionSpec& conv,
+                                         FormatSinkImpl* sink) {
+  if (conv.conv().id() != ConversionChar::s) return {false};
+
+  bool is_left = conv.flags().left;
+  size_t space_remaining = 0;
+
+  int width = conv.width();
+  if (width >= 0) space_remaining = width;
+
+  size_t to_write = value.size();
+
+  int precision = conv.precision();
+  if (precision >= 0)
+    to_write = std::min(to_write, static_cast<size_t>(precision));
+
+  space_remaining = Excess(to_write, space_remaining);
+
+  if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
+
+  string_view piece;
+  for (AbslCordReader reader(value);
+       to_write > 0 && reader.ReadFragment(&piece); to_write -= piece.size()) {
+    if (piece.size() > to_write) piece.remove_suffix(piece.size() - to_write);
+    sink->Append(piece);
+  }
+
+  if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
+  return {true};
+}
+
+using IntegralConvertResult =
+    ConvertResult<Conv::c | Conv::numeric | Conv::star>;
+using FloatingConvertResult = ConvertResult<Conv::floating>;
+
+// Floats.
+FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+FloatingConvertResult FormatConvertImpl(long double v,
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+
+// Chars.
+IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(signed char v,
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+
+// Ints.
+IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
+                                        const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(uint128 v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink);
+template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
+IntegralConvertResult FormatConvertImpl(T v, const ConversionSpec& conv,
+                                        FormatSinkImpl* sink) {
+  return FormatConvertImpl(static_cast<int>(v), conv, sink);
+}
+
+// We provide this function to help the checker, but it is never defined.
+// FormatArgImpl will use the underlying Convert functions instead.
+template <typename T>
+typename std::enable_if<std::is_enum<T>::value &&
+                            !HasUserDefinedConvert<T>::value,
+                        IntegralConvertResult>::type
+FormatConvertImpl(T v, const ConversionSpec& conv, FormatSinkImpl* sink);
+
+template <typename T>
+ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
+                                         const ConversionSpec& conv,
+                                         FormatSinkImpl* out) {
+  std::ostringstream oss;
+  oss << v.v_;
+  if (!oss) return {false};
+  return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
+}
+
+// Use templates and dependent types to delay evaluation of the function
+// until after FormatCountCapture is fully defined.
+struct FormatCountCaptureHelper {
+  template <class T = int>
+  static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
+                                              const ConversionSpec& conv,
+                                              FormatSinkImpl* sink) {
+    const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
+
+    if (conv.conv().id() != str_format_internal::ConversionChar::n)
+      return {false};
+    *v2.p_ = static_cast<int>(sink->size());
+    return {true};
+  }
+};
+
+template <class T = int>
+ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
+                                         const ConversionSpec& conv,
+                                         FormatSinkImpl* sink) {
+  return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
+}
+
+// Helper friend struct to hide implementation details from the public API of
+// FormatArgImpl.
+struct FormatArgImplFriend {
+  template <typename Arg>
+  static bool ToInt(Arg arg, int* out) {
+    if (!arg.vtbl_->to_int) return false;
+    *out = arg.vtbl_->to_int(arg.data_);
+    return true;
+  }
+
+  template <typename Arg>
+  static bool Convert(Arg arg, const str_format_internal::ConversionSpec& conv,
+                      FormatSinkImpl* out) {
+    return arg.vtbl_->convert(arg.data_, conv, out);
+  }
+
+  template <typename Arg>
+  static const void* GetVTablePtrForTest(Arg arg) {
+    return arg.vtbl_;
+  }
+};
+
+// A type-erased handle to a format argument.
+class FormatArgImpl {
+ private:
+  enum { kInlinedSpace = 8 };
+
+  using VoidPtr = str_format_internal::VoidPtr;
+
+  union Data {
+    const void* ptr;
+    const volatile void* volatile_ptr;
+    char buf[kInlinedSpace];
+  };
+
+  struct VTable {
+    bool (*convert)(Data, const str_format_internal::ConversionSpec& conv,
+                    FormatSinkImpl* out);
+    int (*to_int)(Data);
+  };
+
+  template <typename T>
+  struct store_by_value
+      : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) &&
+                                         (std::is_integral<T>::value ||
+                                          std::is_floating_point<T>::value ||
+                                          std::is_pointer<T>::value ||
+                                          std::is_same<VoidPtr, T>::value)> {};
+
+  enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue };
+  template <typename T>
+  struct storage_policy
+      : std::integral_constant<StoragePolicy,
+                               (std::is_volatile<T>::value
+                                    ? ByVolatilePointer
+                                    : (store_by_value<T>::value ? ByValue
+                                                                : ByPointer))> {
+  };
+
+  // An instance of an FormatArgImpl::VTable suitable for 'T'.
+  template <typename T>
+  struct TypedVTable;
+
+  // To reduce the number of vtables we will decay values before hand.
+  // Anything with a user-defined Convert will get its own vtable.
+  // For everything else:
+  //   - Decay char* and char arrays into `const char*`
+  //   - Decay any other pointer to `const void*`
+  //   - Decay all enums to their underlying type.
+  //   - Decay function pointers to void*.
+  template <typename T, typename = void>
+  struct DecayType {
+    static constexpr bool kHasUserDefined =
+        str_format_internal::HasUserDefinedConvert<T>::value;
+    using type = typename std::conditional<
+        !kHasUserDefined && std::is_convertible<T, const char*>::value,
+        const char*,
+        typename std::conditional<!kHasUserDefined &&
+                                      std::is_convertible<T, VoidPtr>::value,
+                                  VoidPtr, const T&>::type>::type;
+  };
+  template <typename T>
+  struct DecayType<T,
+                   typename std::enable_if<
+                       !str_format_internal::HasUserDefinedConvert<T>::value &&
+                       std::is_enum<T>::value>::type> {
+    using type = typename std::underlying_type<T>::type;
+  };
+
+ public:
+  template <typename T>
+  explicit FormatArgImpl(const T& value) {
+    using D = typename DecayType<T>::type;
+    static_assert(
+        std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue,
+        "Decayed types must be stored by value");
+    Init(static_cast<D>(value));
+  }
+
+ private:
+  friend struct str_format_internal::FormatArgImplFriend;
+  template <typename T, StoragePolicy = storage_policy<T>::value>
+  struct Manager;
+
+  template <typename T>
+  struct Manager<T, ByPointer> {
+    static Data SetValue(const T& value) {
+      Data data;
+      data.ptr = &value;
+      return data;
+    }
+
+    static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
+  };
+
+  template <typename T>
+  struct Manager<T, ByVolatilePointer> {
+    static Data SetValue(const T& value) {
+      Data data;
+      data.volatile_ptr = &value;
+      return data;
+    }
+
+    static const T& Value(Data arg) {
+      return *static_cast<const T*>(arg.volatile_ptr);
+    }
+  };
+
+  template <typename T>
+  struct Manager<T, ByValue> {
+    static Data SetValue(const T& value) {
+      Data data;
+      memcpy(data.buf, &value, sizeof(value));
+      return data;
+    }
+
+    static T Value(Data arg) {
+      T value;
+      memcpy(&value, arg.buf, sizeof(T));
+      return value;
+    }
+  };
+
+  template <typename T>
+  void Init(const T& value);
+
+  template <typename T>
+  static int ToIntVal(const T& val) {
+    using CommonType = typename std::conditional<std::is_signed<T>::value,
+                                                 int64_t, uint64_t>::type;
+    if (static_cast<CommonType>(val) >
+        static_cast<CommonType>(std::numeric_limits<int>::max())) {
+      return std::numeric_limits<int>::max();
+    } else if (std::is_signed<T>::value &&
+               static_cast<CommonType>(val) <
+                   static_cast<CommonType>(std::numeric_limits<int>::min())) {
+      return std::numeric_limits<int>::min();
+    }
+    return static_cast<int>(val);
+  }
+
+  Data data_;
+  const VTable* vtbl_;
+};
+
+template <typename T>
+struct FormatArgImpl::TypedVTable {
+ private:
+  static bool ConvertImpl(Data arg,
+                          const str_format_internal::ConversionSpec& conv,
+                          FormatSinkImpl* out) {
+    return str_format_internal::FormatConvertImpl(Manager<T>::Value(arg), conv,
+                                                  out)
+        .value;
+  }
+
+  template <typename U = T, typename = void>
+  struct ToIntImpl {
+    static constexpr int (*value)(Data) = nullptr;
+  };
+
+  template <typename U>
+  struct ToIntImpl<U,
+                   typename std::enable_if<std::is_integral<U>::value>::type> {
+    static int Invoke(Data arg) { return ToIntVal(Manager<T>::Value(arg)); }
+    static constexpr int (*value)(Data) = &Invoke;
+  };
+
+  template <typename U>
+  struct ToIntImpl<U, typename std::enable_if<std::is_enum<U>::value>::type> {
+    static int Invoke(Data arg) {
+      return ToIntVal(static_cast<typename std::underlying_type<T>::type>(
+          Manager<T>::Value(arg)));
+    }
+    static constexpr int (*value)(Data) = &Invoke;
+  };
+
+ public:
+  static constexpr VTable value{&ConvertImpl, ToIntImpl<>::value};
+};
+
+template <typename T>
+constexpr FormatArgImpl::VTable FormatArgImpl::TypedVTable<T>::value;
+
+template <typename T>
+void FormatArgImpl::Init(const T& value) {
+  data_ = Manager<T>::SetValue(value);
+  vtbl_ = &TypedVTable<T>::value;
+}
+
+extern template struct FormatArgImpl::TypedVTable<str_format_internal::VoidPtr>;
+
+extern template struct FormatArgImpl::TypedVTable<bool>;
+extern template struct FormatArgImpl::TypedVTable<char>;
+extern template struct FormatArgImpl::TypedVTable<signed char>;
+extern template struct FormatArgImpl::TypedVTable<unsigned char>;
+extern template struct FormatArgImpl::TypedVTable<short>;           // NOLINT
+extern template struct FormatArgImpl::TypedVTable<unsigned short>;  // NOLINT
+extern template struct FormatArgImpl::TypedVTable<int>;
+extern template struct FormatArgImpl::TypedVTable<unsigned>;
+extern template struct FormatArgImpl::TypedVTable<long>;           // NOLINT
+extern template struct FormatArgImpl::TypedVTable<unsigned long>;  // NOLINT
+extern template struct FormatArgImpl::TypedVTable<long long>;      // NOLINT
+extern template struct FormatArgImpl::TypedVTable<
+    unsigned long long>;  // NOLINT
+extern template struct FormatArgImpl::TypedVTable<uint128>;
+
+extern template struct FormatArgImpl::TypedVTable<float>;
+extern template struct FormatArgImpl::TypedVTable<double>;
+extern template struct FormatArgImpl::TypedVTable<long double>;
+
+extern template struct FormatArgImpl::TypedVTable<const char*>;
+extern template struct FormatArgImpl::TypedVTable<std::string>;
+extern template struct FormatArgImpl::TypedVTable<string_view>;
+}  // namespace str_format_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc
new file mode 100644
index 0000000..83d5904
--- /dev/null
+++ b/absl/strings/internal/str_format/arg_test.cc
@@ -0,0 +1,111 @@
+// Copyright 2017 The Abseil 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
+//
+#include "absl/strings/internal/str_format/arg.h"
+
+#include <ostream>
+#include <string>
+#include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+
+class FormatArgImplTest : public ::testing::Test {
+ public:
+  enum Color { kRed, kGreen, kBlue };
+
+  static const char *hi() { return "hi"; }
+};
+
+TEST_F(FormatArgImplTest, ToInt) {
+  int out = 0;
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(1), &out));
+  EXPECT_EQ(1, out);
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(-1), &out));
+  EXPECT_EQ(-1, out);
+  EXPECT_TRUE(
+      FormatArgImplFriend::ToInt(FormatArgImpl(static_cast<char>(64)), &out));
+  EXPECT_EQ(64, out);
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(
+      FormatArgImpl(static_cast<unsigned long long>(123456)), &out));  // NOLINT
+  EXPECT_EQ(123456, out);
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(
+      FormatArgImpl(static_cast<unsigned long long>(  // NOLINT
+                        std::numeric_limits<int>::max()) +
+                    1),
+      &out));
+  EXPECT_EQ(std::numeric_limits<int>::max(), out);
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(
+      FormatArgImpl(static_cast<long long>(  // NOLINT
+                        std::numeric_limits<int>::min()) -
+                    10),
+      &out));
+  EXPECT_EQ(std::numeric_limits<int>::min(), out);
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(false), &out));
+  EXPECT_EQ(0, out);
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(true), &out));
+  EXPECT_EQ(1, out);
+  EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(2.2), &out));
+  EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(3.2f), &out));
+  EXPECT_FALSE(FormatArgImplFriend::ToInt(
+      FormatArgImpl(static_cast<int *>(nullptr)), &out));
+  EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(hi()), &out));
+  EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl("hi"), &out));
+  EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(kBlue), &out));
+  EXPECT_EQ(2, out);
+}
+
+extern const char kMyArray[];
+
+TEST_F(FormatArgImplTest, CharArraysDecayToCharPtr) {
+  const char* a = "";
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)),
+            FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl("")));
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)),
+            FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl("A")));
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)),
+            FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl("ABC")));
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)),
+            FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(kMyArray)));
+}
+
+TEST_F(FormatArgImplTest, OtherPtrDecayToVoidPtr) {
+  auto expected = FormatArgImplFriend::GetVTablePtrForTest(
+      FormatArgImpl(static_cast<void *>(nullptr)));
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(
+                FormatArgImpl(static_cast<int *>(nullptr))),
+            expected);
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(
+                FormatArgImpl(static_cast<volatile int *>(nullptr))),
+            expected);
+
+  auto p = static_cast<void (*)()>([] {});
+  EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(p)),
+            expected);
+}
+
+TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) {
+  std::string s;
+  FormatSinkImpl sink(&s);
+  ConversionSpec conv;
+  conv.set_conv(ConversionChar::FromChar('s'));
+  conv.set_flags(Flags());
+  conv.set_width(-1);
+  conv.set_precision(-1);
+  EXPECT_TRUE(
+      FormatArgImplFriend::Convert(FormatArgImpl(kMyArray), conv, &sink));
+  sink.Flush();
+  EXPECT_EQ("ABCDE", s);
+}
+const char kMyArray[] = "ABCDE";
+
+}  // namespace
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc
new file mode 100644
index 0000000..33e8641
--- /dev/null
+++ b/absl/strings/internal/str_format/bind.cc
@@ -0,0 +1,232 @@
+#include "absl/strings/internal/str_format/bind.h"
+
+#include <cerrno>
+#include <limits>
+#include <sstream>
+#include <string>
+
+namespace absl {
+namespace str_format_internal {
+
+namespace {
+
+inline bool BindFromPosition(int position, int* value,
+                             absl::Span<const FormatArgImpl> pack) {
+  assert(position > 0);
+  if (static_cast<size_t>(position) > pack.size()) {
+    return false;
+  }
+  // -1 because positions are 1-based
+  return FormatArgImplFriend::ToInt(pack[position - 1], value);
+}
+
+class ArgContext {
+ public:
+  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
+
+  // Fill 'bound' with the results of applying the context's argument pack
+  // to the specified 'props'. We synthesize a BoundConversion by
+  // lining up a UnboundConversion with a user argument. We also
+  // resolve any '*' specifiers for width and precision, so after
+  // this call, 'bound' has all the information it needs to be formatted.
+  // Returns false on failure.
+  bool Bind(const UnboundConversion *props, BoundConversion *bound);
+
+ private:
+  absl::Span<const FormatArgImpl> pack_;
+};
+
+inline bool ArgContext::Bind(const UnboundConversion* unbound,
+                             BoundConversion* bound) {
+  const FormatArgImpl* arg = nullptr;
+  int arg_position = unbound->arg_position;
+  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
+  arg = &pack_[arg_position - 1];  // 1-based
+
+  if (!unbound->flags.basic) {
+    int width = unbound->width.value();
+    bool force_left = false;
+    if (unbound->width.is_from_arg()) {
+      if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
+        return false;
+      if (width < 0) {
+        // "A negative field width is taken as a '-' flag followed by a
+        // positive field width."
+        force_left = true;
+        width = -width;
+      }
+    }
+
+    int precision = unbound->precision.value();
+    if (unbound->precision.is_from_arg()) {
+      if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
+                            pack_))
+        return false;
+    }
+
+    bound->set_width(width);
+    bound->set_precision(precision);
+    bound->set_flags(unbound->flags);
+    if (force_left)
+      bound->set_left(true);
+  } else {
+    bound->set_flags(unbound->flags);
+    bound->set_width(-1);
+    bound->set_precision(-1);
+  }
+
+  bound->set_length_mod(unbound->length_mod);
+  bound->set_conv(unbound->conv);
+  bound->set_arg(arg);
+  return true;
+}
+
+template <typename Converter>
+class ConverterConsumer {
+ public:
+  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
+      : converter_(converter), arg_context_(pack) {}
+
+  bool Append(string_view s) {
+    converter_.Append(s);
+    return true;
+  }
+  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
+    BoundConversion bound;
+    if (!arg_context_.Bind(&conv, &bound)) return false;
+    return converter_.ConvertOne(bound, conv_string);
+  }
+
+ private:
+  Converter converter_;
+  ArgContext arg_context_;
+};
+
+template <typename Converter>
+bool ConvertAll(const UntypedFormatSpecImpl& format,
+                absl::Span<const FormatArgImpl> args,
+                const Converter& converter) {
+  const ParsedFormatBase* pc = format.parsed_conversion();
+  if (pc)
+    return pc->ProcessFormat(ConverterConsumer<Converter>(converter, args));
+
+  return ParseFormatString(format.str(),
+                           ConverterConsumer<Converter>(converter, args));
+}
+
+class DefaultConverter {
+ public:
+  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
+
+  void Append(string_view s) const { sink_->Append(s); }
+
+  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
+    return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
+  }
+
+ private:
+  FormatSinkImpl* sink_;
+};
+
+class SummarizingConverter {
+ public:
+  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
+
+  void Append(string_view s) const { sink_->Append(s); }
+
+  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
+    UntypedFormatSpecImpl spec("%d");
+
+    std::ostringstream ss;
+    ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags();
+    if (bound.width() >= 0) ss << bound.width();
+    if (bound.precision() >= 0) ss << "." << bound.precision();
+    ss << bound.length_mod() << bound.conv() << "}";
+    Append(ss.str());
+    return true;
+  }
+
+ private:
+  FormatSinkImpl* sink_;
+};
+
+}  // namespace
+
+bool BindWithPack(const UnboundConversion* props,
+                  absl::Span<const FormatArgImpl> pack,
+                  BoundConversion* bound) {
+  return ArgContext(pack).Bind(props, bound);
+}
+
+std::string Summarize(const UntypedFormatSpecImpl& format,
+                 absl::Span<const FormatArgImpl> args) {
+  typedef SummarizingConverter Converter;
+  std::string out;
+  {
+    // inner block to destroy sink before returning out. It ensures a last
+    // flush.
+    FormatSinkImpl sink(&out);
+    if (!ConvertAll(format, args, Converter(&sink))) {
+      sink.Flush();
+      out.clear();
+    }
+  }
+  return out;
+}
+
+bool FormatUntyped(FormatRawSinkImpl raw_sink,
+                   const UntypedFormatSpecImpl& format,
+                   absl::Span<const FormatArgImpl> args) {
+  FormatSinkImpl sink(raw_sink);
+  using Converter = DefaultConverter;
+  if (!ConvertAll(format, args, Converter(&sink))) {
+    sink.Flush();
+    return false;
+  }
+  return true;
+}
+
+std::ostream& Streamable::Print(std::ostream& os) const {
+  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
+  return os;
+}
+
+std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl& format,
+                   absl::Span<const FormatArgImpl> args) {
+  size_t orig = out->size();
+  if (!FormatUntyped(out, format, args)) out->resize(orig);
+  return *out;
+}
+
+int FprintF(std::FILE* output, const UntypedFormatSpecImpl& format,
+            absl::Span<const FormatArgImpl> args) {
+  FILERawSink sink(output);
+  if (!FormatUntyped(&sink, format, args)) {
+    errno = EINVAL;
+    return -1;
+  }
+  if (sink.error()) {
+    errno = sink.error();
+    return -1;
+  }
+  if (sink.count() > std::numeric_limits<int>::max()) {
+    errno = EFBIG;
+    return -1;
+  }
+  return static_cast<int>(sink.count());
+}
+
+int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl& format,
+             absl::Span<const FormatArgImpl> args) {
+  BufferRawSink sink(output, size ? size - 1 : 0);
+  if (!FormatUntyped(&sink, format, args)) {
+    errno = EINVAL;
+    return -1;
+  }
+  size_t total = sink.total_written();
+  if (size) output[std::min(total, size - 1)] = 0;
+  return static_cast<int>(total);
+}
+
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
new file mode 100644
index 0000000..4008611
--- /dev/null
+++ b/absl/strings/internal/str_format/bind.h
@@ -0,0 +1,189 @@
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
+
+#include <array>
+#include <cstdio>
+#include <sstream>
+#include <string>
+
+#include "absl/base/port.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/str_format/arg.h"
+#include "absl/strings/internal/str_format/checker.h"
+#include "absl/strings/internal/str_format/parser.h"
+#include "absl/types/span.h"
+
+namespace absl {
+
+class UntypedFormatSpec;
+
+namespace str_format_internal {
+
+class BoundConversion : public ConversionSpec {
+ public:
+  const FormatArgImpl* arg() const { return arg_; }
+  void set_arg(const FormatArgImpl* a) { arg_ = a; }
+
+ private:
+  const FormatArgImpl* arg_;
+};
+
+// This is the type-erased class that the implementation uses.
+class UntypedFormatSpecImpl {
+ public:
+  UntypedFormatSpecImpl() = delete;
+
+  explicit UntypedFormatSpecImpl(string_view s) : str_(s), pc_() {}
+  explicit UntypedFormatSpecImpl(
+      const str_format_internal::ParsedFormatBase* pc)
+      : pc_(pc) {}
+  string_view str() const { return str_; }
+  const str_format_internal::ParsedFormatBase* parsed_conversion() const {
+    return pc_;
+  }
+
+  template <typename T>
+  static const UntypedFormatSpecImpl& Extract(const T& s) {
+    return s.spec_;
+  }
+
+ private:
+  string_view str_;
+  const str_format_internal::ParsedFormatBase* pc_;
+};
+
+template <typename T, typename...>
+struct MakeDependent {
+  using type = T;
+};
+
+// Implicitly convertible from `const char*`, `string_view`, and the
+// `ExtendedParsedFormat` type. This abstraction allows all format functions to
+// operate on any without providing too many overloads.
+template <typename... Args>
+class FormatSpecTemplate
+    : public MakeDependent<UntypedFormatSpec, Args...>::type {
+  using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
+
+ public:
+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+  // Honeypot overload for when the std::string is not constexpr.
+  // We use the 'unavailable' attribute to give a better compiler error than
+  // just 'method is deleted'.
+  FormatSpecTemplate(...)  // NOLINT
+      __attribute__((unavailable("Format std::string is not constexpr.")));
+
+  // Honeypot overload for when the format is constexpr and invalid.
+  // We use the 'unavailable' attribute to give a better compiler error than
+  // just 'method is deleted'.
+  // To avoid checking the format twice, we just check that the format is
+  // constexpr. If is it valid, then the overload below will kick in.
+  // We add the template here to make this overload have lower priority.
+  template <typename = void>
+  FormatSpecTemplate(const char* s)  // NOLINT
+      __attribute__((
+          enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"),
+          unavailable(
+              "Format specified does not match the arguments passed.")));
+
+  template <typename T = void>
+  FormatSpecTemplate(string_view s)  // NOLINT
+      __attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
+                               "constexpr trap"))) {
+    static_assert(sizeof(T*) == 0,
+                  "Format specified does not match the arguments passed.");
+  }
+
+  // Good format overload.
+  FormatSpecTemplate(const char* s)  // NOLINT
+      __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
+                               "bad format trap")))
+      : Base(s) {}
+
+  FormatSpecTemplate(string_view s)  // NOLINT
+      __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
+                               "bad format trap")))
+      : Base(s) {}
+
+#else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+  FormatSpecTemplate(const char* s) : Base(s) {}  // NOLINT
+  FormatSpecTemplate(string_view s) : Base(s) {}  // NOLINT
+
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+  template <Conv... C, typename = typename std::enable_if<
+                           sizeof...(C) == sizeof...(Args) &&
+                           AllOf(Contains(ArgumentToConv<Args>(),
+                                          C)...)>::type>
+  FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
+      : Base(&pc) {}
+};
+
+template <typename... Args>
+struct FormatSpecDeductionBarrier {
+  using type = FormatSpecTemplate<Args...>;
+};
+
+class Streamable {
+ public:
+  Streamable(const UntypedFormatSpecImpl& format,
+             absl::Span<const FormatArgImpl> args)
+      : format_(format), args_(args.begin(), args.end()) {}
+
+  std::ostream& Print(std::ostream& os) const;
+
+  friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
+    return l.Print(os);
+  }
+
+ private:
+  const UntypedFormatSpecImpl& format_;
+  absl::InlinedVector<FormatArgImpl, 4> args_;
+};
+
+// for testing
+std::string Summarize(const UntypedFormatSpecImpl& format,
+                 absl::Span<const FormatArgImpl> args);
+bool BindWithPack(const UnboundConversion* props,
+                  absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
+
+bool FormatUntyped(FormatRawSinkImpl raw_sink,
+                   const UntypedFormatSpecImpl& format,
+                   absl::Span<const FormatArgImpl> args);
+
+std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl& format,
+                   absl::Span<const FormatArgImpl> args);
+
+inline std::string FormatPack(const UntypedFormatSpecImpl& format,
+                         absl::Span<const FormatArgImpl> args) {
+  std::string out;
+  AppendPack(&out, format, args);
+  return out;
+}
+
+int FprintF(std::FILE* output, const UntypedFormatSpecImpl& format,
+            absl::Span<const FormatArgImpl> args);
+int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl& format,
+             absl::Span<const FormatArgImpl> args);
+
+// Returned by Streamed(v). Converts via '%s' to the std::string created
+// by std::ostream << v.
+template <typename T>
+class StreamedWrapper {
+ public:
+  explicit StreamedWrapper(const T& v) : v_(v) { }
+
+ private:
+  template <typename S>
+  friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
+                                                  const ConversionSpec& conv,
+                                                  FormatSinkImpl* out);
+  const T& v_;
+};
+
+}  // namespace str_format_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc
new file mode 100644
index 0000000..4757573
--- /dev/null
+++ b/absl/strings/internal/str_format/bind_test.cc
@@ -0,0 +1,131 @@
+#include "absl/strings/internal/str_format/bind.h"
+
+#include <string.h>
+
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+
+template <typename T, size_t N>
+size_t ArraySize(T (&)[N]) {
+  return N;
+}
+
+class FormatBindTest : public ::testing::Test {
+ public:
+  bool Extract(const char *s, UnboundConversion *props, int *next) const {
+    absl::string_view src = s;
+    return ConsumeUnboundConversion(&src, props, next) && src.empty();
+  }
+};
+
+TEST_F(FormatBindTest, BindSingle) {
+  struct Expectation {
+    int line;
+    const char *fmt;
+    int ok_phases;
+    const FormatArgImpl *arg;
+    int width;
+    int precision;
+    int next_arg;
+  };
+  const int no = -1;
+  const int ia[] = { 10, 20, 30, 40};
+  const FormatArgImpl args[] = {FormatArgImpl(ia[0]), FormatArgImpl(ia[1]),
+                                FormatArgImpl(ia[2]), FormatArgImpl(ia[3])};
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+  const Expectation kExpect[] = {
+    {__LINE__, "d",          2, &args[0], no, no, 2},
+    {__LINE__, "4d",         2, &args[0],  4, no, 2},
+    {__LINE__, ".5d",        2, &args[0], no,  5, 2},
+    {__LINE__, "4.5d",       2, &args[0],  4,  5, 2},
+    {__LINE__, "*d",         2, &args[1], 10, no, 3},
+    {__LINE__, ".*d",        2, &args[1], no, 10, 3},
+    {__LINE__, "*.*d",       2, &args[2], 10, 20, 4},
+    {__LINE__, "1$d",        2, &args[0], no, no, 0},
+    {__LINE__, "2$d",        2, &args[1], no, no, 0},
+    {__LINE__, "3$d",        2, &args[2], no, no, 0},
+    {__LINE__, "4$d",        2, &args[3], no, no, 0},
+    {__LINE__, "2$*1$d",     2, &args[1], 10, no, 0},
+    {__LINE__, "2$*2$d",     2, &args[1], 20, no, 0},
+    {__LINE__, "2$*3$d",     2, &args[1], 30, no, 0},
+    {__LINE__, "2$.*1$d",    2, &args[1], no, 10, 0},
+    {__LINE__, "2$.*2$d",    2, &args[1], no, 20, 0},
+    {__LINE__, "2$.*3$d",    2, &args[1], no, 30, 0},
+    {__LINE__, "2$*3$.*1$d", 2, &args[1], 30, 10, 0},
+    {__LINE__, "2$*2$.*2$d", 2, &args[1], 20, 20, 0},
+    {__LINE__, "2$*1$.*3$d", 2, &args[1], 10, 30, 0},
+    {__LINE__, "2$*3$.*1$d", 2, &args[1], 30, 10, 0},
+    {__LINE__, "1$*d",       0},  // indexed, then positional
+    {__LINE__, "*2$d",       0},  // positional, then indexed
+    {__LINE__, "6$d",        1},  // arg position out of bounds
+    {__LINE__, "1$6$d",      0},  // width position incorrectly specified
+    {__LINE__, "1$.6$d",     0},  // precision position incorrectly specified
+    {__LINE__, "1$*6$d",     1},  // width position out of bounds
+    {__LINE__, "1$.*6$d",    1},  // precision position out of bounds
+  };
+#pragma GCC diagnostic pop
+  for (const Expectation &e : kExpect) {
+    SCOPED_TRACE(e.line);
+    SCOPED_TRACE(e.fmt);
+    UnboundConversion props;
+    BoundConversion bound;
+    int ok_phases = 0;
+    int next = 0;
+    if (Extract(e.fmt, &props, &next)) {
+      ++ok_phases;
+      if (BindWithPack(&props, args, &bound)) {
+        ++ok_phases;
+      }
+    }
+    EXPECT_EQ(e.ok_phases, ok_phases);
+    if (e.ok_phases < 2) continue;
+    if (e.arg != nullptr) {
+      EXPECT_EQ(e.arg, bound.arg());
+    }
+    EXPECT_EQ(e.width, bound.width());
+    EXPECT_EQ(e.precision, bound.precision());
+  }
+}
+
+TEST_F(FormatBindTest, FormatPack) {
+  struct Expectation {
+    int line;
+    const char *fmt;
+    const char *summary;
+  };
+  const int ia[] = { 10, 20, 30, 40, -10 };
+  const FormatArgImpl args[] = {FormatArgImpl(ia[0]), FormatArgImpl(ia[1]),
+                                FormatArgImpl(ia[2]), FormatArgImpl(ia[3]),
+                                FormatArgImpl(ia[4])};
+  const Expectation kExpect[] = {
+    {__LINE__, "a%4db%dc", "a{10:4d}b{20:d}c"},
+    {__LINE__, "a%.4db%dc", "a{10:.4d}b{20:d}c"},
+    {__LINE__, "a%4.5db%dc", "a{10:4.5d}b{20:d}c"},
+    {__LINE__, "a%db%4.5dc", "a{10:d}b{20:4.5d}c"},
+    {__LINE__, "a%db%*.*dc", "a{10:d}b{40:20.30d}c"},
+    {__LINE__, "a%.*fb", "a{20:.10f}b"},
+    {__LINE__, "a%1$db%2$*3$.*4$dc", "a{10:d}b{20:30.40d}c"},
+    {__LINE__, "a%4$db%3$*2$.*1$dc", "a{40:d}b{30:20.10d}c"},
+    {__LINE__, "a%04ldb", "a{10:04ld}b"},
+    {__LINE__, "a%-#04lldb", "a{10:-#04lld}b"},
+    {__LINE__, "a%1$*5$db", "a{10:-10d}b"},
+    {__LINE__, "a%1$.*5$db", "a{10:d}b"},
+  };
+  for (const Expectation &e : kExpect) {
+    absl::string_view fmt = e.fmt;
+    SCOPED_TRACE(e.line);
+    SCOPED_TRACE(e.fmt);
+    UntypedFormatSpecImpl format(fmt);
+    EXPECT_EQ(e.summary,
+              str_format_internal::Summarize(format, absl::MakeSpan(args)))
+        << "line:" << e.line;
+  }
+}
+
+}  // namespace
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h
new file mode 100644
index 0000000..8b594f2
--- /dev/null
+++ b/absl/strings/internal/str_format/checker.h
@@ -0,0 +1,325 @@
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
+
+#include "absl/strings/internal/str_format/arg.h"
+#include "absl/strings/internal/str_format/extension.h"
+
+// Compile time check support for entry points.
+
+#ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+#if defined(__clang__) && !defined(__native_client__)
+#if __has_attribute(enable_if)
+#define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1
+#endif  // __has_attribute(enable_if)
+#endif  // defined(__clang__) && !defined(__native_client__)
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+namespace absl {
+namespace str_format_internal {
+
+constexpr bool AllOf() { return true; }
+
+template <typename... T>
+constexpr bool AllOf(bool b, T... t) {
+  return b && AllOf(t...);
+}
+
+template <typename Arg>
+constexpr Conv ArgumentToConv() {
+  return decltype(str_format_internal::FormatConvertImpl(
+      std::declval<const Arg&>(), std::declval<const ConversionSpec&>(),
+      std::declval<FormatSinkImpl*>()))::kConv;
+}
+
+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+constexpr bool ContainsChar(const char* chars, char c) {
+  return *chars == c || (*chars && ContainsChar(chars + 1, c));
+}
+
+// A constexpr compatible list of Convs.
+struct ConvList {
+  const Conv* array;
+  int count;
+
+  // We do the bound check here to avoid having to do it on the callers.
+  // Returning an empty Conv has the same effect as short circuiting because it
+  // will never match any conversion.
+  constexpr Conv operator[](int i) const {
+    return i < count ? array[i] : Conv{};
+  }
+
+  constexpr ConvList without_front() const {
+    return count != 0 ? ConvList{array + 1, count - 1} : *this;
+  }
+};
+
+template <size_t count>
+struct ConvListT {
+  // Make sure the array has size > 0.
+  Conv list[count ? count : 1];
+};
+
+constexpr char GetChar(string_view str, size_t index) {
+  return index < str.size() ? str[index] : char{};
+}
+
+constexpr string_view ConsumeFront(string_view str, size_t len = 1) {
+  return len <= str.size() ? string_view(str.data() + len, str.size() - len)
+                           : string_view();
+}
+
+constexpr string_view ConsumeAnyOf(string_view format, const char* chars) {
+  return ContainsChar(chars, GetChar(format, 0))
+             ? ConsumeAnyOf(ConsumeFront(format), chars)
+             : format;
+}
+
+constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; }
+
+// Helper class for the ParseDigits function.
+// It encapsulates the two return values we need there.
+struct Integer {
+  string_view format;
+  int value;
+
+  // If the next character is a '$', consume it.
+  // Otherwise, make `this` an invalid positional argument.
+  constexpr Integer ConsumePositionalDollar() const {
+    return GetChar(format, 0) == '$' ? Integer{ConsumeFront(format), value}
+                                     : Integer{format, 0};
+  }
+};
+
+constexpr Integer ParseDigits(string_view format, int value = 0) {
+  return IsDigit(GetChar(format, 0))
+             ? ParseDigits(ConsumeFront(format),
+                           10 * value + GetChar(format, 0) - '0')
+             : Integer{format, value};
+}
+
+// Parse digits for a positional argument.
+// The parsing also consumes the '$'.
+constexpr Integer ParsePositional(string_view format) {
+  return ParseDigits(format).ConsumePositionalDollar();
+}
+
+// Parses a single conversion specifier.
+// See ConvParser::Run() for post conditions.
+class ConvParser {
+  constexpr ConvParser SetFormat(string_view format) const {
+    return ConvParser(format, args_, error_, arg_position_, is_positional_);
+  }
+
+  constexpr ConvParser SetArgs(ConvList args) const {
+    return ConvParser(format_, args, error_, arg_position_, is_positional_);
+  }
+
+  constexpr ConvParser SetError(bool error) const {
+    return ConvParser(format_, args_, error_ || error, arg_position_,
+                      is_positional_);
+  }
+
+  constexpr ConvParser SetArgPosition(int arg_position) const {
+    return ConvParser(format_, args_, error_, arg_position, is_positional_);
+  }
+
+  // Consumes the next arg and verifies that it matches `conv`.
+  // `error_` is set if there is no next arg or if it doesn't match `conv`.
+  constexpr ConvParser ConsumeNextArg(char conv) const {
+    return SetArgs(args_.without_front()).SetError(!Contains(args_[0], conv));
+  }
+
+  // Verify that positional argument `i.value` matches `conv`.
+  // `error_` is set if `i.value` is not a valid argument or if it doesn't
+  // match.
+  constexpr ConvParser VerifyPositional(Integer i, char conv) const {
+    return SetFormat(i.format).SetError(!Contains(args_[i.value - 1], conv));
+  }
+
+  // Parse the position of the arg and store it in `arg_position_`.
+  constexpr ConvParser ParseArgPosition(Integer arg) const {
+    return SetFormat(arg.format).SetArgPosition(arg.value);
+  }
+
+  // Consume the flags.
+  constexpr ConvParser ParseFlags() const {
+    return SetFormat(ConsumeAnyOf(format_, "-+ #0"));
+  }
+
+  // Consume the width.
+  // If it is '*', we verify that it matches `args_`. `error_` is set if it
+  // doesn't match.
+  constexpr ConvParser ParseWidth() const {
+    return IsDigit(GetChar(format_, 0))
+               ? SetFormat(ParseDigits(format_).format)
+               : GetChar(format_, 0) == '*'
+                     ? is_positional_
+                           ? VerifyPositional(
+                                 ParsePositional(ConsumeFront(format_)), '*')
+                           : SetFormat(ConsumeFront(format_))
+                                 .ConsumeNextArg('*')
+                     : *this;
+  }
+
+  // Consume the precision.
+  // If it is '*', we verify that it matches `args_`. `error_` is set if it
+  // doesn't match.
+  constexpr ConvParser ParsePrecision() const {
+    return GetChar(format_, 0) != '.'
+               ? *this
+               : GetChar(format_, 1) == '*'
+                     ? is_positional_
+                           ? VerifyPositional(
+                                 ParsePositional(ConsumeFront(format_, 2)), '*')
+                           : SetFormat(ConsumeFront(format_, 2))
+                                 .ConsumeNextArg('*')
+                     : SetFormat(ParseDigits(ConsumeFront(format_)).format);
+  }
+
+  // Consume the length characters.
+  constexpr ConvParser ParseLength() const {
+    return SetFormat(ConsumeAnyOf(format_, "lLhjztq"));
+  }
+
+  // Consume the conversion character and verify that it matches `args_`.
+  // `error_` is set if it doesn't match.
+  constexpr ConvParser ParseConversion() const {
+    return is_positional_
+               ? VerifyPositional({ConsumeFront(format_), arg_position_},
+                                  GetChar(format_, 0))
+               : ConsumeNextArg(GetChar(format_, 0))
+                     .SetFormat(ConsumeFront(format_));
+  }
+
+  constexpr ConvParser(string_view format, ConvList args, bool error,
+                       int arg_position, bool is_positional)
+      : format_(format),
+        args_(args),
+        error_(error),
+        arg_position_(arg_position),
+        is_positional_(is_positional) {}
+
+ public:
+  constexpr ConvParser(string_view format, ConvList args, bool is_positional)
+      : format_(format),
+        args_(args),
+        error_(false),
+        arg_position_(0),
+        is_positional_(is_positional) {}
+
+  // Consume the whole conversion specifier.
+  // `format()` will be set to the character after the conversion character.
+  // `error()` will be set if any of the arguments do not match.
+  constexpr ConvParser Run() const {
+    return (is_positional_ ? ParseArgPosition(ParsePositional(format_)) : *this)
+        .ParseFlags()
+        .ParseWidth()
+        .ParsePrecision()
+        .ParseLength()
+        .ParseConversion();
+  }
+
+  constexpr string_view format() const { return format_; }
+  constexpr ConvList args() const { return args_; }
+  constexpr bool error() const { return error_; }
+  constexpr bool is_positional() const { return is_positional_; }
+
+ private:
+  string_view format_;
+  // Current list of arguments. If we are not in positional mode we will consume
+  // from the front.
+  ConvList args_;
+  bool error_;
+  // Holds the argument position of the conversion character, if we are in
+  // positional mode. Otherwise, it is unspecified.
+  int arg_position_;
+  // Whether we are in positional mode.
+  // It changes the behavior of '*' and where to find the converted argument.
+  bool is_positional_;
+};
+
+// Parses a whole format expression.
+// See FormatParser::Run().
+class FormatParser {
+  static constexpr bool FoundPercent(string_view format) {
+    return format.empty() ||
+           (GetChar(format, 0) == '%' && GetChar(format, 1) != '%');
+  }
+
+  // We use an inner function to increase the recursion limit.
+  // The inner function consumes up to `limit` characters on every run.
+  // This increases the limit from 512 to ~512*limit.
+  static constexpr string_view ConsumeNonPercentInner(string_view format,
+                                                      int limit = 20) {
+    return FoundPercent(format) || !limit
+               ? format
+               : ConsumeNonPercentInner(
+                     ConsumeFront(format, GetChar(format, 0) == '%' &&
+                                                  GetChar(format, 1) == '%'
+                                              ? 2
+                                              : 1),
+                     limit - 1);
+  }
+
+  // Consume characters until the next conversion spec %.
+  // It skips %%.
+  static constexpr string_view ConsumeNonPercent(string_view format) {
+    return FoundPercent(format)
+               ? format
+               : ConsumeNonPercent(ConsumeNonPercentInner(format));
+  }
+
+  static constexpr bool IsPositional(string_view format) {
+    return IsDigit(GetChar(format, 0)) ? IsPositional(ConsumeFront(format))
+                                       : GetChar(format, 0) == '$';
+  }
+
+  constexpr bool RunImpl(bool is_positional) const {
+    // In non-positional mode we require all arguments to be consumed.
+    // In positional mode just reaching the end of the format without errors is
+    // enough.
+    return (format_.empty() && (is_positional || args_.count == 0)) ||
+           (!format_.empty() &&
+            ValidateArg(
+                ConvParser(ConsumeFront(format_), args_, is_positional).Run()));
+  }
+
+  constexpr bool ValidateArg(ConvParser conv) const {
+    return !conv.error() && FormatParser(conv.format(), conv.args())
+                                .RunImpl(conv.is_positional());
+  }
+
+ public:
+  constexpr FormatParser(string_view format, ConvList args)
+      : format_(ConsumeNonPercent(format)), args_(args) {}
+
+  // Runs the parser for `format` and `args`.
+  // It verifies that the format is valid and that all conversion specifiers
+  // match the arguments passed.
+  // In non-positional mode it also verfies that all arguments are consumed.
+  constexpr bool Run() const {
+    return RunImpl(!format_.empty() && IsPositional(ConsumeFront(format_)));
+  }
+
+ private:
+  string_view format_;
+  // Current list of arguments.
+  // If we are not in positional mode we will consume from the front and will
+  // have to be empty in the end.
+  ConvList args_;
+};
+
+template <Conv... C>
+constexpr bool ValidFormatImpl(string_view format) {
+  return FormatParser(format,
+                      {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)})
+      .Run();
+}
+
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+}  // namespace str_format_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
new file mode 100644
index 0000000..14d11ea
--- /dev/null
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -0,0 +1,150 @@
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+
+std::string ConvToString(Conv conv) {
+  std::string out;
+#define CONV_SET_CASE(c) \
+  if (Contains(conv, Conv::c)) out += #c;
+  ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
+#undef CONV_SET_CASE
+  if (Contains(conv, Conv::star)) out += "*";
+  return out;
+}
+
+TEST(StrFormatChecker, ArgumentToConv) {
+  Conv conv = ArgumentToConv<std::string>();
+  EXPECT_EQ(ConvToString(conv), "s");
+
+  conv = ArgumentToConv<const char*>();
+  EXPECT_EQ(ConvToString(conv), "sp");
+
+  conv = ArgumentToConv<double>();
+  EXPECT_EQ(ConvToString(conv), "fFeEgGaA");
+
+  conv = ArgumentToConv<int>();
+  EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaA*");
+
+  conv = ArgumentToConv<std::string*>();
+  EXPECT_EQ(ConvToString(conv), "p");
+}
+
+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+struct Case {
+  bool result;
+  const char* format;
+};
+
+template <typename... Args>
+constexpr Case ValidFormat(const char* format) {
+  return {ValidFormatImpl<ArgumentToConv<Args>()...>(format), format};
+}
+
+TEST(StrFormatChecker, ValidFormat) {
+  // We want to make sure these expressions are constexpr and they have the
+  // expected value.
+  // If they are not constexpr the attribute will just ignore them and not give
+  // a compile time error.
+  enum e {};
+  enum class e2 {};
+  constexpr Case trues[] = {
+      ValidFormat<>("abc"),  //
+
+      ValidFormat<e>("%d"),                             //
+      ValidFormat<e2>("%d"),                            //
+      ValidFormat<int>("%% %d"),                        //
+      ValidFormat<int>("%ld"),                          //
+      ValidFormat<int>("%lld"),                         //
+      ValidFormat<std::string>("%s"),                        //
+      ValidFormat<std::string>("%10s"),                      //
+      ValidFormat<int>("%.10x"),                        //
+      ValidFormat<int, int>("%*.3x"),                   //
+      ValidFormat<int>("%1.d"),                         //
+      ValidFormat<int>("%.d"),                          //
+      ValidFormat<int, double>("%d %g"),                //
+      ValidFormat<int, std::string>("%*s"),                  //
+      ValidFormat<int, double>("%.*f"),                 //
+      ValidFormat<void (*)(), volatile int*>("%p %p"),  //
+      ValidFormat<string_view, const char*, double, void*>(
+          "string_view=%s const char*=%s double=%f void*=%p)"),
+
+      ValidFormat<int>("%% %1$d"),            //
+      ValidFormat<int>("%1$ld"),              //
+      ValidFormat<int>("%1$lld"),             //
+      ValidFormat<std::string>("%1$s"),            //
+      ValidFormat<std::string>("%1$10s"),          //
+      ValidFormat<int>("%1$.10x"),            //
+      ValidFormat<int>("%1$*1$.*1$d"),        //
+      ValidFormat<int, int>("%1$*2$.3x"),     //
+      ValidFormat<int>("%1$1.d"),             //
+      ValidFormat<int>("%1$.d"),              //
+      ValidFormat<double, int>("%2$d %1$g"),  //
+      ValidFormat<int, std::string>("%2$*1$s"),    //
+      ValidFormat<int, double>("%2$.*1$f"),   //
+      ValidFormat<void*, string_view, const char*, double>(
+          "string_view=%2$s const char*=%3$s double=%4$f void*=%1$p "
+          "repeat=%3$s)")};
+
+  for (Case c : trues) {
+    EXPECT_TRUE(c.result) << c.format;
+  }
+
+  constexpr Case falses[] = {
+      ValidFormat<int>(""),  //
+
+      ValidFormat<e>("%s"),             //
+      ValidFormat<e2>("%s"),            //
+      ValidFormat<>("%s"),              //
+      ValidFormat<>("%r"),              //
+      ValidFormat<int>("%s"),           //
+      ValidFormat<int>("%.1.d"),        //
+      ValidFormat<int>("%*1d"),         //
+      ValidFormat<int>("%1-d"),         //
+      ValidFormat<std::string, int>("%*s"),  //
+      ValidFormat<int>("%*d"),          //
+      ValidFormat<std::string>("%p"),        //
+      ValidFormat<int (*)(int)>("%d"),  //
+
+      ValidFormat<>("%3$d"),                //
+      ValidFormat<>("%1$r"),                //
+      ValidFormat<int>("%1$s"),             //
+      ValidFormat<int>("%1$.1.d"),          //
+      ValidFormat<int>("%1$*2$1d"),         //
+      ValidFormat<int>("%1$1-d"),           //
+      ValidFormat<std::string, int>("%2$*1$s"),  //
+      ValidFormat<std::string>("%1$p"),
+
+      ValidFormat<int, int>("%d %2$d"),  //
+  };
+
+  for (Case c : falses) {
+    EXPECT_FALSE(c.result) << c.format;
+  }
+}
+
+TEST(StrFormatChecker, LongFormat) {
+#define CHARS_X_40 "1234567890123456789012345678901234567890"
+#define CHARS_X_400                                                            \
+  CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 \
+      CHARS_X_40 CHARS_X_40 CHARS_X_40
+#define CHARS_X_4000                                                      \
+  CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 \
+      CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400
+  constexpr char long_format[] =
+      CHARS_X_4000 "%d" CHARS_X_4000 "%s" CHARS_X_4000;
+  constexpr bool is_valid = ValidFormat<int, std::string>(long_format).result;
+  EXPECT_TRUE(is_valid);
+}
+
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+}  // namespace
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
new file mode 100644
index 0000000..32f8a0f
--- /dev/null
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -0,0 +1,575 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <cmath>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/strings/internal/str_format/bind.h"
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+
+template <typename T, size_t N>
+size_t ArraySize(T (&)[N]) {
+  return N;
+}
+
+std::string LengthModFor(float) { return ""; }
+std::string LengthModFor(double) { return ""; }
+std::string LengthModFor(long double) { return "L"; }
+std::string LengthModFor(char) { return "hh"; }
+std::string LengthModFor(signed char) { return "hh"; }
+std::string LengthModFor(unsigned char) { return "hh"; }
+std::string LengthModFor(short) { return "h"; }           // NOLINT
+std::string LengthModFor(unsigned short) { return "h"; }  // NOLINT
+std::string LengthModFor(int) { return ""; }
+std::string LengthModFor(unsigned) { return ""; }
+std::string LengthModFor(long) { return "l"; }                 // NOLINT
+std::string LengthModFor(unsigned long) { return "l"; }        // NOLINT
+std::string LengthModFor(long long) { return "ll"; }           // NOLINT
+std::string LengthModFor(unsigned long long) { return "ll"; }  // NOLINT
+
+std::string EscCharImpl(int v) {
+  if (isprint(v)) return std::string(1, static_cast<char>(v));
+  char buf[64];
+  int n = snprintf(buf, sizeof(buf), "\\%#.2x",
+                   static_cast<unsigned>(v & 0xff));
+  assert(n > 0 && n < sizeof(buf));
+  return std::string(buf, n);
+}
+
+std::string Esc(char v) { return EscCharImpl(v); }
+std::string Esc(signed char v) { return EscCharImpl(v); }
+std::string Esc(unsigned char v) { return EscCharImpl(v); }
+
+template <typename T>
+std::string Esc(const T &v) {
+  std::ostringstream oss;
+  oss << v;
+  return oss.str();
+}
+
+void StrAppend(std::string *dst, const char *format, va_list ap) {
+  // First try with a small fixed size buffer
+  static const int kSpaceLength = 1024;
+  char space[kSpaceLength];
+
+  // It's possible for methods that use a va_list to invalidate
+  // the data in it upon use.  The fix is to make a copy
+  // of the structure before using it and use that copy instead.
+  va_list backup_ap;
+  va_copy(backup_ap, ap);
+  int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+  va_end(backup_ap);
+  if (result < kSpaceLength) {
+    if (result >= 0) {
+      // Normal case -- everything fit.
+      dst->append(space, result);
+      return;
+    }
+    if (result < 0) {
+      // Just an error.
+      return;
+    }
+  }
+
+  // Increase the buffer size to the size requested by vsnprintf,
+  // plus one for the closing \0.
+  int length = result + 1;
+  char *buf = new char[length];
+
+  // Restore the va_list before we use it again
+  va_copy(backup_ap, ap);
+  result = vsnprintf(buf, length, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result >= 0 && result < length) {
+    // It fit
+    dst->append(buf, result);
+  }
+  delete[] buf;
+}
+
+std::string StrPrint(const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string result;
+  StrAppend(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+
+class FormatConvertTest : public ::testing::Test { };
+
+template <typename T>
+void TestStringConvert(const T& str) {
+  const FormatArgImpl args[] = {FormatArgImpl(str)};
+  struct Expectation {
+    const char *out;
+    const char *fmt;
+  };
+  const Expectation kExpect[] = {
+    {"hello",  "%1$s"      },
+    {"",       "%1$.s"     },
+    {"",       "%1$.0s"    },
+    {"h",      "%1$.1s"    },
+    {"he",     "%1$.2s"    },
+    {"hello",  "%1$.10s"   },
+    {" hello", "%1$6s"     },
+    {"   he",  "%1$5.2s"   },
+    {"he   ",  "%1$-5.2s"  },
+    {"hello ", "%1$-6.10s" },
+  };
+  for (const Expectation &e : kExpect) {
+    UntypedFormatSpecImpl format(e.fmt);
+    EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args)));
+  }
+}
+
+TEST_F(FormatConvertTest, BasicString) {
+  TestStringConvert("hello");  // As char array.
+  TestStringConvert(static_cast<const char*>("hello"));
+  TestStringConvert(std::string("hello"));
+  TestStringConvert(string_view("hello"));
+}
+
+TEST_F(FormatConvertTest, NullString) {
+  const char* p = nullptr;
+  UntypedFormatSpecImpl format("%s");
+  EXPECT_EQ("", FormatPack(format, {FormatArgImpl(p)}));
+}
+
+TEST_F(FormatConvertTest, StringPrecision) {
+  // We cap at the precision.
+  char c = 'a';
+  const char* p = &c;
+  UntypedFormatSpecImpl format("%.1s");
+  EXPECT_EQ("a", FormatPack(format, {FormatArgImpl(p)}));
+
+  // We cap at the nul terminator.
+  p = "ABC";
+  UntypedFormatSpecImpl format2("%.10s");
+  EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)}));
+}
+
+TEST_F(FormatConvertTest, Pointer) {
+#if _MSC_VER
+  // MSVC's printf implementation prints pointers differently. We can't easily
+  // compare our implementation to theirs.
+  return;
+#endif
+  static int x = 0;
+  const int *xp = &x;
+  char c = 'h';
+  char *mcp = &c;
+  const char *cp = "hi";
+  const char *cnil = nullptr;
+  const int *inil = nullptr;
+  using VoidF = void (*)();
+  VoidF fp = [] {}, fnil = nullptr;
+  volatile char vc;
+  volatile char* vcp = &vc;
+  volatile char* vcnil = nullptr;
+  const FormatArgImpl args[] = {
+      FormatArgImpl(xp),   FormatArgImpl(cp),  FormatArgImpl(inil),
+      FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp),
+      FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil),
+  };
+  struct Expectation {
+    std::string out;
+    const char *fmt;
+  };
+  const Expectation kExpect[] = {
+      {StrPrint("%p", &x), "%p"},
+      {StrPrint("%20p", &x), "%20p"},
+      {StrPrint("%.1p", &x), "%.1p"},
+      {StrPrint("%.20p", &x), "%.20p"},
+      {StrPrint("%30.20p", &x), "%30.20p"},
+
+      {StrPrint("%-p", &x), "%-p"},
+      {StrPrint("%-20p", &x), "%-20p"},
+      {StrPrint("%-.1p", &x), "%-.1p"},
+      {StrPrint("%.20p", &x), "%.20p"},
+      {StrPrint("%-30.20p", &x), "%-30.20p"},
+
+      {StrPrint("%p", cp), "%2$p"},   // const char*
+      {"(nil)", "%3$p"},              // null const char *
+      {"(nil)", "%4$p"},              // null const int *
+      {StrPrint("%p", mcp), "%5$p"},  // nonconst char*
+
+      {StrPrint("%p", fp), "%6$p"},   // function pointer
+      {StrPrint("%p", vcp), "%8$p"},  // function pointer
+
+#ifndef __APPLE__
+      // Apple's printf differs here (0x0 vs. nil)
+      {StrPrint("%p", fnil), "%7$p"},   // null function pointer
+      {StrPrint("%p", vcnil), "%9$p"},  // null function pointer
+#endif
+  };
+  for (const Expectation &e : kExpect) {
+    UntypedFormatSpecImpl format(e.fmt);
+    EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))) << e.fmt;
+  }
+}
+
+struct Cardinal {
+  enum Pos { k1 = 1, k2 = 2, k3 = 3 };
+  enum Neg { kM1 = -1, kM2 = -2, kM3 = -3 };
+};
+
+TEST_F(FormatConvertTest, Enum) {
+  const Cardinal::Pos k3 = Cardinal::k3;
+  const Cardinal::Neg km3 = Cardinal::kM3;
+  const FormatArgImpl args[] = {FormatArgImpl(k3), FormatArgImpl(km3)};
+  UntypedFormatSpecImpl format("%1$d");
+  UntypedFormatSpecImpl format2("%2$d");
+  EXPECT_EQ("3", FormatPack(format, absl::MakeSpan(args)));
+  EXPECT_EQ("-3", FormatPack(format2, absl::MakeSpan(args)));
+}
+
+template <typename T>
+class TypedFormatConvertTest : public FormatConvertTest { };
+
+TYPED_TEST_CASE_P(TypedFormatConvertTest);
+
+std::vector<std::string> AllFlagCombinations() {
+  const char kFlags[] = {'-', '#', '0', '+', ' '};
+  std::vector<std::string> result;
+  for (size_t fsi = 0; fsi < (1ull << ArraySize(kFlags)); ++fsi) {
+    std::string flag_set;
+    for (size_t fi = 0; fi < ArraySize(kFlags); ++fi)
+      if (fsi & (1ull << fi))
+        flag_set += kFlags[fi];
+    result.push_back(flag_set);
+  }
+  return result;
+}
+
+TYPED_TEST_P(TypedFormatConvertTest, AllIntsWithFlags) {
+  typedef TypeParam T;
+  typedef typename std::make_unsigned<T>::type UnsignedT;
+  using remove_volatile_t = typename std::remove_volatile<T>::type;
+  const T kMin = std::numeric_limits<remove_volatile_t>::min();
+  const T kMax = std::numeric_limits<remove_volatile_t>::max();
+  const T kVals[] = {
+      remove_volatile_t(1),
+      remove_volatile_t(2),
+      remove_volatile_t(3),
+      remove_volatile_t(123),
+      remove_volatile_t(-1),
+      remove_volatile_t(-2),
+      remove_volatile_t(-3),
+      remove_volatile_t(-123),
+      remove_volatile_t(0),
+      kMax - remove_volatile_t(1),
+      kMax,
+      kMin + remove_volatile_t(1),
+      kMin,
+  };
+  const char kConvChars[] = {'d', 'i', 'u', 'o', 'x', 'X'};
+  const std::string kWid[] = {"", "4", "10"};
+  const std::string kPrec[] = {"", ".", ".0", ".4", ".10"};
+
+  const std::vector<std::string> flag_sets = AllFlagCombinations();
+
+  for (size_t vi = 0; vi < ArraySize(kVals); ++vi) {
+    const T val = kVals[vi];
+    SCOPED_TRACE(Esc(val));
+    const FormatArgImpl args[] = {FormatArgImpl(val)};
+    for (size_t ci = 0; ci < ArraySize(kConvChars); ++ci) {
+      const char conv_char = kConvChars[ci];
+      for (size_t fsi = 0; fsi < flag_sets.size(); ++fsi) {
+        const std::string &flag_set = flag_sets[fsi];
+        for (size_t wi = 0; wi < ArraySize(kWid); ++wi) {
+          const std::string &wid = kWid[wi];
+          for (size_t pi = 0; pi < ArraySize(kPrec); ++pi) {
+            const std::string &prec = kPrec[pi];
+
+            const bool is_signed_conv = (conv_char == 'd' || conv_char == 'i');
+            const bool is_unsigned_to_signed =
+                !std::is_signed<T>::value && is_signed_conv;
+            // Don't consider sign-related flags '+' and ' ' when doing
+            // unsigned to signed conversions.
+            if (is_unsigned_to_signed &&
+                flag_set.find_first_of("+ ") != std::string::npos) {
+              continue;
+            }
+
+            std::string new_fmt("%");
+            new_fmt += flag_set;
+            new_fmt += wid;
+            new_fmt += prec;
+            // old and new always agree up to here.
+            std::string old_fmt = new_fmt;
+            new_fmt += conv_char;
+            std::string old_result;
+            if (is_unsigned_to_signed) {
+              // don't expect agreement on unsigned formatted as signed,
+              // as printf can't do that conversion properly. For those
+              // cases, we do expect agreement with printf with a "%u"
+              // and the unsigned equivalent of 'val'.
+              UnsignedT uval = val;
+              old_fmt += LengthModFor(uval);
+              old_fmt += "u";
+              old_result = StrPrint(old_fmt.c_str(), uval);
+            } else {
+              old_fmt += LengthModFor(val);
+              old_fmt += conv_char;
+              old_result = StrPrint(old_fmt.c_str(), val);
+            }
+
+            SCOPED_TRACE(std::string() + " old_fmt: \"" + old_fmt +
+                         "\"'"
+                         " new_fmt: \"" +
+                         new_fmt + "\"");
+            UntypedFormatSpecImpl format(new_fmt);
+            EXPECT_EQ(old_result, FormatPack(format, absl::MakeSpan(args)));
+          }
+        }
+      }
+    }
+  }
+}
+
+TYPED_TEST_P(TypedFormatConvertTest, Char) {
+  typedef TypeParam T;
+  using remove_volatile_t = typename std::remove_volatile<T>::type;
+  static const T kMin = std::numeric_limits<remove_volatile_t>::min();
+  static const T kMax = std::numeric_limits<remove_volatile_t>::max();
+  T kVals[] = {
+    remove_volatile_t(1), remove_volatile_t(2), remove_volatile_t(10),
+    remove_volatile_t(-1), remove_volatile_t(-2), remove_volatile_t(-10),
+    remove_volatile_t(0),
+    kMin + remove_volatile_t(1), kMin,
+    kMax - remove_volatile_t(1), kMax
+  };
+  for (const T &c : kVals) {
+    const FormatArgImpl args[] = {FormatArgImpl(c)};
+    UntypedFormatSpecImpl format("%c");
+    EXPECT_EQ(StrPrint("%c", c), FormatPack(format, absl::MakeSpan(args)));
+  }
+}
+
+REGISTER_TYPED_TEST_CASE_P(TypedFormatConvertTest, AllIntsWithFlags, Char);
+
+typedef ::testing::Types<
+    int, unsigned, volatile int,
+    short, unsigned short,
+    long, unsigned long,
+    long long, unsigned long long,
+    signed char, unsigned char, char>
+    AllIntTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes,
+                              TypedFormatConvertTest, AllIntTypes);
+TEST_F(FormatConvertTest, Uint128) {
+  absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979;
+  absl::uint128 max = absl::Uint128Max();
+  const FormatArgImpl args[] = {FormatArgImpl(v), FormatArgImpl(max)};
+
+  struct Case {
+    const char* format;
+    const char* expected;
+  } cases[] = {
+      {"%1$d", "2595989796776606496405"},
+      {"%1$30d", "        2595989796776606496405"},
+      {"%1$-30d", "2595989796776606496405        "},
+      {"%1$u", "2595989796776606496405"},
+      {"%1$x", "8cba9876066020f695"},
+      {"%2$d", "340282366920938463463374607431768211455"},
+      {"%2$u", "340282366920938463463374607431768211455"},
+      {"%2$x", "ffffffffffffffffffffffffffffffff"},
+  };
+
+  for (auto c : cases) {
+    UntypedFormatSpecImpl format(c.format);
+    EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args)));
+  }
+}
+
+TEST_F(FormatConvertTest, Float) {
+#if _MSC_VER
+  // MSVC has a different rounding policy than us so we can't test our
+  // implementation against the native one there.
+  return;
+#endif  // _MSC_VER
+
+  const char *const kFormats[] = {
+      "%",  "%.3",  "%8.5",   "%9",   "%.60", "%.30",   "%03",    "%+",
+      "% ", "%-10", "%#15.3", "%#.0", "%.0",  "%1$*2$", "%1$.*2$"};
+
+  std::vector<double> doubles = {0.0,
+                                 -0.0,
+                                 .99999999999999,
+                                 99999999999999.,
+                                 std::numeric_limits<double>::max(),
+                                 -std::numeric_limits<double>::max(),
+                                 std::numeric_limits<double>::min(),
+                                 -std::numeric_limits<double>::min(),
+                                 std::numeric_limits<double>::lowest(),
+                                 -std::numeric_limits<double>::lowest(),
+                                 std::numeric_limits<double>::epsilon(),
+                                 std::numeric_limits<double>::epsilon() + 1,
+                                 std::numeric_limits<double>::infinity(),
+                                 -std::numeric_limits<double>::infinity()};
+
+#ifndef __APPLE__
+  // Apple formats NaN differently (+nan) vs. (nan)
+  doubles.push_back(std::nan(""));
+#endif
+
+  // Some regression tests.
+  doubles.push_back(0.99999999999999989);
+
+  if (std::numeric_limits<double>::has_denorm != std::denorm_absent) {
+    doubles.push_back(std::numeric_limits<double>::denorm_min());
+    doubles.push_back(-std::numeric_limits<double>::denorm_min());
+  }
+
+  for (double base :
+       {1., 12., 123., 1234., 12345., 123456., 1234567., 12345678., 123456789.,
+        1234567890., 12345678901., 123456789012., 1234567890123.}) {
+    for (int exp = -123; exp <= 123; ++exp) {
+      for (int sign : {1, -1}) {
+        doubles.push_back(sign * std::ldexp(base, exp));
+      }
+    }
+  }
+
+  for (const char *fmt : kFormats) {
+    for (char f : {'f', 'F',  //
+                   'g', 'G',  //
+                   'a', 'A',  //
+                   'e', 'E'}) {
+      std::string fmt_str = std::string(fmt) + f;
+      for (double d : doubles) {
+        int i = -10;
+        FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
+        UntypedFormatSpecImpl format(fmt_str);
+        // We use ASSERT_EQ here because failures are usually correlated and a
+        // bug would print way too many failed expectations causing the test to
+        // time out.
+        ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i),
+                  FormatPack(format, absl::MakeSpan(args)))
+            << fmt_str << " " << StrPrint("%.18g", d) << " "
+            << StrPrint("%.999f", d);
+      }
+    }
+  }
+}
+
+TEST_F(FormatConvertTest, LongDouble) {
+  const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",
+                                  "%.60", "%+",  "% ",   "%-10"};
+
+  // This value is not representable in double, but it is in long double that
+  // uses the extended format.
+  // This is to verify that we are not truncating the value mistakenly through a
+  // double.
+  long double very_precise = 10000000000000000.25L;
+
+  std::vector<long double> doubles = {
+      0.0,
+      -0.0,
+      very_precise,
+      1 / very_precise,
+      std::numeric_limits<long double>::max(),
+      -std::numeric_limits<long double>::max(),
+      std::numeric_limits<long double>::min(),
+      -std::numeric_limits<long double>::min(),
+      std::numeric_limits<long double>::infinity(),
+      -std::numeric_limits<long double>::infinity()};
+
+  for (const char *fmt : kFormats) {
+    for (char f : {'f', 'F',  //
+                   'g', 'G',  //
+                   'a', 'A',  //
+                   'e', 'E'}) {
+      std::string fmt_str = std::string(fmt) + 'L' + f;
+      for (auto d : doubles) {
+        FormatArgImpl arg(d);
+        UntypedFormatSpecImpl format(fmt_str);
+        // We use ASSERT_EQ here because failures are usually correlated and a
+        // bug would print way too many failed expectations causing the test to
+        // time out.
+        ASSERT_EQ(StrPrint(fmt_str.c_str(), d),
+                  FormatPack(format, {&arg, 1}))
+            << fmt_str << " " << StrPrint("%.18Lg", d) << " "
+            << StrPrint("%.999Lf", d);
+      }
+    }
+  }
+}
+
+TEST_F(FormatConvertTest, IntAsFloat) {
+  const int kMin = std::numeric_limits<int>::min();
+  const int kMax = std::numeric_limits<int>::max();
+  const int ia[] = {
+    1, 2, 3, 123,
+    -1, -2, -3, -123,
+    0, kMax - 1, kMax, kMin + 1, kMin };
+  for (const int fx : ia) {
+    SCOPED_TRACE(fx);
+    const FormatArgImpl args[] = {FormatArgImpl(fx)};
+    struct Expectation {
+      int line;
+      std::string out;
+      const char *fmt;
+    };
+    const double dx = static_cast<double>(fx);
+    const Expectation kExpect[] = {
+      { __LINE__, StrPrint("%f", dx), "%f" },
+      { __LINE__, StrPrint("%12f", dx), "%12f" },
+      { __LINE__, StrPrint("%.12f", dx), "%.12f" },
+      { __LINE__, StrPrint("%12a", dx), "%12a" },
+      { __LINE__, StrPrint("%.12a", dx), "%.12a" },
+    };
+    for (const Expectation &e : kExpect) {
+      SCOPED_TRACE(e.line);
+      SCOPED_TRACE(e.fmt);
+      UntypedFormatSpecImpl format(e.fmt);
+      EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args)));
+    }
+  }
+}
+
+template <typename T>
+bool FormatFails(const char* test_format, T value) {
+  std::string format_string = std::string("<<") + test_format + ">>";
+  UntypedFormatSpecImpl format(format_string);
+
+  int one = 1;
+  const FormatArgImpl args[] = {FormatArgImpl(value), FormatArgImpl(one)};
+  EXPECT_EQ(FormatPack(format, absl::MakeSpan(args)), "")
+      << "format=" << test_format << " value=" << value;
+  return FormatPack(format, absl::MakeSpan(args)).empty();
+}
+
+TEST_F(FormatConvertTest, ExpectedFailures) {
+  // Int input
+  EXPECT_TRUE(FormatFails("%p", 1));
+  EXPECT_TRUE(FormatFails("%s", 1));
+  EXPECT_TRUE(FormatFails("%n", 1));
+
+  // Double input
+  EXPECT_TRUE(FormatFails("%p", 1.));
+  EXPECT_TRUE(FormatFails("%s", 1.));
+  EXPECT_TRUE(FormatFails("%n", 1.));
+  EXPECT_TRUE(FormatFails("%c", 1.));
+  EXPECT_TRUE(FormatFails("%d", 1.));
+  EXPECT_TRUE(FormatFails("%x", 1.));
+  EXPECT_TRUE(FormatFails("%*d", 1.));
+
+  // String input
+  EXPECT_TRUE(FormatFails("%n", ""));
+  EXPECT_TRUE(FormatFails("%c", ""));
+  EXPECT_TRUE(FormatFails("%d", ""));
+  EXPECT_TRUE(FormatFails("%x", ""));
+  EXPECT_TRUE(FormatFails("%f", ""));
+  EXPECT_TRUE(FormatFails("%*d", ""));
+}
+
+}  // namespace
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc
new file mode 100644
index 0000000..c217470
--- /dev/null
+++ b/absl/strings/internal/str_format/extension.cc
@@ -0,0 +1,84 @@
+//
+// Copyright 2017 The Abseil 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 "absl/strings/internal/str_format/extension.h"
+
+#include <errno.h>
+#include <algorithm>
+#include <string>
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+// clang-format off
+#define ABSL_LENGTH_MODS_EXPAND_ \
+  X_VAL(h) X_SEP \
+  X_VAL(hh) X_SEP \
+  X_VAL(l) X_SEP \
+  X_VAL(ll) X_SEP \
+  X_VAL(L) X_SEP \
+  X_VAL(j) X_SEP \
+  X_VAL(z) X_SEP \
+  X_VAL(t) X_SEP \
+  X_VAL(q)
+// clang-format on
+}  // namespace
+
+const LengthMod::Spec LengthMod::kSpecs[] = {
+#define X_VAL(id) { LengthMod::id, #id, strlen(#id) }
+#define X_SEP ,
+    ABSL_LENGTH_MODS_EXPAND_, {LengthMod::none, "", 0}
+#undef X_VAL
+#undef X_SEP
+};
+
+const ConversionChar::Spec ConversionChar::kSpecs[] = {
+#define X_VAL(id) { ConversionChar::id, #id[0] }
+#define X_SEP ,
+    ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP),
+    {ConversionChar::none, '\0'},
+#undef X_VAL
+#undef X_SEP
+};
+
+std::string Flags::ToString() const {
+  std::string s;
+  s.append(left     ? "-" : "");
+  s.append(show_pos ? "+" : "");
+  s.append(sign_col ? " " : "");
+  s.append(alt      ? "#" : "");
+  s.append(zero     ? "0" : "");
+  return s;
+}
+
+const size_t LengthMod::kNumValues;
+
+const size_t ConversionChar::kNumValues;
+
+bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) {
+  size_t space_remaining = 0;
+  if (w >= 0) space_remaining = w;
+  size_t n = v.size();
+  if (p >= 0) n = std::min(n, static_cast<size_t>(p));
+  string_view shown(v.data(), n);
+  space_remaining = Excess(shown.size(), space_remaining);
+  if (!l) Append(space_remaining, ' ');
+  Append(shown);
+  if (l) Append(space_remaining, ' ');
+  return true;
+}
+
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
new file mode 100644
index 0000000..810330b
--- /dev/null
+++ b/absl/strings/internal/str_format/extension.h
@@ -0,0 +1,406 @@
+//
+// Copyright 2017 The Abseil 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 ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
+
+#include <limits.h>
+#include <cstring>
+#include <ostream>
+
+#include "absl/base/port.h"
+#include "absl/strings/internal/str_format/output.h"
+#include "absl/strings/string_view.h"
+
+class Cord;
+
+namespace absl {
+
+namespace str_format_internal {
+
+class FormatRawSinkImpl {
+ public:
+  // Implicitly convert from any type that provides the hook function as
+  // described above.
+  template <typename T, decltype(str_format_internal::InvokeFlush(
+                            std::declval<T*>(), string_view()))* = nullptr>
+  FormatRawSinkImpl(T* raw)  // NOLINT
+      : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
+
+  void Write(string_view s) { write_(sink_, s); }
+
+  template <typename T>
+  static FormatRawSinkImpl Extract(T s) {
+    return s.sink_;
+  }
+
+ private:
+  template <typename T>
+  static void Flush(void* r, string_view s) {
+    str_format_internal::InvokeFlush(static_cast<T*>(r), s);
+  }
+
+  void* sink_;
+  void (*write_)(void*, string_view);
+};
+
+// An abstraction to which conversions write their std::string data.
+class FormatSinkImpl {
+ public:
+  explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
+
+  ~FormatSinkImpl() { Flush(); }
+
+  void Flush() {
+    raw_.Write(string_view(buf_, pos_ - buf_));
+    pos_ = buf_;
+  }
+
+  void Append(size_t n, char c) {
+    if (n == 0) return;
+    size_ += n;
+    auto raw_append = [&](size_t count) {
+      memset(pos_, c, count);
+      pos_ += count;
+    };
+    while (n > Avail()) {
+      n -= Avail();
+      if (Avail() > 0) {
+        raw_append(Avail());
+      }
+      Flush();
+    }
+    raw_append(n);
+  }
+
+  void Append(string_view v) {
+    size_t n = v.size();
+    if (n == 0) return;
+    size_ += n;
+    if (n >= Avail()) {
+      Flush();
+      raw_.Write(v);
+      return;
+    }
+    memcpy(pos_, v.data(), n);
+    pos_ += n;
+  }
+
+  size_t size() const { return size_; }
+
+  // Put 'v' to 'sink' with specified width, precision, and left flag.
+  bool PutPaddedString(string_view v, int w, int p, bool l);
+
+  template <typename T>
+  T Wrap() {
+    return T(this);
+  }
+
+  template <typename T>
+  static FormatSinkImpl* Extract(T* s) {
+    return s->sink_;
+  }
+
+ private:
+  size_t Avail() const { return buf_ + sizeof(buf_) - pos_; }
+
+  FormatRawSinkImpl raw_;
+  size_t size_ = 0;
+  char* pos_ = buf_;
+  char buf_[1024];
+};
+
+struct Flags {
+  bool basic : 1;     // fastest conversion: no flags, width, or precision
+  bool left : 1;      // "-"
+  bool show_pos : 1;  // "+"
+  bool sign_col : 1;  // " "
+  bool alt : 1;       // "#"
+  bool zero : 1;      // "0"
+  std::string ToString() const;
+  friend std::ostream& operator<<(std::ostream& os, const Flags& v) {
+    return os << v.ToString();
+  }
+};
+
+struct LengthMod {
+ public:
+  enum Id : uint8_t {
+    h, hh, l, ll, L, j, z, t, q, none
+  };
+  static const size_t kNumValues = none + 1;
+
+  LengthMod() : id_(none) {}
+
+  // Index into the opaque array of LengthMod enums.
+  // Requires: i < kNumValues
+  static LengthMod FromIndex(size_t i) {
+    return LengthMod(kSpecs[i].value);
+  }
+
+  static LengthMod FromId(Id id) { return LengthMod(id); }
+
+  // The length modifier std::string associated with a specified LengthMod.
+  string_view name() const {
+    const Spec& spec = kSpecs[id_];
+    return {spec.name, spec.name_length};
+  }
+
+  Id id() const { return id_; }
+
+  friend bool operator==(const LengthMod& a, const LengthMod& b) {
+    return a.id() == b.id();
+  }
+  friend bool operator!=(const LengthMod& a, const LengthMod& b) {
+    return !(a == b);
+  }
+  friend std::ostream& operator<<(std::ostream& os, const LengthMod& v) {
+    return os << v.name();
+  }
+
+ private:
+  struct Spec {
+    Id value;
+    const char *name;
+    size_t name_length;
+  };
+  static const Spec kSpecs[];
+
+  explicit LengthMod(Id id) : id_(id) {}
+
+  Id id_;
+};
+
+// clang-format off
+#define ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
+  /* text */ \
+  X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \
+  /* ints */ \
+  X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
+  X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
+  /* floats */ \
+  X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
+  X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
+  /* misc */ \
+  X_VAL(n) X_SEP X_VAL(p)
+// clang-format on
+
+struct ConversionChar {
+ public:
+  enum Id : uint8_t {
+    c, C, s, S,              // text
+    d, i, o, u, x, X,        // int
+    f, F, e, E, g, G, a, A,  // float
+    n, p,                    // misc
+    none
+  };
+  static const size_t kNumValues = none + 1;
+
+  ConversionChar() : id_(none) {}
+
+ public:
+  // Index into the opaque array of ConversionChar enums.
+  // Requires: i < kNumValues
+  static ConversionChar FromIndex(size_t i) {
+    return ConversionChar(kSpecs[i].value);
+  }
+
+  static ConversionChar FromChar(char c) {
+    ConversionChar::Id out_id = ConversionChar::none;
+    switch (c) {
+#define X_VAL(id)                \
+  case #id[0]:                   \
+    out_id = ConversionChar::id; \
+    break;
+      ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, )
+#undef X_VAL
+      default:
+        break;
+    }
+    return ConversionChar(out_id);
+  }
+
+  static ConversionChar FromId(Id id) { return ConversionChar(id); }
+  Id id() const { return id_; }
+
+  int radix() const {
+    switch (id()) {
+      case x: case X: case a: case A: case p: return 16;
+      case o: return 8;
+      default: return 10;
+    }
+  }
+
+  bool upper() const {
+    switch (id()) {
+      case X: case F: case E: case G: case A: return true;
+      default: return false;
+    }
+  }
+
+  bool is_signed() const {
+    switch (id()) {
+      case d: case i: return true;
+      default: return false;
+    }
+  }
+
+  bool is_integral() const {
+    switch (id()) {
+      case d: case i: case u: case o: case x: case X:
+        return true;
+      default: return false;
+    }
+  }
+
+  bool is_float() const {
+    switch (id()) {
+      case a: case e: case f: case g: case A: case E: case F: case G:
+        return true;
+      default: return false;
+    }
+  }
+
+  bool IsValid() const { return id() != none; }
+
+  // The associated char.
+  char Char() const { return kSpecs[id_].name; }
+
+  friend bool operator==(const ConversionChar& a, const ConversionChar& b) {
+    return a.id() == b.id();
+  }
+  friend bool operator!=(const ConversionChar& a, const ConversionChar& b) {
+    return !(a == b);
+  }
+  friend std::ostream& operator<<(std::ostream& os, const ConversionChar& v) {
+    char c = v.Char();
+    if (!c) c = '?';
+    return os << c;
+  }
+
+ private:
+  struct Spec {
+    Id value;
+    char name;
+  };
+  static const Spec kSpecs[];
+
+  explicit ConversionChar(Id id) : id_(id) {}
+
+  Id id_;
+};
+
+class ConversionSpec {
+ public:
+  Flags flags() const { return flags_; }
+  LengthMod length_mod() const { return length_mod_; }
+  ConversionChar conv() const { return conv_; }
+
+  // Returns the specified width. If width is unspecfied, it returns a negative
+  // value.
+  int width() const { return width_; }
+  // Returns the specified precision. If precision is unspecfied, it returns a
+  // negative value.
+  int precision() const { return precision_; }
+
+  void set_flags(Flags f) { flags_ = f; }
+  void set_length_mod(LengthMod lm) { length_mod_ = lm; }
+  void set_conv(ConversionChar c) { conv_ = c; }
+  void set_width(int w) { width_ = w; }
+  void set_precision(int p) { precision_ = p; }
+  void set_left(bool b) { flags_.left = b; }
+
+ private:
+  Flags flags_;
+  LengthMod length_mod_;
+  ConversionChar conv_;
+  int width_;
+  int precision_;
+};
+
+constexpr uint64_t ConversionCharToConvValue(char conv) {
+  return
+#define CONV_SET_CASE(c) \
+  conv == #c[0] ? (uint64_t{1} << (1 + ConversionChar::Id::c)):
+      ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
+#undef CONV_SET_CASE
+                  conv == '*'
+          ? 1
+          : 0;
+}
+
+enum class Conv : uint64_t {
+#define CONV_SET_CASE(c) c = ConversionCharToConvValue(#c[0]),
+  ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
+#undef CONV_SET_CASE
+
+  // Used for width/precision '*' specification.
+  star = ConversionCharToConvValue('*'),
+
+  // Some predefined values:
+  integral = d | i | u | o | x | X,
+  floating = a | e | f | g | A | E | F | G,
+  numeric = integral | floating,
+  string = s,  // absl:ignore(std::string)
+  pointer = p
+};
+
+// Type safe OR operator.
+// We need this for two reasons:
+//  1. operator| on enums makes them decay to integers and the result is an
+//     integer. We need the result to stay as an enum.
+//  2. We use "enum class" which would not work even if we accepted the decay.
+constexpr Conv operator|(Conv a, Conv b) {
+  return Conv(static_cast<uint64_t>(a) | static_cast<uint64_t>(b));
+}
+
+// Get a conversion with a single character in it.
+constexpr Conv ConversionCharToConv(char c) {
+  return Conv(ConversionCharToConvValue(c));
+}
+
+// Checks whether `c` exists in `set`.
+constexpr bool Contains(Conv set, char c) {
+  return (static_cast<uint64_t>(set) & ConversionCharToConvValue(c)) != 0;
+}
+
+// Checks whether all the characters in `c` are contained in `set`
+constexpr bool Contains(Conv set, Conv c) {
+  return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
+         static_cast<uint64_t>(c);
+}
+
+// Return type of the AbslFormatConvert() functions.
+// The Conv template parameter is used to inform the framework of what
+// conversion characters are supported by that AbslFormatConvert routine.
+template <Conv C>
+struct ConvertResult {
+  static constexpr Conv kConv = C;
+  bool value;
+};
+template <Conv C>
+constexpr Conv ConvertResult<C>::kConv;
+
+// Return capacity - used, clipped to a minimum of 0.
+inline size_t Excess(size_t used, size_t capacity) {
+  return used < capacity ? capacity - used : 0;
+}
+
+}  // namespace str_format_internal
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_FORMAT_EXTENSION_H_
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
new file mode 100644
index 0000000..224fc92
--- /dev/null
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -0,0 +1,65 @@
+//
+// Copyright 2017 The Abseil 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 "absl/strings/internal/str_format/extension.h"
+
+#include <random>
+#include <string>
+#include "absl/strings/str_format.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+std::string MakeRandomString(size_t len) {
+  std::random_device rd;
+  std::mt19937 gen(rd());
+  std::uniform_int_distribution<> dis('a', 'z');
+  std::string s(len, '0');
+  for (char& c : s) {
+    c = dis(gen);
+  }
+  return s;
+}
+
+TEST(FormatExtensionTest, SinkAppendSubstring) {
+  for (size_t chunk_size : {1, 10, 100, 1000, 10000}) {
+    std::string expected, actual;
+    absl::str_format_internal::FormatSinkImpl sink(&actual);
+    for (size_t chunks = 0; chunks < 10; ++chunks) {
+      std::string rand = MakeRandomString(chunk_size);
+      expected += rand;
+      sink.Append(rand);
+    }
+    sink.Flush();
+    EXPECT_EQ(actual, expected);
+  }
+}
+
+TEST(FormatExtensionTest, SinkAppendChars) {
+  for (size_t chunk_size : {1, 10, 100, 1000, 10000}) {
+    std::string expected, actual;
+    absl::str_format_internal::FormatSinkImpl sink(&actual);
+    for (size_t chunks = 0; chunks < 10; ++chunks) {
+      std::string rand = MakeRandomString(1);
+      expected.append(chunk_size, rand[0]);
+      sink.Append(chunk_size, rand[0]);
+    }
+    sink.Flush();
+    EXPECT_EQ(actual, expected);
+  }
+}
+}  // namespace
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
new file mode 100644
index 0000000..37952b4
--- /dev/null
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -0,0 +1,476 @@
+#include "absl/strings/internal/str_format/float_conversion.h"
+
+#include <string.h>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <string>
+
+namespace absl {
+namespace str_format_internal {
+
+namespace {
+
+char *CopyStringTo(string_view v, char *out) {
+  std::memcpy(out, v.data(), v.size());
+  return out + v.size();
+}
+
+template <typename Float>
+bool FallbackToSnprintf(const Float v, const ConversionSpec &conv,
+                        FormatSinkImpl *sink) {
+  int w = conv.width() >= 0 ? conv.width() : 0;
+  int p = conv.precision() >= 0 ? conv.precision() : -1;
+  char fmt[32];
+  {
+    char *fp = fmt;
+    *fp++ = '%';
+    fp = CopyStringTo(conv.flags().ToString(), fp);
+    fp = CopyStringTo("*.*", fp);
+    if (std::is_same<long double, Float>()) {
+      *fp++ = 'L';
+    }
+    *fp++ = conv.conv().Char();
+    *fp = 0;
+    assert(fp < fmt + sizeof(fmt));
+  }
+  std::string space(512, '\0');
+  string_view result;
+  while (true) {
+    int n = snprintf(&space[0], space.size(), fmt, w, p, v);
+    if (n < 0) return false;
+    if (static_cast<size_t>(n) < space.size()) {
+      result = string_view(space.data(), n);
+      break;
+    }
+    space.resize(n + 1);
+  }
+  sink->Append(result);
+  return true;
+}
+
+// 128-bits in decimal: ceil(128*log(2)/log(10))
+//   or std::numeric_limits<__uint128_t>::digits10
+constexpr int kMaxFixedPrecision = 39;
+
+constexpr int kBufferLength = /*sign*/ 1 +
+                              /*integer*/ kMaxFixedPrecision +
+                              /*point*/ 1 +
+                              /*fraction*/ kMaxFixedPrecision +
+                              /*exponent e+123*/ 5;
+
+struct Buffer {
+  void push_front(char c) {
+    assert(begin > data);
+    *--begin = c;
+  }
+  void push_back(char c) {
+    assert(end < data + sizeof(data));
+    *end++ = c;
+  }
+  void pop_back() {
+    assert(begin < end);
+    --end;
+  }
+
+  char &back() {
+    assert(begin < end);
+    return end[-1];
+  }
+
+  char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; }
+
+  int size() const { return static_cast<int>(end - begin); }
+
+  char data[kBufferLength];
+  char *begin;
+  char *end;
+};
+
+enum class FormatStyle { Fixed, Precision };
+
+// If the value is Inf or Nan, print it and return true.
+// Otherwise, return false.
+template <typename Float>
+bool ConvertNonNumericFloats(char sign_char, Float v,
+                             const ConversionSpec &conv, FormatSinkImpl *sink) {
+  char text[4], *ptr = text;
+  if (sign_char) *ptr++ = sign_char;
+  if (std::isnan(v)) {
+    ptr = std::copy_n(conv.conv().upper() ? "NAN" : "nan", 3, ptr);
+  } else if (std::isinf(v)) {
+    ptr = std::copy_n(conv.conv().upper() ? "INF" : "inf", 3, ptr);
+  } else {
+    return false;
+  }
+
+  return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1,
+                               conv.flags().left);
+}
+
+// Round up the last digit of the value.
+// It will carry over and potentially overflow. 'exp' will be adjusted in that
+// case.
+template <FormatStyle mode>
+void RoundUp(Buffer *buffer, int *exp) {
+  char *p = &buffer->back();
+  while (p >= buffer->begin && (*p == '9' || *p == '.')) {
+    if (*p == '9') *p = '0';
+    --p;
+  }
+
+  if (p < buffer->begin) {
+    *p = '1';
+    buffer->begin = p;
+    if (mode == FormatStyle::Precision) {
+      std::swap(p[1], p[2]);  // move the .
+      ++*exp;
+      buffer->pop_back();
+    }
+  } else {
+    ++*p;
+  }
+}
+
+void PrintExponent(int exp, char e, Buffer *out) {
+  out->push_back(e);
+  if (exp < 0) {
+    out->push_back('-');
+    exp = -exp;
+  } else {
+    out->push_back('+');
+  }
+  // Exponent digits.
+  if (exp > 99) {
+    out->push_back(exp / 100 + '0');
+    out->push_back(exp / 10 % 10 + '0');
+    out->push_back(exp % 10 + '0');
+  } else {
+    out->push_back(exp / 10 + '0');
+    out->push_back(exp % 10 + '0');
+  }
+}
+
+template <typename Float, typename Int>
+constexpr bool CanFitMantissa() {
+  return std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits;
+}
+
+template <typename Float>
+struct Decomposed {
+  Float mantissa;
+  int exponent;
+};
+
+// Decompose the double into an integer mantissa and an exponent.
+template <typename Float>
+Decomposed<Float> Decompose(Float v) {
+  int exp;
+  Float m = std::frexp(v, &exp);
+  m = std::ldexp(m, std::numeric_limits<Float>::digits);
+  exp -= std::numeric_limits<Float>::digits;
+  return {m, exp};
+}
+
+// Print 'digits' as decimal.
+// In Fixed mode, we add a '.' at the end.
+// In Precision mode, we add a '.' after the first digit.
+template <FormatStyle mode, typename Int>
+int PrintIntegralDigits(Int digits, Buffer *out) {
+  int printed = 0;
+  if (digits) {
+    for (; digits; digits /= 10) out->push_front(digits % 10 + '0');
+    printed = out->size();
+    if (mode == FormatStyle::Precision) {
+      out->push_front(*out->begin);
+      out->begin[1] = '.';
+    } else {
+      out->push_back('.');
+    }
+  } else if (mode == FormatStyle::Fixed) {
+    out->push_front('0');
+    out->push_back('.');
+    printed = 1;
+  }
+  return printed;
+}
+
+// Back out 'extra_digits' digits and round up if necessary.
+bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value,
+                          Buffer *out, int *exp_out) {
+  if (extra_digits <= 0) return false;
+
+  // Back out the extra digits
+  out->end -= extra_digits;
+
+  bool needs_to_round_up = [&] {
+    // We look at the digit just past the end.
+    // There must be 'extra_digits' extra valid digits after end.
+    if (*out->end > '5') return true;
+    if (*out->end < '5') return false;
+    if (has_leftover_value || std::any_of(out->end + 1, out->end + extra_digits,
+                                          [](char c) { return c != '0'; }))
+      return true;
+
+    // Ends in ...50*, round to even.
+    return out->last_digit() % 2 == 1;
+  }();
+
+  if (needs_to_round_up) {
+    RoundUp<FormatStyle::Precision>(out, exp_out);
+  }
+  return true;
+}
+
+// Print the value into the buffer.
+// This will not include the exponent, which will be returned in 'exp_out' for
+// Precision mode.
+template <typename Int, typename Float, FormatStyle mode>
+bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
+                       int *exp_out) {
+  assert((CanFitMantissa<Float, Int>()));
+
+  const int int_bits = std::numeric_limits<Int>::digits;
+
+  // In precision mode, we start printing one char to the right because it will
+  // also include the '.'
+  // In fixed mode we put the dot afterwards on the right.
+  out->begin = out->end =
+      out->data + 1 + kMaxFixedPrecision + (mode == FormatStyle::Precision);
+
+  if (exp >= 0) {
+    if (std::numeric_limits<Float>::digits + exp > int_bits) {
+      // The value will overflow the Int
+      return false;
+    }
+    int digits_printed = PrintIntegralDigits<mode>(int_mantissa << exp, out);
+    int digits_to_zero_pad = precision;
+    if (mode == FormatStyle::Precision) {
+      *exp_out = digits_printed - 1;
+      digits_to_zero_pad -= digits_printed - 1;
+      if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) {
+        return true;
+      }
+    }
+    for (; digits_to_zero_pad-- > 0;) out->push_back('0');
+    return true;
+  }
+
+  exp = -exp;
+  // We need at least 4 empty bits for the next decimal digit.
+  // We will multiply by 10.
+  if (exp > int_bits - 4) return false;
+
+  const Int mask = (Int{1} << exp) - 1;
+
+  // Print the integral part first.
+  int digits_printed = PrintIntegralDigits<mode>(int_mantissa >> exp, out);
+  int_mantissa &= mask;
+
+  int fractional_count = precision;
+  if (mode == FormatStyle::Precision) {
+    if (digits_printed == 0) {
+      // Find the first non-zero digit, when in Precision mode.
+      *exp_out = 0;
+      if (int_mantissa) {
+        while (int_mantissa <= mask) {
+          int_mantissa *= 10;
+          --*exp_out;
+        }
+      }
+      out->push_front(static_cast<char>(int_mantissa >> exp) + '0');
+      out->push_back('.');
+      int_mantissa &= mask;
+    } else {
+      // We already have a digit, and a '.'
+      *exp_out = digits_printed - 1;
+      fractional_count -= *exp_out;
+      if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out,
+                               exp_out)) {
+        // If we had enough digits, return right away.
+        // The code below will try to round again otherwise.
+        return true;
+      }
+    }
+  }
+
+  auto get_next_digit = [&] {
+    int_mantissa *= 10;
+    int digit = static_cast<int>(int_mantissa >> exp);
+    int_mantissa &= mask;
+    return digit;
+  };
+
+  // Print fractional_count more digits, if available.
+  for (; fractional_count > 0; --fractional_count) {
+    out->push_back(get_next_digit() + '0');
+  }
+
+  int next_digit = get_next_digit();
+  if (next_digit > 5 ||
+      (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) {
+    RoundUp<mode>(out, exp_out);
+  }
+
+  return true;
+}
+
+template <FormatStyle mode, typename Float>
+bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
+                   int *exp) {
+  if (precision > kMaxFixedPrecision) return false;
+
+  // Try with uint64_t.
+  if (CanFitMantissa<Float, std::uint64_t>() &&
+      FloatToBufferImpl<std::uint64_t, Float, mode>(
+          static_cast<std::uint64_t>(decomposed.mantissa),
+          static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp))
+    return true;
+
+#if defined(__SIZEOF_INT128__)
+  // If that is not enough, try with __uint128_t.
+  return CanFitMantissa<Float, __uint128_t>() &&
+         FloatToBufferImpl<__uint128_t, Float, mode>(
+             static_cast<__uint128_t>(decomposed.mantissa),
+             static_cast<__uint128_t>(decomposed.exponent), precision, out,
+             exp);
+#endif
+  return false;
+}
+
+void WriteBufferToSink(char sign_char, string_view str,
+                       const ConversionSpec &conv, FormatSinkImpl *sink) {
+  int left_spaces = 0, zeros = 0, right_spaces = 0;
+  int missing_chars =
+      conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
+                                       static_cast<int>(sign_char != 0),
+                                   0)
+                        : 0;
+  if (conv.flags().left) {
+    right_spaces = missing_chars;
+  } else if (conv.flags().zero) {
+    zeros = missing_chars;
+  } else {
+    left_spaces = missing_chars;
+  }
+
+  sink->Append(left_spaces, ' ');
+  if (sign_char) sink->Append(1, sign_char);
+  sink->Append(zeros, '0');
+  sink->Append(str);
+  sink->Append(right_spaces, ' ');
+}
+
+template <typename Float>
+bool FloatToSink(const Float v, const ConversionSpec &conv,
+                 FormatSinkImpl *sink) {
+  // Print the sign or the sign column.
+  Float abs_v = v;
+  char sign_char = 0;
+  if (std::signbit(abs_v)) {
+    sign_char = '-';
+    abs_v = -abs_v;
+  } else if (conv.flags().show_pos) {
+    sign_char = '+';
+  } else if (conv.flags().sign_col) {
+    sign_char = ' ';
+  }
+
+  // Print nan/inf.
+  if (ConvertNonNumericFloats(sign_char, abs_v, conv, sink)) {
+    return true;
+  }
+
+  int precision = conv.precision() < 0 ? 6 : conv.precision();
+
+  int exp = 0;
+
+  auto decomposed = Decompose(abs_v);
+
+  Buffer buffer;
+
+  switch (conv.conv().id()) {
+    case ConversionChar::f:
+    case ConversionChar::F:
+      if (!FloatToBuffer<FormatStyle::Fixed>(decomposed, precision, &buffer,
+                                             nullptr)) {
+        return FallbackToSnprintf(v, conv, sink);
+      }
+      if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
+      break;
+
+    case ConversionChar::e:
+    case ConversionChar::E:
+      if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                                 &exp)) {
+        return FallbackToSnprintf(v, conv, sink);
+      }
+      if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
+      PrintExponent(exp, conv.conv().upper() ? 'E' : 'e', &buffer);
+      break;
+
+    case ConversionChar::g:
+    case ConversionChar::G:
+      precision = std::max(0, precision - 1);
+      if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                                 &exp)) {
+        return FallbackToSnprintf(v, conv, sink);
+      }
+      if (precision + 1 > exp && exp >= -4) {
+        if (exp < 0) {
+          // Have 1.23456, needs 0.00123456
+          // Move the first digit
+          buffer.begin[1] = *buffer.begin;
+          // Add some zeros
+          for (; exp < -1; ++exp) *buffer.begin-- = '0';
+          *buffer.begin-- = '.';
+          *buffer.begin = '0';
+        } else if (exp > 0) {
+          // Have 1.23456, needs 1234.56
+          // Move the '.' exp positions to the right.
+          std::rotate(buffer.begin + 1, buffer.begin + 2,
+                      buffer.begin + exp + 2);
+        }
+        exp = 0;
+      }
+      if (!conv.flags().alt) {
+        while (buffer.back() == '0') buffer.pop_back();
+        if (buffer.back() == '.') buffer.pop_back();
+      }
+      if (exp) PrintExponent(exp, conv.conv().upper() ? 'E' : 'e', &buffer);
+      break;
+
+    case ConversionChar::a:
+    case ConversionChar::A:
+      return FallbackToSnprintf(v, conv, sink);
+
+    default:
+      return false;
+  }
+
+  WriteBufferToSink(sign_char,
+                    string_view(buffer.begin, buffer.end - buffer.begin), conv,
+                    sink);
+
+  return true;
+}
+
+}  // namespace
+
+bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+                      FormatSinkImpl *sink) {
+  return FloatToSink(v, conv, sink);
+}
+
+bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+                      FormatSinkImpl *sink) {
+  return FloatToSink(v, conv, sink);
+}
+
+bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+                      FormatSinkImpl *sink) {
+  return FloatToSink(v, conv, sink);
+}
+
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/float_conversion.h b/absl/strings/internal/str_format/float_conversion.h
new file mode 100644
index 0000000..8ba5566
--- /dev/null
+++ b/absl/strings/internal/str_format/float_conversion.h
@@ -0,0 +1,21 @@
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
+
+#include "absl/strings/internal/str_format/extension.h"
+
+namespace absl {
+namespace str_format_internal {
+
+bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+                      FormatSinkImpl *sink);
+
+bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+                      FormatSinkImpl *sink);
+
+bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+                      FormatSinkImpl *sink);
+
+}  // namespace str_format_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc
new file mode 100644
index 0000000..5c3795b
--- /dev/null
+++ b/absl/strings/internal/str_format/output.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/str_format/output.h"
+
+#include <errno.h>
+#include <cstring>
+
+namespace absl {
+namespace str_format_internal {
+
+void BufferRawSink::Write(string_view v) {
+  size_t to_write = std::min(v.size(), size_);
+  std::memcpy(buffer_, v.data(), to_write);
+  buffer_ += to_write;
+  size_ -= to_write;
+  total_written_ += v.size();
+}
+
+void FILERawSink::Write(string_view v) {
+  while (!v.empty() && !error_) {
+    if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) {
+      // Some progress was made.
+      count_ += result;
+      v.remove_prefix(result);
+    } else {
+      // Some error occurred.
+      if (errno != EINTR) {
+        error_ = errno;
+      }
+    }
+  }
+}
+
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h
new file mode 100644
index 0000000..3b0aa5e
--- /dev/null
+++ b/absl/strings/internal/str_format/output.h
@@ -0,0 +1,101 @@
+// Copyright 2017 The Abseil 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.
+//
+// Output extension hooks for the Format library.
+// `internal::InvokeFlush` calls the appropriate flush function for the
+// specified output argument.
+// `BufferRawSink` is a simple output sink for a char buffer. Used by SnprintF.
+// `FILERawSink` is a std::FILE* based sink. Used by PrintF and FprintF.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
+
+#include <cstdio>
+#include <ostream>
+#include <string>
+
+#include "absl/base/port.h"
+#include "absl/strings/string_view.h"
+
+class Cord;
+
+namespace absl {
+namespace str_format_internal {
+
+// RawSink implementation that writes into a char* buffer.
+// It will not overflow the buffer, but will keep the total count of chars
+// that would have been written.
+class BufferRawSink {
+ public:
+  BufferRawSink(char* buffer, size_t size) : buffer_(buffer), size_(size) {}
+
+  size_t total_written() const { return total_written_; }
+  void Write(string_view v);
+
+ private:
+  char* buffer_;
+  size_t size_;
+  size_t total_written_ = 0;
+};
+
+// RawSink implementation that writes into a FILE*.
+// It keeps track of the total number of bytes written and any error encountered
+// during the writes.
+class FILERawSink {
+ public:
+  explicit FILERawSink(std::FILE* output) : output_(output) {}
+
+  void Write(string_view v);
+
+  size_t count() const { return count_; }
+  int error() const { return error_; }
+
+ private:
+  std::FILE* output_;
+  int error_ = 0;
+  size_t count_ = 0;
+};
+
+// Provide RawSink integration with common types from the STL.
+inline void AbslFormatFlush(std::string* out, string_view s) {
+  out->append(s.begin(), s.size());
+}
+inline void AbslFormatFlush(std::ostream* out, string_view s) {
+  out->write(s.begin(), s.size());
+}
+
+template <class AbslCord, typename = typename std::enable_if<
+                              std::is_same<AbslCord, ::Cord>::value>::type>
+inline void AbslFormatFlush(AbslCord* out, string_view s) {
+  out->Append(s);
+}
+
+inline void AbslFormatFlush(FILERawSink* sink, string_view v) {
+  sink->Write(v);
+}
+
+inline void AbslFormatFlush(BufferRawSink* sink, string_view v) {
+  sink->Write(v);
+}
+
+template <typename T>
+auto InvokeFlush(T* out, string_view s)
+    -> decltype(str_format_internal::AbslFormatFlush(out, s)) {
+  str_format_internal::AbslFormatFlush(out, s);
+}
+
+}  // namespace str_format_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc
new file mode 100644
index 0000000..cc3c615
--- /dev/null
+++ b/absl/strings/internal/str_format/output_test.cc
@@ -0,0 +1,78 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/str_format/output.h"
+
+#include <sstream>
+#include <string>
+
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace {
+
+TEST(InvokeFlush, String) {
+  std::string str = "ABC";
+  str_format_internal::InvokeFlush(&str, "DEF");
+  EXPECT_EQ(str, "ABCDEF");
+
+#if UTIL_FORMAT_HAS_GLOBAL_STRING
+  std::string str2 = "ABC";
+  str_format_internal::InvokeFlush(&str2, "DEF");
+  EXPECT_EQ(str2, "ABCDEF");
+#endif  // UTIL_FORMAT_HAS_GLOBAL_STRING
+}
+
+TEST(InvokeFlush, Stream) {
+  std::stringstream str;
+  str << "ABC";
+  str_format_internal::InvokeFlush(&str, "DEF");
+  EXPECT_EQ(str.str(), "ABCDEF");
+}
+
+TEST(BufferRawSink, Limits) {
+  char buf[16];
+  {
+    std::fill(std::begin(buf), std::end(buf), 'x');
+    str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1);
+    str_format_internal::InvokeFlush(&bufsink, "Hello World237");
+    EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World237xx");
+  }
+  {
+    std::fill(std::begin(buf), std::end(buf), 'x');
+    str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1);
+    str_format_internal::InvokeFlush(&bufsink, "Hello World237237");
+    EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World2372x");
+  }
+  {
+    std::fill(std::begin(buf), std::end(buf), 'x');
+    str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1);
+    str_format_internal::InvokeFlush(&bufsink, "Hello World");
+    str_format_internal::InvokeFlush(&bufsink, "237");
+    EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World237xx");
+  }
+  {
+    std::fill(std::begin(buf), std::end(buf), 'x');
+    str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1);
+    str_format_internal::InvokeFlush(&bufsink, "Hello World");
+    str_format_internal::InvokeFlush(&bufsink, "237237");
+    EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World2372x");
+  }
+}
+
+}  // namespace
+}  // namespace absl
+
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc
new file mode 100644
index 0000000..10114f4
--- /dev/null
+++ b/absl/strings/internal/str_format/parser.cc
@@ -0,0 +1,294 @@
+#include "absl/strings/internal/str_format/parser.h"
+
+#include <assert.h>
+#include <string.h>
+#include <wchar.h>
+#include <cctype>
+#include <cstdint>
+
+#include <algorithm>
+#include <initializer_list>
+#include <limits>
+#include <ostream>
+#include <string>
+#include <unordered_set>
+
+namespace absl {
+namespace str_format_internal {
+namespace {
+
+bool CheckFastPathSetting(const UnboundConversion& conv) {
+  bool should_be_basic = !conv.flags.left &&      //
+                         !conv.flags.show_pos &&  //
+                         !conv.flags.sign_col &&  //
+                         !conv.flags.alt &&       //
+                         !conv.flags.zero &&      //
+                         (conv.width.value() == -1) &&
+                         (conv.precision.value() == -1);
+  if (should_be_basic != conv.flags.basic) {
+    fprintf(stderr,
+            "basic=%d left=%d show_pos=%d sign_col=%d alt=%d zero=%d "
+            "width=%d precision=%d\n",
+            conv.flags.basic, conv.flags.left, conv.flags.show_pos,
+            conv.flags.sign_col, conv.flags.alt, conv.flags.zero,
+            conv.width.value(), conv.precision.value());
+  }
+  return should_be_basic == conv.flags.basic;
+}
+
+// Keep a single table for all the conversion chars and length modifiers.
+// We invert the length modifiers to make them negative so that we can easily
+// test for them.
+// Everything else is `none`, which is a negative constant.
+using CC = ConversionChar::Id;
+using LM = LengthMod::Id;
+static constexpr std::int8_t none = -128;
+static constexpr std::int8_t kIds[] = {
+    none,   none,   none,   none,  none,   none,  none,  none,   // 00-07
+    none,   none,   none,   none,  none,   none,  none,  none,   // 08-0f
+    none,   none,   none,   none,  none,   none,  none,  none,   // 10-17
+    none,   none,   none,   none,  none,   none,  none,  none,   // 18-1f
+    none,   none,   none,   none,  none,   none,  none,  none,   // 20-27
+    none,   none,   none,   none,  none,   none,  none,  none,   // 28-2f
+    none,   none,   none,   none,  none,   none,  none,  none,   // 30-37
+    none,   none,   none,   none,  none,   none,  none,  none,   // 38-3f
+    none,   CC::A,  none,   CC::C, none,   CC::E, CC::F, CC::G,  // @ABCDEFG
+    none,   none,   none,   none,  ~LM::L, none,  none,  none,   // HIJKLMNO
+    none,   none,   none,   CC::S, none,   none,  none,  none,   // PQRSTUVW
+    CC::X,  none,   none,   none,  none,   none,  none,  none,   // XYZ[\]^_
+    none,   CC::a,  none,   CC::c, CC::d,  CC::e, CC::f, CC::g,  // `abcdefg
+    ~LM::h, CC::i,  ~LM::j, none,  ~LM::l, none,  CC::n, CC::o,  // hijklmno
+    CC::p,  ~LM::q, none,   CC::s, ~LM::t, CC::u, none,  none,   // pqrstuvw
+    CC::x,  none,   ~LM::z, none,  none,   none,  none,  none,   // xyz{|}~!
+    none,   none,   none,   none,  none,   none,  none,  none,   // 80-87
+    none,   none,   none,   none,  none,   none,  none,  none,   // 88-8f
+    none,   none,   none,   none,  none,   none,  none,  none,   // 90-97
+    none,   none,   none,   none,  none,   none,  none,  none,   // 98-9f
+    none,   none,   none,   none,  none,   none,  none,  none,   // a0-a7
+    none,   none,   none,   none,  none,   none,  none,  none,   // a8-af
+    none,   none,   none,   none,  none,   none,  none,  none,   // b0-b7
+    none,   none,   none,   none,  none,   none,  none,  none,   // b8-bf
+    none,   none,   none,   none,  none,   none,  none,  none,   // c0-c7
+    none,   none,   none,   none,  none,   none,  none,  none,   // c8-cf
+    none,   none,   none,   none,  none,   none,  none,  none,   // d0-d7
+    none,   none,   none,   none,  none,   none,  none,  none,   // d8-df
+    none,   none,   none,   none,  none,   none,  none,  none,   // e0-e7
+    none,   none,   none,   none,  none,   none,  none,  none,   // e8-ef
+    none,   none,   none,   none,  none,   none,  none,  none,   // f0-f7
+    none,   none,   none,   none,  none,   none,  none,  none,   // f8-ff
+};
+
+template <bool is_positional>
+bool ConsumeConversion(string_view *src, UnboundConversion *conv,
+                       int *next_arg) {
+  const char *pos = src->begin();
+  const char *const end = src->end();
+  char c;
+  // Read the next char into `c` and update `pos`. Reads '\0' if at end.
+  const auto get_char = [&] { c = pos == end ? '\0' : *pos++; };
+
+  const auto parse_digits = [&] {
+    int digits = c - '0';
+    // We do not want to overflow `digits` so we consume at most digits10-1
+    // digits. If there are more digits the parsing will fail later on when the
+    // digit doesn't match the expected characters.
+    int num_digits = std::numeric_limits<int>::digits10 - 2;
+    for (get_char(); num_digits && std::isdigit(c); get_char()) {
+      --num_digits;
+      digits = 10 * digits + c - '0';
+    }
+    return digits;
+  };
+
+  if (is_positional) {
+    get_char();
+    if (c < '1' || c > '9') return false;
+    conv->arg_position = parse_digits();
+    assert(conv->arg_position > 0);
+    if (c != '$') return false;
+  }
+
+  get_char();
+
+  // We should start with the basic flag on.
+  assert(conv->flags.basic);
+
+  // Any non alpha character makes this conversion not basic.
+  // This includes flags (-+ #0), width (1-9, *) or precision (.).
+  // All conversion characters and length modifiers are alpha characters.
+  if (c < 'A') {
+    conv->flags.basic = false;
+
+    for (; c <= '0'; get_char()) {
+      switch (c) {
+        case '-':
+          conv->flags.left = true;
+          continue;
+        case '+':
+          conv->flags.show_pos = true;
+          continue;
+        case ' ':
+          conv->flags.sign_col = true;
+          continue;
+        case '#':
+          conv->flags.alt = true;
+          continue;
+        case '0':
+          conv->flags.zero = true;
+          continue;
+      }
+      break;
+    }
+
+    if (c <= '9') {
+      if (c >= '0') {
+        int maybe_width = parse_digits();
+        if (!is_positional && c == '$') {
+          if (*next_arg != 0) return false;
+          // Positional conversion.
+          *next_arg = -1;
+          conv->flags = Flags();
+          conv->flags.basic = true;
+          return ConsumeConversion<true>(src, conv, next_arg);
+        }
+        conv->width.set_value(maybe_width);
+      } else if (c == '*') {
+        get_char();
+        if (is_positional) {
+          if (c < '1' || c > '9') return false;
+          conv->width.set_from_arg(parse_digits());
+          if (c != '$') return false;
+          get_char();
+        } else {
+          conv->width.set_from_arg(++*next_arg);
+        }
+      }
+    }
+
+    if (c == '.') {
+      get_char();
+      if (std::isdigit(c)) {
+        conv->precision.set_value(parse_digits());
+      } else if (c == '*') {
+        get_char();
+        if (is_positional) {
+          if (c < '1' || c > '9') return false;
+          conv->precision.set_from_arg(parse_digits());
+          if (c != '$') return false;
+          get_char();
+        } else {
+          conv->precision.set_from_arg(++*next_arg);
+        }
+      } else {
+        conv->precision.set_value(0);
+      }
+    }
+  }
+
+  std::int8_t id = kIds[static_cast<unsigned char>(c)];
+
+  if (id < 0) {
+    if (id == none) return false;
+
+    // It is a length modifier.
+    using str_format_internal::LengthMod;
+    LengthMod length_mod = LengthMod::FromId(static_cast<LM>(~id));
+    get_char();
+    if (c == 'h' && length_mod.id() == LengthMod::h) {
+      conv->length_mod = LengthMod::FromId(LengthMod::hh);
+      get_char();
+    } else if (c == 'l' && length_mod.id() == LengthMod::l) {
+      conv->length_mod = LengthMod::FromId(LengthMod::ll);
+      get_char();
+    } else {
+      conv->length_mod = length_mod;
+    }
+    id = kIds[static_cast<unsigned char>(c)];
+    if (id < 0) return false;
+  }
+
+  assert(CheckFastPathSetting(*conv));
+  (void)(&CheckFastPathSetting);
+
+  conv->conv = ConversionChar::FromId(static_cast<CC>(id));
+  if (!is_positional) conv->arg_position = ++*next_arg;
+  *src = string_view(pos, end - pos);
+  return true;
+}
+
+}  // namespace
+
+bool ConsumeUnboundConversion(string_view *src, UnboundConversion *conv,
+                              int *next_arg) {
+  if (*next_arg < 0) return ConsumeConversion<true>(src, conv, next_arg);
+  return ConsumeConversion<false>(src, conv, next_arg);
+}
+
+struct ParsedFormatBase::ParsedFormatConsumer {
+  explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat)
+      : parsed(parsedformat), data_pos(parsedformat->data_.get()) {}
+
+  bool Append(string_view s) {
+    if (s.empty()) return true;
+
+    size_t text_end = AppendText(s);
+
+    if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) {
+      // Let's extend the existing text run.
+      parsed->items_.back().text_end = text_end;
+    } else {
+      // Let's make a new text run.
+      parsed->items_.push_back({false, text_end, {}});
+    }
+    return true;
+  }
+
+  bool ConvertOne(const UnboundConversion &conv, string_view s) {
+    size_t text_end = AppendText(s);
+    parsed->items_.push_back({true, text_end, conv});
+    return true;
+  }
+
+  size_t AppendText(string_view s) {
+    memcpy(data_pos, s.data(), s.size());
+    data_pos += s.size();
+    return static_cast<size_t>(data_pos - parsed->data_.get());
+  }
+
+  ParsedFormatBase *parsed;
+  char* data_pos;
+};
+
+ParsedFormatBase::ParsedFormatBase(string_view format, bool allow_ignored,
+                                   std::initializer_list<Conv> convs)
+    : data_(format.empty() ? nullptr : new char[format.size()]) {
+  has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
+               !MatchesConversions(allow_ignored, convs);
+}
+
+bool ParsedFormatBase::MatchesConversions(
+    bool allow_ignored, std::initializer_list<Conv> convs) const {
+  std::unordered_set<int> used;
+  auto add_if_valid_conv = [&](int pos, char c) {
+      if (static_cast<size_t>(pos) > convs.size() ||
+          !Contains(convs.begin()[pos - 1], c))
+        return false;
+      used.insert(pos);
+      return true;
+  };
+  for (const ConversionItem &item : items_) {
+    if (!item.is_conversion) continue;
+    auto &conv = item.conv;
+    if (conv.precision.is_from_arg() &&
+        !add_if_valid_conv(conv.precision.get_from_arg(), '*'))
+      return false;
+    if (conv.width.is_from_arg() &&
+        !add_if_valid_conv(conv.width.get_from_arg(), '*'))
+      return false;
+    if (!add_if_valid_conv(conv.arg_position, conv.conv.Char())) return false;
+  }
+  return used.size() == convs.size() || allow_ignored;
+}
+
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h
new file mode 100644
index 0000000..5bebc95
--- /dev/null
+++ b/absl/strings/internal/str_format/parser.h
@@ -0,0 +1,291 @@
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <cassert>
+#include <initializer_list>
+#include <iosfwd>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "absl/strings/internal/str_format/checker.h"
+#include "absl/strings/internal/str_format/extension.h"
+
+namespace absl {
+namespace str_format_internal {
+
+// The analyzed properties of a single specified conversion.
+struct UnboundConversion {
+  UnboundConversion()
+      : flags() /* This is required to zero all the fields of flags. */ {
+    flags.basic = true;
+  }
+
+  class InputValue {
+   public:
+    void set_value(int value) {
+      assert(value >= 0);
+      value_ = value;
+    }
+    int value() const { return value_; }
+
+    // Marks the value as "from arg". aka the '*' format.
+    // Requires `value >= 1`.
+    // When set, is_from_arg() return true and get_from_arg() returns the
+    // original value.
+    // `value()`'s return value is unspecfied in this state.
+    void set_from_arg(int value) {
+      assert(value > 0);
+      value_ = -value - 1;
+    }
+    bool is_from_arg() const { return value_ < -1; }
+    int get_from_arg() const {
+      assert(is_from_arg());
+      return -value_ - 1;
+    }
+
+   private:
+    int value_ = -1;
+  };
+
+  // No need to initialize. It will always be set in the parser.
+  int arg_position;
+
+  InputValue width;
+  InputValue precision;
+
+  Flags flags;
+  LengthMod length_mod;
+  ConversionChar conv;
+};
+
+// Consume conversion spec prefix (not including '%') of '*src' if valid.
+// Examples of valid specs would be e.g.: "s", "d", "-12.6f".
+// If valid, the front of src is advanced such that src becomes the
+// part following the conversion spec, and the spec part is broken down and
+// returned in 'conv'.
+// If invalid, returns false and leaves 'src' unmodified.
+// For example:
+//   Given "d9", returns "d", and leaves src="9",
+//   Given "!", returns "" and leaves src="!".
+bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv,
+                              int* next_arg);
+
+// Parse the format std::string provided in 'src' and pass the identified items into
+// 'consumer'.
+// Text runs will be passed by calling
+//   Consumer::Append(string_view);
+// ConversionItems will be passed by calling
+//   Consumer::ConvertOne(UnboundConversion, string_view);
+// In the case of ConvertOne, the string_view that is passed is the
+// portion of the format std::string corresponding to the conversion, not including
+// the leading %. On success, it returns true. On failure, it stops and returns
+// false.
+template <typename Consumer>
+bool ParseFormatString(string_view src, Consumer consumer) {
+  int next_arg = 0;
+  while (!src.empty()) {
+    const char* percent =
+        static_cast<const char*>(memchr(src.begin(), '%', src.size()));
+    if (!percent) {
+      // We found the last substring.
+      return consumer.Append(src);
+    }
+    // We found a percent, so push the text run then process the percent.
+    size_t percent_loc = percent - src.data();
+    if (!consumer.Append(string_view(src.data(), percent_loc))) return false;
+    if (percent + 1 >= src.end()) return false;
+
+    UnboundConversion conv;
+
+    switch (percent[1]) {
+      case '%':
+        if (!consumer.Append("%")) return false;
+        src.remove_prefix(percent_loc + 2);
+        continue;
+
+#define PARSER_CASE(ch)                                     \
+  case #ch[0]:                                              \
+    src.remove_prefix(percent_loc + 2);                     \
+    conv.conv = ConversionChar::FromId(ConversionChar::ch); \
+    conv.arg_position = ++next_arg;                         \
+    break;
+        ABSL_CONVERSION_CHARS_EXPAND_(PARSER_CASE, );
+#undef PARSER_CASE
+
+      default:
+        src.remove_prefix(percent_loc + 1);
+        if (!ConsumeUnboundConversion(&src, &conv, &next_arg)) return false;
+        break;
+    }
+    if (next_arg == 0) {
+      // This indicates an error in the format std::string.
+      // The only way to get next_arg == 0 is to have a positional argument
+      // first which sets next_arg to -1 and then a non-positional argument
+      // which does ++next_arg.
+      // Checking here seems to be the cheapeast place to do it.
+      return false;
+    }
+    if (!consumer.ConvertOne(
+            conv, string_view(percent + 1, src.data() - (percent + 1)))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Always returns true, or fails to compile in a constexpr context if s does not
+// point to a constexpr char array.
+constexpr bool EnsureConstexpr(string_view s) {
+  return s.empty() || s[0] == s[0];
+}
+
+class ParsedFormatBase {
+ public:
+  explicit ParsedFormatBase(string_view format, bool allow_ignored,
+                            std::initializer_list<Conv> convs);
+
+  ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
+
+  ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); }
+
+  ParsedFormatBase& operator=(const ParsedFormatBase& other) {
+    if (this == &other) return *this;
+    has_error_ = other.has_error_;
+    items_ = other.items_;
+    size_t text_size = items_.empty() ? 0 : items_.back().text_end;
+    data_.reset(new char[text_size]);
+    memcpy(data_.get(), other.data_.get(), text_size);
+    return *this;
+  }
+
+  ParsedFormatBase& operator=(ParsedFormatBase&& other) {
+    if (this == &other) return *this;
+    has_error_ = other.has_error_;
+    data_ = std::move(other.data_);
+    items_ = std::move(other.items_);
+    // Reset the vector to make sure the invariants hold.
+    other.items_.clear();
+    return *this;
+  }
+
+  template <typename Consumer>
+  bool ProcessFormat(Consumer consumer) const {
+    const char* const base = data_.get();
+    string_view text(base, 0);
+    for (const auto& item : items_) {
+      text = string_view(text.end(), (base + item.text_end) - text.end());
+      if (item.is_conversion) {
+        if (!consumer.ConvertOne(item.conv, text)) return false;
+      } else {
+        if (!consumer.Append(text)) return false;
+      }
+    }
+    return !has_error_;
+  }
+
+  bool has_error() const { return has_error_; }
+
+ private:
+  // Returns whether the conversions match and if !allow_ignored it verifies
+  // that all conversions are used by the format.
+  bool MatchesConversions(bool allow_ignored,
+                          std::initializer_list<Conv> convs) const;
+
+  struct ParsedFormatConsumer;
+
+  struct ConversionItem {
+    bool is_conversion;
+    // Points to the past-the-end location of this element in the data_ array.
+    size_t text_end;
+    UnboundConversion conv;
+  };
+
+  bool has_error_;
+  std::unique_ptr<char[]> data_;
+  std::vector<ConversionItem> items_;
+};
+
+
+// A value type representing a preparsed format.  These can be created, copied
+// around, and reused to speed up formatting loops.
+// The user must specify through the template arguments the conversion
+// characters used in the format. This will be checked at compile time.
+//
+// This class uses Conv enum values to specify each argument.
+// This allows for more flexibility as you can specify multiple possible
+// conversion characters for each argument.
+// ParsedFormat<char...> is a simplified alias for when the user only
+// needs to specify a single conversion character for each argument.
+//
+// Example:
+//   // Extended format supports multiple characters per argument:
+//   using MyFormat = ExtendedParsedFormat<Conv::d | Conv::x>;
+//   MyFormat GetFormat(bool use_hex) {
+//     if (use_hex) return MyFormat("foo %x bar");
+//     return MyFormat("foo %d bar");
+//   }
+//   // 'format' can be used with any value that supports 'd' and 'x',
+//   // like `int`.
+//   auto format = GetFormat(use_hex);
+//   value = StringF(format, i);
+//
+// This class also supports runtime format checking with the ::New() and
+// ::NewAllowIgnored() factory functions.
+// This is the only API that allows the user to pass a runtime specified format
+// std::string. These factory functions will return NULL if the format does not match
+// the conversions requested by the user.
+template <str_format_internal::Conv... C>
+class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
+ public:
+  explicit ExtendedParsedFormat(string_view format)
+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+      __attribute__((
+          enable_if(str_format_internal::EnsureConstexpr(format),
+                    "Format std::string is not constexpr."),
+          enable_if(str_format_internal::ValidFormatImpl<C...>(format),
+                    "Format specified does not match the template arguments.")))
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+      : ExtendedParsedFormat(format, false) {
+  }
+
+  // ExtendedParsedFormat factory function.
+  // The user still has to specify the conversion characters, but they will not
+  // be checked at compile time. Instead, it will be checked at runtime.
+  // This delays the checking to runtime, but allows the user to pass
+  // dynamically sourced formats.
+  // It returns NULL if the format does not match the conversion characters.
+  // The user is responsible for checking the return value before using it.
+  //
+  // The 'New' variant will check that all the specified arguments are being
+  // consumed by the format and return NULL if any argument is being ignored.
+  // The 'NewAllowIgnored' variant will not verify this and will allow formats
+  // that ignore arguments.
+  static std::unique_ptr<ExtendedParsedFormat> New(string_view format) {
+    return New(format, false);
+  }
+  static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored(
+      string_view format) {
+    return New(format, true);
+  }
+
+ private:
+  static std::unique_ptr<ExtendedParsedFormat> New(string_view format,
+                                                   bool allow_ignored) {
+    std::unique_ptr<ExtendedParsedFormat> conv(
+        new ExtendedParsedFormat(format, allow_ignored));
+    if (conv->has_error()) return nullptr;
+    return conv;
+  }
+
+  ExtendedParsedFormat(string_view s, bool allow_ignored)
+      : ParsedFormatBase(s, allow_ignored, {C...}) {}
+};
+}  // namespace str_format_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc
new file mode 100644
index 0000000..e698020
--- /dev/null
+++ b/absl/strings/internal/str_format/parser_test.cc
@@ -0,0 +1,379 @@
+#include "absl/strings/internal/str_format/parser.h"
+
+#include <string.h>
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+namespace str_format_internal {
+
+namespace {
+
+TEST(LengthModTest, Names) {
+  struct Expectation {
+    int line;
+    LengthMod::Id id;
+    const char *name;
+  };
+  const Expectation kExpect[] = {
+    {__LINE__, LengthMod::none, ""  },
+    {__LINE__, LengthMod::h,    "h" },
+    {__LINE__, LengthMod::hh,   "hh"},
+    {__LINE__, LengthMod::l,    "l" },
+    {__LINE__, LengthMod::ll,   "ll"},
+    {__LINE__, LengthMod::L,    "L" },
+    {__LINE__, LengthMod::j,    "j" },
+    {__LINE__, LengthMod::z,    "z" },
+    {__LINE__, LengthMod::t,    "t" },
+    {__LINE__, LengthMod::q,    "q" },
+  };
+  EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), LengthMod::kNumValues);
+  for (auto e : kExpect) {
+    SCOPED_TRACE(e.line);
+    LengthMod mod = LengthMod::FromId(e.id);
+    EXPECT_EQ(e.id, mod.id());
+    EXPECT_EQ(e.name, mod.name());
+  }
+}
+
+TEST(ConversionCharTest, Names) {
+  struct Expectation {
+    ConversionChar::Id id;
+    char name;
+  };
+  // clang-format off
+  const Expectation kExpect[] = {
+#define X(c) {ConversionChar::c, #c[0]}
+    X(c), X(C), X(s), X(S),                          // text
+    X(d), X(i), X(o), X(u), X(x), X(X),              // int
+    X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A),  // float
+    X(n), X(p),                                      // misc
+#undef X
+    {ConversionChar::none, '\0'},
+  };
+  // clang-format on
+  EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), ConversionChar::kNumValues);
+  for (auto e : kExpect) {
+    SCOPED_TRACE(e.name);
+    ConversionChar v = ConversionChar::FromId(e.id);
+    EXPECT_EQ(e.id, v.id());
+    EXPECT_EQ(e.name, v.Char());
+  }
+}
+
+class ConsumeUnboundConversionTest : public ::testing::Test {
+ public:
+  typedef UnboundConversion Props;
+  string_view Consume(string_view* src) {
+    int next = 0;
+    const char* prev_begin = src->begin();
+    o = UnboundConversion();  // refresh
+    ConsumeUnboundConversion(src, &o, &next);
+    return {prev_begin, static_cast<size_t>(src->begin() - prev_begin)};
+  }
+
+  bool Run(const char *fmt, bool force_positional = false) {
+    string_view src = fmt;
+    int next = force_positional ? -1 : 0;
+    o = UnboundConversion();  // refresh
+    return ConsumeUnboundConversion(&src, &o, &next) && src.empty();
+  }
+  UnboundConversion o;
+};
+
+TEST_F(ConsumeUnboundConversionTest, ConsumeSpecification) {
+  struct Expectation {
+    int line;
+    const char *src;
+    const char *out;
+    const char *src_post;
+  };
+  const Expectation kExpect[] = {
+    {__LINE__, "",     "",     ""  },
+    {__LINE__, "b",    "",     "b" },  // 'b' is invalid
+    {__LINE__, "ba",   "",     "ba"},  // 'b' is invalid
+    {__LINE__, "l",    "",     "l" },  // just length mod isn't okay
+    {__LINE__, "d",    "d",    ""  },  // basic
+    {__LINE__, "d ",   "d",    " " },  // leave suffix
+    {__LINE__, "dd",   "d",    "d" },  // don't be greedy
+    {__LINE__, "d9",   "d",    "9" },  // leave non-space suffix
+    {__LINE__, "dzz",  "d",    "zz"},  // length mod as suffix
+    {__LINE__, "1$*2$d", "1$*2$d", ""  },  // arg indexing and * allowed.
+    {__LINE__, "0-14.3hhd", "0-14.3hhd", ""},  // precision, width
+    {__LINE__, " 0-+#14.3hhd", " 0-+#14.3hhd", ""},  // flags
+  };
+  for (const auto& e : kExpect) {
+    SCOPED_TRACE(e.line);
+    string_view src = e.src;
+    EXPECT_EQ(e.src, src);
+    string_view out = Consume(&src);
+    EXPECT_EQ(e.out, out);
+    EXPECT_EQ(e.src_post, src);
+  }
+}
+
+TEST_F(ConsumeUnboundConversionTest, BasicConversion) {
+  EXPECT_FALSE(Run(""));
+  EXPECT_FALSE(Run("z"));
+
+  EXPECT_FALSE(Run("dd"));  // no excess allowed
+
+  EXPECT_TRUE(Run("d"));
+  EXPECT_EQ('d', o.conv.Char());
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_LT(o.width.value(), 0);
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_LT(o.precision.value(), 0);
+  EXPECT_EQ(1, o.arg_position);
+  EXPECT_EQ(LengthMod::none, o.length_mod.id());
+}
+
+TEST_F(ConsumeUnboundConversionTest, ArgPosition) {
+  EXPECT_TRUE(Run("d"));
+  EXPECT_EQ(1, o.arg_position);
+  EXPECT_TRUE(Run("3$d"));
+  EXPECT_EQ(3, o.arg_position);
+  EXPECT_TRUE(Run("1$d"));
+  EXPECT_EQ(1, o.arg_position);
+  EXPECT_TRUE(Run("1$d", true));
+  EXPECT_EQ(1, o.arg_position);
+  EXPECT_TRUE(Run("123$d"));
+  EXPECT_EQ(123, o.arg_position);
+  EXPECT_TRUE(Run("123$d", true));
+  EXPECT_EQ(123, o.arg_position);
+  EXPECT_TRUE(Run("10$d"));
+  EXPECT_EQ(10, o.arg_position);
+  EXPECT_TRUE(Run("10$d", true));
+  EXPECT_EQ(10, o.arg_position);
+
+  // Position can't be zero.
+  EXPECT_FALSE(Run("0$d"));
+  EXPECT_FALSE(Run("0$d", true));
+  EXPECT_FALSE(Run("1$*0$d"));
+  EXPECT_FALSE(Run("1$.*0$d"));
+
+  // Position can't start with a zero digit at all. That is not a 'decimal'.
+  EXPECT_FALSE(Run("01$p"));
+  EXPECT_FALSE(Run("01$p", true));
+  EXPECT_FALSE(Run("1$*01$p"));
+  EXPECT_FALSE(Run("1$.*01$p"));
+}
+
+TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) {
+  EXPECT_TRUE(Run("14d"));
+  EXPECT_EQ('d', o.conv.Char());
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_EQ(14, o.width.value());
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_LT(o.precision.value(), 0);
+
+  EXPECT_TRUE(Run("14.d"));
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_EQ(14, o.width.value());
+  EXPECT_EQ(0, o.precision.value());
+
+  EXPECT_TRUE(Run(".d"));
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_LT(o.width.value(), 0);
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_EQ(0, o.precision.value());
+
+  EXPECT_TRUE(Run(".5d"));
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_LT(o.width.value(), 0);
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_EQ(5, o.precision.value());
+
+  EXPECT_TRUE(Run(".0d"));
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_LT(o.width.value(), 0);
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_EQ(0, o.precision.value());
+
+  EXPECT_TRUE(Run("14.5d"));
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_EQ(14, o.width.value());
+  EXPECT_EQ(5, o.precision.value());
+
+  EXPECT_TRUE(Run("*.*d"));
+  EXPECT_TRUE(o.width.is_from_arg());
+  EXPECT_EQ(1, o.width.get_from_arg());
+  EXPECT_TRUE(o.precision.is_from_arg());
+  EXPECT_EQ(2, o.precision.get_from_arg());
+  EXPECT_EQ(3, o.arg_position);
+
+  EXPECT_TRUE(Run("*d"));
+  EXPECT_TRUE(o.width.is_from_arg());
+  EXPECT_EQ(1, o.width.get_from_arg());
+  EXPECT_FALSE(o.precision.is_from_arg());
+  EXPECT_LT(o.precision.value(), 0);
+  EXPECT_EQ(2, o.arg_position);
+
+  EXPECT_TRUE(Run(".*d"));
+  EXPECT_FALSE(o.width.is_from_arg());
+  EXPECT_LT(o.width.value(), 0);
+  EXPECT_TRUE(o.precision.is_from_arg());
+  EXPECT_EQ(1, o.precision.get_from_arg());
+  EXPECT_EQ(2, o.arg_position);
+
+  // mixed implicit and explicit: didn't specify arg position.
+  EXPECT_FALSE(Run("*23$.*34$d"));
+
+  EXPECT_TRUE(Run("12$*23$.*34$d"));
+  EXPECT_EQ(12, o.arg_position);
+  EXPECT_TRUE(o.width.is_from_arg());
+  EXPECT_EQ(23, o.width.get_from_arg());
+  EXPECT_TRUE(o.precision.is_from_arg());
+  EXPECT_EQ(34, o.precision.get_from_arg());
+
+  EXPECT_TRUE(Run("2$*5$.*9$d"));
+  EXPECT_EQ(2, o.arg_position);
+  EXPECT_TRUE(o.width.is_from_arg());
+  EXPECT_EQ(5, o.width.get_from_arg());
+  EXPECT_TRUE(o.precision.is_from_arg());
+  EXPECT_EQ(9, o.precision.get_from_arg());
+
+  EXPECT_FALSE(Run(".*0$d")) << "no arg 0";
+}
+
+TEST_F(ConsumeUnboundConversionTest, Flags) {
+  static const char kAllFlags[] = "-+ #0";
+  static const int kNumFlags = ABSL_ARRAYSIZE(kAllFlags) - 1;
+  for (int rev = 0; rev < 2; ++rev) {
+    for (int i = 0; i < 1 << kNumFlags; ++i) {
+      std::string fmt;
+      for (int k = 0; k < kNumFlags; ++k)
+        if ((i >> k) & 1) fmt += kAllFlags[k];
+      // flag order shouldn't matter
+      if (rev == 1) { std::reverse(fmt.begin(), fmt.end()); }
+      fmt += 'd';
+      SCOPED_TRACE(fmt);
+      EXPECT_TRUE(Run(fmt.c_str()));
+      EXPECT_EQ(fmt.find('-') == std::string::npos, !o.flags.left);
+      EXPECT_EQ(fmt.find('+') == std::string::npos, !o.flags.show_pos);
+      EXPECT_EQ(fmt.find(' ') == std::string::npos, !o.flags.sign_col);
+      EXPECT_EQ(fmt.find('#') == std::string::npos, !o.flags.alt);
+      EXPECT_EQ(fmt.find('0') == std::string::npos, !o.flags.zero);
+    }
+  }
+}
+
+TEST_F(ConsumeUnboundConversionTest, BasicFlag) {
+  // Flag is on
+  for (const char* fmt : {"d", "llx", "G", "1$X"}) {
+    SCOPED_TRACE(fmt);
+    EXPECT_TRUE(Run(fmt));
+    EXPECT_TRUE(o.flags.basic);
+  }
+
+  // Flag is off
+  for (const char* fmt : {"3d", ".llx", "-G", "1$#X"}) {
+    SCOPED_TRACE(fmt);
+    EXPECT_TRUE(Run(fmt));
+    EXPECT_FALSE(o.flags.basic);
+  }
+}
+
+struct SummarizeConsumer {
+  std::string* out;
+  explicit SummarizeConsumer(std::string* out) : out(out) {}
+
+  bool Append(string_view s) {
+    *out += "[" + std::string(s) + "]";
+    return true;
+  }
+
+  bool ConvertOne(const UnboundConversion& conv, string_view s) {
+    *out += "{";
+    *out += std::string(s);
+    *out += ":";
+    *out += std::to_string(conv.arg_position) + "$";
+    if (conv.width.is_from_arg()) {
+      *out += std::to_string(conv.width.get_from_arg()) + "$*";
+    }
+    if (conv.precision.is_from_arg()) {
+      *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
+    }
+    *out += conv.conv.Char();
+    *out += "}";
+    return true;
+  }
+};
+
+std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
+  std::string out;
+  if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
+  return out;
+}
+
+class ParsedFormatTest : public testing::Test {};
+
+TEST_F(ParsedFormatTest, ValueSemantics) {
+  ParsedFormatBase p1({}, true, {});  // empty format
+  EXPECT_EQ("", SummarizeParsedFormat(p1));
+
+  ParsedFormatBase p2 = p1;  // copy construct (empty)
+  EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
+
+  p1 = ParsedFormatBase("hello%s", true, {Conv::s});  // move assign
+  EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
+
+  ParsedFormatBase p3 = p1;  // copy construct (nonempty)
+  EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p3));
+
+  using std::swap;
+  swap(p1, p2);
+  EXPECT_EQ("", SummarizeParsedFormat(p1));
+  EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p2));
+  swap(p1, p2);  // undo
+
+  p2 = p1;  // copy assign
+  EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
+}
+
+struct ExpectParse {
+  const char* in;
+  std::initializer_list<Conv> conv_set;
+  const char* out;
+};
+
+TEST_F(ParsedFormatTest, Parsing) {
+  // Parse should be equivalent to that obtained by ConversionParseIterator.
+  // No need to retest the parsing edge cases here.
+  const ExpectParse kExpect[] = {
+      {"", {}, ""},
+      {"ab", {}, "[ab]"},
+      {"a%d", {Conv::d}, "[a]{d:1$d}"},
+      {"a%+d", {Conv::d}, "[a]{+d:1$d}"},
+      {"a% d", {Conv::d}, "[a]{ d:1$d}"},
+      {"a%b %d", {}, "[a]!"},  // stop after error
+  };
+  for (const auto& e : kExpect) {
+    SCOPED_TRACE(e.in);
+    EXPECT_EQ(e.out,
+              SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set)));
+  }
+}
+
+TEST_F(ParsedFormatTest, ParsingFlagOrder) {
+  const ExpectParse kExpect[] = {
+      {"a%+ 0d", {Conv::d}, "[a]{+ 0d:1$d}"},
+      {"a%+0 d", {Conv::d}, "[a]{+0 d:1$d}"},
+      {"a%0+ d", {Conv::d}, "[a]{0+ d:1$d}"},
+      {"a% +0d", {Conv::d}, "[a]{ +0d:1$d}"},
+      {"a%0 +d", {Conv::d}, "[a]{0 +d:1$d}"},
+      {"a% 0+d", {Conv::d}, "[a]{ 0+d:1$d}"},
+      {"a%+   0+d", {Conv::d}, "[a]{+   0+d:1$d}"},
+  };
+  for (const auto& e : kExpect) {
+    SCOPED_TRACE(e.in);
+    EXPECT_EQ(e.out,
+              SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set)));
+  }
+}
+
+}  // namespace
+}  // namespace str_format_internal
+}  // namespace absl
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
new file mode 100644
index 0000000..a734758
--- /dev/null
+++ b/absl/strings/internal/str_join_internal.h
@@ -0,0 +1,311 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+
+// This file declares INTERNAL parts of the Join API that are inlined/templated
+// or otherwise need to be available at compile time. The main abstractions
+// defined in this file are:
+//
+//   - A handful of default Formatters
+//   - JoinAlgorithm() overloads
+//   - JoinRange() overloads
+//   - JoinTuple()
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_join.h
+//
+// IWYU pragma: private, include "absl/strings/str_join.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
+
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/strings/internal/ostringstream.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+namespace strings_internal {
+
+//
+// Formatter objects
+//
+// The following are implementation classes for standard Formatter objects. The
+// factory functions that users will call to create and use these formatters are
+// defined and documented in strings/join.h.
+//
+
+// The default formatter. Converts alpha-numeric types to strings.
+struct AlphaNumFormatterImpl {
+  // This template is needed in order to support passing in a dereferenced
+  // vector<bool>::iterator
+  template <typename T>
+  void operator()(std::string* out, const T& t) const {
+    StrAppend(out, AlphaNum(t));
+  }
+
+  void operator()(std::string* out, const AlphaNum& t) const {
+    StrAppend(out, t);
+  }
+};
+
+// A type that's used to overload the JoinAlgorithm() function (defined below)
+// for ranges that do not require additional formatting (e.g., a range of
+// strings).
+
+struct NoFormatter : public AlphaNumFormatterImpl {};
+
+// Formats types to strings using the << operator.
+class StreamFormatterImpl {
+ public:
+  // The method isn't const because it mutates state. Making it const will
+  // render StreamFormatterImpl thread-hostile.
+  template <typename T>
+  void operator()(std::string* out, const T& t) {
+    // The stream is created lazily to avoid paying the relatively high cost
+    // of its construction when joining an empty range.
+    if (strm_) {
+      strm_->clear();  // clear the bad, fail and eof bits in case they were set
+      strm_->str(out);
+    } else {
+      strm_.reset(new strings_internal::OStringStream(out));
+    }
+    *strm_ << t;
+  }
+
+ private:
+  std::unique_ptr<strings_internal::OStringStream> strm_;
+};
+
+// Formats a std::pair<>. The 'first' member is formatted using f1_ and the
+// 'second' member is formatted using f2_. sep_ is the separator.
+template <typename F1, typename F2>
+class PairFormatterImpl {
+ public:
+  PairFormatterImpl(F1 f1, absl::string_view sep, F2 f2)
+      : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {}
+
+  template <typename T>
+  void operator()(std::string* out, const T& p) {
+    f1_(out, p.first);
+    out->append(sep_);
+    f2_(out, p.second);
+  }
+
+  template <typename T>
+  void operator()(std::string* out, const T& p) const {
+    f1_(out, p.first);
+    out->append(sep_);
+    f2_(out, p.second);
+  }
+
+ private:
+  F1 f1_;
+  std::string sep_;
+  F2 f2_;
+};
+
+// Wraps another formatter and dereferences the argument to operator() then
+// passes the dereferenced argument to the wrapped formatter. This can be
+// useful, for example, to join a std::vector<int*>.
+template <typename Formatter>
+class DereferenceFormatterImpl {
+ public:
+  DereferenceFormatterImpl() : f_() {}
+  explicit DereferenceFormatterImpl(Formatter&& f)
+      : f_(std::forward<Formatter>(f)) {}
+
+  template <typename T>
+  void operator()(std::string* out, const T& t) {
+    f_(out, *t);
+  }
+
+  template <typename T>
+  void operator()(std::string* out, const T& t) const {
+    f_(out, *t);
+  }
+
+ private:
+  Formatter f_;
+};
+
+// DefaultFormatter<T> is a traits class that selects a default Formatter to use
+// for the given type T. The ::Type member names the Formatter to use. This is
+// used by the strings::Join() functions that do NOT take a Formatter argument,
+// in which case a default Formatter must be chosen.
+//
+// AlphaNumFormatterImpl is the default in the base template, followed by
+// specializations for other types.
+template <typename ValueType>
+struct DefaultFormatter {
+  typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<const char*> {
+  typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<char*> {
+  typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<std::string> {
+  typedef NoFormatter Type;
+};
+template <>
+struct DefaultFormatter<absl::string_view> {
+  typedef NoFormatter Type;
+};
+template <typename ValueType>
+struct DefaultFormatter<ValueType*> {
+  typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type>
+      Type;
+};
+
+template <typename ValueType>
+struct DefaultFormatter<std::unique_ptr<ValueType>>
+    : public DefaultFormatter<ValueType*> {};
+
+//
+// JoinAlgorithm() functions
+//
+
+// The main joining algorithm. This simply joins the elements in the given
+// iterator range, each separated by the given separator, into an output std::string,
+// and formats each element using the provided Formatter object.
+template <typename Iterator, typename Formatter>
+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
+                     Formatter&& f) {
+  std::string result;
+  absl::string_view sep("");
+  for (Iterator it = start; it != end; ++it) {
+    result.append(sep.data(), sep.size());
+    f(&result, *it);
+    sep = s;
+  }
+  return result;
+}
+
+// A joining algorithm that's optimized for a forward iterator range of
+// std::string-like objects that do not need any additional formatting. This is to
+// optimize the common case of joining, say, a std::vector<std::string> or a
+// std::vector<absl::string_view>.
+//
+// This is an overload of the previous JoinAlgorithm() function. Here the
+// Formatter argument is of type NoFormatter. Since NoFormatter is an internal
+// type, this overload is only invoked when strings::Join() is called with a
+// range of std::string-like objects (e.g., std::string, absl::string_view), and an
+// explicit Formatter argument was NOT specified.
+//
+// The optimization is that the needed space will be reserved in the output
+// std::string to avoid the need to resize while appending. To do this, the iterator
+// range will be traversed twice: once to calculate the total needed size, and
+// then again to copy the elements and delimiters to the output std::string.
+template <typename Iterator,
+          typename = typename std::enable_if<std::is_convertible<
+              typename std::iterator_traits<Iterator>::iterator_category,
+              std::forward_iterator_tag>::value>::type>
+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
+                     NoFormatter) {
+  std::string result;
+  if (start != end) {
+    // Sums size
+    size_t result_size = start->size();
+    for (Iterator it = start; ++it != end;) {
+      result_size += s.size();
+      result_size += it->size();
+    }
+
+    if (result_size > 0) {
+      STLStringResizeUninitialized(&result, result_size);
+
+      // Joins strings
+      char* result_buf = &*result.begin();
+      memcpy(result_buf, start->data(), start->size());
+      result_buf += start->size();
+      for (Iterator it = start; ++it != end;) {
+        memcpy(result_buf, s.data(), s.size());
+        result_buf += s.size();
+        memcpy(result_buf, it->data(), it->size());
+        result_buf += it->size();
+      }
+    }
+  }
+
+  return result;
+}
+
+// JoinTupleLoop implements a loop over the elements of a std::tuple, which
+// are heterogeneous. The primary template matches the tuple interior case. It
+// continues the iteration after appending a separator (for nonzero indices)
+// and formatting an element of the tuple. The specialization for the I=N case
+// matches the end-of-tuple, and terminates the iteration.
+template <size_t I, size_t N>
+struct JoinTupleLoop {
+  template <typename Tup, typename Formatter>
+  void operator()(std::string* out, const Tup& tup, absl::string_view sep,
+                  Formatter&& fmt) {
+    if (I > 0) out->append(sep.data(), sep.size());
+    fmt(out, std::get<I>(tup));
+    JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt);
+  }
+};
+template <size_t N>
+struct JoinTupleLoop<N, N> {
+  template <typename Tup, typename Formatter>
+  void operator()(std::string*, const Tup&, absl::string_view, Formatter&&) {}
+};
+
+template <typename... T, typename Formatter>
+std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep,
+                     Formatter&& fmt) {
+  std::string result;
+  JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt);
+  return result;
+}
+
+template <typename Iterator>
+std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) {
+  // No formatter was explicitly given, so a default must be chosen.
+  typedef typename std::iterator_traits<Iterator>::value_type ValueType;
+  typedef typename DefaultFormatter<ValueType>::Type Formatter;
+  return JoinAlgorithm(first, last, separator, Formatter());
+}
+
+template <typename Range, typename Formatter>
+std::string JoinRange(const Range& range, absl::string_view separator,
+                 Formatter&& fmt) {
+  using std::begin;
+  using std::end;
+  return JoinAlgorithm(begin(range), end(range), separator, fmt);
+}
+
+template <typename Range>
+std::string JoinRange(const Range& range, absl::string_view separator) {
+  using std::begin;
+  using std::end;
+  return JoinRange(begin(range), end(range), separator);
+}
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
new file mode 100644
index 0000000..9cf0833
--- /dev/null
+++ b/absl/strings/internal/str_split_internal.h
@@ -0,0 +1,453 @@
+// Copyright 2017 The Abseil 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.
+//
+
+// This file declares INTERNAL parts of the Split API that are inline/templated
+// or otherwise need to be available at compile time. The main abstractions
+// defined in here are
+//
+//   - ConvertibleToStringView
+//   - SplitIterator<>
+//   - Splitter<>
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_split.h.
+//
+// IWYU pragma: private, include "absl/strings/str_split.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
+
+#include <array>
+#include <initializer_list>
+#include <iterator>
+#include <map>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+#ifdef _GLIBCXX_DEBUG
+#include "absl/strings/internal/stl_type_traits.h"
+#endif  // _GLIBCXX_DEBUG
+
+namespace absl {
+namespace strings_internal {
+
+// This class is implicitly constructible from everything that absl::string_view
+// is implicitly constructible from. If it's constructed from a temporary
+// std::string, the data is moved into a data member so its lifetime matches that of
+// the ConvertibleToStringView instance.
+class ConvertibleToStringView {
+ public:
+  ConvertibleToStringView(const char* s)  // NOLINT(runtime/explicit)
+      : value_(s) {}
+  ConvertibleToStringView(char* s) : value_(s) {}  // NOLINT(runtime/explicit)
+  ConvertibleToStringView(absl::string_view s)     // NOLINT(runtime/explicit)
+      : value_(s) {}
+  ConvertibleToStringView(const std::string& s)  // NOLINT(runtime/explicit)
+      : value_(s) {}
+
+  // Matches rvalue strings and moves their data to a member.
+ConvertibleToStringView(std::string&& s)  // NOLINT(runtime/explicit)
+    : copy_(std::move(s)), value_(copy_) {}
+
+  ConvertibleToStringView(const ConvertibleToStringView& other)
+      : copy_(other.copy_),
+        value_(other.IsSelfReferential() ? copy_ : other.value_) {}
+
+  ConvertibleToStringView(ConvertibleToStringView&& other) {
+    StealMembers(std::move(other));
+  }
+
+  ConvertibleToStringView& operator=(ConvertibleToStringView other) {
+    StealMembers(std::move(other));
+    return *this;
+  }
+
+  absl::string_view value() const { return value_; }
+
+ private:
+  // Returns true if ctsp's value refers to its internal copy_ member.
+  bool IsSelfReferential() const { return value_.data() == copy_.data(); }
+
+  void StealMembers(ConvertibleToStringView&& other) {
+    if (other.IsSelfReferential()) {
+      copy_ = std::move(other.copy_);
+      value_ = copy_;
+      other.value_ = other.copy_;
+    } else {
+      value_ = other.value_;
+    }
+  }
+
+  // Holds the data moved from temporary std::string arguments. Declared first so
+  // that 'value' can refer to 'copy_'.
+  std::string copy_;
+  absl::string_view value_;
+};
+
+// An iterator that enumerates the parts of a std::string from a Splitter. The text
+// to be split, the Delimiter, and the Predicate are all taken from the given
+// Splitter object. Iterators may only be compared if they refer to the same
+// Splitter instance.
+//
+// This class is NOT part of the public splitting API.
+template <typename Splitter>
+class SplitIterator {
+ public:
+  using iterator_category = std::input_iterator_tag;
+  using value_type = absl::string_view;
+  using difference_type = ptrdiff_t;
+  using pointer = const value_type*;
+  using reference = const value_type&;
+
+  enum State { kInitState, kLastState, kEndState };
+  SplitIterator(State state, const Splitter* splitter)
+      : pos_(0),
+        state_(state),
+        splitter_(splitter),
+        delimiter_(splitter->delimiter()),
+        predicate_(splitter->predicate()) {
+    // Hack to maintain backward compatibility. This one block makes it so an
+    // empty absl::string_view whose .data() happens to be nullptr behaves
+    // *differently* from an otherwise empty absl::string_view whose .data() is
+    // not nullptr. This is an undesirable difference in general, but this
+    // behavior is maintained to avoid breaking existing code that happens to
+    // depend on this old behavior/bug. Perhaps it will be fixed one day. The
+    // difference in behavior is as follows:
+    //   Split(absl::string_view(""), '-');  // {""}
+    //   Split(absl::string_view(), '-');    // {}
+    if (splitter_->text().data() == nullptr) {
+      state_ = kEndState;
+      pos_ = splitter_->text().size();
+      return;
+    }
+
+    if (state_ == kEndState) {
+      pos_ = splitter_->text().size();
+    } else {
+      ++(*this);
+    }
+  }
+
+  bool at_end() const { return state_ == kEndState; }
+
+  reference operator*() const { return curr_; }
+  pointer operator->() const { return &curr_; }
+
+  SplitIterator& operator++() {
+    do {
+      if (state_ == kLastState) {
+        state_ = kEndState;
+        return *this;
+      }
+      const absl::string_view text = splitter_->text();
+      const absl::string_view d = delimiter_.Find(text, pos_);
+      if (d.data() == text.end()) state_ = kLastState;
+      curr_ = text.substr(pos_, d.data() - (text.data() + pos_));
+      pos_ += curr_.size() + d.size();
+    } while (!predicate_(curr_));
+    return *this;
+  }
+
+  SplitIterator operator++(int) {
+    SplitIterator old(*this);
+    ++(*this);
+    return old;
+  }
+
+  friend bool operator==(const SplitIterator& a, const SplitIterator& b) {
+    return a.state_ == b.state_ && a.pos_ == b.pos_;
+  }
+
+  friend bool operator!=(const SplitIterator& a, const SplitIterator& b) {
+    return !(a == b);
+  }
+
+ private:
+  size_t pos_;
+  State state_;
+  absl::string_view curr_;
+  const Splitter* splitter_;
+  typename Splitter::DelimiterType delimiter_;
+  typename Splitter::PredicateType predicate_;
+};
+
+// HasMappedType<T>::value is true iff there exists a type T::mapped_type.
+template <typename T, typename = void>
+struct HasMappedType : std::false_type {};
+template <typename T>
+struct HasMappedType<T, absl::void_t<typename T::mapped_type>>
+    : std::true_type {};
+
+// HasValueType<T>::value is true iff there exists a type T::value_type.
+template <typename T, typename = void>
+struct HasValueType : std::false_type {};
+template <typename T>
+struct HasValueType<T, absl::void_t<typename T::value_type>> : std::true_type {
+};
+
+// HasConstIterator<T>::value is true iff there exists a type T::const_iterator.
+template <typename T, typename = void>
+struct HasConstIterator : std::false_type {};
+template <typename T>
+struct HasConstIterator<T, absl::void_t<typename T::const_iterator>>
+    : std::true_type {};
+
+// IsInitializerList<T>::value is true iff T is an std::initializer_list. More
+// details below in Splitter<> where this is used.
+std::false_type IsInitializerListDispatch(...);  // default: No
+template <typename T>
+std::true_type IsInitializerListDispatch(std::initializer_list<T>*);
+template <typename T>
+struct IsInitializerList
+    : decltype(IsInitializerListDispatch(static_cast<T*>(nullptr))) {};
+
+// A SplitterIsConvertibleTo<C>::type alias exists iff the specified condition
+// is true for type 'C'.
+//
+// Restricts conversion to container-like types (by testing for the presence of
+// a const_iterator member type) and also to disable conversion to an
+// std::initializer_list (which also has a const_iterator). Otherwise, code
+// compiled in C++11 will get an error due to ambiguous conversion paths (in
+// C++11 std::vector<T>::operator= is overloaded to take either a std::vector<T>
+// or an std::initializer_list<T>).
+
+template <typename C, bool has_value_type, bool has_mapped_type>
+struct SplitterIsConvertibleToImpl : std::false_type {};
+
+template <typename C>
+struct SplitterIsConvertibleToImpl<C, true, false>
+    : std::is_constructible<typename C::value_type, absl::string_view> {};
+
+template <typename C>
+struct SplitterIsConvertibleToImpl<C, true, true>
+    : absl::conjunction<
+          std::is_constructible<typename C::key_type, absl::string_view>,
+          std::is_constructible<typename C::mapped_type, absl::string_view>> {};
+
+template <typename C>
+struct SplitterIsConvertibleTo
+    : SplitterIsConvertibleToImpl<
+          C,
+#ifdef _GLIBCXX_DEBUG
+          !IsStrictlyBaseOfAndConvertibleToSTLContainer<C>::value &&
+#endif  // _GLIBCXX_DEBUG
+              !IsInitializerList<
+                  typename std::remove_reference<C>::type>::value &&
+              HasValueType<C>::value && HasConstIterator<C>::value,
+          HasMappedType<C>::value> {
+};
+
+// This class implements the range that is returned by absl::StrSplit(). This
+// class has templated conversion operators that allow it to be implicitly
+// converted to a variety of types that the caller may have specified on the
+// left-hand side of an assignment.
+//
+// The main interface for interacting with this class is through its implicit
+// conversion operators. However, this class may also be used like a container
+// in that it has .begin() and .end() member functions. It may also be used
+// within a range-for loop.
+//
+// Output containers can be collections of any type that is constructible from
+// an absl::string_view.
+//
+// An Predicate functor may be supplied. This predicate will be used to filter
+// the split strings: only strings for which the predicate returns true will be
+// kept. A Predicate object is any unary functor that takes an absl::string_view
+// and returns bool.
+template <typename Delimiter, typename Predicate>
+class Splitter {
+ public:
+  using DelimiterType = Delimiter;
+  using PredicateType = Predicate;
+  using const_iterator = strings_internal::SplitIterator<Splitter>;
+  using value_type = typename std::iterator_traits<const_iterator>::value_type;
+
+  Splitter(ConvertibleToStringView input_text, Delimiter d, Predicate p)
+      : text_(std::move(input_text)),
+        delimiter_(std::move(d)),
+        predicate_(std::move(p)) {}
+
+  absl::string_view text() const { return text_.value(); }
+  const Delimiter& delimiter() const { return delimiter_; }
+  const Predicate& predicate() const { return predicate_; }
+
+  // Range functions that iterate the split substrings as absl::string_view
+  // objects. These methods enable a Splitter to be used in a range-based for
+  // loop.
+  const_iterator begin() const { return {const_iterator::kInitState, this}; }
+  const_iterator end() const { return {const_iterator::kEndState, this}; }
+
+  // An implicit conversion operator that is restricted to only those containers
+  // that the splitter is convertible to.
+  template <typename Container,
+            typename = typename std::enable_if<
+                SplitterIsConvertibleTo<Container>::value>::type>
+  operator Container() const {  // NOLINT(runtime/explicit)
+    return ConvertToContainer<Container, typename Container::value_type,
+                              HasMappedType<Container>::value>()(*this);
+  }
+
+  // Returns a pair with its .first and .second members set to the first two
+  // strings returned by the begin() iterator. Either/both of .first and .second
+  // will be constructed with empty strings if the iterator doesn't have a
+  // corresponding value.
+  template <typename First, typename Second>
+  operator std::pair<First, Second>() const {  // NOLINT(runtime/explicit)
+    absl::string_view first, second;
+    auto it = begin();
+    if (it != end()) {
+      first = *it;
+      if (++it != end()) {
+        second = *it;
+      }
+    }
+    return {First(first), Second(second)};
+  }
+
+ private:
+  // ConvertToContainer is a functor converting a Splitter to the requested
+  // Container of ValueType. It is specialized below to optimize splitting to
+  // certain combinations of Container and ValueType.
+  //
+  // This base template handles the generic case of storing the split results in
+  // the requested non-map-like container and converting the split substrings to
+  // the requested type.
+  template <typename Container, typename ValueType, bool is_map = false>
+  struct ConvertToContainer {
+    Container operator()(const Splitter& splitter) const {
+      Container c;
+      auto it = std::inserter(c, c.end());
+      for (const auto sp : splitter) {
+        *it++ = ValueType(sp);
+      }
+      return c;
+    }
+  };
+
+  // Partial specialization for a std::vector<absl::string_view>.
+  //
+  // Optimized for the common case of splitting to a
+  // std::vector<absl::string_view>. In this case we first split the results to
+  // a small array of absl::string_view on the stack, to reduce reallocations.
+  template <typename A>
+  struct ConvertToContainer<std::vector<absl::string_view, A>,
+                            absl::string_view, false> {
+    std::vector<absl::string_view, A> operator()(
+        const Splitter& splitter) const {
+      struct raw_view {
+        const char* data;
+        size_t size;
+        operator absl::string_view() const {  // NOLINT(runtime/explicit)
+          return {data, size};
+        }
+      };
+      std::vector<absl::string_view, A> v;
+      std::array<raw_view, 16> ar;
+      for (auto it = splitter.begin(); !it.at_end();) {
+        size_t index = 0;
+        do {
+          ar[index].data = it->data();
+          ar[index].size = it->size();
+          ++it;
+        } while (++index != ar.size() && !it.at_end());
+        v.insert(v.end(), ar.begin(), ar.begin() + index);
+      }
+      return v;
+    }
+  };
+
+  // Partial specialization for a std::vector<std::string>.
+  //
+  // Optimized for the common case of splitting to a std::vector<std::string>. In
+  // this case we first split the results to a std::vector<absl::string_view> so
+  // the returned std::vector<std::string> can have space reserved to avoid std::string
+  // moves.
+  template <typename A>
+  struct ConvertToContainer<std::vector<std::string, A>, std::string, false> {
+    std::vector<std::string, A> operator()(const Splitter& splitter) const {
+      const std::vector<absl::string_view> v = splitter;
+      return std::vector<std::string, A>(v.begin(), v.end());
+    }
+  };
+
+  // Partial specialization for containers of pairs (e.g., maps).
+  //
+  // The algorithm is to insert a new pair into the map for each even-numbered
+  // item, with the even-numbered item as the key with a default-constructed
+  // value. Each odd-numbered item will then be assigned to the last pair's
+  // value.
+  template <typename Container, typename First, typename Second>
+  struct ConvertToContainer<Container, std::pair<const First, Second>, true> {
+    Container operator()(const Splitter& splitter) const {
+      Container m;
+      typename Container::iterator it;
+      bool insert = true;
+      for (const auto sp : splitter) {
+        if (insert) {
+          it = Inserter<Container>::Insert(&m, First(sp), Second());
+        } else {
+          it->second = Second(sp);
+        }
+        insert = !insert;
+      }
+      return m;
+    }
+
+    // Inserts the key and value into the given map, returning an iterator to
+    // the inserted item. Specialized for std::map and std::multimap to use
+    // emplace() and adapt emplace()'s return value.
+    template <typename Map>
+    struct Inserter {
+      using M = Map;
+      template <typename... Args>
+      static typename M::iterator Insert(M* m, Args&&... args) {
+        return m->insert(std::make_pair(std::forward<Args>(args)...)).first;
+      }
+    };
+
+    template <typename... Ts>
+    struct Inserter<std::map<Ts...>> {
+      using M = std::map<Ts...>;
+      template <typename... Args>
+      static typename M::iterator Insert(M* m, Args&&... args) {
+        return m->emplace(std::make_pair(std::forward<Args>(args)...)).first;
+      }
+    };
+
+    template <typename... Ts>
+    struct Inserter<std::multimap<Ts...>> {
+      using M = std::multimap<Ts...>;
+      template <typename... Args>
+      static typename M::iterator Insert(M* m, Args&&... args) {
+        return m->emplace(std::make_pair(std::forward<Args>(args)...));
+      }
+    };
+  };
+
+  ConvertibleToStringView text_;
+  Delimiter delimiter_;
+  Predicate predicate_;
+};
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc
new file mode 100644
index 0000000..2415c2c
--- /dev/null
+++ b/absl/strings/internal/utf8.cc
@@ -0,0 +1,51 @@
+// Copyright 2017 The Abseil 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.
+
+// UTF8 utilities, implemented to reduce dependencies.
+
+#include "absl/strings/internal/utf8.h"
+
+namespace absl {
+namespace strings_internal {
+
+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
+  if (utf8_char <= 0x7F) {
+    *buffer = static_cast<char>(utf8_char);
+    return 1;
+  } else if (utf8_char <= 0x7FF) {
+    buffer[1] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[0] = 0xC0 | utf8_char;
+    return 2;
+  } else if (utf8_char <= 0xFFFF) {
+    buffer[2] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[1] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[0] = 0xE0 | utf8_char;
+    return 3;
+  } else {
+    buffer[3] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[2] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[1] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[0] = 0xF0 | utf8_char;
+    return 4;
+  }
+}
+
+}  // namespace strings_internal
+}  // namespace absl
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h
new file mode 100644
index 0000000..d2c3c0b
--- /dev/null
+++ b/absl/strings/internal/utf8.h
@@ -0,0 +1,47 @@
+// Copyright 2017 The Abseil 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.
+//
+// UTF8 utilities, implemented to reduce dependencies.
+//
+
+#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_
+#define ABSL_STRINGS_INTERNAL_UTF8_H_
+
+#include <cstddef>
+#include <cstdint>
+
+namespace absl {
+namespace strings_internal {
+
+// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes
+// out the UTF-8 encoding into buffer, and returns the number of chars
+// it wrote.
+//
+// As described in https://tools.ietf.org/html/rfc3629#section-3 , the encodings
+// are:
+//    00 -     7F : 0xxxxxxx
+//    80 -    7FF : 110xxxxx 10xxxxxx
+//   800 -   FFFF : 1110xxxx 10xxxxxx 10xxxxxx
+// 10000 - 10FFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+//
+// Values greater than 0x10FFFF are not supported and may or may not write
+// characters into buffer, however never will more than kMaxEncodedUTF8Size
+// bytes be written, regardless of the value of utf8_char.
+enum { kMaxEncodedUTF8Size = 4 };
+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char);
+
+}  // namespace strings_internal
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc
new file mode 100644
index 0000000..64cec70
--- /dev/null
+++ b/absl/strings/internal/utf8_test.cc
@@ -0,0 +1,57 @@
+// Copyright 2017 The Abseil 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 "absl/strings/internal/utf8.h"
+
+#include <cstdint>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/port.h"
+
+namespace {
+
+TEST(EncodeUTF8Char, BasicFunction) {
+  std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"},
+                                         {0x00A3, u8"\u00A3"},
+                                         {0x00010000, u8"\U00010000"},
+                                         {0x0000FFFF, u8"\U0000FFFF"},
+                                         {0x0010FFFD, u8"\U0010FFFD"}};
+  for (auto &test : tests) {
+    char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
+    char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
+    char *buf0_written =
+        &buf0[absl::strings_internal::EncodeUTF8Char(buf0, test.first)];
+    char *buf1_written =
+        &buf1[absl::strings_internal::EncodeUTF8Char(buf1, test.first)];
+    int apparent_length = 7;
+    while (buf0[apparent_length - 1] == '\x00' &&
+           buf1[apparent_length - 1] == '\xFF') {
+      if (--apparent_length == 0) break;
+    }
+    EXPECT_EQ(apparent_length, buf0_written - buf0);
+    EXPECT_EQ(apparent_length, buf1_written - buf1);
+    EXPECT_EQ(apparent_length, test.second.length());
+    EXPECT_EQ(std::string(buf0, apparent_length), test.second);
+    EXPECT_EQ(std::string(buf1, apparent_length), test.second);
+  }
+  char buf[32] = "Don't Tread On Me";
+  EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf, 0x00110000),
+            absl::strings_internal::kMaxEncodedUTF8Size);
+  char buf2[32] = "Negative is invalid but sane";
+  EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1),
+            absl::strings_internal::kMaxEncodedUTF8Size);
+}
+
+}  // namespace
diff --git a/absl/strings/match.cc b/absl/strings/match.cc
new file mode 100644
index 0000000..25bd7f0
--- /dev/null
+++ b/absl/strings/match.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Abseil 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 "absl/strings/match.h"
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+
+namespace {
+bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
+  return (piece1.size() == piece2.size() &&
+          0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
+                                            piece1.size()));
+  // memcasecmp uses ascii_tolower().
+}
+}  // namespace
+
+bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) {
+  return (text.size() >= prefix.size()) &&
+         CaseEqual(text.substr(0, prefix.size()), prefix);
+}
+
+bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
+  return (text.size() >= suffix.size()) &&
+         CaseEqual(text.substr(text.size() - suffix.size()), suffix);
+}
+
+}  // namespace absl
diff --git a/absl/strings/match.h b/absl/strings/match.h
new file mode 100644
index 0000000..108b604
--- /dev/null
+++ b/absl/strings/match.h
@@ -0,0 +1,83 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: match.h
+// -----------------------------------------------------------------------------
+//
+// This file contains simple utilities for performing std::string matching checks.
+// All of these function parameters are specified as `absl::string_view`,
+// meaning that these functions can accept `std::string`, `absl::string_view` or
+// nul-terminated C-style strings.
+//
+// Examples:
+//   std::string s = "foo";
+//   absl::string_view sv = "f";
+//   assert(absl::StrContains(s, sv));
+//
+// Note: The order of parameters in these functions is designed to mimic the
+// order an equivalent member function would exhibit;
+// e.g. `s.Contains(x)` ==> `absl::StrContains(s, x).
+#ifndef ABSL_STRINGS_MATCH_H_
+#define ABSL_STRINGS_MATCH_H_
+
+#include <cstring>
+
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// StrContains()
+//
+// Returns whether a given std::string `haystack` contains the substring `needle`.
+inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
+  return haystack.find(needle, 0) != haystack.npos;
+}
+
+// StartsWith()
+//
+// Returns whether a given std::string `text` begins with `prefix`.
+inline bool StartsWith(absl::string_view text, absl::string_view prefix) {
+  return prefix.empty() ||
+         (text.size() >= prefix.size() &&
+          memcmp(text.data(), prefix.data(), prefix.size()) == 0);
+}
+
+// EndsWith()
+//
+// Returns whether a given std::string `text` ends with `suffix`.
+inline bool EndsWith(absl::string_view text, absl::string_view suffix) {
+  return suffix.empty() ||
+         (text.size() >= suffix.size() &&
+          memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
+                 suffix.size()) == 0
+         );
+}
+
+// StartsWithIgnoreCase()
+//
+// Returns whether a given std::string `text` starts with `starts_with`, ignoring
+// case in the comparison.
+bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix);
+
+// EndsWithIgnoreCase()
+//
+// Returns whether a given std::string `text` ends with `ends_with`, ignoring case
+// in the comparison.
+bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix);
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_MATCH_H_
diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc
new file mode 100644
index 0000000..d194f0e
--- /dev/null
+++ b/absl/strings/match_test.cc
@@ -0,0 +1,99 @@
+// Copyright 2017 The Abseil 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 "absl/strings/match.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(MatchTest, StartsWith) {
+  const std::string s1("123" "\0" "456", 7);
+  const absl::string_view a("foobar");
+  const absl::string_view b(s1);
+  const absl::string_view e;
+  EXPECT_TRUE(absl::StartsWith(a, a));
+  EXPECT_TRUE(absl::StartsWith(a, "foo"));
+  EXPECT_TRUE(absl::StartsWith(a, e));
+  EXPECT_TRUE(absl::StartsWith(b, s1));
+  EXPECT_TRUE(absl::StartsWith(b, b));
+  EXPECT_TRUE(absl::StartsWith(b, e));
+  EXPECT_TRUE(absl::StartsWith(e, ""));
+  EXPECT_FALSE(absl::StartsWith(a, b));
+  EXPECT_FALSE(absl::StartsWith(b, a));
+  EXPECT_FALSE(absl::StartsWith(e, a));
+}
+
+TEST(MatchTest, EndsWith) {
+  const std::string s1("123" "\0" "456", 7);
+  const absl::string_view a("foobar");
+  const absl::string_view b(s1);
+  const absl::string_view e;
+  EXPECT_TRUE(absl::EndsWith(a, a));
+  EXPECT_TRUE(absl::EndsWith(a, "bar"));
+  EXPECT_TRUE(absl::EndsWith(a, e));
+  EXPECT_TRUE(absl::EndsWith(b, s1));
+  EXPECT_TRUE(absl::EndsWith(b, b));
+  EXPECT_TRUE(absl::EndsWith(b, e));
+  EXPECT_TRUE(absl::EndsWith(e, ""));
+  EXPECT_FALSE(absl::EndsWith(a, b));
+  EXPECT_FALSE(absl::EndsWith(b, a));
+  EXPECT_FALSE(absl::EndsWith(e, a));
+}
+
+TEST(MatchTest, Contains) {
+  absl::string_view a("abcdefg");
+  absl::string_view b("abcd");
+  absl::string_view c("efg");
+  absl::string_view d("gh");
+  EXPECT_TRUE(absl::StrContains(a, a));
+  EXPECT_TRUE(absl::StrContains(a, b));
+  EXPECT_TRUE(absl::StrContains(a, c));
+  EXPECT_FALSE(absl::StrContains(a, d));
+  EXPECT_TRUE(absl::StrContains("", ""));
+  EXPECT_TRUE(absl::StrContains("abc", ""));
+  EXPECT_FALSE(absl::StrContains("", "a"));
+}
+
+TEST(MatchTest, ContainsNull) {
+  const std::string s = "foo";
+  const char* cs = "foo";
+  const absl::string_view sv("foo");
+  const absl::string_view sv2("foo\0bar", 4);
+  EXPECT_EQ(s, "foo");
+  EXPECT_EQ(sv, "foo");
+  EXPECT_NE(sv2, "foo");
+  EXPECT_TRUE(absl::EndsWith(s, sv));
+  EXPECT_TRUE(absl::StartsWith(cs, sv));
+  EXPECT_TRUE(absl::StrContains(cs, sv));
+  EXPECT_FALSE(absl::StrContains(cs, sv2));
+}
+
+TEST(MatchTest, StartsWithIgnoreCase) {
+  EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "foo"));
+  EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "Fo"));
+  EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", ""));
+  EXPECT_FALSE(absl::StartsWithIgnoreCase("foo", "fooo"));
+  EXPECT_FALSE(absl::StartsWithIgnoreCase("", "fo"));
+}
+
+TEST(MatchTest, EndsWithIgnoreCase) {
+  EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "foo"));
+  EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "Oo"));
+  EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", ""));
+  EXPECT_FALSE(absl::EndsWithIgnoreCase("foo", "fooo"));
+  EXPECT_FALSE(absl::EndsWithIgnoreCase("", "fo"));
+}
+
+}  // namespace
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
new file mode 100644
index 0000000..f842ed8
--- /dev/null
+++ b/absl/strings/numbers.cc
@@ -0,0 +1,912 @@
+// Copyright 2017 The Abseil 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.
+
+// This file contains std::string processing functions related to
+// numeric values.
+
+#include "absl/strings/numbers.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cfloat>          // for DBL_DIG and FLT_DIG
+#include <cmath>           // for HUGE_VAL
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/charconv.h"
+#include "absl/strings/internal/bits.h"
+#include "absl/strings/internal/memutil.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+
+bool SimpleAtof(absl::string_view str, float* value) {
+  *value = 0.0;
+  str = StripAsciiWhitespace(str);
+  if (!str.empty() && str[0] == '+') {
+    str.remove_prefix(1);
+  }
+  auto result = absl::from_chars(str.data(), str.data() + str.size(), *value);
+  if (result.ec == std::errc::invalid_argument) {
+    return false;
+  }
+  if (result.ptr != str.data() + str.size()) {
+    // not all non-whitespace characters consumed
+    return false;
+  }
+  // from_chars() with DR 3801's current wording will return max() on
+  // overflow.  SimpleAtof returns infinity instead.
+  if (result.ec == std::errc::result_out_of_range) {
+    if (*value > 1.0) {
+      *value = std::numeric_limits<float>::infinity();
+    } else if (*value < -1.0) {
+      *value = -std::numeric_limits<float>::infinity();
+    }
+  }
+  return true;
+}
+
+bool SimpleAtod(absl::string_view str, double* value) {
+  *value = 0.0;
+  str = StripAsciiWhitespace(str);
+  if (!str.empty() && str[0] == '+') {
+    str.remove_prefix(1);
+  }
+  auto result = absl::from_chars(str.data(), str.data() + str.size(), *value);
+  if (result.ec == std::errc::invalid_argument) {
+    return false;
+  }
+  if (result.ptr != str.data() + str.size()) {
+    // not all non-whitespace characters consumed
+    return false;
+  }
+  // from_chars() with DR 3801's current wording will return max() on
+  // overflow.  SimpleAtod returns infinity instead.
+  if (result.ec == std::errc::result_out_of_range) {
+    if (*value > 1.0) {
+      *value = std::numeric_limits<double>::infinity();
+    } else if (*value < -1.0) {
+      *value = -std::numeric_limits<double>::infinity();
+    }
+  }
+  return true;
+}
+
+namespace {
+
+// TODO(rogeeff): replace with the real released thing once we figure out what
+// it is.
+inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
+  return (piece1.size() == piece2.size() &&
+          0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
+                                            piece1.size()));
+}
+
+// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
+// range 0 <= i < 100, and buf must have space for two characters. Example:
+//   char buf[2];
+//   PutTwoDigits(42, buf);
+//   // buf[0] == '4'
+//   // buf[1] == '2'
+inline void PutTwoDigits(size_t i, char* buf) {
+  static const char two_ASCII_digits[100][2] = {
+    {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'},
+    {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'},
+    {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'},
+    {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'},
+    {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'},
+    {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
+    {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'},
+    {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'},
+    {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'},
+    {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'},
+    {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'},
+    {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
+    {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'},
+    {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'},
+    {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'},
+    {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'},
+    {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'},
+    {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
+    {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'},
+    {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}
+  };
+  assert(i < 100);
+  memcpy(buf, two_ASCII_digits[i], 2);
+}
+
+}  // namespace
+
+bool SimpleAtob(absl::string_view str, bool* value) {
+  ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr.");
+  if (CaseEqual(str, "true") || CaseEqual(str, "t") ||
+      CaseEqual(str, "yes") || CaseEqual(str, "y") ||
+      CaseEqual(str, "1")) {
+    *value = true;
+    return true;
+  }
+  if (CaseEqual(str, "false") || CaseEqual(str, "f") ||
+      CaseEqual(str, "no") || CaseEqual(str, "n") ||
+      CaseEqual(str, "0")) {
+    *value = false;
+    return true;
+  }
+  return false;
+}
+
+// ----------------------------------------------------------------------
+// FastIntToBuffer() overloads
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer.  The caller is responsible
+// for ensuring that the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the std::string (i.e. the null character
+// terminating the std::string).
+// ----------------------------------------------------------------------
+
+namespace {
+
+// Used to optimize printing a decimal number's final digit.
+const char one_ASCII_final_digits[10][2] {
+  {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0},
+  {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0},
+};
+
+}  // namespace
+
+char* numbers_internal::FastIntToBuffer(uint32_t i, char* buffer) {
+  uint32_t digits;
+  // The idea of this implementation is to trim the number of divides to as few
+  // as possible, and also reducing memory stores and branches, by going in
+  // steps of two digits at a time rather than one whenever possible.
+  // The huge-number case is first, in the hopes that the compiler will output
+  // that case in one branch-free block of code, and only output conditional
+  // branches into it from below.
+  if (i >= 1000000000) {     // >= 1,000,000,000
+    digits = i / 100000000;  //      100,000,000
+    i -= digits * 100000000;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+  lt100_000_000:
+    digits = i / 1000000;  // 1,000,000
+    i -= digits * 1000000;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+  lt1_000_000:
+    digits = i / 10000;  // 10,000
+    i -= digits * 10000;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+  lt10_000:
+    digits = i / 100;
+    i -= digits * 100;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+ lt100:
+    digits = i;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+    *buffer = 0;
+    return buffer;
+  }
+
+  if (i < 100) {
+    digits = i;
+    if (i >= 10) goto lt100;
+    memcpy(buffer, one_ASCII_final_digits[i], 2);
+    return buffer + 1;
+  }
+  if (i < 10000) {  //    10,000
+    if (i >= 1000) goto lt10_000;
+    digits = i / 100;
+    i -= digits * 100;
+    *buffer++ = '0' + digits;
+    goto lt100;
+  }
+  if (i < 1000000) {  //    1,000,000
+    if (i >= 100000) goto lt1_000_000;
+    digits = i / 10000;  //    10,000
+    i -= digits * 10000;
+    *buffer++ = '0' + digits;
+    goto lt10_000;
+  }
+  if (i < 100000000) {  //    100,000,000
+    if (i >= 10000000) goto lt100_000_000;
+    digits = i / 1000000;  //   1,000,000
+    i -= digits * 1000000;
+    *buffer++ = '0' + digits;
+    goto lt1_000_000;
+  }
+  // we already know that i < 1,000,000,000
+  digits = i / 100000000;  //   100,000,000
+  i -= digits * 100000000;
+  *buffer++ = '0' + digits;
+  goto lt100_000_000;
+}
+
+char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) {
+  uint32_t u = i;
+  if (i < 0) {
+    *buffer++ = '-';
+    // We need to do the negation in modular (i.e., "unsigned")
+    // arithmetic; MSVC++ apprently warns for plain "-u", so
+    // we write the equivalent expression "0 - u" instead.
+    u = 0 - u;
+  }
+  return numbers_internal::FastIntToBuffer(u, buffer);
+}
+
+char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) {
+  uint32_t u32 = static_cast<uint32_t>(i);
+  if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer);
+
+  // Here we know i has at least 10 decimal digits.
+  uint64_t top_1to11 = i / 1000000000;
+  u32 = static_cast<uint32_t>(i - top_1to11 * 1000000000);
+  uint32_t top_1to11_32 = static_cast<uint32_t>(top_1to11);
+
+  if (top_1to11_32 == top_1to11) {
+    buffer = numbers_internal::FastIntToBuffer(top_1to11_32, buffer);
+  } else {
+    // top_1to11 has more than 32 bits too; print it in two steps.
+    uint32_t top_8to9 = static_cast<uint32_t>(top_1to11 / 100);
+    uint32_t mid_2 = static_cast<uint32_t>(top_1to11 - top_8to9 * 100);
+    buffer = numbers_internal::FastIntToBuffer(top_8to9, buffer);
+    PutTwoDigits(mid_2, buffer);
+    buffer += 2;
+  }
+
+  // We have only 9 digits now, again the maximum uint32_t can handle fully.
+  uint32_t digits = u32 / 10000000;  // 10,000,000
+  u32 -= digits * 10000000;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  digits = u32 / 100000;  // 100,000
+  u32 -= digits * 100000;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  digits = u32 / 1000;  // 1,000
+  u32 -= digits * 1000;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  digits = u32 / 10;
+  u32 -= digits * 10;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  memcpy(buffer, one_ASCII_final_digits[u32], 2);
+  return buffer + 1;
+}
+
+char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) {
+  uint64_t u = i;
+  if (i < 0) {
+    *buffer++ = '-';
+    u = 0 - u;
+  }
+  return numbers_internal::FastIntToBuffer(u, buffer);
+}
+
+// Given a 128-bit number expressed as a pair of uint64_t, high half first,
+// return that number multiplied by the given 32-bit value.  If the result is
+// too large to fit in a 128-bit number, divide it by 2 until it fits.
+static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num,
+                                           uint32_t mul) {
+  uint64_t bits0_31 = num.second & 0xFFFFFFFF;
+  uint64_t bits32_63 = num.second >> 32;
+  uint64_t bits64_95 = num.first & 0xFFFFFFFF;
+  uint64_t bits96_127 = num.first >> 32;
+
+  // The picture so far: each of these 64-bit values has only the lower 32 bits
+  // filled in.
+  // bits96_127:          [ 00000000 xxxxxxxx ]
+  // bits64_95:                    [ 00000000 xxxxxxxx ]
+  // bits32_63:                             [ 00000000 xxxxxxxx ]
+  // bits0_31:                                       [ 00000000 xxxxxxxx ]
+
+  bits0_31 *= mul;
+  bits32_63 *= mul;
+  bits64_95 *= mul;
+  bits96_127 *= mul;
+
+  // Now the top halves may also have value, though all 64 of their bits will
+  // never be set at the same time, since they are a result of a 32x32 bit
+  // multiply.  This makes the carry calculation slightly easier.
+  // bits96_127:          [ mmmmmmmm | mmmmmmmm ]
+  // bits64_95:                    [ | mmmmmmmm mmmmmmmm | ]
+  // bits32_63:                      |        [ mmmmmmmm | mmmmmmmm ]
+  // bits0_31:                       |                 [ | mmmmmmmm mmmmmmmm ]
+  // eventually:        [ bits128_up | ...bits64_127.... | ..bits0_63... ]
+
+  uint64_t bits0_63 = bits0_31 + (bits32_63 << 32);
+  uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) +
+                        (bits0_63 < bits0_31);
+  uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
+  if (bits128_up == 0) return {bits64_127, bits0_63};
+
+  int shift = 64 - strings_internal::CountLeadingZeros64(bits128_up);
+  uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
+  uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
+  return {hi, lo};
+}
+
+// Compute num * 5 ^ expfive, and return the first 128 bits of the result,
+// where the first bit is always a one.  So PowFive(1, 0) starts 0b100000,
+// PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc.
+static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) {
+  std::pair<uint64_t, uint64_t> result = {num, 0};
+  while (expfive >= 13) {
+    // 5^13 is the highest power of five that will fit in a 32-bit integer.
+    result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5);
+    expfive -= 13;
+  }
+  constexpr int powers_of_five[13] = {
+      1,
+      5,
+      5 * 5,
+      5 * 5 * 5,
+      5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
+  result = Mul32(result, powers_of_five[expfive & 15]);
+  int shift = strings_internal::CountLeadingZeros64(result.first);
+  if (shift != 0) {
+    result.first = (result.first << shift) + (result.second >> (64 - shift));
+    result.second = (result.second << shift);
+  }
+  return result;
+}
+
+struct ExpDigits {
+  int32_t exponent;
+  char digits[6];
+};
+
+// SplitToSix converts value, a positive double-precision floating-point number,
+// into a base-10 exponent and 6 ASCII digits, where the first digit is never
+// zero.  For example, SplitToSix(1) returns an exponent of zero and a digits
+// array of {'1', '0', '0', '0', '0', '0'}.  If value is exactly halfway between
+// two possible representations, e.g. value = 100000.5, then "round to even" is
+// performed.
+static ExpDigits SplitToSix(const double value) {
+  ExpDigits exp_dig;
+  int exp = 5;
+  double d = value;
+  // First step: calculate a close approximation of the output, where the
+  // value d will be between 100,000 and 999,999, representing the digits
+  // in the output ASCII array, and exp is the base-10 exponent.  It would be
+  // faster to use a table here, and to look up the base-2 exponent of value,
+  // however value is an IEEE-754 64-bit number, so the table would have 2,000
+  // entries, which is not cache-friendly.
+  if (d >= 999999.5) {
+    if (d >= 1e+261) exp += 256, d *= 1e-256;
+    if (d >= 1e+133) exp += 128, d *= 1e-128;
+    if (d >= 1e+69) exp += 64, d *= 1e-64;
+    if (d >= 1e+37) exp += 32, d *= 1e-32;
+    if (d >= 1e+21) exp += 16, d *= 1e-16;
+    if (d >= 1e+13) exp += 8, d *= 1e-8;
+    if (d >= 1e+9) exp += 4, d *= 1e-4;
+    if (d >= 1e+7) exp += 2, d *= 1e-2;
+    if (d >= 1e+6) exp += 1, d *= 1e-1;
+  } else {
+    if (d < 1e-250) exp -= 256, d *= 1e256;
+    if (d < 1e-122) exp -= 128, d *= 1e128;
+    if (d < 1e-58) exp -= 64, d *= 1e64;
+    if (d < 1e-26) exp -= 32, d *= 1e32;
+    if (d < 1e-10) exp -= 16, d *= 1e16;
+    if (d < 1e-2) exp -= 8, d *= 1e8;
+    if (d < 1e+2) exp -= 4, d *= 1e4;
+    if (d < 1e+4) exp -= 2, d *= 1e2;
+    if (d < 1e+5) exp -= 1, d *= 1e1;
+  }
+  // At this point, d is in the range [99999.5..999999.5) and exp is in the
+  // range [-324..308]. Since we need to round d up, we want to add a half
+  // and truncate.
+  // However, the technique above may have lost some precision, due to its
+  // repeated multiplication by constants that each may be off by half a bit
+  // of precision.  This only matters if we're close to the edge though.
+  // Since we'd like to know if the fractional part of d is close to a half,
+  // we multiply it by 65536 and see if the fractional part is close to 32768.
+  // (The number doesn't have to be a power of two,but powers of two are faster)
+  uint64_t d64k = d * 65536;
+  int dddddd;  // A 6-digit decimal integer.
+  if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) {
+    // OK, it's fairly likely that precision was lost above, which is
+    // not a surprise given only 52 mantissa bits are available.  Therefore
+    // redo the calculation using 128-bit numbers.  (64 bits are not enough).
+
+    // Start out with digits rounded down; maybe add one below.
+    dddddd = static_cast<int>(d64k / 65536);
+
+    // mantissa is a 64-bit integer representing M.mmm... * 2^63.  The actual
+    // value we're representing, of course, is M.mmm... * 2^exp2.
+    int exp2;
+    double m = std::frexp(value, &exp2);
+    uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0);
+    // std::frexp returns an m value in the range [0.5, 1.0), however we
+    // can't multiply it by 2^64 and convert to an integer because some FPUs
+    // throw an exception when converting an number higher than 2^63 into an
+    // integer - even an unsigned 64-bit integer!  Fortunately it doesn't matter
+    // since m only has 52 significant bits anyway.
+    mantissa <<= 1;
+    exp2 -= 64;  // not needed, but nice for debugging
+
+    // OK, we are here to compare:
+    //     (dddddd + 0.5) * 10^(exp-5)  vs.  mantissa * 2^exp2
+    // so we can round up dddddd if appropriate.  Those values span the full
+    // range of 600 orders of magnitude of IEE 64-bit floating-point.
+    // Fortunately, we already know they are very close, so we don't need to
+    // track the base-2 exponent of both sides.  This greatly simplifies the
+    // the math since the 2^exp2 calculation is unnecessary and the power-of-10
+    // calculation can become a power-of-5 instead.
+
+    std::pair<uint64_t, uint64_t> edge, val;
+    if (exp >= 6) {
+      // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa
+      // Since we're tossing powers of two, 2 * dddddd + 1 is the
+      // same as dddddd + 0.5
+      edge = PowFive(2 * dddddd + 1, exp - 5);
+
+      val.first = mantissa;
+      val.second = 0;
+    } else {
+      // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did
+      // above because (exp - 5) is negative.  So we compare (dddddd + 0.5) to
+      // mantissa * 5 ^ (5 - exp)
+      edge = PowFive(2 * dddddd + 1, 0);
+
+      val = PowFive(mantissa, 5 - exp);
+    }
+    // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first,
+    //        val.second, edge.first, edge.second);
+    if (val > edge) {
+      dddddd++;
+    } else if (val == edge) {
+      dddddd += (dddddd & 1);
+    }
+  } else {
+    // Here, we are not close to the edge.
+    dddddd = static_cast<int>((d64k + 32768) / 65536);
+  }
+  if (dddddd == 1000000) {
+    dddddd = 100000;
+    exp += 1;
+  }
+  exp_dig.exponent = exp;
+
+  int two_digits = dddddd / 10000;
+  dddddd -= two_digits * 10000;
+  PutTwoDigits(two_digits, &exp_dig.digits[0]);
+
+  two_digits = dddddd / 100;
+  dddddd -= two_digits * 100;
+  PutTwoDigits(two_digits, &exp_dig.digits[2]);
+
+  PutTwoDigits(dddddd, &exp_dig.digits[4]);
+  return exp_dig;
+}
+
+// Helper function for fast formatting of floating-point.
+// The result is the same as "%g", a.k.a. "%.6g".
+size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) {
+  static_assert(std::numeric_limits<float>::is_iec559,
+                "IEEE-754/IEC-559 support only");
+
+  char* out = buffer;  // we write data to out, incrementing as we go, but
+                       // FloatToBuffer always returns the address of the buffer
+                       // passed in.
+
+  if (std::isnan(d)) {
+    strcpy(out, "nan");  // NOLINT(runtime/printf)
+    return 3;
+  }
+  if (d == 0) {  // +0 and -0 are handled here
+    if (std::signbit(d)) *out++ = '-';
+    *out++ = '0';
+    *out = 0;
+    return out - buffer;
+  }
+  if (d < 0) {
+    *out++ = '-';
+    d = -d;
+  }
+  if (std::isinf(d)) {
+    strcpy(out, "inf");  // NOLINT(runtime/printf)
+    return out + 3 - buffer;
+  }
+
+  auto exp_dig = SplitToSix(d);
+  int exp = exp_dig.exponent;
+  const char* digits = exp_dig.digits;
+  out[0] = '0';
+  out[1] = '.';
+  switch (exp) {
+    case 5:
+      memcpy(out, &digits[0], 6), out += 6;
+      *out = 0;
+      return out - buffer;
+    case 4:
+      memcpy(out, &digits[0], 5), out += 5;
+      if (digits[5] != '0') {
+        *out++ = '.';
+        *out++ = digits[5];
+      }
+      *out = 0;
+      return out - buffer;
+    case 3:
+      memcpy(out, &digits[0], 4), out += 4;
+      if ((digits[5] | digits[4]) != '0') {
+        *out++ = '.';
+        *out++ = digits[4];
+        if (digits[5] != '0') *out++ = digits[5];
+      }
+      *out = 0;
+      return out - buffer;
+    case 2:
+      memcpy(out, &digits[0], 3), out += 3;
+      *out++ = '.';
+      memcpy(out, &digits[3], 3);
+      out += 3;
+      while (out[-1] == '0') --out;
+      if (out[-1] == '.') --out;
+      *out = 0;
+      return out - buffer;
+    case 1:
+      memcpy(out, &digits[0], 2), out += 2;
+      *out++ = '.';
+      memcpy(out, &digits[2], 4);
+      out += 4;
+      while (out[-1] == '0') --out;
+      if (out[-1] == '.') --out;
+      *out = 0;
+      return out - buffer;
+    case 0:
+      memcpy(out, &digits[0], 1), out += 1;
+      *out++ = '.';
+      memcpy(out, &digits[1], 5);
+      out += 5;
+      while (out[-1] == '0') --out;
+      if (out[-1] == '.') --out;
+      *out = 0;
+      return out - buffer;
+    case -4:
+      out[2] = '0';
+      ++out;
+      ABSL_FALLTHROUGH_INTENDED;
+    case -3:
+      out[2] = '0';
+      ++out;
+      ABSL_FALLTHROUGH_INTENDED;
+    case -2:
+      out[2] = '0';
+      ++out;
+      ABSL_FALLTHROUGH_INTENDED;
+    case -1:
+      out += 2;
+      memcpy(out, &digits[0], 6);
+      out += 6;
+      while (out[-1] == '0') --out;
+      *out = 0;
+      return out - buffer;
+  }
+  assert(exp < -4 || exp >= 6);
+  out[0] = digits[0];
+  assert(out[1] == '.');
+  out += 2;
+  memcpy(out, &digits[1], 5), out += 5;
+  while (out[-1] == '0') --out;
+  if (out[-1] == '.') --out;
+  *out++ = 'e';
+  if (exp > 0) {
+    *out++ = '+';
+  } else {
+    *out++ = '-';
+    exp = -exp;
+  }
+  if (exp > 99) {
+    int dig1 = exp / 100;
+    exp -= dig1 * 100;
+    *out++ = '0' + dig1;
+  }
+  PutTwoDigits(exp, out);
+  out += 2;
+  *out = 0;
+  return out - buffer;
+}
+
+namespace {
+// Represents integer values of digits.
+// Uses 36 to indicate an invalid character since we support
+// bases up to 36.
+static const int8_t kAsciiToInt[256] = {
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 16 36s.
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0,  1,  2,  3,  4,  5,
+    6,  7,  8,  9,  36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17,
+    18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+    36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36};
+
+// Parse the sign and optional hex or oct prefix in text.
+inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/,
+                                     int* base_ptr /*inout*/,
+                                     bool* negative_ptr /*output*/) {
+  if (text->data() == nullptr) {
+    return false;
+  }
+
+  const char* start = text->data();
+  const char* end = start + text->size();
+  int base = *base_ptr;
+
+  // Consume whitespace.
+  while (start < end && absl::ascii_isspace(start[0])) {
+    ++start;
+  }
+  while (start < end && absl::ascii_isspace(end[-1])) {
+    --end;
+  }
+  if (start >= end) {
+    return false;
+  }
+
+  // Consume sign.
+  *negative_ptr = (start[0] == '-');
+  if (*negative_ptr || start[0] == '+') {
+    ++start;
+    if (start >= end) {
+      return false;
+    }
+  }
+
+  // Consume base-dependent prefix.
+  //  base 0: "0x" -> base 16, "0" -> base 8, default -> base 10
+  //  base 16: "0x" -> base 16
+  // Also validate the base.
+  if (base == 0) {
+    if (end - start >= 2 && start[0] == '0' &&
+        (start[1] == 'x' || start[1] == 'X')) {
+      base = 16;
+      start += 2;
+      if (start >= end) {
+        // "0x" with no digits after is invalid.
+        return false;
+      }
+    } else if (end - start >= 1 && start[0] == '0') {
+      base = 8;
+      start += 1;
+    } else {
+      base = 10;
+    }
+  } else if (base == 16) {
+    if (end - start >= 2 && start[0] == '0' &&
+        (start[1] == 'x' || start[1] == 'X')) {
+      start += 2;
+      if (start >= end) {
+        // "0x" with no digits after is invalid.
+        return false;
+      }
+    }
+  } else if (base >= 2 && base <= 36) {
+    // okay
+  } else {
+    return false;
+  }
+  *text = absl::string_view(start, end - start);
+  *base_ptr = base;
+  return true;
+}
+
+// Consume digits.
+//
+// The classic loop:
+//
+//   for each digit
+//     value = value * base + digit
+//   value *= sign
+//
+// The classic loop needs overflow checking.  It also fails on the most
+// negative integer, -2147483648 in 32-bit two's complement representation.
+//
+// My improved loop:
+//
+//  if (!negative)
+//    for each digit
+//      value = value * base
+//      value = value + digit
+//  else
+//    for each digit
+//      value = value * base
+//      value = value - digit
+//
+// Overflow checking becomes simple.
+
+// Lookup tables per IntType:
+// vmax/base and vmin/base are precomputed because division costs at least 8ns.
+// TODO(junyer): Doing this per base instead (i.e. an array of structs, not a
+// struct of arrays) would probably be better in terms of d-cache for the most
+// commonly used bases.
+template <typename IntType>
+struct LookupTables {
+  static const IntType kVmaxOverBase[];
+  static const IntType kVminOverBase[];
+};
+
+// An array initializer macro for X/base where base in [0, 36].
+// However, note that lookups for base in [0, 1] should never happen because
+// base has been validated to be in [2, 36] by safe_parse_sign_and_base().
+#define X_OVER_BASE_INITIALIZER(X)                                        \
+  {                                                                       \
+    0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \
+        X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18,   \
+        X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26,   \
+        X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34,   \
+        X / 35, X / 36,                                                   \
+  }
+
+template <typename IntType>
+const IntType LookupTables<IntType>::kVmaxOverBase[] =
+    X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
+
+template <typename IntType>
+const IntType LookupTables<IntType>::kVminOverBase[] =
+    X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::min());
+
+#undef X_OVER_BASE_INITIALIZER
+
+template <typename IntType>
+inline bool safe_parse_positive_int(absl::string_view text, int base,
+                                    IntType* value_p) {
+  IntType value = 0;
+  const IntType vmax = std::numeric_limits<IntType>::max();
+  assert(vmax > 0);
+  assert(base >= 0);
+  assert(vmax >= static_cast<IntType>(base));
+  const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base];
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = kAsciiToInt[c];
+    if (digit >= base) {
+      *value_p = value;
+      return false;
+    }
+    if (value > vmax_over_base) {
+      *value_p = vmax;
+      return false;
+    }
+    value *= base;
+    if (value > vmax - digit) {
+      *value_p = vmax;
+      return false;
+    }
+    value += digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+template <typename IntType>
+inline bool safe_parse_negative_int(absl::string_view text, int base,
+                                    IntType* value_p) {
+  IntType value = 0;
+  const IntType vmin = std::numeric_limits<IntType>::min();
+  assert(vmin < 0);
+  assert(vmin <= 0 - base);
+  IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base];
+  // 2003 c++ standard [expr.mul]
+  // "... the sign of the remainder is implementation-defined."
+  // Although (vmin/base)*base + vmin%base is always vmin.
+  // 2011 c++ standard tightens the spec but we cannot rely on it.
+  // TODO(junyer): Handle this in the lookup table generation.
+  if (vmin % base > 0) {
+    vmin_over_base += 1;
+  }
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = kAsciiToInt[c];
+    if (digit >= base) {
+      *value_p = value;
+      return false;
+    }
+    if (value < vmin_over_base) {
+      *value_p = vmin;
+      return false;
+    }
+    value *= base;
+    if (value < vmin + digit) {
+      *value_p = vmin;
+      return false;
+    }
+    value -= digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+// Input format based on POSIX.1-2008 strtol
+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
+template <typename IntType>
+inline bool safe_int_internal(absl::string_view text, IntType* value_p,
+                              int base) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign_and_base(&text, &base, &negative)) {
+    return false;
+  }
+  if (!negative) {
+    return safe_parse_positive_int(text, base, value_p);
+  } else {
+    return safe_parse_negative_int(text, base, value_p);
+  }
+}
+
+template <typename IntType>
+inline bool safe_uint_internal(absl::string_view text, IntType* value_p,
+                               int base) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) {
+    return false;
+  }
+  return safe_parse_positive_int(text, base, value_p);
+}
+}  // anonymous namespace
+
+namespace numbers_internal {
+bool safe_strto32_base(absl::string_view text, int32_t* value, int base) {
+  return safe_int_internal<int32_t>(text, value, base);
+}
+
+bool safe_strto64_base(absl::string_view text, int64_t* value, int base) {
+  return safe_int_internal<int64_t>(text, value, base);
+}
+
+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
+  return safe_uint_internal<uint32_t>(text, value, base);
+}
+
+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) {
+  return safe_uint_internal<uint64_t>(text, value, base);
+}
+}  // namespace numbers_internal
+
+}  // namespace absl
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
new file mode 100644
index 0000000..cf3c597
--- /dev/null
+++ b/absl/strings/numbers.h
@@ -0,0 +1,184 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: numbers.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for converting strings to numbers. For
+// converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h,
+// which automatically detect and convert most number values appropriately.
+
+#ifndef ABSL_STRINGS_NUMBERS_H_
+#define ABSL_STRINGS_NUMBERS_H_
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// SimpleAtoi()
+//
+// Converts the given std::string into an integer value, returning `true` if
+// successful. The std::string must reflect a base-10 integer (optionally followed or
+// preceded by ASCII whitespace) whose value falls within the range of the
+// integer type,
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out);
+
+// SimpleAtof()
+//
+// Converts the given std::string (optionally followed or preceded by ASCII
+// whitespace) into a float, which may be rounded on overflow or underflow.
+// See http://en.cppreference.com/w/c/std::string/byte/strtof for details about the
+// allowed formats for `str`.
+ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value);
+
+// SimpleAtod()
+//
+// Converts the given std::string (optionally followed or preceded by ASCII
+// whitespace) into a double, which may be rounded on overflow or underflow.
+// See http://en.cppreference.com/w/c/std::string/byte/strtof for details about the
+// allowed formats for `str`.
+ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value);
+
+// SimpleAtob()
+//
+// Converts the given std::string into a boolean, returning `true` if successful.
+// The following case-insensitive strings are interpreted as boolean `true`:
+// "true", "t", "yes", "y", "1". The following case-insensitive strings
+// are interpreted as boolean `false`: "false", "f", "no", "n", "0".
+ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value);
+
+}  // namespace absl
+
+// End of public API.  Implementation details follow.
+
+namespace absl {
+namespace numbers_internal {
+
+// safe_strto?() functions for implementing SimpleAtoi()
+bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
+bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
+
+static const int kFastToBufferSize = 32;
+static const int kSixDigitsToBufferSize = 16;
+
+// Helper function for fast formatting of floating-point values.
+// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six
+// significant digits are returned, trailing zeros are removed, and numbers
+// outside the range 0.0001-999999 are output using scientific notation
+// (1.23456e+06). This routine is heavily optimized.
+// Required buffer size is `kSixDigitsToBufferSize`.
+size_t SixDigitsToBuffer(double d, char* buffer);
+
+// These functions are intended for speed. All functions take an output buffer
+// as an argument and return a pointer to the last byte they wrote, which is the
+// terminating '\0'. At most `kFastToBufferSize` bytes are written.
+char* FastIntToBuffer(int32_t, char*);
+char* FastIntToBuffer(uint32_t, char*);
+char* FastIntToBuffer(int64_t, char*);
+char* FastIntToBuffer(uint64_t, char*);
+
+// For enums and integer types that are not an exact match for the types above,
+// use templates to call the appropriate one of the four overloads above.
+template <typename int_type>
+char* FastIntToBuffer(int_type i, char* buffer) {
+  static_assert(sizeof(i) <= 64 / 8,
+                "FastIntToBuffer works only with 64-bit-or-less integers.");
+  // TODO(jorg): This signed-ness check is used because it works correctly
+  // with enums, and it also serves to check that int_type is not a pointer.
+  // If one day something like std::is_signed<enum E> works, switch to it.
+  if (static_cast<int_type>(1) - 2 < 0) {  // Signed
+    if (sizeof(i) > 32 / 8) {           // 33-bit to 64-bit
+      return FastIntToBuffer(static_cast<int64_t>(i), buffer);
+    } else {  // 32-bit or less
+      return FastIntToBuffer(static_cast<int32_t>(i), buffer);
+    }
+  } else {                     // Unsigned
+    if (sizeof(i) > 32 / 8) {  // 33-bit to 64-bit
+      return FastIntToBuffer(static_cast<uint64_t>(i), buffer);
+    } else {  // 32-bit or less
+      return FastIntToBuffer(static_cast<uint32_t>(i), buffer);
+    }
+  }
+}
+
+// Implementation of SimpleAtoi, generalized to support arbitrary base (used
+// with base different from 10 elsewhere in Abseil implementation).
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out,
+                                           int base) {
+  static_assert(sizeof(*out) == 4 || sizeof(*out) == 8,
+                "SimpleAtoi works only with 32-bit or 64-bit integers.");
+  static_assert(!std::is_floating_point<int_type>::value,
+                "Use SimpleAtof or SimpleAtod instead.");
+  bool parsed;
+  // TODO(jorg): This signed-ness check is used because it works correctly
+  // with enums, and it also serves to check that int_type is not a pointer.
+  // If one day something like std::is_signed<enum E> works, switch to it.
+  if (static_cast<int_type>(1) - 2 < 0) {  // Signed
+    if (sizeof(*out) == 64 / 8) {       // 64-bit
+      int64_t val;
+      parsed = numbers_internal::safe_strto64_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    } else {  // 32-bit
+      int32_t val;
+      parsed = numbers_internal::safe_strto32_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    }
+  } else {                         // Unsigned
+    if (sizeof(*out) == 64 / 8) {  // 64-bit
+      uint64_t val;
+      parsed = numbers_internal::safe_strtou64_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    } else {  // 32-bit
+      uint32_t val;
+      parsed = numbers_internal::safe_strtou32_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    }
+  }
+  return parsed;
+}
+
+}  // namespace numbers_internal
+
+// SimpleAtoi()
+//
+// Converts a std::string to an integer, using `safe_strto?()` functions for actual
+// parsing, returning `true` if successful. The `safe_strto?()` functions apply
+// strict checking; the std::string must be a base-10 integer, optionally followed or
+// preceded by ASCII whitespace, with a value in the range of the corresponding
+// integer type.
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out) {
+  return numbers_internal::safe_strtoi_base(s, out, 10);
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_NUMBERS_H_
diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc
new file mode 100644
index 0000000..8ef650b
--- /dev/null
+++ b/absl/strings/numbers_benchmark.cc
@@ -0,0 +1,263 @@
+// Copyright 2018 The Abseil 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 <cstdint>
+#include <random>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/numbers.h"
+
+namespace {
+
+template <typename T>
+void BM_FastIntToBuffer(benchmark::State& state) {
+  const int inc = state.range(0);
+  char buf[absl::numbers_internal::kFastToBufferSize];
+  // Use the unsigned type to increment to take advantage of well-defined
+  // modular arithmetic.
+  typename std::make_unsigned<T>::type x = 0;
+  for (auto _ : state) {
+    absl::numbers_internal::FastIntToBuffer(static_cast<T>(x), buf);
+    x += inc;
+  }
+}
+BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int32_t)->Range(0, 1 << 15);
+BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int64_t)->Range(0, 1 << 30);
+
+// Creates an integer that would be printed as `num_digits` repeated 7s in the
+// given `base`. `base` must be greater than or equal to 8.
+int64_t RepeatedSevens(int num_digits, int base) {
+  ABSL_RAW_CHECK(base >= 8, "");
+  int64_t num = 7;
+  while (--num_digits) num = base * num + 7;
+  return num;
+}
+
+void BM_safe_strto32_string(benchmark::State& state) {
+  const int digits = state.range(0);
+  const int base = state.range(1);
+  std::string str(digits, '7');  // valid in octal, decimal and hex
+  int32_t value = 0;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::numbers_internal::safe_strto32_base(str, &value, base));
+  }
+  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
+}
+BENCHMARK(BM_safe_strto32_string)
+    ->ArgPair(1, 8)
+    ->ArgPair(1, 10)
+    ->ArgPair(1, 16)
+    ->ArgPair(2, 8)
+    ->ArgPair(2, 10)
+    ->ArgPair(2, 16)
+    ->ArgPair(4, 8)
+    ->ArgPair(4, 10)
+    ->ArgPair(4, 16)
+    ->ArgPair(8, 8)
+    ->ArgPair(8, 10)
+    ->ArgPair(8, 16)
+    ->ArgPair(10, 8)
+    ->ArgPair(9, 10);
+
+void BM_safe_strto64_string(benchmark::State& state) {
+  const int digits = state.range(0);
+  const int base = state.range(1);
+  std::string str(digits, '7');  // valid in octal, decimal and hex
+  int64_t value = 0;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::numbers_internal::safe_strto64_base(str, &value, base));
+  }
+  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
+}
+BENCHMARK(BM_safe_strto64_string)
+    ->ArgPair(1, 8)
+    ->ArgPair(1, 10)
+    ->ArgPair(1, 16)
+    ->ArgPair(2, 8)
+    ->ArgPair(2, 10)
+    ->ArgPair(2, 16)
+    ->ArgPair(4, 8)
+    ->ArgPair(4, 10)
+    ->ArgPair(4, 16)
+    ->ArgPair(8, 8)
+    ->ArgPair(8, 10)
+    ->ArgPair(8, 16)
+    ->ArgPair(16, 8)
+    ->ArgPair(16, 10)
+    ->ArgPair(16, 16);
+
+void BM_safe_strtou32_string(benchmark::State& state) {
+  const int digits = state.range(0);
+  const int base = state.range(1);
+  std::string str(digits, '7');  // valid in octal, decimal and hex
+  uint32_t value = 0;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::numbers_internal::safe_strtou32_base(str, &value, base));
+  }
+  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
+}
+BENCHMARK(BM_safe_strtou32_string)
+    ->ArgPair(1, 8)
+    ->ArgPair(1, 10)
+    ->ArgPair(1, 16)
+    ->ArgPair(2, 8)
+    ->ArgPair(2, 10)
+    ->ArgPair(2, 16)
+    ->ArgPair(4, 8)
+    ->ArgPair(4, 10)
+    ->ArgPair(4, 16)
+    ->ArgPair(8, 8)
+    ->ArgPair(8, 10)
+    ->ArgPair(8, 16)
+    ->ArgPair(10, 8)
+    ->ArgPair(9, 10);
+
+void BM_safe_strtou64_string(benchmark::State& state) {
+  const int digits = state.range(0);
+  const int base = state.range(1);
+  std::string str(digits, '7');  // valid in octal, decimal and hex
+  uint64_t value = 0;
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::numbers_internal::safe_strtou64_base(str, &value, base));
+  }
+  ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
+}
+BENCHMARK(BM_safe_strtou64_string)
+    ->ArgPair(1, 8)
+    ->ArgPair(1, 10)
+    ->ArgPair(1, 16)
+    ->ArgPair(2, 8)
+    ->ArgPair(2, 10)
+    ->ArgPair(2, 16)
+    ->ArgPair(4, 8)
+    ->ArgPair(4, 10)
+    ->ArgPair(4, 16)
+    ->ArgPair(8, 8)
+    ->ArgPair(8, 10)
+    ->ArgPair(8, 16)
+    ->ArgPair(16, 8)
+    ->ArgPair(16, 10)
+    ->ArgPair(16, 16);
+
+// Returns a vector of `num_strings` strings. Each std::string represents a
+// floating point number with `num_digits` digits before the decimal point and
+// another `num_digits` digits after.
+std::vector<std::string> MakeFloatStrings(int num_strings, int num_digits) {
+  // For convenience, use a random number generator to generate the test data.
+  // We don't actually need random properties, so use a fixed seed.
+  std::minstd_rand0 rng(1);
+  std::uniform_int_distribution<int> random_digit('0', '9');
+
+  std::vector<std::string> float_strings(num_strings);
+  for (std::string& s : float_strings) {
+    s.reserve(2 * num_digits + 1);
+    for (int i = 0; i < num_digits; ++i) {
+      s.push_back(static_cast<char>(random_digit(rng)));
+    }
+    s.push_back('.');
+    for (int i = 0; i < num_digits; ++i) {
+      s.push_back(static_cast<char>(random_digit(rng)));
+    }
+  }
+  return float_strings;
+}
+
+template <typename StringType>
+StringType GetStringAs(const std::string& s) {
+  return static_cast<StringType>(s);
+}
+template <>
+const char* GetStringAs<const char*>(const std::string& s) {
+  return s.c_str();
+}
+
+template <typename StringType>
+std::vector<StringType> GetStringsAs(const std::vector<std::string>& strings) {
+  std::vector<StringType> result;
+  result.reserve(strings.size());
+  for (const std::string& s : strings) {
+    result.push_back(GetStringAs<StringType>(s));
+  }
+  return result;
+}
+
+template <typename T>
+void BM_SimpleAtof(benchmark::State& state) {
+  const int num_strings = state.range(0);
+  const int num_digits = state.range(1);
+  std::vector<std::string> backing_strings =
+      MakeFloatStrings(num_strings, num_digits);
+  std::vector<T> inputs = GetStringsAs<T>(backing_strings);
+  float value;
+  for (auto _ : state) {
+    for (const T& input : inputs) {
+      benchmark::DoNotOptimize(absl::SimpleAtof(input, &value));
+    }
+  }
+}
+BENCHMARK_TEMPLATE(BM_SimpleAtof, absl::string_view)
+    ->ArgPair(10, 1)
+    ->ArgPair(10, 2)
+    ->ArgPair(10, 4)
+    ->ArgPair(10, 8);
+BENCHMARK_TEMPLATE(BM_SimpleAtof, const char*)
+    ->ArgPair(10, 1)
+    ->ArgPair(10, 2)
+    ->ArgPair(10, 4)
+    ->ArgPair(10, 8);
+BENCHMARK_TEMPLATE(BM_SimpleAtof, std::string)
+    ->ArgPair(10, 1)
+    ->ArgPair(10, 2)
+    ->ArgPair(10, 4)
+    ->ArgPair(10, 8);
+
+template <typename T>
+void BM_SimpleAtod(benchmark::State& state) {
+  const int num_strings = state.range(0);
+  const int num_digits = state.range(1);
+  std::vector<std::string> backing_strings =
+      MakeFloatStrings(num_strings, num_digits);
+  std::vector<T> inputs = GetStringsAs<T>(backing_strings);
+  double value;
+  for (auto _ : state) {
+    for (const T& input : inputs) {
+      benchmark::DoNotOptimize(absl::SimpleAtod(input, &value));
+    }
+  }
+}
+BENCHMARK_TEMPLATE(BM_SimpleAtod, absl::string_view)
+    ->ArgPair(10, 1)
+    ->ArgPair(10, 2)
+    ->ArgPair(10, 4)
+    ->ArgPair(10, 8);
+BENCHMARK_TEMPLATE(BM_SimpleAtod, const char*)
+    ->ArgPair(10, 1)
+    ->ArgPair(10, 2)
+    ->ArgPair(10, 4)
+    ->ArgPair(10, 8);
+BENCHMARK_TEMPLATE(BM_SimpleAtod, std::string)
+    ->ArgPair(10, 1)
+    ->ArgPair(10, 2)
+    ->ArgPair(10, 4)
+    ->ArgPair(10, 8);
+
+}  // namespace
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
new file mode 100644
index 0000000..24e7138
--- /dev/null
+++ b/absl/strings/numbers_test.cc
@@ -0,0 +1,1189 @@
+// Copyright 2017 The Abseil 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.
+
+// This file tests std::string processing functions related to numeric values.
+
+#include "absl/strings/numbers.h"
+
+#include <sys/types.h>
+#include <cfenv>  // NOLINT(build/c++11)
+#include <cinttypes>
+#include <climits>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <numeric>
+#include <random>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_cat.h"
+
+#include "absl/strings/internal/numbers_test_common.h"
+
+namespace {
+
+using absl::numbers_internal::kSixDigitsToBufferSize;
+using absl::numbers_internal::safe_strto32_base;
+using absl::numbers_internal::safe_strto64_base;
+using absl::numbers_internal::safe_strtou32_base;
+using absl::numbers_internal::safe_strtou64_base;
+using absl::numbers_internal::SixDigitsToBuffer;
+using absl::strings_internal::Itoa;
+using absl::strings_internal::strtouint32_test_cases;
+using absl::strings_internal::strtouint64_test_cases;
+using absl::SimpleAtoi;
+using testing::Eq;
+using testing::MatchesRegex;
+
+// Number of floats to test with.
+// 10,000,000 is a reasonable default for a test that only takes a few seconds.
+// 1,000,000,000+ triggers checking for all possible mantissa values for
+// double-precision tests. 2,000,000,000+ triggers checking for every possible
+// single-precision float.
+#ifdef _MSC_VER
+// Use a smaller number on MSVC to avoid test time out (1 min)
+const int kFloatNumCases = 5000000;
+#else
+const int kFloatNumCases = 10000000;
+#endif
+
+// This is a slow, brute-force routine to compute the exact base-10
+// representation of a double-precision floating-point number.  It
+// is useful for debugging only.
+std::string PerfectDtoa(double d) {
+  if (d == 0) return "0";
+  if (d < 0) return "-" + PerfectDtoa(-d);
+
+  // Basic theory: decompose d into mantissa and exp, where
+  // d = mantissa * 2^exp, and exp is as close to zero as possible.
+  int64_t mantissa, exp = 0;
+  while (d >= 1ULL << 63) ++exp, d *= 0.5;
+  while ((mantissa = d) != d) --exp, d *= 2.0;
+
+  // Then convert mantissa to ASCII, and either double it (if
+  // exp > 0) or halve it (if exp < 0) repeatedly.  "halve it"
+  // in this case means multiplying it by five and dividing by 10.
+  constexpr int maxlen = 1100;  // worst case is actually 1030 or so.
+  char buf[maxlen + 5];
+  for (int64_t num = mantissa, pos = maxlen; --pos >= 0;) {
+    buf[pos] = '0' + (num % 10);
+    num /= 10;
+  }
+  char* begin = &buf[0];
+  char* end = buf + maxlen;
+  for (int i = 0; i != exp; i += (exp > 0) ? 1 : -1) {
+    int carry = 0;
+    for (char* p = end; --p != begin;) {
+      int dig = *p - '0';
+      dig = dig * (exp > 0 ? 2 : 5) + carry;
+      carry = dig / 10;
+      dig %= 10;
+      *p = '0' + dig;
+    }
+  }
+  if (exp < 0) {
+    // "dividing by 10" above means we have to add the decimal point.
+    memmove(end + 1 + exp, end + exp, 1 - exp);
+    end[exp] = '.';
+    ++end;
+  }
+  while (*begin == '0' && begin[1] != '.') ++begin;
+  return {begin, end};
+}
+
+TEST(ToString, PerfectDtoa) {
+  EXPECT_THAT(PerfectDtoa(1), Eq("1"));
+  EXPECT_THAT(PerfectDtoa(0.1),
+              Eq("0.1000000000000000055511151231257827021181583404541015625"));
+  EXPECT_THAT(PerfectDtoa(1e24), Eq("999999999999999983222784"));
+  EXPECT_THAT(PerfectDtoa(5e-324), MatchesRegex("0.0000.*625"));
+  for (int i = 0; i < 100; ++i) {
+    for (double multiplier :
+         {1e-300, 1e-200, 1e-100, 0.1, 1.0, 10.0, 1e100, 1e300}) {
+      double d = multiplier * i;
+      std::string s = PerfectDtoa(d);
+      EXPECT_DOUBLE_EQ(d, strtod(s.c_str(), nullptr));
+    }
+  }
+}
+
+template <typename integer>
+struct MyInteger {
+  integer i;
+  explicit constexpr MyInteger(integer i) : i(i) {}
+  constexpr operator integer() const { return i; }
+
+  constexpr MyInteger operator+(MyInteger other) const { return i + other.i; }
+  constexpr MyInteger operator-(MyInteger other) const { return i - other.i; }
+  constexpr MyInteger operator*(MyInteger other) const { return i * other.i; }
+  constexpr MyInteger operator/(MyInteger other) const { return i / other.i; }
+
+  constexpr bool operator<(MyInteger other) const { return i < other.i; }
+  constexpr bool operator<=(MyInteger other) const { return i <= other.i; }
+  constexpr bool operator==(MyInteger other) const { return i == other.i; }
+  constexpr bool operator>=(MyInteger other) const { return i >= other.i; }
+  constexpr bool operator>(MyInteger other) const { return i > other.i; }
+  constexpr bool operator!=(MyInteger other) const { return i != other.i; }
+
+  integer as_integer() const { return i; }
+};
+
+typedef MyInteger<int64_t> MyInt64;
+typedef MyInteger<uint64_t> MyUInt64;
+
+void CheckInt32(int32_t x) {
+  char buffer[absl::numbers_internal::kFastToBufferSize];
+  char* actual = absl::numbers_internal::FastIntToBuffer(x, buffer);
+  std::string expected = std::to_string(x);
+  EXPECT_EQ(expected, std::string(buffer, actual)) << " Input " << x;
+
+  char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, buffer);
+  EXPECT_EQ(expected, std::string(buffer, generic_actual)) << " Input " << x;
+}
+
+void CheckInt64(int64_t x) {
+  char buffer[absl::numbers_internal::kFastToBufferSize + 3];
+  buffer[0] = '*';
+  buffer[23] = '*';
+  buffer[24] = '*';
+  char* actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]);
+  std::string expected = std::to_string(x);
+  EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x;
+  EXPECT_EQ(buffer[0], '*');
+  EXPECT_EQ(buffer[23], '*');
+  EXPECT_EQ(buffer[24], '*');
+
+  char* my_actual =
+      absl::numbers_internal::FastIntToBuffer(MyInt64(x), &buffer[1]);
+  EXPECT_EQ(expected, std::string(&buffer[1], my_actual)) << " Input " << x;
+}
+
+void CheckUInt32(uint32_t x) {
+  char buffer[absl::numbers_internal::kFastToBufferSize];
+  char* actual = absl::numbers_internal::FastIntToBuffer(x, buffer);
+  std::string expected = std::to_string(x);
+  EXPECT_EQ(expected, std::string(buffer, actual)) << " Input " << x;
+
+  char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, buffer);
+  EXPECT_EQ(expected, std::string(buffer, generic_actual)) << " Input " << x;
+}
+
+void CheckUInt64(uint64_t x) {
+  char buffer[absl::numbers_internal::kFastToBufferSize + 1];
+  char* actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]);
+  std::string expected = std::to_string(x);
+  EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x;
+
+  char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]);
+  EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) << " Input " << x;
+
+  char* my_actual =
+      absl::numbers_internal::FastIntToBuffer(MyUInt64(x), &buffer[1]);
+  EXPECT_EQ(expected, std::string(&buffer[1], my_actual)) << " Input " << x;
+}
+
+void CheckHex64(uint64_t v) {
+  char expected[16 + 1];
+  std::string actual = absl::StrCat(absl::Hex(v, absl::kZeroPad16));
+  snprintf(expected, sizeof(expected), "%016" PRIx64, static_cast<uint64_t>(v));
+  EXPECT_EQ(expected, actual) << " Input " << v;
+}
+
+TEST(Numbers, TestFastPrints) {
+  for (int i = -100; i <= 100; i++) {
+    CheckInt32(i);
+    CheckInt64(i);
+  }
+  for (int i = 0; i <= 100; i++) {
+    CheckUInt32(i);
+    CheckUInt64(i);
+  }
+  // Test min int to make sure that works
+  CheckInt32(INT_MIN);
+  CheckInt32(INT_MAX);
+  CheckInt64(LONG_MIN);
+  CheckInt64(uint64_t{1000000000});
+  CheckInt64(uint64_t{9999999999});
+  CheckInt64(uint64_t{100000000000000});
+  CheckInt64(uint64_t{999999999999999});
+  CheckInt64(uint64_t{1000000000000000000});
+  CheckInt64(uint64_t{1199999999999999999});
+  CheckInt64(int64_t{-700000000000000000});
+  CheckInt64(LONG_MAX);
+  CheckUInt32(std::numeric_limits<uint32_t>::max());
+  CheckUInt64(uint64_t{1000000000});
+  CheckUInt64(uint64_t{9999999999});
+  CheckUInt64(uint64_t{100000000000000});
+  CheckUInt64(uint64_t{999999999999999});
+  CheckUInt64(uint64_t{1000000000000000000});
+  CheckUInt64(uint64_t{1199999999999999999});
+  CheckUInt64(std::numeric_limits<uint64_t>::max());
+
+  for (int i = 0; i < 10000; i++) {
+    CheckHex64(i);
+  }
+  CheckHex64(uint64_t{0x123456789abcdef0});
+}
+
+template <typename int_type, typename in_val_type>
+void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
+  std::string s = absl::StrCat(in_value);
+  int_type x = static_cast<int_type>(~exp_value);
+  EXPECT_TRUE(SimpleAtoi(s, &x))
+      << "in_value=" << in_value << " s=" << s << " x=" << x;
+  EXPECT_EQ(exp_value, x);
+  x = static_cast<int_type>(~exp_value);
+  EXPECT_TRUE(SimpleAtoi(s.c_str(), &x));
+  EXPECT_EQ(exp_value, x);
+}
+
+template <typename int_type, typename in_val_type>
+void VerifySimpleAtoiBad(in_val_type in_value) {
+  std::string s = absl::StrCat(in_value);
+  int_type x;
+  EXPECT_FALSE(SimpleAtoi(s, &x));
+  EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
+}
+
+TEST(NumbersTest, Atoi) {
+  // SimpleAtoi(absl::string_view, int32_t)
+  VerifySimpleAtoiGood<int32_t>(0, 0);
+  VerifySimpleAtoiGood<int32_t>(42, 42);
+  VerifySimpleAtoiGood<int32_t>(-42, -42);
+
+  VerifySimpleAtoiGood<int32_t>(std::numeric_limits<int32_t>::min(),
+                                std::numeric_limits<int32_t>::min());
+  VerifySimpleAtoiGood<int32_t>(std::numeric_limits<int32_t>::max(),
+                                std::numeric_limits<int32_t>::max());
+
+  // SimpleAtoi(absl::string_view, uint32_t)
+  VerifySimpleAtoiGood<uint32_t>(0, 0);
+  VerifySimpleAtoiGood<uint32_t>(42, 42);
+  VerifySimpleAtoiBad<uint32_t>(-42);
+
+  VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int32_t>::min());
+  VerifySimpleAtoiGood<uint32_t>(std::numeric_limits<int32_t>::max(),
+                                 std::numeric_limits<int32_t>::max());
+  VerifySimpleAtoiGood<uint32_t>(std::numeric_limits<uint32_t>::max(),
+                                 std::numeric_limits<uint32_t>::max());
+  VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int64_t>::min());
+  VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int64_t>::max());
+  VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<uint64_t>::max());
+
+  // SimpleAtoi(absl::string_view, int64_t)
+  VerifySimpleAtoiGood<int64_t>(0, 0);
+  VerifySimpleAtoiGood<int64_t>(42, 42);
+  VerifySimpleAtoiGood<int64_t>(-42, -42);
+
+  VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int32_t>::min(),
+                                std::numeric_limits<int32_t>::min());
+  VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int32_t>::max(),
+                                std::numeric_limits<int32_t>::max());
+  VerifySimpleAtoiGood<int64_t>(std::numeric_limits<uint32_t>::max(),
+                                std::numeric_limits<uint32_t>::max());
+  VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int64_t>::min(),
+                                std::numeric_limits<int64_t>::min());
+  VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int64_t>::max(),
+                                std::numeric_limits<int64_t>::max());
+  VerifySimpleAtoiBad<int64_t>(std::numeric_limits<uint64_t>::max());
+
+  // SimpleAtoi(absl::string_view, uint64_t)
+  VerifySimpleAtoiGood<uint64_t>(0, 0);
+  VerifySimpleAtoiGood<uint64_t>(42, 42);
+  VerifySimpleAtoiBad<uint64_t>(-42);
+
+  VerifySimpleAtoiBad<uint64_t>(std::numeric_limits<int32_t>::min());
+  VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<int32_t>::max(),
+                                 std::numeric_limits<int32_t>::max());
+  VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint32_t>::max(),
+                                 std::numeric_limits<uint32_t>::max());
+  VerifySimpleAtoiBad<uint64_t>(std::numeric_limits<int64_t>::min());
+  VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<int64_t>::max(),
+                                 std::numeric_limits<int64_t>::max());
+  VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(),
+                                 std::numeric_limits<uint64_t>::max());
+
+  // Some other types
+  VerifySimpleAtoiGood<int>(-42, -42);
+  VerifySimpleAtoiGood<int32_t>(-42, -42);
+  VerifySimpleAtoiGood<uint32_t>(42, 42);
+  VerifySimpleAtoiGood<unsigned int>(42, 42);
+  VerifySimpleAtoiGood<int64_t>(-42, -42);
+  VerifySimpleAtoiGood<long>(-42, -42);  // NOLINT(runtime/int)
+  VerifySimpleAtoiGood<uint64_t>(42, 42);
+  VerifySimpleAtoiGood<size_t>(42, 42);
+  VerifySimpleAtoiGood<std::string::size_type>(42, 42);
+}
+
+TEST(NumbersTest, Atoenum) {
+  enum E01 {
+    E01_zero = 0,
+    E01_one = 1,
+  };
+
+  VerifySimpleAtoiGood<E01>(E01_zero, E01_zero);
+  VerifySimpleAtoiGood<E01>(E01_one, E01_one);
+
+  enum E_101 {
+    E_101_minusone = -1,
+    E_101_zero = 0,
+    E_101_one = 1,
+  };
+
+  VerifySimpleAtoiGood<E_101>(E_101_minusone, E_101_minusone);
+  VerifySimpleAtoiGood<E_101>(E_101_zero, E_101_zero);
+  VerifySimpleAtoiGood<E_101>(E_101_one, E_101_one);
+
+  enum E_bigint {
+    E_bigint_zero = 0,
+    E_bigint_one = 1,
+    E_bigint_max31 = static_cast<int32_t>(0x7FFFFFFF),
+  };
+
+  VerifySimpleAtoiGood<E_bigint>(E_bigint_zero, E_bigint_zero);
+  VerifySimpleAtoiGood<E_bigint>(E_bigint_one, E_bigint_one);
+  VerifySimpleAtoiGood<E_bigint>(E_bigint_max31, E_bigint_max31);
+
+  enum E_fullint {
+    E_fullint_zero = 0,
+    E_fullint_one = 1,
+    E_fullint_max31 = static_cast<int32_t>(0x7FFFFFFF),
+    E_fullint_min32 = INT32_MIN,
+  };
+
+  VerifySimpleAtoiGood<E_fullint>(E_fullint_zero, E_fullint_zero);
+  VerifySimpleAtoiGood<E_fullint>(E_fullint_one, E_fullint_one);
+  VerifySimpleAtoiGood<E_fullint>(E_fullint_max31, E_fullint_max31);
+  VerifySimpleAtoiGood<E_fullint>(E_fullint_min32, E_fullint_min32);
+
+  enum E_biguint {
+    E_biguint_zero = 0,
+    E_biguint_one = 1,
+    E_biguint_max31 = static_cast<uint32_t>(0x7FFFFFFF),
+    E_biguint_max32 = static_cast<uint32_t>(0xFFFFFFFF),
+  };
+
+  VerifySimpleAtoiGood<E_biguint>(E_biguint_zero, E_biguint_zero);
+  VerifySimpleAtoiGood<E_biguint>(E_biguint_one, E_biguint_one);
+  VerifySimpleAtoiGood<E_biguint>(E_biguint_max31, E_biguint_max31);
+  VerifySimpleAtoiGood<E_biguint>(E_biguint_max32, E_biguint_max32);
+}
+
+TEST(stringtest, safe_strto32_base) {
+  int32_t value;
+  EXPECT_TRUE(safe_strto32_base("0x34234324", &value, 16));
+  EXPECT_EQ(0x34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base("0X34234324", &value, 16));
+  EXPECT_EQ(0x34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base("34234324", &value, 16));
+  EXPECT_EQ(0x34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base("0", &value, 16));
+  EXPECT_EQ(0, value);
+
+  EXPECT_TRUE(safe_strto32_base(" \t\n -0x34234324", &value, 16));
+  EXPECT_EQ(-0x34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base(" \t\n -34234324", &value, 16));
+  EXPECT_EQ(-0x34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base("7654321", &value, 8));
+  EXPECT_EQ(07654321, value);
+
+  EXPECT_TRUE(safe_strto32_base("-01234", &value, 8));
+  EXPECT_EQ(-01234, value);
+
+  EXPECT_FALSE(safe_strto32_base("1834", &value, 8));
+
+  // Autodetect base.
+  EXPECT_TRUE(safe_strto32_base("0", &value, 0));
+  EXPECT_EQ(0, value);
+
+  EXPECT_TRUE(safe_strto32_base("077", &value, 0));
+  EXPECT_EQ(077, value);  // Octal interpretation
+
+  // Leading zero indicates octal, but then followed by invalid digit.
+  EXPECT_FALSE(safe_strto32_base("088", &value, 0));
+
+  // Leading 0x indicated hex, but then followed by invalid digit.
+  EXPECT_FALSE(safe_strto32_base("0xG", &value, 0));
+
+  // Base-10 version.
+  EXPECT_TRUE(safe_strto32_base("34234324", &value, 10));
+  EXPECT_EQ(34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base("0", &value, 10));
+  EXPECT_EQ(0, value);
+
+  EXPECT_TRUE(safe_strto32_base(" \t\n -34234324", &value, 10));
+  EXPECT_EQ(-34234324, value);
+
+  EXPECT_TRUE(safe_strto32_base("34234324 \n\t ", &value, 10));
+  EXPECT_EQ(34234324, value);
+
+  // Invalid ints.
+  EXPECT_FALSE(safe_strto32_base("", &value, 10));
+  EXPECT_FALSE(safe_strto32_base("  ", &value, 10));
+  EXPECT_FALSE(safe_strto32_base("abc", &value, 10));
+  EXPECT_FALSE(safe_strto32_base("34234324a", &value, 10));
+  EXPECT_FALSE(safe_strto32_base("34234.3", &value, 10));
+
+  // Out of bounds.
+  EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10));
+  EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10));
+
+  // String version.
+  EXPECT_TRUE(safe_strto32_base(std::string("0x1234"), &value, 16));
+  EXPECT_EQ(0x1234, value);
+
+  // Base-10 std::string version.
+  EXPECT_TRUE(safe_strto32_base("1234", &value, 10));
+  EXPECT_EQ(1234, value);
+}
+
+TEST(stringtest, safe_strto32_range) {
+  // These tests verify underflow/overflow behaviour.
+  int32_t value;
+  EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), value);
+
+  EXPECT_TRUE(safe_strto32_base("-2147483648", &value, 10));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
+
+  EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto64_range) {
+  // These tests verify underflow/overflow behaviour.
+  int64_t value;
+  EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10));
+  EXPECT_EQ(std::numeric_limits<int64_t>::max(), value);
+
+  EXPECT_TRUE(safe_strto64_base("-9223372036854775808", &value, 10));
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
+
+  EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10));
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto32_leading_substring) {
+  // These tests verify this comment in numbers.h:
+  // On error, returns false, and sets *value to: [...]
+  //   conversion of leading substring if available ("123@@@" -> 123)
+  //   0 if no leading substring available
+  int32_t value;
+  EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 10));
+  EXPECT_EQ(4069, value);
+
+  EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 8));
+  EXPECT_EQ(0406, value);
+
+  EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 10));
+  EXPECT_EQ(4069, value);
+
+  EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 16));
+  EXPECT_EQ(0x4069ba, value);
+
+  EXPECT_FALSE(safe_strto32_base("@@@", &value, 10));
+  EXPECT_EQ(0, value);  // there was no leading substring
+}
+
+TEST(stringtest, safe_strto64_leading_substring) {
+  // These tests verify this comment in numbers.h:
+  // On error, returns false, and sets *value to: [...]
+  //   conversion of leading substring if available ("123@@@" -> 123)
+  //   0 if no leading substring available
+  int64_t value;
+  EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 10));
+  EXPECT_EQ(4069, value);
+
+  EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 8));
+  EXPECT_EQ(0406, value);
+
+  EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 10));
+  EXPECT_EQ(4069, value);
+
+  EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 16));
+  EXPECT_EQ(0x4069ba, value);
+
+  EXPECT_FALSE(safe_strto64_base("@@@", &value, 10));
+  EXPECT_EQ(0, value);  // there was no leading substring
+}
+
+TEST(stringtest, safe_strto64_base) {
+  int64_t value;
+  EXPECT_TRUE(safe_strto64_base("0x3423432448783446", &value, 16));
+  EXPECT_EQ(int64_t{0x3423432448783446}, value);
+
+  EXPECT_TRUE(safe_strto64_base("3423432448783446", &value, 16));
+  EXPECT_EQ(int64_t{0x3423432448783446}, value);
+
+  EXPECT_TRUE(safe_strto64_base("0", &value, 16));
+  EXPECT_EQ(0, value);
+
+  EXPECT_TRUE(safe_strto64_base(" \t\n -0x3423432448783446", &value, 16));
+  EXPECT_EQ(int64_t{-0x3423432448783446}, value);
+
+  EXPECT_TRUE(safe_strto64_base(" \t\n -3423432448783446", &value, 16));
+  EXPECT_EQ(int64_t{-0x3423432448783446}, value);
+
+  EXPECT_TRUE(safe_strto64_base("123456701234567012", &value, 8));
+  EXPECT_EQ(int64_t{0123456701234567012}, value);
+
+  EXPECT_TRUE(safe_strto64_base("-017777777777777", &value, 8));
+  EXPECT_EQ(int64_t{-017777777777777}, value);
+
+  EXPECT_FALSE(safe_strto64_base("19777777777777", &value, 8));
+
+  // Autodetect base.
+  EXPECT_TRUE(safe_strto64_base("0", &value, 0));
+  EXPECT_EQ(0, value);
+
+  EXPECT_TRUE(safe_strto64_base("077", &value, 0));
+  EXPECT_EQ(077, value);  // Octal interpretation
+
+  // Leading zero indicates octal, but then followed by invalid digit.
+  EXPECT_FALSE(safe_strto64_base("088", &value, 0));
+
+  // Leading 0x indicated hex, but then followed by invalid digit.
+  EXPECT_FALSE(safe_strto64_base("0xG", &value, 0));
+
+  // Base-10 version.
+  EXPECT_TRUE(safe_strto64_base("34234324487834466", &value, 10));
+  EXPECT_EQ(int64_t{34234324487834466}, value);
+
+  EXPECT_TRUE(safe_strto64_base("0", &value, 10));
+  EXPECT_EQ(0, value);
+
+  EXPECT_TRUE(safe_strto64_base(" \t\n -34234324487834466", &value, 10));
+  EXPECT_EQ(int64_t{-34234324487834466}, value);
+
+  EXPECT_TRUE(safe_strto64_base("34234324487834466 \n\t ", &value, 10));
+  EXPECT_EQ(int64_t{34234324487834466}, value);
+
+  // Invalid ints.
+  EXPECT_FALSE(safe_strto64_base("", &value, 10));
+  EXPECT_FALSE(safe_strto64_base("  ", &value, 10));
+  EXPECT_FALSE(safe_strto64_base("abc", &value, 10));
+  EXPECT_FALSE(safe_strto64_base("34234324487834466a", &value, 10));
+  EXPECT_FALSE(safe_strto64_base("34234487834466.3", &value, 10));
+
+  // Out of bounds.
+  EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10));
+  EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10));
+
+  // String version.
+  EXPECT_TRUE(safe_strto64_base(std::string("0x1234"), &value, 16));
+  EXPECT_EQ(0x1234, value);
+
+  // Base-10 std::string version.
+  EXPECT_TRUE(safe_strto64_base("1234", &value, 10));
+  EXPECT_EQ(1234, value);
+}
+
+const size_t kNumRandomTests = 10000;
+
+template <typename IntType>
+void test_random_integer_parse_base(bool (*parse_func)(absl::string_view,
+                                                       IntType* value,
+                                                       int base)) {
+  using RandomEngine = std::minstd_rand0;
+  std::random_device rd;
+  RandomEngine rng(rd());
+  std::uniform_int_distribution<IntType> random_int(
+      std::numeric_limits<IntType>::min());
+  std::uniform_int_distribution<int> random_base(2, 35);
+  for (size_t i = 0; i < kNumRandomTests; i++) {
+    IntType value = random_int(rng);
+    int base = random_base(rng);
+    std::string str_value;
+    EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+    IntType parsed_value;
+
+    // Test successful parse
+    EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+    EXPECT_EQ(parsed_value, value);
+
+    // Test overflow
+    EXPECT_FALSE(
+        parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value),
+                   &parsed_value, base));
+
+    // Test underflow
+    if (std::numeric_limits<IntType>::min() < 0) {
+      EXPECT_FALSE(
+          parse_func(absl::StrCat(std::numeric_limits<IntType>::min(), value),
+                     &parsed_value, base));
+    } else {
+      EXPECT_FALSE(parse_func(absl::StrCat("-", value), &parsed_value, base));
+    }
+  }
+}
+
+TEST(stringtest, safe_strto32_random) {
+  test_random_integer_parse_base<int32_t>(&safe_strto32_base);
+}
+TEST(stringtest, safe_strto64_random) {
+  test_random_integer_parse_base<int64_t>(&safe_strto64_base);
+}
+TEST(stringtest, safe_strtou32_random) {
+  test_random_integer_parse_base<uint32_t>(&safe_strtou32_base);
+}
+TEST(stringtest, safe_strtou64_random) {
+  test_random_integer_parse_base<uint64_t>(&safe_strtou64_base);
+}
+
+TEST(stringtest, safe_strtou32_base) {
+  for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
+    const auto& e = strtouint32_test_cases()[i];
+    uint32_t value;
+    EXPECT_EQ(e.expect_ok, safe_strtou32_base(e.str, &value, e.base))
+        << "str=\"" << e.str << "\" base=" << e.base;
+    if (e.expect_ok) {
+      EXPECT_EQ(e.expected, value) << "i=" << i << " str=\"" << e.str
+                                   << "\" base=" << e.base;
+    }
+  }
+}
+
+TEST(stringtest, safe_strtou32_base_length_delimited) {
+  for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
+    const auto& e = strtouint32_test_cases()[i];
+    std::string tmp(e.str);
+    tmp.append("12");  // Adds garbage at the end.
+
+    uint32_t value;
+    EXPECT_EQ(e.expect_ok,
+              safe_strtou32_base(absl::string_view(tmp.data(), strlen(e.str)),
+                                 &value, e.base))
+        << "str=\"" << e.str << "\" base=" << e.base;
+    if (e.expect_ok) {
+      EXPECT_EQ(e.expected, value) << "i=" << i << " str=" << e.str
+                                   << " base=" << e.base;
+    }
+  }
+}
+
+TEST(stringtest, safe_strtou64_base) {
+  for (int i = 0; strtouint64_test_cases()[i].str != nullptr; ++i) {
+    const auto& e = strtouint64_test_cases()[i];
+    uint64_t value;
+    EXPECT_EQ(e.expect_ok, safe_strtou64_base(e.str, &value, e.base))
+        << "str=\"" << e.str << "\" base=" << e.base;
+    if (e.expect_ok) {
+      EXPECT_EQ(e.expected, value) << "str=" << e.str << " base=" << e.base;
+    }
+  }
+}
+
+TEST(stringtest, safe_strtou64_base_length_delimited) {
+  for (int i = 0; strtouint64_test_cases()[i].str != nullptr; ++i) {
+    const auto& e = strtouint64_test_cases()[i];
+    std::string tmp(e.str);
+    tmp.append("12");  // Adds garbage at the end.
+
+    uint64_t value;
+    EXPECT_EQ(e.expect_ok,
+              safe_strtou64_base(absl::string_view(tmp.data(), strlen(e.str)),
+                                 &value, e.base))
+        << "str=\"" << e.str << "\" base=" << e.base;
+    if (e.expect_ok) {
+      EXPECT_EQ(e.expected, value) << "str=\"" << e.str << "\" base=" << e.base;
+    }
+  }
+}
+
+// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC.
+#if defined(_MSC_VER) || defined(__APPLE__)
+#define ABSL_MISSING_FEENABLEEXCEPT 1
+#define ABSL_MISSING_FEDISABLEEXCEPT 1
+#endif
+
+class SimpleDtoaTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Store the current floating point env & clear away any pending exceptions.
+    feholdexcept(&fp_env_);
+#ifndef ABSL_MISSING_FEENABLEEXCEPT
+    // Turn on floating point exceptions.
+    feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+#endif
+  }
+
+  void TearDown() override {
+    // Restore the floating point environment to the original state.
+    // In theory fedisableexcept is unnecessary; fesetenv will also do it.
+    // In practice, our toolchains have subtle bugs.
+#ifndef ABSL_MISSING_FEDISABLEEXCEPT
+    fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+#endif
+    fesetenv(&fp_env_);
+  }
+
+  std::string ToNineDigits(double value) {
+    char buffer[16];  // more than enough for %.9g
+    snprintf(buffer, sizeof(buffer), "%.9g", value);
+    return buffer;
+  }
+
+  fenv_t fp_env_;
+};
+
+// Run the given runnable functor for "cases" test cases, chosen over the
+// available range of float.  pi and e and 1/e are seeded, and then all
+// available integer powers of 2 and 10 are multiplied against them.  In
+// addition to trying all those values, we try the next higher and next lower
+// float, and then we add additional test cases evenly distributed between them.
+// Each test case is passed to runnable as both a positive and negative value.
+template <typename R>
+void ExhaustiveFloat(uint32_t cases, R&& runnable) {
+  runnable(0.0f);
+  runnable(-0.0f);
+  if (cases >= 2e9) {  // more than 2 billion?  Might as well run them all.
+    for (float f = 0; f < std::numeric_limits<float>::max(); ) {
+      f = nextafterf(f, std::numeric_limits<float>::max());
+      runnable(-f);
+      runnable(f);
+    }
+    return;
+  }
+  std::set<float> floats = {3.4028234e38f};
+  for (float f : {1.0, 3.14159265, 2.718281828, 1 / 2.718281828}) {
+    for (float testf = f; testf != 0; testf *= 0.1f) floats.insert(testf);
+    for (float testf = f; testf != 0; testf *= 0.5f) floats.insert(testf);
+    for (float testf = f; testf < 3e38f / 2; testf *= 2.0f)
+      floats.insert(testf);
+    for (float testf = f; testf < 3e38f / 10; testf *= 10) floats.insert(testf);
+  }
+
+  float last = *floats.begin();
+
+  runnable(last);
+  runnable(-last);
+  int iters_per_float = cases / floats.size();
+  if (iters_per_float == 0) iters_per_float = 1;
+  for (float f : floats) {
+    if (f == last) continue;
+    float testf = nextafter(last, std::numeric_limits<float>::max());
+    runnable(testf);
+    runnable(-testf);
+    last = testf;
+    if (f == last) continue;
+    double step = (double{f} - last) / iters_per_float;
+    for (double d = last + step; d < f; d += step) {
+      testf = d;
+      if (testf != last) {
+        runnable(testf);
+        runnable(-testf);
+        last = testf;
+      }
+    }
+    testf = nextafter(f, 0.0f);
+    if (testf > last) {
+      runnable(testf);
+      runnable(-testf);
+      last = testf;
+    }
+    if (f != last) {
+      runnable(f);
+      runnable(-f);
+      last = f;
+    }
+  }
+}
+
+TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) {
+  uint64_t test_count = 0;
+  std::vector<double> mismatches;
+  auto checker = [&](double d) {
+    if (d != d) return;  // rule out NaNs
+    ++test_count;
+    char sixdigitsbuf[kSixDigitsToBufferSize] = {0};
+    SixDigitsToBuffer(d, sixdigitsbuf);
+    char snprintfbuf[kSixDigitsToBufferSize] = {0};
+    snprintf(snprintfbuf, kSixDigitsToBufferSize, "%g", d);
+    if (strcmp(sixdigitsbuf, snprintfbuf) != 0) {
+      mismatches.push_back(d);
+      if (mismatches.size() < 10) {
+        ABSL_RAW_LOG(ERROR, "%s",
+                     absl::StrCat("Six-digit failure with double.  ", "d=", d,
+                                  "=", d, " sixdigits=", sixdigitsbuf,
+                                  " printf(%g)=", snprintfbuf)
+                         .c_str());
+      }
+    }
+  };
+  // Some quick sanity checks...
+  checker(5e-324);
+  checker(1e-308);
+  checker(1.0);
+  checker(1.000005);
+  checker(1.7976931348623157e308);
+  checker(0.00390625);
+#ifndef _MSC_VER
+  // on MSVC, snprintf() rounds it to 0.00195313. SixDigitsToBuffer() rounds it
+  // to 0.00195312 (round half to even).
+  checker(0.001953125);
+#endif
+  checker(0.005859375);
+  // Some cases where the rounding is very very close
+  checker(1.089095e-15);
+  checker(3.274195e-55);
+  checker(6.534355e-146);
+  checker(2.920845e+234);
+
+  if (mismatches.empty()) {
+    test_count = 0;
+    ExhaustiveFloat(kFloatNumCases, checker);
+
+    test_count = 0;
+    std::vector<int> digit_testcases{
+        100000, 100001, 100002, 100005, 100010, 100020, 100050, 100100,  // misc
+        195312, 195313,  // 1.953125 is a case where we round down, just barely.
+        200000, 500000, 800000,  // misc mid-range cases
+        585937, 585938,  // 5.859375 is a case where we round up, just barely.
+        900000, 990000, 999000, 999900, 999990, 999996, 999997, 999998, 999999};
+    if (kFloatNumCases >= 1e9) {
+      // If at least 1 billion test cases were requested, user wants an
+      // exhaustive test. So let's test all mantissas, too.
+      constexpr int min_mantissa = 100000, max_mantissa = 999999;
+      digit_testcases.resize(max_mantissa - min_mantissa + 1);
+      std::iota(digit_testcases.begin(), digit_testcases.end(), min_mantissa);
+    }
+
+    for (int exponent = -324; exponent <= 308; ++exponent) {
+      double powten = pow(10.0, exponent);
+      if (powten == 0) powten = 5e-324;
+      if (kFloatNumCases >= 1e9) {
+        // The exhaustive test takes a very long time, so log progress.
+        char buf[kSixDigitsToBufferSize];
+        ABSL_RAW_LOG(
+            INFO, "%s",
+            absl::StrCat("Exp ", exponent, " powten=", powten, "(",
+                         powten, ") (",
+                         std::string(buf, SixDigitsToBuffer(powten, buf)), ")")
+                .c_str());
+      }
+      for (int digits : digit_testcases) {
+        if (exponent == 308 && digits >= 179769) break;  // don't overflow!
+        double digiform = (digits + 0.5) * 0.00001;
+        double testval = digiform * powten;
+        double pretestval = nextafter(testval, 0);
+        double posttestval = nextafter(testval, 1.7976931348623157e308);
+        checker(testval);
+        checker(pretestval);
+        checker(posttestval);
+      }
+    }
+  } else {
+    EXPECT_EQ(mismatches.size(), 0);
+    for (size_t i = 0; i < mismatches.size(); ++i) {
+      if (i > 100) i = mismatches.size() - 1;
+      double d = mismatches[i];
+      char sixdigitsbuf[kSixDigitsToBufferSize] = {0};
+      SixDigitsToBuffer(d, sixdigitsbuf);
+      char snprintfbuf[kSixDigitsToBufferSize] = {0};
+      snprintf(snprintfbuf, kSixDigitsToBufferSize, "%g", d);
+      double before = nextafter(d, 0.0);
+      double after = nextafter(d, 1.7976931348623157e308);
+      char b1[32], b2[kSixDigitsToBufferSize];
+      ABSL_RAW_LOG(
+          ERROR, "%s",
+          absl::StrCat(
+              "Mismatch #", i, "  d=", d, " (", ToNineDigits(d), ")",
+              " sixdigits='", sixdigitsbuf, "'", " snprintf='", snprintfbuf,
+              "'", " Before.=", PerfectDtoa(before), " ",
+              (SixDigitsToBuffer(before, b2), b2),
+              " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", before), b1),
+              " Perfect=", PerfectDtoa(d), " ", (SixDigitsToBuffer(d, b2), b2),
+              " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", d), b1),
+              " After.=.", PerfectDtoa(after), " ",
+              (SixDigitsToBuffer(after, b2), b2),
+              " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", after), b1))
+              .c_str());
+    }
+  }
+}
+
+TEST(StrToInt32, Partial) {
+  struct Int32TestLine {
+    std::string input;
+    bool status;
+    int32_t value;
+  };
+  const int32_t int32_min = std::numeric_limits<int32_t>::min();
+  const int32_t int32_max = std::numeric_limits<int32_t>::max();
+  Int32TestLine int32_test_line[] = {
+      {"", false, 0},
+      {" ", false, 0},
+      {"-", false, 0},
+      {"123@@@", false, 123},
+      {absl::StrCat(int32_min, int32_max), false, int32_min},
+      {absl::StrCat(int32_max, int32_max), false, int32_max},
+  };
+
+  for (const Int32TestLine& test_line : int32_test_line) {
+    int32_t value = -2;
+    bool status = safe_strto32_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = -2;
+    status = safe_strto32_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = -2;
+    status = safe_strto32_base(absl::string_view(test_line.input), &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+  }
+}
+
+TEST(StrToUint32, Partial) {
+  struct Uint32TestLine {
+    std::string input;
+    bool status;
+    uint32_t value;
+  };
+  const uint32_t uint32_max = std::numeric_limits<uint32_t>::max();
+  Uint32TestLine uint32_test_line[] = {
+      {"", false, 0},
+      {" ", false, 0},
+      {"-", false, 0},
+      {"123@@@", false, 123},
+      {absl::StrCat(uint32_max, uint32_max), false, uint32_max},
+  };
+
+  for (const Uint32TestLine& test_line : uint32_test_line) {
+    uint32_t value = 2;
+    bool status = safe_strtou32_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = 2;
+    status = safe_strtou32_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = 2;
+    status = safe_strtou32_base(absl::string_view(test_line.input), &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+  }
+}
+
+TEST(StrToInt64, Partial) {
+  struct Int64TestLine {
+    std::string input;
+    bool status;
+    int64_t value;
+  };
+  const int64_t int64_min = std::numeric_limits<int64_t>::min();
+  const int64_t int64_max = std::numeric_limits<int64_t>::max();
+  Int64TestLine int64_test_line[] = {
+      {"", false, 0},
+      {" ", false, 0},
+      {"-", false, 0},
+      {"123@@@", false, 123},
+      {absl::StrCat(int64_min, int64_max), false, int64_min},
+      {absl::StrCat(int64_max, int64_max), false, int64_max},
+  };
+
+  for (const Int64TestLine& test_line : int64_test_line) {
+    int64_t value = -2;
+    bool status = safe_strto64_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = -2;
+    status = safe_strto64_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = -2;
+    status = safe_strto64_base(absl::string_view(test_line.input), &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+  }
+}
+
+TEST(StrToUint64, Partial) {
+  struct Uint64TestLine {
+    std::string input;
+    bool status;
+    uint64_t value;
+  };
+  const uint64_t uint64_max = std::numeric_limits<uint64_t>::max();
+  Uint64TestLine uint64_test_line[] = {
+      {"", false, 0},
+      {" ", false, 0},
+      {"-", false, 0},
+      {"123@@@", false, 123},
+      {absl::StrCat(uint64_max, uint64_max), false, uint64_max},
+  };
+
+  for (const Uint64TestLine& test_line : uint64_test_line) {
+    uint64_t value = 2;
+    bool status = safe_strtou64_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = 2;
+    status = safe_strtou64_base(test_line.input, &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+    value = 2;
+    status = safe_strtou64_base(absl::string_view(test_line.input), &value, 10);
+    EXPECT_EQ(test_line.status, status) << test_line.input;
+    EXPECT_EQ(test_line.value, value) << test_line.input;
+  }
+}
+
+TEST(StrToInt32Base, PrefixOnly) {
+  struct Int32TestLine {
+    std::string input;
+    bool status;
+    int32_t value;
+  };
+  Int32TestLine int32_test_line[] = {
+    { "", false, 0 },
+    { "-", false, 0 },
+    { "-0", true, 0 },
+    { "0", true, 0 },
+    { "0x", false, 0 },
+    { "-0x", false, 0 },
+  };
+  const int base_array[] = { 0, 2, 8, 10, 16 };
+
+  for (const Int32TestLine& line : int32_test_line) {
+    for (const int base : base_array) {
+      int32_t value = 2;
+      bool status = safe_strto32_base(line.input.c_str(), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strto32_base(line.input, &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strto32_base(absl::string_view(line.input), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+    }
+  }
+}
+
+TEST(StrToUint32Base, PrefixOnly) {
+  struct Uint32TestLine {
+    std::string input;
+    bool status;
+    uint32_t value;
+  };
+  Uint32TestLine uint32_test_line[] = {
+    { "", false, 0 },
+    { "0", true, 0 },
+    { "0x", false, 0 },
+  };
+  const int base_array[] = { 0, 2, 8, 10, 16 };
+
+  for (const Uint32TestLine& line : uint32_test_line) {
+    for (const int base : base_array) {
+      uint32_t value = 2;
+      bool status = safe_strtou32_base(line.input.c_str(), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strtou32_base(line.input, &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strtou32_base(absl::string_view(line.input), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+    }
+  }
+}
+
+TEST(StrToInt64Base, PrefixOnly) {
+  struct Int64TestLine {
+    std::string input;
+    bool status;
+    int64_t value;
+  };
+  Int64TestLine int64_test_line[] = {
+    { "", false, 0 },
+    { "-", false, 0 },
+    { "-0", true, 0 },
+    { "0", true, 0 },
+    { "0x", false, 0 },
+    { "-0x", false, 0 },
+  };
+  const int base_array[] = { 0, 2, 8, 10, 16 };
+
+  for (const Int64TestLine& line : int64_test_line) {
+    for (const int base : base_array) {
+      int64_t value = 2;
+      bool status = safe_strto64_base(line.input.c_str(), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strto64_base(line.input, &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strto64_base(absl::string_view(line.input), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+    }
+  }
+}
+
+TEST(StrToUint64Base, PrefixOnly) {
+  struct Uint64TestLine {
+    std::string input;
+    bool status;
+    uint64_t value;
+  };
+  Uint64TestLine uint64_test_line[] = {
+    { "", false, 0 },
+    { "0", true, 0 },
+    { "0x", false, 0 },
+  };
+  const int base_array[] = { 0, 2, 8, 10, 16 };
+
+  for (const Uint64TestLine& line : uint64_test_line) {
+    for (const int base : base_array) {
+      uint64_t value = 2;
+      bool status = safe_strtou64_base(line.input.c_str(), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strtou64_base(line.input, &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+      value = 2;
+      status = safe_strtou64_base(absl::string_view(line.input), &value, base);
+      EXPECT_EQ(line.status, status) << line.input << " " << base;
+      EXPECT_EQ(line.value, value) << line.input << " " << base;
+    }
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
new file mode 100644
index 0000000..3fe8c95
--- /dev/null
+++ b/absl/strings/str_cat.cc
@@ -0,0 +1,239 @@
+// Copyright 2017 The Abseil 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 "absl/strings/str_cat.h"
+
+#include <assert.h>
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+
+#include "absl/strings/ascii.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+
+namespace absl {
+
+AlphaNum::AlphaNum(Hex hex) {
+  char* const end = &digits_[numbers_internal::kFastToBufferSize];
+  char* writer = end;
+  uint64_t value = hex.value;
+  static const char hexdigits[] = "0123456789abcdef";
+  do {
+    *--writer = hexdigits[value & 0xF];
+    value >>= 4;
+  } while (value != 0);
+
+  char* beg;
+  if (end - writer < hex.width) {
+    beg = end - hex.width;
+    std::fill_n(beg, writer - beg, hex.fill);
+  } else {
+    beg = writer;
+  }
+
+  piece_ = absl::string_view(beg, end - beg);
+}
+
+AlphaNum::AlphaNum(Dec dec) {
+  assert(dec.width <= numbers_internal::kFastToBufferSize);
+  char* const end = &digits_[numbers_internal::kFastToBufferSize];
+  char* const minfill = end - dec.width;
+  char* writer = end;
+  uint64_t value = dec.value;
+  bool neg = dec.neg;
+  while (value > 9) {
+    *--writer = '0' + (value % 10);
+    value /= 10;
+  }
+  *--writer = '0' + value;
+  if (neg) *--writer = '-';
+
+  ptrdiff_t fillers = writer - minfill;
+  if (fillers > 0) {
+    // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
+    // But...: if the fill character is '0', then it's <+/-><fill><digits>
+    bool add_sign_again = false;
+    if (neg && dec.fill == '0') {  // If filling with '0',
+      ++writer;                    // ignore the sign we just added
+      add_sign_again = true;       // and re-add the sign later.
+    }
+    writer -= fillers;
+    std::fill_n(writer, fillers, dec.fill);
+    if (add_sign_again) *--writer = '-';
+  }
+
+  piece_ = absl::string_view(writer, end - writer);
+}
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or integers, with no delimiter.  This
+//    is designed to be the fastest possible way to construct a std::string out
+//    of a mix of raw C strings, StringPieces, strings, and integer values.
+// ----------------------------------------------------------------------
+
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten.
+static char* Append(char* out, const AlphaNum& x) {
+  // memcpy is allowed to overwrite arbitrary memory, so doing this after the
+  // call would force an extra fetch of x.size().
+  char* after = out + x.size();
+  memcpy(out, x.data(), x.size());
+  return after;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
+  std::string result;
+  absl::strings_internal::STLStringResizeUninitialized(&result,
+                                                       a.size() + b.size());
+  char* const begin = &*result.begin();
+  char* out = begin;
+  out = Append(out, a);
+  out = Append(out, b);
+  assert(out == begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
+  std::string result;
+  strings_internal::STLStringResizeUninitialized(
+      &result, a.size() + b.size() + c.size());
+  char* const begin = &*result.begin();
+  char* out = begin;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  assert(out == begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
+              const AlphaNum& d) {
+  std::string result;
+  strings_internal::STLStringResizeUninitialized(
+      &result, a.size() + b.size() + c.size() + d.size());
+  char* const begin = &*result.begin();
+  char* out = begin;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  out = Append(out, d);
+  assert(out == begin + result.size());
+  return result;
+}
+
+namespace strings_internal {
+
+// Do not call directly - these are not part of the public API.
+std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
+  std::string result;
+  size_t total_size = 0;
+  for (const absl::string_view piece : pieces) total_size += piece.size();
+  strings_internal::STLStringResizeUninitialized(&result, total_size);
+
+  char* const begin = &*result.begin();
+  char* out = begin;
+  for (const absl::string_view piece : pieces) {
+    const size_t this_size = piece.size();
+    memcpy(out, piece.data(), this_size);
+    out += this_size;
+  }
+  assert(out == begin + result.size());
+  return result;
+}
+
+// It's possible to call StrAppend with an absl::string_view that is itself a
+// fragment of the std::string we're appending to.  However the results of this are
+// random. Therefore, check for this in debug mode.  Use unsigned math so we
+// only have to do one comparison. Note, there's an exception case: appending an
+// empty std::string is always allowed.
+#define ASSERT_NO_OVERLAP(dest, src) \
+  assert(((src).size() == 0) ||      \
+         (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
+
+void AppendPieces(std::string* dest,
+                  std::initializer_list<absl::string_view> pieces) {
+  size_t old_size = dest->size();
+  size_t total_size = old_size;
+  for (const absl::string_view piece : pieces) {
+    ASSERT_NO_OVERLAP(*dest, piece);
+    total_size += piece.size();
+  }
+  strings_internal::STLStringResizeUninitialized(dest, total_size);
+
+  char* const begin = &*dest->begin();
+  char* out = begin + old_size;
+  for (const absl::string_view piece : pieces) {
+    const size_t this_size = piece.size();
+    memcpy(out, piece.data(), this_size);
+    out += this_size;
+  }
+  assert(out == begin + dest->size());
+}
+
+}  // namespace strings_internal
+
+void StrAppend(std::string* dest, const AlphaNum& a) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  dest->append(a.data(), a.size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  ASSERT_NO_OVERLAP(*dest, b);
+  std::string::size_type old_size = dest->size();
+  strings_internal::STLStringResizeUninitialized(
+      dest, old_size + a.size() + b.size());
+  char* const begin = &*dest->begin();
+  char* out = begin + old_size;
+  out = Append(out, a);
+  out = Append(out, b);
+  assert(out == begin + dest->size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  ASSERT_NO_OVERLAP(*dest, b);
+  ASSERT_NO_OVERLAP(*dest, c);
+  std::string::size_type old_size = dest->size();
+  strings_internal::STLStringResizeUninitialized(
+      dest, old_size + a.size() + b.size() + c.size());
+  char* const begin = &*dest->begin();
+  char* out = begin + old_size;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  assert(out == begin + dest->size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c, const AlphaNum& d) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  ASSERT_NO_OVERLAP(*dest, b);
+  ASSERT_NO_OVERLAP(*dest, c);
+  ASSERT_NO_OVERLAP(*dest, d);
+  std::string::size_type old_size = dest->size();
+  strings_internal::STLStringResizeUninitialized(
+      dest, old_size + a.size() + b.size() + c.size() + d.size());
+  char* const begin = &*dest->begin();
+  char* out = begin + old_size;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  out = Append(out, d);
+  assert(out == begin + dest->size());
+}
+
+}  // namespace absl
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
new file mode 100644
index 0000000..e5501a5
--- /dev/null
+++ b/absl/strings/str_cat.h
@@ -0,0 +1,385 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: str_cat.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for efficiently concatenating and appending
+// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines
+// is actually handled through use of a special AlphaNum type, which was
+// designed to be used as a parameter type that efficiently manages conversion
+// to strings and avoids copies in the above operations.
+//
+// Any routine accepting either a std::string or a number may accept `AlphaNum`.
+// The basic idea is that by accepting a `const AlphaNum &` as an argument
+// to your function, your callers will automagically convert bools, integers,
+// and floating point values to strings for you.
+//
+// NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported
+// except for the specific case of function parameters of type `AlphaNum` or
+// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a
+// stack variable is not supported.
+//
+// Conversion from 8-bit values is not accepted because, if it were, then an
+// attempt to pass ':' instead of ":" might result in a 58 ending up in your
+// result.
+//
+// Bools convert to "0" or "1".
+//
+// Floating point numbers are formatted with six-digit precision, which is
+// the default for "std::cout <<" or printf "%g" (the same as "%.6g").
+//
+//
+// You can convert to hexadecimal output rather than decimal output using the
+// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
+// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
+// a `PadSpec` enum.
+//
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_STRINGS_STR_CAT_H_
+#define ABSL_STRINGS_STR_CAT_H_
+
+#include <array>
+#include <cstdint>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+namespace strings_internal {
+// AlphaNumBuffer allows a way to pass a std::string to StrCat without having to do
+// memory allocation.  It is simply a pair of a fixed-size character array, and
+// a size.  Please don't use outside of absl, yet.
+template <size_t max_size>
+struct AlphaNumBuffer {
+  std::array<char, max_size> data;
+  size_t size;
+};
+
+}  // namespace strings_internal
+
+// Enum that specifies the number of significant digits to return in a `Hex` or
+// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
+// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
+// would produce hexadecimal strings such as "    A","    F".
+enum PadSpec : uint8_t {
+  kNoPad = 1,
+  kZeroPad2,
+  kZeroPad3,
+  kZeroPad4,
+  kZeroPad5,
+  kZeroPad6,
+  kZeroPad7,
+  kZeroPad8,
+  kZeroPad9,
+  kZeroPad10,
+  kZeroPad11,
+  kZeroPad12,
+  kZeroPad13,
+  kZeroPad14,
+  kZeroPad15,
+  kZeroPad16,
+
+  kSpacePad2 = kZeroPad2 + 64,
+  kSpacePad3,
+  kSpacePad4,
+  kSpacePad5,
+  kSpacePad6,
+  kSpacePad7,
+  kSpacePad8,
+  kSpacePad9,
+  kSpacePad10,
+  kSpacePad11,
+  kSpacePad12,
+  kSpacePad13,
+  kSpacePad14,
+  kSpacePad15,
+  kSpacePad16,
+};
+
+// -----------------------------------------------------------------------------
+// Hex
+// -----------------------------------------------------------------------------
+//
+// `Hex` stores a set of hexadecimal std::string conversion parameters for use
+// within `AlphaNum` std::string conversions.
+struct Hex {
+  uint64_t value;
+  uint8_t width;
+  char fill;
+
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 1 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint8_t>(v)) {}
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 2 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint16_t>(v)) {}
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 4 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint32_t>(v)) {}
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 8 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint64_t>(v)) {}
+  template <typename Pointee>
+  explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
+      : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
+
+ private:
+  Hex(PadSpec spec, uint64_t v)
+      : value(v),
+        width(spec == absl::kNoPad
+                  ? 1
+                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
+                                             : spec - absl::kZeroPad2 + 2),
+        fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
+};
+
+// -----------------------------------------------------------------------------
+// Dec
+// -----------------------------------------------------------------------------
+//
+// `Dec` stores a set of decimal std::string conversion parameters for use
+// within `AlphaNum` std::string conversions.  Dec is slower than the default
+// integer conversion, so use it only if you need padding.
+struct Dec {
+  uint64_t value;
+  uint8_t width;
+  char fill;
+  bool neg;
+
+  template <typename Int>
+  explicit Dec(Int v, PadSpec spec = absl::kNoPad,
+               typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
+      : value(v >= 0 ? static_cast<uint64_t>(v)
+                     : uint64_t{0} - static_cast<uint64_t>(v)),
+        width(spec == absl::kNoPad
+                  ? 1
+                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
+                                             : spec - absl::kZeroPad2 + 2),
+        fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
+        neg(v < 0) {}
+};
+
+// -----------------------------------------------------------------------------
+// AlphaNum
+// -----------------------------------------------------------------------------
+//
+// The `AlphaNum` class acts as the main parameter type for `StrCat()` and
+// `StrAppend()`, providing efficient conversion of numeric, boolean, and
+// hexadecimal values (through the `Hex` type) into strings.
+
+class AlphaNum {
+ public:
+  // No bool ctor -- bools convert to an integral type.
+  // A bool ctor would also convert incoming pointers (bletch).
+
+  AlphaNum(int x)  // NOLINT(runtime/explicit)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(unsigned int x)  // NOLINT(runtime/explicit)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(unsigned long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(long long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(unsigned long long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+
+  AlphaNum(float f)  // NOLINT(runtime/explicit)
+      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
+  AlphaNum(double f)  // NOLINT(runtime/explicit)
+      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
+
+  AlphaNum(Hex hex);  // NOLINT(runtime/explicit)
+  AlphaNum(Dec dec);  // NOLINT(runtime/explicit)
+
+  template <size_t size>
+  AlphaNum(  // NOLINT(runtime/explicit)
+      const strings_internal::AlphaNumBuffer<size>& buf)
+      : piece_(&buf.data[0], buf.size) {}
+
+  AlphaNum(const char* c_str) : piece_(c_str) {}  // NOLINT(runtime/explicit)
+  AlphaNum(absl::string_view pc) : piece_(pc) {}  // NOLINT(runtime/explicit)
+  template <typename Allocator>
+  AlphaNum(  // NOLINT(runtime/explicit)
+      const std::basic_string<char, std::char_traits<char>, Allocator>& str)
+      : piece_(str) {}
+
+  // Use std::string literals ":" instead of character literals ':'.
+  AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
+
+  AlphaNum(const AlphaNum&) = delete;
+  AlphaNum& operator=(const AlphaNum&) = delete;
+
+  absl::string_view::size_type size() const { return piece_.size(); }
+  const char* data() const { return piece_.data(); }
+  absl::string_view Piece() const { return piece_; }
+
+  // Normal enums are already handled by the integer formatters.
+  // This overload matches only scoped enums.
+  template <typename T,
+            typename = typename std::enable_if<
+                std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
+  AlphaNum(T e)  // NOLINT(runtime/explicit)
+      : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
+
+ private:
+  absl::string_view piece_;
+  char digits_[numbers_internal::kFastToBufferSize];
+};
+
+// -----------------------------------------------------------------------------
+// StrCat()
+// -----------------------------------------------------------------------------
+//
+// Merges given strings or numbers, using no delimiter(s).
+//
+// `StrCat()` is designed to be the fastest possible way to construct a std::string
+// out of a mix of raw C strings, string_views, strings, bool values,
+// and numeric values.
+//
+// Don't use `StrCat()` for user-visible strings. The localization process
+// works poorly on strings built up out of fragments.
+//
+// For clarity and performance, don't use `StrCat()` when appending to a
+// std::string. Use `StrAppend()` instead. In particular, avoid using any of these
+// (anti-)patterns:
+//
+//   str.append(StrCat(...))
+//   str += StrCat(...)
+//   str = StrCat(str, ...)
+//
+// The last case is the worst, with a potential to change a loop
+// from a linear time operation with O(1) dynamic allocations into a
+// quadratic time operation with O(n) dynamic allocations.
+//
+// See `StrAppend()` below for more information.
+
+namespace strings_internal {
+
+// Do not call directly - this is not part of the public API.
+std::string CatPieces(std::initializer_list<absl::string_view> pieces);
+void AppendPieces(std::string* dest,
+                  std::initializer_list<absl::string_view> pieces);
+
+}  // namespace strings_internal
+
+ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
+
+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
+  return std::string(a.data(), a.size());
+}
+
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c);
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                   const AlphaNum& c, const AlphaNum& d);
+
+// Support 5 or more arguments
+template <typename... AV>
+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                          const AlphaNum& c, const AlphaNum& d,
+                                          const AlphaNum& e,
+                                          const AV&... args) {
+  return strings_internal::CatPieces(
+      {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
+       static_cast<const AlphaNum&>(args).Piece()...});
+}
+
+// -----------------------------------------------------------------------------
+// StrAppend()
+// -----------------------------------------------------------------------------
+//
+// Appends a std::string or set of strings to an existing std::string, in a similar
+// fashion to `StrCat()`.
+//
+// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
+// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
+// not try to check each of its input arguments to be sure that they are not
+// a subset of the std::string being appended to. That is, while this will work:
+//
+//   std::string s = "foo";
+//   s += s;
+//
+// This output is undefined:
+//
+//   std::string s = "foo";
+//   StrAppend(&s, s);
+//
+// This output is undefined as well, since `absl::string_view` does not own its
+// data:
+//
+//   std::string s = "foobar";
+//   absl::string_view p = s;
+//   StrAppend(&s, p);
+
+inline void StrAppend(std::string*) {}
+void StrAppend(std::string* dest, const AlphaNum& a);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c, const AlphaNum& d);
+
+// Support 5 or more arguments
+template <typename... AV>
+inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+                      const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
+                      const AV&... args) {
+  strings_internal::AppendPieces(
+      dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
+             static_cast<const AlphaNum&>(args).Piece()...});
+}
+
+// Helper function for the future StrCat default floating-point format, %.6g
+// This is fast.
+inline strings_internal::AlphaNumBuffer<
+    numbers_internal::kSixDigitsToBufferSize>
+SixDigits(double d) {
+  strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize>
+      result;
+  result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
+  return result;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_CAT_H_
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc
new file mode 100644
index 0000000..b6df9e3
--- /dev/null
+++ b/absl/strings/str_cat_benchmark.cc
@@ -0,0 +1,140 @@
+// Copyright 2018 The Abseil 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 "absl/strings/str_cat.h"
+
+#include <cstdint>
+#include <string>
+
+#include "benchmark/benchmark.h"
+#include "absl/strings/substitute.h"
+
+namespace {
+
+const char kStringOne[] = "Once Upon A Time, ";
+const char kStringTwo[] = "There was a std::string benchmark";
+
+// We want to include negative numbers in the benchmark, so this function
+// is used to count 0, 1, -1, 2, -2, 3, -3, ...
+inline int IncrementAlternatingSign(int i) {
+  return i > 0 ? -i : 1 - i;
+}
+
+void BM_Sum_By_StrCat(benchmark::State& state) {
+  int i = 0;
+  char foo[100];
+  for (auto _ : state) {
+    // NOLINTNEXTLINE(runtime/printf)
+    strcpy(foo, absl::StrCat(kStringOne, i, kStringTwo, i * 65536ULL).c_str());
+    int sum = 0;
+    for (char* f = &foo[0]; *f != 0; ++f) {
+      sum += *f;
+    }
+    benchmark::DoNotOptimize(sum);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_Sum_By_StrCat);
+
+void BM_StrCat_By_snprintf(benchmark::State& state) {
+  int i = 0;
+  char on_stack[1000];
+  for (auto _ : state) {
+    snprintf(on_stack, sizeof(on_stack), "%s %s:%d", kStringOne, kStringTwo, i);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_StrCat_By_snprintf);
+
+void BM_StrCat_By_Strings(benchmark::State& state) {
+  int i = 0;
+  for (auto _ : state) {
+    std::string result =
+        std::string(kStringOne) + " " + kStringTwo + ":" + absl::StrCat(i);
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_StrCat_By_Strings);
+
+void BM_StrCat_By_StringOpPlus(benchmark::State& state) {
+  int i = 0;
+  for (auto _ : state) {
+    std::string result = kStringOne;
+    result += " ";
+    result += kStringTwo;
+    result += ":";
+    result += absl::StrCat(i);
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_StrCat_By_StringOpPlus);
+
+void BM_StrCat_By_StrCat(benchmark::State& state) {
+  int i = 0;
+  for (auto _ : state) {
+    std::string result = absl::StrCat(kStringOne, " ", kStringTwo, ":", i);
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_StrCat_By_StrCat);
+
+void BM_HexCat_By_StrCat(benchmark::State& state) {
+  int i = 0;
+  for (auto _ : state) {
+    std::string result =
+        absl::StrCat(kStringOne, " ", absl::Hex(int64_t{i} + 0x10000000));
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_HexCat_By_StrCat);
+
+void BM_HexCat_By_Substitute(benchmark::State& state) {
+  int i = 0;
+  for (auto _ : state) {
+    std::string result = absl::Substitute(
+        "$0 $1", kStringOne, reinterpret_cast<void*>(int64_t{i} + 0x10000000));
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_HexCat_By_Substitute);
+
+void BM_FloatToString_By_StrCat(benchmark::State& state) {
+  int i = 0;
+  float foo = 0.0f;
+  for (auto _ : state) {
+    std::string result = absl::StrCat(foo += 1.001f, " != ", int64_t{i});
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_FloatToString_By_StrCat);
+
+void BM_DoubleToString_By_SixDigits(benchmark::State& state) {
+  int i = 0;
+  double foo = 0.0;
+  for (auto _ : state) {
+    std::string result =
+        absl::StrCat(absl::SixDigits(foo += 1.001), " != ", int64_t{i});
+    benchmark::DoNotOptimize(result);
+    i = IncrementAlternatingSign(i);
+  }
+}
+BENCHMARK(BM_DoubleToString_By_SixDigits);
+
+}  // namespace
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
new file mode 100644
index 0000000..e9d6769
--- /dev/null
+++ b/absl/strings/str_cat_test.cc
@@ -0,0 +1,549 @@
+// Copyright 2017 The Abseil 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.
+
+// Unit tests for all str_cat.h functions
+
+#include "absl/strings/str_cat.h"
+
+#include <cstdint>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/strings/substitute.h"
+
+#ifdef __ANDROID__
+// Android assert messages only go to system log, so death tests cannot inspect
+// the message for matching.
+#define ABSL_EXPECT_DEBUG_DEATH(statement, regex) \
+  EXPECT_DEBUG_DEATH(statement, ".*")
+#else
+#define ABSL_EXPECT_DEBUG_DEATH EXPECT_DEBUG_DEATH
+#endif
+
+namespace {
+
+// Test absl::StrCat of ints and longs of various sizes and signdedness.
+TEST(StrCat, Ints) {
+  const short s = -1;  // NOLINT(runtime/int)
+  const uint16_t us = 2;
+  const int i = -3;
+  const unsigned int ui = 4;
+  const long l = -5;                 // NOLINT(runtime/int)
+  const unsigned long ul = 6;        // NOLINT(runtime/int)
+  const long long ll = -7;           // NOLINT(runtime/int)
+  const unsigned long long ull = 8;  // NOLINT(runtime/int)
+  const ptrdiff_t ptrdiff = -9;
+  const size_t size = 10;
+  const intptr_t intptr = -12;
+  const uintptr_t uintptr = 13;
+  std::string answer;
+  answer = absl::StrCat(s, us);
+  EXPECT_EQ(answer, "-12");
+  answer = absl::StrCat(i, ui);
+  EXPECT_EQ(answer, "-34");
+  answer = absl::StrCat(l, ul);
+  EXPECT_EQ(answer, "-56");
+  answer = absl::StrCat(ll, ull);
+  EXPECT_EQ(answer, "-78");
+  answer = absl::StrCat(ptrdiff, size);
+  EXPECT_EQ(answer, "-910");
+  answer = absl::StrCat(ptrdiff, intptr);
+  EXPECT_EQ(answer, "-9-12");
+  answer = absl::StrCat(uintptr, 0);
+  EXPECT_EQ(answer, "130");
+}
+
+TEST(StrCat, Enums) {
+  enum SmallNumbers { One = 1, Ten = 10 } e = Ten;
+  EXPECT_EQ("10", absl::StrCat(e));
+  EXPECT_EQ("-5", absl::StrCat(SmallNumbers(-5)));
+
+  enum class Option { Boxers = 1, Briefs = -1 };
+
+  EXPECT_EQ("-1", absl::StrCat(Option::Briefs));
+
+  enum class Airplane : uint64_t {
+    Airbus = 1,
+    Boeing = 1000,
+    Canary = 10000000000  // too big for "int"
+  };
+
+  EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary));
+
+  enum class TwoGig : int32_t {
+    TwoToTheZero = 1,
+    TwoToTheSixteenth = 1 << 16,
+    TwoToTheThirtyFirst = INT32_MIN
+  };
+  EXPECT_EQ("65536", absl::StrCat(TwoGig::TwoToTheSixteenth));
+  EXPECT_EQ("-2147483648", absl::StrCat(TwoGig::TwoToTheThirtyFirst));
+  EXPECT_EQ("-1", absl::StrCat(static_cast<TwoGig>(-1)));
+
+  enum class FourGig : uint32_t {
+    TwoToTheZero = 1,
+    TwoToTheSixteenth = 1 << 16,
+    TwoToTheThirtyFirst = 1U << 31  // too big for "int"
+  };
+  EXPECT_EQ("65536", absl::StrCat(FourGig::TwoToTheSixteenth));
+  EXPECT_EQ("2147483648", absl::StrCat(FourGig::TwoToTheThirtyFirst));
+  EXPECT_EQ("4294967295", absl::StrCat(static_cast<FourGig>(-1)));
+
+  EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary));
+}
+
+TEST(StrCat, Basics) {
+  std::string result;
+
+  std::string strs[] = {
+    "Hello",
+    "Cruel",
+    "World"
+  };
+
+  std::string stdstrs[] = {
+    "std::Hello",
+    "std::Cruel",
+    "std::World"
+  };
+
+  absl::string_view pieces[] = {"Hello", "Cruel", "World"};
+
+  const char* c_strs[] = {
+    "Hello",
+    "Cruel",
+    "World"
+  };
+
+  int32_t i32s[] = {'H', 'C', 'W'};
+  uint64_t ui64s[] = {12345678910LL, 10987654321LL};
+
+  EXPECT_EQ(absl::StrCat(), "");
+
+  result = absl::StrCat(false, true, 2, 3);
+  EXPECT_EQ(result, "0123");
+
+  result = absl::StrCat(-1);
+  EXPECT_EQ(result, "-1");
+
+  result = absl::StrCat(absl::SixDigits(0.5));
+  EXPECT_EQ(result, "0.5");
+
+  result = absl::StrCat(strs[1], pieces[2]);
+  EXPECT_EQ(result, "CruelWorld");
+
+  result = absl::StrCat(stdstrs[1], " ", stdstrs[2]);
+  EXPECT_EQ(result, "std::Cruel std::World");
+
+  result = absl::StrCat(strs[0], ", ", pieces[2]);
+  EXPECT_EQ(result, "Hello, World");
+
+  result = absl::StrCat(strs[0], ", ", strs[1], " ", strs[2], "!");
+  EXPECT_EQ(result, "Hello, Cruel World!");
+
+  result = absl::StrCat(pieces[0], ", ", pieces[1], " ", pieces[2]);
+  EXPECT_EQ(result, "Hello, Cruel World");
+
+  result = absl::StrCat(c_strs[0], ", ", c_strs[1], " ", c_strs[2]);
+  EXPECT_EQ(result, "Hello, Cruel World");
+
+  result = absl::StrCat("ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!");
+  EXPECT_EQ(result, "ASCII 72, 67 87!");
+
+  result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!");
+  EXPECT_EQ(result, "12345678910, 10987654321!");
+
+  std::string one = "1";  // Actually, it's the size of this std::string that we want; a
+                     // 64-bit build distinguishes between size_t and uint64_t,
+                     // even though they're both unsigned 64-bit values.
+  result = absl::StrCat("And a ", one.size(), " and a ",
+                        &result[2] - &result[0], " and a ", one, " 2 3 4", "!");
+  EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!");
+
+  // result = absl::StrCat("Single chars won't compile", '!');
+  // result = absl::StrCat("Neither will nullptrs", nullptr);
+  result =
+      absl::StrCat("To output a char by ASCII/numeric value, use +: ", '!' + 0);
+  EXPECT_EQ(result, "To output a char by ASCII/numeric value, use +: 33");
+
+  float f = 100000.5;
+  result = absl::StrCat("A hundred K and a half is ", absl::SixDigits(f));
+  EXPECT_EQ(result, "A hundred K and a half is 100000");
+
+  f = 100001.5;
+  result =
+      absl::StrCat("A hundred K and one and a half is ", absl::SixDigits(f));
+  EXPECT_EQ(result, "A hundred K and one and a half is 100002");
+
+  double d = 100000.5;
+  d *= d;
+  result =
+      absl::StrCat("A hundred K and a half squared is ", absl::SixDigits(d));
+  EXPECT_EQ(result, "A hundred K and a half squared is 1.00001e+10");
+
+  result = absl::StrCat(1, 2, 333, 4444, 55555, 666666, 7777777, 88888888,
+                        999999999);
+  EXPECT_EQ(result, "12333444455555666666777777788888888999999999");
+}
+
+// A minimal allocator that uses malloc().
+template <typename T>
+struct Mallocator {
+  typedef T value_type;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+  typedef T* pointer;
+  typedef const T* const_pointer;
+  typedef T& reference;
+  typedef const T& const_reference;
+
+  size_type max_size() const {
+    return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type);
+  }
+  template <typename U>
+  struct rebind {
+    typedef Mallocator<U> other;
+  };
+  Mallocator() = default;
+  template <class U>
+  Mallocator(const Mallocator<U>&) {}  // NOLINT(runtime/explicit)
+
+  T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
+  void deallocate(T* p, size_t) { std::free(p); }
+};
+template <typename T, typename U>
+bool operator==(const Mallocator<T>&, const Mallocator<U>&) {
+  return true;
+}
+template <typename T, typename U>
+bool operator!=(const Mallocator<T>&, const Mallocator<U>&) {
+  return false;
+}
+
+TEST(StrCat, CustomAllocator) {
+  using mstring =
+      std::basic_string<char, std::char_traits<char>, Mallocator<char>>;
+  const mstring str1("PARACHUTE OFF A BLIMP INTO MOSCONE!!");
+
+  const mstring str2("Read this book about coffee tables");
+
+  std::string result = absl::StrCat(str1, str2);
+  EXPECT_EQ(result,
+            "PARACHUTE OFF A BLIMP INTO MOSCONE!!"
+            "Read this book about coffee tables");
+}
+
+TEST(StrCat, MaxArgs) {
+  std::string result;
+  // Test 10 up to 26 arguments, the old maximum
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a");
+  EXPECT_EQ(result, "123456789a");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b");
+  EXPECT_EQ(result, "123456789ab");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c");
+  EXPECT_EQ(result, "123456789abc");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d");
+  EXPECT_EQ(result, "123456789abcd");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e");
+  EXPECT_EQ(result, "123456789abcde");
+  result =
+      absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f");
+  EXPECT_EQ(result, "123456789abcdef");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g");
+  EXPECT_EQ(result, "123456789abcdefg");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h");
+  EXPECT_EQ(result, "123456789abcdefgh");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i");
+  EXPECT_EQ(result, "123456789abcdefghi");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j");
+  EXPECT_EQ(result, "123456789abcdefghij");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k");
+  EXPECT_EQ(result, "123456789abcdefghijk");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k", "l");
+  EXPECT_EQ(result, "123456789abcdefghijkl");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k", "l", "m");
+  EXPECT_EQ(result, "123456789abcdefghijklm");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k", "l", "m", "n");
+  EXPECT_EQ(result, "123456789abcdefghijklmn");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k", "l", "m", "n", "o");
+  EXPECT_EQ(result, "123456789abcdefghijklmno");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k", "l", "m", "n", "o", "p");
+  EXPECT_EQ(result, "123456789abcdefghijklmnop");
+  result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+                        "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q");
+  EXPECT_EQ(result, "123456789abcdefghijklmnopq");
+  // No limit thanks to C++11's variadic templates
+  result = absl::StrCat(
+      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "a", "b", "c", "d", "e", "f", "g", "h",
+      "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w",
+      "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
+      "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
+  EXPECT_EQ(result,
+            "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+}
+
+TEST(StrAppend, Basics) {
+  std::string result = "existing text";
+
+  std::string strs[] = {
+    "Hello",
+    "Cruel",
+    "World"
+  };
+
+  std::string stdstrs[] = {
+    "std::Hello",
+    "std::Cruel",
+    "std::World"
+  };
+
+  absl::string_view pieces[] = {"Hello", "Cruel", "World"};
+
+  const char* c_strs[] = {
+    "Hello",
+    "Cruel",
+    "World"
+  };
+
+  int32_t i32s[] = {'H', 'C', 'W'};
+  uint64_t ui64s[] = {12345678910LL, 10987654321LL};
+
+  std::string::size_type old_size = result.size();
+  absl::StrAppend(&result);
+  EXPECT_EQ(result.size(), old_size);
+
+  old_size = result.size();
+  absl::StrAppend(&result, strs[0]);
+  EXPECT_EQ(result.substr(old_size), "Hello");
+
+  old_size = result.size();
+  absl::StrAppend(&result, strs[1], pieces[2]);
+  EXPECT_EQ(result.substr(old_size), "CruelWorld");
+
+  old_size = result.size();
+  absl::StrAppend(&result, stdstrs[0], ", ", pieces[2]);
+  EXPECT_EQ(result.substr(old_size), "std::Hello, World");
+
+  old_size = result.size();
+  absl::StrAppend(&result, strs[0], ", ", stdstrs[1], " ", strs[2], "!");
+  EXPECT_EQ(result.substr(old_size), "Hello, std::Cruel World!");
+
+  old_size = result.size();
+  absl::StrAppend(&result, pieces[0], ", ", pieces[1], " ", pieces[2]);
+  EXPECT_EQ(result.substr(old_size), "Hello, Cruel World");
+
+  old_size = result.size();
+  absl::StrAppend(&result, c_strs[0], ", ", c_strs[1], " ", c_strs[2]);
+  EXPECT_EQ(result.substr(old_size), "Hello, Cruel World");
+
+  old_size = result.size();
+  absl::StrAppend(&result, "ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!");
+  EXPECT_EQ(result.substr(old_size), "ASCII 72, 67 87!");
+
+  old_size = result.size();
+  absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!");
+  EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!");
+
+  std::string one = "1";  // Actually, it's the size of this std::string that we want; a
+                     // 64-bit build distinguishes between size_t and uint64_t,
+                     // even though they're both unsigned 64-bit values.
+  old_size = result.size();
+  absl::StrAppend(&result, "And a ", one.size(), " and a ",
+                  &result[2] - &result[0], " and a ", one, " 2 3 4", "!");
+  EXPECT_EQ(result.substr(old_size), "And a 1 and a 2 and a 1 2 3 4!");
+
+  // result = absl::StrCat("Single chars won't compile", '!');
+  // result = absl::StrCat("Neither will nullptrs", nullptr);
+  old_size = result.size();
+  absl::StrAppend(&result,
+                  "To output a char by ASCII/numeric value, use +: ", '!' + 0);
+  EXPECT_EQ(result.substr(old_size),
+            "To output a char by ASCII/numeric value, use +: 33");
+
+  // Test 9 arguments, the old maximum
+  old_size = result.size();
+  absl::StrAppend(&result, 1, 22, 333, 4444, 55555, 666666, 7777777, 88888888,
+                  9);
+  EXPECT_EQ(result.substr(old_size), "1223334444555556666667777777888888889");
+
+  // No limit thanks to C++11's variadic templates
+  old_size = result.size();
+  absl::StrAppend(
+      &result, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,                           //
+      "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",  //
+      "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",  //
+      "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",  //
+      "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",  //
+      "No limit thanks to C++11's variadic templates");
+  EXPECT_EQ(result.substr(old_size),
+            "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            "No limit thanks to C++11's variadic templates");
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+TEST(StrAppend, Death) {
+  std::string s = "self";
+  // on linux it's "assertion", on mac it's "Assertion",
+  // on chromiumos it's "Assertion ... failed".
+  ABSL_EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s.c_str() + 1),
+                          "ssertion.*failed");
+  ABSL_EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s), "ssertion.*failed");
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+TEST(StrAppend, EmptyString) {
+  std::string s = "";
+  absl::StrAppend(&s, s);
+  EXPECT_EQ(s, "");
+}
+
+template <typename IntType>
+void CheckHex(IntType v, const char* nopad_format, const char* zeropad_format,
+              const char* spacepad_format) {
+  char expected[256];
+
+  std::string actual = absl::StrCat(absl::Hex(v, absl::kNoPad));
+  snprintf(expected, sizeof(expected), nopad_format, v);
+  EXPECT_EQ(expected, actual) << " decimal value " << v;
+
+  for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) {
+    std::string actual =
+        absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
+    snprintf(expected, sizeof(expected), zeropad_format,
+             spec - absl::kZeroPad2 + 2, v);
+    EXPECT_EQ(expected, actual) << " decimal value " << v;
+  }
+
+  for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) {
+    std::string actual =
+        absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
+    snprintf(expected, sizeof(expected), spacepad_format,
+             spec - absl::kSpacePad2 + 2, v);
+    EXPECT_EQ(expected, actual) << " decimal value " << v;
+  }
+}
+
+template <typename IntType>
+void CheckDec(IntType v, const char* nopad_format, const char* zeropad_format,
+              const char* spacepad_format) {
+  char expected[256];
+
+  std::string actual = absl::StrCat(absl::Dec(v, absl::kNoPad));
+  snprintf(expected, sizeof(expected), nopad_format, v);
+  EXPECT_EQ(expected, actual) << " decimal value " << v;
+
+  for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) {
+    std::string actual =
+        absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec)));
+    snprintf(expected, sizeof(expected), zeropad_format,
+             spec - absl::kZeroPad2 + 2, v);
+    EXPECT_EQ(expected, actual)
+        << " decimal value " << v << " format '" << zeropad_format
+        << "' digits " << (spec - absl::kZeroPad2 + 2);
+  }
+
+  for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) {
+    std::string actual =
+        absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec)));
+    snprintf(expected, sizeof(expected), spacepad_format,
+             spec - absl::kSpacePad2 + 2, v);
+    EXPECT_EQ(expected, actual)
+        << " decimal value " << v << " format '" << spacepad_format
+        << "' digits " << (spec - absl::kSpacePad2 + 2);
+  }
+}
+
+void CheckHexDec64(uint64_t v) {
+  unsigned long long ullv = v;  // NOLINT(runtime/int)
+
+  CheckHex(ullv, "%llx", "%0*llx", "%*llx");
+  CheckDec(ullv, "%llu", "%0*llu", "%*llu");
+
+  long long llv = static_cast<long long>(ullv);  // NOLINT(runtime/int)
+  CheckDec(llv, "%lld", "%0*lld", "%*lld");
+
+  if (sizeof(v) == sizeof(&v)) {
+    auto uintptr = static_cast<uintptr_t>(v);
+    void* ptr = reinterpret_cast<void*>(uintptr);
+    CheckHex(ptr, "%llx", "%0*llx", "%*llx");
+  }
+}
+
+void CheckHexDec32(uint32_t uv) {
+  CheckHex(uv, "%x", "%0*x", "%*x");
+  CheckDec(uv, "%u", "%0*u", "%*u");
+  int32_t v = static_cast<int32_t>(uv);
+  CheckDec(v, "%d", "%0*d", "%*d");
+
+  if (sizeof(v) == sizeof(&v)) {
+    auto uintptr = static_cast<uintptr_t>(v);
+    void* ptr = reinterpret_cast<void*>(uintptr);
+    CheckHex(ptr, "%x", "%0*x", "%*x");
+  }
+}
+
+void CheckAll(uint64_t v) {
+  CheckHexDec64(v);
+  CheckHexDec32(static_cast<uint32_t>(v));
+}
+
+void TestFastPrints() {
+  // Test all small ints; there aren't many and they're common.
+  for (int i = 0; i < 10000; i++) {
+    CheckAll(i);
+  }
+
+  CheckAll(std::numeric_limits<uint64_t>::max());
+  CheckAll(std::numeric_limits<uint64_t>::max() - 1);
+  CheckAll(std::numeric_limits<int64_t>::min());
+  CheckAll(std::numeric_limits<int64_t>::min() + 1);
+  CheckAll(std::numeric_limits<uint32_t>::max());
+  CheckAll(std::numeric_limits<uint32_t>::max() - 1);
+  CheckAll(std::numeric_limits<int32_t>::min());
+  CheckAll(std::numeric_limits<int32_t>::min() + 1);
+  CheckAll(999999999);              // fits in 32 bits
+  CheckAll(1000000000);             // fits in 32 bits
+  CheckAll(9999999999);             // doesn't fit in 32 bits
+  CheckAll(10000000000);            // doesn't fit in 32 bits
+  CheckAll(999999999999999999);     // fits in signed 64-bit
+  CheckAll(9999999999999999999u);   // fits in unsigned 64-bit, but not signed.
+  CheckAll(1000000000000000000);    // fits in signed 64-bit
+  CheckAll(10000000000000000000u);  // fits in unsigned 64-bit, but not signed.
+
+  CheckAll(999999999876543210);    // check all decimal digits, signed
+  CheckAll(9999999999876543210u);  // check all decimal digits, unsigned.
+  CheckAll(0x123456789abcdef0);    // check all hex digits
+  CheckAll(0x12345678);
+
+  int8_t minus_one_8bit = -1;
+  EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit)));
+
+  int16_t minus_one_16bit = -1;
+  EXPECT_EQ("ffff", absl::StrCat(absl::Hex(minus_one_16bit)));
+}
+
+TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) {
+  TestFastPrints();
+}
+
+}  // namespace
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
new file mode 100644
index 0000000..70a811b
--- /dev/null
+++ b/absl/strings/str_format.h
@@ -0,0 +1,512 @@
+//
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: str_format.h
+// -----------------------------------------------------------------------------
+//
+// The `str_format` library is a typesafe replacement for the family of
+// `printf()` std::string formatting routines within the `<cstdio>` standard library
+// header. Like the `printf` family, the `str_format` uses a "format string" to
+// perform argument substitutions based on types.
+//
+// Example:
+//
+//   std::string s = absl::StrFormat("%s %s You have $%d!", "Hello", name, dollars);
+//
+// The library consists of the following basic utilities:
+//
+//   * `absl::StrFormat()`, a type-safe replacement for `std::sprintf()`, to
+//     write a format std::string to a `string` value.
+//   * `absl::StrAppendFormat()` to append a format std::string to a `string`
+//   * `absl::StreamFormat()` to more efficiently write a format std::string to a
+//     stream, such as`std::cout`.
+//   * `absl::PrintF()`, `absl::FPrintF()` and `absl::SNPrintF()` as
+//     replacements for `std::printf()`, `std::fprintf()` and `std::snprintf()`.
+//
+//     Note: a version of `std::sprintf()` is not supported as it is
+//     generally unsafe due to buffer overflows.
+//
+// Additionally, you can provide a format std::string (and its associated arguments)
+// using one of the following abstractions:
+//
+//   * A `FormatSpec` class template fully encapsulates a format std::string and its
+//     type arguments and is usually provided to `str_format` functions as a
+//     variadic argument of type `FormatSpec<Arg...>`. The `FormatSpec<Args...>`
+//     template is evaluated at compile-time, providing type safety.
+//   * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled
+//     format std::string for a specific set of type(s), and which can be passed
+//     between API boundaries. (The `FormatSpec` type should not be used
+//     directly.)
+//
+// The `str_format` library provides the ability to output its format strings to
+// arbitrary sink types:
+//
+//   * A generic `Format()` function to write outputs to arbitrary sink types,
+//     which must implement a `RawSinkFormat` interface. (See
+//     `str_format_sink.h` for more information.)
+//
+//   * A `FormatUntyped()` function that is similar to `Format()` except it is
+//     loosely typed. `FormatUntyped()` is not a template and does not perform
+//     any compile-time checking of the format std::string; instead, it returns a
+//     boolean from a runtime check.
+//
+// In addition, the `str_format` library provides extension points for
+// augmenting formatting to new types. These extensions are fully documented
+// within the `str_format_extension.h` header file.
+#ifndef ABSL_STRINGS_STR_FORMAT_H_
+#define ABSL_STRINGS_STR_FORMAT_H_
+
+#include <cstdio>
+#include <string>
+
+#include "absl/strings/internal/str_format/arg.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/bind.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/checker.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/extension.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/parser.h"  // IWYU pragma: export
+
+namespace absl {
+
+// UntypedFormatSpec
+//
+// A type-erased class that can be used directly within untyped API entry
+// points. An `UntypedFormatSpec` is specifically used as an argument to
+// `FormatUntyped()`.
+//
+// Example:
+//
+//   absl::UntypedFormatSpec format("%d");
+//   std::string out;
+//   CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)}));
+class UntypedFormatSpec {
+ public:
+  UntypedFormatSpec() = delete;
+  UntypedFormatSpec(const UntypedFormatSpec&) = delete;
+  UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete;
+
+  explicit UntypedFormatSpec(string_view s) : spec_(s) {}
+
+ protected:
+  explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc)
+      : spec_(pc) {}
+
+ private:
+  friend str_format_internal::UntypedFormatSpecImpl;
+  str_format_internal::UntypedFormatSpecImpl spec_;
+};
+
+// FormatStreamed()
+//
+// Takes a streamable argument and returns an object that can print it
+// with '%s'. Allows printing of types that have an `operator<<` but no
+// intrinsic type support within `StrFormat()` itself.
+//
+// Example:
+//
+//   absl::StrFormat("%s", absl::FormatStreamed(obj));
+template <typename T>
+str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) {
+  return str_format_internal::StreamedWrapper<T>(v);
+}
+
+// FormatCountCapture
+//
+// This class provides a way to safely wrap `StrFormat()` captures of `%n`
+// conversions, which denote the number of characters written by a formatting
+// operation to this point, into an integer value.
+//
+// This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in
+// the `printf()` family of functions, `%n` is not safe to use, as the `int *`
+// buffer can be used to capture arbitrary data.
+//
+// Example:
+//
+//   int n = 0;
+//   std::string s = absl::StrFormat("%s%d%n", "hello", 123,
+//                   absl::FormatCountCapture(&n));
+//   EXPECT_EQ(8, n);
+class FormatCountCapture {
+ public:
+  explicit FormatCountCapture(int* p) : p_(p) {}
+
+ private:
+  // FormatCountCaptureHelper is used to define FormatConvertImpl() for this
+  // class.
+  friend struct str_format_internal::FormatCountCaptureHelper;
+  // Unused() is here because of the false positive from -Wunused-private-field
+  // p_ is used in the templated function of the friend FormatCountCaptureHelper
+  // class.
+  int* Unused() { return p_; }
+  int* p_;
+};
+
+// FormatSpec
+//
+// The `FormatSpec` type defines the makeup of a format std::string within the
+// `str_format` library. You should not need to use or manipulate this type
+// directly. A `FormatSpec` is a variadic class template that is evaluated at
+// compile-time, according to the format std::string and arguments that are passed
+// to it.
+//
+// For a `FormatSpec` to be valid at compile-time, it must be provided as
+// either:
+//
+// * A `constexpr` literal or `absl::string_view`, which is how it most often
+//   used.
+// * A `ParsedFormat` instantiation, which ensures the format std::string is
+//   valid before use. (See below.)
+//
+// Example:
+//
+//   // Provided as a std::string literal.
+//   absl::StrFormat("Welcome to %s, Number %d!", "The Village", 6);
+//
+//   // Provided as a constexpr absl::string_view.
+//   constexpr absl::string_view formatString = "Welcome to %s, Number %d!";
+//   absl::StrFormat(formatString, "The Village", 6);
+//
+//   // Provided as a pre-compiled ParsedFormat object.
+//   // Note that this example is useful only for illustration purposes.
+//   absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!");
+//   absl::StrFormat(formatString, "TheVillage", 6);
+//
+// A format std::string generally follows the POSIX syntax as used within the POSIX
+// `printf` specification.
+//
+// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.)
+//
+// In specific, the `FormatSpec` supports the following type specifiers:
+//   * `c` for characters
+//   * `s` for strings
+//   * `d` or `i` for integers
+//   * `o` for unsigned integer conversions into octal
+//   * `x` or `X` for unsigned integer conversions into hex
+//   * `u` for unsigned integers
+//   * `f` or `F` for floating point values into decimal notation
+//   * `e` or `E` for floating point values into exponential notation
+//   * `a` or `A` for floating point values into hex exponential notation
+//   * `g` or `G` for floating point values into decimal or exponential
+//     notation based on their precision
+//   * `p` for pointer address values
+//   * `n` for the special case of writing out the number of characters
+//     written to this point. The resulting value must be captured within an
+//     `absl::FormatCountCapture` type.
+//
+// NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned
+// counterpart before formatting.
+//
+// Examples:
+//     "%c", 'a'                -> "a"
+//     "%c", 32                 -> " "
+//     "%s", "C"                -> "C"
+//     "%s", std::string("C++") -> "C++"
+//     "%d", -10                -> "-10"
+//     "%o", 10                 -> "12"
+//     "%x", 16                 -> "10"
+//     "%f", 123456789          -> "123456789.000000"
+//     "%e", .01                -> "1.00000e-2"
+//     "%a", -3.0               -> "-0x1.8p+1"
+//     "%g", .01                -> "1e-2"
+//     "%p", *int               -> "0x7ffdeb6ad2a4"
+//
+//     int n = 0;
+//     std::string s = absl::StrFormat(
+//         "%s%d%n", "hello", 123, absl::FormatCountCapture(&n));
+//     EXPECT_EQ(8, n);
+//
+// The `FormatSpec` intrinsically supports all of these fundamental C++ types:
+//
+// *   Characters: `char`, `signed char`, `unsigned char`
+// *   Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`,
+//         `unsigned long`, `long long`, `unsigned long long`
+// *   Floating-point: `float`, `double`, `long double`
+//
+// However, in the `str_format` library, a format conversion specifies a broader
+// C++ conceptual category instead of an exact type. For example, `%s` binds to
+// any std::string-like argument, so `std::string`, `absl::string_view`, and
+// `const char*` are all accepted. Likewise, `%d` accepts any integer-like
+// argument, etc.
+
+template <typename... Args>
+using FormatSpec =
+    typename str_format_internal::FormatSpecDeductionBarrier<Args...>::type;
+
+// ParsedFormat
+//
+// A `ParsedFormat` is a class template representing a preparsed `FormatSpec`,
+// with template arguments specifying the conversion characters used within the
+// format std::string. Such characters must be valid format type specifiers, and
+// these type specifiers are checked at compile-time.
+//
+// Instances of `ParsedFormat` can be created, copied, and reused to speed up
+// formatting loops. A `ParsedFormat` may either be constructed statically, or
+// dynamically through its `New()` factory function, which only constructs a
+// runtime object if the format is valid at that time.
+//
+// Example:
+//
+//   // Verified at compile time.
+//   absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!");
+//   absl::StrFormat(formatString, "TheVillage", 6);
+//
+//   // Verified at runtime.
+//   auto format_runtime = absl::ParsedFormat<'d'>::New(format_string);
+//   if (format_runtime) {
+//     value = absl::StrFormat(*format_runtime, i);
+//   } else {
+//     ... error case ...
+//   }
+template <char... Conv>
+using ParsedFormat = str_format_internal::ExtendedParsedFormat<
+    str_format_internal::ConversionCharToConv(Conv)...>;
+
+// StrFormat()
+//
+// Returns a `string` given a `printf()`-style format std::string and zero or more
+// additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the
+// primary formatting function within the `str_format` library, and should be
+// used in most cases where you need type-safe conversion of types into
+// formatted strings.
+//
+// The format std::string generally consists of ordinary character data along with
+// one or more format conversion specifiers (denoted by the `%` character).
+// Ordinary character data is returned unchanged into the result std::string, while
+// each conversion specification performs a type substitution from
+// `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full
+// information on the makeup of this format std::string.
+//
+// Example:
+//
+//   std::string s = absl::StrFormat(
+//       "Welcome to %s, Number %d!", "The Village", 6);
+//   EXPECT_EQ("Welcome to The Village, Number 6!", s);
+//
+// Returns an empty std::string in case of error.
+template <typename... Args>
+ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format,
+                                      const Args&... args) {
+  return str_format_internal::FormatPack(
+      str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// StrAppendFormat()
+//
+// Appends to a `dst` std::string given a format std::string, and zero or more additional
+// arguments, returning `*dst` as a convenience for chaining purposes. Appends
+// nothing in case of error (but possibly alters its capacity).
+//
+// Example:
+//
+//   std::string orig("For example PI is approximately ");
+//   std::cout << StrAppendFormat(&orig, "%12.6f", 3.14);
+template <typename... Args>
+std::string& StrAppendFormat(std::string* dst, const FormatSpec<Args...>& format,
+                        const Args&... args) {
+  return str_format_internal::AppendPack(
+      dst, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// StreamFormat()
+//
+// Writes to an output stream given a format std::string and zero or more arguments,
+// generally in a manner that is more efficient than streaming the result of
+// `absl:: StrFormat()`. The returned object must be streamed before the full
+// expression ends.
+//
+// Example:
+//
+//   std::cout << StreamFormat("%12.6f", 3.14);
+template <typename... Args>
+ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat(
+    const FormatSpec<Args...>& format, const Args&... args) {
+  return str_format_internal::Streamable(
+      str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// PrintF()
+//
+// Writes to stdout given a format std::string and zero or more arguments. This
+// function is functionally equivalent to `std::printf()` (and type-safe);
+// prefer `absl::PrintF()` over `std::printf()`.
+//
+// Example:
+//
+//   std::string_view s = "Ulaanbaatar";
+//   absl::PrintF("The capital of Mongolia is %s", s);
+//
+//   Outputs: "The capital of Mongolia is Ulaanbaatar"
+//
+template <typename... Args>
+int PrintF(const FormatSpec<Args...>& format, const Args&... args) {
+  return str_format_internal::FprintF(
+      stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// FPrintF()
+//
+// Writes to a file given a format std::string and zero or more arguments. This
+// function is functionally equivalent to `std::fprintf()` (and type-safe);
+// prefer `absl::FPrintF()` over `std::fprintf()`.
+//
+// Example:
+//
+//   std::string_view s = "Ulaanbaatar";
+//   absl::FPrintF("The capital of Mongolia is %s", s);
+//
+//   Outputs: "The capital of Mongolia is Ulaanbaatar"
+//
+template <typename... Args>
+int FPrintF(std::FILE* output, const FormatSpec<Args...>& format,
+            const Args&... args) {
+  return str_format_internal::FprintF(
+      output, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// SNPrintF()
+//
+// Writes to a sized buffer given a format std::string and zero or more arguments.
+// This function is functionally equivalent to `std::snprintf()` (and
+// type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`.
+//
+// Example:
+//
+//   std::string_view s = "Ulaanbaatar";
+//   char output[128];
+//   absl::SNPrintF(output, sizeof(output),
+//                  "The capital of Mongolia is %s", s);
+//
+//   Post-condition: output == "The capital of Mongolia is Ulaanbaatar"
+//
+template <typename... Args>
+int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format,
+             const Args&... args) {
+  return str_format_internal::SnprintF(
+      output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// -----------------------------------------------------------------------------
+// Custom Output Formatting Functions
+// -----------------------------------------------------------------------------
+
+// FormatRawSink
+//
+// FormatRawSink is a type erased wrapper around arbitrary sink objects
+// specifically used as an argument to `Format()`.
+// FormatRawSink does not own the passed sink object. The passed object must
+// outlive the FormatRawSink.
+class FormatRawSink {
+ public:
+  // Implicitly convert from any type that provides the hook function as
+  // described above.
+  template <typename T,
+            typename = typename std::enable_if<std::is_constructible<
+                str_format_internal::FormatRawSinkImpl, T*>::value>::type>
+  FormatRawSink(T* raw)  // NOLINT
+      : sink_(raw) {}
+
+ private:
+  friend str_format_internal::FormatRawSinkImpl;
+  str_format_internal::FormatRawSinkImpl sink_;
+};
+
+// Format()
+//
+// Writes a formatted std::string to an arbitrary sink object (implementing the
+// `absl::FormatRawSink` interface), using a format std::string and zero or more
+// additional arguments.
+//
+// By default, `string` and `std::ostream` are supported as destination objects.
+//
+// `absl::Format()` is a generic version of `absl::StrFormat(), for custom
+// sinks. The format std::string, like format strings for `StrFormat()`, is checked
+// at compile-time.
+//
+// On failure, this function returns `false` and the state of the sink is
+// unspecified.
+template <typename... Args>
+bool Format(FormatRawSink raw_sink, const FormatSpec<Args...>& format,
+            const Args&... args) {
+  return str_format_internal::FormatUntyped(
+      str_format_internal::FormatRawSinkImpl::Extract(raw_sink),
+      str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// FormatArg
+//
+// A type-erased handle to a format argument specifically used as an argument to
+// `FormatUntyped()`. You may construct `FormatArg` by passing
+// reference-to-const of any printable type. `FormatArg` is both copyable and
+// assignable. The source data must outlive the `FormatArg` instance. See
+// example below.
+//
+using FormatArg = str_format_internal::FormatArgImpl;
+
+// FormatUntyped()
+//
+// Writes a formatted std::string to an arbitrary sink object (implementing the
+// `absl::FormatRawSink` interface), using an `UntypedFormatSpec` and zero or
+// more additional arguments.
+//
+// This function acts as the most generic formatting function in the
+// `str_format` library. The caller provides a raw sink, an unchecked format
+// std::string, and (usually) a runtime specified list of arguments; no compile-time
+// checking of formatting is performed within this function. As a result, a
+// caller should check the return value to verify that no error occurred.
+// On failure, this function returns `false` and the state of the sink is
+// unspecified.
+//
+// The arguments are provided in an `absl::Span<const absl::FormatArg>`.
+// Each `absl::FormatArg` object binds to a single argument and keeps a
+// reference to it. The values used to create the `FormatArg` objects must
+// outlive this function call. (See `str_format_arg.h` for information on
+// the `FormatArg` class.)_
+//
+// Example:
+//
+//   std::optional<std::string> FormatDynamic(const std::string& in_format,
+//                                       const vector<std::string>& in_args) {
+//     std::string out;
+//     std::vector<absl::FormatArg> args;
+//     for (const auto& v : in_args) {
+//       // It is important that 'v' is a reference to the objects in in_args.
+//       // The values we pass to FormatArg must outlive the call to
+//       // FormatUntyped.
+//       args.emplace_back(v);
+//     }
+//     absl::UntypedFormatSpec format(in_format);
+//     if (!absl::FormatUntyped(&out, format, args)) {
+//       return std::nullopt;
+//     }
+//     return std::move(out);
+//   }
+//
+ABSL_MUST_USE_RESULT inline bool FormatUntyped(
+    FormatRawSink raw_sink, const UntypedFormatSpec& format,
+    absl::Span<const FormatArg> args) {
+  return str_format_internal::FormatUntyped(
+      str_format_internal::FormatRawSinkImpl::Extract(raw_sink),
+      str_format_internal::UntypedFormatSpecImpl::Extract(format), args);
+}
+
+}  // namespace absl
+#endif  // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
new file mode 100644
index 0000000..fe742bf
--- /dev/null
+++ b/absl/strings/str_format_test.cc
@@ -0,0 +1,603 @@
+
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace {
+using str_format_internal::FormatArgImpl;
+
+class FormatEntryPointTest : public ::testing::Test { };
+
+TEST_F(FormatEntryPointTest, Format) {
+  std::string sink;
+  EXPECT_TRUE(Format(&sink, "A format %d", 123));
+  EXPECT_EQ("A format 123", sink);
+  sink.clear();
+
+  ParsedFormat<'d'> pc("A format %d");
+  EXPECT_TRUE(Format(&sink, pc, 123));
+  EXPECT_EQ("A format 123", sink);
+}
+TEST_F(FormatEntryPointTest, UntypedFormat) {
+  constexpr const char* formats[] = {
+    "",
+    "a",
+    "%80d",
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
+    // MSVC and Android don't support positional syntax.
+    "complicated multipart %% %1$d format %1$0999d",
+#endif  // _MSC_VER
+  };
+  for (const char* fmt : formats) {
+    std::string actual;
+    int i = 123;
+    FormatArgImpl arg_123(i);
+    absl::Span<const FormatArgImpl> args(&arg_123, 1);
+    UntypedFormatSpec format(fmt);
+
+    EXPECT_TRUE(FormatUntyped(&actual, format, args));
+    char buf[4096]{};
+    snprintf(buf, sizeof(buf), fmt, 123);
+    EXPECT_EQ(
+        str_format_internal::FormatPack(
+            str_format_internal::UntypedFormatSpecImpl::Extract(format), args),
+        buf);
+    EXPECT_EQ(actual, buf);
+  }
+  // The internal version works with a preparsed format.
+  ParsedFormat<'d'> pc("A format %d");
+  int i = 345;
+  FormatArg arg(i);
+  std::string out;
+  EXPECT_TRUE(str_format_internal::FormatUntyped(
+      &out, str_format_internal::UntypedFormatSpecImpl(&pc), {&arg, 1}));
+  EXPECT_EQ("A format 345", out);
+}
+
+TEST_F(FormatEntryPointTest, StringFormat) {
+  EXPECT_EQ("123", StrFormat("%d", 123));
+  constexpr absl::string_view view("=%d=", 4);
+  EXPECT_EQ("=123=", StrFormat(view, 123));
+}
+
+TEST_F(FormatEntryPointTest, AppendFormat) {
+  std::string s;
+  std::string& r = StrAppendFormat(&s, "%d", 123);
+  EXPECT_EQ(&s, &r);  // should be same object
+  EXPECT_EQ("123", r);
+}
+
+TEST_F(FormatEntryPointTest, AppendFormatFail) {
+  std::string s = "orig";
+
+  UntypedFormatSpec format(" more %d");
+  FormatArgImpl arg("not an int");
+
+  EXPECT_EQ("orig",
+            str_format_internal::AppendPack(
+                &s, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+                {&arg, 1}));
+}
+
+
+TEST_F(FormatEntryPointTest, ManyArgs) {
+  EXPECT_EQ("24", StrFormat("%24$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                            14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24));
+  EXPECT_EQ("60", StrFormat("%60$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                            14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+                            27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+                            40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+                            53, 54, 55, 56, 57, 58, 59, 60));
+}
+
+TEST_F(FormatEntryPointTest, Preparsed) {
+  ParsedFormat<'d'> pc("%d");
+  EXPECT_EQ("123", StrFormat(pc, 123));
+  // rvalue ok?
+  EXPECT_EQ("123", StrFormat(ParsedFormat<'d'>("%d"), 123));
+  constexpr absl::string_view view("=%d=", 4);
+  EXPECT_EQ("=123=", StrFormat(ParsedFormat<'d'>(view), 123));
+}
+
+TEST_F(FormatEntryPointTest, FormatCountCapture) {
+  int n = 0;
+  EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
+  EXPECT_EQ(0, n);
+  EXPECT_EQ("123", StrFormat("%d%n", 123, FormatCountCapture(&n)));
+  EXPECT_EQ(3, n);
+}
+
+TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) {
+  // Should reject int*.
+  int n = 0;
+  UntypedFormatSpec format("%d%n");
+  int i = 123, *ip = &n;
+  FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)};
+
+  EXPECT_EQ("", str_format_internal::FormatPack(
+                    str_format_internal::UntypedFormatSpecImpl::Extract(format),
+                    absl::MakeSpan(args)));
+}
+
+TEST_F(FormatEntryPointTest, FormatCountCaptureMultiple) {
+  int n1 = 0;
+  int n2 = 0;
+  EXPECT_EQ("    1         2",
+            StrFormat("%5d%n%10d%n", 1, FormatCountCapture(&n1), 2,
+                      FormatCountCapture(&n2)));
+  EXPECT_EQ(5, n1);
+  EXPECT_EQ(15, n2);
+}
+
+TEST_F(FormatEntryPointTest, FormatCountCaptureExample) {
+  int n;
+  std::string s;
+  StrAppendFormat(&s, "%s: %n%s\n", "(1,1)", FormatCountCapture(&n), "(1,2)");
+  StrAppendFormat(&s, "%*s%s\n", n, "", "(2,2)");
+  EXPECT_EQ(7, n);
+  EXPECT_EQ(
+      "(1,1): (1,2)\n"
+      "       (2,2)\n",
+      s);
+}
+
+TEST_F(FormatEntryPointTest, Stream) {
+  const std::string formats[] = {
+    "",
+    "a",
+    "%80d",
+#if !defined(_MSC_VER) && !defined(__ANDROID__)
+    // MSVC doesn't support positional syntax.
+    "complicated multipart %% %1$d format %1$080d",
+#endif  // _MSC_VER
+  };
+  std::string buf(4096, '\0');
+  for (const auto& fmt : formats) {
+    const auto parsed = ParsedFormat<'d'>::NewAllowIgnored(fmt);
+    std::ostringstream oss;
+    oss << StreamFormat(*parsed, 123);
+    int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), 123);
+    ASSERT_TRUE(oss) << fmt;
+    ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
+        << fmt_result;
+    EXPECT_EQ(buf.c_str(), oss.str());
+  }
+}
+
+TEST_F(FormatEntryPointTest, StreamOk) {
+  std::ostringstream oss;
+  oss << StreamFormat("hello %d", 123);
+  EXPECT_EQ("hello 123", oss.str());
+  EXPECT_TRUE(oss.good());
+}
+
+TEST_F(FormatEntryPointTest, StreamFail) {
+  std::ostringstream oss;
+  UntypedFormatSpec format("hello %d");
+  FormatArgImpl arg("non-numeric");
+  oss << str_format_internal::Streamable(
+      str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1});
+  EXPECT_EQ("hello ", oss.str());  // partial write
+  EXPECT_TRUE(oss.fail());
+}
+
+std::string WithSnprintf(const char* fmt, ...) {
+  std::string buf;
+  buf.resize(128);
+  va_list va;
+  va_start(va, fmt);
+  int r = vsnprintf(&*buf.begin(), buf.size(), fmt, va);
+  va_end(va);
+  EXPECT_GE(r, 0);
+  EXPECT_LT(r, buf.size());
+  buf.resize(r);
+  return buf;
+}
+
+TEST_F(FormatEntryPointTest, FloatPrecisionArg) {
+  // Test that positional parameters for width and precision
+  // are indexed to precede the value.
+  // Also sanity check the same formats against snprintf.
+  EXPECT_EQ("0.1", StrFormat("%.1f", 0.1));
+  EXPECT_EQ("0.1", WithSnprintf("%.1f", 0.1));
+  EXPECT_EQ("  0.1", StrFormat("%*.1f", 5, 0.1));
+  EXPECT_EQ("  0.1", WithSnprintf("%*.1f", 5, 0.1));
+  EXPECT_EQ("0.1", StrFormat("%.*f", 1, 0.1));
+  EXPECT_EQ("0.1", WithSnprintf("%.*f", 1, 0.1));
+  EXPECT_EQ("  0.1", StrFormat("%*.*f", 5, 1, 0.1));
+  EXPECT_EQ("  0.1", WithSnprintf("%*.*f", 5, 1, 0.1));
+}
+namespace streamed_test {
+struct X {};
+std::ostream& operator<<(std::ostream& os, const X&) {
+  return os << "X";
+}
+}  // streamed_test
+
+TEST_F(FormatEntryPointTest, FormatStreamed) {
+  EXPECT_EQ("123", StrFormat("%s", FormatStreamed(123)));
+  EXPECT_EQ("  123", StrFormat("%5s", FormatStreamed(123)));
+  EXPECT_EQ("123  ", StrFormat("%-5s", FormatStreamed(123)));
+  EXPECT_EQ("X", StrFormat("%s", FormatStreamed(streamed_test::X())));
+  EXPECT_EQ("123", StrFormat("%s", FormatStreamed(StreamFormat("%d", 123))));
+}
+
+// Helper class that creates a temporary file and exposes a FILE* to it.
+// It will close the file on destruction.
+class TempFile {
+ public:
+  TempFile() : file_(std::tmpfile()) {}
+  ~TempFile() { std::fclose(file_); }
+
+  std::FILE* file() const { return file_; }
+
+  // Read the file into a std::string.
+  std::string ReadFile() {
+    std::fseek(file_, 0, SEEK_END);
+    int size = std::ftell(file_);
+    std::rewind(file_);
+    std::string str(2 * size, ' ');
+    int read_bytes = std::fread(&str[0], 1, str.size(), file_);
+    EXPECT_EQ(read_bytes, size);
+    str.resize(read_bytes);
+    EXPECT_TRUE(std::feof(file_));
+    return str;
+  }
+
+ private:
+  std::FILE* file_;
+};
+
+TEST_F(FormatEntryPointTest, FPrintF) {
+  TempFile tmp;
+  int result =
+      FPrintF(tmp.file(), "STRING: %s NUMBER: %010d", std::string("ABC"), -19);
+  EXPECT_EQ(result, 30);
+  EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
+}
+
+TEST_F(FormatEntryPointTest, FPrintFError) {
+  errno = 0;
+  int result = FPrintF(stdin, "ABC");
+  EXPECT_LT(result, 0);
+  EXPECT_EQ(errno, EBADF);
+}
+
+#if __GNUC__
+TEST_F(FormatEntryPointTest, FprintfTooLarge) {
+  std::FILE* f = std::fopen("/dev/null", "w");
+  int width = 2000000000;
+  errno = 0;
+  int result = FPrintF(f, "%*d %*d", width, 0, width, 0);
+  EXPECT_LT(result, 0);
+  EXPECT_EQ(errno, EFBIG);
+  std::fclose(f);
+}
+
+TEST_F(FormatEntryPointTest, PrintF) {
+  int stdout_tmp = dup(STDOUT_FILENO);
+
+  TempFile tmp;
+  std::fflush(stdout);
+  dup2(fileno(tmp.file()), STDOUT_FILENO);
+
+  int result = PrintF("STRING: %s NUMBER: %010d", std::string("ABC"), -19);
+
+  std::fflush(stdout);
+  dup2(stdout_tmp, STDOUT_FILENO);
+  close(stdout_tmp);
+
+  EXPECT_EQ(result, 30);
+  EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
+}
+#endif  // __GNUC__
+
+TEST_F(FormatEntryPointTest, SNPrintF) {
+  char buffer[16];
+  int result =
+      SNPrintF(buffer, sizeof(buffer), "STRING: %s", std::string("ABC"));
+  EXPECT_EQ(result, 11);
+  EXPECT_EQ(std::string(buffer), "STRING: ABC");
+
+  result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456);
+  EXPECT_EQ(result, 14);
+  EXPECT_EQ(std::string(buffer), "NUMBER: 123456");
+
+  result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 1234567);
+  EXPECT_EQ(result, 15);
+  EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
+
+  result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 12345678);
+  EXPECT_EQ(result, 16);
+  EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
+
+  result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456789);
+  EXPECT_EQ(result, 17);
+  EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
+
+  result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size");
+  EXPECT_EQ(result, 37);
+}
+
+TEST(StrFormat, BehavesAsDocumented) {
+  std::string s = absl::StrFormat("%s, %d!", "Hello", 123);
+  EXPECT_EQ("Hello, 123!", s);
+  // The format of a replacement is
+  // '%'[position][flags][width['.'precision]][length_modifier][format]
+  EXPECT_EQ(absl::StrFormat("%1$+3.2Lf", 1.1), "+1.10");
+  // Text conversion:
+  //     "c" - Character.              Eg: 'a' -> "A", 20 -> " "
+  EXPECT_EQ(StrFormat("%c", 'a'), "a");
+  EXPECT_EQ(StrFormat("%c", 0x20), " ");
+  //           Formats char and integral types: int, long, uint64_t, etc.
+  EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
+  EXPECT_EQ(StrFormat("%c", long{'a'}), "a");  // NOLINT
+  EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
+  //     "s" - std::string                  Eg: "C" -> "C", std::string("C++") -> "C++"
+  //           Formats std::string, char*, string_view, and Cord.
+  EXPECT_EQ(StrFormat("%s", "C"), "C");
+  EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
+  EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
+  // Integral Conversion
+  //     These format integral types: char, int, long, uint64_t, etc.
+  EXPECT_EQ(StrFormat("%d", char{10}), "10");
+  EXPECT_EQ(StrFormat("%d", int{10}), "10");
+  EXPECT_EQ(StrFormat("%d", long{10}), "10");  // NOLINT
+  EXPECT_EQ(StrFormat("%d", uint64_t{10}), "10");
+  //     d,i - signed decimal          Eg: -10 -> "-10"
+  EXPECT_EQ(StrFormat("%d", -10), "-10");
+  EXPECT_EQ(StrFormat("%i", -10), "-10");
+  //      o  - octal                   Eg:  10 -> "12"
+  EXPECT_EQ(StrFormat("%o", 10), "12");
+  //      u  - unsigned decimal        Eg:  10 -> "10"
+  EXPECT_EQ(StrFormat("%u", 10), "10");
+  //     x/X - lower,upper case hex    Eg:  10 -> "a"/"A"
+  EXPECT_EQ(StrFormat("%x", 10), "a");
+  EXPECT_EQ(StrFormat("%X", 10), "A");
+  // Floating-point, with upper/lower-case output.
+  //     These format floating points types: float, double, long double, etc.
+  EXPECT_EQ(StrFormat("%.1f", float{1}), "1.0");
+  EXPECT_EQ(StrFormat("%.1f", double{1}), "1.0");
+  const long double long_double = 1.0;
+  EXPECT_EQ(StrFormat("%.1f", long_double), "1.0");
+  //     These also format integral types: char, int, long, uint64_t, etc.:
+  EXPECT_EQ(StrFormat("%.1f", char{1}), "1.0");
+  EXPECT_EQ(StrFormat("%.1f", int{1}), "1.0");
+  EXPECT_EQ(StrFormat("%.1f", long{1}), "1.0");  // NOLINT
+  EXPECT_EQ(StrFormat("%.1f", uint64_t{1}), "1.0");
+  //     f/F - decimal.                Eg: 123456789 -> "123456789.000000"
+  EXPECT_EQ(StrFormat("%f", 123456789), "123456789.000000");
+  EXPECT_EQ(StrFormat("%F", 123456789), "123456789.000000");
+  //     e/E - exponentiated           Eg: .01 -> "1.00000e-2"/"1.00000E-2"
+  EXPECT_EQ(StrFormat("%e", .01), "1.000000e-02");
+  EXPECT_EQ(StrFormat("%E", .01), "1.000000E-02");
+  //     g/G - exponentiate to fit     Eg: .01 -> "0.01", 1e10 ->"1e+10"/"1E+10"
+  EXPECT_EQ(StrFormat("%g", .01), "0.01");
+  EXPECT_EQ(StrFormat("%g", 1e10), "1e+10");
+  EXPECT_EQ(StrFormat("%G", 1e10), "1E+10");
+  //     a/A - lower,upper case hex    Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1"
+
+// On NDK r16, there is a regression in hexfloat formatting.
+#if !defined(__NDK_MAJOR__) || __NDK_MAJOR__ != 16
+  EXPECT_EQ(StrFormat("%.1a", -3.0), "-0x1.8p+1");  // .1 to fix MSVC output
+  EXPECT_EQ(StrFormat("%.1A", -3.0), "-0X1.8P+1");  // .1 to fix MSVC output
+#endif
+
+  // Other conversion
+  int64_t value = 0x7ffdeb6;
+  auto ptr_value = static_cast<uintptr_t>(value);
+  const int& something = *reinterpret_cast<const int*>(ptr_value);
+  EXPECT_EQ(StrFormat("%p", &something), StrFormat("0x%x", ptr_value));
+
+  // Output widths are supported, with optional flags.
+  EXPECT_EQ(StrFormat("%3d", 1), "  1");
+  EXPECT_EQ(StrFormat("%3d", 123456), "123456");
+  EXPECT_EQ(StrFormat("%06.2f", 1.234), "001.23");
+  EXPECT_EQ(StrFormat("%+d", 1), "+1");
+  EXPECT_EQ(StrFormat("% d", 1), " 1");
+  EXPECT_EQ(StrFormat("%-4d", -1), "-1  ");
+  EXPECT_EQ(StrFormat("%#o", 10), "012");
+  EXPECT_EQ(StrFormat("%#x", 15), "0xf");
+  EXPECT_EQ(StrFormat("%04d", 8), "0008");
+  // Posix positional substitution.
+  EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"),
+            "veni, vidi, vici!");
+  // Length modifiers are ignored.
+  EXPECT_EQ(StrFormat("%hhd", int{1}), "1");
+  EXPECT_EQ(StrFormat("%hd", int{1}), "1");
+  EXPECT_EQ(StrFormat("%ld", int{1}), "1");
+  EXPECT_EQ(StrFormat("%lld", int{1}), "1");
+  EXPECT_EQ(StrFormat("%Ld", int{1}), "1");
+  EXPECT_EQ(StrFormat("%jd", int{1}), "1");
+  EXPECT_EQ(StrFormat("%zd", int{1}), "1");
+  EXPECT_EQ(StrFormat("%td", int{1}), "1");
+  EXPECT_EQ(StrFormat("%qd", int{1}), "1");
+}
+
+using str_format_internal::ExtendedParsedFormat;
+using str_format_internal::ParsedFormatBase;
+
+struct SummarizeConsumer {
+  std::string* out;
+  explicit SummarizeConsumer(std::string* out) : out(out) {}
+
+  bool Append(string_view s) {
+    *out += "[" + std::string(s) + "]";
+    return true;
+  }
+
+  bool ConvertOne(const str_format_internal::UnboundConversion& conv,
+                  string_view s) {
+    *out += "{";
+    *out += std::string(s);
+    *out += ":";
+    *out += std::to_string(conv.arg_position) + "$";
+    if (conv.width.is_from_arg()) {
+      *out += std::to_string(conv.width.get_from_arg()) + "$*";
+    }
+    if (conv.precision.is_from_arg()) {
+      *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
+    }
+    *out += conv.conv.Char();
+    *out += "}";
+    return true;
+  }
+};
+
+std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
+  std::string out;
+  if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
+  return out;
+}
+
+class ParsedFormatTest : public testing::Test {};
+
+TEST_F(ParsedFormatTest, SimpleChecked) {
+  EXPECT_EQ("[ABC]{d:1$d}[DEF]",
+            SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF")));
+  EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}",
+            SummarizeParsedFormat(ParsedFormat<'s', 'd', 'f'>("%sFFF%dZZZ%f")));
+  EXPECT_EQ("{s:1$s}[ ]{.*d:3$.2$*d}",
+            SummarizeParsedFormat(ParsedFormat<'s', '*', 'd'>("%s %.*d")));
+}
+
+TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) {
+  auto f = ParsedFormat<'d'>::New("ABC%dDEF");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
+
+  std::string format = "%sFFF%dZZZ%f";
+  auto f2 = ParsedFormat<'s', 'd', 'f'>::New(format);
+
+  ASSERT_TRUE(f2);
+  EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
+
+  f2 = ParsedFormat<'s', 'd', 'f'>::New("%s %d %f");
+
+  ASSERT_TRUE(f2);
+  EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
+
+  auto star = ParsedFormat<'*', 'd'>::New("%*d");
+  ASSERT_TRUE(star);
+  EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
+
+  auto dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d");
+  ASSERT_TRUE(dollar);
+  EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
+  // with reuse
+  dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d %1$d");
+  ASSERT_TRUE(dollar);
+  EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
+            SummarizeParsedFormat(*dollar));
+}
+
+TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
+  EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC")));
+  EXPECT_FALSE((ParsedFormat<'d', 's'>::New("%dABC")));
+  EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC%2$s")));
+  auto f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
+  f = ParsedFormat<'d', 's'>::NewAllowIgnored("%dABC");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
+  f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC%2$s");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
+}
+
+TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) {
+  EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x"));
+  EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x"));
+}
+
+TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
+  EXPECT_FALSE(ParsedFormat<'d'>::New(""));
+
+  EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d"));
+
+  std::string format = "%sFFF%dZZZ%f";
+  EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
+}
+
+using str_format_internal::Conv;
+
+TEST_F(ParsedFormatTest, UncheckedCorrect) {
+  auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
+
+  std::string format = "%sFFF%dZZZ%f";
+  auto f2 =
+      ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(format);
+
+  ASSERT_TRUE(f2);
+  EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
+
+  f2 = ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(
+      "%s %d %f");
+
+  ASSERT_TRUE(f2);
+  EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
+
+  auto star = ExtendedParsedFormat<Conv::star, Conv::d>::New("%*d");
+  ASSERT_TRUE(star);
+  EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
+
+  auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d");
+  ASSERT_TRUE(dollar);
+  EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
+  // with reuse
+  dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d");
+  ASSERT_TRUE(dollar);
+  EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
+            SummarizeParsedFormat(*dollar));
+}
+
+TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
+  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC")));
+  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC")));
+  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s")));
+  auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
+  f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
+  f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s");
+  ASSERT_TRUE(f);
+  EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
+}
+
+TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
+  auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x");
+  EXPECT_TRUE(dx);
+  EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
+
+  dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d");
+  EXPECT_TRUE(dx);
+  EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
+}
+
+TEST_F(ParsedFormatTest, UncheckedIncorrect) {
+  EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New(""));
+
+  EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d"));
+
+  std::string format = "%sFFF%dZZZ%f";
+  EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format)));
+}
+
+TEST_F(ParsedFormatTest, RegressionMixPositional) {
+  EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o")));
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h
new file mode 100644
index 0000000..bd4d0e1
--- /dev/null
+++ b/absl/strings/str_join.h
@@ -0,0 +1,288 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: str_join.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains functions for joining a range of elements and
+// returning the result as a std::string. StrJoin operations are specified by passing
+// a range, a separator std::string to use between the elements joined, and an
+// optional Formatter responsible for converting each argument in the range to a
+// std::string. If omitted, a default `AlphaNumFormatter()` is called on the elements
+// to be joined, using the same formatting that `absl::StrCat()` uses. This
+// package defines a number of default formatters, and you can define your own
+// implementations.
+//
+// Ranges are specified by passing a container with `std::begin()` and
+// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a
+// brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous
+// objects. The separator std::string is specified as an `absl::string_view`.
+//
+// Because the default formatter uses the `absl::AlphaNum` class,
+// `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on
+// collections of strings, ints, floats, doubles, etc.
+//
+// Example:
+//
+//   std::vector<std::string> v = {"foo", "bar", "baz"};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("foo-bar-baz", s);
+//
+// See comments on the `absl::StrJoin()` function for more examples.
+
+#ifndef ABSL_STRINGS_STR_JOIN_H_
+#define ABSL_STRINGS_STR_JOIN_H_
+
+#include <cstdio>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/strings/internal/str_join_internal.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Concept: Formatter
+// -----------------------------------------------------------------------------
+//
+// A Formatter is a function object that is responsible for formatting its
+// argument as a std::string and appending it to a given output std::string. Formatters
+// may be implemented as function objects, lambdas, or normal functions. You may
+// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary
+// types.
+//
+// The following is an example of a custom Formatter that simply uses
+// `std::to_string()` to format an integer as a std::string.
+//
+//   struct MyFormatter {
+//     void operator()(std::string* out, int i) const {
+//       out->append(std::to_string(i));
+//     }
+//   };
+//
+// You would use the above formatter by passing an instance of it as the final
+// argument to `absl::StrJoin()`:
+//
+//   std::vector<int> v = {1, 2, 3, 4};
+//   std::string s = absl::StrJoin(v, "-", MyFormatter());
+//   EXPECT_EQ("1-2-3-4", s);
+//
+// The following standard formatters are provided within this file:
+//
+// - `AlphaNumFormatter()` (the default)
+// - `StreamFormatter()`
+// - `PairFormatter()`
+// - `DereferenceFormatter()`
+
+// AlphaNumFormatter()
+//
+// Default formatter used if none is specified. Uses `absl::AlphaNum` to convert
+// numeric arguments to strings.
+inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() {
+  return strings_internal::AlphaNumFormatterImpl();
+}
+
+// StreamFormatter()
+//
+// Formats its argument using the << operator.
+inline strings_internal::StreamFormatterImpl StreamFormatter() {
+  return strings_internal::StreamFormatterImpl();
+}
+
+// Function Template: PairFormatter(Formatter, absl::string_view, Formatter)
+//
+// Formats a `std::pair` by putting a given separator between the pair's
+// `.first` and `.second` members. This formatter allows you to specify
+// custom Formatters for both the first and second member of each pair.
+template <typename FirstFormatter, typename SecondFormatter>
+inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
+PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) {
+  return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>(
+      std::move(f1), sep, std::move(f2));
+}
+
+// Function overload of PairFormatter() for using a default
+// `AlphaNumFormatter()` for each Formatter in the pair.
+inline strings_internal::PairFormatterImpl<
+    strings_internal::AlphaNumFormatterImpl,
+    strings_internal::AlphaNumFormatterImpl>
+PairFormatter(absl::string_view sep) {
+  return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter());
+}
+
+// Function Template: DereferenceFormatter(Formatter)
+//
+// Formats its argument by dereferencing it and then applying the given
+// formatter. This formatter is useful for formatting a container of
+// pointer-to-T. This pattern often shows up when joining repeated fields in
+// protocol buffers.
+template <typename Formatter>
+strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
+    Formatter&& f) {
+  return strings_internal::DereferenceFormatterImpl<Formatter>(
+      std::forward<Formatter>(f));
+}
+
+// Function overload of `DererefenceFormatter()` for using a default
+// `AlphaNumFormatter()`.
+inline strings_internal::DereferenceFormatterImpl<
+    strings_internal::AlphaNumFormatterImpl>
+DereferenceFormatter() {
+  return strings_internal::DereferenceFormatterImpl<
+      strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter());
+}
+
+// -----------------------------------------------------------------------------
+// StrJoin()
+// -----------------------------------------------------------------------------
+//
+// Joins a range of elements and returns the result as a std::string.
+// `absl::StrJoin()` takes a range, a separator std::string to use between the
+// elements joined, and an optional Formatter responsible for converting each
+// argument in the range to a std::string.
+//
+// If omitted, the default `AlphaNumFormatter()` is called on the elements to be
+// joined.
+//
+// Example 1:
+//   // Joins a collection of strings. This pattern also works with a collection
+//   // of `absl::string_view` or even `const char*`.
+//   std::vector<std::string> v = {"foo", "bar", "baz"};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("foo-bar-baz", s);
+//
+// Example 2:
+//   // Joins the values in the given `std::initializer_list<>` specified using
+//   // brace initialization. This pattern also works with an initializer_list
+//   // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
+//   std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
+//   EXPECT_EQ("foo-bar-baz", s);
+//
+// Example 3:
+//   // Joins a collection of ints. This pattern also works with floats,
+//   // doubles, int64s -- any `StrCat()`-compatible type.
+//   std::vector<int> v = {1, 2, 3, -4};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("1-2-3--4", s);
+//
+// Example 4:
+//   // Joins a collection of pointer-to-int. By default, pointers are
+//   // dereferenced and the pointee is formatted using the default format for
+//   // that type; such dereferencing occurs for all levels of indirection, so
+//   // this pattern works just as well for `std::vector<int**>` as for
+//   // `std::vector<int*>`.
+//   int x = 1, y = 2, z = 3;
+//   std::vector<int*> v = {&x, &y, &z};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("1-2-3", s);
+//
+// Example 5:
+//   // Dereferencing of `std::unique_ptr<>` is also supported:
+//   std::vector<std::unique_ptr<int>> v
+//   v.emplace_back(new int(1));
+//   v.emplace_back(new int(2));
+//   v.emplace_back(new int(3));
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("1-2-3", s);
+//
+// Example 6:
+//   // Joins a `std::map`, with each key-value pair separated by an equals
+//   // sign. This pattern would also work with, say, a
+//   // `std::vector<std::pair<>>`.
+//   std::map<std::string, int> m = {
+//       std::make_pair("a", 1),
+//       std::make_pair("b", 2),
+//       std::make_pair("c", 3)};
+//   std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
+//   EXPECT_EQ("a=1,b=2,c=3", s);
+//
+// Example 7:
+//   // These examples show how `absl::StrJoin()` handles a few common edge
+//   // cases:
+//   std::vector<std::string> v_empty;
+//   EXPECT_EQ("", absl::StrJoin(v_empty, "-"));
+//
+//   std::vector<std::string> v_one_item = {"foo"};
+//   EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-"));
+//
+//   std::vector<std::string> v_empty_string = {""};
+//   EXPECT_EQ("", absl::StrJoin(v_empty_string, "-"));
+//
+//   std::vector<std::string> v_one_item_empty_string = {"a", ""};
+//   EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-"));
+//
+//   std::vector<std::string> v_two_empty_string = {"", ""};
+//   EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-"));
+//
+// Example 8:
+//   // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
+//   // a std::string using the `absl::AlphaNum` class.
+//   std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+//   EXPECT_EQ("123-abc-0.456", s);
+
+template <typename Iterator, typename Formatter>
+std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
+               Formatter&& fmt) {
+  return strings_internal::JoinAlgorithm(start, end, sep, fmt);
+}
+
+template <typename Range, typename Formatter>
+std::string StrJoin(const Range& range, absl::string_view separator,
+               Formatter&& fmt) {
+  return strings_internal::JoinRange(range, separator, fmt);
+}
+
+template <typename T, typename Formatter>
+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
+               Formatter&& fmt) {
+  return strings_internal::JoinRange(il, separator, fmt);
+}
+
+template <typename... T, typename Formatter>
+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
+               Formatter&& fmt) {
+  return strings_internal::JoinAlgorithm(value, separator, fmt);
+}
+
+template <typename Iterator>
+std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) {
+  return strings_internal::JoinRange(start, end, separator);
+}
+
+template <typename Range>
+std::string StrJoin(const Range& range, absl::string_view separator) {
+  return strings_internal::JoinRange(range, separator);
+}
+
+template <typename T>
+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) {
+  return strings_internal::JoinRange(il, separator);
+}
+
+template <typename... T>
+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) {
+  return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_JOIN_H_
diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc
new file mode 100644
index 0000000..7fb0e49
--- /dev/null
+++ b/absl/strings/str_join_benchmark.cc
@@ -0,0 +1,96 @@
+//
+// Copyright 2018 The Abseil 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 "absl/strings/str_join.h"
+
+#include <string>
+#include <vector>
+#include <utility>
+
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_Join2_Strings(benchmark::State& state) {
+  const int string_len = state.range(0);
+  const int num_strings = state.range(1);
+  const std::string s(string_len, 'x');
+  const std::vector<std::string> v(num_strings, s);
+  for (auto _ : state) {
+    std::string s = absl::StrJoin(v, "-");
+    benchmark::DoNotOptimize(s);
+  }
+}
+BENCHMARK(BM_Join2_Strings)
+    ->ArgPair(1 << 0, 1 << 3)
+    ->ArgPair(1 << 10, 1 << 3)
+    ->ArgPair(1 << 13, 1 << 3)
+    ->ArgPair(1 << 0, 1 << 10)
+    ->ArgPair(1 << 10, 1 << 10)
+    ->ArgPair(1 << 13, 1 << 10)
+    ->ArgPair(1 << 0, 1 << 13)
+    ->ArgPair(1 << 10, 1 << 13)
+    ->ArgPair(1 << 13, 1 << 13);
+
+void BM_Join2_Ints(benchmark::State& state) {
+  const int num_ints = state.range(0);
+  const std::vector<int> v(num_ints, 42);
+  for (auto _ : state) {
+    std::string s = absl::StrJoin(v, "-");
+    benchmark::DoNotOptimize(s);
+  }
+}
+BENCHMARK(BM_Join2_Ints)->Range(0, 1 << 13);
+
+void BM_Join2_KeysAndValues(benchmark::State& state) {
+  const int string_len = state.range(0);
+  const int num_pairs = state.range(1);
+  const std::string s(string_len, 'x');
+  const std::vector<std::pair<std::string, int>> v(num_pairs, std::make_pair(s, 42));
+  for (auto _ : state) {
+    std::string s = absl::StrJoin(v, ",", absl::PairFormatter("="));
+    benchmark::DoNotOptimize(s);
+  }
+}
+BENCHMARK(BM_Join2_KeysAndValues)
+    ->ArgPair(1 << 0, 1 << 3)
+    ->ArgPair(1 << 10, 1 << 3)
+    ->ArgPair(1 << 13, 1 << 3)
+    ->ArgPair(1 << 0, 1 << 10)
+    ->ArgPair(1 << 10, 1 << 10)
+    ->ArgPair(1 << 13, 1 << 10)
+    ->ArgPair(1 << 0, 1 << 13)
+    ->ArgPair(1 << 10, 1 << 13)
+    ->ArgPair(1 << 13, 1 << 13);
+
+void BM_JoinStreamable(benchmark::State& state) {
+  const int string_len = state.range(0);
+  const int num_strings = state.range(1);
+  const std::vector<std::string> v(num_strings, std::string(string_len, 'x'));
+  for (auto _ : state) {
+    std::string s = absl::StrJoin(v, "", absl::StreamFormatter());
+    benchmark::DoNotOptimize(s);
+  }
+}
+BENCHMARK(BM_JoinStreamable)
+    ->ArgPair(0, 0)
+    ->ArgPair(16, 1)
+    ->ArgPair(256, 1)
+    ->ArgPair(16, 16)
+    ->ArgPair(256, 16)
+    ->ArgPair(16, 256)
+    ->ArgPair(256, 256);
+
+}  // namespace
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
new file mode 100644
index 0000000..c941f9c
--- /dev/null
+++ b/absl/strings/str_join_test.cc
@@ -0,0 +1,472 @@
+// Copyright 2017 The Abseil 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.
+
+// Unit tests for all join.h functions
+
+#include "absl/strings/str_join.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <functional>
+#include <initializer_list>
+#include <map>
+#include <memory>
+#include <ostream>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+
+namespace {
+
+TEST(StrJoin, APIExamples) {
+  {
+    // Collection of strings
+    std::vector<std::string> v = {"foo", "bar", "baz"};
+    EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Collection of absl::string_view
+    std::vector<absl::string_view> v = {"foo", "bar", "baz"};
+    EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Collection of const char*
+    std::vector<const char*> v = {"foo", "bar", "baz"};
+    EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Collection of non-const char*
+    std::string a = "foo", b = "bar", c = "baz";
+    std::vector<char*> v = {&a[0], &b[0], &c[0]};
+    EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Collection of ints
+    std::vector<int> v = {1, 2, 3, -4};
+    EXPECT_EQ("1-2-3--4", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Literals passed as a std::initializer_list
+    std::string s = absl::StrJoin({"a", "b", "c"}, "-");
+    EXPECT_EQ("a-b-c", s);
+  }
+  {
+    // Join a std::tuple<T...>.
+    std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+    EXPECT_EQ("123-abc-0.456", s);
+  }
+
+  {
+    // Collection of unique_ptrs
+    std::vector<std::unique_ptr<int>> v;
+    v.emplace_back(new int(1));
+    v.emplace_back(new int(2));
+    v.emplace_back(new int(3));
+    EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Array of ints
+    const int a[] = {1, 2, 3, -4};
+    EXPECT_EQ("1-2-3--4", absl::StrJoin(a, a + ABSL_ARRAYSIZE(a), "-"));
+  }
+
+  {
+    // Collection of pointers
+    int x = 1, y = 2, z = 3;
+    std::vector<int*> v = {&x, &y, &z};
+    EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Collection of pointers to pointers
+    int x = 1, y = 2, z = 3;
+    int *px = &x, *py = &y, *pz = &z;
+    std::vector<int**> v = {&px, &py, &pz};
+    EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // Collection of pointers to std::string
+    std::string a("a"), b("b");
+    std::vector<std::string*> v = {&a, &b};
+    EXPECT_EQ("a-b", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // A std::map, which is a collection of std::pair<>s.
+    std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} };
+    EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("=")));
+  }
+
+  {
+    // Shows absl::StrSplit and absl::StrJoin working together. This example is
+    // equivalent to s/=/-/g.
+    const std::string s = "a=b=c=d";
+    EXPECT_EQ("a-b-c-d", absl::StrJoin(absl::StrSplit(s, "="), "-"));
+  }
+
+  //
+  // A few examples of edge cases
+  //
+
+  {
+    // Empty range yields an empty std::string.
+    std::vector<std::string> v;
+    EXPECT_EQ("", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // A range of 1 element gives a std::string with that element but no separator.
+    std::vector<std::string> v = {"foo"};
+    EXPECT_EQ("foo", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // A range with a single empty std::string element
+    std::vector<std::string> v = {""};
+    EXPECT_EQ("", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // A range with 2 elements, one of which is an empty std::string
+    std::vector<std::string> v = {"a", ""};
+    EXPECT_EQ("a-", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // A range with 2 empty elements.
+    std::vector<std::string> v = {"", ""};
+    EXPECT_EQ("-", absl::StrJoin(v, "-"));
+  }
+
+  {
+    // A std::vector of bool.
+    std::vector<bool> v = {true, false, true};
+    EXPECT_EQ("1-0-1", absl::StrJoin(v, "-"));
+  }
+}
+
+TEST(StrJoin, CustomFormatter) {
+  std::vector<std::string> v{"One", "Two", "Three"};
+  {
+    std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
+      absl::StrAppend(out, "(", in, ")");
+    });
+    EXPECT_EQ("(One)(Two)(Three)", joined);
+  }
+  {
+    class ImmovableFormatter {
+     public:
+      void operator()(std::string* out, const std::string& in) {
+        absl::StrAppend(out, "(", in, ")");
+      }
+      ImmovableFormatter() {}
+      ImmovableFormatter(const ImmovableFormatter&) = delete;
+    };
+    EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", ImmovableFormatter()));
+  }
+  {
+    class OverloadedFormatter {
+     public:
+      void operator()(std::string* out, const std::string& in) {
+        absl::StrAppend(out, "(", in, ")");
+      }
+      void operator()(std::string* out, const std::string& in) const {
+        absl::StrAppend(out, "[", in, "]");
+      }
+    };
+    EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", OverloadedFormatter()));
+    const OverloadedFormatter fmt = {};
+    EXPECT_EQ("[One][Two][Three]", absl::StrJoin(v, "", fmt));
+  }
+}
+
+//
+// Tests the Formatters
+//
+
+TEST(AlphaNumFormatter, FormatterAPI) {
+  // Not an exhaustive test. See strings/strcat_test.h for the exhaustive test
+  // of what AlphaNum can convert.
+  auto f = absl::AlphaNumFormatter();
+  std::string s;
+  f(&s, "Testing: ");
+  f(&s, static_cast<int>(1));
+  f(&s, static_cast<int16_t>(2));
+  f(&s, static_cast<int64_t>(3));
+  f(&s, static_cast<float>(4));
+  f(&s, static_cast<double>(5));
+  f(&s, static_cast<unsigned>(6));
+  f(&s, static_cast<size_t>(7));
+  f(&s, absl::string_view(" OK"));
+  EXPECT_EQ("Testing: 1234567 OK", s);
+}
+
+// Make sure people who are mistakenly using std::vector<bool> even though
+// they're not memory-constrained can use absl::AlphaNumFormatter().
+TEST(AlphaNumFormatter, VectorOfBool) {
+  auto f = absl::AlphaNumFormatter();
+  std::string s;
+  std::vector<bool> v = {true, false, true};
+  f(&s, *v.cbegin());
+  f(&s, *v.begin());
+  f(&s, v[1]);
+  EXPECT_EQ("110", s);
+}
+
+TEST(AlphaNumFormatter, AlphaNum) {
+  auto f = absl::AlphaNumFormatter();
+  std::string s;
+  f(&s, absl::AlphaNum("hello"));
+  EXPECT_EQ("hello", s);
+}
+
+struct StreamableType {
+  std::string contents;
+};
+inline std::ostream& operator<<(std::ostream& os, const StreamableType& t) {
+  os << "Streamable:" << t.contents;
+  return os;
+}
+
+TEST(StreamFormatter, FormatterAPI) {
+  auto f = absl::StreamFormatter();
+  std::string s;
+  f(&s, "Testing: ");
+  f(&s, static_cast<int>(1));
+  f(&s, static_cast<int16_t>(2));
+  f(&s, static_cast<int64_t>(3));
+  f(&s, static_cast<float>(4));
+  f(&s, static_cast<double>(5));
+  f(&s, static_cast<unsigned>(6));
+  f(&s, static_cast<size_t>(7));
+  f(&s, absl::string_view(" OK "));
+  StreamableType streamable = {"object"};
+  f(&s, streamable);
+  EXPECT_EQ("Testing: 1234567 OK Streamable:object", s);
+}
+
+// A dummy formatter that wraps each element in parens. Used in some tests
+// below.
+struct TestingParenFormatter {
+  template <typename T>
+  void operator()(std::string* s, const T& t) {
+    absl::StrAppend(s, "(", t, ")");
+  }
+};
+
+TEST(PairFormatter, FormatterAPI) {
+  {
+    // Tests default PairFormatter(sep) that uses AlphaNumFormatter for the
+    // 'first' and 'second' members.
+    const auto f = absl::PairFormatter("=");
+    std::string s;
+    f(&s, std::make_pair("a", "b"));
+    f(&s, std::make_pair(1, 2));
+    EXPECT_EQ("a=b1=2", s);
+  }
+
+  {
+    // Tests using a custom formatter for the 'first' and 'second' members.
+    auto f = absl::PairFormatter(TestingParenFormatter(), "=",
+                                 TestingParenFormatter());
+    std::string s;
+    f(&s, std::make_pair("a", "b"));
+    f(&s, std::make_pair(1, 2));
+    EXPECT_EQ("(a)=(b)(1)=(2)", s);
+  }
+}
+
+TEST(DereferenceFormatter, FormatterAPI) {
+  {
+    // Tests wrapping the default AlphaNumFormatter.
+    const absl::strings_internal::DereferenceFormatterImpl<
+        absl::strings_internal::AlphaNumFormatterImpl>
+        f;
+    int x = 1, y = 2, z = 3;
+    std::string s;
+    f(&s, &x);
+    f(&s, &y);
+    f(&s, &z);
+    EXPECT_EQ("123", s);
+  }
+
+  {
+    // Tests wrapping std::string's default formatter.
+    absl::strings_internal::DereferenceFormatterImpl<
+        absl::strings_internal::DefaultFormatter<std::string>::Type>
+        f;
+
+    std::string x = "x";
+    std::string y = "y";
+    std::string z = "z";
+    std::string s;
+    f(&s, &x);
+    f(&s, &y);
+    f(&s, &z);
+    EXPECT_EQ(s, "xyz");
+  }
+
+  {
+    // Tests wrapping a custom formatter.
+    auto f = absl::DereferenceFormatter(TestingParenFormatter());
+    int x = 1, y = 2, z = 3;
+    std::string s;
+    f(&s, &x);
+    f(&s, &y);
+    f(&s, &z);
+    EXPECT_EQ("(1)(2)(3)", s);
+  }
+
+  {
+    absl::strings_internal::DereferenceFormatterImpl<
+        absl::strings_internal::AlphaNumFormatterImpl>
+        f;
+    auto x = std::unique_ptr<int>(new int(1));
+    auto y = std::unique_ptr<int>(new int(2));
+    auto z = std::unique_ptr<int>(new int(3));
+    std::string s;
+    f(&s, x);
+    f(&s, y);
+    f(&s, z);
+    EXPECT_EQ("123", s);
+  }
+}
+
+//
+// Tests the interfaces for the 4 public Join function overloads. The semantics
+// of the algorithm is covered in the above APIExamples test.
+//
+TEST(StrJoin, PublicAPIOverloads) {
+  std::vector<std::string> v = {"a", "b", "c"};
+
+  // Iterators + formatter
+  EXPECT_EQ("a-b-c",
+            absl::StrJoin(v.begin(), v.end(), "-", absl::AlphaNumFormatter()));
+  // Range + formatter
+  EXPECT_EQ("a-b-c", absl::StrJoin(v, "-", absl::AlphaNumFormatter()));
+  // Iterators, no formatter
+  EXPECT_EQ("a-b-c", absl::StrJoin(v.begin(), v.end(), "-"));
+  // Range, no formatter
+  EXPECT_EQ("a-b-c", absl::StrJoin(v, "-"));
+}
+
+TEST(StrJoin, Array) {
+  const absl::string_view a[] = {"a", "b", "c"};
+  EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+}
+
+TEST(StrJoin, InitializerList) {
+  { EXPECT_EQ("a-b-c", absl::StrJoin({"a", "b", "c"}, "-")); }
+
+  {
+    auto a = {"a", "b", "c"};
+    EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+  }
+
+  {
+    std::initializer_list<const char*> a = {"a", "b", "c"};
+    EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+  }
+
+  {
+    std::initializer_list<std::string> a = {"a", "b", "c"};
+    EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+  }
+
+  {
+    std::initializer_list<absl::string_view> a = {"a", "b", "c"};
+    EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+  }
+
+  {
+    // Tests initializer_list with a non-default formatter
+    auto a = {"a", "b", "c"};
+    TestingParenFormatter f;
+    EXPECT_EQ("(a)-(b)-(c)", absl::StrJoin(a, "-", f));
+  }
+
+  {
+    // initializer_list of ints
+    EXPECT_EQ("1-2-3", absl::StrJoin({1, 2, 3}, "-"));
+  }
+
+  {
+    // Tests initializer_list of ints with a non-default formatter
+    auto a = {1, 2, 3};
+    TestingParenFormatter f;
+    EXPECT_EQ("(1)-(2)-(3)", absl::StrJoin(a, "-", f));
+  }
+}
+
+TEST(StrJoin, Tuple) {
+  EXPECT_EQ("", absl::StrJoin(std::make_tuple(), "-"));
+  EXPECT_EQ("hello", absl::StrJoin(std::make_tuple("hello"), "-"));
+
+  int x(10);
+  std::string y("hello");
+  double z(3.14);
+  EXPECT_EQ("10-hello-3.14", absl::StrJoin(std::make_tuple(x, y, z), "-"));
+
+  // Faster! Faster!!
+  EXPECT_EQ("10-hello-3.14",
+            absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-"));
+
+  struct TestFormatter {
+    char buffer[128];
+    void operator()(std::string* out, int v) {
+      snprintf(buffer, sizeof(buffer), "%#.8x", v);
+      out->append(buffer);
+    }
+    void operator()(std::string* out, double v) {
+      snprintf(buffer, sizeof(buffer), "%#.0f", v);
+      out->append(buffer);
+    }
+    void operator()(std::string* out, const std::string& v) {
+      snprintf(buffer, sizeof(buffer), "%.4s", v.c_str());
+      out->append(buffer);
+    }
+  };
+  EXPECT_EQ("0x0000000a-hell-3.",
+            absl::StrJoin(std::make_tuple(x, y, z), "-", TestFormatter()));
+  EXPECT_EQ(
+      "0x0000000a-hell-3.",
+      absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-", TestFormatter()));
+  EXPECT_EQ("0x0000000a-hell-3.",
+            absl::StrJoin(std::make_tuple(&x, &y, &z), "-",
+                          absl::DereferenceFormatter(TestFormatter())));
+  EXPECT_EQ("0x0000000a-hell-3.",
+            absl::StrJoin(std::make_tuple(absl::make_unique<int>(x),
+                                          absl::make_unique<std::string>(y),
+                                          absl::make_unique<double>(z)),
+                          "-", absl::DereferenceFormatter(TestFormatter())));
+  EXPECT_EQ("0x0000000a-hell-3.",
+            absl::StrJoin(std::make_tuple(absl::make_unique<int>(x), &y, &z),
+                          "-", absl::DereferenceFormatter(TestFormatter())));
+}
+
+}  // namespace
diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc
new file mode 100644
index 0000000..69efa35
--- /dev/null
+++ b/absl/strings/str_replace.cc
@@ -0,0 +1,79 @@
+// Copyright 2017 The Abseil 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 "absl/strings/str_replace.h"
+
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+namespace strings_internal {
+
+using FixedMapping =
+    std::initializer_list<std::pair<absl::string_view, absl::string_view>>;
+
+// Applies the ViableSubstitutions in subs_ptr to the absl::string_view s, and
+// stores the result in *result_ptr. Returns the number of substitutions that
+// occurred.
+int ApplySubstitutions(
+    absl::string_view s,
+    std::vector<strings_internal::ViableSubstitution>* subs_ptr,
+    std::string* result_ptr) {
+  auto& subs = *subs_ptr;
+  int substitutions = 0;
+  size_t pos = 0;
+  while (!subs.empty()) {
+    auto& sub = subs.back();
+    if (sub.offset >= pos) {
+      if (pos <= s.size()) {
+        StrAppend(result_ptr, s.substr(pos, sub.offset - pos), sub.replacement);
+      }
+      pos = sub.offset + sub.old.size();
+      substitutions += 1;
+    }
+    sub.offset = s.find(sub.old, pos);
+    if (sub.offset == s.npos) {
+      subs.pop_back();
+    } else {
+      // Insertion sort to ensure the last ViableSubstitution continues to be
+      // before all the others.
+      size_t index = subs.size();
+      while (--index && subs[index - 1].OccursBefore(subs[index])) {
+        std::swap(subs[index], subs[index - 1]);
+      }
+    }
+  }
+  result_ptr->append(s.data() + pos, s.size() - pos);
+  return substitutions;
+}
+
+}  // namespace strings_internal
+
+// We can implement this in terms of the generic StrReplaceAll, but
+// we must specify the template overload because C++ cannot deduce the type
+// of an initializer_list parameter to a function, and also if we don't specify
+// the type, we just call ourselves.
+//
+// Note that we implement them here, rather than in the header, so that they
+// aren't inlined.
+
+std::string StrReplaceAll(absl::string_view s,
+                     strings_internal::FixedMapping replacements) {
+  return StrReplaceAll<strings_internal::FixedMapping>(s, replacements);
+}
+
+int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) {
+  return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
+}
+
+}  // namespace absl
diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h
new file mode 100644
index 0000000..f4d9bb9
--- /dev/null
+++ b/absl/strings/str_replace.h
@@ -0,0 +1,213 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: str_replace.h
+// -----------------------------------------------------------------------------
+//
+// This file defines `absl::StrReplaceAll()`, a general-purpose std::string
+// replacement function designed for large, arbitrary text substitutions,
+// especially on strings which you are receiving from some other system for
+// further processing (e.g. processing regular expressions, escaping HTML
+// entities, etc. `StrReplaceAll` is designed to be efficient even when only
+// one substitution is being performed, or when substitution is rare.
+//
+// If the std::string being modified is known at compile-time, and the substitutions
+// vary, `absl::Substitute()` may be a better choice.
+//
+// Example:
+//
+// std::string html_escaped = absl::StrReplaceAll(user_input, {
+//                                           {"&", "&amp;"},
+//                                           {"<", "&lt;"},
+//                                           {">", "&gt;"},
+//                                           {"\"", "&quot;"},
+//                                           {"'", "&#39;"}});
+#ifndef ABSL_STRINGS_STR_REPLACE_H_
+#define ABSL_STRINGS_STR_REPLACE_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// StrReplaceAll()
+//
+// Replaces character sequences within a given std::string with replacements provided
+// within an initializer list of key/value pairs. Candidate replacements are
+// considered in order as they occur within the std::string, with earlier matches
+// taking precedence, and longer matches taking precedence for candidates
+// starting at the same position in the std::string. Once a substitution is made, the
+// replaced text is not considered for any further substitutions.
+//
+// Example:
+//
+//   std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
+//                                  {{"$count", absl::StrCat(5)},
+//                                   {"$who", "Bob"},
+//                                   {"#Noun", "Apples"}});
+//   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+ABSL_MUST_USE_RESULT std::string StrReplaceAll(
+    absl::string_view s,
+    std::initializer_list<std::pair<absl::string_view, absl::string_view>>
+        replacements);
+
+// Overload of `StrReplaceAll()` to accept a container of key/value replacement
+// pairs (typically either an associative map or a `std::vector` of `std::pair`
+// elements). A vector of pairs is generally more efficient.
+//
+// Examples:
+//
+//   std::map<const absl::string_view, const absl::string_view> replacements;
+//   replacements["$who"] = "Bob";
+//   replacements["$count"] = "5";
+//   replacements["#Noun"] = "Apples";
+//   std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
+//                                  replacements);
+//   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+//
+//   // A std::vector of std::pair elements can be more efficient.
+//   std::vector<std::pair<const absl::string_view, std::string>> replacements;
+//   replacements.push_back({"&", "&amp;"});
+//   replacements.push_back({"<", "&lt;"});
+//   replacements.push_back({">", "&gt;"});
+//   std::string s = absl::StrReplaceAll("if (ptr < &foo)",
+//                                  replacements);
+//   EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
+template <typename StrToStrMapping>
+std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements);
+
+// Overload of `StrReplaceAll()` to replace character sequences within a given
+// output std::string *in place* with replacements provided within an initializer
+// list of key/value pairs, returning the number of substitutions that occurred.
+//
+// Example:
+//
+//   std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+//   int count;
+//   count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
+//                               {"$who", "Bob"},
+//                               {"#Noun", "Apples"}}, &s);
+//  EXPECT_EQ(count, 4);
+//  EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+int StrReplaceAll(
+    std::initializer_list<std::pair<absl::string_view, absl::string_view>>
+        replacements,
+    std::string* target);
+
+// Overload of `StrReplaceAll()` to replace patterns within a given output
+// std::string *in place* with replacements provided within a container of key/value
+// pairs.
+//
+// Example:
+//
+//   std::string s = std::string("if (ptr < &foo)");
+//   int count = absl::StrReplaceAll({{"&", "&amp;"},
+//                                    {"<", "&lt;"},
+//                                    {">", "&gt;"}}, &s);
+//  EXPECT_EQ(count, 2);
+//  EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
+template <typename StrToStrMapping>
+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target);
+
+// Implementation details only, past this point.
+namespace strings_internal {
+
+struct ViableSubstitution {
+  absl::string_view old;
+  absl::string_view replacement;
+  size_t offset;
+
+  ViableSubstitution(absl::string_view old_str,
+                     absl::string_view replacement_str, size_t offset_val)
+      : old(old_str), replacement(replacement_str), offset(offset_val) {}
+
+  // One substitution occurs "before" another (takes priority) if either
+  // it has the lowest offset, or it has the same offset but a larger size.
+  bool OccursBefore(const ViableSubstitution& y) const {
+    if (offset != y.offset) return offset < y.offset;
+    return old.size() > y.old.size();
+  }
+};
+
+// Build a vector of ViableSubstitutions based on the given list of
+// replacements. subs can be implemented as a priority_queue. However, it turns
+// out that most callers have small enough a list of substitutions that the
+// overhead of such a queue isn't worth it.
+template <typename StrToStrMapping>
+std::vector<ViableSubstitution> FindSubstitutions(
+    absl::string_view s, const StrToStrMapping& replacements) {
+  std::vector<ViableSubstitution> subs;
+  subs.reserve(replacements.size());
+
+  for (const auto& rep : replacements) {
+    using std::get;
+    absl::string_view old(get<0>(rep));
+
+    size_t pos = s.find(old);
+    if (pos == s.npos) continue;
+
+    // Ignore attempts to replace "". This condition is almost never true,
+    // but above condition is frequently true. That's why we test for this
+    // now and not before.
+    if (old.empty()) continue;
+
+    subs.emplace_back(old, get<1>(rep), pos);
+
+    // Insertion sort to ensure the last ViableSubstitution comes before
+    // all the others.
+    size_t index = subs.size();
+    while (--index && subs[index - 1].OccursBefore(subs[index])) {
+      std::swap(subs[index], subs[index - 1]);
+    }
+  }
+  return subs;
+}
+
+int ApplySubstitutions(absl::string_view s,
+                       std::vector<ViableSubstitution>* subs_ptr,
+                       std::string* result_ptr);
+
+}  // namespace strings_internal
+
+template <typename StrToStrMapping>
+std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) {
+  auto subs = strings_internal::FindSubstitutions(s, replacements);
+  std::string result;
+  result.reserve(s.size());
+  strings_internal::ApplySubstitutions(s, &subs, &result);
+  return result;
+}
+
+template <typename StrToStrMapping>
+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) {
+  auto subs = strings_internal::FindSubstitutions(*target, replacements);
+  if (subs.empty()) return 0;
+
+  std::string result;
+  result.reserve(target->size());
+  int substitutions =
+      strings_internal::ApplySubstitutions(*target, &subs, &result);
+  target->swap(result);
+  return substitutions;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_REPLACE_H_
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc
new file mode 100644
index 0000000..e608de8
--- /dev/null
+++ b/absl/strings/str_replace_benchmark.cc
@@ -0,0 +1,122 @@
+// Copyright 2018 The Abseil 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 "absl/strings/str_replace.h"
+
+#include <cstring>
+#include <string>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace {
+
+std::string* big_string;
+std::string* after_replacing_the;
+std::string* after_replacing_many;
+
+struct Replacement {
+  const char* needle;
+  const char* replacement;
+} replacements[] = {
+    {"the", "box"},          //
+    {"brown", "quick"},      //
+    {"jumped", "liquored"},  //
+    {"dozen", "brown"},      //
+    {"lazy", "pack"},        //
+    {"liquor", "shakes"},    //
+};
+
+// Here, we set up a std::string for use in global-replace benchmarks.
+// We started with a million blanks, and then deterministically insert
+// 10,000 copies each of two pangrams.  The result is a std::string that is
+// 40% blank space and 60% these words.  'the' occurs 18,247 times and
+// all the substitutions together occur 49,004 times.
+//
+// We then create "after_replacing_the" to be a std::string that is a result of
+// replacing "the" with "box" in big_string.
+//
+// And then we create "after_replacing_many" to be a std::string that is result
+// of preferring several substitutions.
+void SetUpStrings() {
+  if (big_string == nullptr) {
+    size_t r = 0;
+    big_string = new std::string(1000 * 1000, ' ');
+    for (std::string phrase : {"the quick brown fox jumped over the lazy dogs",
+                          "pack my box with the five dozen liquor jugs"}) {
+      for (int i = 0; i < 10 * 1000; ++i) {
+        r = r * 237 + 41;  // not very random.
+        memcpy(&(*big_string)[r % (big_string->size() - phrase.size())],
+               phrase.data(), phrase.size());
+      }
+    }
+    // big_string->resize(50);
+    // OK, we've set up the std::string, now let's set up expectations - first by
+    // just replacing "the" with "box"
+    after_replacing_the = new std::string(*big_string);
+    for (size_t pos = 0;
+         (pos = after_replacing_the->find("the", pos)) != std::string::npos;) {
+      memcpy(&(*after_replacing_the)[pos], "box", 3);
+    }
+    // And then with all the replacements.
+    after_replacing_many = new std::string(*big_string);
+    for (size_t pos = 0;;) {
+      size_t next_pos = static_cast<size_t>(-1);
+      const char* needle_string = nullptr;
+      const char* replacement_string = nullptr;
+      for (const auto& r : replacements) {
+        auto needlepos = after_replacing_many->find(r.needle, pos);
+        if (needlepos != std::string::npos && needlepos < next_pos) {
+          next_pos = needlepos;
+          needle_string = r.needle;
+          replacement_string = r.replacement;
+        }
+      }
+      if (next_pos > after_replacing_many->size()) break;
+      after_replacing_many->replace(next_pos, strlen(needle_string),
+                                    replacement_string);
+      next_pos += strlen(replacement_string);
+      pos = next_pos;
+    }
+  }
+}
+
+void BM_StrReplaceAllOneReplacement(benchmark::State& state) {
+  SetUpStrings();
+  std::string src = *big_string;
+  for (auto _ : state) {
+    std::string dest = absl::StrReplaceAll(src, {{"the", "box"}});
+    ABSL_RAW_CHECK(dest == *after_replacing_the,
+                   "not benchmarking intended behavior");
+  }
+}
+BENCHMARK(BM_StrReplaceAllOneReplacement);
+
+void BM_StrReplaceAll(benchmark::State& state) {
+  SetUpStrings();
+  std::string src = *big_string;
+  for (auto _ : state) {
+    std::string dest = absl::StrReplaceAll(src, {{"the", "box"},
+                                            {"brown", "quick"},
+                                            {"jumped", "liquored"},
+                                            {"dozen", "brown"},
+                                            {"lazy", "pack"},
+                                            {"liquor", "shakes"}});
+    ABSL_RAW_CHECK(dest == *after_replacing_many,
+                   "not benchmarking intended behavior");
+  }
+}
+BENCHMARK(BM_StrReplaceAll);
+
+}  // namespace
diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc
new file mode 100644
index 0000000..5d003a2
--- /dev/null
+++ b/absl/strings/str_replace_test.cc
@@ -0,0 +1,341 @@
+// Copyright 2017 The Abseil 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 "absl/strings/str_replace.h"
+
+#include <list>
+#include <map>
+#include <tuple>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+
+TEST(StrReplaceAll, OneReplacement) {
+  std::string s;
+
+  // Empty std::string.
+  s = absl::StrReplaceAll(s, {{"", ""}});
+  EXPECT_EQ(s, "");
+  s = absl::StrReplaceAll(s, {{"x", ""}});
+  EXPECT_EQ(s, "");
+  s = absl::StrReplaceAll(s, {{"", "y"}});
+  EXPECT_EQ(s, "");
+  s = absl::StrReplaceAll(s, {{"x", "y"}});
+  EXPECT_EQ(s, "");
+
+  // Empty substring.
+  s = absl::StrReplaceAll("abc", {{"", ""}});
+  EXPECT_EQ(s, "abc");
+  s = absl::StrReplaceAll("abc", {{"", "y"}});
+  EXPECT_EQ(s, "abc");
+  s = absl::StrReplaceAll("abc", {{"x", ""}});
+  EXPECT_EQ(s, "abc");
+
+  // Substring not found.
+  s = absl::StrReplaceAll("abc", {{"xyz", "123"}});
+  EXPECT_EQ(s, "abc");
+
+  // Replace entire std::string.
+  s = absl::StrReplaceAll("abc", {{"abc", "xyz"}});
+  EXPECT_EQ(s, "xyz");
+
+  // Replace once at the start.
+  s = absl::StrReplaceAll("abc", {{"a", "x"}});
+  EXPECT_EQ(s, "xbc");
+
+  // Replace once in the middle.
+  s = absl::StrReplaceAll("abc", {{"b", "x"}});
+  EXPECT_EQ(s, "axc");
+
+  // Replace once at the end.
+  s = absl::StrReplaceAll("abc", {{"c", "x"}});
+  EXPECT_EQ(s, "abx");
+
+  // Replace multiple times with varying lengths of original/replacement.
+  s = absl::StrReplaceAll("ababa", {{"a", "xxx"}});
+  EXPECT_EQ(s, "xxxbxxxbxxx");
+
+  s = absl::StrReplaceAll("ababa", {{"b", "xxx"}});
+  EXPECT_EQ(s, "axxxaxxxa");
+
+  s = absl::StrReplaceAll("aaabaaabaaa", {{"aaa", "x"}});
+  EXPECT_EQ(s, "xbxbx");
+
+  s = absl::StrReplaceAll("abbbabbba", {{"bbb", "x"}});
+  EXPECT_EQ(s, "axaxa");
+
+  // Overlapping matches are replaced greedily.
+  s = absl::StrReplaceAll("aaa", {{"aa", "x"}});
+  EXPECT_EQ(s, "xa");
+
+  // The replacements are not recursive.
+  s = absl::StrReplaceAll("aaa", {{"aa", "a"}});
+  EXPECT_EQ(s, "aa");
+}
+
+TEST(StrReplaceAll, ManyReplacements) {
+  std::string s;
+
+  // Empty std::string.
+  s = absl::StrReplaceAll("", {{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}});
+  EXPECT_EQ(s, "");
+
+  // Empty substring.
+  s = absl::StrReplaceAll("abc", {{"", ""}, {"", "y"}, {"x", ""}});
+  EXPECT_EQ(s, "abc");
+
+  // Replace entire std::string, one char at a time
+  s = absl::StrReplaceAll("abc", {{"a", "x"}, {"b", "y"}, {"c", "z"}});
+  EXPECT_EQ(s, "xyz");
+  s = absl::StrReplaceAll("zxy", {{"z", "x"}, {"x", "y"}, {"y", "z"}});
+  EXPECT_EQ(s, "xyz");
+
+  // Replace once at the start (longer matches take precedence)
+  s = absl::StrReplaceAll("abc", {{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}});
+  EXPECT_EQ(s, "xyz");
+
+  // Replace once in the middle.
+  s = absl::StrReplaceAll(
+      "Abc!", {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}});
+  EXPECT_EQ(s, "Ayz!");
+
+  // Replace once at the end.
+  s = absl::StrReplaceAll(
+      "Abc!",
+      {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}});
+  EXPECT_EQ(s, "Ayz?");
+
+  // Replace multiple times with varying lengths of original/replacement.
+  s = absl::StrReplaceAll("ababa", {{"a", "xxx"}, {"b", "XXXX"}});
+  EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx");
+
+  // Overlapping matches are replaced greedily.
+  s = absl::StrReplaceAll("aaa", {{"aa", "x"}, {"a", "X"}});
+  EXPECT_EQ(s, "xX");
+  s = absl::StrReplaceAll("aaa", {{"a", "X"}, {"aa", "x"}});
+  EXPECT_EQ(s, "xX");
+
+  // Two well-known sentences
+  s = absl::StrReplaceAll("the quick brown fox jumped over the lazy dogs",
+                          {
+                              {"brown", "box"},
+                              {"dogs", "jugs"},
+                              {"fox", "with"},
+                              {"jumped", "five"},
+                              {"over", "dozen"},
+                              {"quick", "my"},
+                              {"the", "pack"},
+                              {"the lazy", "liquor"},
+                          });
+  EXPECT_EQ(s, "pack my box with five dozen liquor jugs");
+}
+
+TEST(StrReplaceAll, ManyReplacementsInMap) {
+  std::map<const char *, const char *> replacements;
+  replacements["$who"] = "Bob";
+  replacements["$count"] = "5";
+  replacements["#Noun"] = "Apples";
+  std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
+                                 replacements);
+  EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+}
+
+TEST(StrReplaceAll, ReplacementsInPlace) {
+  std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+  int count;
+  count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
+                              {"$who", "Bob"},
+                              {"#Noun", "Apples"}}, &s);
+  EXPECT_EQ(count, 4);
+  EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+}
+
+TEST(StrReplaceAll, ReplacementsInPlaceInMap) {
+  std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+  std::map<absl::string_view, absl::string_view> replacements;
+  replacements["$who"] = "Bob";
+  replacements["$count"] = "5";
+  replacements["#Noun"] = "Apples";
+  int count;
+  count = absl::StrReplaceAll(replacements, &s);
+  EXPECT_EQ(count, 4);
+  EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+}
+
+struct Cont {
+  Cont() {}
+  explicit Cont(absl::string_view src) : data(src) {}
+
+  absl::string_view data;
+};
+
+template <int index>
+absl::string_view get(const Cont& c) {
+  auto splitter = absl::StrSplit(c.data, ':');
+  auto it = splitter.begin();
+  for (int i = 0; i < index; ++i) ++it;
+
+  return *it;
+}
+
+TEST(StrReplaceAll, VariableNumber) {
+  std::string s;
+  {
+    std::vector<std::pair<std::string, std::string>> replacements;
+
+    s = "abc";
+    EXPECT_EQ(0, absl::StrReplaceAll(replacements, &s));
+    EXPECT_EQ("abc", s);
+
+    s = "abc";
+    replacements.push_back({"a", "A"});
+    EXPECT_EQ(1, absl::StrReplaceAll(replacements, &s));
+    EXPECT_EQ("Abc", s);
+
+    s = "abc";
+    replacements.push_back({"b", "B"});
+    EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
+    EXPECT_EQ("ABc", s);
+
+    s = "abc";
+    replacements.push_back({"d", "D"});
+    EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
+    EXPECT_EQ("ABc", s);
+
+    EXPECT_EQ("ABcABc", absl::StrReplaceAll("abcabc", replacements));
+  }
+
+  {
+    std::map<const char*, const char*> replacements;
+    replacements["aa"] = "x";
+    replacements["a"] = "X";
+    s = "aaa";
+    EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
+    EXPECT_EQ("xX", s);
+
+    EXPECT_EQ("xxX", absl::StrReplaceAll("aaaaa", replacements));
+  }
+
+  {
+    std::list<std::pair<absl::string_view, absl::string_view>> replacements = {
+        {"a", "x"}, {"b", "y"}, {"c", "z"}};
+
+    std::string s = absl::StrReplaceAll("abc", replacements);
+    EXPECT_EQ(s, "xyz");
+  }
+
+  {
+    using X = std::tuple<absl::string_view, std::string, int>;
+    std::vector<X> replacements(3);
+    replacements[0] = X{"a", "x", 1};
+    replacements[1] = X{"b", "y", 0};
+    replacements[2] = X{"c", "z", -1};
+
+    std::string s = absl::StrReplaceAll("abc", replacements);
+    EXPECT_EQ(s, "xyz");
+  }
+
+  {
+    std::vector<Cont> replacements(3);
+    replacements[0] = Cont{"a:x"};
+    replacements[1] = Cont{"b:y"};
+    replacements[2] = Cont{"c:z"};
+
+    std::string s = absl::StrReplaceAll("abc", replacements);
+    EXPECT_EQ(s, "xyz");
+  }
+}
+
+// Same as above, but using the in-place variant of absl::StrReplaceAll,
+// that returns the # of replacements performed.
+TEST(StrReplaceAll, Inplace) {
+  std::string s;
+  int reps;
+
+  // Empty std::string.
+  s = "";
+  reps = absl::StrReplaceAll({{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}, &s);
+  EXPECT_EQ(reps, 0);
+  EXPECT_EQ(s, "");
+
+  // Empty substring.
+  s = "abc";
+  reps = absl::StrReplaceAll({{"", ""}, {"", "y"}, {"x", ""}}, &s);
+  EXPECT_EQ(reps, 0);
+  EXPECT_EQ(s, "abc");
+
+  // Replace entire std::string, one char at a time
+  s = "abc";
+  reps = absl::StrReplaceAll({{"a", "x"}, {"b", "y"}, {"c", "z"}}, &s);
+  EXPECT_EQ(reps, 3);
+  EXPECT_EQ(s, "xyz");
+  s = "zxy";
+  reps = absl::StrReplaceAll({{"z", "x"}, {"x", "y"}, {"y", "z"}}, &s);
+  EXPECT_EQ(reps, 3);
+  EXPECT_EQ(s, "xyz");
+
+  // Replace once at the start (longer matches take precedence)
+  s = "abc";
+  reps = absl::StrReplaceAll({{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}}, &s);
+  EXPECT_EQ(reps, 1);
+  EXPECT_EQ(s, "xyz");
+
+  // Replace once in the middle.
+  s = "Abc!";
+  reps = absl::StrReplaceAll(
+      {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}}, &s);
+  EXPECT_EQ(reps, 1);
+  EXPECT_EQ(s, "Ayz!");
+
+  // Replace once at the end.
+  s = "Abc!";
+  reps = absl::StrReplaceAll(
+      {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}}, &s);
+  EXPECT_EQ(reps, 1);
+  EXPECT_EQ(s, "Ayz?");
+
+  // Replace multiple times with varying lengths of original/replacement.
+  s = "ababa";
+  reps = absl::StrReplaceAll({{"a", "xxx"}, {"b", "XXXX"}}, &s);
+  EXPECT_EQ(reps, 5);
+  EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx");
+
+  // Overlapping matches are replaced greedily.
+  s = "aaa";
+  reps = absl::StrReplaceAll({{"aa", "x"}, {"a", "X"}}, &s);
+  EXPECT_EQ(reps, 2);
+  EXPECT_EQ(s, "xX");
+  s = "aaa";
+  reps = absl::StrReplaceAll({{"a", "X"}, {"aa", "x"}}, &s);
+  EXPECT_EQ(reps, 2);
+  EXPECT_EQ(s, "xX");
+
+  // Two well-known sentences
+  s = "the quick brown fox jumped over the lazy dogs";
+  reps = absl::StrReplaceAll(
+      {
+          {"brown", "box"},
+          {"dogs", "jugs"},
+          {"fox", "with"},
+          {"jumped", "five"},
+          {"over", "dozen"},
+          {"quick", "my"},
+          {"the", "pack"},
+          {"the lazy", "liquor"},
+      },
+      &s);
+  EXPECT_EQ(reps, 8);
+  EXPECT_EQ(s, "pack my box with five dozen liquor jugs");
+}
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc
new file mode 100644
index 0000000..0207213
--- /dev/null
+++ b/absl/strings/str_split.cc
@@ -0,0 +1,136 @@
+// Copyright 2017 The Abseil 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 "absl/strings/str_split.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+
+namespace absl {
+
+namespace {
+
+// This GenericFind() template function encapsulates the finding algorithm
+// shared between the ByString and ByAnyChar delimiters. The FindPolicy
+// template parameter allows each delimiter to customize the actual find
+// function to use and the length of the found delimiter. For example, the
+// Literal delimiter will ultimately use absl::string_view::find(), and the
+// AnyOf delimiter will use absl::string_view::find_first_of().
+template <typename FindPolicy>
+absl::string_view GenericFind(absl::string_view text,
+                              absl::string_view delimiter, size_t pos,
+                              FindPolicy find_policy) {
+  if (delimiter.empty() && text.length() > 0) {
+    // Special case for empty std::string delimiters: always return a zero-length
+    // absl::string_view referring to the item at position 1 past pos.
+    return absl::string_view(text.begin() + pos + 1, 0);
+  }
+  size_t found_pos = absl::string_view::npos;
+  absl::string_view found(text.end(), 0);  // By default, not found
+  found_pos = find_policy.Find(text, delimiter, pos);
+  if (found_pos != absl::string_view::npos) {
+    found = absl::string_view(text.data() + found_pos,
+                              find_policy.Length(delimiter));
+  }
+  return found;
+}
+
+// Finds using absl::string_view::find(), therefore the length of the found
+// delimiter is delimiter.length().
+struct LiteralPolicy {
+  size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+    return text.find(delimiter, pos);
+  }
+  size_t Length(absl::string_view delimiter) { return delimiter.length(); }
+};
+
+// Finds using absl::string_view::find_first_of(), therefore the length of the
+// found delimiter is 1.
+struct AnyOfPolicy {
+  size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+    return text.find_first_of(delimiter, pos);
+  }
+  size_t Length(absl::string_view /* delimiter */) { return 1; }
+};
+
+}  // namespace
+
+//
+// ByString
+//
+
+ByString::ByString(absl::string_view sp) : delimiter_(sp) {}
+
+absl::string_view ByString::Find(absl::string_view text, size_t pos) const {
+  if (delimiter_.length() == 1) {
+    // Much faster to call find on a single character than on an
+    // absl::string_view.
+    size_t found_pos = text.find(delimiter_[0], pos);
+    if (found_pos == absl::string_view::npos)
+      return absl::string_view(text.end(), 0);
+    return text.substr(found_pos, 1);
+  }
+  return GenericFind(text, delimiter_, pos, LiteralPolicy());
+}
+
+//
+// ByChar
+//
+
+absl::string_view ByChar::Find(absl::string_view text, size_t pos) const {
+  size_t found_pos = text.find(c_, pos);
+  if (found_pos == absl::string_view::npos)
+    return absl::string_view(text.end(), 0);
+  return text.substr(found_pos, 1);
+}
+
+//
+// ByAnyChar
+//
+
+ByAnyChar::ByAnyChar(absl::string_view sp) : delimiters_(sp) {}
+
+absl::string_view ByAnyChar::Find(absl::string_view text, size_t pos) const {
+  return GenericFind(text, delimiters_, pos, AnyOfPolicy());
+}
+
+//
+// ByLength
+//
+ByLength::ByLength(ptrdiff_t length) : length_(length) {
+  ABSL_RAW_CHECK(length > 0, "");
+}
+
+absl::string_view ByLength::Find(absl::string_view text,
+                                      size_t pos) const {
+  pos = std::min(pos, text.size());  // truncate `pos`
+  absl::string_view substr = text.substr(pos);
+  // If the std::string is shorter than the chunk size we say we
+  // "can't find the delimiter" so this will be the last chunk.
+  if (substr.length() <= static_cast<size_t>(length_))
+    return absl::string_view(text.end(), 0);
+
+  return absl::string_view(substr.begin() + length_, 0);
+}
+
+}  // namespace absl
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
new file mode 100644
index 0000000..1f089b9
--- /dev/null
+++ b/absl/strings/str_split.h
@@ -0,0 +1,511 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: str_split.h
+// -----------------------------------------------------------------------------
+//
+// This file contains functions for splitting strings. It defines the main
+// `StrSplit()` function, several delimiters for determining the boundaries on
+// which to split the std::string, and predicates for filtering delimited results.
+// `StrSplit()` adapts the returned collection to the type specified by the
+// caller.
+//
+// Example:
+//
+//   // Splits the given std::string on commas. Returns the results in a
+//   // vector of strings.
+//   std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+//   // Can also use ","
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// See StrSplit() below for more information.
+#ifndef ABSL_STRINGS_STR_SPLIT_H_
+#define ABSL_STRINGS_STR_SPLIT_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/internal/str_split_internal.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace absl {
+
+//------------------------------------------------------------------------------
+// Delimiters
+//------------------------------------------------------------------------------
+//
+// `StrSplit()` uses delimiters to define the boundaries between elements in the
+// provided input. Several `Delimiter` types are defined below. If a std::string
+// (`const char*`, `std::string`, or `absl::string_view`) is passed in place of
+// an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it
+// were passed a `ByString` delimiter.
+//
+// A `Delimiter` is an object with a `Find()` function that knows how to find
+// the first occurrence of itself in a given `absl::string_view`.
+//
+// The following `Delimiter` types are available for use within `StrSplit()`:
+//
+//   - `ByString` (default for std::string arguments)
+//   - `ByChar` (default for a char argument)
+//   - `ByAnyChar`
+//   - `ByLength`
+//   - `MaxSplits`
+//
+//
+// A Delimiter's Find() member function will be passed the input text that is to
+// be split and the position to begin searching for the next delimiter in the
+// input text. The returned absl::string_view should refer to the next
+// occurrence (after pos) of the represented delimiter; this returned
+// absl::string_view represents the next location where the input std::string should
+// be broken. The returned absl::string_view may be zero-length if the Delimiter
+// does not represent a part of the std::string (e.g., a fixed-length delimiter). If
+// no delimiter is found in the given text, a zero-length absl::string_view
+// referring to text.end() should be returned (e.g.,
+// absl::string_view(text.end(), 0)). It is important that the returned
+// absl::string_view always be within the bounds of input text given as an
+// argument--it must not refer to a std::string that is physically located outside of
+// the given std::string.
+//
+// The following example is a simple Delimiter object that is created with a
+// single char and will look for that char in the text passed to the Find()
+// function:
+//
+//   struct SimpleDelimiter {
+//     const char c_;
+//     explicit SimpleDelimiter(char c) : c_(c) {}
+//     absl::string_view Find(absl::string_view text, size_t pos) {
+//       auto found = text.find(c_, pos);
+//       if (found == absl::string_view::npos)
+//         return absl::string_view(text.end(), 0);
+//
+//       return absl::string_view(text, found, 1);
+//     }
+//   };
+
+// ByString
+//
+// A sub-std::string delimiter. If `StrSplit()` is passed a std::string in place of a
+// `Delimiter` object, the std::string will be implicitly converted into a
+// `ByString` delimiter.
+//
+// Example:
+//
+//   // Because a std::string literal is converted to an `absl::ByString`,
+//   // the following two splits are equivalent.
+//
+//   std::vector<std::string> v1 = absl::StrSplit("a, b, c", ", ");
+//
+//   using absl::ByString;
+//   std::vector<std::string> v2 = absl::StrSplit("a, b, c",
+//                                                ByString(", "));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+class ByString {
+ public:
+  explicit ByString(absl::string_view sp);
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  const std::string delimiter_;
+};
+
+// ByChar
+//
+// A single character delimiter. `ByChar` is functionally equivalent to a
+// 1-char std::string within a `ByString` delimiter, but slightly more
+// efficient.
+//
+// Example:
+//
+//   // Because a char literal is converted to a absl::ByChar,
+//   // the following two splits are equivalent.
+//   std::vector<std::string> v1 = absl::StrSplit("a,b,c", ',');
+//   using absl::ByChar;
+//   std::vector<std::string> v2 = absl::StrSplit("a,b,c", ByChar(','));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// `ByChar` is also the default delimiter if a single character is given
+// as the delimiter to `StrSplit()`. For example, the following calls are
+// equivalent:
+//
+//   std::vector<std::string> v = absl::StrSplit("a-b", '-');
+//
+//   using absl::ByChar;
+//   std::vector<std::string> v = absl::StrSplit("a-b", ByChar('-'));
+//
+class ByChar {
+ public:
+  explicit ByChar(char c) : c_(c) {}
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  char c_;
+};
+
+// ByAnyChar
+//
+// A delimiter that will match any of the given byte-sized characters within
+// its provided std::string.
+//
+// Note: this delimiter works with single-byte std::string data, but does not work
+// with variable-width encodings, such as UTF-8.
+//
+// Example:
+//
+//   using absl::ByAnyChar;
+//   std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// If `ByAnyChar` is given the empty std::string, it behaves exactly like
+// `ByString` and matches each individual character in the input std::string.
+//
+class ByAnyChar {
+ public:
+  explicit ByAnyChar(absl::string_view sp);
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  const std::string delimiters_;
+};
+
+// ByLength
+//
+// A delimiter for splitting into equal-length strings. The length argument to
+// the constructor must be greater than 0.
+//
+// Note: this delimiter works with single-byte std::string data, but does not work
+// with variable-width encodings, such as UTF-8.
+//
+// Example:
+//
+//   using absl::ByLength;
+//   std::vector<std::string> v = absl::StrSplit("123456789", ByLength(3));
+
+//   // v[0] == "123", v[1] == "456", v[2] == "789"
+//
+// Note that the std::string does not have to be a multiple of the fixed split
+// length. In such a case, the last substring will be shorter.
+//
+//   using absl::ByLength;
+//   std::vector<std::string> v = absl::StrSplit("12345", ByLength(2));
+//
+//   // v[0] == "12", v[1] == "34", v[2] == "5"
+class ByLength {
+ public:
+  explicit ByLength(ptrdiff_t length);
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  const ptrdiff_t length_;
+};
+
+namespace strings_internal {
+
+// A traits-like metafunction for selecting the default Delimiter object type
+// for a particular Delimiter type. The base case simply exposes type Delimiter
+// itself as the delimiter's Type. However, there are specializations for
+// std::string-like objects that map them to the ByString delimiter object.
+// This allows functions like absl::StrSplit() and absl::MaxSplits() to accept
+// std::string-like objects (e.g., ',') as delimiter arguments but they will be
+// treated as if a ByString delimiter was given.
+template <typename Delimiter>
+struct SelectDelimiter {
+  using type = Delimiter;
+};
+
+template <>
+struct SelectDelimiter<char> {
+  using type = ByChar;
+};
+template <>
+struct SelectDelimiter<char*> {
+  using type = ByString;
+};
+template <>
+struct SelectDelimiter<const char*> {
+  using type = ByString;
+};
+template <>
+struct SelectDelimiter<absl::string_view> {
+  using type = ByString;
+};
+template <>
+struct SelectDelimiter<std::string> {
+  using type = ByString;
+};
+
+// Wraps another delimiter and sets a max number of matches for that delimiter.
+template <typename Delimiter>
+class MaxSplitsImpl {
+ public:
+  MaxSplitsImpl(Delimiter delimiter, int limit)
+      : delimiter_(delimiter), limit_(limit), count_(0) {}
+  absl::string_view Find(absl::string_view text, size_t pos) {
+    if (count_++ == limit_) {
+      return absl::string_view(text.end(), 0);  // No more matches.
+    }
+    return delimiter_.Find(text, pos);
+  }
+
+ private:
+  Delimiter delimiter_;
+  const int limit_;
+  int count_;
+};
+
+}  // namespace strings_internal
+
+// MaxSplits()
+//
+// A delimiter that limits the number of matches which can occur to the passed
+// `limit`. The last element in the returned collection will contain all
+// remaining unsplit pieces, which may contain instances of the delimiter.
+// The collection will contain at most `limit` + 1 elements.
+// Example:
+//
+//   using absl::MaxSplits;
+//   std::vector<std::string> v = absl::StrSplit("a,b,c", MaxSplits(',', 1));
+//
+//   // v[0] == "a", v[1] == "b,c"
+template <typename Delimiter>
+inline strings_internal::MaxSplitsImpl<
+    typename strings_internal::SelectDelimiter<Delimiter>::type>
+MaxSplits(Delimiter delimiter, int limit) {
+  typedef
+      typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType;
+  return strings_internal::MaxSplitsImpl<DelimiterType>(
+      DelimiterType(delimiter), limit);
+}
+
+//------------------------------------------------------------------------------
+// Predicates
+//------------------------------------------------------------------------------
+//
+// Predicates filter the results of a `StrSplit()` by determining whether or not
+// a resultant element is included in the result set. A predicate may be passed
+// as an optional third argument to the `StrSplit()` function.
+//
+// Predicates are unary functions (or functors) that take a single
+// `absl::string_view` argument and return a bool indicating whether the
+// argument should be included (`true`) or excluded (`false`).
+//
+// Predicates are useful when filtering out empty substrings. By default, empty
+// substrings may be returned by `StrSplit()`, which is similar to the way split
+// functions work in other programming languages.
+
+// AllowEmpty()
+//
+// Always returns `true`, indicating that all strings--including empty
+// strings--should be included in the split output. This predicate is not
+// strictly needed because this is the default behavior of `StrSplit()`;
+// however, it might be useful at some call sites to make the intent explicit.
+//
+// Example:
+//
+//  std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', AllowEmpty());
+//
+//  // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == ""
+struct AllowEmpty {
+  bool operator()(absl::string_view) const { return true; }
+};
+
+// SkipEmpty()
+//
+// Returns `false` if the given `absl::string_view` is empty, indicating that
+// `StrSplit()` should omit the empty std::string.
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit(",a,,b,", ',', SkipEmpty());
+//
+//   // v[0] == "a", v[1] == "b"
+//
+// Note: `SkipEmpty()` does not consider a std::string containing only whitespace
+// to be empty. To skip such whitespace as well, use the `SkipWhitespace()`
+// predicate.
+struct SkipEmpty {
+  bool operator()(absl::string_view sp) const { return !sp.empty(); }
+};
+
+// SkipWhitespace()
+//
+// Returns `false` if the given `absl::string_view` is empty *or* contains only
+// whitespace, indicating that `StrSplit()` should omit the std::string.
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
+//                                               ',', SkipWhitespace());
+//   // v[0] == " a ", v[1] == "b"
+//
+//   // SkipEmpty() would return whitespace elements
+//   std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipEmpty());
+//   // v[0] == " a ", v[1] == " ", v[2] == "b"
+struct SkipWhitespace {
+  bool operator()(absl::string_view sp) const {
+    sp = absl::StripAsciiWhitespace(sp);
+    return !sp.empty();
+  }
+};
+
+//------------------------------------------------------------------------------
+//                                  StrSplit()
+//------------------------------------------------------------------------------
+
+// StrSplit()
+//
+// Splits a given `std::string` based on the provided `Delimiter` object,
+// returning the elements within the type specified by the caller. Optionally,
+// you may also pass a `Predicate` to `StrSplit()` indicating whether to include
+// or exclude the resulting element within the final result set. (See the
+// overviews for Delimiters and Predicates above.)
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit("a,b,c,d", ',');
+//   // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d"
+//
+// You can also provide an explicit `Delimiter` object:
+//
+// Example:
+//
+//   using absl::ByAnyChar;
+//   std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// See above for more information on delimiters.
+//
+// By default, empty strings are included in the result set. You can optionally
+// include a third `Predicate` argument to apply a test for whether the
+// resultant element should be included in the result set:
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
+//                                               ',', SkipWhitespace());
+//   // v[0] == " a ", v[1] == "b"
+//
+// See above for more information on predicates.
+//
+//------------------------------------------------------------------------------
+// StrSplit() Return Types
+//------------------------------------------------------------------------------
+//
+// The `StrSplit()` function adapts the returned collection to the collection
+// specified by the caller (e.g. `std::vector` above). The returned collections
+// may contain `string`, `absl::string_view` (in which case the original std::string
+// being split must ensure that it outlives the collection), or any object that
+// can be explicitly created from an `absl::string_view`. This behavior works
+// for:
+//
+// 1) All standard STL containers including `std::vector`, `std::list`,
+//    `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
+// 2) `std::pair` (which is not actually a container). See below.
+//
+// Example:
+//
+//   // The results are returned as `absl::string_view` objects. Note that we
+//   // have to ensure that the input std::string outlives any results.
+//   std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+//
+//   // Stores results in a std::set<std::string>, which also performs
+//   // de-duplication and orders the elements in ascending order.
+//   std::set<std::string> a = absl::StrSplit("b,a,c,a,b", ',');
+//   // v[0] == "a", v[1] == "b", v[2] = "c"
+//
+//   // `StrSplit()` can be used within a range-based for loop, in which case
+//   // each element will be of type `absl::string_view`.
+//   std::vector<std::string> v;
+//   for (const auto sv : absl::StrSplit("a,b,c", ',')) {
+//     if (sv != "b") v.emplace_back(sv);
+//   }
+//   // v[0] == "a", v[1] == "c"
+//
+//   // Stores results in a map. The map implementation assumes that the input
+//   // is provided as a series of key/value pairs. For example, the 0th element
+//   // resulting from the split will be stored as a key to the 1st element. If
+//   // an odd number of elements are resolved, the last element is paired with
+//   // a default-constructed value (e.g., empty std::string).
+//   std::map<std::string, std::string> m = absl::StrSplit("a,b,c", ',');
+//   // m["a"] == "b", m["c"] == ""     // last component value equals ""
+//
+// Splitting to `std::pair` is an interesting case because it can hold only two
+// elements and is not a collection type. When splitting to a `std::pair` the
+// first two split strings become the `std::pair` `.first` and `.second`
+// members, respectively. The remaining split substrings are discarded. If there
+// are less than two split substrings, the empty std::string is used for the
+// corresponding
+// `std::pair` member.
+//
+// Example:
+//
+//   // Stores first two split strings as the members in a std::pair.
+//   std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+//   // p.first == "a", p.second == "b"       // "c" is omitted.
+//
+// The `StrSplit()` function can be used multiple times to perform more
+// complicated splitting logic, such as intelligently parsing key-value pairs.
+//
+// Example:
+//
+//   // The input std::string "a=b=c,d=e,f=,g" becomes
+//   // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" }
+//   std::map<std::string, std::string> m;
+//   for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
+//     m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
+//   }
+//   EXPECT_EQ("b=c", m.find("a")->second);
+//   EXPECT_EQ("e", m.find("d")->second);
+//   EXPECT_EQ("", m.find("f")->second);
+//   EXPECT_EQ("", m.find("g")->second);
+//
+// WARNING: Due to a legacy bug that is maintained for backward compatibility,
+// splitting the following empty string_views produces different results:
+//
+//   absl::StrSplit(absl::string_view(""), '-');  // {""}
+//   absl::StrSplit(absl::string_view(), '-');    // {}, but should be {""}
+//
+// Try not to depend on this distinction because the bug may one day be fixed.
+template <typename Delimiter>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty>
+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, AllowEmpty>(
+      std::move(text), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename Predicate>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate>
+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
+         Predicate p) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, Predicate>(
+      std::move(text), DelimiterType(d), std::move(p));
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_SPLIT_H_
diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc
new file mode 100644
index 0000000..326ff74
--- /dev/null
+++ b/absl/strings/str_split_benchmark.cc
@@ -0,0 +1,156 @@
+// Copyright 2018 The Abseil 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 "absl/strings/str_split.h"
+
+#include <iterator>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/string_view.h"
+
+namespace {
+
+std::string MakeTestString(int desired_length) {
+  static const int kAverageValueLen = 25;
+  std::string test(desired_length * kAverageValueLen, 'x');
+  for (int i = 1; i < test.size(); i += kAverageValueLen) {
+    test[i] = ';';
+  }
+  return test;
+}
+
+void BM_Split2StringPiece(benchmark::State& state) {
+  std::string test = MakeTestString(state.range(0));
+  for (auto _ : state) {
+    std::vector<absl::string_view> result = absl::StrSplit(test, ';');
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK_RANGE(BM_Split2StringPiece, 0, 1 << 20);
+
+void BM_Split2StringPieceLifted(benchmark::State& state) {
+  std::string test = MakeTestString(state.range(0));
+  std::vector<absl::string_view> result;
+  for (auto _ : state) {
+    result = absl::StrSplit(test, ';');
+  }
+  benchmark::DoNotOptimize(result);
+}
+BENCHMARK_RANGE(BM_Split2StringPieceLifted, 0, 1 << 20);
+
+void BM_Split2String(benchmark::State& state) {
+  std::string test = MakeTestString(state.range(0));
+  for (auto _ : state) {
+    std::vector<std::string> result = absl::StrSplit(test, ';');
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK_RANGE(BM_Split2String, 0, 1 << 20);
+
+// This benchmark is for comparing Split2 to Split1 (SplitStringUsing). In
+// particular, this benchmark uses SkipEmpty() to match SplitStringUsing's
+// behavior.
+void BM_Split2SplitStringUsing(benchmark::State& state) {
+  std::string test = MakeTestString(state.range(0));
+  for (auto _ : state) {
+    std::vector<std::string> result = absl::StrSplit(test, ';', absl::SkipEmpty());
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK_RANGE(BM_Split2SplitStringUsing, 0, 1 << 20);
+
+void BM_SplitStringToUnorderedSet(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string test(len, 'x');
+  for (int i = 1; i < len; i += 2) {
+    test[i] = ';';
+  }
+  for (auto _ : state) {
+    std::unordered_set<std::string> result =
+        absl::StrSplit(test, ':', absl::SkipEmpty());
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK_RANGE(BM_SplitStringToUnorderedSet, 0, 1 << 20);
+
+void BM_SplitStringToUnorderedMap(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string test(len, 'x');
+  for (int i = 1; i < len; i += 2) {
+    test[i] = ';';
+  }
+  for (auto _ : state) {
+    std::unordered_map<std::string, std::string> result =
+        absl::StrSplit(test, ':', absl::SkipEmpty());
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK_RANGE(BM_SplitStringToUnorderedMap, 0, 1 << 20);
+
+void BM_SplitStringAllowEmpty(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string test(len, 'x');
+  for (int i = 1; i < len; i += 2) {
+    test[i] = ';';
+  }
+  for (auto _ : state) {
+    std::vector<std::string> result = absl::StrSplit(test, ';');
+    benchmark::DoNotOptimize(result);
+  }
+}
+BENCHMARK_RANGE(BM_SplitStringAllowEmpty, 0, 1 << 20);
+
+struct OneCharLiteral {
+  char operator()() const { return 'X'; }
+};
+
+struct OneCharStringLiteral {
+  const char* operator()() const { return "X"; }
+};
+
+template <typename DelimiterFactory>
+void BM_SplitStringWithOneChar(benchmark::State& state) {
+  const auto delimiter = DelimiterFactory()();
+  std::vector<absl::string_view> pieces;
+  size_t v = 0;
+  for (auto _ : state) {
+    pieces = absl::StrSplit("The quick brown fox jumps over the lazy dog",
+                            delimiter);
+    v += pieces.size();
+  }
+  ABSL_RAW_CHECK(v == state.iterations(), "");
+}
+BENCHMARK_TEMPLATE(BM_SplitStringWithOneChar, OneCharLiteral);
+BENCHMARK_TEMPLATE(BM_SplitStringWithOneChar, OneCharStringLiteral);
+
+template <typename DelimiterFactory>
+void BM_SplitStringWithOneCharNoVector(benchmark::State& state) {
+  const auto delimiter = DelimiterFactory()();
+  size_t v = 0;
+  for (auto _ : state) {
+    auto splitter = absl::StrSplit(
+        "The quick brown fox jumps over the lazy dog", delimiter);
+    v += std::distance(splitter.begin(), splitter.end());
+  }
+  ABSL_RAW_CHECK(v == state.iterations(), "");
+}
+BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharLiteral);
+BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharStringLiteral);
+
+}  // namespace
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
new file mode 100644
index 0000000..29a6804
--- /dev/null
+++ b/absl/strings/str_split_test.cc
@@ -0,0 +1,935 @@
+// Copyright 2017 The Abseil 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 "absl/strings/str_split.h"
+
+#include <deque>
+#include <initializer_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/dynamic_annotations.h"  // for AbslRunningOnValgrind
+#include "absl/base/macros.h"
+#include "absl/strings/numbers.h"
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+TEST(Split, TraitsTest) {
+  static_assert(!absl::strings_internal::SplitterIsConvertibleTo<int>::value,
+                "");
+  static_assert(!absl::strings_internal::SplitterIsConvertibleTo<std::string>::value,
+                "");
+  static_assert(absl::strings_internal::SplitterIsConvertibleTo<
+                    std::vector<std::string>>::value,
+                "");
+  static_assert(
+      !absl::strings_internal::SplitterIsConvertibleTo<std::vector<int>>::value,
+      "");
+  static_assert(absl::strings_internal::SplitterIsConvertibleTo<
+                    std::vector<absl::string_view>>::value,
+                "");
+  static_assert(absl::strings_internal::SplitterIsConvertibleTo<
+                    std::map<std::string, std::string>>::value,
+                "");
+  static_assert(absl::strings_internal::SplitterIsConvertibleTo<
+                    std::map<absl::string_view, absl::string_view>>::value,
+                "");
+  static_assert(!absl::strings_internal::SplitterIsConvertibleTo<
+                    std::map<int, std::string>>::value,
+                "");
+  static_assert(!absl::strings_internal::SplitterIsConvertibleTo<
+                    std::map<std::string, int>>::value,
+                "");
+}
+
+// This tests the overall split API, which is made up of the absl::StrSplit()
+// function and the Delimiter objects in the absl:: namespace.
+// This TEST macro is outside of any namespace to require full specification of
+// namespaces just like callers will need to use.
+TEST(Split, APIExamples) {
+  {
+    // Passes std::string delimiter. Assumes the default of Literal.
+    std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+    // Equivalent to...
+    using absl::ByString;
+    v = absl::StrSplit("a,b,c", ByString(","));
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+    // Equivalent to...
+    EXPECT_THAT(absl::StrSplit("a,b,c", ByString(",")),
+                ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Same as above, but using a single character as the delimiter.
+    std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+    // Equivalent to...
+    using absl::ByChar;
+    v = absl::StrSplit("a,b,c", ByChar(','));
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Same as above, but using std::string
+    std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+    // Equivalent to...
+    using absl::ByChar;
+    v = absl::StrSplit("a,b,c", ByChar(','));
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Uses the Literal std::string "=>" as the delimiter.
+    const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>");
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // The substrings are returned as string_views, eliminating copying.
+    std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Leading and trailing empty substrings.
+    std::vector<std::string> v = absl::StrSplit(",a,b,c,", ',');
+    EXPECT_THAT(v, ElementsAre("", "a", "b", "c", ""));
+  }
+
+  {
+    // Splits on a delimiter that is not found.
+    std::vector<std::string> v = absl::StrSplit("abc", ',');
+    EXPECT_THAT(v, ElementsAre("abc"));
+  }
+
+  {
+    // Splits the input std::string into individual characters by using an empty
+    // std::string as the delimiter.
+    std::vector<std::string> v = absl::StrSplit("abc", "");
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Splits std::string data with embedded NUL characters, using NUL as the
+    // delimiter. A simple delimiter of "\0" doesn't work because strlen() will
+    // say that's the empty std::string when constructing the absl::string_view
+    // delimiter. Instead, a non-empty std::string containing NUL can be used as the
+    // delimiter.
+    std::string embedded_nulls("a\0b\0c", 5);
+    std::string null_delim("\0", 1);
+    std::vector<std::string> v = absl::StrSplit(embedded_nulls, null_delim);
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Stores first two split strings as the members in a std::pair.
+    std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+    EXPECT_EQ("a", p.first);
+    EXPECT_EQ("b", p.second);
+    // "c" is omitted because std::pair can hold only two elements.
+  }
+
+  {
+    // Results stored in std::set<std::string>
+    std::set<std::string> v = absl::StrSplit("a,b,c,a,b,c,a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Uses a non-const char* delimiter.
+    char a[] = ",";
+    char* d = a + 0;
+    std::vector<std::string> v = absl::StrSplit("a,b,c", d);
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Results split using either of , or ;
+    using absl::ByAnyChar;
+    std::vector<std::string> v = absl::StrSplit("a,b;c", ByAnyChar(",;"));
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Uses the SkipWhitespace predicate.
+    using absl::SkipWhitespace;
+    std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipWhitespace());
+    EXPECT_THAT(v, ElementsAre(" a ", "b"));
+  }
+
+  {
+    // Uses the ByLength delimiter.
+    using absl::ByLength;
+    std::vector<std::string> v = absl::StrSplit("abcdefg", ByLength(3));
+    EXPECT_THAT(v, ElementsAre("abc", "def", "g"));
+  }
+
+  {
+    // Different forms of initialization / conversion.
+    std::vector<std::string> v1 = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v1, ElementsAre("a", "b", "c"));
+    std::vector<std::string> v2(absl::StrSplit("a,b,c", ','));
+    EXPECT_THAT(v2, ElementsAre("a", "b", "c"));
+    auto v3 = std::vector<std::string>(absl::StrSplit("a,b,c", ','));
+    EXPECT_THAT(v3, ElementsAre("a", "b", "c"));
+    v3 = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v3, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Results stored in a std::map.
+    std::map<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
+    EXPECT_EQ(2, m.size());
+    EXPECT_EQ("3", m["a"]);
+    EXPECT_EQ("2", m["b"]);
+  }
+
+  {
+    // Results stored in a std::multimap.
+    std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
+    EXPECT_EQ(3, m.size());
+    auto it = m.find("a");
+    EXPECT_EQ("1", it->second);
+    ++it;
+    EXPECT_EQ("3", it->second);
+    it = m.find("b");
+    EXPECT_EQ("2", it->second);
+  }
+
+  {
+    // Demonstrates use in a range-based for loop in C++11.
+    std::string s = "x,x,x,x,x,x,x";
+    for (absl::string_view sp : absl::StrSplit(s, ',')) {
+      EXPECT_EQ("x", sp);
+    }
+  }
+
+  {
+    // Demonstrates use with a Predicate in a range-based for loop.
+    using absl::SkipWhitespace;
+    std::string s = " ,x,,x,,x,x,x,,";
+    for (absl::string_view sp : absl::StrSplit(s, ',', SkipWhitespace())) {
+      EXPECT_EQ("x", sp);
+    }
+  }
+
+  {
+    // Demonstrates a "smart" split to std::map using two separate calls to
+    // absl::StrSplit. One call to split the records, and another call to split
+    // the keys and values. This also uses the Limit delimiter so that the
+    // std::string "a=b=c" will split to "a" -> "b=c".
+    std::map<std::string, std::string> m;
+    for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
+      m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
+    }
+    EXPECT_EQ("b=c", m.find("a")->second);
+    EXPECT_EQ("e", m.find("d")->second);
+    EXPECT_EQ("", m.find("f")->second);
+    EXPECT_EQ("", m.find("g")->second);
+  }
+}
+
+//
+// Tests for SplitIterator
+//
+
+TEST(SplitIterator, Basics) {
+  auto splitter = absl::StrSplit("a,b", ',');
+  auto it = splitter.begin();
+  auto end = splitter.end();
+
+  EXPECT_NE(it, end);
+  EXPECT_EQ("a", *it);  // tests dereference
+  ++it;                 // tests preincrement
+  EXPECT_NE(it, end);
+  EXPECT_EQ("b", std::string(it->data(), it->size()));  // tests dereference as ptr
+  it++;                                            // tests postincrement
+  EXPECT_EQ(it, end);
+}
+
+// Simple Predicate to skip a particular std::string.
+class Skip {
+ public:
+  explicit Skip(const std::string& s) : s_(s) {}
+  bool operator()(absl::string_view sp) { return sp != s_; }
+
+ private:
+  std::string s_;
+};
+
+TEST(SplitIterator, Predicate) {
+  auto splitter = absl::StrSplit("a,b,c", ',', Skip("b"));
+  auto it = splitter.begin();
+  auto end = splitter.end();
+
+  EXPECT_NE(it, end);
+  EXPECT_EQ("a", *it);  // tests dereference
+  ++it;                 // tests preincrement -- "b" should be skipped here.
+  EXPECT_NE(it, end);
+  EXPECT_EQ("c", std::string(it->data(), it->size()));  // tests dereference as ptr
+  it++;                                            // tests postincrement
+  EXPECT_EQ(it, end);
+}
+
+TEST(SplitIterator, EdgeCases) {
+  // Expected input and output, assuming a delimiter of ','
+  struct {
+    std::string in;
+    std::vector<std::string> expect;
+  } specs[] = {
+      {"", {""}},
+      {"foo", {"foo"}},
+      {",", {"", ""}},
+      {",foo", {"", "foo"}},
+      {"foo,", {"foo", ""}},
+      {",foo,", {"", "foo", ""}},
+      {"foo,bar", {"foo", "bar"}},
+  };
+
+  for (const auto& spec : specs) {
+    SCOPED_TRACE(spec.in);
+    auto splitter = absl::StrSplit(spec.in, ',');
+    auto it = splitter.begin();
+    auto end = splitter.end();
+    for (const auto& expected : spec.expect) {
+      EXPECT_NE(it, end);
+      EXPECT_EQ(expected, *it++);
+    }
+    EXPECT_EQ(it, end);
+  }
+}
+
+TEST(Splitter, Const) {
+  const auto splitter = absl::StrSplit("a,b,c", ',');
+  EXPECT_THAT(splitter, ElementsAre("a", "b", "c"));
+}
+
+TEST(Split, EmptyAndNull) {
+  // Attention: Splitting a null absl::string_view is different than splitting
+  // an empty absl::string_view even though both string_views are considered
+  // equal. This behavior is likely surprising and undesirable. However, to
+  // maintain backward compatibility, there is a small "hack" in
+  // str_split_internal.h that preserves this behavior. If that behavior is ever
+  // changed/fixed, this test will need to be updated.
+  EXPECT_THAT(absl::StrSplit(absl::string_view(""), '-'), ElementsAre(""));
+  EXPECT_THAT(absl::StrSplit(absl::string_view(), '-'), ElementsAre());
+}
+
+TEST(SplitIterator, EqualityAsEndCondition) {
+  auto splitter = absl::StrSplit("a,b,c", ',');
+  auto it = splitter.begin();
+  auto it2 = it;
+
+  // Increments it2 twice to point to "c" in the input text.
+  ++it2;
+  ++it2;
+  EXPECT_EQ("c", *it2);
+
+  // This test uses a non-end SplitIterator as the terminating condition in a
+  // for loop. This relies on SplitIterator equality for non-end SplitIterators
+  // working correctly. At this point it2 points to "c", and we use that as the
+  // "end" condition in this test.
+  std::vector<absl::string_view> v;
+  for (; it != it2; ++it) {
+    v.push_back(*it);
+  }
+  EXPECT_THAT(v, ElementsAre("a", "b"));
+}
+
+//
+// Tests for Splitter
+//
+
+TEST(Splitter, RangeIterators) {
+  auto splitter = absl::StrSplit("a,b,c", ',');
+  std::vector<absl::string_view> output;
+  for (const absl::string_view p : splitter) {
+    output.push_back(p);
+  }
+  EXPECT_THAT(output, ElementsAre("a", "b", "c"));
+}
+
+// Some template functions for use in testing conversion operators
+template <typename ContainerType, typename Splitter>
+void TestConversionOperator(const Splitter& splitter) {
+  ContainerType output = splitter;
+  EXPECT_THAT(output, UnorderedElementsAre("a", "b", "c", "d"));
+}
+
+template <typename MapType, typename Splitter>
+void TestMapConversionOperator(const Splitter& splitter) {
+  MapType m = splitter;
+  EXPECT_THAT(m, UnorderedElementsAre(Pair("a", "b"), Pair("c", "d")));
+}
+
+template <typename FirstType, typename SecondType, typename Splitter>
+void TestPairConversionOperator(const Splitter& splitter) {
+  std::pair<FirstType, SecondType> p = splitter;
+  EXPECT_EQ(p, (std::pair<FirstType, SecondType>("a", "b")));
+}
+
+TEST(Splitter, ConversionOperator) {
+  auto splitter = absl::StrSplit("a,b,c,d", ',');
+
+  TestConversionOperator<std::vector<absl::string_view>>(splitter);
+  TestConversionOperator<std::vector<std::string>>(splitter);
+  TestConversionOperator<std::list<absl::string_view>>(splitter);
+  TestConversionOperator<std::list<std::string>>(splitter);
+  TestConversionOperator<std::deque<absl::string_view>>(splitter);
+  TestConversionOperator<std::deque<std::string>>(splitter);
+  TestConversionOperator<std::set<absl::string_view>>(splitter);
+  TestConversionOperator<std::set<std::string>>(splitter);
+  TestConversionOperator<std::multiset<absl::string_view>>(splitter);
+  TestConversionOperator<std::multiset<std::string>>(splitter);
+  TestConversionOperator<std::unordered_set<std::string>>(splitter);
+
+  // Tests conversion to map-like objects.
+
+  TestMapConversionOperator<std::map<absl::string_view, absl::string_view>>(
+      splitter);
+  TestMapConversionOperator<std::map<absl::string_view, std::string>>(splitter);
+  TestMapConversionOperator<std::map<std::string, absl::string_view>>(splitter);
+  TestMapConversionOperator<std::map<std::string, std::string>>(splitter);
+  TestMapConversionOperator<
+      std::multimap<absl::string_view, absl::string_view>>(splitter);
+  TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter);
+  TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter);
+  TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter);
+  TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter);
+
+  // Tests conversion to std::pair
+
+  TestPairConversionOperator<absl::string_view, absl::string_view>(splitter);
+  TestPairConversionOperator<absl::string_view, std::string>(splitter);
+  TestPairConversionOperator<std::string, absl::string_view>(splitter);
+  TestPairConversionOperator<std::string, std::string>(splitter);
+}
+
+// A few additional tests for conversion to std::pair. This conversion is
+// different from others because a std::pair always has exactly two elements:
+// .first and .second. The split has to work even when the split has
+// less-than, equal-to, and more-than 2 strings.
+TEST(Splitter, ToPair) {
+  {
+    // Empty std::string
+    std::pair<std::string, std::string> p = absl::StrSplit("", ',');
+    EXPECT_EQ("", p.first);
+    EXPECT_EQ("", p.second);
+  }
+
+  {
+    // Only first
+    std::pair<std::string, std::string> p = absl::StrSplit("a", ',');
+    EXPECT_EQ("a", p.first);
+    EXPECT_EQ("", p.second);
+  }
+
+  {
+    // Only second
+    std::pair<std::string, std::string> p = absl::StrSplit(",b", ',');
+    EXPECT_EQ("", p.first);
+    EXPECT_EQ("b", p.second);
+  }
+
+  {
+    // First and second.
+    std::pair<std::string, std::string> p = absl::StrSplit("a,b", ',');
+    EXPECT_EQ("a", p.first);
+    EXPECT_EQ("b", p.second);
+  }
+
+  {
+    // First and second and then more stuff that will be ignored.
+    std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+    EXPECT_EQ("a", p.first);
+    EXPECT_EQ("b", p.second);
+    // "c" is omitted.
+  }
+}
+
+TEST(Splitter, Predicates) {
+  static const char kTestChars[] = ",a, ,b,";
+  using absl::AllowEmpty;
+  using absl::SkipEmpty;
+  using absl::SkipWhitespace;
+
+  {
+    // No predicate. Does not skip empties.
+    auto splitter = absl::StrSplit(kTestChars, ',');
+    std::vector<std::string> v = splitter;
+    EXPECT_THAT(v, ElementsAre("", "a", " ", "b", ""));
+  }
+
+  {
+    // Allows empty strings. Same behavior as no predicate at all.
+    auto splitter = absl::StrSplit(kTestChars, ',', AllowEmpty());
+    std::vector<std::string> v_allowempty = splitter;
+    EXPECT_THAT(v_allowempty, ElementsAre("", "a", " ", "b", ""));
+
+    // Ensures AllowEmpty equals the behavior with no predicate.
+    auto splitter_nopredicate = absl::StrSplit(kTestChars, ',');
+    std::vector<std::string> v_nopredicate = splitter_nopredicate;
+    EXPECT_EQ(v_allowempty, v_nopredicate);
+  }
+
+  {
+    // Skips empty strings.
+    auto splitter = absl::StrSplit(kTestChars, ',', SkipEmpty());
+    std::vector<std::string> v = splitter;
+    EXPECT_THAT(v, ElementsAre("a", " ", "b"));
+  }
+
+  {
+    // Skips empty and all-whitespace strings.
+    auto splitter = absl::StrSplit(kTestChars, ',', SkipWhitespace());
+    std::vector<std::string> v = splitter;
+    EXPECT_THAT(v, ElementsAre("a", "b"));
+  }
+}
+
+//
+// Tests for StrSplit()
+//
+
+TEST(Split, Basics) {
+  {
+    // Doesn't really do anything useful because the return value is ignored,
+    // but it should work.
+    absl::StrSplit("a,b,c", ',');
+  }
+
+  {
+    std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+  }
+
+  {
+    // Ensures that assignment works. This requires a little extra work with
+    // C++11 because of overloads with initializer_list.
+    std::vector<std::string> v;
+    v = absl::StrSplit("a,b,c", ',');
+
+    EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+    std::map<std::string, std::string> m;
+    m = absl::StrSplit("a,b,c", ',');
+    EXPECT_EQ(2, m.size());
+    std::unordered_map<std::string, std::string> hm;
+    hm = absl::StrSplit("a,b,c", ',');
+    EXPECT_EQ(2, hm.size());
+  }
+}
+
+absl::string_view ReturnStringView() { return "Hello World"; }
+const char* ReturnConstCharP() { return "Hello World"; }
+char* ReturnCharP() { return const_cast<char*>("Hello World"); }
+
+TEST(Split, AcceptsCertainTemporaries) {
+  std::vector<std::string> v;
+  v = absl::StrSplit(ReturnStringView(), ' ');
+  EXPECT_THAT(v, ElementsAre("Hello", "World"));
+  v = absl::StrSplit(ReturnConstCharP(), ' ');
+  EXPECT_THAT(v, ElementsAre("Hello", "World"));
+  v = absl::StrSplit(ReturnCharP(), ' ');
+  EXPECT_THAT(v, ElementsAre("Hello", "World"));
+}
+
+TEST(Split, Temporary) {
+  // Use a std::string longer than the small-std::string-optimization length, so that when
+  // the temporary is destroyed, if the splitter keeps a reference to the
+  // std::string's contents, it'll reference freed memory instead of just dead
+  // on-stack memory.
+  const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u";
+  EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input))
+      << "Input should be larger than fits on the stack.";
+
+  // This happens more often in C++11 as part of a range-based for loop.
+  auto splitter = absl::StrSplit(std::string(input), ',');
+  std::string expected = "a";
+  for (absl::string_view letter : splitter) {
+    EXPECT_EQ(expected, letter);
+    ++expected[0];
+  }
+  EXPECT_EQ("v", expected);
+
+  // This happens more often in C++11 as part of a range-based for loop.
+  auto std_splitter = absl::StrSplit(std::string(input), ',');
+  expected = "a";
+  for (absl::string_view letter : std_splitter) {
+    EXPECT_EQ(expected, letter);
+    ++expected[0];
+  }
+  EXPECT_EQ("v", expected);
+}
+
+template <typename T>
+static std::unique_ptr<T> CopyToHeap(const T& value) {
+  return std::unique_ptr<T>(new T(value));
+}
+
+TEST(Split, LvalueCaptureIsCopyable) {
+  std::string input = "a,b";
+  auto heap_splitter = CopyToHeap(absl::StrSplit(input, ','));
+  auto stack_splitter = *heap_splitter;
+  heap_splitter.reset();
+  std::vector<std::string> result = stack_splitter;
+  EXPECT_THAT(result, testing::ElementsAre("a", "b"));
+}
+
+TEST(Split, TemporaryCaptureIsCopyable) {
+  auto heap_splitter = CopyToHeap(absl::StrSplit(std::string("a,b"), ','));
+  auto stack_splitter = *heap_splitter;
+  heap_splitter.reset();
+  std::vector<std::string> result = stack_splitter;
+  EXPECT_THAT(result, testing::ElementsAre("a", "b"));
+}
+
+TEST(Split, SplitterIsCopyableAndMoveable) {
+  auto a = absl::StrSplit("foo", '-');
+
+  // Ensures that the following expressions compile.
+  auto b = a;             // Copy construct
+  auto c = std::move(a);  // Move construct
+  b = c;                  // Copy assign
+  c = std::move(b);       // Move assign
+
+  EXPECT_THAT(c, ElementsAre("foo"));
+}
+
+TEST(Split, StringDelimiter) {
+  {
+    std::vector<absl::string_view> v = absl::StrSplit("a,b", ',');
+    EXPECT_THAT(v, ElementsAre("a", "b"));
+  }
+
+  {
+    std::vector<absl::string_view> v = absl::StrSplit("a,b", std::string(","));
+    EXPECT_THAT(v, ElementsAre("a", "b"));
+  }
+
+  {
+    std::vector<absl::string_view> v =
+        absl::StrSplit("a,b", absl::string_view(","));
+    EXPECT_THAT(v, ElementsAre("a", "b"));
+  }
+}
+
+TEST(Split, UTF8) {
+  // Tests splitting utf8 strings and utf8 delimiters.
+  std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
+  {
+    // A utf8 input std::string with an ascii delimiter.
+    std::string to_split = "a," + utf8_string;
+    std::vector<absl::string_view> v = absl::StrSplit(to_split, ',');
+    EXPECT_THAT(v, ElementsAre("a", utf8_string));
+  }
+
+  {
+    // A utf8 input std::string and a utf8 delimiter.
+    std::string to_split = "a," + utf8_string + ",b";
+    std::string unicode_delimiter = "," + utf8_string + ",";
+    std::vector<absl::string_view> v =
+        absl::StrSplit(to_split, unicode_delimiter);
+    EXPECT_THAT(v, ElementsAre("a", "b"));
+  }
+
+  {
+    // A utf8 input std::string and ByAnyChar with ascii chars.
+    std::vector<absl::string_view> v =
+        absl::StrSplit(u8"Foo h\u00E4llo th\u4E1Ere", absl::ByAnyChar(" \t"));
+    EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
+  }
+}
+
+TEST(Split, EmptyStringDelimiter) {
+  {
+    std::vector<std::string> v = absl::StrSplit("", "");
+    EXPECT_THAT(v, ElementsAre(""));
+  }
+
+  {
+    std::vector<std::string> v = absl::StrSplit("a", "");
+    EXPECT_THAT(v, ElementsAre("a"));
+  }
+
+  {
+    std::vector<std::string> v = absl::StrSplit("ab", "");
+    EXPECT_THAT(v, ElementsAre("a", "b"));
+  }
+
+  {
+    std::vector<std::string> v = absl::StrSplit("a b", "");
+    EXPECT_THAT(v, ElementsAre("a", " ", "b"));
+  }
+}
+
+TEST(Split, SubstrDelimiter) {
+  std::vector<absl::string_view> results;
+  absl::string_view delim("//");
+
+  results = absl::StrSplit("", delim);
+  EXPECT_THAT(results, ElementsAre(""));
+
+  results = absl::StrSplit("//", delim);
+  EXPECT_THAT(results, ElementsAre("", ""));
+
+  results = absl::StrSplit("ab", delim);
+  EXPECT_THAT(results, ElementsAre("ab"));
+
+  results = absl::StrSplit("ab//", delim);
+  EXPECT_THAT(results, ElementsAre("ab", ""));
+
+  results = absl::StrSplit("ab/", delim);
+  EXPECT_THAT(results, ElementsAre("ab/"));
+
+  results = absl::StrSplit("a/b", delim);
+  EXPECT_THAT(results, ElementsAre("a/b"));
+
+  results = absl::StrSplit("a//b", delim);
+  EXPECT_THAT(results, ElementsAre("a", "b"));
+
+  results = absl::StrSplit("a///b", delim);
+  EXPECT_THAT(results, ElementsAre("a", "/b"));
+
+  results = absl::StrSplit("a////b", delim);
+  EXPECT_THAT(results, ElementsAre("a", "", "b"));
+}
+
+TEST(Split, EmptyResults) {
+  std::vector<absl::string_view> results;
+
+  results = absl::StrSplit("", '#');
+  EXPECT_THAT(results, ElementsAre(""));
+
+  results = absl::StrSplit("#", '#');
+  EXPECT_THAT(results, ElementsAre("", ""));
+
+  results = absl::StrSplit("#cd", '#');
+  EXPECT_THAT(results, ElementsAre("", "cd"));
+
+  results = absl::StrSplit("ab#cd#", '#');
+  EXPECT_THAT(results, ElementsAre("ab", "cd", ""));
+
+  results = absl::StrSplit("ab##cd", '#');
+  EXPECT_THAT(results, ElementsAre("ab", "", "cd"));
+
+  results = absl::StrSplit("ab##", '#');
+  EXPECT_THAT(results, ElementsAre("ab", "", ""));
+
+  results = absl::StrSplit("ab#ab#", '#');
+  EXPECT_THAT(results, ElementsAre("ab", "ab", ""));
+
+  results = absl::StrSplit("aaaa", 'a');
+  EXPECT_THAT(results, ElementsAre("", "", "", "", ""));
+
+  results = absl::StrSplit("", '#', absl::SkipEmpty());
+  EXPECT_THAT(results, ElementsAre());
+}
+
+template <typename Delimiter>
+static bool IsFoundAtStartingPos(absl::string_view text, Delimiter d,
+                                 size_t starting_pos, int expected_pos) {
+  absl::string_view found = d.Find(text, starting_pos);
+  return found.data() != text.end() &&
+         expected_pos == found.data() - text.data();
+}
+
+// Helper function for testing Delimiter objects. Returns true if the given
+// Delimiter is found in the given std::string at the given position. This function
+// tests two cases:
+//   1. The actual text given, staring at position 0
+//   2. The text given with leading padding that should be ignored
+template <typename Delimiter>
+static bool IsFoundAt(absl::string_view text, Delimiter d, int expected_pos) {
+  const std::string leading_text = ",x,y,z,";
+  return IsFoundAtStartingPos(text, d, 0, expected_pos) &&
+         IsFoundAtStartingPos(leading_text + std::string(text), d,
+                              leading_text.length(),
+                              expected_pos + leading_text.length());
+}
+
+//
+// Tests for Literal
+//
+
+// Tests using any delimiter that represents a single comma.
+template <typename Delimiter>
+void TestComma(Delimiter d) {
+  EXPECT_TRUE(IsFoundAt(",", d, 0));
+  EXPECT_TRUE(IsFoundAt("a,", d, 1));
+  EXPECT_TRUE(IsFoundAt(",b", d, 0));
+  EXPECT_TRUE(IsFoundAt("a,b", d, 1));
+  EXPECT_TRUE(IsFoundAt("a,b,", d, 1));
+  EXPECT_TRUE(IsFoundAt("a,b,c", d, 1));
+  EXPECT_FALSE(IsFoundAt("", d, -1));
+  EXPECT_FALSE(IsFoundAt(" ", d, -1));
+  EXPECT_FALSE(IsFoundAt("a", d, -1));
+  EXPECT_FALSE(IsFoundAt("a b c", d, -1));
+  EXPECT_FALSE(IsFoundAt("a;b;c", d, -1));
+  EXPECT_FALSE(IsFoundAt(";", d, -1));
+}
+
+TEST(Delimiter, Literal) {
+  using absl::ByString;
+  TestComma(ByString(","));
+
+  // Works as named variable.
+  ByString comma_string(",");
+  TestComma(comma_string);
+
+  // The first occurrence of empty std::string ("") in a std::string is at position 0.
+  // There is a test below that demonstrates this for absl::string_view::find().
+  // If the ByString delimiter returned position 0 for this, there would
+  // be an infinite loop in the SplitIterator code. To avoid this, empty std::string
+  // is a special case in that it always returns the item at position 1.
+  absl::string_view abc("abc");
+  EXPECT_EQ(0, abc.find(""));  // "" is found at position 0
+  ByString empty("");
+  EXPECT_FALSE(IsFoundAt("", empty, 0));
+  EXPECT_FALSE(IsFoundAt("a", empty, 0));
+  EXPECT_TRUE(IsFoundAt("ab", empty, 1));
+  EXPECT_TRUE(IsFoundAt("abc", empty, 1));
+}
+
+TEST(Split, ByChar) {
+  using absl::ByChar;
+  TestComma(ByChar(','));
+
+  // Works as named variable.
+  ByChar comma_char(',');
+  TestComma(comma_char);
+}
+
+//
+// Tests for ByAnyChar
+//
+
+TEST(Delimiter, ByAnyChar) {
+  using absl::ByAnyChar;
+  ByAnyChar one_delim(",");
+  // Found
+  EXPECT_TRUE(IsFoundAt(",", one_delim, 0));
+  EXPECT_TRUE(IsFoundAt("a,", one_delim, 1));
+  EXPECT_TRUE(IsFoundAt("a,b", one_delim, 1));
+  EXPECT_TRUE(IsFoundAt(",b", one_delim, 0));
+  // Not found
+  EXPECT_FALSE(IsFoundAt("", one_delim, -1));
+  EXPECT_FALSE(IsFoundAt(" ", one_delim, -1));
+  EXPECT_FALSE(IsFoundAt("a", one_delim, -1));
+  EXPECT_FALSE(IsFoundAt("a;b;c", one_delim, -1));
+  EXPECT_FALSE(IsFoundAt(";", one_delim, -1));
+
+  ByAnyChar two_delims(",;");
+  // Found
+  EXPECT_TRUE(IsFoundAt(",", two_delims, 0));
+  EXPECT_TRUE(IsFoundAt(";", two_delims, 0));
+  EXPECT_TRUE(IsFoundAt(",;", two_delims, 0));
+  EXPECT_TRUE(IsFoundAt(";,", two_delims, 0));
+  EXPECT_TRUE(IsFoundAt(",;b", two_delims, 0));
+  EXPECT_TRUE(IsFoundAt(";,b", two_delims, 0));
+  EXPECT_TRUE(IsFoundAt("a;,", two_delims, 1));
+  EXPECT_TRUE(IsFoundAt("a,;", two_delims, 1));
+  EXPECT_TRUE(IsFoundAt("a;,b", two_delims, 1));
+  EXPECT_TRUE(IsFoundAt("a,;b", two_delims, 1));
+  // Not found
+  EXPECT_FALSE(IsFoundAt("", two_delims, -1));
+  EXPECT_FALSE(IsFoundAt(" ", two_delims, -1));
+  EXPECT_FALSE(IsFoundAt("a", two_delims, -1));
+  EXPECT_FALSE(IsFoundAt("a=b=c", two_delims, -1));
+  EXPECT_FALSE(IsFoundAt("=", two_delims, -1));
+
+  // ByAnyChar behaves just like ByString when given a delimiter of empty
+  // std::string. That is, it always returns a zero-length absl::string_view
+  // referring to the item at position 1, not position 0.
+  ByAnyChar empty("");
+  EXPECT_FALSE(IsFoundAt("", empty, 0));
+  EXPECT_FALSE(IsFoundAt("a", empty, 0));
+  EXPECT_TRUE(IsFoundAt("ab", empty, 1));
+  EXPECT_TRUE(IsFoundAt("abc", empty, 1));
+}
+
+//
+// Tests for ByLength
+//
+
+TEST(Delimiter, ByLength) {
+  using absl::ByLength;
+
+  ByLength four_char_delim(4);
+
+  // Found
+  EXPECT_TRUE(IsFoundAt("abcde", four_char_delim, 4));
+  EXPECT_TRUE(IsFoundAt("abcdefghijklmnopqrstuvwxyz", four_char_delim, 4));
+  EXPECT_TRUE(IsFoundAt("a b,c\nd", four_char_delim, 4));
+  // Not found
+  EXPECT_FALSE(IsFoundAt("", four_char_delim, 0));
+  EXPECT_FALSE(IsFoundAt("a", four_char_delim, 0));
+  EXPECT_FALSE(IsFoundAt("ab", four_char_delim, 0));
+  EXPECT_FALSE(IsFoundAt("abc", four_char_delim, 0));
+  EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0));
+}
+
+TEST(Split, WorksWithLargeStrings) {
+  if (sizeof(size_t) > 4) {
+    std::string s((uint32_t{1} << 31) + 1, 'x');  // 2G + 1 byte
+    s.back() = '-';
+    std::vector<absl::string_view> v = absl::StrSplit(s, '-');
+    EXPECT_EQ(2, v.size());
+    // The first element will contain 2G of 'x's.
+    // testing::StartsWith is too slow with a 2G std::string.
+    EXPECT_EQ('x', v[0][0]);
+    EXPECT_EQ('x', v[0][1]);
+    EXPECT_EQ('x', v[0][3]);
+    EXPECT_EQ("", v[1]);
+  }
+}
+
+TEST(SplitInternalTest, TypeTraits) {
+  EXPECT_FALSE(absl::strings_internal::HasMappedType<int>::value);
+  EXPECT_TRUE(
+      (absl::strings_internal::HasMappedType<std::map<int, int>>::value));
+  EXPECT_FALSE(absl::strings_internal::HasValueType<int>::value);
+  EXPECT_TRUE(
+      (absl::strings_internal::HasValueType<std::map<int, int>>::value));
+  EXPECT_FALSE(absl::strings_internal::HasConstIterator<int>::value);
+  EXPECT_TRUE(
+      (absl::strings_internal::HasConstIterator<std::map<int, int>>::value));
+  EXPECT_FALSE(absl::strings_internal::IsInitializerList<int>::value);
+  EXPECT_TRUE((absl::strings_internal::IsInitializerList<
+               std::initializer_list<int>>::value));
+}
+
+}  // namespace
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc
new file mode 100644
index 0000000..4ceeb6b
--- /dev/null
+++ b/absl/strings/string_view.cc
@@ -0,0 +1,245 @@
+// Copyright 2017 The Abseil 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 "absl/strings/string_view.h"
+
+#ifndef ABSL_HAVE_STD_STRING_VIEW
+
+#include <algorithm>
+#include <climits>
+#include <cstring>
+#include <ostream>
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+
+namespace {
+void WritePadding(std::ostream& o, size_t pad) {
+  char fill_buf[32];
+  memset(fill_buf, o.fill(), sizeof(fill_buf));
+  while (pad) {
+    size_t n = std::min(pad, sizeof(fill_buf));
+    o.write(fill_buf, n);
+    pad -= n;
+  }
+}
+
+class LookupTable {
+ public:
+  // For each character in wanted, sets the index corresponding
+  // to the ASCII code of that character. This is used by
+  // the find_.*_of methods below to tell whether or not a character is in
+  // the lookup table in constant time.
+  explicit LookupTable(string_view wanted) {
+    for (char c : wanted) {
+      table_[Index(c)] = true;
+    }
+  }
+  bool operator[](char c) const { return table_[Index(c)]; }
+
+ private:
+  static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
+  bool table_[UCHAR_MAX + 1] = {};
+};
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& o, string_view piece) {
+  std::ostream::sentry sentry(o);
+  if (sentry) {
+    size_t lpad = 0;
+    size_t rpad = 0;
+    if (static_cast<size_t>(o.width()) > piece.size()) {
+      size_t pad = o.width() - piece.size();
+      if ((o.flags() & o.adjustfield) == o.left) {
+        rpad = pad;
+      } else {
+        lpad = pad;
+      }
+    }
+    if (lpad) WritePadding(o, lpad);
+    o.write(piece.data(), piece.size());
+    if (rpad) WritePadding(o, rpad);
+    o.width(0);
+  }
+  return o;
+}
+
+string_view::size_type string_view::copy(char* buf, size_type n,
+                                         size_type pos) const {
+  size_type ulen = length_;
+  assert(pos <= ulen);
+  size_type rlen = std::min(ulen - pos, n);
+  if (rlen > 0) {
+    const char* start = ptr_ + pos;
+    std::copy(start, start + rlen, buf);
+  }
+  return rlen;
+}
+
+string_view::size_type string_view::find(string_view s, size_type pos) const
+    noexcept {
+  if (empty() || pos > length_) {
+    if (empty() && pos == 0 && s.empty()) return 0;
+    return npos;
+  }
+  const char* result =
+      strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
+  return result ? result - ptr_ : npos;
+}
+
+string_view::size_type string_view::find(char c, size_type pos) const noexcept {
+  if (empty() || pos >= length_) {
+    return npos;
+  }
+  const char* result =
+      static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
+  return result != nullptr ? result - ptr_ : npos;
+}
+
+string_view::size_type string_view::rfind(string_view s, size_type pos) const
+    noexcept {
+  if (length_ < s.length_) return npos;
+  if (s.empty()) return std::min(length_, pos);
+  const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
+  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
+  return result != last ? result - ptr_ : npos;
+}
+
+// Search range is [0..pos] inclusive.  If pos == npos, search everything.
+string_view::size_type string_view::rfind(char c, size_type pos) const
+    noexcept {
+  // Note: memrchr() is not available on Windows.
+  if (empty()) return npos;
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (ptr_[i] == c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_first_of(string_view s,
+                                                  size_type pos) const
+    noexcept {
+  if (empty() || s.empty()) {
+    return npos;
+  }
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (size_type i = pos; i < length_; ++i) {
+    if (tbl[ptr_[i]]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(string_view s,
+                                                      size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (size_type i = pos; i < length_; ++i) {
+    if (!tbl[ptr_[i]]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(char c,
+                                                      size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  for (; pos < length_; ++pos) {
+    if (ptr_[pos] != c) {
+      return pos;
+    }
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_last_of(string_view s,
+                                                 size_type pos) const noexcept {
+  if (empty() || s.empty()) return npos;
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (tbl[ptr_[i]]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(string_view s,
+                                                     size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  size_type i = std::min(pos, length_ - 1);
+  if (s.empty()) return i;
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (;; --i) {
+    if (!tbl[ptr_[i]]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(char c,
+                                                     size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  size_type i = std::min(pos, length_ - 1);
+  for (;; --i) {
+    if (ptr_[i] != c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+// MSVC has non-standard behavior that implicitly creates definitions for static
+// const members. These implicit definitions conflict with explicit out-of-class
+// member definitions that are required by the C++ standard, resulting in
+// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks
+// MSVC to choose only one definition for the symbol it decorates. See details
+// at http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
+#ifdef _MSC_VER
+#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany)
+#else
+#define ABSL_STRING_VIEW_SELECTANY
+#endif
+
+ABSL_STRING_VIEW_SELECTANY
+constexpr string_view::size_type string_view::npos;
+ABSL_STRING_VIEW_SELECTANY
+constexpr string_view::size_type string_view::kMaxSize;
+
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_STRING_VIEW
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
new file mode 100644
index 0000000..a7f9199
--- /dev/null
+++ b/absl/strings/string_view.h
@@ -0,0 +1,570 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: string_view.h
+// -----------------------------------------------------------------------------
+//
+// This file contains the definition of the `absl::string_view` class. A
+// `string_view` points to a contiguous span of characters, often part or all of
+// another `std::string`, double-quoted std::string literal, character array, or even
+// another `string_view`.
+//
+// This `absl::string_view` abstraction is designed to be a drop-in
+// replacement for the C++17 `std::string_view` abstraction.
+#ifndef ABSL_STRINGS_STRING_VIEW_H_
+#define ABSL_STRINGS_STRING_VIEW_H_
+
+#include <algorithm>
+#include "absl/base/config.h"
+
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+
+#include <string_view>
+
+namespace absl {
+using std::string_view;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_STRING_VIEW
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+#include <limits>
+#include <string>
+
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+// absl::string_view
+//
+// A `string_view` provides a lightweight view into the std::string data provided by
+// a `std::string`, double-quoted std::string literal, character array, or even
+// another `string_view`. A `string_view` does *not* own the std::string to which it
+// points, and that data cannot be modified through the view.
+//
+// You can use `string_view` as a function or method parameter anywhere a
+// parameter can receive a double-quoted std::string literal, `const char*`,
+// `std::string`, or another `absl::string_view` argument with no need to copy
+// the std::string data. Systematic use of `string_view` within function arguments
+// reduces data copies and `strlen()` calls.
+//
+// Because of its small size, prefer passing `string_view` by value:
+//
+//   void MyFunction(absl::string_view arg);
+//
+// If circumstances require, you may also pass one by const reference:
+//
+//   void MyFunction(const absl::string_view& arg);  // not preferred
+//
+// Passing by value generates slightly smaller code for many architectures.
+//
+// In either case, the source data of the `string_view` must outlive the
+// `string_view` itself.
+//
+// A `string_view` is also suitable for local variables if you know that the
+// lifetime of the underlying object is longer than the lifetime of your
+// `string_view` variable. However, beware of binding a `string_view` to a
+// temporary value:
+//
+//   // BAD use of string_view: lifetime problem
+//   absl::string_view sv = obj.ReturnAString();
+//
+//   // GOOD use of string_view: str outlives sv
+//   std::string str = obj.ReturnAString();
+//   absl::string_view sv = str;
+//
+// Due to lifetime issues, a `string_view` is sometimes a poor choice for a
+// return value and usually a poor choice for a data member. If you do use a
+// `string_view` this way, it is your responsibility to ensure that the object
+// pointed to by the `string_view` outlives the `string_view`.
+//
+// A `string_view` may represent a whole std::string or just part of a std::string. For
+// example, when splitting a std::string, `std::vector<absl::string_view>` is a
+// natural data type for the output.
+//
+//
+// When constructed from a source which is nul-terminated, the `string_view`
+// itself will not include the nul-terminator unless a specific size (including
+// the nul) is passed to the constructor. As a result, common idioms that work
+// on nul-terminated strings do not work on `string_view` objects. If you write
+// code that scans a `string_view`, you must check its length rather than test
+// for nul, for example. Note, however, that nuls may still be embedded within
+// a `string_view` explicitly.
+//
+// You may create a null `string_view` in two ways:
+//
+//   absl::string_view sv();
+//   absl::string_view sv(nullptr, 0);
+//
+// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and
+// `sv.empty() == true`. Also, if you create a `string_view` with a non-null
+// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to
+// signal an undefined value that is different from other `string_view` values
+// in a similar fashion to how `const char* p1 = nullptr;` is different from
+// `const char* p2 = "";`. However, in practice, it is not recommended to rely
+// on this behavior.
+//
+// Be careful not to confuse a null `string_view` with an empty one. A null
+// `string_view` is an empty `string_view`, but some empty `string_view`s are
+// not null. Prefer checking for emptiness over checking for null.
+//
+// There are many ways to create an empty string_view:
+//
+//   const char* nullcp = nullptr;
+//   // string_view.size() will return 0 in all cases.
+//   absl::string_view();
+//   absl::string_view(nullcp, 0);
+//   absl::string_view("");
+//   absl::string_view("", 0);
+//   absl::string_view("abcdef", 0);
+//   absl::string_view("abcdef" + 6, 0);
+//
+// All empty `string_view` objects whether null or not, are equal:
+//
+//   absl::string_view() == absl::string_view("", 0)
+//   absl::string_view(nullptr, 0) == absl:: string_view("abcdef"+6, 0)
+class string_view {
+ public:
+  using traits_type = std::char_traits<char>;
+  using value_type = char;
+  using pointer = char*;
+  using const_pointer = const char*;
+  using reference = char&;
+  using const_reference = const char&;
+  using const_iterator = const char*;
+  using iterator = const_iterator;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using reverse_iterator = const_reverse_iterator;
+  using size_type = size_t;
+  using difference_type = std::ptrdiff_t;
+
+  static constexpr size_type npos = static_cast<size_type>(-1);
+
+  // Null `string_view` constructor
+  constexpr string_view() noexcept : ptr_(nullptr), length_(0) {}
+
+  // Implicit constructors
+
+  template <typename Allocator>
+  string_view(  // NOLINT(runtime/explicit)
+      const std::basic_string<char, std::char_traits<char>, Allocator>&
+          str) noexcept
+      : ptr_(str.data()), length_(CheckLengthInternal(str.size())) {}
+
+  // Implicit constructor of a `string_view` from nul-terminated `str`. When
+  // accepting possibly null strings, use `absl::NullSafeStringView(str)`
+  // instead (see below).
+  constexpr string_view(const char* str)  // NOLINT(runtime/explicit)
+      : ptr_(str), length_(CheckLengthInternal(StrLenInternal(str))) {}
+
+  // Implicit constructor of a `string_view` from a `const char*` and length.
+  constexpr string_view(const char* data, size_type len)
+      : ptr_(data), length_(CheckLengthInternal(len)) {}
+
+  // NOTE: Harmlessly omitted to work around gdb bug.
+  //   constexpr string_view(const string_view&) noexcept = default;
+  //   string_view& operator=(const string_view&) noexcept = default;
+
+  // Iterators
+
+  // string_view::begin()
+  //
+  // Returns an iterator pointing to the first character at the beginning of the
+  // `string_view`, or `end()` if the `string_view` is empty.
+  constexpr const_iterator begin() const noexcept { return ptr_; }
+
+  // string_view::end()
+  //
+  // Returns an iterator pointing just beyond the last character at the end of
+  // the `string_view`. This iterator acts as a placeholder; attempting to
+  // access it results in undefined behavior.
+  constexpr const_iterator end() const noexcept { return ptr_ + length_; }
+
+  // string_view::cbegin()
+  //
+  // Returns a const iterator pointing to the first character at the beginning
+  // of the `string_view`, or `end()` if the `string_view` is empty.
+  constexpr const_iterator cbegin() const noexcept { return begin(); }
+
+  // string_view::cend()
+  //
+  // Returns a const iterator pointing just beyond the last character at the end
+  // of the `string_view`. This pointer acts as a placeholder; attempting to
+  // access its element results in undefined behavior.
+  constexpr const_iterator cend() const noexcept { return end(); }
+
+  // string_view::rbegin()
+  //
+  // Returns a reverse iterator pointing to the last character at the end of the
+  // `string_view`, or `rend()` if the `string_view` is empty.
+  const_reverse_iterator rbegin() const noexcept {
+    return const_reverse_iterator(end());
+  }
+
+  // string_view::rend()
+  //
+  // Returns a reverse iterator pointing just before the first character at the
+  // beginning of the `string_view`. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
+  const_reverse_iterator rend() const noexcept {
+    return const_reverse_iterator(begin());
+  }
+
+  // string_view::crbegin()
+  //
+  // Returns a const reverse iterator pointing to the last character at the end
+  // of the `string_view`, or `crend()` if the `string_view` is empty.
+  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+  // string_view::crend()
+  //
+  // Returns a const reverse iterator pointing just before the first character
+  // at the beginning of the `string_view`. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
+  const_reverse_iterator crend() const noexcept { return rend(); }
+
+  // Capacity Utilities
+
+  // string_view::size()
+  //
+  // Returns the number of characters in the `string_view`.
+  constexpr size_type size() const noexcept {
+    return length_;
+  }
+
+  // string_view::length()
+  //
+  // Returns the number of characters in the `string_view`. Alias for `size()`.
+  constexpr size_type length() const noexcept { return size(); }
+
+  // string_view::max_size()
+  //
+  // Returns the maximum number of characters the `string_view` can hold.
+  constexpr size_type max_size() const noexcept { return kMaxSize; }
+
+  // string_view::empty()
+  //
+  // Checks if the `string_view` is empty (refers to no characters).
+  constexpr bool empty() const noexcept { return length_ == 0; }
+
+  // std::string:view::operator[]
+  //
+  // Returns the ith element of an `string_view` using the array operator.
+  // Note that this operator does not perform any bounds checking.
+  constexpr const_reference operator[](size_type i) const { return ptr_[i]; }
+
+  // string_view::front()
+  //
+  // Returns the first element of a `string_view`.
+  constexpr const_reference front() const { return ptr_[0]; }
+
+  // string_view::back()
+  //
+  // Returns the last element of a `string_view`.
+  constexpr const_reference back() const { return ptr_[size() - 1]; }
+
+  // string_view::data()
+  //
+  // Returns a pointer to the underlying character array (which is of course
+  // stored elsewhere). Note that `string_view::data()` may contain embedded nul
+  // characters, but the returned buffer may or may not be nul-terminated;
+  // therefore, do not pass `data()` to a routine that expects a nul-terminated
+  // std::string.
+  constexpr const_pointer data() const noexcept { return ptr_; }
+
+  // Modifiers
+
+  // string_view::remove_prefix()
+  //
+  // Removes the first `n` characters from the `string_view`. Note that the
+  // underlying std::string is not changed, only the view.
+  void remove_prefix(size_type n) {
+    assert(n <= length_);
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  // string_view::remove_suffix()
+  //
+  // Removes the last `n` characters from the `string_view`. Note that the
+  // underlying std::string is not changed, only the view.
+  void remove_suffix(size_type n) {
+    assert(n <= length_);
+    length_ -= n;
+  }
+
+  // string_view::swap()
+  //
+  // Swaps this `string_view` with another `string_view`.
+  void swap(string_view& s) noexcept {
+    auto t = *this;
+    *this = s;
+    s = t;
+  }
+
+  // Explicit conversion operators
+
+  // Converts to `std::basic_string`.
+  template <typename A>
+  explicit operator std::basic_string<char, traits_type, A>() const {
+    if (!data()) return {};
+    return std::basic_string<char, traits_type, A>(data(), size());
+  }
+
+  // string_view::copy()
+  //
+  // Copies the contents of the `string_view` at offset `pos` and length `n`
+  // into `buf`.
+  size_type copy(char* buf, size_type n, size_type pos = 0) const;
+
+  // string_view::substr()
+  //
+  // Returns a "substring" of the `string_view` (at offset `pos` and length
+  // `n`) as another string_view. This function throws `std::out_of_bounds` if
+  // `pos > size'.
+  string_view substr(size_type pos, size_type n = npos) const {
+    if (ABSL_PREDICT_FALSE(pos > length_))
+      base_internal::ThrowStdOutOfRange("absl::string_view::substr");
+    n = std::min(n, length_ - pos);
+    return string_view(ptr_ + pos, n);
+  }
+
+  // string_view::compare()
+  //
+  // Performs a lexicographical comparison between the `string_view` and
+  // another `absl::string_view), returning -1 if `this` is less than, 0 if
+  // `this` is equal to, and 1 if `this` is greater than the passed std::string
+  // view. Note that in the case of data equality, a further comparison is made
+  // on the respective sizes of the two `string_view`s to determine which is
+  // smaller, equal, or greater.
+  int compare(string_view x) const noexcept {
+    auto min_length = std::min(length_, x.length_);
+    if (min_length > 0) {
+      int r = memcmp(ptr_, x.ptr_, min_length);
+      if (r < 0) return -1;
+      if (r > 0) return 1;
+    }
+    if (length_ < x.length_) return -1;
+    if (length_ > x.length_) return 1;
+    return 0;
+  }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // 'string_view` and another `absl::string_view`.
+  int compare(size_type pos1, size_type count1, string_view v) const {
+    return substr(pos1, count1).compare(v);
+  }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // `string_view` and a substring of another `absl::string_view`.
+  int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
+              size_type count2) const {
+    return substr(pos1, count1).compare(v.substr(pos2, count2));
+  }
+
+  // Overload of `string_view::compare()` for comparing a `string_view` and a
+  // a different  C-style std::string `s`.
+  int compare(const char* s) const { return compare(string_view(s)); }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // `string_view` and a different std::string C-style std::string `s`.
+  int compare(size_type pos1, size_type count1, const char* s) const {
+    return substr(pos1, count1).compare(string_view(s));
+  }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // `string_view` and a substring of a different C-style std::string `s`.
+  int compare(size_type pos1, size_type count1, const char* s,
+              size_type count2) const {
+    return substr(pos1, count1).compare(string_view(s, count2));
+  }
+
+  // Find Utilities
+
+  // string_view::find()
+  //
+  // Finds the first occurrence of the substring `s` within the `string_view`,
+  // returning the position of the first character's match, or `npos` if no
+  // match was found.
+  size_type find(string_view s, size_type pos = 0) const noexcept;
+
+  // Overload of `string_view::find()` for finding the given character `c`
+  // within the `string_view`.
+  size_type find(char c, size_type pos = 0) const noexcept;
+
+  // string_view::rfind()
+  //
+  // Finds the last occurrence of a substring `s` within the `string_view`,
+  // returning the position of the first character's match, or `npos` if no
+  // match was found.
+  size_type rfind(string_view s, size_type pos = npos) const
+      noexcept;
+
+  // Overload of `string_view::rfind()` for finding the last given character `c`
+  // within the `string_view`.
+  size_type rfind(char c, size_type pos = npos) const noexcept;
+
+  // string_view::find_first_of()
+  //
+  // Finds the first occurrence of any of the characters in `s` within the
+  // `string_view`, returning the start position of the match, or `npos` if no
+  // match was found.
+  size_type find_first_of(string_view s, size_type pos = 0) const
+      noexcept;
+
+  // Overload of `string_view::find_first_of()` for finding a character `c`
+  // within the `string_view`.
+  size_type find_first_of(char c, size_type pos = 0) const
+      noexcept {
+    return find(c, pos);
+  }
+
+  // string_view::find_last_of()
+  //
+  // Finds the last occurrence of any of the characters in `s` within the
+  // `string_view`, returning the start position of the match, or `npos` if no
+  // match was found.
+  size_type find_last_of(string_view s, size_type pos = npos) const
+      noexcept;
+
+  // Overload of `string_view::find_last_of()` for finding a character `c`
+  // within the `string_view`.
+  size_type find_last_of(char c, size_type pos = npos) const
+      noexcept {
+    return rfind(c, pos);
+  }
+
+  // string_view::find_first_not_of()
+  //
+  // Finds the first occurrence of any of the characters not in `s` within the
+  // `string_view`, returning the start position of the first non-match, or
+  // `npos` if no non-match was found.
+  size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept;
+
+  // Overload of `string_view::find_first_not_of()` for finding a character
+  // that is not `c` within the `string_view`.
+  size_type find_first_not_of(char c, size_type pos = 0) const noexcept;
+
+  // string_view::find_last_not_of()
+  //
+  // Finds the last occurrence of any of the characters not in `s` within the
+  // `string_view`, returning the start position of the last non-match, or
+  // `npos` if no non-match was found.
+  size_type find_last_not_of(string_view s,
+                                          size_type pos = npos) const noexcept;
+
+  // Overload of `string_view::find_last_not_of()` for finding a character
+  // that is not `c` within the `string_view`.
+  size_type find_last_not_of(char c, size_type pos = npos) const
+      noexcept;
+
+ private:
+  static constexpr size_type kMaxSize =
+      std::numeric_limits<difference_type>::max();
+
+  // check whether __builtin_strlen is provided by the compiler.
+  // GCC doesn't have __has_builtin()
+  // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970),
+  // but has __builtin_strlen according to
+  // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html.
+#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
+    (defined(__GNUC__) && !defined(__clang__))
+  static constexpr size_type StrLenInternal(const char* str) {
+    return str ? __builtin_strlen(str) : 0;
+  }
+#else
+  static constexpr size_type StrLenInternal(const char* str) {
+    return str ? strlen(str) : 0;
+  }
+#endif
+
+  static constexpr size_type CheckLengthInternal(size_type len) {
+    return ABSL_ASSERT(len <= kMaxSize), len;
+  }
+
+  const char* ptr_;
+  size_type length_;
+};
+
+// This large function is defined inline so that in a fairly common case where
+// one of the arguments is a literal, the compiler can elide a lot of the
+// following comparisons.
+inline bool operator==(string_view x, string_view y) noexcept {
+  auto len = x.size();
+  if (len != y.size()) {
+    return false;
+  }
+  return x.data() == y.data() || len <= 0 ||
+         memcmp(x.data(), y.data(), len) == 0;
+}
+
+inline bool operator!=(string_view x, string_view y) noexcept {
+  return !(x == y);
+}
+
+inline bool operator<(string_view x, string_view y) noexcept {
+  auto min_size = std::min(x.size(), y.size());
+  const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
+  return (r < 0) || (r == 0 && x.size() < y.size());
+}
+
+inline bool operator>(string_view x, string_view y) noexcept { return y < x; }
+
+inline bool operator<=(string_view x, string_view y) noexcept {
+  return !(y < x);
+}
+
+inline bool operator>=(string_view x, string_view y) noexcept {
+  return !(x < y);
+}
+
+// IO Insertion Operator
+std::ostream& operator<<(std::ostream& o, string_view piece);
+
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_STRING_VIEW
+
+namespace absl {
+
+// ClippedSubstr()
+//
+// Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`.
+// Provided because std::string_view::substr throws if `pos > size()`
+inline string_view ClippedSubstr(string_view s, size_t pos,
+                                 size_t n = string_view::npos) {
+  pos = std::min(pos, static_cast<size_t>(s.size()));
+  return s.substr(pos, n);
+}
+
+// NullSafeStringView()
+//
+// Creates an `absl::string_view` from a pointer `p` even if it's null-valued.
+// This function should be used where an `absl::string_view` can be created from
+// a possibly-null pointer.
+inline string_view NullSafeStringView(const char* p) {
+  return p ? string_view(p) : string_view();
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STRING_VIEW_H_
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc
new file mode 100644
index 0000000..fb46db1
--- /dev/null
+++ b/absl/strings/string_view_benchmark.cc
@@ -0,0 +1,329 @@
+// Copyright 2018 The Abseil 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 "absl/strings/string_view.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <map>
+#include <random>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+// Provide a forcibly out-of-line wrapper for operator== that can be used in
+// benchmarks to measure the impact of inlining.
+ABSL_ATTRIBUTE_NOINLINE
+bool NonInlinedEq(absl::string_view a, absl::string_view b) { return a == b; }
+
+// We use functions that cannot be inlined to perform the comparison loops so
+// that inlining of the operator== can't optimize away *everything*.
+ABSL_ATTRIBUTE_NOINLINE
+void DoEqualityComparisons(benchmark::State& state, absl::string_view a,
+                           absl::string_view b) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(a == b);
+  }
+}
+
+void BM_EqualIdentical(benchmark::State& state) {
+  std::string x(state.range(0), 'a');
+  DoEqualityComparisons(state, x, x);
+}
+BENCHMARK(BM_EqualIdentical)->DenseRange(0, 3)->Range(4, 1 << 10);
+
+void BM_EqualSame(benchmark::State& state) {
+  std::string x(state.range(0), 'a');
+  std::string y = x;
+  DoEqualityComparisons(state, x, y);
+}
+BENCHMARK(BM_EqualSame)
+    ->DenseRange(0, 10)
+    ->Arg(20)
+    ->Arg(40)
+    ->Arg(70)
+    ->Arg(110)
+    ->Range(160, 4096);
+
+void BM_EqualDifferent(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string x(len, 'a');
+  std::string y = x;
+  if (len > 0) {
+    y[len - 1] = 'b';
+  }
+  DoEqualityComparisons(state, x, y);
+}
+BENCHMARK(BM_EqualDifferent)->DenseRange(0, 3)->Range(4, 1 << 10);
+
+// This benchmark is intended to check that important simplifications can be
+// made with absl::string_view comparisons against constant strings. The idea is
+// that if constant strings cause redundant components of the comparison, the
+// compiler should detect and eliminate them. Here we use 8 different strings,
+// each with the same size. Provided our comparison makes the implementation
+// inline-able by the compiler, it should fold all of these away into a single
+// size check once per loop iteration.
+ABSL_ATTRIBUTE_NOINLINE
+void DoConstantSizeInlinedEqualityComparisons(benchmark::State& state,
+                                              absl::string_view a) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(a == "aaa");
+    benchmark::DoNotOptimize(a == "bbb");
+    benchmark::DoNotOptimize(a == "ccc");
+    benchmark::DoNotOptimize(a == "ddd");
+    benchmark::DoNotOptimize(a == "eee");
+    benchmark::DoNotOptimize(a == "fff");
+    benchmark::DoNotOptimize(a == "ggg");
+    benchmark::DoNotOptimize(a == "hhh");
+  }
+}
+void BM_EqualConstantSizeInlined(benchmark::State& state) {
+  std::string x(state.range(0), 'a');
+  DoConstantSizeInlinedEqualityComparisons(state, x);
+}
+// We only need to check for size of 3, and <> 3 as this benchmark only has to
+// do with size differences.
+BENCHMARK(BM_EqualConstantSizeInlined)->DenseRange(2, 4);
+
+// This benchmark exists purely to give context to the above timings: this is
+// what they would look like if the compiler is completely unable to simplify
+// between two comparisons when they are comparing against constant strings.
+ABSL_ATTRIBUTE_NOINLINE
+void DoConstantSizeNonInlinedEqualityComparisons(benchmark::State& state,
+                                                 absl::string_view a) {
+  for (auto _ : state) {
+    // Force these out-of-line to compare with the above function.
+    benchmark::DoNotOptimize(NonInlinedEq(a, "aaa"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "bbb"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "ccc"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "ddd"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "eee"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "fff"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "ggg"));
+    benchmark::DoNotOptimize(NonInlinedEq(a, "hhh"));
+  }
+}
+
+void BM_EqualConstantSizeNonInlined(benchmark::State& state) {
+  std::string x(state.range(0), 'a');
+  DoConstantSizeNonInlinedEqualityComparisons(state, x);
+}
+// We only need to check for size of 3, and <> 3 as this benchmark only has to
+// do with size differences.
+BENCHMARK(BM_EqualConstantSizeNonInlined)->DenseRange(2, 4);
+
+void BM_CompareSame(benchmark::State& state) {
+  const int len = state.range(0);
+  std::string x;
+  for (int i = 0; i < len; i++) {
+    x += 'a';
+  }
+  std::string y = x;
+  absl::string_view a = x;
+  absl::string_view b = y;
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(a.compare(b));
+  }
+}
+BENCHMARK(BM_CompareSame)->DenseRange(0, 3)->Range(4, 1 << 10);
+
+void BM_find_string_view_len_one(benchmark::State& state) {
+  std::string haystack(state.range(0), '0');
+  absl::string_view s(haystack);
+  for (auto _ : state) {
+    s.find("x");  // not present; length 1
+  }
+}
+BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20);
+
+void BM_find_string_view_len_two(benchmark::State& state) {
+  std::string haystack(state.range(0), '0');
+  absl::string_view s(haystack);
+  for (auto _ : state) {
+    s.find("xx");  // not present; length 2
+  }
+}
+BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20);
+
+void BM_find_one_char(benchmark::State& state) {
+  std::string haystack(state.range(0), '0');
+  absl::string_view s(haystack);
+  for (auto _ : state) {
+    s.find('x');  // not present
+  }
+}
+BENCHMARK(BM_find_one_char)->Range(1, 1 << 20);
+
+void BM_rfind_one_char(benchmark::State& state) {
+  std::string haystack(state.range(0), '0');
+  absl::string_view s(haystack);
+  for (auto _ : state) {
+    s.rfind('x');  // not present
+  }
+}
+BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20);
+
+void BM_worst_case_find_first_of(benchmark::State& state, int haystack_len) {
+  const int needle_len = state.range(0);
+  std::string needle;
+  for (int i = 0; i < needle_len; ++i) {
+    needle += 'a' + i;
+  }
+  std::string haystack(haystack_len, '0');  // 1000 zeros.
+
+  absl::string_view s(haystack);
+  for (auto _ : state) {
+    s.find_first_of(needle);
+  }
+}
+
+void BM_find_first_of_short(benchmark::State& state) {
+  BM_worst_case_find_first_of(state, 10);
+}
+
+void BM_find_first_of_medium(benchmark::State& state) {
+  BM_worst_case_find_first_of(state, 100);
+}
+
+void BM_find_first_of_long(benchmark::State& state) {
+  BM_worst_case_find_first_of(state, 1000);
+}
+
+BENCHMARK(BM_find_first_of_short)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
+BENCHMARK(BM_find_first_of_medium)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
+BENCHMARK(BM_find_first_of_long)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32);
+
+struct EasyMap : public std::map<absl::string_view, uint64_t> {
+  explicit EasyMap(size_t) {}
+};
+
+// This templated benchmark helper function is intended to stress operator== or
+// operator< in a realistic test.  It surely isn't entirely realistic, but it's
+// a start.  The test creates a map of type Map, a template arg, and populates
+// it with table_size key/value pairs. Each key has WordsPerKey words.  After
+// creating the map, a number of lookups are done in random order.  Some keys
+// are used much more frequently than others in this phase of the test.
+template <typename Map, int WordsPerKey>
+void StringViewMapBenchmark(benchmark::State& state) {
+  const int table_size = state.range(0);
+  const double kFractionOfKeysThatAreHot = 0.2;
+  const int kNumLookupsOfHotKeys = 20;
+  const int kNumLookupsOfColdKeys = 1;
+  const char* words[] = {"the",   "quick",  "brown",    "fox",      "jumped",
+                         "over",  "the",    "lazy",     "dog",      "and",
+                         "found", "a",      "large",    "mushroom", "and",
+                         "a",     "couple", "crickets", "eating",   "pie"};
+  // Create some keys that consist of words in random order.
+  std::random_device r;
+  std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
+  std::mt19937 rng(seed);
+  std::vector<std::string> keys(table_size);
+  std::vector<int> all_indices;
+  const int kBlockSize = 1 << 12;
+  std::unordered_set<std::string> t(kBlockSize);
+  std::uniform_int_distribution<int> uniform(0, ABSL_ARRAYSIZE(words) - 1);
+  for (int i = 0; i < table_size; i++) {
+    all_indices.push_back(i);
+    do {
+      keys[i].clear();
+      for (int j = 0; j < WordsPerKey; j++) {
+        absl::StrAppend(&keys[i], j > 0 ? " " : "", words[uniform(rng)]);
+      }
+    } while (!t.insert(keys[i]).second);
+  }
+
+  // Create a list of strings to lookup: a permutation of the array of
+  // keys we just created, with repeats.  "Hot" keys get repeated more.
+  std::shuffle(all_indices.begin(), all_indices.end(), rng);
+  const int num_hot = table_size * kFractionOfKeysThatAreHot;
+  const int num_cold = table_size - num_hot;
+  std::vector<int> hot_indices(all_indices.begin(),
+                               all_indices.begin() + num_hot);
+  std::vector<int> indices;
+  for (int i = 0; i < kNumLookupsOfColdKeys; i++) {
+    indices.insert(indices.end(), all_indices.begin(), all_indices.end());
+  }
+  for (int i = 0; i < kNumLookupsOfHotKeys - kNumLookupsOfColdKeys; i++) {
+    indices.insert(indices.end(), hot_indices.begin(), hot_indices.end());
+  }
+  std::shuffle(indices.begin(), indices.end(), rng);
+  ABSL_RAW_CHECK(
+      num_cold * kNumLookupsOfColdKeys + num_hot * kNumLookupsOfHotKeys ==
+          indices.size(),
+      "");
+  // After constructing the array we probe it with absl::string_views built from
+  // test_strings.  This means operator== won't see equal pointers, so
+  // it'll have to check for equal lengths and equal characters.
+  std::vector<std::string> test_strings(indices.size());
+  for (int i = 0; i < indices.size(); i++) {
+    test_strings[i] = keys[indices[i]];
+  }
+
+  // Run the benchmark. It includes map construction but is mostly
+  // map lookups.
+  for (auto _ : state) {
+    Map h(table_size);
+    for (int i = 0; i < table_size; i++) {
+      h[keys[i]] = i * 2;
+    }
+    ABSL_RAW_CHECK(h.size() == table_size, "");
+    uint64_t sum = 0;
+    for (int i = 0; i < indices.size(); i++) {
+      sum += h[test_strings[i]];
+    }
+    benchmark::DoNotOptimize(sum);
+  }
+}
+
+void BM_StdMap_4(benchmark::State& state) {
+  StringViewMapBenchmark<EasyMap, 4>(state);
+}
+BENCHMARK(BM_StdMap_4)->Range(1 << 10, 1 << 16);
+
+void BM_StdMap_8(benchmark::State& state) {
+  StringViewMapBenchmark<EasyMap, 8>(state);
+}
+BENCHMARK(BM_StdMap_8)->Range(1 << 10, 1 << 16);
+
+void BM_CopyToStringNative(benchmark::State& state) {
+  std::string src(state.range(0), 'x');
+  absl::string_view sv(src);
+  std::string dst;
+  for (auto _ : state) {
+    dst.assign(sv.begin(), sv.end());
+  }
+}
+BENCHMARK(BM_CopyToStringNative)->Range(1 << 3, 1 << 12);
+
+void BM_AppendToStringNative(benchmark::State& state) {
+  std::string src(state.range(0), 'x');
+  absl::string_view sv(src);
+  std::string dst;
+  for (auto _ : state) {
+    dst.clear();
+    dst.insert(dst.end(), sv.begin(), sv.end());
+  }
+}
+BENCHMARK(BM_AppendToStringNative)->Range(1 << 3, 1 << 12);
+
+}  // namespace
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
new file mode 100644
index 0000000..b19d07c
--- /dev/null
+++ b/absl/strings/string_view_test.cc
@@ -0,0 +1,1146 @@
+// Copyright 2017 The Abseil 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 "absl/strings/string_view.h"
+
+#include <stdlib.h>
+#include <iomanip>
+#include <iterator>
+#include <limits>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+
+#ifdef __ANDROID__
+// Android assert messages only go to system log, so death tests cannot inspect
+// the message for matching.
+#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+  EXPECT_DEATH_IF_SUPPORTED(statement, ".*")
+#else
+#define ABSL_EXPECT_DEATH_IF_SUPPORTED EXPECT_DEATH_IF_SUPPORTED
+#endif
+
+namespace {
+
+// A minimal allocator that uses malloc().
+template <typename T>
+struct Mallocator {
+  typedef T value_type;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+  typedef T* pointer;
+  typedef const T* const_pointer;
+  typedef T& reference;
+  typedef const T& const_reference;
+
+  size_type max_size() const {
+    return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type);
+  }
+  template <typename U>
+  struct rebind {
+    typedef Mallocator<U> other;
+  };
+  Mallocator() = default;
+  template <class U>
+  Mallocator(const Mallocator<U>&) {}  // NOLINT(runtime/explicit)
+
+  T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
+  void deallocate(T* p, size_t) { std::free(p); }
+};
+template <typename T, typename U>
+bool operator==(const Mallocator<T>&, const Mallocator<U>&) {
+  return true;
+}
+template <typename T, typename U>
+bool operator!=(const Mallocator<T>&, const Mallocator<U>&) {
+  return false;
+}
+
+TEST(StringViewTest, Ctor) {
+  {
+    // Null.
+    absl::string_view s10;
+    EXPECT_TRUE(s10.data() == nullptr);
+    EXPECT_EQ(0, s10.length());
+  }
+
+  {
+    // const char* without length.
+    const char* hello = "hello";
+    absl::string_view s20(hello);
+    EXPECT_TRUE(s20.data() == hello);
+    EXPECT_EQ(5, s20.length());
+
+    // const char* with length.
+    absl::string_view s21(hello, 4);
+    EXPECT_TRUE(s21.data() == hello);
+    EXPECT_EQ(4, s21.length());
+
+    // Not recommended, but valid C++
+    absl::string_view s22(hello, 6);
+    EXPECT_TRUE(s22.data() == hello);
+    EXPECT_EQ(6, s22.length());
+  }
+
+  {
+    // std::string.
+    std::string hola = "hola";
+    absl::string_view s30(hola);
+    EXPECT_TRUE(s30.data() == hola.data());
+    EXPECT_EQ(4, s30.length());
+
+    // std::string with embedded '\0'.
+    hola.push_back('\0');
+    hola.append("h2");
+    hola.push_back('\0');
+    absl::string_view s31(hola);
+    EXPECT_TRUE(s31.data() == hola.data());
+    EXPECT_EQ(8, s31.length());
+  }
+
+  {
+    using mstring =
+        std::basic_string<char, std::char_traits<char>, Mallocator<char>>;
+    mstring str1("BUNGIE-JUMPING!");
+    const mstring str2("SLEEPING!");
+
+    absl::string_view s1(str1);
+    s1.remove_prefix(strlen("BUNGIE-JUM"));
+
+    absl::string_view s2(str2);
+    s2.remove_prefix(strlen("SLEE"));
+
+    EXPECT_EQ(s1, s2);
+    EXPECT_EQ(s1, "PING!");
+  }
+
+  // TODO(mec): absl::string_view(const absl::string_view&);
+}
+
+TEST(StringViewTest, Swap) {
+  absl::string_view a("a");
+  absl::string_view b("bbb");
+  EXPECT_TRUE(noexcept(a.swap(b)));
+  a.swap(b);
+  EXPECT_EQ(a, "bbb");
+  EXPECT_EQ(b, "a");
+  a.swap(b);
+  EXPECT_EQ(a, "a");
+  EXPECT_EQ(b, "bbb");
+}
+
+TEST(StringViewTest, STLComparator) {
+  std::string s1("foo");
+  std::string s2("bar");
+  std::string s3("baz");
+
+  absl::string_view p1(s1);
+  absl::string_view p2(s2);
+  absl::string_view p3(s3);
+
+  typedef std::map<absl::string_view, int> TestMap;
+  TestMap map;
+
+  map.insert(std::make_pair(p1, 0));
+  map.insert(std::make_pair(p2, 1));
+  map.insert(std::make_pair(p3, 2));
+  EXPECT_EQ(map.size(), 3);
+
+  TestMap::const_iterator iter = map.begin();
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  EXPECT_EQ(iter->second, 0);
+  ++iter;
+  EXPECT_TRUE(iter == map.end());
+
+  TestMap::iterator new_iter = map.find("zot");
+  EXPECT_TRUE(new_iter == map.end());
+
+  new_iter = map.find("bar");
+  EXPECT_TRUE(new_iter != map.end());
+
+  map.erase(new_iter);
+  EXPECT_EQ(map.size(), 2);
+
+  iter = map.begin();
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  EXPECT_EQ(iter->second, 0);
+  ++iter;
+  EXPECT_TRUE(iter == map.end());
+}
+
+#define COMPARE(result, op, x, y)                                      \
+  EXPECT_EQ(result, absl::string_view((x)) op absl::string_view((y))); \
+  EXPECT_EQ(result, absl::string_view((x)).compare(absl::string_view((y))) op 0)
+
+TEST(StringViewTest, ComparisonOperators) {
+  COMPARE(true, ==, "",   "");
+  COMPARE(true, ==, "", absl::string_view());
+  COMPARE(true, ==, absl::string_view(), "");
+  COMPARE(true, ==, "a",  "a");
+  COMPARE(true, ==, "aa", "aa");
+  COMPARE(false, ==, "a",  "");
+  COMPARE(false, ==, "",   "a");
+  COMPARE(false, ==, "a",  "b");
+  COMPARE(false, ==, "a",  "aa");
+  COMPARE(false, ==, "aa", "a");
+
+  COMPARE(false, !=, "",   "");
+  COMPARE(false, !=, "a",  "a");
+  COMPARE(false, !=, "aa", "aa");
+  COMPARE(true, !=, "a",  "");
+  COMPARE(true, !=, "",   "a");
+  COMPARE(true, !=, "a",  "b");
+  COMPARE(true, !=, "a",  "aa");
+  COMPARE(true, !=, "aa", "a");
+
+  COMPARE(true, <, "a",  "b");
+  COMPARE(true, <, "a",  "aa");
+  COMPARE(true, <, "aa", "b");
+  COMPARE(true, <, "aa", "bb");
+  COMPARE(false, <, "a",  "a");
+  COMPARE(false, <, "b",  "a");
+  COMPARE(false, <, "aa", "a");
+  COMPARE(false, <, "b",  "aa");
+  COMPARE(false, <, "bb", "aa");
+
+  COMPARE(true, <=, "a",  "a");
+  COMPARE(true, <=, "a",  "b");
+  COMPARE(true, <=, "a",  "aa");
+  COMPARE(true, <=, "aa", "b");
+  COMPARE(true, <=, "aa", "bb");
+  COMPARE(false, <=, "b",  "a");
+  COMPARE(false, <=, "aa", "a");
+  COMPARE(false, <=, "b",  "aa");
+  COMPARE(false, <=, "bb", "aa");
+
+  COMPARE(false, >=, "a",  "b");
+  COMPARE(false, >=, "a",  "aa");
+  COMPARE(false, >=, "aa", "b");
+  COMPARE(false, >=, "aa", "bb");
+  COMPARE(true, >=, "a",  "a");
+  COMPARE(true, >=, "b",  "a");
+  COMPARE(true, >=, "aa", "a");
+  COMPARE(true, >=, "b",  "aa");
+  COMPARE(true, >=, "bb", "aa");
+
+  COMPARE(false, >, "a",  "a");
+  COMPARE(false, >, "a",  "b");
+  COMPARE(false, >, "a",  "aa");
+  COMPARE(false, >, "aa", "b");
+  COMPARE(false, >, "aa", "bb");
+  COMPARE(true, >, "b",  "a");
+  COMPARE(true, >, "aa", "a");
+  COMPARE(true, >, "b",  "aa");
+  COMPARE(true, >, "bb", "aa");
+}
+
+TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) {
+  std::string x;
+  for (int i = 0; i < 256; i++) {
+    x += 'a';
+    std::string y = x;
+    COMPARE(true, ==, x, y);
+    for (int j = 0; j < i; j++) {
+      std::string z = x;
+      z[j] = 'b';       // Differs in position 'j'
+      COMPARE(false, ==, x, z);
+      COMPARE(true, <, x, z);
+      COMPARE(true, >, z, x);
+      if (j + 1 < i) {
+        z[j + 1] = 'A';  // Differs in position 'j+1' as well
+        COMPARE(false, ==, x, z);
+        COMPARE(true, <, x, z);
+        COMPARE(true, >, z, x);
+        z[j + 1] = 'z';  // Differs in position 'j+1' as well
+        COMPARE(false, ==, x, z);
+        COMPARE(true, <, x, z);
+        COMPARE(true, >, z, x);
+      }
+    }
+  }
+}
+#undef COMPARE
+
+// Sadly, our users often confuse std::string::npos with absl::string_view::npos;
+// So much so that we test here that they are the same.  They need to
+// both be unsigned, and both be the maximum-valued integer of their type.
+
+template <typename T>
+struct is_type {
+  template <typename U>
+  static bool same(U) {
+    return false;
+  }
+  static bool same(T) { return true; }
+};
+
+TEST(StringViewTest, NposMatchesStdStringView) {
+  EXPECT_EQ(absl::string_view::npos, std::string::npos);
+
+  EXPECT_TRUE(is_type<size_t>::same(absl::string_view::npos));
+  EXPECT_FALSE(is_type<size_t>::same(""));
+
+  // Make sure absl::string_view::npos continues to be a header constant.
+  char test[absl::string_view::npos & 1] = {0};
+  EXPECT_EQ(0, test[0]);
+}
+
+TEST(StringViewTest, STL1) {
+  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+  const absl::string_view b("abc");
+  const absl::string_view c("xyz");
+  const absl::string_view d("foobar");
+  const absl::string_view e;
+  std::string temp("123");
+  temp += '\0';
+  temp += "456";
+  const absl::string_view f(temp);
+
+  EXPECT_EQ(a[6], 'g');
+  EXPECT_EQ(b[0], 'a');
+  EXPECT_EQ(c[2], 'z');
+  EXPECT_EQ(f[3], '\0');
+  EXPECT_EQ(f[5], '5');
+
+  EXPECT_EQ(*d.data(), 'f');
+  EXPECT_EQ(d.data()[5], 'r');
+  EXPECT_TRUE(e.data() == nullptr);
+
+  EXPECT_EQ(*a.begin(), 'a');
+  EXPECT_EQ(*(b.begin() + 2), 'c');
+  EXPECT_EQ(*(c.end() - 1), 'z');
+
+  EXPECT_EQ(*a.rbegin(), 'z');
+  EXPECT_EQ(*(b.rbegin() + 2), 'a');
+  EXPECT_EQ(*(c.rend() - 1), 'x');
+  EXPECT_TRUE(a.rbegin() + 26 == a.rend());
+
+  EXPECT_EQ(a.size(), 26);
+  EXPECT_EQ(b.size(), 3);
+  EXPECT_EQ(c.size(), 3);
+  EXPECT_EQ(d.size(), 6);
+  EXPECT_EQ(e.size(), 0);
+  EXPECT_EQ(f.size(), 7);
+
+  EXPECT_TRUE(!d.empty());
+  EXPECT_TRUE(d.begin() != d.end());
+  EXPECT_TRUE(d.begin() + 6 == d.end());
+
+  EXPECT_TRUE(e.empty());
+  EXPECT_TRUE(e.begin() == e.end());
+
+  char buf[4] = { '%', '%', '%', '%' };
+  EXPECT_EQ(a.copy(buf, 4), 4);
+  EXPECT_EQ(buf[0], a[0]);
+  EXPECT_EQ(buf[1], a[1]);
+  EXPECT_EQ(buf[2], a[2]);
+  EXPECT_EQ(buf[3], a[3]);
+  EXPECT_EQ(a.copy(buf, 3, 7), 3);
+  EXPECT_EQ(buf[0], a[7]);
+  EXPECT_EQ(buf[1], a[8]);
+  EXPECT_EQ(buf[2], a[9]);
+  EXPECT_EQ(buf[3], a[3]);
+  EXPECT_EQ(c.copy(buf, 99), 3);
+  EXPECT_EQ(buf[0], c[0]);
+  EXPECT_EQ(buf[1], c[1]);
+  EXPECT_EQ(buf[2], c[2]);
+  EXPECT_EQ(buf[3], a[3]);
+}
+
+// Separated from STL1() because some compilers produce an overly
+// large stack frame for the combined function.
+TEST(StringViewTest, STL2) {
+  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+  const absl::string_view b("abc");
+  const absl::string_view c("xyz");
+  absl::string_view d("foobar");
+  const absl::string_view e;
+  const absl::string_view f(
+      "123"
+      "\0"
+      "456",
+      7);
+
+  d = absl::string_view();
+  EXPECT_EQ(d.size(), 0);
+  EXPECT_TRUE(d.empty());
+  EXPECT_TRUE(d.data() == nullptr);
+  EXPECT_TRUE(d.begin() == d.end());
+
+  EXPECT_EQ(a.find(b), 0);
+  EXPECT_EQ(a.find(b, 1), absl::string_view::npos);
+  EXPECT_EQ(a.find(c), 23);
+  EXPECT_EQ(a.find(c, 9), 23);
+  EXPECT_EQ(a.find(c, absl::string_view::npos), absl::string_view::npos);
+  EXPECT_EQ(b.find(c), absl::string_view::npos);
+  EXPECT_EQ(b.find(c, absl::string_view::npos), absl::string_view::npos);
+  EXPECT_EQ(a.find(d), 0);
+  EXPECT_EQ(a.find(e), 0);
+  EXPECT_EQ(a.find(d, 12), 12);
+  EXPECT_EQ(a.find(e, 17), 17);
+  absl::string_view g("xx not found bb");
+  EXPECT_EQ(a.find(g), absl::string_view::npos);
+  // empty std::string nonsense
+  EXPECT_EQ(d.find(b), absl::string_view::npos);
+  EXPECT_EQ(e.find(b), absl::string_view::npos);
+  EXPECT_EQ(d.find(b, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find(b, 7), absl::string_view::npos);
+
+  size_t empty_search_pos = std::string().find(std::string());
+  EXPECT_EQ(d.find(d), empty_search_pos);
+  EXPECT_EQ(d.find(e), empty_search_pos);
+  EXPECT_EQ(e.find(d), empty_search_pos);
+  EXPECT_EQ(e.find(e), empty_search_pos);
+  EXPECT_EQ(d.find(d, 4), std::string().find(std::string(), 4));
+  EXPECT_EQ(d.find(e, 4), std::string().find(std::string(), 4));
+  EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4));
+  EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4));
+
+  EXPECT_EQ(a.find('a'), 0);
+  EXPECT_EQ(a.find('c'), 2);
+  EXPECT_EQ(a.find('z'), 25);
+  EXPECT_EQ(a.find('$'), absl::string_view::npos);
+  EXPECT_EQ(a.find('\0'), absl::string_view::npos);
+  EXPECT_EQ(f.find('\0'), 3);
+  EXPECT_EQ(f.find('3'), 2);
+  EXPECT_EQ(f.find('5'), 5);
+  EXPECT_EQ(g.find('o'), 4);
+  EXPECT_EQ(g.find('o', 4), 4);
+  EXPECT_EQ(g.find('o', 5), 8);
+  EXPECT_EQ(a.find('b', 5), absl::string_view::npos);
+  // empty std::string nonsense
+  EXPECT_EQ(d.find('\0'), absl::string_view::npos);
+  EXPECT_EQ(e.find('\0'), absl::string_view::npos);
+  EXPECT_EQ(d.find('\0', 4), absl::string_view::npos);
+  EXPECT_EQ(e.find('\0', 7), absl::string_view::npos);
+  EXPECT_EQ(d.find('x'), absl::string_view::npos);
+  EXPECT_EQ(e.find('x'), absl::string_view::npos);
+  EXPECT_EQ(d.find('x', 4), absl::string_view::npos);
+  EXPECT_EQ(e.find('x', 7), absl::string_view::npos);
+
+  EXPECT_EQ(a.rfind(b), 0);
+  EXPECT_EQ(a.rfind(b, 1), 0);
+  EXPECT_EQ(a.rfind(c), 23);
+  EXPECT_EQ(a.rfind(c, 22), absl::string_view::npos);
+  EXPECT_EQ(a.rfind(c, 1), absl::string_view::npos);
+  EXPECT_EQ(a.rfind(c, 0), absl::string_view::npos);
+  EXPECT_EQ(b.rfind(c), absl::string_view::npos);
+  EXPECT_EQ(b.rfind(c, 0), absl::string_view::npos);
+  EXPECT_EQ(a.rfind(d), std::string(a).rfind(std::string()));
+  EXPECT_EQ(a.rfind(e), std::string(a).rfind(std::string()));
+  EXPECT_EQ(a.rfind(d, 12), 12);
+  EXPECT_EQ(a.rfind(e, 17), 17);
+  EXPECT_EQ(a.rfind(g), absl::string_view::npos);
+  EXPECT_EQ(d.rfind(b), absl::string_view::npos);
+  EXPECT_EQ(e.rfind(b), absl::string_view::npos);
+  EXPECT_EQ(d.rfind(b, 4), absl::string_view::npos);
+  EXPECT_EQ(e.rfind(b, 7), absl::string_view::npos);
+  // empty std::string nonsense
+  EXPECT_EQ(d.rfind(d, 4), std::string().rfind(std::string()));
+  EXPECT_EQ(e.rfind(d, 7), std::string().rfind(std::string()));
+  EXPECT_EQ(d.rfind(e, 4), std::string().rfind(std::string()));
+  EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
+  EXPECT_EQ(d.rfind(d), std::string().rfind(std::string()));
+  EXPECT_EQ(e.rfind(d), std::string().rfind(std::string()));
+  EXPECT_EQ(d.rfind(e), std::string().rfind(std::string()));
+  EXPECT_EQ(e.rfind(e), std::string().rfind(std::string()));
+
+  EXPECT_EQ(g.rfind('o'), 8);
+  EXPECT_EQ(g.rfind('q'), absl::string_view::npos);
+  EXPECT_EQ(g.rfind('o', 8), 8);
+  EXPECT_EQ(g.rfind('o', 7), 4);
+  EXPECT_EQ(g.rfind('o', 3), absl::string_view::npos);
+  EXPECT_EQ(f.rfind('\0'), 3);
+  EXPECT_EQ(f.rfind('\0', 12), 3);
+  EXPECT_EQ(f.rfind('3'), 2);
+  EXPECT_EQ(f.rfind('5'), 5);
+  // empty std::string nonsense
+  EXPECT_EQ(d.rfind('o'), absl::string_view::npos);
+  EXPECT_EQ(e.rfind('o'), absl::string_view::npos);
+  EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos);
+  EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos);
+}
+
+// Continued from STL2
+TEST(StringViewTest, STL2FindFirst) {
+  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+  const absl::string_view b("abc");
+  const absl::string_view c("xyz");
+  absl::string_view d("foobar");
+  const absl::string_view e;
+  const absl::string_view f(
+      "123"
+      "\0"
+      "456",
+      7);
+  absl::string_view g("xx not found bb");
+
+  d = absl::string_view();
+  EXPECT_EQ(a.find_first_of(b), 0);
+  EXPECT_EQ(a.find_first_of(b, 0), 0);
+  EXPECT_EQ(a.find_first_of(b, 1), 1);
+  EXPECT_EQ(a.find_first_of(b, 2), 2);
+  EXPECT_EQ(a.find_first_of(b, 3), absl::string_view::npos);
+  EXPECT_EQ(a.find_first_of(c), 23);
+  EXPECT_EQ(a.find_first_of(c, 23), 23);
+  EXPECT_EQ(a.find_first_of(c, 24), 24);
+  EXPECT_EQ(a.find_first_of(c, 25), 25);
+  EXPECT_EQ(a.find_first_of(c, 26), absl::string_view::npos);
+  EXPECT_EQ(g.find_first_of(b), 13);
+  EXPECT_EQ(g.find_first_of(c), 0);
+  EXPECT_EQ(a.find_first_of(f), absl::string_view::npos);
+  EXPECT_EQ(f.find_first_of(a), absl::string_view::npos);
+  // empty std::string nonsense
+  EXPECT_EQ(a.find_first_of(d), absl::string_view::npos);
+  EXPECT_EQ(a.find_first_of(e), absl::string_view::npos);
+  EXPECT_EQ(d.find_first_of(b), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_of(b), absl::string_view::npos);
+  EXPECT_EQ(d.find_first_of(d), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_of(d), absl::string_view::npos);
+  EXPECT_EQ(d.find_first_of(e), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_of(e), absl::string_view::npos);
+
+  EXPECT_EQ(a.find_first_not_of(b), 3);
+  EXPECT_EQ(a.find_first_not_of(c), 0);
+  EXPECT_EQ(b.find_first_not_of(a), absl::string_view::npos);
+  EXPECT_EQ(c.find_first_not_of(a), absl::string_view::npos);
+  EXPECT_EQ(f.find_first_not_of(a), 0);
+  EXPECT_EQ(a.find_first_not_of(f), 0);
+  EXPECT_EQ(a.find_first_not_of(d), 0);
+  EXPECT_EQ(a.find_first_not_of(e), 0);
+  // empty std::string nonsense
+  EXPECT_EQ(a.find_first_not_of(d), 0);
+  EXPECT_EQ(a.find_first_not_of(e), 0);
+  EXPECT_EQ(a.find_first_not_of(d, 1), 1);
+  EXPECT_EQ(a.find_first_not_of(e, 1), 1);
+  EXPECT_EQ(a.find_first_not_of(d, a.size() - 1), a.size() - 1);
+  EXPECT_EQ(a.find_first_not_of(e, a.size() - 1), a.size() - 1);
+  EXPECT_EQ(a.find_first_not_of(d, a.size()), absl::string_view::npos);
+  EXPECT_EQ(a.find_first_not_of(e, a.size()), absl::string_view::npos);
+  EXPECT_EQ(a.find_first_not_of(d, absl::string_view::npos),
+            absl::string_view::npos);
+  EXPECT_EQ(a.find_first_not_of(e, absl::string_view::npos),
+            absl::string_view::npos);
+  EXPECT_EQ(d.find_first_not_of(a), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_not_of(a), absl::string_view::npos);
+  EXPECT_EQ(d.find_first_not_of(d), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_not_of(d), absl::string_view::npos);
+  EXPECT_EQ(d.find_first_not_of(e), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_not_of(e), absl::string_view::npos);
+
+  absl::string_view h("====");
+  EXPECT_EQ(h.find_first_not_of('='), absl::string_view::npos);
+  EXPECT_EQ(h.find_first_not_of('=', 3), absl::string_view::npos);
+  EXPECT_EQ(h.find_first_not_of('\0'), 0);
+  EXPECT_EQ(g.find_first_not_of('x'), 2);
+  EXPECT_EQ(f.find_first_not_of('\0'), 0);
+  EXPECT_EQ(f.find_first_not_of('\0', 3), 4);
+  EXPECT_EQ(f.find_first_not_of('\0', 2), 2);
+  // empty std::string nonsense
+  EXPECT_EQ(d.find_first_not_of('x'), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_not_of('x'), absl::string_view::npos);
+  EXPECT_EQ(d.find_first_not_of('\0'), absl::string_view::npos);
+  EXPECT_EQ(e.find_first_not_of('\0'), absl::string_view::npos);
+}
+
+// Continued from STL2
+TEST(StringViewTest, STL2FindLast) {
+  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+  const absl::string_view b("abc");
+  const absl::string_view c("xyz");
+  absl::string_view d("foobar");
+  const absl::string_view e;
+  const absl::string_view f(
+      "123"
+      "\0"
+      "456",
+      7);
+  absl::string_view g("xx not found bb");
+  absl::string_view h("====");
+  absl::string_view i("56");
+
+  d = absl::string_view();
+  EXPECT_EQ(h.find_last_of(a), absl::string_view::npos);
+  EXPECT_EQ(g.find_last_of(a), g.size()-1);
+  EXPECT_EQ(a.find_last_of(b), 2);
+  EXPECT_EQ(a.find_last_of(c), a.size()-1);
+  EXPECT_EQ(f.find_last_of(i), 6);
+  EXPECT_EQ(a.find_last_of('a'), 0);
+  EXPECT_EQ(a.find_last_of('b'), 1);
+  EXPECT_EQ(a.find_last_of('z'), 25);
+  EXPECT_EQ(a.find_last_of('a', 5), 0);
+  EXPECT_EQ(a.find_last_of('b', 5), 1);
+  EXPECT_EQ(a.find_last_of('b', 0), absl::string_view::npos);
+  EXPECT_EQ(a.find_last_of('z', 25), 25);
+  EXPECT_EQ(a.find_last_of('z', 24), absl::string_view::npos);
+  EXPECT_EQ(f.find_last_of(i, 5), 5);
+  EXPECT_EQ(f.find_last_of(i, 6), 6);
+  EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos);
+  // empty std::string nonsense
+  EXPECT_EQ(f.find_last_of(d), absl::string_view::npos);
+  EXPECT_EQ(f.find_last_of(e), absl::string_view::npos);
+  EXPECT_EQ(f.find_last_of(d, 4), absl::string_view::npos);
+  EXPECT_EQ(f.find_last_of(e, 4), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_of(d), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_of(e), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_of(d), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_of(e), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_of(f), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_of(f), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_of(d, 4), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_of(e, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_of(d, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_of(e, 4), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_of(f, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_of(f, 4), absl::string_view::npos);
+
+  EXPECT_EQ(a.find_last_not_of(b), a.size()-1);
+  EXPECT_EQ(a.find_last_not_of(c), 22);
+  EXPECT_EQ(b.find_last_not_of(a), absl::string_view::npos);
+  EXPECT_EQ(b.find_last_not_of(b), absl::string_view::npos);
+  EXPECT_EQ(f.find_last_not_of(i), 4);
+  EXPECT_EQ(a.find_last_not_of(c, 24), 22);
+  EXPECT_EQ(a.find_last_not_of(b, 3), 3);
+  EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos);
+  // empty std::string nonsense
+  EXPECT_EQ(f.find_last_not_of(d), f.size()-1);
+  EXPECT_EQ(f.find_last_not_of(e), f.size()-1);
+  EXPECT_EQ(f.find_last_not_of(d, 4), 4);
+  EXPECT_EQ(f.find_last_not_of(e, 4), 4);
+  EXPECT_EQ(d.find_last_not_of(d), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_not_of(e), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of(d), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of(e), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_not_of(f), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of(f), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_not_of(d, 4), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_not_of(e, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of(d, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of(e, 4), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_not_of(f, 4), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of(f, 4), absl::string_view::npos);
+
+  EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1);
+  EXPECT_EQ(h.find_last_not_of('='), absl::string_view::npos);
+  EXPECT_EQ(b.find_last_not_of('c'), 1);
+  EXPECT_EQ(h.find_last_not_of('x', 2), 2);
+  EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos);
+  EXPECT_EQ(b.find_last_not_of('b', 1), 0);
+  // empty std::string nonsense
+  EXPECT_EQ(d.find_last_not_of('x'), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of('x'), absl::string_view::npos);
+  EXPECT_EQ(d.find_last_not_of('\0'), absl::string_view::npos);
+  EXPECT_EQ(e.find_last_not_of('\0'), absl::string_view::npos);
+}
+
+// Continued from STL2
+TEST(StringViewTest, STL2Substr) {
+  const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+  const absl::string_view b("abc");
+  const absl::string_view c("xyz");
+  absl::string_view d("foobar");
+  const absl::string_view e;
+
+  d = absl::string_view();
+  EXPECT_EQ(a.substr(0, 3), b);
+  EXPECT_EQ(a.substr(23), c);
+  EXPECT_EQ(a.substr(23, 3), c);
+  EXPECT_EQ(a.substr(23, 99), c);
+  EXPECT_EQ(a.substr(0), a);
+  EXPECT_EQ(a.substr(3, 2), "de");
+  // empty std::string nonsense
+  EXPECT_EQ(d.substr(0, 99), e);
+  // use of npos
+  EXPECT_EQ(a.substr(0, absl::string_view::npos), a);
+  EXPECT_EQ(a.substr(23, absl::string_view::npos), c);
+  // throw exception
+#ifdef ABSL_HAVE_EXCEPTIONS
+  EXPECT_THROW(a.substr(99, 2), std::out_of_range);
+#else
+  EXPECT_DEATH(a.substr(99, 2), "absl::string_view::substr");
+#endif
+}
+
+TEST(StringViewTest, TruncSubstr) {
+  const absl::string_view hi("hi");
+  EXPECT_EQ("", absl::ClippedSubstr(hi, 0, 0));
+  EXPECT_EQ("h", absl::ClippedSubstr(hi, 0, 1));
+  EXPECT_EQ("hi", absl::ClippedSubstr(hi, 0));
+  EXPECT_EQ("i", absl::ClippedSubstr(hi, 1));
+  EXPECT_EQ("", absl::ClippedSubstr(hi, 2));
+  EXPECT_EQ("", absl::ClippedSubstr(hi, 3));  // truncation
+  EXPECT_EQ("", absl::ClippedSubstr(hi, 3, 2));  // truncation
+}
+
+TEST(StringViewTest, UTF8) {
+  std::string utf8 = "\u00E1";
+  std::string utf8_twice = utf8 + " " + utf8;
+  int utf8_len = strlen(utf8.data());
+  EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" "));
+  EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" \t"));
+}
+
+TEST(StringViewTest, FindConformance) {
+  struct {
+    std::string haystack;
+    std::string needle;
+  } specs[] = {
+    {"", ""},
+    {"", "a"},
+    {"a", ""},
+    {"a", "a"},
+    {"a", "b"},
+    {"aa", ""},
+    {"aa", "a"},
+    {"aa", "b"},
+    {"ab", "a"},
+    {"ab", "b"},
+    {"abcd", ""},
+    {"abcd", "a"},
+    {"abcd", "d"},
+    {"abcd", "ab"},
+    {"abcd", "bc"},
+    {"abcd", "cd"},
+    {"abcd", "abcd"},
+  };
+  for (const auto& s : specs) {
+    SCOPED_TRACE(s.haystack);
+    SCOPED_TRACE(s.needle);
+    std::string st = s.haystack;
+    absl::string_view sp = s.haystack;
+    for (size_t i = 0; i <= sp.size(); ++i) {
+      size_t pos = (i == sp.size()) ? absl::string_view::npos : i;
+      SCOPED_TRACE(pos);
+      EXPECT_EQ(sp.find(s.needle, pos),
+                st.find(s.needle, pos));
+      EXPECT_EQ(sp.rfind(s.needle, pos),
+                st.rfind(s.needle, pos));
+      EXPECT_EQ(sp.find_first_of(s.needle, pos),
+                st.find_first_of(s.needle, pos));
+      EXPECT_EQ(sp.find_first_not_of(s.needle, pos),
+                st.find_first_not_of(s.needle, pos));
+      EXPECT_EQ(sp.find_last_of(s.needle, pos),
+                st.find_last_of(s.needle, pos));
+      EXPECT_EQ(sp.find_last_not_of(s.needle, pos),
+                st.find_last_not_of(s.needle, pos));
+    }
+  }
+}
+
+TEST(StringViewTest, Remove) {
+  absl::string_view a("foobar");
+  std::string s1("123");
+  s1 += '\0';
+  s1 += "456";
+  absl::string_view b(s1);
+  absl::string_view e;
+  std::string s2;
+
+  // remove_prefix
+  absl::string_view c(a);
+  c.remove_prefix(3);
+  EXPECT_EQ(c, "bar");
+  c = a;
+  c.remove_prefix(0);
+  EXPECT_EQ(c, a);
+  c.remove_prefix(c.size());
+  EXPECT_EQ(c, e);
+
+  // remove_suffix
+  c = a;
+  c.remove_suffix(3);
+  EXPECT_EQ(c, "foo");
+  c = a;
+  c.remove_suffix(0);
+  EXPECT_EQ(c, a);
+  c.remove_suffix(c.size());
+  EXPECT_EQ(c, e);
+}
+
+TEST(StringViewTest, Set) {
+  absl::string_view a("foobar");
+  absl::string_view empty;
+  absl::string_view b;
+
+  // set
+  b = absl::string_view("foobar", 6);
+  EXPECT_EQ(b, a);
+  b = absl::string_view("foobar", 0);
+  EXPECT_EQ(b, empty);
+  b = absl::string_view("foobar", 7);
+  EXPECT_NE(b, a);
+
+  b = absl::string_view("foobar");
+  EXPECT_EQ(b, a);
+}
+
+TEST(StringViewTest, FrontBack) {
+  static const char arr[] = "abcd";
+  const absl::string_view csp(arr, 4);
+  EXPECT_EQ(&arr[0], &csp.front());
+  EXPECT_EQ(&arr[3], &csp.back());
+}
+
+TEST(StringViewTest, FrontBackSingleChar) {
+  static const char c = 'a';
+  const absl::string_view csp(&c, 1);
+  EXPECT_EQ(&c, &csp.front());
+  EXPECT_EQ(&c, &csp.back());
+}
+
+// `std::string_view::string_view(const char*)` calls
+// `std::char_traits<char>::length(const char*)` to get the std::string length. In
+// libc++, it doesn't allow `nullptr` in the constexpr context, with the error
+// "read of dereferenced null pointer is not allowed in a constant expression".
+// At run time, the behavior of `std::char_traits::length()` on `nullptr` is
+// undefined by the standard and usually results in crash with libc++. This
+// conforms to the standard, but `absl::string_view` implements a different
+// behavior for historical reasons. We work around tests that construct
+// `string_view` from `nullptr` when using libc++.
+#if !defined(ABSL_HAVE_STD_STRING_VIEW) || !defined(_LIBCPP_VERSION)
+#define ABSL_HAVE_STRING_VIEW_FROM_NULLPTR 1
+#endif  // !defined(ABSL_HAVE_STD_STRING_VIEW) || !defined(_LIBCPP_VERSION)
+
+TEST(StringViewTest, NULLInput) {
+  absl::string_view s;
+  EXPECT_EQ(s.data(), nullptr);
+  EXPECT_EQ(s.size(), 0);
+
+#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
+  s = absl::string_view(nullptr);
+  EXPECT_EQ(s.data(), nullptr);
+  EXPECT_EQ(s.size(), 0);
+
+  // .ToString() on a absl::string_view with nullptr should produce the empty
+  // std::string.
+  EXPECT_EQ("", std::string(s));
+#endif  // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
+}
+
+TEST(StringViewTest, Comparisons2) {
+  // The `compare` member has 6 overloads (v: string_view, s: const char*):
+  //  (1) compare(v)
+  //  (2) compare(pos1, count1, v)
+  //  (3) compare(pos1, count1, v, pos2, count2)
+  //  (4) compare(s)
+  //  (5) compare(pos1, count1, s)
+  //  (6) compare(pos1, count1, s, count2)
+
+  absl::string_view abc("abcdefghijklmnopqrstuvwxyz");
+
+  // check comparison operations on strings longer than 4 bytes.
+  EXPECT_EQ(abc, absl::string_view("abcdefghijklmnopqrstuvwxyz"));
+  EXPECT_EQ(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyz")), 0);
+
+  EXPECT_LT(abc, absl::string_view("abcdefghijklmnopqrstuvwxzz"));
+  EXPECT_LT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxzz")), 0);
+
+  EXPECT_GT(abc, absl::string_view("abcdefghijklmnopqrstuvwxyy"));
+  EXPECT_GT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyy")), 0);
+
+  // The "substr" variants of `compare`.
+  absl::string_view digits("0123456789");
+  auto npos = absl::string_view::npos;
+
+  // Taking string_view
+  EXPECT_EQ(digits.compare(3, npos, absl::string_view("3456789")), 0);  // 2
+  EXPECT_EQ(digits.compare(3, 4, absl::string_view("3456")), 0);        // 2
+  EXPECT_EQ(digits.compare(10, 0, absl::string_view()), 0);             // 2
+  EXPECT_EQ(digits.compare(3, 4, absl::string_view("0123456789"), 3, 4),
+            0);  // 3
+  EXPECT_LT(digits.compare(3, 4, absl::string_view("0123456789"), 3, 5),
+            0);  // 3
+  EXPECT_LT(digits.compare(0, npos, absl::string_view("0123456789"), 3, 5),
+            0);  // 3
+  // Taking const char*
+  EXPECT_EQ(digits.compare(3, 4, "3456"), 0);                 // 5
+  EXPECT_EQ(digits.compare(3, npos, "3456789"), 0);           // 5
+  EXPECT_EQ(digits.compare(10, 0, ""), 0);                    // 5
+  EXPECT_EQ(digits.compare(3, 4, "0123456789", 3, 4), 0);     // 6
+  EXPECT_LT(digits.compare(3, 4, "0123456789", 3, 5), 0);     // 6
+  EXPECT_LT(digits.compare(0, npos, "0123456789", 3, 5), 0);  // 6
+}
+
+struct MyCharAlloc : std::allocator<char> {};
+
+TEST(StringViewTest, ExplicitConversionOperator) {
+  absl::string_view sp = "hi";
+  EXPECT_EQ(sp, std::string(sp));
+}
+
+TEST(StringViewTest, NullSafeStringView) {
+  {
+    absl::string_view s = absl::NullSafeStringView(nullptr);
+    EXPECT_EQ(nullptr, s.data());
+    EXPECT_EQ(0, s.size());
+    EXPECT_EQ(absl::string_view(), s);
+  }
+  {
+    static const char kHi[] = "hi";
+    absl::string_view s = absl::NullSafeStringView(kHi);
+    EXPECT_EQ(kHi, s.data());
+    EXPECT_EQ(strlen(kHi), s.size());
+    EXPECT_EQ(absl::string_view("hi"), s);
+  }
+}
+
+TEST(StringViewTest, ConstexprCompiles) {
+  constexpr absl::string_view sp;
+#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
+  constexpr absl::string_view cstr(nullptr);
+#endif
+  constexpr absl::string_view cstr_len("cstr", 4);
+
+#if defined(ABSL_HAVE_STD_STRING_VIEW)
+  // In libstdc++ (as of 7.2), `std::string_view::string_view(const char*)`
+  // calls `std::char_traits<char>::length(const char*)` to get the std::string
+  // length, but it is not marked constexpr yet. See GCC bug:
+  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78156
+  // Also, there is a LWG issue that adds constexpr to length() which was just
+  // resolved 2017-06-02. See
+  // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2232
+  // TODO(zhangxy): Update the condition when libstdc++ adopts the constexpr
+  // length().
+#if !defined(__GLIBCXX__)
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
+#endif  // !__GLIBCXX__
+
+#else  // ABSL_HAVE_STD_STRING_VIEW
+
+// This duplicates the check for __builtin_strlen in the header.
+#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
+#elif defined(__GNUC__)  // GCC or clang
+#error GCC/clang should have constexpr string_view.
+#endif
+
+#endif  // ABSL_HAVE_STD_STRING_VIEW
+
+#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR
+  constexpr absl::string_view cstr_strlen("foo");
+  EXPECT_EQ(cstr_strlen.length(), 3);
+  constexpr absl::string_view cstr_strlen2 = "bar";
+  EXPECT_EQ(cstr_strlen2, "bar");
+#endif
+
+#if !defined(__clang__) || 3 < __clang_major__ || \
+  (3 == __clang_major__ && 4 < __clang_minor__)
+  // older clang versions (< 3.5) complain that:
+  //   "cannot perform pointer arithmetic on null pointer"
+  constexpr absl::string_view::iterator const_begin_empty = sp.begin();
+  constexpr absl::string_view::iterator const_end_empty = sp.end();
+  EXPECT_EQ(const_begin_empty, const_end_empty);
+
+#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
+  constexpr absl::string_view::iterator const_begin_nullptr = cstr.begin();
+  constexpr absl::string_view::iterator const_end_nullptr = cstr.end();
+  EXPECT_EQ(const_begin_nullptr, const_end_nullptr);
+#endif  // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
+#endif  // !defined(__clang__) || ...
+
+  constexpr absl::string_view::iterator const_begin = cstr_len.begin();
+  constexpr absl::string_view::iterator const_end = cstr_len.end();
+  constexpr absl::string_view::size_type const_size = cstr_len.size();
+  constexpr absl::string_view::size_type const_length = cstr_len.length();
+  EXPECT_EQ(const_begin + const_size, const_end);
+  EXPECT_EQ(const_begin + const_length, const_end);
+
+  constexpr bool isempty = sp.empty();
+  EXPECT_TRUE(isempty);
+
+  constexpr const char c = cstr_len[2];
+  EXPECT_EQ(c, 't');
+
+  constexpr const char cfront = cstr_len.front();
+  constexpr const char cback = cstr_len.back();
+  EXPECT_EQ(cfront, 'c');
+  EXPECT_EQ(cback, 'r');
+
+  constexpr const char* np = sp.data();
+  constexpr const char* cstr_ptr = cstr_len.data();
+  EXPECT_EQ(np, nullptr);
+  EXPECT_NE(cstr_ptr, nullptr);
+
+  constexpr size_t sp_npos = sp.npos;
+  EXPECT_EQ(sp_npos, -1);
+}
+
+TEST(StringViewTest, Noexcept) {
+  EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
+                                             const std::string&>::value));
+  EXPECT_TRUE(
+      (std::is_nothrow_constructible<absl::string_view, const std::string&>::value));
+  EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value);
+  constexpr absl::string_view sp;
+  EXPECT_TRUE(noexcept(sp.begin()));
+  EXPECT_TRUE(noexcept(sp.end()));
+  EXPECT_TRUE(noexcept(sp.cbegin()));
+  EXPECT_TRUE(noexcept(sp.cend()));
+  EXPECT_TRUE(noexcept(sp.rbegin()));
+  EXPECT_TRUE(noexcept(sp.rend()));
+  EXPECT_TRUE(noexcept(sp.crbegin()));
+  EXPECT_TRUE(noexcept(sp.crend()));
+  EXPECT_TRUE(noexcept(sp.size()));
+  EXPECT_TRUE(noexcept(sp.length()));
+  EXPECT_TRUE(noexcept(sp.empty()));
+  EXPECT_TRUE(noexcept(sp.data()));
+  EXPECT_TRUE(noexcept(sp.compare(sp)));
+  EXPECT_TRUE(noexcept(sp.find(sp)));
+  EXPECT_TRUE(noexcept(sp.find('f')));
+  EXPECT_TRUE(noexcept(sp.rfind(sp)));
+  EXPECT_TRUE(noexcept(sp.rfind('f')));
+  EXPECT_TRUE(noexcept(sp.find_first_of(sp)));
+  EXPECT_TRUE(noexcept(sp.find_first_of('f')));
+  EXPECT_TRUE(noexcept(sp.find_last_of(sp)));
+  EXPECT_TRUE(noexcept(sp.find_last_of('f')));
+  EXPECT_TRUE(noexcept(sp.find_first_not_of(sp)));
+  EXPECT_TRUE(noexcept(sp.find_first_not_of('f')));
+  EXPECT_TRUE(noexcept(sp.find_last_not_of(sp)));
+  EXPECT_TRUE(noexcept(sp.find_last_not_of('f')));
+}
+
+TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
+  EXPECT_EQ("hello", std::string("hello"));
+  EXPECT_LT("hello", std::string("world"));
+}
+
+TEST(ComparisonOpsTest, HeterogenousStringViewEquals) {
+  EXPECT_EQ(absl::string_view("hello"), std::string("hello"));
+  EXPECT_EQ("hello", absl::string_view("hello"));
+}
+
+TEST(FindOneCharTest, EdgeCases) {
+  absl::string_view a("xxyyyxx");
+
+  // Set a = "xyyyx".
+  a.remove_prefix(1);
+  a.remove_suffix(1);
+
+  EXPECT_EQ(0, a.find('x'));
+  EXPECT_EQ(0, a.find('x', 0));
+  EXPECT_EQ(4, a.find('x', 1));
+  EXPECT_EQ(4, a.find('x', 4));
+  EXPECT_EQ(absl::string_view::npos, a.find('x', 5));
+
+  EXPECT_EQ(4, a.rfind('x'));
+  EXPECT_EQ(4, a.rfind('x', 5));
+  EXPECT_EQ(4, a.rfind('x', 4));
+  EXPECT_EQ(0, a.rfind('x', 3));
+  EXPECT_EQ(0, a.rfind('x', 0));
+
+  // Set a = "yyy".
+  a.remove_prefix(1);
+  a.remove_suffix(1);
+
+  EXPECT_EQ(absl::string_view::npos, a.find('x'));
+  EXPECT_EQ(absl::string_view::npos, a.rfind('x'));
+}
+
+#ifndef THREAD_SANITIZER  // Allocates too much memory for tsan.
+TEST(HugeStringView, TwoPointTwoGB) {
+  if (sizeof(size_t) <= 4 || AbslRunningOnValgrind())
+    return;
+  // Try a huge std::string piece.
+  const size_t size = size_t{2200} * 1000 * 1000;
+  std::string s(size, 'a');
+  absl::string_view sp(s);
+  EXPECT_EQ(size, sp.length());
+  sp.remove_prefix(1);
+  EXPECT_EQ(size - 1, sp.length());
+  sp.remove_suffix(2);
+  EXPECT_EQ(size - 1 - 2, sp.length());
+}
+#endif  // THREAD_SANITIZER
+
+#if !defined(NDEBUG) && !defined(ABSL_HAVE_STD_STRING_VIEW)
+TEST(NonNegativeLenTest, NonNegativeLen) {
+  ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("xyz", -1),
+                                 "len <= kMaxSize");
+}
+
+TEST(LenExceedsMaxSizeTest, LenExceedsMaxSize) {
+  auto max_size = absl::string_view().max_size();
+
+  // This should construct ok (although the view itself is obviously invalid).
+  absl::string_view ok_view("", max_size);
+
+  // Adding one to the max should trigger an assertion.
+  ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("", max_size + 1),
+                                 "len <= kMaxSize");
+}
+#endif  // !defined(NDEBUG) && !defined(ABSL_HAVE_STD_STRING_VIEW)
+
+class StringViewStreamTest : public ::testing::Test {
+ public:
+  // Set negative 'width' for right justification.
+  template <typename T>
+  std::string Pad(const T& s, int width, char fill = 0) {
+    std::ostringstream oss;
+    if (fill != 0) {
+      oss << std::setfill(fill);
+    }
+    if (width < 0) {
+      width = -width;
+      oss << std::right;
+    }
+    oss << std::setw(width) << s;
+    return oss.str();
+  }
+};
+
+TEST_F(StringViewStreamTest, Padding) {
+  std::string s("hello");
+  absl::string_view sp(s);
+  for (int w = -64; w < 64; ++w) {
+    SCOPED_TRACE(w);
+    EXPECT_EQ(Pad(s, w), Pad(sp, w));
+  }
+  for (int w = -64; w < 64; ++w) {
+    SCOPED_TRACE(w);
+    EXPECT_EQ(Pad(s, w, '#'), Pad(sp, w, '#'));
+  }
+}
+
+TEST_F(StringViewStreamTest, ResetsWidth) {
+  // Width should reset after one formatted write.
+  // If we weren't resetting width after formatting the string_view,
+  // we'd have width=5 carrying over to the printing of the "]",
+  // creating "[###hi####]".
+  std::string s = "hi";
+  absl::string_view sp = s;
+  {
+    std::ostringstream oss;
+    oss << "[" << std::setfill('#') << std::setw(5) << s << "]";
+    ASSERT_EQ("[###hi]", oss.str());
+  }
+  {
+    std::ostringstream oss;
+    oss << "[" << std::setfill('#') << std::setw(5) << sp << "]";
+    EXPECT_EQ("[###hi]", oss.str());
+  }
+}
+
+}  // namespace
diff --git a/absl/strings/strip.h b/absl/strings/strip.h
new file mode 100644
index 0000000..2f8d21f
--- /dev/null
+++ b/absl/strings/strip.h
@@ -0,0 +1,89 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: strip.h
+// -----------------------------------------------------------------------------
+//
+// This file contains various functions for stripping substrings from a std::string.
+#ifndef ABSL_STRINGS_STRIP_H_
+#define ABSL_STRINGS_STRIP_H_
+
+#include <cstddef>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// ConsumePrefix()
+//
+// Strips the `expected` prefix from the start of the given std::string, returning
+// `true` if the strip operation succeeded or false otherwise.
+//
+// Example:
+//
+//   absl::string_view input("abc");
+//   EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
+//   EXPECT_EQ(input, "bc");
+inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) {
+  if (!absl::StartsWith(*str, expected)) return false;
+  str->remove_prefix(expected.size());
+  return true;
+}
+// ConsumeSuffix()
+//
+// Strips the `expected` suffix from the end of the given std::string, returning
+// `true` if the strip operation succeeded or false otherwise.
+//
+// Example:
+//
+//   absl::string_view input("abcdef");
+//   EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
+//   EXPECT_EQ(input, "abc");
+inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) {
+  if (!absl::EndsWith(*str, expected)) return false;
+  str->remove_suffix(expected.size());
+  return true;
+}
+
+// StripPrefix()
+//
+// Returns a view into the input std::string 'str' with the given 'prefix' removed,
+// but leaving the original std::string intact. If the prefix does not match at the
+// start of the std::string, returns the original std::string instead.
+ABSL_MUST_USE_RESULT inline absl::string_view StripPrefix(
+    absl::string_view str, absl::string_view prefix) {
+  if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size());
+  return str;
+}
+
+// StripSuffix()
+//
+// Returns a view into the input std::string 'str' with the given 'suffix' removed,
+// but leaving the original std::string intact. If the suffix does not match at the
+// end of the std::string, returns the original std::string instead.
+ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix(
+    absl::string_view str, absl::string_view suffix) {
+  if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size());
+  return str;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STRIP_H_
diff --git a/absl/strings/strip_test.cc b/absl/strings/strip_test.cc
new file mode 100644
index 0000000..205c160
--- /dev/null
+++ b/absl/strings/strip_test.cc
@@ -0,0 +1,201 @@
+// Copyright 2017 The Abseil 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.
+
+// This file contains functions that remove a defined part from the std::string,
+// i.e., strip the std::string.
+
+#include "absl/strings/strip.h"
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/string_view.h"
+
+namespace {
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+TEST(Strip, ConsumePrefixOneChar) {
+  absl::string_view input("abc");
+  EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
+  EXPECT_EQ(input, "bc");
+
+  EXPECT_FALSE(absl::ConsumePrefix(&input, "x"));
+  EXPECT_EQ(input, "bc");
+
+  EXPECT_TRUE(absl::ConsumePrefix(&input, "b"));
+  EXPECT_EQ(input, "c");
+
+  EXPECT_TRUE(absl::ConsumePrefix(&input, "c"));
+  EXPECT_EQ(input, "");
+
+  EXPECT_FALSE(absl::ConsumePrefix(&input, "a"));
+  EXPECT_EQ(input, "");
+}
+
+TEST(Strip, ConsumePrefix) {
+  absl::string_view input("abcdef");
+  EXPECT_FALSE(absl::ConsumePrefix(&input, "abcdefg"));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_FALSE(absl::ConsumePrefix(&input, "abce"));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_TRUE(absl::ConsumePrefix(&input, ""));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_FALSE(absl::ConsumePrefix(&input, "abcdeg"));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_TRUE(absl::ConsumePrefix(&input, "abcdef"));
+  EXPECT_EQ(input, "");
+
+  input = "abcdef";
+  EXPECT_TRUE(absl::ConsumePrefix(&input, "abcde"));
+  EXPECT_EQ(input, "f");
+}
+
+TEST(Strip, ConsumeSuffix) {
+  absl::string_view input("abcdef");
+  EXPECT_FALSE(absl::ConsumeSuffix(&input, "abcdefg"));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_TRUE(absl::ConsumeSuffix(&input, ""));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
+  EXPECT_EQ(input, "abc");
+
+  input = "abcdef";
+  EXPECT_FALSE(absl::ConsumeSuffix(&input, "abcdeg"));
+  EXPECT_EQ(input, "abcdef");
+
+  EXPECT_TRUE(absl::ConsumeSuffix(&input, "f"));
+  EXPECT_EQ(input, "abcde");
+
+  EXPECT_TRUE(absl::ConsumeSuffix(&input, "abcde"));
+  EXPECT_EQ(input, "");
+}
+
+TEST(Strip, StripPrefix) {
+  const absl::string_view null_str;
+
+  EXPECT_EQ(absl::StripPrefix("foobar", "foo"), "bar");
+  EXPECT_EQ(absl::StripPrefix("foobar", ""), "foobar");
+  EXPECT_EQ(absl::StripPrefix("foobar", null_str), "foobar");
+  EXPECT_EQ(absl::StripPrefix("foobar", "foobar"), "");
+  EXPECT_EQ(absl::StripPrefix("foobar", "bar"), "foobar");
+  EXPECT_EQ(absl::StripPrefix("foobar", "foobarr"), "foobar");
+  EXPECT_EQ(absl::StripPrefix("", ""), "");
+}
+
+TEST(Strip, StripSuffix) {
+  const absl::string_view null_str;
+
+  EXPECT_EQ(absl::StripSuffix("foobar", "bar"), "foo");
+  EXPECT_EQ(absl::StripSuffix("foobar", ""), "foobar");
+  EXPECT_EQ(absl::StripSuffix("foobar", null_str), "foobar");
+  EXPECT_EQ(absl::StripSuffix("foobar", "foobar"), "");
+  EXPECT_EQ(absl::StripSuffix("foobar", "foo"), "foobar");
+  EXPECT_EQ(absl::StripSuffix("foobar", "ffoobar"), "foobar");
+  EXPECT_EQ(absl::StripSuffix("", ""), "");
+}
+
+TEST(Strip, RemoveExtraAsciiWhitespace) {
+  const char* inputs[] = {
+      "No extra space",
+      "  Leading whitespace",
+      "Trailing whitespace  ",
+      "  Leading and trailing  ",
+      " Whitespace \t  in\v   middle  ",
+      "'Eeeeep!  \n Newlines!\n",
+      "nospaces",
+  };
+  const char* outputs[] = {
+      "No extra space",
+      "Leading whitespace",
+      "Trailing whitespace",
+      "Leading and trailing",
+      "Whitespace in middle",
+      "'Eeeeep! Newlines!",
+      "nospaces",
+  };
+  int NUM_TESTS = 7;
+
+  for (int i = 0; i < NUM_TESTS; i++) {
+    std::string s(inputs[i]);
+    absl::RemoveExtraAsciiWhitespace(&s);
+    EXPECT_STREQ(outputs[i], s.c_str());
+  }
+
+  // Test that absl::RemoveExtraAsciiWhitespace returns immediately for empty
+  // strings (It was adding the \0 character to the C++ std::string, which broke
+  // tests involving empty())
+  std::string zero_string = "";
+  assert(zero_string.empty());
+  absl::RemoveExtraAsciiWhitespace(&zero_string);
+  EXPECT_EQ(zero_string.size(), 0);
+  EXPECT_TRUE(zero_string.empty());
+}
+
+TEST(Strip, StripTrailingAsciiWhitespace) {
+  std::string test = "foo  ";
+  absl::StripTrailingAsciiWhitespace(&test);
+  EXPECT_EQ(test, "foo");
+
+  test = "   ";
+  absl::StripTrailingAsciiWhitespace(&test);
+  EXPECT_EQ(test, "");
+
+  test = "";
+  absl::StripTrailingAsciiWhitespace(&test);
+  EXPECT_EQ(test, "");
+
+  test = " abc\t";
+  absl::StripTrailingAsciiWhitespace(&test);
+  EXPECT_EQ(test, " abc");
+}
+
+TEST(String, StripLeadingAsciiWhitespace) {
+  absl::string_view orig = "\t  \n\f\r\n\vfoo";
+  EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace(orig));
+  orig = "\t  \n\f\r\v\n\t  \n\f\r\v\n";
+  EXPECT_EQ(absl::string_view(), absl::StripLeadingAsciiWhitespace(orig));
+}
+
+TEST(Strip, StripAsciiWhitespace) {
+  std::string test2 = "\t  \f\r\n\vfoo \t\f\r\v\n";
+  absl::StripAsciiWhitespace(&test2);
+  EXPECT_EQ(test2, "foo");
+  std::string test3 = "bar";
+  absl::StripAsciiWhitespace(&test3);
+  EXPECT_EQ(test3, "bar");
+  std::string test4 = "\t  \f\r\n\vfoo";
+  absl::StripAsciiWhitespace(&test4);
+  EXPECT_EQ(test4, "foo");
+  std::string test5 = "foo \t\f\r\v\n";
+  absl::StripAsciiWhitespace(&test5);
+  EXPECT_EQ(test5, "foo");
+  absl::string_view test6("\t  \f\r\n\vfoo \t\f\r\v\n");
+  test6 = absl::StripAsciiWhitespace(test6);
+  EXPECT_EQ(test6, "foo");
+  test6 = absl::StripAsciiWhitespace(test6);
+  EXPECT_EQ(test6, "foo");  // already stripped
+}
+
+}  // namespace
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
new file mode 100644
index 0000000..3b20059
--- /dev/null
+++ b/absl/strings/substitute.cc
@@ -0,0 +1,170 @@
+// Copyright 2017 The Abseil 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 "absl/strings/substitute.h"
+
+#include <algorithm>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace substitute_internal {
+
+void SubstituteAndAppendArray(std::string* output, absl::string_view format,
+                              const absl::string_view* args_array,
+                              size_t num_args) {
+  // Determine total size needed.
+  size_t size = 0;
+  for (size_t i = 0; i < format.size(); i++) {
+    if (format[i] == '$') {
+      if (i + 1 >= format.size()) {
+#ifndef NDEBUG
+        ABSL_RAW_LOG(FATAL,
+                     "Invalid strings::Substitute() format std::string: \"%s\".",
+                     absl::CEscape(format).c_str());
+#endif
+        return;
+      } else if (absl::ascii_isdigit(format[i + 1])) {
+        int index = format[i + 1] - '0';
+        if (static_cast<size_t>(index) >= num_args) {
+#ifndef NDEBUG
+          ABSL_RAW_LOG(
+              FATAL,
+              "Invalid strings::Substitute() format std::string: asked for \"$"
+              "%d\", but only %d args were given.  Full format std::string was: "
+              "\"%s\".",
+              index, static_cast<int>(num_args), absl::CEscape(format).c_str());
+#endif
+          return;
+        }
+        size += args_array[index].size();
+        ++i;  // Skip next char.
+      } else if (format[i + 1] == '$') {
+        ++size;
+        ++i;  // Skip next char.
+      } else {
+#ifndef NDEBUG
+        ABSL_RAW_LOG(FATAL,
+                     "Invalid strings::Substitute() format std::string: \"%s\".",
+                     absl::CEscape(format).c_str());
+#endif
+        return;
+      }
+    } else {
+      ++size;
+    }
+  }
+
+  if (size == 0) return;
+
+  // Build the std::string.
+  size_t original_size = output->size();
+  strings_internal::STLStringResizeUninitialized(output, original_size + size);
+  char* target = &(*output)[original_size];
+  for (size_t i = 0; i < format.size(); i++) {
+    if (format[i] == '$') {
+      if (absl::ascii_isdigit(format[i + 1])) {
+        const absl::string_view src = args_array[format[i + 1] - '0'];
+        target = std::copy(src.begin(), src.end(), target);
+        ++i;  // Skip next char.
+      } else if (format[i + 1] == '$') {
+        *target++ = '$';
+        ++i;  // Skip next char.
+      }
+    } else {
+      *target++ = format[i];
+    }
+  }
+
+  assert(target == output->data() + output->size());
+}
+
+static const char kHexDigits[] = "0123456789abcdef";
+Arg::Arg(const void* value) {
+  static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
+                "fix sizeof(scratch_)");
+  if (value == nullptr) {
+    piece_ = "NULL";
+  } else {
+    char* ptr = scratch_ + sizeof(scratch_);
+    uintptr_t num = reinterpret_cast<uintptr_t>(value);
+    do {
+      *--ptr = kHexDigits[num & 0xf];
+      num >>= 4;
+    } while (num != 0);
+    *--ptr = 'x';
+    *--ptr = '0';
+    piece_ = absl::string_view(ptr, scratch_ + sizeof(scratch_) - ptr);
+  }
+}
+
+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
+Arg::Arg(Hex hex) {
+  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
+  char* writer = end;
+  uint64_t value = hex.value;
+  do {
+    *--writer = kHexDigits[value & 0xF];
+    value >>= 4;
+  } while (value != 0);
+
+  char* beg;
+  if (end - writer < hex.width) {
+    beg = end - hex.width;
+    std::fill_n(beg, writer - beg, hex.fill);
+  } else {
+    beg = writer;
+  }
+
+  piece_ = absl::string_view(beg, end - beg);
+}
+
+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
+Arg::Arg(Dec dec) {
+  assert(dec.width <= numbers_internal::kFastToBufferSize);
+  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
+  char* const minfill = end - dec.width;
+  char* writer = end;
+  uint64_t value = dec.value;
+  bool neg = dec.neg;
+  while (value > 9) {
+    *--writer = '0' + (value % 10);
+    value /= 10;
+  }
+  *--writer = '0' + value;
+  if (neg) *--writer = '-';
+
+  ptrdiff_t fillers = writer - minfill;
+  if (fillers > 0) {
+    // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
+    // But...: if the fill character is '0', then it's <+/-><fill><digits>
+    bool add_sign_again = false;
+    if (neg && dec.fill == '0') {  // If filling with '0',
+      ++writer;                    // ignore the sign we just added
+      add_sign_again = true;       // and re-add the sign later.
+    }
+    writer -= fillers;
+    std::fill_n(writer, fillers, dec.fill);
+    if (add_sign_again) *--writer = '-';
+  }
+
+  piece_ = absl::string_view(writer, end - writer);
+}
+
+}  // namespace substitute_internal
+}  // namespace absl
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
new file mode 100644
index 0000000..c4b25ba
--- /dev/null
+++ b/absl/strings/substitute.h
@@ -0,0 +1,671 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: substitute.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for efficiently performing std::string
+// substitutions using a format std::string with positional notation:
+// `Substitute()` and `SubstituteAndAppend()`.
+//
+// Unlike printf-style format specifiers, `Substitute()` functions do not need
+// to specify the type of the substitution arguments. Supported arguments
+// following the format std::string, such as strings, string_views, ints,
+// floats, and bools, are automatically converted to strings during the
+// substitution process. (See below for a full list of supported types.)
+//
+// `Substitute()` does not allow you to specify *how* to format a value, beyond
+// the default conversion to std::string. For example, you cannot format an integer
+// in hex.
+//
+// The format std::string uses positional identifiers indicated by a dollar sign ($)
+// and single digit positional ids to indicate which substitution arguments to
+// use at that location within the format std::string.
+//
+// Example 1:
+//   std::string s = Substitute("$1 purchased $0 $2. Thanks $1!",
+//                         5, "Bob", "Apples");
+//   EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s);
+//
+// Example 2:
+//   std::string s = "Hi. ";
+//   SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
+//   EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
+//
+//
+// Supported types:
+//   * absl::string_view, std::string, const char* (null is equivalent to "")
+//   * int32_t, int64_t, uint32_t, uint64
+//   * float, double
+//   * bool (Printed as "true" or "false")
+//   * pointer types other than char* (Printed as "0x<lower case hex std::string>",
+//     except that null is printed as "NULL")
+//
+// If an invalid format std::string is provided, Substitute returns an empty std::string
+// and SubstituteAndAppend does not change the provided output std::string.
+// A format std::string is invalid if it:
+//   * ends in an unescaped $ character,
+//     e.g. "Hello $", or
+//   * calls for a position argument which is not provided,
+//     e.g. Substitute("Hello $2", "world"), or
+//   * specifies a non-digit, non-$ character after an unescaped $ character,
+//     e.g. "Hello $f".
+// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program.
+
+#ifndef ABSL_STRINGS_SUBSTITUTE_H_
+#define ABSL_STRINGS_SUBSTITUTE_H_
+
+#include <cstring>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace absl {
+namespace substitute_internal {
+
+// Arg
+//
+// This class provides an argument type for `absl::Substitute()` and
+// `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various
+// types to a std::string. (`Arg` is very similar to the `AlphaNum` class in
+// `StrCat()`.)
+//
+// This class has implicit constructors.
+class Arg {
+ public:
+  // Overloads for std::string-y things
+  //
+  // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
+  Arg(const char* value)  // NOLINT(runtime/explicit)
+      : piece_(absl::NullSafeStringView(value)) {}
+  template <typename Allocator>
+  Arg(  // NOLINT
+      const std::basic_string<char, std::char_traits<char>, Allocator>&
+          value) noexcept
+      : piece_(value) {}
+  Arg(absl::string_view value)  // NOLINT(runtime/explicit)
+      : piece_(value) {}
+
+  // Overloads for primitives
+  //
+  // No overloads are available for signed and unsigned char because if people
+  // are explicitly declaring their chars as signed or unsigned then they are
+  // probably using them as 8-bit integers and would probably prefer an integer
+  // representation. However, we can't really know, so we make the caller decide
+  // what to do.
+  Arg(char value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_, 1) { scratch_[0] = value; }
+  Arg(short value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned short value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(int value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned int value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(long long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned long long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(float value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
+  }
+  Arg(double value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
+  }
+  Arg(bool value)  // NOLINT(runtime/explicit)
+      : piece_(value ? "true" : "false") {}
+
+  Arg(Hex hex);  // NOLINT(runtime/explicit)
+  Arg(Dec dec);  // NOLINT(runtime/explicit)
+
+  // `void*` values, with the exception of `char*`, are printed as
+  // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
+  Arg(const void* value);  // NOLINT(runtime/explicit)
+
+  Arg(const Arg&) = delete;
+  Arg& operator=(const Arg&) = delete;
+
+  absl::string_view piece() const { return piece_; }
+
+ private:
+  absl::string_view piece_;
+  char scratch_[numbers_internal::kFastToBufferSize];
+};
+
+// Internal helper function. Don't call this from outside this implementation.
+// This interface may change without notice.
+void SubstituteAndAppendArray(std::string* output, absl::string_view format,
+                              const absl::string_view* args_array,
+                              size_t num_args);
+
+#if defined(ABSL_BAD_CALL_IF)
+constexpr int CalculateOneBit(const char* format) {
+  return (*format < '0' || *format > '9') ? 0 : (1 << (*format - '0'));
+}
+
+constexpr const char* SkipNumber(const char* format) {
+  return !*format ? format : (format + 1);
+}
+
+constexpr int PlaceholderBitmask(const char* format) {
+  return !*format ? 0 : *format != '$'
+                             ? PlaceholderBitmask(format + 1)
+                             : (CalculateOneBit(format + 1) |
+                                   PlaceholderBitmask(SkipNumber(format + 1)));
+}
+#endif  // ABSL_BAD_CALL_IF
+
+}  // namespace substitute_internal
+
+//
+// PUBLIC API
+//
+
+// SubstituteAndAppend()
+//
+// Substitutes variables into a given format std::string and appends to a given
+// output std::string. See file comments above for usage.
+//
+// The declarations of `SubstituteAndAppend()` below consist of overloads
+// for passing 0 to 10 arguments, respectively.
+//
+// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
+// templates to allow a variable number of arguments.
+//
+// Example:
+//  template <typename... Args>
+//  void VarMsg(std::string* boilerplate, absl::string_view format,
+//      const Args&... args) {
+//    absl::SubstituteAndAppend(boilerplate, format, args...);
+//  }
+//
+inline void SubstituteAndAppend(std::string* output, absl::string_view format) {
+  substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0) {
+  const absl::string_view args[] = {a0.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1) {
+  const absl::string_view args[] = {a0.piece(), a1.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3,
+                                const substitute_internal::Arg& a4) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3,
+                                const substitute_internal::Arg& a4,
+                                const substitute_internal::Arg& a5) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3,
+                                const substitute_internal::Arg& a4,
+                                const substitute_internal::Arg& a5,
+                                const substitute_internal::Arg& a6) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece(),
+                                    a6.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+    std::string* output, absl::string_view format,
+    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece(),
+                                    a6.piece(), a7.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+    std::string* output, absl::string_view format,
+    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
+    const substitute_internal::Arg& a8) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece(),
+                                    a6.piece(), a7.piece(), a8.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+    std::string* output, absl::string_view format,
+    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
+    const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
+  const absl::string_view args[] = {
+      a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
+      a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+#if defined(ABSL_BAD_CALL_IF)
+// This body of functions catches cases where the number of placeholders
+// doesn't match the number of data arguments.
+void SubstituteAndAppend(std::string* output, const char* format)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
+                     "There were no substitution arguments "
+                     "but this format std::string has a $[0-9] in it");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
+                     "There was 1 substitution argument given, but "
+                     "this format std::string is either missing its $0, or "
+                     "contains one of $1-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
+                     "There were 2 substitution arguments given, but "
+                     "this format std::string is either missing its $0/$1, or "
+                     "contains one of $2-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
+                     "There were 3 substitution arguments given, but "
+                     "this format std::string is either missing its $0/$1/$2, or "
+                     "contains one of $3-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2,
+                         const substitute_internal::Arg& a3)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
+                     "There were 4 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$3, or "
+                     "contains one of $4-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2,
+                         const substitute_internal::Arg& a3,
+                         const substitute_internal::Arg& a4)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
+                     "There were 5 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$4, or "
+                     "contains one of $5-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2,
+                         const substitute_internal::Arg& a3,
+                         const substitute_internal::Arg& a4,
+                         const substitute_internal::Arg& a5)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
+                     "There were 6 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$5, or "
+                     "contains one of $6-$9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
+                     "There were 7 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$6, or "
+                     "contains one of $7-$9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
+                     "There were 8 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$7, or "
+                     "contains one of $8-$9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
+    ABSL_BAD_CALL_IF(
+        substitute_internal::PlaceholderBitmask(format) != 511,
+        "There were 9 substitution arguments given, but "
+        "this format std::string is either missing its $0-$8, or contains a $9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+    const substitute_internal::Arg& a9)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
+                     "There were 10 substitution arguments given, but this "
+                     "format std::string doesn't contain all of $0 through $9");
+#endif  // ABSL_BAD_CALL_IF
+
+// Substitute()
+//
+// Substitutes variables into a given format std::string. See file comments above
+// for usage.
+//
+// The declarations of `Substitute()` below consist of overloads for passing 0
+// to 10 arguments, respectively.
+//
+// NOTE: A zero-argument `Substitute()` may be used within variadic templates to
+// allow a variable number of arguments.
+//
+// Example:
+//  template <typename... Args>
+//  void VarMsg(absl::string_view format, const Args&... args) {
+//    std::string s = absl::Substitute(format, args...);
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
+  std::string result;
+  SubstituteAndAppend(&result, format);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+    const substitute_internal::Arg& a9) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+  return result;
+}
+
+#if defined(ABSL_BAD_CALL_IF)
+// This body of functions catches cases where the number of placeholders
+// doesn't match the number of data arguments.
+std::string Substitute(const char* format)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
+                     "There were no substitution arguments "
+                     "but this format std::string has a $[0-9] in it");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
+                     "There was 1 substitution argument given, but "
+                     "this format std::string is either missing its $0, or "
+                     "contains one of $1-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
+                     "There were 2 substitution arguments given, but "
+                     "this format std::string is either missing its $0/$1, or "
+                     "contains one of $2-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1,
+                  const substitute_internal::Arg& a2)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
+                     "There were 3 substitution arguments given, but "
+                     "this format std::string is either missing its $0/$1/$2, or "
+                     "contains one of $3-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1,
+                  const substitute_internal::Arg& a2,
+                  const substitute_internal::Arg& a3)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
+                     "There were 4 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$3, or "
+                     "contains one of $4-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1,
+                  const substitute_internal::Arg& a2,
+                  const substitute_internal::Arg& a3,
+                  const substitute_internal::Arg& a4)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
+                     "There were 5 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$4, or "
+                     "contains one of $5-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1,
+                  const substitute_internal::Arg& a2,
+                  const substitute_internal::Arg& a3,
+                  const substitute_internal::Arg& a4,
+                  const substitute_internal::Arg& a5)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
+                     "There were 6 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$5, or "
+                     "contains one of $6-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1,
+                  const substitute_internal::Arg& a2,
+                  const substitute_internal::Arg& a3,
+                  const substitute_internal::Arg& a4,
+                  const substitute_internal::Arg& a5,
+                  const substitute_internal::Arg& a6)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
+                     "There were 7 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$6, or "
+                     "contains one of $7-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                  const substitute_internal::Arg& a1,
+                  const substitute_internal::Arg& a2,
+                  const substitute_internal::Arg& a3,
+                  const substitute_internal::Arg& a4,
+                  const substitute_internal::Arg& a5,
+                  const substitute_internal::Arg& a6,
+                  const substitute_internal::Arg& a7)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
+                     "There were 8 substitution arguments given, but "
+                     "this format std::string is either missing its $0-$7, or "
+                     "contains one of $8-$9");
+
+std::string Substitute(
+    const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
+    ABSL_BAD_CALL_IF(
+        substitute_internal::PlaceholderBitmask(format) != 511,
+        "There were 9 substitution arguments given, but "
+        "this format std::string is either missing its $0-$8, or contains a $9");
+
+std::string Substitute(
+    const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+    const substitute_internal::Arg& a9)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
+                     "There were 10 substitution arguments given, but this "
+                     "format std::string doesn't contain all of $0 through $9");
+#endif  // ABSL_BAD_CALL_IF
+
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_SUBSTITUTE_H_
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
new file mode 100644
index 0000000..144df01
--- /dev/null
+++ b/absl/strings/substitute_test.cc
@@ -0,0 +1,192 @@
+// Copyright 2017 The Abseil 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 "absl/strings/substitute.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+TEST(SubstituteTest, Substitute) {
+  // Basic.
+  EXPECT_EQ("Hello, world!", absl::Substitute("$0, $1!", "Hello", "world"));
+
+  // Non-char* types.
+  EXPECT_EQ("123 0.2 0.1 foo true false x",
+            absl::Substitute("$0 $1 $2 $3 $4 $5 $6", 123, 0.2, 0.1f,
+                             std::string("foo"), true, false, 'x'));
+
+  // All int types.
+  EXPECT_EQ(
+      "-32767 65535 "
+      "-1234567890 3234567890 "
+      "-1234567890 3234567890 "
+      "-1234567890123456789 9234567890123456789",
+      absl::Substitute(
+          "$0 $1 $2 $3 $4 $5 $6 $7",
+          static_cast<short>(-32767),          // NOLINT(runtime/int)
+          static_cast<unsigned short>(65535),  // NOLINT(runtime/int)
+          -1234567890, 3234567890U, -1234567890L, 3234567890UL,
+          -int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
+
+  // Hex format
+  EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef",
+            absl::Substitute("$0$1$2$3$4 $5",  //
+                             absl::Hex(0), absl::Hex(1, absl::kSpacePad2),
+                             absl::Hex(0xf, absl::kSpacePad2),
+                             absl::Hex(int16_t{-1}, absl::kSpacePad5),
+                             absl::Hex(int16_t{-1}, absl::kZeroPad5),
+                             absl::Hex(0x123456789abcdef, absl::kZeroPad16)));
+
+  // Dec format
+  EXPECT_EQ("0 115   -1-0001 81985529216486895",
+            absl::Substitute("$0$1$2$3$4 $5",  //
+                             absl::Dec(0), absl::Dec(1, absl::kSpacePad2),
+                             absl::Dec(0xf, absl::kSpacePad2),
+                             absl::Dec(int16_t{-1}, absl::kSpacePad5),
+                             absl::Dec(int16_t{-1}, absl::kZeroPad5),
+                             absl::Dec(0x123456789abcdef, absl::kZeroPad16)));
+
+  // Pointer.
+  const int* int_p = reinterpret_cast<const int*>(0x12345);
+  std::string str = absl::Substitute("$0", int_p);
+  EXPECT_EQ(absl::StrCat("0x", absl::Hex(int_p)), str);
+
+  // Volatile Pointer.
+  // Like C++ streamed I/O, such pointers implicitly become bool
+  volatile int vol = 237;
+  volatile int *volatile volptr = &vol;
+  str = absl::Substitute("$0", volptr);
+  EXPECT_EQ("true", str);
+
+  // null is special. StrCat prints 0x0. Substitute prints NULL.
+  const uint64_t* null_p = nullptr;
+  str = absl::Substitute("$0", null_p);
+  EXPECT_EQ("NULL", str);
+
+  // char* is also special.
+  const char* char_p = "print me";
+  str = absl::Substitute("$0", char_p);
+  EXPECT_EQ("print me", str);
+
+  char char_buf[16];
+  strncpy(char_buf, "print me too", sizeof(char_buf));
+  str = absl::Substitute("$0", char_buf);
+  EXPECT_EQ("print me too", str);
+
+  // null char* is "doubly" special. Represented as the empty std::string.
+  char_p = nullptr;
+  str = absl::Substitute("$0", char_p);
+  EXPECT_EQ("", str);
+
+  // Out-of-order.
+  EXPECT_EQ("b, a, c, b", absl::Substitute("$1, $0, $2, $1", "a", "b", "c"));
+
+  // Literal $
+  EXPECT_EQ("$", absl::Substitute("$$"));
+
+  EXPECT_EQ("$1", absl::Substitute("$$1"));
+
+  // Test all overloads.
+  EXPECT_EQ("a", absl::Substitute("$0", "a"));
+  EXPECT_EQ("a b", absl::Substitute("$0 $1", "a", "b"));
+  EXPECT_EQ("a b c", absl::Substitute("$0 $1 $2", "a", "b", "c"));
+  EXPECT_EQ("a b c d", absl::Substitute("$0 $1 $2 $3", "a", "b", "c", "d"));
+  EXPECT_EQ("a b c d e",
+            absl::Substitute("$0 $1 $2 $3 $4", "a", "b", "c", "d", "e"));
+  EXPECT_EQ("a b c d e f", absl::Substitute("$0 $1 $2 $3 $4 $5", "a", "b", "c",
+                                            "d", "e", "f"));
+  EXPECT_EQ("a b c d e f g", absl::Substitute("$0 $1 $2 $3 $4 $5 $6", "a", "b",
+                                              "c", "d", "e", "f", "g"));
+  EXPECT_EQ("a b c d e f g h",
+            absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d", "e",
+                             "f", "g", "h"));
+  EXPECT_EQ("a b c d e f g h i",
+            absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c", "d",
+                             "e", "f", "g", "h", "i"));
+  EXPECT_EQ("a b c d e f g h i j",
+            absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b", "c",
+                             "d", "e", "f", "g", "h", "i", "j"));
+  EXPECT_EQ("a b c d e f g h i j b0",
+            absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10", "a", "b", "c",
+                             "d", "e", "f", "g", "h", "i", "j"));
+
+  const char* null_cstring = nullptr;
+  EXPECT_EQ("Text: ''", absl::Substitute("Text: '$0'", null_cstring));
+}
+
+TEST(SubstituteTest, SubstituteAndAppend) {
+  std::string str = "Hello";
+  absl::SubstituteAndAppend(&str, ", $0!", "world");
+  EXPECT_EQ("Hello, world!", str);
+
+  // Test all overloads.
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0", "a");
+  EXPECT_EQ("a", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1", "a", "b");
+  EXPECT_EQ("a b", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2", "a", "b", "c");
+  EXPECT_EQ("a b c", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", "a", "b", "c", "d");
+  EXPECT_EQ("a b c d", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4", "a", "b", "c", "d", "e");
+  EXPECT_EQ("a b c d e", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5", "a", "b", "c", "d", "e",
+                            "f");
+  EXPECT_EQ("a b c d e f", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6", "a", "b", "c", "d",
+                            "e", "f", "g");
+  EXPECT_EQ("a b c d e f g", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d",
+                            "e", "f", "g", "h");
+  EXPECT_EQ("a b c d e f g h", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c",
+                            "d", "e", "f", "g", "h", "i");
+  EXPECT_EQ("a b c d e f g h i", str);
+  str.clear();
+  absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b",
+                            "c", "d", "e", "f", "g", "h", "i", "j");
+  EXPECT_EQ("a b c d e f g h i j", str);
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST(SubstituteDeathTest, SubstituteDeath) {
+  EXPECT_DEBUG_DEATH(
+      static_cast<void>(absl::Substitute(absl::string_view("-$2"), "a", "b")),
+      "Invalid strings::Substitute\\(\\) format std::string: asked for \"\\$2\", "
+      "but only 2 args were given.");
+  EXPECT_DEBUG_DEATH(
+      static_cast<void>(absl::Substitute("-$z-")),
+      "Invalid strings::Substitute\\(\\) format std::string: \"-\\$z-\"");
+  EXPECT_DEBUG_DEATH(
+      static_cast<void>(absl::Substitute("-$")),
+      "Invalid strings::Substitute\\(\\) format std::string: \"-\\$\"");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace
diff --git a/absl/strings/testdata/getline-1.txt b/absl/strings/testdata/getline-1.txt
new file mode 100644
index 0000000..19b9097
--- /dev/null
+++ b/absl/strings/testdata/getline-1.txt
@@ -0,0 +1,3 @@
+alpha
+
+beta gamma
diff --git a/absl/strings/testdata/getline-2.txt b/absl/strings/testdata/getline-2.txt
new file mode 100644
index 0000000..d6842d8
--- /dev/null
+++ b/absl/strings/testdata/getline-2.txt
@@ -0,0 +1 @@
+one.two.three
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
new file mode 100644
index 0000000..8d302e0
--- /dev/null
+++ b/absl/synchronization/BUILD.bazel
@@ -0,0 +1,234 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+# Internal data structure for efficiently detecting mutex dependency cycles
+cc_library(
+    name = "graphcycles_internal",
+    srcs = [
+        "internal/graphcycles.cc",
+    ],
+    hdrs = [
+        "internal/graphcycles.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        "//absl/base",
+        "//absl/base:base_internal",
+        "//absl/base:core_headers",
+        "//absl/base:malloc_internal",
+    ],
+)
+
+cc_library(
+    name = "synchronization",
+    srcs = [
+        "barrier.cc",
+        "blocking_counter.cc",
+        "internal/create_thread_identity.cc",
+        "internal/per_thread_sem.cc",
+        "internal/waiter.cc",
+        "notification.cc",
+    ] + select({
+        "//conditions:default": ["mutex.cc"],
+    }),
+    hdrs = [
+        "barrier.h",
+        "blocking_counter.h",
+        "internal/create_thread_identity.h",
+        "internal/kernel_timeout.h",
+        "internal/mutex_nonprod.inc",
+        "internal/per_thread_sem.h",
+        "internal/waiter.h",
+        "mutex.h",
+        "notification.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":graphcycles_internal",
+        "//absl/base",
+        "//absl/base:base_internal",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:dynamic_annotations",
+        "//absl/base:malloc_internal",
+        "//absl/debugging:stacktrace",
+        "//absl/debugging:symbolize",
+        "//absl/time",
+    ],
+)
+
+cc_test(
+    name = "barrier_test",
+    size = "small",
+    srcs = ["barrier_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":synchronization",
+        "//absl/time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "blocking_counter_test",
+    size = "small",
+    srcs = ["blocking_counter_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":synchronization",
+        "//absl/time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "graphcycles_test",
+    size = "medium",
+    srcs = ["internal/graphcycles_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":graphcycles_internal",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "graphcycles_benchmark",
+    srcs = ["internal/graphcycles_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = [
+        "benchmark",
+    ],
+    deps = [
+        ":graphcycles_internal",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
+    name = "thread_pool",
+    testonly = 1,
+    hdrs = ["internal/thread_pool.h"],
+    deps = [
+        ":synchronization",
+        "//absl/base:core_headers",
+    ],
+)
+
+cc_test(
+    name = "mutex_test",
+    size = "large",
+    srcs = ["mutex_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":synchronization",
+        ":thread_pool",
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "//absl/time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "mutex_benchmark",
+    srcs = ["mutex_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":synchronization",
+        ":thread_pool",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "notification_test",
+    size = "small",
+    srcs = ["notification_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":synchronization",
+        "//absl/time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "per_thread_sem_test_common",
+    testonly = 1,
+    srcs = ["internal/per_thread_sem_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":synchronization",
+        "//absl/base",
+        "//absl/strings",
+        "//absl/time",
+        "@com_google_googletest//:gtest",
+    ],
+    alwayslink = 1,
+)
+
+cc_test(
+    name = "per_thread_sem_test",
+    size = "medium",
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":per_thread_sem_test_common",
+        ":synchronization",
+        "//absl/base",
+        "//absl/strings",
+        "//absl/time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "lifetime_test",
+    srcs = [
+        "lifetime_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    linkopts = select({
+        "//absl:windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    tags = ["no_test_ios_x86_64"],
+    deps = [
+        ":synchronization",
+        "//absl/base",
+        "//absl/base:core_headers",
+    ],
+)
diff --git a/absl/synchronization/BUILD.gn b/absl/synchronization/BUILD.gn
new file mode 100644
index 0000000..3664aa1
--- /dev/null
+++ b/absl/synchronization/BUILD.gn
@@ -0,0 +1,116 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("graphcycles_internal") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/graphcycles.cc",
+  ]
+  public = [
+    "internal/graphcycles.h",
+  ]
+  deps = [
+    "../base",
+    "../base:base_internal",
+    "../base:core_headers",
+    "../base:malloc_internal",
+  ]
+  visibility = []
+  visibility += [ "../*" ]
+}
+
+source_set("synchronization") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "barrier.cc",
+    "blocking_counter.cc",
+    "internal/create_thread_identity.cc",
+    "internal/per_thread_sem.cc",
+    "internal/waiter.cc",
+    "notification.cc",
+    "mutex.cc"
+  ]
+  public = [
+    "barrier.h",
+    "blocking_counter.h",
+    "internal/create_thread_identity.h",
+    "internal/kernel_timeout.h",
+    "internal/mutex_nonprod.inc",
+    "internal/per_thread_sem.h",
+    "internal/waiter.h",
+    "mutex.h",
+    "notification.h",
+  ]
+  deps = [
+    ":graphcycles_internal",
+    "../base",
+    "../base:base_internal",
+    "../base:config",
+    "../base:core_headers",
+    "../base:dynamic_annotations",
+    "../base:malloc_internal",
+    "../debugging:stacktrace",
+    "../debugging:symbolize",
+    "../time",
+  ]
+}
+
+source_set("thread_pool") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "internal/thread_pool.h",
+  ]
+  deps = [
+    ":synchronization",
+    "../base:core_headers",
+  ]
+}
+
+source_set("per_thread_sem_test_common") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_test_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/per_thread_sem_test.cc",
+  ]
+  deps = [
+    ":synchronization",
+    "../base",
+    "../strings",
+    "../time",
+    "//testing/gtest",
+  ]
+}
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
new file mode 100644
index 0000000..c19f572
--- /dev/null
+++ b/absl/synchronization/CMakeLists.txt
@@ -0,0 +1,155 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS
+  "barrier.h"
+  "blocking_counter.h"
+  "mutex.h"
+  "notification.h"
+)
+
+
+list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS
+  "internal/create_thread_identity.h"
+  "internal/graphcycles.h"
+  "internal/kernel_timeout.h"
+  "internal/per_thread_sem.h"
+  "internal/thread_pool.h"
+  "internal/waiter.h"
+)
+
+
+
+# synchronization library
+list(APPEND SYNCHRONIZATION_SRC 
+  "barrier.cc"
+  "blocking_counter.cc"
+  "internal/create_thread_identity.cc"
+  "internal/per_thread_sem.cc"
+  "internal/waiter.cc"
+  "internal/graphcycles.cc"
+  "notification.cc"
+  "mutex.cc"
+)
+
+set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time)
+
+absl_library(
+  TARGET
+    absl_synchronization
+  SOURCES
+    ${SYNCHRONIZATION_SRC}
+  PUBLIC_LIBRARIES
+    ${SYNCHRONIZATION_PUBLIC_LIBRARIES}
+  EXPORT_NAME
+    synchronization
+)
+
+
+#
+## TESTS
+#
+
+
+# test barrier_test
+set(BARRIER_TEST_SRC "barrier_test.cc")
+set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization)
+
+absl_test(
+  TARGET
+    barrier_test
+  SOURCES
+    ${BARRIER_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${BARRIER_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test blocking_counter_test
+set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc")
+set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization)
+
+absl_test(
+  TARGET
+    blocking_counter_test
+  SOURCES
+    ${BLOCKING_COUNTER_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test graphcycles_test
+set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc")
+set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization)
+
+absl_test(
+  TARGET
+    graphcycles_test
+  SOURCES
+    ${GRAPHCYCLES_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test mutex_test
+set(MUTEX_TEST_SRC "mutex_test.cc")
+set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization)
+
+absl_test(
+  TARGET
+    mutex_test
+  SOURCES
+    ${MUTEX_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${MUTEX_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test notification_test
+set(NOTIFICATION_TEST_SRC "notification_test.cc")
+set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization)
+
+absl_test(
+  TARGET
+    notification_test
+  SOURCES
+    ${NOTIFICATION_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${NOTIFICATION_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test per_thread_sem_test_common
+set(PER_THREAD_SEM_TEST_COMMON_SRC "internal/per_thread_sem_test.cc")
+set(PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES absl::synchronization absl::strings)
+
+absl_test(
+  TARGET
+    per_thread_sem_test_common
+  SOURCES
+    ${PER_THREAD_SEM_TEST_COMMON_SRC}
+  PUBLIC_LIBRARIES
+    ${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES}
+)
+
+
+
+
+
+
+
diff --git a/absl/synchronization/barrier.cc b/absl/synchronization/barrier.cc
new file mode 100644
index 0000000..a1b3ad5
--- /dev/null
+++ b/absl/synchronization/barrier.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/barrier.h"
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// Return whether int *arg is zero.
+static bool IsZero(void *arg) {
+  return 0 == *reinterpret_cast<int *>(arg);
+}
+
+bool Barrier::Block() {
+  MutexLock l(&this->lock_);
+
+  this->num_to_block_--;
+  if (this->num_to_block_ < 0) {
+    ABSL_RAW_LOG(
+        FATAL,
+        "Block() called too many times.  num_to_block_=%d out of total=%d",
+        this->num_to_block_, this->num_to_exit_);
+  }
+
+  this->lock_.Await(Condition(IsZero, &this->num_to_block_));
+
+  // Determine which thread can safely delete this Barrier object
+  this->num_to_exit_--;
+  ABSL_RAW_CHECK(this->num_to_exit_ >= 0, "barrier underflow");
+
+  // If num_to_exit_ == 0 then all other threads in the barrier have
+  // exited the Wait() and have released the Mutex so this thread is
+  // free to delete the barrier.
+  return this->num_to_exit_ == 0;
+}
+
+}  // namespace absl
diff --git a/absl/synchronization/barrier.h b/absl/synchronization/barrier.h
new file mode 100644
index 0000000..f834fee
--- /dev/null
+++ b/absl/synchronization/barrier.h
@@ -0,0 +1,77 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// barrier.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_SYNCHRONIZATION_BARRIER_H_
+#define ABSL_SYNCHRONIZATION_BARRIER_H_
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// Barrier
+//
+// This class creates a barrier which blocks threads until a prespecified
+// threshold of threads (`num_threads`) utilizes the barrier. A thread utilizes
+// the `Barrier` by calling `Block()` on the barrier, which will block that
+// thread; no call to `Block()` will return until `num_threads` threads have
+// called it.
+//
+// Exactly one call to `Block()` will return `true`, which is then responsible
+// for destroying the barrier; because stack allocation will cause the barrier
+// to be deleted when it is out of scope, barriers should not be stack
+// allocated.
+//
+// Example:
+//
+//   // Main thread creates a `Barrier`:
+//   barrier = new Barrier(num_threads);
+//
+//   // Each participating thread could then call:
+//   if (barrier->Block()) delete barrier;  // Exactly one call to `Block()`
+//                                          // returns `true`; that call
+//                                          // deletes the barrier.
+class Barrier {
+ public:
+  // `num_threads` is the number of threads that will participate in the barrier
+  explicit Barrier(int num_threads)
+      : num_to_block_(num_threads), num_to_exit_(num_threads) {}
+
+  Barrier(const Barrier&) = delete;
+  Barrier& operator=(const Barrier&) = delete;
+
+  // Barrier::Block()
+  //
+  // Blocks the current thread, and returns only when the `num_threads`
+  // threshold of threads utilizing this barrier has been reached. `Block()`
+  // returns `true` for precisely one caller, which may then destroy the
+  // barrier.
+  //
+  // Memory ordering: For any threads X and Y, any action taken by X
+  // before X calls `Block()` will be visible to Y after Y returns from
+  // `Block()`.
+  bool Block();
+
+ private:
+  Mutex lock_;
+  int num_to_block_ GUARDED_BY(lock_);
+  int num_to_exit_ GUARDED_BY(lock_);
+};
+
+}  // namespace absl
+#endif  // ABSL_SYNCHRONIZATION_BARRIER_H_
diff --git a/absl/synchronization/barrier_test.cc b/absl/synchronization/barrier_test.cc
new file mode 100644
index 0000000..d6cabab
--- /dev/null
+++ b/absl/synchronization/barrier_test.cc
@@ -0,0 +1,75 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/barrier.h"
+
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/time/clock.h"
+
+
+TEST(Barrier, SanityTest) {
+  constexpr int kNumThreads = 10;
+  absl::Barrier* barrier = new absl::Barrier(kNumThreads);
+
+  absl::Mutex mutex;
+  int counter = 0;  // Guarded by mutex.
+
+  auto thread_func = [&] {
+    if (barrier->Block()) {
+      // This thread is the last thread to reach the barrier so it is
+      // responsible for deleting it.
+      delete barrier;
+    }
+
+    // Increment the counter.
+    absl::MutexLock lock(&mutex);
+    ++counter;
+  };
+
+  // Start (kNumThreads - 1) threads running thread_func.
+  std::vector<std::thread> threads;
+  for (int i = 0; i < kNumThreads - 1; ++i) {
+    threads.push_back(std::thread(thread_func));
+  }
+
+  // Give (kNumThreads - 1) threads a chance to reach the barrier.
+  // This test assumes at least one thread will have run after the
+  // sleep has elapsed. Sleeping in a test is usually bad form, but we
+  // need to make sure that we are testing the barrier instead of some
+  // other synchronization method.
+  absl::SleepFor(absl::Seconds(1));
+
+  // The counter should still be zero since no thread should have
+  // been able to pass the barrier yet.
+  {
+    absl::MutexLock lock(&mutex);
+    EXPECT_EQ(counter, 0);
+  }
+
+  // Start 1 more thread. This should make all threads pass the barrier.
+  threads.push_back(std::thread(thread_func));
+
+  // All threads should now be able to proceed and finish.
+  for (auto& thread : threads) {
+    thread.join();
+  }
+
+  // All threads should now have incremented the counter.
+  absl::MutexLock lock(&mutex);
+  EXPECT_EQ(counter, kNumThreads);
+}
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
new file mode 100644
index 0000000..7e68e96
--- /dev/null
+++ b/absl/synchronization/blocking_counter.cc
@@ -0,0 +1,55 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/blocking_counter.h"
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+// Return whether int *arg is zero.
+static bool IsZero(void *arg) {
+  return 0 == *reinterpret_cast<int *>(arg);
+}
+
+bool BlockingCounter::DecrementCount() {
+  MutexLock l(&lock_);
+  count_--;
+  if (count_ < 0) {
+    ABSL_RAW_LOG(
+        FATAL,
+        "BlockingCounter::DecrementCount() called too many times.  count=%d",
+        count_);
+  }
+  return count_ == 0;
+}
+
+void BlockingCounter::Wait() {
+  MutexLock l(&this->lock_);
+  ABSL_RAW_CHECK(count_ >= 0, "BlockingCounter underflow");
+
+  // only one thread may call Wait(). To support more than one thread,
+  // implement a counter num_to_exit, like in the Barrier class.
+  ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
+  num_waiting_++;
+
+  this->lock_.Await(Condition(IsZero, &this->count_));
+
+  // At this point, We know that all threads executing DecrementCount have
+  // released the lock, and so will not touch this object again.
+  // Therefore, the thread calling this method is free to delete the object
+  // after we return from this method.
+}
+
+}  // namespace absl
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h
new file mode 100644
index 0000000..557ed02
--- /dev/null
+++ b/absl/synchronization/blocking_counter.h
@@ -0,0 +1,97 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// blocking_counter.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+#define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// BlockingCounter
+//
+// This class allows a thread to block for a pre-specified number of actions.
+// `BlockingCounter` maintains a single non-negative abstract integer "count"
+// with an initial value `initial_count`. A thread can then call `Wait()` on
+// this blocking counter to block until the specified number of events occur;
+// worker threads then call 'DecrementCount()` on the counter upon completion of
+// their work. Once the counter's internal "count" reaches zero, the blocked
+// thread unblocks.
+//
+// A `BlockingCounter` requires the following:
+//     - its `initial_count` is non-negative.
+//     - the number of calls to `DecrementCount()` on it is at most
+//       `initial_count`.
+//     - `Wait()` is called at most once on it.
+//
+// Given the above requirements, a `BlockingCounter` provides the following
+// guarantees:
+//     - Once its internal "count" reaches zero, no legal action on the object
+//       can further change the value of "count".
+//     - When `Wait()` returns, it is legal to destroy the `BlockingCounter`.
+//     - When `Wait()` returns, the number of calls to `DecrementCount()` on
+//       this blocking counter exactly equals `initial_count`.
+//
+// Example:
+//     BlockingCounter bcount(N);         // there are N items of work
+//     ... Allow worker threads to start.
+//     ... On completing each work item, workers do:
+//     ... bcount.DecrementCount();      // an item of work has been completed
+//
+//     bcount.Wait();                    // wait for all work to be complete
+//
+class BlockingCounter {
+ public:
+  explicit BlockingCounter(int initial_count)
+      : count_(initial_count), num_waiting_(0) {}
+
+  BlockingCounter(const BlockingCounter&) = delete;
+  BlockingCounter& operator=(const BlockingCounter&) = delete;
+
+  // BlockingCounter::DecrementCount()
+  //
+  // Decrements the counter's "count" by one, and return "count == 0". This
+  // function requires that "count != 0" when it is called.
+  //
+  // Memory ordering: For any threads X and Y, any action taken by X
+  // before it calls `DecrementCount()` is visible to thread Y after
+  // Y's call to `DecrementCount()`, provided Y's call returns `true`.
+  bool DecrementCount();
+
+  // BlockingCounter::Wait()
+  //
+  // Blocks until the counter reaches zero. This function may be called at most
+  // once. On return, `DecrementCount()` will have been called "initial_count"
+  // times and the blocking counter may be destroyed.
+  //
+  // Memory ordering: For any threads X and Y, any action taken by X
+  // before X calls `DecrementCount()` is visible to Y after Y returns
+  // from `Wait()`.
+  void Wait();
+
+ private:
+  Mutex lock_;
+  int count_ GUARDED_BY(lock_);
+  int num_waiting_ GUARDED_BY(lock_);
+};
+
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc
new file mode 100644
index 0000000..e8223f8
--- /dev/null
+++ b/absl/synchronization/blocking_counter_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/blocking_counter.h"
+
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace {
+
+void PauseAndDecreaseCounter(BlockingCounter* counter, int* done) {
+  absl::SleepFor(absl::Seconds(1));
+  *done = 1;
+  counter->DecrementCount();
+}
+
+TEST(BlockingCounterTest, BasicFunctionality) {
+  // This test verifies that BlockingCounter functions correctly. Starts a
+  // number of threads that just sleep for a second and decrement a counter.
+
+  // Initialize the counter.
+  const int num_workers = 10;
+  BlockingCounter counter(num_workers);
+
+  std::vector<std::thread> workers;
+  std::vector<int> done(num_workers, 0);
+
+  // Start a number of parallel tasks that will just wait for a seconds and
+  // then decrement the count.
+  workers.reserve(num_workers);
+  for (int k = 0; k < num_workers; k++) {
+    workers.emplace_back(
+        [&counter, &done, k] { PauseAndDecreaseCounter(&counter, &done[k]); });
+  }
+
+  // Wait for the threads to have all finished.
+  counter.Wait();
+
+  // Check that all the workers have completed.
+  for (int k = 0; k < num_workers; k++) {
+    EXPECT_EQ(1, done[k]);
+  }
+
+  for (std::thread& w : workers) {
+    w.join();
+  }
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
new file mode 100644
index 0000000..e7a65cd
--- /dev/null
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -0,0 +1,112 @@
+// Copyright 2017 The Abseil 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 <stdint.h>
+#include <new>
+
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include <string.h>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// ThreadIdentity storage is persistent, we maintain a free-list of previously
+// released ThreadIdentity objects.
+static base_internal::SpinLock freelist_lock(base_internal::kLinkerInitialized);
+static base_internal::ThreadIdentity* thread_identity_freelist;
+
+// A per-thread destructor for reclaiming associated ThreadIdentity objects.
+// Since we must preserve their storage we cache them for re-use.
+static void ReclaimThreadIdentity(void* v) {
+  base_internal::ThreadIdentity* identity =
+      static_cast<base_internal::ThreadIdentity*>(v);
+
+  // all_locks might have been allocated by the Mutex implementation.
+  // We free it here when we are notified that our thread is dying.
+  if (identity->per_thread_synch.all_locks != nullptr) {
+    base_internal::LowLevelAlloc::Free(identity->per_thread_synch.all_locks);
+  }
+
+  // We must explicitly clear the current thread's identity:
+  // (a) Subsequent (unrelated) per-thread destructors may require an identity.
+  //     We must guarantee a new identity is used in this case (this instructor
+  //     will be reinvoked up to PTHREAD_DESTRUCTOR_ITERATIONS in this case).
+  // (b) ThreadIdentity implementations may depend on memory that is not
+  //     reinitialized before reuse.  We must allow explicit clearing of the
+  //     association state in this case.
+  base_internal::ClearCurrentThreadIdentity();
+  {
+    base_internal::SpinLockHolder l(&freelist_lock);
+    identity->next = thread_identity_freelist;
+    thread_identity_freelist = identity;
+  }
+}
+
+// Return value rounded up to next multiple of align.
+// Align must be a power of two.
+static intptr_t RoundUp(intptr_t addr, intptr_t align) {
+  return (addr + align - 1) & ~(align - 1);
+}
+
+static base_internal::ThreadIdentity* NewThreadIdentity() {
+  base_internal::ThreadIdentity* identity = nullptr;
+
+  {
+    // Re-use a previously released object if possible.
+    base_internal::SpinLockHolder l(&freelist_lock);
+    if (thread_identity_freelist) {
+      identity = thread_identity_freelist;  // Take list-head.
+      thread_identity_freelist = thread_identity_freelist->next;
+    }
+  }
+
+  if (identity == nullptr) {
+    // Allocate enough space to align ThreadIdentity to a multiple of
+    // PerThreadSynch::kAlignment. This space is never released (it is
+    // added to a freelist by ReclaimThreadIdentity instead).
+    void* allocation = base_internal::LowLevelAlloc::Alloc(
+        sizeof(*identity) + base_internal::PerThreadSynch::kAlignment - 1);
+    // Round up the address to the required alignment.
+    identity = reinterpret_cast<base_internal::ThreadIdentity*>(
+        RoundUp(reinterpret_cast<intptr_t>(allocation),
+                base_internal::PerThreadSynch::kAlignment));
+  }
+  memset(identity, 0, sizeof(*identity));
+
+  return identity;
+}
+
+// Allocates and attaches ThreadIdentity object for the calling thread.  Returns
+// the new identity.
+// REQUIRES: CurrentThreadIdentity(false) == nullptr
+base_internal::ThreadIdentity* CreateThreadIdentity() {
+  base_internal::ThreadIdentity* identity = NewThreadIdentity();
+  PerThreadSem::Init(identity);
+  // Associate the value with the current thread, and attach our destructor.
+  base_internal::SetCurrentThreadIdentity(identity, ReclaimThreadIdentity);
+  return identity;
+}
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/create_thread_identity.h b/absl/synchronization/internal/create_thread_identity.h
new file mode 100644
index 0000000..1bb87de
--- /dev/null
+++ b/absl/synchronization/internal/create_thread_identity.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 The Abseil 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.
+ */
+
+// Interface for getting the current ThreadIdentity, creating one if necessary.
+// See thread_identity.h.
+//
+// This file is separate from thread_identity.h because creating a new
+// ThreadIdentity requires slightly higher level libraries (per_thread_sem
+// and low_level_alloc) than accessing an existing one.  This separation allows
+// us to have a smaller //absl/base:base.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// Allocates and attaches a ThreadIdentity object for the calling thread.
+// For private use only.
+base_internal::ThreadIdentity* CreateThreadIdentity();
+
+// Returns the ThreadIdentity object representing the calling thread; guaranteed
+// to be unique for its lifetime.  The returned object will remain valid for the
+// program's lifetime; although it may be re-assigned to a subsequent thread.
+// If one does not exist for the calling thread, allocate it now.
+inline base_internal::ThreadIdentity* GetOrCreateCurrentThreadIdentity() {
+  base_internal::ThreadIdentity* identity =
+      base_internal::CurrentThreadIdentityIfPresent();
+  if (ABSL_PREDICT_FALSE(identity == nullptr)) {
+    return CreateThreadIdentity();
+  }
+  return identity;
+}
+
+}  // namespace synchronization_internal
+}  // namespace absl
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
new file mode 100644
index 0000000..ab1f3f8
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -0,0 +1,699 @@
+// Copyright 2017 The Abseil 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.
+
+// GraphCycles provides incremental cycle detection on a dynamic
+// graph using the following algorithm:
+//
+// A dynamic topological sort algorithm for directed acyclic graphs
+// David J. Pearce, Paul H. J. Kelly
+// Journal of Experimental Algorithmics (JEA) JEA Homepage archive
+// Volume 11, 2006, Article No. 1.7
+//
+// Brief summary of the algorithm:
+//
+// (1) Maintain a rank for each node that is consistent
+//     with the topological sort of the graph. I.e., path from x to y
+//     implies rank[x] < rank[y].
+// (2) When a new edge (x->y) is inserted, do nothing if rank[x] < rank[y].
+// (3) Otherwise: adjust ranks in the neighborhood of x and y.
+
+#include "absl/base/attributes.h"
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/graphcycles.h"
+
+#include <algorithm>
+#include <array>
+#include "absl/base/internal/hide_ptr.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+// Do not use STL.   This module does not use standard memory allocation.
+
+namespace absl {
+namespace synchronization_internal {
+
+namespace {
+
+// Avoid LowLevelAlloc's default arena since it calls malloc hooks in
+// which people are doing things like acquiring Mutexes.
+static absl::base_internal::SpinLock arena_mu(
+    absl::base_internal::kLinkerInitialized);
+static base_internal::LowLevelAlloc::Arena* arena;
+
+static void InitArenaIfNecessary() {
+  arena_mu.Lock();
+  if (arena == nullptr) {
+    arena = base_internal::LowLevelAlloc::NewArena(0);
+  }
+  arena_mu.Unlock();
+}
+
+// Number of inlined elements in Vec.  Hash table implementation
+// relies on this being a power of two.
+static const uint32_t kInline = 8;
+
+// A simple LowLevelAlloc based resizable vector with inlined storage
+// for a few elements.  T must be a plain type since constructor
+// and destructor are not run on elements of type T managed by Vec.
+template <typename T>
+class Vec {
+ public:
+  Vec() { Init(); }
+  ~Vec() { Discard(); }
+
+  void clear() {
+    Discard();
+    Init();
+  }
+
+  bool empty() const { return size_ == 0; }
+  uint32_t size() const { return size_; }
+  T* begin() { return ptr_; }
+  T* end() { return ptr_ + size_; }
+  const T& operator[](uint32_t i) const { return ptr_[i]; }
+  T& operator[](uint32_t i) { return ptr_[i]; }
+  const T& back() const { return ptr_[size_-1]; }
+  void pop_back() { size_--; }
+
+  void push_back(const T& v) {
+    if (size_ == capacity_) Grow(size_ + 1);
+    ptr_[size_] = v;
+    size_++;
+  }
+
+  void resize(uint32_t n) {
+    if (n > capacity_) Grow(n);
+    size_ = n;
+  }
+
+  void fill(const T& val) {
+    for (uint32_t i = 0; i < size(); i++) {
+      ptr_[i] = val;
+    }
+  }
+
+  // Guarantees src is empty at end.
+  // Provided for the hash table resizing code below.
+  void MoveFrom(Vec<T>* src) {
+    if (src->ptr_ == src->space_) {
+      // Need to actually copy
+      resize(src->size_);
+      std::copy(src->ptr_, src->ptr_ + src->size_, ptr_);
+      src->size_ = 0;
+    } else {
+      Discard();
+      ptr_ = src->ptr_;
+      size_ = src->size_;
+      capacity_ = src->capacity_;
+      src->Init();
+    }
+  }
+
+ private:
+  T* ptr_;
+  T space_[kInline];
+  uint32_t size_;
+  uint32_t capacity_;
+
+  void Init() {
+    ptr_ = space_;
+    size_ = 0;
+    capacity_ = kInline;
+  }
+
+  void Discard() {
+    if (ptr_ != space_) base_internal::LowLevelAlloc::Free(ptr_);
+  }
+
+  void Grow(uint32_t n) {
+    while (capacity_ < n) {
+      capacity_ *= 2;
+    }
+    size_t request = static_cast<size_t>(capacity_) * sizeof(T);
+    T* copy = static_cast<T*>(
+        base_internal::LowLevelAlloc::AllocWithArena(request, arena));
+    std::copy(ptr_, ptr_ + size_, copy);
+    Discard();
+    ptr_ = copy;
+  }
+
+  Vec(const Vec&) = delete;
+  Vec& operator=(const Vec&) = delete;
+};
+
+// A hash set of non-negative int32_t that uses Vec for its underlying storage.
+class NodeSet {
+ public:
+  NodeSet() { Init(); }
+
+  void clear() { Init(); }
+  bool contains(int32_t v) const { return table_[FindIndex(v)] == v; }
+
+  bool insert(int32_t v) {
+    uint32_t i = FindIndex(v);
+    if (table_[i] == v) {
+      return false;
+    }
+    if (table_[i] == kEmpty) {
+      // Only inserting over an empty cell increases the number of occupied
+      // slots.
+      occupied_++;
+    }
+    table_[i] = v;
+    // Double when 75% full.
+    if (occupied_ >= table_.size() - table_.size()/4) Grow();
+    return true;
+  }
+
+  void erase(uint32_t v) {
+    uint32_t i = FindIndex(v);
+    if (static_cast<uint32_t>(table_[i]) == v) {
+      table_[i] = kDel;
+    }
+  }
+
+  // Iteration: is done via HASH_FOR_EACH
+  // Example:
+  //    HASH_FOR_EACH(elem, node->out) { ... }
+#define HASH_FOR_EACH(elem, eset) \
+  for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); )
+  bool Next(int32_t* cursor, int32_t* elem) {
+    while (static_cast<uint32_t>(*cursor) < table_.size()) {
+      int32_t v = table_[*cursor];
+      (*cursor)++;
+      if (v >= 0) {
+        *elem = v;
+        return true;
+      }
+    }
+    return false;
+  }
+
+ private:
+  static const int32_t kEmpty;
+  static const int32_t kDel;
+  Vec<int32_t> table_;
+  uint32_t occupied_;     // Count of non-empty slots (includes deleted slots)
+
+  static uint32_t Hash(uint32_t a) { return a * 41; }
+
+  // Return index for storing v.  May return an empty index or deleted index
+  int FindIndex(int32_t v) const {
+    // Search starting at hash index.
+    const uint32_t mask = table_.size() - 1;
+    uint32_t i = Hash(v) & mask;
+    int deleted_index = -1;  // If >= 0, index of first deleted element we see
+    while (true) {
+      int32_t e = table_[i];
+      if (v == e) {
+        return i;
+      } else if (e == kEmpty) {
+        // Return any previously encountered deleted slot.
+        return (deleted_index >= 0) ? deleted_index : i;
+      } else if (e == kDel && deleted_index < 0) {
+        // Keep searching since v might be present later.
+        deleted_index = i;
+      }
+      i = (i + 1) & mask;  // Linear probing; quadratic is slightly slower.
+    }
+  }
+
+  void Init() {
+    table_.clear();
+    table_.resize(kInline);
+    table_.fill(kEmpty);
+    occupied_ = 0;
+  }
+
+  void Grow() {
+    Vec<int32_t> copy;
+    copy.MoveFrom(&table_);
+    occupied_ = 0;
+    table_.resize(copy.size() * 2);
+    table_.fill(kEmpty);
+
+    for (const auto& e : copy) {
+      if (e >= 0) insert(e);
+    }
+  }
+
+  NodeSet(const NodeSet&) = delete;
+  NodeSet& operator=(const NodeSet&) = delete;
+};
+
+const int32_t NodeSet::kEmpty = -1;
+const int32_t NodeSet::kDel = -2;
+
+// We encode a node index and a node version in GraphId.  The version
+// number is incremented when the GraphId is freed which automatically
+// invalidates all copies of the GraphId.
+
+inline GraphId MakeId(int32_t index, uint32_t version) {
+  GraphId g;
+  g.handle =
+      (static_cast<uint64_t>(version) << 32) | static_cast<uint32_t>(index);
+  return g;
+}
+
+inline int32_t NodeIndex(GraphId id) {
+  return static_cast<uint32_t>(id.handle & 0xfffffffful);
+}
+
+inline uint32_t NodeVersion(GraphId id) {
+  return static_cast<uint32_t>(id.handle >> 32);
+}
+
+struct Node {
+  int32_t rank;               // rank number assigned by Pearce-Kelly algorithm
+  uint32_t version;           // Current version number
+  int32_t next_hash;          // Next entry in hash table
+  bool visited;               // Temporary marker used by depth-first-search
+  uintptr_t masked_ptr;       // User-supplied pointer
+  NodeSet in;                 // List of immediate predecessor nodes in graph
+  NodeSet out;                // List of immediate successor nodes in graph
+  int priority;               // Priority of recorded stack trace.
+  int nstack;                 // Depth of recorded stack trace.
+  void* stack[40];            // stack[0,nstack-1] holds stack trace for node.
+};
+
+// Hash table for pointer to node index lookups.
+class PointerMap {
+ public:
+  explicit PointerMap(const Vec<Node*>* nodes) : nodes_(nodes) {
+    table_.fill(-1);
+  }
+
+  int32_t Find(void* ptr) {
+    auto masked = base_internal::HidePtr(ptr);
+    for (int32_t i = table_[Hash(ptr)]; i != -1;) {
+      Node* n = (*nodes_)[i];
+      if (n->masked_ptr == masked) return i;
+      i = n->next_hash;
+    }
+    return -1;
+  }
+
+  void Add(void* ptr, int32_t i) {
+    int32_t* head = &table_[Hash(ptr)];
+    (*nodes_)[i]->next_hash = *head;
+    *head = i;
+  }
+
+  int32_t Remove(void* ptr) {
+    // Advance through linked list while keeping track of the
+    // predecessor slot that points to the current entry.
+    auto masked = base_internal::HidePtr(ptr);
+    for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1; ) {
+      int32_t index = *slot;
+      Node* n = (*nodes_)[index];
+      if (n->masked_ptr == masked) {
+        *slot = n->next_hash;  // Remove n from linked list
+        n->next_hash = -1;
+        return index;
+      }
+      slot = &n->next_hash;
+    }
+    return -1;
+  }
+
+ private:
+  // Number of buckets in hash table for pointer lookups.
+  static constexpr uint32_t kHashTableSize = 8171;  // should be prime
+
+  const Vec<Node*>* nodes_;
+  std::array<int32_t, kHashTableSize> table_;
+
+  static uint32_t Hash(void* ptr) {
+    return reinterpret_cast<uintptr_t>(ptr) % kHashTableSize;
+  }
+};
+
+}  // namespace
+
+struct GraphCycles::Rep {
+  Vec<Node*> nodes_;
+  Vec<int32_t> free_nodes_;  // Indices for unused entries in nodes_
+  PointerMap ptrmap_;
+
+  // Temporary state.
+  Vec<int32_t> deltaf_;  // Results of forward DFS
+  Vec<int32_t> deltab_;  // Results of backward DFS
+  Vec<int32_t> list_;    // All nodes to reprocess
+  Vec<int32_t> merged_;  // Rank values to assign to list_ entries
+  Vec<int32_t> stack_;   // Emulates recursion stack for depth-first searches
+
+  Rep() : ptrmap_(&nodes_) {}
+};
+
+static Node* FindNode(GraphCycles::Rep* rep, GraphId id) {
+  Node* n = rep->nodes_[NodeIndex(id)];
+  return (n->version == NodeVersion(id)) ? n : nullptr;
+}
+
+GraphCycles::GraphCycles() {
+  InitArenaIfNecessary();
+  rep_ = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Rep), arena))
+      Rep;
+}
+
+GraphCycles::~GraphCycles() {
+  for (auto* node : rep_->nodes_) {
+    node->Node::~Node();
+    base_internal::LowLevelAlloc::Free(node);
+  }
+  rep_->Rep::~Rep();
+  base_internal::LowLevelAlloc::Free(rep_);
+}
+
+bool GraphCycles::CheckInvariants() const {
+  Rep* r = rep_;
+  NodeSet ranks;  // Set of ranks seen so far.
+  for (uint32_t x = 0; x < r->nodes_.size(); x++) {
+    Node* nx = r->nodes_[x];
+    void* ptr = base_internal::UnhidePtr<void>(nx->masked_ptr);
+    if (ptr != nullptr && static_cast<uint32_t>(r->ptrmap_.Find(ptr)) != x) {
+      ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %u %p", x, ptr);
+    }
+    if (nx->visited) {
+      ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %u", x);
+    }
+    if (!ranks.insert(nx->rank)) {
+      ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %d", nx->rank);
+    }
+    HASH_FOR_EACH(y, nx->out) {
+      Node* ny = r->nodes_[y];
+      if (nx->rank >= ny->rank) {
+        ABSL_RAW_LOG(FATAL, "Edge %u->%d has bad rank assignment %d->%d", x, y,
+                     nx->rank, ny->rank);
+      }
+    }
+  }
+  return true;
+}
+
+GraphId GraphCycles::GetId(void* ptr) {
+  int32_t i = rep_->ptrmap_.Find(ptr);
+  if (i != -1) {
+    return MakeId(i, rep_->nodes_[i]->version);
+  } else if (rep_->free_nodes_.empty()) {
+    Node* n =
+        new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Node), arena))
+            Node;
+    n->version = 1;  // Avoid 0 since it is used by InvalidGraphId()
+    n->visited = false;
+    n->rank = rep_->nodes_.size();
+    n->masked_ptr = base_internal::HidePtr(ptr);
+    n->nstack = 0;
+    n->priority = 0;
+    rep_->nodes_.push_back(n);
+    rep_->ptrmap_.Add(ptr, n->rank);
+    return MakeId(n->rank, n->version);
+  } else {
+    // Preserve preceding rank since the set of ranks in use must be
+    // a permutation of [0,rep_->nodes_.size()-1].
+    int32_t r = rep_->free_nodes_.back();
+    rep_->free_nodes_.pop_back();
+    Node* n = rep_->nodes_[r];
+    n->masked_ptr = base_internal::HidePtr(ptr);
+    n->nstack = 0;
+    n->priority = 0;
+    rep_->ptrmap_.Add(ptr, r);
+    return MakeId(r, n->version);
+  }
+}
+
+void GraphCycles::RemoveNode(void* ptr) {
+  int32_t i = rep_->ptrmap_.Remove(ptr);
+  if (i == -1) {
+    return;
+  }
+  Node* x = rep_->nodes_[i];
+  HASH_FOR_EACH(y, x->out) {
+    rep_->nodes_[y]->in.erase(i);
+  }
+  HASH_FOR_EACH(y, x->in) {
+    rep_->nodes_[y]->out.erase(i);
+  }
+  x->in.clear();
+  x->out.clear();
+  x->masked_ptr = base_internal::HidePtr<void>(nullptr);
+  if (x->version == std::numeric_limits<uint32_t>::max()) {
+    // Cannot use x any more
+  } else {
+    x->version++;  // Invalidates all copies of node.
+    rep_->free_nodes_.push_back(i);
+  }
+}
+
+void* GraphCycles::Ptr(GraphId id) {
+  Node* n = FindNode(rep_, id);
+  return n == nullptr ? nullptr
+                      : base_internal::UnhidePtr<void>(n->masked_ptr);
+}
+
+bool GraphCycles::HasNode(GraphId node) {
+  return FindNode(rep_, node) != nullptr;
+}
+
+bool GraphCycles::HasEdge(GraphId x, GraphId y) const {
+  Node* xn = FindNode(rep_, x);
+  return xn && FindNode(rep_, y) && xn->out.contains(NodeIndex(y));
+}
+
+void GraphCycles::RemoveEdge(GraphId x, GraphId y) {
+  Node* xn = FindNode(rep_, x);
+  Node* yn = FindNode(rep_, y);
+  if (xn && yn) {
+    xn->out.erase(NodeIndex(y));
+    yn->in.erase(NodeIndex(x));
+    // No need to update the rank assignment since a previous valid
+    // rank assignment remains valid after an edge deletion.
+  }
+}
+
+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound);
+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound);
+static void Reorder(GraphCycles::Rep* r);
+static void Sort(const Vec<Node*>&, Vec<int32_t>* delta);
+static void MoveToList(
+    GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst);
+
+bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) {
+  Rep* r = rep_;
+  const int32_t x = NodeIndex(idx);
+  const int32_t y = NodeIndex(idy);
+  Node* nx = FindNode(r, idx);
+  Node* ny = FindNode(r, idy);
+  if (nx == nullptr || ny == nullptr) return true;  // Expired ids
+
+  if (nx == ny) return false;  // Self edge
+  if (!nx->out.insert(y)) {
+    // Edge already exists.
+    return true;
+  }
+
+  ny->in.insert(x);
+
+  if (nx->rank <= ny->rank) {
+    // New edge is consistent with existing rank assignment.
+    return true;
+  }
+
+  // Current rank assignments are incompatible with the new edge.  Recompute.
+  // We only need to consider nodes that fall in the range [ny->rank,nx->rank].
+  if (!ForwardDFS(r, y, nx->rank)) {
+    // Found a cycle.  Undo the insertion and tell caller.
+    nx->out.erase(y);
+    ny->in.erase(x);
+    // Since we do not call Reorder() on this path, clear any visited
+    // markers left by ForwardDFS.
+    for (const auto& d : r->deltaf_) {
+      r->nodes_[d]->visited = false;
+    }
+    return false;
+  }
+  BackwardDFS(r, x, ny->rank);
+  Reorder(r);
+  return true;
+}
+
+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) {
+  // Avoid recursion since stack space might be limited.
+  // We instead keep a stack of nodes to visit.
+  r->deltaf_.clear();
+  r->stack_.clear();
+  r->stack_.push_back(n);
+  while (!r->stack_.empty()) {
+    n = r->stack_.back();
+    r->stack_.pop_back();
+    Node* nn = r->nodes_[n];
+    if (nn->visited) continue;
+
+    nn->visited = true;
+    r->deltaf_.push_back(n);
+
+    HASH_FOR_EACH(w, nn->out) {
+      Node* nw = r->nodes_[w];
+      if (nw->rank == upper_bound) {
+        return false;  // Cycle
+      }
+      if (!nw->visited && nw->rank < upper_bound) {
+        r->stack_.push_back(w);
+      }
+    }
+  }
+  return true;
+}
+
+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound) {
+  r->deltab_.clear();
+  r->stack_.clear();
+  r->stack_.push_back(n);
+  while (!r->stack_.empty()) {
+    n = r->stack_.back();
+    r->stack_.pop_back();
+    Node* nn = r->nodes_[n];
+    if (nn->visited) continue;
+
+    nn->visited = true;
+    r->deltab_.push_back(n);
+
+    HASH_FOR_EACH(w, nn->in) {
+      Node* nw = r->nodes_[w];
+      if (!nw->visited && lower_bound < nw->rank) {
+        r->stack_.push_back(w);
+      }
+    }
+  }
+}
+
+static void Reorder(GraphCycles::Rep* r) {
+  Sort(r->nodes_, &r->deltab_);
+  Sort(r->nodes_, &r->deltaf_);
+
+  // Adds contents of delta lists to list_ (backwards deltas first).
+  r->list_.clear();
+  MoveToList(r, &r->deltab_, &r->list_);
+  MoveToList(r, &r->deltaf_, &r->list_);
+
+  // Produce sorted list of all ranks that will be reassigned.
+  r->merged_.resize(r->deltab_.size() + r->deltaf_.size());
+  std::merge(r->deltab_.begin(), r->deltab_.end(),
+             r->deltaf_.begin(), r->deltaf_.end(),
+             r->merged_.begin());
+
+  // Assign the ranks in order to the collected list.
+  for (uint32_t i = 0; i < r->list_.size(); i++) {
+    r->nodes_[r->list_[i]]->rank = r->merged_[i];
+  }
+}
+
+static void Sort(const Vec<Node*>& nodes, Vec<int32_t>* delta) {
+  struct ByRank {
+    const Vec<Node*>* nodes;
+    bool operator()(int32_t a, int32_t b) const {
+      return (*nodes)[a]->rank < (*nodes)[b]->rank;
+    }
+  };
+  ByRank cmp;
+  cmp.nodes = &nodes;
+  std::sort(delta->begin(), delta->end(), cmp);
+}
+
+static void MoveToList(
+    GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) {
+  for (auto& v : *src) {
+    int32_t w = v;
+    v = r->nodes_[w]->rank;         // Replace v entry with its rank
+    r->nodes_[w]->visited = false;  // Prepare for future DFS calls
+    dst->push_back(w);
+  }
+}
+
+int GraphCycles::FindPath(GraphId idx, GraphId idy, int max_path_len,
+                          GraphId path[]) const {
+  Rep* r = rep_;
+  if (FindNode(r, idx) == nullptr || FindNode(r, idy) == nullptr) return 0;
+  const int32_t x = NodeIndex(idx);
+  const int32_t y = NodeIndex(idy);
+
+  // Forward depth first search starting at x until we hit y.
+  // As we descend into a node, we push it onto the path.
+  // As we leave a node, we remove it from the path.
+  int path_len = 0;
+
+  NodeSet seen;
+  r->stack_.clear();
+  r->stack_.push_back(x);
+  while (!r->stack_.empty()) {
+    int32_t n = r->stack_.back();
+    r->stack_.pop_back();
+    if (n < 0) {
+      // Marker to indicate that we are leaving a node
+      path_len--;
+      continue;
+    }
+
+    if (path_len < max_path_len) {
+      path[path_len] = MakeId(n, rep_->nodes_[n]->version);
+    }
+    path_len++;
+    r->stack_.push_back(-1);  // Will remove tentative path entry
+
+    if (n == y) {
+      return path_len;
+    }
+
+    HASH_FOR_EACH(w, r->nodes_[n]->out) {
+      if (seen.insert(w)) {
+        r->stack_.push_back(w);
+      }
+    }
+  }
+
+  return 0;
+}
+
+bool GraphCycles::IsReachable(GraphId x, GraphId y) const {
+  return FindPath(x, y, 0, nullptr) > 0;
+}
+
+void GraphCycles::UpdateStackTrace(GraphId id, int priority,
+                                   int (*get_stack_trace)(void** stack, int)) {
+  Node* n = FindNode(rep_, id);
+  if (n == nullptr || n->priority >= priority) {
+    return;
+  }
+  n->nstack = (*get_stack_trace)(n->stack, ABSL_ARRAYSIZE(n->stack));
+  n->priority = priority;
+}
+
+int GraphCycles::GetStackTrace(GraphId id, void*** ptr) {
+  Node* n = FindNode(rep_, id);
+  if (n == nullptr) {
+    *ptr = nullptr;
+    return 0;
+  } else {
+    *ptr = n->stack;
+    return n->nstack;
+  }
+}
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/graphcycles.h b/absl/synchronization/internal/graphcycles.h
new file mode 100644
index 0000000..2e6686a
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles.h
@@ -0,0 +1,137 @@
+// Copyright 2017 The Abseil 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 ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
+
+// GraphCycles detects the introduction of a cycle into a directed
+// graph that is being built up incrementally.
+//
+// Nodes are identified by small integers.  It is not possible to
+// record multiple edges with the same (source, destination) pair;
+// requests to add an edge where one already exists are silently
+// ignored.
+//
+// It is also not possible to introduce a cycle; an attempt to insert
+// an edge that would introduce a cycle fails and returns false.
+//
+// GraphCycles uses no internal locking; calls into it should be
+// serialized externally.
+
+// Performance considerations:
+//   Works well on sparse graphs, poorly on dense graphs.
+//   Extra information is maintained incrementally to detect cycles quickly.
+//   InsertEdge() is very fast when the edge already exists, and reasonably fast
+//   otherwise.
+//   FindPath() is linear in the size of the graph.
+// The current implemenation uses O(|V|+|E|) space.
+
+#include <cstdint>
+
+namespace absl {
+namespace synchronization_internal {
+
+// Opaque identifier for a graph node.
+struct GraphId {
+  uint64_t handle;
+
+  bool operator==(const GraphId& x) const { return handle == x.handle; }
+  bool operator!=(const GraphId& x) const { return handle != x.handle; }
+};
+
+// Return an invalid graph id that will never be assigned by GraphCycles.
+inline GraphId InvalidGraphId() {
+  return GraphId{0};
+}
+
+class GraphCycles {
+ public:
+  GraphCycles();
+  ~GraphCycles();
+
+  // Return the id to use for ptr, assigning one if necessary.
+  // Subsequent calls with the same ptr value will return the same id
+  // until Remove().
+  GraphId GetId(void* ptr);
+
+  // Remove "ptr" from the graph.  Its corresponding node and all
+  // edges to and from it are removed.
+  void RemoveNode(void* ptr);
+
+  // Return the pointer associated with id, or nullptr if id is not
+  // currently in the graph.
+  void* Ptr(GraphId id);
+
+  // Attempt to insert an edge from source_node to dest_node.  If the
+  // edge would introduce a cycle, return false without making any
+  // changes. Otherwise add the edge and return true.
+  bool InsertEdge(GraphId source_node, GraphId dest_node);
+
+  // Remove any edge that exists from source_node to dest_node.
+  void RemoveEdge(GraphId source_node, GraphId dest_node);
+
+  // Return whether node exists in the graph.
+  bool HasNode(GraphId node);
+
+  // Return whether there is an edge directly from source_node to dest_node.
+  bool HasEdge(GraphId source_node, GraphId dest_node) const;
+
+  // Return whether dest_node is reachable from source_node
+  // by following edges.
+  bool IsReachable(GraphId source_node, GraphId dest_node) const;
+
+  // Find a path from "source" to "dest".  If such a path exists,
+  // place the nodes on the path in the array path[], and return
+  // the number of nodes on the path.  If the path is longer than
+  // max_path_len nodes, only the first max_path_len nodes are placed
+  // in path[].  The client should compare the return value with
+  // max_path_len" to see when this occurs.  If no path exists, return
+  // 0.  Any valid path stored in path[] will start with "source" and
+  // end with "dest".  There is no guarantee that the path is the
+  // shortest, but no node will appear twice in the path, except the
+  // source and destination node if they are identical; therefore, the
+  // return value is at most one greater than the number of nodes in
+  // the graph.
+  int FindPath(GraphId source, GraphId dest, int max_path_len,
+               GraphId path[]) const;
+
+  // Update the stack trace recorded for id with the current stack
+  // trace if the last time it was updated had a smaller priority
+  // than the priority passed on this call.
+  //
+  // *get_stack_trace is called to get the stack trace.
+  void UpdateStackTrace(GraphId id, int priority,
+                        int (*get_stack_trace)(void**, int));
+
+  // Set *ptr to the beginning of the array that holds the recorded
+  // stack trace for id and return the depth of the stack trace.
+  int GetStackTrace(GraphId id, void*** ptr);
+
+  // Check internal invariants. Crashes on failure, returns true on success.
+  // Expensive: should only be called from graphcycles_test.cc.
+  bool CheckInvariants() const;
+
+  // ----------------------------------------------------
+  struct Rep;
+ private:
+  Rep *rep_;      // opaque representation
+  GraphCycles(const GraphCycles&) = delete;
+  GraphCycles& operator=(const GraphCycles&) = delete;
+};
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+#endif
diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc
new file mode 100644
index 0000000..a239c25
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles_benchmark.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Abseil 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 "absl/synchronization/internal/graphcycles.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace {
+
+void BM_StressTest(benchmark::State& state) {
+  const int num_nodes = state.range(0);
+  while (state.KeepRunningBatch(num_nodes)) {
+    absl::synchronization_internal::GraphCycles g;
+    std::vector<absl::synchronization_internal::GraphId> nodes(num_nodes);
+    for (int i = 0; i < num_nodes; i++) {
+      nodes[i] = g.GetId(reinterpret_cast<void*>(static_cast<uintptr_t>(i)));
+    }
+    for (int i = 0; i < num_nodes; i++) {
+      int end = std::min(num_nodes, i + 5);
+      for (int j = i + 1; j < end; j++) {
+        ABSL_RAW_CHECK(g.InsertEdge(nodes[i], nodes[j]), "");
+      }
+    }
+  }
+}
+BENCHMARK(BM_StressTest)->Range(2048, 1048576);
+
+}  // namespace
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc
new file mode 100644
index 0000000..9a85b39
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -0,0 +1,462 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/internal/graphcycles.h"
+
+#include <map>
+#include <random>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// We emulate a GraphCycles object with a node vector and an edge vector.
+// We then compare the two implementations.
+
+using Nodes = std::vector<int>;
+struct Edge {
+  int from;
+  int to;
+};
+using Edges = std::vector<Edge>;
+using RandomEngine = std::mt19937_64;
+
+// Mapping from integer index to GraphId.
+typedef std::map<int, GraphId> IdMap;
+static GraphId Get(const IdMap& id, int num) {
+  auto iter = id.find(num);
+  return (iter == id.end()) ? InvalidGraphId() : iter->second;
+}
+
+// Return whether "to" is reachable from "from".
+static bool IsReachable(Edges *edges, int from, int to,
+                        std::unordered_set<int> *seen) {
+  seen->insert(from);     // we are investigating "from"; don't do it again
+  if (from == to) return true;
+  for (const auto &edge : *edges) {
+    if (edge.from == from) {
+      if (edge.to == to) {  // success via edge directly
+        return true;
+      } else if (seen->find(edge.to) == seen->end() &&  // success via edge
+                 IsReachable(edges, edge.to, to, seen)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static void PrintEdges(Edges *edges) {
+  ABSL_RAW_LOG(INFO, "EDGES (%zu)", edges->size());
+  for (const auto &edge : *edges) {
+    int a = edge.from;
+    int b = edge.to;
+    ABSL_RAW_LOG(INFO, "%d %d", a, b);
+  }
+  ABSL_RAW_LOG(INFO, "---");
+}
+
+static void PrintGCEdges(Nodes *nodes, const IdMap &id, GraphCycles *gc) {
+  ABSL_RAW_LOG(INFO, "GC EDGES");
+  for (int a : *nodes) {
+    for (int b : *nodes) {
+      if (gc->HasEdge(Get(id, a), Get(id, b))) {
+        ABSL_RAW_LOG(INFO, "%d %d", a, b);
+      }
+    }
+  }
+  ABSL_RAW_LOG(INFO, "---");
+}
+
+static void PrintTransitiveClosure(Nodes *nodes, Edges *edges) {
+  ABSL_RAW_LOG(INFO, "Transitive closure");
+  for (int a : *nodes) {
+    for (int b : *nodes) {
+      std::unordered_set<int> seen;
+      if (IsReachable(edges, a, b, &seen)) {
+        ABSL_RAW_LOG(INFO, "%d %d", a, b);
+      }
+    }
+  }
+  ABSL_RAW_LOG(INFO, "---");
+}
+
+static void PrintGCTransitiveClosure(Nodes *nodes, const IdMap &id,
+                                     GraphCycles *gc) {
+  ABSL_RAW_LOG(INFO, "GC Transitive closure");
+  for (int a : *nodes) {
+    for (int b : *nodes) {
+      if (gc->IsReachable(Get(id, a), Get(id, b))) {
+        ABSL_RAW_LOG(INFO, "%d %d", a, b);
+      }
+    }
+  }
+  ABSL_RAW_LOG(INFO, "---");
+}
+
+static void CheckTransitiveClosure(Nodes *nodes, Edges *edges, const IdMap &id,
+                                   GraphCycles *gc) {
+  std::unordered_set<int> seen;
+  for (const auto &a : *nodes) {
+    for (const auto &b : *nodes) {
+      seen.clear();
+      bool gc_reachable = gc->IsReachable(Get(id, a), Get(id, b));
+      bool reachable = IsReachable(edges, a, b, &seen);
+      if (gc_reachable != reachable) {
+        PrintEdges(edges);
+        PrintGCEdges(nodes, id, gc);
+        PrintTransitiveClosure(nodes, edges);
+        PrintGCTransitiveClosure(nodes, id, gc);
+        ABSL_RAW_LOG(FATAL, "gc_reachable %s reachable %s a %d b %d",
+                     gc_reachable ? "true" : "false",
+                     reachable ? "true" : "false", a, b);
+      }
+    }
+  }
+}
+
+static void CheckEdges(Nodes *nodes, Edges *edges, const IdMap &id,
+                       GraphCycles *gc) {
+  int count = 0;
+  for (const auto &edge : *edges) {
+    int a = edge.from;
+    int b = edge.to;
+    if (!gc->HasEdge(Get(id, a), Get(id, b))) {
+      PrintEdges(edges);
+      PrintGCEdges(nodes, id, gc);
+      ABSL_RAW_LOG(FATAL, "!gc->HasEdge(%d, %d)", a, b);
+    }
+  }
+  for (const auto &a : *nodes) {
+    for (const auto &b : *nodes) {
+      if (gc->HasEdge(Get(id, a), Get(id, b))) {
+        count++;
+      }
+    }
+  }
+  if (count != edges->size()) {
+    PrintEdges(edges);
+    PrintGCEdges(nodes, id, gc);
+    ABSL_RAW_LOG(FATAL, "edges->size() %zu  count %d", edges->size(), count);
+  }
+}
+
+static void CheckInvariants(const GraphCycles &gc) {
+  if (ABSL_PREDICT_FALSE(!gc.CheckInvariants()))
+    ABSL_RAW_LOG(FATAL, "CheckInvariants");
+}
+
+// Returns the index of a randomly chosen node in *nodes.
+// Requires *nodes be non-empty.
+static int RandomNode(RandomEngine* rng, Nodes *nodes) {
+  std::uniform_int_distribution<int> uniform(0, nodes->size()-1);
+  return uniform(*rng);
+}
+
+// Returns the index of a randomly chosen edge in *edges.
+// Requires *edges be non-empty.
+static int RandomEdge(RandomEngine* rng, Edges *edges) {
+  std::uniform_int_distribution<int> uniform(0, edges->size()-1);
+  return uniform(*rng);
+}
+
+// Returns the index of edge (from, to) in *edges or -1 if it is not in *edges.
+static int EdgeIndex(Edges *edges, int from, int to) {
+  int i = 0;
+  while (i != edges->size() &&
+         ((*edges)[i].from != from || (*edges)[i].to != to)) {
+    i++;
+  }
+  return i == edges->size()? -1 : i;
+}
+
+TEST(GraphCycles, RandomizedTest) {
+  int next_node = 0;
+  Nodes nodes;
+  Edges edges;   // from, to
+  IdMap id;
+  GraphCycles graph_cycles;
+  static const int kMaxNodes = 7;  // use <= 7 nodes to keep test short
+  static const int kDataOffset = 17;  // an offset to the node-specific data
+  int n = 100000;
+  int op = 0;
+  RandomEngine rng(testing::UnitTest::GetInstance()->random_seed());
+  std::uniform_int_distribution<int> uniform(0, 5);
+
+  auto ptr = [](intptr_t i) {
+    return reinterpret_cast<void*>(i + kDataOffset);
+  };
+
+  for (int iter = 0; iter != n; iter++) {
+    for (const auto &node : nodes) {
+      ASSERT_EQ(graph_cycles.Ptr(Get(id, node)), ptr(node)) << " node " << node;
+    }
+    CheckEdges(&nodes, &edges, id, &graph_cycles);
+    CheckTransitiveClosure(&nodes, &edges, id, &graph_cycles);
+    op = uniform(rng);
+    switch (op) {
+    case 0:     // Add a node
+      if (nodes.size() < kMaxNodes) {
+        int new_node = next_node++;
+        GraphId new_gnode = graph_cycles.GetId(ptr(new_node));
+        ASSERT_NE(new_gnode, InvalidGraphId());
+        id[new_node] = new_gnode;
+        ASSERT_EQ(ptr(new_node), graph_cycles.Ptr(new_gnode));
+        nodes.push_back(new_node);
+      }
+      break;
+
+    case 1:    // Remove a node
+      if (nodes.size() > 0) {
+        int node_index = RandomNode(&rng, &nodes);
+        int node = nodes[node_index];
+        nodes[node_index] = nodes.back();
+        nodes.pop_back();
+        graph_cycles.RemoveNode(ptr(node));
+        ASSERT_EQ(graph_cycles.Ptr(Get(id, node)), nullptr);
+        id.erase(node);
+        int i = 0;
+        while (i != edges.size()) {
+          if (edges[i].from == node || edges[i].to == node) {
+            edges[i] = edges.back();
+            edges.pop_back();
+          } else {
+            i++;
+          }
+        }
+      }
+      break;
+
+    case 2:   // Add an edge
+      if (nodes.size() > 0) {
+        int from = RandomNode(&rng, &nodes);
+        int to = RandomNode(&rng, &nodes);
+        if (EdgeIndex(&edges, nodes[from], nodes[to]) == -1) {
+          if (graph_cycles.InsertEdge(id[nodes[from]], id[nodes[to]])) {
+            Edge new_edge;
+            new_edge.from = nodes[from];
+            new_edge.to = nodes[to];
+            edges.push_back(new_edge);
+          } else {
+            std::unordered_set<int> seen;
+            ASSERT_TRUE(IsReachable(&edges, nodes[to], nodes[from], &seen))
+                << "Edge " << nodes[to] << "->" << nodes[from];
+          }
+        }
+      }
+      break;
+
+    case 3:    // Remove an edge
+      if (edges.size() > 0) {
+        int i = RandomEdge(&rng, &edges);
+        int from = edges[i].from;
+        int to = edges[i].to;
+        ASSERT_EQ(i, EdgeIndex(&edges, from, to));
+        edges[i] = edges.back();
+        edges.pop_back();
+        ASSERT_EQ(-1, EdgeIndex(&edges, from, to));
+        graph_cycles.RemoveEdge(id[from], id[to]);
+      }
+      break;
+
+    case 4:   // Check a path
+      if (nodes.size() > 0) {
+        int from = RandomNode(&rng, &nodes);
+        int to = RandomNode(&rng, &nodes);
+        GraphId path[2*kMaxNodes];
+        int path_len = graph_cycles.FindPath(id[nodes[from]], id[nodes[to]],
+                                             ABSL_ARRAYSIZE(path), path);
+        std::unordered_set<int> seen;
+        bool reachable = IsReachable(&edges, nodes[from], nodes[to], &seen);
+        bool gc_reachable =
+            graph_cycles.IsReachable(Get(id, nodes[from]), Get(id, nodes[to]));
+        ASSERT_EQ(path_len != 0, reachable);
+        ASSERT_EQ(path_len != 0, gc_reachable);
+        // In the following line, we add one because a node can appear
+        // twice, if the path is from that node to itself, perhaps via
+        // every other node.
+        ASSERT_LE(path_len, kMaxNodes + 1);
+        if (path_len != 0) {
+          ASSERT_EQ(id[nodes[from]], path[0]);
+          ASSERT_EQ(id[nodes[to]], path[path_len-1]);
+          for (int i = 1; i < path_len; i++) {
+            ASSERT_TRUE(graph_cycles.HasEdge(path[i-1], path[i]));
+          }
+        }
+      }
+      break;
+
+    case 5:  // Check invariants
+      CheckInvariants(graph_cycles);
+      break;
+
+    default:
+      ABSL_RAW_LOG(FATAL, "op %d", op);
+    }
+
+    // Very rarely, test graph expansion by adding then removing many nodes.
+    std::bernoulli_distribution one_in_1024(1.0 / 1024);
+    if (one_in_1024(rng)) {
+      CheckEdges(&nodes, &edges, id, &graph_cycles);
+      CheckTransitiveClosure(&nodes, &edges, id, &graph_cycles);
+      for (int i = 0; i != 256; i++) {
+        int new_node = next_node++;
+        GraphId new_gnode = graph_cycles.GetId(ptr(new_node));
+        ASSERT_NE(InvalidGraphId(), new_gnode);
+        id[new_node] = new_gnode;
+        ASSERT_EQ(ptr(new_node), graph_cycles.Ptr(new_gnode));
+        for (const auto &node : nodes) {
+          ASSERT_NE(node, new_node);
+        }
+        nodes.push_back(new_node);
+      }
+      for (int i = 0; i != 256; i++) {
+        ASSERT_GT(nodes.size(), 0);
+        int node_index = RandomNode(&rng, &nodes);
+        int node = nodes[node_index];
+        nodes[node_index] = nodes.back();
+        nodes.pop_back();
+        graph_cycles.RemoveNode(ptr(node));
+        id.erase(node);
+        int j = 0;
+        while (j != edges.size()) {
+          if (edges[j].from == node || edges[j].to == node) {
+            edges[j] = edges.back();
+            edges.pop_back();
+          } else {
+            j++;
+          }
+        }
+      }
+      CheckInvariants(graph_cycles);
+    }
+  }
+}
+
+class GraphCyclesTest : public ::testing::Test {
+ public:
+  IdMap id_;
+  GraphCycles g_;
+
+  static void* Ptr(int i) {
+    return reinterpret_cast<void*>(static_cast<uintptr_t>(i));
+  }
+
+  static int Num(void* ptr) {
+    return static_cast<int>(reinterpret_cast<uintptr_t>(ptr));
+  }
+
+  // Test relies on ith NewNode() call returning Node numbered i
+  GraphCyclesTest() {
+    for (int i = 0; i < 100; i++) {
+      id_[i] = g_.GetId(Ptr(i));
+    }
+    CheckInvariants(g_);
+  }
+
+  bool AddEdge(int x, int y) {
+    return g_.InsertEdge(Get(id_, x), Get(id_, y));
+  }
+
+  void AddMultiples() {
+    // For every node x > 0: add edge to 2*x, 3*x
+    for (int x = 1; x < 25; x++) {
+      EXPECT_TRUE(AddEdge(x, 2*x)) << x;
+      EXPECT_TRUE(AddEdge(x, 3*x)) << x;
+    }
+    CheckInvariants(g_);
+  }
+
+  std::string Path(int x, int y) {
+    GraphId path[5];
+    int np = g_.FindPath(Get(id_, x), Get(id_, y), ABSL_ARRAYSIZE(path), path);
+    std::string result;
+    for (int i = 0; i < np; i++) {
+      if (i >= ABSL_ARRAYSIZE(path)) {
+        result += " ...";
+        break;
+      }
+      if (!result.empty()) result.push_back(' ');
+      char buf[20];
+      snprintf(buf, sizeof(buf), "%d", Num(g_.Ptr(path[i])));
+      result += buf;
+    }
+    return result;
+  }
+};
+
+TEST_F(GraphCyclesTest, NoCycle) {
+  AddMultiples();
+  CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, SimpleCycle) {
+  AddMultiples();
+  EXPECT_FALSE(AddEdge(8, 4));
+  EXPECT_EQ("4 8", Path(4, 8));
+  CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, IndirectCycle) {
+  AddMultiples();
+  EXPECT_TRUE(AddEdge(16, 9));
+  CheckInvariants(g_);
+  EXPECT_FALSE(AddEdge(9, 2));
+  EXPECT_EQ("2 4 8 16 9", Path(2, 9));
+  CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, LongPath) {
+  ASSERT_TRUE(AddEdge(2, 4));
+  ASSERT_TRUE(AddEdge(4, 6));
+  ASSERT_TRUE(AddEdge(6, 8));
+  ASSERT_TRUE(AddEdge(8, 10));
+  ASSERT_TRUE(AddEdge(10, 12));
+  ASSERT_FALSE(AddEdge(12, 2));
+  EXPECT_EQ("2 4 6 8 10 ...", Path(2, 12));
+  CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, RemoveNode) {
+  ASSERT_TRUE(AddEdge(1, 2));
+  ASSERT_TRUE(AddEdge(2, 3));
+  ASSERT_TRUE(AddEdge(3, 4));
+  ASSERT_TRUE(AddEdge(4, 5));
+  g_.RemoveNode(g_.Ptr(id_[3]));
+  id_.erase(3);
+  ASSERT_TRUE(AddEdge(5, 1));
+}
+
+TEST_F(GraphCyclesTest, ManyEdges) {
+  const int N = 50;
+  for (int i = 0; i < N; i++) {
+    for (int j = 1; j < N; j++) {
+      ASSERT_TRUE(AddEdge(i, i+j));
+    }
+  }
+  CheckInvariants(g_);
+  ASSERT_TRUE(AddEdge(2*N-1, 0));
+  CheckInvariants(g_);
+  ASSERT_FALSE(AddEdge(10, 9));
+  CheckInvariants(g_);
+}
+
+}  // namespace synchronization_internal
+}  // namespace absl
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
new file mode 100644
index 0000000..0d132d9
--- /dev/null
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -0,0 +1,149 @@
+// Copyright 2017 The Abseil 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.
+//
+
+// An optional absolute timeout, with nanosecond granularity,
+// compatible with absl::Time. Suitable for in-register
+// parameter-passing (e.g. syscalls.)
+// Constructible from a absl::Time (for a timeout to be respected) or {}
+// (for "no timeout".)
+// This is a private low-level API for use by a handful of low-level
+// components that are friends of this class. Higher-level components
+// should build APIs based on absl::Time and absl::Duration.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+
+#ifdef _WIN32
+#include <intsafe.h>
+#endif
+#include <time.h>
+#include <algorithm>
+#include <limits>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+class Futex;
+class Waiter;
+
+class KernelTimeout {
+ public:
+  // A timeout that should expire at <t>.  Any value, in the full
+  // InfinitePast() to InfiniteFuture() range, is valid here and will be
+  // respected.
+  explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {}
+  // No timeout.
+  KernelTimeout() : ns_(0) {}
+
+  // A more explicit factory for those who prefer it.  Equivalent to {}.
+  static KernelTimeout Never() { return {}; }
+
+  // We explicitly do not support other custom formats: timespec, int64_t nanos.
+  // Unify on this and absl::Time, please.
+  bool has_timeout() const { return ns_ != 0; }
+
+ private:
+  // internal rep, not user visible: ns after unix epoch.
+  // zero = no timeout.
+  // Negative we treat as an unlikely (and certainly expired!) but valid
+  // timeout.
+  int64_t ns_;
+
+  static int64_t MakeNs(absl::Time t) {
+    // optimization--InfiniteFuture is common "no timeout" value
+    // and cheaper to compare than convert.
+    if (t == absl::InfiniteFuture()) return 0;
+    int64_t x = ToUnixNanos(t);
+
+    // A timeout that lands exactly on the epoch (x=0) needs to be respected,
+    // so we alter it unnoticably to 1.  Negative timeouts are in
+    // theory supported, but handled poorly by the kernel (long
+    // delays) so push them forward too; since all such times have
+    // already passed, it's indistinguishable.
+    if (x <= 0) x = 1;
+    // A time larger than what can be represented to the kernel is treated
+    // as no timeout.
+    if (x == std::numeric_limits<int64_t>::max()) x = 0;
+    return x;
+  }
+
+  // Convert to parameter for sem_timedwait/futex/similar.  Only for approved
+  // users.  Do not call if !has_timeout.
+  struct timespec MakeAbsTimespec() {
+    int64_t n = ns_;
+    static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+    if (n == 0) {
+      ABSL_RAW_LOG(
+          ERROR,
+          "Tried to create a timespec from a non-timeout; never do this.");
+      // But we'll try to continue sanely.  no-timeout ~= saturated timeout.
+      n = std::numeric_limits<int64_t>::max();
+    }
+
+    // Kernel APIs validate timespecs as being at or after the epoch,
+    // despite the kernel time type being signed.  However, no one can
+    // tell the difference between a timeout at or before the epoch (since
+    // all such timeouts have expired!)
+    if (n < 0) n = 0;
+
+    struct timespec abstime;
+    int64_t seconds = std::min(n / kNanosPerSecond,
+                             int64_t{std::numeric_limits<time_t>::max()});
+    abstime.tv_sec = static_cast<time_t>(seconds);
+    abstime.tv_nsec =
+        static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
+    return abstime;
+  }
+
+#ifdef _WIN32
+  // Converts to milliseconds from now, or INFINITE when
+  // !has_timeout(). For use by SleepConditionVariableSRW on
+  // Windows. Callers should recognize that the return value is a
+  // relative duration (it should be recomputed by calling this method
+  // in the case of a spurious wakeup).
+  DWORD InMillisecondsFromNow() const {
+    if (!has_timeout()) {
+      return INFINITE;
+    }
+    // The use of absl::Now() to convert from absolute time to
+    // relative time means that absl::Now() cannot use anything that
+    // depends on KernelTimeout (for example, Mutex) on Windows.
+    int64_t now = ToUnixNanos(absl::Now());
+    if (ns_ >= now) {
+      // Round up so that Now() + ms_from_now >= ns_.
+      constexpr uint64_t max_nanos =
+          std::numeric_limits<int64_t>::max() - 999999u;
+      uint64_t ms_from_now =
+          (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;
+      if (ms_from_now > std::numeric_limits<DWORD>::max()) {
+        return INFINITE;
+      }
+      return static_cast<DWORD>(ms_from_now);
+    }
+    return 0;
+  }
+#endif
+
+  friend class Futex;
+  friend class Waiter;
+};
+
+}  // namespace synchronization_internal
+}  // namespace absl
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/absl/synchronization/internal/mutex_nonprod.cc b/absl/synchronization/internal/mutex_nonprod.cc
new file mode 100644
index 0000000..45c6032
--- /dev/null
+++ b/absl/synchronization/internal/mutex_nonprod.cc
@@ -0,0 +1,318 @@
+// Copyright 2017 The Abseil 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.
+
+// Implementation of a small subset of Mutex and CondVar functionality
+// for platforms where the production implementation hasn't been fully
+// ported yet.
+
+#include "absl/synchronization/mutex.h"
+
+#if defined(_WIN32)
+#include <chrono>  // NOLINT(build/c++11)
+#else
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include <algorithm>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+namespace {
+
+// Return the current time plus the timeout.
+absl::Time DeadlineFromTimeout(absl::Duration timeout) {
+  return absl::Now() + timeout;
+}
+
+// Limit the deadline to a positive, 32-bit time_t value to accommodate
+// implementation restrictions.  This also deals with InfinitePast and
+// InfiniteFuture.
+absl::Time LimitedDeadline(absl::Time deadline) {
+  deadline = std::max(absl::FromTimeT(0), deadline);
+  deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
+  return deadline;
+}
+
+}  // namespace
+
+#if defined(_WIN32)
+
+MutexImpl::MutexImpl() {}
+
+MutexImpl::~MutexImpl() {
+  if (locked_) {
+    std_mutex_.unlock();
+  }
+}
+
+void MutexImpl::Lock() {
+  std_mutex_.lock();
+  locked_ = true;
+}
+
+bool MutexImpl::TryLock() {
+  bool locked = std_mutex_.try_lock();
+  if (locked) locked_ = true;
+  return locked;
+}
+
+void MutexImpl::Unlock() {
+  locked_ = false;
+  released_.SignalAll();
+  std_mutex_.unlock();
+}
+
+CondVarImpl::CondVarImpl() {}
+
+CondVarImpl::~CondVarImpl() {}
+
+void CondVarImpl::Signal() { std_cv_.notify_one(); }
+
+void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
+
+void CondVarImpl::Wait(MutexImpl* mu) {
+  mu->released_.SignalAll();
+  std_cv_.wait(mu->std_mutex_);
+}
+
+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
+  mu->released_.SignalAll();
+  time_t when = ToTimeT(deadline);
+  int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
+  std::chrono::system_clock::time_point deadline_tp =
+      std::chrono::system_clock::from_time_t(when) +
+      std::chrono::duration_cast<std::chrono::system_clock::duration>(
+          std::chrono::nanoseconds(nanos));
+  auto deadline_since_epoch =
+      std::chrono::duration_cast<std::chrono::duration<double>>(
+          deadline_tp - std::chrono::system_clock::from_time_t(0));
+  return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
+         std::cv_status::timeout;
+}
+
+#else  // ! _WIN32
+
+MutexImpl::MutexImpl() {
+  ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
+                 "pthread error");
+}
+
+MutexImpl::~MutexImpl() {
+  if (locked_) {
+    ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
+  }
+  ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
+}
+
+void MutexImpl::Lock() {
+  ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
+  locked_ = true;
+}
+
+bool MutexImpl::TryLock() {
+  bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
+  if (locked) locked_ = true;
+  return locked;
+}
+
+void MutexImpl::Unlock() {
+  locked_ = false;
+  released_.SignalAll();
+  ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
+}
+
+CondVarImpl::CondVarImpl() {
+  ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
+                 "pthread error");
+}
+
+CondVarImpl::~CondVarImpl() {
+  ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::Signal() {
+  ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::SignalAll() {
+  ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::Wait(MutexImpl* mu) {
+  mu->released_.SignalAll();
+  ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
+                 "pthread error");
+}
+
+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
+  mu->released_.SignalAll();
+  struct timespec ts = ToTimespec(deadline);
+  int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
+  if (rc == ETIMEDOUT) return true;
+  ABSL_RAW_CHECK(rc == 0, "pthread error");
+  return false;
+}
+
+#endif  // ! _WIN32
+
+void MutexImpl::Await(const Condition& cond) {
+  if (cond.Eval()) return;
+  released_.SignalAll();
+  do {
+    released_.Wait(this);
+  } while (!cond.Eval());
+}
+
+bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
+  if (cond.Eval()) return true;
+  released_.SignalAll();
+  while (true) {
+    if (released_.WaitWithDeadline(this, deadline)) return false;
+    if (cond.Eval()) return true;
+  }
+}
+
+}  // namespace synchronization_internal
+
+Mutex::Mutex() {}
+
+Mutex::~Mutex() {}
+
+void Mutex::Lock() { impl()->Lock(); }
+
+void Mutex::Unlock() { impl()->Unlock(); }
+
+bool Mutex::TryLock() { return impl()->TryLock(); }
+
+void Mutex::ReaderLock() { Lock(); }
+
+void Mutex::ReaderUnlock() { Unlock(); }
+
+void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
+
+void Mutex::LockWhen(const Condition& cond) {
+  Lock();
+  Await(cond);
+}
+
+bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
+  return impl()->AwaitWithDeadline(
+      cond, synchronization_internal::LimitedDeadline(deadline));
+}
+
+bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
+  return AwaitWithDeadline(
+      cond, synchronization_internal::DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
+  Lock();
+  return AwaitWithDeadline(cond, deadline);
+}
+
+bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
+  return LockWhenWithDeadline(
+      cond, synchronization_internal::DeadlineFromTimeout(timeout));
+}
+
+void Mutex::ReaderLockWhen(const Condition& cond) {
+  ReaderLock();
+  Await(cond);
+}
+
+bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
+                                      absl::Duration timeout) {
+  return LockWhenWithTimeout(cond, timeout);
+}
+bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
+                                       absl::Time deadline) {
+  return LockWhenWithDeadline(cond, deadline);
+}
+
+void Mutex::EnableDebugLog(const char*) {}
+void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
+void Mutex::ForgetDeadlockInfo() {}
+void Mutex::AssertHeld() const {}
+void Mutex::AssertReaderHeld() const {}
+void Mutex::AssertNotHeld() const {}
+
+CondVar::CondVar() {}
+
+CondVar::~CondVar() {}
+
+void CondVar::Signal() { impl()->Signal(); }
+
+void CondVar::SignalAll() { impl()->SignalAll(); }
+
+void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
+
+bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
+  return impl()->WaitWithDeadline(
+      mu->impl(), synchronization_internal::LimitedDeadline(deadline));
+}
+
+bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
+  return WaitWithDeadline(mu, absl::Now() + timeout);
+}
+
+void CondVar::EnableDebugLog(const char*) {}
+
+#ifdef THREAD_SANITIZER
+extern "C" void __tsan_read1(void *addr);
+#else
+#define __tsan_read1(addr)  // do nothing if TSan not enabled
+#endif
+
+// A function that just returns its argument, dereferenced
+static bool Dereference(void *arg) {
+  // ThreadSanitizer does not instrument this file for memory accesses.
+  // This function dereferences a user variable that can participate
+  // in a data race, so we need to manually tell TSan about this memory access.
+  __tsan_read1(arg);
+  return *(static_cast<bool *>(arg));
+}
+
+Condition::Condition() {}   // null constructor, used for kTrue only
+const Condition Condition::kTrue;
+
+Condition::Condition(bool (*func)(void *), void *arg)
+    : eval_(&CallVoidPtrFunction),
+      function_(func),
+      method_(nullptr),
+      arg_(arg) {}
+
+bool Condition::CallVoidPtrFunction(const Condition *c) {
+  return (*c->function_)(c->arg_);
+}
+
+Condition::Condition(const bool *cond)
+    : eval_(CallVoidPtrFunction),
+      function_(Dereference),
+      method_(nullptr),
+      // const_cast is safe since Dereference does not modify arg
+      arg_(const_cast<bool *>(cond)) {}
+
+bool Condition::Eval() const {
+  // eval_ == null for kTrue
+  return (this->eval_ == nullptr) || (*this->eval_)(this);
+}
+
+void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
+
+}  // namespace absl
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc
new file mode 100644
index 0000000..0aab3d1
--- /dev/null
+++ b/absl/synchronization/internal/mutex_nonprod.inc
@@ -0,0 +1,256 @@
+// Do not include.  This is an implementation detail of base/mutex.h.
+//
+// Declares three classes:
+//
+// base::internal::MutexImpl - implementation helper for Mutex
+// base::internal::CondVarImpl - implementation helper for CondVar
+// base::internal::SynchronizationStorage<T> - implementation helper for
+//                                             Mutex, CondVar
+
+#include <type_traits>
+
+#if defined(_WIN32)
+#include <condition_variable>
+#include <mutex>
+#else
+#include <pthread.h>
+#endif
+
+#include "absl/base/call_once.h"
+#include "absl/time/time.h"
+
+// Declare that Mutex::ReaderLock is actually Lock().  Intended primarily
+// for tests, and even then as a last resort.
+#ifdef ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
+#error ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE cannot be directly set
+#else
+#define ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE 1
+#endif
+
+// Declare that Mutex::EnableInvariantDebugging is not implemented.
+// Intended primarily for tests, and even then as a last resort.
+#ifdef ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED
+#error ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED cannot be directly set
+#else
+#define ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED 1
+#endif
+
+namespace absl {
+class Condition;
+
+namespace synchronization_internal {
+
+class MutexImpl;
+
+// Do not use this implementation detail of CondVar. Provides most of the
+// implementation, but should not be placed directly in static storage
+// because it will not linker initialize properly. See
+// SynchronizationStorage<T> below for what we mean by linker
+// initialization.
+class CondVarImpl {
+ public:
+  CondVarImpl();
+  CondVarImpl(const CondVarImpl&) = delete;
+  CondVarImpl& operator=(const CondVarImpl&) = delete;
+  ~CondVarImpl();
+
+  void Signal();
+  void SignalAll();
+  void Wait(MutexImpl* mutex);
+  bool WaitWithDeadline(MutexImpl* mutex, absl::Time deadline);
+
+ private:
+#if defined(_WIN32)
+  std::condition_variable_any std_cv_;
+#else
+  pthread_cond_t pthread_cv_;
+#endif
+};
+
+// Do not use this implementation detail of Mutex. Provides most of the
+// implementation, but should not be placed directly in static storage
+// because it will not linker initialize properly. See
+// SynchronizationStorage<T> below for what we mean by linker
+// initialization.
+class MutexImpl {
+ public:
+  MutexImpl();
+  MutexImpl(const MutexImpl&) = delete;
+  MutexImpl& operator=(const MutexImpl&) = delete;
+  ~MutexImpl();
+
+  void Lock();
+  bool TryLock();
+  void Unlock();
+  void Await(const Condition& cond);
+  bool AwaitWithDeadline(const Condition& cond, absl::Time deadline);
+
+ private:
+  friend class CondVarImpl;
+
+#if defined(_WIN32)
+  std::mutex std_mutex_;
+#else
+  pthread_mutex_t pthread_mutex_;
+#endif
+
+  // True if the underlying mutex is locked.  If the destructor is entered
+  // while locked_, the underlying mutex is unlocked.  Mutex supports
+  // destruction while locked, but the same is undefined behavior for both
+  // pthread_mutex_t and std::mutex.
+  bool locked_ = false;
+
+  // Signaled before releasing the lock, in support of Await.
+  CondVarImpl released_;
+};
+
+// Do not use this implementation detail of CondVar and Mutex.  A storage
+// space for T that supports a LinkerInitialized constructor. T must
+// have a default constructor, which is called by the first call to
+// get(). T's destructor is never called if the LinkerInitialized
+// constructor is called.
+//
+// Objects constructed with the default constructor are constructed and
+// destructed like any other object, and should never be allocated in
+// static storage.
+//
+// Objects constructed with the LinkerInitialized constructor should
+// always be in static storage. For such objects, calls to get() are always
+// valid, except from signal handlers.
+//
+// Note that this implementation relies on undefined language behavior that
+// are known to hold for the set of supported compilers. An analysis
+// follows.
+//
+// From the C++11 standard:
+//
+// [basic.life] says an object has non-trivial initialization if it is of
+// class type and it is initialized by a constructor other than a trivial
+// default constructor.  (the LinkerInitialized constructor is
+// non-trivial)
+//
+// [basic.life] says the lifetime of an object with a non-trivial
+// constructor begins when the call to the constructor is complete.
+//
+// [basic.life] says the lifetime of an object with non-trivial destructor
+// ends when the call to the destructor begins.
+//
+// [basic.life] p5 specifies undefined behavior when accessing non-static
+// members of an instance outside its
+// lifetime. (SynchronizationStorage::get() access non-static members)
+//
+// So, LinkerInitialized object of SynchronizationStorage uses a
+// non-trivial constructor, which is called at some point during dynamic
+// initialization, and is therefore subject to order of dynamic
+// initialization bugs, where get() is called before the object's
+// constructor is, resulting in undefined behavior.
+//
+// Similarly, a LinkerInitialized SynchronizationStorage object has a
+// non-trivial destructor, and so its lifetime ends at some point during
+// destruction of objects with static storage duration [basic.start.term]
+// p4. There is a window where other exit code could call get() after this
+// occurs, resulting in undefined behavior.
+//
+// Combined, these statements imply that LinkerInitialized instances
+// of SynchronizationStorage<T> rely on undefined behavior.
+//
+// However, in practice, the implementation works on all supported
+// compilers. Specifically, we rely on:
+//
+// a) zero-initialization being sufficient to initialize
+// LinkerInitialized instances for the purposes of calling
+// get(), regardless of when the constructor is called. This is
+// because the is_dynamic_ boolean is correctly zero-initialized to
+// false.
+//
+// b) the LinkerInitialized constructor is a NOP, and immaterial to
+// even to concurrent calls to get().
+//
+// c) the destructor being a NOP for LinkerInitialized objects
+// (guaranteed by a check for !is_dynamic_), and so any concurrent and
+// subsequent calls to get() functioning as if the destructor were not
+// called, by virtue of the instances' storage remaining valid after the
+// destructor runs.
+//
+// d) That a-c apply transitively when SynchronizationStorage<T> is the
+// only member of a class allocated in static storage.
+//
+// Nothing in the language standard guarantees that a-d hold.  In practice,
+// these hold in all supported compilers.
+//
+// Future direction:
+//
+// Ideally, we would simply use std::mutex or a similar class, which when
+// allocated statically would support use immediately after static
+// initialization up until static storage is reclaimed (i.e. the properties
+// we require of all "linker initialized" instances).
+//
+// Regarding construction in static storage, std::mutex is required to
+// provide a constexpr default constructor [thread.mutex.class], which
+// ensures the instance's lifetime begins with static initialization
+// [basic.start.init], and so is immune to any problems caused by the order
+// of dynamic initialization. However, as of this writing Microsoft's
+// Visual Studio does not provide a constexpr constructor for std::mutex.
+// See
+// https://blogs.msdn.microsoft.com/vcblog/2015/06/02/constexpr-complete-for-vs-2015-rtm-c11-compiler-c17-stl/
+//
+// Regarding destruction of instances in static storage, [basic.life] does
+// say an object ends when storage in which the occupies is released, in
+// the case of non-trivial destructor. However, std::mutex is not specified
+// to have a trivial destructor.
+//
+// So, we would need a class with a constexpr default constructor and a
+// trivial destructor. Today, we can achieve neither desired property using
+// std::mutex directly.
+template <typename T>
+class SynchronizationStorage {
+ public:
+  // Instances allocated on the heap or on the stack should use the default
+  // constructor.
+  SynchronizationStorage()
+      : is_dynamic_(true), once_() {}
+
+  // Instances allocated in static storage (not on the heap, not on the
+  // stack) should use this constructor.
+  explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
+
+  SynchronizationStorage(SynchronizationStorage&) = delete;
+  SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
+
+  ~SynchronizationStorage() {
+    if (is_dynamic_) {
+      get()->~T();
+    }
+  }
+
+  // Retrieve the object in storage. This is fast and thread safe, but does
+  // incur the cost of absl::call_once().
+  //
+  // For instances in static storage constructed with the
+  // LinkerInitialized constructor, may be called at any time without
+  // regard for order of dynamic initialization or destruction of objects
+  // in static storage. See the class comment for caveats.
+  T* get() {
+    absl::call_once(once_, SynchronizationStorage::Construct, this);
+    return reinterpret_cast<T*>(&space_);
+  }
+
+ private:
+  static void Construct(SynchronizationStorage<T>* self) {
+    new (&self->space_) T();
+  }
+
+  // When true, T's destructor is run when this is destructed.
+  //
+  // The LinkerInitialized constructor assumes this value will be set
+  // false by static initialization.
+  bool is_dynamic_;
+
+  absl::once_flag once_;
+
+  // An aligned space for T.
+  typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
+};
+
+}  // namespace synchronization_internal
+}  // namespace absl
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc
new file mode 100644
index 0000000..caa2baf
--- /dev/null
+++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -0,0 +1,99 @@
+// Copyright 2017 The Abseil 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.
+
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/waiter.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
+  base_internal::ThreadIdentity *identity;
+  identity = GetOrCreateCurrentThreadIdentity();
+  identity->blocked_count_ptr = counter;
+}
+
+std::atomic<int> *PerThreadSem::GetThreadBlockedCounter() {
+  base_internal::ThreadIdentity *identity;
+  identity = GetOrCreateCurrentThreadIdentity();
+  return identity->blocked_count_ptr;
+}
+
+void PerThreadSem::Init(base_internal::ThreadIdentity *identity) {
+  Waiter::GetWaiter(identity)->Init();
+  identity->ticker.store(0, std::memory_order_relaxed);
+  identity->wait_start.store(0, std::memory_order_relaxed);
+  identity->is_idle.store(false, std::memory_order_relaxed);
+}
+
+void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
+  const int ticker =
+      identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1;
+  const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+  const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+  if (wait_start && (ticker - wait_start > Waiter::kIdlePeriods) && !is_idle) {
+    // Wakeup the waiting thread since it is time for it to become idle.
+    Waiter::GetWaiter(identity)->Poke();
+  }
+}
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalPerThreadSemPost(
+    absl::base_internal::ThreadIdentity *identity) {
+  absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
+}
+
+ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait(
+    absl::synchronization_internal::KernelTimeout t) {
+  bool timeout = false;
+  absl::base_internal::ThreadIdentity *identity;
+  identity = absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
+
+  // Ensure wait_start != 0.
+  int ticker = identity->ticker.load(std::memory_order_relaxed);
+  identity->wait_start.store(ticker ? ticker : 1, std::memory_order_relaxed);
+  identity->is_idle.store(false, std::memory_order_relaxed);
+
+  if (identity->blocked_count_ptr != nullptr) {
+    // Increment count of threads blocked in a given thread pool.
+    identity->blocked_count_ptr->fetch_add(1, std::memory_order_relaxed);
+  }
+
+  timeout =
+      !absl::synchronization_internal::Waiter::GetWaiter(identity)->Wait(t);
+
+  if (identity->blocked_count_ptr != nullptr) {
+    identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
+  }
+  identity->is_idle.store(false, std::memory_order_relaxed);
+  identity->wait_start.store(0, std::memory_order_relaxed);
+  return !timeout;
+}
+
+}  // extern "C"
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h
new file mode 100644
index 0000000..678b69e
--- /dev/null
+++ b/absl/synchronization/internal/per_thread_sem.h
@@ -0,0 +1,107 @@
+// Copyright 2017 The Abseil 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.
+//
+
+// PerThreadSem is a low-level synchronization primitive controlling the
+// runnability of a single thread, used internally by Mutex and CondVar.
+//
+// This is NOT a general-purpose synchronization mechanism, and should not be
+// used directly by applications.  Applications should use Mutex and CondVar.
+//
+// The semantics of PerThreadSem are the same as that of a counting semaphore.
+// Each thread maintains an abstract "count" value associated with its identity.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+
+#include <atomic>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+
+class Mutex;
+
+namespace synchronization_internal {
+
+class PerThreadSem {
+ public:
+  PerThreadSem() = delete;
+  PerThreadSem(const PerThreadSem&) = delete;
+  PerThreadSem& operator=(const PerThreadSem&) = delete;
+
+  // Routine invoked periodically (once a second) by a background thread.
+  // Has no effect on user-visible state.
+  static void Tick(base_internal::ThreadIdentity* identity);
+
+  // ---------------------------------------------------------------------------
+  // Routines used by autosizing threadpools to detect when threads are
+  // blocked.  Each thread has a counter pointer, initially zero.  If non-zero,
+  // the implementation atomically increments the counter when it blocks on a
+  // semaphore, a decrements it again when it wakes.  This allows a threadpool
+  // to keep track of how many of its threads are blocked.
+  // SetThreadBlockedCounter() should be used only by threadpool
+  // implementations.  GetThreadBlockedCounter() should be used by modules that
+  // block threads; if the pointer returned is non-zero, the location should be
+  // incremented before the thread blocks, and decremented after it wakes.
+  static void SetThreadBlockedCounter(std::atomic<int> *counter);
+  static std::atomic<int> *GetThreadBlockedCounter();
+
+ private:
+  // Create the PerThreadSem associated with "identity".  Initializes count=0.
+  // REQUIRES: May only be called by ThreadIdentity.
+  static void Init(base_internal::ThreadIdentity* identity);
+
+  // Increments "identity"'s count.
+  static inline void Post(base_internal::ThreadIdentity* identity);
+
+  // Waits until either our count > 0 or t has expired.
+  // If count > 0, decrements count and returns true.  Otherwise returns false.
+  // !t.has_timeout() => Wait(t) will return true.
+  static inline bool Wait(KernelTimeout t);
+
+  // White-listed callers.
+  friend class PerThreadSemTest;
+  friend class absl::Mutex;
+  friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
+};
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void AbslInternalPerThreadSemPost(
+    absl::base_internal::ThreadIdentity* identity);
+bool AbslInternalPerThreadSemWait(
+    absl::synchronization_internal::KernelTimeout t);
+}  // extern "C"
+
+void absl::synchronization_internal::PerThreadSem::Post(
+    absl::base_internal::ThreadIdentity* identity) {
+  AbslInternalPerThreadSemPost(identity);
+}
+
+bool absl::synchronization_internal::PerThreadSem::Wait(
+    absl::synchronization_internal::KernelTimeout t) {
+  return AbslInternalPerThreadSemWait(t);
+}
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/per_thread_sem_test.cc b/absl/synchronization/internal/per_thread_sem_test.cc
new file mode 100644
index 0000000..2b52ea7
--- /dev/null
+++ b/absl/synchronization/internal/per_thread_sem_test.cc
@@ -0,0 +1,172 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+#include <condition_variable>  // NOLINT(build/c++11)
+#include <functional>
+#include <limits>
+#include <mutex>               // NOLINT(build/c++11)
+#include <string>
+#include <thread>              // NOLINT(build/c++11)
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/strings/str_cat.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+// In this test we explicitly avoid the use of synchronization
+// primitives which might use PerThreadSem, most notably absl::Mutex.
+
+namespace absl {
+namespace synchronization_internal {
+
+class SimpleSemaphore {
+ public:
+  SimpleSemaphore() : count_(0) {}
+
+  // Decrements (locks) the semaphore. If the semaphore's value is
+  // greater than zero, then the decrement proceeds, and the function
+  // returns, immediately. If the semaphore currently has the value
+  // zero, then the call blocks until it becomes possible to perform
+  // the decrement.
+  void Wait() {
+    std::unique_lock<std::mutex> lock(mu_);
+    cv_.wait(lock, [this]() { return count_ > 0; });
+    --count_;
+    cv_.notify_one();
+  }
+
+  // Increments (unlocks) the semaphore. If the semaphore's value
+  // consequently becomes greater than zero, then another thread
+  // blocked Wait() call will be woken up and proceed to lock the
+  // semaphore.
+  void Post() {
+    std::lock_guard<std::mutex> lock(mu_);
+    ++count_;
+    cv_.notify_one();
+  }
+
+ private:
+  std::mutex mu_;
+  std::condition_variable cv_;
+  int count_;
+};
+
+struct ThreadData {
+  int num_iterations;                 // Number of replies to send.
+  SimpleSemaphore identity2_written;  // Posted by thread writing identity2.
+  base_internal::ThreadIdentity *identity1;  // First Post()-er.
+  base_internal::ThreadIdentity *identity2;  // First Wait()-er.
+  KernelTimeout timeout;
+};
+
+// Need friendship with PerThreadSem.
+class PerThreadSemTest : public testing::Test {
+ public:
+  static void TimingThread(ThreadData* t) {
+    t->identity2 = GetOrCreateCurrentThreadIdentity();
+    t->identity2_written.Post();
+    while (t->num_iterations--) {
+      Wait(t->timeout);
+      Post(t->identity1);
+    }
+  }
+
+  void TestTiming(const char *msg, bool timeout) {
+    static const int kNumIterations = 100;
+    ThreadData t;
+    t.num_iterations = kNumIterations;
+    t.timeout = timeout ?
+        KernelTimeout(absl::Now() + absl::Seconds(10000))  // far in the future
+        : KernelTimeout::Never();
+    t.identity1 = GetOrCreateCurrentThreadIdentity();
+
+    // We can't use the Thread class here because it uses the Mutex
+    // class which will invoke PerThreadSem, so we use std::thread instead.
+    std::thread partner_thread(std::bind(TimingThread, &t));
+
+    // Wait for our partner thread to register their identity.
+    t.identity2_written.Wait();
+
+    int64_t min_cycles = std::numeric_limits<int64_t>::max();
+    int64_t total_cycles = 0;
+    for (int i = 0; i < kNumIterations; ++i) {
+      absl::SleepFor(absl::Milliseconds(20));
+      int64_t cycles = base_internal::CycleClock::Now();
+      Post(t.identity2);
+      Wait(t.timeout);
+      cycles = base_internal::CycleClock::Now() - cycles;
+      min_cycles = std::min(min_cycles, cycles);
+      total_cycles += cycles;
+    }
+    std::string out =
+        StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=",
+               absl::SixDigits(static_cast<double>(total_cycles) /
+                               kNumIterations));
+    printf("%s\n", out.c_str());
+
+    partner_thread.join();
+  }
+
+ protected:
+  static void Post(base_internal::ThreadIdentity *id) {
+    PerThreadSem::Post(id);
+  }
+  static bool Wait(KernelTimeout t) {
+    return PerThreadSem::Wait(t);
+  }
+
+  // convenience overload
+  static bool Wait(absl::Time t) {
+    return Wait(KernelTimeout(t));
+  }
+
+  static void Tick(base_internal::ThreadIdentity *identity) {
+    PerThreadSem::Tick(identity);
+  }
+};
+
+namespace {
+
+TEST_F(PerThreadSemTest, WithoutTimeout) {
+  PerThreadSemTest::TestTiming("Without timeout: ", false);
+}
+
+TEST_F(PerThreadSemTest, WithTimeout) {
+  PerThreadSemTest::TestTiming("With timeout:    ", true);
+}
+
+TEST_F(PerThreadSemTest, Timeouts) {
+  absl::Time timeout = absl::Now() + absl::Milliseconds(50);
+  EXPECT_FALSE(Wait(timeout));
+  EXPECT_LE(timeout, absl::Now());
+
+  absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100);
+  EXPECT_FALSE(Wait(negative_timeout));
+  EXPECT_LE(negative_timeout, absl::Now());  // trivially true :)
+
+  Post(GetOrCreateCurrentThreadIdentity());
+  // The wait here has an expired timeout, but we have a wake to consume,
+  // so this should succeed
+  EXPECT_TRUE(Wait(negative_timeout));
+}
+
+}  // namespace
+
+}  // namespace synchronization_internal
+}  // namespace absl
diff --git a/absl/synchronization/internal/thread_pool.h b/absl/synchronization/internal/thread_pool.h
new file mode 100644
index 0000000..8464042
--- /dev/null
+++ b/absl/synchronization/internal/thread_pool.h
@@ -0,0 +1,90 @@
+// Copyright 2017 The Abseil 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 ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+
+#include <cassert>
+#include <functional>
+#include <queue>
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// A simple ThreadPool implementation for tests.
+class ThreadPool {
+ public:
+  explicit ThreadPool(int num_threads) {
+    for (int i = 0; i < num_threads; ++i) {
+      threads_.push_back(std::thread(&ThreadPool::WorkLoop, this));
+    }
+  }
+
+  ThreadPool(const ThreadPool &) = delete;
+  ThreadPool &operator=(const ThreadPool &) = delete;
+
+  ~ThreadPool() {
+    {
+      absl::MutexLock l(&mu_);
+      for (int i = 0; i < threads_.size(); ++i) {
+        queue_.push(nullptr);  // Shutdown signal.
+      }
+    }
+    for (auto &t : threads_) {
+      t.join();
+    }
+  }
+
+  // Schedule a function to be run on a ThreadPool thread immediately.
+  void Schedule(std::function<void()> func) {
+    assert(func != nullptr);
+    absl::MutexLock l(&mu_);
+    queue_.push(std::move(func));
+  }
+
+ private:
+  bool WorkAvailable() const EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+    return !queue_.empty();
+  }
+
+  void WorkLoop() {
+    while (true) {
+      std::function<void()> func;
+      {
+        absl::MutexLock l(&mu_);
+        mu_.Await(absl::Condition(this, &ThreadPool::WorkAvailable));
+        func = std::move(queue_.front());
+        queue_.pop();
+      }
+      if (func == nullptr) {  // Shutdown signal.
+        break;
+      }
+      func();
+    }
+  }
+
+  absl::Mutex mu_;
+  std::queue<std::function<void()>> queue_ GUARDED_BY(mu_);
+  std::vector<std::thread> threads_;
+};
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
new file mode 100644
index 0000000..768c520
--- /dev/null
+++ b/absl/synchronization/internal/waiter.cc
@@ -0,0 +1,412 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/internal/waiter.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+static void MaybeBecomeIdle() {
+  base_internal::ThreadIdentity *identity =
+      base_internal::CurrentThreadIdentityIfPresent();
+  assert(identity != nullptr);
+  const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+  const int ticker = identity->ticker.load(std::memory_order_relaxed);
+  const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+  if (!is_idle && ticker - wait_start > Waiter::kIdlePeriods) {
+    identity->is_idle.store(true, std::memory_order_relaxed);
+  }
+}
+
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+class Futex {
+ public:
+  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+                       KernelTimeout t) {
+    int err = 0;
+    if (t.has_timeout()) {
+      // https://locklessinc.com/articles/futex_cheat_sheet/
+      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+      struct timespec abs_timeout = t.MakeAbsTimespec();
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+      err = syscall(
+          SYS_futex, reinterpret_cast<int32_t *>(v),
+          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    } else {
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until woken by FUTEX_WAKE.
+      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+    }
+    if (err != 0) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int Wake(std::atomic<int32_t> *v, int32_t count) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+};
+
+void Waiter::Init() {
+  futex_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+  // Loop until we can atomically decrement futex from a positive
+  // value, waiting on a futex while we believe it is zero.
+  while (true) {
+    int32_t x = futex_.load(std::memory_order_relaxed);
+    if (x != 0) {
+      if (!futex_.compare_exchange_weak(x, x - 1,
+                                        std::memory_order_acquire,
+                                        std::memory_order_relaxed)) {
+        continue;  // Raced with someone, retry.
+      }
+      return true;  // Consumed a wakeup, we are done.
+    }
+
+    const int err = Futex::WaitUntil(&futex_, 0, t);
+    if (err != 0) {
+      if (err == -EINTR || err == -EWOULDBLOCK) {
+        // Do nothing, the loop will retry.
+      } else if (err == -ETIMEDOUT) {
+        return false;
+      } else {
+        ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
+      }
+    }
+
+    MaybeBecomeIdle();
+  }
+}
+
+void Waiter::Post() {
+  if (futex_.fetch_add(1, std::memory_order_release) == 0) {
+    // We incremented from 0, need to wake a potential waker.
+    Poke();
+  }
+}
+
+void Waiter::Poke() {
+  // Wake one thread waiting on the futex.
+  const int err = Futex::Wake(&futex_, 1);
+  if (ABSL_PREDICT_FALSE(err < 0)) {
+    ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
+  }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+
+class PthreadMutexHolder {
+ public:
+  explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
+    const int err = pthread_mutex_lock(mu_);
+    if (err != 0) {
+      ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
+    }
+  }
+
+  PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
+  PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
+
+  ~PthreadMutexHolder() {
+    const int err = pthread_mutex_unlock(mu_);
+    if (err != 0) {
+      ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
+    }
+  }
+
+ private:
+  pthread_mutex_t *mu_;
+};
+
+void Waiter::Init() {
+  const int err = pthread_mutex_init(&mu_, 0);
+  if (err != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
+  }
+
+  const int err2 = pthread_cond_init(&cv_, 0);
+  if (err2 != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
+  }
+
+  waiter_count_.store(0, std::memory_order_relaxed);
+  wakeup_count_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+  struct timespec abs_timeout;
+  if (t.has_timeout()) {
+    abs_timeout = t.MakeAbsTimespec();
+  }
+
+  PthreadMutexHolder h(&mu_);
+  waiter_count_.fetch_add(1, std::memory_order_relaxed);
+  // Loop until we find a wakeup to consume or timeout.
+  while (true) {
+    int x = wakeup_count_.load(std::memory_order_relaxed);
+    if (x != 0) {
+      if (!wakeup_count_.compare_exchange_weak(x, x - 1,
+                                               std::memory_order_acquire,
+                                               std::memory_order_relaxed)) {
+        continue;  // Raced with someone, retry.
+      }
+      // Successfully consumed a wakeup, we're done.
+      waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+      return true;
+    }
+
+    // No wakeups available, time to wait.
+    if (!t.has_timeout()) {
+      const int err = pthread_cond_wait(&cv_, &mu_);
+      if (err != 0) {
+        ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+      }
+    } else {
+      const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
+      if (err == ETIMEDOUT) {
+        waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+        return false;
+      }
+      if (err != 0) {
+        ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+      }
+    }
+    MaybeBecomeIdle();
+  }
+}
+
+void Waiter::Post() {
+  wakeup_count_.fetch_add(1, std::memory_order_release);
+  Poke();
+}
+
+void Waiter::Poke() {
+  if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+    return;
+  }
+  // Potentially a waker. Take the lock and check again.
+  PthreadMutexHolder h(&mu_);
+  if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+    return;
+  }
+  const int err = pthread_cond_signal(&cv_);
+  if (err != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
+  }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+
+void Waiter::Init() {
+  if (sem_init(&sem_, 0, 0) != 0) {
+    ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno);
+  }
+  wakeups_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+  struct timespec abs_timeout;
+  if (t.has_timeout()) {
+    abs_timeout = t.MakeAbsTimespec();
+  }
+
+  // Loop until we timeout or consume a wakeup.
+  while (true) {
+    int x = wakeups_.load(std::memory_order_relaxed);
+    if (x != 0) {
+      if (!wakeups_.compare_exchange_weak(x, x - 1,
+                                          std::memory_order_acquire,
+                                          std::memory_order_relaxed)) {
+        continue;  // Raced with someone, retry.
+      }
+      // Successfully consumed a wakeup, we're done.
+      return true;
+    }
+
+    // Nothing to consume, wait (looping on EINTR).
+    while (true) {
+      if (!t.has_timeout()) {
+        if (sem_wait(&sem_) == 0) break;
+        if (errno == EINTR) continue;
+        ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno);
+      } else {
+        if (sem_timedwait(&sem_, &abs_timeout) == 0) break;
+        if (errno == EINTR) continue;
+        if (errno == ETIMEDOUT) return false;
+        ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
+      }
+    }
+    MaybeBecomeIdle();
+  }
+}
+
+void Waiter::Post() {
+  wakeups_.fetch_add(1, std::memory_order_release);  // Post a wakeup.
+  Poke();
+}
+
+void Waiter::Poke() {
+  if (sem_post(&sem_) != 0) {  // Wake any semaphore waiter.
+    ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno);
+  }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+
+class LockHolder {
+ public:
+  explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
+    AcquireSRWLockExclusive(mu_);
+  }
+
+  LockHolder(const LockHolder&) = delete;
+  LockHolder& operator=(const LockHolder&) = delete;
+
+  ~LockHolder() {
+    ReleaseSRWLockExclusive(mu_);
+  }
+
+ private:
+  SRWLOCK* mu_;
+};
+
+void Waiter::Init() {
+  InitializeSRWLock(&mu_);
+  InitializeConditionVariable(&cv_);
+  waiter_count_.store(0, std::memory_order_relaxed);
+  wakeup_count_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+  LockHolder h(&mu_);
+  waiter_count_.fetch_add(1, std::memory_order_relaxed);
+
+  // Loop until we find a wakeup to consume or timeout.
+  while (true) {
+    int x = wakeup_count_.load(std::memory_order_relaxed);
+    if (x != 0) {
+      if (!wakeup_count_.compare_exchange_weak(x, x - 1,
+                                               std::memory_order_acquire,
+                                               std::memory_order_relaxed)) {
+        continue;  // Raced with someone, retry.
+      }
+      // Successfully consumed a wakeup, we're done.
+      waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+      return true;
+    }
+
+    // No wakeups available, time to wait.
+    if (!SleepConditionVariableSRW(
+            &cv_, &mu_, t.InMillisecondsFromNow(), 0)) {
+      // GetLastError() returns a Win32 DWORD, but we assign to
+      // unsigned long to simplify the ABSL_RAW_LOG case below.  The uniform
+      // initialization guarantees this is not a narrowing conversion.
+      const unsigned long err{GetLastError()};  // NOLINT(runtime/int)
+      if (err == ERROR_TIMEOUT) {
+        waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+        return false;
+      } else {
+        ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
+      }
+    }
+
+    MaybeBecomeIdle();
+  }
+}
+
+void Waiter::Post() {
+  wakeup_count_.fetch_add(1, std::memory_order_release);
+  Poke();
+}
+
+void Waiter::Poke() {
+  if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+    return;
+  }
+  // Potentially a waker. Take the lock and check again.
+  LockHolder h(&mu_);
+  if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+    return;
+  }
+  WakeConditionVariable(&cv_);
+}
+
+#else
+#error Unknown ABSL_WAITER_MODE
+#endif
+
+}  // namespace synchronization_internal
+}  // namespace absl
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
new file mode 100644
index 0000000..23166f4
--- /dev/null
+++ b/absl/synchronization/internal/waiter.h
@@ -0,0 +1,139 @@
+// Copyright 2017 The Abseil 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 ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+// May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
+#define ABSL_WAITER_MODE_FUTEX 0
+#define ABSL_WAITER_MODE_SEM 1
+#define ABSL_WAITER_MODE_CONDVAR 2
+#define ABSL_WAITER_MODE_WIN32 3
+
+#if defined(ABSL_FORCE_WAITER_MODE)
+#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
+#elif defined(_WIN32)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
+#elif defined(__linux__)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
+#elif defined(ABSL_HAVE_SEMAPHORE_H)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
+#else
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR
+#endif
+
+namespace absl {
+namespace synchronization_internal {
+
+// Waiter is an OS-specific semaphore.
+class Waiter {
+ public:
+  // No constructor, instances use the reserved space in ThreadIdentity.
+  // All initialization logic belongs in `Init()`.
+  Waiter() = delete;
+  Waiter(const Waiter&) = delete;
+  Waiter& operator=(const Waiter&) = delete;
+
+  // Prepare any data to track waits.
+  void Init();
+
+  // Blocks the calling thread until a matching call to `Post()` or
+  // `t` has passed. Returns `true` if woken (`Post()` called),
+  // `false` on timeout.
+  bool Wait(KernelTimeout t);
+
+  // Restart the caller of `Wait()` as with a normal semaphore.
+  void Post();
+
+  // If anyone is waiting, wake them up temporarily and cause them to
+  // call `MaybeBecomeIdle()`. They will then return to waiting for a
+  // `Post()` or timeout.
+  void Poke();
+
+  // Returns the Waiter associated with the identity.
+  static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) {
+    static_assert(
+        sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState),
+        "Insufficient space for Waiter");
+    return reinterpret_cast<Waiter*>(identity->waiter_state.data);
+  }
+
+  // How many periods to remain idle before releasing resources
+#ifndef THREAD_SANITIZER
+  static const int kIdlePeriods = 60;
+#else
+  // Memory consumption under ThreadSanitizer is a serious concern,
+  // so we release resources sooner. The value of 1 leads to 1 to 2 second
+  // delay before marking a thread as idle.
+  static const int kIdlePeriods = 1;
+#endif
+
+ private:
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+  // Futexes are defined by specification to be 32-bits.
+  // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods.
+  std::atomic<int32_t> futex_;
+  static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex");
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+  pthread_mutex_t mu_;
+  pthread_cond_t cv_;
+  std::atomic<int> waiter_count_;
+  std::atomic<int> wakeup_count_;  // Unclaimed wakeups, written under lock.
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+  sem_t sem_;
+  // This seems superfluous, but for Poke() we need to cause spurious
+  // wakeups on the semaphore. Hence we can't actually use the
+  // semaphore's count.
+  std::atomic<int> wakeups_;
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+  // The Windows API has lots of choices for synchronization
+  // primivitives.  We are using SRWLOCK and CONDITION_VARIABLE
+  // because they don't require a destructor to release system
+  // resources.
+  SRWLOCK mu_;
+  CONDITION_VARIABLE cv_;
+  std::atomic<int> waiter_count_;
+  std::atomic<int> wakeup_count_;
+
+#else
+  #error Unknown ABSL_WAITER_MODE
+#endif
+};
+
+}  // namespace synchronization_internal
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc
new file mode 100644
index 0000000..90c9009
--- /dev/null
+++ b/absl/synchronization/lifetime_test.cc
@@ -0,0 +1,132 @@
+// Copyright 2017 The Abseil 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 <cstdlib>
+#include <thread>  // NOLINT(build/c++11), Abseil test
+#include <type_traits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/synchronization/notification.h"
+
+namespace {
+
+// A two-threaded test which checks that Mutex, CondVar, and Notification have
+// correct basic functionality.  The intent is to establish that they
+// function correctly in various phases of construction and destruction.
+//
+// Thread one acquires a lock on 'mutex', wakes thread two via 'notification',
+// then waits for 'state' to be set, as signalled by 'condvar'.
+//
+// Thread two waits on 'notification', then sets 'state' inside the 'mutex',
+// signalling the change via 'condvar'.
+//
+// These tests use ABSL_RAW_CHECK to validate invariants, rather than EXPECT or
+// ASSERT from gUnit, because we need to invoke them during global destructors,
+// when gUnit teardown would have already begun.
+void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar,
+               absl::Notification* notification, bool* state) {
+  // Test that the notification is in a valid initial state.
+  ABSL_RAW_CHECK(!notification->HasBeenNotified(), "invalid Notification");
+  ABSL_RAW_CHECK(*state == false, "*state not initialized");
+
+  {
+    absl::MutexLock lock(mutex);
+
+    notification->Notify();
+    ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
+
+    while (*state == false) {
+      condvar->Wait(mutex);
+    }
+  }
+}
+
+void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar,
+               absl::Notification* notification, bool* state) {
+  ABSL_RAW_CHECK(*state == false, "*state not initialized");
+
+  // Wake thread one
+  notification->WaitForNotification();
+  ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
+  {
+    absl::MutexLock lock(mutex);
+    *state = true;
+    condvar->Signal();
+  }
+}
+
+// Launch thread 1 and thread 2, and block on their completion.
+// If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally
+// constructed instance instead.
+void RunTests(absl::Mutex* mutex, absl::CondVar* condvar,
+              absl::Notification* notification) {
+  absl::Mutex default_mutex;
+  absl::CondVar default_condvar;
+  absl::Notification default_notification;
+  if (!mutex) {
+    mutex = &default_mutex;
+  }
+  if (!condvar) {
+    condvar = &default_condvar;
+  }
+  if (!notification) {
+    notification = &default_notification;
+  }
+  bool state = false;
+  std::thread thread_one(ThreadOne, mutex, condvar, notification, &state);
+  std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state);
+  thread_one.join();
+  thread_two.join();
+}
+
+void TestLocals() {
+  absl::Mutex mutex;
+  absl::CondVar condvar;
+  absl::Notification notification;
+  RunTests(&mutex, &condvar, &notification);
+}
+
+// Global variables during start and termination
+//
+// In a translation unit, static storage duration variables are initialized in
+// the order of their definitions, and destroyed in the reverse order of their
+// definitions.  We can use this to arrange for tests to be run on these objects
+// before they are created, and after they are destroyed.
+
+using Function = void (*)();
+
+class OnConstruction {
+ public:
+  explicit OnConstruction(Function fn) { fn(); }
+};
+
+class OnDestruction {
+ public:
+  explicit OnDestruction(Function fn) : fn_(fn) {}
+  ~OnDestruction() { fn_(); }
+ private:
+  Function fn_;
+};
+
+}  // namespace
+
+int main() {
+  TestLocals();
+  // Explicitly call exit(0) here, to make it clear that we intend for the
+  // above global object destructors to run.
+  std::exit(0);
+}
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
new file mode 100644
index 0000000..80f34f0
--- /dev/null
+++ b/absl/synchronization/mutex.cc
@@ -0,0 +1,2687 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/mutex.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#ifdef ERROR
+#undef ERROR
+#endif
+#else
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/time.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cinttypes>
+#include <thread>  // NOLINT(build/c++11)
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/hide_ptr.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/port.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/synchronization/internal/graphcycles.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/time/time.h"
+
+using absl::base_internal::CurrentThreadIdentityIfPresent;
+using absl::base_internal::PerThreadSynch;
+using absl::base_internal::ThreadIdentity;
+using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
+using absl::synchronization_internal::GraphCycles;
+using absl::synchronization_internal::GraphId;
+using absl::synchronization_internal::InvalidGraphId;
+using absl::synchronization_internal::KernelTimeout;
+using absl::synchronization_internal::PerThreadSem;
+
+extern "C" {
+ABSL_ATTRIBUTE_WEAK void AbslInternalMutexYield() { std::this_thread::yield(); }
+}  // extern "C"
+
+namespace absl {
+
+namespace {
+
+#if defined(THREAD_SANITIZER)
+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kIgnore;
+#else
+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kAbort;
+#endif
+
+ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection(
+    kDeadlockDetectionDefault);
+ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
+
+// ------------------------------------------ spinlock support
+
+// Make sure read-only globals used in the Mutex code are contained on the
+// same cacheline and cacheline aligned to eliminate any false sharing with
+// other globals from this and other modules.
+static struct MutexGlobals {
+  MutexGlobals() {
+    // Find machine-specific data needed for Delay() and
+    // TryAcquireWithSpinning(). This runs in the global constructor
+    // sequence, and before that zeros are safe values.
+    num_cpus = absl::base_internal::NumCPUs();
+    spinloop_iterations = num_cpus > 1 ? 1500 : 0;
+  }
+  int num_cpus;
+  int spinloop_iterations;
+  // Pad this struct to a full cacheline to prevent false sharing.
+  char padding[ABSL_CACHELINE_SIZE - 2 * sizeof(int)];
+} ABSL_CACHELINE_ALIGNED mutex_globals;
+static_assert(
+    sizeof(MutexGlobals) == ABSL_CACHELINE_SIZE,
+    "MutexGlobals must occupy an entire cacheline to prevent false sharing");
+
+ABSL_CONST_INIT absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
+    submit_profile_data;
+ABSL_CONST_INIT absl::base_internal::AtomicHook<
+    void (*)(const char *msg, const void *obj, int64_t wait_cycles)> mutex_tracer;
+ABSL_CONST_INIT absl::base_internal::AtomicHook<
+    void (*)(const char *msg, const void *cv)> cond_var_tracer;
+ABSL_CONST_INIT absl::base_internal::AtomicHook<
+    bool (*)(const void *pc, char *out, int out_size)>
+    symbolizer(absl::Symbolize);
+
+}  // namespace
+
+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) {
+  submit_profile_data.Store(fn);
+}
+
+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
+                                    int64_t wait_cycles)) {
+  mutex_tracer.Store(fn);
+}
+
+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)) {
+  cond_var_tracer.Store(fn);
+}
+
+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) {
+  symbolizer.Store(fn);
+}
+
+// spinlock delay on iteration c.  Returns new c.
+namespace {
+  enum DelayMode { AGGRESSIVE, GENTLE };
+};
+static int Delay(int32_t c, DelayMode mode) {
+  // If this a uniprocessor, only yield/sleep.  Otherwise, if the mode is
+  // aggressive then spin many times before yielding.  If the mode is
+  // gentle then spin only a few times before yielding.  Aggressive spinning is
+  // used to ensure that an Unlock() call, which  must get the spin lock for
+  // any thread to make progress gets it without undue delay.
+  int32_t limit = (mutex_globals.num_cpus > 1) ?
+      ((mode == AGGRESSIVE) ? 5000 : 250) : 0;
+  if (c < limit) {
+    c++;               // spin
+  } else {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(0, 0);
+    if (c == limit) {  // yield once
+      AbslInternalMutexYield();
+      c++;
+    } else {           // then wait
+      absl::SleepFor(absl::Microseconds(10));
+      c = 0;
+    }
+    ABSL_TSAN_MUTEX_POST_DIVERT(0, 0);
+  }
+  return (c);
+}
+
+// --------------------------Generic atomic ops
+// Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to
+// "*pv | bits" if necessary.  Wait until (*pv & wait_until_clear)==0
+// before making any change.
+// This is used to set flags in mutex and condition variable words.
+static void AtomicSetBits(std::atomic<intptr_t>* pv, intptr_t bits,
+                          intptr_t wait_until_clear) {
+  intptr_t v;
+  do {
+    v = pv->load(std::memory_order_relaxed);
+  } while ((v & bits) != bits &&
+           ((v & wait_until_clear) != 0 ||
+            !pv->compare_exchange_weak(v, v | bits,
+                                       std::memory_order_release,
+                                       std::memory_order_relaxed)));
+}
+
+// Ensure that "(*pv & bits) == 0" by doing an atomic update of "*pv" to
+// "*pv & ~bits" if necessary.  Wait until (*pv & wait_until_clear)==0
+// before making any change.
+// This is used to unset flags in mutex and condition variable words.
+static void AtomicClearBits(std::atomic<intptr_t>* pv, intptr_t bits,
+                            intptr_t wait_until_clear) {
+  intptr_t v;
+  do {
+    v = pv->load(std::memory_order_relaxed);
+  } while ((v & bits) != 0 &&
+           ((v & wait_until_clear) != 0 ||
+            !pv->compare_exchange_weak(v, v & ~bits,
+                                       std::memory_order_release,
+                                       std::memory_order_relaxed)));
+}
+
+//------------------------------------------------------------------
+
+// Data for doing deadlock detection.
+static absl::base_internal::SpinLock deadlock_graph_mu(
+    absl::base_internal::kLinkerInitialized);
+
+// graph used to detect deadlocks.
+static GraphCycles *deadlock_graph GUARDED_BY(deadlock_graph_mu)
+    PT_GUARDED_BY(deadlock_graph_mu);
+
+//------------------------------------------------------------------
+// An event mechanism for debugging mutex use.
+// It also allows mutexes to be given names for those who can't handle
+// addresses, and instead like to give their data structures names like
+// "Henry", "Fido", or "Rupert IV, King of Yondavia".
+
+namespace {  // to prevent name pollution
+enum {       // Mutex and CondVar events passed as "ev" to PostSynchEvent
+             // Mutex events
+  SYNCH_EV_TRYLOCK_SUCCESS,
+  SYNCH_EV_TRYLOCK_FAILED,
+  SYNCH_EV_READERTRYLOCK_SUCCESS,
+  SYNCH_EV_READERTRYLOCK_FAILED,
+  SYNCH_EV_LOCK,
+  SYNCH_EV_LOCK_RETURNING,
+  SYNCH_EV_READERLOCK,
+  SYNCH_EV_READERLOCK_RETURNING,
+  SYNCH_EV_UNLOCK,
+  SYNCH_EV_READERUNLOCK,
+
+  // CondVar events
+  SYNCH_EV_WAIT,
+  SYNCH_EV_WAIT_RETURNING,
+  SYNCH_EV_SIGNAL,
+  SYNCH_EV_SIGNALALL,
+};
+
+enum {                 // Event flags
+  SYNCH_F_R = 0x01,    // reader event
+  SYNCH_F_LCK = 0x02,  // PostSynchEvent called with mutex held
+  SYNCH_F_ACQ = 0x04,  // event is an acquire
+
+  SYNCH_F_LCK_W = SYNCH_F_LCK,
+  SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R,
+  SYNCH_F_ACQ_W = SYNCH_F_ACQ,
+  SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R,
+};
+}  // anonymous namespace
+
+// Properties of the events.
+static const struct {
+  int flags;
+  const char *msg;
+} event_properties[] = {
+  { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " },
+  { 0,                           "TryLock failed " },
+  { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " },
+  { 0,                           "ReaderTryLock failed " },
+  {               SYNCH_F_ACQ_W, "Lock blocking " },
+  { SYNCH_F_LCK_W,               "Lock returning " },
+  {               SYNCH_F_ACQ_R, "ReaderLock blocking " },
+  { SYNCH_F_LCK_R,               "ReaderLock returning " },
+  { SYNCH_F_LCK_W,               "Unlock " },
+  { SYNCH_F_LCK_R,               "ReaderUnlock " },
+  { 0,                           "Wait on " },
+  { 0,                           "Wait unblocked " },
+  { 0,                           "Signal on " },
+  { 0,                           "SignalAll on " },
+};
+static absl::base_internal::SpinLock synch_event_mu(
+    absl::base_internal::kLinkerInitialized);
+// protects synch_event
+
+// Hash table size; should be prime > 2.
+// Can't be too small, as it's used for deadlock detection information.
+static const uint32_t kNSynchEvent = 1031;
+
+static struct SynchEvent {     // this is a trivial hash table for the events
+  // struct is freed when refcount reaches 0
+  int refcount GUARDED_BY(synch_event_mu);
+
+  // buckets have linear, 0-terminated  chains
+  SynchEvent *next GUARDED_BY(synch_event_mu);
+
+  // Constant after initialization
+  uintptr_t masked_addr;  // object at this address is called "name"
+
+  // No explicit synchronization used.  Instead we assume that the
+  // client who enables/disables invariants/logging on a Mutex does so
+  // while the Mutex is not being concurrently accessed by others.
+  void (*invariant)(void *arg);  // called on each event
+  void *arg;            // first arg to (*invariant)()
+  bool log;             // logging turned on
+
+  // Constant after initialization
+  char name[1];         // actually longer---null-terminated std::string
+} *synch_event[kNSynchEvent] GUARDED_BY(synch_event_mu);
+
+// Ensure that the object at "addr" has a SynchEvent struct associated with it,
+// set "bits" in the word there (waiting until lockbit is clear before doing
+// so), and return a refcounted reference that will remain valid until
+// UnrefSynchEvent() is called.  If a new SynchEvent is allocated,
+// the std::string name is copied into it.
+// When used with a mutex, the caller should also ensure that kMuEvent
+// is set in the mutex word, and similarly for condition variables and kCVEvent.
+static SynchEvent *EnsureSynchEvent(std::atomic<intptr_t> *addr,
+                                    const char *name, intptr_t bits,
+                                    intptr_t lockbit) {
+  uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+  SynchEvent *e;
+  // first look for existing SynchEvent struct..
+  synch_event_mu.Lock();
+  for (e = synch_event[h];
+       e != nullptr && e->masked_addr != base_internal::HidePtr(addr);
+       e = e->next) {
+  }
+  if (e == nullptr) {  // no SynchEvent struct found; make one.
+    if (name == nullptr) {
+      name = "";
+    }
+    size_t l = strlen(name);
+    e = reinterpret_cast<SynchEvent *>(
+        base_internal::LowLevelAlloc::Alloc(sizeof(*e) + l));
+    e->refcount = 2;    // one for return value, one for linked list
+    e->masked_addr = base_internal::HidePtr(addr);
+    e->invariant = nullptr;
+    e->arg = nullptr;
+    e->log = false;
+    strcpy(e->name, name);  // NOLINT(runtime/printf)
+    e->next = synch_event[h];
+    AtomicSetBits(addr, bits, lockbit);
+    synch_event[h] = e;
+  } else {
+    e->refcount++;      // for return value
+  }
+  synch_event_mu.Unlock();
+  return e;
+}
+
+// Deallocate the SynchEvent *e, whose refcount has fallen to zero.
+static void DeleteSynchEvent(SynchEvent *e) {
+  base_internal::LowLevelAlloc::Free(e);
+}
+
+// Decrement the reference count of *e, or do nothing if e==null.
+static void UnrefSynchEvent(SynchEvent *e) {
+  if (e != nullptr) {
+    synch_event_mu.Lock();
+    bool del = (--(e->refcount) == 0);
+    synch_event_mu.Unlock();
+    if (del) {
+      DeleteSynchEvent(e);
+    }
+  }
+}
+
+// Forget the mapping from the object (Mutex or CondVar) at address addr
+// to SynchEvent object, and clear "bits" in its word (waiting until lockbit
+// is clear before doing so).
+static void ForgetSynchEvent(std::atomic<intptr_t> *addr, intptr_t bits,
+                             intptr_t lockbit) {
+  uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+  SynchEvent **pe;
+  SynchEvent *e;
+  synch_event_mu.Lock();
+  for (pe = &synch_event[h];
+       (e = *pe) != nullptr && e->masked_addr != base_internal::HidePtr(addr);
+       pe = &e->next) {
+  }
+  bool del = false;
+  if (e != nullptr) {
+    *pe = e->next;
+    del = (--(e->refcount) == 0);
+  }
+  AtomicClearBits(addr, bits, lockbit);
+  synch_event_mu.Unlock();
+  if (del) {
+    DeleteSynchEvent(e);
+  }
+}
+
+// Return a refcounted reference to the SynchEvent of the object at address
+// "addr", if any.  The pointer returned is valid until the UnrefSynchEvent() is
+// called.
+static SynchEvent *GetSynchEvent(const void *addr) {
+  uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+  SynchEvent *e;
+  synch_event_mu.Lock();
+  for (e = synch_event[h];
+       e != nullptr && e->masked_addr != base_internal::HidePtr(addr);
+       e = e->next) {
+  }
+  if (e != nullptr) {
+    e->refcount++;
+  }
+  synch_event_mu.Unlock();
+  return e;
+}
+
+// Called when an event "ev" occurs on a Mutex of CondVar "obj"
+// if event recording is on
+static void PostSynchEvent(void *obj, int ev) {
+  SynchEvent *e = GetSynchEvent(obj);
+  // logging is on if event recording is on and either there's no event struct,
+  // or it explicitly says to log
+  if (e == nullptr || e->log) {
+    void *pcs[40];
+    int n = absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 1);
+    // A buffer with enough space for the ASCII for all the PCs, even on a
+    // 64-bit machine.
+    char buffer[ABSL_ARRAYSIZE(pcs) * 24];
+    int pos = snprintf(buffer, sizeof (buffer), " @");
+    for (int i = 0; i != n; i++) {
+      pos += snprintf(&buffer[pos], sizeof (buffer) - pos, " %p", pcs[i]);
+    }
+    ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj,
+                 (e == nullptr ? "" : e->name), buffer);
+  }
+  if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr &&
+      e->invariant != nullptr) {
+    (*e->invariant)(e->arg);
+  }
+  UnrefSynchEvent(e);
+}
+
+//------------------------------------------------------------------
+
+// The SynchWaitParams struct encapsulates the way in which a thread is waiting:
+// whether it has a timeout, the condition, exclusive/shared, and whether a
+// condition variable wait has an associated Mutex (as opposed to another
+// type of lock).  It also points to the PerThreadSynch struct of its thread.
+// cv_word tells Enqueue() to enqueue on a CondVar using CondVarEnqueue().
+//
+// This structure is held on the stack rather than directly in
+// PerThreadSynch because a thread can be waiting on multiple Mutexes if,
+// while waiting on one Mutex, the implementation calls a client callback
+// (such as a Condition function) that acquires another Mutex. We don't
+// strictly need to allow this, but programmers become confused if we do not
+// allow them to use functions such a LOG() within Condition functions.  The
+// PerThreadSynch struct points at the most recent SynchWaitParams struct when
+// the thread is on a Mutex's waiter queue.
+struct SynchWaitParams {
+  SynchWaitParams(Mutex::MuHow how_arg, const Condition *cond_arg,
+                  KernelTimeout timeout_arg, Mutex *cvmu_arg,
+                  PerThreadSynch *thread_arg,
+                  std::atomic<intptr_t> *cv_word_arg)
+      : how(how_arg),
+        cond(cond_arg),
+        timeout(timeout_arg),
+        cvmu(cvmu_arg),
+        thread(thread_arg),
+        cv_word(cv_word_arg),
+        contention_start_cycles(base_internal::CycleClock::Now()) {}
+
+  const Mutex::MuHow how;  // How this thread needs to wait.
+  const Condition *cond;  // The condition that this thread is waiting for.
+                          // In Mutex, this field is set to zero if a timeout
+                          // expires.
+  KernelTimeout timeout;  // timeout expiry---absolute time
+                          // In Mutex, this field is set to zero if a timeout
+                          // expires.
+  Mutex *const cvmu;      // used for transfer from cond var to mutex
+  PerThreadSynch *const thread;  // thread that is waiting
+
+  // If not null, thread should be enqueued on the CondVar whose state
+  // word is cv_word instead of queueing normally on the Mutex.
+  std::atomic<intptr_t> *cv_word;
+
+  int64_t contention_start_cycles;  // Time (in cycles) when this thread started
+                                  // to contend for the mutex.
+};
+
+struct SynchLocksHeld {
+  int n;              // number of valid entries in locks[]
+  bool overflow;      // true iff we overflowed the array at some point
+  struct {
+    Mutex *mu;        // lock acquired
+    int32_t count;      // times acquired
+    GraphId id;       // deadlock_graph id of acquired lock
+  } locks[40];
+  // If a thread overfills the array during deadlock detection, we
+  // continue, discarding information as needed.  If no overflow has
+  // taken place, we can provide more error checking, such as
+  // detecting when a thread releases a lock it does not hold.
+};
+
+// A sentinel value in lists that is not 0.
+// A 0 value is used to mean "not on a list".
+static PerThreadSynch *const kPerThreadSynchNull =
+  reinterpret_cast<PerThreadSynch *>(1);
+
+static SynchLocksHeld *LocksHeldAlloc() {
+  SynchLocksHeld *ret = reinterpret_cast<SynchLocksHeld *>(
+      base_internal::LowLevelAlloc::Alloc(sizeof(SynchLocksHeld)));
+  ret->n = 0;
+  ret->overflow = false;
+  return ret;
+}
+
+// Return the PerThreadSynch-struct for this thread.
+static PerThreadSynch *Synch_GetPerThread() {
+  ThreadIdentity *identity = GetOrCreateCurrentThreadIdentity();
+  return &identity->per_thread_synch;
+}
+
+static PerThreadSynch *Synch_GetPerThreadAnnotated(Mutex *mu) {
+  if (mu) {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  }
+  PerThreadSynch *w = Synch_GetPerThread();
+  if (mu) {
+    ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  }
+  return w;
+}
+
+static SynchLocksHeld *Synch_GetAllLocks() {
+  PerThreadSynch *s = Synch_GetPerThread();
+  if (s->all_locks == nullptr) {
+    s->all_locks = LocksHeldAlloc();  // Freed by ReclaimThreadIdentity.
+  }
+  return s->all_locks;
+}
+
+// Post on "w"'s associated PerThreadSem.
+inline void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
+  if (mu) {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  }
+  PerThreadSem::Post(w->thread_identity());
+  if (mu) {
+    ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  }
+}
+
+// Wait on "w"'s associated PerThreadSem; returns false if timeout expired.
+bool Mutex::DecrementSynchSem(Mutex *mu, PerThreadSynch *w, KernelTimeout t) {
+  if (mu) {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  }
+  assert(w == Synch_GetPerThread());
+  static_cast<void>(w);
+  bool res = PerThreadSem::Wait(t);
+  if (mu) {
+    ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  }
+  return res;
+}
+
+// We're in a fatal signal handler that hopes to use Mutex and to get
+// lucky by not deadlocking.  We try to improve its chances of success
+// by effectively disabling some of the consistency checks.  This will
+// prevent certain ABSL_RAW_CHECK() statements from being triggered when
+// re-rentry is detected.  The ABSL_RAW_CHECK() statements are those in the
+// Mutex code checking that the "waitp" field has not been reused.
+void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() {
+  // Fix the per-thread state only if it exists.
+  ThreadIdentity *identity = CurrentThreadIdentityIfPresent();
+  if (identity != nullptr) {
+    identity->per_thread_synch.suppress_fatal_errors = true;
+  }
+  // Don't do deadlock detection when we are already failing.
+  synch_deadlock_detection.store(OnDeadlockCycle::kIgnore,
+                                 std::memory_order_release);
+}
+
+// --------------------------time support
+
+// Return the current time plus the timeout.  Use the same clock as
+// PerThreadSem::Wait() for consistency.  Unfortunately, we don't have
+// such a choice when a deadline is given directly.
+static absl::Time DeadlineFromTimeout(absl::Duration timeout) {
+#ifndef _WIN32
+  struct timeval tv;
+  gettimeofday(&tv, nullptr);
+  return absl::TimeFromTimeval(tv) + timeout;
+#else
+  return absl::Now() + timeout;
+#endif
+}
+
+// --------------------------Mutexes
+
+// In the layout below, the msb of the bottom byte is currently unused.  Also,
+// the following constraints were considered in choosing the layout:
+//  o Both the debug allocator's "uninitialized" and "freed" patterns (0xab and
+//    0xcd) are illegal: reader and writer lock both held.
+//  o kMuWriter and kMuEvent should exceed kMuDesig and kMuWait, to enable the
+//    bit-twiddling trick in Mutex::Unlock().
+//  o kMuWriter / kMuReader == kMuWrWait / kMuWait,
+//    to enable the bit-twiddling trick in CheckForMutexCorruption().
+static const intptr_t kMuReader      = 0x0001L;  // a reader holds the lock
+static const intptr_t kMuDesig       = 0x0002L;  // there's a designated waker
+static const intptr_t kMuWait        = 0x0004L;  // threads are waiting
+static const intptr_t kMuWriter      = 0x0008L;  // a writer holds the lock
+static const intptr_t kMuEvent       = 0x0010L;  // record this mutex's events
+// INVARIANT1:  there's a thread that was blocked on the mutex, is
+// no longer, yet has not yet acquired the mutex.  If there's a
+// designated waker, all threads can avoid taking the slow path in
+// unlock because the designated waker will subsequently acquire
+// the lock and wake someone.  To maintain INVARIANT1 the bit is
+// set when a thread is unblocked(INV1a), and threads that were
+// unblocked reset the bit when they either acquire or re-block
+// (INV1b).
+static const intptr_t kMuWrWait      = 0x0020L;  // runnable writer is waiting
+                                                 // for a reader
+static const intptr_t kMuSpin        = 0x0040L;  // spinlock protects wait list
+static const intptr_t kMuLow         = 0x00ffL;  // mask all mutex bits
+static const intptr_t kMuHigh        = ~kMuLow;  // mask pointer/reader count
+
+// Hack to make constant values available to gdb pretty printer
+enum {
+  kGdbMuSpin = kMuSpin,
+  kGdbMuEvent = kMuEvent,
+  kGdbMuWait = kMuWait,
+  kGdbMuWriter = kMuWriter,
+  kGdbMuDesig = kMuDesig,
+  kGdbMuWrWait = kMuWrWait,
+  kGdbMuReader = kMuReader,
+  kGdbMuLow = kMuLow,
+};
+
+// kMuWrWait implies kMuWait.
+// kMuReader and kMuWriter are mutually exclusive.
+// If kMuReader is zero, there are no readers.
+// Otherwise, if kMuWait is zero, the high order bits contain a count of the
+// number of readers.  Otherwise, the reader count is held in
+// PerThreadSynch::readers of the most recently queued waiter, again in the
+// bits above kMuLow.
+static const intptr_t kMuOne = 0x0100;  // a count of one reader
+
+// flags passed to Enqueue and LockSlow{,WithTimeout,Loop}
+static const int kMuHasBlocked = 0x01;  // already blocked (MUST == 1)
+static const int kMuIsCond = 0x02;      // conditional waiter (CV or Condition)
+
+static_assert(PerThreadSynch::kAlignment > kMuLow,
+              "PerThreadSynch::kAlignment must be greater than kMuLow");
+
+// This struct contains various bitmasks to be used in
+// acquiring and releasing a mutex in a particular mode.
+struct MuHowS {
+  // if all the bits in fast_need_zero are zero, the lock can be acquired by
+  // adding fast_add and oring fast_or.  The bit kMuDesig should be reset iff
+  // this is the designated waker.
+  intptr_t fast_need_zero;
+  intptr_t fast_or;
+  intptr_t fast_add;
+
+  intptr_t slow_need_zero;  // fast_need_zero with events (e.g. logging)
+
+  intptr_t slow_inc_need_zero;  // if all the bits in slow_inc_need_zero are
+                                // zero a reader can acquire a read share by
+                                // setting the reader bit and incrementing
+                                // the reader count (in last waiter since
+                                // we're now slow-path).  kMuWrWait be may
+                                // be ignored if we already waited once.
+};
+
+static const MuHowS kSharedS = {
+    // shared or read lock
+    kMuWriter | kMuWait | kMuEvent,   // fast_need_zero
+    kMuReader,                        // fast_or
+    kMuOne,                           // fast_add
+    kMuWriter | kMuWait,              // slow_need_zero
+    kMuSpin | kMuWriter | kMuWrWait,  // slow_inc_need_zero
+};
+static const MuHowS kExclusiveS = {
+    // exclusive or write lock
+    kMuWriter | kMuReader | kMuEvent,  // fast_need_zero
+    kMuWriter,                         // fast_or
+    0,                                 // fast_add
+    kMuWriter | kMuReader,             // slow_need_zero
+    ~static_cast<intptr_t>(0),         // slow_inc_need_zero
+};
+static const Mutex::MuHow kShared = &kSharedS;        // shared lock
+static const Mutex::MuHow kExclusive = &kExclusiveS;  // exclusive lock
+
+#ifdef NDEBUG
+static constexpr bool kDebugMode = false;
+#else
+static constexpr bool kDebugMode = true;
+#endif
+
+#ifdef THREAD_SANITIZER
+static unsigned TsanFlags(Mutex::MuHow how) {
+  return how == kShared ? __tsan_mutex_read_lock : 0;
+}
+#endif
+
+static bool DebugOnlyIsExiting() {
+  return false;
+}
+
+Mutex::~Mutex() {
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  if ((v & kMuEvent) != 0 && !DebugOnlyIsExiting()) {
+    ForgetSynchEvent(&this->mu_, kMuEvent, kMuSpin);
+  }
+  if (kDebugMode) {
+    this->ForgetDeadlockInfo();
+  }
+  ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static);
+}
+
+void Mutex::EnableDebugLog(const char *name) {
+  SynchEvent *e = EnsureSynchEvent(&this->mu_, name, kMuEvent, kMuSpin);
+  e->log = true;
+  UnrefSynchEvent(e);
+}
+
+void EnableMutexInvariantDebugging(bool enabled) {
+  synch_check_invariants.store(enabled, std::memory_order_release);
+}
+
+void Mutex::EnableInvariantDebugging(void (*invariant)(void *),
+                                     void *arg) {
+  if (synch_check_invariants.load(std::memory_order_acquire) &&
+      invariant != nullptr) {
+    SynchEvent *e = EnsureSynchEvent(&this->mu_, nullptr, kMuEvent, kMuSpin);
+    e->invariant = invariant;
+    e->arg = arg;
+    UnrefSynchEvent(e);
+  }
+}
+
+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode) {
+  synch_deadlock_detection.store(mode, std::memory_order_release);
+}
+
+// Return true iff threads x and y are waiting on the same condition for the
+// same type of lock.  Requires that x and y be waiting on the same Mutex
+// queue.
+static bool MuSameCondition(PerThreadSynch *x, PerThreadSynch *y) {
+  return x->waitp->how == y->waitp->how &&
+         Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond);
+}
+
+// Given the contents of a mutex word containing a PerThreadSynch pointer,
+// return the pointer.
+static inline PerThreadSynch *GetPerThreadSynch(intptr_t v) {
+  return reinterpret_cast<PerThreadSynch *>(v & kMuHigh);
+}
+
+// The next several routines maintain the per-thread next and skip fields
+// used in the Mutex waiter queue.
+// The queue is a circular singly-linked list, of which the "head" is the
+// last element, and head->next if the first element.
+// The skip field has the invariant:
+//   For thread x, x->skip is one of:
+//     - invalid (iff x is not in a Mutex wait queue),
+//     - null, or
+//     - a pointer to a distinct thread waiting later in the same Mutex queue
+//       such that all threads in [x, x->skip] have the same condition and
+//       lock type (MuSameCondition() is true for all pairs in [x, x->skip]).
+// In addition, if x->skip is  valid, (x->may_skip || x->skip == null)
+//
+// By the spec of MuSameCondition(), it is not necessary when removing the
+// first runnable thread y from the front a Mutex queue to adjust the skip
+// field of another thread x because if x->skip==y, x->skip must (have) become
+// invalid before y is removed.  The function TryRemove can remove a specified
+// thread from an arbitrary position in the queue whether runnable or not, so
+// it fixes up skip fields that would otherwise be left dangling.
+// The statement
+//     if (x->may_skip && MuSameCondition(x, x->next)) { x->skip = x->next; }
+// maintains the invariant provided x is not the last waiter in a Mutex queue
+// The statement
+//          if (x->skip != null) { x->skip = x->skip->skip; }
+// maintains the invariant.
+
+// Returns the last thread y in a mutex waiter queue such that all threads in
+// [x, y] inclusive share the same condition.  Sets skip fields of some threads
+// in that range to optimize future evaluation of Skip() on x values in
+// the range.  Requires thread x is in a mutex waiter queue.
+// The locking is unusual.  Skip() is called under these conditions:
+//   - spinlock is held in call from Enqueue(), with maybe_unlocking == false
+//   - Mutex is held in call from UnlockSlow() by last unlocker, with
+//     maybe_unlocking == true
+//   - both Mutex and spinlock are held in call from DequeueAllWakeable() (from
+//     UnlockSlow()) and TryRemove()
+// These cases are mutually exclusive, so Skip() never runs concurrently
+// with itself on the same Mutex.   The skip chain is used in these other places
+// that cannot occur concurrently:
+//   - FixSkip() (from TryRemove()) - spinlock and Mutex are held)
+//   - Dequeue() (with spinlock and Mutex held)
+//   - UnlockSlow() (with spinlock and Mutex held)
+// A more complex case is Enqueue()
+//   - Enqueue() (with spinlock held and maybe_unlocking == false)
+//               This is the first case in which Skip is called, above.
+//   - Enqueue() (without spinlock held; but queue is empty and being freshly
+//                formed)
+//   - Enqueue() (with spinlock held and maybe_unlocking == true)
+// The first case has mutual exclusion, and the second isolation through
+// working on an otherwise unreachable data structure.
+// In the last case, Enqueue() is required to change no skip/next pointers
+// except those in the added node and the former "head" node.  This implies
+// that the new node is added after head, and so must be the new head or the
+// new front of the queue.
+static PerThreadSynch *Skip(PerThreadSynch *x) {
+  PerThreadSynch *x0 = nullptr;
+  PerThreadSynch *x1 = x;
+  PerThreadSynch *x2 = x->skip;
+  if (x2 != nullptr) {
+    // Each iteration attempts to advance sequence (x0,x1,x2) to next sequence
+    // such that   x1 == x0->skip && x2 == x1->skip
+    while ((x0 = x1, x1 = x2, x2 = x2->skip) != nullptr) {
+      x0->skip = x2;      // short-circuit skip from x0 to x2
+    }
+    x->skip = x1;         // short-circuit skip from x to result
+  }
+  return x1;
+}
+
+// "ancestor" appears before "to_be_removed" in the same Mutex waiter queue.
+// The latter is going to be removed out of order, because of a timeout.
+// Check whether "ancestor" has a skip field pointing to "to_be_removed",
+// and fix it if it does.
+static void FixSkip(PerThreadSynch *ancestor, PerThreadSynch *to_be_removed) {
+  if (ancestor->skip == to_be_removed) {  // ancestor->skip left dangling
+    if (to_be_removed->skip != nullptr) {
+      ancestor->skip = to_be_removed->skip;  // can skip past to_be_removed
+    } else if (ancestor->next != to_be_removed) {  // they are not adjacent
+      ancestor->skip = ancestor->next;             // can skip one past ancestor
+    } else {
+      ancestor->skip = nullptr;  // can't skip at all
+    }
+  }
+}
+
+static void CondVarEnqueue(SynchWaitParams *waitp);
+
+// Enqueue thread "waitp->thread" on a waiter queue.
+// Called with mutex spinlock held if head != nullptr
+// If head==nullptr and waitp->cv_word==nullptr, then Enqueue() is
+// idempotent; it alters no state associated with the existing (empty)
+// queue.
+//
+// If waitp->cv_word == nullptr, queue the thread at either the front or
+// the end (according to its priority) of the circular mutex waiter queue whose
+// head is "head", and return the new head.  mu is the previous mutex state,
+// which contains the reader count (perhaps adjusted for the operation in
+// progress) if the list was empty and a read lock held, and the holder hint if
+// the list was empty and a write lock held.  (flags & kMuIsCond) indicates
+// whether this thread was transferred from a CondVar or is waiting for a
+// non-trivial condition.  In this case, Enqueue() never returns nullptr
+//
+// If waitp->cv_word != nullptr, CondVarEnqueue() is called, and "head" is
+// returned. This mechanism is used by CondVar to queue a thread on the
+// condition variable queue instead of the mutex queue in implementing Wait().
+// In this case, Enqueue() can return nullptr (if head==nullptr).
+static PerThreadSynch *Enqueue(PerThreadSynch *head,
+                               SynchWaitParams *waitp, intptr_t mu, int flags) {
+  // If we have been given a cv_word, call CondVarEnqueue() and return
+  // the previous head of the Mutex waiter queue.
+  if (waitp->cv_word != nullptr) {
+    CondVarEnqueue(waitp);
+    return head;
+  }
+
+  PerThreadSynch *s = waitp->thread;
+  ABSL_RAW_CHECK(
+      s->waitp == nullptr ||    // normal case
+          s->waitp == waitp ||  // Fer()---transfer from condition variable
+          s->suppress_fatal_errors,
+      "detected illegal recursion into Mutex code");
+  s->waitp = waitp;
+  s->skip = nullptr;             // maintain skip invariant (see above)
+  s->may_skip = true;            // always true on entering queue
+  s->wake = false;               // not being woken
+  s->cond_waiter = ((flags & kMuIsCond) != 0);
+  if (head == nullptr) {         // s is the only waiter
+    s->next = s;                 // it's the only entry in the cycle
+    s->readers = mu;             // reader count is from mu word
+    s->maybe_unlocking = false;  // no one is searching an empty list
+    head = s;                    // s is new head
+  } else {
+    PerThreadSynch *enqueue_after = nullptr;  // we'll put s after this element
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+    int64_t now_cycles = base_internal::CycleClock::Now();
+    if (s->next_priority_read_cycles < now_cycles) {
+      // Every so often, update our idea of the thread's priority.
+      // pthread_getschedparam() is 5% of the block/wakeup time;
+      // base_internal::CycleClock::Now() is 0.5%.
+      int policy;
+      struct sched_param param;
+      pthread_getschedparam(pthread_self(), &policy, &param);
+      s->priority = param.sched_priority;
+      s->next_priority_read_cycles =
+          now_cycles +
+          static_cast<int64_t>(base_internal::CycleClock::Frequency());
+    }
+    if (s->priority > head->priority) {  // s's priority is above head's
+      // try to put s in priority-fifo order, or failing that at the front.
+      if (!head->maybe_unlocking) {
+        // No unlocker can be scanning the queue, so we can insert between
+        // skip-chains, and within a skip-chain if it has the same condition as
+        // s.  We insert in priority-fifo order, examining the end of every
+        // skip-chain, plus every element with the same condition as s.
+        PerThreadSynch *advance_to = head;    // next value of enqueue_after
+        PerThreadSynch *cur;                  // successor of enqueue_after
+        do {
+          enqueue_after = advance_to;
+          cur = enqueue_after->next;  // this advance ensures progress
+          advance_to = Skip(cur);   // normally, advance to end of skip chain
+                                    // (side-effect: optimizes skip chain)
+          if (advance_to != cur && s->priority > advance_to->priority &&
+              MuSameCondition(s, cur)) {
+            // but this skip chain is not a singleton, s has higher priority
+            // than its tail and has the same condition as the chain,
+            // so we can insert within the skip-chain
+            advance_to = cur;         // advance by just one
+          }
+        } while (s->priority <= advance_to->priority);
+              // termination guaranteed because s->priority > head->priority
+              // and head is the end of a skip chain
+      } else if (waitp->how == kExclusive &&
+                 Condition::GuaranteedEqual(waitp->cond, nullptr)) {
+        // An unlocker could be scanning the queue, but we know it will recheck
+        // the queue front for writers that have no condition, which is what s
+        // is, so an insert at front is safe.
+        enqueue_after = head;       // add after head, at front
+      }
+    }
+#endif
+    if (enqueue_after != nullptr) {
+      s->next = enqueue_after->next;
+      enqueue_after->next = s;
+
+      // enqueue_after can be: head, Skip(...), or cur.
+      // The first two imply enqueue_after->skip == nullptr, and
+      // the last is used only if MuSameCondition(s, cur).
+      // We require this because clearing enqueue_after->skip
+      // is impossible; enqueue_after's predecessors might also
+      // incorrectly skip over s if we were to allow other
+      // insertion points.
+      ABSL_RAW_CHECK(
+          enqueue_after->skip == nullptr || MuSameCondition(enqueue_after, s),
+          "Mutex Enqueue failure");
+
+      if (enqueue_after != head && enqueue_after->may_skip &&
+          MuSameCondition(enqueue_after, enqueue_after->next)) {
+        // enqueue_after can skip to its new successor, s
+        enqueue_after->skip = enqueue_after->next;
+      }
+      if (MuSameCondition(s, s->next)) {  // s->may_skip is known to be true
+        s->skip = s->next;                // s may skip to its successor
+      }
+    } else {   // enqueue not done any other way, so
+               // we're inserting s at the back
+      // s will become new head; copy data from head into it
+      s->next = head->next;        // add s after head
+      head->next = s;
+      s->readers = head->readers;  // reader count is from previous head
+      s->maybe_unlocking = head->maybe_unlocking;  // same for unlock hint
+      if (head->may_skip && MuSameCondition(head, s)) {
+        // head now has successor; may skip
+        head->skip = s;
+      }
+      head = s;  // s is new head
+    }
+  }
+  s->state.store(PerThreadSynch::kQueued, std::memory_order_relaxed);
+  return head;
+}
+
+// Dequeue the successor pw->next of thread pw from the Mutex waiter queue
+// whose last element is head.  The new head element is returned, or null
+// if the list is made empty.
+// Dequeue is called with both spinlock and Mutex held.
+static PerThreadSynch *Dequeue(PerThreadSynch *head, PerThreadSynch *pw) {
+  PerThreadSynch *w = pw->next;
+  pw->next = w->next;         // snip w out of list
+  if (head == w) {            // we removed the head
+    head = (pw == w) ? nullptr : pw;  // either emptied list, or pw is new head
+  } else if (pw != head && MuSameCondition(pw, pw->next)) {
+    // pw can skip to its new successor
+    if (pw->next->skip !=
+        nullptr) {  // either skip to its successors skip target
+      pw->skip = pw->next->skip;
+    } else {                   // or to pw's successor
+      pw->skip = pw->next;
+    }
+  }
+  return head;
+}
+
+// Traverse the elements [ pw->next, h] of the circular list whose last element
+// is head.
+// Remove all elements with wake==true and place them in the
+// singly-linked list wake_list in the order found.   Assumes that
+// there is only one such element if the element has how == kExclusive.
+// Return the new head.
+static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head,
+                                          PerThreadSynch *pw,
+                                          PerThreadSynch **wake_tail) {
+  PerThreadSynch *orig_h = head;
+  PerThreadSynch *w = pw->next;
+  bool skipped = false;
+  do {
+    if (w->wake) {                    // remove this element
+      ABSL_RAW_CHECK(pw->skip == nullptr, "bad skip in DequeueAllWakeable");
+      // we're removing pw's successor so either pw->skip is zero or we should
+      // already have removed pw since if pw->skip!=null, pw has the same
+      // condition as w.
+      head = Dequeue(head, pw);
+      w->next = *wake_tail;           // keep list terminated
+      *wake_tail = w;                 // add w to wake_list;
+      wake_tail = &w->next;           // next addition to end
+      if (w->waitp->how == kExclusive) {  // wake at most 1 writer
+        break;
+      }
+    } else {                // not waking this one; skip
+      pw = Skip(w);       // skip as much as possible
+      skipped = true;
+    }
+    w = pw->next;
+    // We want to stop processing after we've considered the original head,
+    // orig_h.  We can't test for w==orig_h in the loop because w may skip over
+    // it; we are guaranteed only that w's predecessor will not skip over
+    // orig_h.  When we've considered orig_h, either we've processed it and
+    // removed it (so orig_h != head), or we considered it and skipped it (so
+    // skipped==true && pw == head because skipping from head always skips by
+    // just one, leaving pw pointing at head).  So we want to
+    // continue the loop with the negation of that expression.
+  } while (orig_h == head && (pw != head || !skipped));
+  return head;
+}
+
+// Try to remove thread s from the list of waiters on this mutex.
+// Does nothing if s is not on the waiter list.
+void Mutex::TryRemove(PerThreadSynch *s) {
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // acquire spinlock & lock
+  if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
+      mu_.compare_exchange_strong(v, v | kMuSpin | kMuWriter,
+                                  std::memory_order_acquire,
+                                  std::memory_order_relaxed)) {
+    PerThreadSynch *h = GetPerThreadSynch(v);
+    if (h != nullptr) {
+      PerThreadSynch *pw = h;   // pw is w's predecessor
+      PerThreadSynch *w;
+      if ((w = pw->next) != s) {  // search for thread,
+        do {                      // processing at least one element
+          if (!MuSameCondition(s, w)) {  // seeking different condition
+            pw = Skip(w);                // so skip all that won't match
+            // we don't have to worry about dangling skip fields
+            // in the threads we skipped; none can point to s
+            // because their condition differs from s
+          } else {          // seeking same condition
+            FixSkip(w, s);  // fix up any skip pointer from w to s
+            pw = w;
+          }
+          // don't search further if we found the thread, or we're about to
+          // process the first thread again.
+        } while ((w = pw->next) != s && pw != h);
+      }
+      if (w == s) {                 // found thread; remove it
+        // pw->skip may be non-zero here; the loop above ensured that
+        // no ancestor of s can skip to s, so removal is safe anyway.
+        h = Dequeue(h, pw);
+        s->next = nullptr;
+        s->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+      }
+    }
+    intptr_t nv;
+    do {                        // release spinlock and lock
+      v = mu_.load(std::memory_order_relaxed);
+      nv = v & (kMuDesig | kMuEvent);
+      if (h != nullptr) {
+        nv |= kMuWait | reinterpret_cast<intptr_t>(h);
+        h->readers = 0;            // we hold writer lock
+        h->maybe_unlocking = false;  // finished unlocking
+      }
+    } while (!mu_.compare_exchange_weak(v, nv,
+                                        std::memory_order_release,
+                                        std::memory_order_relaxed));
+  }
+}
+
+// Wait until thread "s", which must be the current thread, is removed from the
+// this mutex's waiter queue.  If "s->waitp->timeout" has a timeout, wake up
+// if the wait extends past the absolute time specified, even if "s" is still
+// on the mutex queue.  In this case, remove "s" from the queue and return
+// true, otherwise return false.
+void Mutex::Block(PerThreadSynch *s) {
+  while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) {
+    if (!DecrementSynchSem(this, s, s->waitp->timeout)) {
+      // After a timeout, we go into a spin loop until we remove ourselves
+      // from the queue, or someone else removes us.  We can't be sure to be
+      // able to remove ourselves in a single lock acquisition because this
+      // mutex may be held, and the holder has the right to read the centre
+      // of the waiter queue without holding the spinlock.
+      this->TryRemove(s);
+      int c = 0;
+      while (s->next != nullptr) {
+        c = Delay(c, GENTLE);
+        this->TryRemove(s);
+      }
+      if (kDebugMode) {
+        // This ensures that we test the case that TryRemove() is called when s
+        // is not on the queue.
+        this->TryRemove(s);
+      }
+      s->waitp->timeout = KernelTimeout::Never();      // timeout is satisfied
+      s->waitp->cond = nullptr;  // condition no longer relevant for wakeups
+    }
+  }
+  ABSL_RAW_CHECK(s->waitp != nullptr || s->suppress_fatal_errors,
+                 "detected illegal recursion in Mutex code");
+  s->waitp = nullptr;
+}
+
+// Wake thread w, and return the next thread in the list.
+PerThreadSynch *Mutex::Wakeup(PerThreadSynch *w) {
+  PerThreadSynch *next = w->next;
+  w->next = nullptr;
+  w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+  IncrementSynchSem(this, w);
+
+  return next;
+}
+
+static GraphId GetGraphIdLocked(Mutex *mu)
+    EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) {
+  if (!deadlock_graph) {  // (re)create the deadlock graph.
+    deadlock_graph =
+        new (base_internal::LowLevelAlloc::Alloc(sizeof(*deadlock_graph)))
+            GraphCycles;
+  }
+  return deadlock_graph->GetId(mu);
+}
+
+static GraphId GetGraphId(Mutex *mu) LOCKS_EXCLUDED(deadlock_graph_mu) {
+  deadlock_graph_mu.Lock();
+  GraphId id = GetGraphIdLocked(mu);
+  deadlock_graph_mu.Unlock();
+  return id;
+}
+
+// Record a lock acquisition.  This is used in debug mode for deadlock
+// detection.  The held_locks pointer points to the relevant data
+// structure for each case.
+static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) {
+  int n = held_locks->n;
+  int i = 0;
+  while (i != n && held_locks->locks[i].id != id) {
+    i++;
+  }
+  if (i == n) {
+    if (n == ABSL_ARRAYSIZE(held_locks->locks)) {
+      held_locks->overflow = true;  // lost some data
+    } else {                        // we have room for lock
+      held_locks->locks[i].mu = mu;
+      held_locks->locks[i].count = 1;
+      held_locks->locks[i].id = id;
+      held_locks->n = n + 1;
+    }
+  } else {
+    held_locks->locks[i].count++;
+  }
+}
+
+// Record a lock release.  Each call to LockEnter(mu, id, x) should be
+// eventually followed by a call to LockLeave(mu, id, x) by the same thread.
+// It does not process the event if is not needed when deadlock detection is
+// disabled.
+static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) {
+  int n = held_locks->n;
+  int i = 0;
+  while (i != n && held_locks->locks[i].id != id) {
+    i++;
+  }
+  if (i == n) {
+    if (!held_locks->overflow) {
+      // The deadlock id may have been reassigned after ForgetDeadlockInfo,
+      // but in that case mu should still be present.
+      i = 0;
+      while (i != n && held_locks->locks[i].mu != mu) {
+        i++;
+      }
+      if (i == n) {  // mu missing means releasing unheld lock
+        SynchEvent *mu_events = GetSynchEvent(mu);
+        ABSL_RAW_LOG(FATAL,
+                     "thread releasing lock it does not hold: %p %s; "
+                     ,
+                     static_cast<void *>(mu),
+                     mu_events == nullptr ? "" : mu_events->name);
+      }
+    }
+  } else if (held_locks->locks[i].count == 1) {
+    held_locks->n = n - 1;
+    held_locks->locks[i] = held_locks->locks[n - 1];
+    held_locks->locks[n - 1].id = InvalidGraphId();
+    held_locks->locks[n - 1].mu =
+        nullptr;  // clear mu to please the leak detector.
+  } else {
+    assert(held_locks->locks[i].count > 0);
+    held_locks->locks[i].count--;
+  }
+}
+
+// Call LockEnter() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockEnter(Mutex *mu) {
+  if (kDebugMode) {
+    if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+        OnDeadlockCycle::kIgnore) {
+      LockEnter(mu, GetGraphId(mu), Synch_GetAllLocks());
+    }
+  }
+}
+
+// Call LockEnter() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockEnter(Mutex *mu, GraphId id) {
+  if (kDebugMode) {
+    if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+        OnDeadlockCycle::kIgnore) {
+      LockEnter(mu, id, Synch_GetAllLocks());
+    }
+  }
+}
+
+// Call LockLeave() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockLeave(Mutex *mu) {
+  if (kDebugMode) {
+    if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+        OnDeadlockCycle::kIgnore) {
+      LockLeave(mu, GetGraphId(mu), Synch_GetAllLocks());
+    }
+  }
+}
+
+static char *StackString(void **pcs, int n, char *buf, int maxlen,
+                         bool symbolize) {
+  static const int kSymLen = 200;
+  char sym[kSymLen];
+  int len = 0;
+  for (int i = 0; i != n; i++) {
+    if (symbolize) {
+      if (!symbolizer(pcs[i], sym, kSymLen)) {
+        sym[0] = '\0';
+      }
+      snprintf(buf + len, maxlen - len, "%s\t@ %p %s\n",
+               (i == 0 ? "\n" : ""),
+               pcs[i], sym);
+    } else {
+      snprintf(buf + len, maxlen - len, " %p", pcs[i]);
+    }
+    len += strlen(&buf[len]);
+  }
+  return buf;
+}
+
+static char *CurrentStackString(char *buf, int maxlen, bool symbolize) {
+  void *pcs[40];
+  return StackString(pcs, absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 2), buf,
+                     maxlen, symbolize);
+}
+
+namespace {
+enum { kMaxDeadlockPathLen = 10 };  // maximum length of a deadlock cycle;
+                                    // a path this long would be remarkable
+// Buffers required to report a deadlock.
+// We do not allocate them on stack to avoid large stack frame.
+struct DeadlockReportBuffers {
+  char buf[6100];
+  GraphId path[kMaxDeadlockPathLen];
+};
+
+struct ScopedDeadlockReportBuffers {
+  ScopedDeadlockReportBuffers() {
+    b = reinterpret_cast<DeadlockReportBuffers *>(
+        base_internal::LowLevelAlloc::Alloc(sizeof(*b)));
+  }
+  ~ScopedDeadlockReportBuffers() { base_internal::LowLevelAlloc::Free(b); }
+  DeadlockReportBuffers *b;
+};
+
+// Helper to pass to GraphCycles::UpdateStackTrace.
+int GetStack(void** stack, int max_depth) {
+  return absl::GetStackTrace(stack, max_depth, 3);
+}
+}  // anonymous namespace
+
+// Called in debug mode when a thread is about to acquire a lock in a way that
+// may block.
+static GraphId DeadlockCheck(Mutex *mu) {
+  if (synch_deadlock_detection.load(std::memory_order_acquire) ==
+      OnDeadlockCycle::kIgnore) {
+    return InvalidGraphId();
+  }
+
+  SynchLocksHeld *all_locks = Synch_GetAllLocks();
+
+  absl::base_internal::SpinLockHolder lock(&deadlock_graph_mu);
+  const GraphId mu_id = GetGraphIdLocked(mu);
+
+  if (all_locks->n == 0) {
+    // There are no other locks held. Return now so that we don't need to
+    // call GetSynchEvent(). This way we do not record the stack trace
+    // for this Mutex. It's ok, since if this Mutex is involved in a deadlock,
+    // it can't always be the first lock acquired by a thread.
+    return mu_id;
+  }
+
+  // We prefer to keep stack traces that show a thread holding and acquiring
+  // as many locks as possible.  This increases the chances that a given edge
+  // in the acquires-before graph will be represented in the stack traces
+  // recorded for the locks.
+  deadlock_graph->UpdateStackTrace(mu_id, all_locks->n + 1, GetStack);
+
+  // For each other mutex already held by this thread:
+  for (int i = 0; i != all_locks->n; i++) {
+    const GraphId other_node_id = all_locks->locks[i].id;
+    const Mutex *other =
+        static_cast<const Mutex *>(deadlock_graph->Ptr(other_node_id));
+    if (other == nullptr) {
+      // Ignore stale lock
+      continue;
+    }
+
+    // Add the acquired-before edge to the graph.
+    if (!deadlock_graph->InsertEdge(other_node_id, mu_id)) {
+      ScopedDeadlockReportBuffers scoped_buffers;
+      DeadlockReportBuffers *b = scoped_buffers.b;
+      static int number_of_reported_deadlocks = 0;
+      number_of_reported_deadlocks++;
+      // Symbolize only 2 first deadlock report to avoid huge slowdowns.
+      bool symbolize = number_of_reported_deadlocks <= 2;
+      ABSL_RAW_LOG(ERROR, "Potential Mutex deadlock: %s",
+                   CurrentStackString(b->buf, sizeof (b->buf), symbolize));
+      int len = 0;
+      for (int j = 0; j != all_locks->n; j++) {
+        void* pr = deadlock_graph->Ptr(all_locks->locks[j].id);
+        if (pr != nullptr) {
+          snprintf(b->buf + len, sizeof (b->buf) - len, " %p", pr);
+          len += static_cast<int>(strlen(&b->buf[len]));
+        }
+      }
+      ABSL_RAW_LOG(ERROR, "Acquiring %p    Mutexes held: %s",
+                   static_cast<void *>(mu), b->buf);
+      ABSL_RAW_LOG(ERROR, "Cycle: ");
+      int path_len = deadlock_graph->FindPath(
+          mu_id, other_node_id, ABSL_ARRAYSIZE(b->path), b->path);
+      for (int j = 0; j != path_len; j++) {
+        GraphId id = b->path[j];
+        Mutex *path_mu = static_cast<Mutex *>(deadlock_graph->Ptr(id));
+        if (path_mu == nullptr) continue;
+        void** stack;
+        int depth = deadlock_graph->GetStackTrace(id, &stack);
+        snprintf(b->buf, sizeof(b->buf),
+                 "mutex@%p stack: ", static_cast<void *>(path_mu));
+        StackString(stack, depth, b->buf + strlen(b->buf),
+                    static_cast<int>(sizeof(b->buf) - strlen(b->buf)),
+                    symbolize);
+        ABSL_RAW_LOG(ERROR, "%s", b->buf);
+      }
+      if (synch_deadlock_detection.load(std::memory_order_acquire) ==
+          OnDeadlockCycle::kAbort) {
+        deadlock_graph_mu.Unlock();  // avoid deadlock in fatal sighandler
+        ABSL_RAW_LOG(FATAL, "dying due to potential deadlock");
+        return mu_id;
+      }
+      break;   // report at most one potential deadlock per acquisition
+    }
+  }
+
+  return mu_id;
+}
+
+// Invoke DeadlockCheck() iff we're in debug mode and
+// deadlock checking has been enabled.
+static inline GraphId DebugOnlyDeadlockCheck(Mutex *mu) {
+  if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
+                        OnDeadlockCycle::kIgnore) {
+    return DeadlockCheck(mu);
+  } else {
+    return InvalidGraphId();
+  }
+}
+
+void Mutex::ForgetDeadlockInfo() {
+  if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
+                        OnDeadlockCycle::kIgnore) {
+    deadlock_graph_mu.Lock();
+    if (deadlock_graph != nullptr) {
+      deadlock_graph->RemoveNode(this);
+    }
+    deadlock_graph_mu.Unlock();
+  }
+}
+
+void Mutex::AssertNotHeld() const {
+  // We have the data to allow this check only if in debug mode and deadlock
+  // detection is enabled.
+  if (kDebugMode &&
+      (mu_.load(std::memory_order_relaxed) & (kMuWriter | kMuReader)) != 0 &&
+      synch_deadlock_detection.load(std::memory_order_acquire) !=
+          OnDeadlockCycle::kIgnore) {
+    GraphId id = GetGraphId(const_cast<Mutex *>(this));
+    SynchLocksHeld *locks = Synch_GetAllLocks();
+    for (int i = 0; i != locks->n; i++) {
+      if (locks->locks[i].id == id) {
+        SynchEvent *mu_events = GetSynchEvent(this);
+        ABSL_RAW_LOG(FATAL, "thread should not hold mutex %p %s",
+                     static_cast<const void *>(this),
+                     (mu_events == nullptr ? "" : mu_events->name));
+      }
+    }
+  }
+}
+
+// Attempt to acquire *mu, and return whether successful.  The implementation
+// may spin for a short while if the lock cannot be acquired immediately.
+static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) {
+  int c = mutex_globals.spinloop_iterations;
+  int result = -1;  // result of operation:  0=false, 1=true, -1=unknown
+
+  do {  // do/while somewhat faster on AMD
+    intptr_t v = mu->load(std::memory_order_relaxed);
+    if ((v & (kMuReader|kMuEvent)) != 0) {  // a reader or tracing -> give up
+      result = 0;
+    } else if (((v & kMuWriter) == 0) &&  // no holder -> try to acquire
+               mu->compare_exchange_strong(v, kMuWriter | v,
+                                           std::memory_order_acquire,
+                                           std::memory_order_relaxed)) {
+      result = 1;
+    }
+  } while (result == -1 && --c > 0);
+  return result == 1;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // try fast acquire, then spin loop
+  if ((v & (kMuWriter | kMuReader | kMuEvent)) != 0 ||
+      !mu_.compare_exchange_strong(v, kMuWriter | v,
+                                   std::memory_order_acquire,
+                                   std::memory_order_relaxed)) {
+    // try spin acquire, then slow loop
+    if (!TryAcquireWithSpinning(&this->mu_)) {
+      this->LockSlow(kExclusive, nullptr, 0);
+    }
+  }
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderLock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // try fast acquire, then slow loop
+  if ((v & (kMuWriter | kMuWait | kMuEvent)) != 0 ||
+      !mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+                                   std::memory_order_acquire,
+                                   std::memory_order_relaxed)) {
+    this->LockSlow(kShared, nullptr, 0);
+  }
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+}
+
+void Mutex::LockWhen(const Condition &cond) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  this->LockSlow(kExclusive, &cond, 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+}
+
+bool Mutex::LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) {
+  return LockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::LockWhenWithDeadline(const Condition &cond, absl::Time deadline) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  bool res = LockSlowWithDeadline(kExclusive, &cond,
+                                  KernelTimeout(deadline), 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+  return res;
+}
+
+void Mutex::ReaderLockWhen(const Condition &cond) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  this->LockSlow(kShared, &cond, 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+}
+
+bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond,
+                                      absl::Duration timeout) {
+  return ReaderLockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond,
+                                       absl::Time deadline) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  bool res = LockSlowWithDeadline(kShared, &cond, KernelTimeout(deadline), 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+  return res;
+}
+
+void Mutex::Await(const Condition &cond) {
+  if (cond.Eval()) {    // condition already true; nothing to do
+    if (kDebugMode) {
+      this->AssertReaderHeld();
+    }
+  } else {              // normal case
+    ABSL_RAW_CHECK(this->AwaitCommon(cond, KernelTimeout::Never()),
+                   "condition untrue on return from Await");
+  }
+}
+
+bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) {
+  return AwaitWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) {
+  if (cond.Eval()) {      // condition already true; nothing to do
+    if (kDebugMode) {
+      this->AssertReaderHeld();
+    }
+    return true;
+  }
+
+  KernelTimeout t{deadline};
+  bool res = this->AwaitCommon(cond, t);
+  ABSL_RAW_CHECK(res || t.has_timeout(),
+                 "condition untrue on return from Await");
+  return res;
+}
+
+bool Mutex::AwaitCommon(const Condition &cond, KernelTimeout t) {
+  this->AssertReaderHeld();
+  MuHow how =
+      (mu_.load(std::memory_order_relaxed) & kMuWriter) ? kExclusive : kShared;
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(this, TsanFlags(how));
+  SynchWaitParams waitp(
+      how, &cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this),
+      nullptr /*no cv_word*/);
+  int flags = kMuHasBlocked;
+  if (!Condition::GuaranteedEqual(&cond, nullptr)) {
+    flags |= kMuIsCond;
+  }
+  this->UnlockSlow(&waitp);
+  this->Block(waitp.thread);
+  ABSL_TSAN_MUTEX_POST_UNLOCK(this, TsanFlags(how));
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how));
+  this->LockSlowLoop(&waitp, flags);
+  bool res = waitp.cond != nullptr ||  // => cond known true from LockSlowLoop
+             cond.Eval();
+  ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0);
+  return res;
+}
+
+ABSL_XRAY_LOG_ARGS(1) bool Mutex::TryLock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  if ((v & (kMuWriter | kMuReader | kMuEvent)) == 0 &&  // try fast acquire
+      mu_.compare_exchange_strong(v, kMuWriter | v,
+                                  std::memory_order_acquire,
+                                  std::memory_order_relaxed)) {
+    DebugOnlyLockEnter(this);
+    ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+    return true;
+  }
+  if ((v & kMuEvent) != 0) {              // we're recording events
+    if ((v & kExclusive->slow_need_zero) == 0 &&  // try fast acquire
+        mu_.compare_exchange_strong(
+            v, (kExclusive->fast_or | v) + kExclusive->fast_add,
+            std::memory_order_acquire, std::memory_order_relaxed)) {
+      DebugOnlyLockEnter(this);
+      PostSynchEvent(this, SYNCH_EV_TRYLOCK_SUCCESS);
+      ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+      return true;
+    } else {
+      PostSynchEvent(this, SYNCH_EV_TRYLOCK_FAILED);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_LOCK(
+      this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0);
+  return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) bool Mutex::ReaderTryLock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this,
+                           __tsan_mutex_read_lock | __tsan_mutex_try_lock);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // The while-loops (here and below) iterate only if the mutex word keeps
+  // changing (typically because the reader count changes) under the CAS.  We
+  // limit the number of attempts to avoid having to think about livelock.
+  int loop_limit = 5;
+  while ((v & (kMuWriter|kMuWait|kMuEvent)) == 0 && loop_limit != 0) {
+    if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+                                    std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      DebugOnlyLockEnter(this);
+      ABSL_TSAN_MUTEX_POST_LOCK(
+          this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0);
+      return true;
+    }
+    loop_limit--;
+    v = mu_.load(std::memory_order_relaxed);
+  }
+  if ((v & kMuEvent) != 0) {   // we're recording events
+    loop_limit = 5;
+    while ((v & kShared->slow_need_zero) == 0 && loop_limit != 0) {
+      if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+                                      std::memory_order_acquire,
+                                      std::memory_order_relaxed)) {
+        DebugOnlyLockEnter(this);
+        PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_SUCCESS);
+        ABSL_TSAN_MUTEX_POST_LOCK(
+            this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0);
+        return true;
+      }
+      loop_limit--;
+      v = mu_.load(std::memory_order_relaxed);
+    }
+    if ((v & kMuEvent) != 0) {
+      PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_FAILED);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_LOCK(this,
+                            __tsan_mutex_read_lock | __tsan_mutex_try_lock |
+                                __tsan_mutex_try_lock_failed,
+                            0);
+  return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Unlock() {
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
+  DebugOnlyLockLeave(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+
+  if (kDebugMode && ((v & (kMuWriter | kMuReader)) != kMuWriter)) {
+    ABSL_RAW_LOG(FATAL, "Mutex unlocked when destroyed or not locked: v=0x%x",
+                 static_cast<unsigned>(v));
+  }
+
+  // should_try_cas is whether we'll try a compare-and-swap immediately.
+  // NOTE: optimized out when kDebugMode is false.
+  bool should_try_cas = ((v & (kMuEvent | kMuWriter)) == kMuWriter &&
+                          (v & (kMuWait | kMuDesig)) != kMuWait);
+  // But, we can use an alternate computation of it, that compilers
+  // currently don't find on their own.  When that changes, this function
+  // can be simplified.
+  intptr_t x = (v ^ (kMuWriter | kMuWait)) & (kMuWriter | kMuEvent);
+  intptr_t y = (v ^ (kMuWriter | kMuWait)) & (kMuWait | kMuDesig);
+  // Claim: "x == 0 && y > 0" is equal to should_try_cas.
+  // Also, because kMuWriter and kMuEvent exceed kMuDesig and kMuWait,
+  // all possible non-zero values for x exceed all possible values for y.
+  // Therefore, (x == 0 && y > 0) == (x < y).
+  if (kDebugMode && should_try_cas != (x < y)) {
+    // We would usually use PRIdPTR here, but is not correctly implemented
+    // within the android toolchain.
+    ABSL_RAW_LOG(FATAL, "internal logic error %llx %llx %llx\n",
+                 static_cast<long long>(v), static_cast<long long>(x),
+                 static_cast<long long>(y));
+  }
+  if (x < y &&
+      mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+                                  std::memory_order_release,
+                                  std::memory_order_relaxed)) {
+    // fast writer release (writer with no waiters or with designated waker)
+  } else {
+    this->UnlockSlow(nullptr /*no waitp*/);  // take slow path
+  }
+  ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
+}
+
+// Requires v to represent a reader-locked state.
+static bool ExactlyOneReader(intptr_t v) {
+  assert((v & (kMuWriter|kMuReader)) == kMuReader);
+  assert((v & kMuHigh) != 0);
+  // The more straightforward "(v & kMuHigh) == kMuOne" also works, but
+  // on some architectures the following generates slightly smaller code.
+  // It may be faster too.
+  constexpr intptr_t kMuMultipleWaitersMask = kMuHigh ^ kMuOne;
+  return (v & kMuMultipleWaitersMask) == 0;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderUnlock() {
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(this, __tsan_mutex_read_lock);
+  DebugOnlyLockLeave(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  assert((v & (kMuWriter|kMuReader)) == kMuReader);
+  if ((v & (kMuReader|kMuWait|kMuEvent)) == kMuReader) {
+    // fast reader release (reader with no waiters)
+    intptr_t clear = ExactlyOneReader(v) ? kMuReader|kMuOne : kMuOne;
+    if (mu_.compare_exchange_strong(v, v - clear,
+                                    std::memory_order_release,
+                                    std::memory_order_relaxed)) {
+      ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock);
+      return;
+    }
+  }
+  this->UnlockSlow(nullptr /*no waitp*/);  // take slow path
+  ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock);
+}
+
+// The zap_desig_waker bitmask is used to clear the designated waker flag in
+// the mutex if this thread has blocked, and therefore may be the designated
+// waker.
+static const intptr_t zap_desig_waker[] = {
+    ~static_cast<intptr_t>(0),  // not blocked
+    ~static_cast<intptr_t>(
+        kMuDesig)  // blocked; turn off the designated waker bit
+};
+
+// The ignore_waiting_writers bitmask is used to ignore the existence
+// of waiting writers if a reader that has already blocked once
+// wakes up.
+static const intptr_t ignore_waiting_writers[] = {
+    ~static_cast<intptr_t>(0),  // not blocked
+    ~static_cast<intptr_t>(
+        kMuWrWait)  // blocked; pretend there are no waiting writers
+};
+
+// Internal version of LockWhen().  See LockSlowWithDeadline()
+void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) {
+  ABSL_RAW_CHECK(
+      this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags),
+      "condition untrue on return from LockSlow");
+}
+
+// Compute cond->Eval() and tell race detectors that we do it under mutex mu.
+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
+                                          bool locking, Mutex::MuHow how) {
+  // Delicate annotation dance.
+  // We are currently inside of read/write lock/unlock operation.
+  // All memory accesses are ignored inside of mutex operations + for unlock
+  // operation tsan considers that we've already released the mutex.
+  bool res = false;
+  if (locking) {
+    // For lock we pretend that we have finished the operation,
+    // evaluate the predicate, then unlock the mutex and start locking it again
+    // to match the annotation at the end of outer lock operation.
+    // Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan
+    // will think the lock acquisition is recursive which will trigger
+    // deadlock detector.
+    ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+    res = cond->Eval();
+    ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
+    ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
+    ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
+  } else {
+    // Similarly, for unlock we pretend that we have unlocked the mutex,
+    // lock the mutex, evaluate the predicate, and start unlocking it again
+    // to match the annotation at the end of outer unlock operation.
+    ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
+    ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
+    ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+    res = cond->Eval();
+    ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
+  }
+  // Prevent unused param warnings in non-TSAN builds.
+  static_cast<void>(mu);
+  static_cast<void>(how);
+  return res;
+}
+
+// Compute cond->Eval() hiding it from race detectors.
+// We are hiding it because inside of UnlockSlow we can evaluate a predicate
+// that was just added by a concurrent Lock operation; Lock adds the predicate
+// to the internal Mutex list without actually acquiring the Mutex
+// (it only acquires the internal spinlock, which is rightfully invisible for
+// tsan). As the result there is no tsan-visible synchronization between the
+// addition and this thread. So if we would enable race detection here,
+// it would race with the predicate initialization.
+static inline bool EvalConditionIgnored(Mutex *mu, const Condition *cond) {
+  // Memory accesses are already ignored inside of lock/unlock operations,
+  // but synchronization operations are also ignored. When we evaluate the
+  // predicate we must ignore only memory accesses but not synchronization,
+  // because missed synchronization can lead to false reports later.
+  // So we "divert" (which un-ignores both memory accesses and synchronization)
+  // and then separately turn on ignores of memory accesses.
+  ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+  bool res = cond->Eval();
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
+  ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  static_cast<void>(mu);  // Prevent unused param warning in non-TSAN builds.
+  return res;
+}
+
+// Internal equivalent of *LockWhenWithDeadline(), where
+//   "t" represents the absolute timeout; !t.has_timeout() means "forever".
+//   "how" is "kShared" (for ReaderLockWhen) or "kExclusive" (for LockWhen)
+// In flags, bits are ored together:
+// - kMuHasBlocked indicates that the client has already blocked on the call so
+//   the designated waker bit must be cleared and waiting writers should not
+//   obstruct this call
+// - kMuIsCond indicates that this is a conditional acquire (condition variable,
+//   Await,  LockWhen) so contention profiling should be suppressed.
+bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond,
+                                 KernelTimeout t, int flags) {
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  bool unlock = false;
+  if ((v & how->fast_need_zero) == 0 &&  // try fast acquire
+      mu_.compare_exchange_strong(
+          v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) +
+                 how->fast_add,
+          std::memory_order_acquire, std::memory_order_relaxed)) {
+    if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) {
+      return true;
+    }
+    unlock = true;
+  }
+  SynchWaitParams waitp(
+      how, cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this),
+      nullptr /*no cv_word*/);
+  if (!Condition::GuaranteedEqual(cond, nullptr)) {
+    flags |= kMuIsCond;
+  }
+  if (unlock) {
+    this->UnlockSlow(&waitp);
+    this->Block(waitp.thread);
+    flags |= kMuHasBlocked;
+  }
+  this->LockSlowLoop(&waitp, flags);
+  return waitp.cond != nullptr ||  // => cond known true from LockSlowLoop
+         cond == nullptr || EvalConditionAnnotated(cond, this, true, how);
+}
+
+// RAW_CHECK_FMT() takes a condition, a printf-style format std::string, and
+// the printf-style argument list.   The format std::string must be a literal.
+// Arguments after the first are not evaluated unless the condition is true.
+#define RAW_CHECK_FMT(cond, ...)                                   \
+  do {                                                             \
+    if (ABSL_PREDICT_FALSE(!(cond))) {                             \
+      ABSL_RAW_LOG(FATAL, "Check " #cond " failed: " __VA_ARGS__); \
+    }                                                              \
+  } while (0)
+
+static void CheckForMutexCorruption(intptr_t v, const char* label) {
+  // Test for either of two situations that should not occur in v:
+  //   kMuWriter and kMuReader
+  //   kMuWrWait and !kMuWait
+  const intptr_t w = v ^ kMuWait;
+  // By flipping that bit, we can now test for:
+  //   kMuWriter and kMuReader in w
+  //   kMuWrWait and kMuWait in w
+  // We've chosen these two pairs of values to be so that they will overlap,
+  // respectively, when the word is left shifted by three.  This allows us to
+  // save a branch in the common (correct) case of them not being coincident.
+  static_assert(kMuReader << 3 == kMuWriter, "must match");
+  static_assert(kMuWait << 3 == kMuWrWait, "must match");
+  if (ABSL_PREDICT_TRUE((w & (w << 3) & (kMuWriter | kMuWrWait)) == 0)) return;
+  RAW_CHECK_FMT((v & (kMuWriter | kMuReader)) != (kMuWriter | kMuReader),
+                "%s: Mutex corrupt: both reader and writer lock held: %p",
+                label, reinterpret_cast<void *>(v));
+  RAW_CHECK_FMT((v & (kMuWait | kMuWrWait)) != kMuWrWait,
+                "%s: Mutex corrupt: waiting writer with no waiters: %p",
+                label, reinterpret_cast<void *>(v));
+  assert(false);
+}
+
+void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
+  int c = 0;
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  if ((v & kMuEvent) != 0) {
+    PostSynchEvent(this,
+         waitp->how == kExclusive?  SYNCH_EV_LOCK: SYNCH_EV_READERLOCK);
+  }
+  ABSL_RAW_CHECK(
+      waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+      "detected illegal recursion into Mutex code");
+  for (;;) {
+    v = mu_.load(std::memory_order_relaxed);
+    CheckForMutexCorruption(v, "Lock");
+    if ((v & waitp->how->slow_need_zero) == 0) {
+      if (mu_.compare_exchange_strong(
+              v, (waitp->how->fast_or |
+                  (v & zap_desig_waker[flags & kMuHasBlocked])) +
+                     waitp->how->fast_add,
+              std::memory_order_acquire, std::memory_order_relaxed)) {
+        if (waitp->cond == nullptr ||
+            EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+          break;  // we timed out, or condition true, so return
+        }
+        this->UnlockSlow(waitp);  // got lock but condition false
+        this->Block(waitp->thread);
+        flags |= kMuHasBlocked;
+        c = 0;
+      }
+    } else {                      // need to access waiter list
+      bool dowait = false;
+      if ((v & (kMuSpin|kMuWait)) == 0) {   // no waiters
+        // This thread tries to become the one and only waiter.
+        PerThreadSynch *new_h = Enqueue(nullptr, waitp, v, flags);
+        intptr_t nv = (v & zap_desig_waker[flags & kMuHasBlocked] & kMuLow) |
+                      kMuWait;
+        ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to empty list failed");
+        if (waitp->how == kExclusive && (v & kMuReader) != 0) {
+          nv |= kMuWrWait;
+        }
+        if (mu_.compare_exchange_strong(
+                v, reinterpret_cast<intptr_t>(new_h) | nv,
+                std::memory_order_release, std::memory_order_relaxed)) {
+          dowait = true;
+        } else {            // attempted Enqueue() failed
+          // zero out the waitp field set by Enqueue()
+          waitp->thread->waitp = nullptr;
+        }
+      } else if ((v & waitp->how->slow_inc_need_zero &
+                  ignore_waiting_writers[flags & kMuHasBlocked]) == 0) {
+        // This is a reader that needs to increment the reader count,
+        // but the count is currently held in the last waiter.
+        if (mu_.compare_exchange_strong(
+                v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin |
+                       kMuReader,
+                std::memory_order_acquire, std::memory_order_relaxed)) {
+          PerThreadSynch *h = GetPerThreadSynch(v);
+          h->readers += kMuOne;       // inc reader count in waiter
+          do {                        // release spinlock
+            v = mu_.load(std::memory_order_relaxed);
+          } while (!mu_.compare_exchange_weak(v, (v & ~kMuSpin) | kMuReader,
+                                              std::memory_order_release,
+                                              std::memory_order_relaxed));
+          if (waitp->cond == nullptr ||
+              EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+            break;  // we timed out, or condition true, so return
+          }
+          this->UnlockSlow(waitp);           // got lock but condition false
+          this->Block(waitp->thread);
+          flags |= kMuHasBlocked;
+          c = 0;
+        }
+      } else if ((v & kMuSpin) == 0 &&  // attempt to queue ourselves
+                 mu_.compare_exchange_strong(
+                     v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin |
+                            kMuWait,
+                     std::memory_order_acquire, std::memory_order_relaxed)) {
+        PerThreadSynch *h = GetPerThreadSynch(v);
+        PerThreadSynch *new_h = Enqueue(h, waitp, v, flags);
+        intptr_t wr_wait = 0;
+        ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to list failed");
+        if (waitp->how == kExclusive && (v & kMuReader) != 0) {
+          wr_wait = kMuWrWait;      // give priority to a waiting writer
+        }
+        do {                        // release spinlock
+          v = mu_.load(std::memory_order_relaxed);
+        } while (!mu_.compare_exchange_weak(
+            v, (v & (kMuLow & ~kMuSpin)) | kMuWait | wr_wait |
+            reinterpret_cast<intptr_t>(new_h),
+            std::memory_order_release, std::memory_order_relaxed));
+        dowait = true;
+      }
+      if (dowait) {
+        this->Block(waitp->thread);  // wait until removed from list or timeout
+        flags |= kMuHasBlocked;
+        c = 0;
+      }
+    }
+    ABSL_RAW_CHECK(
+        waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+        "detected illegal recursion into Mutex code");
+    c = Delay(c, GENTLE);          // delay, then try again
+  }
+  ABSL_RAW_CHECK(
+      waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+      "detected illegal recursion into Mutex code");
+  if ((v & kMuEvent) != 0) {
+    PostSynchEvent(this,
+                   waitp->how == kExclusive? SYNCH_EV_LOCK_RETURNING :
+                                      SYNCH_EV_READERLOCK_RETURNING);
+  }
+}
+
+// Unlock this mutex, which is held by the current thread.
+// If waitp is non-zero, it must be the wait parameters for the current thread
+// which holds the lock but is not runnable because its condition is false
+// or it n the process of blocking on a condition variable; it must requeue
+// itself on the mutex/condvar to wait for its condition to become true.
+void Mutex::UnlockSlow(SynchWaitParams *waitp) {
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  this->AssertReaderHeld();
+  CheckForMutexCorruption(v, "Unlock");
+  if ((v & kMuEvent) != 0) {
+    PostSynchEvent(this,
+                (v & kMuWriter) != 0? SYNCH_EV_UNLOCK: SYNCH_EV_READERUNLOCK);
+  }
+  int c = 0;
+  // the waiter under consideration to wake, or zero
+  PerThreadSynch *w = nullptr;
+  // the predecessor to w or zero
+  PerThreadSynch *pw = nullptr;
+  // head of the list searched previously, or zero
+  PerThreadSynch *old_h = nullptr;
+  // a condition that's known to be false.
+  const Condition *known_false = nullptr;
+  PerThreadSynch *wake_list = kPerThreadSynchNull;   // list of threads to wake
+  intptr_t wr_wait = 0;        // set to kMuWrWait if we wake a reader and a
+                               // later writer could have acquired the lock
+                               // (starvation avoidance)
+  ABSL_RAW_CHECK(waitp == nullptr || waitp->thread->waitp == nullptr ||
+                     waitp->thread->suppress_fatal_errors,
+                 "detected illegal recursion into Mutex code");
+  // This loop finds threads wake_list to wakeup if any, and removes them from
+  // the list of waiters.  In addition, it places waitp.thread on the queue of
+  // waiters if waitp is non-zero.
+  for (;;) {
+    v = mu_.load(std::memory_order_relaxed);
+    if ((v & kMuWriter) != 0 && (v & (kMuWait | kMuDesig)) != kMuWait &&
+        waitp == nullptr) {
+      // fast writer release (writer with no waiters or with designated waker)
+      if (mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+                                      std::memory_order_release,
+                                      std::memory_order_relaxed)) {
+        return;
+      }
+    } else if ((v & (kMuReader | kMuWait)) == kMuReader && waitp == nullptr) {
+      // fast reader release (reader with no waiters)
+      intptr_t clear = ExactlyOneReader(v) ? kMuReader | kMuOne : kMuOne;
+      if (mu_.compare_exchange_strong(v, v - clear,
+                                      std::memory_order_release,
+                                      std::memory_order_relaxed)) {
+        return;
+      }
+    } else if ((v & kMuSpin) == 0 &&  // attempt to get spinlock
+               mu_.compare_exchange_strong(v, v | kMuSpin,
+                                           std::memory_order_acquire,
+                                           std::memory_order_relaxed)) {
+      if ((v & kMuWait) == 0) {       // no one to wake
+        intptr_t nv;
+        bool do_enqueue = true;  // always Enqueue() the first time
+        ABSL_RAW_CHECK(waitp != nullptr,
+                       "UnlockSlow is confused");  // about to sleep
+        do {    // must loop to release spinlock as reader count may change
+          v = mu_.load(std::memory_order_relaxed);
+          // decrement reader count if there are readers
+          intptr_t new_readers = (v >= kMuOne)?  v - kMuOne : v;
+          PerThreadSynch *new_h = nullptr;
+          if (do_enqueue) {
+            // If we are enqueuing on a CondVar (waitp->cv_word != nullptr) then
+            // we must not retry here.  The initial attempt will always have
+            // succeeded, further attempts would enqueue us against *this due to
+            // Fer() handling.
+            do_enqueue = (waitp->cv_word == nullptr);
+            new_h = Enqueue(nullptr, waitp, new_readers, kMuIsCond);
+          }
+          intptr_t clear = kMuWrWait | kMuWriter;  // by default clear write bit
+          if ((v & kMuWriter) == 0 && ExactlyOneReader(v)) {  // last reader
+            clear = kMuWrWait | kMuReader;                    // clear read bit
+          }
+          nv = (v & kMuLow & ~clear & ~kMuSpin);
+          if (new_h != nullptr) {
+            nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+          } else {  // new_h could be nullptr if we queued ourselves on a
+                    // CondVar
+            // In that case, we must place the reader count back in the mutex
+            // word, as Enqueue() did not store it in the new waiter.
+            nv |= new_readers & kMuHigh;
+          }
+          // release spinlock & our lock; retry if reader-count changed
+          // (writer count cannot change since we hold lock)
+        } while (!mu_.compare_exchange_weak(v, nv,
+                                            std::memory_order_release,
+                                            std::memory_order_relaxed));
+        break;
+      }
+
+      // There are waiters.
+      // Set h to the head of the circular waiter list.
+      PerThreadSynch *h = GetPerThreadSynch(v);
+      if ((v & kMuReader) != 0 && (h->readers & kMuHigh) > kMuOne) {
+        // a reader but not the last
+        h->readers -= kMuOne;  // release our lock
+        intptr_t nv = v;       // normally just release spinlock
+        if (waitp != nullptr) {  // but waitp!=nullptr => must queue ourselves
+          PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond);
+          ABSL_RAW_CHECK(new_h != nullptr,
+                         "waiters disappeared during Enqueue()!");
+          nv &= kMuLow;
+          nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+        }
+        mu_.store(nv, std::memory_order_release);  // release spinlock
+        // can release with a store because there were waiters
+        break;
+      }
+
+      // Either we didn't search before, or we marked the queue
+      // as "maybe_unlocking" and no one else should have changed it.
+      ABSL_RAW_CHECK(old_h == nullptr || h->maybe_unlocking,
+                     "Mutex queue changed beneath us");
+
+      // The lock is becoming free, and there's a waiter
+      if (old_h != nullptr &&
+          !old_h->may_skip) {                  // we used old_h as a terminator
+        old_h->may_skip = true;                // allow old_h to skip once more
+        ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head");
+        if (h != old_h && MuSameCondition(old_h, old_h->next)) {
+          old_h->skip = old_h->next;  // old_h not head & can skip to successor
+        }
+      }
+      if (h->next->waitp->how == kExclusive &&
+          Condition::GuaranteedEqual(h->next->waitp->cond, nullptr)) {
+        // easy case: writer with no condition; no need to search
+        pw = h;                       // wake w, the successor of h (=pw)
+        w = h->next;
+        w->wake = true;
+        // We are waking up a writer.  This writer may be racing against
+        // an already awake reader for the lock.  We want the
+        // writer to usually win this race,
+        // because if it doesn't, we can potentially keep taking a reader
+        // perpetually and writers will starve.  Worse than
+        // that, this can also starve other readers if kMuWrWait gets set
+        // later.
+        wr_wait = kMuWrWait;
+      } else if (w != nullptr && (w->waitp->how == kExclusive || h == old_h)) {
+        // we found a waiter w to wake on a previous iteration and either it's
+        // a writer, or we've searched the entire list so we have all the
+        // readers.
+        if (pw == nullptr) {  // if w's predecessor is unknown, it must be h
+          pw = h;
+        }
+      } else {
+        // At this point we don't know all the waiters to wake, and the first
+        // waiter has a condition or is a reader.  We avoid searching over
+        // waiters we've searched on previous iterations by starting at
+        // old_h if it's set.  If old_h==h, there's no one to wakeup at all.
+        if (old_h == h) {      // we've searched before, and nothing's new
+                               // so there's no one to wake.
+          intptr_t nv = (v & ~(kMuReader|kMuWriter|kMuWrWait));
+          h->readers = 0;
+          h->maybe_unlocking = false;   // finished unlocking
+          if (waitp != nullptr) {       // we must queue ourselves and sleep
+            PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond);
+            nv &= kMuLow;
+            if (new_h != nullptr) {
+              nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+            }  // else new_h could be nullptr if we queued ourselves on a
+               // CondVar
+          }
+          // release spinlock & lock
+          // can release with a store because there were waiters
+          mu_.store(nv, std::memory_order_release);
+          break;
+        }
+
+        // set up to walk the list
+        PerThreadSynch *w_walk;   // current waiter during list walk
+        PerThreadSynch *pw_walk;  // previous waiter during list walk
+        if (old_h != nullptr) {  // we've searched up to old_h before
+          pw_walk = old_h;
+          w_walk = old_h->next;
+        } else {            // no prior search, start at beginning
+          pw_walk =
+              nullptr;  // h->next's predecessor may change; don't record it
+          w_walk = h->next;
+        }
+
+        h->may_skip = false;  // ensure we never skip past h in future searches
+                              // even if other waiters are queued after it.
+        ABSL_RAW_CHECK(h->skip == nullptr, "illegal skip from head");
+
+        h->maybe_unlocking = true;  // we're about to scan the waiter list
+                                    // without the spinlock held.
+                                    // Enqueue must be conservative about
+                                    // priority queuing.
+
+        // We must release the spinlock to evaluate the conditions.
+        mu_.store(v, std::memory_order_release);  // release just spinlock
+        // can release with a store because there were waiters
+
+        // h is the last waiter queued, and w_walk the first unsearched waiter.
+        // Without the spinlock, the locations mu_ and h->next may now change
+        // underneath us, but since we hold the lock itself, the only legal
+        // change is to add waiters between h and w_walk.  Therefore, it's safe
+        // to walk the path from w_walk to h inclusive. (TryRemove() can remove
+        // a waiter anywhere, but it acquires both the spinlock and the Mutex)
+
+        old_h = h;        // remember we searched to here
+
+        // Walk the path upto and including h looking for waiters we can wake.
+        while (pw_walk != h) {
+          w_walk->wake = false;
+          if (w_walk->waitp->cond ==
+                  nullptr ||  // no condition => vacuously true OR
+              (w_walk->waitp->cond != known_false &&
+               // this thread's condition is not known false, AND
+               //  is in fact true
+               EvalConditionIgnored(this, w_walk->waitp->cond))) {
+            if (w == nullptr) {
+              w_walk->wake = true;    // can wake this waiter
+              w = w_walk;
+              pw = pw_walk;
+              if (w_walk->waitp->how == kExclusive) {
+                wr_wait = kMuWrWait;
+                break;                // bail if waking this writer
+              }
+            } else if (w_walk->waitp->how == kShared) {  // wake if a reader
+              w_walk->wake = true;
+            } else {   // writer with true condition
+              wr_wait = kMuWrWait;
+            }
+          } else {                  // can't wake; condition false
+            known_false = w_walk->waitp->cond;  // remember last false condition
+          }
+          if (w_walk->wake) {   // we're waking reader w_walk
+            pw_walk = w_walk;   // don't skip similar waiters
+          } else {              // not waking; skip as much as possible
+            pw_walk = Skip(w_walk);
+          }
+          // If pw_walk == h, then load of pw_walk->next can race with
+          // concurrent write in Enqueue(). However, at the same time
+          // we do not need to do the load, because we will bail out
+          // from the loop anyway.
+          if (pw_walk != h) {
+            w_walk = pw_walk->next;
+          }
+        }
+
+        continue;  // restart for(;;)-loop to wakeup w or to find more waiters
+      }
+      ABSL_RAW_CHECK(pw->next == w, "pw not w's predecessor");
+      // The first (and perhaps only) waiter we've chosen to wake is w, whose
+      // predecessor is pw.  If w is a reader, we must wake all the other
+      // waiters with wake==true as well.  We may also need to queue
+      // ourselves if waitp != null.  The spinlock and the lock are still
+      // held.
+
+      // This traverses the list in [ pw->next, h ], where h is the head,
+      // removing all elements with wake==true and placing them in the
+      // singly-linked list wake_list.  Returns the new head.
+      h = DequeueAllWakeable(h, pw, &wake_list);
+
+      intptr_t nv = (v & kMuEvent) | kMuDesig;
+                                             // assume no waiters left,
+                                             // set kMuDesig for INV1a
+
+      if (waitp != nullptr) {  // we must queue ourselves and sleep
+        h = Enqueue(h, waitp, v, kMuIsCond);
+        // h is new last waiter; could be null if we queued ourselves on a
+        // CondVar
+      }
+
+      ABSL_RAW_CHECK(wake_list != kPerThreadSynchNull,
+                     "unexpected empty wake list");
+
+      if (h != nullptr) {  // there are waiters left
+        h->readers = 0;
+        h->maybe_unlocking = false;     // finished unlocking
+        nv |= wr_wait | kMuWait | reinterpret_cast<intptr_t>(h);
+      }
+
+      // release both spinlock & lock
+      // can release with a store because there were waiters
+      mu_.store(nv, std::memory_order_release);
+      break;  // out of for(;;)-loop
+    }
+    c = Delay(c, AGGRESSIVE);  // aggressive here; no one can proceed till we do
+  }                            // end of for(;;)-loop
+
+  if (wake_list != kPerThreadSynchNull) {
+    int64_t enqueue_timestamp = wake_list->waitp->contention_start_cycles;
+    bool cond_waiter = wake_list->cond_waiter;
+    do {
+      wake_list = Wakeup(wake_list);              // wake waiters
+    } while (wake_list != kPerThreadSynchNull);
+    if (!cond_waiter) {
+      // Sample lock contention events only if the (first) waiter was trying to
+      // acquire the lock, not waiting on a condition variable or Condition.
+      int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp;
+      mutex_tracer("slow release", this, wait_cycles);
+      ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+      submit_profile_data(enqueue_timestamp);
+      ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+    }
+  }
+}
+
+// Used by CondVar implementation to reacquire mutex after waking from
+// condition variable.  This routine is used instead of Lock() because the
+// waiting thread may have been moved from the condition variable queue to the
+// mutex queue without a wakeup, by Trans().  In that case, when the thread is
+// finally woken, the woken thread will believe it has been woken from the
+// condition variable (i.e. its PC will be in when in the CondVar code), when
+// in fact it has just been woken from the mutex.  Thus, it must enter the slow
+// path of the mutex in the same state as if it had just woken from the mutex.
+// That is, it must ensure to clear kMuDesig (INV1b).
+void Mutex::Trans(MuHow how) {
+  this->LockSlow(how, nullptr, kMuHasBlocked | kMuIsCond);
+}
+
+// Used by CondVar implementation to effectively wake thread w from the
+// condition variable.  If this mutex is free, we simply wake the thread.
+// It will later acquire the mutex with high probability.  Otherwise, we
+// enqueue thread w on this mutex.
+void Mutex::Fer(PerThreadSynch *w) {
+  int c = 0;
+  ABSL_RAW_CHECK(w->waitp->cond == nullptr,
+                 "Mutex::Fer while waiting on Condition");
+  ABSL_RAW_CHECK(!w->waitp->timeout.has_timeout(),
+                 "Mutex::Fer while in timed wait");
+  ABSL_RAW_CHECK(w->waitp->cv_word == nullptr,
+                 "Mutex::Fer with pending CondVar queueing");
+  for (;;) {
+    intptr_t v = mu_.load(std::memory_order_relaxed);
+    // Note: must not queue if the mutex is unlocked (nobody will wake it).
+    // For example, we can have only kMuWait (conditional) or maybe
+    // kMuWait|kMuWrWait.
+    // conflicting != 0 implies that the waking thread cannot currently take
+    // the mutex, which in turn implies that someone else has it and can wake
+    // us if we queue.
+    const intptr_t conflicting =
+        kMuWriter | (w->waitp->how == kShared ? 0 : kMuReader);
+    if ((v & conflicting) == 0) {
+      w->next = nullptr;
+      w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+      IncrementSynchSem(this, w);
+      return;
+    } else {
+      if ((v & (kMuSpin|kMuWait)) == 0) {       // no waiters
+        // This thread tries to become the one and only waiter.
+        PerThreadSynch *new_h = Enqueue(nullptr, w->waitp, v, kMuIsCond);
+        ABSL_RAW_CHECK(new_h != nullptr,
+                       "Enqueue failed");  // we must queue ourselves
+        if (mu_.compare_exchange_strong(
+                v, reinterpret_cast<intptr_t>(new_h) | (v & kMuLow) | kMuWait,
+                std::memory_order_release, std::memory_order_relaxed)) {
+          return;
+        }
+      } else if ((v & kMuSpin) == 0 &&
+                 mu_.compare_exchange_strong(v, v | kMuSpin | kMuWait)) {
+        PerThreadSynch *h = GetPerThreadSynch(v);
+        PerThreadSynch *new_h = Enqueue(h, w->waitp, v, kMuIsCond);
+        ABSL_RAW_CHECK(new_h != nullptr,
+                       "Enqueue failed");  // we must queue ourselves
+        do {
+          v = mu_.load(std::memory_order_relaxed);
+        } while (!mu_.compare_exchange_weak(
+            v,
+            (v & kMuLow & ~kMuSpin) | kMuWait |
+                reinterpret_cast<intptr_t>(new_h),
+            std::memory_order_release, std::memory_order_relaxed));
+        return;
+      }
+    }
+    c = Delay(c, GENTLE);
+  }
+}
+
+void Mutex::AssertHeld() const {
+  if ((mu_.load(std::memory_order_relaxed) & kMuWriter) == 0) {
+    SynchEvent *e = GetSynchEvent(this);
+    ABSL_RAW_LOG(FATAL, "thread should hold write lock on Mutex %p %s",
+                 static_cast<const void *>(this),
+                 (e == nullptr ? "" : e->name));
+  }
+}
+
+void Mutex::AssertReaderHeld() const {
+  if ((mu_.load(std::memory_order_relaxed) & (kMuReader | kMuWriter)) == 0) {
+    SynchEvent *e = GetSynchEvent(this);
+    ABSL_RAW_LOG(
+        FATAL, "thread should hold at least a read lock on Mutex %p %s",
+        static_cast<const void *>(this), (e == nullptr ? "" : e->name));
+  }
+}
+
+// -------------------------------- condition variables
+static const intptr_t kCvSpin = 0x0001L;   // spinlock protects waiter list
+static const intptr_t kCvEvent = 0x0002L;  // record events
+
+static const intptr_t kCvLow = 0x0003L;  // low order bits of CV
+
+// Hack to make constant values available to gdb pretty printer
+enum { kGdbCvSpin = kCvSpin, kGdbCvEvent = kCvEvent, kGdbCvLow = kCvLow, };
+
+static_assert(PerThreadSynch::kAlignment > kCvLow,
+              "PerThreadSynch::kAlignment must be greater than kCvLow");
+
+void CondVar::EnableDebugLog(const char *name) {
+  SynchEvent *e = EnsureSynchEvent(&this->cv_, name, kCvEvent, kCvSpin);
+  e->log = true;
+  UnrefSynchEvent(e);
+}
+
+CondVar::~CondVar() {
+  if ((cv_.load(std::memory_order_relaxed) & kCvEvent) != 0) {
+    ForgetSynchEvent(&this->cv_, kCvEvent, kCvSpin);
+  }
+}
+
+
+// Remove thread s from the list of waiters on this condition variable.
+void CondVar::Remove(PerThreadSynch *s) {
+  intptr_t v;
+  int c = 0;
+  for (v = cv_.load(std::memory_order_relaxed);;
+       v = cv_.load(std::memory_order_relaxed)) {
+    if ((v & kCvSpin) == 0 &&  // attempt to acquire spinlock
+        cv_.compare_exchange_strong(v, v | kCvSpin,
+                                    std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+      if (h != nullptr) {
+        PerThreadSynch *w = h;
+        while (w->next != s && w->next != h) {  // search for thread
+          w = w->next;
+        }
+        if (w->next == s) {           // found thread; remove it
+          w->next = s->next;
+          if (h == s) {
+            h = (w == s) ? nullptr : w;
+          }
+          s->next = nullptr;
+          s->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+        }
+      }
+                                      // release spinlock
+      cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h),
+                std::memory_order_release);
+      return;
+    } else {
+      c = Delay(c, GENTLE);            // try again after a delay
+    }
+  }
+}
+
+// Queue thread waitp->thread on condition variable word cv_word using
+// wait parameters waitp.
+// We split this into a separate routine, rather than simply doing it as part
+// of WaitCommon().  If we were to queue ourselves on the condition variable
+// before calling Mutex::UnlockSlow(), the Mutex code might be re-entered (via
+// the logging code, or via a Condition function) and might potentially attempt
+// to block this thread.  That would be a problem if the thread were already on
+// a the condition variable waiter queue.  Thus, we use the waitp->cv_word
+// to tell the unlock code to call CondVarEnqueue() to queue the thread on the
+// condition variable queue just before the mutex is to be unlocked, and (most
+// importantly) after any call to an external routine that might re-enter the
+// mutex code.
+static void CondVarEnqueue(SynchWaitParams *waitp) {
+  // This thread might be transferred to the Mutex queue by Fer() when
+  // we are woken.  To make sure that is what happens, Enqueue() doesn't
+  // call CondVarEnqueue() again but instead uses its normal code.  We
+  // must do this before we queue ourselves so that cv_word will be null
+  // when seen by the dequeuer, who may wish immediately to requeue
+  // this thread on another queue.
+  std::atomic<intptr_t> *cv_word = waitp->cv_word;
+  waitp->cv_word = nullptr;
+
+  intptr_t v = cv_word->load(std::memory_order_relaxed);
+  int c = 0;
+  while ((v & kCvSpin) != 0 ||  // acquire spinlock
+         !cv_word->compare_exchange_weak(v, v | kCvSpin,
+                                         std::memory_order_acquire,
+                                         std::memory_order_relaxed)) {
+    c = Delay(c, GENTLE);
+    v = cv_word->load(std::memory_order_relaxed);
+  }
+  ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be");
+  waitp->thread->waitp = waitp;      // prepare ourselves for waiting
+  PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+  if (h == nullptr) {  // add this thread to waiter list
+    waitp->thread->next = waitp->thread;
+  } else {
+    waitp->thread->next = h->next;
+    h->next = waitp->thread;
+  }
+  waitp->thread->state.store(PerThreadSynch::kQueued,
+                             std::memory_order_relaxed);
+  cv_word->store((v & kCvEvent) | reinterpret_cast<intptr_t>(waitp->thread),
+                 std::memory_order_release);
+}
+
+bool CondVar::WaitCommon(Mutex *mutex, KernelTimeout t) {
+  bool rc = false;          // return value; true iff we timed-out
+
+  intptr_t mutex_v = mutex->mu_.load(std::memory_order_relaxed);
+  Mutex::MuHow mutex_how = ((mutex_v & kMuWriter) != 0) ? kExclusive : kShared;
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(mutex, TsanFlags(mutex_how));
+
+  // maybe trace this call
+  intptr_t v = cv_.load(std::memory_order_relaxed);
+  cond_var_tracer("Wait", this);
+  if ((v & kCvEvent) != 0) {
+    PostSynchEvent(this, SYNCH_EV_WAIT);
+  }
+
+  // Release mu and wait on condition variable.
+  SynchWaitParams waitp(mutex_how, nullptr, t, mutex,
+                        Synch_GetPerThreadAnnotated(mutex), &cv_);
+  // UnlockSlow() will call CondVarEnqueue() just before releasing the
+  // Mutex, thus queuing this thread on the condition variable.  See
+  // CondVarEnqueue() for the reasons.
+  mutex->UnlockSlow(&waitp);
+
+  // wait for signal
+  while (waitp.thread->state.load(std::memory_order_acquire) ==
+         PerThreadSynch::kQueued) {
+    if (!Mutex::DecrementSynchSem(mutex, waitp.thread, t)) {
+      this->Remove(waitp.thread);
+      rc = true;
+    }
+  }
+
+  ABSL_RAW_CHECK(waitp.thread->waitp != nullptr, "not waiting when should be");
+  waitp.thread->waitp = nullptr;  // cleanup
+
+  // maybe trace this call
+  cond_var_tracer("Unwait", this);
+  if ((v & kCvEvent) != 0) {
+    PostSynchEvent(this, SYNCH_EV_WAIT_RETURNING);
+  }
+
+  // From synchronization point of view Wait is unlock of the mutex followed
+  // by lock of the mutex. We've annotated start of unlock in the beginning
+  // of the function. Now, finish unlock and annotate lock of the mutex.
+  // (Trans is effectively lock).
+  ABSL_TSAN_MUTEX_POST_UNLOCK(mutex, TsanFlags(mutex_how));
+  ABSL_TSAN_MUTEX_PRE_LOCK(mutex, TsanFlags(mutex_how));
+  mutex->Trans(mutex_how);  // Reacquire mutex
+  ABSL_TSAN_MUTEX_POST_LOCK(mutex, TsanFlags(mutex_how), 0);
+  return rc;
+}
+
+bool CondVar::WaitWithTimeout(Mutex *mu, absl::Duration timeout) {
+  return WaitWithDeadline(mu, DeadlineFromTimeout(timeout));
+}
+
+bool CondVar::WaitWithDeadline(Mutex *mu, absl::Time deadline) {
+  return WaitCommon(mu, KernelTimeout(deadline));
+}
+
+void CondVar::Wait(Mutex *mu) {
+  WaitCommon(mu, KernelTimeout::Never());
+}
+
+// Wake thread w
+// If it was a timed wait, w will be waiting on w->cv
+// Otherwise, if it was not a Mutex mutex, w will be waiting on w->sem
+// Otherwise, w is transferred to the Mutex mutex via Mutex::Fer().
+void CondVar::Wakeup(PerThreadSynch *w) {
+  if (w->waitp->timeout.has_timeout() || w->waitp->cvmu == nullptr) {
+    // The waiting thread only needs to observe "w->state == kAvailable" to be
+    // released, we must cache "cvmu" before clearing "next".
+    Mutex *mu = w->waitp->cvmu;
+    w->next = nullptr;
+    w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+    Mutex::IncrementSynchSem(mu, w);
+  } else {
+    w->waitp->cvmu->Fer(w);
+  }
+}
+
+void CondVar::Signal() {
+  ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0);
+  intptr_t v;
+  int c = 0;
+  for (v = cv_.load(std::memory_order_relaxed); v != 0;
+       v = cv_.load(std::memory_order_relaxed)) {
+    if ((v & kCvSpin) == 0 &&  // attempt to acquire spinlock
+        cv_.compare_exchange_strong(v, v | kCvSpin,
+                                    std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+      PerThreadSynch *w = nullptr;
+      if (h != nullptr) {  // remove first waiter
+        w = h->next;
+        if (w == h) {
+          h = nullptr;
+        } else {
+          h->next = w->next;
+        }
+      }
+                                      // release spinlock
+      cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h),
+                std::memory_order_release);
+      if (w != nullptr) {
+        CondVar::Wakeup(w);                // wake waiter, if there was one
+        cond_var_tracer("Signal wakeup", this);
+      }
+      if ((v & kCvEvent) != 0) {
+        PostSynchEvent(this, SYNCH_EV_SIGNAL);
+      }
+      ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+      return;
+    } else {
+      c = Delay(c, GENTLE);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+}
+
+void CondVar::SignalAll () {
+  ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0);
+  intptr_t v;
+  int c = 0;
+  for (v = cv_.load(std::memory_order_relaxed); v != 0;
+       v = cv_.load(std::memory_order_relaxed)) {
+    // empty the list if spinlock free
+    // We do this by simply setting the list to empty using
+    // compare and swap.   We then have the entire list in our hands,
+    // which cannot be changing since we grabbed it while no one
+    // held the lock.
+    if ((v & kCvSpin) == 0 &&
+        cv_.compare_exchange_strong(v, v & kCvEvent, std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+      if (h != nullptr) {
+        PerThreadSynch *w;
+        PerThreadSynch *n = h->next;
+        do {                          // for every thread, wake it up
+          w = n;
+          n = n->next;
+          CondVar::Wakeup(w);
+        } while (w != h);
+        cond_var_tracer("SignalAll wakeup", this);
+      }
+      if ((v & kCvEvent) != 0) {
+        PostSynchEvent(this, SYNCH_EV_SIGNALALL);
+      }
+      ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+      return;
+    } else {
+      c = Delay(c, GENTLE);           // try again after a delay
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+}
+
+void ReleasableMutexLock::Release() {
+  ABSL_RAW_CHECK(this->mu_ != nullptr,
+                 "ReleasableMutexLock::Release may only be called once");
+  this->mu_->Unlock();
+  this->mu_ = nullptr;
+}
+
+#ifdef THREAD_SANITIZER
+extern "C" void __tsan_read1(void *addr);
+#else
+#define __tsan_read1(addr)  // do nothing if TSan not enabled
+#endif
+
+// A function that just returns its argument, dereferenced
+static bool Dereference(void *arg) {
+  // ThreadSanitizer does not instrument this file for memory accesses.
+  // This function dereferences a user variable that can participate
+  // in a data race, so we need to manually tell TSan about this memory access.
+  __tsan_read1(arg);
+  return *(static_cast<bool *>(arg));
+}
+
+Condition::Condition() {}   // null constructor, used for kTrue only
+const Condition Condition::kTrue;
+
+Condition::Condition(bool (*func)(void *), void *arg)
+    : eval_(&CallVoidPtrFunction),
+      function_(func),
+      method_(nullptr),
+      arg_(arg) {}
+
+bool Condition::CallVoidPtrFunction(const Condition *c) {
+  return (*c->function_)(c->arg_);
+}
+
+Condition::Condition(const bool *cond)
+    : eval_(CallVoidPtrFunction),
+      function_(Dereference),
+      method_(nullptr),
+      // const_cast is safe since Dereference does not modify arg
+      arg_(const_cast<bool *>(cond)) {}
+
+bool Condition::Eval() const {
+  // eval_ == null for kTrue
+  return (this->eval_ == nullptr) || (*this->eval_)(this);
+}
+
+bool Condition::GuaranteedEqual(const Condition *a, const Condition *b) {
+  if (a == nullptr) {
+    return b == nullptr || b->eval_ == nullptr;
+  }
+  if (b == nullptr || b->eval_ == nullptr) {
+    return a->eval_ == nullptr;
+  }
+  return a->eval_ == b->eval_ && a->function_ == b->function_ &&
+         a->arg_ == b->arg_ && a->method_ == b->method_;
+}
+
+}  // namespace absl
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
new file mode 100644
index 0000000..840b9d6
--- /dev/null
+++ b/absl/synchronization/mutex.h
@@ -0,0 +1,1028 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// mutex.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Mutex` -- a mutually exclusive lock -- and the
+// most common type of synchronization primitive for facilitating locks on
+// shared resources. A mutex is used to prevent multiple threads from accessing
+// and/or writing to a shared resource concurrently.
+//
+// Unlike a `std::mutex`, the Abseil `Mutex` provides the following additional
+// features:
+//   * Conditional predicates intrinsic to the `Mutex` object
+//   * Reader/writer locks, in addition to standard exclusive/writer locks
+//   * Deadlock detection and debug support.
+//
+// The following helper classes are also defined within this file:
+//
+//  MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/
+//              write access within the current scope.
+//  ReaderMutexLock
+//            - An RAII wrapper to acquire and release a `Mutex` for shared/read
+//              access within the current scope.
+//
+//  WriterMutexLock
+//            - Alias for `MutexLock` above, designed for use in distinguishing
+//              reader and writer locks within code.
+//
+// In addition to simple mutex locks, this file also defines ways to perform
+// locking under certain conditions.
+//
+//  Condition   - (Preferred) Used to wait for a particular predicate that
+//                depends on state protected by the `Mutex` to become true.
+//  CondVar     - A lower-level variant of `Condition` that relies on
+//                application code to explicitly signal the `CondVar` when
+//                a condition has been met.
+//
+// See below for more information on using `Condition` or `CondVar`.
+//
+// Mutexes and mutex behavior can be quite complicated. The information within
+// this header file is limited, as a result. Please consult the Mutex guide for
+// more complete information and examples.
+
+#ifndef ABSL_SYNCHRONIZATION_MUTEX_H_
+#define ABSL_SYNCHRONIZATION_MUTEX_H_
+
+#include <atomic>
+#include <cstdint>
+#include <string>
+
+#include "absl/base/internal/identity.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/time/time.h"
+
+// Decide if we should use the non-production implementation because
+// the production implementation hasn't been fully ported yet.
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+#error ABSL_INTERNAL_USE_NONPROD_MUTEX cannot be directly set
+#elif defined(ABSL_LOW_LEVEL_ALLOC_MISSING)
+#define ABSL_INTERNAL_USE_NONPROD_MUTEX 1
+#include "absl/synchronization/internal/mutex_nonprod.inc"
+#endif
+
+namespace absl {
+
+class Condition;
+struct SynchWaitParams;
+
+// -----------------------------------------------------------------------------
+// Mutex
+// -----------------------------------------------------------------------------
+//
+// A `Mutex` is a non-reentrant (aka non-recursive) Mutually Exclusive lock
+// on some resource, typically a variable or data structure with associated
+// invariants. Proper usage of mutexes prevents concurrent access by different
+// threads to the same resource.
+//
+// A `Mutex` has two basic operations: `Mutex::Lock()` and `Mutex::Unlock()`.
+// The `Lock()` operation *acquires* a `Mutex` (in a state known as an
+// *exclusive* -- or write -- lock), while the `Unlock()` operation *releases* a
+// Mutex. During the span of time between the Lock() and Unlock() operations,
+// a mutex is said to be *held*. By design all mutexes support exclusive/write
+// locks, as this is the most common way to use a mutex.
+//
+// The `Mutex` state machine for basic lock/unlock operations is quite simple:
+//
+// |                | Lock()     | Unlock() |
+// |----------------+------------+----------|
+// | Free           | Exclusive  | invalid  |
+// | Exclusive      | blocks     | Free     |
+//
+// Attempts to `Unlock()` must originate from the thread that performed the
+// corresponding `Lock()` operation.
+//
+// An "invalid" operation is disallowed by the API. The `Mutex` implementation
+// is allowed to do anything on an invalid call, including but not limited to
+// crashing with a useful error message, silently succeeding, or corrupting
+// data structures. In debug mode, the implementation attempts to crash with a
+// useful error message.
+//
+// `Mutex` is not guaranteed to be "fair" in prioritizing waiting threads; it
+// is, however, approximately fair over long periods, and starvation-free for
+// threads at the same priority.
+//
+// The lock/unlock primitives are now annotated with lock annotations
+// defined in (base/thread_annotations.h). When writing multi-threaded code,
+// you should use lock annotations whenever possible to document your lock
+// synchronization policy. Besides acting as documentation, these annotations
+// also help compilers or static analysis tools to identify and warn about
+// issues that could potentially result in race conditions and deadlocks.
+//
+// For more information about the lock annotations, please see
+// [Thread Safety Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
+// in the Clang documentation.
+//
+// See also `MutexLock`, below, for scoped `Mutex` acquisition.
+
+class LOCKABLE Mutex {
+ public:
+  Mutex();
+  ~Mutex();
+
+  // Mutex::Lock()
+  //
+  // Blocks the calling thread, if necessary, until this `Mutex` is free, and
+  // then acquires it exclusively. (This lock is also known as a "write lock.")
+  void Lock() EXCLUSIVE_LOCK_FUNCTION();
+
+  // Mutex::Unlock()
+  //
+  // Releases this `Mutex` and returns it from the exclusive/write state to the
+  // free state. Caller must hold the `Mutex` exclusively.
+  void Unlock() UNLOCK_FUNCTION();
+
+  // Mutex::TryLock()
+  //
+  // If the mutex can be acquired without blocking, does so exclusively and
+  // returns `true`. Otherwise, returns `false`. Returns `true` with high
+  // probability if the `Mutex` was free.
+  bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
+
+  // Mutex::AssertHeld()
+  //
+  // Return immediately if this thread holds the `Mutex` exclusively (in write
+  // mode). Otherwise, may report an error (typically by crashing with a
+  // diagnostic), or may return immediately.
+  void AssertHeld() const ASSERT_EXCLUSIVE_LOCK();
+
+  // ---------------------------------------------------------------------------
+  // Reader-Writer Locking
+  // ---------------------------------------------------------------------------
+
+  // A Mutex can also be used as a starvation-free reader-writer lock.
+  // Neither read-locks nor write-locks are reentrant/recursive to avoid
+  // potential client programming errors.
+  //
+  // The Mutex API provides `Writer*()` aliases for the existing `Lock()`,
+  // `Unlock()` and `TryLock()` methods for use within applications mixing
+  // reader/writer locks. Using `Reader*()` and `Writer*()` operations in this
+  // manner can make locking behavior clearer when mixing read and write modes.
+  //
+  // Introducing reader locks necessarily complicates the `Mutex` state
+  // machine somewhat. The table below illustrates the allowed state transitions
+  // of a mutex in such cases. Note that ReaderLock() may block even if the lock
+  // is held in shared mode; this occurs when another thread is blocked on a
+  // call to WriterLock().
+  //
+  // ---------------------------------------------------------------------------
+  //     Operation: WriterLock() Unlock()  ReaderLock()           ReaderUnlock()
+  // ---------------------------------------------------------------------------
+  // State
+  // ---------------------------------------------------------------------------
+  // Free           Exclusive    invalid   Shared(1)              invalid
+  // Shared(1)      blocks       invalid   Shared(2) or blocks    Free
+  // Shared(n) n>1  blocks       invalid   Shared(n+1) or blocks  Shared(n-1)
+  // Exclusive      blocks       Free      blocks                 invalid
+  // ---------------------------------------------------------------------------
+  //
+  // In comments below, "shared" refers to a state of Shared(n) for any n > 0.
+
+  // Mutex::ReaderLock()
+  //
+  // Blocks the calling thread, if necessary, until this `Mutex` is either free,
+  // or in shared mode, and then acquires a share of it. Note that
+  // `ReaderLock()` will block if some other thread has an exclusive/writer lock
+  // on the mutex.
+
+  void ReaderLock() SHARED_LOCK_FUNCTION();
+
+  // Mutex::ReaderUnlock()
+  //
+  // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to
+  // the free state if this thread holds the last reader lock on the mutex. Note
+  // that you cannot call `ReaderUnlock()` on a mutex held in write mode.
+  void ReaderUnlock() UNLOCK_FUNCTION();
+
+  // Mutex::ReaderTryLock()
+  //
+  // If the mutex can be acquired without blocking, acquires this mutex for
+  // shared access and returns `true`. Otherwise, returns `false`. Returns
+  // `true` with high probability if the `Mutex` was free or shared.
+  bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
+
+  // Mutex::AssertReaderHeld()
+  //
+  // Returns immediately if this thread holds the `Mutex` in at least shared
+  // mode (read mode). Otherwise, may report an error (typically by
+  // crashing with a diagnostic), or may return immediately.
+  void AssertReaderHeld() const ASSERT_SHARED_LOCK();
+
+  // Mutex::WriterLock()
+  // Mutex::WriterUnlock()
+  // Mutex::WriterTryLock()
+  //
+  // Aliases for `Mutex::Lock()`, `Mutex::Unlock()`, and `Mutex::TryLock()`.
+  //
+  // These methods may be used (along with the complementary `Reader*()`
+  // methods) to distingish simple exclusive `Mutex` usage (`Lock()`,
+  // etc.) from reader/writer lock usage.
+  void WriterLock() EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
+
+  void WriterUnlock() UNLOCK_FUNCTION() { this->Unlock(); }
+
+  bool WriterTryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    return this->TryLock();
+  }
+
+  // ---------------------------------------------------------------------------
+  // Conditional Critical Regions
+  // ---------------------------------------------------------------------------
+
+  // Conditional usage of a `Mutex` can occur using two distinct paradigms:
+  //
+  //   * Use of `Mutex` member functions with `Condition` objects.
+  //   * Use of the separate `CondVar` abstraction.
+  //
+  // In general, prefer use of `Condition` and the `Mutex` member functions
+  // listed below over `CondVar`. When there are multiple threads waiting on
+  // distinctly different conditions, however, a battery of `CondVar`s may be
+  // more efficient. This section discusses use of `Condition` objects.
+  //
+  // `Mutex` contains member functions for performing lock operations only under
+  // certain conditions, of class `Condition`. For correctness, the `Condition`
+  // must return a boolean that is a pure function, only of state protected by
+  // the `Mutex`. The condition must be invariant w.r.t. environmental state
+  // such as thread, cpu id, or time, and must be `noexcept`. The condition will
+  // always be invoked with the mutex held in at least read mode, so you should
+  // not block it for long periods or sleep it on a timer.
+  //
+  // Since a condition must not depend directly on the current time, use
+  // `*WithTimeout()` member function variants to make your condition
+  // effectively true after a given duration, or `*WithDeadline()` variants to
+  // make your condition effectively true after a given time.
+  //
+  // The condition function should have no side-effects aside from debug
+  // logging; as a special exception, the function may acquire other mutexes
+  // provided it releases all those that it acquires.  (This exception was
+  // required to allow logging.)
+
+  // Mutex::Await()
+  //
+  // Unlocks this `Mutex` and blocks until simultaneously both `cond` is `true`
+  // and this `Mutex` can be reacquired, then reacquires this `Mutex` in the
+  // same mode in which it was previously held. If the condition is initially
+  // `true`, `Await()` *may* skip the release/re-acquire step.
+  //
+  // `Await()` requires that this thread holds this `Mutex` in some mode.
+  void Await(const Condition &cond);
+
+  // Mutex::LockWhen()
+  // Mutex::ReaderLockWhen()
+  // Mutex::WriterLockWhen()
+  //
+  // Blocks until simultaneously both `cond` is `true` and this` Mutex` can
+  // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is
+  // logically equivalent to `*Lock(); Await();` though they may have different
+  // performance characteristics.
+  void LockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION();
+
+  void ReaderLockWhen(const Condition &cond) SHARED_LOCK_FUNCTION();
+
+  void WriterLockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION() {
+    this->LockWhen(cond);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Mutex Variants with Timeouts/Deadlines
+  // ---------------------------------------------------------------------------
+
+  // Mutex::AwaitWithTimeout()
+  // Mutex::AwaitWithDeadline()
+  //
+  // If `cond` is initially true, do nothing, or act as though `cond` is
+  // initially false.
+  //
+  // If `cond` is initially false, unlock this `Mutex` and block until
+  // simultaneously:
+  //   - either `cond` is true or the {timeout has expired, deadline has passed}
+  //     and
+  //   - this `Mutex` can be reacquired,
+  // then reacquire this `Mutex` in the same mode in which it was previously
+  // held, returning `true` iff `cond` is `true` on return.
+  //
+  // Deadlines in the past are equivalent to an immediate deadline.
+  // Negative timeouts are equivalent to a zero timeout.
+  //
+  // This method requires that this thread holds this `Mutex` in some mode.
+  bool AwaitWithTimeout(const Condition &cond, absl::Duration timeout);
+
+  bool AwaitWithDeadline(const Condition &cond, absl::Time deadline);
+
+  // Mutex::LockWhenWithTimeout()
+  // Mutex::ReaderLockWhenWithTimeout()
+  // Mutex::WriterLockWhenWithTimeout()
+  //
+  // Blocks until simultaneously both:
+  //   - either `cond` is `true` or the timeout has expired, and
+  //   - this `Mutex` can be acquired,
+  // then atomically acquires this `Mutex`, returning `true` iff `cond` is
+  // `true` on return.
+  //
+  // Negative timeouts are equivalent to a zero timeout.
+  bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+      EXCLUSIVE_LOCK_FUNCTION();
+  bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+      SHARED_LOCK_FUNCTION();
+  bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+      EXCLUSIVE_LOCK_FUNCTION() {
+    return this->LockWhenWithTimeout(cond, timeout);
+  }
+
+  // Mutex::LockWhenWithDeadline()
+  // Mutex::ReaderLockWhenWithDeadline()
+  // Mutex::WriterLockWhenWithDeadline()
+  //
+  // Blocks until simultaneously both:
+  //   - either `cond` is `true` or the deadline has been passed, and
+  //   - this `Mutex` can be acquired,
+  // then atomically acquires this Mutex, returning `true` iff `cond` is `true`
+  // on return.
+  //
+  // Deadlines in the past are equivalent to an immediate deadline.
+  bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+      EXCLUSIVE_LOCK_FUNCTION();
+  bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+      SHARED_LOCK_FUNCTION();
+  bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+      EXCLUSIVE_LOCK_FUNCTION() {
+    return this->LockWhenWithDeadline(cond, deadline);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Debug Support: Invariant Checking, Deadlock Detection, Logging.
+  // ---------------------------------------------------------------------------
+
+  // Mutex::EnableInvariantDebugging()
+  //
+  // If `invariant`!=null and if invariant debugging has been enabled globally,
+  // cause `(*invariant)(arg)` to be called at moments when the invariant for
+  // this `Mutex` should hold (for example: just after acquire, just before
+  // release).
+  //
+  // The routine `invariant` should have no side-effects since it is not
+  // guaranteed how many times it will be called; it should check the invariant
+  // and crash if it does not hold. Enabling global invariant debugging may
+  // substantially reduce `Mutex` performance; it should be set only for
+  // non-production runs.  Optimization options may also disable invariant
+  // checks.
+  void EnableInvariantDebugging(void (*invariant)(void *), void *arg);
+
+  // Mutex::EnableDebugLog()
+  //
+  // Cause all subsequent uses of this `Mutex` to be logged via
+  // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if no previous
+  // call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made.
+  //
+  // Note: This method substantially reduces `Mutex` performance.
+  void EnableDebugLog(const char *name);
+
+  // Deadlock detection
+
+  // Mutex::ForgetDeadlockInfo()
+  //
+  // Forget any deadlock-detection information previously gathered
+  // about this `Mutex`. Call this method in debug mode when the lock ordering
+  // of a `Mutex` changes.
+  void ForgetDeadlockInfo();
+
+  // Mutex::AssertNotHeld()
+  //
+  // Return immediately if this thread does not hold this `Mutex` in any
+  // mode; otherwise, may report an error (typically by crashing with a
+  // diagnostic), or may return immediately.
+  //
+  // Currently this check is performed only if all of:
+  //    - in debug mode
+  //    - SetMutexDeadlockDetectionMode() has been set to kReport or kAbort
+  //    - number of locks concurrently held by this thread is not large.
+  // are true.
+  void AssertNotHeld() const;
+
+  // Special cases.
+
+  // A `MuHow` is a constant that indicates how a lock should be acquired.
+  // Internal implementation detail.  Clients should ignore.
+  typedef const struct MuHowS *MuHow;
+
+  // Mutex::InternalAttemptToUseMutexInFatalSignalHandler()
+  //
+  // Causes the `Mutex` implementation to prepare itself for re-entry caused by
+  // future use of `Mutex` within a fatal signal handler. This method is
+  // intended for use only for last-ditch attempts to log crash information.
+  // It does not guarantee that attempts to use Mutexes within the handler will
+  // not deadlock; it merely makes other faults less likely.
+  //
+  // WARNING:  This routine must be invoked from a signal handler, and the
+  // signal handler must either loop forever or terminate the process.
+  // Attempts to return from (or `longjmp` out of) the signal handler once this
+  // call has been made may cause arbitrary program behaviour including
+  // crashes and deadlocks.
+  static void InternalAttemptToUseMutexInFatalSignalHandler();
+
+ private:
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+  friend class CondVar;
+
+  synchronization_internal::MutexImpl *impl() { return impl_.get(); }
+
+  synchronization_internal::SynchronizationStorage<
+      synchronization_internal::MutexImpl>
+      impl_;
+#else
+  std::atomic<intptr_t> mu_;  // The Mutex state.
+
+  // Post()/Wait() versus associated PerThreadSem; in class for required
+  // friendship with PerThreadSem.
+  static inline void IncrementSynchSem(Mutex *mu,
+                                       base_internal::PerThreadSynch *w);
+  static inline bool DecrementSynchSem(
+      Mutex *mu, base_internal::PerThreadSynch *w,
+      synchronization_internal::KernelTimeout t);
+
+  // slow path acquire
+  void LockSlowLoop(SynchWaitParams *waitp, int flags);
+  // wrappers around LockSlowLoop()
+  bool LockSlowWithDeadline(MuHow how, const Condition *cond,
+                            synchronization_internal::KernelTimeout t,
+                            int flags);
+  void LockSlow(MuHow how, const Condition *cond,
+                int flags) ABSL_ATTRIBUTE_COLD;
+  // slow path release
+  void UnlockSlow(SynchWaitParams *waitp) ABSL_ATTRIBUTE_COLD;
+  // Common code between Await() and AwaitWithTimeout/Deadline()
+  bool AwaitCommon(const Condition &cond,
+                   synchronization_internal::KernelTimeout t);
+  // Attempt to remove thread s from queue.
+  void TryRemove(base_internal::PerThreadSynch *s);
+  // Block a thread on mutex.
+  void Block(base_internal::PerThreadSynch *s);
+  // Wake a thread; return successor.
+  base_internal::PerThreadSynch *Wakeup(base_internal::PerThreadSynch *w);
+
+  friend class CondVar;   // for access to Trans()/Fer().
+  void Trans(MuHow how);  // used for CondVar->Mutex transfer
+  void Fer(
+      base_internal::PerThreadSynch *w);  // used for CondVar->Mutex transfer
+#endif
+
+  // Catch the error of writing Mutex when intending MutexLock.
+  Mutex(const volatile Mutex * /*ignored*/) {}  // NOLINT(runtime/explicit)
+
+  Mutex(const Mutex&) = delete;
+  Mutex& operator=(const Mutex&) = delete;
+};
+
+// -----------------------------------------------------------------------------
+// Mutex RAII Wrappers
+// -----------------------------------------------------------------------------
+
+// MutexLock
+//
+// `MutexLock` is a helper class, which acquires and releases a `Mutex` via
+// RAII.
+//
+// Example:
+//
+// Class Foo {
+//
+//   Foo::Bar* Baz() {
+//     MutexLock l(&lock_);
+//     ...
+//     return bar;
+//   }
+//
+// private:
+//   Mutex lock_;
+// };
+class SCOPED_LOCKABLE MutexLock {
+ public:
+  explicit MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+    this->mu_->Lock();
+  }
+
+  MutexLock(const MutexLock &) = delete;  // NOLINT(runtime/mutex)
+  MutexLock(MutexLock&&) = delete;  // NOLINT(runtime/mutex)
+  MutexLock& operator=(const MutexLock&) = delete;
+  MutexLock& operator=(MutexLock&&) = delete;
+
+  ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }
+
+ private:
+  Mutex *const mu_;
+};
+
+// ReaderMutexLock
+//
+// The `ReaderMutexLock` is a helper class, like `MutexLock`, which acquires and
+// releases a shared lock on a `Mutex` via RAII.
+class SCOPED_LOCKABLE ReaderMutexLock {
+ public:
+  explicit ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu)
+      :  mu_(mu) {
+    mu->ReaderLock();
+  }
+
+  ReaderMutexLock(const ReaderMutexLock&) = delete;
+  ReaderMutexLock(ReaderMutexLock&&) = delete;
+  ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
+  ReaderMutexLock& operator=(ReaderMutexLock&&) = delete;
+
+  ~ReaderMutexLock() UNLOCK_FUNCTION() {
+    this->mu_->ReaderUnlock();
+  }
+
+ private:
+  Mutex *const mu_;
+};
+
+// WriterMutexLock
+//
+// The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and
+// releases a write (exclusive) lock on a `Mutex` va RAII.
+class SCOPED_LOCKABLE WriterMutexLock {
+ public:
+  explicit WriterMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->WriterLock();
+  }
+
+  WriterMutexLock(const WriterMutexLock&) = delete;
+  WriterMutexLock(WriterMutexLock&&) = delete;
+  WriterMutexLock& operator=(const WriterMutexLock&) = delete;
+  WriterMutexLock& operator=(WriterMutexLock&&) = delete;
+
+  ~WriterMutexLock() UNLOCK_FUNCTION() {
+    this->mu_->WriterUnlock();
+  }
+
+ private:
+  Mutex *const mu_;
+};
+
+// -----------------------------------------------------------------------------
+// Condition
+// -----------------------------------------------------------------------------
+//
+// As noted above, `Mutex` contains a number of member functions which take a
+// `Condition` as a argument; clients can wait for conditions to become `true`
+// before attempting to acquire the mutex. These sections are known as
+// "condition critical" sections. To use a `Condition`, you simply need to
+// construct it, and use within an appropriate `Mutex` member function;
+// everything else in the `Condition` class is an implementation detail.
+//
+// A `Condition` is specified as a function pointer which returns a boolean.
+// `Condition` functions should be pure functions -- their results should depend
+// only on passed arguments, should not consult any external state (such as
+// clocks), and should have no side-effects, aside from debug logging. Any
+// objects that the function may access should be limited to those which are
+// constant while the mutex is blocked on the condition (e.g. a stack variable),
+// or objects of state protected explicitly by the mutex.
+//
+// No matter which construction is used for `Condition`, the underlying
+// function pointer / functor / callable must not throw any
+// exceptions. Correctness of `Mutex` / `Condition` is not guaranteed in
+// the face of a throwing `Condition`. (When Abseil is allowed to depend
+// on C++17, these function pointers will be explicitly marked
+// `noexcept`; until then this requirement cannot be enforced in the
+// type system.)
+//
+// Note: to use a `Condition`, you need only construct it and pass it within the
+// appropriate `Mutex' member function, such as `Mutex::Await()`.
+//
+// Example:
+//
+//   // assume count_ is not internal reference count
+//   int count_ GUARDED_BY(mu_);
+//
+//   mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
+//         &count_));
+//
+// When multiple threads are waiting on exactly the same condition, make sure
+// that they are constructed with the same parameters (same pointer to function
+// + arg, or same pointer to object + method), so that the mutex implementation
+// can avoid redundantly evaluating the same condition for each thread.
+class Condition {
+ public:
+  // A Condition that returns the result of "(*func)(arg)"
+  Condition(bool (*func)(void *), void *arg);
+
+  // Templated version for people who are averse to casts.
+  //
+  // To use a lambda, prepend it with unary plus, which converts the lambda
+  // into a function pointer:
+  //     Condition(+[](T* t) { return ...; }, arg).
+  //
+  // Note: lambdas in this case must contain no bound variables.
+  //
+  // See class comment for performance advice.
+  template<typename T>
+  Condition(bool (*func)(T *), T *arg);
+
+  // Templated version for invoking a method that returns a `bool`.
+  //
+  // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates
+  // `object->Method()`.
+  //
+  // Implementation Note: `absl::internal::identity` is used to allow methods to
+  // come from base classes. A simpler signature like
+  // `Condition(T*, bool (T::*)())` does not suffice.
+  template<typename T>
+  Condition(T *object, bool (absl::internal::identity<T>::type::* method)());
+
+  // Same as above, for const members
+  template<typename T>
+  Condition(const T *object,
+            bool (absl::internal::identity<T>::type::* method)() const);
+
+  // A Condition that returns the value of `*cond`
+  explicit Condition(const bool *cond);
+
+  // Templated version for invoking a functor that returns a `bool`.
+  // This approach accepts pointers to non-mutable lambdas, `std::function`,
+  // the result of` std::bind` and user-defined functors that define
+  // `bool F::operator()() const`.
+  //
+  // Example:
+  //
+  //   auto reached = [this, current]() {
+  //     mu_.AssertReaderHeld();                // For annotalysis.
+  //     return processed_ >= current;
+  //   };
+  //   mu_.Await(Condition(&reached));
+
+  // See class comment for performance advice. In particular, if there
+  // might be more than one waiter for the same condition, make sure
+  // that all waiters construct the condition with the same pointers.
+
+  // Implementation note: The second template parameter ensures that this
+  // constructor doesn't participate in overload resolution if T doesn't have
+  // `bool operator() const`.
+  template <typename T, typename E = decltype(
+      static_cast<bool (T::*)() const>(&T::operator()))>
+  explicit Condition(const T *obj)
+      : Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
+
+  // A Condition that always returns `true`.
+  static const Condition kTrue;
+
+  // Evaluates the condition.
+  bool Eval() const;
+
+  // Returns `true` if the two conditions are guaranteed to return the same
+  // value if evaluated at the same time, `false` if the evaluation *may* return
+  // different results.
+  //
+  // Two `Condition` values are guaranteed equal if both their `func` and `arg`
+  // components are the same. A null pointer is equivalent to a `true`
+  // condition.
+  static bool GuaranteedEqual(const Condition *a, const Condition *b);
+
+ private:
+  typedef bool (*InternalFunctionType)(void * arg);
+  typedef bool (Condition::*InternalMethodType)();
+  typedef bool (*InternalMethodCallerType)(void * arg,
+                                           InternalMethodType internal_method);
+
+  bool (*eval_)(const Condition*);  // Actual evaluator
+  InternalFunctionType function_;   // function taking pointer returning bool
+  InternalMethodType method_;       // method returning bool
+  void *arg_;                       // arg of function_ or object of method_
+
+  Condition();        // null constructor used only to create kTrue
+
+  // Various functions eval_ can point to:
+  static bool CallVoidPtrFunction(const Condition*);
+  template <typename T> static bool CastAndCallFunction(const Condition* c);
+  template <typename T> static bool CastAndCallMethod(const Condition* c);
+};
+
+// -----------------------------------------------------------------------------
+// CondVar
+// -----------------------------------------------------------------------------
+//
+// A condition variable, reflecting state evaluated separately outside of the
+// `Mutex` object, which can be signaled to wake callers.
+// This class is not normally needed; use `Mutex` member functions such as
+// `Mutex::Await()` and intrinsic `Condition` abstractions. In rare cases
+// with many threads and many conditions, `CondVar` may be faster.
+//
+// The implementation may deliver signals to any condition variable at
+// any time, even when no call to `Signal()` or `SignalAll()` is made; as a
+// result, upon being awoken, you must check the logical condition you have
+// been waiting upon.
+//
+// Examples:
+//
+// Usage for a thread waiting for some condition C protected by mutex mu:
+//       mu.Lock();
+//       while (!C) { cv->Wait(&mu); }        // releases and reacquires mu
+//       //  C holds; process data
+//       mu.Unlock();
+//
+// Usage to wake T is:
+//       mu.Lock();
+//      // process data, possibly establishing C
+//      if (C) { cv->Signal(); }
+//      mu.Unlock();
+//
+// If C may be useful to more than one waiter, use `SignalAll()` instead of
+// `Signal()`.
+//
+// With this implementation it is efficient to use `Signal()/SignalAll()` inside
+// the locked region; this usage can make reasoning about your program easier.
+//
+class CondVar {
+ public:
+  CondVar();
+  ~CondVar();
+
+  // CondVar::Wait()
+  //
+  // Atomically releases a `Mutex` and blocks on this condition variable.
+  // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a
+  // spurious wakeup), then reacquires the `Mutex` and returns.
+  //
+  // Requires and ensures that the current thread holds the `Mutex`.
+  void Wait(Mutex *mu);
+
+  // CondVar::WaitWithTimeout()
+  //
+  // Atomically releases a `Mutex` and blocks on this condition variable.
+  // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a
+  // spurious wakeup), or until the timeout has expired, then reacquires
+  // the `Mutex` and returns.
+  //
+  // Returns true if the timeout has expired without this `CondVar`
+  // being signalled in any manner. If both the timeout has expired
+  // and this `CondVar` has been signalled, the implementation is free
+  // to return `true` or `false`.
+  //
+  // Requires and ensures that the current thread holds the `Mutex`.
+  bool WaitWithTimeout(Mutex *mu, absl::Duration timeout);
+
+  // CondVar::WaitWithDeadline()
+  //
+  // Atomically releases a `Mutex` and blocks on this condition variable.
+  // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a
+  // spurious wakeup), or until the deadline has passed, then reacquires
+  // the `Mutex` and returns.
+  //
+  // Deadlines in the past are equivalent to an immediate deadline.
+  //
+  // Returns true if the deadline has passed without this `CondVar`
+  // being signalled in any manner. If both the deadline has passed
+  // and this `CondVar` has been signalled, the implementation is free
+  // to return `true` or `false`.
+  //
+  // Requires and ensures that the current thread holds the `Mutex`.
+  bool WaitWithDeadline(Mutex *mu, absl::Time deadline);
+
+  // CondVar::Signal()
+  //
+  // Signal this `CondVar`; wake at least one waiter if one exists.
+  void Signal();
+
+  // CondVar::SignalAll()
+  //
+  // Signal this `CondVar`; wake all waiters.
+  void SignalAll();
+
+  // CondVar::EnableDebugLog()
+  //
+  // Causes all subsequent uses of this `CondVar` to be logged via
+  // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`.
+  // Note: this method substantially reduces `CondVar` performance.
+  void EnableDebugLog(const char *name);
+
+ private:
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+  synchronization_internal::CondVarImpl *impl() { return impl_.get(); }
+  synchronization_internal::SynchronizationStorage<
+      synchronization_internal::CondVarImpl>
+      impl_;
+#else
+  bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t);
+  void Remove(base_internal::PerThreadSynch *s);
+  void Wakeup(base_internal::PerThreadSynch *w);
+  std::atomic<intptr_t> cv_;  // Condition variable state.
+#endif
+  CondVar(const CondVar&) = delete;
+  CondVar& operator=(const CondVar&) = delete;
+};
+
+
+// Variants of MutexLock.
+//
+// If you find yourself using one of these, consider instead using
+// Mutex::Unlock() and/or if-statements for clarity.
+
+// MutexLockMaybe
+//
+// MutexLockMaybe is like MutexLock, but is a no-op when mu is null.
+class SCOPED_LOCKABLE MutexLockMaybe {
+ public:
+  explicit MutexLockMaybe(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
+  ~MutexLockMaybe() UNLOCK_FUNCTION() {
+    if (this->mu_ != nullptr) { this->mu_->Unlock(); }
+  }
+ private:
+  Mutex *const mu_;
+  MutexLockMaybe(const MutexLockMaybe&) = delete;
+  MutexLockMaybe(MutexLockMaybe&&) = delete;
+  MutexLockMaybe& operator=(const MutexLockMaybe&) = delete;
+  MutexLockMaybe& operator=(MutexLockMaybe&&) = delete;
+};
+
+// ReleasableMutexLock
+//
+// ReleasableMutexLock is like MutexLock, but permits `Release()` of its
+// mutex before destruction. `Release()` may be called at most once.
+class SCOPED_LOCKABLE ReleasableMutexLock {
+ public:
+  explicit ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->Lock();
+  }
+  ~ReleasableMutexLock() UNLOCK_FUNCTION() {
+    if (this->mu_ != nullptr) { this->mu_->Unlock(); }
+  }
+
+  void Release() UNLOCK_FUNCTION();
+
+ private:
+  Mutex *mu_;
+  ReleasableMutexLock(const ReleasableMutexLock&) = delete;
+  ReleasableMutexLock(ReleasableMutexLock&&) = delete;
+  ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
+  ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete;
+};
+
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+#else
+inline Mutex::Mutex() : mu_(0) {
+  ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+}
+
+inline CondVar::CondVar() : cv_(0) {}
+#endif
+
+// static
+template <typename T>
+bool Condition::CastAndCallMethod(const Condition *c) {
+  typedef bool (T::*MemberType)();
+  MemberType rm = reinterpret_cast<MemberType>(c->method_);
+  T *x = static_cast<T *>(c->arg_);
+  return (x->*rm)();
+}
+
+// static
+template <typename T>
+bool Condition::CastAndCallFunction(const Condition *c) {
+  typedef bool (*FuncType)(T *);
+  FuncType fn = reinterpret_cast<FuncType>(c->function_);
+  T *x = static_cast<T *>(c->arg_);
+  return (*fn)(x);
+}
+
+template <typename T>
+inline Condition::Condition(bool (*func)(T *), T *arg)
+    : eval_(&CastAndCallFunction<T>),
+      function_(reinterpret_cast<InternalFunctionType>(func)),
+      method_(nullptr),
+      arg_(const_cast<void *>(static_cast<const void *>(arg))) {}
+
+template <typename T>
+inline Condition::Condition(T *object,
+                            bool (absl::internal::identity<T>::type::*method)())
+    : eval_(&CastAndCallMethod<T>),
+      function_(nullptr),
+      method_(reinterpret_cast<InternalMethodType>(method)),
+      arg_(object) {}
+
+template <typename T>
+inline Condition::Condition(const T *object,
+                            bool (absl::internal::identity<T>::type::*method)()
+                                const)
+    : eval_(&CastAndCallMethod<T>),
+      function_(nullptr),
+      method_(reinterpret_cast<InternalMethodType>(method)),
+      arg_(reinterpret_cast<void *>(const_cast<T *>(object))) {}
+
+// Register a hook for profiling support.
+//
+// The function pointer registered here will be called whenever a mutex is
+// contended.  The callback is given the absl/base/cycleclock.h timestamp when
+// waiting began.
+//
+// Calls to this function do not race or block, but there is no ordering
+// guaranteed between calls to this function and call to the provided hook.
+// In particular, the previously registered hook may still be called for some
+// time after this function returns.
+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp));
+
+// Register a hook for Mutex tracing.
+//
+// The function pointer registered here will be called whenever a mutex is
+// contended.  The callback is given an opaque handle to the contended mutex,
+// an event name, and the number of wait cycles (as measured by
+// //absl/base/internal/cycleclock.h, and which may not be real
+// "cycle" counts.)
+//
+// The only event name currently sent is "slow release".
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
+                              int64_t wait_cycles));
+
+// TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
+// into a single interface, since they are only ever called in pairs.
+
+// Register a hook for CondVar tracing.
+//
+// The function pointer registered here will be called here on various CondVar
+// events.  The callback is given an opaque handle to the CondVar object and
+// a std::string identifying the event.  This is thread-safe, but only a single
+// tracer can be registered.
+//
+// Events that can be sent are "Wait", "Unwait", "Signal wakeup", and
+// "SignalAll wakeup".
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv));
+
+// Register a hook for symbolizing stack traces in deadlock detector reports.
+//
+// 'pc' is the program counter being symbolized, 'out' is the buffer to write
+// into, and 'out_size' is the size of the buffer.  This function can return
+// false if symbolizing failed, or true if a null-terminated symbol was written
+// to 'out.'
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+//
+// DEPRECATED: The default symbolizer function is absl::Symbolize() and the
+// ability to register a different hook for symbolizing stack traces will be
+// removed on or after 2023-05-01.
+ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed "
+                "on or after 2023-05-01")
+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size));
+
+// EnableMutexInvariantDebugging()
+//
+// Enable or disable global support for Mutex invariant debugging.  If enabled,
+// then invariant predicates can be registered per-Mutex for debug checking.
+// See Mutex::EnableInvariantDebugging().
+void EnableMutexInvariantDebugging(bool enabled);
+
+// When in debug mode, and when the feature has been enabled globally, the
+// implementation will keep track of lock ordering and complain (or optionally
+// crash) if a cycle is detected in the acquired-before graph.
+
+// Possible modes of operation for the deadlock detector in debug mode.
+enum class OnDeadlockCycle {
+  kIgnore,  // Neither report on nor attempt to track cycles in lock ordering
+  kReport,  // Report lock cycles to stderr when detected
+  kAbort,  // Report lock cycles to stderr when detected, then abort
+};
+
+// SetMutexDeadlockDetectionMode()
+//
+// Enable or disable global support for detection of potential deadlocks
+// due to Mutex lock ordering inversions.  When set to 'kIgnore', tracking of
+// lock ordering is disabled.  Otherwise, in debug builds, a lock ordering graph
+// will be maintained internally, and detected cycles will be reported in
+// the manner chosen here.
+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
+
+}  // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void AbslInternalMutexYield();
+}  // extern "C"
+#endif  // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc
new file mode 100644
index 0000000..30a5235
--- /dev/null
+++ b/absl/synchronization/mutex_benchmark.cc
@@ -0,0 +1,94 @@
+// Copyright 2017 The Abseil 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 <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/synchronization/blocking_counter.h"
+#include "absl/synchronization/internal/thread_pool.h"
+#include "absl/synchronization/mutex.h"
+
+namespace {
+
+// Measure the overhead of conditions on mutex release (when they must be
+// evaluated).  Mutex has (some) support for equivalence classes allowing
+// Conditions with the same function/argument to potentially not be multiply
+// evaluated.
+//
+// num_classes==0 is used for the special case of every waiter being distinct.
+void BM_ConditionWaiters(benchmark::State& state) {
+  int num_classes = state.range(0);
+  int num_waiters = state.range(1);
+
+  struct Helper {
+    static void Waiter(absl::BlockingCounter* init, absl::Mutex* m, int* p) {
+      init->DecrementCount();
+      m->LockWhen(absl::Condition(
+          static_cast<bool (*)(int*)>([](int* v) { return *v == 0; }), p));
+      m->Unlock();
+    }
+  };
+
+  if (num_classes == 0) {
+    // No equivalence classes.
+    num_classes = num_waiters;
+  }
+
+  absl::BlockingCounter init(num_waiters);
+  absl::Mutex mu;
+  std::vector<int> equivalence_classes(num_classes, 1);
+
+  // Must be declared last to be destroyed first.
+  absl::synchronization_internal::ThreadPool pool(num_waiters);
+
+  for (int i = 0; i < num_waiters; i++) {
+    // Mutex considers Conditions with the same function and argument
+    // to be equivalent.
+    pool.Schedule([&, i] {
+      Helper::Waiter(&init, &mu, &equivalence_classes[i % num_classes]);
+    });
+  }
+  init.Wait();
+
+  for (auto _ : state) {
+    mu.Lock();
+    mu.Unlock();  // Each unlock requires Condition evaluation for our waiters.
+  }
+
+  mu.Lock();
+  for (int i = 0; i < num_classes; i++) {
+    equivalence_classes[i] = 0;
+  }
+  mu.Unlock();
+}
+
+#ifdef THREAD_SANITIZER
+// ThreadSanitizer can't handle 8192 threads.
+constexpr int kMaxConditionWaiters = 2048;
+#else
+constexpr int kMaxConditionWaiters = 8192;
+#endif
+BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters);
+
+void BM_ContendedMutex(benchmark::State& state) {
+  static absl::Mutex* mu = new absl::Mutex;
+  for (auto _ : state) {
+    absl::MutexLock lock(mu);
+  }
+}
+BENCHMARK(BM_ContendedMutex)->Threads(1);
+BENCHMARK(BM_ContendedMutex)->ThreadPerCpu();
+
+}  // namespace
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
new file mode 100644
index 0000000..53b9378
--- /dev/null
+++ b/absl/synchronization/mutex_test.cc
@@ -0,0 +1,1539 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/mutex.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cstdlib>
+#include <functional>
+#include <memory>
+#include <random>
+#include <string>
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/memory/memory.h"
+#include "absl/synchronization/internal/thread_pool.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace {
+
+// TODO(dmauro): Replace with a commandline flag.
+static constexpr bool kExtendedTest = false;
+
+std::unique_ptr<absl::synchronization_internal::ThreadPool> CreatePool(
+    int threads) {
+  return absl::make_unique<absl::synchronization_internal::ThreadPool>(threads);
+}
+
+std::unique_ptr<absl::synchronization_internal::ThreadPool>
+CreateDefaultPool() {
+  return CreatePool(kExtendedTest ? 32 : 10);
+}
+
+// Hack to schedule a function to run on a thread pool thread after a
+// duration has elapsed.
+static void ScheduleAfter(absl::synchronization_internal::ThreadPool *tp,
+                          const std::function<void()> &func,
+                          absl::Duration after) {
+  tp->Schedule([func, after] {
+    absl::SleepFor(after);
+    func();
+  });
+}
+
+struct TestContext {
+  int iterations;
+  int threads;
+  int g0;  // global 0
+  int g1;  // global 1
+  absl::Mutex mu;
+  absl::CondVar cv;
+};
+
+// To test whether the invariant check call occurs
+static std::atomic<bool> invariant_checked;
+
+static bool GetInvariantChecked() {
+  return invariant_checked.load(std::memory_order_relaxed);
+}
+
+static void SetInvariantChecked(bool new_value) {
+  invariant_checked.store(new_value, std::memory_order_relaxed);
+}
+
+static void CheckSumG0G1(void *v) {
+  TestContext *cxt = static_cast<TestContext *>(v);
+  ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in CheckSumG0G1");
+  SetInvariantChecked(true);
+}
+
+static void TestMu(TestContext *cxt, int c) {
+  for (int i = 0; i != cxt->iterations; i++) {
+    absl::MutexLock l(&cxt->mu);
+    int a = cxt->g0 + 1;
+    cxt->g0 = a;
+    cxt->g1--;
+  }
+}
+
+static void TestTry(TestContext *cxt, int c) {
+  for (int i = 0; i != cxt->iterations; i++) {
+    do {
+      std::this_thread::yield();
+    } while (!cxt->mu.TryLock());
+    int a = cxt->g0 + 1;
+    cxt->g0 = a;
+    cxt->g1--;
+    cxt->mu.Unlock();
+  }
+}
+
+static void TestR20ms(TestContext *cxt, int c) {
+  for (int i = 0; i != cxt->iterations; i++) {
+    absl::ReaderMutexLock l(&cxt->mu);
+    absl::SleepFor(absl::Milliseconds(20));
+    cxt->mu.AssertReaderHeld();
+  }
+}
+
+static void TestRW(TestContext *cxt, int c) {
+  if ((c & 1) == 0) {
+    for (int i = 0; i != cxt->iterations; i++) {
+      absl::WriterMutexLock l(&cxt->mu);
+      cxt->g0++;
+      cxt->g1--;
+      cxt->mu.AssertHeld();
+      cxt->mu.AssertReaderHeld();
+    }
+  } else {
+    for (int i = 0; i != cxt->iterations; i++) {
+      absl::ReaderMutexLock l(&cxt->mu);
+      ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in TestRW");
+      cxt->mu.AssertReaderHeld();
+    }
+  }
+}
+
+struct MyContext {
+  int target;
+  TestContext *cxt;
+  bool MyTurn();
+};
+
+bool MyContext::MyTurn() {
+  TestContext *cxt = this->cxt;
+  return cxt->g0 == this->target || cxt->g0 == cxt->iterations;
+}
+
+static void TestAwait(TestContext *cxt, int c) {
+  MyContext mc;
+  mc.target = c;
+  mc.cxt = cxt;
+  absl::MutexLock l(&cxt->mu);
+  cxt->mu.AssertHeld();
+  while (cxt->g0 < cxt->iterations) {
+    cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn));
+    ABSL_RAW_CHECK(mc.MyTurn(), "Error in TestAwait");
+    cxt->mu.AssertHeld();
+    if (cxt->g0 < cxt->iterations) {
+      int a = cxt->g0 + 1;
+      cxt->g0 = a;
+      mc.target += cxt->threads;
+    }
+  }
+}
+
+static void TestSignalAll(TestContext *cxt, int c) {
+  int target = c;
+  absl::MutexLock l(&cxt->mu);
+  cxt->mu.AssertHeld();
+  while (cxt->g0 < cxt->iterations) {
+    while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
+      cxt->cv.Wait(&cxt->mu);
+    }
+    if (cxt->g0 < cxt->iterations) {
+      int a = cxt->g0 + 1;
+      cxt->g0 = a;
+      cxt->cv.SignalAll();
+      target += cxt->threads;
+    }
+  }
+}
+
+static void TestSignal(TestContext *cxt, int c) {
+  ABSL_RAW_CHECK(cxt->threads == 2, "TestSignal should use 2 threads");
+  int target = c;
+  absl::MutexLock l(&cxt->mu);
+  cxt->mu.AssertHeld();
+  while (cxt->g0 < cxt->iterations) {
+    while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
+      cxt->cv.Wait(&cxt->mu);
+    }
+    if (cxt->g0 < cxt->iterations) {
+      int a = cxt->g0 + 1;
+      cxt->g0 = a;
+      cxt->cv.Signal();
+      target += cxt->threads;
+    }
+  }
+}
+
+static void TestCVTimeout(TestContext *cxt, int c) {
+  int target = c;
+  absl::MutexLock l(&cxt->mu);
+  cxt->mu.AssertHeld();
+  while (cxt->g0 < cxt->iterations) {
+    while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
+    }
+    if (cxt->g0 < cxt->iterations) {
+      int a = cxt->g0 + 1;
+      cxt->g0 = a;
+      cxt->cv.SignalAll();
+      target += cxt->threads;
+    }
+  }
+}
+
+static bool G0GE2(TestContext *cxt) { return cxt->g0 >= 2; }
+
+static void TestTime(TestContext *cxt, int c, bool use_cv) {
+  ABSL_RAW_CHECK(cxt->iterations == 1, "TestTime should only use 1 iteration");
+  ABSL_RAW_CHECK(cxt->threads > 2, "TestTime should use more than 2 threads");
+  const bool kFalse = false;
+  absl::Condition false_cond(&kFalse);
+  absl::Condition g0ge2(G0GE2, cxt);
+  if (c == 0) {
+    absl::MutexLock l(&cxt->mu);
+
+    absl::Time start = absl::Now();
+    if (use_cv) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+    } else {
+      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+                     "TestTime failed");
+    }
+    absl::Duration elapsed = absl::Now() - start;
+    ABSL_RAW_CHECK(
+        absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
+        "TestTime failed");
+    ABSL_RAW_CHECK(cxt->g0 == 1, "TestTime failed");
+
+    start = absl::Now();
+    if (use_cv) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+    } else {
+      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+                     "TestTime failed");
+    }
+    elapsed = absl::Now() - start;
+    ABSL_RAW_CHECK(
+        absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
+        "TestTime failed");
+    cxt->g0++;
+    if (use_cv) {
+      cxt->cv.Signal();
+    }
+
+    start = absl::Now();
+    if (use_cv) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(4));
+    } else {
+      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4)),
+                     "TestTime failed");
+    }
+    elapsed = absl::Now() - start;
+    ABSL_RAW_CHECK(
+        absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0),
+        "TestTime failed");
+    ABSL_RAW_CHECK(cxt->g0 >= 3, "TestTime failed");
+
+    start = absl::Now();
+    if (use_cv) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+    } else {
+      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+                     "TestTime failed");
+    }
+    elapsed = absl::Now() - start;
+    ABSL_RAW_CHECK(
+        absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
+        "TestTime failed");
+    if (use_cv) {
+      cxt->cv.SignalAll();
+    }
+
+    start = absl::Now();
+    if (use_cv) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+    } else {
+      ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+                     "TestTime failed");
+    }
+    elapsed = absl::Now() - start;
+    ABSL_RAW_CHECK(absl::Seconds(0.9) <= elapsed &&
+                   elapsed <= absl::Seconds(2.0), "TestTime failed");
+    ABSL_RAW_CHECK(cxt->g0 == cxt->threads, "TestTime failed");
+
+  } else if (c == 1) {
+    absl::MutexLock l(&cxt->mu);
+    const absl::Time start = absl::Now();
+    if (use_cv) {
+      cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500));
+    } else {
+      ABSL_RAW_CHECK(
+          !cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500)),
+          "TestTime failed");
+    }
+    const absl::Duration elapsed = absl::Now() - start;
+    ABSL_RAW_CHECK(
+        absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9),
+        "TestTime failed");
+    cxt->g0++;
+  } else if (c == 2) {
+    absl::MutexLock l(&cxt->mu);
+    if (use_cv) {
+      while (cxt->g0 < 2) {
+        cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
+      }
+    } else {
+      ABSL_RAW_CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100)),
+                     "TestTime failed");
+    }
+    cxt->g0++;
+  } else {
+    absl::MutexLock l(&cxt->mu);
+    if (use_cv) {
+      while (cxt->g0 < 2) {
+        cxt->cv.Wait(&cxt->mu);
+      }
+    } else {
+      cxt->mu.Await(g0ge2);
+    }
+    cxt->g0++;
+  }
+}
+
+static void TestMuTime(TestContext *cxt, int c) { TestTime(cxt, c, false); }
+
+static void TestCVTime(TestContext *cxt, int c) { TestTime(cxt, c, true); }
+
+static void EndTest(int *c0, int *c1, absl::Mutex *mu, absl::CondVar *cv,
+                    const std::function<void(int)>& cb) {
+  mu->Lock();
+  int c = (*c0)++;
+  mu->Unlock();
+  cb(c);
+  absl::MutexLock l(mu);
+  (*c1)++;
+  cv->Signal();
+}
+
+// Code common to RunTest() and RunTestWithInvariantDebugging().
+static int RunTestCommon(TestContext *cxt, void (*test)(TestContext *cxt, int),
+                         int threads, int iterations, int operations) {
+  absl::Mutex mu2;
+  absl::CondVar cv2;
+  int c0 = 0;
+  int c1 = 0;
+  cxt->g0 = 0;
+  cxt->g1 = 0;
+  cxt->iterations = iterations;
+  cxt->threads = threads;
+  absl::synchronization_internal::ThreadPool tp(threads);
+  for (int i = 0; i != threads; i++) {
+    tp.Schedule(std::bind(&EndTest, &c0, &c1, &mu2, &cv2,
+                          std::function<void(int)>(
+                              std::bind(test, cxt, std::placeholders::_1))));
+  }
+  mu2.Lock();
+  while (c1 != threads) {
+    cv2.Wait(&mu2);
+  }
+  mu2.Unlock();
+  return cxt->g0;
+}
+
+// Basis for the parameterized tests configured below.
+static int RunTest(void (*test)(TestContext *cxt, int), int threads,
+                   int iterations, int operations) {
+  TestContext cxt;
+  return RunTestCommon(&cxt, test, threads, iterations, operations);
+}
+
+// Like RunTest(), but sets an invariant on the tested Mutex and
+// verifies that the invariant check happened. The invariant function
+// will be passed the TestContext* as its arg and must call
+// SetInvariantChecked(true);
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+static int RunTestWithInvariantDebugging(void (*test)(TestContext *cxt, int),
+                                         int threads, int iterations,
+                                         int operations,
+                                         void (*invariant)(void *)) {
+  absl::EnableMutexInvariantDebugging(true);
+  SetInvariantChecked(false);
+  TestContext cxt;
+  cxt.mu.EnableInvariantDebugging(invariant, &cxt);
+  int ret = RunTestCommon(&cxt, test, threads, iterations, operations);
+  ABSL_RAW_CHECK(GetInvariantChecked(), "Invariant not checked");
+  absl::EnableMutexInvariantDebugging(false);  // Restore.
+  return ret;
+}
+#endif
+
+// --------------------------------------------------------
+// Test for fix of bug in TryRemove()
+struct TimeoutBugStruct {
+  absl::Mutex mu;
+  bool a;
+  int a_waiter_count;
+};
+
+static void WaitForA(TimeoutBugStruct *x) {
+  x->mu.LockWhen(absl::Condition(&x->a));
+  x->a_waiter_count--;
+  x->mu.Unlock();
+}
+
+static bool NoAWaiters(TimeoutBugStruct *x) { return x->a_waiter_count == 0; }
+
+// Test that a CondVar.Wait(&mutex) can un-block a call to mutex.Await() in
+// another thread.
+TEST(Mutex, CondVarWaitSignalsAwait) {
+  // Use a struct so the lock annotations apply.
+  struct {
+    absl::Mutex barrier_mu;
+    bool barrier GUARDED_BY(barrier_mu) = false;
+
+    absl::Mutex release_mu;
+    bool release GUARDED_BY(release_mu) = false;
+    absl::CondVar released_cv;
+  } state;
+
+  auto pool = CreateDefaultPool();
+
+  // Thread A.  Sets barrier, waits for release using Mutex::Await, then
+  // signals released_cv.
+  pool->Schedule([&state] {
+    state.release_mu.Lock();
+
+    state.barrier_mu.Lock();
+    state.barrier = true;
+    state.barrier_mu.Unlock();
+
+    state.release_mu.Await(absl::Condition(&state.release));
+    state.released_cv.Signal();
+    state.release_mu.Unlock();
+  });
+
+  state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
+  state.barrier_mu.Unlock();
+  state.release_mu.Lock();
+  // Thread A is now blocked on release by way of Mutex::Await().
+
+  // Set release.  Calling released_cv.Wait() should un-block thread A,
+  // which will signal released_cv.  If not, the test will hang.
+  state.release = true;
+  state.released_cv.Wait(&state.release_mu);
+  state.release_mu.Unlock();
+}
+
+// Test that a CondVar.WaitWithTimeout(&mutex) can un-block a call to
+// mutex.Await() in another thread.
+TEST(Mutex, CondVarWaitWithTimeoutSignalsAwait) {
+  // Use a struct so the lock annotations apply.
+  struct {
+    absl::Mutex barrier_mu;
+    bool barrier GUARDED_BY(barrier_mu) = false;
+
+    absl::Mutex release_mu;
+    bool release GUARDED_BY(release_mu) = false;
+    absl::CondVar released_cv;
+  } state;
+
+  auto pool = CreateDefaultPool();
+
+  // Thread A.  Sets barrier, waits for release using Mutex::Await, then
+  // signals released_cv.
+  pool->Schedule([&state] {
+    state.release_mu.Lock();
+
+    state.barrier_mu.Lock();
+    state.barrier = true;
+    state.barrier_mu.Unlock();
+
+    state.release_mu.Await(absl::Condition(&state.release));
+    state.released_cv.Signal();
+    state.release_mu.Unlock();
+  });
+
+  state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
+  state.barrier_mu.Unlock();
+  state.release_mu.Lock();
+  // Thread A is now blocked on release by way of Mutex::Await().
+
+  // Set release.  Calling released_cv.Wait() should un-block thread A,
+  // which will signal released_cv.  If not, the test will hang.
+  state.release = true;
+  EXPECT_TRUE(
+      !state.released_cv.WaitWithTimeout(&state.release_mu, absl::Seconds(10)))
+      << "; Unrecoverable test failure: CondVar::WaitWithTimeout did not "
+         "unblock the absl::Mutex::Await call in another thread.";
+
+  state.release_mu.Unlock();
+}
+
+// Test for regression of a bug in loop of TryRemove()
+TEST(Mutex, MutexTimeoutBug) {
+  auto tp = CreateDefaultPool();
+
+  TimeoutBugStruct x;
+  x.a = false;
+  x.a_waiter_count = 2;
+  tp->Schedule(std::bind(&WaitForA, &x));
+  tp->Schedule(std::bind(&WaitForA, &x));
+  absl::SleepFor(absl::Seconds(1));  // Allow first two threads to hang.
+  // The skip field of the second will point to the first because there are
+  // only two.
+
+  // Now cause a thread waiting on an always-false to time out
+  // This would deadlock when the bug was present.
+  bool always_false = false;
+  x.mu.LockWhenWithTimeout(absl::Condition(&always_false),
+                           absl::Milliseconds(500));
+
+  // if we get here, the bug is not present.   Cleanup the state.
+
+  x.a = true;                                    // wakeup the two waiters on A
+  x.mu.Await(absl::Condition(&NoAWaiters, &x));  // wait for them to exit
+  x.mu.Unlock();
+}
+
+struct CondVarWaitDeadlock : testing::TestWithParam<int> {
+  absl::Mutex mu;
+  absl::CondVar cv;
+  bool cond1 = false;
+  bool cond2 = false;
+  bool read_lock1;
+  bool read_lock2;
+  bool signal_unlocked;
+
+  CondVarWaitDeadlock() {
+    read_lock1 = GetParam() & (1 << 0);
+    read_lock2 = GetParam() & (1 << 1);
+    signal_unlocked = GetParam() & (1 << 2);
+  }
+
+  void Waiter1() {
+    if (read_lock1) {
+      mu.ReaderLock();
+      while (!cond1) {
+        cv.Wait(&mu);
+      }
+      mu.ReaderUnlock();
+    } else {
+      mu.Lock();
+      while (!cond1) {
+        cv.Wait(&mu);
+      }
+      mu.Unlock();
+    }
+  }
+
+  void Waiter2() {
+    if (read_lock2) {
+      mu.ReaderLockWhen(absl::Condition(&cond2));
+      mu.ReaderUnlock();
+    } else {
+      mu.LockWhen(absl::Condition(&cond2));
+      mu.Unlock();
+    }
+  }
+};
+
+// Test for a deadlock bug in Mutex::Fer().
+// The sequence of events that lead to the deadlock is:
+// 1. waiter1 blocks on cv in read mode (mu bits = 0).
+// 2. waiter2 blocks on mu in either mode (mu bits = kMuWait).
+// 3. main thread locks mu, sets cond1, unlocks mu (mu bits = kMuWait).
+// 4. main thread signals on cv and this eventually calls Mutex::Fer().
+// Currently Fer wakes waiter1 since mu bits = kMuWait (mutex is unlocked).
+// Before the bug fix Fer neither woke waiter1 nor queued it on mutex,
+// which resulted in deadlock.
+TEST_P(CondVarWaitDeadlock, Test) {
+  auto waiter1 = CreatePool(1);
+  auto waiter2 = CreatePool(1);
+  waiter1->Schedule([this] { this->Waiter1(); });
+  waiter2->Schedule([this] { this->Waiter2(); });
+
+  // Wait while threads block (best-effort is fine).
+  absl::SleepFor(absl::Milliseconds(100));
+
+  // Wake condwaiter.
+  mu.Lock();
+  cond1 = true;
+  if (signal_unlocked) {
+    mu.Unlock();
+    cv.Signal();
+  } else {
+    cv.Signal();
+    mu.Unlock();
+  }
+  waiter1.reset();  // "join" waiter1
+
+  // Wake waiter.
+  mu.Lock();
+  cond2 = true;
+  mu.Unlock();
+  waiter2.reset();  // "join" waiter2
+}
+
+INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
+                        ::testing::Range(0, 8),
+                        ::testing::PrintToStringParamName());
+
+// --------------------------------------------------------
+// Test for fix of bug in DequeueAllWakeable()
+// Bug was that if there was more than one waiting reader
+// and all should be woken, the most recently blocked one
+// would not be.
+
+struct DequeueAllWakeableBugStruct {
+  absl::Mutex mu;
+  absl::Mutex mu2;       // protects all fields below
+  int unfinished_count;  // count of unfinished readers; under mu2
+  bool done1;            // unfinished_count == 0; under mu2
+  int finished_count;    // count of finished readers, under mu2
+  bool done2;            // finished_count == 0; under mu2
+};
+
+// Test for regression of a bug in loop of DequeueAllWakeable()
+static void AcquireAsReader(DequeueAllWakeableBugStruct *x) {
+  x->mu.ReaderLock();
+  x->mu2.Lock();
+  x->unfinished_count--;
+  x->done1 = (x->unfinished_count == 0);
+  x->mu2.Unlock();
+  // make sure that both readers acquired mu before we release it.
+  absl::SleepFor(absl::Seconds(2));
+  x->mu.ReaderUnlock();
+
+  x->mu2.Lock();
+  x->finished_count--;
+  x->done2 = (x->finished_count == 0);
+  x->mu2.Unlock();
+}
+
+// Test for regression of a bug in loop of DequeueAllWakeable()
+TEST(Mutex, MutexReaderWakeupBug) {
+  auto tp = CreateDefaultPool();
+
+  DequeueAllWakeableBugStruct x;
+  x.unfinished_count = 2;
+  x.done1 = false;
+  x.finished_count = 2;
+  x.done2 = false;
+  x.mu.Lock();  // acquire mu exclusively
+  // queue two thread that will block on reader locks on x.mu
+  tp->Schedule(std::bind(&AcquireAsReader, &x));
+  tp->Schedule(std::bind(&AcquireAsReader, &x));
+  absl::SleepFor(absl::Seconds(1));  // give time for reader threads to block
+  x.mu.Unlock();                     // wake them up
+
+  // both readers should finish promptly
+  EXPECT_TRUE(
+      x.mu2.LockWhenWithTimeout(absl::Condition(&x.done1), absl::Seconds(10)));
+  x.mu2.Unlock();
+
+  EXPECT_TRUE(
+      x.mu2.LockWhenWithTimeout(absl::Condition(&x.done2), absl::Seconds(10)));
+  x.mu2.Unlock();
+}
+
+struct LockWhenTestStruct {
+  absl::Mutex mu1;
+  bool cond = false;
+
+  absl::Mutex mu2;
+  bool waiting = false;
+};
+
+static bool LockWhenTestIsCond(LockWhenTestStruct* s) {
+  s->mu2.Lock();
+  s->waiting = true;
+  s->mu2.Unlock();
+  return s->cond;
+}
+
+static void LockWhenTestWaitForIsCond(LockWhenTestStruct* s) {
+  s->mu1.LockWhen(absl::Condition(&LockWhenTestIsCond, s));
+  s->mu1.Unlock();
+}
+
+TEST(Mutex, LockWhen) {
+  LockWhenTestStruct s;
+
+  std::thread t(LockWhenTestWaitForIsCond, &s);
+  s.mu2.LockWhen(absl::Condition(&s.waiting));
+  s.mu2.Unlock();
+
+  s.mu1.Lock();
+  s.cond = true;
+  s.mu1.Unlock();
+
+  t.join();
+}
+
+// --------------------------------------------------------
+// The following test requires Mutex::ReaderLock to be a real shared
+// lock, which is not the case in all builds.
+#if !defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
+
+// Test for fix of bug in UnlockSlow() that incorrectly decremented the reader
+// count when putting a thread to sleep waiting for a false condition when the
+// lock was not held.
+
+// For this bug to strike, we make a thread wait on a free mutex with no
+// waiters by causing its wakeup condition to be false.   Then the
+// next two acquirers must be readers.   The bug causes the lock
+// to be released when one reader unlocks, rather than both.
+
+struct ReaderDecrementBugStruct {
+  bool cond;  // to delay first thread (under mu)
+  int done;   // reference count (under mu)
+  absl::Mutex mu;
+
+  bool waiting_on_cond;   // under mu2
+  bool have_reader_lock;  // under mu2
+  bool complete;          // under mu2
+  absl::Mutex mu2;        // > mu
+};
+
+// L >= mu, L < mu_waiting_on_cond
+static bool IsCond(void *v) {
+  ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
+  x->mu2.Lock();
+  x->waiting_on_cond = true;
+  x->mu2.Unlock();
+  return x->cond;
+}
+
+// L >= mu
+static bool AllDone(void *v) {
+  ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
+  return x->done == 0;
+}
+
+// L={}
+static void WaitForCond(ReaderDecrementBugStruct *x) {
+  absl::Mutex dummy;
+  absl::MutexLock l(&dummy);
+  x->mu.LockWhen(absl::Condition(&IsCond, x));
+  x->done--;
+  x->mu.Unlock();
+}
+
+// L={}
+static void GetReadLock(ReaderDecrementBugStruct *x) {
+  x->mu.ReaderLock();
+  x->mu2.Lock();
+  x->have_reader_lock = true;
+  x->mu2.Await(absl::Condition(&x->complete));
+  x->mu2.Unlock();
+  x->mu.ReaderUnlock();
+  x->mu.Lock();
+  x->done--;
+  x->mu.Unlock();
+}
+
+// Test for reader counter being decremented incorrectly by waiter
+// with false condition.
+TEST(Mutex, MutexReaderDecrementBug) NO_THREAD_SAFETY_ANALYSIS {
+  ReaderDecrementBugStruct x;
+  x.cond = false;
+  x.waiting_on_cond = false;
+  x.have_reader_lock = false;
+  x.complete = false;
+  x.done = 2;  // initial ref count
+
+  // Run WaitForCond() and wait for it to sleep
+  std::thread thread1(WaitForCond, &x);
+  x.mu2.LockWhen(absl::Condition(&x.waiting_on_cond));
+  x.mu2.Unlock();
+
+  // Run GetReadLock(), and wait for it to get the read lock
+  std::thread thread2(GetReadLock, &x);
+  x.mu2.LockWhen(absl::Condition(&x.have_reader_lock));
+  x.mu2.Unlock();
+
+  // Get the reader lock ourselves, and release it.
+  x.mu.ReaderLock();
+  x.mu.ReaderUnlock();
+
+  // The lock should be held in read mode by GetReadLock().
+  // If we have the bug, the lock will be free.
+  x.mu.AssertReaderHeld();
+
+  // Wake up all the threads.
+  x.mu2.Lock();
+  x.complete = true;
+  x.mu2.Unlock();
+
+  // TODO(delesley): turn on analysis once lock upgrading is supported.
+  // (This call upgrades the lock from shared to exclusive.)
+  x.mu.Lock();
+  x.cond = true;
+  x.mu.Await(absl::Condition(&AllDone, &x));
+  x.mu.Unlock();
+
+  thread1.join();
+  thread2.join();
+}
+#endif  // !ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
+
+// Test that we correctly handle the situation when a lock is
+// held and then destroyed (w/o unlocking).
+TEST(Mutex, LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+  for (int i = 0; i != 10; i++) {
+    // Create, lock and destroy 10 locks.
+    const int kNumLocks = 10;
+    auto mu = absl::make_unique<absl::Mutex[]>(kNumLocks);
+    for (int j = 0; j != kNumLocks; j++) {
+      if ((j % 2) == 0) {
+        mu[j].WriterLock();
+      } else {
+        mu[j].ReaderLock();
+      }
+    }
+  }
+}
+
+// --------------------------------------------------------
+// Test for bug with pattern of readers using a condvar.  The bug was that if a
+// reader went to sleep on a condition variable while one or more other readers
+// held the lock, but there were no waiters, the reader count (held in the
+// mutex word) would be lost.  (This is because Enqueue() had at one time
+// always placed the thread on the Mutex queue.  Later (CL 4075610), to
+// tolerate re-entry into Mutex from a Condition predicate, Enqueue() was
+// changed so that it could also place a thread on a condition-variable.  This
+// introduced the case where Enqueue() returned with an empty queue, and this
+// case was handled incorrectly in one place.)
+
+static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv,
+                                     int *running) {
+  std::random_device dev;
+  std::mt19937 gen(dev());
+  std::uniform_int_distribution<int> random_millis(0, 15);
+  mu->ReaderLock();
+  while (*running == 3) {
+    absl::SleepFor(absl::Milliseconds(random_millis(gen)));
+    cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen)));
+  }
+  mu->ReaderUnlock();
+  mu->Lock();
+  (*running)--;
+  mu->Unlock();
+}
+
+struct True {
+  template <class... Args>
+  bool operator()(Args...) const {
+    return true;
+  }
+};
+
+struct DerivedTrue : True {};
+
+TEST(Mutex, FunctorCondition) {
+  {  // Variadic
+    True f;
+    EXPECT_TRUE(absl::Condition(&f).Eval());
+  }
+
+  {  // Inherited
+    DerivedTrue g;
+    EXPECT_TRUE(absl::Condition(&g).Eval());
+  }
+
+  {  // lambda
+    int value = 3;
+    auto is_zero = [&value] { return value == 0; };
+    absl::Condition c(&is_zero);
+    EXPECT_FALSE(c.Eval());
+    value = 0;
+    EXPECT_TRUE(c.Eval());
+  }
+
+  {  // bind
+    int value = 0;
+    auto is_positive = std::bind(std::less<int>(), 0, std::cref(value));
+    absl::Condition c(&is_positive);
+    EXPECT_FALSE(c.Eval());
+    value = 1;
+    EXPECT_TRUE(c.Eval());
+  }
+
+  {  // std::function
+    int value = 3;
+    std::function<bool()> is_zero = [&value] { return value == 0; };
+    absl::Condition c(&is_zero);
+    EXPECT_FALSE(c.Eval());
+    value = 0;
+    EXPECT_TRUE(c.Eval());
+  }
+}
+
+static bool IntIsZero(int *x) { return *x == 0; }
+
+// Test for reader waiting condition variable when there are other readers
+// but no waiters.
+TEST(Mutex, TestReaderOnCondVar) {
+  auto tp = CreateDefaultPool();
+  absl::Mutex mu;
+  absl::CondVar cv;
+  int running = 3;
+  tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
+  tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
+  absl::SleepFor(absl::Seconds(2));
+  mu.Lock();
+  running--;
+  mu.Await(absl::Condition(&IntIsZero, &running));
+  mu.Unlock();
+}
+
+// --------------------------------------------------------
+struct AcquireFromConditionStruct {
+  absl::Mutex mu0;   // protects value, done
+  int value;         // times condition function is called; under mu0,
+  bool done;         // done with test?  under mu0
+  absl::Mutex mu1;   // used to attempt to mess up state of mu0
+  absl::CondVar cv;  // so the condition function can be invoked from
+                     // CondVar::Wait().
+};
+
+static bool ConditionWithAcquire(AcquireFromConditionStruct *x) {
+  x->value++;  // count times this function is called
+
+  if (x->value == 2 || x->value == 3) {
+    // On the second and third invocation of this function, sleep for 100ms,
+    // but with the side-effect of altering the state of a Mutex other than
+    // than one for which this is a condition.  The spec now explicitly allows
+    // this side effect; previously it did not.  it was illegal.
+    bool always_false = false;
+    x->mu1.LockWhenWithTimeout(absl::Condition(&always_false),
+                               absl::Milliseconds(100));
+    x->mu1.Unlock();
+  }
+  ABSL_RAW_CHECK(x->value < 4, "should not be invoked a fourth time");
+
+  // We arrange for the condition to return true on only the 2nd and 3rd calls.
+  return x->value == 2 || x->value == 3;
+}
+
+static void WaitForCond2(AcquireFromConditionStruct *x) {
+  // wait for cond0 to become true
+  x->mu0.LockWhen(absl::Condition(&ConditionWithAcquire, x));
+  x->done = true;
+  x->mu0.Unlock();
+}
+
+// Test for Condition whose function acquires other Mutexes
+TEST(Mutex, AcquireFromCondition) {
+  auto tp = CreateDefaultPool();
+
+  AcquireFromConditionStruct x;
+  x.value = 0;
+  x.done = false;
+  tp->Schedule(
+      std::bind(&WaitForCond2, &x));  // run WaitForCond2() in a thread T
+  // T will hang because the first invocation of ConditionWithAcquire() will
+  // return false.
+  absl::SleepFor(absl::Milliseconds(500));  // allow T time to hang
+
+  x.mu0.Lock();
+  x.cv.WaitWithTimeout(&x.mu0, absl::Milliseconds(500));  // wake T
+  // T will be woken because the Wait() will call ConditionWithAcquire()
+  // for the second time, and it will return true.
+
+  x.mu0.Unlock();
+
+  // T will then acquire the lock and recheck its own condition.
+  // It will find the condition true, as this is the third invocation,
+  // but the use of another Mutex by the calling function will
+  // cause the old mutex implementation to think that the outer
+  // LockWhen() has timed out because the inner LockWhenWithTimeout() did.
+  // T will then check the condition a fourth time because it finds a
+  // timeout occurred.  This should not happen in the new
+  // implementation that allows the Condition function to use Mutexes.
+
+  // It should also succeed, even though the Condition function
+  // is being invoked from CondVar::Wait, and thus this thread
+  // is conceptually waiting both on the condition variable, and on mu2.
+
+  x.mu0.LockWhen(absl::Condition(&x.done));
+  x.mu0.Unlock();
+}
+
+// The deadlock detector is not part of non-prod builds, so do not test it.
+#if !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
+
+TEST(Mutex, DeadlockDetector) {
+  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+
+  // check that we can call ForgetDeadlockInfo() on a lock with the lock held
+  absl::Mutex m1;
+  absl::Mutex m2;
+  absl::Mutex m3;
+  absl::Mutex m4;
+
+  m1.Lock();  // m1 gets ID1
+  m2.Lock();  // m2 gets ID2
+  m3.Lock();  // m3 gets ID3
+  m3.Unlock();
+  m2.Unlock();
+  // m1 still held
+  m1.ForgetDeadlockInfo();  // m1 loses ID
+  m2.Lock();                // m2 gets ID2
+  m3.Lock();                // m3 gets ID3
+  m4.Lock();                // m4 gets ID4
+  m3.Unlock();
+  m2.Unlock();
+  m4.Unlock();
+  m1.Unlock();
+}
+
+// Bazel has a test "warning" file that programs can write to if the
+// test should pass with a warning.  This class disables the warning
+// file until it goes out of scope.
+class ScopedDisableBazelTestWarnings {
+ public:
+  ScopedDisableBazelTestWarnings() {
+#ifdef WIN32
+    char file[MAX_PATH];
+    if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) {
+      warnings_output_file_ = file;
+      SetEnvironmentVariable(kVarName, nullptr);
+    }
+#else
+    const char *file = getenv(kVarName);
+    if (file != nullptr) {
+      warnings_output_file_ = file;
+      unsetenv(kVarName);
+    }
+#endif
+  }
+
+  ~ScopedDisableBazelTestWarnings() {
+    if (!warnings_output_file_.empty()) {
+#ifdef WIN32
+      SetEnvironmentVariable(kVarName, warnings_output_file_.c_str());
+#else
+      setenv(kVarName, warnings_output_file_.c_str(), 0);
+#endif
+    }
+  }
+
+ private:
+  static const char kVarName[];
+  std::string warnings_output_file_;
+};
+const char ScopedDisableBazelTestWarnings::kVarName[] =
+    "TEST_WARNINGS_OUTPUT_FILE";
+
+TEST(Mutex, DeadlockDetectorBazelWarning) {
+  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport);
+
+  // Cause deadlock detection to detect something, if it's
+  // compiled in and enabled.  But turn off the bazel warning.
+  ScopedDisableBazelTestWarnings disable_bazel_test_warnings;
+
+  absl::Mutex mu0;
+  absl::Mutex mu1;
+  bool got_mu0 = mu0.TryLock();
+  mu1.Lock();  // acquire mu1 while holding mu0
+  if (got_mu0) {
+    mu0.Unlock();
+  }
+  if (mu0.TryLock()) {  // try lock shouldn't cause deadlock detector to fire
+    mu0.Unlock();
+  }
+  mu0.Lock();  // acquire mu0 while holding mu1; should get one deadlock
+               // report here
+  mu0.Unlock();
+  mu1.Unlock();
+
+  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+}
+
+// This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the
+// annotation-based static thread-safety analysis is not currently
+// predicate-aware and cannot tell if the two for-loops that acquire and
+// release the locks have the same predicates.
+TEST(Mutex, DeadlockDetectorStessTest) NO_THREAD_SAFETY_ANALYSIS {
+  // Stress test: Here we create a large number of locks and use all of them.
+  // If a deadlock detector keeps a full graph of lock acquisition order,
+  // it will likely be too slow for this test to pass.
+  const int n_locks = 1 << 17;
+  auto array_of_locks = absl::make_unique<absl::Mutex[]>(n_locks);
+  for (int i = 0; i < n_locks; i++) {
+    int end = std::min(n_locks, i + 5);
+    // acquire and then release locks i, i+1, ..., i+4
+    for (int j = i; j < end; j++) {
+      array_of_locks[j].Lock();
+    }
+    for (int j = i; j < end; j++) {
+      array_of_locks[j].Unlock();
+    }
+  }
+}
+
+TEST(Mutex, DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+  // Test a scenario where a cached deadlock graph node id in the
+  // list of held locks is not invalidated when the corresponding
+  // mutex is deleted.
+  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+  // Mutex that will be destroyed while being held
+  absl::Mutex *a = new absl::Mutex;
+  // Other mutexes needed by test
+  absl::Mutex b, c;
+
+  // Hold mutex.
+  a->Lock();
+
+  // Force deadlock id assignment by acquiring another lock.
+  b.Lock();
+  b.Unlock();
+
+  // Delete the mutex. The Mutex destructor tries to remove held locks,
+  // but the attempt isn't foolproof.  It can fail if:
+  //   (a) Deadlock detection is currently disabled.
+  //   (b) The destruction is from another thread.
+  // We exploit (a) by temporarily disabling deadlock detection.
+  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore);
+  delete a;
+  absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+
+  // Now acquire another lock which will force a deadlock id assignment.
+  // We should end up getting assigned the same deadlock id that was
+  // freed up when "a" was deleted, which will cause a spurious deadlock
+  // report if the held lock entry for "a" was not invalidated.
+  c.Lock();
+  c.Unlock();
+}
+#endif  // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
+
+// --------------------------------------------------------
+// Test for timeouts/deadlines on condition waits that are specified using
+// absl::Duration and absl::Time.  For each waiting function we test with
+// a timeout/deadline that has already expired/passed, one that is infinite
+// and so never expires/passes, and one that will expire/pass in the near
+// future.
+
+// Encapsulate a Mutex-protected bool with its associated Condition/CondVar.
+class Cond {
+ public:
+  explicit Cond(bool use_deadline) : use_deadline_(use_deadline), c_(&b_) {}
+
+  void Set(bool v) {
+    absl::MutexLock lock(&mu_);
+    b_ = v;
+  }
+
+  bool AwaitWithTimeout(absl::Duration timeout) {
+    absl::MutexLock lock(&mu_);
+    return use_deadline_ ? mu_.AwaitWithDeadline(c_, absl::Now() + timeout)
+                         : mu_.AwaitWithTimeout(c_, timeout);
+  }
+
+  bool LockWhenWithTimeout(absl::Duration timeout) {
+    bool b = use_deadline_ ? mu_.LockWhenWithDeadline(c_, absl::Now() + timeout)
+                           : mu_.LockWhenWithTimeout(c_, timeout);
+    mu_.Unlock();
+    return b;
+  }
+
+  bool ReaderLockWhenWithTimeout(absl::Duration timeout) {
+    bool b = use_deadline_
+                 ? mu_.ReaderLockWhenWithDeadline(c_, absl::Now() + timeout)
+                 : mu_.ReaderLockWhenWithTimeout(c_, timeout);
+    mu_.ReaderUnlock();
+    return b;
+  }
+
+  void Await() {
+    absl::MutexLock lock(&mu_);
+    mu_.Await(c_);
+  }
+
+  void Signal(bool v) {
+    absl::MutexLock lock(&mu_);
+    b_ = v;
+    cv_.Signal();
+  }
+
+  bool WaitWithTimeout(absl::Duration timeout) {
+    absl::MutexLock lock(&mu_);
+    absl::Time deadline = absl::Now() + timeout;
+    if (use_deadline_) {
+      while (!b_ && !cv_.WaitWithDeadline(&mu_, deadline)) {
+      }
+    } else {
+      while (!b_ && !cv_.WaitWithTimeout(&mu_, timeout)) {
+        timeout = deadline - absl::Now();  // recompute timeout
+      }
+    }
+    return b_;
+  }
+
+  void Wait() {
+    absl::MutexLock lock(&mu_);
+    while (!b_) cv_.Wait(&mu_);
+  }
+
+ private:
+  const bool use_deadline_;
+
+  bool b_;
+  absl::Condition c_;
+  absl::CondVar cv_;
+  absl::Mutex mu_;
+};
+
+class OperationTimer {
+ public:
+  OperationTimer() : start_(absl::Now()) {}
+  absl::Duration Get() const { return absl::Now() - start_; }
+
+ private:
+  const absl::Time start_;
+};
+
+static void CheckResults(bool exp_result, bool act_result,
+                         absl::Duration exp_duration,
+                         absl::Duration act_duration) {
+  ABSL_RAW_CHECK(exp_result == act_result, "CheckResults failed");
+  // Allow for some worse-case scheduling delay and clock skew.
+  if ((exp_duration - absl::Milliseconds(40) > act_duration) ||
+      (exp_duration + absl::Milliseconds(150) < act_duration)) {
+    ABSL_RAW_LOG(FATAL, "CheckResults failed: operation took %s, expected %s",
+                 absl::FormatDuration(act_duration).c_str(),
+                 absl::FormatDuration(exp_duration).c_str());
+  }
+}
+
+static void TestAwaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,
+                             absl::Duration exp_duration) {
+  OperationTimer t;
+  bool act_result = cp->AwaitWithTimeout(timeout);
+  CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+static void TestLockWhenTimeout(Cond *cp, absl::Duration timeout,
+                                bool exp_result, absl::Duration exp_duration) {
+  OperationTimer t;
+  bool act_result = cp->LockWhenWithTimeout(timeout);
+  CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+static void TestReaderLockWhenTimeout(Cond *cp, absl::Duration timeout,
+                                      bool exp_result,
+                                      absl::Duration exp_duration) {
+  OperationTimer t;
+  bool act_result = cp->ReaderLockWhenWithTimeout(timeout);
+  CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+static void TestWaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,
+                            absl::Duration exp_duration) {
+  OperationTimer t;
+  bool act_result = cp->WaitWithTimeout(timeout);
+  CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+// Tests with a negative timeout (deadline in the past), which should
+// immediately return the current state of the condition.
+static void TestNegativeTimeouts(absl::synchronization_internal::ThreadPool *tp,
+                                 Cond *cp) {
+  const absl::Duration negative = -absl::InfiniteDuration();
+  const absl::Duration immediate = absl::ZeroDuration();
+
+  // The condition is already true:
+  cp->Set(true);
+  TestAwaitTimeout(cp, negative, true, immediate);
+  TestLockWhenTimeout(cp, negative, true, immediate);
+  TestReaderLockWhenTimeout(cp, negative, true, immediate);
+  TestWaitTimeout(cp, negative, true, immediate);
+
+  // The condition becomes true, but the timeout has already expired:
+  const absl::Duration delay = absl::Milliseconds(200);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay);
+  TestAwaitTimeout(cp, negative, false, immediate);
+  TestLockWhenTimeout(cp, negative, false, immediate);
+  TestReaderLockWhenTimeout(cp, negative, false, immediate);
+  cp->Await();  // wait for the scheduled Set() to complete
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);
+  TestWaitTimeout(cp, negative, false, immediate);
+  cp->Wait();  // wait for the scheduled Signal() to complete
+
+  // The condition never becomes true:
+  cp->Set(false);
+  TestAwaitTimeout(cp, negative, false, immediate);
+  TestLockWhenTimeout(cp, negative, false, immediate);
+  TestReaderLockWhenTimeout(cp, negative, false, immediate);
+  TestWaitTimeout(cp, negative, false, immediate);
+}
+
+// Tests with an infinite timeout (deadline in the infinite future), which
+// should only return when the condition becomes true.
+static void TestInfiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,
+                                 Cond *cp) {
+  const absl::Duration infinite = absl::InfiniteDuration();
+  const absl::Duration immediate = absl::ZeroDuration();
+
+  // The condition is already true:
+  cp->Set(true);
+  TestAwaitTimeout(cp, infinite, true, immediate);
+  TestLockWhenTimeout(cp, infinite, true, immediate);
+  TestReaderLockWhenTimeout(cp, infinite, true, immediate);
+  TestWaitTimeout(cp, infinite, true, immediate);
+
+  // The condition becomes true before the (infinite) expiry:
+  const absl::Duration delay = absl::Milliseconds(200);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
+  TestAwaitTimeout(cp, infinite, true, delay);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
+  TestLockWhenTimeout(cp, infinite, true, delay);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
+  TestReaderLockWhenTimeout(cp, infinite, true, delay);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);
+  TestWaitTimeout(cp, infinite, true, delay);
+}
+
+// Tests with a (small) finite timeout (deadline soon), with the condition
+// becoming true both before and after its expiry.
+static void TestFiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,
+                               Cond *cp) {
+  const absl::Duration finite = absl::Milliseconds(400);
+  const absl::Duration immediate = absl::ZeroDuration();
+
+  // The condition is already true:
+  cp->Set(true);
+  TestAwaitTimeout(cp, finite, true, immediate);
+  TestLockWhenTimeout(cp, finite, true, immediate);
+  TestReaderLockWhenTimeout(cp, finite, true, immediate);
+  TestWaitTimeout(cp, finite, true, immediate);
+
+  // The condition becomes true before the expiry:
+  const absl::Duration delay1 = finite / 2;
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
+  TestAwaitTimeout(cp, finite, true, delay1);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
+  TestLockWhenTimeout(cp, finite, true, delay1);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
+  TestReaderLockWhenTimeout(cp, finite, true, delay1);
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay1);
+  TestWaitTimeout(cp, finite, true, delay1);
+
+  // The condition becomes true, but the timeout has already expired:
+  const absl::Duration delay2 = finite * 2;
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay2);
+  TestAwaitTimeout(cp, finite, false, finite);
+  TestLockWhenTimeout(cp, finite, false, finite);
+  TestReaderLockWhenTimeout(cp, finite, false, finite);
+  cp->Await();  // wait for the scheduled Set() to complete
+  cp->Set(false);
+  ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay2);
+  TestWaitTimeout(cp, finite, false, finite);
+  cp->Wait();  // wait for the scheduled Signal() to complete
+
+  // The condition never becomes true:
+  cp->Set(false);
+  TestAwaitTimeout(cp, finite, false, finite);
+  TestLockWhenTimeout(cp, finite, false, finite);
+  TestReaderLockWhenTimeout(cp, finite, false, finite);
+  TestWaitTimeout(cp, finite, false, finite);
+}
+
+TEST(Mutex, Timeouts) {
+  auto tp = CreateDefaultPool();
+  for (bool use_deadline : {false, true}) {
+    Cond cond(use_deadline);
+    TestNegativeTimeouts(tp.get(), &cond);
+    TestInfiniteTimeouts(tp.get(), &cond);
+    TestFiniteTimeouts(tp.get(), &cond);
+  }
+}
+
+TEST(Mutex, Logging) {
+  // Allow user to look at logging output
+  absl::Mutex logged_mutex;
+  logged_mutex.EnableDebugLog("fido_mutex");
+  absl::CondVar logged_cv;
+  logged_cv.EnableDebugLog("rover_cv");
+  logged_mutex.Lock();
+  logged_cv.WaitWithTimeout(&logged_mutex, absl::Milliseconds(20));
+  logged_mutex.Unlock();
+  logged_mutex.ReaderLock();
+  logged_mutex.ReaderUnlock();
+  logged_mutex.Lock();
+  logged_mutex.Unlock();
+  logged_cv.Signal();
+  logged_cv.SignalAll();
+}
+
+// --------------------------------------------------------
+
+// Generate the vector of thread counts for tests parameterized on thread count.
+static std::vector<int> AllThreadCountValues() {
+  if (kExtendedTest) {
+    return {2, 4, 8, 10, 16, 20, 24, 30, 32};
+  }
+  return {2, 4, 10};
+}
+
+// A test fixture parameterized by thread count.
+class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {};
+
+// Instantiate the above with AllThreadCountOptions().
+INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest,
+                        ::testing::ValuesIn(AllThreadCountValues()),
+                        ::testing::PrintToStringParamName());
+
+// Reduces iterations by some factor for slow platforms
+// (determined empirically).
+static int ScaleIterations(int x) {
+  // ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE is set in the implementation
+  // of Mutex that uses either std::mutex or pthread_mutex_t. Use
+  // these as keys to determine the slow implementation.
+#if defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
+  return x / 10;
+#else
+  return x;
+#endif
+}
+
+TEST_P(MutexVariableThreadCountTest, Mutex) {
+  int threads = GetParam();
+  int iterations = ScaleIterations(10000000) / threads;
+  int operations = threads * iterations;
+  EXPECT_EQ(RunTest(&TestMu, threads, iterations, operations), operations);
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+  iterations = std::min(iterations, 10);
+  operations = threads * iterations;
+  EXPECT_EQ(RunTestWithInvariantDebugging(&TestMu, threads, iterations,
+                                          operations, CheckSumG0G1),
+            operations);
+#endif
+}
+
+TEST_P(MutexVariableThreadCountTest, Try) {
+  int threads = GetParam();
+  int iterations = 1000000 / threads;
+  int operations = iterations * threads;
+  EXPECT_EQ(RunTest(&TestTry, threads, iterations, operations), operations);
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+  iterations = std::min(iterations, 10);
+  operations = threads * iterations;
+  EXPECT_EQ(RunTestWithInvariantDebugging(&TestTry, threads, iterations,
+                                          operations, CheckSumG0G1),
+            operations);
+#endif
+}
+
+TEST_P(MutexVariableThreadCountTest, R20ms) {
+  int threads = GetParam();
+  int iterations = 100;
+  int operations = iterations * threads;
+  EXPECT_EQ(RunTest(&TestR20ms, threads, iterations, operations), 0);
+}
+
+TEST_P(MutexVariableThreadCountTest, RW) {
+  int threads = GetParam();
+  int iterations = ScaleIterations(20000000) / threads;
+  int operations = iterations * threads;
+  EXPECT_EQ(RunTest(&TestRW, threads, iterations, operations), operations / 2);
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+  iterations = std::min(iterations, 10);
+  operations = threads * iterations;
+  EXPECT_EQ(RunTestWithInvariantDebugging(&TestRW, threads, iterations,
+                                          operations, CheckSumG0G1),
+            operations / 2);
+#endif
+}
+
+TEST_P(MutexVariableThreadCountTest, Await) {
+  int threads = GetParam();
+  int iterations = ScaleIterations(500000);
+  int operations = iterations;
+  EXPECT_EQ(RunTest(&TestAwait, threads, iterations, operations), operations);
+}
+
+TEST_P(MutexVariableThreadCountTest, SignalAll) {
+  int threads = GetParam();
+  int iterations = 200000 / threads;
+  int operations = iterations;
+  EXPECT_EQ(RunTest(&TestSignalAll, threads, iterations, operations),
+            operations);
+}
+
+TEST(Mutex, Signal) {
+  int threads = 2;  // TestSignal must use two threads
+  int iterations = 200000;
+  int operations = iterations;
+  EXPECT_EQ(RunTest(&TestSignal, threads, iterations, operations), operations);
+}
+
+TEST(Mutex, Timed) {
+  int threads = 10;  // Use a fixed thread count of 10
+  int iterations = 1000;
+  int operations = iterations;
+  EXPECT_EQ(RunTest(&TestCVTimeout, threads, iterations, operations),
+            operations);
+}
+
+TEST(Mutex, CVTime) {
+  int threads = 10;  // Use a fixed thread count of 10
+  int iterations = 1;
+  EXPECT_EQ(RunTest(&TestCVTime, threads, iterations, 1),
+            threads * iterations);
+}
+
+TEST(Mutex, MuTime) {
+  int threads = 10;  // Use a fixed thread count of 10
+  int iterations = 1;
+  EXPECT_EQ(RunTest(&TestMuTime, threads, iterations, 1), threads * iterations);
+}
+
+}  // namespace
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
new file mode 100644
index 0000000..ed8cc90
--- /dev/null
+++ b/absl/synchronization/notification.cc
@@ -0,0 +1,84 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/notification.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
+
+namespace absl {
+void Notification::Notify() {
+  MutexLock l(&this->mutex_);
+
+#ifndef NDEBUG
+  if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) {
+    ABSL_RAW_LOG(
+        FATAL,
+        "Notify() method called more than once for Notification object %p",
+        static_cast<void *>(this));
+  }
+#endif
+
+  notified_yet_.store(true, std::memory_order_release);
+}
+
+Notification::~Notification() {
+  // Make sure that the thread running Notify() exits before the object is
+  // destructed.
+  MutexLock l(&this->mutex_);
+}
+
+static inline bool HasBeenNotifiedInternal(
+    const std::atomic<bool> *notified_yet) {
+  return notified_yet->load(std::memory_order_acquire);
+}
+
+bool Notification::HasBeenNotified() const {
+  return HasBeenNotifiedInternal(&this->notified_yet_);
+}
+
+void Notification::WaitForNotification() const {
+  if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
+    this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal,
+                                    &this->notified_yet_));
+    this->mutex_.Unlock();
+  }
+}
+
+bool Notification::WaitForNotificationWithTimeout(
+    absl::Duration timeout) const {
+  bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
+  if (!notified) {
+    notified = this->mutex_.LockWhenWithTimeout(
+        Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
+    this->mutex_.Unlock();
+  }
+  return notified;
+}
+
+bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
+  bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
+  if (!notified) {
+    notified = this->mutex_.LockWhenWithDeadline(
+        Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
+    this->mutex_.Unlock();
+  }
+  return notified;
+}
+
+}  // namespace absl
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
new file mode 100644
index 0000000..107932f
--- /dev/null
+++ b/absl/synchronization/notification.h
@@ -0,0 +1,112 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// notification.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Notification` abstraction, which allows threads
+// to receive notification of a single occurrence of a single event.
+//
+// The `Notification` object maintains a private boolean "notified" state that
+// transitions to `true` at most once. The `Notification` class provides the
+// following primary member functions:
+//   * `HasBeenNotified() `to query its state
+//   * `WaitForNotification*()` to have threads wait until the "notified" state
+//      is `true`.
+//   * `Notify()` to set the notification's "notified" state to `true` and
+//     notify all waiting threads that the event has occurred.
+//     This method may only be called once.
+//
+// Note that while `Notify()` may only be called once, it is perfectly valid to
+// call any of the `WaitForNotification*()` methods multiple times, from
+// multiple threads -- even after the notification's "notified" state has been
+// set -- in which case those methods will immediately return.
+//
+// Note that the lifetime of a `Notification` requires careful consideration;
+// it might not be safe to destroy a notification after calling `Notify()` since
+// it is still legal for other threads to call `WaitForNotification*()` methods
+// on the notification. However, observers responding to a "notified" state of
+// `true` can safely delete the notification without interfering with the call
+// to `Notify()` in the other thread.
+//
+// Memory ordering: For any threads X and Y, if X calls `Notify()`, then any
+// action taken by X before it calls `Notify()` is visible to thread Y after:
+//  * Y returns from `WaitForNotification()`, or
+//  * Y receives a `true` return value from either `HasBeenNotified()` or
+//    `WaitForNotificationWithTimeout()`.
+
+#ifndef ABSL_SYNCHRONIZATION_NOTIFICATION_H_
+#define ABSL_SYNCHRONIZATION_NOTIFICATION_H_
+
+#include <atomic>
+
+#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Notification
+// -----------------------------------------------------------------------------
+class Notification {
+ public:
+  // Initializes the "notified" state to unnotified.
+  Notification() : notified_yet_(false) {}
+  explicit Notification(bool prenotify) : notified_yet_(prenotify) {}
+  Notification(const Notification&) = delete;
+  Notification& operator=(const Notification&) = delete;
+  ~Notification();
+
+  // Notification::HasBeenNotified()
+  //
+  // Returns the value of the notification's internal "notified" state.
+  bool HasBeenNotified() const;
+
+  // Notification::WaitForNotification()
+  //
+  // Blocks the calling thread until the notification's "notified" state is
+  // `true`. Note that if `Notify()` has been previously called on this
+  // notification, this function will immediately return.
+  void WaitForNotification() const;
+
+  // Notification::WaitForNotificationWithTimeout()
+  //
+  // Blocks until either the notification's "notified" state is `true` (which
+  // may occur immediately) or the timeout has elapsed, returning the value of
+  // its "notified" state in either case.
+  bool WaitForNotificationWithTimeout(absl::Duration timeout) const;
+
+  // Notification::WaitForNotificationWithDeadline()
+  //
+  // Blocks until either the notification's "notified" state is `true` (which
+  // may occur immediately) or the deadline has expired, returning the value of
+  // its "notified" state in either case.
+  bool WaitForNotificationWithDeadline(absl::Time deadline) const;
+
+  // Notification::Notify()
+  //
+  // Sets the "notified" state of this notification to `true` and wakes waiting
+  // threads. Note: do not call `Notify()` multiple times on the same
+  // `Notification`; calling `Notify()` more than once on the same notification
+  // results in undefined behavior.
+  void Notify();
+
+ private:
+  mutable Mutex mutex_;
+  std::atomic<bool> notified_yet_;  // written under mutex_
+};
+
+}  // namespace absl
+#endif  // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc
new file mode 100644
index 0000000..9b3b6a5
--- /dev/null
+++ b/absl/synchronization/notification_test.cc
@@ -0,0 +1,124 @@
+// Copyright 2017 The Abseil 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 "absl/synchronization/notification.h"
+
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// A thread-safe class that holds a counter.
+class ThreadSafeCounter {
+ public:
+  ThreadSafeCounter() : count_(0) {}
+
+  void Increment() {
+    MutexLock lock(&mutex_);
+    ++count_;
+  }
+
+  int Get() const {
+    MutexLock lock(&mutex_);
+    return count_;
+  }
+
+  void WaitUntilGreaterOrEqual(int n) {
+    MutexLock lock(&mutex_);
+    auto cond = [this, n]() { return count_ >= n; };
+    mutex_.Await(Condition(&cond));
+  }
+
+ private:
+  mutable Mutex mutex_;
+  int count_;
+};
+
+// Runs the |i|'th worker thread for the tests in BasicTests().  Increments the
+// |ready_counter|, waits on the |notification|, and then increments the
+// |done_counter|.
+static void RunWorker(int i, ThreadSafeCounter* ready_counter,
+                      Notification* notification,
+                      ThreadSafeCounter* done_counter) {
+  ready_counter->Increment();
+  notification->WaitForNotification();
+  done_counter->Increment();
+}
+
+// Tests that the |notification| properly blocks and awakens threads.  Assumes
+// that the |notification| is not yet triggered.  If |notify_before_waiting| is
+// true, the |notification| is triggered before any threads are created, so the
+// threads never block in WaitForNotification().  Otherwise, the |notification|
+// is triggered at a later point when most threads are likely to be blocking in
+// WaitForNotification().
+static void BasicTests(bool notify_before_waiting, Notification* notification) {
+  EXPECT_FALSE(notification->HasBeenNotified());
+  EXPECT_FALSE(
+      notification->WaitForNotificationWithTimeout(absl::Milliseconds(0)));
+  EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
+
+  absl::Time start = absl::Now();
+  EXPECT_FALSE(
+      notification->WaitForNotificationWithTimeout(absl::Milliseconds(50)));
+  EXPECT_LE(start + absl::Milliseconds(50), absl::Now());
+
+  ThreadSafeCounter ready_counter;
+  ThreadSafeCounter done_counter;
+
+  if (notify_before_waiting) {
+    notification->Notify();
+  }
+
+  // Create a bunch of threads that increment the |done_counter| after being
+  // notified.
+  const int kNumThreads = 10;
+  std::vector<std::thread> workers;
+  for (int i = 0; i < kNumThreads; ++i) {
+    workers.push_back(std::thread(&RunWorker, i, &ready_counter, notification,
+                                  &done_counter));
+  }
+
+  if (!notify_before_waiting) {
+    ready_counter.WaitUntilGreaterOrEqual(kNumThreads);
+
+    // Workers have not been notified yet, so the |done_counter| should be
+    // unmodified.
+    EXPECT_EQ(0, done_counter.Get());
+
+    notification->Notify();
+  }
+
+  // After notifying and then joining the workers, both counters should be
+  // fully incremented.
+  notification->WaitForNotification();  // should exit immediately
+  EXPECT_TRUE(notification->HasBeenNotified());
+  EXPECT_TRUE(notification->WaitForNotificationWithTimeout(absl::Seconds(0)));
+  EXPECT_TRUE(notification->WaitForNotificationWithDeadline(absl::Now()));
+  for (std::thread& worker : workers) {
+    worker.join();
+  }
+  EXPECT_EQ(kNumThreads, ready_counter.Get());
+  EXPECT_EQ(kNumThreads, done_counter.Get());
+}
+
+TEST(NotificationTest, SanityTest) {
+  Notification local_notification1, local_notification2;
+  BasicTests(false, &local_notification1);
+  BasicTests(true, &local_notification2);
+}
+
+}  // namespace absl
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
new file mode 100644
index 0000000..e793da8
--- /dev/null
+++ b/absl/time/BUILD.bazel
@@ -0,0 +1,113 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "time",
+    srcs = [
+        "clock.cc",
+        "duration.cc",
+        "format.cc",
+        "internal/get_current_time_ios.inc",
+        "internal/get_current_time_posix.inc",
+        "internal/get_current_time_windows.inc",
+        "time.cc",
+    ],
+    hdrs = [
+        "clock.h",
+        "time.h",
+    ],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base",
+        "//absl/base:core_headers",
+        "//absl/numeric:int128",
+        "//absl/strings",
+        "//absl/time/internal/cctz:civil_time",
+        "//absl/time/internal/cctz:time_zone",
+    ],
+)
+
+cc_library(
+    name = "test_util",
+    testonly = 1,
+    srcs = [
+        "internal/test_util.cc",
+        "internal/zoneinfo.inc",
+    ],
+    hdrs = ["internal/test_util.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    visibility = [
+        "//absl/time:__pkg__",
+    ],
+    deps = [
+        ":time",
+        "//absl/base",
+        "//absl/time/internal/cctz:time_zone",
+        "@com_google_googletest//:gtest",
+    ],
+)
+
+cc_test(
+    name = "time_test",
+    srcs = [
+        "clock_test.cc",
+        "duration_test.cc",
+        "format_test.cc",
+        "time_norm_test.cc",
+        "time_test.cc",
+        "time_zone_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":test_util",
+        ":time",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/time/internal/cctz:time_zone",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "time_benchmark",
+    srcs = [
+        "clock_benchmark.cc",
+        "duration_benchmark.cc",
+        "format_benchmark.cc",
+        "time_benchmark.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    tags = [
+        "benchmark",
+    ],
+    deps = [
+        ":test_util",
+        ":time",
+        "//absl/base",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
diff --git a/absl/time/BUILD.gn b/absl/time/BUILD.gn
new file mode 100644
index 0000000..24de31c
--- /dev/null
+++ b/absl/time/BUILD.gn
@@ -0,0 +1,81 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+config("suppress_unguarded_availability") {
+  # TODO(bugs.webrtc.org/9557): Remove -Wno-unguarded-availability when
+  # abseil will support Xcode 9.0+ (it currently supports Xcode 7.3.1+
+  # which doesn't have -Wunguarded-availability and __builtin_available).
+  cflags = [
+    "-Wno-unguarded-availability",
+  ]
+}
+
+source_set("time") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+    ":suppress_unguarded_availability",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "clock.cc",
+    "duration.cc",
+    "format.cc",
+    "internal/get_current_time_ios.inc",
+    "internal/get_current_time_posix.inc",
+    "internal/get_current_time_windows.inc",
+    "time.cc",
+  ]
+  public = [
+    "clock.h",
+    "time.h",
+  ]
+  deps = [
+    "../base",
+    "../base:core_headers",
+    "../numeric:int128",
+    "../strings",
+    "../time/internal/cctz:civil_time",
+    "../time/internal/cctz:time_zone",
+  ]
+}
+
+source_set("test_util") {
+  testonly = true
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/test_util.cc",
+    "internal/zoneinfo.inc",
+  ]
+  public = [
+    "internal/test_util.h",
+  ]
+  deps = [
+    ":time",
+    "../base",
+    "../time/internal/cctz:time_zone",
+    "//testing/gtest",
+    "//testing/gmock",
+  ]
+  visibility = []
+  visibility += [ "../time:*" ]
+}
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
new file mode 100644
index 0000000..0627236
--- /dev/null
+++ b/absl/time/CMakeLists.txt
@@ -0,0 +1,96 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND TIME_PUBLIC_HEADERS
+  "clock.h"
+  "time.h"
+)
+
+
+list(APPEND TIME_INTERNAL_HEADERS
+  "internal/test_util.h"
+  "internal/cctz/include/cctz/civil_time.h"
+  "internal/cctz/include/cctz/civil_time_detail.h"
+  "internal/cctz/include/cctz/time_zone.h"
+  "internal/cctz/include/cctz/zone_info_source.h"
+)
+
+list(APPEND TIME_SRC
+  "time.cc"
+  "clock.cc"
+  "duration.cc"
+  "format.cc"
+  "internal/cctz/src/civil_time_detail.cc"
+  "internal/cctz/src/time_zone_fixed.cc"
+  "internal/cctz/src/time_zone_fixed.h"
+  "internal/cctz/src/time_zone_format.cc"
+  "internal/cctz/src/time_zone_if.cc"
+  "internal/cctz/src/time_zone_if.h"
+  "internal/cctz/src/time_zone_impl.cc"
+  "internal/cctz/src/time_zone_impl.h"
+  "internal/cctz/src/time_zone_info.cc"
+  "internal/cctz/src/time_zone_info.h"
+  "internal/cctz/src/time_zone_libc.cc"
+  "internal/cctz/src/time_zone_libc.h"
+  "internal/cctz/src/time_zone_lookup.cc"
+  "internal/cctz/src/time_zone_posix.cc"
+  "internal/cctz/src/time_zone_posix.h"
+  "internal/cctz/src/tzfile.h"
+  "internal/cctz/src/zone_info_source.cc"
+  ${TIME_PUBLIC_HEADERS}
+  ${TIME_INTERNAL_HEADERS}
+)
+set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 absl::strings)
+
+absl_library(
+  TARGET
+    absl_time
+  SOURCES
+    ${TIME_SRC}
+  PUBLIC_LIBRARIES
+    ${TIME_PUBLIC_LIBRARIES}
+  EXPORT_NAME
+    time
+)
+
+
+
+#
+## TESTS
+#
+
+# test time_test
+list(APPEND TIME_TEST_SRC
+  "time_test.cc"
+  "clock_test.cc"
+  "duration_test.cc"
+  "format_test.cc"
+  "time_norm_test.cc"
+  "time_test.cc"
+  "time_zone_test.cc"
+  "internal/test_util.cc"
+)
+set(TIME_TEST_PUBLIC_LIBRARIES absl::time)
+
+absl_test(
+  TARGET
+    time_test
+  SOURCES
+    ${TIME_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${TIME_TEST_PUBLIC_LIBRARIES}
+)
+
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
new file mode 100644
index 0000000..772f852
--- /dev/null
+++ b/absl/time/clock.cc
@@ -0,0 +1,563 @@
+// Copyright 2017 The Abseil 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 "absl/time/clock.h"
+
+#include "absl/base/attributes.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <cstdint>
+#include <ctime>
+#include <limits>
+
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/unscaledcycleclock.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+
+namespace absl {
+Time Now() {
+  // TODO(bww): Get a timespec instead so we don't have to divide.
+  int64_t n = absl::GetCurrentTimeNanos();
+  if (n >= 0) {
+    return time_internal::FromUnixDuration(
+        time_internal::MakeDuration(n / 1000000000, n % 1000000000 * 4));
+  }
+  return time_internal::FromUnixDuration(absl::Nanoseconds(n));
+}
+}  // namespace absl
+
+// Decide if we should use the fast GetCurrentTimeNanos() algorithm
+// based on the cyclecounter, otherwise just get the time directly
+// from the OS on every call. This can be chosen at compile-time via
+// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1]
+#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1
+#else
+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0
+#endif
+#endif
+
+#if defined(__APPLE__)
+#include "absl/time/internal/get_current_time_ios.inc"
+#elif defined(_WIN32)
+#include "absl/time/internal/get_current_time_windows.inc"
+#else
+#include "absl/time/internal/get_current_time_posix.inc"
+#endif
+
+// Allows override by test.
+#ifndef GET_CURRENT_TIME_NANOS_FROM_SYSTEM
+#define GET_CURRENT_TIME_NANOS_FROM_SYSTEM() \
+  ::absl::time_internal::GetCurrentTimeNanosFromSystem()
+#endif
+
+#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+namespace absl {
+int64_t GetCurrentTimeNanos() {
+  return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+}
+}  // namespace absl
+#else  // Use the cyclecounter-based implementation below.
+
+// Allows override by test.
+#ifndef GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW
+#define GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW() \
+  ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now()
+#endif
+
+// The following counters are used only by the test code.
+static int64_t stats_initializations;
+static int64_t stats_reinitializations;
+static int64_t stats_calibrations;
+static int64_t stats_slow_paths;
+static int64_t stats_fast_slow_paths;
+
+namespace absl {
+namespace time_internal {
+// This is a friend wrapper around UnscaledCycleClock::Now()
+// (needed to access UnscaledCycleClock).
+class UnscaledCycleClockWrapperForGetCurrentTime {
+ public:
+  static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
+};
+}  // namespace time_internal
+
+// uint64_t is used in this module to provide an extra bit in multiplications
+
+// Return the time in ns as told by the kernel interface.  Place in *cycleclock
+// the value of the cycleclock at about the time of the syscall.
+// This call represents the time base that this module synchronizes to.
+// Ensures that *cycleclock does not step back by up to (1 << 16) from
+// last_cycleclock, to discard small backward counter steps.  (Larger steps are
+// assumed to be complete resyncs, which shouldn't happen.  If they do, a full
+// reinitialization of the outer algorithm should occur.)
+static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
+                                             uint64_t *cycleclock) {
+  // We try to read clock values at about the same time as the kernel clock.
+  // This value gets adjusted up or down as estimate of how long that should
+  // take, so we can reject attempts that take unusually long.
+  static std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
+
+  uint64_t local_approx_syscall_time_in_cycles =  // local copy
+      approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
+
+  int64_t current_time_nanos_from_system;
+  uint64_t before_cycles;
+  uint64_t after_cycles;
+  uint64_t elapsed_cycles;
+  int loops = 0;
+  do {
+    before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+    after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    // elapsed_cycles is unsigned, so is large on overflow
+    elapsed_cycles = after_cycles - before_cycles;
+    if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
+        ++loops == 20) {  // clock changed frequencies?  Back off.
+      loops = 0;
+      if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
+        local_approx_syscall_time_in_cycles =
+            (local_approx_syscall_time_in_cycles + 1) << 1;
+      }
+      approx_syscall_time_in_cycles.store(
+          local_approx_syscall_time_in_cycles,
+          std::memory_order_relaxed);
+    }
+  } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
+           last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
+
+  // Number of times in a row we've seen a kernel time call take substantially
+  // less than approx_syscall_time_in_cycles.
+  static std::atomic<uint32_t> seen_smaller{ 0 };
+
+  // Adjust approx_syscall_time_in_cycles to be within a factor of 2
+  // of the typical time to execute one iteration of the loop above.
+  if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
+    // measured time is no smaller than half current approximation
+    seen_smaller.store(0, std::memory_order_relaxed);
+  } else if (seen_smaller.fetch_add(1, std::memory_order_relaxed) >= 3) {
+    // smaller delays several times in a row; reduce approximation by 12.5%
+    const uint64_t new_approximation =
+        local_approx_syscall_time_in_cycles -
+        (local_approx_syscall_time_in_cycles >> 3);
+    approx_syscall_time_in_cycles.store(new_approximation,
+                                        std::memory_order_relaxed);
+    seen_smaller.store(0, std::memory_order_relaxed);
+  }
+
+  *cycleclock = after_cycles;
+  return current_time_nanos_from_system;
+}
+
+
+// ---------------------------------------------------------------------
+// An implementation of reader-write locks that use no atomic ops in the read
+// case.  This is a generalization of Lamport's method for reading a multiword
+// clock.  Increment a word on each write acquisition, using the low-order bit
+// as a spinlock; the word is the high word of the "clock".  Readers read the
+// high word, then all other data, then the high word again, and repeat the
+// read if the reads of the high words yields different answers, or an odd
+// value (either case suggests possible interference from a writer).
+// Here we use a spinlock to ensure only one writer at a time, rather than
+// spinning on the bottom bit of the word to benefit from SpinLock
+// spin-delay tuning.
+
+// Acquire seqlock (*seq) and return the value to be written to unlock.
+static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) {
+  uint64_t x = seq->fetch_add(1, std::memory_order_relaxed);
+
+  // We put a release fence between update to *seq and writes to shared data.
+  // Thus all stores to shared data are effectively release operations and
+  // update to *seq above cannot be re-ordered past any of them.  Note that
+  // this barrier is not for the fetch_add above.  A release barrier for the
+  // fetch_add would be before it, not after.
+  std::atomic_thread_fence(std::memory_order_release);
+
+  return x + 2;   // original word plus 2
+}
+
+// Release seqlock (*seq) by writing x to it---a value previously returned by
+// SeqAcquire.
+static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) {
+  // The unlock store to *seq must have release ordering so that all
+  // updates to shared data must finish before this store.
+  seq->store(x, std::memory_order_release);  // release lock for readers
+}
+
+// ---------------------------------------------------------------------
+
+// "nsscaled" is unit of time equal to a (2**kScale)th of a nanosecond.
+enum { kScale = 30 };
+
+// The minimum interval between samples of the time base.
+// We pick enough time to amortize the cost of the sample,
+// to get a reasonably accurate cycle counter rate reading,
+// and not so much that calculations will overflow 64-bits.
+static const uint64_t kMinNSBetweenSamples = 2000 << 20;
+
+// We require that kMinNSBetweenSamples shifted by kScale
+// have at least a bit left over for 64-bit calculations.
+static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) ==
+               kMinNSBetweenSamples,
+               "cannot represent kMaxBetweenSamplesNSScaled");
+
+// A reader-writer lock protecting the static locations below.
+// See SeqAcquire() and SeqRelease() above.
+static absl::base_internal::SpinLock lock(
+    absl::base_internal::kLinkerInitialized);
+static std::atomic<uint64_t> seq(0);
+
+// data from a sample of the kernel's time value
+struct TimeSampleAtomic {
+  std::atomic<uint64_t> raw_ns;              // raw kernel time
+  std::atomic<uint64_t> base_ns;             // our estimate of time
+  std::atomic<uint64_t> base_cycles;         // cycle counter reading
+  std::atomic<uint64_t> nsscaled_per_cycle;  // cycle period
+  // cycles before we'll sample again (a scaled reciprocal of the period,
+  // to avoid a division on the fast path).
+  std::atomic<uint64_t> min_cycles_per_sample;
+};
+// Same again, but with non-atomic types
+struct TimeSample {
+  uint64_t raw_ns;                 // raw kernel time
+  uint64_t base_ns;                // our estimate of time
+  uint64_t base_cycles;            // cycle counter reading
+  uint64_t nsscaled_per_cycle;     // cycle period
+  uint64_t min_cycles_per_sample;  // approx cycles before next sample
+};
+
+static struct TimeSampleAtomic last_sample;   // the last sample; under seq
+
+static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD;
+
+// Read the contents of *atomic into *sample.
+// Each field is read atomically, but to maintain atomicity between fields,
+// the access must be done under a lock.
+static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic,
+                                 struct TimeSample *sample) {
+  sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed);
+  sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed);
+  sample->nsscaled_per_cycle =
+      atomic->nsscaled_per_cycle.load(std::memory_order_relaxed);
+  sample->min_cycles_per_sample =
+      atomic->min_cycles_per_sample.load(std::memory_order_relaxed);
+  sample->raw_ns = atomic->raw_ns.load(std::memory_order_relaxed);
+}
+
+// Public routine.
+// Algorithm:  We wish to compute real time from a cycle counter.  In normal
+// operation, we construct a piecewise linear approximation to the kernel time
+// source, using the cycle counter value.  The start of each line segment is at
+// the same point as the end of the last, but may have a different slope (that
+// is, a different idea of the cycle counter frequency).  Every couple of
+// seconds, the kernel time source is sampled and compared with the current
+// approximation.  A new slope is chosen that, if followed for another couple
+// of seconds, will correct the error at the current position.  The information
+// for a sample is in the "last_sample" struct.  The linear approximation is
+//   estimated_time = last_sample.base_ns +
+//     last_sample.ns_per_cycle * (counter_reading - last_sample.base_cycles)
+// (ns_per_cycle is actually stored in different units and scaled, to avoid
+// overflow).  The base_ns of the next linear approximation is the
+// estimated_time using the last approximation; the base_cycles is the cycle
+// counter value at that time; the ns_per_cycle is the number of ns per cycle
+// measured since the last sample, but adjusted so that most of the difference
+// between the estimated_time and the kernel time will be corrected by the
+// estimated time to the next sample.  In normal operation, this algorithm
+// relies on:
+// - the cycle counter and kernel time rates not changing a lot in a few
+//   seconds.
+// - the client calling into the code often compared to a couple of seconds, so
+//   the time to the next correction can be estimated.
+// Any time ns_per_cycle is not known, a major error is detected, or the
+// assumption about frequent calls is violated, the implementation returns the
+// kernel time.  It records sufficient data that a linear approximation can
+// resume a little later.
+
+int64_t GetCurrentTimeNanos() {
+  // read the data from the "last_sample" struct (but don't need raw_ns yet)
+  // The reads of "seq" and test of the values emulate a reader lock.
+  uint64_t base_ns;
+  uint64_t base_cycles;
+  uint64_t nsscaled_per_cycle;
+  uint64_t min_cycles_per_sample;
+  uint64_t seq_read0;
+  uint64_t seq_read1;
+
+  // If we have enough information to interpolate, the value returned will be
+  // derived from this cycleclock-derived time estimate.  On some platforms
+  // (POWER) the function to retrieve this value has enough complexity to
+  // contribute to register pressure - reading it early before initializing
+  // the other pieces of the calculation minimizes spill/restore instructions,
+  // minimizing icache cost.
+  uint64_t now_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+
+  // Acquire pairs with the barrier in SeqRelease - if this load sees that
+  // store, the shared-data reads necessarily see that SeqRelease's updates
+  // to the same shared data.
+  seq_read0 = seq.load(std::memory_order_acquire);
+
+  base_ns = last_sample.base_ns.load(std::memory_order_relaxed);
+  base_cycles = last_sample.base_cycles.load(std::memory_order_relaxed);
+  nsscaled_per_cycle =
+      last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
+  min_cycles_per_sample =
+      last_sample.min_cycles_per_sample.load(std::memory_order_relaxed);
+
+  // This acquire fence pairs with the release fence in SeqAcquire.  Since it
+  // is sequenced between reads of shared data and seq_read1, the reads of
+  // shared data are effectively acquiring.
+  std::atomic_thread_fence(std::memory_order_acquire);
+
+  // The shared-data reads are effectively acquire ordered, and the
+  // shared-data writes are effectively release ordered. Therefore if our
+  // shared-data reads see any of a particular update's shared-data writes,
+  // seq_read1 is guaranteed to see that update's SeqAcquire.
+  seq_read1 = seq.load(std::memory_order_relaxed);
+
+  // Fast path.  Return if min_cycles_per_sample has not yet elapsed since the
+  // last sample, and we read a consistent sample.  The fast path activates
+  // only when min_cycles_per_sample is non-zero, which happens when we get an
+  // estimate for the cycle time.  The predicate will fail if now_cycles <
+  // base_cycles, or if some other thread is in the slow path.
+  //
+  // Since we now read now_cycles before base_ns, it is possible for now_cycles
+  // to be less than base_cycles (if we were interrupted between those loads and
+  // last_sample was updated). This is harmless, because delta_cycles will wrap
+  // and report a time much much bigger than min_cycles_per_sample. In that case
+  // we will take the slow path.
+  uint64_t delta_cycles = now_cycles - base_cycles;
+  if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 &&
+      delta_cycles < min_cycles_per_sample) {
+    return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale);
+  }
+  return GetCurrentTimeNanosSlowPath();
+}
+
+// Return (a << kScale)/b.
+// Zero is returned if b==0.   Scaling is performed internally to
+// preserve precision without overflow.
+static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) {
+  // Find maximum safe_shift so that
+  //  0 <= safe_shift <= kScale  and  (a << safe_shift) does not overflow.
+  int safe_shift = kScale;
+  while (((a << safe_shift) >> safe_shift) != a) {
+    safe_shift--;
+  }
+  uint64_t scaled_b = b >> (kScale - safe_shift);
+  uint64_t quotient = 0;
+  if (scaled_b != 0) {
+    quotient = (a << safe_shift) / scaled_b;
+  }
+  return quotient;
+}
+
+static uint64_t UpdateLastSample(
+    uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles,
+    const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD;
+
+// The slow path of GetCurrentTimeNanos().  This is taken while gathering
+// initial samples, when enough time has elapsed since the last sample, and if
+// any other thread is writing to last_sample.
+//
+// Manually mark this 'noinline' to minimize stack frame size of the fast
+// path.  Without this, sometimes a compiler may inline this big block of code
+// into the fast past.  That causes lots of register spills and reloads that
+// are unnecessary unless the slow path is taken.
+//
+// TODO(absl-team): Remove this attribute when our compiler is smart enough
+// to do the right thing.
+ABSL_ATTRIBUTE_NOINLINE
+static int64_t GetCurrentTimeNanosSlowPath() LOCKS_EXCLUDED(lock) {
+  // Serialize access to slow-path.  Fast-path readers are not blocked yet, and
+  // code below must not modify last_sample until the seqlock is acquired.
+  lock.Lock();
+
+  // Sample the kernel time base.  This is the definition of
+  // "now" if we take the slow path.
+  static uint64_t last_now_cycles;  // protected by lock
+  uint64_t now_cycles;
+  uint64_t now_ns = GetCurrentTimeNanosFromKernel(last_now_cycles, &now_cycles);
+  last_now_cycles = now_cycles;
+
+  uint64_t estimated_base_ns;
+
+  // ----------
+  // Read the "last_sample" values again; this time holding the write lock.
+  struct TimeSample sample;
+  ReadTimeSampleAtomic(&last_sample, &sample);
+
+  // ----------
+  // Try running the fast path again; another thread may have updated the
+  // sample between our run of the fast path and the sample we just read.
+  uint64_t delta_cycles = now_cycles - sample.base_cycles;
+  if (delta_cycles < sample.min_cycles_per_sample) {
+    // Another thread updated the sample.  This path does not take the seqlock
+    // so that blocked readers can make progress without blocking new readers.
+    estimated_base_ns = sample.base_ns +
+        ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
+    stats_fast_slow_paths++;
+  } else {
+    estimated_base_ns =
+        UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
+  }
+
+  lock.Unlock();
+
+  return estimated_base_ns;
+}
+
+// Main part of the algorithm.  Locks out readers, updates the approximation
+// using the new sample from the kernel, and stores the result in last_sample
+// for readers.  Returns the new estimated time.
+static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
+                                 uint64_t delta_cycles,
+                                 const struct TimeSample *sample)
+    EXCLUSIVE_LOCKS_REQUIRED(lock) {
+  uint64_t estimated_base_ns = now_ns;
+  uint64_t lock_value = SeqAcquire(&seq);  // acquire seqlock to block readers
+
+  // The 5s in the next if-statement limits the time for which we will trust
+  // the cycle counter and our last sample to give a reasonable result.
+  // Errors in the rate of the source clock can be multiplied by the ratio
+  // between this limit and kMinNSBetweenSamples.
+  if (sample->raw_ns == 0 ||  // no recent sample, or clock went backwards
+      sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns ||
+      now_ns < sample->raw_ns || now_cycles < sample->base_cycles) {
+    // record this sample, and forget any previously known slope.
+    last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
+    last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
+    last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
+    last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
+    stats_initializations++;
+  } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns &&
+             sample->base_cycles + 100 < now_cycles) {
+    // Enough time has passed to compute the cycle time.
+    if (sample->nsscaled_per_cycle != 0) {  // Have a cycle time estimate.
+      // Compute time from counter reading, but avoiding overflow
+      // delta_cycles may be larger than on the fast path.
+      uint64_t estimated_scaled_ns;
+      int s = -1;
+      do {
+        s++;
+        estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle;
+      } while (estimated_scaled_ns / sample->nsscaled_per_cycle !=
+               (delta_cycles >> s));
+      estimated_base_ns = sample->base_ns +
+                          (estimated_scaled_ns >> (kScale - s));
+    }
+
+    // Compute the assumed cycle time kMinNSBetweenSamples ns into the future
+    // assuming the cycle counter rate stays the same as the last interval.
+    uint64_t ns = now_ns - sample->raw_ns;
+    uint64_t measured_nsscaled_per_cycle = SafeDivideAndScale(ns, delta_cycles);
+
+    uint64_t assumed_next_sample_delta_cycles =
+        SafeDivideAndScale(kMinNSBetweenSamples, measured_nsscaled_per_cycle);
+
+    int64_t diff_ns = now_ns - estimated_base_ns;  // estimate low by this much
+
+    // We want to set nsscaled_per_cycle so that our estimate of the ns time
+    // at the assumed cycle time is the assumed ns time.
+    // That is, we want to set nsscaled_per_cycle so:
+    //  kMinNSBetweenSamples + diff_ns  ==
+    //  (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
+    // But we wish to damp oscillations, so instead correct only most
+    // of our current error, by solving:
+    //  kMinNSBetweenSamples + diff_ns - (diff_ns / 16) ==
+    //  (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
+    ns = kMinNSBetweenSamples + diff_ns - (diff_ns / 16);
+    uint64_t new_nsscaled_per_cycle =
+        SafeDivideAndScale(ns, assumed_next_sample_delta_cycles);
+    if (new_nsscaled_per_cycle != 0 &&
+        diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
+      // record the cycle time measurement
+      last_sample.nsscaled_per_cycle.store(
+          new_nsscaled_per_cycle, std::memory_order_relaxed);
+      uint64_t new_min_cycles_per_sample =
+          SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle);
+      last_sample.min_cycles_per_sample.store(
+          new_min_cycles_per_sample, std::memory_order_relaxed);
+      stats_calibrations++;
+    } else {  // something went wrong; forget the slope
+      last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
+      last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
+      estimated_base_ns = now_ns;
+      stats_reinitializations++;
+    }
+    last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
+    last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
+  } else {
+    // have a sample, but no slope; waiting for enough time for a calibration
+    stats_slow_paths++;
+  }
+
+  SeqRelease(&seq, lock_value);  // release the readers
+
+  return estimated_base_ns;
+}
+}  // namespace absl
+#endif  // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+
+namespace absl {
+namespace {
+
+// Returns the maximum duration that SleepOnce() can sleep for.
+constexpr absl::Duration MaxSleep() {
+#ifdef _WIN32
+  // Windows Sleep() takes unsigned long argument in milliseconds.
+  return absl::Milliseconds(
+      std::numeric_limits<unsigned long>::max());  // NOLINT(runtime/int)
+#else
+  return absl::Seconds(std::numeric_limits<time_t>::max());
+#endif
+}
+
+// Sleeps for the given duration.
+// REQUIRES: to_sleep <= MaxSleep().
+void SleepOnce(absl::Duration to_sleep) {
+#ifdef _WIN32
+  Sleep(to_sleep / absl::Milliseconds(1));
+#else
+  struct timespec sleep_time = absl::ToTimespec(to_sleep);
+  while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {
+    // Ignore signals and wait for the full interval to elapse.
+  }
+#endif
+}
+
+}  // namespace
+}  // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalSleepFor(absl::Duration duration) {
+  while (duration > absl::ZeroDuration()) {
+    absl::Duration to_sleep = std::min(duration, absl::MaxSleep());
+    absl::SleepOnce(to_sleep);
+    duration -= to_sleep;
+  }
+}
+
+}  // extern "C"
diff --git a/absl/time/clock.h b/absl/time/clock.h
new file mode 100644
index 0000000..3753d4e
--- /dev/null
+++ b/absl/time/clock.h
@@ -0,0 +1,72 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: clock.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for working with the system-wide
+// realtime clock. For descriptions of the main time abstractions used within
+// this header file, consult the time.h header file.
+#ifndef ABSL_TIME_CLOCK_H_
+#define ABSL_TIME_CLOCK_H_
+
+#include "absl/base/macros.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+// Now()
+//
+// Returns the current time, expressed as an `absl::Time` absolute time value.
+absl::Time Now();
+
+// GetCurrentTimeNanos()
+//
+// Returns the current time, expressed as a count of nanoseconds since the Unix
+// Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead
+// for all but the most performance-sensitive cases (i.e. when you are calling
+// this function hundreds of thousands of times per second).
+int64_t GetCurrentTimeNanos();
+
+// SleepFor()
+//
+// Sleeps for the specified duration, expressed as an `absl::Duration`.
+//
+// Notes:
+// * Signal interruptions will not reduce the sleep duration.
+// * Returns immediately when passed a nonpositive duration.
+void SleepFor(absl::Duration duration);
+
+}  // namespace absl
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void AbslInternalSleepFor(absl::Duration duration);
+}  // extern "C"
+
+inline void absl::SleepFor(absl::Duration duration) {
+  AbslInternalSleepFor(duration);
+}
+
+#endif  // ABSL_TIME_CLOCK_H_
diff --git a/absl/time/clock_benchmark.cc b/absl/time/clock_benchmark.cc
new file mode 100644
index 0000000..3d3cd9d
--- /dev/null
+++ b/absl/time/clock_benchmark.cc
@@ -0,0 +1,72 @@
+// Copyright 2018 The Abseil 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 "absl/time/clock.h"
+
+#if !defined(_WIN32)
+#include <sys/time.h>
+#endif  // _WIN32
+#include <cstdio>
+
+#include "absl/base/internal/cycleclock.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_Clock_Now_AbslTime(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Now());
+  }
+}
+BENCHMARK(BM_Clock_Now_AbslTime);
+
+void BM_Clock_Now_GetCurrentTimeNanos(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::GetCurrentTimeNanos());
+  }
+}
+BENCHMARK(BM_Clock_Now_GetCurrentTimeNanos);
+
+void BM_Clock_Now_AbslTime_ToUnixNanos(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToUnixNanos(absl::Now()));
+  }
+}
+BENCHMARK(BM_Clock_Now_AbslTime_ToUnixNanos);
+
+void BM_Clock_Now_CycleClock(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::base_internal::CycleClock::Now());
+  }
+}
+BENCHMARK(BM_Clock_Now_CycleClock);
+
+#if !defined(_WIN32)
+static void BM_Clock_Now_gettimeofday(benchmark::State& state) {
+  struct timeval tv;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(gettimeofday(&tv, nullptr));
+  }
+}
+BENCHMARK(BM_Clock_Now_gettimeofday);
+
+static void BM_Clock_Now_clock_gettime(benchmark::State& state) {
+  struct timespec ts;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(clock_gettime(CLOCK_REALTIME, &ts));
+  }
+}
+BENCHMARK(BM_Clock_Now_clock_gettime);
+#endif  // _WIN32
+
+}  // namespace
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc
new file mode 100644
index 0000000..f143c03
--- /dev/null
+++ b/absl/time/clock_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2017 The Abseil 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 "absl/time/clock.h"
+
+#include "absl/base/config.h"
+#if defined(ABSL_HAVE_ALARM)
+#include <signal.h>
+#include <unistd.h>
+#elif defined(__linux__) || defined(__APPLE__)
+#error all known Linux and Apple targets have alarm
+#endif
+
+#include "gtest/gtest.h"
+#include "absl/time/time.h"
+
+namespace {
+
+TEST(Time, Now) {
+  const absl::Time before = absl::FromUnixNanos(absl::GetCurrentTimeNanos());
+  const absl::Time now = absl::Now();
+  const absl::Time after = absl::FromUnixNanos(absl::GetCurrentTimeNanos());
+  EXPECT_GE(now, before);
+  EXPECT_GE(after, now);
+}
+
+TEST(SleepForTest, BasicSanity) {
+  absl::Duration sleep_time = absl::Milliseconds(2500);
+  absl::Time start = absl::Now();
+  absl::SleepFor(sleep_time);
+  absl::Time end = absl::Now();
+  EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
+  EXPECT_GE(sleep_time + absl::Milliseconds(200), end - start);
+}
+
+#ifdef ABSL_HAVE_ALARM
+// Helper for test SleepFor.
+bool alarm_handler_invoked = false;
+void AlarmHandler(int signo) {
+  ASSERT_EQ(signo, SIGALRM);
+  alarm_handler_invoked = true;
+}
+
+TEST(SleepForTest, AlarmSupport) {
+  alarm_handler_invoked = false;
+  sig_t old_alarm = signal(SIGALRM, AlarmHandler);
+  alarm(2);
+  absl::Duration sleep_time = absl::Milliseconds(3500);
+  absl::Time start = absl::Now();
+  absl::SleepFor(sleep_time);
+  absl::Time end = absl::Now();
+  EXPECT_TRUE(alarm_handler_invoked);
+  EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
+  EXPECT_GE(sleep_time + absl::Milliseconds(200), end - start);
+  signal(SIGALRM, old_alarm);
+}
+#endif  // ABSL_HAVE_ALARM
+
+}  // namespace
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
new file mode 100644
index 0000000..c13fa79
--- /dev/null
+++ b/absl/time/duration.cc
@@ -0,0 +1,907 @@
+// Copyright 2017 The Abseil 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 implementation of the absl::Duration class, which is declared in
+// //absl/time.h.  This class behaves like a numeric type; it has no public
+// methods and is used only through the operators defined here.
+//
+// Implementation notes:
+//
+// An absl::Duration is represented as
+//
+//   rep_hi_ : (int64_t)  Whole seconds
+//   rep_lo_ : (uint32_t) Fractions of a second
+//
+// The seconds value (rep_hi_) may be positive or negative as appropriate.
+// The fractional seconds (rep_lo_) is always a positive offset from rep_hi_.
+// The API for Duration guarantees at least nanosecond resolution, which
+// means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds.
+// However, to utilize more of the available 32 bits of space in rep_lo_,
+// we instead store quarters of a nanosecond in rep_lo_ resulting in a max
+// value of 4B - 1.  This allows us to correctly handle calculations like
+// 0.5 nanos + 0.5 nanos = 1 nano.  The following example shows the actual
+// Duration rep using quarters of a nanosecond.
+//
+//    2.5 sec = {rep_hi_=2,  rep_lo_=2000000000}  // lo = 4 * 500000000
+//   -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000}
+//
+// Infinite durations are represented as Durations with the rep_lo_ field set
+// to all 1s.
+//
+//   +InfiniteDuration:
+//     rep_hi_ : kint64max
+//     rep_lo_ : ~0U
+//
+//   -InfiniteDuration:
+//     rep_hi_ : kint64min
+//     rep_lo_ : ~0U
+//
+// Arithmetic overflows/underflows to +/- infinity and saturates.
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <functional>
+#include <limits>
+#include <string>
+
+#include "absl/base/casts.h"
+#include "absl/numeric/int128.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+namespace {
+
+using time_internal::kTicksPerNanosecond;
+using time_internal::kTicksPerSecond;
+
+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+
+// Can't use std::isinfinite() because it doesn't exist on windows.
+inline bool IsFinite(double d) {
+  return d != std::numeric_limits<double>::infinity() &&
+         d != -std::numeric_limits<double>::infinity();
+}
+
+// Can't use std::round() because it is only available in C++11.
+// Note that we ignore the possibility of floating-point over/underflow.
+template <typename Double>
+inline double Round(Double d) {
+  return d < 0 ? std::ceil(d - 0.5) : std::floor(d + 0.5);
+}
+
+// *sec may be positive or negative.  *ticks must be in the range
+// -kTicksPerSecond < *ticks < kTicksPerSecond.  If *ticks is negative it
+// will be normalized to a positive value by adjusting *sec accordingly.
+inline void NormalizeTicks(int64_t* sec, int64_t* ticks) {
+  if (*ticks < 0) {
+    --*sec;
+    *ticks += kTicksPerSecond;
+  }
+}
+
+// Makes a uint128 from the absolute value of the given scalar.
+inline uint128 MakeU128(int64_t a) {
+  uint128 u128 = 0;
+  if (a < 0) {
+    ++u128;
+    ++a;  // Makes it safe to negate 'a'
+    a = -a;
+  }
+  u128 += static_cast<uint64_t>(a);
+  return u128;
+}
+
+// Makes a uint128 count of ticks out of the absolute value of the Duration.
+inline uint128 MakeU128Ticks(Duration d) {
+  int64_t rep_hi = time_internal::GetRepHi(d);
+  uint32_t rep_lo = time_internal::GetRepLo(d);
+  if (rep_hi < 0) {
+    ++rep_hi;
+    rep_hi = -rep_hi;
+    rep_lo = kTicksPerSecond - rep_lo;
+  }
+  uint128 u128 = static_cast<uint64_t>(rep_hi);
+  u128 *= static_cast<uint64_t>(kTicksPerSecond);
+  u128 += rep_lo;
+  return u128;
+}
+
+// Breaks a uint128 of ticks into a Duration.
+inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) {
+  int64_t rep_hi;
+  uint32_t rep_lo;
+  const uint64_t h64 = Uint128High64(u128);
+  const uint64_t l64 = Uint128Low64(u128);
+  if (h64 == 0) {  // fastpath
+    const uint64_t hi = l64 / kTicksPerSecond;
+    rep_hi = static_cast<int64_t>(hi);
+    rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond);
+  } else {
+    // kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond).
+    // Any positive tick count whose high 64 bits are >= kMaxRepHi64
+    // is not representable as a Duration.  A negative tick count can
+    // have its high 64 bits == kMaxRepHi64 but only when the low 64
+    // bits are all zero, otherwise it is not representable either.
+    const uint64_t kMaxRepHi64 = 0x77359400UL;
+    if (h64 >= kMaxRepHi64) {
+      if (is_neg && h64 == kMaxRepHi64 && l64 == 0) {
+        // Avoid trying to represent -kint64min below.
+        return time_internal::MakeDuration(kint64min);
+      }
+      return is_neg ? -InfiniteDuration() : InfiniteDuration();
+    }
+    const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond);
+    const uint128 hi = u128 / kTicksPerSecond128;
+    rep_hi = static_cast<int64_t>(Uint128Low64(hi));
+    rep_lo =
+        static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128));
+  }
+  if (is_neg) {
+    rep_hi = -rep_hi;
+    if (rep_lo != 0) {
+      --rep_hi;
+      rep_lo = kTicksPerSecond - rep_lo;
+    }
+  }
+  return time_internal::MakeDuration(rep_hi, rep_lo);
+}
+
+// Convert between int64_t and uint64_t, preserving representation. This
+// allows us to do arithmetic in the unsigned domain, where overflow has
+// well-defined behavior. See operator+=() and operator-=().
+//
+// C99 7.20.1.1.1, as referenced by C++11 18.4.1.2, says, "The typedef
+// name intN_t designates a signed integer type with width N, no padding
+// bits, and a two's complement representation." So, we can convert to
+// and from the corresponding uint64_t value using a bit cast.
+inline uint64_t EncodeTwosComp(int64_t v) {
+  return absl::bit_cast<uint64_t>(v);
+}
+inline int64_t DecodeTwosComp(uint64_t v) { return absl::bit_cast<int64_t>(v); }
+
+// Note: The overflow detection in this function is done using greater/less *or
+// equal* because kint64max/min is too large to be represented exactly in a
+// double (which only has 53 bits of precision). In order to avoid assigning to
+// rep->hi a double value that is too large for an int64_t (and therefore is
+// undefined), we must consider computations that equal kint64max/min as a
+// double as overflow cases.
+inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) {
+  double c = a_hi + b_hi;
+  if (c >= kint64max) {
+    *d = InfiniteDuration();
+    return false;
+  }
+  if (c <= kint64min) {
+    *d = -InfiniteDuration();
+    return false;
+  }
+  *d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d));
+  return true;
+}
+
+// A functor that's similar to std::multiplies<T>, except this returns the max
+// T value instead of overflowing. This is only defined for uint128.
+template <typename Ignored>
+struct SafeMultiply {
+  uint128 operator()(uint128 a, uint128 b) const {
+    // b hi is always zero because it originated as an int64_t.
+    assert(Uint128High64(b) == 0);
+    // Fastpath to avoid the expensive overflow check with division.
+    if (Uint128High64(a) == 0) {
+      return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0)
+                 ? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b))
+                 : a * b;
+    }
+    return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b;
+  }
+};
+
+// Scales (i.e., multiplies or divides, depending on the Operation template)
+// the Duration d by the int64_t r.
+template <template <typename> class Operation>
+inline Duration ScaleFixed(Duration d, int64_t r) {
+  const uint128 a = MakeU128Ticks(d);
+  const uint128 b = MakeU128(r);
+  const uint128 q = Operation<uint128>()(a, b);
+  const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0);
+  return MakeDurationFromU128(q, is_neg);
+}
+
+// Scales (i.e., multiplies or divides, depending on the Operation template)
+// the Duration d by the double r.
+template <template <typename> class Operation>
+inline Duration ScaleDouble(Duration d, double r) {
+  Operation<double> op;
+  double hi_doub = op(time_internal::GetRepHi(d), r);
+  double lo_doub = op(time_internal::GetRepLo(d), r);
+
+  double hi_int = 0;
+  double hi_frac = std::modf(hi_doub, &hi_int);
+
+  // Moves hi's fractional bits to lo.
+  lo_doub /= kTicksPerSecond;
+  lo_doub += hi_frac;
+
+  double lo_int = 0;
+  double lo_frac = std::modf(lo_doub, &lo_int);
+
+  // Rolls lo into hi if necessary.
+  int64_t lo64 = Round(lo_frac * kTicksPerSecond);
+
+  Duration ans;
+  if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans;
+  int64_t hi64 = time_internal::GetRepHi(ans);
+  if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans;
+  hi64 = time_internal::GetRepHi(ans);
+  lo64 %= kTicksPerSecond;
+  NormalizeTicks(&hi64, &lo64);
+  return time_internal::MakeDuration(hi64, lo64);
+}
+
+// Tries to divide num by den as fast as possible by looking for common, easy
+// cases. If the division was done, the quotient is in *q and the remainder is
+// in *rem and true will be returned.
+inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q,
+                         Duration* rem) {
+  // Bail if num or den is an infinity.
+  if (time_internal::IsInfiniteDuration(num) ||
+      time_internal::IsInfiniteDuration(den))
+    return false;
+
+  int64_t num_hi = time_internal::GetRepHi(num);
+  uint32_t num_lo = time_internal::GetRepLo(num);
+  int64_t den_hi = time_internal::GetRepHi(den);
+  uint32_t den_lo = time_internal::GetRepLo(den);
+
+  if (den_hi == 0 && den_lo == kTicksPerNanosecond) {
+    // Dividing by 1ns
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) {
+      *q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond;
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) {
+    // Dividing by 100ns (common when converting to Universal time)
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) {
+      *q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond);
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) {
+    // Dividing by 1us
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) {
+      *q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond);
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) {
+    // Dividing by 1ms
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) {
+      *q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond);
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi > 0 && den_lo == 0) {
+    // Dividing by positive multiple of 1s
+    if (num_hi >= 0) {
+      if (den_hi == 1) {
+        *q = num_hi;
+        *rem = time_internal::MakeDuration(0, num_lo);
+        return true;
+      }
+      *q = num_hi / den_hi;
+      *rem = time_internal::MakeDuration(num_hi % den_hi, num_lo);
+      return true;
+    }
+    if (num_lo != 0) {
+      num_hi += 1;
+    }
+    int64_t quotient = num_hi / den_hi;
+    int64_t rem_sec = num_hi % den_hi;
+    if (rem_sec > 0) {
+      rem_sec -= den_hi;
+      quotient += 1;
+    }
+    if (num_lo != 0) {
+      rem_sec -= 1;
+    }
+    *q = quotient;
+    *rem = time_internal::MakeDuration(rem_sec, num_lo);
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+namespace time_internal {
+
+// The 'satq' argument indicates whether the quotient should saturate at the
+// bounds of int64_t.  If it does saturate, the difference will spill over to
+// the remainder.  If it does not saturate, the remainder remain accurate,
+// but the returned quotient will over/underflow int64_t and should not be used.
+int64_t IDivDuration(bool satq, const Duration num, const Duration den,
+                   Duration* rem) {
+  int64_t q = 0;
+  if (IDivFastPath(num, den, &q, rem)) {
+    return q;
+  }
+
+  const bool num_neg = num < ZeroDuration();
+  const bool den_neg = den < ZeroDuration();
+  const bool quotient_neg = num_neg != den_neg;
+
+  if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
+    *rem = num_neg ? -InfiniteDuration() : InfiniteDuration();
+    return quotient_neg ? kint64min : kint64max;
+  }
+  if (time_internal::IsInfiniteDuration(den)) {
+    *rem = num;
+    return 0;
+  }
+
+  const uint128 a = MakeU128Ticks(num);
+  const uint128 b = MakeU128Ticks(den);
+  uint128 quotient128 = a / b;
+
+  if (satq) {
+    // Limits the quotient to the range of int64_t.
+    if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) {
+      quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min))
+                                 : uint128(static_cast<uint64_t>(kint64max));
+    }
+  }
+
+  const uint128 remainder128 = a - quotient128 * b;
+  *rem = MakeDurationFromU128(remainder128, num_neg);
+
+  if (!quotient_neg || quotient128 == 0) {
+    return Uint128Low64(quotient128) & kint64max;
+  }
+  // The quotient needs to be negated, but we need to carefully handle
+  // quotient128s with the top bit on.
+  return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1;
+}
+
+}  // namespace time_internal
+
+//
+// Additive operators.
+//
+
+Duration& Duration::operator+=(Duration rhs) {
+  if (time_internal::IsInfiniteDuration(*this)) return *this;
+  if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs;
+  const int64_t orig_rep_hi = rep_hi_;
+  rep_hi_ =
+      DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.rep_hi_));
+  if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) {
+    rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1);
+    rep_lo_ -= kTicksPerSecond;
+  }
+  rep_lo_ += rhs.rep_lo_;
+  if (rhs.rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) {
+    return *this = rhs.rep_hi_ < 0 ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this;
+}
+
+Duration& Duration::operator-=(Duration rhs) {
+  if (time_internal::IsInfiniteDuration(*this)) return *this;
+  if (time_internal::IsInfiniteDuration(rhs)) {
+    return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
+  }
+  const int64_t orig_rep_hi = rep_hi_;
+  rep_hi_ =
+      DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.rep_hi_));
+  if (rep_lo_ < rhs.rep_lo_) {
+    rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1);
+    rep_lo_ += kTicksPerSecond;
+  }
+  rep_lo_ -= rhs.rep_lo_;
+  if (rhs.rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) {
+    return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this;
+}
+
+//
+// Multiplicative operators.
+//
+
+Duration& Duration::operator*=(int64_t r) {
+  if (time_internal::IsInfiniteDuration(*this)) {
+    const bool is_neg = (r < 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleFixed<SafeMultiply>(*this, r);
+}
+
+Duration& Duration::operator*=(double r) {
+  if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) {
+    const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleDouble<std::multiplies>(*this, r);
+}
+
+Duration& Duration::operator/=(int64_t r) {
+  if (time_internal::IsInfiniteDuration(*this) || r == 0) {
+    const bool is_neg = (r < 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleFixed<std::divides>(*this, r);
+}
+
+Duration& Duration::operator/=(double r) {
+  if (time_internal::IsInfiniteDuration(*this) || r == 0.0) {
+    const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleDouble<std::divides>(*this, r);
+}
+
+Duration& Duration::operator%=(Duration rhs) {
+  time_internal::IDivDuration(false, *this, rhs, this);
+  return *this;
+}
+
+double FDivDuration(Duration num, Duration den) {
+  // Arithmetic with infinity is sticky.
+  if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
+    return (num < ZeroDuration()) == (den < ZeroDuration())
+               ? std::numeric_limits<double>::infinity()
+               : -std::numeric_limits<double>::infinity();
+  }
+  if (time_internal::IsInfiniteDuration(den)) return 0.0;
+
+  double a =
+      static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond +
+      time_internal::GetRepLo(num);
+  double b =
+      static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond +
+      time_internal::GetRepLo(den);
+  return a / b;
+}
+
+//
+// Trunc/Floor/Ceil.
+//
+
+Duration Trunc(Duration d, Duration unit) {
+  return d - (d % unit);
+}
+
+Duration Floor(const Duration d, const Duration unit) {
+  const absl::Duration td = Trunc(d, unit);
+  return td <= d ? td : td - AbsDuration(unit);
+}
+
+Duration Ceil(const Duration d, const Duration unit) {
+  const absl::Duration td = Trunc(d, unit);
+  return td >= d ? td : td + AbsDuration(unit);
+}
+
+//
+// Factory functions.
+//
+
+Duration DurationFromTimespec(timespec ts) {
+  if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) {
+    int64_t ticks = ts.tv_nsec * kTicksPerNanosecond;
+    return time_internal::MakeDuration(ts.tv_sec, ticks);
+  }
+  return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec);
+}
+
+Duration DurationFromTimeval(timeval tv) {
+  if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) {
+    int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond;
+    return time_internal::MakeDuration(tv.tv_sec, ticks);
+  }
+  return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec);
+}
+
+//
+// Conversion to other duration types.
+//
+
+int64_t ToInt64Nanoseconds(Duration d) {
+  if (time_internal::GetRepHi(d) >= 0 &&
+      time_internal::GetRepHi(d) >> 33 == 0) {
+    return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
+           (time_internal::GetRepLo(d) / kTicksPerNanosecond);
+  }
+  return d / Nanoseconds(1);
+}
+int64_t ToInt64Microseconds(Duration d) {
+  if (time_internal::GetRepHi(d) >= 0 &&
+      time_internal::GetRepHi(d) >> 43 == 0) {
+    return (time_internal::GetRepHi(d) * 1000 * 1000) +
+           (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000));
+  }
+  return d / Microseconds(1);
+}
+int64_t ToInt64Milliseconds(Duration d) {
+  if (time_internal::GetRepHi(d) >= 0 &&
+      time_internal::GetRepHi(d) >> 53 == 0) {
+    return (time_internal::GetRepHi(d) * 1000) +
+           (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000));
+  }
+  return d / Milliseconds(1);
+}
+int64_t ToInt64Seconds(Duration d) {
+  int64_t hi = time_internal::GetRepHi(d);
+  if (time_internal::IsInfiniteDuration(d)) return hi;
+  if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+  return hi;
+}
+int64_t ToInt64Minutes(Duration d) {
+  int64_t hi = time_internal::GetRepHi(d);
+  if (time_internal::IsInfiniteDuration(d)) return hi;
+  if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+  return hi / 60;
+}
+int64_t ToInt64Hours(Duration d) {
+  int64_t hi = time_internal::GetRepHi(d);
+  if (time_internal::IsInfiniteDuration(d)) return hi;
+  if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+  return hi / (60 * 60);
+}
+
+double ToDoubleNanoseconds(Duration d) {
+  return FDivDuration(d, Nanoseconds(1));
+}
+double ToDoubleMicroseconds(Duration d) {
+  return FDivDuration(d, Microseconds(1));
+}
+double ToDoubleMilliseconds(Duration d) {
+  return FDivDuration(d, Milliseconds(1));
+}
+double ToDoubleSeconds(Duration d) {
+  return FDivDuration(d, Seconds(1));
+}
+double ToDoubleMinutes(Duration d) {
+  return FDivDuration(d, Minutes(1));
+}
+double ToDoubleHours(Duration d) {
+  return FDivDuration(d, Hours(1));
+}
+
+timespec ToTimespec(Duration d) {
+  timespec ts;
+  if (!time_internal::IsInfiniteDuration(d)) {
+    int64_t rep_hi = time_internal::GetRepHi(d);
+    uint32_t rep_lo = time_internal::GetRepLo(d);
+    if (rep_hi < 0) {
+      // Tweak the fields so that unsigned division of rep_lo
+      // maps to truncation (towards zero) for the timespec.
+      rep_lo += kTicksPerNanosecond - 1;
+      if (rep_lo >= kTicksPerSecond) {
+        rep_hi += 1;
+        rep_lo -= kTicksPerSecond;
+      }
+    }
+    ts.tv_sec = rep_hi;
+    if (ts.tv_sec == rep_hi) {  // no time_t narrowing
+      ts.tv_nsec = rep_lo / kTicksPerNanosecond;
+      return ts;
+    }
+  }
+  if (d >= ZeroDuration()) {
+    ts.tv_sec = std::numeric_limits<time_t>::max();
+    ts.tv_nsec = 1000 * 1000 * 1000 - 1;
+  } else {
+    ts.tv_sec = std::numeric_limits<time_t>::min();
+    ts.tv_nsec = 0;
+  }
+  return ts;
+}
+
+timeval ToTimeval(Duration d) {
+  timeval tv;
+  timespec ts = ToTimespec(d);
+  if (ts.tv_sec < 0) {
+    // Tweak the fields so that positive division of tv_nsec
+    // maps to truncation (towards zero) for the timeval.
+    ts.tv_nsec += 1000 - 1;
+    if (ts.tv_nsec >= 1000 * 1000 * 1000) {
+      ts.tv_sec += 1;
+      ts.tv_nsec -= 1000 * 1000 * 1000;
+    }
+  }
+  tv.tv_sec = ts.tv_sec;
+  if (tv.tv_sec != ts.tv_sec) {  // narrowing
+    if (ts.tv_sec < 0) {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
+      tv.tv_usec = 0;
+    } else {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
+      tv.tv_usec = 1000 * 1000 - 1;
+    }
+    return tv;
+  }
+  tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t
+  return tv;
+}
+
+std::chrono::nanoseconds ToChronoNanoseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d);
+}
+std::chrono::microseconds ToChronoMicroseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::microseconds>(d);
+}
+std::chrono::milliseconds ToChronoMilliseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::milliseconds>(d);
+}
+std::chrono::seconds ToChronoSeconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::seconds>(d);
+}
+std::chrono::minutes ToChronoMinutes(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::minutes>(d);
+}
+std::chrono::hours ToChronoHours(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::hours>(d);
+}
+
+//
+// To/From std::string formatting.
+//
+
+namespace {
+
+// Formats a positive 64-bit integer in the given field width.  Note that
+// it is up to the caller of Format64() to ensure that there is sufficient
+// space before ep to hold the conversion.
+char* Format64(char* ep, int width, int64_t v) {
+  do {
+    --width;
+    *--ep = '0' + (v % 10);  // contiguous digits
+  } while (v /= 10);
+  while (--width >= 0) *--ep = '0';  // zero pad
+  return ep;
+}
+
+// Helpers for FormatDuration() that format 'n' and append it to 'out'
+// followed by the given 'unit'.  If 'n' formats to "0", nothing is
+// appended (not even the unit).
+
+// A type that encapsulates how to display a value of a particular unit. For
+// values that are displayed with fractional parts, the precision indicates
+// where to round the value. The precision varies with the display unit because
+// a Duration can hold only quarters of a nanosecond, so displaying information
+// beyond that is just noise.
+//
+// For example, a microsecond value of 42.00025xxxxx should not display beyond 5
+// fractional digits, because it is in the noise of what a Duration can
+// represent.
+struct DisplayUnit {
+  const char* abbr;
+  int prec;
+  double pow10;
+};
+const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
+const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
+const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
+const DisplayUnit kDisplaySec = {"s", 11, 1e11};
+const DisplayUnit kDisplayMin = {"m", -1, 0.0};   // prec ignored
+const DisplayUnit kDisplayHour = {"h", -1, 0.0};  // prec ignored
+
+void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
+  char buf[sizeof("2562047788015216")];  // hours in max duration
+  char* const ep = buf + sizeof(buf);
+  char* bp = Format64(ep, 0, n);
+  if (*bp != '0' || bp + 1 != ep) {
+    out->append(bp, ep - bp);
+    out->append(unit.abbr);
+  }
+}
+
+// Note: unit.prec is limited to double's digits10 value (typically 15) so it
+// always fits in buf[].
+void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
+  const int buf_size = std::numeric_limits<double>::digits10;
+  const int prec = std::min(buf_size, unit.prec);
+  char buf[buf_size];  // also large enough to hold integer part
+  char* ep = buf + sizeof(buf);
+  double d = 0;
+  int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
+  int64_t int_part = d;
+  if (int_part != 0 || frac_part != 0) {
+    char* bp = Format64(ep, 0, int_part);  // always < 1000
+    out->append(bp, ep - bp);
+    if (frac_part != 0) {
+      out->push_back('.');
+      bp = Format64(ep, prec, frac_part);
+      while (ep[-1] == '0') --ep;
+      out->append(bp, ep - bp);
+    }
+    out->append(unit.abbr);
+  }
+}
+
+}  // namespace
+
+// From Go's doc at http://golang.org/pkg/time/#Duration.String
+//   [FormatDuration] returns a std::string representing the duration in the
+//   form "72h3m0.5s".  Leading zero units are omitted.  As a special
+//   case, durations less than one second format use a smaller unit
+//   (milli-, micro-, or nanoseconds) to ensure that the leading digit
+//   is non-zero.  The zero duration formats as 0, with no unit.
+std::string FormatDuration(Duration d) {
+  const Duration min_duration = Seconds(kint64min);
+  if (d == min_duration) {
+    // Avoid needing to negate kint64min by directly returning what the
+    // following code should produce in that case.
+    return "-2562047788015215h30m8s";
+  }
+  std::string s;
+  if (d < ZeroDuration()) {
+    s.append("-");
+    d = -d;
+  }
+  if (d == InfiniteDuration()) {
+    s.append("inf");
+  } else if (d < Seconds(1)) {
+    // Special case for durations with a magnitude < 1 second.  The duration
+    // is printed as a fraction of a single unit, e.g., "1.2ms".
+    if (d < Microseconds(1)) {
+      AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano);
+    } else if (d < Milliseconds(1)) {
+      AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro);
+    } else {
+      AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli);
+    }
+  } else {
+    AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour);
+    AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin);
+    AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec);
+  }
+  if (s.empty() || s == "-") {
+    s = "0";
+  }
+  return s;
+}
+
+namespace {
+
+// A helper for ParseDuration() that parses a leading number from the given
+// std::string and stores the result in *int_part/*frac_part/*frac_scale.  The
+// given std::string pointer is modified to point to the first unconsumed char.
+bool ConsumeDurationNumber(const char** dpp, int64_t* int_part,
+                           int64_t* frac_part, int64_t* frac_scale) {
+  *int_part = 0;
+  *frac_part = 0;
+  *frac_scale = 1;  // invariant: *frac_part < *frac_scale
+  const char* start = *dpp;
+  for (; std::isdigit(**dpp); *dpp += 1) {
+    const int d = **dpp - '0';  // contiguous digits
+    if (*int_part > kint64max / 10) return false;
+    *int_part *= 10;
+    if (*int_part > kint64max - d) return false;
+    *int_part += d;
+  }
+  const bool int_part_empty = (*dpp == start);
+  if (**dpp != '.') return !int_part_empty;
+  for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) {
+    const int d = **dpp - '0';  // contiguous digits
+    if (*frac_scale <= kint64max / 10) {
+      *frac_part *= 10;
+      *frac_part += d;
+      *frac_scale *= 10;
+    }
+  }
+  return !int_part_empty || *frac_scale != 1;
+}
+
+// A helper for ParseDuration() that parses a leading unit designator (e.g.,
+// ns, us, ms, s, m, h) from the given std::string and stores the resulting unit
+// in "*unit".  The given std::string pointer is modified to point to the first
+// unconsumed char.
+bool ConsumeDurationUnit(const char** start, Duration* unit) {
+  const char *s = *start;
+  bool ok = true;
+  if (strncmp(s, "ns", 2) == 0) {
+    s += 2;
+    *unit = Nanoseconds(1);
+  } else if (strncmp(s, "us", 2) == 0) {
+    s += 2;
+    *unit = Microseconds(1);
+  } else if (strncmp(s, "ms", 2) == 0) {
+    s += 2;
+    *unit = Milliseconds(1);
+  } else if (strncmp(s, "s", 1) == 0) {
+    s += 1;
+    *unit = Seconds(1);
+  } else if (strncmp(s, "m", 1) == 0) {
+    s += 1;
+    *unit = Minutes(1);
+  } else if (strncmp(s, "h", 1) == 0) {
+    s += 1;
+    *unit = Hours(1);
+  } else {
+    ok = false;
+  }
+  *start = s;
+  return ok;
+}
+
+}  // namespace
+
+// From Go's doc at http://golang.org/pkg/time/#ParseDuration
+//   [ParseDuration] parses a duration std::string.  A duration std::string is
+//   a possibly signed sequence of decimal numbers, each with optional
+//   fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
+//   Valid time units are "ns", "us" "ms", "s", "m", "h".
+bool ParseDuration(const std::string& dur_string, Duration* d) {
+  const char* start = dur_string.c_str();
+  int sign = 1;
+
+  if (*start == '-' || *start == '+') {
+    sign = *start == '-' ? -1 : 1;
+    ++start;
+  }
+
+  // Can't parse a duration from an empty std::string.
+  if (*start == '\0') {
+    return false;
+  }
+
+  // Special case for a std::string of "0".
+  if (*start == '0' && *(start + 1) == '\0') {
+    *d = ZeroDuration();
+    return true;
+  }
+
+  if (strcmp(start, "inf") == 0) {
+    *d = sign * InfiniteDuration();
+    return true;
+  }
+
+  Duration dur;
+  while (*start != '\0') {
+    int64_t int_part;
+    int64_t frac_part;
+    int64_t frac_scale;
+    Duration unit;
+    if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) ||
+        !ConsumeDurationUnit(&start, &unit)) {
+      return false;
+    }
+    if (int_part != 0) dur += sign * int_part * unit;
+    if (frac_part != 0) dur += sign * frac_part * unit / frac_scale;
+  }
+  *d = dur;
+  return true;
+}
+
+bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
+  return ParseDuration(text, dst);
+}
+
+std::string UnparseFlag(Duration d) {
+  return FormatDuration(d);
+}
+
+}  // namespace absl
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc
new file mode 100644
index 0000000..54f89a1
--- /dev/null
+++ b/absl/time/duration_benchmark.cc
@@ -0,0 +1,361 @@
+// Copyright 2018 The Abseil 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 <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <ctime>
+#include <string>
+
+#include "absl/time/time.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+//
+// Factory functions
+//
+
+void BM_Duration_Factory_Nanoseconds(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Nanoseconds(1));
+  }
+}
+BENCHMARK(BM_Duration_Factory_Nanoseconds);
+
+void BM_Duration_Factory_Microseconds(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Microseconds(1));
+  }
+}
+BENCHMARK(BM_Duration_Factory_Microseconds);
+
+void BM_Duration_Factory_Milliseconds(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Milliseconds(1));
+  }
+}
+BENCHMARK(BM_Duration_Factory_Milliseconds);
+
+void BM_Duration_Factory_Seconds(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Seconds(1));
+  }
+}
+BENCHMARK(BM_Duration_Factory_Seconds);
+
+void BM_Duration_Factory_Minutes(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Minutes(1));
+  }
+}
+BENCHMARK(BM_Duration_Factory_Minutes);
+
+void BM_Duration_Factory_Hours(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::Hours(1));
+  }
+}
+BENCHMARK(BM_Duration_Factory_Hours);
+
+//
+// Arithmetic
+//
+
+void BM_Duration_Addition(benchmark::State& state) {
+  absl::Duration d = absl::Nanoseconds(1);
+  absl::Duration step = absl::Milliseconds(1);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d += step);
+  }
+}
+BENCHMARK(BM_Duration_Addition);
+
+void BM_Duration_Subtraction(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(std::numeric_limits<int64_t>::max());
+  absl::Duration step = absl::Milliseconds(1);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d -= step);
+  }
+}
+BENCHMARK(BM_Duration_Subtraction);
+
+void BM_Duration_Multiplication_Fixed(benchmark::State& state) {
+  absl::Duration d = absl::Milliseconds(1);
+  absl::Duration s;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(s += d * (i + 1));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_Multiplication_Fixed);
+
+void BM_Duration_Multiplication_Double(benchmark::State& state) {
+  absl::Duration d = absl::Milliseconds(1);
+  absl::Duration s;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(s += d * (i + 1.0));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_Multiplication_Double);
+
+void BM_Duration_Division_Fixed(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(1);
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d /= i + 1);
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_Division_Fixed);
+
+void BM_Duration_Division_Double(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(1);
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(d /= i + 1.0);
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_Division_Double);
+
+void BM_Duration_FDivDuration_Nanoseconds(benchmark::State& state) {
+  double d = 1;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        d += absl::FDivDuration(absl::Milliseconds(i), absl::Nanoseconds(1)));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_FDivDuration_Nanoseconds);
+
+void BM_Duration_IDivDuration_Nanoseconds(benchmark::State& state) {
+  int64_t a = 1;
+  absl::Duration ignore;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(a +=
+                             absl::IDivDuration(absl::Nanoseconds(i),
+                                                absl::Nanoseconds(1), &ignore));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_IDivDuration_Nanoseconds);
+
+void BM_Duration_IDivDuration_Microseconds(benchmark::State& state) {
+  int64_t a = 1;
+  absl::Duration ignore;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Microseconds(i),
+                                                     absl::Microseconds(1),
+                                                     &ignore));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_IDivDuration_Microseconds);
+
+void BM_Duration_IDivDuration_Milliseconds(benchmark::State& state) {
+  int64_t a = 1;
+  absl::Duration ignore;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Milliseconds(i),
+                                                     absl::Milliseconds(1),
+                                                     &ignore));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_IDivDuration_Milliseconds);
+
+void BM_Duration_IDivDuration_Seconds(benchmark::State& state) {
+  int64_t a = 1;
+  absl::Duration ignore;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        a += absl::IDivDuration(absl::Seconds(i), absl::Seconds(1), &ignore));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_IDivDuration_Seconds);
+
+void BM_Duration_IDivDuration_Minutes(benchmark::State& state) {
+  int64_t a = 1;
+  absl::Duration ignore;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        a += absl::IDivDuration(absl::Minutes(i), absl::Minutes(1), &ignore));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_IDivDuration_Minutes);
+
+void BM_Duration_IDivDuration_Hours(benchmark::State& state) {
+  int64_t a = 1;
+  absl::Duration ignore;
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        a += absl::IDivDuration(absl::Hours(i), absl::Hours(1), &ignore));
+    ++i;
+  }
+}
+BENCHMARK(BM_Duration_IDivDuration_Hours);
+
+void BM_Duration_ToInt64Nanoseconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToInt64Nanoseconds(d));
+  }
+}
+BENCHMARK(BM_Duration_ToInt64Nanoseconds);
+
+void BM_Duration_ToInt64Microseconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToInt64Microseconds(d));
+  }
+}
+BENCHMARK(BM_Duration_ToInt64Microseconds);
+
+void BM_Duration_ToInt64Milliseconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToInt64Milliseconds(d));
+  }
+}
+BENCHMARK(BM_Duration_ToInt64Milliseconds);
+
+void BM_Duration_ToInt64Seconds(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToInt64Seconds(d));
+  }
+}
+BENCHMARK(BM_Duration_ToInt64Seconds);
+
+void BM_Duration_ToInt64Minutes(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToInt64Minutes(d));
+  }
+}
+BENCHMARK(BM_Duration_ToInt64Minutes);
+
+void BM_Duration_ToInt64Hours(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(100000);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToInt64Hours(d));
+  }
+}
+BENCHMARK(BM_Duration_ToInt64Hours);
+
+//
+// To/FromTimespec
+//
+
+void BM_Duration_ToTimespec_AbslTime(benchmark::State& state) {
+  absl::Duration d = absl::Seconds(1);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToTimespec(d));
+  }
+}
+BENCHMARK(BM_Duration_ToTimespec_AbslTime);
+
+ABSL_ATTRIBUTE_NOINLINE timespec DoubleToTimespec(double seconds) {
+  timespec ts;
+  ts.tv_sec = seconds;
+  ts.tv_nsec = (seconds - ts.tv_sec) * (1000 * 1000 * 1000);
+  return ts;
+}
+
+void BM_Duration_ToTimespec_Double(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(DoubleToTimespec(1.0));
+  }
+}
+BENCHMARK(BM_Duration_ToTimespec_Double);
+
+void BM_Duration_FromTimespec_AbslTime(benchmark::State& state) {
+  timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  while (state.KeepRunning()) {
+    if (++ts.tv_nsec == 1000 * 1000 * 1000) {
+      ++ts.tv_sec;
+      ts.tv_nsec = 0;
+    }
+    benchmark::DoNotOptimize(absl::DurationFromTimespec(ts));
+  }
+}
+BENCHMARK(BM_Duration_FromTimespec_AbslTime);
+
+ABSL_ATTRIBUTE_NOINLINE double TimespecToDouble(timespec ts) {
+  return ts.tv_sec + (ts.tv_nsec / (1000 * 1000 * 1000));
+}
+
+void BM_Duration_FromTimespec_Double(benchmark::State& state) {
+  timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  while (state.KeepRunning()) {
+    if (++ts.tv_nsec == 1000 * 1000 * 1000) {
+      ++ts.tv_sec;
+      ts.tv_nsec = 0;
+    }
+    benchmark::DoNotOptimize(TimespecToDouble(ts));
+  }
+}
+BENCHMARK(BM_Duration_FromTimespec_Double);
+
+//
+// String conversions
+//
+
+const char* const kDurations[] = {
+    "0",                                   // 0
+    "123ns",                               // 1
+    "1h2m3s",                              // 2
+    "-2h3m4.005006007s",                   // 3
+    "2562047788015215h30m7.99999999975s",  // 4
+};
+const int kNumDurations = sizeof(kDurations) / sizeof(kDurations[0]);
+
+void BM_Duration_FormatDuration(benchmark::State& state) {
+  const std::string s = kDurations[state.range(0)];
+  state.SetLabel(s);
+  absl::Duration d;
+  absl::ParseDuration(kDurations[state.range(0)], &d);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::FormatDuration(d));
+  }
+}
+BENCHMARK(BM_Duration_FormatDuration)->DenseRange(0, kNumDurations - 1);
+
+void BM_Duration_ParseDuration(benchmark::State& state) {
+  const std::string s = kDurations[state.range(0)];
+  state.SetLabel(s);
+  absl::Duration d;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ParseDuration(s, &d));
+  }
+}
+BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1);
+
+}  // namespace
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
new file mode 100644
index 0000000..704684e
--- /dev/null
+++ b/absl/time/duration_test.cc
@@ -0,0 +1,1672 @@
+// Copyright 2017 The Abseil 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 <chrono>  // NOLINT(build/c++11)
+#include <cmath>
+#include <cstdint>
+#include <ctime>
+#include <limits>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/time.h"
+
+namespace {
+
+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+
+// Approximates the given number of years. This is only used to make some test
+// code more readable.
+absl::Duration ApproxYears(int64_t n) { return absl::Hours(n) * 365 * 24; }
+
+// A gMock matcher to match timespec values. Use this matcher like:
+// timespec ts1, ts2;
+// EXPECT_THAT(ts1, TimespecMatcher(ts2));
+MATCHER_P(TimespecMatcher, ts, "") {
+  if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec)
+    return true;
+  *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} ";
+  *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}";
+  return false;
+}
+
+// A gMock matcher to match timeval values. Use this matcher like:
+// timeval tv1, tv2;
+// EXPECT_THAT(tv1, TimevalMatcher(tv2));
+MATCHER_P(TimevalMatcher, tv, "") {
+  if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec)
+    return true;
+  *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} ";
+  *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}";
+  return false;
+}
+
+TEST(Duration, ValueSemantics) {
+  // If this compiles, the test passes.
+  constexpr absl::Duration a;      // Default construction
+  constexpr absl::Duration b = a;  // Copy construction
+  constexpr absl::Duration c(b);   // Copy construction (again)
+
+  absl::Duration d;
+  d = c;  // Assignment
+}
+
+TEST(Duration, Factories) {
+  constexpr absl::Duration zero = absl::ZeroDuration();
+  constexpr absl::Duration nano = absl::Nanoseconds(1);
+  constexpr absl::Duration micro = absl::Microseconds(1);
+  constexpr absl::Duration milli = absl::Milliseconds(1);
+  constexpr absl::Duration sec = absl::Seconds(1);
+  constexpr absl::Duration min = absl::Minutes(1);
+  constexpr absl::Duration hour = absl::Hours(1);
+
+  EXPECT_EQ(zero, absl::Duration());
+  EXPECT_EQ(zero, absl::Seconds(0));
+  EXPECT_EQ(nano, absl::Nanoseconds(1));
+  EXPECT_EQ(micro, absl::Nanoseconds(1000));
+  EXPECT_EQ(milli, absl::Microseconds(1000));
+  EXPECT_EQ(sec, absl::Milliseconds(1000));
+  EXPECT_EQ(min, absl::Seconds(60));
+  EXPECT_EQ(hour, absl::Minutes(60));
+
+  // Tests factory limits
+  const absl::Duration inf = absl::InfiniteDuration();
+
+  EXPECT_GT(inf, absl::Seconds(kint64max));
+  EXPECT_LT(-inf, absl::Seconds(kint64min));
+  EXPECT_LT(-inf, absl::Seconds(-kint64max));
+
+  EXPECT_EQ(inf, absl::Minutes(kint64max));
+  EXPECT_EQ(-inf, absl::Minutes(kint64min));
+  EXPECT_EQ(-inf, absl::Minutes(-kint64max));
+  EXPECT_GT(inf, absl::Minutes(kint64max / 60));
+  EXPECT_LT(-inf, absl::Minutes(kint64min / 60));
+  EXPECT_LT(-inf, absl::Minutes(-kint64max / 60));
+
+  EXPECT_EQ(inf, absl::Hours(kint64max));
+  EXPECT_EQ(-inf, absl::Hours(kint64min));
+  EXPECT_EQ(-inf, absl::Hours(-kint64max));
+  EXPECT_GT(inf, absl::Hours(kint64max / 3600));
+  EXPECT_LT(-inf, absl::Hours(kint64min / 3600));
+  EXPECT_LT(-inf, absl::Hours(-kint64max / 3600));
+}
+
+TEST(Duration, ToConversion) {
+#define TEST_DURATION_CONVERSION(UNIT)                              \
+  do {                                                              \
+    const absl::Duration d = absl::UNIT(1.5);                       \
+    const absl::Duration z = absl::ZeroDuration();                  \
+    const absl::Duration inf = absl::InfiniteDuration();            \
+    const double dbl_inf = std::numeric_limits<double>::infinity(); \
+    EXPECT_EQ(kint64min, absl::ToInt64##UNIT(-inf));                \
+    EXPECT_EQ(-1, absl::ToInt64##UNIT(-d));                         \
+    EXPECT_EQ(0, absl::ToInt64##UNIT(z));                           \
+    EXPECT_EQ(1, absl::ToInt64##UNIT(d));                           \
+    EXPECT_EQ(kint64max, absl::ToInt64##UNIT(inf));                 \
+    EXPECT_EQ(-dbl_inf, absl::ToDouble##UNIT(-inf));                \
+    EXPECT_EQ(-1.5, absl::ToDouble##UNIT(-d));                      \
+    EXPECT_EQ(0, absl::ToDouble##UNIT(z));                          \
+    EXPECT_EQ(1.5, absl::ToDouble##UNIT(d));                        \
+    EXPECT_EQ(dbl_inf, absl::ToDouble##UNIT(inf));                  \
+  } while (0)
+
+  TEST_DURATION_CONVERSION(Nanoseconds);
+  TEST_DURATION_CONVERSION(Microseconds);
+  TEST_DURATION_CONVERSION(Milliseconds);
+  TEST_DURATION_CONVERSION(Seconds);
+  TEST_DURATION_CONVERSION(Minutes);
+  TEST_DURATION_CONVERSION(Hours);
+
+#undef TEST_DURATION_CONVERSION
+}
+
+template <int64_t N>
+void TestToConversion() {
+  constexpr absl::Duration nano = absl::Nanoseconds(N);
+  EXPECT_EQ(N, absl::ToInt64Nanoseconds(nano));
+  EXPECT_EQ(0, absl::ToInt64Microseconds(nano));
+  EXPECT_EQ(0, absl::ToInt64Milliseconds(nano));
+  EXPECT_EQ(0, absl::ToInt64Seconds(nano));
+  EXPECT_EQ(0, absl::ToInt64Minutes(nano));
+  EXPECT_EQ(0, absl::ToInt64Hours(nano));
+  const absl::Duration micro = absl::Microseconds(N);
+  EXPECT_EQ(N * 1000, absl::ToInt64Nanoseconds(micro));
+  EXPECT_EQ(N, absl::ToInt64Microseconds(micro));
+  EXPECT_EQ(0, absl::ToInt64Milliseconds(micro));
+  EXPECT_EQ(0, absl::ToInt64Seconds(micro));
+  EXPECT_EQ(0, absl::ToInt64Minutes(micro));
+  EXPECT_EQ(0, absl::ToInt64Hours(micro));
+  const absl::Duration milli = absl::Milliseconds(N);
+  EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Nanoseconds(milli));
+  EXPECT_EQ(N * 1000, absl::ToInt64Microseconds(milli));
+  EXPECT_EQ(N, absl::ToInt64Milliseconds(milli));
+  EXPECT_EQ(0, absl::ToInt64Seconds(milli));
+  EXPECT_EQ(0, absl::ToInt64Minutes(milli));
+  EXPECT_EQ(0, absl::ToInt64Hours(milli));
+  const absl::Duration sec = absl::Seconds(N);
+  EXPECT_EQ(N * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(sec));
+  EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Microseconds(sec));
+  EXPECT_EQ(N * 1000, absl::ToInt64Milliseconds(sec));
+  EXPECT_EQ(N, absl::ToInt64Seconds(sec));
+  EXPECT_EQ(0, absl::ToInt64Minutes(sec));
+  EXPECT_EQ(0, absl::ToInt64Hours(sec));
+  const absl::Duration min = absl::Minutes(N);
+  EXPECT_EQ(N * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(min));
+  EXPECT_EQ(N * 60 * 1000 * 1000, absl::ToInt64Microseconds(min));
+  EXPECT_EQ(N * 60 * 1000, absl::ToInt64Milliseconds(min));
+  EXPECT_EQ(N * 60, absl::ToInt64Seconds(min));
+  EXPECT_EQ(N, absl::ToInt64Minutes(min));
+  EXPECT_EQ(0, absl::ToInt64Hours(min));
+  const absl::Duration hour = absl::Hours(N);
+  EXPECT_EQ(N * 60 * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(hour));
+  EXPECT_EQ(N * 60 * 60 * 1000 * 1000, absl::ToInt64Microseconds(hour));
+  EXPECT_EQ(N * 60 * 60 * 1000, absl::ToInt64Milliseconds(hour));
+  EXPECT_EQ(N * 60 * 60, absl::ToInt64Seconds(hour));
+  EXPECT_EQ(N * 60, absl::ToInt64Minutes(hour));
+  EXPECT_EQ(N, absl::ToInt64Hours(hour));
+}
+
+TEST(Duration, ToConversionDeprecated) {
+  TestToConversion<43>();
+  TestToConversion<1>();
+  TestToConversion<0>();
+  TestToConversion<-1>();
+  TestToConversion<-43>();
+}
+
+template <int64_t N>
+void TestFromChronoBasicEquality() {
+  using std::chrono::nanoseconds;
+  using std::chrono::microseconds;
+  using std::chrono::milliseconds;
+  using std::chrono::seconds;
+  using std::chrono::minutes;
+  using std::chrono::hours;
+
+  static_assert(absl::Nanoseconds(N) == absl::FromChrono(nanoseconds(N)), "");
+  static_assert(absl::Microseconds(N) == absl::FromChrono(microseconds(N)), "");
+  static_assert(absl::Milliseconds(N) == absl::FromChrono(milliseconds(N)), "");
+  static_assert(absl::Seconds(N) == absl::FromChrono(seconds(N)), "");
+  static_assert(absl::Minutes(N) == absl::FromChrono(minutes(N)), "");
+  static_assert(absl::Hours(N) == absl::FromChrono(hours(N)), "");
+}
+
+TEST(Duration, FromChrono) {
+  TestFromChronoBasicEquality<-123>();
+  TestFromChronoBasicEquality<-1>();
+  TestFromChronoBasicEquality<0>();
+  TestFromChronoBasicEquality<1>();
+  TestFromChronoBasicEquality<123>();
+
+  // Minutes (might, depending on the platform) saturate at +inf.
+  const auto chrono_minutes_max = std::chrono::minutes::max();
+  const auto minutes_max = absl::FromChrono(chrono_minutes_max);
+  const int64_t minutes_max_count = chrono_minutes_max.count();
+  if (minutes_max_count > kint64max / 60) {
+    EXPECT_EQ(absl::InfiniteDuration(), minutes_max);
+  } else {
+    EXPECT_EQ(absl::Minutes(minutes_max_count), minutes_max);
+  }
+
+  // Minutes (might, depending on the platform) saturate at -inf.
+  const auto chrono_minutes_min = std::chrono::minutes::min();
+  const auto minutes_min = absl::FromChrono(chrono_minutes_min);
+  const int64_t minutes_min_count = chrono_minutes_min.count();
+  if (minutes_min_count < kint64min / 60) {
+    EXPECT_EQ(-absl::InfiniteDuration(), minutes_min);
+  } else {
+    EXPECT_EQ(absl::Minutes(minutes_min_count), minutes_min);
+  }
+
+  // Hours (might, depending on the platform) saturate at +inf.
+  const auto chrono_hours_max = std::chrono::hours::max();
+  const auto hours_max = absl::FromChrono(chrono_hours_max);
+  const int64_t hours_max_count = chrono_hours_max.count();
+  if (hours_max_count > kint64max / 3600) {
+    EXPECT_EQ(absl::InfiniteDuration(), hours_max);
+  } else {
+    EXPECT_EQ(absl::Hours(hours_max_count), hours_max);
+  }
+
+  // Hours (might, depending on the platform) saturate at -inf.
+  const auto chrono_hours_min = std::chrono::hours::min();
+  const auto hours_min = absl::FromChrono(chrono_hours_min);
+  const int64_t hours_min_count = chrono_hours_min.count();
+  if (hours_min_count < kint64min / 3600) {
+    EXPECT_EQ(-absl::InfiniteDuration(), hours_min);
+  } else {
+    EXPECT_EQ(absl::Hours(hours_min_count), hours_min);
+  }
+}
+
+template <int64_t N>
+void TestToChrono() {
+  using std::chrono::nanoseconds;
+  using std::chrono::microseconds;
+  using std::chrono::milliseconds;
+  using std::chrono::seconds;
+  using std::chrono::minutes;
+  using std::chrono::hours;
+
+  EXPECT_EQ(nanoseconds(N), absl::ToChronoNanoseconds(absl::Nanoseconds(N)));
+  EXPECT_EQ(microseconds(N), absl::ToChronoMicroseconds(absl::Microseconds(N)));
+  EXPECT_EQ(milliseconds(N), absl::ToChronoMilliseconds(absl::Milliseconds(N)));
+  EXPECT_EQ(seconds(N), absl::ToChronoSeconds(absl::Seconds(N)));
+
+  constexpr auto absl_minutes = absl::Minutes(N);
+  auto chrono_minutes = minutes(N);
+  if (absl_minutes == -absl::InfiniteDuration()) {
+    chrono_minutes = minutes::min();
+  } else if (absl_minutes == absl::InfiniteDuration()) {
+    chrono_minutes = minutes::max();
+  }
+  EXPECT_EQ(chrono_minutes, absl::ToChronoMinutes(absl_minutes));
+
+  constexpr auto absl_hours = absl::Hours(N);
+  auto chrono_hours = hours(N);
+  if (absl_hours == -absl::InfiniteDuration()) {
+    chrono_hours = hours::min();
+  } else if (absl_hours == absl::InfiniteDuration()) {
+    chrono_hours = hours::max();
+  }
+  EXPECT_EQ(chrono_hours, absl::ToChronoHours(absl_hours));
+}
+
+TEST(Duration, ToChrono) {
+  using std::chrono::nanoseconds;
+  using std::chrono::microseconds;
+  using std::chrono::milliseconds;
+  using std::chrono::seconds;
+  using std::chrono::minutes;
+  using std::chrono::hours;
+
+  TestToChrono<kint64min>();
+  TestToChrono<-1>();
+  TestToChrono<0>();
+  TestToChrono<1>();
+  TestToChrono<kint64max>();
+
+  // Verify truncation toward zero.
+  const auto tick = absl::Nanoseconds(1) / 4;
+  EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(tick));
+  EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(-tick));
+  EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(tick));
+  EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(-tick));
+  EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(tick));
+  EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(-tick));
+  EXPECT_EQ(seconds(0), absl::ToChronoSeconds(tick));
+  EXPECT_EQ(seconds(0), absl::ToChronoSeconds(-tick));
+  EXPECT_EQ(minutes(0), absl::ToChronoMinutes(tick));
+  EXPECT_EQ(minutes(0), absl::ToChronoMinutes(-tick));
+  EXPECT_EQ(hours(0), absl::ToChronoHours(tick));
+  EXPECT_EQ(hours(0), absl::ToChronoHours(-tick));
+
+  // Verifies +/- infinity saturation at max/min.
+  constexpr auto inf = absl::InfiniteDuration();
+  EXPECT_EQ(nanoseconds::min(), absl::ToChronoNanoseconds(-inf));
+  EXPECT_EQ(nanoseconds::max(), absl::ToChronoNanoseconds(inf));
+  EXPECT_EQ(microseconds::min(), absl::ToChronoMicroseconds(-inf));
+  EXPECT_EQ(microseconds::max(), absl::ToChronoMicroseconds(inf));
+  EXPECT_EQ(milliseconds::min(), absl::ToChronoMilliseconds(-inf));
+  EXPECT_EQ(milliseconds::max(), absl::ToChronoMilliseconds(inf));
+  EXPECT_EQ(seconds::min(), absl::ToChronoSeconds(-inf));
+  EXPECT_EQ(seconds::max(), absl::ToChronoSeconds(inf));
+  EXPECT_EQ(minutes::min(), absl::ToChronoMinutes(-inf));
+  EXPECT_EQ(minutes::max(), absl::ToChronoMinutes(inf));
+  EXPECT_EQ(hours::min(), absl::ToChronoHours(-inf));
+  EXPECT_EQ(hours::max(), absl::ToChronoHours(inf));
+}
+
+TEST(Duration, FactoryOverloads) {
+  enum E { kOne = 1 };
+#define TEST_FACTORY_OVERLOADS(NAME)                                          \
+  EXPECT_EQ(1, NAME(kOne) / NAME(kOne));                                      \
+  EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1));                       \
+  EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1));                      \
+  EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1));                      \
+  EXPECT_EQ(1, NAME(static_cast<int64_t>(1)) / NAME(1));                      \
+  EXPECT_EQ(1, NAME(static_cast<uint8_t>(1)) / NAME(1));                      \
+  EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1));                     \
+  EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1));                     \
+  EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1));                     \
+  EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5)));                      \
+  EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5)));                     \
+  EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \
+  EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<double>(1.5)), NAME(1)));
+
+  TEST_FACTORY_OVERLOADS(absl::Nanoseconds);
+  TEST_FACTORY_OVERLOADS(absl::Microseconds);
+  TEST_FACTORY_OVERLOADS(absl::Milliseconds);
+  TEST_FACTORY_OVERLOADS(absl::Seconds);
+  TEST_FACTORY_OVERLOADS(absl::Minutes);
+  TEST_FACTORY_OVERLOADS(absl::Hours);
+
+#undef TEST_FACTORY_OVERLOADS
+
+  EXPECT_EQ(absl::Milliseconds(1500), absl::Seconds(1.5));
+  EXPECT_LT(absl::Nanoseconds(1), absl::Nanoseconds(1.5));
+  EXPECT_GT(absl::Nanoseconds(2), absl::Nanoseconds(1.5));
+
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(absl::InfiniteDuration(), absl::Nanoseconds(dbl_inf));
+  EXPECT_EQ(absl::InfiniteDuration(), absl::Microseconds(dbl_inf));
+  EXPECT_EQ(absl::InfiniteDuration(), absl::Milliseconds(dbl_inf));
+  EXPECT_EQ(absl::InfiniteDuration(), absl::Seconds(dbl_inf));
+  EXPECT_EQ(absl::InfiniteDuration(), absl::Minutes(dbl_inf));
+  EXPECT_EQ(absl::InfiniteDuration(), absl::Hours(dbl_inf));
+  EXPECT_EQ(-absl::InfiniteDuration(), absl::Nanoseconds(-dbl_inf));
+  EXPECT_EQ(-absl::InfiniteDuration(), absl::Microseconds(-dbl_inf));
+  EXPECT_EQ(-absl::InfiniteDuration(), absl::Milliseconds(-dbl_inf));
+  EXPECT_EQ(-absl::InfiniteDuration(), absl::Seconds(-dbl_inf));
+  EXPECT_EQ(-absl::InfiniteDuration(), absl::Minutes(-dbl_inf));
+  EXPECT_EQ(-absl::InfiniteDuration(), absl::Hours(-dbl_inf));
+}
+
+TEST(Duration, InfinityExamples) {
+  // These examples are used in the documentation in time.h. They are
+  // written so that they can be copy-n-pasted easily.
+
+  constexpr absl::Duration inf = absl::InfiniteDuration();
+  constexpr absl::Duration d = absl::Seconds(1);  // Any finite duration
+
+  EXPECT_TRUE(inf == inf + inf);
+  EXPECT_TRUE(inf == inf + d);
+  EXPECT_TRUE(inf == inf - inf);
+  EXPECT_TRUE(-inf == d - inf);
+
+  EXPECT_TRUE(inf == d * 1e100);
+  EXPECT_TRUE(0 == d / inf);  // NOLINT(readability/check)
+
+  // Division by zero returns infinity, or kint64min/MAX where necessary.
+  EXPECT_TRUE(inf == d / 0);
+  EXPECT_TRUE(kint64max == d / absl::ZeroDuration());
+}
+
+TEST(Duration, InfinityComparison) {
+  const absl::Duration inf = absl::InfiniteDuration();
+  const absl::Duration any_dur = absl::Seconds(1);
+
+  // Equality
+  EXPECT_EQ(inf, inf);
+  EXPECT_EQ(-inf, -inf);
+  EXPECT_NE(inf, -inf);
+  EXPECT_NE(any_dur, inf);
+  EXPECT_NE(any_dur, -inf);
+
+  // Relational
+  EXPECT_GT(inf, any_dur);
+  EXPECT_LT(-inf, any_dur);
+  EXPECT_LT(-inf, inf);
+  EXPECT_GT(inf, -inf);
+}
+
+TEST(Duration, InfinityAddition) {
+  const absl::Duration sec_max = absl::Seconds(kint64max);
+  const absl::Duration sec_min = absl::Seconds(kint64min);
+  const absl::Duration any_dur = absl::Seconds(1);
+  const absl::Duration inf = absl::InfiniteDuration();
+
+  // Addition
+  EXPECT_EQ(inf, inf + inf);
+  EXPECT_EQ(inf, inf + -inf);
+  EXPECT_EQ(-inf, -inf + inf);
+  EXPECT_EQ(-inf, -inf + -inf);
+
+  EXPECT_EQ(inf, inf + any_dur);
+  EXPECT_EQ(inf, any_dur + inf);
+  EXPECT_EQ(-inf, -inf + any_dur);
+  EXPECT_EQ(-inf, any_dur + -inf);
+
+  // Interesting case
+  absl::Duration almost_inf = sec_max + absl::Nanoseconds(999999999);
+  EXPECT_GT(inf, almost_inf);
+  almost_inf += -absl::Nanoseconds(999999999);
+  EXPECT_GT(inf, almost_inf);
+
+  // Addition overflow/underflow
+  EXPECT_EQ(inf, sec_max + absl::Seconds(1));
+  EXPECT_EQ(inf, sec_max + sec_max);
+  EXPECT_EQ(-inf, sec_min + -absl::Seconds(1));
+  EXPECT_EQ(-inf, sec_min + -sec_max);
+
+  // For reference: IEEE 754 behavior
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+  EXPECT_TRUE(std::isinf(dbl_inf + dbl_inf));
+  EXPECT_TRUE(std::isnan(dbl_inf + -dbl_inf));  // We return inf
+  EXPECT_TRUE(std::isnan(-dbl_inf + dbl_inf));  // We return inf
+  EXPECT_TRUE(std::isinf(-dbl_inf + -dbl_inf));
+}
+
+TEST(Duration, InfinitySubtraction) {
+  const absl::Duration sec_max = absl::Seconds(kint64max);
+  const absl::Duration sec_min = absl::Seconds(kint64min);
+  const absl::Duration any_dur = absl::Seconds(1);
+  const absl::Duration inf = absl::InfiniteDuration();
+
+  // Subtraction
+  EXPECT_EQ(inf, inf - inf);
+  EXPECT_EQ(inf, inf - -inf);
+  EXPECT_EQ(-inf, -inf - inf);
+  EXPECT_EQ(-inf, -inf - -inf);
+
+  EXPECT_EQ(inf, inf - any_dur);
+  EXPECT_EQ(-inf, any_dur - inf);
+  EXPECT_EQ(-inf, -inf - any_dur);
+  EXPECT_EQ(inf, any_dur - -inf);
+
+  // Subtraction overflow/underflow
+  EXPECT_EQ(inf, sec_max - -absl::Seconds(1));
+  EXPECT_EQ(inf, sec_max - -sec_max);
+  EXPECT_EQ(-inf, sec_min - absl::Seconds(1));
+  EXPECT_EQ(-inf, sec_min - sec_max);
+
+  // Interesting case
+  absl::Duration almost_neg_inf = sec_min;
+  EXPECT_LT(-inf, almost_neg_inf);
+  almost_neg_inf -= -absl::Nanoseconds(1);
+  EXPECT_LT(-inf, almost_neg_inf);
+
+  // For reference: IEEE 754 behavior
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+  EXPECT_TRUE(std::isnan(dbl_inf - dbl_inf));  // We return inf
+  EXPECT_TRUE(std::isinf(dbl_inf - -dbl_inf));
+  EXPECT_TRUE(std::isinf(-dbl_inf - dbl_inf));
+  EXPECT_TRUE(std::isnan(-dbl_inf - -dbl_inf));  // We return inf
+}
+
+TEST(Duration, InfinityMultiplication) {
+  const absl::Duration sec_max = absl::Seconds(kint64max);
+  const absl::Duration sec_min = absl::Seconds(kint64min);
+  const absl::Duration inf = absl::InfiniteDuration();
+
+#define TEST_INF_MUL_WITH_TYPE(T)                                     \
+  EXPECT_EQ(inf, inf * static_cast<T>(2));                            \
+  EXPECT_EQ(-inf, inf * static_cast<T>(-2));                          \
+  EXPECT_EQ(-inf, -inf * static_cast<T>(2));                          \
+  EXPECT_EQ(inf, -inf * static_cast<T>(-2));                          \
+  EXPECT_EQ(inf, inf * static_cast<T>(0));                            \
+  EXPECT_EQ(-inf, -inf * static_cast<T>(0));                          \
+  EXPECT_EQ(inf, sec_max * static_cast<T>(2));                        \
+  EXPECT_EQ(inf, sec_min * static_cast<T>(-2));                       \
+  EXPECT_EQ(inf, (sec_max / static_cast<T>(2)) * static_cast<T>(3));  \
+  EXPECT_EQ(-inf, sec_max * static_cast<T>(-2));                      \
+  EXPECT_EQ(-inf, sec_min * static_cast<T>(2));                       \
+  EXPECT_EQ(-inf, (sec_min / static_cast<T>(2)) * static_cast<T>(3));
+
+  TEST_INF_MUL_WITH_TYPE(int64_t);  // NOLINT(readability/function)
+  TEST_INF_MUL_WITH_TYPE(double);   // NOLINT(readability/function)
+
+#undef TEST_INF_MUL_WITH_TYPE
+
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(inf, inf * dbl_inf);
+  EXPECT_EQ(-inf, -inf * dbl_inf);
+  EXPECT_EQ(-inf, inf * -dbl_inf);
+  EXPECT_EQ(inf, -inf * -dbl_inf);
+
+  const absl::Duration any_dur = absl::Seconds(1);
+  EXPECT_EQ(inf, any_dur * dbl_inf);
+  EXPECT_EQ(-inf, -any_dur * dbl_inf);
+  EXPECT_EQ(-inf, any_dur * -dbl_inf);
+  EXPECT_EQ(inf, -any_dur * -dbl_inf);
+
+  // Fixed-point multiplication will produce a finite value, whereas floating
+  // point fuzziness will overflow to inf.
+  EXPECT_NE(absl::InfiniteDuration(), absl::Seconds(1) * kint64max);
+  EXPECT_EQ(inf, absl::Seconds(1) * static_cast<double>(kint64max));
+  EXPECT_NE(-absl::InfiniteDuration(), absl::Seconds(1) * kint64min);
+  EXPECT_EQ(-inf, absl::Seconds(1) * static_cast<double>(kint64min));
+
+  // Note that sec_max * or / by 1.0 overflows to inf due to the 53-bit
+  // limitations of double.
+  EXPECT_NE(inf, sec_max);
+  EXPECT_NE(inf, sec_max / 1);
+  EXPECT_EQ(inf, sec_max / 1.0);
+  EXPECT_NE(inf, sec_max * 1);
+  EXPECT_EQ(inf, sec_max * 1.0);
+}
+
+TEST(Duration, InfinityDivision) {
+  const absl::Duration sec_max = absl::Seconds(kint64max);
+  const absl::Duration sec_min = absl::Seconds(kint64min);
+  const absl::Duration inf = absl::InfiniteDuration();
+
+  // Division of Duration by a double
+#define TEST_INF_DIV_WITH_TYPE(T)            \
+  EXPECT_EQ(inf, inf / static_cast<T>(2));   \
+  EXPECT_EQ(-inf, inf / static_cast<T>(-2)); \
+  EXPECT_EQ(-inf, -inf / static_cast<T>(2)); \
+  EXPECT_EQ(inf, -inf / static_cast<T>(-2));
+
+  TEST_INF_DIV_WITH_TYPE(int64_t);  // NOLINT(readability/function)
+  TEST_INF_DIV_WITH_TYPE(double);   // NOLINT(readability/function)
+
+#undef TEST_INF_DIV_WITH_TYPE
+
+  // Division of Duration by a double overflow/underflow
+  EXPECT_EQ(inf, sec_max / 0.5);
+  EXPECT_EQ(inf, sec_min / -0.5);
+  EXPECT_EQ(inf, ((sec_max / 0.5) + absl::Seconds(1)) / 0.5);
+  EXPECT_EQ(-inf, sec_max / -0.5);
+  EXPECT_EQ(-inf, sec_min / 0.5);
+  EXPECT_EQ(-inf, ((sec_min / 0.5) - absl::Seconds(1)) / 0.5);
+
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(inf, inf / dbl_inf);
+  EXPECT_EQ(-inf, inf / -dbl_inf);
+  EXPECT_EQ(-inf, -inf / dbl_inf);
+  EXPECT_EQ(inf, -inf / -dbl_inf);
+
+  const absl::Duration any_dur = absl::Seconds(1);
+  EXPECT_EQ(absl::ZeroDuration(), any_dur / dbl_inf);
+  EXPECT_EQ(absl::ZeroDuration(), any_dur / -dbl_inf);
+  EXPECT_EQ(absl::ZeroDuration(), -any_dur / dbl_inf);
+  EXPECT_EQ(absl::ZeroDuration(), -any_dur / -dbl_inf);
+}
+
+TEST(Duration, InfinityModulus) {
+  const absl::Duration sec_max = absl::Seconds(kint64max);
+  const absl::Duration any_dur = absl::Seconds(1);
+  const absl::Duration inf = absl::InfiniteDuration();
+
+  EXPECT_EQ(inf, inf % inf);
+  EXPECT_EQ(inf, inf % -inf);
+  EXPECT_EQ(-inf, -inf % -inf);
+  EXPECT_EQ(-inf, -inf % inf);
+
+  EXPECT_EQ(any_dur, any_dur % inf);
+  EXPECT_EQ(any_dur, any_dur % -inf);
+  EXPECT_EQ(-any_dur, -any_dur % inf);
+  EXPECT_EQ(-any_dur, -any_dur % -inf);
+
+  EXPECT_EQ(inf, inf % -any_dur);
+  EXPECT_EQ(inf, inf % any_dur);
+  EXPECT_EQ(-inf, -inf % -any_dur);
+  EXPECT_EQ(-inf, -inf % any_dur);
+
+  // Remainder isn't affected by overflow.
+  EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Seconds(1));
+  EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Milliseconds(1));
+  EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Microseconds(1));
+  EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1));
+  EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1) / 4);
+}
+
+TEST(Duration, InfinityIDiv) {
+  const absl::Duration sec_max = absl::Seconds(kint64max);
+  const absl::Duration any_dur = absl::Seconds(1);
+  const absl::Duration inf = absl::InfiniteDuration();
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+
+  // IDivDuration (int64_t return value + a remainer)
+  absl::Duration rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64max, absl::IDivDuration(inf, inf, &rem));
+  EXPECT_EQ(inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -inf, &rem));
+  EXPECT_EQ(-inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64max, absl::IDivDuration(inf, any_dur, &rem));
+  EXPECT_EQ(inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(0, absl::IDivDuration(any_dur, inf, &rem));
+  EXPECT_EQ(any_dur, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -any_dur, &rem));
+  EXPECT_EQ(-inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(0, absl::IDivDuration(-any_dur, -inf, &rem));
+  EXPECT_EQ(-any_dur, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64min, absl::IDivDuration(-inf, inf, &rem));
+  EXPECT_EQ(-inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64min, absl::IDivDuration(inf, -inf, &rem));
+  EXPECT_EQ(inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64min, absl::IDivDuration(-inf, any_dur, &rem));
+  EXPECT_EQ(-inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(0, absl::IDivDuration(-any_dur, inf, &rem));
+  EXPECT_EQ(-any_dur, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(kint64min, absl::IDivDuration(inf, -any_dur, &rem));
+  EXPECT_EQ(inf, rem);
+
+  rem = absl::ZeroDuration();
+  EXPECT_EQ(0, absl::IDivDuration(any_dur, -inf, &rem));
+  EXPECT_EQ(any_dur, rem);
+
+  // IDivDuration overflow/underflow
+  rem = any_dur;
+  EXPECT_EQ(kint64max,
+            absl::IDivDuration(sec_max, absl::Nanoseconds(1) / 4, &rem));
+  EXPECT_EQ(sec_max - absl::Nanoseconds(kint64max) / 4, rem);
+
+  rem = any_dur;
+  EXPECT_EQ(kint64max,
+            absl::IDivDuration(sec_max, absl::Milliseconds(1), &rem));
+  EXPECT_EQ(sec_max - absl::Milliseconds(kint64max), rem);
+
+  rem = any_dur;
+  EXPECT_EQ(kint64max,
+            absl::IDivDuration(-sec_max, -absl::Milliseconds(1), &rem));
+  EXPECT_EQ(-sec_max + absl::Milliseconds(kint64max), rem);
+
+  rem = any_dur;
+  EXPECT_EQ(kint64min,
+            absl::IDivDuration(-sec_max, absl::Milliseconds(1), &rem));
+  EXPECT_EQ(-sec_max - absl::Milliseconds(kint64min), rem);
+
+  rem = any_dur;
+  EXPECT_EQ(kint64min,
+            absl::IDivDuration(sec_max, -absl::Milliseconds(1), &rem));
+  EXPECT_EQ(sec_max + absl::Milliseconds(kint64min), rem);
+
+  //
+  // operator/(Duration, Duration) is a wrapper for IDivDuration().
+  //
+
+  // IEEE 754 says inf / inf should be nan, but int64_t doesn't have
+  // nan so we'll return kint64max/kint64min instead.
+  EXPECT_TRUE(std::isnan(dbl_inf / dbl_inf));
+  EXPECT_EQ(kint64max, inf / inf);
+  EXPECT_EQ(kint64max, -inf / -inf);
+  EXPECT_EQ(kint64min, -inf / inf);
+  EXPECT_EQ(kint64min, inf / -inf);
+
+  EXPECT_TRUE(std::isinf(dbl_inf / 2.0));
+  EXPECT_EQ(kint64max, inf / any_dur);
+  EXPECT_EQ(kint64max, -inf / -any_dur);
+  EXPECT_EQ(kint64min, -inf / any_dur);
+  EXPECT_EQ(kint64min, inf / -any_dur);
+
+  EXPECT_EQ(0.0, 2.0 / dbl_inf);
+  EXPECT_EQ(0, any_dur / inf);
+  EXPECT_EQ(0, any_dur / -inf);
+  EXPECT_EQ(0, -any_dur / inf);
+  EXPECT_EQ(0, -any_dur / -inf);
+  EXPECT_EQ(0, absl::ZeroDuration() / inf);
+
+  // Division of Duration by a Duration overflow/underflow
+  EXPECT_EQ(kint64max, sec_max / absl::Milliseconds(1));
+  EXPECT_EQ(kint64max, -sec_max / -absl::Milliseconds(1));
+  EXPECT_EQ(kint64min, -sec_max / absl::Milliseconds(1));
+  EXPECT_EQ(kint64min, sec_max / -absl::Milliseconds(1));
+}
+
+TEST(Duration, InfinityFDiv) {
+  const absl::Duration any_dur = absl::Seconds(1);
+  const absl::Duration inf = absl::InfiniteDuration();
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+
+  EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, inf));
+  EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -inf));
+  EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, any_dur));
+  EXPECT_EQ(0.0, absl::FDivDuration(any_dur, inf));
+  EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -any_dur));
+  EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, -inf));
+
+  EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, inf));
+  EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -inf));
+  EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, any_dur));
+  EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, inf));
+  EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -any_dur));
+  EXPECT_EQ(0.0, absl::FDivDuration(any_dur, -inf));
+}
+
+TEST(Duration, DivisionByZero) {
+  const absl::Duration zero = absl::ZeroDuration();
+  const absl::Duration inf = absl::InfiniteDuration();
+  const absl::Duration any_dur = absl::Seconds(1);
+  const double dbl_inf = std::numeric_limits<double>::infinity();
+  const double dbl_denorm = std::numeric_limits<double>::denorm_min();
+
+  // IEEE 754 behavior
+  double z = 0.0, two = 2.0;
+  EXPECT_TRUE(std::isinf(two / z));
+  EXPECT_TRUE(std::isnan(z / z));  // We'll return inf
+
+  // Operator/(Duration, double)
+  EXPECT_EQ(inf, zero / 0.0);
+  EXPECT_EQ(-inf, zero / -0.0);
+  EXPECT_EQ(inf, any_dur / 0.0);
+  EXPECT_EQ(-inf, any_dur / -0.0);
+  EXPECT_EQ(-inf, -any_dur / 0.0);
+  EXPECT_EQ(inf, -any_dur / -0.0);
+
+  // Tests dividing by a number very close to, but not quite zero.
+  EXPECT_EQ(zero, zero / dbl_denorm);
+  EXPECT_EQ(zero, zero / -dbl_denorm);
+  EXPECT_EQ(inf, any_dur / dbl_denorm);
+  EXPECT_EQ(-inf, any_dur / -dbl_denorm);
+  EXPECT_EQ(-inf, -any_dur / dbl_denorm);
+  EXPECT_EQ(inf, -any_dur / -dbl_denorm);
+
+  // IDiv
+  absl::Duration rem = zero;
+  EXPECT_EQ(kint64max, absl::IDivDuration(zero, zero, &rem));
+  EXPECT_EQ(inf, rem);
+
+  rem = zero;
+  EXPECT_EQ(kint64max, absl::IDivDuration(any_dur, zero, &rem));
+  EXPECT_EQ(inf, rem);
+
+  rem = zero;
+  EXPECT_EQ(kint64min, absl::IDivDuration(-any_dur, zero, &rem));
+  EXPECT_EQ(-inf, rem);
+
+  // Operator/(Duration, Duration)
+  EXPECT_EQ(kint64max, zero / zero);
+  EXPECT_EQ(kint64max, any_dur / zero);
+  EXPECT_EQ(kint64min, -any_dur / zero);
+
+  // FDiv
+  EXPECT_EQ(dbl_inf, absl::FDivDuration(zero, zero));
+  EXPECT_EQ(dbl_inf, absl::FDivDuration(any_dur, zero));
+  EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero));
+}
+
+TEST(Duration, Range) {
+  const absl::Duration range = ApproxYears(100 * 1e9);
+  const absl::Duration range_future = range;
+  const absl::Duration range_past = -range;
+
+  EXPECT_LT(range_future, absl::InfiniteDuration());
+  EXPECT_GT(range_past, -absl::InfiniteDuration());
+
+  const absl::Duration full_range = range_future - range_past;
+  EXPECT_GT(full_range, absl::ZeroDuration());
+  EXPECT_LT(full_range, absl::InfiniteDuration());
+
+  const absl::Duration neg_full_range = range_past - range_future;
+  EXPECT_LT(neg_full_range, absl::ZeroDuration());
+  EXPECT_GT(neg_full_range, -absl::InfiniteDuration());
+
+  EXPECT_LT(neg_full_range, full_range);
+  EXPECT_EQ(neg_full_range, -full_range);
+}
+
+TEST(Duration, RelationalOperators) {
+#define TEST_REL_OPS(UNIT)               \
+  static_assert(UNIT(2) == UNIT(2), ""); \
+  static_assert(UNIT(1) != UNIT(2), ""); \
+  static_assert(UNIT(1) < UNIT(2), "");  \
+  static_assert(UNIT(3) > UNIT(2), "");  \
+  static_assert(UNIT(1) <= UNIT(2), ""); \
+  static_assert(UNIT(2) <= UNIT(2), ""); \
+  static_assert(UNIT(3) >= UNIT(2), ""); \
+  static_assert(UNIT(2) >= UNIT(2), "");
+
+  TEST_REL_OPS(absl::Nanoseconds);
+  TEST_REL_OPS(absl::Microseconds);
+  TEST_REL_OPS(absl::Milliseconds);
+  TEST_REL_OPS(absl::Seconds);
+  TEST_REL_OPS(absl::Minutes);
+  TEST_REL_OPS(absl::Hours);
+
+#undef TEST_REL_OPS
+}
+
+TEST(Duration, Addition) {
+#define TEST_ADD_OPS(UNIT)                  \
+  do {                                      \
+    EXPECT_EQ(UNIT(2), UNIT(1) + UNIT(1));  \
+    EXPECT_EQ(UNIT(1), UNIT(2) - UNIT(1));  \
+    EXPECT_EQ(UNIT(0), UNIT(2) - UNIT(2));  \
+    EXPECT_EQ(UNIT(-1), UNIT(1) - UNIT(2)); \
+    EXPECT_EQ(UNIT(-2), UNIT(0) - UNIT(2)); \
+    EXPECT_EQ(UNIT(-2), UNIT(1) - UNIT(3)); \
+    absl::Duration a = UNIT(1);             \
+    a += UNIT(1);                           \
+    EXPECT_EQ(UNIT(2), a);                  \
+    a -= UNIT(1);                           \
+    EXPECT_EQ(UNIT(1), a);                  \
+  } while (0)
+
+  TEST_ADD_OPS(absl::Nanoseconds);
+  TEST_ADD_OPS(absl::Microseconds);
+  TEST_ADD_OPS(absl::Milliseconds);
+  TEST_ADD_OPS(absl::Seconds);
+  TEST_ADD_OPS(absl::Minutes);
+  TEST_ADD_OPS(absl::Hours);
+
+#undef TEST_ADD_OPS
+
+  EXPECT_EQ(absl::Seconds(2), absl::Seconds(3) - 2 * absl::Milliseconds(500));
+  EXPECT_EQ(absl::Seconds(2) + absl::Milliseconds(500),
+            absl::Seconds(3) - absl::Milliseconds(500));
+
+  EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(998),
+            absl::Milliseconds(999) + absl::Milliseconds(999));
+
+  EXPECT_EQ(absl::Milliseconds(-1),
+            absl::Milliseconds(998) - absl::Milliseconds(999));
+
+  // Tests fractions of a nanoseconds. These are implementation details only.
+  EXPECT_GT(absl::Nanoseconds(1), absl::Nanoseconds(1) / 2);
+  EXPECT_EQ(absl::Nanoseconds(1),
+            absl::Nanoseconds(1) / 2 + absl::Nanoseconds(1) / 2);
+  EXPECT_GT(absl::Nanoseconds(1) / 4, absl::Nanoseconds(0));
+  EXPECT_EQ(absl::Nanoseconds(1) / 8, absl::Nanoseconds(0));
+
+  // Tests subtraction that will cause wrap around of the rep_lo_ bits.
+  absl::Duration d_7_5 = absl::Seconds(7) + absl::Milliseconds(500);
+  absl::Duration d_3_7 = absl::Seconds(3) + absl::Milliseconds(700);
+  absl::Duration ans_3_8 = absl::Seconds(3) + absl::Milliseconds(800);
+  EXPECT_EQ(ans_3_8, d_7_5 - d_3_7);
+
+  // Subtracting min_duration
+  absl::Duration min_dur = absl::Seconds(kint64min);
+  EXPECT_EQ(absl::Seconds(0), min_dur - min_dur);
+  EXPECT_EQ(absl::Seconds(kint64max), absl::Seconds(-1) - min_dur);
+}
+
+TEST(Duration, Negation) {
+  // By storing negations of various values in constexpr variables we
+  // verify that the initializers are constant expressions.
+  constexpr absl::Duration negated_zero_duration = -absl::ZeroDuration();
+  EXPECT_EQ(negated_zero_duration, absl::ZeroDuration());
+
+  constexpr absl::Duration negated_infinite_duration =
+      -absl::InfiniteDuration();
+  EXPECT_NE(negated_infinite_duration, absl::InfiniteDuration());
+  EXPECT_EQ(-negated_infinite_duration, absl::InfiniteDuration());
+
+  // The public APIs to check if a duration is infinite depend on using
+  // -InfiniteDuration(), but we're trying to test operator- here, so we
+  // need to use the lower-level internal query IsInfiniteDuration.
+  EXPECT_TRUE(
+      absl::time_internal::IsInfiniteDuration(negated_infinite_duration));
+
+  // The largest Duration is kint64max seconds and kTicksPerSecond - 1 ticks.
+  // Using the absl::time_internal::MakeDuration API is the cleanest way to
+  // construct that Duration.
+  constexpr absl::Duration max_duration = absl::time_internal::MakeDuration(
+      kint64max, absl::time_internal::kTicksPerSecond - 1);
+  constexpr absl::Duration negated_max_duration = -max_duration;
+  // The largest negatable value is one tick above the minimum representable;
+  // it's the negation of max_duration.
+  constexpr absl::Duration nearly_min_duration =
+      absl::time_internal::MakeDuration(kint64min, int64_t{1});
+  constexpr absl::Duration negated_nearly_min_duration = -nearly_min_duration;
+
+  EXPECT_EQ(negated_max_duration, nearly_min_duration);
+  EXPECT_EQ(negated_nearly_min_duration, max_duration);
+  EXPECT_EQ(-(-max_duration), max_duration);
+
+  constexpr absl::Duration min_duration =
+      absl::time_internal::MakeDuration(kint64min);
+  constexpr absl::Duration negated_min_duration = -min_duration;
+  EXPECT_EQ(negated_min_duration, absl::InfiniteDuration());
+}
+
+TEST(Duration, AbsoluteValue) {
+  EXPECT_EQ(absl::ZeroDuration(), AbsDuration(absl::ZeroDuration()));
+  EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(1)));
+  EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(-1)));
+
+  EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(absl::InfiniteDuration()));
+  EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(-absl::InfiniteDuration()));
+
+  absl::Duration max_dur =
+      absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4);
+  EXPECT_EQ(max_dur, AbsDuration(max_dur));
+
+  absl::Duration min_dur = absl::Seconds(kint64min);
+  EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(min_dur));
+  EXPECT_EQ(max_dur, AbsDuration(min_dur + absl::Nanoseconds(1) / 4));
+}
+
+TEST(Duration, Multiplication) {
+#define TEST_MUL_OPS(UNIT)                                    \
+  do {                                                        \
+    EXPECT_EQ(UNIT(5), UNIT(2) * 2.5);                        \
+    EXPECT_EQ(UNIT(2), UNIT(5) / 2.5);                        \
+    EXPECT_EQ(UNIT(-5), UNIT(-2) * 2.5);                      \
+    EXPECT_EQ(UNIT(-5), -UNIT(2) * 2.5);                      \
+    EXPECT_EQ(UNIT(-5), UNIT(2) * -2.5);                      \
+    EXPECT_EQ(UNIT(-2), UNIT(-5) / 2.5);                      \
+    EXPECT_EQ(UNIT(-2), -UNIT(5) / 2.5);                      \
+    EXPECT_EQ(UNIT(-2), UNIT(5) / -2.5);                      \
+    EXPECT_EQ(UNIT(2), UNIT(11) % UNIT(3));                   \
+    absl::Duration a = UNIT(2);                               \
+    a *= 2.5;                                                 \
+    EXPECT_EQ(UNIT(5), a);                                    \
+    a /= 2.5;                                                 \
+    EXPECT_EQ(UNIT(2), a);                                    \
+    a %= UNIT(1);                                             \
+    EXPECT_EQ(UNIT(0), a);                                    \
+    absl::Duration big = UNIT(1000000000);                    \
+    big *= 3;                                                 \
+    big /= 3;                                                 \
+    EXPECT_EQ(UNIT(1000000000), big);                         \
+    EXPECT_EQ(-UNIT(2), -UNIT(2));                            \
+    EXPECT_EQ(-UNIT(2), UNIT(2) * -1);                        \
+    EXPECT_EQ(-UNIT(2), -1 * UNIT(2));                        \
+    EXPECT_EQ(-UNIT(-2), UNIT(2));                            \
+    EXPECT_EQ(2, UNIT(2) / UNIT(1));                          \
+    absl::Duration rem;                                       \
+    EXPECT_EQ(2, absl::IDivDuration(UNIT(2), UNIT(1), &rem)); \
+    EXPECT_EQ(2.0, absl::FDivDuration(UNIT(2), UNIT(1)));     \
+  } while (0)
+
+  TEST_MUL_OPS(absl::Nanoseconds);
+  TEST_MUL_OPS(absl::Microseconds);
+  TEST_MUL_OPS(absl::Milliseconds);
+  TEST_MUL_OPS(absl::Seconds);
+  TEST_MUL_OPS(absl::Minutes);
+  TEST_MUL_OPS(absl::Hours);
+
+#undef TEST_MUL_OPS
+
+  // Ensures that multiplication and division by 1 with a maxed-out durations
+  // doesn't lose precision.
+  absl::Duration max_dur =
+      absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4);
+  absl::Duration min_dur = absl::Seconds(kint64min);
+  EXPECT_EQ(max_dur, max_dur * 1);
+  EXPECT_EQ(max_dur, max_dur / 1);
+  EXPECT_EQ(min_dur, min_dur * 1);
+  EXPECT_EQ(min_dur, min_dur / 1);
+
+  // Tests division on a Duration with a large number of significant digits.
+  // Tests when the digits span hi and lo as well as only in hi.
+  absl::Duration sigfigs = absl::Seconds(2000000000) + absl::Nanoseconds(3);
+  EXPECT_EQ(absl::Seconds(666666666) + absl::Nanoseconds(666666667) +
+                absl::Nanoseconds(1) / 2,
+            sigfigs / 3);
+  sigfigs = absl::Seconds(7000000000LL);
+  EXPECT_EQ(absl::Seconds(2333333333) + absl::Nanoseconds(333333333) +
+                absl::Nanoseconds(1) / 4,
+            sigfigs / 3);
+
+  EXPECT_EQ(absl::Seconds(7) + absl::Milliseconds(500), absl::Seconds(3) * 2.5);
+  EXPECT_EQ(absl::Seconds(8) * -1 + absl::Milliseconds(300),
+            (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5);
+  EXPECT_EQ(-absl::Seconds(8) + absl::Milliseconds(300),
+            (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5);
+  EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(875),
+            (absl::Seconds(7) + absl::Milliseconds(500)) / 4);
+  EXPECT_EQ(absl::Seconds(30),
+            (absl::Seconds(7) + absl::Milliseconds(500)) / 0.25);
+  EXPECT_EQ(absl::Seconds(3),
+            (absl::Seconds(7) + absl::Milliseconds(500)) / 2.5);
+
+  // Tests division remainder.
+  EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(7) % absl::Nanoseconds(1));
+  EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(0) % absl::Nanoseconds(10));
+  EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(7) % absl::Nanoseconds(5));
+  EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(2) % absl::Nanoseconds(5));
+
+  EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(10) % absl::Nanoseconds(3));
+  EXPECT_EQ(absl::Nanoseconds(1),
+            absl::Nanoseconds(10) % absl::Nanoseconds(-3));
+  EXPECT_EQ(absl::Nanoseconds(-1),
+            absl::Nanoseconds(-10) % absl::Nanoseconds(3));
+  EXPECT_EQ(absl::Nanoseconds(-1),
+            absl::Nanoseconds(-10) % absl::Nanoseconds(-3));
+
+  EXPECT_EQ(absl::Milliseconds(100),
+            absl::Seconds(1) % absl::Milliseconds(300));
+  EXPECT_EQ(
+      absl::Milliseconds(300),
+      (absl::Seconds(3) + absl::Milliseconds(800)) % absl::Milliseconds(500));
+
+  EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(1) % absl::Seconds(1));
+  EXPECT_EQ(absl::Nanoseconds(-1), absl::Nanoseconds(-1) % absl::Seconds(1));
+  EXPECT_EQ(0, absl::Nanoseconds(-1) / absl::Seconds(1));  // Actual -1e-9
+
+  // Tests identity a = (a/b)*b + a%b
+#define TEST_MOD_IDENTITY(a, b) \
+  EXPECT_EQ((a), ((a) / (b))*(b) + ((a)%(b)))
+
+  TEST_MOD_IDENTITY(absl::Seconds(0), absl::Seconds(2));
+  TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(1));
+  TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(2));
+  TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(1));
+
+  TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(1));
+  TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(-1));
+  TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(-1));
+
+  TEST_MOD_IDENTITY(absl::Nanoseconds(0), absl::Nanoseconds(2));
+  TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(1));
+  TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(2));
+  TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(1));
+
+  TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(1));
+  TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(-1));
+  TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(-1));
+
+  // Mixed seconds + subseconds
+  absl::Duration mixed_a = absl::Seconds(1) + absl::Nanoseconds(2);
+  absl::Duration mixed_b = absl::Seconds(1) + absl::Nanoseconds(3);
+
+  TEST_MOD_IDENTITY(absl::Seconds(0), mixed_a);
+  TEST_MOD_IDENTITY(mixed_a, mixed_a);
+  TEST_MOD_IDENTITY(mixed_a, mixed_b);
+  TEST_MOD_IDENTITY(mixed_b, mixed_a);
+
+  TEST_MOD_IDENTITY(-mixed_a, mixed_b);
+  TEST_MOD_IDENTITY(mixed_a, -mixed_b);
+  TEST_MOD_IDENTITY(-mixed_a, -mixed_b);
+
+#undef TEST_MOD_IDENTITY
+}
+
+TEST(Duration, Truncation) {
+  const absl::Duration d = absl::Nanoseconds(1234567890);
+  const absl::Duration inf = absl::InfiniteDuration();
+  for (int unit_sign : {1, -1}) {  // sign shouldn't matter
+    EXPECT_EQ(absl::Nanoseconds(1234567890),
+              Trunc(d, unit_sign * absl::Nanoseconds(1)));
+    EXPECT_EQ(absl::Microseconds(1234567),
+              Trunc(d, unit_sign * absl::Microseconds(1)));
+    EXPECT_EQ(absl::Milliseconds(1234),
+              Trunc(d, unit_sign * absl::Milliseconds(1)));
+    EXPECT_EQ(absl::Seconds(1), Trunc(d, unit_sign * absl::Seconds(1)));
+    EXPECT_EQ(inf, Trunc(inf, unit_sign * absl::Seconds(1)));
+
+    EXPECT_EQ(absl::Nanoseconds(-1234567890),
+              Trunc(-d, unit_sign * absl::Nanoseconds(1)));
+    EXPECT_EQ(absl::Microseconds(-1234567),
+              Trunc(-d, unit_sign * absl::Microseconds(1)));
+    EXPECT_EQ(absl::Milliseconds(-1234),
+              Trunc(-d, unit_sign * absl::Milliseconds(1)));
+    EXPECT_EQ(absl::Seconds(-1), Trunc(-d, unit_sign * absl::Seconds(1)));
+    EXPECT_EQ(-inf, Trunc(-inf, unit_sign * absl::Seconds(1)));
+  }
+}
+
+TEST(Duration, Flooring) {
+  const absl::Duration d = absl::Nanoseconds(1234567890);
+  const absl::Duration inf = absl::InfiniteDuration();
+  for (int unit_sign : {1, -1}) {  // sign shouldn't matter
+    EXPECT_EQ(absl::Nanoseconds(1234567890),
+              absl::Floor(d, unit_sign * absl::Nanoseconds(1)));
+    EXPECT_EQ(absl::Microseconds(1234567),
+              absl::Floor(d, unit_sign * absl::Microseconds(1)));
+    EXPECT_EQ(absl::Milliseconds(1234),
+              absl::Floor(d, unit_sign * absl::Milliseconds(1)));
+    EXPECT_EQ(absl::Seconds(1), absl::Floor(d, unit_sign * absl::Seconds(1)));
+    EXPECT_EQ(inf, absl::Floor(inf, unit_sign * absl::Seconds(1)));
+
+    EXPECT_EQ(absl::Nanoseconds(-1234567890),
+              absl::Floor(-d, unit_sign * absl::Nanoseconds(1)));
+    EXPECT_EQ(absl::Microseconds(-1234568),
+              absl::Floor(-d, unit_sign * absl::Microseconds(1)));
+    EXPECT_EQ(absl::Milliseconds(-1235),
+              absl::Floor(-d, unit_sign * absl::Milliseconds(1)));
+    EXPECT_EQ(absl::Seconds(-2), absl::Floor(-d, unit_sign * absl::Seconds(1)));
+    EXPECT_EQ(-inf, absl::Floor(-inf, unit_sign * absl::Seconds(1)));
+  }
+}
+
+TEST(Duration, Ceiling) {
+  const absl::Duration d = absl::Nanoseconds(1234567890);
+  const absl::Duration inf = absl::InfiniteDuration();
+  for (int unit_sign : {1, -1}) {  // // sign shouldn't matter
+    EXPECT_EQ(absl::Nanoseconds(1234567890),
+              absl::Ceil(d, unit_sign * absl::Nanoseconds(1)));
+    EXPECT_EQ(absl::Microseconds(1234568),
+              absl::Ceil(d, unit_sign * absl::Microseconds(1)));
+    EXPECT_EQ(absl::Milliseconds(1235),
+              absl::Ceil(d, unit_sign * absl::Milliseconds(1)));
+    EXPECT_EQ(absl::Seconds(2), absl::Ceil(d, unit_sign * absl::Seconds(1)));
+    EXPECT_EQ(inf, absl::Ceil(inf, unit_sign * absl::Seconds(1)));
+
+    EXPECT_EQ(absl::Nanoseconds(-1234567890),
+              absl::Ceil(-d, unit_sign * absl::Nanoseconds(1)));
+    EXPECT_EQ(absl::Microseconds(-1234567),
+              absl::Ceil(-d, unit_sign * absl::Microseconds(1)));
+    EXPECT_EQ(absl::Milliseconds(-1234),
+              absl::Ceil(-d, unit_sign * absl::Milliseconds(1)));
+    EXPECT_EQ(absl::Seconds(-1), absl::Ceil(-d, unit_sign * absl::Seconds(1)));
+    EXPECT_EQ(-inf, absl::Ceil(-inf, unit_sign * absl::Seconds(1)));
+  }
+}
+
+TEST(Duration, RoundTripUnits) {
+  const int kRange = 100000;
+
+#define ROUND_TRIP_UNIT(U, LOW, HIGH)          \
+  do {                                         \
+    for (int64_t i = LOW; i < HIGH; ++i) {     \
+      absl::Duration d = absl::U(i);           \
+      if (d == absl::InfiniteDuration())       \
+        EXPECT_EQ(kint64max, d / absl::U(1));  \
+      else if (d == -absl::InfiniteDuration()) \
+        EXPECT_EQ(kint64min, d / absl::U(1));  \
+      else                                     \
+        EXPECT_EQ(i, absl::U(i) / absl::U(1)); \
+    }                                          \
+  } while (0)
+
+  ROUND_TRIP_UNIT(Nanoseconds, kint64min, kint64min + kRange);
+  ROUND_TRIP_UNIT(Nanoseconds, -kRange, kRange);
+  ROUND_TRIP_UNIT(Nanoseconds, kint64max - kRange, kint64max);
+
+  ROUND_TRIP_UNIT(Microseconds, kint64min, kint64min + kRange);
+  ROUND_TRIP_UNIT(Microseconds, -kRange, kRange);
+  ROUND_TRIP_UNIT(Microseconds, kint64max - kRange, kint64max);
+
+  ROUND_TRIP_UNIT(Milliseconds, kint64min, kint64min + kRange);
+  ROUND_TRIP_UNIT(Milliseconds, -kRange, kRange);
+  ROUND_TRIP_UNIT(Milliseconds, kint64max - kRange, kint64max);
+
+  ROUND_TRIP_UNIT(Seconds, kint64min, kint64min + kRange);
+  ROUND_TRIP_UNIT(Seconds, -kRange, kRange);
+  ROUND_TRIP_UNIT(Seconds, kint64max - kRange, kint64max);
+
+  ROUND_TRIP_UNIT(Minutes, kint64min / 60, kint64min / 60 + kRange);
+  ROUND_TRIP_UNIT(Minutes, -kRange, kRange);
+  ROUND_TRIP_UNIT(Minutes, kint64max / 60 - kRange, kint64max / 60);
+
+  ROUND_TRIP_UNIT(Hours, kint64min / 3600, kint64min / 3600 + kRange);
+  ROUND_TRIP_UNIT(Hours, -kRange, kRange);
+  ROUND_TRIP_UNIT(Hours, kint64max / 3600 - kRange, kint64max / 3600);
+
+#undef ROUND_TRIP_UNIT
+}
+
+TEST(Duration, TruncConversions) {
+  // Tests ToTimespec()/DurationFromTimespec()
+  const struct {
+    absl::Duration d;
+    timespec ts;
+  } to_ts[] = {
+      {absl::Seconds(1) + absl::Nanoseconds(1), {1, 1}},
+      {absl::Seconds(1) + absl::Nanoseconds(1) / 2, {1, 0}},
+      {absl::Seconds(1) + absl::Nanoseconds(0), {1, 0}},
+      {absl::Seconds(0) + absl::Nanoseconds(0), {0, 0}},
+      {absl::Seconds(0) - absl::Nanoseconds(1) / 2, {0, 0}},
+      {absl::Seconds(0) - absl::Nanoseconds(1), {-1, 999999999}},
+      {absl::Seconds(-1) + absl::Nanoseconds(1), {-1, 1}},
+      {absl::Seconds(-1) + absl::Nanoseconds(1) / 2, {-1, 1}},
+      {absl::Seconds(-1) + absl::Nanoseconds(0), {-1, 0}},
+      {absl::Seconds(-1) - absl::Nanoseconds(1) / 2, {-1, 0}},
+  };
+  for (const auto& test : to_ts) {
+    EXPECT_THAT(absl::ToTimespec(test.d), TimespecMatcher(test.ts));
+  }
+  const struct {
+    timespec ts;
+    absl::Duration d;
+  } from_ts[] = {
+      {{1, 1}, absl::Seconds(1) + absl::Nanoseconds(1)},
+      {{1, 0}, absl::Seconds(1) + absl::Nanoseconds(0)},
+      {{0, 0}, absl::Seconds(0) + absl::Nanoseconds(0)},
+      {{0, -1}, absl::Seconds(0) - absl::Nanoseconds(1)},
+      {{-1, 999999999}, absl::Seconds(0) - absl::Nanoseconds(1)},
+      {{-1, 1}, absl::Seconds(-1) + absl::Nanoseconds(1)},
+      {{-1, 0}, absl::Seconds(-1) + absl::Nanoseconds(0)},
+      {{-1, -1}, absl::Seconds(-1) - absl::Nanoseconds(1)},
+      {{-2, 999999999}, absl::Seconds(-1) - absl::Nanoseconds(1)},
+  };
+  for (const auto& test : from_ts) {
+    EXPECT_EQ(test.d, absl::DurationFromTimespec(test.ts));
+  }
+
+  // Tests ToTimeval()/DurationFromTimeval() (same as timespec above)
+  const struct {
+    absl::Duration d;
+    timeval tv;
+  } to_tv[] = {
+      {absl::Seconds(1) + absl::Microseconds(1), {1, 1}},
+      {absl::Seconds(1) + absl::Microseconds(1) / 2, {1, 0}},
+      {absl::Seconds(1) + absl::Microseconds(0), {1, 0}},
+      {absl::Seconds(0) + absl::Microseconds(0), {0, 0}},
+      {absl::Seconds(0) - absl::Microseconds(1) / 2, {0, 0}},
+      {absl::Seconds(0) - absl::Microseconds(1), {-1, 999999}},
+      {absl::Seconds(-1) + absl::Microseconds(1), {-1, 1}},
+      {absl::Seconds(-1) + absl::Microseconds(1) / 2, {-1, 1}},
+      {absl::Seconds(-1) + absl::Microseconds(0), {-1, 0}},
+      {absl::Seconds(-1) - absl::Microseconds(1) / 2, {-1, 0}},
+  };
+  for (const auto& test : to_tv) {
+    EXPECT_THAT(absl::ToTimeval(test.d), TimevalMatcher(test.tv));
+  }
+  const struct {
+    timeval tv;
+    absl::Duration d;
+  } from_tv[] = {
+      {{1, 1}, absl::Seconds(1) + absl::Microseconds(1)},
+      {{1, 0}, absl::Seconds(1) + absl::Microseconds(0)},
+      {{0, 0}, absl::Seconds(0) + absl::Microseconds(0)},
+      {{0, -1}, absl::Seconds(0) - absl::Microseconds(1)},
+      {{-1, 999999}, absl::Seconds(0) - absl::Microseconds(1)},
+      {{-1, 1}, absl::Seconds(-1) + absl::Microseconds(1)},
+      {{-1, 0}, absl::Seconds(-1) + absl::Microseconds(0)},
+      {{-1, -1}, absl::Seconds(-1) - absl::Microseconds(1)},
+      {{-2, 999999}, absl::Seconds(-1) - absl::Microseconds(1)},
+  };
+  for (const auto& test : from_tv) {
+    EXPECT_EQ(test.d, absl::DurationFromTimeval(test.tv));
+  }
+}
+
+TEST(Duration, SmallConversions) {
+  // Special tests for conversions of small durations.
+
+  EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0));
+  // TODO(bww): Is the next one OK?
+  EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0.124999999e-9));
+  EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.125e-9));
+  EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.250e-9));
+  EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.375e-9));
+  EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.500e-9));
+  EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.625e-9));
+  EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.750e-9));
+  EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(0.875e-9));
+  EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(1.000e-9));
+
+  timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(0)), TimespecMatcher(ts));
+  // TODO(bww): Are the next three OK?
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(1) / 4), TimespecMatcher(ts));
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(2) / 4), TimespecMatcher(ts));
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(3) / 4), TimespecMatcher(ts));
+  ts.tv_nsec = 1;
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(4) / 4), TimespecMatcher(ts));
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(5) / 4), TimespecMatcher(ts));
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(6) / 4), TimespecMatcher(ts));
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(7) / 4), TimespecMatcher(ts));
+  ts.tv_nsec = 2;
+  EXPECT_THAT(ToTimespec(absl::Nanoseconds(8) / 4), TimespecMatcher(ts));
+
+  timeval tv;
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+  EXPECT_THAT(ToTimeval(absl::Nanoseconds(0)), TimevalMatcher(tv));
+  // TODO(bww): Is the next one OK?
+  EXPECT_THAT(ToTimeval(absl::Nanoseconds(999)), TimevalMatcher(tv));
+  tv.tv_usec = 1;
+  EXPECT_THAT(ToTimeval(absl::Nanoseconds(1000)), TimevalMatcher(tv));
+  EXPECT_THAT(ToTimeval(absl::Nanoseconds(1999)), TimevalMatcher(tv));
+  tv.tv_usec = 2;
+  EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv));
+}
+
+TEST(Duration, ConversionSaturation) {
+  absl::Duration d;
+
+  const auto max_timeval_sec =
+      std::numeric_limits<decltype(timeval::tv_sec)>::max();
+  const auto min_timeval_sec =
+      std::numeric_limits<decltype(timeval::tv_sec)>::min();
+  timeval tv;
+  tv.tv_sec = max_timeval_sec;
+  tv.tv_usec = 999998;
+  d = absl::DurationFromTimeval(tv);
+  tv = ToTimeval(d);
+  EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(999998, tv.tv_usec);
+  d += absl::Microseconds(1);
+  tv = ToTimeval(d);
+  EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(999999, tv.tv_usec);
+  d += absl::Microseconds(1);  // no effect
+  tv = ToTimeval(d);
+  EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(999999, tv.tv_usec);
+
+  tv.tv_sec = min_timeval_sec;
+  tv.tv_usec = 1;
+  d = absl::DurationFromTimeval(tv);
+  tv = ToTimeval(d);
+  EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(1, tv.tv_usec);
+  d -= absl::Microseconds(1);
+  tv = ToTimeval(d);
+  EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(0, tv.tv_usec);
+  d -= absl::Microseconds(1);  // no effect
+  tv = ToTimeval(d);
+  EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(0, tv.tv_usec);
+
+  const auto max_timespec_sec =
+      std::numeric_limits<decltype(timespec::tv_sec)>::max();
+  const auto min_timespec_sec =
+      std::numeric_limits<decltype(timespec::tv_sec)>::min();
+  timespec ts;
+  ts.tv_sec = max_timespec_sec;
+  ts.tv_nsec = 999999998;
+  d = absl::DurationFromTimespec(ts);
+  ts = absl::ToTimespec(d);
+  EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(999999998, ts.tv_nsec);
+  d += absl::Nanoseconds(1);
+  ts = absl::ToTimespec(d);
+  EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(999999999, ts.tv_nsec);
+  d += absl::Nanoseconds(1);  // no effect
+  ts = absl::ToTimespec(d);
+  EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(999999999, ts.tv_nsec);
+
+  ts.tv_sec = min_timespec_sec;
+  ts.tv_nsec = 1;
+  d = absl::DurationFromTimespec(ts);
+  ts = absl::ToTimespec(d);
+  EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(1, ts.tv_nsec);
+  d -= absl::Nanoseconds(1);
+  ts = absl::ToTimespec(d);
+  EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(0, ts.tv_nsec);
+  d -= absl::Nanoseconds(1);  // no effect
+  ts = absl::ToTimespec(d);
+  EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(0, ts.tv_nsec);
+}
+
+TEST(Duration, FormatDuration) {
+  // Example from Go's docs.
+  EXPECT_EQ("72h3m0.5s",
+            absl::FormatDuration(absl::Hours(72) + absl::Minutes(3) +
+                                 absl::Milliseconds(500)));
+  // Go's largest time: 2540400h10m10.000000000s
+  EXPECT_EQ("2540400h10m10s",
+            absl::FormatDuration(absl::Hours(2540400) + absl::Minutes(10) +
+                                 absl::Seconds(10)));
+
+  EXPECT_EQ("0", absl::FormatDuration(absl::ZeroDuration()));
+  EXPECT_EQ("0", absl::FormatDuration(absl::Seconds(0)));
+  EXPECT_EQ("0", absl::FormatDuration(absl::Nanoseconds(0)));
+
+  EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1)));
+  EXPECT_EQ("1us", absl::FormatDuration(absl::Microseconds(1)));
+  EXPECT_EQ("1ms", absl::FormatDuration(absl::Milliseconds(1)));
+  EXPECT_EQ("1s", absl::FormatDuration(absl::Seconds(1)));
+  EXPECT_EQ("1m", absl::FormatDuration(absl::Minutes(1)));
+  EXPECT_EQ("1h", absl::FormatDuration(absl::Hours(1)));
+
+  EXPECT_EQ("1h1m", absl::FormatDuration(absl::Hours(1) + absl::Minutes(1)));
+  EXPECT_EQ("1h1s", absl::FormatDuration(absl::Hours(1) + absl::Seconds(1)));
+  EXPECT_EQ("1m1s", absl::FormatDuration(absl::Minutes(1) + absl::Seconds(1)));
+
+  EXPECT_EQ("1h0.25s",
+            absl::FormatDuration(absl::Hours(1) + absl::Milliseconds(250)));
+  EXPECT_EQ("1m0.25s",
+            absl::FormatDuration(absl::Minutes(1) + absl::Milliseconds(250)));
+  EXPECT_EQ("1h1m0.25s",
+            absl::FormatDuration(absl::Hours(1) + absl::Minutes(1) +
+                                 absl::Milliseconds(250)));
+  EXPECT_EQ("1h0.0005s",
+            absl::FormatDuration(absl::Hours(1) + absl::Microseconds(500)));
+  EXPECT_EQ("1h0.0000005s",
+            absl::FormatDuration(absl::Hours(1) + absl::Nanoseconds(500)));
+
+  // Subsecond special case.
+  EXPECT_EQ("1.5ns", absl::FormatDuration(absl::Nanoseconds(1) +
+                                          absl::Nanoseconds(1) / 2));
+  EXPECT_EQ("1.25ns", absl::FormatDuration(absl::Nanoseconds(1) +
+                                           absl::Nanoseconds(1) / 4));
+  EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1) +
+                                        absl::Nanoseconds(1) / 9));
+  EXPECT_EQ("1.2us", absl::FormatDuration(absl::Microseconds(1) +
+                                          absl::Nanoseconds(200)));
+  EXPECT_EQ("1.2ms", absl::FormatDuration(absl::Milliseconds(1) +
+                                          absl::Microseconds(200)));
+  EXPECT_EQ("1.0002ms", absl::FormatDuration(absl::Milliseconds(1) +
+                                             absl::Nanoseconds(200)));
+  EXPECT_EQ("1.00001ms", absl::FormatDuration(absl::Milliseconds(1) +
+                                              absl::Nanoseconds(10)));
+  EXPECT_EQ("1.000001ms",
+            absl::FormatDuration(absl::Milliseconds(1) + absl::Nanoseconds(1)));
+
+  // Negative durations.
+  EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1)));
+  EXPECT_EQ("-1us", absl::FormatDuration(absl::Microseconds(-1)));
+  EXPECT_EQ("-1ms", absl::FormatDuration(absl::Milliseconds(-1)));
+  EXPECT_EQ("-1s", absl::FormatDuration(absl::Seconds(-1)));
+  EXPECT_EQ("-1m", absl::FormatDuration(absl::Minutes(-1)));
+  EXPECT_EQ("-1h", absl::FormatDuration(absl::Hours(-1)));
+
+  EXPECT_EQ("-1h1m",
+            absl::FormatDuration(-(absl::Hours(1) + absl::Minutes(1))));
+  EXPECT_EQ("-1h1s",
+            absl::FormatDuration(-(absl::Hours(1) + absl::Seconds(1))));
+  EXPECT_EQ("-1m1s",
+            absl::FormatDuration(-(absl::Minutes(1) + absl::Seconds(1))));
+
+  EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1)));
+  EXPECT_EQ("-1.2us", absl::FormatDuration(
+                          -(absl::Microseconds(1) + absl::Nanoseconds(200))));
+  EXPECT_EQ("-1.2ms", absl::FormatDuration(
+                          -(absl::Milliseconds(1) + absl::Microseconds(200))));
+  EXPECT_EQ("-1.0002ms", absl::FormatDuration(-(absl::Milliseconds(1) +
+                                                absl::Nanoseconds(200))));
+  EXPECT_EQ("-1.00001ms", absl::FormatDuration(-(absl::Milliseconds(1) +
+                                                 absl::Nanoseconds(10))));
+  EXPECT_EQ("-1.000001ms", absl::FormatDuration(-(absl::Milliseconds(1) +
+                                                  absl::Nanoseconds(1))));
+
+  //
+  // Interesting corner cases.
+  //
+
+  const absl::Duration qns = absl::Nanoseconds(1) / 4;
+  const absl::Duration max_dur =
+      absl::Seconds(kint64max) + (absl::Seconds(1) - qns);
+  const absl::Duration min_dur = absl::Seconds(kint64min);
+
+  EXPECT_EQ("0.25ns", absl::FormatDuration(qns));
+  EXPECT_EQ("-0.25ns", absl::FormatDuration(-qns));
+  EXPECT_EQ("2562047788015215h30m7.99999999975s",
+            absl::FormatDuration(max_dur));
+  EXPECT_EQ("-2562047788015215h30m8s", absl::FormatDuration(min_dur));
+
+  // Tests printing full precision from units that print using FDivDuration
+  EXPECT_EQ("55.00000000025s", absl::FormatDuration(absl::Seconds(55) + qns));
+  EXPECT_EQ("55.00000025ms",
+            absl::FormatDuration(absl::Milliseconds(55) + qns));
+  EXPECT_EQ("55.00025us", absl::FormatDuration(absl::Microseconds(55) + qns));
+  EXPECT_EQ("55.25ns", absl::FormatDuration(absl::Nanoseconds(55) + qns));
+
+  // Formatting infinity
+  EXPECT_EQ("inf", absl::FormatDuration(absl::InfiniteDuration()));
+  EXPECT_EQ("-inf", absl::FormatDuration(-absl::InfiniteDuration()));
+
+  // Formatting approximately +/- 100 billion years
+  const absl::Duration huge_range = ApproxYears(100000000000);
+  EXPECT_EQ("876000000000000h", absl::FormatDuration(huge_range));
+  EXPECT_EQ("-876000000000000h", absl::FormatDuration(-huge_range));
+
+  EXPECT_EQ("876000000000000h0.999999999s",
+            absl::FormatDuration(huge_range +
+                                 (absl::Seconds(1) - absl::Nanoseconds(1))));
+  EXPECT_EQ("876000000000000h0.9999999995s",
+            absl::FormatDuration(
+                huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 2)));
+  EXPECT_EQ("876000000000000h0.99999999975s",
+            absl::FormatDuration(
+                huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 4)));
+
+  EXPECT_EQ("-876000000000000h0.999999999s",
+            absl::FormatDuration(-huge_range -
+                                 (absl::Seconds(1) - absl::Nanoseconds(1))));
+  EXPECT_EQ("-876000000000000h0.9999999995s",
+            absl::FormatDuration(
+                -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 2)));
+  EXPECT_EQ("-876000000000000h0.99999999975s",
+            absl::FormatDuration(
+                -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 4)));
+}
+
+TEST(Duration, ParseDuration) {
+  absl::Duration d;
+
+  // No specified unit. Should only work for zero and infinity.
+  EXPECT_TRUE(absl::ParseDuration("0", &d));
+  EXPECT_EQ(absl::ZeroDuration(), d);
+  EXPECT_TRUE(absl::ParseDuration("+0", &d));
+  EXPECT_EQ(absl::ZeroDuration(), d);
+  EXPECT_TRUE(absl::ParseDuration("-0", &d));
+  EXPECT_EQ(absl::ZeroDuration(), d);
+
+  EXPECT_TRUE(absl::ParseDuration("inf", &d));
+  EXPECT_EQ(absl::InfiniteDuration(), d);
+  EXPECT_TRUE(absl::ParseDuration("+inf", &d));
+  EXPECT_EQ(absl::InfiniteDuration(), d);
+  EXPECT_TRUE(absl::ParseDuration("-inf", &d));
+  EXPECT_EQ(-absl::InfiniteDuration(), d);
+  EXPECT_FALSE(absl::ParseDuration("infBlah", &d));
+
+  // Illegal input forms.
+  EXPECT_FALSE(absl::ParseDuration("", &d));
+  EXPECT_FALSE(absl::ParseDuration("0.0", &d));
+  EXPECT_FALSE(absl::ParseDuration(".0", &d));
+  EXPECT_FALSE(absl::ParseDuration(".", &d));
+  EXPECT_FALSE(absl::ParseDuration("01", &d));
+  EXPECT_FALSE(absl::ParseDuration("1", &d));
+  EXPECT_FALSE(absl::ParseDuration("-1", &d));
+  EXPECT_FALSE(absl::ParseDuration("2", &d));
+  EXPECT_FALSE(absl::ParseDuration("2 s", &d));
+  EXPECT_FALSE(absl::ParseDuration(".s", &d));
+  EXPECT_FALSE(absl::ParseDuration("-.s", &d));
+  EXPECT_FALSE(absl::ParseDuration("s", &d));
+  EXPECT_FALSE(absl::ParseDuration(" 2s", &d));
+  EXPECT_FALSE(absl::ParseDuration("2s ", &d));
+  EXPECT_FALSE(absl::ParseDuration(" 2s ", &d));
+  EXPECT_FALSE(absl::ParseDuration("2mt", &d));
+  EXPECT_FALSE(absl::ParseDuration("1e3s", &d));
+
+  // One unit type.
+  EXPECT_TRUE(absl::ParseDuration("1ns", &d));
+  EXPECT_EQ(absl::Nanoseconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1us", &d));
+  EXPECT_EQ(absl::Microseconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1ms", &d));
+  EXPECT_EQ(absl::Milliseconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1s", &d));
+  EXPECT_EQ(absl::Seconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("2m", &d));
+  EXPECT_EQ(absl::Minutes(2), d);
+  EXPECT_TRUE(absl::ParseDuration("2h", &d));
+  EXPECT_EQ(absl::Hours(2), d);
+
+  // Huge counts of a unit.
+  EXPECT_TRUE(absl::ParseDuration("9223372036854775807us", &d));
+  EXPECT_EQ(absl::Microseconds(9223372036854775807), d);
+  EXPECT_TRUE(absl::ParseDuration("-9223372036854775807us", &d));
+  EXPECT_EQ(absl::Microseconds(-9223372036854775807), d);
+
+  // Multiple units.
+  EXPECT_TRUE(absl::ParseDuration("2h3m4s", &d));
+  EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4), d);
+  EXPECT_TRUE(absl::ParseDuration("3m4s5us", &d));
+  EXPECT_EQ(absl::Minutes(3) + absl::Seconds(4) + absl::Microseconds(5), d);
+  EXPECT_TRUE(absl::ParseDuration("2h3m4s5ms6us7ns", &d));
+  EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4) +
+                absl::Milliseconds(5) + absl::Microseconds(6) +
+                absl::Nanoseconds(7),
+            d);
+
+  // Multiple units out of order.
+  EXPECT_TRUE(absl::ParseDuration("2us3m4s5h", &d));
+  EXPECT_EQ(absl::Hours(5) + absl::Minutes(3) + absl::Seconds(4) +
+                absl::Microseconds(2),
+            d);
+
+  // Fractional values of units.
+  EXPECT_TRUE(absl::ParseDuration("1.5ns", &d));
+  EXPECT_EQ(1.5 * absl::Nanoseconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1.5us", &d));
+  EXPECT_EQ(1.5 * absl::Microseconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1.5ms", &d));
+  EXPECT_EQ(1.5 * absl::Milliseconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1.5s", &d));
+  EXPECT_EQ(1.5 * absl::Seconds(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1.5m", &d));
+  EXPECT_EQ(1.5 * absl::Minutes(1), d);
+  EXPECT_TRUE(absl::ParseDuration("1.5h", &d));
+  EXPECT_EQ(1.5 * absl::Hours(1), d);
+
+  // Huge fractional counts of a unit.
+  EXPECT_TRUE(absl::ParseDuration("0.4294967295s", &d));
+  EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d);
+  EXPECT_TRUE(absl::ParseDuration("0.429496729501234567890123456789s", &d));
+  EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d);
+
+  // Negative durations.
+  EXPECT_TRUE(absl::ParseDuration("-1s", &d));
+  EXPECT_EQ(absl::Seconds(-1), d);
+  EXPECT_TRUE(absl::ParseDuration("-1m", &d));
+  EXPECT_EQ(absl::Minutes(-1), d);
+  EXPECT_TRUE(absl::ParseDuration("-1h", &d));
+  EXPECT_EQ(absl::Hours(-1), d);
+
+  EXPECT_TRUE(absl::ParseDuration("-1h2s", &d));
+  EXPECT_EQ(-(absl::Hours(1) + absl::Seconds(2)), d);
+  EXPECT_FALSE(absl::ParseDuration("1h-2s", &d));
+  EXPECT_FALSE(absl::ParseDuration("-1h-2s", &d));
+  EXPECT_FALSE(absl::ParseDuration("-1h -2s", &d));
+}
+
+TEST(Duration, FormatParseRoundTrip) {
+#define TEST_PARSE_ROUNDTRIP(d)                \
+  do {                                         \
+    std::string s = absl::FormatDuration(d);        \
+    absl::Duration dur;                        \
+    EXPECT_TRUE(absl::ParseDuration(s, &dur)); \
+    EXPECT_EQ(d, dur);                         \
+  } while (0)
+
+  TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1));
+  TEST_PARSE_ROUNDTRIP(absl::Microseconds(1));
+  TEST_PARSE_ROUNDTRIP(absl::Milliseconds(1));
+  TEST_PARSE_ROUNDTRIP(absl::Seconds(1));
+  TEST_PARSE_ROUNDTRIP(absl::Minutes(1));
+  TEST_PARSE_ROUNDTRIP(absl::Hours(1));
+  TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(2));
+
+  TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(-1));
+  TEST_PARSE_ROUNDTRIP(absl::Microseconds(-1));
+  TEST_PARSE_ROUNDTRIP(absl::Milliseconds(-1));
+  TEST_PARSE_ROUNDTRIP(absl::Seconds(-1));
+  TEST_PARSE_ROUNDTRIP(absl::Minutes(-1));
+  TEST_PARSE_ROUNDTRIP(absl::Hours(-1));
+
+  TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(2));
+  TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(-2));
+  TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(-2));
+
+  TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1) +
+                       absl::Nanoseconds(1) / 4);  // 1.25ns
+
+  const absl::Duration huge_range = ApproxYears(100000000000);
+  TEST_PARSE_ROUNDTRIP(huge_range);
+  TEST_PARSE_ROUNDTRIP(huge_range + (absl::Seconds(1) - absl::Nanoseconds(1)));
+
+#undef TEST_PARSE_ROUNDTRIP
+}
+
+}  // namespace
diff --git a/absl/time/format.cc b/absl/time/format.cc
new file mode 100644
index 0000000..e98e60a
--- /dev/null
+++ b/absl/time/format.cc
@@ -0,0 +1,139 @@
+// Copyright 2017 The Abseil 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 <string.h>
+#include <cctype>
+#include <cstdint>
+
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "absl/time/time.h"
+
+namespace cctz = absl::time_internal::cctz;
+
+namespace absl {
+
+extern const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
+extern const char RFC3339_sec[] =  "%Y-%m-%dT%H:%M:%S%Ez";
+
+extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
+extern const char RFC1123_no_wday[] =  "%d %b %E4Y %H:%M:%S %z";
+
+namespace {
+
+const char kInfiniteFutureStr[] = "infinite-future";
+const char kInfinitePastStr[] = "infinite-past";
+
+struct cctz_parts {
+  cctz::time_point<cctz::seconds> sec;
+  cctz::detail::femtoseconds fem;
+};
+
+inline cctz::time_point<cctz::seconds> unix_epoch() {
+  return std::chrono::time_point_cast<cctz::seconds>(
+      std::chrono::system_clock::from_time_t(0));
+}
+
+// Splits a Time into seconds and femtoseconds, which can be used with CCTZ.
+// Requires that 't' is finite. See duration.cc for details about rep_hi and
+// rep_lo.
+cctz_parts Split(absl::Time t) {
+  const auto d = time_internal::ToUnixDuration(t);
+  const int64_t rep_hi = time_internal::GetRepHi(d);
+  const int64_t rep_lo = time_internal::GetRepLo(d);
+  const auto sec = unix_epoch() + cctz::seconds(rep_hi);
+  const auto fem = cctz::detail::femtoseconds(rep_lo * (1000 * 1000 / 4));
+  return {sec, fem};
+}
+
+// Joins the given seconds and femtoseconds into a Time. See duration.cc for
+// details about rep_hi and rep_lo.
+absl::Time Join(const cctz_parts& parts) {
+  const int64_t rep_hi = (parts.sec - unix_epoch()).count();
+  const uint32_t rep_lo = parts.fem.count() / (1000 * 1000 / 4);
+  const auto d = time_internal::MakeDuration(rep_hi, rep_lo);
+  return time_internal::FromUnixDuration(d);
+}
+
+}  // namespace
+
+std::string FormatTime(const std::string& format, absl::Time t, absl::TimeZone tz) {
+  if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
+  if (t == absl::InfinitePast()) return kInfinitePastStr;
+  const auto parts = Split(t);
+  return cctz::detail::format(format, parts.sec, parts.fem,
+                              cctz::time_zone(tz));
+}
+
+std::string FormatTime(absl::Time t, absl::TimeZone tz) {
+  return FormatTime(RFC3339_full, t, tz);
+}
+
+std::string FormatTime(absl::Time t) {
+  return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
+}
+
+bool ParseTime(const std::string& format, const std::string& input, absl::Time* time,
+               std::string* err) {
+  return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
+}
+
+// If the input std::string does not contain an explicit UTC offset, interpret
+// the fields with respect to the given TimeZone.
+bool ParseTime(const std::string& format, const std::string& input, absl::TimeZone tz,
+               absl::Time* time, std::string* err) {
+  const char* data = input.c_str();
+  while (std::isspace(*data)) ++data;
+
+  size_t inf_size = strlen(kInfiniteFutureStr);
+  if (strncmp(data, kInfiniteFutureStr, inf_size) == 0) {
+    const char* new_data = data + inf_size;
+    while (std::isspace(*new_data)) ++new_data;
+    if (*new_data == '\0') {
+      *time = InfiniteFuture();
+      return true;
+    }
+  }
+
+  inf_size = strlen(kInfinitePastStr);
+  if (strncmp(data, kInfinitePastStr, inf_size) == 0) {
+    const char* new_data = data + inf_size;
+    while (std::isspace(*new_data)) ++new_data;
+    if (*new_data == '\0') {
+      *time = InfinitePast();
+      return true;
+    }
+  }
+
+  std::string error;
+  cctz_parts parts;
+  const bool b = cctz::detail::parse(format, input, cctz::time_zone(tz),
+                                     &parts.sec, &parts.fem, &error);
+  if (b) {
+    *time = Join(parts);
+  } else if (err != nullptr) {
+    *err = error;
+  }
+  return b;
+}
+
+// Functions required to support absl::Time flags.
+bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
+  return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
+}
+
+std::string UnparseFlag(absl::Time t) {
+  return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
+
+}  // namespace absl
diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc
new file mode 100644
index 0000000..ee53d71
--- /dev/null
+++ b/absl/time/format_benchmark.cc
@@ -0,0 +1,63 @@
+// Copyright 2018 The Abseil 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 <cstddef>
+#include <string>
+
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+namespace {
+const char* const kFormats[] = {
+    absl::RFC1123_full,     // 0
+    absl::RFC1123_no_wday,  // 1
+    absl::RFC3339_full,     // 2
+    absl::RFC3339_sec,      // 3
+    "%Y-%m-%dT%H:%M:%S",    // 4
+    "%Y-%m-%d",             // 5
+};
+const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
+}  // namespace
+
+void BM_Format_FormatTime(benchmark::State& state) {
+  const std::string fmt = kFormats[state.range(0)];
+  state.SetLabel(fmt);
+  const absl::TimeZone lax =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  const absl::Time t =
+      absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length());
+  }
+}
+BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1);
+
+void BM_Format_ParseTime(benchmark::State& state) {
+  const std::string fmt = kFormats[state.range(0)];
+  state.SetLabel(fmt);
+  const absl::TimeZone lax =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  absl::Time t =
+      absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
+  const std::string when = absl::FormatTime(fmt, t, lax);
+  std::string err;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ParseTime(fmt, when, lax, &t, &err));
+  }
+}
+BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1);
+
+}  // namespace
diff --git a/absl/time/format_test.cc b/absl/time/format_test.cc
new file mode 100644
index 0000000..7c84c33
--- /dev/null
+++ b/absl/time/format_test.cc
@@ -0,0 +1,434 @@
+// Copyright 2017 The Abseil 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 <cstdint>
+#include <limits>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+
+using testing::HasSubstr;
+
+namespace {
+
+// A helper that tests the given format specifier by itself, and with leading
+// and trailing characters.  For example: TestFormatSpecifier(t, "%a", "Thu").
+void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, const std::string& fmt,
+                         const std::string& ans) {
+  EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz));
+  EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz));
+  EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz));
+  EXPECT_EQ("xxx " + ans + " yyy",
+            absl::FormatTime("xxx " + fmt + " yyy", t, tz));
+}
+
+//
+// Testing FormatTime()
+//
+
+TEST(FormatTime, Basics) {
+  absl::TimeZone tz = absl::UTCTimeZone();
+  absl::Time t = absl::FromTimeT(0);
+
+  // Starts with a couple basic edge cases.
+  EXPECT_EQ("", absl::FormatTime("", t, tz));
+  EXPECT_EQ(" ", absl::FormatTime(" ", t, tz));
+  EXPECT_EQ("  ", absl::FormatTime("  ", t, tz));
+  EXPECT_EQ("xxx", absl::FormatTime("xxx", t, tz));
+  std::string big(128, 'x');
+  EXPECT_EQ(big, absl::FormatTime(big, t, tz));
+  // Cause the 1024-byte buffer to grow.
+  std::string bigger(100000, 'x');
+  EXPECT_EQ(bigger, absl::FormatTime(bigger, t, tz));
+
+  t += absl::Hours(13) + absl::Minutes(4) + absl::Seconds(5);
+  t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8);
+  EXPECT_EQ("1970-01-01", absl::FormatTime("%Y-%m-%d", t, tz));
+  EXPECT_EQ("13:04:05", absl::FormatTime("%H:%M:%S", t, tz));
+  EXPECT_EQ("13:04:05.006", absl::FormatTime("%H:%M:%E3S", t, tz));
+  EXPECT_EQ("13:04:05.006007", absl::FormatTime("%H:%M:%E6S", t, tz));
+  EXPECT_EQ("13:04:05.006007008", absl::FormatTime("%H:%M:%E9S", t, tz));
+}
+
+TEST(FormatTime, LocaleSpecific) {
+  const absl::TimeZone tz = absl::UTCTimeZone();
+  absl::Time t = absl::FromTimeT(0);
+
+  TestFormatSpecifier(t, tz, "%a", "Thu");
+  TestFormatSpecifier(t, tz, "%A", "Thursday");
+  TestFormatSpecifier(t, tz, "%b", "Jan");
+  TestFormatSpecifier(t, tz, "%B", "January");
+
+  // %c should at least produce the numeric year and time-of-day.
+  const std::string s =
+      absl::FormatTime("%c", absl::FromTimeT(0), absl::UTCTimeZone());
+  EXPECT_THAT(s, HasSubstr("1970"));
+  EXPECT_THAT(s, HasSubstr("00:00:00"));
+
+  TestFormatSpecifier(t, tz, "%p", "AM");
+  TestFormatSpecifier(t, tz, "%x", "01/01/70");
+  TestFormatSpecifier(t, tz, "%X", "00:00:00");
+}
+
+TEST(FormatTime, ExtendedSeconds) {
+  const absl::TimeZone tz = absl::UTCTimeZone();
+
+  // No subseconds.
+  absl::Time t = absl::FromTimeT(0) + absl::Seconds(5);
+  EXPECT_EQ("05", absl::FormatTime("%E*S", t, tz));
+  EXPECT_EQ("05.000000000000000", absl::FormatTime("%E15S", t, tz));
+
+  // With subseconds.
+  t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8);
+  EXPECT_EQ("05.006007008", absl::FormatTime("%E*S", t, tz));
+  EXPECT_EQ("05", absl::FormatTime("%E0S", t, tz));
+  EXPECT_EQ("05.006007008000000", absl::FormatTime("%E15S", t, tz));
+
+  // Times before the Unix epoch.
+  t = absl::FromUnixMicros(-1);
+  EXPECT_EQ("1969-12-31 23:59:59.999999",
+            absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz));
+
+  // Here is a "%E*S" case we got wrong for a while.  While the first
+  // instant below is correctly rendered as "...:07.333304", the second
+  // one used to appear as "...:07.33330499999999999".
+  t = absl::FromUnixMicros(1395024427333304);
+  EXPECT_EQ("2014-03-17 02:47:07.333304",
+            absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz));
+  t += absl::Microseconds(1);
+  EXPECT_EQ("2014-03-17 02:47:07.333305",
+            absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz));
+}
+
+TEST(FormatTime, RFC1123FormatPadsYear) {  // locale specific
+  absl::TimeZone tz = absl::UTCTimeZone();
+
+  // A year of 77 should be padded to 0077.
+  absl::Time t = absl::FromDateTime(77, 6, 28, 9, 8, 7, tz);
+  EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000",
+            absl::FormatTime(absl::RFC1123_full, t, tz));
+  EXPECT_EQ("28 Jun 0077 09:08:07 +0000",
+            absl::FormatTime(absl::RFC1123_no_wday, t, tz));
+}
+
+TEST(FormatTime, InfiniteTime) {
+  absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+
+  // The format and timezone are ignored.
+  EXPECT_EQ("infinite-future",
+            absl::FormatTime("%H:%M blah", absl::InfiniteFuture(), tz));
+  EXPECT_EQ("infinite-past",
+            absl::FormatTime("%H:%M blah", absl::InfinitePast(), tz));
+}
+
+//
+// Testing ParseTime()
+//
+
+TEST(ParseTime, Basics) {
+  absl::Time t = absl::FromTimeT(1234567890);
+  std::string err;
+
+  // Simple edge cases.
+  EXPECT_TRUE(absl::ParseTime("", "", &t, &err)) << err;
+  EXPECT_EQ(absl::UnixEpoch(), t);  // everything defaulted
+  EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err;
+  EXPECT_TRUE(absl::ParseTime("  ", "  ", &t, &err)) << err;
+  EXPECT_TRUE(absl::ParseTime("x", "x", &t, &err)) << err;
+  EXPECT_TRUE(absl::ParseTime("xxx", "xxx", &t, &err)) << err;
+
+  EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
+                              "2013-06-28 19:08:09 -0800", &t, &err))
+      << err;
+  absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false);
+  EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+}
+
+TEST(ParseTime, NullErrorString) {
+  absl::Time t;
+  EXPECT_FALSE(absl::ParseTime("%Q", "invalid format", &t, nullptr));
+  EXPECT_FALSE(absl::ParseTime("%H", "12 trailing data", &t, nullptr));
+  EXPECT_FALSE(
+      absl::ParseTime("%H out of range", "42 out of range", &t, nullptr));
+}
+
+TEST(ParseTime, WithTimeZone) {
+  const absl::TimeZone tz =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  absl::Time t;
+  std::string e;
+
+  // We can parse a std::string without a UTC offset if we supply a timezone.
+  EXPECT_TRUE(
+      absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
+      << e;
+  absl::Time::Breakdown bd = t.In(tz);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true);
+  EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+
+  // But the timezone is ignored when a UTC offset is present.
+  EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
+                              "2013-06-28 19:08:09 +0800", tz, &t, &e))
+      << e;
+  bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false);
+  EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+}
+
+TEST(ParseTime, ErrorCases) {
+  absl::Time t = absl::FromTimeT(0);
+  std::string err;
+
+  EXPECT_FALSE(absl::ParseTime("%S", "123", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+  // Can't parse an illegal format specifier.
+  err.clear();
+  EXPECT_FALSE(absl::ParseTime("%Q", "x", &t, &err)) << err;
+  // Exact contents of "err" are platform-dependent because of
+  // differences in the strptime implementation between OSX and Linux.
+  EXPECT_FALSE(err.empty());
+
+  // Fails because of trailing, unparsed data "blah".
+  EXPECT_FALSE(absl::ParseTime("%m-%d", "2-3 blah", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+  // Feb 31 requires normalization.
+  EXPECT_FALSE(absl::ParseTime("%m-%d", "2-31", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Out-of-range"));
+
+  // Check that we cannot have spaces in UTC offsets.
+  EXPECT_TRUE(absl::ParseTime("%z", "-0203", &t, &err)) << err;
+  EXPECT_FALSE(absl::ParseTime("%z", "- 2 3", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_TRUE(absl::ParseTime("%Ez", "-02:03", &t, &err)) << err;
+  EXPECT_FALSE(absl::ParseTime("%Ez", "- 2: 3", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+
+  // Check that we reject other malformed UTC offsets.
+  EXPECT_FALSE(absl::ParseTime("%Ez", "+-08:00", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%Ez", "-+08:00", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+
+  // Check that we do not accept "-0" in fields that allow zero.
+  EXPECT_FALSE(absl::ParseTime("%Y", "-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%E4Y", "-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%H", "-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%M", "-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%S", "-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%z", "+-000", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%Ez", "+-0:00", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+  EXPECT_FALSE(absl::ParseTime("%z", "-00-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+  EXPECT_FALSE(absl::ParseTime("%Ez", "-00:-0", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+}
+
+TEST(ParseTime, ExtendedSeconds) {
+  std::string err;
+  absl::Time t;
+
+  // Here is a "%E*S" case we got wrong for a while.  The fractional
+  // part of the first instant is less than 2^31 and was correctly
+  // parsed, while the second (and any subsecond field >=2^31) failed.
+  t = absl::UnixEpoch();
+  EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483647", &t, &err)) << err;
+  EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) +
+                absl::Nanoseconds(1) / 2,
+            t);
+  t = absl::UnixEpoch();
+  EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483648", &t, &err)) << err;
+  EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) +
+                absl::Nanoseconds(3) / 4,
+            t);
+
+  // We should also be able to specify long strings of digits far
+  // beyond the current resolution and have them convert the same way.
+  t = absl::UnixEpoch();
+  EXPECT_TRUE(absl::ParseTime(
+      "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
+      &t, &err))
+      << err;
+  EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) +
+                absl::Nanoseconds(3) / 4,
+            t);
+}
+
+TEST(ParseTime, ExtendedOffsetErrors) {
+  std::string err;
+  absl::Time t;
+
+  // %z against +-HHMM.
+  EXPECT_FALSE(absl::ParseTime("%z", "-123", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+  // %z against +-HH.
+  EXPECT_FALSE(absl::ParseTime("%z", "-1", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+
+  // %Ez against +-HH:MM.
+  EXPECT_FALSE(absl::ParseTime("%Ez", "-12:3", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+  // %Ez against +-HHMM.
+  EXPECT_FALSE(absl::ParseTime("%Ez", "-123", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+  // %Ez against +-HH.
+  EXPECT_FALSE(absl::ParseTime("%Ez", "-1", &t, &err)) << err;
+  EXPECT_THAT(err, HasSubstr("Failed to parse"));
+}
+
+TEST(ParseTime, InfiniteTime) {
+  absl::Time t;
+  std::string err;
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future", &t, &err));
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+
+  // Surrounding whitespace.
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "  infinite-future", &t, &err));
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future  ", &t, &err));
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "  infinite-future  ", &t, &err));
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past", &t, &err));
+  EXPECT_EQ(absl::InfinitePast(), t);
+
+  // Surrounding whitespace.
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "  infinite-past", &t, &err));
+  EXPECT_EQ(absl::InfinitePast(), t);
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past  ", &t, &err));
+  EXPECT_EQ(absl::InfinitePast(), t);
+  EXPECT_TRUE(absl::ParseTime("%H:%M blah", "  infinite-past  ", &t, &err));
+  EXPECT_EQ(absl::InfinitePast(), t);
+
+  // "infinite-future" as literal std::string
+  absl::TimeZone tz = absl::UTCTimeZone();
+  EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04",
+                              &t, &err));
+  EXPECT_NE(absl::InfiniteFuture(), t);
+  EXPECT_EQ(3, t.In(tz).hour);
+  EXPECT_EQ(4, t.In(tz).minute);
+
+  // "infinite-past" as literal std::string
+  EXPECT_TRUE(
+      absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err));
+  EXPECT_NE(absl::InfinitePast(), t);
+  EXPECT_EQ(3, t.In(tz).hour);
+  EXPECT_EQ(4, t.In(tz).minute);
+
+  // The input doesn't match the format.
+  EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err));
+  EXPECT_FALSE(absl::ParseTime("infinite-past %H:%M", "03:04", &t, &err));
+}
+
+TEST(ParseTime, FailsOnUnrepresentableTime) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  absl::Time t;
+  EXPECT_FALSE(
+      absl::ParseTime("%Y-%m-%d", "-292277022657-01-27", utc, &t, nullptr));
+  EXPECT_TRUE(
+      absl::ParseTime("%Y-%m-%d", "-292277022657-01-28", utc, &t, nullptr));
+  EXPECT_TRUE(
+      absl::ParseTime("%Y-%m-%d", "292277026596-12-04", utc, &t, nullptr));
+  EXPECT_FALSE(
+      absl::ParseTime("%Y-%m-%d", "292277026596-12-05", utc, &t, nullptr));
+}
+
+//
+// Roundtrip test for FormatTime()/ParseTime().
+//
+
+TEST(FormatParse, RoundTrip) {
+  const absl::TimeZone gst =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  const absl::Time in = absl::FromDateTime(1977, 6, 28, 9, 8, 7, gst);
+  const absl::Duration subseconds = absl::Nanoseconds(654321);
+  std::string err;
+
+  // RFC3339, which renders subseconds.
+  {
+    absl::Time out;
+    const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, gst);
+    EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
+        << s << ": " << err;
+    EXPECT_EQ(in + subseconds, out);  // RFC3339_full includes %Ez
+  }
+
+  // RFC1123, which only does whole seconds.
+  {
+    absl::Time out;
+    const std::string s = absl::FormatTime(absl::RFC1123_full, in, gst);
+    EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err))
+        << s << ": " << err;
+    EXPECT_EQ(in, out);  // RFC1123_full includes %z
+  }
+
+  // `absl::FormatTime()` falls back to strftime() for "%c", which appears to
+  // work. On Windows, `absl::ParseTime()` falls back to std::get_time() which
+  // appears to fail on "%c" (or at least on the "%c" text produced by
+  // `strftime()`). This makes it fail the round-trip test.
+#ifndef _MSC_VER
+  // Even though we don't know what %c will produce, it should roundtrip,
+  // but only in the 0-offset timezone.
+  {
+    absl::Time out;
+    const std::string s = absl::FormatTime("%c", in, absl::UTCTimeZone());
+    EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err;
+    EXPECT_EQ(in, out);
+  }
+#endif  // _MSC_VER
+}
+
+TEST(FormatParse, RoundTripDistantFuture) {
+  const absl::TimeZone tz = absl::UTCTimeZone();
+  const absl::Time in =
+      absl::FromUnixSeconds(std::numeric_limits<int64_t>::max());
+  std::string err;
+
+  absl::Time out;
+  const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz);
+  EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
+      << s << ": " << err;
+  EXPECT_EQ(in, out);
+}
+
+TEST(FormatParse, RoundTripDistantPast) {
+  const absl::TimeZone tz = absl::UTCTimeZone();
+  const absl::Time in =
+      absl::FromUnixSeconds(std::numeric_limits<int64_t>::min());
+  std::string err;
+
+  absl::Time out;
+  const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz);
+  EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
+      << s << ": " << err;
+  EXPECT_EQ(in, out);
+}
+
+}  // namespace
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
new file mode 100644
index 0000000..9f1ba21
--- /dev/null
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -0,0 +1,140 @@
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# 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.
+
+licenses(["notice"])  # Apache License
+
+### libraries
+
+cc_library(
+    name = "includes",
+    textual_hdrs = [
+        "include/cctz/civil_time.h",
+        "include/cctz/civil_time_detail.h",
+        "include/cctz/time_zone.h",
+    ],
+    visibility = ["//absl/time:__pkg__"],
+)
+
+cc_library(
+    name = "civil_time",
+    srcs = ["src/civil_time_detail.cc"],
+    hdrs = [
+        "include/cctz/civil_time.h",
+    ],
+    textual_hdrs = ["include/cctz/civil_time_detail.h"],
+    visibility = ["//visibility:public"],
+)
+
+cc_library(
+    name = "time_zone",
+    srcs = [
+        "src/time_zone_fixed.cc",
+        "src/time_zone_fixed.h",
+        "src/time_zone_format.cc",
+        "src/time_zone_if.cc",
+        "src/time_zone_if.h",
+        "src/time_zone_impl.cc",
+        "src/time_zone_impl.h",
+        "src/time_zone_info.cc",
+        "src/time_zone_info.h",
+        "src/time_zone_libc.cc",
+        "src/time_zone_libc.h",
+        "src/time_zone_lookup.cc",
+        "src/time_zone_posix.cc",
+        "src/time_zone_posix.h",
+        "src/tzfile.h",
+        "src/zone_info_source.cc",
+    ],
+    hdrs = [
+        "include/cctz/time_zone.h",
+        "include/cctz/zone_info_source.h",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [":civil_time"],
+)
+
+### tests
+
+cc_test(
+    name = "civil_time_test",
+    size = "small",
+    srcs = ["src/civil_time_test.cc"],
+    deps = [
+        ":civil_time",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "time_zone_format_test",
+    size = "small",
+    srcs = ["src/time_zone_format_test.cc"],
+    data = [":zoneinfo"],
+    tags = [
+        "no_test_android_arm",
+        "no_test_android_arm64",
+        "no_test_android_x86",
+    ],
+    deps = [
+        ":civil_time",
+        ":time_zone",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "time_zone_lookup_test",
+    size = "small",
+    srcs = ["src/time_zone_lookup_test.cc"],
+    data = [":zoneinfo"],
+    tags = [
+        "no_test_android_arm",
+        "no_test_android_arm64",
+        "no_test_android_x86",
+    ],
+    deps = [
+        ":civil_time",
+        ":time_zone",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+### benchmarks
+
+cc_test(
+    name = "cctz_benchmark",
+    srcs = [
+        "src/cctz_benchmark.cc",
+        "src/time_zone_if.h",
+        "src/time_zone_impl.h",
+        "src/time_zone_info.h",
+        "src/tzfile.h",
+    ],
+    linkstatic = 1,
+    tags = ["benchmark"],
+    deps = [
+        ":civil_time",
+        ":time_zone",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+### examples
+
+### binaries
+
+filegroup(
+    name = "zoneinfo",
+    srcs = glob(["testdata/zoneinfo/**"]),
+)
diff --git a/absl/time/internal/cctz/BUILD.gn b/absl/time/internal/cctz/BUILD.gn
new file mode 100644
index 0000000..86417e7
--- /dev/null
+++ b/absl/time/internal/cctz/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("includes") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "include/cctz/civil_time.h",
+    "include/cctz/civil_time_detail.h",
+    "include/cctz/time_zone.h",
+  ]
+  visibility = []
+  visibility += [ "../time:*" ]
+}
+
+source_set("civil_time") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "src/civil_time_detail.cc",
+  ]
+  public = [
+    "include/cctz/civil_time.h",
+    "include/cctz/civil_time_detail.h",
+  ]
+}
+
+source_set("time_zone") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "src/time_zone_fixed.cc",
+    "src/time_zone_fixed.h",
+    "src/time_zone_format.cc",
+    "src/time_zone_if.cc",
+    "src/time_zone_if.h",
+    "src/time_zone_impl.cc",
+    "src/time_zone_impl.h",
+    "src/time_zone_info.cc",
+    "src/time_zone_info.h",
+    "src/time_zone_libc.cc",
+    "src/time_zone_libc.h",
+    "src/time_zone_lookup.cc",
+    "src/time_zone_posix.cc",
+    "src/time_zone_posix.h",
+    "src/tzfile.h",
+    "src/zone_info_source.cc",
+  ]
+  public = [
+    "include/cctz/time_zone.h",
+    "include/cctz/zone_info_source.h",
+  ]
+  deps = [
+    ":civil_time",
+  ]
+}
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h
new file mode 100644
index 0000000..898222b
--- /dev/null
+++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -0,0 +1,329 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
+#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
+
+#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// The term "civil time" refers to the legally recognized human-scale time
+// that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil
+// time follows the Gregorian Calendar and is a time-zone-independent concept.
+// A "date" is perhaps the most common example of a civil time (represented in
+// this library as cctz::civil_day). This library provides six classes and a
+// handful of functions that help with rounding, iterating, and arithmetic on
+// civil times while avoiding complications like daylight-saving time (DST).
+//
+// The following six classes form the core of this civil-time library:
+//
+//   * civil_second
+//   * civil_minute
+//   * civil_hour
+//   * civil_day
+//   * civil_month
+//   * civil_year
+//
+// Each class is a simple value type with the same interface for construction
+// and the same six accessors for each of the civil fields (year, month, day,
+// hour, minute, and second, aka YMDHMS). These classes differ only in their
+// alignment, which is indicated by the type name and specifies the field on
+// which arithmetic operates.
+//
+// Each class can be constructed by passing up to six optional integer
+// arguments representing the YMDHMS fields (in that order) to the
+// constructor. Omitted fields are assigned their minimum valid value. Hours,
+// minutes, and seconds will be set to 0, month and day will be set to 1, and
+// since there is no minimum valid year, it will be set to 1970. So, a
+// default-constructed civil-time object will have YMDHMS fields representing
+// "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g.,
+// October 32 -> November 1) so that all civil-time objects represent valid
+// values.
+//
+// Each civil-time class is aligned to the civil-time field indicated in the
+// class's name after normalization. Alignment is performed by setting all the
+// inferior fields to their minimum valid value (as described above). The
+// following are examples of how each of the six types would align the fields
+// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the
+// std::string format used here is not important; it's just a shorthand way of
+// showing the six YMDHMS fields.)
+//
+//   civil_second  2015-11-22 12:34:56
+//   civil_minute  2015-11-22 12:34:00
+//   civil_hour    2015-11-22 12:00:00
+//   civil_day     2015-11-22 00:00:00
+//   civil_month   2015-11-01 00:00:00
+//   civil_year    2015-01-01 00:00:00
+//
+// Each civil-time type performs arithmetic on the field to which it is
+// aligned. This means that adding 1 to a civil_day increments the day field
+// (normalizing as necessary), and subtracting 7 from a civil_month operates
+// on the month field (normalizing as necessary). All arithmetic produces a
+// valid civil time. Difference requires two similarly aligned civil-time
+// objects and returns the scalar answer in units of the objects' alignment.
+// For example, the difference between two civil_hour objects will give an
+// answer in units of civil hours.
+//
+// In addition to the six civil-time types just described, there are
+// a handful of helper functions and algorithms for performing common
+// calculations. These are described below.
+//
+// Note: In C++14 and later, this library is usable in a constexpr context.
+//
+// CONSTRUCTION:
+//
+// Each of the civil-time types can be constructed in two ways: by directly
+// passing to the constructor up to six (optional) integers representing the
+// YMDHMS fields, or by copying the YMDHMS fields from a differently aligned
+// civil-time type.
+//
+//   civil_day default_value;  // 1970-01-01 00:00:00
+//
+//   civil_day a(2015, 2, 3);           // 2015-02-03 00:00:00
+//   civil_day b(2015, 2, 3, 4, 5, 6);  // 2015-02-03 00:00:00
+//   civil_day c(2015);                 // 2015-01-01 00:00:00
+//
+//   civil_second ss(2015, 2, 3, 4, 5, 6);  // 2015-02-03 04:05:06
+//   civil_minute mm(ss);                   // 2015-02-03 04:05:00
+//   civil_hour hh(mm);                     // 2015-02-03 04:00:00
+//   civil_day d(hh);                       // 2015-02-03 00:00:00
+//   civil_month m(d);                      // 2015-02-01 00:00:00
+//   civil_year y(m);                       // 2015-01-01 00:00:00
+//
+//   m = civil_month(y);     // 2015-01-01 00:00:00
+//   d = civil_day(m);       // 2015-01-01 00:00:00
+//   hh = civil_hour(d);     // 2015-01-01 00:00:00
+//   mm = civil_minute(hh);  // 2015-01-01 00:00:00
+//   ss = civil_second(mm);  // 2015-01-01 00:00:00
+//
+// ALIGNMENT CONVERSION:
+//
+// The alignment of a civil-time object cannot change, but the object may be
+// used to construct a new object with a different alignment. This is referred
+// to as "realigning". When realigning to a type with the same or more
+// precision (e.g., civil_day -> civil_second), the conversion may be
+// performed implicitly since no information is lost. However, if information
+// could be discarded (e.g., civil_second -> civil_day), the conversion must
+// be explicit at the call site.
+//
+//   void fun(const civil_day& day);
+//
+//   civil_second cs;
+//   fun(cs);  // Won't compile because data may be discarded
+//   fun(civil_day(cs));  // OK: explicit conversion
+//
+//   civil_day cd;
+//   fun(cd);  // OK: no conversion needed
+//
+//   civil_month cm;
+//   fun(cm);  // OK: implicit conversion to civil_day
+//
+// NORMALIZATION:
+//
+// Integer arguments passed to the constructor may be out-of-range, in which
+// case they are normalized to produce a valid civil-time object. This enables
+// natural arithmetic on constructor arguments without worrying about the
+// field's range. Normalization guarantees that there are no invalid
+// civil-time objects.
+//
+//   civil_day d(2016, 10, 32);  // Out-of-range day; normalized to 2016-11-01
+//
+// Note: If normalization is undesired, you can signal an error by comparing
+// the constructor arguments to the normalized values returned by the YMDHMS
+// properties.
+//
+// PROPERTIES:
+//
+// All civil-time types have accessors for all six of the civil-time fields:
+// year, month, day, hour, minute, and second. Recall that fields inferior to
+// the type's aligment will be set to their minimum valid value.
+//
+//   civil_day d(2015, 6, 28);
+//   // d.year() == 2015
+//   // d.month() == 6
+//   // d.day() == 28
+//   // d.hour() == 0
+//   // d.minute() == 0
+//   // d.second() == 0
+//
+// COMPARISON:
+//
+// Comparison always considers all six YMDHMS fields, regardless of the type's
+// alignment. Comparison between differently aligned civil-time types is
+// allowed.
+//
+//   civil_day feb_3(2015, 2, 3);  // 2015-02-03 00:00:00
+//   civil_day mar_4(2015, 3, 4);  // 2015-03-04 00:00:00
+//   // feb_3 < mar_4
+//   // civil_year(feb_3) == civil_year(mar_4)
+//
+//   civil_second feb_3_noon(2015, 2, 3, 12, 0, 0);  // 2015-02-03 12:00:00
+//   // feb_3 < feb_3_noon
+//   // feb_3 == civil_day(feb_3_noon)
+//
+//   // Iterates all the days of February 2015.
+//   for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) {
+//     // ...
+//   }
+//
+// STREAMING:
+//
+// Each civil-time type may be sent to an output stream using operator<<().
+// The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields
+// inferior to the type's alignment are omitted.
+//
+//   civil_second cs(2015, 2, 3, 4, 5, 6);
+//   std::cout << cs << "\n";  // Outputs: 2015-02-03T04:05:06
+//
+//   civil_day cd(cs);
+//   std::cout << cd << "\n";  // Outputs: 2015-02-03
+//
+//   civil_year cy(cs);
+//   std::cout << cy << "\n";  // Outputs: 2015
+//
+// ARITHMETIC:
+//
+// Civil-time types support natural arithmetic operators such as addition,
+// subtraction, and difference. Arithmetic operates on the civil-time field
+// indicated in the type's name. Difference requires arguments with the same
+// alignment and returns the answer in units of the alignment.
+//
+//   civil_day a(2015, 2, 3);
+//   ++a;                         // 2015-02-04 00:00:00
+//   --a;                         // 2015-02-03 00:00:00
+//   civil_day b = a + 1;         // 2015-02-04 00:00:00
+//   civil_day c = 1 + b;         // 2015-02-05 00:00:00
+//   int n = c - a;               // n = 2 (civil days)
+//   int m = c - civil_month(c);  // Won't compile: different types.
+//
+// EXAMPLE: Adding a month to January 31.
+//
+// One of the classic questions that arises when considering a civil-time
+// library (or a date library or a date/time library) is this: "What happens
+// when you add a month to January 31?" This is an interesting question
+// because there could be a number of possible answers:
+//
+//   1. March 3 (or 2 if a leap year). This may make sense if the operation
+//      wants the equivalent of February 31.
+//   2. February 28 (or 29 if a leap year). This may make sense if the operation
+//      wants the last day of January to go to the last day of February.
+//   3. Error. The caller may get some error, an exception, an invalid date
+//      object, or maybe false is returned. This may make sense because there is
+//      no single unambiguously correct answer to the question.
+//
+// Practically speaking, any answer that is not what the programmer intended
+// is the wrong answer.
+//
+// This civil-time library avoids the problem by making it impossible to ask
+// ambiguous questions. All civil-time objects are aligned to a particular
+// civil-field boundary (such as aligned to a year, month, day, hour, minute,
+// or second), and arithmetic operates on the field to which the object is
+// aligned. This means that in order to "add a month" the object must first be
+// aligned to a month boundary, which is equivalent to the first day of that
+// month.
+//
+// Of course, there are ways to compute an answer the question at hand using
+// this civil-time library, but they require the programmer to be explicit
+// about the answer they expect. To illustrate, let's see how to compute all
+// three of the above possible answers to the question of "Jan 31 plus 1
+// month":
+//
+//   const civil_day d(2015, 1, 31);
+//
+//   // Answer 1:
+//   // Add 1 to the month field in the constructor, and rely on normalization.
+//   const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day());
+//   // ans_normalized == 2015-03-03 (aka Feb 31)
+//
+//   // Answer 2:
+//   // Add 1 to month field, capping to the end of next month.
+//   const auto next_month = civil_month(d) + 1;
+//   const auto last_day_of_next_month = civil_day(next_month + 1) - 1;
+//   const auto ans_capped = std::min(ans_normalized, last_day_of_next_month);
+//   // ans_capped == 2015-02-28
+//
+//   // Answer 3:
+//   // Signal an error if the normalized answer is not in next month.
+//   if (civil_month(ans_normalized) != next_month) {
+//     // error, month overflow
+//   }
+//
+using civil_year = detail::civil_year;
+using civil_month = detail::civil_month;
+using civil_day = detail::civil_day;
+using civil_hour = detail::civil_hour;
+using civil_minute = detail::civil_minute;
+using civil_second = detail::civil_second;
+
+// An enum class with members monday, tuesday, wednesday, thursday, friday,
+// saturday, and sunday. These enum values may be sent to an output stream
+// using operator<<(). The result is the full weekday name in English with a
+// leading capital letter.
+//
+//   weekday wd = weekday::thursday;
+//   std::cout << wd << "\n";  // Outputs: Thursday
+//
+using detail::weekday;
+
+// Returns the weekday for the given civil_day.
+//
+//   civil_day a(2015, 8, 13);
+//   weekday wd = get_weekday(a);  // wd == weekday::thursday
+//
+using detail::get_weekday;
+
+// Returns the civil_day that strictly follows or precedes the given
+// civil_day, and that falls on the given weekday.
+//
+// For example, given:
+//
+//     August 2015
+// Su Mo Tu We Th Fr Sa
+//                    1
+//  2  3  4  5  6  7  8
+//  9 10 11 12 13 14 15
+// 16 17 18 19 20 21 22
+// 23 24 25 26 27 28 29
+// 30 31
+//
+//   civil_day a(2015, 8, 13);  // get_weekday(a) == weekday::thursday
+//   civil_day b = next_weekday(a, weekday::thursday);  // b = 2015-08-20
+//   civil_day c = prev_weekday(a, weekday::thursday);  // c = 2015-08-06
+//
+//   civil_day d = ...
+//   // Gets the following Thursday if d is not already Thursday
+//   civil_day thurs1 = prev_weekday(d, weekday::thursday) + 7;
+//   // Gets the previous Thursday if d is not already Thursday
+//   civil_day thurs2 = next_weekday(d, weekday::thursday) - 7;
+//
+using detail::next_weekday;
+using detail::prev_weekday;
+
+// Returns the day-of-year for the given civil_day.
+//
+//   civil_day a(2015, 1, 1);
+//   int yd_jan_1 = get_yearday(a);   // yd_jan_1 = 1
+//   civil_day b(2015, 12, 31);
+//   int yd_dec_31 = get_yearday(b);  // yd_dec_31 = 365
+//
+using detail::get_yearday;
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
new file mode 100644
index 0000000..2362a4f
--- /dev/null
+++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -0,0 +1,560 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
+#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
+
+#include <cstdint>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+// Disable constexpr support unless we are in C++14 mode.
+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
+#define CONSTEXPR_D constexpr  // data
+#define CONSTEXPR_F constexpr  // function
+#define CONSTEXPR_M constexpr  // member
+#else
+#define CONSTEXPR_D const
+#define CONSTEXPR_F inline
+#define CONSTEXPR_M
+#endif
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// Support years that at least span the range of 64-bit time_t values.
+using year_t = std::int_fast64_t;
+
+// Type alias that indicates an argument is not normalized (e.g., the
+// constructor parameters and operands/results of addition/subtraction).
+using diff_t = std::int_fast64_t;
+
+namespace detail {
+
+// Type aliases that indicate normalized argument values.
+using month_t = std::int_fast8_t;   // [1:12]
+using day_t = std::int_fast8_t;     // [1:31]
+using hour_t = std::int_fast8_t;    // [0:23]
+using minute_t = std::int_fast8_t;  // [0:59]
+using second_t = std::int_fast8_t;  // [0:59]
+
+// Normalized civil-time fields: Y-M-D HH:MM:SS.
+struct fields {
+  CONSTEXPR_M fields(year_t year, month_t month, day_t day,
+                     hour_t hour, minute_t minute, second_t second)
+      : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
+  std::int_least64_t y;
+  std::int_least8_t m;
+  std::int_least8_t d;
+  std::int_least8_t hh;
+  std::int_least8_t mm;
+  std::int_least8_t ss;
+};
+
+struct second_tag {};
+struct minute_tag : second_tag {};
+struct hour_tag : minute_tag {};
+struct day_tag : hour_tag {};
+struct month_tag : day_tag {};
+struct year_tag : month_tag {};
+
+////////////////////////////////////////////////////////////////////////
+
+// Field normalization (without avoidable overflow).
+
+namespace impl {
+
+CONSTEXPR_F bool is_leap_year(year_t y) noexcept {
+  return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
+}
+CONSTEXPR_F int year_index(year_t y, month_t m) noexcept {
+  return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400;
+}
+CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept {
+  const int yi = year_index(y, m);
+  return 36524 + (yi == 0 || yi > 300);
+}
+CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept {
+  const int yi = year_index(y, m);
+  return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96);
+}
+CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept {
+  return is_leap_year(y + (m > 2)) ? 366 : 365;
+}
+CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
+  CONSTEXPR_D int k_days_per_month[1 + 12] = {
+      -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31  // non leap year
+  };
+  return k_days_per_month[m] + (m == 2 && is_leap_year(y));
+}
+
+CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd,
+                         hour_t hh, minute_t mm, second_t ss) noexcept {
+  y += (cd / 146097) * 400;
+  cd %= 146097;
+  if (cd < 0) {
+    y -= 400;
+    cd += 146097;
+  }
+  y += (d / 146097) * 400;
+  d = d % 146097 + cd;
+  if (d > 0) {
+    if (d > 146097) {
+      y += 400;
+      d -= 146097;
+    }
+  } else {
+    if (d > -365) {
+      // We often hit the previous year when stepping a civil time backwards,
+      // so special case it to avoid counting up by 100/4/1-year chunks.
+      y -= 1;
+      d += days_per_year(y, m);
+    } else {
+      y -= 400;
+      d += 146097;
+    }
+  }
+  if (d > 365) {
+    for (int n = days_per_century(y, m); d > n; n = days_per_century(y, m)) {
+      d -= n;
+      y += 100;
+    }
+    for (int n = days_per_4years(y, m); d > n; n = days_per_4years(y, m)) {
+      d -= n;
+      y += 4;
+    }
+    for (int n = days_per_year(y, m); d > n; n = days_per_year(y, m)) {
+      d -= n;
+      ++y;
+    }
+  }
+  if (d > 28) {
+    for (int n = days_per_month(y, m); d > n; n = days_per_month(y, m)) {
+      d -= n;
+      if (++m > 12) {
+        ++y;
+        m = 1;
+      }
+    }
+  }
+  return fields(y, m, static_cast<day_t>(d), hh, mm, ss);
+}
+CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd,
+                         hour_t hh, minute_t mm, second_t ss) noexcept {
+  if (m != 12) {
+    y += m / 12;
+    m %= 12;
+    if (m <= 0) {
+      y -= 1;
+      m += 12;
+    }
+  }
+  return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
+}
+CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd,
+                          diff_t hh, minute_t mm, second_t ss) noexcept {
+  cd += hh / 24;
+  hh %= 24;
+  if (hh < 0) {
+    cd -= 1;
+    hh += 24;
+  }
+  return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss);
+}
+CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch,
+                         diff_t mm, second_t ss) noexcept {
+  ch += mm / 60;
+  mm %= 60;
+  if (mm < 0) {
+    ch -= 1;
+    mm += 60;
+  }
+  return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24,
+                static_cast<minute_t>(mm), ss);
+}
+CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm,
+                         diff_t ss) noexcept {
+  // Optimization for when (non-constexpr) fields are already normalized.
+  if (0 <= ss && ss < 60) {
+    const second_t nss = static_cast<second_t>(ss);
+    if (0 <= mm && mm < 60) {
+      const minute_t nmm = static_cast<minute_t>(mm);
+      if (0 <= hh && hh < 24) {
+        const hour_t nhh = static_cast<hour_t>(hh);
+        if (1 <= d && d <= 28 && 1 <= m && m <= 12) {
+          const day_t nd = static_cast<day_t>(d);
+          const month_t nm = static_cast<month_t>(m);
+          return fields(y, nm, nd, nhh, nmm, nss);
+        }
+        return n_mon(y, m, d, 0, nhh, nmm, nss);
+      }
+      return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss);
+    }
+    return n_min(y, m, d, hh, mm / 60, mm % 60, nss);
+  }
+  diff_t cm = ss / 60;
+  ss %= 60;
+  if (ss < 0) {
+    cm -= 1;
+    ss += 60;
+  }
+  return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60,
+               static_cast<second_t>(ss));
+}
+
+}  // namespace impl
+
+////////////////////////////////////////////////////////////////////////
+
+// Increments the indicated (normalized) field by "n".
+CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept {
+  return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60);
+}
+CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept {
+  return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss);
+}
+CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept {
+  return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept {
+  return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept {
+  return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept {
+  return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+namespace impl {
+
+// Returns (v * f + a) but avoiding intermediate overflow when possible.
+CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept {
+  return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f;
+}
+
+// Map a (normalized) Y/M/D to the number of days before/after 1970-01-01.
+// Probably overflows for years outside [-292277022656:292277026595].
+CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept {
+  const diff_t eyear = (m <= 2) ? y - 1 : y;
+  const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400;
+  const diff_t yoe = eyear - era * 400;
+  const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
+  const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
+  return era * 146097 + doe - 719468;
+}
+
+// Returns the difference in days between two normalized Y-M-D tuples.
+// ymd_ord() will encounter integer overflow given extreme year values,
+// yet the difference between two such extreme values may actually be
+// small, so we take a little care to avoid overflow when possible by
+// exploiting the 146097-day cycle.
+CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1,
+                                  year_t y2, month_t m2, day_t d2) noexcept {
+  const diff_t a_c4_off = y1 % 400;
+  const diff_t b_c4_off = y2 % 400;
+  diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
+  diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2);
+  if (c4_diff > 0 && delta < 0) {
+    delta += 2 * 146097;
+    c4_diff -= 2 * 400;
+  } else if (c4_diff < 0 && delta > 0) {
+    delta -= 2 * 146097;
+    c4_diff += 2 * 400;
+  }
+  return (c4_diff / 400 * 146097) + delta;
+}
+
+}  // namespace impl
+
+// Returns the difference between fields structs using the indicated unit.
+CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept {
+  return f1.y - f2.y;
+}
+CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m));
+}
+CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept {
+  return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d);
+}
+CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh));
+}
+CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm));
+}
+CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// Aligns the (normalized) fields struct to the indicated field.
+CONSTEXPR_F fields align(second_tag, fields f) noexcept {
+  return f;
+}
+CONSTEXPR_F fields align(minute_tag, fields f) noexcept {
+  return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
+}
+CONSTEXPR_F fields align(hour_tag, fields f) noexcept {
+  return fields{f.y, f.m, f.d, f.hh, 0, 0};
+}
+CONSTEXPR_F fields align(day_tag, fields f) noexcept {
+  return fields{f.y, f.m, f.d, 0, 0, 0};
+}
+CONSTEXPR_F fields align(month_tag, fields f) noexcept {
+  return fields{f.y, f.m, 1, 0, 0, 0};
+}
+CONSTEXPR_F fields align(year_tag, fields f) noexcept {
+  return fields{f.y, 1, 1, 0, 0, 0};
+}
+
+////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+class civil_time {
+ public:
+  explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1,
+                                  diff_t hh = 0, diff_t mm = 0,
+                                  diff_t ss = 0) noexcept
+      : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {}
+
+  CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {}
+  civil_time(const civil_time&) = default;
+  civil_time& operator=(const civil_time&) = default;
+
+  // Conversion between civil times of different alignment. Conversion to
+  // a more precise alignment is allowed implicitly (e.g., day -> hour),
+  // but conversion where information is discarded must be explicit
+  // (e.g., second -> minute).
+  template <typename U, typename S>
+  using preserves_data =
+      typename std::enable_if<std::is_base_of<U, S>::value>::type;
+  template <typename U>
+  CONSTEXPR_M civil_time(const civil_time<U>& ct,
+                         preserves_data<T, U>* = nullptr) noexcept
+      : civil_time(ct.f_) {}
+  template <typename U>
+  explicit CONSTEXPR_M civil_time(const civil_time<U>& ct,
+                                  preserves_data<U, T>* = nullptr) noexcept
+      : civil_time(ct.f_) {}
+
+  // Factories for the maximum/minimum representable civil_time.
+  static civil_time max() {
+    const auto max_year = std::numeric_limits<std::int_least64_t>::max();
+    return civil_time(max_year, 12, 31, 23, 59, 59);
+  }
+  static civil_time min() {
+    const auto min_year = std::numeric_limits<std::int_least64_t>::min();
+    return civil_time(min_year, 1, 1, 0, 0, 0);
+  }
+
+  // Field accessors.  Note: All but year() return an int.
+  CONSTEXPR_M year_t year() const noexcept { return f_.y; }
+  CONSTEXPR_M int month() const noexcept { return f_.m; }
+  CONSTEXPR_M int day() const noexcept { return f_.d; }
+  CONSTEXPR_M int hour() const noexcept { return f_.hh; }
+  CONSTEXPR_M int minute() const noexcept { return f_.mm; }
+  CONSTEXPR_M int second() const noexcept { return f_.ss; }
+
+  // Assigning arithmetic.
+  CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
+    f_ = step(T{}, f_, n);
+    return *this;
+  }
+  CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
+    if (n != std::numeric_limits<diff_t>::min()) {
+      f_ = step(T{}, f_, -n);
+    } else {
+      f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
+    }
+    return *this;
+  }
+  CONSTEXPR_M civil_time& operator++() noexcept {
+    return *this += 1;
+  }
+  CONSTEXPR_M civil_time operator++(int) noexcept {
+    const civil_time a = *this;
+    ++*this;
+    return a;
+  }
+  CONSTEXPR_M civil_time& operator--() noexcept {
+    return *this -= 1;
+  }
+  CONSTEXPR_M civil_time operator--(int) noexcept {
+    const civil_time a = *this;
+    --*this;
+    return a;
+  }
+
+  // Binary arithmetic operators.
+  friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
+    return a += n;
+  }
+  friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
+    return a += n;
+  }
+  friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
+    return a -= n;
+  }
+  friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
+    return difference(T{}, lhs.f_, rhs.f_);
+  }
+
+ private:
+  // All instantiations of this template are allowed to call the following
+  // private constructor and access the private fields member.
+  template <typename U>
+  friend class civil_time;
+
+  // The designated constructor that all others eventually call.
+  explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {}
+
+  fields f_;
+};
+
+// Disallows difference between differently aligned types.
+// auto n = civil_day(...) - civil_hour(...);  // would be confusing.
+template <typename T, typename U>
+CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete;
+
+using civil_year = civil_time<year_tag>;
+using civil_month = civil_time<month_tag>;
+using civil_day = civil_time<day_tag>;
+using civil_hour = civil_time<hour_tag>;
+using civil_minute = civil_time<minute_tag>;
+using civil_second = civil_time<second_tag>;
+
+////////////////////////////////////////////////////////////////////////
+
+// Relational operators that work with differently aligned objects.
+// Always compares all six fields.
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
+                           const civil_time<T2>& rhs) noexcept {
+  return (lhs.year() < rhs.year() ||
+          (lhs.year() == rhs.year() &&
+           (lhs.month() < rhs.month() ||
+            (lhs.month() == rhs.month() &&
+             (lhs.day() < rhs.day() ||
+              (lhs.day() == rhs.day() &&
+               (lhs.hour() < rhs.hour() ||
+                (lhs.hour() == rhs.hour() &&
+                 (lhs.minute() < rhs.minute() ||
+                  (lhs.minute() == rhs.minute() &&
+                   (lhs.second() < rhs.second())))))))))));
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return !(rhs < lhs);
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return !(lhs < rhs);
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator>(const civil_time<T1>& lhs,
+                           const civil_time<T2>& rhs) noexcept {
+  return rhs < lhs;
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator==(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return lhs.year() == rhs.year() && lhs.month() == rhs.month() &&
+         lhs.day() == rhs.day() && lhs.hour() == rhs.hour() &&
+         lhs.minute() == rhs.minute() && lhs.second() == rhs.second();
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return !(lhs == rhs);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+enum class weekday {
+  monday,
+  tuesday,
+  wednesday,
+  thursday,
+  friday,
+  saturday,
+  sunday,
+};
+
+CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept {
+  CONSTEXPR_D weekday k_weekday_by_sun_off[7] = {
+      weekday::sunday,     weekday::monday,    weekday::tuesday,
+      weekday::wednesday,  weekday::thursday,  weekday::friday,
+      weekday::saturday,
+  };
+  CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
+      -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
+  };
+  year_t wd = cd.year() - (cd.month() < 3);
+  if (wd >= 0) {
+    wd += wd / 4 - wd / 100 + wd / 400;
+  } else {
+    wd += (wd - 3) / 4 - (wd - 99) / 100 + (wd - 399) / 400;
+  }
+  wd += k_weekday_offsets[cd.month()] + cd.day();
+  return k_weekday_by_sun_off[(wd % 7 + 7) % 7];
+}
+
+////////////////////////////////////////////////////////////////////////
+
+CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
+  do { cd += 1; } while (get_weekday(cd) != wd);
+  return cd;
+}
+
+CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
+  do { cd -= 1; } while (get_weekday(cd) != wd);
+  return cd;
+}
+
+CONSTEXPR_F int get_yearday(const civil_day& cd) noexcept {
+  CONSTEXPR_D int k_month_offsets[1 + 12] = {
+      -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+  };
+  const int feb29 = (cd.month() > 2 && impl::is_leap_year(cd.year()));
+  return k_month_offsets[cd.month()] + feb29 + cd.day();
+}
+
+////////////////////////////////////////////////////////////////////////
+
+std::ostream& operator<<(std::ostream& os, const civil_year& y);
+std::ostream& operator<<(std::ostream& os, const civil_month& m);
+std::ostream& operator<<(std::ostream& os, const civil_day& d);
+std::ostream& operator<<(std::ostream& os, const civil_hour& h);
+std::ostream& operator<<(std::ostream& os, const civil_minute& m);
+std::ostream& operator<<(std::ostream& os, const civil_second& s);
+std::ostream& operator<<(std::ostream& os, weekday wd);
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#undef CONSTEXPR_M
+#undef CONSTEXPR_F
+#undef CONSTEXPR_D
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h
new file mode 100644
index 0000000..0b9764e
--- /dev/null
+++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -0,0 +1,380 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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.
+
+// A library for translating between absolute times (represented by
+// std::chrono::time_points of the std::chrono::system_clock) and civil
+// times (represented by cctz::civil_second) using the rules defined by
+// a time zone (cctz::time_zone).
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
+
+#include <chrono>
+#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// Convenience aliases. Not intended as public API points.
+template <typename D>
+using time_point = std::chrono::time_point<std::chrono::system_clock, D>;
+using seconds = std::chrono::duration<std::int_fast64_t>;
+using sys_seconds = seconds;  // Deprecated.  Use cctz::seconds instead.
+
+namespace detail {
+template <typename D>
+inline std::pair<time_point<seconds>, D>
+split_seconds(const time_point<D>& tp) {
+  auto sec = std::chrono::time_point_cast<seconds>(tp);
+  auto sub = tp - sec;
+  if (sub.count() < 0) {
+    sec -= seconds(1);
+    sub += seconds(1);
+  }
+  return {sec, std::chrono::duration_cast<D>(sub)};
+}
+inline std::pair<time_point<seconds>, seconds>
+split_seconds(const time_point<seconds>& tp) {
+  return {tp, seconds::zero()};
+}
+}  // namespace detail
+
+// cctz::time_zone is an opaque, small, value-type class representing a
+// geo-political region within which particular rules are used for mapping
+// between absolute and civil times. Time zones are named using the TZ
+// identifiers from the IANA Time Zone Database, such as "America/Los_Angeles"
+// or "Australia/Sydney". Time zones are created from factory functions such
+// as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ
+// identifiers.
+//
+// Example:
+//   cctz::time_zone utc = cctz::utc_time_zone();
+//   cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8));
+//   cctz::time_zone loc = cctz::local_time_zone();
+//   cctz::time_zone lax;
+//   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+//
+// See also:
+// - http://www.iana.org/time-zones
+// - http://en.wikipedia.org/wiki/Zoneinfo
+class time_zone {
+ public:
+  time_zone() : time_zone(nullptr) {}  // Equivalent to UTC
+  time_zone(const time_zone&) = default;
+  time_zone& operator=(const time_zone&) = default;
+
+  std::string name() const;
+
+  // An absolute_lookup represents the civil time (cctz::civil_second) within
+  // this time_zone at the given absolute time (time_point). There are
+  // additionally a few other fields that may be useful when working with
+  // older APIs, such as std::tm.
+  //
+  // Example:
+  //   const cctz::time_zone tz = ...
+  //   const auto tp = std::chrono::system_clock::now();
+  //   const cctz::time_zone::absolute_lookup al = tz.lookup(tp);
+  struct absolute_lookup {
+    civil_second cs;
+    // Note: The following fields exist for backward compatibility with older
+    // APIs. Accessing these fields directly is a sign of imprudent logic in
+    // the calling code. Modern time-related code should only access this data
+    // indirectly by way of cctz::format().
+    int offset;        // civil seconds east of UTC
+    bool is_dst;       // is offset non-standard?
+    const char* abbr;  // time-zone abbreviation (e.g., "PST")
+  };
+  absolute_lookup lookup(const time_point<seconds>& tp) const;
+  template <typename D>
+  absolute_lookup lookup(const time_point<D>& tp) const {
+    return lookup(detail::split_seconds(tp).first);
+  }
+
+  // A civil_lookup represents the absolute time(s) (time_point) that
+  // correspond to the given civil time (cctz::civil_second) within this
+  // time_zone. Usually the given civil time represents a unique instant
+  // in time, in which case the conversion is unambiguous. However,
+  // within this time zone, the given civil time may be skipped (e.g.,
+  // during a positive UTC offset shift), or repeated (e.g., during a
+  // negative UTC offset shift). To account for these possibilities,
+  // civil_lookup is richer than just a single time_point.
+  //
+  // In all cases the civil_lookup::kind enum will indicate the nature
+  // of the given civil-time argument, and the pre, trans, and post
+  // members will give the absolute time answers using the pre-transition
+  // offset, the transition point itself, and the post-transition offset,
+  // respectively (all three times are equal if kind == UNIQUE). If any
+  // of these three absolute times is outside the representable range of a
+  // time_point<seconds> the field is set to its maximum/minimum value.
+  //
+  // Example:
+  //   cctz::time_zone lax;
+  //   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+  //
+  //   // A unique civil time.
+  //   auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0));
+  //   // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE
+  //   // jan01.pre    is 2011/01/01 00:00:00 -0800
+  //   // jan01.trans  is 2011/01/01 00:00:00 -0800
+  //   // jan01.post   is 2011/01/01 00:00:00 -0800
+  //
+  //   // A Spring DST transition, when there is a gap in civil time.
+  //   auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0));
+  //   // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED
+  //   // mar13.pre   is 2011/03/13 03:15:00 -0700
+  //   // mar13.trans is 2011/03/13 03:00:00 -0700
+  //   // mar13.post  is 2011/03/13 01:15:00 -0800
+  //
+  //   // A Fall DST transition, when civil times are repeated.
+  //   auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0));
+  //   // nov06.kind == cctz::time_zone::civil_lookup::REPEATED
+  //   // nov06.pre   is 2011/11/06 01:15:00 -0700
+  //   // nov06.trans is 2011/11/06 01:00:00 -0800
+  //   // nov06.post  is 2011/11/06 01:15:00 -0800
+  struct civil_lookup {
+    enum civil_kind {
+      UNIQUE,    // the civil time was singular (pre == trans == post)
+      SKIPPED,   // the civil time did not exist (pre >= trans > post)
+      REPEATED,  // the civil time was ambiguous (pre < trans <= post)
+    } kind;
+    time_point<seconds> pre;    // uses the pre-transition offset
+    time_point<seconds> trans;  // instant of civil-offset change
+    time_point<seconds> post;   // uses the post-transition offset
+  };
+  civil_lookup lookup(const civil_second& cs) const;
+
+  // Finds the time of the next/previous offset change in this time zone.
+  //
+  // By definition, next_transition(tp, &trans) returns false when tp has
+  // its maximum value, and prev_transition(tp, &trans) returns false
+  // when tp has its minimum value. If the zone has no transitions, the
+  // result will also be false no matter what the argument.
+  //
+  // Otherwise, when tp has its minimum value, next_transition(tp, &trans)
+  // returns true and sets trans to the first recorded transition. Chains
+  // of calls to next_transition()/prev_transition() will eventually return
+  // false, but it is unspecified exactly when next_transition(tp, &trans)
+  // jumps to false, or what time is set by prev_transition(tp, &trans) for
+  // a very distant tp.
+  //
+  // Note: Enumeration of time-zone transitions is for informational purposes
+  // only. Modern time-related code should not care about when offset changes
+  // occur.
+  //
+  // Example:
+  //   cctz::time_zone nyc;
+  //   if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
+  //   const auto now = std::chrono::system_clock::now();
+  //   auto tp = cctz::time_point<cctz::seconds>::min();
+  //   cctz::time_zone::civil_transition trans;
+  //   while (tp <= now && nyc.next_transition(tp, &trans)) {
+  //     // transition: trans.from -> trans.to
+  //     tp = nyc.lookup(trans.to).trans;
+  //   }
+  struct civil_transition {
+    civil_second from;  // the civil time we jump from
+    civil_second to;    // the civil time we jump to
+  };
+  bool next_transition(const time_point<seconds>& tp,
+                       civil_transition* trans) const;
+  template <typename D>
+  bool next_transition(const time_point<D>& tp,
+                       civil_transition* trans) const {
+    return next_transition(detail::split_seconds(tp).first, trans);
+  }
+  bool prev_transition(const time_point<seconds>& tp,
+                       civil_transition* trans) const;
+  template <typename D>
+  bool prev_transition(const time_point<D>& tp,
+                       civil_transition* trans) const {
+    return prev_transition(detail::split_seconds(tp).first, trans);
+  }
+
+  // version() and description() provide additional information about the
+  // time zone. The content of each of the returned strings is unspecified,
+  // however, when the IANA Time Zone Database is the underlying data source
+  // the version() std::string will be in the familar form (e.g, "2018e") or
+  // empty when unavailable.
+  //
+  // Note: These functions are for informational or testing purposes only.
+  std::string version() const;  // empty when unknown
+  std::string description() const;
+
+  // Relational operators.
+  friend bool operator==(time_zone lhs, time_zone rhs) {
+    return &lhs.effective_impl() == &rhs.effective_impl();
+  }
+  friend bool operator!=(time_zone lhs, time_zone rhs) {
+    return !(lhs == rhs);
+  }
+
+  class Impl;
+
+ private:
+  explicit time_zone(const Impl* impl) : impl_(impl) {}
+  const Impl& effective_impl() const;  // handles implicit UTC
+  const Impl* impl_;
+};
+
+// Loads the named time zone. May perform I/O on the initial load.
+// If the name is invalid, or some other kind of error occurs, returns
+// false and "*tz" is set to the UTC time zone.
+bool load_time_zone(const std::string& name, time_zone* tz);
+
+// Returns a time_zone representing UTC. Cannot fail.
+time_zone utc_time_zone();
+
+// Returns a time zone that is a fixed offset (seconds east) from UTC.
+// Note: If the absolute value of the offset is greater than 24 hours
+// you'll get UTC (i.e., zero offset) instead.
+time_zone fixed_time_zone(const seconds& offset);
+
+// Returns a time zone representing the local time zone. Falls back to UTC.
+// Note: local_time_zone.name() may only be something like "localtime".
+time_zone local_time_zone();
+
+// Returns the civil time (cctz::civil_second) within the given time zone at
+// the given absolute time (time_point). Since the additional fields provided
+// by the time_zone::absolute_lookup struct should rarely be needed in modern
+// code, this convert() function is simpler and should be preferred.
+template <typename D>
+inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
+  return tz.lookup(tp).cs;
+}
+
+// Returns the absolute time (time_point) that corresponds to the given civil
+// time within the given time zone. If the civil time is not unique (i.e., if
+// it was either repeated or non-existent), then the returned time_point is
+// the best estimate that preserves relative order. That is, this function
+// guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz).
+inline time_point<seconds> convert(const civil_second& cs,
+                                   const time_zone& tz) {
+  const time_zone::civil_lookup cl = tz.lookup(cs);
+  if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
+  return cl.pre;
+}
+
+namespace detail {
+using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
+std::string format(const std::string&, const time_point<seconds>&,
+                   const femtoseconds&, const time_zone&);
+bool parse(const std::string&, const std::string&, const time_zone&,
+           time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
+}  // namespace detail
+
+// Formats the given time_point in the given cctz::time_zone according to
+// the provided format std::string. Uses strftime()-like formatting options,
+// with the following extensions:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E#f - Fractional seconds with # digits of precision
+//   - %E*f - Fractional seconds with full precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//
+// Note that %E0S behaves like %S, and %E0f produces no characters. In
+// contrast %E*f always produces at least one digit, which may be '0'.
+//
+// Note that %Y produces as many characters as it takes to fully render the
+// year. A year outside of [-999:9999] when formatted with %E4Y will produce
+// more than four characters, just like %Y.
+//
+// Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z)
+// so that the resulting std::string uniquely identifies an absolute time.
+//
+// Example:
+//   cctz::time_zone lax;
+//   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+//   auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax);
+//   std::string f = cctz::format("%H:%M:%S", tp, lax);  // "03:04:05"
+//   f = cctz::format("%H:%M:%E3S", tp, lax);            // "03:04:05.000"
+template <typename D>
+inline std::string format(const std::string& fmt, const time_point<D>& tp,
+                          const time_zone& tz) {
+  const auto p = detail::split_seconds(tp);
+  const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second);
+  return detail::format(fmt, p.first, n, tz);
+}
+
+// Parses an input std::string according to the provided format std::string and
+// returns the corresponding time_point. Uses strftime()-like formatting
+// options, with the same extensions as cctz::format(), but with the
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
+// and %E*z also accept the same inputs.
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric. %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+//   "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a std::string of "15:45" (%H:%M) will return a time_point
+// that represents "1970-01-01 15:45:00.0 +0000".
+//
+// Note that parse() returns time instants, so it makes most sense to parse
+// fully-specified date/time strings that include a UTC offset (%z, %Ez, or
+// %E*z).
+//
+// Note also that parse() only heeds the fields year, month, day, hour,
+// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
+// or %A), while parsed for syntactic validity, are ignored in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors rather
+// than normalizing them like cctz::civil_second() would do. For example, it
+// is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A second of ":60" is normalized to ":00" of the following minute with
+// fractional seconds discarded. The following table shows how the given
+// seconds and subseconds will be parsed:
+//
+//   "59.x" -> 59.x  // exact
+//   "60.x" -> 00.0  // normalized
+//   "00.x" -> 00.x  // exact
+//
+// Errors are indicated by returning false.
+//
+// Example:
+//   const cctz::time_zone tz = ...
+//   std::chrono::system_clock::time_point tp;
+//   if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) {
+//     ...
+//   }
+template <typename D>
+inline bool parse(const std::string& fmt, const std::string& input,
+                  const time_zone& tz, time_point<D>* tpp) {
+  time_point<seconds> sec;
+  detail::femtoseconds fs;
+  const bool b = detail::parse(fmt, input, tz, &sec, &fs);
+  if (b) {
+    // TODO: Return false if unrepresentable as a time_point<D>.
+    *tpp = std::chrono::time_point_cast<D>(sec);
+    *tpp += std::chrono::duration_cast<D>(fs);
+  }
+  return b;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
diff --git a/absl/time/internal/cctz/include/cctz/zone_info_source.h b/absl/time/internal/cctz/include/cctz/zone_info_source.h
new file mode 100644
index 0000000..20a7697
--- /dev/null
+++ b/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -0,0 +1,96 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
+#define ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
+
+#include <cstddef>
+#include <functional>
+#include <memory>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// A stdio-like interface for providing zoneinfo data for a particular zone.
+class ZoneInfoSource {
+ public:
+  virtual ~ZoneInfoSource();
+
+  virtual std::size_t Read(void* ptr, std::size_t size) = 0;  // like fread()
+  virtual int Skip(std::size_t offset) = 0;  // like fseek()
+
+  // Until the zoneinfo data supports versioning information, we provide
+  // a way for a ZoneInfoSource to indicate it out-of-band.  The default
+  // implementation returns an empty std::string.
+  virtual std::string Version() const;
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+namespace absl {
+namespace time_internal {
+namespace cctz_extension {
+
+// A function-pointer type for a factory that returns a ZoneInfoSource
+// given the name of a time zone and a fallback factory.  Returns null
+// when the data for the named zone cannot be found.
+using ZoneInfoSourceFactory =
+    std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)(
+        const std::string&,
+        const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
+            const std::string&)>&);
+
+// The user can control the mapping of zone names to zoneinfo data by
+// providing a definition for cctz_extension::zone_info_source_factory.
+// For example, given functions my_factory() and my_other_factory() that
+// can return a ZoneInfoSource for a named zone, we could inject them into
+// cctz::load_time_zone() with:
+//
+//   namespace cctz_extension {
+//   namespace {
+//   std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
+//       const std::string& name,
+//       const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+//           const std::string& name)>& fallback_factory) {
+//     if (auto zip = my_factory(name)) return zip;
+//     if (auto zip = fallback_factory(name)) return zip;
+//     if (auto zip = my_other_factory(name)) return zip;
+//     return nullptr;
+//   }
+//   }  // namespace
+//   ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
+//   }  // namespace cctz_extension
+//
+// This might be used, say, to use zoneinfo data embedded in the program,
+// or read from a (possibly compressed) file archive, or both.
+//
+// cctz_extension::zone_info_source_factory() will be called:
+//   (1) from the same thread as the cctz::load_time_zone() call,
+//   (2) only once for any zone name, and
+//   (3) serially (i.e., no concurrent execution).
+//
+// The fallback factory obtains zoneinfo data by reading files in ${TZDIR},
+// and it is used automatically when no zone_info_source_factory definition
+// is linked into the program.
+extern ZoneInfoSourceFactory zone_info_source_factory;
+
+}  // namespace cctz_extension
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
new file mode 100644
index 0000000..c97df78
--- /dev/null
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -0,0 +1,980 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 <cassert>
+#include <chrono>
+#include <ctime>
+#include <random>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "time_zone_impl.h"
+
+namespace {
+
+namespace cctz = absl::time_internal::cctz;
+
+void BM_Difference_Days(benchmark::State& state) {
+  const cctz::civil_day c(2014, 8, 22);
+  const cctz::civil_day epoch(1970, 1, 1);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(c - epoch);
+  }
+}
+BENCHMARK(BM_Difference_Days);
+
+void BM_Step_Days(benchmark::State& state) {
+  const cctz::civil_day kStart(2014, 8, 22);
+  cctz::civil_day c = kStart;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(++c);
+  }
+}
+BENCHMARK(BM_Step_Days);
+
+const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+
+const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
+const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
+
+// A list of known time-zone names.
+// TODO: Refactor with src/time_zone_lookup_test.cc.
+const char* const kTimeZoneNames[] = {
+  "Africa/Abidjan",
+  "Africa/Accra",
+  "Africa/Addis_Ababa",
+  "Africa/Algiers",
+  "Africa/Asmara",
+  "Africa/Asmera",
+  "Africa/Bamako",
+  "Africa/Bangui",
+  "Africa/Banjul",
+  "Africa/Bissau",
+  "Africa/Blantyre",
+  "Africa/Brazzaville",
+  "Africa/Bujumbura",
+  "Africa/Cairo",
+  "Africa/Casablanca",
+  "Africa/Ceuta",
+  "Africa/Conakry",
+  "Africa/Dakar",
+  "Africa/Dar_es_Salaam",
+  "Africa/Djibouti",
+  "Africa/Douala",
+  "Africa/El_Aaiun",
+  "Africa/Freetown",
+  "Africa/Gaborone",
+  "Africa/Harare",
+  "Africa/Johannesburg",
+  "Africa/Juba",
+  "Africa/Kampala",
+  "Africa/Khartoum",
+  "Africa/Kigali",
+  "Africa/Kinshasa",
+  "Africa/Lagos",
+  "Africa/Libreville",
+  "Africa/Lome",
+  "Africa/Luanda",
+  "Africa/Lubumbashi",
+  "Africa/Lusaka",
+  "Africa/Malabo",
+  "Africa/Maputo",
+  "Africa/Maseru",
+  "Africa/Mbabane",
+  "Africa/Mogadishu",
+  "Africa/Monrovia",
+  "Africa/Nairobi",
+  "Africa/Ndjamena",
+  "Africa/Niamey",
+  "Africa/Nouakchott",
+  "Africa/Ouagadougou",
+  "Africa/Porto-Novo",
+  "Africa/Sao_Tome",
+  "Africa/Timbuktu",
+  "Africa/Tripoli",
+  "Africa/Tunis",
+  "Africa/Windhoek",
+  "America/Adak",
+  "America/Anchorage",
+  "America/Anguilla",
+  "America/Antigua",
+  "America/Araguaina",
+  "America/Argentina/Buenos_Aires",
+  "America/Argentina/Catamarca",
+  "America/Argentina/ComodRivadavia",
+  "America/Argentina/Cordoba",
+  "America/Argentina/Jujuy",
+  "America/Argentina/La_Rioja",
+  "America/Argentina/Mendoza",
+  "America/Argentina/Rio_Gallegos",
+  "America/Argentina/Salta",
+  "America/Argentina/San_Juan",
+  "America/Argentina/San_Luis",
+  "America/Argentina/Tucuman",
+  "America/Argentina/Ushuaia",
+  "America/Aruba",
+  "America/Asuncion",
+  "America/Atikokan",
+  "America/Atka",
+  "America/Bahia",
+  "America/Bahia_Banderas",
+  "America/Barbados",
+  "America/Belem",
+  "America/Belize",
+  "America/Blanc-Sablon",
+  "America/Boa_Vista",
+  "America/Bogota",
+  "America/Boise",
+  "America/Buenos_Aires",
+  "America/Cambridge_Bay",
+  "America/Campo_Grande",
+  "America/Cancun",
+  "America/Caracas",
+  "America/Catamarca",
+  "America/Cayenne",
+  "America/Cayman",
+  "America/Chicago",
+  "America/Chihuahua",
+  "America/Coral_Harbour",
+  "America/Cordoba",
+  "America/Costa_Rica",
+  "America/Creston",
+  "America/Cuiaba",
+  "America/Curacao",
+  "America/Danmarkshavn",
+  "America/Dawson",
+  "America/Dawson_Creek",
+  "America/Denver",
+  "America/Detroit",
+  "America/Dominica",
+  "America/Edmonton",
+  "America/Eirunepe",
+  "America/El_Salvador",
+  "America/Ensenada",
+  "America/Fort_Nelson",
+  "America/Fort_Wayne",
+  "America/Fortaleza",
+  "America/Glace_Bay",
+  "America/Godthab",
+  "America/Goose_Bay",
+  "America/Grand_Turk",
+  "America/Grenada",
+  "America/Guadeloupe",
+  "America/Guatemala",
+  "America/Guayaquil",
+  "America/Guyana",
+  "America/Halifax",
+  "America/Havana",
+  "America/Hermosillo",
+  "America/Indiana/Indianapolis",
+  "America/Indiana/Knox",
+  "America/Indiana/Marengo",
+  "America/Indiana/Petersburg",
+  "America/Indiana/Tell_City",
+  "America/Indiana/Vevay",
+  "America/Indiana/Vincennes",
+  "America/Indiana/Winamac",
+  "America/Indianapolis",
+  "America/Inuvik",
+  "America/Iqaluit",
+  "America/Jamaica",
+  "America/Jujuy",
+  "America/Juneau",
+  "America/Kentucky/Louisville",
+  "America/Kentucky/Monticello",
+  "America/Knox_IN",
+  "America/Kralendijk",
+  "America/La_Paz",
+  "America/Lima",
+  "America/Los_Angeles",
+  "America/Louisville",
+  "America/Lower_Princes",
+  "America/Maceio",
+  "America/Managua",
+  "America/Manaus",
+  "America/Marigot",
+  "America/Martinique",
+  "America/Matamoros",
+  "America/Mazatlan",
+  "America/Mendoza",
+  "America/Menominee",
+  "America/Merida",
+  "America/Metlakatla",
+  "America/Mexico_City",
+  "America/Miquelon",
+  "America/Moncton",
+  "America/Monterrey",
+  "America/Montevideo",
+  "America/Montreal",
+  "America/Montserrat",
+  "America/Nassau",
+  "America/New_York",
+  "America/Nipigon",
+  "America/Nome",
+  "America/Noronha",
+  "America/North_Dakota/Beulah",
+  "America/North_Dakota/Center",
+  "America/North_Dakota/New_Salem",
+  "America/Ojinaga",
+  "America/Panama",
+  "America/Pangnirtung",
+  "America/Paramaribo",
+  "America/Phoenix",
+  "America/Port-au-Prince",
+  "America/Port_of_Spain",
+  "America/Porto_Acre",
+  "America/Porto_Velho",
+  "America/Puerto_Rico",
+  "America/Punta_Arenas",
+  "America/Rainy_River",
+  "America/Rankin_Inlet",
+  "America/Recife",
+  "America/Regina",
+  "America/Resolute",
+  "America/Rio_Branco",
+  "America/Rosario",
+  "America/Santa_Isabel",
+  "America/Santarem",
+  "America/Santiago",
+  "America/Santo_Domingo",
+  "America/Sao_Paulo",
+  "America/Scoresbysund",
+  "America/Shiprock",
+  "America/Sitka",
+  "America/St_Barthelemy",
+  "America/St_Johns",
+  "America/St_Kitts",
+  "America/St_Lucia",
+  "America/St_Thomas",
+  "America/St_Vincent",
+  "America/Swift_Current",
+  "America/Tegucigalpa",
+  "America/Thule",
+  "America/Thunder_Bay",
+  "America/Tijuana",
+  "America/Toronto",
+  "America/Tortola",
+  "America/Vancouver",
+  "America/Virgin",
+  "America/Whitehorse",
+  "America/Winnipeg",
+  "America/Yakutat",
+  "America/Yellowknife",
+  "Antarctica/Casey",
+  "Antarctica/Davis",
+  "Antarctica/DumontDUrville",
+  "Antarctica/Macquarie",
+  "Antarctica/Mawson",
+  "Antarctica/McMurdo",
+  "Antarctica/Palmer",
+  "Antarctica/Rothera",
+  "Antarctica/South_Pole",
+  "Antarctica/Syowa",
+  "Antarctica/Troll",
+  "Antarctica/Vostok",
+  "Arctic/Longyearbyen",
+  "Asia/Aden",
+  "Asia/Almaty",
+  "Asia/Amman",
+  "Asia/Anadyr",
+  "Asia/Aqtau",
+  "Asia/Aqtobe",
+  "Asia/Ashgabat",
+  "Asia/Ashkhabad",
+  "Asia/Atyrau",
+  "Asia/Baghdad",
+  "Asia/Bahrain",
+  "Asia/Baku",
+  "Asia/Bangkok",
+  "Asia/Barnaul",
+  "Asia/Beirut",
+  "Asia/Bishkek",
+  "Asia/Brunei",
+  "Asia/Calcutta",
+  "Asia/Chita",
+  "Asia/Choibalsan",
+  "Asia/Chongqing",
+  "Asia/Chungking",
+  "Asia/Colombo",
+  "Asia/Dacca",
+  "Asia/Damascus",
+  "Asia/Dhaka",
+  "Asia/Dili",
+  "Asia/Dubai",
+  "Asia/Dushanbe",
+  "Asia/Famagusta",
+  "Asia/Gaza",
+  "Asia/Harbin",
+  "Asia/Hebron",
+  "Asia/Ho_Chi_Minh",
+  "Asia/Hong_Kong",
+  "Asia/Hovd",
+  "Asia/Irkutsk",
+  "Asia/Istanbul",
+  "Asia/Jakarta",
+  "Asia/Jayapura",
+  "Asia/Jerusalem",
+  "Asia/Kabul",
+  "Asia/Kamchatka",
+  "Asia/Karachi",
+  "Asia/Kashgar",
+  "Asia/Kathmandu",
+  "Asia/Katmandu",
+  "Asia/Khandyga",
+  "Asia/Kolkata",
+  "Asia/Krasnoyarsk",
+  "Asia/Kuala_Lumpur",
+  "Asia/Kuching",
+  "Asia/Kuwait",
+  "Asia/Macao",
+  "Asia/Macau",
+  "Asia/Magadan",
+  "Asia/Makassar",
+  "Asia/Manila",
+  "Asia/Muscat",
+  "Asia/Nicosia",
+  "Asia/Novokuznetsk",
+  "Asia/Novosibirsk",
+  "Asia/Omsk",
+  "Asia/Oral",
+  "Asia/Phnom_Penh",
+  "Asia/Pontianak",
+  "Asia/Pyongyang",
+  "Asia/Qatar",
+  "Asia/Qyzylorda",
+  "Asia/Rangoon",
+  "Asia/Riyadh",
+  "Asia/Saigon",
+  "Asia/Sakhalin",
+  "Asia/Samarkand",
+  "Asia/Seoul",
+  "Asia/Shanghai",
+  "Asia/Singapore",
+  "Asia/Srednekolymsk",
+  "Asia/Taipei",
+  "Asia/Tashkent",
+  "Asia/Tbilisi",
+  "Asia/Tehran",
+  "Asia/Tel_Aviv",
+  "Asia/Thimbu",
+  "Asia/Thimphu",
+  "Asia/Tokyo",
+  "Asia/Tomsk",
+  "Asia/Ujung_Pandang",
+  "Asia/Ulaanbaatar",
+  "Asia/Ulan_Bator",
+  "Asia/Urumqi",
+  "Asia/Ust-Nera",
+  "Asia/Vientiane",
+  "Asia/Vladivostok",
+  "Asia/Yakutsk",
+  "Asia/Yangon",
+  "Asia/Yekaterinburg",
+  "Asia/Yerevan",
+  "Atlantic/Azores",
+  "Atlantic/Bermuda",
+  "Atlantic/Canary",
+  "Atlantic/Cape_Verde",
+  "Atlantic/Faeroe",
+  "Atlantic/Faroe",
+  "Atlantic/Jan_Mayen",
+  "Atlantic/Madeira",
+  "Atlantic/Reykjavik",
+  "Atlantic/South_Georgia",
+  "Atlantic/St_Helena",
+  "Atlantic/Stanley",
+  "Australia/ACT",
+  "Australia/Adelaide",
+  "Australia/Brisbane",
+  "Australia/Broken_Hill",
+  "Australia/Canberra",
+  "Australia/Currie",
+  "Australia/Darwin",
+  "Australia/Eucla",
+  "Australia/Hobart",
+  "Australia/LHI",
+  "Australia/Lindeman",
+  "Australia/Lord_Howe",
+  "Australia/Melbourne",
+  "Australia/NSW",
+  "Australia/North",
+  "Australia/Perth",
+  "Australia/Queensland",
+  "Australia/South",
+  "Australia/Sydney",
+  "Australia/Tasmania",
+  "Australia/Victoria",
+  "Australia/West",
+  "Australia/Yancowinna",
+  "Brazil/Acre",
+  "Brazil/DeNoronha",
+  "Brazil/East",
+  "Brazil/West",
+  "CET",
+  "CST6CDT",
+  "Canada/Atlantic",
+  "Canada/Central",
+  "Canada/Eastern",
+  "Canada/Mountain",
+  "Canada/Newfoundland",
+  "Canada/Pacific",
+  "Canada/Saskatchewan",
+  "Canada/Yukon",
+  "Chile/Continental",
+  "Chile/EasterIsland",
+  "Cuba",
+  "EET",
+  "EST",
+  "EST5EDT",
+  "Egypt",
+  "Eire",
+  "Etc/GMT",
+  "Etc/GMT+0",
+  "Etc/GMT+1",
+  "Etc/GMT+10",
+  "Etc/GMT+11",
+  "Etc/GMT+12",
+  "Etc/GMT+2",
+  "Etc/GMT+3",
+  "Etc/GMT+4",
+  "Etc/GMT+5",
+  "Etc/GMT+6",
+  "Etc/GMT+7",
+  "Etc/GMT+8",
+  "Etc/GMT+9",
+  "Etc/GMT-0",
+  "Etc/GMT-1",
+  "Etc/GMT-10",
+  "Etc/GMT-11",
+  "Etc/GMT-12",
+  "Etc/GMT-13",
+  "Etc/GMT-14",
+  "Etc/GMT-2",
+  "Etc/GMT-3",
+  "Etc/GMT-4",
+  "Etc/GMT-5",
+  "Etc/GMT-6",
+  "Etc/GMT-7",
+  "Etc/GMT-8",
+  "Etc/GMT-9",
+  "Etc/GMT0",
+  "Etc/Greenwich",
+  "Etc/UCT",
+  "Etc/UTC",
+  "Etc/Universal",
+  "Etc/Zulu",
+  "Europe/Amsterdam",
+  "Europe/Andorra",
+  "Europe/Astrakhan",
+  "Europe/Athens",
+  "Europe/Belfast",
+  "Europe/Belgrade",
+  "Europe/Berlin",
+  "Europe/Bratislava",
+  "Europe/Brussels",
+  "Europe/Bucharest",
+  "Europe/Budapest",
+  "Europe/Busingen",
+  "Europe/Chisinau",
+  "Europe/Copenhagen",
+  "Europe/Dublin",
+  "Europe/Gibraltar",
+  "Europe/Guernsey",
+  "Europe/Helsinki",
+  "Europe/Isle_of_Man",
+  "Europe/Istanbul",
+  "Europe/Jersey",
+  "Europe/Kaliningrad",
+  "Europe/Kiev",
+  "Europe/Kirov",
+  "Europe/Lisbon",
+  "Europe/Ljubljana",
+  "Europe/London",
+  "Europe/Luxembourg",
+  "Europe/Madrid",
+  "Europe/Malta",
+  "Europe/Mariehamn",
+  "Europe/Minsk",
+  "Europe/Monaco",
+  "Europe/Moscow",
+  "Europe/Nicosia",
+  "Europe/Oslo",
+  "Europe/Paris",
+  "Europe/Podgorica",
+  "Europe/Prague",
+  "Europe/Riga",
+  "Europe/Rome",
+  "Europe/Samara",
+  "Europe/San_Marino",
+  "Europe/Sarajevo",
+  "Europe/Saratov",
+  "Europe/Simferopol",
+  "Europe/Skopje",
+  "Europe/Sofia",
+  "Europe/Stockholm",
+  "Europe/Tallinn",
+  "Europe/Tirane",
+  "Europe/Tiraspol",
+  "Europe/Ulyanovsk",
+  "Europe/Uzhgorod",
+  "Europe/Vaduz",
+  "Europe/Vatican",
+  "Europe/Vienna",
+  "Europe/Vilnius",
+  "Europe/Volgograd",
+  "Europe/Warsaw",
+  "Europe/Zagreb",
+  "Europe/Zaporozhye",
+  "Europe/Zurich",
+  "GB",
+  "GB-Eire",
+  "GMT",
+  "GMT+0",
+  "GMT-0",
+  "GMT0",
+  "Greenwich",
+  "HST",
+  "Hongkong",
+  "Iceland",
+  "Indian/Antananarivo",
+  "Indian/Chagos",
+  "Indian/Christmas",
+  "Indian/Cocos",
+  "Indian/Comoro",
+  "Indian/Kerguelen",
+  "Indian/Mahe",
+  "Indian/Maldives",
+  "Indian/Mauritius",
+  "Indian/Mayotte",
+  "Indian/Reunion",
+  "Iran",
+  "Israel",
+  "Jamaica",
+  "Japan",
+  "Kwajalein",
+  "Libya",
+  "MET",
+  "MST",
+  "MST7MDT",
+  "Mexico/BajaNorte",
+  "Mexico/BajaSur",
+  "Mexico/General",
+  "NZ",
+  "NZ-CHAT",
+  "Navajo",
+  "PRC",
+  "PST8PDT",
+  "Pacific/Apia",
+  "Pacific/Auckland",
+  "Pacific/Bougainville",
+  "Pacific/Chatham",
+  "Pacific/Chuuk",
+  "Pacific/Easter",
+  "Pacific/Efate",
+  "Pacific/Enderbury",
+  "Pacific/Fakaofo",
+  "Pacific/Fiji",
+  "Pacific/Funafuti",
+  "Pacific/Galapagos",
+  "Pacific/Gambier",
+  "Pacific/Guadalcanal",
+  "Pacific/Guam",
+  "Pacific/Honolulu",
+  "Pacific/Johnston",
+  "Pacific/Kiritimati",
+  "Pacific/Kosrae",
+  "Pacific/Kwajalein",
+  "Pacific/Majuro",
+  "Pacific/Marquesas",
+  "Pacific/Midway",
+  "Pacific/Nauru",
+  "Pacific/Niue",
+  "Pacific/Norfolk",
+  "Pacific/Noumea",
+  "Pacific/Pago_Pago",
+  "Pacific/Palau",
+  "Pacific/Pitcairn",
+  "Pacific/Pohnpei",
+  "Pacific/Ponape",
+  "Pacific/Port_Moresby",
+  "Pacific/Rarotonga",
+  "Pacific/Saipan",
+  "Pacific/Samoa",
+  "Pacific/Tahiti",
+  "Pacific/Tarawa",
+  "Pacific/Tongatapu",
+  "Pacific/Truk",
+  "Pacific/Wake",
+  "Pacific/Wallis",
+  "Pacific/Yap",
+  "Poland",
+  "Portugal",
+  "ROC",
+  "ROK",
+  "Singapore",
+  "Turkey",
+  "UCT",
+  "US/Alaska",
+  "US/Aleutian",
+  "US/Arizona",
+  "US/Central",
+  "US/East-Indiana",
+  "US/Eastern",
+  "US/Hawaii",
+  "US/Indiana-Starke",
+  "US/Michigan",
+  "US/Mountain",
+  "US/Pacific",
+  "US/Samoa",
+  "UTC",
+  "Universal",
+  "W-SU",
+  "WET",
+  "Zulu",
+  nullptr
+};
+
+std::vector<std::string> AllTimeZoneNames() {
+  std::vector<std::string> names;
+  for (const char* const* namep = kTimeZoneNames; *namep != nullptr; ++namep) {
+    names.push_back(std::string("file:") + *namep);
+  }
+  assert(!names.empty());
+
+  std::mt19937 urbg(42);  // a UniformRandomBitGenerator with fixed seed
+  std::shuffle(names.begin(), names.end(), urbg);
+  return names;
+}
+
+cctz::time_zone TestTimeZone() {
+  cctz::time_zone tz;
+  cctz::load_time_zone("America/Los_Angeles", &tz);
+  return tz;
+}
+
+void BM_Zone_LoadUTCTimeZoneFirst(benchmark::State& state) {
+  cctz::time_zone tz;
+  cctz::load_time_zone("UTC", &tz);  // in case we're first
+  cctz::time_zone::Impl::ClearTimeZoneMapTestOnly();
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz));
+  }
+}
+BENCHMARK(BM_Zone_LoadUTCTimeZoneFirst);
+
+void BM_Zone_LoadUTCTimeZoneLast(benchmark::State& state) {
+  cctz::time_zone tz;
+  for (const auto& name : AllTimeZoneNames()) {
+    cctz::load_time_zone(name, &tz);  // prime cache
+  }
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz));
+  }
+}
+BENCHMARK(BM_Zone_LoadUTCTimeZoneLast);
+
+void BM_Zone_LoadTimeZoneFirst(benchmark::State& state) {
+  cctz::time_zone tz = cctz::utc_time_zone();  // in case we're first
+  const std::string name = "file:America/Los_Angeles";
+  while (state.KeepRunning()) {
+    state.PauseTiming();
+    cctz::time_zone::Impl::ClearTimeZoneMapTestOnly();
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz));
+  }
+}
+BENCHMARK(BM_Zone_LoadTimeZoneFirst);
+
+void BM_Zone_LoadTimeZoneCached(benchmark::State& state) {
+  cctz::time_zone tz = cctz::utc_time_zone();  // in case we're first
+  cctz::time_zone::Impl::ClearTimeZoneMapTestOnly();
+  const std::string name = "file:America/Los_Angeles";
+  cctz::load_time_zone(name, &tz);  // prime cache
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz));
+  }
+}
+BENCHMARK(BM_Zone_LoadTimeZoneCached);
+
+void BM_Zone_LoadLocalTimeZoneCached(benchmark::State& state) {
+  cctz::utc_time_zone();  // in case we're first
+  cctz::time_zone::Impl::ClearTimeZoneMapTestOnly();
+  cctz::local_time_zone();  // prime cache
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::local_time_zone());
+  }
+}
+BENCHMARK(BM_Zone_LoadLocalTimeZoneCached);
+
+void BM_Zone_LoadAllTimeZonesFirst(benchmark::State& state) {
+  cctz::time_zone tz;
+  const std::vector<std::string> names = AllTimeZoneNames();
+  for (auto index = names.size(); state.KeepRunning(); ++index) {
+    if (index == names.size()) {
+      index = 0;
+    }
+    if (index == 0) {
+      state.PauseTiming();
+      cctz::time_zone::Impl::ClearTimeZoneMapTestOnly();
+      state.ResumeTiming();
+    }
+    benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz));
+  }
+}
+BENCHMARK(BM_Zone_LoadAllTimeZonesFirst);
+
+void BM_Zone_LoadAllTimeZonesCached(benchmark::State& state) {
+  cctz::time_zone tz;
+  const std::vector<std::string> names = AllTimeZoneNames();
+  for (const auto& name : names) {
+    cctz::load_time_zone(name, &tz);  // prime cache
+  }
+  for (auto index = names.size(); state.KeepRunning(); ++index) {
+    if (index == names.size()) {
+      index = 0;
+    }
+    benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz));
+  }
+}
+BENCHMARK(BM_Zone_LoadAllTimeZonesCached);
+
+void BM_Zone_TimeZoneEqualityImplicit(benchmark::State& state) {
+  cctz::time_zone tz;  // implicit UTC
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(tz == tz);
+  }
+}
+BENCHMARK(BM_Zone_TimeZoneEqualityImplicit);
+
+void BM_Zone_TimeZoneEqualityExplicit(benchmark::State& state) {
+  cctz::time_zone tz = cctz::utc_time_zone();  // explicit UTC
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(tz == tz);
+  }
+}
+BENCHMARK(BM_Zone_TimeZoneEqualityExplicit);
+
+void BM_Zone_UTCTimeZone(benchmark::State& state) {
+  cctz::time_zone tz;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::utc_time_zone());
+  }
+}
+BENCHMARK(BM_Zone_UTCTimeZone);
+
+// In each "ToDateTime" benchmark we switch between two instants
+// separated by at least one transition in order to defeat any
+// internal caching of previous results (e.g., see local_time_hint_).
+//
+// The "UTC" variants use UTC instead of the Google/local time zone.
+
+void BM_Time_ToDateTime_CCTZ(benchmark::State& state) {
+  const cctz::time_zone tz = TestTimeZone();
+  std::chrono::system_clock::time_point tp =
+      std::chrono::system_clock::from_time_t(1384569027);
+  std::chrono::system_clock::time_point tp2 =
+      std::chrono::system_clock::from_time_t(1418962578);
+  while (state.KeepRunning()) {
+    std::swap(tp, tp2);
+    tp += std::chrono::seconds(1);
+    benchmark::DoNotOptimize(cctz::convert(tp, tz));
+  }
+}
+BENCHMARK(BM_Time_ToDateTime_CCTZ);
+
+void BM_Time_ToDateTime_Libc(benchmark::State& state) {
+  // No timezone support, so just use localtime.
+  time_t t = 1384569027;
+  time_t t2 = 1418962578;
+  struct tm tm;
+  while (state.KeepRunning()) {
+    std::swap(t, t2);
+    t += 1;
+#if defined(_WIN32) || defined(_WIN64)
+    benchmark::DoNotOptimize(localtime_s(&tm, &t));
+#else
+    benchmark::DoNotOptimize(localtime_r(&t, &tm));
+#endif
+  }
+}
+BENCHMARK(BM_Time_ToDateTime_Libc);
+
+void BM_Time_ToDateTimeUTC_CCTZ(benchmark::State& state) {
+  const cctz::time_zone tz = cctz::utc_time_zone();
+  std::chrono::system_clock::time_point tp =
+      std::chrono::system_clock::from_time_t(1384569027);
+  while (state.KeepRunning()) {
+    tp += std::chrono::seconds(1);
+    benchmark::DoNotOptimize(cctz::convert(tp, tz));
+  }
+}
+BENCHMARK(BM_Time_ToDateTimeUTC_CCTZ);
+
+void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) {
+  time_t t = 1384569027;
+  struct tm tm;
+  while (state.KeepRunning()) {
+    t += 1;
+#if defined(_WIN32) || defined(_WIN64)
+    benchmark::DoNotOptimize(gmtime_s(&tm, &t));
+#else
+    benchmark::DoNotOptimize(gmtime_r(&t, &tm));
+#endif
+  }
+}
+BENCHMARK(BM_Time_ToDateTimeUTC_Libc);
+
+// In each "FromDateTime" benchmark we switch between two YMDhms
+// values separated by at least one transition in order to defeat any
+// internal caching of previous results (e.g., see time_local_hint_).
+//
+// The "UTC" variants use UTC instead of the Google/local time zone.
+// The "Day0" variants require normalization of the day of month.
+
+void BM_Time_FromDateTime_CCTZ(benchmark::State& state) {
+  const cctz::time_zone tz = TestTimeZone();
+  int i = 0;
+  while (state.KeepRunning()) {
+    if ((i++ & 1) == 0) {
+      benchmark::DoNotOptimize(
+          cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz));
+    } else {
+      benchmark::DoNotOptimize(
+          cctz::convert(cctz::civil_second(2013, 11, 15, 18, 30, 27), tz));
+    }
+  }
+}
+BENCHMARK(BM_Time_FromDateTime_CCTZ);
+
+void BM_Time_FromDateTime_Libc(benchmark::State& state) {
+  // No timezone support, so just use localtime.
+  int i = 0;
+  while (state.KeepRunning()) {
+    struct tm tm;
+    if ((i++ & 1) == 0) {
+      tm.tm_year = 2014 - 1900;
+      tm.tm_mon = 12 - 1;
+      tm.tm_mday = 18;
+      tm.tm_hour = 20;
+      tm.tm_min = 16;
+      tm.tm_sec = 18;
+    } else {
+      tm.tm_year = 2013 - 1900;
+      tm.tm_mon = 11 - 1;
+      tm.tm_mday = 15;
+      tm.tm_hour = 18;
+      tm.tm_min = 30;
+      tm.tm_sec = 27;
+    }
+    tm.tm_isdst = -1;
+    benchmark::DoNotOptimize(mktime(&tm));
+  }
+}
+BENCHMARK(BM_Time_FromDateTime_Libc);
+
+void BM_Time_FromDateTimeUTC_CCTZ(benchmark::State& state) {
+  const cctz::time_zone tz = cctz::utc_time_zone();
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(
+        cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz));
+  }
+}
+BENCHMARK(BM_Time_FromDateTimeUTC_CCTZ);
+
+// There is no BM_Time_FromDateTimeUTC_Libc.
+
+void BM_Time_FromDateTimeDay0_CCTZ(benchmark::State& state) {
+  const cctz::time_zone tz = TestTimeZone();
+  int i = 0;
+  while (state.KeepRunning()) {
+    if ((i++ & 1) == 0) {
+      benchmark::DoNotOptimize(
+          cctz::convert(cctz::civil_second(2014, 12, 0, 20, 16, 18), tz));
+    } else {
+      benchmark::DoNotOptimize(
+          cctz::convert(cctz::civil_second(2013, 11, 0, 18, 30, 27), tz));
+    }
+  }
+}
+BENCHMARK(BM_Time_FromDateTimeDay0_CCTZ);
+
+void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) {
+  // No timezone support, so just use localtime.
+  int i = 0;
+  while (state.KeepRunning()) {
+    struct tm tm;
+    if ((i++ & 1) == 0) {
+      tm.tm_year = 2014 - 1900;
+      tm.tm_mon = 12 - 1;
+      tm.tm_mday = 0;
+      tm.tm_hour = 20;
+      tm.tm_min = 16;
+      tm.tm_sec = 18;
+    } else {
+      tm.tm_year = 2013 - 1900;
+      tm.tm_mon = 11 - 1;
+      tm.tm_mday = 0;
+      tm.tm_hour = 18;
+      tm.tm_min = 30;
+      tm.tm_sec = 27;
+    }
+    tm.tm_isdst = -1;
+    benchmark::DoNotOptimize(mktime(&tm));
+  }
+}
+BENCHMARK(BM_Time_FromDateTimeDay0_Libc);
+
+const char* const kFormats[] = {
+    RFC1123_full,         // 0
+    RFC1123_no_wday,      // 1
+    RFC3339_full,         // 2
+    RFC3339_sec,          // 3
+    "%Y-%m-%dT%H:%M:%S",  // 4
+    "%Y-%m-%d",           // 5
+};
+const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
+
+void BM_Format_FormatTime(benchmark::State& state) {
+  const std::string fmt = kFormats[state.range(0)];
+  state.SetLabel(fmt);
+  const cctz::time_zone tz = TestTimeZone();
+  const std::chrono::system_clock::time_point tp =
+      cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) +
+      std::chrono::microseconds(1);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::format(fmt, tp, tz));
+  }
+}
+BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1);
+
+void BM_Format_ParseTime(benchmark::State& state) {
+  const std::string fmt = kFormats[state.range(0)];
+  state.SetLabel(fmt);
+  const cctz::time_zone tz = TestTimeZone();
+  std::chrono::system_clock::time_point tp =
+      cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) +
+      std::chrono::microseconds(1);
+  const std::string when = cctz::format(fmt, tp, tz);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(cctz::parse(fmt, when, tz, &tp));
+  }
+}
+BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1);
+
+}  // namespace
diff --git a/absl/time/internal/cctz/src/civil_time_detail.cc b/absl/time/internal/cctz/src/civil_time_detail.cc
new file mode 100644
index 0000000..780d5c9
--- /dev/null
+++ b/absl/time/internal/cctz/src/civil_time_detail.cc
@@ -0,0 +1,90 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
+
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+namespace detail {
+
+// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss,
+// while omitting fields inferior to the type's alignment. For example,
+// civil_day is formatted only as YYYY-MM-DD.
+std::ostream& operator<<(std::ostream& os, const civil_year& y) {
+  std::stringstream ss;
+  ss << y.year();  // No padding.
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_month& m) {
+  std::stringstream ss;
+  ss << civil_year(m) << '-';
+  ss << std::setfill('0') << std::setw(2) << m.month();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_day& d) {
+  std::stringstream ss;
+  ss << civil_month(d) << '-';
+  ss << std::setfill('0') << std::setw(2) << d.day();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_hour& h) {
+  std::stringstream ss;
+  ss << civil_day(h) << 'T';
+  ss << std::setfill('0') << std::setw(2) << h.hour();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_minute& m) {
+  std::stringstream ss;
+  ss << civil_hour(m) << ':';
+  ss << std::setfill('0') << std::setw(2) << m.minute();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_second& s) {
+  std::stringstream ss;
+  ss << civil_minute(s) << ':';
+  ss << std::setfill('0') << std::setw(2) << s.second();
+  return os << ss.str();
+}
+
+////////////////////////////////////////////////////////////////////////
+
+std::ostream& operator<<(std::ostream& os, weekday wd) {
+  switch (wd) {
+    case weekday::monday:
+      return os << "Monday";
+    case weekday::tuesday:
+      return os << "Tuesday";
+    case weekday::wednesday:
+      return os << "Wednesday";
+    case weekday::thursday:
+      return os << "Thursday";
+    case weekday::friday:
+      return os << "Friday";
+    case weekday::saturday:
+      return os << "Saturday";
+    case weekday::sunday:
+      return os << "Sunday";
+  }
+  return os;  // Should never get here, but -Wreturn-type may warn without this.
+}
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
new file mode 100644
index 0000000..f6648c8
--- /dev/null
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -0,0 +1,1049 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "absl/time/internal/cctz/include/cctz/civil_time.h"
+
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+template <typename T>
+std::string Format(const T& t) {
+  std::stringstream ss;
+  ss << t;
+  return ss.str();
+}
+
+}  // namespace
+
+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
+// Construction constexpr tests
+
+TEST(CivilTime, Normal) {
+  constexpr civil_second css(2016, 1, 28, 17, 14, 12);
+  static_assert(css.second() == 12, "Normal.second");
+  constexpr civil_minute cmm(2016, 1, 28, 17, 14);
+  static_assert(cmm.minute() == 14, "Normal.minute");
+  constexpr civil_hour chh(2016, 1, 28, 17);
+  static_assert(chh.hour() == 17, "Normal.hour");
+  constexpr civil_day cd(2016, 1, 28);
+  static_assert(cd.day() == 28, "Normal.day");
+  constexpr civil_month cm(2016, 1);
+  static_assert(cm.month() == 1, "Normal.month");
+  constexpr civil_year cy(2016);
+  static_assert(cy.year() == 2016, "Normal.year");
+}
+
+TEST(CivilTime, Conversion) {
+  constexpr civil_year cy(2016);
+  static_assert(cy.year() == 2016, "Conversion.year");
+  constexpr civil_month cm(cy);
+  static_assert(cm.month() == 1, "Conversion.month");
+  constexpr civil_day cd(cm);
+  static_assert(cd.day() == 1, "Conversion.day");
+  constexpr civil_hour chh(cd);
+  static_assert(chh.hour() == 0, "Conversion.hour");
+  constexpr civil_minute cmm(chh);
+  static_assert(cmm.minute() == 0, "Conversion.minute");
+  constexpr civil_second css(cmm);
+  static_assert(css.second() == 0, "Conversion.second");
+}
+
+// Normalization constexpr tests
+
+TEST(CivilTime, Normalized) {
+  constexpr civil_second cs(2016, 1, 28, 17, 14, 12);
+  static_assert(cs.year() == 2016, "Normalized.year");
+  static_assert(cs.month() == 1, "Normalized.month");
+  static_assert(cs.day() == 28, "Normalized.day");
+  static_assert(cs.hour() == 17, "Normalized.hour");
+  static_assert(cs.minute() == 14, "Normalized.minute");
+  static_assert(cs.second() == 12, "Normalized.second");
+}
+
+TEST(CivilTime, SecondOverflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, 14, 121);
+  static_assert(cs.year() == 2016, "SecondOverflow.year");
+  static_assert(cs.month() == 1, "SecondOverflow.month");
+  static_assert(cs.day() == 28, "SecondOverflow.day");
+  static_assert(cs.hour() == 17, "SecondOverflow.hour");
+  static_assert(cs.minute() == 16, "SecondOverflow.minute");
+  static_assert(cs.second() == 1, "SecondOverflow.second");
+}
+
+TEST(CivilTime, SecondUnderflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, 14, -121);
+  static_assert(cs.year() == 2016, "SecondUnderflow.year");
+  static_assert(cs.month() == 1, "SecondUnderflow.month");
+  static_assert(cs.day() == 28, "SecondUnderflow.day");
+  static_assert(cs.hour() == 17, "SecondUnderflow.hour");
+  static_assert(cs.minute() == 11, "SecondUnderflow.minute");
+  static_assert(cs.second() == 59, "SecondUnderflow.second");
+}
+
+TEST(CivilTime, MinuteOverflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, 121, 12);
+  static_assert(cs.year() == 2016, "MinuteOverflow.year");
+  static_assert(cs.month() == 1, "MinuteOverflow.month");
+  static_assert(cs.day() == 28, "MinuteOverflow.day");
+  static_assert(cs.hour() == 19, "MinuteOverflow.hour");
+  static_assert(cs.minute() == 1, "MinuteOverflow.minute");
+  static_assert(cs.second() == 12, "MinuteOverflow.second");
+}
+
+TEST(CivilTime, MinuteUnderflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, -121, 12);
+  static_assert(cs.year() == 2016, "MinuteUnderflow.year");
+  static_assert(cs.month() == 1, "MinuteUnderflow.month");
+  static_assert(cs.day() == 28, "MinuteUnderflow.day");
+  static_assert(cs.hour() == 14, "MinuteUnderflow.hour");
+  static_assert(cs.minute() == 59, "MinuteUnderflow.minute");
+  static_assert(cs.second() == 12, "MinuteUnderflow.second");
+}
+
+TEST(CivilTime, HourOverflow) {
+  constexpr civil_second cs(2016, 1, 28, 49, 14, 12);
+  static_assert(cs.year() == 2016, "HourOverflow.year");
+  static_assert(cs.month() == 1, "HourOverflow.month");
+  static_assert(cs.day() == 30, "HourOverflow.day");
+  static_assert(cs.hour() == 1, "HourOverflow.hour");
+  static_assert(cs.minute() == 14, "HourOverflow.minute");
+  static_assert(cs.second() == 12, "HourOverflow.second");
+}
+
+TEST(CivilTime, HourUnderflow) {
+  constexpr civil_second cs(2016, 1, 28, -49, 14, 12);
+  static_assert(cs.year() == 2016, "HourUnderflow.year");
+  static_assert(cs.month() == 1, "HourUnderflow.month");
+  static_assert(cs.day() == 25, "HourUnderflow.day");
+  static_assert(cs.hour() == 23, "HourUnderflow.hour");
+  static_assert(cs.minute() == 14, "HourUnderflow.minute");
+  static_assert(cs.second() == 12, "HourUnderflow.second");
+}
+
+TEST(CivilTime, MonthOverflow) {
+  constexpr civil_second cs(2016, 25, 28, 17, 14, 12);
+  static_assert(cs.year() == 2018, "MonthOverflow.year");
+  static_assert(cs.month() == 1, "MonthOverflow.month");
+  static_assert(cs.day() == 28, "MonthOverflow.day");
+  static_assert(cs.hour() == 17, "MonthOverflow.hour");
+  static_assert(cs.minute() == 14, "MonthOverflow.minute");
+  static_assert(cs.second() == 12, "MonthOverflow.second");
+}
+
+TEST(CivilTime, MonthUnderflow) {
+  constexpr civil_second cs(2016, -25, 28, 17, 14, 12);
+  static_assert(cs.year() == 2013, "MonthUnderflow.year");
+  static_assert(cs.month() == 11, "MonthUnderflow.month");
+  static_assert(cs.day() == 28, "MonthUnderflow.day");
+  static_assert(cs.hour() == 17, "MonthUnderflow.hour");
+  static_assert(cs.minute() == 14, "MonthUnderflow.minute");
+  static_assert(cs.second() == 12, "MonthUnderflow.second");
+}
+
+TEST(CivilTime, C4Overflow) {
+  constexpr civil_second cs(2016, 1, 292195, 17, 14, 12);
+  static_assert(cs.year() == 2816, "C4Overflow.year");
+  static_assert(cs.month() == 1, "C4Overflow.month");
+  static_assert(cs.day() == 1, "C4Overflow.day");
+  static_assert(cs.hour() == 17, "C4Overflow.hour");
+  static_assert(cs.minute() == 14, "C4Overflow.minute");
+  static_assert(cs.second() == 12, "C4Overflow.second");
+}
+
+TEST(CivilTime, C4Underflow) {
+  constexpr civil_second cs(2016, 1, -292195, 17, 14, 12);
+  static_assert(cs.year() == 1215, "C4Underflow.year");
+  static_assert(cs.month() == 12, "C4Underflow.month");
+  static_assert(cs.day() == 30, "C4Underflow.day");
+  static_assert(cs.hour() == 17, "C4Underflow.hour");
+  static_assert(cs.minute() == 14, "C4Underflow.minute");
+  static_assert(cs.second() == 12, "C4Underflow.second");
+}
+
+TEST(CivilTime, MixedNormalization) {
+  constexpr civil_second cs(2016, -42, 122, 99, -147, 4949);
+  static_assert(cs.year() == 2012, "MixedNormalization.year");
+  static_assert(cs.month() == 10, "MixedNormalization.month");
+  static_assert(cs.day() == 4, "MixedNormalization.day");
+  static_assert(cs.hour() == 1, "MixedNormalization.hour");
+  static_assert(cs.minute() == 55, "MixedNormalization.minute");
+  static_assert(cs.second() == 29, "MixedNormalization.second");
+}
+
+// Relational constexpr tests
+
+TEST(CivilTime, Less) {
+  constexpr civil_second cs1(2016, 1, 28, 17, 14, 12);
+  constexpr civil_second cs2(2016, 1, 28, 17, 14, 13);
+  constexpr bool less = cs1 < cs2;
+  static_assert(less, "Less");
+}
+
+// Arithmetic constexpr tests
+
+TEST(CivilTime, Addition) {
+  constexpr civil_second cs1(2016, 1, 28, 17, 14, 12);
+  constexpr civil_second cs2 = cs1 + 50;
+  static_assert(cs2.year() == 2016, "Addition.year");
+  static_assert(cs2.month() == 1, "Addition.month");
+  static_assert(cs2.day() == 28, "Addition.day");
+  static_assert(cs2.hour() == 17, "Addition.hour");
+  static_assert(cs2.minute() == 15, "Addition.minute");
+  static_assert(cs2.second() == 2, "Addition.second");
+}
+
+TEST(CivilTime, Subtraction) {
+  constexpr civil_second cs1(2016, 1, 28, 17, 14, 12);
+  constexpr civil_second cs2 = cs1 - 50;
+  static_assert(cs2.year() == 2016, "Subtraction.year");
+  static_assert(cs2.month() == 1, "Subtraction.month");
+  static_assert(cs2.day() == 28, "Subtraction.day");
+  static_assert(cs2.hour() == 17, "Subtraction.hour");
+  static_assert(cs2.minute() == 13, "Subtraction.minute");
+  static_assert(cs2.second() == 22, "Subtraction.second");
+}
+
+TEST(CivilTime, Difference) {
+  constexpr civil_day cd1(2016, 1, 28);
+  constexpr civil_day cd2(2015, 1, 28);
+  constexpr int diff = cd1 - cd2;
+  static_assert(diff == 365, "Difference");
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, DifferenceWithHugeYear) {
+  {
+    constexpr civil_day d1(9223372036854775807, 1, 1);
+    constexpr civil_day d2(9223372036854775807, 12, 31);
+    static_assert(d2 - d1 == 364, "DifferenceWithHugeYear");
+  }
+  {
+    constexpr civil_day d1(-9223372036854775807 - 1, 1, 1);
+    constexpr civil_day d2(-9223372036854775807 - 1, 12, 31);
+    static_assert(d2 - d1 == 365, "DifferenceWithHugeYear");
+  }
+  {
+    // Check the limits of the return value at the end of the year range.
+    constexpr civil_day d1(9223372036854775807, 1, 1);
+    constexpr civil_day d2(9198119301927009252, 6, 6);
+    static_assert(d1 - d2 == 9223372036854775807, "DifferenceWithHugeYear");
+    static_assert((d2 - 1) - d1 == -9223372036854775807 - 1,
+                  "DifferenceWithHugeYear");
+  }
+  {
+    // Check the limits of the return value at the start of the year range.
+    constexpr civil_day d1(-9223372036854775807 - 1, 1, 1);
+    constexpr civil_day d2(-9198119301927009254, 7, 28);
+    static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear");
+    static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1,
+                  "DifferenceWithHugeYear");
+  }
+  {
+    // Check the limits of the return value from either side of year 0.
+    constexpr civil_day d1(-12626367463883278, 9, 3);
+    constexpr civil_day d2(12626367463883277, 3, 28);
+    static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear");
+    static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1,
+                  "DifferenceWithHugeYear");
+  }
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, DifferenceNoIntermediateOverflow) {
+  {
+    // The difference up to the minute field would be below the minimum
+    // diff_t, but the 52 extra seconds brings us back to the minimum.
+    constexpr civil_second s1(-292277022657, 1, 27, 8, 29 - 1, 52);
+    constexpr civil_second s2(1970, 1, 1, 0, 0 - 1, 0);
+    static_assert(s1 - s2 == -9223372036854775807 - 1,
+                  "DifferenceNoIntermediateOverflow");
+  }
+  {
+    // The difference up to the minute field would be above the maximum
+    // diff_t, but the -53 extra seconds brings us back to the maximum.
+    constexpr civil_second s1(292277026596, 12, 4, 15, 30, 7 - 7);
+    constexpr civil_second s2(1970, 1, 1, 0, 0, 0 - 7);
+    static_assert(s1 - s2 == 9223372036854775807,
+                  "DifferenceNoIntermediateOverflow");
+  }
+}
+
+// Helper constexpr tests
+
+TEST(CivilTime, WeekDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr weekday wd = get_weekday(cd);
+  static_assert(wd == weekday::thursday, "Weekday");
+}
+
+TEST(CivilTime, NextWeekDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr civil_day next = next_weekday(cd, weekday::thursday);
+  static_assert(next.year() == 2016, "NextWeekDay.year");
+  static_assert(next.month() == 2, "NextWeekDay.month");
+  static_assert(next.day() == 4, "NextWeekDay.day");
+}
+
+TEST(CivilTime, PrevWeekDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr civil_day prev = prev_weekday(cd, weekday::thursday);
+  static_assert(prev.year() == 2016, "PrevWeekDay.year");
+  static_assert(prev.month() == 1, "PrevWeekDay.month");
+  static_assert(prev.day() == 21, "PrevWeekDay.day");
+}
+
+TEST(CivilTime, YearDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr int yd = get_yearday(cd);
+  static_assert(yd == 28, "YearDay");
+}
+#endif  // __cpp_constexpr >= 201304 || _MSC_VER >= 1910
+
+// The remaining tests do not use constexpr.
+
+TEST(CivilTime, DefaultConstruction) {
+  civil_second ss;
+  EXPECT_EQ("1970-01-01T00:00:00", Format(ss));
+
+  civil_minute mm;
+  EXPECT_EQ("1970-01-01T00:00", Format(mm));
+
+  civil_hour hh;
+  EXPECT_EQ("1970-01-01T00", Format(hh));
+
+  civil_day d;
+  EXPECT_EQ("1970-01-01", Format(d));
+
+  civil_month m;
+  EXPECT_EQ("1970-01", Format(m));
+
+  civil_year y;
+  EXPECT_EQ("1970", Format(y));
+}
+
+TEST(CivilTime, StructMember) {
+  struct S {
+    civil_day day;
+  };
+  S s = {};
+  EXPECT_EQ(civil_day{}, s.day);
+}
+
+TEST(CivilTime, FieldsConstruction) {
+  EXPECT_EQ("2015-01-02T03:04:05", Format(civil_second(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02T03:04:00", Format(civil_second(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02T03:00:00", Format(civil_second(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02T00:00:00", Format(civil_second(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015, 1)));
+  EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015)));
+
+  EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02T03:00", Format(civil_minute(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02T00:00", Format(civil_minute(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015, 1)));
+  EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015)));
+
+  EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02T00", Format(civil_hour(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015, 1)));
+  EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015)));
+
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01", Format(civil_day(2015, 1)));
+  EXPECT_EQ("2015-01-01", Format(civil_day(2015)));
+
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015)));
+
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1)));
+  EXPECT_EQ("2015", Format(civil_year(2015)));
+}
+
+TEST(CivilTime, FieldsConstructionLimits) {
+  const int kIntMax = std::numeric_limits<int>::max();
+  EXPECT_EQ("2038-01-19T03:14:07",
+            Format(civil_second(1970, 1, 1, 0, 0, kIntMax)));
+  EXPECT_EQ("6121-02-11T05:21:07",
+            Format(civil_second(1970, 1, 1, 0, kIntMax, kIntMax)));
+  EXPECT_EQ("251104-11-20T12:21:07",
+            Format(civil_second(1970, 1, 1, kIntMax, kIntMax, kIntMax)));
+  EXPECT_EQ("6130715-05-30T12:21:07",
+            Format(civil_second(1970, 1, kIntMax, kIntMax, kIntMax, kIntMax)));
+  EXPECT_EQ(
+      "185087685-11-26T12:21:07",
+      Format(civil_second(1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax)));
+
+  const int kIntMin = std::numeric_limits<int>::min();
+  EXPECT_EQ("1901-12-13T20:45:52",
+            Format(civil_second(1970, 1, 1, 0, 0, kIntMin)));
+  EXPECT_EQ("-2182-11-20T18:37:52",
+            Format(civil_second(1970, 1, 1, 0, kIntMin, kIntMin)));
+  EXPECT_EQ("-247165-02-11T10:37:52",
+            Format(civil_second(1970, 1, 1, kIntMin, kIntMin, kIntMin)));
+  EXPECT_EQ("-6126776-08-01T10:37:52",
+            Format(civil_second(1970, 1, kIntMin, kIntMin, kIntMin, kIntMin)));
+  EXPECT_EQ(
+      "-185083747-10-31T10:37:52",
+      Format(civil_second(1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin)));
+}
+
+TEST(CivilTime, ImplicitCrossAlignment) {
+  civil_year year(2015);
+  civil_month month = year;
+  civil_day day = month;
+  civil_hour hour = day;
+  civil_minute minute = hour;
+  civil_second second = minute;
+
+  second = year;
+  EXPECT_EQ(second, year);
+  second = month;
+  EXPECT_EQ(second, month);
+  second = day;
+  EXPECT_EQ(second, day);
+  second = hour;
+  EXPECT_EQ(second, hour);
+  second = minute;
+  EXPECT_EQ(second, minute);
+
+  minute = year;
+  EXPECT_EQ(minute, year);
+  minute = month;
+  EXPECT_EQ(minute, month);
+  minute = day;
+  EXPECT_EQ(minute, day);
+  minute = hour;
+  EXPECT_EQ(minute, hour);
+
+  hour = year;
+  EXPECT_EQ(hour, year);
+  hour = month;
+  EXPECT_EQ(hour, month);
+  hour = day;
+  EXPECT_EQ(hour, day);
+
+  day = year;
+  EXPECT_EQ(day, year);
+  day = month;
+  EXPECT_EQ(day, month);
+
+  month = year;
+  EXPECT_EQ(month, year);
+
+  // Ensures unsafe conversions are not allowed.
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_minute>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_hour>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_day>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_hour>::value));
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_day>::value));
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_hour, civil_day>::value));
+  EXPECT_FALSE((std::is_convertible<civil_hour, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_hour, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_day, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_day, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_month, civil_year>::value));
+}
+
+TEST(CivilTime, ExplicitCrossAlignment) {
+  //
+  // Assign from smaller units -> larger units
+  //
+
+  civil_second second(2015, 1, 2, 3, 4, 5);
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second));
+
+  civil_minute minute(second);
+  EXPECT_EQ("2015-01-02T03:04", Format(minute));
+
+  civil_hour hour(minute);
+  EXPECT_EQ("2015-01-02T03", Format(hour));
+
+  civil_day day(hour);
+  EXPECT_EQ("2015-01-02", Format(day));
+
+  civil_month month(day);
+  EXPECT_EQ("2015-01", Format(month));
+
+  civil_year year(month);
+  EXPECT_EQ("2015", Format(year));
+
+  //
+  // Now assign from larger units -> smaller units
+  //
+
+  month = civil_month(year);
+  EXPECT_EQ("2015-01", Format(month));
+
+  day = civil_day(month);
+  EXPECT_EQ("2015-01-01", Format(day));
+
+  hour = civil_hour(day);
+  EXPECT_EQ("2015-01-01T00", Format(hour));
+
+  minute = civil_minute(hour);
+  EXPECT_EQ("2015-01-01T00:00", Format(minute));
+
+  second = civil_second(minute);
+  EXPECT_EQ("2015-01-01T00:00:00", Format(second));
+}
+
+// Metafunction to test whether difference is allowed between two types.
+template <typename T1, typename T2>
+struct HasDifference {
+  template <typename U1, typename U2>
+  static std::false_type test(...);
+  template <typename U1, typename U2>
+  static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>()));
+  static constexpr bool value = decltype(test<T1, T2>(0))::value;
+};
+
+TEST(CivilTime, DisallowCrossAlignedDifference) {
+  // Difference is allowed between types with the same alignment.
+  static_assert(HasDifference<civil_second, civil_second>::value, "");
+  static_assert(HasDifference<civil_minute, civil_minute>::value, "");
+  static_assert(HasDifference<civil_hour, civil_hour>::value, "");
+  static_assert(HasDifference<civil_day, civil_day>::value, "");
+  static_assert(HasDifference<civil_month, civil_month>::value, "");
+  static_assert(HasDifference<civil_year, civil_year>::value, "");
+
+  // Difference is disallowed between types with different alignments.
+  static_assert(!HasDifference<civil_second, civil_minute>::value, "");
+  static_assert(!HasDifference<civil_second, civil_hour>::value, "");
+  static_assert(!HasDifference<civil_second, civil_day>::value, "");
+  static_assert(!HasDifference<civil_second, civil_month>::value, "");
+  static_assert(!HasDifference<civil_second, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_minute, civil_hour>::value, "");
+  static_assert(!HasDifference<civil_minute, civil_day>::value, "");
+  static_assert(!HasDifference<civil_minute, civil_month>::value, "");
+  static_assert(!HasDifference<civil_minute, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_hour, civil_day>::value, "");
+  static_assert(!HasDifference<civil_hour, civil_month>::value, "");
+  static_assert(!HasDifference<civil_hour, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_day, civil_month>::value, "");
+  static_assert(!HasDifference<civil_day, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_month, civil_year>::value, "");
+}
+
+TEST(CivilTime, ValueSemantics) {
+  const civil_hour a(2015, 1, 2, 3);
+  const civil_hour b = a;
+  const civil_hour c(b);
+  civil_hour d;
+  d = c;
+  EXPECT_EQ("2015-01-02T03", Format(d));
+}
+
+TEST(CivilTime, Relational) {
+  // Tests that the alignment unit is ignored in comparison.
+  const civil_year year(2014);
+  const civil_month month(year);
+  EXPECT_EQ(year, month);
+
+#define TEST_RELATIONAL(OLDER, YOUNGER) \
+  do {                                  \
+    EXPECT_FALSE(OLDER < OLDER);        \
+    EXPECT_FALSE(OLDER > OLDER);        \
+    EXPECT_TRUE(OLDER >= OLDER);        \
+    EXPECT_TRUE(OLDER <= OLDER);        \
+    EXPECT_FALSE(YOUNGER < YOUNGER);    \
+    EXPECT_FALSE(YOUNGER > YOUNGER);    \
+    EXPECT_TRUE(YOUNGER >= YOUNGER);    \
+    EXPECT_TRUE(YOUNGER <= YOUNGER);    \
+    EXPECT_EQ(OLDER, OLDER);            \
+    EXPECT_NE(OLDER, YOUNGER);          \
+    EXPECT_LT(OLDER, YOUNGER);          \
+    EXPECT_LE(OLDER, YOUNGER);          \
+    EXPECT_GT(YOUNGER, OLDER);          \
+    EXPECT_GE(YOUNGER, OLDER);          \
+  } while (0)
+
+  // Alignment is ignored in comparison (verified above), so kSecond is used
+  // to test comparison in all field positions.
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2015, 1, 1, 0, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2014, 2, 1, 0, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2014, 1, 2, 0, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2014, 1, 1, 1, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 0, 0),
+                  civil_second(2014, 1, 1, 1, 1, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 1, 0),
+                  civil_second(2014, 1, 1, 1, 1, 1));
+
+  // Tests the relational operators of two different CivilTime types.
+  TEST_RELATIONAL(civil_day(2014, 1, 1), civil_minute(2014, 1, 1, 1, 1));
+  TEST_RELATIONAL(civil_day(2014, 1, 1), civil_month(2014, 2));
+
+#undef TEST_RELATIONAL
+}
+
+TEST(CivilTime, Arithmetic) {
+  civil_second second(2015, 1, 2, 3, 4, 5);
+  EXPECT_EQ("2015-01-02T03:04:06", Format(second += 1));
+  EXPECT_EQ("2015-01-02T03:04:07", Format(second + 1));
+  EXPECT_EQ("2015-01-02T03:04:08", Format(2 + second));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second - 1));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second -= 1));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second++));
+  EXPECT_EQ("2015-01-02T03:04:07", Format(++second));
+  EXPECT_EQ("2015-01-02T03:04:07", Format(second--));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(--second));
+
+  civil_minute minute(2015, 1, 2, 3, 4);
+  EXPECT_EQ("2015-01-02T03:05", Format(minute += 1));
+  EXPECT_EQ("2015-01-02T03:06", Format(minute + 1));
+  EXPECT_EQ("2015-01-02T03:07", Format(2 + minute));
+  EXPECT_EQ("2015-01-02T03:04", Format(minute - 1));
+  EXPECT_EQ("2015-01-02T03:04", Format(minute -= 1));
+  EXPECT_EQ("2015-01-02T03:04", Format(minute++));
+  EXPECT_EQ("2015-01-02T03:06", Format(++minute));
+  EXPECT_EQ("2015-01-02T03:06", Format(minute--));
+  EXPECT_EQ("2015-01-02T03:04", Format(--minute));
+
+  civil_hour hour(2015, 1, 2, 3);
+  EXPECT_EQ("2015-01-02T04", Format(hour += 1));
+  EXPECT_EQ("2015-01-02T05", Format(hour + 1));
+  EXPECT_EQ("2015-01-02T06", Format(2 + hour));
+  EXPECT_EQ("2015-01-02T03", Format(hour - 1));
+  EXPECT_EQ("2015-01-02T03", Format(hour -= 1));
+  EXPECT_EQ("2015-01-02T03", Format(hour++));
+  EXPECT_EQ("2015-01-02T05", Format(++hour));
+  EXPECT_EQ("2015-01-02T05", Format(hour--));
+  EXPECT_EQ("2015-01-02T03", Format(--hour));
+
+  civil_day day(2015, 1, 2);
+  EXPECT_EQ("2015-01-03", Format(day += 1));
+  EXPECT_EQ("2015-01-04", Format(day + 1));
+  EXPECT_EQ("2015-01-05", Format(2 + day));
+  EXPECT_EQ("2015-01-02", Format(day - 1));
+  EXPECT_EQ("2015-01-02", Format(day -= 1));
+  EXPECT_EQ("2015-01-02", Format(day++));
+  EXPECT_EQ("2015-01-04", Format(++day));
+  EXPECT_EQ("2015-01-04", Format(day--));
+  EXPECT_EQ("2015-01-02", Format(--day));
+
+  civil_month month(2015, 1);
+  EXPECT_EQ("2015-02", Format(month += 1));
+  EXPECT_EQ("2015-03", Format(month + 1));
+  EXPECT_EQ("2015-04", Format(2 + month));
+  EXPECT_EQ("2015-01", Format(month - 1));
+  EXPECT_EQ("2015-01", Format(month -= 1));
+  EXPECT_EQ("2015-01", Format(month++));
+  EXPECT_EQ("2015-03", Format(++month));
+  EXPECT_EQ("2015-03", Format(month--));
+  EXPECT_EQ("2015-01", Format(--month));
+
+  civil_year year(2015);
+  EXPECT_EQ("2016", Format(year += 1));
+  EXPECT_EQ("2017", Format(year + 1));
+  EXPECT_EQ("2018", Format(2 + year));
+  EXPECT_EQ("2015", Format(year - 1));
+  EXPECT_EQ("2015", Format(year -= 1));
+  EXPECT_EQ("2015", Format(year++));
+  EXPECT_EQ("2017", Format(++year));
+  EXPECT_EQ("2017", Format(year--));
+  EXPECT_EQ("2015", Format(--year));
+}
+
+TEST(CivilTime, ArithmeticLimits) {
+  const int kIntMax = std::numeric_limits<int>::max();
+  const int kIntMin = std::numeric_limits<int>::min();
+
+  civil_second second(1970, 1, 1, 0, 0, 0);
+  second += kIntMax;
+  EXPECT_EQ("2038-01-19T03:14:07", Format(second));
+  second -= kIntMax;
+  EXPECT_EQ("1970-01-01T00:00:00", Format(second));
+  second += kIntMin;
+  EXPECT_EQ("1901-12-13T20:45:52", Format(second));
+  second -= kIntMin;
+  EXPECT_EQ("1970-01-01T00:00:00", Format(second));
+
+  civil_minute minute(1970, 1, 1, 0, 0);
+  minute += kIntMax;
+  EXPECT_EQ("6053-01-23T02:07", Format(minute));
+  minute -= kIntMax;
+  EXPECT_EQ("1970-01-01T00:00", Format(minute));
+  minute += kIntMin;
+  EXPECT_EQ("-2114-12-08T21:52", Format(minute));
+  minute -= kIntMin;
+  EXPECT_EQ("1970-01-01T00:00", Format(minute));
+
+  civil_hour hour(1970, 1, 1, 0);
+  hour += kIntMax;
+  EXPECT_EQ("246953-10-09T07", Format(hour));
+  hour -= kIntMax;
+  EXPECT_EQ("1970-01-01T00", Format(hour));
+  hour += kIntMin;
+  EXPECT_EQ("-243014-03-24T16", Format(hour));
+  hour -= kIntMin;
+  EXPECT_EQ("1970-01-01T00", Format(hour));
+
+  civil_day day(1970, 1, 1);
+  day += kIntMax;
+  EXPECT_EQ("5881580-07-11", Format(day));
+  day -= kIntMax;
+  EXPECT_EQ("1970-01-01", Format(day));
+  day += kIntMin;
+  EXPECT_EQ("-5877641-06-23", Format(day));
+  day -= kIntMin;
+  EXPECT_EQ("1970-01-01", Format(day));
+
+  civil_month month(1970, 1);
+  month += kIntMax;
+  EXPECT_EQ("178958940-08", Format(month));
+  month -= kIntMax;
+  EXPECT_EQ("1970-01", Format(month));
+  month += kIntMin;
+  EXPECT_EQ("-178955001-05", Format(month));
+  month -= kIntMin;
+  EXPECT_EQ("1970-01", Format(month));
+
+  civil_year year(0);
+  year += kIntMax;
+  EXPECT_EQ("2147483647", Format(year));
+  year -= kIntMax;
+  EXPECT_EQ("0", Format(year));
+  year += kIntMin;
+  EXPECT_EQ("-2147483648", Format(year));
+  year -= kIntMin;
+  EXPECT_EQ("0", Format(year));
+}
+
+TEST(CivilTime, ArithmeticDifference) {
+  civil_second second(2015, 1, 2, 3, 4, 5);
+  EXPECT_EQ(0, second - second);
+  EXPECT_EQ(10, (second + 10) - second);
+  EXPECT_EQ(-10, (second - 10) - second);
+
+  civil_minute minute(2015, 1, 2, 3, 4);
+  EXPECT_EQ(0, minute - minute);
+  EXPECT_EQ(10, (minute + 10) - minute);
+  EXPECT_EQ(-10, (minute - 10) - minute);
+
+  civil_hour hour(2015, 1, 2, 3);
+  EXPECT_EQ(0, hour - hour);
+  EXPECT_EQ(10, (hour + 10) - hour);
+  EXPECT_EQ(-10, (hour - 10) - hour);
+
+  civil_day day(2015, 1, 2);
+  EXPECT_EQ(0, day - day);
+  EXPECT_EQ(10, (day + 10) - day);
+  EXPECT_EQ(-10, (day - 10) - day);
+
+  civil_month month(2015, 1);
+  EXPECT_EQ(0, month - month);
+  EXPECT_EQ(10, (month + 10) - month);
+  EXPECT_EQ(-10, (month - 10) - month);
+
+  civil_year year(2015);
+  EXPECT_EQ(0, year - year);
+  EXPECT_EQ(10, (year + 10) - year);
+  EXPECT_EQ(-10, (year - 10) - year);
+}
+
+TEST(CivilTime, DifferenceLimits) {
+  const int kIntMax = std::numeric_limits<int>::max();
+  const int kIntMin = std::numeric_limits<int>::min();
+
+  // Check day arithmetic at the end of the year range.
+  const civil_day max_day(kIntMax, 12, 31);
+  EXPECT_EQ(1, max_day - (max_day - 1));
+  EXPECT_EQ(-1, (max_day - 1) - max_day);
+
+  // Check day arithmetic at the end of the year range.
+  const civil_day min_day(kIntMin, 1, 1);
+  EXPECT_EQ(1, (min_day + 1) - min_day);
+  EXPECT_EQ(-1, min_day - (min_day + 1));
+
+  // Check the limits of the return value.
+  const civil_day d1(1970, 1, 1);
+  const civil_day d2(5881580, 7, 11);
+  EXPECT_EQ(kIntMax, d2 - d1);
+  EXPECT_EQ(kIntMin, d1 - (d2 + 1));
+}
+
+TEST(CivilTime, Properties) {
+  civil_second ss(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, ss.year());
+  EXPECT_EQ(2, ss.month());
+  EXPECT_EQ(3, ss.day());
+  EXPECT_EQ(4, ss.hour());
+  EXPECT_EQ(5, ss.minute());
+  EXPECT_EQ(6, ss.second());
+
+  civil_minute mm(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, mm.year());
+  EXPECT_EQ(2, mm.month());
+  EXPECT_EQ(3, mm.day());
+  EXPECT_EQ(4, mm.hour());
+  EXPECT_EQ(5, mm.minute());
+  EXPECT_EQ(0, mm.second());
+
+  civil_hour hh(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, hh.year());
+  EXPECT_EQ(2, hh.month());
+  EXPECT_EQ(3, hh.day());
+  EXPECT_EQ(4, hh.hour());
+  EXPECT_EQ(0, hh.minute());
+  EXPECT_EQ(0, hh.second());
+
+  civil_day d(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, d.year());
+  EXPECT_EQ(2, d.month());
+  EXPECT_EQ(3, d.day());
+  EXPECT_EQ(0, d.hour());
+  EXPECT_EQ(0, d.minute());
+  EXPECT_EQ(0, d.second());
+  EXPECT_EQ(weekday::tuesday, get_weekday(d));
+  EXPECT_EQ(34, get_yearday(d));
+
+  civil_month m(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, m.year());
+  EXPECT_EQ(2, m.month());
+  EXPECT_EQ(1, m.day());
+  EXPECT_EQ(0, m.hour());
+  EXPECT_EQ(0, m.minute());
+  EXPECT_EQ(0, m.second());
+
+  civil_year y(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, y.year());
+  EXPECT_EQ(1, y.month());
+  EXPECT_EQ(1, y.day());
+  EXPECT_EQ(0, y.hour());
+  EXPECT_EQ(0, y.minute());
+  EXPECT_EQ(0, y.second());
+}
+
+TEST(CivilTime, OutputStream) {
+  // Tests formatting of civil_year, which does not pad.
+  EXPECT_EQ("2016", Format(civil_year(2016)));
+  EXPECT_EQ("123", Format(civil_year(123)));
+  EXPECT_EQ("0", Format(civil_year(0)));
+  EXPECT_EQ("-1", Format(civil_year(-1)));
+
+  // Tests formatting of sub-year types, which pad to 2 digits
+  EXPECT_EQ("2016-02", Format(civil_month(2016, 2)));
+  EXPECT_EQ("2016-02-03", Format(civil_day(2016, 2, 3)));
+  EXPECT_EQ("2016-02-03T04", Format(civil_hour(2016, 2, 3, 4)));
+  EXPECT_EQ("2016-02-03T04:05", Format(civil_minute(2016, 2, 3, 4, 5)));
+  EXPECT_EQ("2016-02-03T04:05:06", Format(civil_second(2016, 2, 3, 4, 5, 6)));
+
+  // Tests formatting of weekday.
+  EXPECT_EQ("Monday", Format(weekday::monday));
+  EXPECT_EQ("Tuesday", Format(weekday::tuesday));
+  EXPECT_EQ("Wednesday", Format(weekday::wednesday));
+  EXPECT_EQ("Thursday", Format(weekday::thursday));
+  EXPECT_EQ("Friday", Format(weekday::friday));
+  EXPECT_EQ("Saturday", Format(weekday::saturday));
+  EXPECT_EQ("Sunday", Format(weekday::sunday));
+}
+
+TEST(CivilTime, OutputStreamLeftFillWidth) {
+  civil_second cs(2016, 2, 3, 4, 5, 6);
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_year(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016.................X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_month(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02..............X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_day(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03...........X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_hour(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03T04........X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_minute(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_second(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str());
+  }
+}
+
+TEST(CivilTime, NextPrevWeekday) {
+  // Jan 1, 1970 was a Thursday.
+  const civil_day thursday(1970, 1, 1);
+  EXPECT_EQ(weekday::thursday, get_weekday(thursday));
+
+  // Thursday -> Thursday
+  civil_day d = next_weekday(thursday, weekday::thursday);
+  EXPECT_EQ(7, d - thursday) << Format(d);
+  EXPECT_EQ(d - 14, prev_weekday(thursday, weekday::thursday));
+
+  // Thursday -> Friday
+  d = next_weekday(thursday, weekday::friday);
+  EXPECT_EQ(1, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::friday));
+
+  // Thursday -> Saturday
+  d = next_weekday(thursday, weekday::saturday);
+  EXPECT_EQ(2, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::saturday));
+
+  // Thursday -> Sunday
+  d = next_weekday(thursday, weekday::sunday);
+  EXPECT_EQ(3, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::sunday));
+
+  // Thursday -> Monday
+  d = next_weekday(thursday, weekday::monday);
+  EXPECT_EQ(4, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::monday));
+
+  // Thursday -> Tuesday
+  d = next_weekday(thursday, weekday::tuesday);
+  EXPECT_EQ(5, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::tuesday));
+
+  // Thursday -> Wednesday
+  d = next_weekday(thursday, weekday::wednesday);
+  EXPECT_EQ(6, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::wednesday));
+}
+
+TEST(CivilTime, NormalizeWithHugeYear) {
+  civil_month c(9223372036854775807, 1);
+  EXPECT_EQ("9223372036854775807-01", Format(c));
+  c = c - 1;  // Causes normalization
+  EXPECT_EQ("9223372036854775806-12", Format(c));
+
+  c = civil_month(-9223372036854775807 - 1, 1);
+  EXPECT_EQ("-9223372036854775808-01", Format(c));
+  c = c + 12;  // Causes normalization
+  EXPECT_EQ("-9223372036854775807-01", Format(c));
+}
+
+TEST(CivilTime, LeapYears) {
+  // Test data for leap years.
+  const struct {
+    int year;
+    int days;
+    struct {
+      int month;
+      int day;
+    } leap_day;  // The date of the day after Feb 28.
+  } kLeapYearTable[]{
+      {1900, 365, {3, 1}},
+      {1999, 365, {3, 1}},
+      {2000, 366, {2, 29}},  // leap year
+      {2001, 365, {3, 1}},
+      {2002, 365, {3, 1}},
+      {2003, 365, {3, 1}},
+      {2004, 366, {2, 29}},  // leap year
+      {2005, 365, {3, 1}},
+      {2006, 365, {3, 1}},
+      {2007, 365, {3, 1}},
+      {2008, 366, {2, 29}},  // leap year
+      {2009, 365, {3, 1}},
+      {2100, 365, {3, 1}},
+  };
+
+  for (const auto& e : kLeapYearTable) {
+    // Tests incrementing through the leap day.
+    const civil_day feb28(e.year, 2, 28);
+    const civil_day next_day = feb28 + 1;
+    EXPECT_EQ(e.leap_day.month, next_day.month());
+    EXPECT_EQ(e.leap_day.day, next_day.day());
+
+    // Tests difference in days of leap years.
+    const civil_year year(feb28);
+    const civil_year next_year = year + 1;
+    EXPECT_EQ(e.days, civil_day(next_year) - civil_day(year));
+  }
+}
+
+TEST(CivilTime, FirstThursdayInMonth) {
+  const civil_day nov1(2014, 11, 1);
+  const civil_day thursday = prev_weekday(nov1, weekday::thursday) + 7;
+  EXPECT_EQ("2014-11-06", Format(thursday));
+
+  // Bonus: Date of Thanksgiving in the United States
+  // Rule: Fourth Thursday of November
+  const civil_day thanksgiving = thursday + 7 * 3;
+  EXPECT_EQ("2014-11-27", Format(thanksgiving));
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
new file mode 100644
index 0000000..598b08f
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -0,0 +1,123 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "time_zone_fixed.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// The prefix used for the internal names of fixed-offset zones.
+const char kFixedOffsetPrefix[] = "Fixed/UTC";
+
+int Parse02d(const char* p) {
+  static const char kDigits[] = "0123456789";
+  if (const char* ap = std::strchr(kDigits, *p)) {
+    int v = static_cast<int>(ap - kDigits);
+    if (const char* bp = std::strchr(kDigits, *++p)) {
+      return (v * 10) + static_cast<int>(bp - kDigits);
+    }
+  }
+  return -1;
+}
+
+}  // namespace
+
+bool FixedOffsetFromName(const std::string& name, seconds* offset) {
+  if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
+    *offset = seconds::zero();
+    return true;
+  }
+
+  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+  const char* const ep = kFixedOffsetPrefix + prefix_len;
+  if (name.size() != prefix_len + 9)  // <prefix>+99:99:99
+    return false;
+  if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
+    return false;
+  const char* np = name.data() + prefix_len;
+  if (np[0] != '+' && np[0] != '-')
+    return false;
+  if (np[3] != ':' || np[6] != ':')  // see note below about large offsets
+    return false;
+
+  int hours = Parse02d(np + 1);
+  if (hours == -1) return false;
+  int mins = Parse02d(np + 4);
+  if (mins == -1) return false;
+  int secs = Parse02d(np + 7);
+  if (secs == -1) return false;
+
+  secs += ((hours * 60) + mins) * 60;
+  if (secs > 24 * 60 * 60) return false;  // outside supported offset range
+  *offset = seconds(secs * (np[0] == '-' ? -1 : 1));  // "-" means west
+  return true;
+}
+
+std::string FixedOffsetToName(const seconds& offset) {
+  if (offset == seconds::zero()) return "UTC";
+  if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) {
+    // We don't support fixed-offset zones more than 24 hours
+    // away from UTC to avoid complications in rendering such
+    // offsets and to (somewhat) limit the total number of zones.
+    return "UTC";
+  }
+  int seconds = static_cast<int>(offset.count());
+  const char sign = (seconds < 0 ? '-' : '+');
+  int minutes = seconds / 60;
+  seconds %= 60;
+  if (sign == '-') {
+    if (seconds > 0) {
+      seconds -= 60;
+      minutes += 1;
+    }
+    seconds = -seconds;
+    minutes = -minutes;
+  }
+  int hours = minutes / 60;
+  minutes %= 60;
+  char buf[sizeof(kFixedOffsetPrefix) + sizeof("-24:00:00")];
+  snprintf(buf, sizeof(buf), "%s%c%02d:%02d:%02d",
+           kFixedOffsetPrefix, sign, hours, minutes, seconds);
+  return buf;
+}
+
+std::string FixedOffsetToAbbr(const seconds& offset) {
+  std::string abbr = FixedOffsetToName(offset);
+  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+  if (abbr.size() == prefix_len + 9) {         // <prefix>+99:99:99
+    abbr.erase(0, prefix_len);                 // +99:99:99
+    abbr.erase(6, 1);                          // +99:9999
+    abbr.erase(3, 1);                          // +999999
+    if (abbr[5] == '0' && abbr[6] == '0') {    // +999900
+      abbr.erase(5, 2);                        // +9999
+      if (abbr[3] == '0' && abbr[4] == '0') {  // +9900
+        abbr.erase(3, 2);                      // +99
+      }
+    }
+  }
+  return abbr;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.h b/absl/time/internal/cctz/src/time_zone_fixed.h
new file mode 100644
index 0000000..489b857
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -0,0 +1,49 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
+
+#include <string>
+
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// Helper functions for dealing with the names and abbreviations
+// of time zones that are a fixed offset (seconds east) from UTC.
+// FixedOffsetFromName() extracts the offset from a valid fixed-offset
+// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate
+// the canonical zone name and abbreviation respectively for the given
+// offset.
+//
+// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>".
+// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the
+// optional pieces are omitted when their values are zero.  (Note that
+// the sign is the opposite of that used in a POSIX TZ specification.)
+//
+// Note: FixedOffsetFromName() fails on syntax errors or when the parsed
+// offset exceeds 24 hours.  FixedOffsetToName() and FixedOffsetToAbbr()
+// both produce "UTC" when the argument offset exceeds 24 hours.
+bool FixedOffsetFromName(const std::string& name, seconds* offset);
+std::string FixedOffsetToName(const seconds& offset);
+std::string FixedOffsetToAbbr(const seconds& offset);
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
new file mode 100644
index 0000000..1b02384
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -0,0 +1,851 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 !defined(HAS_STRPTIME)
+# if !defined(_MSC_VER)
+#  define HAS_STRPTIME 1  // assume everyone has strptime() except windows
+# endif
+#endif
+
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#include <cctype>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <vector>
+#if !HAS_STRPTIME
+#include <iomanip>
+#include <sstream>
+#endif
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "time_zone_if.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+namespace detail {
+
+namespace {
+
+#if !HAS_STRPTIME
+// Build a strptime() using C++11's std::get_time().
+char* strptime(const char* s, const char* fmt, std::tm* tm) {
+  std::istringstream input(s);
+  input >> std::get_time(tm, fmt);
+  if (input.fail()) return nullptr;
+  return const_cast<char*>(s) +
+         (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
+}
+#endif
+
+std::tm ToTM(const time_zone::absolute_lookup& al) {
+  std::tm tm{};
+  tm.tm_sec = al.cs.second();
+  tm.tm_min = al.cs.minute();
+  tm.tm_hour = al.cs.hour();
+  tm.tm_mday = al.cs.day();
+  tm.tm_mon = al.cs.month() - 1;
+
+  // Saturate tm.tm_year is cases of over/underflow.
+  if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
+    tm.tm_year = std::numeric_limits<int>::min();
+  } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
+    tm.tm_year = std::numeric_limits<int>::max();
+  } else {
+    tm.tm_year = static_cast<int>(al.cs.year() - 1900);
+  }
+
+  switch (get_weekday(civil_day(al.cs))) {
+    case weekday::sunday:
+      tm.tm_wday = 0;
+      break;
+    case weekday::monday:
+      tm.tm_wday = 1;
+      break;
+    case weekday::tuesday:
+      tm.tm_wday = 2;
+      break;
+    case weekday::wednesday:
+      tm.tm_wday = 3;
+      break;
+    case weekday::thursday:
+      tm.tm_wday = 4;
+      break;
+    case weekday::friday:
+      tm.tm_wday = 5;
+      break;
+    case weekday::saturday:
+      tm.tm_wday = 6;
+      break;
+  }
+  tm.tm_yday = get_yearday(civil_day(al.cs)) - 1;
+  tm.tm_isdst = al.is_dst ? 1 : 0;
+  return tm;
+}
+
+const char kDigits[] = "0123456789";
+
+// Formats a 64-bit integer in the given field width.  Note that it is up
+// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure
+// that there is sufficient space before ep to hold the conversion.
+char* Format64(char* ep, int width, std::int_fast64_t v) {
+  bool neg = false;
+  if (v < 0) {
+    --width;
+    neg = true;
+    if (v == std::numeric_limits<std::int_fast64_t>::min()) {
+      // Avoid negating minimum value.
+      std::int_fast64_t last_digit = -(v % 10);
+      v /= 10;
+      if (last_digit < 0) {
+        ++v;
+        last_digit += 10;
+      }
+      --width;
+      *--ep = kDigits[last_digit];
+    }
+    v = -v;
+  }
+  do {
+    --width;
+    *--ep = kDigits[v % 10];
+  } while (v /= 10);
+  while (--width >= 0) *--ep = '0';  // zero pad
+  if (neg) *--ep = '-';
+  return ep;
+}
+
+// Formats [0 .. 99] as %02d.
+char* Format02d(char* ep, int v) {
+  *--ep = kDigits[v % 10];
+  *--ep = kDigits[(v / 10) % 10];
+  return ep;
+}
+
+// Formats a UTC offset, like +00:00.
+char* FormatOffset(char* ep, int offset, const char* mode) {
+  // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+  // generate a "negative zero" when we're formatting a zero offset
+  // as the result of a failed load_time_zone().
+  char sign = '+';
+  if (offset < 0) {
+    offset = -offset;  // bounded by 24h so no overflow
+    sign = '-';
+  }
+  char sep = mode[0];
+  if (sep != '\0' && mode[1] == '*') {
+    ep = Format02d(ep, offset % 60);
+    *--ep = sep;
+  }
+  int minutes = offset / 60;
+  ep = Format02d(ep, minutes % 60);
+  if (sep != '\0') *--ep = sep;
+  ep = Format02d(ep, minutes / 60);
+  *--ep = sign;
+  return ep;
+}
+
+// Formats a std::tm using strftime(3).
+void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
+  // strftime(3) returns the number of characters placed in the output
+  // array (which may be 0 characters).  It also returns 0 to indicate
+  // an error, like the array wasn't large enough.  To accommodate this,
+  // the following code grows the buffer size from 2x the format std::string
+  // length up to 32x.
+  for (std::size_t i = 2; i != 32; i *= 2) {
+    std::size_t buf_size = fmt.size() * i;
+    std::vector<char> buf(buf_size);
+    if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
+      out->append(&buf[0], len);
+      return;
+    }
+  }
+}
+
+// Used for %E#S/%E#f specifiers and for data values in parse().
+template <typename T>
+const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
+  if (dp != nullptr) {
+    const T kmin = std::numeric_limits<T>::min();
+    bool erange = false;
+    bool neg = false;
+    T value = 0;
+    if (*dp == '-') {
+      neg = true;
+      if (width <= 0 || --width != 0) {
+        ++dp;
+      } else {
+        dp = nullptr;  // width was 1
+      }
+    }
+    if (const char* const bp = dp) {
+      while (const char* cp = strchr(kDigits, *dp)) {
+        int d = static_cast<int>(cp - kDigits);
+        if (d >= 10) break;
+        if (value < kmin / 10) {
+          erange = true;
+          break;
+        }
+        value *= 10;
+        if (value < kmin + d) {
+          erange = true;
+          break;
+        }
+        value -= d;
+        dp += 1;
+        if (width > 0 && --width == 0) break;
+      }
+      if (dp != bp && !erange && (neg || value != kmin)) {
+        if (!neg || value != 0) {
+          if (!neg) value = -value;  // make positive
+          if (min <= value && value <= max) {
+            *vp = value;
+          } else {
+            dp = nullptr;
+          }
+        } else {
+          dp = nullptr;
+        }
+      } else {
+        dp = nullptr;
+      }
+    }
+  }
+  return dp;
+}
+
+// The number of base-10 digits that can be represented by a signed 64-bit
+// integer.  That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1).
+const int kDigits10_64 = 18;
+
+// 10^n for everything that can be represented by a signed 64-bit integer.
+const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
+    1,
+    10,
+    100,
+    1000,
+    10000,
+    100000,
+    1000000,
+    10000000,
+    100000000,
+    1000000000,
+    10000000000,
+    100000000000,
+    1000000000000,
+    10000000000000,
+    100000000000000,
+    1000000000000000,
+    10000000000000000,
+    100000000000000000,
+    1000000000000000000,
+};
+
+}  // namespace
+
+// Uses strftime(3) to format the given Time.  The following extended format
+// specifiers are also supported:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally for performance reasons.  strftime(3) is slow due to
+// a POSIX requirement to respect changes to ${TZ}.
+//
+// The TZ/GNU %s extension is handled internally because strftime() has
+// to use mktime() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z and %Z specifiers to accommodate platforms that do
+// not support the tm_gmtoff and tm_zone extensions to std::tm.
+//
+// Requires that zero() <= fs < seconds(1).
+std::string format(const std::string& format, const time_point<seconds>& tp,
+                   const detail::femtoseconds& fs, const time_zone& tz) {
+  std::string result;
+  result.reserve(format.size());  // A reasonable guess for the result size.
+  const time_zone::absolute_lookup al = tz.lookup(tp);
+  const std::tm tm = ToTM(al);
+
+  // Scratch buffer for internal conversions.
+  char buf[3 + kDigits10_64];  // enough for longest conversion
+  char* const ep = buf + sizeof(buf);
+  char* bp;  // works back from ep
+
+  // Maintain three, disjoint subsequences that span format.
+  //   [format.begin() ... pending) : already formatted into result
+  //   [pending ... cur) : formatting pending, but no special cases
+  //   [cur ... format.end()) : unexamined
+  // Initially, everything is in the unexamined part.
+  const char* pending = format.c_str();  // NUL terminated
+  const char* cur = pending;
+  const char* end = pending + format.length();
+
+  while (cur != end) {  // while something is unexamined
+    // Moves cur to the next percent sign.
+    const char* start = cur;
+    while (cur != end && *cur != '%') ++cur;
+
+    // If the new pending text is all ordinary, copy it out.
+    if (cur != start && pending == start) {
+      result.append(pending, static_cast<std::size_t>(cur - pending));
+      pending = start = cur;
+    }
+
+    // Span the sequential percent signs.
+    const char* percent = cur;
+    while (cur != end && *cur == '%') ++cur;
+
+    // If the new pending text is all percents, copy out one
+    // percent for every matched pair, then skip those pairs.
+    if (cur != start && pending == start) {
+      std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
+      result.append(pending, escaped);
+      pending += escaped * 2;
+      // Also copy out a single trailing percent.
+      if (pending != cur && cur == end) {
+        result.push_back(*pending++);
+      }
+    }
+
+    // Loop unless we have an unescaped percent.
+    if (cur == end || (cur - percent) % 2 == 0) continue;
+
+    // Simple specifiers that we handle ourselves.
+    if (strchr("YmdeHMSzZs%", *cur)) {
+      if (cur - 1 != pending) {
+        FormatTM(&result, std::string(pending, cur - 1), tm);
+      }
+      switch (*cur) {
+        case 'Y':
+          // This avoids the tm.tm_year overflow problem for %Y, however
+          // tm.tm_year will still be used by other specifiers like %D.
+          bp = Format64(ep, 0, al.cs.year());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'm':
+          bp = Format02d(ep, al.cs.month());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'd':
+        case 'e':
+          bp = Format02d(ep, al.cs.day());
+          if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'H':
+          bp = Format02d(ep, al.cs.hour());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'M':
+          bp = Format02d(ep, al.cs.minute());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'S':
+          bp = Format02d(ep, al.cs.second());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'z':
+          bp = FormatOffset(ep, al.offset, "");
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'Z':
+          result.append(al.abbr);
+          break;
+        case 's':
+          bp = Format64(ep, 0, ToUnixSeconds(tp));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case '%':
+          result.push_back('%');
+          break;
+      }
+      pending = ++cur;
+      continue;
+    }
+
+    // Loop if there is no E modifier.
+    if (*cur != 'E' || ++cur == end) continue;
+
+    // Format our extensions.
+    if (*cur == 'z') {
+      // Formats %Ez.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = FormatOffset(ep, al.offset, ":");
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = ++cur;
+    } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
+      // Formats %E*z.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = FormatOffset(ep, al.offset, ":*");
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = cur += 2;
+    } else if (*cur == '*' && cur + 1 != end &&
+               (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
+      // Formats %E*S or %E*F.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      char* cp = ep;
+      bp = Format64(cp, 15, fs.count());
+      while (cp != bp && cp[-1] == '0') --cp;
+      switch (*(cur + 1)) {
+        case 'S':
+          if (cp != bp) *--bp = '.';
+          bp = Format02d(bp, al.cs.second());
+          break;
+        case 'f':
+          if (cp == bp) *--bp = '0';
+          break;
+      }
+      result.append(bp, static_cast<std::size_t>(cp - bp));
+      pending = cur += 2;
+    } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
+      // Formats %E4Y.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = Format64(ep, 4, al.cs.year());
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = cur += 2;
+    } else if (std::isdigit(*cur)) {
+      // Possibly found %E#S or %E#f.
+      int n = 0;
+      if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
+        if (*np == 'S' || *np == 'f') {
+          // Formats %E#S or %E#f.
+          if (cur - 2 != pending) {
+            FormatTM(&result, std::string(pending, cur - 2), tm);
+          }
+          bp = ep;
+          if (n > 0) {
+            if (n > kDigits10_64) n = kDigits10_64;
+            bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
+                                          : fs.count() / kExp10[15 - n]);
+            if (*np == 'S') *--bp = '.';
+          }
+          if (*np == 'S') bp = Format02d(bp, al.cs.second());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          pending = cur = ++np;
+        }
+      }
+    }
+  }
+
+  // Formats any remaining data.
+  if (end != pending) {
+    FormatTM(&result, std::string(pending, end), tm);
+  }
+
+  return result;
+}
+
+namespace {
+
+const char* ParseOffset(const char* dp, const char* mode, int* offset) {
+  if (dp != nullptr) {
+    const char first = *dp++;
+    if (first == '+' || first == '-') {
+      char sep = mode[0];
+      int hours = 0;
+      int minutes = 0;
+      int seconds = 0;
+      const char* ap = ParseInt(dp, 2, 0, 23, &hours);
+      if (ap != nullptr && ap - dp == 2) {
+        dp = ap;
+        if (sep != '\0' && *ap == sep) ++ap;
+        const char* bp = ParseInt(ap, 2, 0, 59, &minutes);
+        if (bp != nullptr && bp - ap == 2) {
+          dp = bp;
+          if (sep != '\0' && *bp == sep) ++bp;
+          const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
+          if (cp != nullptr && cp - bp == 2) dp = cp;
+        }
+        *offset = ((hours * 60 + minutes) * 60) + seconds;
+        if (first == '-') *offset = -*offset;
+      } else {
+        dp = nullptr;
+      }
+    } else if (first == 'Z') {  // Zulu
+      *offset = 0;
+    } else {
+      dp = nullptr;
+    }
+  }
+  return dp;
+}
+
+const char* ParseZone(const char* dp, std::string* zone) {
+  zone->clear();
+  if (dp != nullptr) {
+    while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
+    if (zone->empty()) dp = nullptr;
+  }
+  return dp;
+}
+
+const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
+  if (dp != nullptr) {
+    std::int_fast64_t v = 0;
+    std::int_fast64_t exp = 0;
+    const char* const bp = dp;
+    while (const char* cp = strchr(kDigits, *dp)) {
+      int d = static_cast<int>(cp - kDigits);
+      if (d >= 10) break;
+      if (exp < 15) {
+        exp += 1;
+        v *= 10;
+        v += d;
+      }
+      ++dp;
+    }
+    if (dp != bp) {
+      v *= kExp10[15 - exp];
+      *subseconds = detail::femtoseconds(v);
+    } else {
+      dp = nullptr;
+    }
+  }
+  return dp;
+}
+
+// Parses a std::string into a std::tm using strptime(3).
+const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
+  if (dp != nullptr) {
+    dp = strptime(dp, fmt, tm);
+  }
+  return dp;
+}
+
+}  // namespace
+
+// Uses strptime(3) to parse the given input.  Supports the same extended
+// format specifiers as format(), although %E#S and %E*S are treated
+// identically (and similarly for %E#f and %E*f).  %Ez and %E*z also accept
+// the same inputs.
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally so that we can normally avoid strptime() altogether
+// (which is particularly helpful when the native implementation is broken).
+//
+// The TZ/GNU %s extension is handled internally because strptime() has to
+// use localtime_r() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z specifier to accommodate platforms that do not
+// support the tm_gmtoff extension to std::tm.  %Z is parsed but ignored.
+bool parse(const std::string& format, const std::string& input,
+           const time_zone& tz, time_point<seconds>* sec,
+           detail::femtoseconds* fs, std::string* err) {
+  // The unparsed input.
+  const char* data = input.c_str();  // NUL terminated
+
+  // Skips leading whitespace.
+  while (std::isspace(*data)) ++data;
+
+  const year_t kyearmax = std::numeric_limits<year_t>::max();
+  const year_t kyearmin = std::numeric_limits<year_t>::min();
+
+  // Sets default values for unspecified fields.
+  bool saw_year = false;
+  year_t year = 1970;
+  std::tm tm{};
+  tm.tm_year = 1970 - 1900;
+  tm.tm_mon = 1 - 1;  // Jan
+  tm.tm_mday = 1;
+  tm.tm_hour = 0;
+  tm.tm_min = 0;
+  tm.tm_sec = 0;
+  tm.tm_wday = 4;  // Thu
+  tm.tm_yday = 0;
+  tm.tm_isdst = 0;
+  auto subseconds = detail::femtoseconds::zero();
+  bool saw_offset = false;
+  int offset = 0;  // No offset from passed tz.
+  std::string zone = "UTC";
+
+  const char* fmt = format.c_str();  // NUL terminated
+  bool twelve_hour = false;
+  bool afternoon = false;
+
+  bool saw_percent_s = false;
+  std::int_fast64_t percent_s = 0;
+
+  // Steps through format, one specifier at a time.
+  while (data != nullptr && *fmt != '\0') {
+    if (std::isspace(*fmt)) {
+      while (std::isspace(*data)) ++data;
+      while (std::isspace(*++fmt)) continue;
+      continue;
+    }
+
+    if (*fmt != '%') {
+      if (*data == *fmt) {
+        ++data;
+        ++fmt;
+      } else {
+        data = nullptr;
+      }
+      continue;
+    }
+
+    const char* percent = fmt;
+    if (*++fmt == '\0') {
+      data = nullptr;
+      continue;
+    }
+    switch (*fmt++) {
+      case 'Y':
+        // Symmetrically with FormatTime(), directly handing %Y avoids the
+        // tm.tm_year overflow problem.  However, tm.tm_year will still be
+        // used by other specifiers like %D.
+        data = ParseInt(data, 0, kyearmin, kyearmax, &year);
+        if (data != nullptr) saw_year = true;
+        continue;
+      case 'm':
+        data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
+        if (data != nullptr) tm.tm_mon -= 1;
+        continue;
+      case 'd':
+      case 'e':
+        data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+        continue;
+      case 'H':
+        data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
+        twelve_hour = false;
+        continue;
+      case 'M':
+        data = ParseInt(data, 2, 0, 59, &tm.tm_min);
+        continue;
+      case 'S':
+        data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+        continue;
+      case 'I':
+      case 'l':
+      case 'r':  // probably uses %I
+        twelve_hour = true;
+        break;
+      case 'R':  // uses %H
+      case 'T':  // uses %H
+      case 'c':  // probably uses %H
+      case 'X':  // probably uses %H
+        twelve_hour = false;
+        break;
+      case 'z':
+        data = ParseOffset(data, "", &offset);
+        if (data != nullptr) saw_offset = true;
+        continue;
+      case 'Z':  // ignored; zone abbreviations are ambiguous
+        data = ParseZone(data, &zone);
+        continue;
+      case 's':
+        data = ParseInt(data, 0,
+                        std::numeric_limits<std::int_fast64_t>::min(),
+                        std::numeric_limits<std::int_fast64_t>::max(),
+                        &percent_s);
+        if (data != nullptr) saw_percent_s = true;
+        continue;
+      case '%':
+        data = (*data == '%' ? data + 1 : nullptr);
+        continue;
+      case 'E':
+        if (*fmt == 'z' || (*fmt == '*' && *(fmt + 1) == 'z')) {
+          data = ParseOffset(data, ":", &offset);
+          if (data != nullptr) saw_offset = true;
+          fmt += (*fmt == 'z') ? 1 : 2;
+          continue;
+        }
+        if (*fmt == '*' && *(fmt + 1) == 'S') {
+          data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+          if (data != nullptr && *data == '.') {
+            data = ParseSubSeconds(data + 1, &subseconds);
+          }
+          fmt += 2;
+          continue;
+        }
+        if (*fmt == '*' && *(fmt + 1) == 'f') {
+          if (data != nullptr && std::isdigit(*data)) {
+            data = ParseSubSeconds(data, &subseconds);
+          }
+          fmt += 2;
+          continue;
+        }
+        if (*fmt == '4' && *(fmt + 1) == 'Y') {
+          const char* bp = data;
+          data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
+          if (data != nullptr) {
+            if (data - bp == 4) {
+              saw_year = true;
+            } else {
+              data = nullptr;  // stopped too soon
+            }
+          }
+          fmt += 2;
+          continue;
+        }
+        if (std::isdigit(*fmt)) {
+          int n = 0;  // value ignored
+          if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
+            if (*np == 'S') {
+              data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+              if (data != nullptr && *data == '.') {
+                data = ParseSubSeconds(data + 1, &subseconds);
+              }
+              fmt = ++np;
+              continue;
+            }
+            if (*np == 'f') {
+              if (data != nullptr && std::isdigit(*data)) {
+                data = ParseSubSeconds(data, &subseconds);
+              }
+              fmt = ++np;
+              continue;
+            }
+          }
+        }
+        if (*fmt == 'c') twelve_hour = false;  // probably uses %H
+        if (*fmt == 'X') twelve_hour = false;  // probably uses %H
+        if (*fmt != '\0') ++fmt;
+        break;
+      case 'O':
+        if (*fmt == 'H') twelve_hour = false;
+        if (*fmt == 'I') twelve_hour = true;
+        if (*fmt != '\0') ++fmt;
+        break;
+    }
+
+    // Parses the current specifier.
+    const char* orig_data = data;
+    std::string spec(percent, static_cast<std::size_t>(fmt - percent));
+    data = ParseTM(data, spec.c_str(), &tm);
+
+    // If we successfully parsed %p we need to remember whether the result
+    // was AM or PM so that we can adjust tm_hour before ConvertDateTime().
+    // So reparse the input with a known AM hour, and check if it is shifted
+    // to a PM hour.
+    if (spec == "%p" && data != nullptr) {
+      std::string test_input = "1";
+      test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
+      const char* test_data = test_input.c_str();
+      std::tm tmp{};
+      ParseTM(test_data, "%I%p", &tmp);
+      afternoon = (tmp.tm_hour == 13);
+    }
+  }
+
+  // Adjust a 12-hour tm_hour value if it should be in the afternoon.
+  if (twelve_hour && afternoon && tm.tm_hour < 12) {
+    tm.tm_hour += 12;
+  }
+
+  if (data == nullptr) {
+    if (err != nullptr) *err = "Failed to parse input";
+    return false;
+  }
+
+  // Skip any remaining whitespace.
+  while (std::isspace(*data)) ++data;
+
+  // parse() must consume the entire input std::string.
+  if (*data != '\0') {
+    if (err != nullptr) *err = "Illegal trailing data in input string";
+    return false;
+  }
+
+  // If we saw %s then we ignore anything else and return that time.
+  if (saw_percent_s) {
+    *sec = FromUnixSeconds(percent_s);
+    *fs = detail::femtoseconds::zero();
+    return true;
+  }
+
+  // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields
+  // in UTC and then shift by that offset.  Otherwise we want to interpret
+  // the fields directly in the passed time_zone.
+  time_zone ptz = saw_offset ? utc_time_zone() : tz;
+
+  // Allows a leap second of 60 to normalize forward to the following ":00".
+  if (tm.tm_sec == 60) {
+    tm.tm_sec -= 1;
+    offset -= 1;
+    subseconds = detail::femtoseconds::zero();
+  }
+
+  if (!saw_year) {
+    year = year_t{tm.tm_year};
+    if (year > kyearmax - 1900) {
+      // Platform-dependent, maybe unreachable.
+      if (err != nullptr) *err = "Out-of-range year";
+      return false;
+    }
+    year += 1900;
+  }
+
+  const int month = tm.tm_mon + 1;
+  civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+  // parse() should not allow normalization. Due to the restricted field
+  // ranges above (see ParseInt()), the only possibility is for days to roll
+  // into months. That is, parsing "Sep 31" should not produce "Oct 1".
+  if (cs.month() != month || cs.day() != tm.tm_mday) {
+    if (err != nullptr) *err = "Out-of-range field";
+    return false;
+  }
+
+  // Accounts for the offset adjustment before converting to absolute time.
+  if ((offset < 0 && cs > civil_second::max() + offset) ||
+      (offset > 0 && cs < civil_second::min() + offset)) {
+    if (err != nullptr) *err = "Out-of-range field";
+    return false;
+  }
+  cs -= offset;
+
+  const auto tp = ptz.lookup(cs).pre;
+  // Checks for overflow/underflow and returns an error as necessary.
+  if (tp == time_point<seconds>::max()) {
+    const auto al = ptz.lookup(time_point<seconds>::max());
+    if (cs > al.cs) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+  if (tp == time_point<seconds>::min()) {
+    const auto al = ptz.lookup(time_point<seconds>::min());
+    if (cs < al.cs) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+
+  *sec = tp;
+  *fs = subseconds;
+  return true;
+}
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
new file mode 100644
index 0000000..a90dda7
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -0,0 +1,1426 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#include <chrono>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace chrono = std::chrono;
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \
+  do {                                                            \
+    time_zone::absolute_lookup al = tz.lookup(tp);                \
+    EXPECT_EQ(y, al.cs.year());                                   \
+    EXPECT_EQ(m, al.cs.month());                                  \
+    EXPECT_EQ(d, al.cs.day());                                    \
+    EXPECT_EQ(hh, al.cs.hour());                                  \
+    EXPECT_EQ(mm, al.cs.minute());                                \
+    EXPECT_EQ(ss, al.cs.second());                                \
+    EXPECT_EQ(off, al.offset);                                    \
+    EXPECT_TRUE(isdst == al.is_dst);                              \
+    EXPECT_STREQ(zone, al.abbr);                                  \
+  } while (0)
+
+const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
+const char RFC3339_sec[] =  "%Y-%m-%dT%H:%M:%S%Ez";
+
+const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
+const char RFC1123_no_wday[] =  "%d %b %Y %H:%M:%S %z";
+
+// A helper that tests the given format specifier by itself, and with leading
+// and trailing characters.  For example: TestFormatSpecifier(tp, "%a", "Thu").
+template <typename D>
+void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt,
+                         const std::string& ans) {
+  EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt;
+  EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz));
+  EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz));
+  EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
+}
+
+// These tests sometimes run on platforms that have zoneinfo data so old
+// that the transition we are attempting to check does not exist, most
+// notably Android emulators.  Fortunately, AndroidZoneInfoSource supports
+// time_zone::version() so, in cases where we've learned that it matters,
+// we can make the check conditionally.
+int VersionCmp(time_zone tz, const std::string& target) {
+  std::string version = tz.version();
+  if (version.empty() && !target.empty()) return 1;  // unknown > known
+  return version.compare(target);
+}
+
+}  // namespace
+
+//
+// Testing format()
+//
+
+TEST(Format, TimePointResolution) {
+  const char kFmt[] = "%H:%M:%E*S";
+  const time_zone utc = utc_time_zone();
+  const time_point<chrono::nanoseconds> t0 =
+      chrono::system_clock::from_time_t(1420167845) +
+      chrono::milliseconds(123) + chrono::microseconds(456) +
+      chrono::nanoseconds(789);
+  EXPECT_EQ(
+      "03:04:05.123456789",
+      format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc));
+  EXPECT_EQ(
+      "03:04:05.123456",
+      format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc));
+  EXPECT_EQ(
+      "03:04:05.123",
+      format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
+  EXPECT_EQ("03:04:05",
+            format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
+  EXPECT_EQ("03:04:05",
+            format(kFmt, chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc));
+  EXPECT_EQ("03:04:00",
+            format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
+  EXPECT_EQ("03:00:00",
+            format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc));
+}
+
+TEST(Format, TimePointExtendedResolution) {
+  const char kFmt[] = "%H:%M:%E*S";
+  const time_zone utc = utc_time_zone();
+  const time_point<absl::time_internal::cctz::seconds> tp =
+      chrono::time_point_cast<absl::time_internal::cctz::seconds>(
+          chrono::system_clock::from_time_t(0)) +
+      chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56);
+
+  EXPECT_EQ(
+      "12:34:56.123456789012345",
+      detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc));
+  EXPECT_EQ(
+      "12:34:56.012345678901234",
+      detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
+  EXPECT_EQ(
+      "12:34:56.001234567890123",
+      detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
+  EXPECT_EQ(
+      "12:34:56.000123456789012",
+      detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
+
+  EXPECT_EQ("12:34:56.000000000000123",
+            detail::format(kFmt, tp, detail::femtoseconds(123), utc));
+  EXPECT_EQ("12:34:56.000000000000012",
+            detail::format(kFmt, tp, detail::femtoseconds(12), utc));
+  EXPECT_EQ("12:34:56.000000000000001",
+            detail::format(kFmt, tp, detail::femtoseconds(1), utc));
+}
+
+TEST(Format, Basics) {
+  time_zone tz = utc_time_zone();
+  time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+
+  // Starts with a couple basic edge cases.
+  EXPECT_EQ("", format("", tp, tz));
+  EXPECT_EQ(" ", format(" ", tp, tz));
+  EXPECT_EQ("  ", format("  ", tp, tz));
+  EXPECT_EQ("xxx", format("xxx", tp, tz));
+  std::string big(128, 'x');
+  EXPECT_EQ(big, format(big, tp, tz));
+  // Cause the 1024-byte buffer to grow.
+  std::string bigger(100000, 'x');
+  EXPECT_EQ(bigger, format(bigger, tp, tz));
+
+  tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5);
+  tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+        chrono::nanoseconds(8);
+  EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz));
+  EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz));
+  EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz));
+  EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz));
+  EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz));
+}
+
+TEST(Format, PosixConversions) {
+  const time_zone tz = utc_time_zone();
+  auto tp = chrono::system_clock::from_time_t(0);
+
+  TestFormatSpecifier(tp, tz, "%d", "01");
+  TestFormatSpecifier(tp, tz, "%e", " 1");  // extension but internal support
+  TestFormatSpecifier(tp, tz, "%H", "00");
+  TestFormatSpecifier(tp, tz, "%I", "12");
+  TestFormatSpecifier(tp, tz, "%j", "001");
+  TestFormatSpecifier(tp, tz, "%m", "01");
+  TestFormatSpecifier(tp, tz, "%M", "00");
+  TestFormatSpecifier(tp, tz, "%S", "00");
+  TestFormatSpecifier(tp, tz, "%U", "00");
+  TestFormatSpecifier(tp, tz, "%w", "4");  // 4=Thursday
+  TestFormatSpecifier(tp, tz, "%W", "00");
+  TestFormatSpecifier(tp, tz, "%y", "70");
+  TestFormatSpecifier(tp, tz, "%Y", "1970");
+  TestFormatSpecifier(tp, tz, "%z", "+0000");
+  TestFormatSpecifier(tp, tz, "%Z", "UTC");
+  TestFormatSpecifier(tp, tz, "%%", "%");
+
+#if defined(__linux__)
+  // SU/C99/TZ extensions
+  TestFormatSpecifier(tp, tz, "%C", "19");
+  TestFormatSpecifier(tp, tz, "%D", "01/01/70");
+  TestFormatSpecifier(tp, tz, "%F", "1970-01-01");
+  TestFormatSpecifier(tp, tz, "%g", "70");
+  TestFormatSpecifier(tp, tz, "%G", "1970");
+  TestFormatSpecifier(tp, tz, "%k", " 0");
+  TestFormatSpecifier(tp, tz, "%l", "12");
+  TestFormatSpecifier(tp, tz, "%n", "\n");
+  TestFormatSpecifier(tp, tz, "%R", "00:00");
+  TestFormatSpecifier(tp, tz, "%t", "\t");
+  TestFormatSpecifier(tp, tz, "%T", "00:00:00");
+  TestFormatSpecifier(tp, tz, "%u", "4");  // 4=Thursday
+  TestFormatSpecifier(tp, tz, "%V", "01");
+  TestFormatSpecifier(tp, tz, "%s", "0");
+#endif
+}
+
+TEST(Format, LocaleSpecific) {
+  const time_zone tz = utc_time_zone();
+  auto tp = chrono::system_clock::from_time_t(0);
+
+  TestFormatSpecifier(tp, tz, "%a", "Thu");
+  TestFormatSpecifier(tp, tz, "%A", "Thursday");
+  TestFormatSpecifier(tp, tz, "%b", "Jan");
+  TestFormatSpecifier(tp, tz, "%B", "January");
+
+  // %c should at least produce the numeric year and time-of-day.
+  const std::string s = format("%c", tp, utc_time_zone());
+  EXPECT_THAT(s, testing::HasSubstr("1970"));
+  EXPECT_THAT(s, testing::HasSubstr("00:00:00"));
+
+  TestFormatSpecifier(tp, tz, "%p", "AM");
+  TestFormatSpecifier(tp, tz, "%x", "01/01/70");
+  TestFormatSpecifier(tp, tz, "%X", "00:00:00");
+
+#if defined(__linux__)
+  // SU/C99/TZ extensions
+  TestFormatSpecifier(tp, tz, "%h", "Jan");  // Same as %b
+  TestFormatSpecifier(tp, tz, "%P", "am");
+  TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM");
+
+  // Modified conversion specifiers %E_
+  TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan  1 00:00:00 1970");
+  TestFormatSpecifier(tp, tz, "%EC", "19");
+  TestFormatSpecifier(tp, tz, "%Ex", "01/01/70");
+  TestFormatSpecifier(tp, tz, "%EX", "00:00:00");
+  TestFormatSpecifier(tp, tz, "%Ey", "70");
+  TestFormatSpecifier(tp, tz, "%EY", "1970");
+
+  // Modified conversion specifiers %O_
+  TestFormatSpecifier(tp, tz, "%Od", "01");
+  TestFormatSpecifier(tp, tz, "%Oe", " 1");
+  TestFormatSpecifier(tp, tz, "%OH", "00");
+  TestFormatSpecifier(tp, tz, "%OI", "12");
+  TestFormatSpecifier(tp, tz, "%Om", "01");
+  TestFormatSpecifier(tp, tz, "%OM", "00");
+  TestFormatSpecifier(tp, tz, "%OS", "00");
+  TestFormatSpecifier(tp, tz, "%Ou", "4");  // 4=Thursday
+  TestFormatSpecifier(tp, tz, "%OU", "00");
+  TestFormatSpecifier(tp, tz, "%OV", "01");
+  TestFormatSpecifier(tp, tz, "%Ow", "4");  // 4=Thursday
+  TestFormatSpecifier(tp, tz, "%OW", "00");
+  TestFormatSpecifier(tp, tz, "%Oy", "70");
+#endif
+}
+
+TEST(Format, Escaping) {
+  const time_zone tz = utc_time_zone();
+  auto tp = chrono::system_clock::from_time_t(0);
+
+  TestFormatSpecifier(tp, tz, "%%", "%");
+  TestFormatSpecifier(tp, tz, "%%a", "%a");
+  TestFormatSpecifier(tp, tz, "%%b", "%b");
+  TestFormatSpecifier(tp, tz, "%%Ea", "%Ea");
+  TestFormatSpecifier(tp, tz, "%%Es", "%Es");
+  TestFormatSpecifier(tp, tz, "%%E3S", "%E3S");
+  TestFormatSpecifier(tp, tz, "%%OS", "%OS");
+  TestFormatSpecifier(tp, tz, "%%O3S", "%O3S");
+
+  // Multiple levels of escaping.
+  TestFormatSpecifier(tp, tz, "%%%Y", "%1970");
+  TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000");
+  TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S");
+}
+
+TEST(Format, ExtendedSeconds) {
+  const time_zone tz = utc_time_zone();
+
+  // No subseconds.
+  time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+  tp += chrono::seconds(5);
+  EXPECT_EQ("05", format("%E*S", tp, tz));
+  EXPECT_EQ("05", format("%E0S", tp, tz));
+  EXPECT_EQ("05.0", format("%E1S", tp, tz));
+  EXPECT_EQ("05.00", format("%E2S", tp, tz));
+  EXPECT_EQ("05.000", format("%E3S", tp, tz));
+  EXPECT_EQ("05.0000", format("%E4S", tp, tz));
+  EXPECT_EQ("05.00000", format("%E5S", tp, tz));
+  EXPECT_EQ("05.000000", format("%E6S", tp, tz));
+  EXPECT_EQ("05.0000000", format("%E7S", tp, tz));
+  EXPECT_EQ("05.00000000", format("%E8S", tp, tz));
+  EXPECT_EQ("05.000000000", format("%E9S", tp, tz));
+  EXPECT_EQ("05.0000000000", format("%E10S", tp, tz));
+  EXPECT_EQ("05.00000000000", format("%E11S", tp, tz));
+  EXPECT_EQ("05.000000000000", format("%E12S", tp, tz));
+  EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz));
+  EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz));
+  EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz));
+
+  // With subseconds.
+  tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+        chrono::nanoseconds(8);
+  EXPECT_EQ("05.006007008", format("%E*S", tp, tz));
+  EXPECT_EQ("05", format("%E0S", tp, tz));
+  EXPECT_EQ("05.0", format("%E1S", tp, tz));
+  EXPECT_EQ("05.00", format("%E2S", tp, tz));
+  EXPECT_EQ("05.006", format("%E3S", tp, tz));
+  EXPECT_EQ("05.0060", format("%E4S", tp, tz));
+  EXPECT_EQ("05.00600", format("%E5S", tp, tz));
+  EXPECT_EQ("05.006007", format("%E6S", tp, tz));
+  EXPECT_EQ("05.0060070", format("%E7S", tp, tz));
+  EXPECT_EQ("05.00600700", format("%E8S", tp, tz));
+  EXPECT_EQ("05.006007008", format("%E9S", tp, tz));
+  EXPECT_EQ("05.0060070080", format("%E10S", tp, tz));
+  EXPECT_EQ("05.00600700800", format("%E11S", tp, tz));
+  EXPECT_EQ("05.006007008000", format("%E12S", tp, tz));
+  EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz));
+  EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz));
+  EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz));
+
+  // Times before the Unix epoch.
+  tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
+  EXPECT_EQ("1969-12-31 23:59:59.999999",
+            format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+
+  // Here is a "%E*S" case we got wrong for a while.  While the first
+  // instant below is correctly rendered as "...:07.333304", the second
+  // one used to appear as "...:07.33330499999999999".
+  tp = chrono::system_clock::from_time_t(0) +
+       chrono::microseconds(1395024427333304);
+  EXPECT_EQ("2014-03-17 02:47:07.333304",
+            format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+  tp += chrono::microseconds(1);
+  EXPECT_EQ("2014-03-17 02:47:07.333305",
+            format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+}
+
+TEST(Format, ExtendedSubeconds) {
+  const time_zone tz = utc_time_zone();
+
+  // No subseconds.
+  time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+  tp += chrono::seconds(5);
+  EXPECT_EQ("0", format("%E*f", tp, tz));
+  EXPECT_EQ("", format("%E0f", tp, tz));
+  EXPECT_EQ("0", format("%E1f", tp, tz));
+  EXPECT_EQ("00", format("%E2f", tp, tz));
+  EXPECT_EQ("000", format("%E3f", tp, tz));
+  EXPECT_EQ("0000", format("%E4f", tp, tz));
+  EXPECT_EQ("00000", format("%E5f", tp, tz));
+  EXPECT_EQ("000000", format("%E6f", tp, tz));
+  EXPECT_EQ("0000000", format("%E7f", tp, tz));
+  EXPECT_EQ("00000000", format("%E8f", tp, tz));
+  EXPECT_EQ("000000000", format("%E9f", tp, tz));
+  EXPECT_EQ("0000000000", format("%E10f", tp, tz));
+  EXPECT_EQ("00000000000", format("%E11f", tp, tz));
+  EXPECT_EQ("000000000000", format("%E12f", tp, tz));
+  EXPECT_EQ("0000000000000", format("%E13f", tp, tz));
+  EXPECT_EQ("00000000000000", format("%E14f", tp, tz));
+  EXPECT_EQ("000000000000000", format("%E15f", tp, tz));
+
+  // With subseconds.
+  tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+        chrono::nanoseconds(8);
+  EXPECT_EQ("006007008", format("%E*f", tp, tz));
+  EXPECT_EQ("", format("%E0f", tp, tz));
+  EXPECT_EQ("0", format("%E1f", tp, tz));
+  EXPECT_EQ("00", format("%E2f", tp, tz));
+  EXPECT_EQ("006", format("%E3f", tp, tz));
+  EXPECT_EQ("0060", format("%E4f", tp, tz));
+  EXPECT_EQ("00600", format("%E5f", tp, tz));
+  EXPECT_EQ("006007", format("%E6f", tp, tz));
+  EXPECT_EQ("0060070", format("%E7f", tp, tz));
+  EXPECT_EQ("00600700", format("%E8f", tp, tz));
+  EXPECT_EQ("006007008", format("%E9f", tp, tz));
+  EXPECT_EQ("0060070080", format("%E10f", tp, tz));
+  EXPECT_EQ("00600700800", format("%E11f", tp, tz));
+  EXPECT_EQ("006007008000", format("%E12f", tp, tz));
+  EXPECT_EQ("0060070080000", format("%E13f", tp, tz));
+  EXPECT_EQ("00600700800000", format("%E14f", tp, tz));
+  EXPECT_EQ("006007008000000", format("%E15f", tp, tz));
+
+  // Times before the Unix epoch.
+  tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
+  EXPECT_EQ("1969-12-31 23:59:59.999999",
+            format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+
+  // Here is a "%E*S" case we got wrong for a while.  While the first
+  // instant below is correctly rendered as "...:07.333304", the second
+  // one used to appear as "...:07.33330499999999999".
+  tp = chrono::system_clock::from_time_t(0) +
+       chrono::microseconds(1395024427333304);
+  EXPECT_EQ("2014-03-17 02:47:07.333304",
+            format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+  tp += chrono::microseconds(1);
+  EXPECT_EQ("2014-03-17 02:47:07.333305",
+            format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+}
+
+TEST(Format, CompareExtendSecondsVsSubseconds) {
+  const time_zone tz = utc_time_zone();
+
+  // This test case illustrates the differences/similarities between:
+  //   fmt_A: %E<prec>S
+  //   fmt_B: %S.%E<prec>f
+  auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; };
+  auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; };
+
+  // No subseconds:
+  time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+  tp += chrono::seconds(5);
+  // ... %E*S and %S.%E*f are different.
+  EXPECT_EQ("05", format(fmt_A("*"), tp, tz));
+  EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz));
+  // ... %E0S and %S.%E0f are different.
+  EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
+  EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
+  // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
+  for (int prec = 1; prec <= 15; ++prec) {
+    const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
+    const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
+    EXPECT_EQ(a, b) << "prec=" << prec;
+  }
+
+  // With subseconds:
+  // ... %E*S and %S.%E*f are the same.
+  tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+        chrono::nanoseconds(8);
+  EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz));
+  EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz));
+  // ... %E0S and %S.%E0f are different.
+  EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
+  EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
+  // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
+  for (int prec = 1; prec <= 15; ++prec) {
+    const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
+    const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
+    EXPECT_EQ(a, b) << "prec=" << prec;
+  }
+}
+
+TEST(Format, ExtendedOffset) {
+  auto tp = chrono::system_clock::from_time_t(0);
+
+  time_zone tz = utc_time_zone();
+  TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+  EXPECT_TRUE(load_time_zone("America/New_York", &tz));
+  TestFormatSpecifier(tp, tz, "%Ez", "-05:00");
+
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+  TestFormatSpecifier(tp, tz, "%Ez", "-08:00");
+
+  EXPECT_TRUE(load_time_zone("Australia/Sydney", &tz));
+  TestFormatSpecifier(tp, tz, "%Ez", "+10:00");
+
+  EXPECT_TRUE(load_time_zone("Africa/Monrovia", &tz));
+  // The true offset is -00:44:30 but %z only gives (truncated) minutes.
+  TestFormatSpecifier(tp, tz, "%z", "-0044");
+  TestFormatSpecifier(tp, tz, "%Ez", "-00:44");
+}
+
+TEST(Format, ExtendedSecondOffset) {
+  const time_zone utc = utc_time_zone();
+  time_point<chrono::seconds> tp;
+  time_zone tz;
+
+  EXPECT_TRUE(load_time_zone("America/New_York", &tz));
+  tp = convert(civil_second(1883, 11, 18, 16, 59, 59), utc);
+  if (tz.lookup(tp).offset == -5 * 60 * 60) {
+    // It looks like the tzdata is only 32 bit (probably macOS),
+    // which bottoms out at 1901-12-13T20:45:52+00:00.
+  } else {
+    TestFormatSpecifier(tp, tz, "%E*z", "-04:56:02");
+    TestFormatSpecifier(tp, tz, "%Ez", "-04:56");
+  }
+  tp += chrono::seconds(1);
+  TestFormatSpecifier(tp, tz, "%E*z", "-05:00:00");
+
+  EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz));
+  tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc);
+  if (VersionCmp(tz, "2016g") >= 0) {
+    TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19");
+    TestFormatSpecifier(tp, tz, "%Ez", "+04:31");
+  }
+  tp += chrono::seconds(1);
+  TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00");
+}
+
+TEST(Format, ExtendedYears) {
+  const time_zone utc = utc_time_zone();
+  const char e4y_fmt[] = "%E4Y%m%d";  // no separators
+
+  // %E4Y zero-pads the year to produce at least 4 chars, including the sign.
+  auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("00001127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("00011127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("00091127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("00991127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("09991127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("99991127", format(e4y_fmt, tp, utc));
+
+  // When the year is outside [-999:9999], more than 4 chars are produced.
+  tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc));
+  tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc);
+  EXPECT_EQ("100001127", format(e4y_fmt, tp, utc));
+}
+
+TEST(Format, RFC3339Format) {
+  time_zone tz;
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+
+  time_point<chrono::nanoseconds> tp =
+      convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::milliseconds(100);
+  EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::milliseconds(20);
+  EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::milliseconds(3);
+  EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::microseconds(400);
+  EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::microseconds(50);
+  EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::microseconds(6);
+  EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::nanoseconds(700);
+  EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::nanoseconds(80);
+  EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+  tp += chrono::nanoseconds(9);
+  EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00",
+            format(RFC3339_full, tp, tz));
+  EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+}
+
+TEST(Format, RFC1123Format) {  // locale specific
+  time_zone tz;
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+
+  auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+  EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz));
+  EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
+}
+
+//
+// Testing parse()
+//
+
+TEST(Parse, TimePointResolution) {
+  const char kFmt[] = "%H:%M:%E*S";
+  const time_zone utc = utc_time_zone();
+
+  time_point<chrono::nanoseconds> tp_ns;
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns));
+  EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc));
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns));
+  EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc));
+
+  time_point<chrono::microseconds> tp_us;
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us));
+  EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us));
+  EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us));
+  EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc));
+
+  time_point<chrono::milliseconds> tp_ms;
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms));
+  EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms));
+  EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
+  EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms));
+  EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc));
+
+  time_point<chrono::seconds> tp_s;
+  EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s));
+  EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
+  EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s));
+  EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
+
+  time_point<chrono::minutes> tp_m;
+  EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m));
+  EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc));
+
+  time_point<chrono::hours> tp_h;
+  EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h));
+  EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc));
+}
+
+TEST(Parse, TimePointExtendedResolution) {
+  const char kFmt[] = "%H:%M:%E*S";
+  const time_zone utc = utc_time_zone();
+
+  time_point<absl::time_internal::cctz::seconds> tp;
+  detail::femtoseconds fs;
+  EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs));
+  EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc));
+  EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs));
+  EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc));
+  EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs));
+  EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc));
+  EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs));
+  EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc));
+  EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs));
+  EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc));
+  EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs));
+  EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc));
+}
+
+TEST(Parse, Basics) {
+  time_zone tz = utc_time_zone();
+  time_point<chrono::nanoseconds> tp =
+      chrono::system_clock::from_time_t(1234567890);
+
+  // Simple edge cases.
+  EXPECT_TRUE(parse("", "", tz, &tp));
+  EXPECT_EQ(chrono::system_clock::from_time_t(0), tp);  // everything defaulted
+  EXPECT_TRUE(parse(" ", " ", tz, &tp));
+  EXPECT_TRUE(parse("  ", "  ", tz, &tp));
+  EXPECT_TRUE(parse("x", "x", tz, &tp));
+  EXPECT_TRUE(parse("xxx", "xxx", tz, &tp));
+
+  EXPECT_TRUE(
+      parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp));
+  ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC");
+}
+
+TEST(Parse, WithTimeZone) {
+  time_zone tz;
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+  time_point<chrono::nanoseconds> tp;
+
+  // We can parse a std::string without a UTC offset if we supply a timezone.
+  EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
+  ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
+
+  // But the timezone is ignored when a UTC offset is present.
+  EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800",
+                    utc_time_zone(), &tp));
+  ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT");
+
+  // Check a skipped time (a Spring DST transition).  parse() returns
+  // the preferred-offset result, as defined for ConvertDateTime().
+  EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp));
+  ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT");
+
+  // Check a repeated time (a Fall DST transition).  parse() returns
+  // the preferred-offset result, as defined for ConvertDateTime().
+  EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp));
+  ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT");
+}
+
+TEST(Parse, LeapSecond) {
+  time_zone tz;
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+  time_point<chrono::nanoseconds> tp;
+
+  // ":59" -> ":59"
+  EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp));
+  ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
+
+  // ":59.5" -> ":59.5"
+  EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp));
+  ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
+
+  // ":60" -> ":00"
+  EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp));
+  ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
+
+  // ":60.5" -> ":00.0"
+  EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp));
+  ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
+
+  // ":61" -> error
+  EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp));
+}
+
+TEST(Parse, ErrorCases) {
+  const time_zone tz = utc_time_zone();
+  auto tp = chrono::system_clock::from_time_t(0);
+
+  // Illegal trailing data.
+  EXPECT_FALSE(parse("%S", "123", tz, &tp));
+
+  // Can't parse an illegal format specifier.
+  EXPECT_FALSE(parse("%Q", "x", tz, &tp));
+
+  // Fails because of trailing, unparsed data "blah".
+  EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp));
+
+  // Trailing whitespace is allowed.
+  EXPECT_TRUE(parse("%m-%d", "2-3  ", tz, &tp));
+  EXPECT_EQ(2, convert(tp, utc_time_zone()).month());
+  EXPECT_EQ(3, convert(tp, utc_time_zone()).day());
+
+  // Feb 31 requires normalization.
+  EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp));
+
+  // Check that we cannot have spaces in UTC offsets.
+  EXPECT_TRUE(parse("%z", "-0203", tz, &tp));
+  EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp));
+  EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp));
+  EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp));
+
+  // Check that we reject other malformed UTC offsets.
+  EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp));
+  EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp));
+
+  // Check that we do not accept "-0" in fields that allow zero.
+  EXPECT_FALSE(parse("%Y", "-0", tz, &tp));
+  EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp));
+  EXPECT_FALSE(parse("%H", "-0", tz, &tp));
+  EXPECT_FALSE(parse("%M", "-0", tz, &tp));
+  EXPECT_FALSE(parse("%S", "-0", tz, &tp));
+  EXPECT_FALSE(parse("%z", "+-000", tz, &tp));
+  EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp));
+  EXPECT_FALSE(parse("%z", "-00-0", tz, &tp));
+  EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
+}
+
+TEST(Parse, PosixConversions) {
+  time_zone tz = utc_time_zone();
+  auto tp = chrono::system_clock::from_time_t(0);
+  const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+
+  tp = reset;
+  EXPECT_TRUE(parse("%d", "15", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).day());
+
+  // %e is an extension, but is supported internally.
+  tp = reset;
+  EXPECT_TRUE(parse("%e", "15", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).day());  // Equivalent to %d
+
+  tp = reset;
+  EXPECT_TRUE(parse("%H", "17", tz, &tp));
+  EXPECT_EQ(17, convert(tp, tz).hour());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%I", "5", tz, &tp));
+  EXPECT_EQ(5, convert(tp, tz).hour());
+
+  // %j is parsed but ignored.
+  EXPECT_TRUE(parse("%j", "32", tz, &tp));
+
+  tp = reset;
+  EXPECT_TRUE(parse("%m", "11", tz, &tp));
+  EXPECT_EQ(11, convert(tp, tz).month());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%M", "33", tz, &tp));
+  EXPECT_EQ(33, convert(tp, tz).minute());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%S", "55", tz, &tp));
+  EXPECT_EQ(55, convert(tp, tz).second());
+
+  // %U is parsed but ignored.
+  EXPECT_TRUE(parse("%U", "15", tz, &tp));
+
+  // %w is parsed but ignored.
+  EXPECT_TRUE(parse("%w", "2", tz, &tp));
+
+  // %W is parsed but ignored.
+  EXPECT_TRUE(parse("%W", "22", tz, &tp));
+
+  tp = reset;
+  EXPECT_TRUE(parse("%y", "04", tz, &tp));
+  EXPECT_EQ(2004, convert(tp, tz).year());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Y", "2004", tz, &tp));
+  EXPECT_EQ(2004, convert(tp, tz).year());
+
+  EXPECT_TRUE(parse("%%", "%", tz, &tp));
+
+#if defined(__linux__)
+  // SU/C99/TZ extensions
+
+  // Because we handle each (non-internal) specifier in a separate call
+  // to strptime(), there is no way to group %C and %y together.  So we
+  // just skip the %C/%y case.
+#if 0
+  tp = reset;
+  EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp));
+  EXPECT_EQ(2004, convert(tp, tz).year());
+#endif
+
+  tp = reset;
+  EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp));
+  EXPECT_EQ(2, convert(tp, tz).month());
+  EXPECT_EQ(3, convert(tp, tz).day());
+  EXPECT_EQ(2004, convert(tp, tz).year());
+
+  EXPECT_TRUE(parse("%n", "\n", tz, &tp));
+
+  tp = reset;
+  EXPECT_TRUE(parse("%R", "03:44", tz, &tp));
+  EXPECT_EQ(3, convert(tp, tz).hour());
+  EXPECT_EQ(44, convert(tp, tz).minute());
+
+  EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp));
+
+  tp = reset;
+  EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp));
+  EXPECT_EQ(3, convert(tp, tz).hour());
+  EXPECT_EQ(44, convert(tp, tz).minute());
+  EXPECT_EQ(55, convert(tp, tz).second());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%s", "1234567890", tz, &tp));
+  EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+  // %s conversion, like %z/%Ez, pays no heed to the optional zone.
+  time_zone lax;
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
+  tp = reset;
+  EXPECT_TRUE(parse("%s", "1234567890", lax, &tp));
+  EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+  // This is most important when the time has the same YMDhms
+  // breakdown in the zone as some other time.  For example, ...
+  //  1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT)
+  //  1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST)
+  tp = reset;
+  EXPECT_TRUE(parse("%s", "1414917000", lax, &tp));
+  EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp);
+  tp = reset;
+  EXPECT_TRUE(parse("%s", "1414920600", lax, &tp));
+  EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp);
+#endif
+}
+
+TEST(Parse, LocaleSpecific) {
+  time_zone tz = utc_time_zone();
+  auto tp = chrono::system_clock::from_time_t(0);
+  const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+
+  // %a is parsed but ignored.
+  EXPECT_TRUE(parse("%a", "Mon", tz, &tp));
+
+  // %A is parsed but ignored.
+  EXPECT_TRUE(parse("%A", "Monday", tz, &tp));
+
+  tp = reset;
+  EXPECT_TRUE(parse("%b", "Feb", tz, &tp));
+  EXPECT_EQ(2, convert(tp, tz).month());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%B", "February", tz, &tp));
+  EXPECT_EQ(2, convert(tp, tz).month());
+
+  // %p is parsed but ignored if it's alone.  But it's used with %I.
+  EXPECT_TRUE(parse("%p", "AM", tz, &tp));
+  tp = reset;
+  EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp));
+  EXPECT_EQ(17, convert(tp, tz).hour());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp));
+  if (convert(tp, tz).month() == 2) {
+    EXPECT_EQ(3, convert(tp, tz).day());
+  } else {
+    EXPECT_EQ(2, convert(tp, tz).day());
+    EXPECT_EQ(3, convert(tp, tz).month());
+  }
+  EXPECT_EQ(2004, convert(tp, tz).year());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).hour());
+  EXPECT_EQ(44, convert(tp, tz).minute());
+  EXPECT_EQ(55, convert(tp, tz).second());
+
+#if defined(__linux__)
+  // SU/C99/TZ extensions
+
+  tp = reset;
+  EXPECT_TRUE(parse("%h", "Feb", tz, &tp));
+  EXPECT_EQ(2, convert(tp, tz).month());  // Equivalent to %b
+
+  tp = reset;
+  EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp));
+  EXPECT_EQ(17, convert(tp, tz).hour());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).hour());
+  EXPECT_EQ(44, convert(tp, tz).minute());
+  EXPECT_EQ(55, convert(tp, tz).second());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp));
+  EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp);
+
+  // Modified conversion specifiers %E_
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp));
+  EXPECT_EQ(2, convert(tp, tz).month());
+  EXPECT_EQ(3, convert(tp, tz).day());
+  EXPECT_EQ(2004, convert(tp, tz).year());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).hour());
+  EXPECT_EQ(44, convert(tp, tz).minute());
+  EXPECT_EQ(55, convert(tp, tz).second());
+
+  // %Ey, the year offset from %EC, doesn't really make sense alone as there
+  // is no way to represent it in tm_year (%EC is not simply the century).
+  // Yet, because we handle each (non-internal) specifier in a separate call
+  // to strptime(), there is no way to group %EC and %Ey either.  So we just
+  // skip the %EC and %Ey cases.
+
+  tp = reset;
+  EXPECT_TRUE(parse("%EY", "2004", tz, &tp));
+  EXPECT_EQ(2004, convert(tp, tz).year());
+
+  // Modified conversion specifiers %O_
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Od", "15", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).day());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Oe", "15", tz, &tp));
+  EXPECT_EQ(15, convert(tp, tz).day());  // Equivalent to %d
+
+  tp = reset;
+  EXPECT_TRUE(parse("%OH", "17", tz, &tp));
+  EXPECT_EQ(17, convert(tp, tz).hour());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%OI", "5", tz, &tp));
+  EXPECT_EQ(5, convert(tp, tz).hour());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Om", "11", tz, &tp));
+  EXPECT_EQ(11, convert(tp, tz).month());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%OM", "33", tz, &tp));
+  EXPECT_EQ(33, convert(tp, tz).minute());
+
+  tp = reset;
+  EXPECT_TRUE(parse("%OS", "55", tz, &tp));
+  EXPECT_EQ(55, convert(tp, tz).second());
+
+  // %OU is parsed but ignored.
+  EXPECT_TRUE(parse("%OU", "15", tz, &tp));
+
+  // %Ow is parsed but ignored.
+  EXPECT_TRUE(parse("%Ow", "2", tz, &tp));
+
+  // %OW is parsed but ignored.
+  EXPECT_TRUE(parse("%OW", "22", tz, &tp));
+
+  tp = reset;
+  EXPECT_TRUE(parse("%Oy", "04", tz, &tp));
+  EXPECT_EQ(2004, convert(tp, tz).year());
+#endif
+}
+
+TEST(Parse, ExtendedSeconds) {
+  const time_zone tz = utc_time_zone();
+  const time_point<chrono::nanoseconds> unix_epoch =
+      chrono::system_clock::from_time_t(0);
+
+  // All %E<prec>S cases are treated the same as %E*S on input.
+  auto precisions = {"*", "0", "1",  "2",  "3",  "4",  "5",  "6", "7",
+                     "8", "9", "10", "11", "12", "13", "14", "15"};
+  for (const std::string& prec : precisions) {
+    const std::string fmt = "%E" + prec + "S";
+    SCOPED_TRACE(fmt);
+    time_point<chrono::nanoseconds> tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "5", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.0", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.00", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.6", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.60", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.600", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.67", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.670", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "05.678", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp);
+  }
+
+  // Here is a "%E*S" case we got wrong for a while.  The fractional
+  // part of the first instant is less than 2^31 and was correctly
+  // parsed, while the second (and any subsecond field >=2^31) failed.
+  time_point<chrono::nanoseconds> tp = unix_epoch;
+  EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp));
+  EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+  tp = unix_epoch;
+  EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp));
+  EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+
+  // We should also be able to specify long strings of digits far
+  // beyond the current resolution and have them convert the same way.
+  tp = unix_epoch;
+  EXPECT_TRUE(parse(
+      "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
+      tz, &tp));
+  EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+}
+
+TEST(Parse, ExtendedSecondsScan) {
+  const time_zone tz = utc_time_zone();
+  time_point<chrono::nanoseconds> tp;
+  for (int ms = 0; ms < 1000; ms += 111) {
+    for (int us = 0; us < 1000; us += 27) {
+      const int micros = ms * 1000 + us;
+      for (int ns = 0; ns < 1000; ns += 9) {
+        const auto expected = chrono::system_clock::from_time_t(0) +
+                              chrono::nanoseconds(micros * 1000 + ns);
+        std::ostringstream oss;
+        oss << "0." << std::setfill('0') << std::setw(3);
+        oss << ms << std::setw(3) << us << std::setw(3) << ns;
+        const std::string input = oss.str();
+        EXPECT_TRUE(parse("%E*S", input, tz, &tp));
+        EXPECT_EQ(expected, tp) << input;
+      }
+    }
+  }
+}
+
+TEST(Parse, ExtendedSubeconds) {
+  const time_zone tz = utc_time_zone();
+  const time_point<chrono::nanoseconds> unix_epoch =
+      chrono::system_clock::from_time_t(0);
+
+  // All %E<prec>f cases are treated the same as %E*f on input.
+  auto precisions = {"*", "0", "1",  "2",  "3",  "4",  "5",  "6", "7",
+                     "8", "9", "10", "11", "12", "13", "14", "15"};
+  for (const std::string& prec : precisions) {
+    const std::string fmt = "%E" + prec + "f";
+    SCOPED_TRACE(fmt);
+    time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1);
+    EXPECT_TRUE(parse(fmt, "", tz, &tp));
+    EXPECT_EQ(unix_epoch, tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "6", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "60", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "600", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "67", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "670", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "678", tz, &tp));
+    EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp);
+    tp = unix_epoch;
+    EXPECT_TRUE(parse(fmt, "6789", tz, &tp));
+    EXPECT_EQ(
+        unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp);
+  }
+
+  // Here is a "%E*f" case we got wrong for a while.  The fractional
+  // part of the first instant is less than 2^31 and was correctly
+  // parsed, while the second (and any subsecond field >=2^31) failed.
+  time_point<chrono::nanoseconds> tp = unix_epoch;
+  EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp));
+  EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+  tp = unix_epoch;
+  EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp));
+  EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+
+  // We should also be able to specify long strings of digits far
+  // beyond the current resolution and have them convert the same way.
+  tp = unix_epoch;
+  EXPECT_TRUE(parse(
+      "%E*f", "214748364801234567890123456789012345678901234567890123456789",
+      tz, &tp));
+  EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+}
+
+TEST(Parse, ExtendedSubecondsScan) {
+  time_point<chrono::nanoseconds> tp;
+  const time_zone tz = utc_time_zone();
+  for (int ms = 0; ms < 1000; ms += 111) {
+    for (int us = 0; us < 1000; us += 27) {
+      const int micros = ms * 1000 + us;
+      for (int ns = 0; ns < 1000; ns += 9) {
+        std::ostringstream oss;
+        oss << std::setfill('0') << std::setw(3) << ms;
+        oss << std::setw(3) << us << std::setw(3) << ns;
+        const std::string nanos = oss.str();
+        const auto expected = chrono::system_clock::from_time_t(0) +
+                              chrono::nanoseconds(micros * 1000 + ns);
+        for (int ps = 0; ps < 1000; ps += 250) {
+          std::ostringstream oss;
+          oss << std::setfill('0') << std::setw(3) << ps;
+          const std::string input = nanos + oss.str() + "999";
+          EXPECT_TRUE(parse("%E*f", input, tz, &tp));
+          EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input;
+        }
+      }
+    }
+  }
+}
+
+TEST(Parse, ExtendedOffset) {
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  // %z against +-HHMM.
+  EXPECT_TRUE(parse("%z", "+0000", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%z", "-1234", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+  EXPECT_TRUE(parse("%z", "+1234", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+  EXPECT_FALSE(parse("%z", "-123", utc, &tp));
+
+  // %z against +-HH.
+  EXPECT_TRUE(parse("%z", "+00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%z", "-12", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%z", "+12", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+  EXPECT_FALSE(parse("%z", "-1", utc, &tp));
+
+  // %Ez against +-HH:MM.
+  EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+  EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
+
+  // %Ez against +-HHMM.
+  EXPECT_TRUE(parse("%Ez", "+0000", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "-1234", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "+1234", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+  EXPECT_FALSE(parse("%Ez", "-123", utc, &tp));
+
+  // %Ez against +-HH.
+  EXPECT_TRUE(parse("%Ez", "+00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "-12", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "+12", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+  EXPECT_FALSE(parse("%Ez", "-1", utc, &tp));
+}
+
+TEST(Parse, ExtendedSecondOffset) {
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  // %Ez against +-HH:MM:SS.
+  EXPECT_TRUE(parse("%Ez", "+00:00:00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "-12:34:56", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "+12:34:56", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+  EXPECT_FALSE(parse("%Ez", "-12:34:5", utc, &tp));
+
+  // %Ez against +-HHMMSS.
+  EXPECT_TRUE(parse("%Ez", "+000000", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "-123456", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+  EXPECT_TRUE(parse("%Ez", "+123456", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+  EXPECT_FALSE(parse("%Ez", "-12345", utc, &tp));
+
+  // %E*z against +-HH:MM:SS.
+  EXPECT_TRUE(parse("%E*z", "+00:00:00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "-12:34:56", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "+12:34:56", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+  EXPECT_FALSE(parse("%E*z", "-12:34:5", utc, &tp));
+
+  // %E*z against +-HHMMSS.
+  EXPECT_TRUE(parse("%E*z", "+000000", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "-123456", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "+123456", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+  EXPECT_FALSE(parse("%E*z", "-12345", utc, &tp));
+
+  // %E*z against +-HH:MM.
+  EXPECT_TRUE(parse("%E*z", "+00:00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "-12:34", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "+12:34", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+  EXPECT_FALSE(parse("%E*z", "-12:3", utc, &tp));
+
+  // %E*z against +-HHMM.
+  EXPECT_TRUE(parse("%E*z", "+0000", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "-1234", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "+1234", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+  EXPECT_FALSE(parse("%E*z", "-123", utc, &tp));
+
+  // %E*z against +-HH.
+  EXPECT_TRUE(parse("%E*z", "+00", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "-12", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+  EXPECT_TRUE(parse("%E*z", "+12", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+  EXPECT_FALSE(parse("%E*z", "-1", utc, &tp));
+}
+
+TEST(Parse, ExtendedYears) {
+  const time_zone utc = utc_time_zone();
+  const char e4y_fmt[] = "%E4Y%m%d";  // no separators
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  // %E4Y consumes exactly four chars, including any sign.
+  EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp);
+  EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp));
+  EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp);
+
+  // When the year is outside [-999:9999], the parse fails.
+  EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp));
+  EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp));
+}
+
+TEST(Parse, RFC3339Format) {
+  const time_zone tz = utc_time_zone();
+  time_point<chrono::nanoseconds> tp;
+  EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
+  ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
+
+  // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+  time_point<chrono::nanoseconds> tp2;
+  EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2));
+  EXPECT_EQ(tp, tp2);
+}
+
+TEST(Parse, MaxRange) {
+  const time_zone utc = utc_time_zone();
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  // tests the upper limit using +00:00 offset
+  EXPECT_TRUE(
+      parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp));
+  EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::max());
+  EXPECT_FALSE(
+      parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp));
+
+  // tests the upper limit using -01:00 offset
+  EXPECT_TRUE(
+      parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp));
+  EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::max());
+  EXPECT_FALSE(
+      parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp));
+
+  // tests the lower limit using +00:00 offset
+  EXPECT_TRUE(
+      parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp));
+  EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::min());
+  EXPECT_FALSE(
+      parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp));
+
+  // tests the lower limit using +01:00 offset
+  EXPECT_TRUE(
+      parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp));
+  EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::min());
+  EXPECT_FALSE(
+      parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
+
+  // tests max/min civil-second overflow
+  EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
+                     utc, &tp));
+  EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
+                     utc, &tp));
+
+  // TODO: Add tests that parsing times with fractional seconds overflow
+  // appropriately. This can't be done until cctz::parse() properly detects
+  // overflow when combining the chrono seconds and femto.
+}
+
+//
+// Roundtrip test for format()/parse().
+//
+
+TEST(FormatParse, RoundTrip) {
+  time_zone lax;
+  EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
+  const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax);
+  const auto subseconds = chrono::nanoseconds(654321);
+
+  // RFC3339, which renders subseconds.
+  {
+    time_point<chrono::nanoseconds> out;
+    const std::string s = format(RFC3339_full, in + subseconds, lax);
+    EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s;
+    EXPECT_EQ(in + subseconds, out);  // RFC3339_full includes %Ez
+  }
+
+  // RFC1123, which only does whole seconds.
+  {
+    time_point<chrono::nanoseconds> out;
+    const std::string s = format(RFC1123_full, in, lax);
+    EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s;
+    EXPECT_EQ(in, out);  // RFC1123_full includes %z
+  }
+
+#if defined(_WIN32) || defined(_WIN64)
+  // Initial investigations indicate the %c does not roundtrip on Windows.
+  // TODO: Figure out what is going on here (perhaps a locale problem).
+#else
+  // Even though we don't know what %c will produce, it should roundtrip,
+  // but only in the 0-offset timezone.
+  {
+    time_point<chrono::nanoseconds> out;
+    time_zone utc = utc_time_zone();
+    const std::string s = format("%c", in, utc);
+    EXPECT_TRUE(parse("%c", s, utc, &out)) << s;
+    EXPECT_EQ(in, out);
+  }
+#endif
+}
+
+TEST(FormatParse, RoundTripDistantFuture) {
+  const time_zone utc = utc_time_zone();
+  const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::max();
+  const std::string s = format(RFC3339_full, in, utc);
+  time_point<absl::time_internal::cctz::seconds> out;
+  EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
+  EXPECT_EQ(in, out);
+}
+
+TEST(FormatParse, RoundTripDistantPast) {
+  const time_zone utc = utc_time_zone();
+  const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::min();
+  const std::string s = format(RFC3339_full, in, utc);
+  time_point<absl::time_internal::cctz::seconds> out;
+  EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
+  EXPECT_EQ(in, out);
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc
new file mode 100644
index 0000000..380834a
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -0,0 +1,41 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "time_zone_if.h"
+#include "time_zone_info.h"
+#include "time_zone_libc.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
+  // Support "libc:localtime" and "libc:*" to access the legacy
+  // localtime and UTC support respectively from the C library.
+  if (name.compare(0, 5, "libc:") == 0) {
+    return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
+  }
+
+  // Otherwise use the "zoneinfo" implementation by default.
+  std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo);
+  if (!tz->Load(name)) tz.reset();
+  return std::unique_ptr<TimeZoneIf>(tz.release());
+}
+
+// Defined out-of-line to avoid emitting a weak vtable in all TUs.
+TimeZoneIf::~TimeZoneIf() {}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h
new file mode 100644
index 0000000..e4bd386
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_if.h
@@ -0,0 +1,72 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
+
+#include <chrono>
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// A simple interface used to hide time-zone complexities from time_zone::Impl.
+// Subclasses implement the functions for civil-time conversions in the zone.
+class TimeZoneIf {
+ public:
+  // A factory function for TimeZoneIf implementations.
+  static std::unique_ptr<TimeZoneIf> Load(const std::string& name);
+
+  virtual ~TimeZoneIf();
+
+  virtual time_zone::absolute_lookup BreakTime(
+      const time_point<seconds>& tp) const = 0;
+  virtual time_zone::civil_lookup MakeTime(
+      const civil_second& cs) const = 0;
+
+  virtual bool NextTransition(const time_point<seconds>& tp,
+                              time_zone::civil_transition* trans) const = 0;
+  virtual bool PrevTransition(const time_point<seconds>& tp,
+                              time_zone::civil_transition* trans) const = 0;
+
+  virtual std::string Version() const = 0;
+  virtual std::string Description() const = 0;
+
+ protected:
+  TimeZoneIf() {}
+};
+
+// Convert between time_point<seconds> and a count of seconds since the
+// Unix epoch.  We assume that the std::chrono::system_clock and the
+// Unix clock are second aligned, but not that they share an epoch.
+inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) {
+  return (tp - std::chrono::time_point_cast<seconds>(
+                   std::chrono::system_clock::from_time_t(0))).count();
+}
+inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
+  return std::chrono::time_point_cast<seconds>(
+             std::chrono::system_clock::from_time_t(0)) + seconds(t);
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
new file mode 100644
index 0000000..3062ccd
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -0,0 +1,108 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "time_zone_impl.h"
+
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "time_zone_fixed.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// time_zone::Impls are linked into a map to support fast lookup by name.
+using TimeZoneImplByName =
+    std::unordered_map<std::string, const time_zone::Impl*>;
+TimeZoneImplByName* time_zone_map = nullptr;
+
+// Mutual exclusion for time_zone_map.
+std::mutex time_zone_mutex;
+
+}  // namespace
+
+time_zone time_zone::Impl::UTC() {
+  return time_zone(UTCImpl());
+}
+
+bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
+  const time_zone::Impl* const utc_impl = UTCImpl();
+
+  // First check for UTC (which is never a key in time_zone_map).
+  auto offset = seconds::zero();
+  if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
+    *tz = time_zone(utc_impl);
+    return true;
+  }
+
+  // Then check, under a shared lock, whether the time zone has already
+  // been loaded. This is the common path. TODO: Move to shared_mutex.
+  {
+    std::lock_guard<std::mutex> lock(time_zone_mutex);
+    if (time_zone_map != nullptr) {
+      TimeZoneImplByName::const_iterator itr = time_zone_map->find(name);
+      if (itr != time_zone_map->end()) {
+        *tz = time_zone(itr->second);
+        return itr->second != utc_impl;
+      }
+    }
+  }
+
+  // Now check again, under an exclusive lock.
+  std::lock_guard<std::mutex> lock(time_zone_mutex);
+  if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
+  const Impl*& impl = (*time_zone_map)[name];
+  if (impl == nullptr) {
+    // The first thread in loads the new time zone.
+    Impl* new_impl = new Impl(name);
+    new_impl->zone_ = TimeZoneIf::Load(new_impl->name_);
+    if (new_impl->zone_ == nullptr) {
+      delete new_impl;  // free the nascent Impl
+      impl = utc_impl;  // and fallback to UTC
+    } else {
+      impl = new_impl;  // install new time zone
+    }
+  }
+  *tz = time_zone(impl);
+  return impl != utc_impl;
+}
+
+void time_zone::Impl::ClearTimeZoneMapTestOnly() {
+  std::lock_guard<std::mutex> lock(time_zone_mutex);
+  if (time_zone_map != nullptr) {
+    // Existing time_zone::Impl* entries are in the wild, so we simply
+    // leak them.  Future requests will result in reloading the data.
+    time_zone_map->clear();
+  }
+}
+
+time_zone::Impl::Impl(const std::string& name) : name_(name) {}
+
+const time_zone::Impl* time_zone::Impl::UTCImpl() {
+  static Impl* utc_impl = [] {
+    Impl* impl = new Impl("UTC");
+    impl->zone_ = TimeZoneIf::Load(impl->name_);  // never fails
+    return impl;
+  }();
+  return utc_impl;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h
new file mode 100644
index 0000000..14965ef
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -0,0 +1,90 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "time_zone_if.h"
+#include "time_zone_info.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// time_zone::Impl is the internal object referenced by a cctz::time_zone.
+class time_zone::Impl {
+ public:
+  // The UTC time zone. Also used for other time zones that fail to load.
+  static time_zone UTC();
+
+  // Load a named time zone. Returns false if the name is invalid, or if
+  // some other kind of error occurs. Note that loading "UTC" never fails.
+  static bool LoadTimeZone(const std::string& name, time_zone* tz);
+
+  // Clears the map of cached time zones.  Primarily for use in benchmarks
+  // that gauge the performance of loading/parsing the time-zone data.
+  static void ClearTimeZoneMapTestOnly();
+
+  // The primary key is the time-zone ID (e.g., "America/New_York").
+  const std::string& Name() const {
+    // TODO: It would nice if the zoneinfo data included the zone name.
+    return name_;
+  }
+
+  // Breaks a time_point down to civil-time components in this time zone.
+  time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const {
+    return zone_->BreakTime(tp);
+  }
+
+  // Converts the civil-time components in this time zone into a time_point.
+  // That is, the opposite of BreakTime(). The requested civil time may be
+  // ambiguous or illegal due to a change of UTC offset.
+  time_zone::civil_lookup MakeTime(const civil_second& cs) const {
+    return zone_->MakeTime(cs);
+  }
+
+  // Finds the time of the next/previous offset change in this time zone.
+  bool NextTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const {
+    return zone_->NextTransition(tp, trans);
+  }
+  bool PrevTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const {
+    return zone_->PrevTransition(tp, trans);
+  }
+
+  // Returns an implementation-defined version std::string for this time zone.
+  std::string Version() const { return zone_->Version(); }
+
+  // Returns an implementation-defined description of this time zone.
+  std::string Description() const { return zone_->Description(); }
+
+ private:
+  explicit Impl(const std::string& name);
+  static const Impl* UTCImpl();
+
+  const std::string name_;
+  std::unique_ptr<TimeZoneIf> zone_;
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
new file mode 100644
index 0000000..bf73635
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -0,0 +1,976 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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.
+
+// This file implements the TimeZoneIf interface using the "zoneinfo"
+// data provided by the IANA Time Zone Database (i.e., the only real game
+// in town).
+//
+// TimeZoneInfo represents the history of UTC-offset changes within a time
+// zone. Most changes are due to daylight-saving rules, but occasionally
+// shifts are made to the time-zone's base offset. The database only attempts
+// to be definitive for times since 1970, so be wary of local-time conversions
+// before that. Also, rule and zone-boundary changes are made at the whim
+// of governments, so the conversion of future times needs to be taken with
+// a grain of salt.
+//
+// For more information see tzfile(5), http://www.iana.org/time-zones, or
+// http://en.wikipedia.org/wiki/Zoneinfo.
+//
+// Note that we assume the proleptic Gregorian calendar and 60-second
+// minutes throughout.
+
+#include "time_zone_info.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "time_zone_fixed.h"
+#include "time_zone_posix.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+inline bool IsLeap(year_t year) {
+  return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
+}
+
+// The number of days in non-leap and leap years respectively.
+const std::int_least32_t kDaysPerYear[2] = {365, 366};
+
+// The day offsets of the beginning of each (1-based) month in non-leap and
+// leap years respectively (e.g., 335 days before December in a leap year).
+const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
+  {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+  {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
+};
+
+// We reject leap-second encoded zoneinfo and so assume 60-second minutes.
+const std::int_least32_t kSecsPerDay = 24 * 60 * 60;
+
+// 400-year chunks always have 146097 days (20871 weeks).
+const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay;
+
+// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay.
+const std::int_least32_t kSecsPerYear[2] = {
+  365 * kSecsPerDay,
+  366 * kSecsPerDay,
+};
+
+// Single-byte, unsigned numeric values are encoded directly.
+inline std::uint_fast8_t Decode8(const char* cp) {
+  return static_cast<std::uint_fast8_t>(*cp) & 0xff;
+}
+
+// Multi-byte, numeric values are encoded using a MSB first,
+// twos-complement representation. These helpers decode, from
+// the given address, 4-byte and 8-byte values respectively.
+// Note: If int_fastXX_t == intXX_t and this machine is not
+// twos complement, then there will be at least one input value
+// we cannot represent.
+std::int_fast32_t Decode32(const char* cp) {
+  std::uint_fast32_t v = 0;
+  for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++);
+  const std::int_fast32_t s32max = 0x7fffffff;
+  const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
+  if (v <= s32maxU) return static_cast<std::int_fast32_t>(v);
+  return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1;
+}
+
+std::int_fast64_t Decode64(const char* cp) {
+  std::uint_fast64_t v = 0;
+  for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++);
+  const std::int_fast64_t s64max = 0x7fffffffffffffff;
+  const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
+  if (v <= s64maxU) return static_cast<std::int_fast64_t>(v);
+  return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1;
+}
+
+// Generate a year-relative offset for a PosixTransition.
+std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
+                              const PosixTransition& pt) {
+  std::int_fast64_t days = 0;
+  switch (pt.date.fmt) {
+    case PosixTransition::J: {
+      days = pt.date.j.day;
+      if (!leap_year || days < kMonthOffsets[1][3]) days -= 1;
+      break;
+    }
+    case PosixTransition::N: {
+      days = pt.date.n.day;
+      break;
+    }
+    case PosixTransition::M: {
+      const bool last_week = (pt.date.m.week == 5);
+      days = kMonthOffsets[leap_year][pt.date.m.month + last_week];
+      const std::int_fast64_t weekday = (jan1_weekday + days) % 7;
+      if (last_week) {
+        days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1;
+      } else {
+        days += (pt.date.m.weekday + 7 - weekday) % 7;
+        days += (pt.date.m.week - 1) * 7;
+      }
+      break;
+    }
+  }
+  return (days * kSecsPerDay) + pt.time.offset;
+}
+
+inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) {
+  time_zone::civil_lookup cl;
+  cl.kind = time_zone::civil_lookup::UNIQUE;
+  cl.pre = cl.trans = cl.post = tp;
+  return cl;
+}
+
+inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) {
+  return MakeUnique(FromUnixSeconds(unix_time));
+}
+
+inline time_zone::civil_lookup MakeSkipped(const Transition& tr,
+                                           const civil_second& cs) {
+  time_zone::civil_lookup cl;
+  cl.kind = time_zone::civil_lookup::SKIPPED;
+  cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec));
+  cl.trans = FromUnixSeconds(tr.unix_time);
+  cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs));
+  return cl;
+}
+
+inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
+                                            const civil_second& cs) {
+  time_zone::civil_lookup cl;
+  cl.kind = time_zone::civil_lookup::REPEATED;
+  cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs));
+  cl.trans = FromUnixSeconds(tr.unix_time);
+  cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec));
+  return cl;
+}
+
+inline civil_second YearShift(const civil_second& cs, year_t shift) {
+  return civil_second(cs.year() + shift, cs.month(), cs.day(),
+                      cs.hour(), cs.minute(), cs.second());
+}
+
+}  // namespace
+
+// What (no leap-seconds) UTC+seconds zoneinfo would look like.
+bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
+  transition_types_.resize(1);
+  TransitionType& tt(transition_types_.back());
+  tt.utc_offset = static_cast<std::int_least32_t>(offset.count());
+  tt.is_dst = false;
+  tt.abbr_index = 0;
+
+  // We temporarily add some redundant, contemporary (2013 through 2023)
+  // transitions for performance reasons.  See TimeZoneInfo::LocalTime().
+  // TODO: Fix the performance issue and remove the extra transitions.
+  transitions_.clear();
+  transitions_.reserve(12);
+  for (const std::int_fast64_t unix_time : {
+           -(1LL << 59),  // BIG_BANG
+           1356998400LL,  // 2013-01-01T00:00:00+00:00
+           1388534400LL,  // 2014-01-01T00:00:00+00:00
+           1420070400LL,  // 2015-01-01T00:00:00+00:00
+           1451606400LL,  // 2016-01-01T00:00:00+00:00
+           1483228800LL,  // 2017-01-01T00:00:00+00:00
+           1514764800LL,  // 2018-01-01T00:00:00+00:00
+           1546300800LL,  // 2019-01-01T00:00:00+00:00
+           1577836800LL,  // 2020-01-01T00:00:00+00:00
+           1609459200LL,  // 2021-01-01T00:00:00+00:00
+           1640995200LL,  // 2022-01-01T00:00:00+00:00
+           1672531200LL,  // 2023-01-01T00:00:00+00:00
+           2147483647LL,  // 2^31 - 1
+       }) {
+    Transition& tr(*transitions_.emplace(transitions_.end()));
+    tr.unix_time = unix_time;
+    tr.type_index = 0;
+    tr.civil_sec = LocalTime(tr.unix_time, tt).cs;
+    tr.prev_civil_sec = tr.civil_sec - 1;
+  }
+
+  default_transition_type_ = 0;
+  abbreviations_ = FixedOffsetToAbbr(offset);
+  abbreviations_.append(1, '\0');  // add NUL
+  future_spec_.clear();  // never needed for a fixed-offset zone
+  extended_ = false;
+
+  tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
+  tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
+
+  transitions_.shrink_to_fit();
+  return true;
+}
+
+// Builds the in-memory header using the raw bytes from the file.
+bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
+  std::int_fast32_t v;
+  if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false;
+  timecnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false;
+  typecnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false;
+  charcnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false;
+  leapcnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
+  ttisstdcnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_ttisgmtcnt)) < 0) return false;
+  ttisgmtcnt = static_cast<std::size_t>(v);
+  return true;
+}
+
+// How many bytes of data are associated with this header. The result
+// depends upon whether this is a section with 4-byte or 8-byte times.
+std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
+  std::size_t len = 0;
+  len += (time_len + 1) * timecnt;  // unix_time + type_index
+  len += (4 + 1 + 1) * typecnt;     // utc_offset + is_dst + abbr_index
+  len += 1 * charcnt;               // abbreviations
+  len += (time_len + 4) * leapcnt;  // leap-time + TAI-UTC
+  len += 1 * ttisstdcnt;            // UTC/local indicators
+  len += 1 * ttisgmtcnt;            // standard/wall indicators
+  return len;
+}
+
+// Check that the TransitionType has the expected offset/is_dst/abbreviation.
+void TimeZoneInfo::CheckTransition(const std::string& name,
+                                   const TransitionType& tt,
+                                   std::int_fast32_t offset, bool is_dst,
+                                   const std::string& abbr) const {
+  if (tt.utc_offset != offset || tt.is_dst != is_dst ||
+      &abbreviations_[tt.abbr_index] != abbr) {
+    std::clog << name << ": Transition"
+              << " offset=" << tt.utc_offset << "/"
+              << (tt.is_dst ? "DST" : "STD")
+              << "/abbr=" << &abbreviations_[tt.abbr_index]
+              << " does not match POSIX spec '" << future_spec_ << "'\n";
+  }
+}
+
+// zic(8) can generate no-op transitions when a zone changes rules at an
+// instant when there is actually no discontinuity.  So we check whether
+// two transitions have equivalent types (same offset/is_dst/abbr).
+bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
+                                    std::uint_fast8_t tt2_index) const {
+  if (tt1_index == tt2_index) return true;
+  const TransitionType& tt1(transition_types_[tt1_index]);
+  const TransitionType& tt2(transition_types_[tt2_index]);
+  if (tt1.is_dst != tt2.is_dst) return false;
+  if (tt1.utc_offset != tt2.utc_offset) return false;
+  if (tt1.abbr_index != tt2.abbr_index) return false;
+  return true;
+}
+
+// Use the POSIX-TZ-environment-variable-style std::string to handle times
+// in years after the last transition stored in the zoneinfo data.
+void TimeZoneInfo::ExtendTransitions(const std::string& name,
+                                     const Header& hdr) {
+  extended_ = false;
+  bool extending = !future_spec_.empty();
+
+  PosixTimeZone posix;
+  if (extending && !ParsePosixSpec(future_spec_, &posix)) {
+    std::clog << name << ": Failed to parse '" << future_spec_ << "'\n";
+    extending = false;
+  }
+
+  if (extending && posix.dst_abbr.empty()) {  // std only
+    // The future specification should match the last/default transition,
+    // and that means that handling the future will fall out naturally.
+    std::uint_fast8_t index = default_transition_type_;
+    if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index;
+    const TransitionType& tt(transition_types_[index]);
+    CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr);
+    extending = false;
+  }
+
+  if (extending && hdr.timecnt < 2) {
+    std::clog << name << ": Too few transitions for POSIX spec\n";
+    extending = false;
+  }
+
+  if (!extending) {
+    // Ensure that there is always a transition in the second half of the
+    // time line (the BIG_BANG transition is in the first half) so that the
+    // signed difference between a civil_second and the civil_second of its
+    // previous transition is always representable, without overflow.
+    const Transition& last(transitions_.back());
+    if (last.unix_time < 0) {
+      const std::uint_fast8_t type_index = last.type_index;
+      Transition& tr(*transitions_.emplace(transitions_.end()));
+      tr.unix_time = 2147483647;  // 2038-01-19T03:14:07+00:00
+      tr.type_index = type_index;
+    }
+    return;  // last transition wins
+  }
+
+  // Extend the transitions for an additional 400 years using the
+  // future specification. Years beyond those can be handled by
+  // mapping back to a cycle-equivalent year within that range.
+  // zic(8) should probably do this so that we don't have to.
+  // TODO: Reduce the extension by the number of compatible
+  // transitions already in place.
+  transitions_.reserve(hdr.timecnt + 400 * 2 + 1);
+  transitions_.resize(hdr.timecnt + 400 * 2);
+  extended_ = true;
+
+  // The future specification should match the last two transitions,
+  // and those transitions should have different is_dst flags.  Note
+  // that nothing says the UTC offset used by the is_dst transition
+  // must be greater than that used by the !is_dst transition.  (See
+  // Europe/Dublin, for example.)
+  const Transition* tr0 = &transitions_[hdr.timecnt - 1];
+  const Transition* tr1 = &transitions_[hdr.timecnt - 2];
+  const TransitionType* tt0 = &transition_types_[tr0->type_index];
+  const TransitionType* tt1 = &transition_types_[tr1->type_index];
+  const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1);
+  const TransitionType& std(tt0->is_dst ? *tt1 : *tt0);
+  CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr);
+  CheckTransition(name, std, posix.std_offset, false, posix.std_abbr);
+
+  // Add the transitions to tr1 and back to tr0 for each extra year.
+  last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year();
+  bool leap_year = IsLeap(last_year_);
+  const civil_day jan1(last_year_, 1, 1);
+  std::int_fast64_t jan1_time = civil_second(jan1) - civil_second();
+  int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7;
+  Transition* tr = &transitions_[hdr.timecnt];  // next trans to fill
+  if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) {
+    // Add a single extra transition to align to a calendar year.
+    transitions_.resize(transitions_.size() + 1);
+    assert(tr == &transitions_[hdr.timecnt]);  // no reallocation
+    const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
+    std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
+    tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
+    tr++->type_index = tr1->type_index;
+    tr0 = &transitions_[hdr.timecnt];
+    tr1 = &transitions_[hdr.timecnt - 1];
+    tt0 = &transition_types_[tr0->type_index];
+    tt1 = &transition_types_[tr1->type_index];
+  }
+  const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
+  const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end);
+  for (const year_t limit = last_year_ + 400; last_year_ < limit;) {
+    last_year_ += 1;  // an additional year of generated transitions
+    jan1_time += kSecsPerYear[leap_year];
+    jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
+    leap_year = !leap_year && IsLeap(last_year_);
+    std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
+    tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
+    tr++->type_index = tr1->type_index;
+    std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0);
+    tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset;
+    tr++->type_index = tr0->type_index;
+  }
+  assert(tr == &transitions_[0] + transitions_.size());
+}
+
+bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
+  // Read and validate the header.
+  tzhead tzh;
+  if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
+    return false;
+  if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
+    return false;
+  Header hdr;
+  if (!hdr.Build(tzh))
+    return false;
+  std::size_t time_len = 4;
+  if (tzh.tzh_version[0] != '\0') {
+    // Skip the 4-byte data.
+    if (zip->Skip(hdr.DataLength(time_len)) != 0)
+      return false;
+    // Read and validate the header for the 8-byte data.
+    if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
+      return false;
+    if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
+      return false;
+    if (tzh.tzh_version[0] == '\0')
+      return false;
+    if (!hdr.Build(tzh))
+      return false;
+    time_len = 8;
+  }
+  if (hdr.typecnt == 0)
+    return false;
+  if (hdr.leapcnt != 0) {
+    // This code assumes 60-second minutes so we do not want
+    // the leap-second encoded zoneinfo. We could reverse the
+    // compensation, but the "right" encoding is rarely used
+    // so currently we simply reject such data.
+    return false;
+  }
+  if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
+    return false;
+  if (hdr.ttisgmtcnt != 0 && hdr.ttisgmtcnt != hdr.typecnt)
+    return false;
+
+  // Read the data into a local buffer.
+  std::size_t len = hdr.DataLength(time_len);
+  std::vector<char> tbuf(len);
+  if (zip->Read(tbuf.data(), len) != len)
+    return false;
+  const char* bp = tbuf.data();
+
+  // Decode and validate the transitions.
+  transitions_.reserve(hdr.timecnt + 2);  // We might add a couple.
+  transitions_.resize(hdr.timecnt);
+  for (std::size_t i = 0; i != hdr.timecnt; ++i) {
+    transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
+    bp += time_len;
+    if (i != 0) {
+      // Check that the transitions are ordered by time (as zic guarantees).
+      if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
+        return false;  // out of order
+    }
+  }
+  bool seen_type_0 = false;
+  for (std::size_t i = 0; i != hdr.timecnt; ++i) {
+    transitions_[i].type_index = Decode8(bp++);
+    if (transitions_[i].type_index >= hdr.typecnt)
+      return false;
+    if (transitions_[i].type_index == 0)
+      seen_type_0 = true;
+  }
+
+  // Decode and validate the transition types.
+  transition_types_.resize(hdr.typecnt);
+  for (std::size_t i = 0; i != hdr.typecnt; ++i) {
+    transition_types_[i].utc_offset =
+        static_cast<std::int_least32_t>(Decode32(bp));
+    if (transition_types_[i].utc_offset >= kSecsPerDay ||
+        transition_types_[i].utc_offset <= -kSecsPerDay)
+      return false;
+    bp += 4;
+    transition_types_[i].is_dst = (Decode8(bp++) != 0);
+    transition_types_[i].abbr_index = Decode8(bp++);
+    if (transition_types_[i].abbr_index >= hdr.charcnt)
+      return false;
+  }
+
+  // Determine the before-first-transition type.
+  default_transition_type_ = 0;
+  if (seen_type_0 && hdr.timecnt != 0) {
+    std::uint_fast8_t index = 0;
+    if (transition_types_[0].is_dst) {
+      index = transitions_[0].type_index;
+      while (index != 0 && transition_types_[index].is_dst)
+        --index;
+    }
+    while (index != hdr.typecnt && transition_types_[index].is_dst)
+      ++index;
+    if (index != hdr.typecnt)
+      default_transition_type_ = index;
+  }
+
+  // Copy all the abbreviations.
+  abbreviations_.assign(bp, hdr.charcnt);
+  bp += hdr.charcnt;
+
+  // Skip the unused portions. We've already dispensed with leap-second
+  // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when
+  // interpreting a POSIX spec that does not include start/end rules, and
+  // that isn't the case here (see "zic -p").
+  bp += (8 + 4) * hdr.leapcnt;  // leap-time + TAI-UTC
+  bp += 1 * hdr.ttisstdcnt;     // UTC/local indicators
+  bp += 1 * hdr.ttisgmtcnt;     // standard/wall indicators
+  assert(bp == tbuf.data() + tbuf.size());
+
+  future_spec_.clear();
+  if (tzh.tzh_version[0] != '\0') {
+    // Snarf up the NL-enclosed future POSIX spec. Note
+    // that version '3' files utilize an extended format.
+    auto get_char = [](ZoneInfoSource* zip) -> int {
+      unsigned char ch;  // all non-EOF results are positive
+      return (zip->Read(&ch, 1) == 1) ? ch : EOF;
+    };
+    if (get_char(zip) != '\n')
+      return false;
+    for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
+      if (c == EOF)
+        return false;
+      future_spec_.push_back(static_cast<char>(c));
+    }
+  }
+
+  // We don't check for EOF so that we're forwards compatible.
+
+  // If we did not find version information during the standard loading
+  // process (as of tzh_version '3' that is unsupported), then ask the
+  // ZoneInfoSource for any out-of-bound version std::string it may be privy to.
+  if (version_.empty()) {
+    version_ = zip->Version();
+  }
+
+  // Trim redundant transitions. zic may have added these to work around
+  // differences between the glibc and reference implementations (see
+  // zic.c:dontmerge) and the Qt library (see zic.c:WORK_AROUND_QTBUG_53071).
+  // For us, they just get in the way when we do future_spec_ extension.
+  while (hdr.timecnt > 1) {
+    if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index,
+                          transitions_[hdr.timecnt - 2].type_index)) {
+      break;
+    }
+    hdr.timecnt -= 1;
+  }
+  transitions_.resize(hdr.timecnt);
+
+  // Ensure that there is always a transition in the first half of the
+  // time line (the second half is handled in ExtendTransitions()) so that
+  // the signed difference between a civil_second and the civil_second of
+  // its previous transition is always representable, without overflow.
+  // A contemporary zic will usually have already done this for us.
+  if (transitions_.empty() || transitions_.front().unix_time >= 0) {
+    Transition& tr(*transitions_.emplace(transitions_.begin()));
+    tr.unix_time = -(1LL << 59);  // see tz/zic.c "BIG_BANG"
+    tr.type_index = default_transition_type_;
+    hdr.timecnt += 1;
+  }
+
+  // Extend the transitions using the future specification.
+  ExtendTransitions(name, hdr);
+
+  // Compute the local civil time for each transition and the preceding
+  // second. These will be used for reverse conversions in MakeTime().
+  const TransitionType* ttp = &transition_types_[default_transition_type_];
+  for (std::size_t i = 0; i != transitions_.size(); ++i) {
+    Transition& tr(transitions_[i]);
+    tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1;
+    ttp = &transition_types_[tr.type_index];
+    tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs;
+    if (i != 0) {
+      // Check that the transitions are ordered by civil time. Essentially
+      // this means that an offset change cannot cross another such change.
+      // No one does this in practice, and we depend on it in MakeTime().
+      if (!Transition::ByCivilTime()(transitions_[i - 1], tr))
+        return false;  // out of order
+    }
+  }
+
+  // Compute the maximum/minimum civil times that can be converted to a
+  // time_point<seconds> for each of the zone's transition types.
+  for (auto& tt : transition_types_) {
+    tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
+    tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
+  }
+
+  transitions_.shrink_to_fit();
+  return true;
+}
+
+namespace {
+
+// fopen(3) adaptor.
+inline FILE* FOpen(const char* path, const char* mode) {
+#if defined(_MSC_VER)
+  FILE* fp;
+  if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
+  return fp;
+#else
+  return fopen(path, mode);  // TODO: Enable the close-on-exec flag.
+#endif
+}
+
+// A stdio(3)-backed implementation of ZoneInfoSource.
+class FileZoneInfoSource : public ZoneInfoSource {
+ public:
+  static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
+
+  std::size_t Read(void* ptr, std::size_t size) override {
+    size = std::min(size, len_);
+    std::size_t nread = fread(ptr, 1, size, fp_.get());
+    len_ -= nread;
+    return nread;
+  }
+  int Skip(std::size_t offset) override {
+    offset = std::min(offset, len_);
+    int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR);
+    if (rc == 0) len_ -= offset;
+    return rc;
+  }
+  std::string Version() const override {
+    // TODO: It would nice if the zoneinfo data included the tzdb version.
+    return std::string();
+  }
+
+ protected:
+  explicit FileZoneInfoSource(
+      FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max())
+      : fp_(fp, fclose), len_(len) {}
+
+ private:
+  std::unique_ptr<FILE, int(*)(FILE*)> fp_;
+  std::size_t len_;
+};
+
+std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
+    const std::string& name) {
+  // Use of the "file:" prefix is intended for testing purposes only.
+  if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
+
+  // Map the time-zone name to a path name.
+  std::string path;
+  if (name.empty() || name[0] != '/') {
+    const char* tzdir = "/usr/share/zoneinfo";
+    char* tzdir_env = nullptr;
+#if defined(_MSC_VER)
+    _dupenv_s(&tzdir_env, nullptr, "TZDIR");
+#else
+    tzdir_env = std::getenv("TZDIR");
+#endif
+    if (tzdir_env && *tzdir_env) tzdir = tzdir_env;
+    path += tzdir;
+    path += '/';
+#if defined(_MSC_VER)
+    free(tzdir_env);
+#endif
+  }
+  path += name;
+
+  // Open the zoneinfo file.
+  FILE* fp = FOpen(path.c_str(), "rb");
+  if (fp == nullptr) return nullptr;
+  std::size_t length = 0;
+  if (fseek(fp, 0, SEEK_END) == 0) {
+    long pos = ftell(fp);
+    if (pos >= 0) {
+      length = static_cast<std::size_t>(pos);
+    }
+    rewind(fp);
+  }
+  return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length));
+}
+
+class AndroidZoneInfoSource : public FileZoneInfoSource {
+ public:
+  static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
+  std::string Version() const override { return version_; }
+
+ private:
+  explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers)
+      : FileZoneInfoSource(fp, len), version_(vers) {}
+  std::string version_;
+};
+
+std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
+    const std::string& name) {
+  // Use of the "file:" prefix is intended for testing purposes only.
+  if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
+
+#if defined(__ANDROID__)
+  // See Android's libc/tzcode/bionic.cpp for additional information.
+  for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
+                             "/system/usr/share/zoneinfo/tzdata"}) {
+    std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose);
+    if (fp.get() == nullptr) continue;
+
+    char hbuf[24];  // covers header.zonetab_offset too
+    if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
+    if (strncmp(hbuf, "tzdata", 6) != 0) continue;
+    const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
+    const std::int_fast32_t index_offset = Decode32(hbuf + 12);
+    const std::int_fast32_t data_offset = Decode32(hbuf + 16);
+    if (index_offset < 0 || data_offset < index_offset) continue;
+    if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
+      continue;
+
+    char ebuf[52];  // covers entry.unused too
+    const std::size_t index_size =
+        static_cast<std::size_t>(data_offset - index_offset);
+    const std::size_t zonecnt = index_size / sizeof(ebuf);
+    if (zonecnt * sizeof(ebuf) != index_size) continue;
+    for (std::size_t i = 0; i != zonecnt; ++i) {
+      if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
+      const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
+      const std::int_fast32_t length = Decode32(ebuf + 44);
+      if (start < 0 || length < 0) break;
+      ebuf[40] = '\0';  // ensure zone name is NUL terminated
+      if (strcmp(name.c_str(), ebuf) == 0) {
+        if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
+        return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
+            fp.release(), static_cast<std::size_t>(length), vers));
+      }
+    }
+  }
+#endif  // __ANDROID__
+  return nullptr;
+}
+
+}  // namespace
+
+bool TimeZoneInfo::Load(const std::string& name) {
+  // We can ensure that the loading of UTC or any other fixed-offset
+  // zone never fails because the simple, fixed-offset state can be
+  // internally generated. Note that this depends on our choice to not
+  // accept leap-second encoded ("right") zoneinfo.
+  auto offset = seconds::zero();
+  if (FixedOffsetFromName(name, &offset)) {
+    return ResetToBuiltinUTC(offset);
+  }
+
+  // Find and use a ZoneInfoSource to load the named zone.
+  auto zip = cctz_extension::zone_info_source_factory(
+      name, [](const std::string& name) -> std::unique_ptr<ZoneInfoSource> {
+        if (auto zip = FileZoneInfoSource::Open(name)) return zip;
+        if (auto zip = AndroidZoneInfoSource::Open(name)) return zip;
+        return nullptr;
+      });
+  return zip != nullptr && Load(name, zip.get());
+}
+
+// BreakTime() translation for a particular transition type.
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(
+    std::int_fast64_t unix_time, const TransitionType& tt) const {
+  // A civil time in "+offset" looks like (time+offset) in UTC.
+  // Note: We perform two additions in the civil_second domain to
+  // sidestep the chance of overflow in (unix_time + tt.utc_offset).
+  return {(civil_second() + unix_time) + tt.utc_offset,
+          tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
+}
+
+// BreakTime() translation for a particular transition.
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(
+    std::int_fast64_t unix_time, const Transition& tr) const {
+  const TransitionType& tt = transition_types_[tr.type_index];
+  // Note: (unix_time - tr.unix_time) will never overflow as we
+  // have ensured that there is always a "nearby" transition.
+  return {tr.civil_sec + (unix_time - tr.unix_time),  // TODO: Optimize.
+          tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
+}
+
+// MakeTime() translation with a conversion-preserving +N * 400-year shift.
+time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
+                                                year_t c4_shift) const {
+  assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_);
+  time_zone::civil_lookup cl = MakeTime(cs);
+  if (c4_shift > seconds::max().count() / kSecsPer400Years) {
+    cl.pre = cl.trans = cl.post = time_point<seconds>::max();
+  } else {
+    const auto offset = seconds(c4_shift * kSecsPer400Years);
+    const auto limit = time_point<seconds>::max() - offset;
+    for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) {
+      if (*tp > limit) {
+        *tp = time_point<seconds>::max();
+      } else {
+        *tp += offset;
+      }
+    }
+  }
+  return cl;
+}
+
+time_zone::absolute_lookup TimeZoneInfo::BreakTime(
+    const time_point<seconds>& tp) const {
+  std::int_fast64_t unix_time = ToUnixSeconds(tp);
+  const std::size_t timecnt = transitions_.size();
+  assert(timecnt != 0);  // We always add a transition.
+
+  if (unix_time < transitions_[0].unix_time) {
+    return LocalTime(unix_time, transition_types_[default_transition_type_]);
+  }
+  if (unix_time >= transitions_[timecnt - 1].unix_time) {
+    // After the last transition. If we extended the transitions using
+    // future_spec_, shift back to a supported year using the 400-year
+    // cycle of calendaric equivalence and then compensate accordingly.
+    if (extended_) {
+      const std::int_fast64_t diff =
+          unix_time - transitions_[timecnt - 1].unix_time;
+      const year_t shift = diff / kSecsPer400Years + 1;
+      const auto d = seconds(shift * kSecsPer400Years);
+      time_zone::absolute_lookup al = BreakTime(tp - d);
+      al.cs = YearShift(al.cs, shift * 400);
+      return al;
+    }
+    return LocalTime(unix_time, transitions_[timecnt - 1]);
+  }
+
+  const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
+  if (0 < hint && hint < timecnt) {
+    if (transitions_[hint - 1].unix_time <= unix_time) {
+      if (unix_time < transitions_[hint].unix_time) {
+        return LocalTime(unix_time, transitions_[hint - 1]);
+      }
+    }
+  }
+
+  const Transition target = {unix_time, 0, civil_second(), civil_second()};
+  const Transition* begin = &transitions_[0];
+  const Transition* tr = std::upper_bound(begin, begin + timecnt, target,
+                                          Transition::ByUnixTime());
+  local_time_hint_.store(static_cast<std::size_t>(tr - begin),
+                         std::memory_order_relaxed);
+  return LocalTime(unix_time, *--tr);
+}
+
+time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
+  const std::size_t timecnt = transitions_.size();
+  assert(timecnt != 0);  // We always add a transition.
+
+  // Find the first transition after our target civil time.
+  const Transition* tr = nullptr;
+  const Transition* begin = &transitions_[0];
+  const Transition* end = begin + timecnt;
+  if (cs < begin->civil_sec) {
+    tr = begin;
+  } else if (cs >= transitions_[timecnt - 1].civil_sec) {
+    tr = end;
+  } else {
+    const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed);
+    if (0 < hint && hint < timecnt) {
+      if (transitions_[hint - 1].civil_sec <= cs) {
+        if (cs < transitions_[hint].civil_sec) {
+          tr = begin + hint;
+        }
+      }
+    }
+    if (tr == nullptr) {
+      const Transition target = {0, 0, cs, civil_second()};
+      tr = std::upper_bound(begin, end, target, Transition::ByCivilTime());
+      time_local_hint_.store(static_cast<std::size_t>(tr - begin),
+                             std::memory_order_relaxed);
+    }
+  }
+
+  if (tr == begin) {
+    if (tr->prev_civil_sec >= cs) {
+      // Before first transition, so use the default offset.
+      const TransitionType& tt(transition_types_[default_transition_type_]);
+      if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min());
+      return MakeUnique(cs - (civil_second() + tt.utc_offset));
+    }
+    // tr->prev_civil_sec < cs < tr->civil_sec
+    return MakeSkipped(*tr, cs);
+  }
+
+  if (tr == end) {
+    if (cs > (--tr)->prev_civil_sec) {
+      // After the last transition. If we extended the transitions using
+      // future_spec_, shift back to a supported year using the 400-year
+      // cycle of calendaric equivalence and then compensate accordingly.
+      if (extended_ && cs.year() > last_year_) {
+        const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
+        return TimeLocal(YearShift(cs, shift * -400), shift);
+      }
+      const TransitionType& tt(transition_types_[tr->type_index]);
+      if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
+      return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
+    }
+    // tr->civil_sec <= cs <= tr->prev_civil_sec
+    return MakeRepeated(*tr, cs);
+  }
+
+  if (tr->prev_civil_sec < cs) {
+    // tr->prev_civil_sec < cs < tr->civil_sec
+    return MakeSkipped(*tr, cs);
+  }
+
+  if (cs <= (--tr)->prev_civil_sec) {
+    // tr->civil_sec <= cs <= tr->prev_civil_sec
+    return MakeRepeated(*tr, cs);
+  }
+
+  // In between transitions.
+  return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
+}
+
+std::string TimeZoneInfo::Version() const {
+  return version_;
+}
+
+std::string TimeZoneInfo::Description() const {
+  std::ostringstream oss;
+  oss << "#trans=" << transitions_.size();
+  oss << " #types=" << transition_types_.size();
+  oss << " spec='" << future_spec_ << "'";
+  return oss.str();
+}
+
+bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
+                                  time_zone::civil_transition* trans) const {
+  if (transitions_.empty()) return false;
+  const Transition* begin = &transitions_[0];
+  const Transition* end = begin + transitions_.size();
+  if (begin->unix_time <= -(1LL << 59)) {
+    // Do not report the BIG_BANG found in recent zoneinfo data as it is
+    // really a sentinel, not a transition.  See tz/zic.c.
+    ++begin;
+  }
+  std::int_fast64_t unix_time = ToUnixSeconds(tp);
+  const Transition target = { unix_time };
+  const Transition* tr = std::upper_bound(begin, end, target,
+                                          Transition::ByUnixTime());
+  for (; tr != end; ++tr) {  // skip no-op transitions
+    std::uint_fast8_t prev_type_index =
+        (tr == begin) ? default_transition_type_ : tr[-1].type_index;
+    if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
+  }
+  // When tr == end we return false, ignoring future_spec_.
+  if (tr == end) return false;
+  trans->from = tr->prev_civil_sec + 1;
+  trans->to = tr->civil_sec;
+  return true;
+}
+
+bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
+                                  time_zone::civil_transition* trans) const {
+  if (transitions_.empty()) return false;
+  const Transition* begin = &transitions_[0];
+  const Transition* end = begin + transitions_.size();
+  if (begin->unix_time <= -(1LL << 59)) {
+    // Do not report the BIG_BANG found in recent zoneinfo data as it is
+    // really a sentinel, not a transition.  See tz/zic.c.
+    ++begin;
+  }
+  std::int_fast64_t unix_time = ToUnixSeconds(tp);
+  if (FromUnixSeconds(unix_time) != tp) {
+    if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) {
+      if (end == begin) return false;  // Ignore future_spec_.
+      trans->from = (--end)->prev_civil_sec + 1;
+      trans->to = end->civil_sec;
+      return true;
+    }
+    unix_time += 1;  // ceils
+  }
+  const Transition target = { unix_time };
+  const Transition* tr = std::lower_bound(begin, end, target,
+                                          Transition::ByUnixTime());
+  for (; tr != begin; --tr) {  // skip no-op transitions
+    std::uint_fast8_t prev_type_index =
+        (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
+    if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
+  }
+  // When tr == end we return the "last" transition, ignoring future_spec_.
+  if (tr == begin) return false;
+  trans->from = (--tr)->prev_civil_sec + 1;
+  trans->to = tr->civil_sec;
+  return true;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h
new file mode 100644
index 0000000..958e9b6
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -0,0 +1,136 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
+#include "time_zone_if.h"
+#include "tzfile.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// A transition to a new UTC offset.
+struct Transition {
+  std::int_least64_t unix_time;   // the instant of this transition
+  std::uint_least8_t type_index;  // index of the transition type
+  civil_second civil_sec;         // local civil time of transition
+  civil_second prev_civil_sec;    // local civil time one second earlier
+
+  struct ByUnixTime {
+    inline bool operator()(const Transition& lhs, const Transition& rhs) const {
+      return lhs.unix_time < rhs.unix_time;
+    }
+  };
+  struct ByCivilTime {
+    inline bool operator()(const Transition& lhs, const Transition& rhs) const {
+      return lhs.civil_sec < rhs.civil_sec;
+    }
+  };
+};
+
+// The characteristics of a particular transition.
+struct TransitionType {
+  std::int_least32_t utc_offset;  // the new prevailing UTC offset
+  civil_second civil_max;         // max convertible civil time for offset
+  civil_second civil_min;         // min convertible civil time for offset
+  bool is_dst;                    // did we move into daylight-saving time
+  std::uint_least8_t abbr_index;  // index of the new abbreviation
+};
+
+// A time zone backed by the IANA Time Zone Database (zoneinfo).
+class TimeZoneInfo : public TimeZoneIf {
+ public:
+  TimeZoneInfo() = default;
+  TimeZoneInfo(const TimeZoneInfo&) = delete;
+  TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
+
+  // Loads the zoneinfo for the given name, returning true if successful.
+  bool Load(const std::string& name);
+
+  // TimeZoneIf implementations.
+  time_zone::absolute_lookup BreakTime(
+      const time_point<seconds>& tp) const override;
+  time_zone::civil_lookup MakeTime(
+      const civil_second& cs) const override;
+  bool NextTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  bool PrevTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  std::string Version() const override;
+  std::string Description() const override;
+
+ private:
+  struct Header {  // counts of:
+    std::size_t timecnt;     // transition times
+    std::size_t typecnt;     // transition types
+    std::size_t charcnt;     // zone abbreviation characters
+    std::size_t leapcnt;     // leap seconds (we expect none)
+    std::size_t ttisstdcnt;  // UTC/local indicators (unused)
+    std::size_t ttisgmtcnt;  // standard/wall indicators (unused)
+
+    bool Build(const tzhead& tzh);
+    std::size_t DataLength(std::size_t time_len) const;
+  };
+
+  void CheckTransition(const std::string& name, const TransitionType& tt,
+                       std::int_fast32_t offset, bool is_dst,
+                       const std::string& abbr) const;
+  bool EquivTransitions(std::uint_fast8_t tt1_index,
+                        std::uint_fast8_t tt2_index) const;
+  void ExtendTransitions(const std::string& name, const Header& hdr);
+
+  bool ResetToBuiltinUTC(const seconds& offset);
+  bool Load(const std::string& name, ZoneInfoSource* zip);
+
+  // Helpers for BreakTime() and MakeTime().
+  time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
+                                       const TransitionType& tt) const;
+  time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
+                                       const Transition& tr) const;
+  time_zone::civil_lookup TimeLocal(const civil_second& cs,
+                                    year_t c4_shift) const;
+
+  std::vector<Transition> transitions_;  // ordered by unix_time and civil_sec
+  std::vector<TransitionType> transition_types_;  // distinct transition types
+  std::uint_fast8_t default_transition_type_;  // for before first transition
+  std::string abbreviations_;  // all the NUL-terminated abbreviations
+
+  std::string version_;      // the tzdata version if available
+  std::string future_spec_;  // for after the last zic transition
+  bool extended_;            // future_spec_ was used to generate transitions
+  year_t last_year_;         // the final year of the generated transitions
+
+  // We remember the transitions found during the last BreakTime() and
+  // MakeTime() calls. If the next request is for the same transition we
+  // will avoid re-searching.
+  mutable std::atomic<std::size_t> local_time_hint_ = {};  // BreakTime() hint
+  mutable std::atomic<std::size_t> time_local_hint_ = {};  // MakeTime() hint
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
new file mode 100644
index 0000000..074c8d0
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -0,0 +1,162 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 defined(_WIN32) || defined(_WIN64)
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include "time_zone_libc.h"
+
+#include <chrono>
+#include <ctime>
+#include <tuple>
+#include <utility>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// .first is seconds east of UTC; .second is the time-zone abbreviation.
+using OffsetAbbr = std::pair<int, const char*>;
+
+// Defines a function that can be called as follows:
+//
+//   std::tm tm = ...;
+//   OffsetAbbr off_abbr = get_offset_abbr(tm);
+//
+#if defined(_WIN32) || defined(_WIN64)
+// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
+OffsetAbbr get_offset_abbr(const std::tm& tm) {
+  const bool is_dst = tm.tm_isdst > 0;
+  const int off = _timezone + (is_dst ? _dstbias : 0);
+  const char* abbr = _tzname[is_dst];
+  return {off, abbr};
+}
+#elif defined(__sun)
+// Uses the globals: 'timezone', 'altzone' and 'tzname'.
+OffsetAbbr get_offset_abbr(const std::tm& tm) {
+  const bool is_dst = tm.tm_isdst > 0;
+  const int off = is_dst ? altzone : timezone;
+  const char* abbr = tzname[is_dst];
+  return {off, abbr};
+}
+#elif defined(__native_client__) || defined(__myriad2__) || \
+    defined(__EMSCRIPTEN__)
+// Uses the globals: 'timezone' and 'tzname'.
+OffsetAbbr get_offset_abbr(const std::tm& tm) {
+  const bool is_dst = tm.tm_isdst > 0;
+  const int off = _timezone + (is_dst ? 60 * 60 : 0);
+  const char* abbr = tzname[is_dst];
+  return {off, abbr};
+}
+#else
+//
+// Returns an OffsetAbbr using std::tm fields with various spellings.
+//
+#if !defined(tm_gmtoff) && !defined(tm_zone)
+template <typename T>
+OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
+                           decltype(&T::tm_zone) = nullptr) {
+  return {tm.tm_gmtoff, tm.tm_zone};
+}
+#endif  // !defined(tm_gmtoff) && !defined(tm_zone)
+#if !defined(__tm_gmtoff) && !defined(__tm_zone)
+template <typename T>
+OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
+                           decltype(&T::__tm_zone) = nullptr) {
+  return {tm.__tm_gmtoff, tm.__tm_zone};
+}
+#endif  // !defined(__tm_gmtoff) && !defined(__tm_zone)
+#endif
+
+}  // namespace
+
+TimeZoneLibC::TimeZoneLibC(const std::string& name)
+    : local_(name == "localtime") {}
+
+time_zone::absolute_lookup TimeZoneLibC::BreakTime(
+    const time_point<seconds>& tp) const {
+  time_zone::absolute_lookup al;
+  std::time_t t = ToUnixSeconds(tp);
+  std::tm tm;
+  if (local_) {
+#if defined(_WIN32) || defined(_WIN64)
+    localtime_s(&tm, &t);
+#else
+    localtime_r(&t, &tm);
+#endif
+    std::tie(al.offset, al.abbr) = get_offset_abbr(tm);
+  } else {
+#if defined(_WIN32) || defined(_WIN64)
+    gmtime_s(&tm, &t);
+#else
+    gmtime_r(&t, &tm);
+#endif
+    al.offset = 0;
+    al.abbr = "UTC";
+  }
+  al.cs = civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+                       tm.tm_hour, tm.tm_min, tm.tm_sec);
+  al.is_dst = tm.tm_isdst > 0;
+  return al;
+}
+
+time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
+  time_zone::civil_lookup cl;
+  std::time_t t;
+  if (local_) {
+    // Does not handle SKIPPED/AMBIGUOUS or huge years.
+    std::tm tm;
+    tm.tm_year = static_cast<int>(cs.year() - 1900);
+    tm.tm_mon = cs.month() - 1;
+    tm.tm_mday = cs.day();
+    tm.tm_hour = cs.hour();
+    tm.tm_min = cs.minute();
+    tm.tm_sec = cs.second();
+    tm.tm_isdst = -1;
+    t = std::mktime(&tm);
+  } else {
+    t = cs - civil_second();
+  }
+  cl.kind = time_zone::civil_lookup::UNIQUE;
+  cl.pre = cl.trans = cl.post = FromUnixSeconds(t);
+  return cl;
+}
+
+bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp,
+                                  time_zone::civil_transition* trans) const {
+  return false;
+}
+
+bool TimeZoneLibC::PrevTransition(const time_point<seconds>& tp,
+                                  time_zone::civil_transition* trans) const {
+  return false;
+}
+
+std::string TimeZoneLibC::Version() const {
+  return std::string();  // unknown
+}
+
+std::string TimeZoneLibC::Description() const {
+  return local_ ? "localtime" : "UTC";
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h
new file mode 100644
index 0000000..4e40c61
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_libc.h
@@ -0,0 +1,53 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
+
+#include <string>
+
+#include "time_zone_if.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3),
+// and which therefore only supports UTC and the local time zone.
+// TODO: Add support for fixed offsets from UTC.
+class TimeZoneLibC : public TimeZoneIf {
+ public:
+  explicit TimeZoneLibC(const std::string& name);
+
+  // TimeZoneIf implementations.
+  time_zone::absolute_lookup BreakTime(
+      const time_point<seconds>& tp) const override;
+  time_zone::civil_lookup MakeTime(
+      const civil_second& cs) const override;
+  bool NextTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  bool PrevTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  std::string Version() const override;
+  std::string Description() const override;
+
+ private:
+  const bool local_;  // localtime or UTC
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
new file mode 100644
index 0000000..f2d151e
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -0,0 +1,168 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#if __ANDROID_API__ >= 21
+#include <dlfcn.h>
+#endif
+#endif
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "time_zone_fixed.h"
+#include "time_zone_impl.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+#if defined(__ANDROID__) && __ANDROID_API__ >= 21
+namespace {
+// Android 'L' removes __system_property_get() from the NDK, however
+// it is still a hidden symbol in libc so we use dlsym() to access it.
+// See Chromium's base/sys_info_android.cc for a similar example.
+
+using property_get_func = int (*)(const char*, char*);
+
+property_get_func LoadSystemPropertyGet() {
+  int flag = RTLD_LAZY | RTLD_GLOBAL;
+#if defined(RTLD_NOLOAD)
+  flag |= RTLD_NOLOAD;  // libc.so should already be resident
+#endif
+  if (void* handle = dlopen("libc.so", flag)) {
+    void* sym = dlsym(handle, "__system_property_get");
+    dlclose(handle);
+    return reinterpret_cast<property_get_func>(sym);
+  }
+  return nullptr;
+}
+
+int __system_property_get(const char* name, char* value) {
+  static property_get_func system_property_get = LoadSystemPropertyGet();
+  return system_property_get ? system_property_get(name, value) : -1;
+}
+
+}  // namespace
+#endif
+
+std::string time_zone::name() const {
+  return effective_impl().Name();
+}
+
+time_zone::absolute_lookup time_zone::lookup(
+    const time_point<seconds>& tp) const {
+  return effective_impl().BreakTime(tp);
+}
+
+time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
+  return effective_impl().MakeTime(cs);
+}
+
+bool time_zone::next_transition(const time_point<seconds>& tp,
+                                civil_transition* trans) const {
+  return effective_impl().NextTransition(tp, trans);
+}
+
+bool time_zone::prev_transition(const time_point<seconds>& tp,
+                                civil_transition* trans) const {
+  return effective_impl().PrevTransition(tp, trans);
+}
+
+std::string time_zone::version() const {
+  return effective_impl().Version();
+}
+
+std::string time_zone::description() const {
+  return effective_impl().Description();
+}
+
+const time_zone::Impl& time_zone::effective_impl() const {
+  if (impl_ == nullptr) {
+    // Dereferencing an implicit-UTC time_zone is expected to be
+    // rare, so we don't mind paying a small synchronization cost.
+    return *time_zone::Impl::UTC().impl_;
+  }
+  return *impl_;
+}
+
+bool load_time_zone(const std::string& name, time_zone* tz) {
+  return time_zone::Impl::LoadTimeZone(name, tz);
+}
+
+time_zone utc_time_zone() {
+  return time_zone::Impl::UTC();  // avoid name lookup
+}
+
+time_zone fixed_time_zone(const seconds& offset) {
+  time_zone tz;
+  load_time_zone(FixedOffsetToName(offset), &tz);
+  return tz;
+}
+
+time_zone local_time_zone() {
+  const char* zone = ":localtime";
+
+  // Allow ${TZ} to override to default zone.
+  char* tz_env = nullptr;
+#if defined(_MSC_VER)
+  _dupenv_s(&tz_env, nullptr, "TZ");
+#else
+  tz_env = std::getenv("TZ");
+#endif
+#if defined(__ANDROID__)
+  char sysprop[PROP_VALUE_MAX];
+  if (tz_env == nullptr)
+    if (__system_property_get("persist.sys.timezone", sysprop) > 0)
+      tz_env = sysprop;
+#endif
+  if (tz_env) zone = tz_env;
+
+  // We only support the "[:]<zone-name>" form.
+  if (*zone == ':') ++zone;
+
+  // Map "localtime" to a system-specific name, but
+  // allow ${LOCALTIME} to override the default name.
+  char* localtime_env = nullptr;
+  if (strcmp(zone, "localtime") == 0) {
+#if defined(_MSC_VER)
+    // System-specific default is just "localtime".
+    _dupenv_s(&localtime_env, nullptr, "LOCALTIME");
+#else
+    zone = "/etc/localtime";  // System-specific default.
+    localtime_env = std::getenv("LOCALTIME");
+#endif
+    if (localtime_env) zone = localtime_env;
+  }
+
+  const std::string name = zone;
+#if defined(_MSC_VER)
+  free(localtime_env);
+  free(tz_env);
+#endif
+
+  time_zone tz;
+  load_time_zone(name, &tz);  // Falls back to UTC.
+  // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+  // arrange for %z to generate "-0000" when we don't know the local
+  // offset because the load_time_zone() failed and we're using UTC.
+  return tz;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
new file mode 100644
index 0000000..551292f
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -0,0 +1,1331 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#include <chrono>
+#include <cstddef>
+#include <future>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "gtest/gtest.h"
+
+namespace chrono = std::chrono;
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// A list of known time-zone names.
+const char* const kTimeZoneNames[] = {
+  "Africa/Abidjan",
+  "Africa/Accra",
+  "Africa/Addis_Ababa",
+  "Africa/Algiers",
+  "Africa/Asmara",
+  "Africa/Asmera",
+  "Africa/Bamako",
+  "Africa/Bangui",
+  "Africa/Banjul",
+  "Africa/Bissau",
+  "Africa/Blantyre",
+  "Africa/Brazzaville",
+  "Africa/Bujumbura",
+  "Africa/Cairo",
+  "Africa/Casablanca",
+  "Africa/Ceuta",
+  "Africa/Conakry",
+  "Africa/Dakar",
+  "Africa/Dar_es_Salaam",
+  "Africa/Djibouti",
+  "Africa/Douala",
+  "Africa/El_Aaiun",
+  "Africa/Freetown",
+  "Africa/Gaborone",
+  "Africa/Harare",
+  "Africa/Johannesburg",
+  "Africa/Juba",
+  "Africa/Kampala",
+  "Africa/Khartoum",
+  "Africa/Kigali",
+  "Africa/Kinshasa",
+  "Africa/Lagos",
+  "Africa/Libreville",
+  "Africa/Lome",
+  "Africa/Luanda",
+  "Africa/Lubumbashi",
+  "Africa/Lusaka",
+  "Africa/Malabo",
+  "Africa/Maputo",
+  "Africa/Maseru",
+  "Africa/Mbabane",
+  "Africa/Mogadishu",
+  "Africa/Monrovia",
+  "Africa/Nairobi",
+  "Africa/Ndjamena",
+  "Africa/Niamey",
+  "Africa/Nouakchott",
+  "Africa/Ouagadougou",
+  "Africa/Porto-Novo",
+  "Africa/Sao_Tome",
+  "Africa/Timbuktu",
+  "Africa/Tripoli",
+  "Africa/Tunis",
+  "Africa/Windhoek",
+  "America/Adak",
+  "America/Anchorage",
+  "America/Anguilla",
+  "America/Antigua",
+  "America/Araguaina",
+  "America/Argentina/Buenos_Aires",
+  "America/Argentina/Catamarca",
+  "America/Argentina/ComodRivadavia",
+  "America/Argentina/Cordoba",
+  "America/Argentina/Jujuy",
+  "America/Argentina/La_Rioja",
+  "America/Argentina/Mendoza",
+  "America/Argentina/Rio_Gallegos",
+  "America/Argentina/Salta",
+  "America/Argentina/San_Juan",
+  "America/Argentina/San_Luis",
+  "America/Argentina/Tucuman",
+  "America/Argentina/Ushuaia",
+  "America/Aruba",
+  "America/Asuncion",
+  "America/Atikokan",
+  "America/Atka",
+  "America/Bahia",
+  "America/Bahia_Banderas",
+  "America/Barbados",
+  "America/Belem",
+  "America/Belize",
+  "America/Blanc-Sablon",
+  "America/Boa_Vista",
+  "America/Bogota",
+  "America/Boise",
+  "America/Buenos_Aires",
+  "America/Cambridge_Bay",
+  "America/Campo_Grande",
+  "America/Cancun",
+  "America/Caracas",
+  "America/Catamarca",
+  "America/Cayenne",
+  "America/Cayman",
+  "America/Chicago",
+  "America/Chihuahua",
+  "America/Coral_Harbour",
+  "America/Cordoba",
+  "America/Costa_Rica",
+  "America/Creston",
+  "America/Cuiaba",
+  "America/Curacao",
+  "America/Danmarkshavn",
+  "America/Dawson",
+  "America/Dawson_Creek",
+  "America/Denver",
+  "America/Detroit",
+  "America/Dominica",
+  "America/Edmonton",
+  "America/Eirunepe",
+  "America/El_Salvador",
+  "America/Ensenada",
+  "America/Fort_Nelson",
+  "America/Fort_Wayne",
+  "America/Fortaleza",
+  "America/Glace_Bay",
+  "America/Godthab",
+  "America/Goose_Bay",
+  "America/Grand_Turk",
+  "America/Grenada",
+  "America/Guadeloupe",
+  "America/Guatemala",
+  "America/Guayaquil",
+  "America/Guyana",
+  "America/Halifax",
+  "America/Havana",
+  "America/Hermosillo",
+  "America/Indiana/Indianapolis",
+  "America/Indiana/Knox",
+  "America/Indiana/Marengo",
+  "America/Indiana/Petersburg",
+  "America/Indiana/Tell_City",
+  "America/Indiana/Vevay",
+  "America/Indiana/Vincennes",
+  "America/Indiana/Winamac",
+  "America/Indianapolis",
+  "America/Inuvik",
+  "America/Iqaluit",
+  "America/Jamaica",
+  "America/Jujuy",
+  "America/Juneau",
+  "America/Kentucky/Louisville",
+  "America/Kentucky/Monticello",
+  "America/Knox_IN",
+  "America/Kralendijk",
+  "America/La_Paz",
+  "America/Lima",
+  "America/Los_Angeles",
+  "America/Louisville",
+  "America/Lower_Princes",
+  "America/Maceio",
+  "America/Managua",
+  "America/Manaus",
+  "America/Marigot",
+  "America/Martinique",
+  "America/Matamoros",
+  "America/Mazatlan",
+  "America/Mendoza",
+  "America/Menominee",
+  "America/Merida",
+  "America/Metlakatla",
+  "America/Mexico_City",
+  "America/Miquelon",
+  "America/Moncton",
+  "America/Monterrey",
+  "America/Montevideo",
+  "America/Montreal",
+  "America/Montserrat",
+  "America/Nassau",
+  "America/New_York",
+  "America/Nipigon",
+  "America/Nome",
+  "America/Noronha",
+  "America/North_Dakota/Beulah",
+  "America/North_Dakota/Center",
+  "America/North_Dakota/New_Salem",
+  "America/Ojinaga",
+  "America/Panama",
+  "America/Pangnirtung",
+  "America/Paramaribo",
+  "America/Phoenix",
+  "America/Port-au-Prince",
+  "America/Port_of_Spain",
+  "America/Porto_Acre",
+  "America/Porto_Velho",
+  "America/Puerto_Rico",
+  "America/Punta_Arenas",
+  "America/Rainy_River",
+  "America/Rankin_Inlet",
+  "America/Recife",
+  "America/Regina",
+  "America/Resolute",
+  "America/Rio_Branco",
+  "America/Rosario",
+  "America/Santa_Isabel",
+  "America/Santarem",
+  "America/Santiago",
+  "America/Santo_Domingo",
+  "America/Sao_Paulo",
+  "America/Scoresbysund",
+  "America/Shiprock",
+  "America/Sitka",
+  "America/St_Barthelemy",
+  "America/St_Johns",
+  "America/St_Kitts",
+  "America/St_Lucia",
+  "America/St_Thomas",
+  "America/St_Vincent",
+  "America/Swift_Current",
+  "America/Tegucigalpa",
+  "America/Thule",
+  "America/Thunder_Bay",
+  "America/Tijuana",
+  "America/Toronto",
+  "America/Tortola",
+  "America/Vancouver",
+  "America/Virgin",
+  "America/Whitehorse",
+  "America/Winnipeg",
+  "America/Yakutat",
+  "America/Yellowknife",
+  "Antarctica/Casey",
+  "Antarctica/Davis",
+  "Antarctica/DumontDUrville",
+  "Antarctica/Macquarie",
+  "Antarctica/Mawson",
+  "Antarctica/McMurdo",
+  "Antarctica/Palmer",
+  "Antarctica/Rothera",
+  "Antarctica/South_Pole",
+  "Antarctica/Syowa",
+  "Antarctica/Troll",
+  "Antarctica/Vostok",
+  "Arctic/Longyearbyen",
+  "Asia/Aden",
+  "Asia/Almaty",
+  "Asia/Amman",
+  "Asia/Anadyr",
+  "Asia/Aqtau",
+  "Asia/Aqtobe",
+  "Asia/Ashgabat",
+  "Asia/Ashkhabad",
+  "Asia/Atyrau",
+  "Asia/Baghdad",
+  "Asia/Bahrain",
+  "Asia/Baku",
+  "Asia/Bangkok",
+  "Asia/Barnaul",
+  "Asia/Beirut",
+  "Asia/Bishkek",
+  "Asia/Brunei",
+  "Asia/Calcutta",
+  "Asia/Chita",
+  "Asia/Choibalsan",
+  "Asia/Chongqing",
+  "Asia/Chungking",
+  "Asia/Colombo",
+  "Asia/Dacca",
+  "Asia/Damascus",
+  "Asia/Dhaka",
+  "Asia/Dili",
+  "Asia/Dubai",
+  "Asia/Dushanbe",
+  "Asia/Famagusta",
+  "Asia/Gaza",
+  "Asia/Harbin",
+  "Asia/Hebron",
+  "Asia/Ho_Chi_Minh",
+  "Asia/Hong_Kong",
+  "Asia/Hovd",
+  "Asia/Irkutsk",
+  "Asia/Istanbul",
+  "Asia/Jakarta",
+  "Asia/Jayapura",
+  "Asia/Jerusalem",
+  "Asia/Kabul",
+  "Asia/Kamchatka",
+  "Asia/Karachi",
+  "Asia/Kashgar",
+  "Asia/Kathmandu",
+  "Asia/Katmandu",
+  "Asia/Khandyga",
+  "Asia/Kolkata",
+  "Asia/Krasnoyarsk",
+  "Asia/Kuala_Lumpur",
+  "Asia/Kuching",
+  "Asia/Kuwait",
+  "Asia/Macao",
+  "Asia/Macau",
+  "Asia/Magadan",
+  "Asia/Makassar",
+  "Asia/Manila",
+  "Asia/Muscat",
+  "Asia/Nicosia",
+  "Asia/Novokuznetsk",
+  "Asia/Novosibirsk",
+  "Asia/Omsk",
+  "Asia/Oral",
+  "Asia/Phnom_Penh",
+  "Asia/Pontianak",
+  "Asia/Pyongyang",
+  "Asia/Qatar",
+  "Asia/Qyzylorda",
+  "Asia/Rangoon",
+  "Asia/Riyadh",
+  "Asia/Saigon",
+  "Asia/Sakhalin",
+  "Asia/Samarkand",
+  "Asia/Seoul",
+  "Asia/Shanghai",
+  "Asia/Singapore",
+  "Asia/Srednekolymsk",
+  "Asia/Taipei",
+  "Asia/Tashkent",
+  "Asia/Tbilisi",
+  "Asia/Tehran",
+  "Asia/Tel_Aviv",
+  "Asia/Thimbu",
+  "Asia/Thimphu",
+  "Asia/Tokyo",
+  "Asia/Tomsk",
+  "Asia/Ujung_Pandang",
+  "Asia/Ulaanbaatar",
+  "Asia/Ulan_Bator",
+  "Asia/Urumqi",
+  "Asia/Ust-Nera",
+  "Asia/Vientiane",
+  "Asia/Vladivostok",
+  "Asia/Yakutsk",
+  "Asia/Yangon",
+  "Asia/Yekaterinburg",
+  "Asia/Yerevan",
+  "Atlantic/Azores",
+  "Atlantic/Bermuda",
+  "Atlantic/Canary",
+  "Atlantic/Cape_Verde",
+  "Atlantic/Faeroe",
+  "Atlantic/Faroe",
+  "Atlantic/Jan_Mayen",
+  "Atlantic/Madeira",
+  "Atlantic/Reykjavik",
+  "Atlantic/South_Georgia",
+  "Atlantic/St_Helena",
+  "Atlantic/Stanley",
+  "Australia/ACT",
+  "Australia/Adelaide",
+  "Australia/Brisbane",
+  "Australia/Broken_Hill",
+  "Australia/Canberra",
+  "Australia/Currie",
+  "Australia/Darwin",
+  "Australia/Eucla",
+  "Australia/Hobart",
+  "Australia/LHI",
+  "Australia/Lindeman",
+  "Australia/Lord_Howe",
+  "Australia/Melbourne",
+  "Australia/NSW",
+  "Australia/North",
+  "Australia/Perth",
+  "Australia/Queensland",
+  "Australia/South",
+  "Australia/Sydney",
+  "Australia/Tasmania",
+  "Australia/Victoria",
+  "Australia/West",
+  "Australia/Yancowinna",
+  "Brazil/Acre",
+  "Brazil/DeNoronha",
+  "Brazil/East",
+  "Brazil/West",
+  "CET",
+  "CST6CDT",
+  "Canada/Atlantic",
+  "Canada/Central",
+  "Canada/Eastern",
+  "Canada/Mountain",
+  "Canada/Newfoundland",
+  "Canada/Pacific",
+  "Canada/Saskatchewan",
+  "Canada/Yukon",
+  "Chile/Continental",
+  "Chile/EasterIsland",
+  "Cuba",
+  "EET",
+  "EST",
+  "EST5EDT",
+  "Egypt",
+  "Eire",
+  "Etc/GMT",
+  "Etc/GMT+0",
+  "Etc/GMT+1",
+  "Etc/GMT+10",
+  "Etc/GMT+11",
+  "Etc/GMT+12",
+  "Etc/GMT+2",
+  "Etc/GMT+3",
+  "Etc/GMT+4",
+  "Etc/GMT+5",
+  "Etc/GMT+6",
+  "Etc/GMT+7",
+  "Etc/GMT+8",
+  "Etc/GMT+9",
+  "Etc/GMT-0",
+  "Etc/GMT-1",
+  "Etc/GMT-10",
+  "Etc/GMT-11",
+  "Etc/GMT-12",
+  "Etc/GMT-13",
+  "Etc/GMT-14",
+  "Etc/GMT-2",
+  "Etc/GMT-3",
+  "Etc/GMT-4",
+  "Etc/GMT-5",
+  "Etc/GMT-6",
+  "Etc/GMT-7",
+  "Etc/GMT-8",
+  "Etc/GMT-9",
+  "Etc/GMT0",
+  "Etc/Greenwich",
+  "Etc/UCT",
+  "Etc/UTC",
+  "Etc/Universal",
+  "Etc/Zulu",
+  "Europe/Amsterdam",
+  "Europe/Andorra",
+  "Europe/Astrakhan",
+  "Europe/Athens",
+  "Europe/Belfast",
+  "Europe/Belgrade",
+  "Europe/Berlin",
+  "Europe/Bratislava",
+  "Europe/Brussels",
+  "Europe/Bucharest",
+  "Europe/Budapest",
+  "Europe/Busingen",
+  "Europe/Chisinau",
+  "Europe/Copenhagen",
+  "Europe/Dublin",
+  "Europe/Gibraltar",
+  "Europe/Guernsey",
+  "Europe/Helsinki",
+  "Europe/Isle_of_Man",
+  "Europe/Istanbul",
+  "Europe/Jersey",
+  "Europe/Kaliningrad",
+  "Europe/Kiev",
+  "Europe/Kirov",
+  "Europe/Lisbon",
+  "Europe/Ljubljana",
+  "Europe/London",
+  "Europe/Luxembourg",
+  "Europe/Madrid",
+  "Europe/Malta",
+  "Europe/Mariehamn",
+  "Europe/Minsk",
+  "Europe/Monaco",
+  "Europe/Moscow",
+  "Europe/Nicosia",
+  "Europe/Oslo",
+  "Europe/Paris",
+  "Europe/Podgorica",
+  "Europe/Prague",
+  "Europe/Riga",
+  "Europe/Rome",
+  "Europe/Samara",
+  "Europe/San_Marino",
+  "Europe/Sarajevo",
+  "Europe/Saratov",
+  "Europe/Simferopol",
+  "Europe/Skopje",
+  "Europe/Sofia",
+  "Europe/Stockholm",
+  "Europe/Tallinn",
+  "Europe/Tirane",
+  "Europe/Tiraspol",
+  "Europe/Ulyanovsk",
+  "Europe/Uzhgorod",
+  "Europe/Vaduz",
+  "Europe/Vatican",
+  "Europe/Vienna",
+  "Europe/Vilnius",
+  "Europe/Volgograd",
+  "Europe/Warsaw",
+  "Europe/Zagreb",
+  "Europe/Zaporozhye",
+  "Europe/Zurich",
+  "GB",
+  "GB-Eire",
+  "GMT",
+  "GMT+0",
+  "GMT-0",
+  "GMT0",
+  "Greenwich",
+  "HST",
+  "Hongkong",
+  "Iceland",
+  "Indian/Antananarivo",
+  "Indian/Chagos",
+  "Indian/Christmas",
+  "Indian/Cocos",
+  "Indian/Comoro",
+  "Indian/Kerguelen",
+  "Indian/Mahe",
+  "Indian/Maldives",
+  "Indian/Mauritius",
+  "Indian/Mayotte",
+  "Indian/Reunion",
+  "Iran",
+  "Israel",
+  "Jamaica",
+  "Japan",
+  "Kwajalein",
+  "Libya",
+  "MET",
+  "MST",
+  "MST7MDT",
+  "Mexico/BajaNorte",
+  "Mexico/BajaSur",
+  "Mexico/General",
+  "NZ",
+  "NZ-CHAT",
+  "Navajo",
+  "PRC",
+  "PST8PDT",
+  "Pacific/Apia",
+  "Pacific/Auckland",
+  "Pacific/Bougainville",
+  "Pacific/Chatham",
+  "Pacific/Chuuk",
+  "Pacific/Easter",
+  "Pacific/Efate",
+  "Pacific/Enderbury",
+  "Pacific/Fakaofo",
+  "Pacific/Fiji",
+  "Pacific/Funafuti",
+  "Pacific/Galapagos",
+  "Pacific/Gambier",
+  "Pacific/Guadalcanal",
+  "Pacific/Guam",
+  "Pacific/Honolulu",
+  "Pacific/Johnston",
+  "Pacific/Kiritimati",
+  "Pacific/Kosrae",
+  "Pacific/Kwajalein",
+  "Pacific/Majuro",
+  "Pacific/Marquesas",
+  "Pacific/Midway",
+  "Pacific/Nauru",
+  "Pacific/Niue",
+  "Pacific/Norfolk",
+  "Pacific/Noumea",
+  "Pacific/Pago_Pago",
+  "Pacific/Palau",
+  "Pacific/Pitcairn",
+  "Pacific/Pohnpei",
+  "Pacific/Ponape",
+  "Pacific/Port_Moresby",
+  "Pacific/Rarotonga",
+  "Pacific/Saipan",
+  "Pacific/Samoa",
+  "Pacific/Tahiti",
+  "Pacific/Tarawa",
+  "Pacific/Tongatapu",
+  "Pacific/Truk",
+  "Pacific/Wake",
+  "Pacific/Wallis",
+  "Pacific/Yap",
+  "Poland",
+  "Portugal",
+  "ROC",
+  "ROK",
+  "Singapore",
+  "Turkey",
+  "UCT",
+  "US/Alaska",
+  "US/Aleutian",
+  "US/Arizona",
+  "US/Central",
+  "US/East-Indiana",
+  "US/Eastern",
+  "US/Hawaii",
+  "US/Indiana-Starke",
+  "US/Michigan",
+  "US/Mountain",
+  "US/Pacific",
+  "US/Samoa",
+  "UTC",
+  "Universal",
+  "W-SU",
+  "WET",
+  "Zulu",
+  nullptr
+};
+
+// Helper to return a loaded time zone by value (UTC on error).
+time_zone LoadZone(const std::string& name) {
+  time_zone tz;
+  load_time_zone(name, &tz);
+  return tz;
+}
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \
+  do {                                                            \
+    time_zone::absolute_lookup al = tz.lookup(tp);                \
+    EXPECT_EQ(y, al.cs.year());                                   \
+    EXPECT_EQ(m, al.cs.month());                                  \
+    EXPECT_EQ(d, al.cs.day());                                    \
+    EXPECT_EQ(hh, al.cs.hour());                                  \
+    EXPECT_EQ(mm, al.cs.minute());                                \
+    EXPECT_EQ(ss, al.cs.second());                                \
+    EXPECT_EQ(off, al.offset);                                    \
+    EXPECT_TRUE(isdst == al.is_dst);                              \
+    /* EXPECT_STREQ(zone, al.abbr); */                            \
+  } while (0)
+
+// These tests sometimes run on platforms that have zoneinfo data so old
+// that the transition we are attempting to check does not exist, most
+// notably Android emulators.  Fortunately, AndroidZoneInfoSource supports
+// time_zone::version() so, in cases where we've learned that it matters,
+// we can make the check conditionally.
+int VersionCmp(time_zone tz, const std::string& target) {
+  std::string version = tz.version();
+  if (version.empty() && !target.empty()) return 1;  // unknown > known
+  return version.compare(target);
+}
+
+}  // namespace
+
+TEST(TimeZones, LoadZonesConcurrently) {
+  std::promise<void> ready_promise;
+  std::shared_future<void> ready_future(ready_promise.get_future());
+  auto load_zones = [ready_future](std::promise<void>* started,
+                                   std::set<std::string>* failures) {
+    started->set_value();
+    ready_future.wait();
+    for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
+      std::string zone = *np;
+      time_zone tz;
+      if (load_time_zone(zone, &tz)) {
+        EXPECT_EQ(zone, tz.name());
+      } else {
+        failures->insert(zone);
+      }
+    }
+  };
+
+  const std::size_t n_threads = 128;
+  std::vector<std::thread> threads;
+  std::vector<std::set<std::string>> thread_failures(n_threads);
+  for (std::size_t i = 0; i != n_threads; ++i) {
+    std::promise<void> started;
+    threads.emplace_back(load_zones, &started, &thread_failures[i]);
+    started.get_future().wait();
+  }
+  ready_promise.set_value();
+  for (auto& thread : threads) {
+    thread.join();
+  }
+
+  // Allow a small number of failures to account for skew between
+  // the contents of kTimeZoneNames and the zoneinfo data source.
+#if defined(__ANDROID__)
+  // Cater to the possibility of using an even older zoneinfo data
+  // source when running on Android, where it is difficult to override
+  // the bionic tzdata provided by the test environment.
+  const std::size_t max_failures = 20;
+#else
+  const std::size_t max_failures = 3;
+#endif
+  std::set<std::string> failures;
+  for (const auto& thread_failure : thread_failures) {
+    failures.insert(thread_failure.begin(), thread_failure.end());
+  }
+  EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
+}
+
+TEST(TimeZone, NamedTimeZones) {
+  const time_zone utc = utc_time_zone();
+  EXPECT_EQ("UTC", utc.name());
+  const time_zone nyc = LoadZone("America/New_York");
+  EXPECT_EQ("America/New_York", nyc.name());
+  const time_zone syd = LoadZone("Australia/Sydney");
+  EXPECT_EQ("Australia/Sydney", syd.name());
+  const time_zone fixed0 = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+  EXPECT_EQ("UTC", fixed0.name());
+  const time_zone fixed_pos = fixed_time_zone(
+      chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
+  EXPECT_EQ("Fixed/UTC+03:25:45", fixed_pos.name());
+  const time_zone fixed_neg = fixed_time_zone(
+      -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
+  EXPECT_EQ("Fixed/UTC-12:34:56", fixed_neg.name());
+}
+
+TEST(TimeZone, Failures) {
+  time_zone tz;
+  EXPECT_FALSE(load_time_zone(":America/Los_Angeles", &tz));
+
+  tz = LoadZone("America/Los_Angeles");
+  EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz));
+  EXPECT_EQ(chrono::system_clock::from_time_t(0),
+            convert(civil_second(1970, 1, 1, 0, 0, 0), tz));  // UTC
+
+  // Ensures that the load still fails on a subsequent attempt.
+  tz = LoadZone("America/Los_Angeles");
+  EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz));
+  EXPECT_EQ(chrono::system_clock::from_time_t(0),
+            convert(civil_second(1970, 1, 1, 0, 0, 0), tz));  // UTC
+
+  // Loading an empty std::string timezone should fail.
+  tz = LoadZone("America/Los_Angeles");
+  EXPECT_FALSE(load_time_zone("", &tz));
+  EXPECT_EQ(chrono::system_clock::from_time_t(0),
+            convert(civil_second(1970, 1, 1, 0, 0, 0), tz));  // UTC
+}
+
+TEST(TimeZone, Equality) {
+  const time_zone a;
+  const time_zone b;
+  EXPECT_EQ(a, b);
+  EXPECT_EQ(a.name(), b.name());
+
+  const time_zone implicit_utc;
+  const time_zone explicit_utc = utc_time_zone();
+  EXPECT_EQ(implicit_utc, explicit_utc);
+  EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
+
+  const time_zone fixed_zero = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+  EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name()));
+  EXPECT_EQ(fixed_zero, explicit_utc);
+
+  const time_zone fixed_utc = LoadZone("Fixed/UTC+00:00:00");
+  EXPECT_EQ(fixed_utc, LoadZone(fixed_utc.name()));
+  EXPECT_EQ(fixed_utc, explicit_utc);
+
+  const time_zone fixed_pos = fixed_time_zone(
+      chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
+  EXPECT_EQ(fixed_pos, LoadZone(fixed_pos.name()));
+  EXPECT_NE(fixed_pos, explicit_utc);
+  const time_zone fixed_neg = fixed_time_zone(
+      -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
+  EXPECT_EQ(fixed_neg, LoadZone(fixed_neg.name()));
+  EXPECT_NE(fixed_neg, explicit_utc);
+
+  const time_zone fixed_lim = fixed_time_zone(chrono::hours(24));
+  EXPECT_EQ(fixed_lim, LoadZone(fixed_lim.name()));
+  EXPECT_NE(fixed_lim, explicit_utc);
+  const time_zone fixed_ovfl =
+      fixed_time_zone(chrono::hours(24) + chrono::seconds(1));
+  EXPECT_EQ(fixed_ovfl, LoadZone(fixed_ovfl.name()));
+  EXPECT_EQ(fixed_ovfl, explicit_utc);
+
+  EXPECT_EQ(fixed_time_zone(chrono::seconds(1)),
+            fixed_time_zone(chrono::seconds(1)));
+
+  const time_zone local = local_time_zone();
+  EXPECT_EQ(local, LoadZone(local.name()));
+
+  time_zone la = LoadZone("America/Los_Angeles");
+  time_zone nyc = LoadZone("America/New_York");
+  EXPECT_NE(la, nyc);
+}
+
+TEST(StdChronoTimePoint, TimeTAlignment) {
+  // Ensures that the Unix epoch and the system clock epoch are an integral
+  // number of seconds apart. This simplifies conversions to/from time_t.
+  auto diff = chrono::system_clock::time_point() -
+              chrono::system_clock::from_time_t(0);
+  EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
+            diff % chrono::seconds(1));
+}
+
+TEST(BreakTime, TimePointResolution) {
+  const time_zone utc = utc_time_zone();
+  const auto t0 = chrono::system_clock::from_time_t(0);
+
+  ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
+             1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+}
+
+TEST(BreakTime, LocalTimeInUTC) {
+  const time_zone tz = utc_time_zone();
+  const auto tp = chrono::system_clock::from_time_t(0);
+  ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+  EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(BreakTime, LocalTimeInUTCUnaligned) {
+  const time_zone tz = utc_time_zone();
+  const auto tp =
+      chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
+  ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC");
+  EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(BreakTime, LocalTimePosix) {
+  // See IEEE Std 1003.1-1988 B.2.3 General Terms, Epoch.
+  const time_zone tz = utc_time_zone();
+  const auto tp = chrono::system_clock::from_time_t(536457599);
+  ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC");
+  EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(TimeZoneImpl, LocalTimeInFixed) {
+  const absl::time_internal::cctz::seconds offset =
+      -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47));
+  const time_zone tz = fixed_time_zone(offset);
+  const auto tp = chrono::system_clock::from_time_t(0);
+  ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
+             "-083347");
+  EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(BreakTime, LocalTimeInNewYork) {
+  const time_zone tz = LoadZone("America/New_York");
+  const auto tp = chrono::system_clock::from_time_t(45);
+  ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST");
+  EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(BreakTime, LocalTimeInMTV) {
+  const time_zone tz = LoadZone("America/Los_Angeles");
+  const auto tp = chrono::system_clock::from_time_t(1380855729);
+  ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT");
+  EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(BreakTime, LocalTimeInSydney) {
+  const time_zone tz = LoadZone("Australia/Sydney");
+  const auto tp = chrono::system_clock::from_time_t(90);
+  ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST");
+  EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(MakeTime, TimePointResolution) {
+  const time_zone utc = utc_time_zone();
+  const time_point<chrono::nanoseconds> tp_ns =
+      convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
+  EXPECT_EQ("04:05", format("%M:%E*S", tp_ns, utc));
+  const time_point<chrono::microseconds> tp_us =
+      convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
+  EXPECT_EQ("04:05", format("%M:%E*S", tp_us, utc));
+  const time_point<chrono::milliseconds> tp_ms =
+      convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
+  EXPECT_EQ("04:05", format("%M:%E*S", tp_ms, utc));
+  const time_point<chrono::seconds> tp_s =
+      convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
+  EXPECT_EQ("04:05", format("%M:%E*S", tp_s, utc));
+  const time_point<absl::time_internal::cctz::seconds> tp_s64 =
+      convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
+  EXPECT_EQ("04:05", format("%M:%E*S", tp_s64, utc));
+
+  // These next two require chrono::time_point_cast because the conversion
+  // from a resolution of seconds (the return value of convert()) to a
+  // coarser resolution requires an explicit cast.
+  const time_point<chrono::minutes> tp_m =
+      chrono::time_point_cast<chrono::minutes>(
+          convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
+  EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc));
+  const time_point<chrono::hours> tp_h =
+      chrono::time_point_cast<chrono::hours>(
+          convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
+  EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc));
+}
+
+TEST(MakeTime, Normalization) {
+  const time_zone tz = LoadZone("America/New_York");
+  const auto tp = convert(civil_second(2009, 2, 13, 18, 31, 30), tz);
+  EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+  // Now requests for the same time_point but with out-of-range fields.
+  EXPECT_EQ(tp, convert(civil_second(2008, 14, 13, 18, 31, 30), tz));  // month
+  EXPECT_EQ(tp, convert(civil_second(2009, 1, 44, 18, 31, 30), tz));   // day
+  EXPECT_EQ(tp, convert(civil_second(2009, 2, 12, 42, 31, 30), tz));   // hour
+  EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 17, 91, 30), tz));   // minute
+  EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz));   // second
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(MakeTime, SysSecondsLimits) {
+  const char RFC3339[] =  "%Y-%m-%dT%H:%M:%S%Ez";
+  const time_zone utc = utc_time_zone();
+  const time_zone east = fixed_time_zone(chrono::hours(14));
+  const time_zone west = fixed_time_zone(-chrono::hours(14));
+  time_point<absl::time_internal::cctz::seconds> tp;
+
+  // Approach the maximal time_point<cctz::seconds> value from below.
+  tp = convert(civil_second(292277026596, 12, 4, 15, 30, 6), utc);
+  EXPECT_EQ("292277026596-12-04T15:30:06+00:00", format(RFC3339, tp, utc));
+  tp = convert(civil_second(292277026596, 12, 4, 15, 30, 7), utc);
+  EXPECT_EQ("292277026596-12-04T15:30:07+00:00", format(RFC3339, tp, utc));
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+  tp = convert(civil_second(292277026596, 12, 4, 15, 30, 8), utc);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+  tp = convert(civil_second::max(), utc);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+
+  // Checks that we can also get the maximal value for a far-east zone.
+  tp = convert(civil_second(292277026596, 12, 5, 5, 30, 7), east);
+  EXPECT_EQ("292277026596-12-05T05:30:07+14:00", format(RFC3339, tp, east));
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+  tp = convert(civil_second(292277026596, 12, 5, 5, 30, 8), east);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+  tp = convert(civil_second::max(), east);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+
+  // Checks that we can also get the maximal value for a far-west zone.
+  tp = convert(civil_second(292277026596, 12, 4, 1, 30, 7), west);
+  EXPECT_EQ("292277026596-12-04T01:30:07-14:00", format(RFC3339, tp, west));
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+  tp = convert(civil_second(292277026596, 12, 4, 7, 30, 8), west);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+  tp = convert(civil_second::max(), west);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp);
+
+  // Approach the minimal time_point<cctz::seconds> value from above.
+  tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 53), utc);
+  EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", format(RFC3339, tp, utc));
+  tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 52), utc);
+  EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", format(RFC3339, tp, utc));
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+  tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 51), utc);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+  tp = convert(civil_second::min(), utc);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+
+  // Checks that we can also get the minimal value for a far-east zone.
+  tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 52), east);
+  EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", format(RFC3339, tp, east));
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+  tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 51), east);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+  tp = convert(civil_second::min(), east);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+
+  // Checks that we can also get the minimal value for a far-west zone.
+  tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 52), west);
+  EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", format(RFC3339, tp, west));
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+  tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 51), west);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+  tp = convert(civil_second::min(), west);
+  EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
+}
+
+TEST(NextTransition, UTC) {
+  const auto tz = utc_time_zone();
+  time_zone::civil_transition trans;
+
+  auto tp = time_point<absl::time_internal::cctz::seconds>::min();
+  EXPECT_FALSE(tz.next_transition(tp, &trans));
+
+  tp = time_point<absl::time_internal::cctz::seconds>::max();
+  EXPECT_FALSE(tz.next_transition(tp, &trans));
+}
+
+TEST(PrevTransition, UTC) {
+  const auto tz = utc_time_zone();
+  time_zone::civil_transition trans;
+
+  auto tp = time_point<absl::time_internal::cctz::seconds>::max();
+  EXPECT_FALSE(tz.prev_transition(tp, &trans));
+
+  tp = time_point<absl::time_internal::cctz::seconds>::min();
+  EXPECT_FALSE(tz.prev_transition(tp, &trans));
+}
+
+TEST(NextTransition, AmericaNewYork) {
+  const auto tz = LoadZone("America/New_York");
+  time_zone::civil_transition trans;
+
+  auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
+  EXPECT_TRUE(tz.next_transition(tp, &trans));
+  EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from);
+  EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to);
+
+  tp = time_point<absl::time_internal::cctz::seconds>::max();
+  EXPECT_FALSE(tz.next_transition(tp, &trans));
+
+  tp = time_point<absl::time_internal::cctz::seconds>::min();
+  EXPECT_TRUE(tz.next_transition(tp, &trans));
+  if (trans.from == civil_second(1918, 3, 31, 2, 0, 0)) {
+    // It looks like the tzdata is only 32 bit (probably macOS),
+    // which bottoms out at 1901-12-13T20:45:52+00:00.
+    EXPECT_EQ(civil_second(1918, 3, 31, 3, 0, 0), trans.to);
+  } else {
+    EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from);
+    EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to);
+  }
+}
+
+TEST(PrevTransition, AmericaNewYork) {
+  const auto tz = LoadZone("America/New_York");
+  time_zone::civil_transition trans;
+
+  auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
+  EXPECT_TRUE(tz.prev_transition(tp, &trans));
+  EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from);
+  EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to);
+
+  tp = time_point<absl::time_internal::cctz::seconds>::min();
+  EXPECT_FALSE(tz.prev_transition(tp, &trans));
+
+  tp = time_point<absl::time_internal::cctz::seconds>::max();
+  EXPECT_TRUE(tz.prev_transition(tp, &trans));
+  // We have a transition but we don't know which one.
+}
+
+TEST(TimeZoneEdgeCase, AmericaNewYork) {
+  const time_zone tz = LoadZone("America/New_York");
+
+  // Spring 1:59:59 -> 3:00:00
+  auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -5 * 3600, false, "EST");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -4 * 3600, true, "EDT");
+
+  // Fall 1:59:59 -> 1:00:00
+  tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -4 * 3600, true, "EDT");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -5 * 3600, false, "EST");
+}
+
+TEST(TimeZoneEdgeCase, AmericaLosAngeles) {
+  const time_zone tz = LoadZone("America/Los_Angeles");
+
+  // Spring 1:59:59 -> 3:00:00
+  auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -8 * 3600, false, "PST");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -7 * 3600, true, "PDT");
+
+  // Fall 1:59:59 -> 1:00:00
+  tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, true, "PDT");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -8 * 3600, false, "PST");
+}
+
+TEST(TimeZoneEdgeCase, ArizonaNoTransition) {
+  const time_zone tz = LoadZone("America/Phoenix");
+
+  // No transition in Spring.
+  auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -7 * 3600, false, "MST");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 3, 10, 2, 0, 0, -7 * 3600, false, "MST");
+
+  // No transition in Fall.
+  tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, false, "MST");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 11, 3, 2, 0, 0, -7 * 3600, false, "MST");
+}
+
+TEST(TimeZoneEdgeCase, AsiaKathmandu) {
+  const time_zone tz = LoadZone("Asia/Kathmandu");
+
+  // A non-DST offset change from +0530 to +0545
+  //
+  //   504901799 == Tue, 31 Dec 1985 23:59:59 +0530 (+0530)
+  //   504901800 == Wed,  1 Jan 1986 00:15:00 +0545 (+0545)
+  auto tp = convert(civil_second(1985, 12, 31, 23, 59, 59), tz);
+  ExpectTime(tp, tz, 1985, 12, 31, 23, 59, 59, 5.5 * 3600, false, "+0530");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 1986, 1, 1, 0, 15, 0, 5.75 * 3600, false, "+0545");
+}
+
+TEST(TimeZoneEdgeCase, PacificChatham) {
+  const time_zone tz = LoadZone("Pacific/Chatham");
+
+  // One-hour DST offset changes, but at atypical values
+  //
+  //   1365256799 == Sun,  7 Apr 2013 03:44:59 +1345 (+1345)
+  //   1365256800 == Sun,  7 Apr 2013 02:45:00 +1245 (+1245)
+  auto tp = convert(civil_second(2013, 4, 7, 3, 44, 59), tz);
+  ExpectTime(tp, tz, 2013, 4, 7, 3, 44, 59, 13.75 * 3600, true, "+1345");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 4, 7, 2, 45, 0, 12.75 * 3600, false, "+1245");
+
+  //   1380376799 == Sun, 29 Sep 2013 02:44:59 +1245 (+1245)
+  //   1380376800 == Sun, 29 Sep 2013 03:45:00 +1345 (+1345)
+  tp = convert(civil_second(2013, 9, 29, 2, 44, 59), tz);
+  ExpectTime(tp, tz, 2013, 9, 29, 2, 44, 59, 12.75 * 3600, false, "+1245");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 9, 29, 3, 45, 0, 13.75 * 3600, true, "+1345");
+}
+
+TEST(TimeZoneEdgeCase, AustraliaLordHowe) {
+  const time_zone tz = LoadZone("Australia/Lord_Howe");
+
+  // Half-hour DST offset changes
+  //
+  //   1365260399 == Sun,  7 Apr 2013 01:59:59 +1100 (+11)
+  //   1365260400 == Sun,  7 Apr 2013 01:30:00 +1030 (+1030)
+  auto tp = convert(civil_second(2013, 4, 7, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 4, 7, 1, 59, 59, 11 * 3600, true, "+11");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 4, 7, 1, 30, 0, 10.5 * 3600, false, "+1030");
+
+  //   1380986999 == Sun,  6 Oct 2013 01:59:59 +1030 (+1030)
+  //   1380987000 == Sun,  6 Oct 2013 02:30:00 +1100 (+11)
+  tp = convert(civil_second(2013, 10, 6, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 2013, 10, 6, 1, 59, 59, 10.5 * 3600, false, "+1030");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2013, 10, 6, 2, 30, 0, 11 * 3600, true, "+11");
+}
+
+TEST(TimeZoneEdgeCase, PacificApia) {
+  const time_zone tz = LoadZone("Pacific/Apia");
+
+  // At the end of December 2011, Samoa jumped forward by one day,
+  // skipping 30 December from the local calendar, when the nation
+  // moved to the west of the International Date Line.
+  //
+  // A one-day, non-DST offset change
+  //
+  //   1325239199 == Thu, 29 Dec 2011 23:59:59 -1000 (-10)
+  //   1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14)
+  auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz);
+  ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10");
+  EXPECT_EQ(363, get_yearday(civil_day(convert(tp, tz))));
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14");
+  EXPECT_EQ(365, get_yearday(civil_day(convert(tp, tz))));
+}
+
+TEST(TimeZoneEdgeCase, AfricaCairo) {
+  const time_zone tz = LoadZone("Africa/Cairo");
+
+  if (VersionCmp(tz, "2014c") >= 0) {
+    // An interesting case of midnight not existing.
+    //
+    //   1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
+    //   1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST)
+    auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz);
+    ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
+    tp += absl::time_internal::cctz::seconds(1);
+    ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
+  }
+}
+
+TEST(TimeZoneEdgeCase, AfricaMonrovia) {
+  const time_zone tz = LoadZone("Africa/Monrovia");
+
+  if (VersionCmp(tz, "2017b") >= 0) {
+    // Strange offset change -00:44:30 -> +00:00:00 (non-DST)
+    //
+    //   63593069 == Thu,  6 Jan 1972 23:59:59 -0044 (MMT)
+    //   63593070 == Fri,  7 Jan 1972 00:44:30 +0000 (GMT)
+    auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
+    ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
+    tp += absl::time_internal::cctz::seconds(1);
+    ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
+  }
+}
+
+TEST(TimeZoneEdgeCase, AmericaJamaica) {
+  // Jamaica discontinued DST transitions in 1983, and is now at a
+  // constant -0500.  This makes it an interesting edge-case target.
+  // Note that the 32-bit times used in a (tzh_version == 0) zoneinfo
+  // file cannot represent the abbreviation-only transition of 1890,
+  // so we ignore the abbreviation by expecting what we received.
+  const time_zone tz = LoadZone("America/Jamaica");
+
+  // Before the first transition.
+  if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) {
+    // We avoid the expectations on the -18430 offset below unless we are
+    // certain we have commit 907241e (Fix off-by-1 error for Jamaica and
+    // T&C before 1913) from 2018d.  TODO: Remove the "version() not empty"
+    // part when 2018d is generally available from /usr/share/zoneinfo.
+    auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz);
+    ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false,
+               tz.lookup(tp).abbr);
+
+    // Over the first (abbreviation-change only) transition.
+    //   -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT)
+    //   -2524503169 == Wed,  1 Jan 1890 00:00:00 -0507 (KMT)
+    tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz);
+    ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false,
+               tz.lookup(tp).abbr);
+    tp += absl::time_internal::cctz::seconds(1);
+    ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT");
+  }
+
+  // Over the last (DST) transition.
+  //     436341599 == Sun, 30 Oct 1983 01:59:59 -0400 (EDT)
+  //     436341600 == Sun, 30 Oct 1983 01:00:00 -0500 (EST)
+  auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz);
+  ExpectTime(tp, tz, 1983, 10, 30, 1, 59, 59, -4 * 3600, true, "EDT");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 1983, 10, 30, 1, 0, 0, -5 * 3600, false, "EST");
+
+  // After the last transition.
+  tp = convert(civil_second(1983, 12, 31, 23, 59, 59), tz);
+  ExpectTime(tp, tz, 1983, 12, 31, 23, 59, 59, -5 * 3600, false, "EST");
+}
+
+TEST(TimeZoneEdgeCase, WET) {
+  // Cover some non-existent times within forward transitions.
+  const time_zone tz = LoadZone("WET");
+
+  // Before the first transition.
+  auto tp = convert(civil_second(1977, 1, 1, 0, 0, 0), tz);
+  ExpectTime(tp, tz, 1977, 1, 1, 0, 0, 0, 0, false, "WET");
+
+  // Over the first transition.
+  //     228877199 == Sun,  3 Apr 1977 00:59:59 +0000 (WET)
+  //     228877200 == Sun,  3 Apr 1977 02:00:00 +0100 (WEST)
+  tp = convert(civil_second(1977, 4, 3, 0, 59, 59), tz);
+  ExpectTime(tp, tz, 1977, 4, 3, 0, 59, 59, 0, false, "WET");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST");
+
+  // A non-existent time within the first transition.
+  time_zone::civil_lookup cl1 = tz.lookup(civil_second(1977, 4, 3, 1, 15, 0));
+  EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl1.kind);
+  ExpectTime(cl1.pre, tz, 1977, 4, 3, 2, 15, 0, 1 * 3600, true, "WEST");
+  ExpectTime(cl1.trans, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST");
+  ExpectTime(cl1.post, tz, 1977, 4, 3, 0, 15, 0, 0 * 3600, false, "WET");
+
+  // A non-existent time within the second forward transition.
+  time_zone::civil_lookup cl2 = tz.lookup(civil_second(1978, 4, 2, 1, 15, 0));
+  EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl2.kind);
+  ExpectTime(cl2.pre, tz, 1978, 4, 2, 2, 15, 0, 1 * 3600, true, "WEST");
+  ExpectTime(cl2.trans, tz, 1978, 4, 2, 2, 0, 0, 1 * 3600, true, "WEST");
+  ExpectTime(cl2.post, tz, 1978, 4, 2, 0, 15, 0, 0 * 3600, false, "WET");
+}
+
+TEST(TimeZoneEdgeCase, FixedOffsets) {
+  const time_zone gmtm5 = LoadZone("Etc/GMT+5");  // -0500
+  auto tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtm5);
+  ExpectTime(tp, gmtm5, 1970, 1, 1, 0, 0, 0, -5 * 3600, false, "-05");
+  EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp);
+
+  const time_zone gmtp5 = LoadZone("Etc/GMT-5");  // +0500
+  tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtp5);
+  ExpectTime(tp, gmtp5, 1970, 1, 1, 0, 0, 0, 5 * 3600, false, "+05");
+  EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp);
+}
+
+TEST(TimeZoneEdgeCase, NegativeYear) {
+  // Tests transition from year 0 (aka 1BCE) to year -1.
+  const time_zone tz = utc_time_zone();
+  auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz);
+  ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
+  EXPECT_EQ(weekday::saturday, get_weekday(civil_day(convert(tp, tz))));
+  tp -= absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
+  EXPECT_EQ(weekday::friday, get_weekday(civil_day(convert(tp, tz))));
+}
+
+TEST(TimeZoneEdgeCase, UTC32bitLimit) {
+  const time_zone tz = utc_time_zone();
+
+  // Limits of signed 32-bit time_t
+  //
+  //   2147483647 == Tue, 19 Jan 2038 03:14:07 +0000 (UTC)
+  //   2147483648 == Tue, 19 Jan 2038 03:14:08 +0000 (UTC)
+  auto tp = convert(civil_second(2038, 1, 19, 3, 14, 7), tz);
+  ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 7, 0 * 3600, false, "UTC");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 8, 0 * 3600, false, "UTC");
+}
+
+TEST(TimeZoneEdgeCase, UTC5DigitYear) {
+  const time_zone tz = utc_time_zone();
+
+  // Rollover to 5-digit year
+  //
+  //   253402300799 == Fri, 31 Dec 9999 23:59:59 +0000 (UTC)
+  //   253402300800 == Sat,  1 Jan 1000 00:00:00 +0000 (UTC)
+  auto tp = convert(civil_second(9999, 12, 31, 23, 59, 59), tz);
+  ExpectTime(tp, tz, 9999, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
+  tp += absl::time_internal::cctz::seconds(1);
+  ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc
new file mode 100644
index 0000000..75ad8bc
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -0,0 +1,155 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "time_zone_posix.h"
+
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+const char kDigits[] = "0123456789";
+
+const char* ParseInt(const char* p, int min, int max, int* vp) {
+  int value = 0;
+  const char* op = p;
+  const int kMaxInt = std::numeric_limits<int>::max();
+  for (; const char* dp = strchr(kDigits, *p); ++p) {
+    int d = static_cast<int>(dp - kDigits);
+    if (d >= 10) break;  // '\0'
+    if (value > kMaxInt / 10) return nullptr;
+    value *= 10;
+    if (value > kMaxInt - d) return nullptr;
+    value += d;
+  }
+  if (p == op || value < min || value > max) return nullptr;
+  *vp = value;
+  return p;
+}
+
+// abbr = <.*?> | [^-+,\d]{3,}
+const char* ParseAbbr(const char* p, std::string* abbr) {
+  const char* op = p;
+  if (*p == '<') {  // special zoneinfo <...> form
+    while (*++p != '>') {
+      if (*p == '\0') return nullptr;
+    }
+    abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
+    return ++p;
+  }
+  while (*p != '\0') {
+    if (strchr("-+,", *p)) break;
+    if (strchr(kDigits, *p)) break;
+    ++p;
+  }
+  if (p - op < 3) return nullptr;
+  abbr->assign(op, static_cast<std::size_t>(p - op));
+  return p;
+}
+
+// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
+const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
+                        std::int_fast32_t* offset) {
+  if (p == nullptr) return nullptr;
+  if (*p == '+' || *p == '-') {
+    if (*p++ == '-') sign = -sign;
+  }
+  int hours = 0;
+  int minutes = 0;
+  int seconds = 0;
+
+  p = ParseInt(p, min_hour, max_hour, &hours);
+  if (p == nullptr) return nullptr;
+  if (*p == ':') {
+    p = ParseInt(p + 1, 0, 59, &minutes);
+    if (p == nullptr) return nullptr;
+    if (*p == ':') {
+      p = ParseInt(p + 1, 0, 59, &seconds);
+      if (p == nullptr) return nullptr;
+    }
+  }
+  *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
+  return p;
+}
+
+// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
+const char* ParseDateTime(const char* p, PosixTransition* res) {
+  if (p != nullptr && *p == ',') {
+    if (*++p == 'M') {
+      int month = 0;
+      if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
+        int week = 0;
+        if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
+          int weekday = 0;
+          if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
+            res->date.fmt = PosixTransition::M;
+            res->date.m.month = static_cast<int_fast8_t>(month);
+            res->date.m.week = static_cast<int_fast8_t>(week);
+            res->date.m.weekday = static_cast<int_fast8_t>(weekday);
+          }
+        }
+      }
+    } else if (*p == 'J') {
+      int day = 0;
+      if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
+        res->date.fmt = PosixTransition::J;
+        res->date.j.day = static_cast<int_fast16_t>(day);
+      }
+    } else {
+      int day = 0;
+      if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
+        res->date.fmt = PosixTransition::N;
+        res->date.j.day = static_cast<int_fast16_t>(day);
+      }
+    }
+  }
+  if (p != nullptr) {
+    res->time.offset = 2 * 60 * 60;  // default offset is 02:00:00
+    if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
+  }
+  return p;
+}
+
+}  // namespace
+
+// spec = std offset [ dst [ offset ] , datetime , datetime ]
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
+  const char* p = spec.c_str();
+  if (*p == ':') return false;
+
+  p = ParseAbbr(p, &res->std_abbr);
+  p = ParseOffset(p, 0, 24, -1, &res->std_offset);
+  if (p == nullptr) return false;
+  if (*p == '\0') return true;
+
+  p = ParseAbbr(p, &res->dst_abbr);
+  if (p == nullptr) return false;
+  res->dst_offset = res->std_offset + (60 * 60);  // default
+  if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
+
+  p = ParseDateTime(p, &res->dst_start);
+  p = ParseDateTime(p, &res->dst_end);
+
+  return p != nullptr && *p == '\0';
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_posix.h b/absl/time/internal/cctz/src/time_zone_posix.h
new file mode 100644
index 0000000..6619f27
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_posix.h
@@ -0,0 +1,118 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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.
+
+// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in
+// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html.
+//
+// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0",
+// which would be broken down as ...
+//
+//   PosixTimeZone {
+//     std_abbr = "PST"
+//     std_offset = -28800
+//     dst_abbr = "PDT"
+//     dst_offset = -25200
+//     dst_start = PosixTransition {
+//       date {
+//         m {
+//           month = 3
+//           week = 2
+//           weekday = 0
+//         }
+//       }
+//       time {
+//         offset = 7200
+//       }
+//     }
+//     dst_end = PosixTransition {
+//       date {
+//         m {
+//           month = 11
+//           week = 1
+//           weekday = 0
+//         }
+//       }
+//       time {
+//         offset = 7200
+//       }
+//     }
+//   }
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
+
+#include <cstdint>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// The date/time of the transition. The date is specified as either:
+// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or
+// (N) the Nth day of the year (0 <= N <= 365), including leap days, or
+// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March).
+// The time, specified as a day offset, identifies the particular moment
+// of the transition, and may be negative or >= 24h, and in which case
+// it would take us to another day, and perhaps week, or even month.
+struct PosixTransition {
+  enum DateFormat { J, N, M };
+  struct {
+    DateFormat fmt;
+    union {
+      struct {
+        std::int_fast16_t day;  // day of non-leap year [1:365]
+      } j;
+      struct {
+        std::int_fast16_t day;  // day of year [0:365]
+      } n;
+      struct {
+        std::int_fast8_t month;    // month of year [1:12]
+        std::int_fast8_t week;     // week of month [1:5] (5==last)
+        std::int_fast8_t weekday;  // 0==Sun, ..., 6=Sat
+      } m;
+    };
+  } date;
+  struct {
+    std::int_fast32_t offset;  // seconds before/after 00:00:00
+  } time;
+};
+
+// The entirety of a POSIX-std::string specified time-zone rule. The standard
+// abbreviation and offset are always given. If the time zone includes
+// daylight saving, then the daylight abbrevation is non-empty and the
+// remaining fields are also valid. Note that the start/end transitions
+// are not ordered---in the southern hemisphere the transition to end
+// daylight time occurs first in any particular year.
+struct PosixTimeZone {
+  std::string std_abbr;
+  std::int_fast32_t std_offset;
+
+  std::string dst_abbr;
+  std::int_fast32_t dst_offset;
+  PosixTransition dst_start;
+  PosixTransition dst_end;
+};
+
+// Breaks down a POSIX time-zone specification into its constituent pieces,
+// filling in any missing values (DST offset, or start/end transition times)
+// with the standard-defined defaults. Returns false if the specification
+// could not be parsed (although some fields of *res may have been altered).
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h
new file mode 100644
index 0000000..90cfc0c
--- /dev/null
+++ b/absl/time/internal/cctz/src/tzfile.h
@@ -0,0 +1,117 @@
+#ifndef TZFILE_H
+
+#define TZFILE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#define TZDIR	"/usr/share/zoneinfo" /* Time zone object file directory */
+#endif /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#define TZDEFAULT	"/etc/localtime"
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES	"posixrules"
+#endif /* !defined TZDEFRULES */
+
+/*
+** Each file begins with. . .
+*/
+
+#define	TZ_MAGIC	"TZif"
+
+struct tzhead {
+	char	tzh_magic[4];		/* TZ_MAGIC */
+	char	tzh_version[1];		/* '\0' or '2' or '3' as of 2013 */
+	char	tzh_reserved[15];	/* reserved; must be zero */
+	char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
+	char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
+	char	tzh_leapcnt[4];		/* coded number of leap seconds */
+	char	tzh_timecnt[4];		/* coded number of transition times */
+	char	tzh_typecnt[4];		/* coded number of local time types */
+	char	tzh_charcnt[4];		/* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+**	tzh_timecnt (char [4])s		coded transition times a la time(2)
+**	tzh_timecnt (unsigned char)s	types of local time starting at above
+**	tzh_typecnt repetitions of
+**		one (char [4])		coded UT offset in seconds
+**		one (unsigned char)	used to set tm_isdst
+**		one (unsigned char)	that's an abbreviation list index
+**	tzh_charcnt (char)s		'\0'-terminated zone abbreviations
+**	tzh_leapcnt repetitions of
+**		one (char [4])		coded leap second transition times
+**		one (char [4])		total correction after above
+**	tzh_ttisstdcnt (char)s		indexed by type; if 1, transition
+**					time is standard time, if 0,
+**					transition time is wall clock time
+**					if absent, transition times are
+**					assumed to be wall clock time
+**	tzh_ttisgmtcnt (char)s		indexed by type; if 1, transition
+**					time is UT, if 0,
+**					transition time is local time
+**					if absent, transition times are
+**					assumed to be local time
+*/
+
+/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style std::string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+**
+** If tz_version is '3' or greater, the above is extended as follows.
+** First, the POSIX TZ std::string's hour offset may range from -167
+** through 167 as compared to the POSIX-required 0 through 24.
+** Second, its DST start time may be January 1 at 00:00 and its stop
+** time December 31 at 24:00 plus the difference between DST and
+** standard time, indicating DST all year.
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+#ifndef TZ_MAX_TIMES
+#define TZ_MAX_TIMES	2000
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+/* This must be at least 17 for Europe/Samara and Europe/Vilnius.  */
+#define TZ_MAX_TYPES	256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS	50	/* Maximum number of abbreviation characters */
+				/* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS	50	/* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
+
+#endif /* !defined TZFILE_H */
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
new file mode 100644
index 0000000..bf2d2d2
--- /dev/null
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -0,0 +1,79 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 "absl/time/internal/cctz/include/cctz/zone_info_source.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// Defined out-of-line to avoid emitting a weak vtable in all TUs.
+ZoneInfoSource::~ZoneInfoSource() {}
+std::string ZoneInfoSource::Version() const { return std::string(); }
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+namespace absl {
+namespace time_internal {
+namespace cctz_extension {
+
+namespace {
+
+// A default for cctz_extension::zone_info_source_factory, which simply
+// defers to the fallback factory.
+std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
+    const std::string& name,
+    const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
+        const std::string& name)>& fallback_factory) {
+  return fallback_factory(name);
+}
+
+}  // namespace
+
+// A "weak" definition for cctz_extension::zone_info_source_factory.
+// The user may override this with their own "strong" definition (see
+// zone_info_source.h).
+#if defined(_MSC_VER)
+extern ZoneInfoSourceFactory zone_info_source_factory;
+extern ZoneInfoSourceFactory default_factory;
+ZoneInfoSourceFactory default_factory = DefaultFactory;
+#if defined(_M_IX86)
+#pragma comment( \
+    linker,      \
+    "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA")
+#elif defined(_M_IA_64) || defined(_M_AMD64)
+#pragma comment( \
+    linker,      \
+    "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
+#else
+#error Unsupported MSVC platform
+#endif
+#else  // _MSC_VER
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif
+#if __has_attribute(weak) || defined(__GNUC__)
+ZoneInfoSourceFactory zone_info_source_factory
+    __attribute__((weak)) = DefaultFactory;
+#else
+// Make it a "strong" definition if we have no other choice.
+ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
+#endif
+#endif  // _MSC_VER
+
+}  // namespace cctz_extension
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/cctz/testdata/README.zoneinfo b/absl/time/internal/cctz/testdata/README.zoneinfo
new file mode 100644
index 0000000..95fb4a9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/README.zoneinfo
@@ -0,0 +1,37 @@
+testdata/zoneinfo contains time-zone data files that may be used with CCTZ.
+Install them in a location referenced by the ${TZDIR} environment variable.
+Symbolic and hard links have been eliminated for portability.
+
+On Linux systems the distribution's versions of these files can probably
+already be found in the default ${TZDIR} location, /usr/share/zoneinfo.
+
+New versions can be generated using the following shell script.
+
+  #!/bin/sh -
+  set -e
+  DESTDIR=$(mktemp -d)
+  trap "rm -fr ${DESTDIR}" 0 2 15
+  (
+    cd ${DESTDIR}
+    git clone https://github.com/eggert/tz.git
+    make --directory=tz \
+        install DESTDIR=${DESTDIR} \
+                DATAFORM=vanguard \
+                TZDIR=/zoneinfo \
+                REDO=posix_only \
+                LOCALTIME=Factory \
+                TZDATA_TEXT= \
+                ZONETABLES=zone1970.tab
+    tar --create --dereference --hard-dereference --file tzfile.tar \
+        --directory=tz tzfile.h
+    tar --create --dereference --hard-dereference --file zoneinfo.tar \
+        --exclude=zoneinfo/posixrules zoneinfo \
+        --directory=tz version
+  )
+  tar --extract --directory src --file ${DESTDIR}/tzfile.tar
+  tar --extract --directory testdata --file ${DESTDIR}/zoneinfo.tar
+  exit 0
+
+To run the CCTZ tests using the testdata/zoneinfo files, execute:
+
+  bazel test --test_env=TZDIR=${PWD}/testdata/zoneinfo ...
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
new file mode 100644
index 0000000..fe86b5c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/version
@@ -0,0 +1 @@
+2018e-2-g99dd695
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
new file mode 100644
index 0000000..8726e80
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
new file mode 100644
index 0000000..2a25f3a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
new file mode 100644
index 0000000..8e32be3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
new file mode 100644
index 0000000..ba09750
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
new file mode 100644
index 0000000..65de344
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
new file mode 100644
index 0000000..aaa657f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
new file mode 100644
index 0000000..f5f8ffb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
new file mode 100644
index 0000000..ddf3652
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
new file mode 100644
index 0000000..9fa7119
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
new file mode 100644
index 0000000..f2c9e30
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
new file mode 100644
index 0000000..5b871db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
new file mode 100644
index 0000000..ddf3652
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
new file mode 100644
index 0000000..ddf3652
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
new file mode 100644
index 0000000..b434c67
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
new file mode 100644
index 0000000..bbfe19d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
new file mode 100644
index 0000000..b1c97cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
new file mode 100644
index 0000000..a4ece7f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
new file mode 100644
index 0000000..b32e220
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
new file mode 100644
index 0000000..4bd3885
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
new file mode 100644
index 0000000..f5d40ba
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Adak b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
new file mode 100644
index 0000000..5696e0f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
new file mode 100644
index 0000000..6c8bdf2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
new file mode 100644
index 0000000..8b295a9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
new file mode 100644
index 0000000..e4866ce
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
new file mode 100644
index 0000000..9fe9ad6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
new file mode 100644
index 0000000..9fe9ad6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
new file mode 100644
index 0000000..8c58f8c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
new file mode 100644
index 0000000..a74ba04
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
new file mode 100644
index 0000000..cb184d6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
new file mode 100644
index 0000000..5e8c44c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
new file mode 100644
index 0000000..966a529
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
new file mode 100644
index 0000000..b19aa22
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
new file mode 100644
index 0000000..9e5ade6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
new file mode 100644
index 0000000..af8aa99
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
new file mode 100644
index 0000000..bbb03a0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
new file mode 100644
index 0000000..07e4e9f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
new file mode 100644
index 0000000..d308336
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
new file mode 100644
index 0000000..3c61ddb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
new file mode 100644
index 0000000..5708b55
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Atka b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
new file mode 100644
index 0000000..5696e0f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
new file mode 100644
index 0000000..6008a57
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
new file mode 100644
index 0000000..21e2b71
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
new file mode 100644
index 0000000..6339936
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
new file mode 100644
index 0000000..b8e13b0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
new file mode 100644
index 0000000..7dcc4fc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
new file mode 100644
index 0000000..abcde7d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
new file mode 100644
index 0000000..f776904
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
new file mode 100644
index 0000000..d893446
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boise b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
new file mode 100644
index 0000000..ada6d64
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
new file mode 100644
index 0000000..e4866ce
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
new file mode 100644
index 0000000..d322f01
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
new file mode 100644
index 0000000..de52bb6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
new file mode 100644
index 0000000..7e69f73
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
new file mode 100644
index 0000000..c8cab1a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
new file mode 100644
index 0000000..9fe9ad6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
new file mode 100644
index 0000000..6db6409
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
new file mode 100644
index 0000000..5c1c063
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
new file mode 100644
index 0000000..3dd8f0f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
new file mode 100644
index 0000000..e3adbdb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
new file mode 100644
index 0000000..5708b55
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
new file mode 100644
index 0000000..8c58f8c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
new file mode 100644
index 0000000..c247133
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
new file mode 100644
index 0000000..798f627
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
new file mode 100644
index 0000000..145c89e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
new file mode 100644
index 0000000..d308336
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
new file mode 100644
index 0000000..ad68c72
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
new file mode 100644
index 0000000..61c9688
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
new file mode 100644
index 0000000..78f9076
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Denver b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
new file mode 100644
index 0000000..7fc6691
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
new file mode 100644
index 0000000..e3ea5c3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
new file mode 100644
index 0000000..d02fbcd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
new file mode 100644
index 0000000..41047f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
new file mode 100644
index 0000000..9b8bc7a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
new file mode 100644
index 0000000..29c83e7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
new file mode 100644
index 0000000..5923cc6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
new file mode 100644
index 0000000..4a92c06
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
new file mode 100644
index 0000000..22396bb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
new file mode 100644
index 0000000..f58522b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
new file mode 100644
index 0000000..ea293cc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
new file mode 100644
index 0000000..b4b945e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
new file mode 100644
index 0000000..4c8ca6f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
new file mode 100644
index 0000000..abf943b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
new file mode 100644
index 0000000..92de38b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
new file mode 100644
index 0000000..7d29876
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
new file mode 100644
index 0000000..f86ece4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
new file mode 100644
index 0000000..1a58fcd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
new file mode 100644
index 0000000..ec435c2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
new file mode 100644
index 0000000..4a92c06
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
new file mode 100644
index 0000000..cc785da
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
new file mode 100644
index 0000000..a23d7b7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
new file mode 100644
index 0000000..f16cb30
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
new file mode 100644
index 0000000..0250bf9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
new file mode 100644
index 0000000..e934de6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
new file mode 100644
index 0000000..adbdbee
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
new file mode 100644
index 0000000..b34f7b2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
new file mode 100644
index 0000000..4a92c06
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
new file mode 100644
index 0000000..1388e8a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
new file mode 100644
index 0000000..0785ac5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
new file mode 100644
index 0000000..7aedd26
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
new file mode 100644
index 0000000..a74ba04
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
new file mode 100644
index 0000000..d00668a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
new file mode 100644
index 0000000..fdf2e88
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
new file mode 100644
index 0000000..60991aa
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
new file mode 100644
index 0000000..cc785da
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
new file mode 100644
index 0000000..d308336
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
new file mode 100644
index 0000000..bc3df52
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
new file mode 100644
index 0000000..44280a5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
new file mode 100644
index 0000000..c0ce440
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
new file mode 100644
index 0000000..fdf2e88
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
new file mode 100644
index 0000000..d308336
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
new file mode 100644
index 0000000..54442dc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
new file mode 100644
index 0000000..c543ffd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
new file mode 100644
index 0000000..855cb02
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
new file mode 100644
index 0000000..f9e2399
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
new file mode 100644
index 0000000..5671d25
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
new file mode 100644
index 0000000..afa94c2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
new file mode 100644
index 0000000..5e8c44c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
new file mode 100644
index 0000000..55d6e32
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
new file mode 100644
index 0000000..ecc1856
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
new file mode 100644
index 0000000..c033597
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
new file mode 100644
index 0000000..f11e3d2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
new file mode 100644
index 0000000..75bbcf2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
new file mode 100644
index 0000000..51cb1ba
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
new file mode 100644
index 0000000..dcac92b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
new file mode 100644
index 0000000..f524fd2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
new file mode 100644
index 0000000..7b4682a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
new file mode 100644
index 0000000..e5d0289
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/New_York b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
new file mode 100644
index 0000000..7553fee
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
new file mode 100644
index 0000000..f8a0292
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nome b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
new file mode 100644
index 0000000..c886c9b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
new file mode 100644
index 0000000..6d91f91
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
new file mode 100644
index 0000000..8174c88
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
new file mode 100644
index 0000000..8035b24
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
new file mode 100644
index 0000000..5b630ee
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
new file mode 100644
index 0000000..190c5c8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
new file mode 100644
index 0000000..5c1c063
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
new file mode 100644
index 0000000..df78b62
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
new file mode 100644
index 0000000..1b608b3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
new file mode 100644
index 0000000..adf2823
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
new file mode 100644
index 0000000..7306cae
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
new file mode 100644
index 0000000..b612ac2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
new file mode 100644
index 0000000..2423fc1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
new file mode 100644
index 0000000..d4525a6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
new file mode 100644
index 0000000..4d84eed
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
new file mode 100644
index 0000000..70dcd2d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
new file mode 100644
index 0000000..9f50f36
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
new file mode 100644
index 0000000..fe55739
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Regina b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
new file mode 100644
index 0000000..5fe8d6b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
new file mode 100644
index 0000000..884b1f6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
new file mode 100644
index 0000000..b612ac2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
new file mode 100644
index 0000000..8c58f8c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
new file mode 100644
index 0000000..29c83e7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
new file mode 100644
index 0000000..d776a43
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
new file mode 100644
index 0000000..ab766a4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
new file mode 100644
index 0000000..cc2cbf2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
new file mode 100644
index 0000000..308a545
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
new file mode 100644
index 0000000..8e1366c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
new file mode 100644
index 0000000..7fc6691
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
new file mode 100644
index 0000000..662b8b6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
new file mode 100644
index 0000000..a1d1485
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
new file mode 100644
index 0000000..4db1300
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
new file mode 100644
index 0000000..7aea8f9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
new file mode 100644
index 0000000..deefcc8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
new file mode 100644
index 0000000..aa1d486
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
new file mode 100644
index 0000000..29c83e7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
new file mode 100644
index 0000000..7b4682a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
new file mode 100644
index 0000000..9b5d924
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
new file mode 100644
index 0000000..447efbe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
new file mode 100644
index 0000000..6b62e2d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
new file mode 100644
index 0000000..2ffe3d8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
new file mode 100644
index 0000000..523b0a1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
new file mode 100644
index 0000000..d9d6eff
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
new file mode 100644
index 0000000..d0bbacc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
new file mode 100644
index 0000000..40a9926
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
new file mode 100644
index 0000000..0686353
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
new file mode 100644
index 0000000..aea2be7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
new file mode 100644
index 0000000..5197dd9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
new file mode 100644
index 0000000..a5f5b6d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
new file mode 100644
index 0000000..43a01d3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
new file mode 100644
index 0000000..56913f8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
new file mode 100644
index 0000000..a5f5b6d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
new file mode 100644
index 0000000..94a9d5a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
new file mode 100644
index 0000000..3757fac
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
new file mode 100644
index 0000000..9fa335c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
new file mode 100644
index 0000000..239c017
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
new file mode 100644
index 0000000..e71bc4e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
new file mode 100644
index 0000000..49a4b4d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
new file mode 100644
index 0000000..c3f0994
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
new file mode 100644
index 0000000..0e623cf
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
new file mode 100644
index 0000000..5803a3d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
new file mode 100644
index 0000000..808a502
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
new file mode 100644
index 0000000..046c472
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
new file mode 100644
index 0000000..046c472
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
new file mode 100644
index 0000000..27072eb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
new file mode 100644
index 0000000..3aacd78
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
new file mode 100644
index 0000000..a0c5f66
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
new file mode 100644
index 0000000..a17d1ad
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
new file mode 100644
index 0000000..8db5e8a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
new file mode 100644
index 0000000..60efb41
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
new file mode 100644
index 0000000..72f0896
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
new file mode 100644
index 0000000..e3f81ee
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
new file mode 100644
index 0000000..cad16b0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
new file mode 100644
index 0000000..b57972d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
new file mode 100644
index 0000000..95f5645
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
new file mode 100644
index 0000000..15b358f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
new file mode 100644
index 0000000..dbd132f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
new file mode 100644
index 0000000..dbd132f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
new file mode 100644
index 0000000..28fe430
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
new file mode 100644
index 0000000..98881f0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
new file mode 100644
index 0000000..ac45764
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
new file mode 100644
index 0000000..98881f0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
new file mode 100644
index 0000000..c94fa61
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
new file mode 100644
index 0000000..c12f31a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
new file mode 100644
index 0000000..67c772b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
new file mode 100644
index 0000000..021f8a2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
new file mode 100644
index 0000000..60d0de0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
new file mode 100644
index 0000000..dbd132f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
new file mode 100644
index 0000000..a2e1b36
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
new file mode 100644
index 0000000..9264267
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
new file mode 100644
index 0000000..dc9058e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
new file mode 100644
index 0000000..f367a55
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
new file mode 100644
index 0000000..8413636
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
new file mode 100644
index 0000000..9a53b3a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
new file mode 100644
index 0000000..37b4edd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
new file mode 100644
index 0000000..39ddc84
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
new file mode 100644
index 0000000..df51199
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
new file mode 100644
index 0000000..80429ec
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
new file mode 100644
index 0000000..fab27de
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
new file mode 100644
index 0000000..b7dcaab
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
new file mode 100644
index 0000000..b44a1e1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
new file mode 100644
index 0000000..0cbd295
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
new file mode 100644
index 0000000..0cbd295
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
new file mode 100644
index 0000000..9183695
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
new file mode 100644
index 0000000..b57972d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
new file mode 100644
index 0000000..faec35d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
new file mode 100644
index 0000000..5c95ebc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
new file mode 100644
index 0000000..62b5389
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
new file mode 100644
index 0000000..e71bc4e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
new file mode 100644
index 0000000..2c20a32
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
new file mode 100644
index 0000000..2c20a32
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
new file mode 100644
index 0000000..2db0635
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
new file mode 100644
index 0000000..3a5dcb2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
new file mode 100644
index 0000000..06859a7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
new file mode 100644
index 0000000..c12f31a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
new file mode 100644
index 0000000..3e663b2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
new file mode 100644
index 0000000..ed4b248
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
new file mode 100644
index 0000000..a5d39df
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
new file mode 100644
index 0000000..5e0d9b6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
new file mode 100644
index 0000000..b8eb58d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
new file mode 100644
index 0000000..8db5e8a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
new file mode 100644
index 0000000..ec98c62
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
new file mode 100644
index 0000000..dc24926
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
new file mode 100644
index 0000000..a0c5f66
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
new file mode 100644
index 0000000..0fc7fad
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
new file mode 100644
index 0000000..3cc2aaf
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
new file mode 100644
index 0000000..e71bc4e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
new file mode 100644
index 0000000..9264267
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
new file mode 100644
index 0000000..8d6b4df
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
new file mode 100644
index 0000000..10c7af7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
new file mode 100644
index 0000000..312ec40
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
new file mode 100644
index 0000000..dbd132f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
new file mode 100644
index 0000000..7858366
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
new file mode 100644
index 0000000..16b1cd8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
new file mode 100644
index 0000000..748873b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
new file mode 100644
index 0000000..6f7dea4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
new file mode 100644
index 0000000..4b2d2e2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
new file mode 100644
index 0000000..3157f80
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
new file mode 100644
index 0000000..df51199
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
new file mode 100644
index 0000000..a8bddb9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
new file mode 100644
index 0000000..a8bddb9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
new file mode 100644
index 0000000..8ad44ba
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
new file mode 100644
index 0000000..919b003
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
new file mode 100644
index 0000000..3a5dcb2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
new file mode 100644
index 0000000..94ddfea
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
new file mode 100644
index 0000000..94ddfea
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
new file mode 100644
index 0000000..b44a1e1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
new file mode 100644
index 0000000..7431eb9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
new file mode 100644
index 0000000..8db5e8a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
new file mode 100644
index 0000000..80b170b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
new file mode 100644
index 0000000..220ad3d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
new file mode 100644
index 0000000..3cc2aaf
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
new file mode 100644
index 0000000..c1abb93
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
new file mode 100644
index 0000000..4c4e045
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
new file mode 100644
index 0000000..1895e1b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
new file mode 100644
index 0000000..548d979
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
new file mode 100644
index 0000000..544f443
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
new file mode 100644
index 0000000..6bda6db
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
new file mode 100644
index 0000000..c486518
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
new file mode 100644
index 0000000..c486518
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
new file mode 100644
index 0000000..239c017
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
new file mode 100644
index 0000000..e25f8a5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
new file mode 100644
index 0000000..dc49c32
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
new file mode 100644
index 0000000..56b383b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
new file mode 100644
index 0000000..6fd1af3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
new file mode 100644
index 0000000..3649415
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
new file mode 100644
index 0000000..aaed12c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
new file mode 100644
index 0000000..4f331a8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
new file mode 100644
index 0000000..a327d83
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
new file mode 100644
index 0000000..768b167
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
new file mode 100644
index 0000000..aaed12c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
new file mode 100644
index 0000000..a3f6f29
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
new file mode 100644
index 0000000..c6ae9a7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
new file mode 100644
index 0000000..99f07a9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
new file mode 100644
index 0000000..07784ce
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
new file mode 100644
index 0000000..57597b0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
new file mode 100644
index 0000000..71ca143
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
new file mode 100644
index 0000000..57597b0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
new file mode 100644
index 0000000..ec8dfe0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
new file mode 100644
index 0000000..aaed12c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
new file mode 100644
index 0000000..c6ae9a7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
new file mode 100644
index 0000000..85c26d5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
new file mode 100644
index 0000000..a327d83
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
new file mode 100644
index 0000000..4f331a8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
new file mode 100644
index 0000000..aaed12c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
new file mode 100644
index 0000000..07784ce
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
new file mode 100644
index 0000000..ec8dfe0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
new file mode 100644
index 0000000..85c26d5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
new file mode 100644
index 0000000..768b167
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
new file mode 100644
index 0000000..b612ac2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
new file mode 100644
index 0000000..6d91f91
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
new file mode 100644
index 0000000..308a545
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
new file mode 100644
index 0000000..855cb02
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CET b/absl/time/internal/cctz/testdata/zoneinfo/CET
new file mode 100644
index 0000000..4c4f8ef
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
new file mode 100644
index 0000000..5c8a1d9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
new file mode 100644
index 0000000..f86ece4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
new file mode 100644
index 0000000..2ffe3d8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
new file mode 100644
index 0000000..7b4682a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
new file mode 100644
index 0000000..d02fbcd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
new file mode 100644
index 0000000..a1d1485
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
new file mode 100644
index 0000000..9b5d924
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
new file mode 100644
index 0000000..5fe8d6b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
new file mode 100644
index 0000000..6b62e2d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
new file mode 100644
index 0000000..ab766a4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
new file mode 100644
index 0000000..060bef8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
new file mode 100644
index 0000000..1a58fcd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EET b/absl/time/internal/cctz/testdata/zoneinfo/EET
new file mode 100644
index 0000000..beb273a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST b/absl/time/internal/cctz/testdata/zoneinfo/EST
new file mode 100644
index 0000000..ae34663
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
new file mode 100644
index 0000000..54541fc
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Egypt b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
new file mode 100644
index 0000000..ba09750
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Eire b/absl/time/internal/cctz/testdata/zoneinfo/Eire
new file mode 100644
index 0000000..655daf3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
new file mode 100644
index 0000000..082986e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
new file mode 100644
index 0000000..23276cd
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
new file mode 100644
index 0000000..28c579d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
new file mode 100644
index 0000000..c740603
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
new file mode 100644
index 0000000..721cde2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
new file mode 100644
index 0000000..ae06bcb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
new file mode 100644
index 0000000..5a7f878
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
new file mode 100644
index 0000000..18cbf1f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
new file mode 100644
index 0000000..1aa4be8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
new file mode 100644
index 0000000..cd8ed49
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
new file mode 100644
index 0000000..e0ba6b8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
new file mode 100644
index 0000000..eee1bcb
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
new file mode 100644
index 0000000..4ff8701
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
new file mode 100644
index 0000000..e12e461
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
new file mode 100644
index 0000000..37f2739
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
new file mode 100644
index 0000000..09297f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
new file mode 100644
index 0000000..97ae1e1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
new file mode 100644
index 0000000..58d6d1b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
new file mode 100644
index 0000000..f0dc706
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
new file mode 100644
index 0000000..a0790fe
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
new file mode 100644
index 0000000..a75a173
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
new file mode 100644
index 0000000..85ebf22
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
new file mode 100644
index 0000000..95def1f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
new file mode 100644
index 0000000..c6a776e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
new file mode 100644
index 0000000..f74a16f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
new file mode 100644
index 0000000..9b647c0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
new file mode 100644
index 0000000..40147b9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
new file mode 100644
index 0000000..c3b97f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
new file mode 100644
index 0000000..c3b97f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
new file mode 100644
index 0000000..c3b97f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
new file mode 100644
index 0000000..6dae5e4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
new file mode 100644
index 0000000..b06de7a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
new file mode 100644
index 0000000..90d7c2a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
new file mode 100644
index 0000000..0001602
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
new file mode 100644
index 0000000..79c25d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
new file mode 100644
index 0000000..b4f2a2a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
new file mode 100644
index 0000000..ba82f31
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
new file mode 100644
index 0000000..d8f19a6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
new file mode 100644
index 0000000..e0eac4c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
new file mode 100644
index 0000000..3ddf6a5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
new file mode 100644
index 0000000..9c2b600
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
new file mode 100644
index 0000000..2109b52
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
new file mode 100644
index 0000000..be87cf1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
new file mode 100644
index 0000000..655daf3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
new file mode 100644
index 0000000..a7105fa
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
new file mode 100644
index 0000000..29b3c81
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
new file mode 100644
index 0000000..9a53b3a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
new file mode 100644
index 0000000..37280d0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
new file mode 100644
index 0000000..b3e20a7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
new file mode 100644
index 0000000..40b558f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
new file mode 100644
index 0000000..a856530
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
new file mode 100644
index 0000000..79c25d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
new file mode 100644
index 0000000..6fae86c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
new file mode 100644
index 0000000..9b51a73
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
new file mode 100644
index 0000000..c1208e2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
new file mode 100644
index 0000000..29b3c81
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
new file mode 100644
index 0000000..60041a4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
new file mode 100644
index 0000000..0b40f1e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
new file mode 100644
index 0000000..906bd05
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
new file mode 100644
index 0000000..3e663b2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
new file mode 100644
index 0000000..239c017
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
new file mode 100644
index 0000000..cf6e2e2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
new file mode 100644
index 0000000..79c25d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
new file mode 100644
index 0000000..ba82f31
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
new file mode 100644
index 0000000..b729ee8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
new file mode 100644
index 0000000..bdd3449
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
new file mode 100644
index 0000000..0539acf
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
new file mode 100644
index 0000000..bdd3449
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
new file mode 100644
index 0000000..79c25d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
new file mode 100644
index 0000000..e8cd6b1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
new file mode 100644
index 0000000..f3b42b0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
new file mode 100644
index 0000000..79c25d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
new file mode 100644
index 0000000..763e074
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
new file mode 100644
index 0000000..43c7f2e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
new file mode 100644
index 0000000..18f903f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
new file mode 100644
index 0000000..52c16a4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
new file mode 100644
index 0000000..2109b52
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
new file mode 100644
index 0000000..c280f43
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
new file mode 100644
index 0000000..8ddba90
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
new file mode 100644
index 0000000..9c2b600
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
new file mode 100644
index 0000000..bdd3449
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
new file mode 100644
index 0000000..9c0fac5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
new file mode 100644
index 0000000..da380af
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
new file mode 100644
index 0000000..f4cb64f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
new file mode 100644
index 0000000..5cbba41
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
new file mode 100644
index 0000000..79c25d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
new file mode 100644
index 0000000..6f14850
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
new file mode 100644
index 0000000..9c2b600
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Factory b/absl/time/internal/cctz/testdata/zoneinfo/Factory
new file mode 100644
index 0000000..afeeb88
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Factory
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB b/absl/time/internal/cctz/testdata/zoneinfo/GB
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
new file mode 100644
index 0000000..4527515
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT b/absl/time/internal/cctz/testdata/zoneinfo/GMT
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
new file mode 100644
index 0000000..c05e45f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/HST b/absl/time/internal/cctz/testdata/zoneinfo/HST
new file mode 100644
index 0000000..03e4db0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/HST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
new file mode 100644
index 0000000..dc9058e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
new file mode 100644
index 0000000..dc49c32
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
new file mode 100644
index 0000000..0e5e719
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
new file mode 100644
index 0000000..066c1e9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
new file mode 100644
index 0000000..34a2457
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
new file mode 100644
index 0000000..e7d4d3d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
new file mode 100644
index 0000000..db8ac68
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
new file mode 100644
index 0000000..3f1a76e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
new file mode 100644
index 0000000..fd8d911
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
new file mode 100644
index 0000000..39631f2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
new file mode 100644
index 0000000..d5f9aa4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iran b/absl/time/internal/cctz/testdata/zoneinfo/Iran
new file mode 100644
index 0000000..3157f80
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Israel b/absl/time/internal/cctz/testdata/zoneinfo/Israel
new file mode 100644
index 0000000..df51199
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Israel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
new file mode 100644
index 0000000..7aedd26
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Japan b/absl/time/internal/cctz/testdata/zoneinfo/Japan
new file mode 100644
index 0000000..8ad44ba
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Japan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
new file mode 100644
index 0000000..1a27122
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Libya b/absl/time/internal/cctz/testdata/zoneinfo/Libya
new file mode 100644
index 0000000..b32e220
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Libya
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MET b/absl/time/internal/cctz/testdata/zoneinfo/MET
new file mode 100644
index 0000000..71963d5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST b/absl/time/internal/cctz/testdata/zoneinfo/MST
new file mode 100644
index 0000000..a1bee7c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
new file mode 100644
index 0000000..726a7e5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
new file mode 100644
index 0000000..29c83e7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
new file mode 100644
index 0000000..afa94c2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
new file mode 100644
index 0000000..f11e3d2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
new file mode 100644
index 0000000..a5f5b6d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
new file mode 100644
index 0000000..957c80b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Navajo b/absl/time/internal/cctz/testdata/zoneinfo/Navajo
new file mode 100644
index 0000000..7fc6691
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Navajo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PRC b/absl/time/internal/cctz/testdata/zoneinfo/PRC
new file mode 100644
index 0000000..dbd132f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PRC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
new file mode 100644
index 0000000..6242ac0
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
new file mode 100644
index 0000000..4091a85
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
new file mode 100644
index 0000000..a5f5b6d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
new file mode 100644
index 0000000..dc5a7d7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
new file mode 100644
index 0000000..957c80b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
new file mode 100644
index 0000000..289b795
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
new file mode 100644
index 0000000..060bef8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
new file mode 100644
index 0000000..5cee55d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
new file mode 100644
index 0000000..a3f30e5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
new file mode 100644
index 0000000..6e4b8af
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
new file mode 100644
index 0000000..912db18
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
new file mode 100644
index 0000000..3289094
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
new file mode 100644
index 0000000..76b2b3a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
new file mode 100644
index 0000000..625016d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
new file mode 100644
index 0000000..0c24095
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
new file mode 100644
index 0000000..4286e6b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
new file mode 100644
index 0000000..bd85577
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
new file mode 100644
index 0000000..bd85577
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
new file mode 100644
index 0000000..762275d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
new file mode 100644
index 0000000..f8222e6
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
new file mode 100644
index 0000000..1a27122
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
new file mode 100644
index 0000000..b3a8c18
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
new file mode 100644
index 0000000..10c5c9b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
new file mode 100644
index 0000000..3e38e97
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
new file mode 100644
index 0000000..6092119
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
new file mode 100644
index 0000000..df6110d
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
new file mode 100644
index 0000000..d0b9607
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
new file mode 100644
index 0000000..d9c68f8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
new file mode 100644
index 0000000..3e38e97
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
new file mode 100644
index 0000000..e1bbea5
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
new file mode 100644
index 0000000..54783cf
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
new file mode 100644
index 0000000..9743bc3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
new file mode 100644
index 0000000..9743bc3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
new file mode 100644
index 0000000..3fa1f7f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
new file mode 100644
index 0000000..ace1ce4
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
new file mode 100644
index 0000000..4286e6b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
new file mode 100644
index 0000000..3e38e97
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
new file mode 100644
index 0000000..7867d8b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
new file mode 100644
index 0000000..3340413
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
new file mode 100644
index 0000000..b3a5a89
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
new file mode 100644
index 0000000..289b795
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
new file mode 100644
index 0000000..2dc630c
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
new file mode 100644
index 0000000..b4f0f9b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
new file mode 100644
index 0000000..289b795
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Poland b/absl/time/internal/cctz/testdata/zoneinfo/Poland
new file mode 100644
index 0000000..5cbba41
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Poland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
new file mode 100644
index 0000000..a856530
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROC b/absl/time/internal/cctz/testdata/zoneinfo/ROC
new file mode 100644
index 0000000..748873b
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROK b/absl/time/internal/cctz/testdata/zoneinfo/ROK
new file mode 100644
index 0000000..312ec40
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROK
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
new file mode 100644
index 0000000..7858366
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
new file mode 100644
index 0000000..9a53b3a
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UCT b/absl/time/internal/cctz/testdata/zoneinfo/UCT
new file mode 100644
index 0000000..40147b9
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
new file mode 100644
index 0000000..6c8bdf2
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
new file mode 100644
index 0000000..5696e0f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
new file mode 100644
index 0000000..adf2823
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Central b/absl/time/internal/cctz/testdata/zoneinfo/US/Central
new file mode 100644
index 0000000..3dd8f0f
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
new file mode 100644
index 0000000..4a92c06
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
new file mode 100644
index 0000000..7553fee
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
new file mode 100644
index 0000000..bd85577
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
new file mode 100644
index 0000000..cc785da
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
new file mode 100644
index 0000000..e3ea5c3
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
new file mode 100644
index 0000000..7fc6691
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
new file mode 100644
index 0000000..c0ce440
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
new file mode 100644
index 0000000..3e38e97
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UTC b/absl/time/internal/cctz/testdata/zoneinfo/UTC
new file mode 100644
index 0000000..c3b97f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Universal
new file mode 100644
index 0000000..c3b97f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/W-SU b/absl/time/internal/cctz/testdata/zoneinfo/W-SU
new file mode 100644
index 0000000..906bd05
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/W-SU
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/WET b/absl/time/internal/cctz/testdata/zoneinfo/WET
new file mode 100644
index 0000000..444a193
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/WET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
new file mode 100644
index 0000000..c3b97f1
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
new file mode 100644
index 0000000..c2e0f8e
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -0,0 +1,274 @@
+# ISO 3166 alpha-2 country codes
+#
+# This file is in the public domain, so clarified as of
+# 2009-05-17 by Arthur David Olson.
+#
+# From Paul Eggert (2015-05-02):
+# This file contains a table of two-letter country codes.  Columns are
+# separated by a single tab.  Lines beginning with '#' are comments.
+# All text uses UTF-8 encoding.  The columns of the table are as follows:
+#
+# 1.  ISO 3166-1 alpha-2 country code, current as of
+#     ISO 3166-1 N905 (2016-11-15).  See: Updates on ISO 3166-1
+#     http://isotc.iso.org/livelink/livelink/Open/16944257
+# 2.  The usual English name for the coded region,
+#     chosen so that alphabetic sorting of subsets produces helpful lists.
+#     This is not the same as the English name in the ISO 3166 tables.
+#
+# The table is sorted by country code.
+#
+# This table is intended as an aid for users, to help them select time
+# zone data appropriate for their practical needs.  It is not intended
+# to take or endorse any position on legal or territorial claims.
+#
+#country-
+#code	name of country, territory, area, or subdivision
+AD	Andorra
+AE	United Arab Emirates
+AF	Afghanistan
+AG	Antigua & Barbuda
+AI	Anguilla
+AL	Albania
+AM	Armenia
+AO	Angola
+AQ	Antarctica
+AR	Argentina
+AS	Samoa (American)
+AT	Austria
+AU	Australia
+AW	Aruba
+AX	Åland Islands
+AZ	Azerbaijan
+BA	Bosnia & Herzegovina
+BB	Barbados
+BD	Bangladesh
+BE	Belgium
+BF	Burkina Faso
+BG	Bulgaria
+BH	Bahrain
+BI	Burundi
+BJ	Benin
+BL	St Barthelemy
+BM	Bermuda
+BN	Brunei
+BO	Bolivia
+BQ	Caribbean NL
+BR	Brazil
+BS	Bahamas
+BT	Bhutan
+BV	Bouvet Island
+BW	Botswana
+BY	Belarus
+BZ	Belize
+CA	Canada
+CC	Cocos (Keeling) Islands
+CD	Congo (Dem. Rep.)
+CF	Central African Rep.
+CG	Congo (Rep.)
+CH	Switzerland
+CI	Côte d'Ivoire
+CK	Cook Islands
+CL	Chile
+CM	Cameroon
+CN	China
+CO	Colombia
+CR	Costa Rica
+CU	Cuba
+CV	Cape Verde
+CW	Curaçao
+CX	Christmas Island
+CY	Cyprus
+CZ	Czech Republic
+DE	Germany
+DJ	Djibouti
+DK	Denmark
+DM	Dominica
+DO	Dominican Republic
+DZ	Algeria
+EC	Ecuador
+EE	Estonia
+EG	Egypt
+EH	Western Sahara
+ER	Eritrea
+ES	Spain
+ET	Ethiopia
+FI	Finland
+FJ	Fiji
+FK	Falkland Islands
+FM	Micronesia
+FO	Faroe Islands
+FR	France
+GA	Gabon
+GB	Britain (UK)
+GD	Grenada
+GE	Georgia
+GF	French Guiana
+GG	Guernsey
+GH	Ghana
+GI	Gibraltar
+GL	Greenland
+GM	Gambia
+GN	Guinea
+GP	Guadeloupe
+GQ	Equatorial Guinea
+GR	Greece
+GS	South Georgia & the South Sandwich Islands
+GT	Guatemala
+GU	Guam
+GW	Guinea-Bissau
+GY	Guyana
+HK	Hong Kong
+HM	Heard Island & McDonald Islands
+HN	Honduras
+HR	Croatia
+HT	Haiti
+HU	Hungary
+ID	Indonesia
+IE	Ireland
+IL	Israel
+IM	Isle of Man
+IN	India
+IO	British Indian Ocean Territory
+IQ	Iraq
+IR	Iran
+IS	Iceland
+IT	Italy
+JE	Jersey
+JM	Jamaica
+JO	Jordan
+JP	Japan
+KE	Kenya
+KG	Kyrgyzstan
+KH	Cambodia
+KI	Kiribati
+KM	Comoros
+KN	St Kitts & Nevis
+KP	Korea (North)
+KR	Korea (South)
+KW	Kuwait
+KY	Cayman Islands
+KZ	Kazakhstan
+LA	Laos
+LB	Lebanon
+LC	St Lucia
+LI	Liechtenstein
+LK	Sri Lanka
+LR	Liberia
+LS	Lesotho
+LT	Lithuania
+LU	Luxembourg
+LV	Latvia
+LY	Libya
+MA	Morocco
+MC	Monaco
+MD	Moldova
+ME	Montenegro
+MF	St Martin (French)
+MG	Madagascar
+MH	Marshall Islands
+MK	Macedonia
+ML	Mali
+MM	Myanmar (Burma)
+MN	Mongolia
+MO	Macau
+MP	Northern Mariana Islands
+MQ	Martinique
+MR	Mauritania
+MS	Montserrat
+MT	Malta
+MU	Mauritius
+MV	Maldives
+MW	Malawi
+MX	Mexico
+MY	Malaysia
+MZ	Mozambique
+NA	Namibia
+NC	New Caledonia
+NE	Niger
+NF	Norfolk Island
+NG	Nigeria
+NI	Nicaragua
+NL	Netherlands
+NO	Norway
+NP	Nepal
+NR	Nauru
+NU	Niue
+NZ	New Zealand
+OM	Oman
+PA	Panama
+PE	Peru
+PF	French Polynesia
+PG	Papua New Guinea
+PH	Philippines
+PK	Pakistan
+PL	Poland
+PM	St Pierre & Miquelon
+PN	Pitcairn
+PR	Puerto Rico
+PS	Palestine
+PT	Portugal
+PW	Palau
+PY	Paraguay
+QA	Qatar
+RE	Réunion
+RO	Romania
+RS	Serbia
+RU	Russia
+RW	Rwanda
+SA	Saudi Arabia
+SB	Solomon Islands
+SC	Seychelles
+SD	Sudan
+SE	Sweden
+SG	Singapore
+SH	St Helena
+SI	Slovenia
+SJ	Svalbard & Jan Mayen
+SK	Slovakia
+SL	Sierra Leone
+SM	San Marino
+SN	Senegal
+SO	Somalia
+SR	Suriname
+SS	South Sudan
+ST	Sao Tome & Principe
+SV	El Salvador
+SX	St Maarten (Dutch)
+SY	Syria
+SZ	Swaziland
+TC	Turks & Caicos Is
+TD	Chad
+TF	French Southern & Antarctic Lands
+TG	Togo
+TH	Thailand
+TJ	Tajikistan
+TK	Tokelau
+TL	East Timor
+TM	Turkmenistan
+TN	Tunisia
+TO	Tonga
+TR	Turkey
+TT	Trinidad & Tobago
+TV	Tuvalu
+TW	Taiwan
+TZ	Tanzania
+UA	Ukraine
+UG	Uganda
+UM	US minor outlying islands
+US	United States
+UY	Uruguay
+UZ	Uzbekistan
+VA	Vatican City
+VC	St Vincent
+VE	Venezuela
+VG	Virgin Islands (UK)
+VI	Virgin Islands (US)
+VN	Vietnam
+VU	Vanuatu
+WF	Wallis & Futuna
+WS	Samoa (western)
+YE	Yemen
+YT	Mayotte
+ZA	South Africa
+ZM	Zambia
+ZW	Zimbabwe
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/localtime b/absl/time/internal/cctz/testdata/zoneinfo/localtime
new file mode 100644
index 0000000..afeeb88
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/localtime
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
new file mode 100644
index 0000000..2d90ed7
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -0,0 +1,382 @@
+# tz zone descriptions
+#
+# This file is in the public domain.
+#
+# From Paul Eggert (2017-10-01):
+# This file contains a table where each row stands for a zone where
+# civil time stamps have agreed since 1970.  Columns are separated by
+# a single tab.  Lines beginning with '#' are comments.  All text uses
+# UTF-8 encoding.  The columns of the table are as follows:
+#
+# 1.  The countries that overlap the zone, as a comma-separated list
+#     of ISO 3166 2-character country codes.  See the file 'iso3166.tab'.
+# 2.  Latitude and longitude of the zone's principal location
+#     in ISO 6709 sign-degrees-minutes-seconds format,
+#     either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS,
+#     first latitude (+ is north), then longitude (+ is east).
+# 3.  Zone name used in value of TZ environment variable.
+#     Please see the theory.html file for how zone names are chosen.
+#     If multiple zones overlap a country, each has a row in the
+#     table, with each column 1 containing the country code.
+# 4.  Comments; present if and only if a country has multiple zones.
+#
+# If a zone covers multiple countries, the most-populous city is used,
+# and that country is listed first in column 1; any other countries
+# are listed alphabetically by country code.  The table is sorted
+# first by country code, then (if possible) by an order within the
+# country that (1) makes some geographical sense, and (2) puts the
+# most populous zones first, where that does not contradict (1).
+#
+# This table is intended as an aid for users, to help them select time
+# zone data entries appropriate for their practical needs.  It is not
+# intended to take or endorse any position on legal or territorial claims.
+#
+#country-
+#codes	coordinates	TZ	comments
+AD	+4230+00131	Europe/Andorra
+AE,OM	+2518+05518	Asia/Dubai
+AF	+3431+06912	Asia/Kabul
+AL	+4120+01950	Europe/Tirane
+AM	+4011+04430	Asia/Yerevan
+AQ	-6617+11031	Antarctica/Casey	Casey
+AQ	-6835+07758	Antarctica/Davis	Davis
+AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville
+AQ	-6736+06253	Antarctica/Mawson	Mawson
+AQ	-6448-06406	Antarctica/Palmer	Palmer
+AQ	-6734-06808	Antarctica/Rothera	Rothera
+AQ	-690022+0393524	Antarctica/Syowa	Syowa
+AQ	-720041+0023206	Antarctica/Troll	Troll
+AQ	-7824+10654	Antarctica/Vostok	Vostok
+AR	-3436-05827	America/Argentina/Buenos_Aires	Buenos Aires (BA, CF)
+AR	-3124-06411	America/Argentina/Cordoba	Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF)
+AR	-2447-06525	America/Argentina/Salta	Salta (SA, LP, NQ, RN)
+AR	-2411-06518	America/Argentina/Jujuy	Jujuy (JY)
+AR	-2649-06513	America/Argentina/Tucuman	Tucumán (TM)
+AR	-2828-06547	America/Argentina/Catamarca	Catamarca (CT); Chubut (CH)
+AR	-2926-06651	America/Argentina/La_Rioja	La Rioja (LR)
+AR	-3132-06831	America/Argentina/San_Juan	San Juan (SJ)
+AR	-3253-06849	America/Argentina/Mendoza	Mendoza (MZ)
+AR	-3319-06621	America/Argentina/San_Luis	San Luis (SL)
+AR	-5138-06913	America/Argentina/Rio_Gallegos	Santa Cruz (SC)
+AR	-5448-06818	America/Argentina/Ushuaia	Tierra del Fuego (TF)
+AS,UM	-1416-17042	Pacific/Pago_Pago	Samoa, Midway
+AT	+4813+01620	Europe/Vienna
+AU	-3133+15905	Australia/Lord_Howe	Lord Howe Island
+AU	-5430+15857	Antarctica/Macquarie	Macquarie Island
+AU	-4253+14719	Australia/Hobart	Tasmania (most areas)
+AU	-3956+14352	Australia/Currie	Tasmania (King Island)
+AU	-3749+14458	Australia/Melbourne	Victoria
+AU	-3352+15113	Australia/Sydney	New South Wales (most areas)
+AU	-3157+14127	Australia/Broken_Hill	New South Wales (Yancowinna)
+AU	-2728+15302	Australia/Brisbane	Queensland (most areas)
+AU	-2016+14900	Australia/Lindeman	Queensland (Whitsunday Islands)
+AU	-3455+13835	Australia/Adelaide	South Australia
+AU	-1228+13050	Australia/Darwin	Northern Territory
+AU	-3157+11551	Australia/Perth	Western Australia (most areas)
+AU	-3143+12852	Australia/Eucla	Western Australia (Eucla)
+AZ	+4023+04951	Asia/Baku
+BB	+1306-05937	America/Barbados
+BD	+2343+09025	Asia/Dhaka
+BE	+5050+00420	Europe/Brussels
+BG	+4241+02319	Europe/Sofia
+BM	+3217-06446	Atlantic/Bermuda
+BN	+0456+11455	Asia/Brunei
+BO	-1630-06809	America/La_Paz
+BR	-0351-03225	America/Noronha	Atlantic islands
+BR	-0127-04829	America/Belem	Pará (east); Amapá
+BR	-0343-03830	America/Fortaleza	Brazil (northeast: MA, PI, CE, RN, PB)
+BR	-0803-03454	America/Recife	Pernambuco
+BR	-0712-04812	America/Araguaina	Tocantins
+BR	-0940-03543	America/Maceio	Alagoas, Sergipe
+BR	-1259-03831	America/Bahia	Bahia
+BR	-2332-04637	America/Sao_Paulo	Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS)
+BR	-2027-05437	America/Campo_Grande	Mato Grosso do Sul
+BR	-1535-05605	America/Cuiaba	Mato Grosso
+BR	-0226-05452	America/Santarem	Pará (west)
+BR	-0846-06354	America/Porto_Velho	Rondônia
+BR	+0249-06040	America/Boa_Vista	Roraima
+BR	-0308-06001	America/Manaus	Amazonas (east)
+BR	-0640-06952	America/Eirunepe	Amazonas (west)
+BR	-0958-06748	America/Rio_Branco	Acre
+BS	+2505-07721	America/Nassau
+BT	+2728+08939	Asia/Thimphu
+BY	+5354+02734	Europe/Minsk
+BZ	+1730-08812	America/Belize
+CA	+4734-05243	America/St_Johns	Newfoundland; Labrador (southeast)
+CA	+4439-06336	America/Halifax	Atlantic - NS (most areas); PE
+CA	+4612-05957	America/Glace_Bay	Atlantic - NS (Cape Breton)
+CA	+4606-06447	America/Moncton	Atlantic - New Brunswick
+CA	+5320-06025	America/Goose_Bay	Atlantic - Labrador (most areas)
+CA	+5125-05707	America/Blanc-Sablon	AST - QC (Lower North Shore)
+CA	+4339-07923	America/Toronto	Eastern - ON, QC (most areas)
+CA	+4901-08816	America/Nipigon	Eastern - ON, QC (no DST 1967-73)
+CA	+4823-08915	America/Thunder_Bay	Eastern - ON (Thunder Bay)
+CA	+6344-06828	America/Iqaluit	Eastern - NU (most east areas)
+CA	+6608-06544	America/Pangnirtung	Eastern - NU (Pangnirtung)
+CA	+484531-0913718	America/Atikokan	EST - ON (Atikokan); NU (Coral H)
+CA	+4953-09709	America/Winnipeg	Central - ON (west); Manitoba
+CA	+4843-09434	America/Rainy_River	Central - ON (Rainy R, Ft Frances)
+CA	+744144-0944945	America/Resolute	Central - NU (Resolute)
+CA	+624900-0920459	America/Rankin_Inlet	Central - NU (central)
+CA	+5024-10439	America/Regina	CST - SK (most areas)
+CA	+5017-10750	America/Swift_Current	CST - SK (midwest)
+CA	+5333-11328	America/Edmonton	Mountain - AB; BC (E); SK (W)
+CA	+690650-1050310	America/Cambridge_Bay	Mountain - NU (west)
+CA	+6227-11421	America/Yellowknife	Mountain - NT (central)
+CA	+682059-1334300	America/Inuvik	Mountain - NT (west)
+CA	+4906-11631	America/Creston	MST - BC (Creston)
+CA	+5946-12014	America/Dawson_Creek	MST - BC (Dawson Cr, Ft St John)
+CA	+5848-12242	America/Fort_Nelson	MST - BC (Ft Nelson)
+CA	+4916-12307	America/Vancouver	Pacific - BC (most areas)
+CA	+6043-13503	America/Whitehorse	Pacific - Yukon (south)
+CA	+6404-13925	America/Dawson	Pacific - Yukon (north)
+CC	-1210+09655	Indian/Cocos
+CH,DE,LI	+4723+00832	Europe/Zurich	Swiss time
+CI,BF,GM,GN,ML,MR,SH,SL,SN,TG	+0519-00402	Africa/Abidjan
+CK	-2114-15946	Pacific/Rarotonga
+CL	-3327-07040	America/Santiago	Chile (most areas)
+CL	-5309-07055	America/Punta_Arenas	Region of Magallanes
+CL	-2709-10926	Pacific/Easter	Easter Island
+CN	+3114+12128	Asia/Shanghai	Beijing Time
+CN	+4348+08735	Asia/Urumqi	Xinjiang Time
+CO	+0436-07405	America/Bogota
+CR	+0956-08405	America/Costa_Rica
+CU	+2308-08222	America/Havana
+CV	+1455-02331	Atlantic/Cape_Verde
+CW,AW,BQ,SX	+1211-06900	America/Curacao
+CX	-1025+10543	Indian/Christmas
+CY	+3510+03322	Asia/Nicosia	Cyprus (most areas)
+CY	+3507+03357	Asia/Famagusta	Northern Cyprus
+CZ,SK	+5005+01426	Europe/Prague
+DE	+5230+01322	Europe/Berlin	Germany (most areas)
+DK	+5540+01235	Europe/Copenhagen
+DO	+1828-06954	America/Santo_Domingo
+DZ	+3647+00303	Africa/Algiers
+EC	-0210-07950	America/Guayaquil	Ecuador (mainland)
+EC	-0054-08936	Pacific/Galapagos	Galápagos Islands
+EE	+5925+02445	Europe/Tallinn
+EG	+3003+03115	Africa/Cairo
+EH	+2709-01312	Africa/El_Aaiun
+ES	+4024-00341	Europe/Madrid	Spain (mainland)
+ES	+3553-00519	Africa/Ceuta	Ceuta, Melilla
+ES	+2806-01524	Atlantic/Canary	Canary Islands
+FI,AX	+6010+02458	Europe/Helsinki
+FJ	-1808+17825	Pacific/Fiji
+FK	-5142-05751	Atlantic/Stanley
+FM	+0725+15147	Pacific/Chuuk	Chuuk/Truk, Yap
+FM	+0658+15813	Pacific/Pohnpei	Pohnpei/Ponape
+FM	+0519+16259	Pacific/Kosrae	Kosrae
+FO	+6201-00646	Atlantic/Faroe
+FR	+4852+00220	Europe/Paris
+GB,GG,IM,JE	+513030-0000731	Europe/London
+GE	+4143+04449	Asia/Tbilisi
+GF	+0456-05220	America/Cayenne
+GH	+0533-00013	Africa/Accra
+GI	+3608-00521	Europe/Gibraltar
+GL	+6411-05144	America/Godthab	Greenland (most areas)
+GL	+7646-01840	America/Danmarkshavn	National Park (east coast)
+GL	+7029-02158	America/Scoresbysund	Scoresbysund/Ittoqqortoormiit
+GL	+7634-06847	America/Thule	Thule/Pituffik
+GR	+3758+02343	Europe/Athens
+GS	-5416-03632	Atlantic/South_Georgia
+GT	+1438-09031	America/Guatemala
+GU,MP	+1328+14445	Pacific/Guam
+GW	+1151-01535	Africa/Bissau
+GY	+0648-05810	America/Guyana
+HK	+2217+11409	Asia/Hong_Kong
+HN	+1406-08713	America/Tegucigalpa
+HT	+1832-07220	America/Port-au-Prince
+HU	+4730+01905	Europe/Budapest
+ID	-0610+10648	Asia/Jakarta	Java, Sumatra
+ID	-0002+10920	Asia/Pontianak	Borneo (west, central)
+ID	-0507+11924	Asia/Makassar	Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west)
+ID	-0232+14042	Asia/Jayapura	New Guinea (West Papua / Irian Jaya); Malukus/Moluccas
+IE	+5320-00615	Europe/Dublin
+IL	+314650+0351326	Asia/Jerusalem
+IN	+2232+08822	Asia/Kolkata
+IO	-0720+07225	Indian/Chagos
+IQ	+3321+04425	Asia/Baghdad
+IR	+3540+05126	Asia/Tehran
+IS	+6409-02151	Atlantic/Reykjavik
+IT,SM,VA	+4154+01229	Europe/Rome
+JM	+175805-0764736	America/Jamaica
+JO	+3157+03556	Asia/Amman
+JP	+353916+1394441	Asia/Tokyo
+KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT	-0117+03649	Africa/Nairobi
+KG	+4254+07436	Asia/Bishkek
+KI	+0125+17300	Pacific/Tarawa	Gilbert Islands
+KI	-0308-17105	Pacific/Enderbury	Phoenix Islands
+KI	+0152-15720	Pacific/Kiritimati	Line Islands
+KP	+3901+12545	Asia/Pyongyang
+KR	+3733+12658	Asia/Seoul
+KZ	+4315+07657	Asia/Almaty	Kazakhstan (most areas)
+KZ	+4448+06528	Asia/Qyzylorda	Qyzylorda/Kyzylorda/Kzyl-Orda
+KZ	+5017+05710	Asia/Aqtobe	Aqtöbe/Aktobe
+KZ	+4431+05016	Asia/Aqtau	Mangghystaū/Mankistau
+KZ	+4707+05156	Asia/Atyrau	Atyraū/Atirau/Gur'yev
+KZ	+5113+05121	Asia/Oral	West Kazakhstan
+LB	+3353+03530	Asia/Beirut
+LK	+0656+07951	Asia/Colombo
+LR	+0618-01047	Africa/Monrovia
+LT	+5441+02519	Europe/Vilnius
+LU	+4936+00609	Europe/Luxembourg
+LV	+5657+02406	Europe/Riga
+LY	+3254+01311	Africa/Tripoli
+MA	+3339-00735	Africa/Casablanca
+MC	+4342+00723	Europe/Monaco
+MD	+4700+02850	Europe/Chisinau
+MH	+0709+17112	Pacific/Majuro	Marshall Islands (most areas)
+MH	+0905+16720	Pacific/Kwajalein	Kwajalein
+MM	+1647+09610	Asia/Yangon
+MN	+4755+10653	Asia/Ulaanbaatar	Mongolia (most areas)
+MN	+4801+09139	Asia/Hovd	Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan
+MN	+4804+11430	Asia/Choibalsan	Dornod, Sükhbaatar
+MO	+2214+11335	Asia/Macau
+MQ	+1436-06105	America/Martinique
+MT	+3554+01431	Europe/Malta
+MU	-2010+05730	Indian/Mauritius
+MV	+0410+07330	Indian/Maldives
+MX	+1924-09909	America/Mexico_City	Central Time
+MX	+2105-08646	America/Cancun	Eastern Standard Time - Quintana Roo
+MX	+2058-08937	America/Merida	Central Time - Campeche, Yucatán
+MX	+2540-10019	America/Monterrey	Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas)
+MX	+2550-09730	America/Matamoros	Central Time US - Coahuila, Nuevo León, Tamaulipas (US border)
+MX	+2313-10625	America/Mazatlan	Mountain Time - Baja California Sur, Nayarit, Sinaloa
+MX	+2838-10605	America/Chihuahua	Mountain Time - Chihuahua (most areas)
+MX	+2934-10425	America/Ojinaga	Mountain Time US - Chihuahua (US border)
+MX	+2904-11058	America/Hermosillo	Mountain Standard Time - Sonora
+MX	+3232-11701	America/Tijuana	Pacific Time US - Baja California
+MX	+2048-10515	America/Bahia_Banderas	Central Time - Bahía de Banderas
+MY	+0310+10142	Asia/Kuala_Lumpur	Malaysia (peninsula)
+MY	+0133+11020	Asia/Kuching	Sabah, Sarawak
+MZ,BI,BW,CD,MW,RW,ZM,ZW	-2558+03235	Africa/Maputo	Central Africa Time
+NA	-2234+01706	Africa/Windhoek
+NC	-2216+16627	Pacific/Noumea
+NF	-2903+16758	Pacific/Norfolk
+NG,AO,BJ,CD,CF,CG,CM,GA,GQ,NE	+0627+00324	Africa/Lagos	West Africa Time
+NI	+1209-08617	America/Managua
+NL	+5222+00454	Europe/Amsterdam
+NO,SJ	+5955+01045	Europe/Oslo
+NP	+2743+08519	Asia/Kathmandu
+NR	-0031+16655	Pacific/Nauru
+NU	-1901-16955	Pacific/Niue
+NZ,AQ	-3652+17446	Pacific/Auckland	New Zealand time
+NZ	-4357-17633	Pacific/Chatham	Chatham Islands
+PA,KY	+0858-07932	America/Panama
+PE	-1203-07703	America/Lima
+PF	-1732-14934	Pacific/Tahiti	Society Islands
+PF	-0900-13930	Pacific/Marquesas	Marquesas Islands
+PF	-2308-13457	Pacific/Gambier	Gambier Islands
+PG	-0930+14710	Pacific/Port_Moresby	Papua New Guinea (most areas)
+PG	-0613+15534	Pacific/Bougainville	Bougainville
+PH	+1435+12100	Asia/Manila
+PK	+2452+06703	Asia/Karachi
+PL	+5215+02100	Europe/Warsaw
+PM	+4703-05620	America/Miquelon
+PN	-2504-13005	Pacific/Pitcairn
+PR	+182806-0660622	America/Puerto_Rico
+PS	+3130+03428	Asia/Gaza	Gaza Strip
+PS	+313200+0350542	Asia/Hebron	West Bank
+PT	+3843-00908	Europe/Lisbon	Portugal (mainland)
+PT	+3238-01654	Atlantic/Madeira	Madeira Islands
+PT	+3744-02540	Atlantic/Azores	Azores
+PW	+0720+13429	Pacific/Palau
+PY	-2516-05740	America/Asuncion
+QA,BH	+2517+05132	Asia/Qatar
+RE,TF	-2052+05528	Indian/Reunion	Réunion, Crozet, Scattered Islands
+RO	+4426+02606	Europe/Bucharest
+RS,BA,HR,ME,MK,SI	+4450+02030	Europe/Belgrade
+RU	+5443+02030	Europe/Kaliningrad	MSK-01 - Kaliningrad
+RU	+554521+0373704	Europe/Moscow	MSK+00 - Moscow area
+RU	+4457+03406	Europe/Simferopol	MSK+00 - Crimea
+RU	+4844+04425	Europe/Volgograd	MSK+00 - Volgograd
+RU	+5836+04939	Europe/Kirov	MSK+00 - Kirov
+RU	+4621+04803	Europe/Astrakhan	MSK+01 - Astrakhan
+RU	+5134+04602	Europe/Saratov	MSK+01 - Saratov
+RU	+5420+04824	Europe/Ulyanovsk	MSK+01 - Ulyanovsk
+RU	+5312+05009	Europe/Samara	MSK+01 - Samara, Udmurtia
+RU	+5651+06036	Asia/Yekaterinburg	MSK+02 - Urals
+RU	+5500+07324	Asia/Omsk	MSK+03 - Omsk
+RU	+5502+08255	Asia/Novosibirsk	MSK+04 - Novosibirsk
+RU	+5322+08345	Asia/Barnaul	MSK+04 - Altai
+RU	+5630+08458	Asia/Tomsk	MSK+04 - Tomsk
+RU	+5345+08707	Asia/Novokuznetsk	MSK+04 - Kemerovo
+RU	+5601+09250	Asia/Krasnoyarsk	MSK+04 - Krasnoyarsk area
+RU	+5216+10420	Asia/Irkutsk	MSK+05 - Irkutsk, Buryatia
+RU	+5203+11328	Asia/Chita	MSK+06 - Zabaykalsky
+RU	+6200+12940	Asia/Yakutsk	MSK+06 - Lena River
+RU	+623923+1353314	Asia/Khandyga	MSK+06 - Tomponsky, Ust-Maysky
+RU	+4310+13156	Asia/Vladivostok	MSK+07 - Amur River
+RU	+643337+1431336	Asia/Ust-Nera	MSK+07 - Oymyakonsky
+RU	+5934+15048	Asia/Magadan	MSK+08 - Magadan
+RU	+4658+14242	Asia/Sakhalin	MSK+08 - Sakhalin Island
+RU	+6728+15343	Asia/Srednekolymsk	MSK+08 - Sakha (E); North Kuril Is
+RU	+5301+15839	Asia/Kamchatka	MSK+09 - Kamchatka
+RU	+6445+17729	Asia/Anadyr	MSK+09 - Bering Sea
+SA,KW,YE	+2438+04643	Asia/Riyadh
+SB	-0932+16012	Pacific/Guadalcanal
+SC	-0440+05528	Indian/Mahe
+SD	+1536+03232	Africa/Khartoum
+SE	+5920+01803	Europe/Stockholm
+SG	+0117+10351	Asia/Singapore
+SR	+0550-05510	America/Paramaribo
+SS	+0451+03137	Africa/Juba
+ST	+0020+00644	Africa/Sao_Tome
+SV	+1342-08912	America/El_Salvador
+SY	+3330+03618	Asia/Damascus
+TC	+2128-07108	America/Grand_Turk
+TD	+1207+01503	Africa/Ndjamena
+TF	-492110+0701303	Indian/Kerguelen	Kerguelen, St Paul Island, Amsterdam Island
+TH,KH,LA,VN	+1345+10031	Asia/Bangkok	Indochina (most areas)
+TJ	+3835+06848	Asia/Dushanbe
+TK	-0922-17114	Pacific/Fakaofo
+TL	-0833+12535	Asia/Dili
+TM	+3757+05823	Asia/Ashgabat
+TN	+3648+01011	Africa/Tunis
+TO	-2110-17510	Pacific/Tongatapu
+TR	+4101+02858	Europe/Istanbul
+TT,AG,AI,BL,DM,GD,GP,KN,LC,MF,MS,VC,VG,VI	+1039-06131	America/Port_of_Spain
+TV	-0831+17913	Pacific/Funafuti
+TW	+2503+12130	Asia/Taipei
+UA	+5026+03031	Europe/Kiev	Ukraine (most areas)
+UA	+4837+02218	Europe/Uzhgorod	Ruthenia
+UA	+4750+03510	Europe/Zaporozhye	Zaporozh'ye/Zaporizhia; Lugansk/Luhansk (east)
+UM	+1917+16637	Pacific/Wake	Wake Island
+US	+404251-0740023	America/New_York	Eastern (most areas)
+US	+421953-0830245	America/Detroit	Eastern - MI (most areas)
+US	+381515-0854534	America/Kentucky/Louisville	Eastern - KY (Louisville area)
+US	+364947-0845057	America/Kentucky/Monticello	Eastern - KY (Wayne)
+US	+394606-0860929	America/Indiana/Indianapolis	Eastern - IN (most areas)
+US	+384038-0873143	America/Indiana/Vincennes	Eastern - IN (Da, Du, K, Mn)
+US	+410305-0863611	America/Indiana/Winamac	Eastern - IN (Pulaski)
+US	+382232-0862041	America/Indiana/Marengo	Eastern - IN (Crawford)
+US	+382931-0871643	America/Indiana/Petersburg	Eastern - IN (Pike)
+US	+384452-0850402	America/Indiana/Vevay	Eastern - IN (Switzerland)
+US	+415100-0873900	America/Chicago	Central (most areas)
+US	+375711-0864541	America/Indiana/Tell_City	Central - IN (Perry)
+US	+411745-0863730	America/Indiana/Knox	Central - IN (Starke)
+US	+450628-0873651	America/Menominee	Central - MI (Wisconsin border)
+US	+470659-1011757	America/North_Dakota/Center	Central - ND (Oliver)
+US	+465042-1012439	America/North_Dakota/New_Salem	Central - ND (Morton rural)
+US	+471551-1014640	America/North_Dakota/Beulah	Central - ND (Mercer)
+US	+394421-1045903	America/Denver	Mountain (most areas)
+US	+433649-1161209	America/Boise	Mountain - ID (south); OR (east)
+US	+332654-1120424	America/Phoenix	MST - Arizona (except Navajo)
+US	+340308-1181434	America/Los_Angeles	Pacific
+US	+611305-1495401	America/Anchorage	Alaska (most areas)
+US	+581807-1342511	America/Juneau	Alaska - Juneau area
+US	+571035-1351807	America/Sitka	Alaska - Sitka area
+US	+550737-1313435	America/Metlakatla	Alaska - Annette Island
+US	+593249-1394338	America/Yakutat	Alaska - Yakutat
+US	+643004-1652423	America/Nome	Alaska (west)
+US	+515248-1763929	America/Adak	Aleutian Islands
+US,UM	+211825-1575130	Pacific/Honolulu	Hawaii
+UY	-345433-0561245	America/Montevideo
+UZ	+3940+06648	Asia/Samarkand	Uzbekistan (west)
+UZ	+4120+06918	Asia/Tashkent	Uzbekistan (east)
+VE	+1030-06656	America/Caracas
+VN	+1045+10640	Asia/Ho_Chi_Minh	Vietnam (south)
+VU	-1740+16825	Pacific/Efate
+WF	-1318-17610	Pacific/Wallis
+WS	-1350-17144	Pacific/Apia
+ZA,LS,SZ	-2615+02800	Africa/Johannesburg
diff --git a/absl/time/internal/get_current_time_ios.inc b/absl/time/internal/get_current_time_ios.inc
new file mode 100644
index 0000000..f3db32b
--- /dev/null
+++ b/absl/time/internal/get_current_time_ios.inc
@@ -0,0 +1,80 @@
+#include "absl/time/clock.h"
+
+#include <sys/time.h>
+#include <ctime>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+// These are not defined in the Xcode 7.3.1 SDK Headers.
+// Once we are no longer supporting Xcode 7.3.1 we can
+// remove these.
+#ifndef __WATCHOS_3_0
+#define __WATCHOS_3_0 30000
+#endif
+
+#ifndef __TVOS_10_0
+#define __TVOS_10_0 100000
+#endif
+
+#ifndef __IPHONE_10_0
+#define __IPHONE_10_0 100000
+#endif
+
+#ifndef __MAC_10_12
+#define __MAC_10_12 101200
+#endif
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12) ||    \
+    (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0) || \
+    (__WATCH_OS_VERSION_MAX_ALLOWED >= __WATCHOS_3_0) ||  \
+    (__TV_OS_VERSION_MAX_ALLOWED >= __TVOS_10_0)
+  // clock_gettime_nsec_np is not defined on SDKs before Xcode 8.0.
+  // This preprocessor logic is based upon __CLOCK_AVAILABILITY in
+  // usr/include/time.h. Once we are no longer supporting Xcode 7.3.1 we can
+  // remove this #if.
+  // We must continue to check if it is defined until we are sure that ALL the
+  // platforms we are shipping on support it.
+  // clock_gettime_nsec_np is preferred because it may give higher accuracy than
+  // gettimeofday in future Apple operating systems.
+  // Currently (macOS 10.12/iOS 10.2) clock_gettime_nsec_np accuracy is
+  // microsecond accuracy (i.e. equivalent to gettimeofday).
+  if (&clock_gettime_nsec_np != nullptr) {
+    return clock_gettime_nsec_np(CLOCK_REALTIME);
+  }
+#endif
+#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) &&            \
+     (__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12)) ||    \
+    (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) &&           \
+     (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)) || \
+    (defined(__WATCH_OS_VERSION_MIN_REQUIRED) &&            \
+     (__WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_3_0)) ||  \
+    (defined(__TV_OS_VERSION_MIN_REQUIRED) &&               \
+     (__TV_OS_VERSION_MIN_REQUIRED < __TVOS_10_0))
+  // We need this block in 2 different cases:
+  // a) where we are compiling with Xcode 7 in which case the block above
+  //    will not be compiled in, and this is the only block executed.
+  // b) where we are compiling with Xcode 8+ but supporting operating systems
+  //    that do not define clock_gettime_nsec_np, so this is in effect
+  //    an else block to the block above.
+  // This block will not be compiled if the min supported version is
+  // guaranteed to supply clock_gettime_nsec_np.
+  //
+  // Once we know that clock_gettime_nsec_np is in the SDK *AND* exists on
+  // all the platforms we support, we can remove both this block and alter the
+  // block above to just call clock_gettime_nsec_np directly.
+  const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+  const int64_t kNanosPerMicrosecond = 1000;
+  struct timeval tp;
+  ABSL_RAW_CHECK(gettimeofday(&tp, nullptr) == 0, "Failed gettimeofday");
+  return (int64_t{tp.tv_sec} * kNanosPerSecond +
+          int64_t{tp.tv_usec} * kNanosPerMicrosecond);
+#endif
+}
+
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/get_current_time_posix.inc b/absl/time/internal/get_current_time_posix.inc
new file mode 100644
index 0000000..65474ca
--- /dev/null
+++ b/absl/time/internal/get_current_time_posix.inc
@@ -0,0 +1,22 @@
+#include "absl/time/clock.h"
+
+#include <sys/time.h>
+#include <ctime>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+  const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+  struct timespec ts;
+  ABSL_RAW_CHECK(clock_gettime(CLOCK_REALTIME, &ts) == 0,
+                 "Failed to read real-time clock.");
+  return (int64_t{ts.tv_sec} * kNanosPerSecond +
+          int64_t{ts.tv_nsec});
+}
+
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/get_current_time_windows.inc b/absl/time/internal/get_current_time_windows.inc
new file mode 100644
index 0000000..b22a9c9
--- /dev/null
+++ b/absl/time/internal/get_current_time_windows.inc
@@ -0,0 +1,17 @@
+#include "absl/time/clock.h"
+
+#include <chrono>
+#include <cstdint>
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             std::chrono::system_clock::now() -
+             std::chrono::system_clock::from_time_t(0))
+      .count();
+}
+
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc
new file mode 100644
index 0000000..bbbef7d
--- /dev/null
+++ b/absl/time/internal/test_util.cc
@@ -0,0 +1,129 @@
+// Copyright 2017 The Abseil 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 "absl/time/internal/test_util.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
+
+namespace cctz = absl::time_internal::cctz;
+
+namespace absl {
+namespace time_internal {
+
+#if GTEST_USES_SIMPLE_RE
+extern const char kZoneAbbrRE[] = ".*";  // just punt
+#else
+extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
+#endif
+
+TimeZone LoadTimeZone(const std::string& name) {
+  TimeZone tz;
+  ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
+  return tz;
+}
+
+}  // namespace time_internal
+}  // namespace absl
+
+namespace absl {
+namespace time_internal {
+namespace cctz_extension {
+namespace {
+
+// Embed the zoneinfo data for time zones used during tests and benchmarks.
+// The data was generated using "xxd -i zoneinfo-file".  There is no need
+// to update the data as long as the tests do not depend on recent changes
+// (and the past rules remain the same).
+#include "absl/time/internal/zoneinfo.inc"
+
+const struct ZoneInfo {
+  const char* name;
+  const char* data;
+  std::size_t length;
+} kZoneInfo[] = {
+    // The three real time zones used by :time_test and :time_benchmark.
+    {"America/Los_Angeles",  //
+     reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+    {"America/New_York",  //
+     reinterpret_cast<char*>(America_New_York), America_New_York_len},
+    {"Australia/Sydney",  //
+     reinterpret_cast<char*>(Australia_Sydney), Australia_Sydney_len},
+
+    // Other zones named in tests but which should fail to load.
+    {"Invalid/TimeZone", nullptr, 0},
+    {"", nullptr, 0},
+
+    // Also allow for loading the local time zone under TZ=US/Pacific.
+    {"US/Pacific",  //
+     reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+
+    // Allows use of the local time zone from a system-specific location.
+#ifdef _MSC_VER
+    {"localtime",  //
+     reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+#else
+    {"/etc/localtime",  //
+     reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+#endif
+};
+
+class TestZoneInfoSource : public cctz::ZoneInfoSource {
+ public:
+  TestZoneInfoSource(const char* data, std::size_t size)
+      : data_(data), end_(data + size) {}
+
+  std::size_t Read(void* ptr, std::size_t size) override {
+    const std::size_t len = std::min<std::size_t>(size, end_ - data_);
+    memcpy(ptr, data_, len);
+    data_ += len;
+    return len;
+  }
+
+  int Skip(std::size_t offset) override {
+    data_ += std::min<std::size_t>(offset, end_ - data_);
+    return 0;
+  }
+
+ private:
+  const char* data_;
+  const char* const end_;
+};
+
+std::unique_ptr<cctz::ZoneInfoSource> TestFactory(
+    const std::string& name,
+    const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+        const std::string& name)>& /*fallback_factory*/) {
+  for (const ZoneInfo& zoneinfo : kZoneInfo) {
+    if (name == zoneinfo.name) {
+      if (zoneinfo.data == nullptr) return nullptr;
+      return std::unique_ptr<cctz::ZoneInfoSource>(
+          new TestZoneInfoSource(zoneinfo.data, zoneinfo.length));
+    }
+  }
+  ABSL_RAW_LOG(FATAL, "Unexpected time zone \"%s\" in test", name.c_str());
+  return nullptr;
+}
+
+}  // namespace
+
+ZoneInfoSourceFactory zone_info_source_factory = TestFactory;
+
+}  // namespace cctz_extension
+}  // namespace time_internal
+}  // namespace absl
diff --git a/absl/time/internal/test_util.h b/absl/time/internal/test_util.h
new file mode 100644
index 0000000..8fd5fb9
--- /dev/null
+++ b/absl/time/internal/test_util.h
@@ -0,0 +1,55 @@
+// Copyright 2017 The Abseil 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 ABSL_TIME_INTERNAL_TEST_UTIL_H_
+#define ABSL_TIME_INTERNAL_TEST_UTIL_H_
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/time.h"
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+//
+// This is for internal testing of the Base Time library itself. This is not
+// part of a public API.
+#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst)     \
+  do {                                                                    \
+    EXPECT_EQ(y, bd.year);                                                \
+    EXPECT_EQ(m, bd.month);                                               \
+    EXPECT_EQ(d, bd.day);                                                 \
+    EXPECT_EQ(h, bd.hour);                                                \
+    EXPECT_EQ(min, bd.minute);                                            \
+    EXPECT_EQ(s, bd.second);                                              \
+    EXPECT_EQ(off, bd.offset);                                            \
+    EXPECT_EQ(isdst, bd.is_dst);                                          \
+    EXPECT_THAT(bd.zone_abbr,                                             \
+                testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \
+  } while (0)
+
+namespace absl {
+namespace time_internal {
+
+// A regular expression that matches all zone abbreviations (%Z).
+extern const char kZoneAbbrRE[];
+
+// Loads the named timezone, but dies on any failure.
+absl::TimeZone LoadTimeZone(const std::string& name);
+
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_TEST_UTIL_H_
diff --git a/absl/time/internal/zoneinfo.inc b/absl/time/internal/zoneinfo.inc
new file mode 100644
index 0000000..bfed829
--- /dev/null
+++ b/absl/time/internal/zoneinfo.inc
@@ -0,0 +1,729 @@
+unsigned char America_Los_Angeles[] = {
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00,
+  0x9e, 0xa6, 0x48, 0xa0, 0x9f, 0xbb, 0x15, 0x90, 0xa0, 0x86, 0x2a, 0xa0,
+  0xa1, 0x9a, 0xf7, 0x90, 0xcb, 0x89, 0x1a, 0xa0, 0xd2, 0x23, 0xf4, 0x70,
+  0xd2, 0x61, 0x26, 0x10, 0xd6, 0xfe, 0x74, 0x5c, 0xd8, 0x80, 0xad, 0x90,
+  0xda, 0xfe, 0xc3, 0x90, 0xdb, 0xc0, 0x90, 0x10, 0xdc, 0xde, 0xa5, 0x90,
+  0xdd, 0xa9, 0xac, 0x90, 0xde, 0xbe, 0x87, 0x90, 0xdf, 0x89, 0x8e, 0x90,
+  0xe0, 0x9e, 0x69, 0x90, 0xe1, 0x69, 0x70, 0x90, 0xe2, 0x7e, 0x4b, 0x90,
+  0xe3, 0x49, 0x52, 0x90, 0xe4, 0x5e, 0x2d, 0x90, 0xe5, 0x29, 0x34, 0x90,
+  0xe6, 0x47, 0x4a, 0x10, 0xe7, 0x12, 0x51, 0x10, 0xe8, 0x27, 0x2c, 0x10,
+  0xe8, 0xf2, 0x33, 0x10, 0xea, 0x07, 0x0e, 0x10, 0xea, 0xd2, 0x15, 0x10,
+  0xeb, 0xe6, 0xf0, 0x10, 0xec, 0xb1, 0xf7, 0x10, 0xed, 0xc6, 0xd2, 0x10,
+  0xee, 0x91, 0xd9, 0x10, 0xef, 0xaf, 0xee, 0x90, 0xf0, 0x71, 0xbb, 0x10,
+  0xf1, 0x8f, 0xd0, 0x90, 0xf2, 0x7f, 0xc1, 0x90, 0xf3, 0x6f, 0xb2, 0x90,
+  0xf4, 0x5f, 0xa3, 0x90, 0xf5, 0x4f, 0x94, 0x90, 0xf6, 0x3f, 0x85, 0x90,
+  0xf7, 0x2f, 0x76, 0x90, 0xf8, 0x28, 0xa2, 0x10, 0xf9, 0x0f, 0x58, 0x90,
+  0xfa, 0x08, 0x84, 0x10, 0xfa, 0xf8, 0x83, 0x20, 0xfb, 0xe8, 0x66, 0x10,
+  0xfc, 0xd8, 0x65, 0x20, 0xfd, 0xc8, 0x48, 0x10, 0xfe, 0xb8, 0x47, 0x20,
+  0xff, 0xa8, 0x2a, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0c, 0x10,
+  0x02, 0x78, 0x0b, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xa0,
+  0x05, 0x51, 0x0a, 0x90, 0x06, 0x41, 0x09, 0xa0, 0x07, 0x30, 0xec, 0x90,
+  0x07, 0x8d, 0x43, 0xa0, 0x09, 0x10, 0xce, 0x90, 0x09, 0xad, 0xbf, 0x20,
+  0x0a, 0xf0, 0xb0, 0x90, 0x0b, 0xe0, 0xaf, 0xa0, 0x0c, 0xd9, 0xcd, 0x10,
+  0x0d, 0xc0, 0x91, 0xa0, 0x0e, 0xb9, 0xaf, 0x10, 0x0f, 0xa9, 0xae, 0x20,
+  0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10,
+  0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20,
+  0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90,
+  0x19, 0x09, 0x18, 0x20, 0x1a, 0x02, 0x35, 0x90, 0x1a, 0xf2, 0x34, 0xa0,
+  0x1b, 0xe2, 0x17, 0x90, 0x1c, 0xd2, 0x16, 0xa0, 0x1d, 0xc1, 0xf9, 0x90,
+  0x1e, 0xb1, 0xf8, 0xa0, 0x1f, 0xa1, 0xdb, 0x90, 0x20, 0x76, 0x2b, 0x20,
+  0x21, 0x81, 0xbd, 0x90, 0x22, 0x56, 0x0d, 0x20, 0x23, 0x6a, 0xda, 0x10,
+  0x24, 0x35, 0xef, 0x20, 0x25, 0x4a, 0xbc, 0x10, 0x26, 0x15, 0xd1, 0x20,
+  0x27, 0x2a, 0x9e, 0x10, 0x27, 0xfe, 0xed, 0xa0, 0x29, 0x0a, 0x80, 0x10,
+  0x29, 0xde, 0xcf, 0xa0, 0x2a, 0xea, 0x62, 0x10, 0x2b, 0xbe, 0xb1, 0xa0,
+  0x2c, 0xd3, 0x7e, 0x90, 0x2d, 0x9e, 0x93, 0xa0, 0x2e, 0xb3, 0x60, 0x90,
+  0x2f, 0x7e, 0x75, 0xa0, 0x30, 0x93, 0x42, 0x90, 0x31, 0x67, 0x92, 0x20,
+  0x32, 0x73, 0x24, 0x90, 0x33, 0x47, 0x74, 0x20, 0x34, 0x53, 0x06, 0x90,
+  0x35, 0x27, 0x56, 0x20, 0x36, 0x32, 0xe8, 0x90, 0x37, 0x07, 0x38, 0x20,
+  0x38, 0x1c, 0x05, 0x10, 0x38, 0xe7, 0x1a, 0x20, 0x39, 0xfb, 0xe7, 0x10,
+  0x3a, 0xc6, 0xfc, 0x20, 0x3b, 0xdb, 0xc9, 0x10, 0x3c, 0xb0, 0x18, 0xa0,
+  0x3d, 0xbb, 0xab, 0x10, 0x3e, 0x8f, 0xfa, 0xa0, 0x3f, 0x9b, 0x8d, 0x10,
+  0x40, 0x6f, 0xdc, 0xa0, 0x41, 0x84, 0xa9, 0x90, 0x42, 0x4f, 0xbe, 0xa0,
+  0x43, 0x64, 0x8b, 0x90, 0x44, 0x2f, 0xa0, 0xa0, 0x45, 0x44, 0x6d, 0x90,
+  0x45, 0xf3, 0xd3, 0x20, 0x47, 0x2d, 0x8a, 0x10, 0x47, 0xd3, 0xb5, 0x20,
+  0x49, 0x0d, 0x6c, 0x10, 0x49, 0xb3, 0x97, 0x20, 0x4a, 0xed, 0x4e, 0x10,
+  0x4b, 0x9c, 0xb3, 0xa0, 0x4c, 0xd6, 0x6a, 0x90, 0x4d, 0x7c, 0x95, 0xa0,
+  0x4e, 0xb6, 0x4c, 0x90, 0x4f, 0x5c, 0x77, 0xa0, 0x50, 0x96, 0x2e, 0x90,
+  0x51, 0x3c, 0x59, 0xa0, 0x52, 0x76, 0x10, 0x90, 0x53, 0x1c, 0x3b, 0xa0,
+  0x54, 0x55, 0xf2, 0x90, 0x54, 0xfc, 0x1d, 0xa0, 0x56, 0x35, 0xd4, 0x90,
+  0x56, 0xe5, 0x3a, 0x20, 0x58, 0x1e, 0xf1, 0x10, 0x58, 0xc5, 0x1c, 0x20,
+  0x59, 0xfe, 0xd3, 0x10, 0x5a, 0xa4, 0xfe, 0x20, 0x5b, 0xde, 0xb5, 0x10,
+  0x5c, 0x84, 0xe0, 0x20, 0x5d, 0xbe, 0x97, 0x10, 0x5e, 0x64, 0xc2, 0x20,
+  0x5f, 0x9e, 0x79, 0x10, 0x60, 0x4d, 0xde, 0xa0, 0x61, 0x87, 0x95, 0x90,
+  0x62, 0x2d, 0xc0, 0xa0, 0x63, 0x67, 0x77, 0x90, 0x64, 0x0d, 0xa2, 0xa0,
+  0x65, 0x47, 0x59, 0x90, 0x65, 0xed, 0x84, 0xa0, 0x67, 0x27, 0x3b, 0x90,
+  0x67, 0xcd, 0x66, 0xa0, 0x69, 0x07, 0x1d, 0x90, 0x69, 0xad, 0x48, 0xa0,
+  0x6a, 0xe6, 0xff, 0x90, 0x6b, 0x96, 0x65, 0x20, 0x6c, 0xd0, 0x1c, 0x10,
+  0x6d, 0x76, 0x47, 0x20, 0x6e, 0xaf, 0xfe, 0x10, 0x6f, 0x56, 0x29, 0x20,
+  0x70, 0x8f, 0xe0, 0x10, 0x71, 0x36, 0x0b, 0x20, 0x72, 0x6f, 0xc2, 0x10,
+  0x73, 0x15, 0xed, 0x20, 0x74, 0x4f, 0xa4, 0x10, 0x74, 0xff, 0x09, 0xa0,
+  0x76, 0x38, 0xc0, 0x90, 0x76, 0xde, 0xeb, 0xa0, 0x78, 0x18, 0xa2, 0x90,
+  0x78, 0xbe, 0xcd, 0xa0, 0x79, 0xf8, 0x84, 0x90, 0x7a, 0x9e, 0xaf, 0xa0,
+  0x7b, 0xd8, 0x66, 0x90, 0x7c, 0x7e, 0x91, 0xa0, 0x7d, 0xb8, 0x48, 0x90,
+  0x7e, 0x5e, 0x73, 0xa0, 0x7f, 0x98, 0x2a, 0x90, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90,
+  0x01, 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90,
+  0x01, 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00,
+  0x50, 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00,
+  0x50, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xbb, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x04,
+  0x1a, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x48, 0xa0, 0xff, 0xff,
+  0xff, 0xff, 0x9f, 0xbb, 0x15, 0x90, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86,
+  0x2a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xf7, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xcb, 0x89, 0x1a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x23,
+  0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x61, 0x26, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xd6, 0xfe, 0x74, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x80,
+  0xad, 0x90, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xc3, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xdb, 0xc0, 0x90, 0x10, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xde,
+  0xa5, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0xac, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xde, 0xbe, 0x87, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x89,
+  0x8e, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x69, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xe1, 0x69, 0x70, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x7e,
+  0x4b, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x52, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xe4, 0x5e, 0x2d, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x29,
+  0x34, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x4a, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xe7, 0x12, 0x51, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x27,
+  0x2c, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0xf2, 0x33, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xea, 0x07, 0x0e, 0x10, 0xff, 0xff, 0xff, 0xff, 0xea, 0xd2,
+  0x15, 0x10, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xf0, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xec, 0xb1, 0xf7, 0x10, 0xff, 0xff, 0xff, 0xff, 0xed, 0xc6,
+  0xd2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xee, 0x91, 0xd9, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xef, 0xaf, 0xee, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x71,
+  0xbb, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xd0, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xf2, 0x7f, 0xc1, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x6f,
+  0xb2, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0xa3, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xf5, 0x4f, 0x94, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x3f,
+  0x85, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x76, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xf8, 0x28, 0xa2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0f,
+  0x58, 0x90, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x84, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xfa, 0xf8, 0x83, 0x20, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe8,
+  0x66, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x65, 0x20, 0xff, 0xff,
+  0xff, 0xff, 0xfd, 0xc8, 0x48, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb8,
+  0x47, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88,
+  0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0b, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61,
+  0x27, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0a, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x41, 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30,
+  0xec, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x43, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x09, 0x10, 0xce, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xad,
+  0xbf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0xb0, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x0b, 0xe0, 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd9,
+  0xcd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x91, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x0e, 0xb9, 0xaf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xa9,
+  0xae, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79,
+  0x73, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x72, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x14, 0x59, 0x55, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15, 0x49,
+  0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x37, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x17, 0x29, 0x36, 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22,
+  0x53, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0x09, 0x18, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x1a, 0x02, 0x35, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xf2,
+  0x34, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe2, 0x17, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x1c, 0xd2, 0x16, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1,
+  0xf9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xf8, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x1f, 0xa1, 0xdb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x20, 0x76,
+  0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0xbd, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x22, 0x56, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6a,
+  0xda, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xef, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x25, 0x4a, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x15,
+  0xd1, 0x20, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x9e, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x27, 0xfe, 0xed, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0a,
+  0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xcf, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x2a, 0xea, 0x62, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xbe,
+  0xb1, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x7e, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x2d, 0x9e, 0x93, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb3,
+  0x60, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x75, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x30, 0x93, 0x42, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x67,
+  0x92, 0x20, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, 0x24, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x33, 0x47, 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x34, 0x53,
+  0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x56, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x36, 0x32, 0xe8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x37, 0x07,
+  0x38, 0x20, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x05, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0xe7, 0x1a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0xfb,
+  0xe7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xfc, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x3b, 0xdb, 0xc9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb0,
+  0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0xab, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x3e, 0x8f, 0xfa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9b,
+  0x8d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xdc, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x41, 0x84, 0xa9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4f,
+  0xbe, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x8b, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x44, 0x2f, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44,
+  0x6d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xd3, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x47, 0x2d, 0x8a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xd3,
+  0xb5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x6c, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x49, 0xb3, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xed,
+  0x4e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0xb3, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x4c, 0xd6, 0x6a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x7c,
+  0x95, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x4c, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x4f, 0x5c, 0x77, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96,
+  0x2e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x59, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x52, 0x76, 0x10, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x1c,
+  0x3b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xf2, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x54, 0xfc, 0x1d, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35,
+  0xd4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x3a, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x58, 0x1e, 0xf1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xc5,
+  0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xd3, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x5a, 0xa4, 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xde,
+  0xb5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xe0, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x5d, 0xbe, 0x97, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x64,
+  0xc2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x79, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x60, 0x4d, 0xde, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87,
+  0x95, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0xc0, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x63, 0x67, 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0d,
+  0xa2, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x59, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x65, 0xed, 0x84, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27,
+  0x3b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x66, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x69, 0x07, 0x1d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xad,
+  0x48, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xff, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x6b, 0x96, 0x65, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xd0,
+  0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x47, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x6e, 0xaf, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x56,
+  0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xe0, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x71, 0x36, 0x0b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f,
+  0xc2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xed, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x74, 0x4f, 0xa4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0xff,
+  0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0xc0, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x76, 0xde, 0xeb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18,
+  0xa2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xcd, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x79, 0xf8, 0x84, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x9e,
+  0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x66, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x7c, 0x7e, 0x91, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7d, 0xb8,
+  0x48, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x73, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x7f, 0x98, 0x2a, 0x90, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, 0x01,
+  0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, 0x01,
+  0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x50,
+  0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50,
+  0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x0a, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x2c, 0x4d, 0x33,
+  0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, 0x2e, 0x31, 0x2e, 0x30,
+  0x0a
+};
+unsigned int America_Los_Angeles_len = 2845;
+unsigned char America_New_York[] = {
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00,
+  0x9e, 0xa6, 0x1e, 0x70, 0x9f, 0xba, 0xeb, 0x60, 0xa0, 0x86, 0x00, 0x70,
+  0xa1, 0x9a, 0xcd, 0x60, 0xa2, 0x65, 0xe2, 0x70, 0xa3, 0x83, 0xe9, 0xe0,
+  0xa4, 0x6a, 0xae, 0x70, 0xa5, 0x35, 0xa7, 0x60, 0xa6, 0x53, 0xca, 0xf0,
+  0xa7, 0x15, 0x89, 0x60, 0xa8, 0x33, 0xac, 0xf0, 0xa8, 0xfe, 0xa5, 0xe0,
+  0xaa, 0x13, 0x8e, 0xf0, 0xaa, 0xde, 0x87, 0xe0, 0xab, 0xf3, 0x70, 0xf0,
+  0xac, 0xbe, 0x69, 0xe0, 0xad, 0xd3, 0x52, 0xf0, 0xae, 0x9e, 0x4b, 0xe0,
+  0xaf, 0xb3, 0x34, 0xf0, 0xb0, 0x7e, 0x2d, 0xe0, 0xb1, 0x9c, 0x51, 0x70,
+  0xb2, 0x67, 0x4a, 0x60, 0xb3, 0x7c, 0x33, 0x70, 0xb4, 0x47, 0x2c, 0x60,
+  0xb5, 0x5c, 0x15, 0x70, 0xb6, 0x27, 0x0e, 0x60, 0xb7, 0x3b, 0xf7, 0x70,
+  0xb8, 0x06, 0xf0, 0x60, 0xb9, 0x1b, 0xd9, 0x70, 0xb9, 0xe6, 0xd2, 0x60,
+  0xbb, 0x04, 0xf5, 0xf0, 0xbb, 0xc6, 0xb4, 0x60, 0xbc, 0xe4, 0xd7, 0xf0,
+  0xbd, 0xaf, 0xd0, 0xe0, 0xbe, 0xc4, 0xb9, 0xf0, 0xbf, 0x8f, 0xb2, 0xe0,
+  0xc0, 0xa4, 0x9b, 0xf0, 0xc1, 0x6f, 0x94, 0xe0, 0xc2, 0x84, 0x7d, 0xf0,
+  0xc3, 0x4f, 0x76, 0xe0, 0xc4, 0x64, 0x5f, 0xf0, 0xc5, 0x2f, 0x58, 0xe0,
+  0xc6, 0x4d, 0x7c, 0x70, 0xc7, 0x0f, 0x3a, 0xe0, 0xc8, 0x2d, 0x5e, 0x70,
+  0xc8, 0xf8, 0x57, 0x60, 0xca, 0x0d, 0x40, 0x70, 0xca, 0xd8, 0x39, 0x60,
+  0xcb, 0x88, 0xf0, 0x70, 0xd2, 0x23, 0xf4, 0x70, 0xd2, 0x60, 0xfb, 0xe0,
+  0xd3, 0x75, 0xe4, 0xf0, 0xd4, 0x40, 0xdd, 0xe0, 0xd5, 0x55, 0xc6, 0xf0,
+  0xd6, 0x20, 0xbf, 0xe0, 0xd7, 0x35, 0xa8, 0xf0, 0xd8, 0x00, 0xa1, 0xe0,
+  0xd9, 0x15, 0x8a, 0xf0, 0xd9, 0xe0, 0x83, 0xe0, 0xda, 0xfe, 0xa7, 0x70,
+  0xdb, 0xc0, 0x65, 0xe0, 0xdc, 0xde, 0x89, 0x70, 0xdd, 0xa9, 0x82, 0x60,
+  0xde, 0xbe, 0x6b, 0x70, 0xdf, 0x89, 0x64, 0x60, 0xe0, 0x9e, 0x4d, 0x70,
+  0xe1, 0x69, 0x46, 0x60, 0xe2, 0x7e, 0x2f, 0x70, 0xe3, 0x49, 0x28, 0x60,
+  0xe4, 0x5e, 0x11, 0x70, 0xe5, 0x57, 0x2e, 0xe0, 0xe6, 0x47, 0x2d, 0xf0,
+  0xe7, 0x37, 0x10, 0xe0, 0xe8, 0x27, 0x0f, 0xf0, 0xe9, 0x16, 0xf2, 0xe0,
+  0xea, 0x06, 0xf1, 0xf0, 0xea, 0xf6, 0xd4, 0xe0, 0xeb, 0xe6, 0xd3, 0xf0,
+  0xec, 0xd6, 0xb6, 0xe0, 0xed, 0xc6, 0xb5, 0xf0, 0xee, 0xbf, 0xd3, 0x60,
+  0xef, 0xaf, 0xd2, 0x70, 0xf0, 0x9f, 0xb5, 0x60, 0xf1, 0x8f, 0xb4, 0x70,
+  0xf2, 0x7f, 0x97, 0x60, 0xf3, 0x6f, 0x96, 0x70, 0xf4, 0x5f, 0x79, 0x60,
+  0xf5, 0x4f, 0x78, 0x70, 0xf6, 0x3f, 0x5b, 0x60, 0xf7, 0x2f, 0x5a, 0x70,
+  0xf8, 0x28, 0x77, 0xe0, 0xf9, 0x0f, 0x3c, 0x70, 0xfa, 0x08, 0x59, 0xe0,
+  0xfa, 0xf8, 0x58, 0xf0, 0xfb, 0xe8, 0x3b, 0xe0, 0xfc, 0xd8, 0x3a, 0xf0,
+  0xfd, 0xc8, 0x1d, 0xe0, 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xa7, 0xff, 0xe0,
+  0x00, 0x97, 0xfe, 0xf0, 0x01, 0x87, 0xe1, 0xe0, 0x02, 0x77, 0xe0, 0xf0,
+  0x03, 0x70, 0xfe, 0x60, 0x04, 0x60, 0xfd, 0x70, 0x05, 0x50, 0xe0, 0x60,
+  0x06, 0x40, 0xdf, 0x70, 0x07, 0x30, 0xc2, 0x60, 0x07, 0x8d, 0x19, 0x70,
+  0x09, 0x10, 0xa4, 0x60, 0x09, 0xad, 0x94, 0xf0, 0x0a, 0xf0, 0x86, 0x60,
+  0x0b, 0xe0, 0x85, 0x70, 0x0c, 0xd9, 0xa2, 0xe0, 0x0d, 0xc0, 0x67, 0x70,
+  0x0e, 0xb9, 0x84, 0xe0, 0x0f, 0xa9, 0x83, 0xf0, 0x10, 0x99, 0x66, 0xe0,
+  0x11, 0x89, 0x65, 0xf0, 0x12, 0x79, 0x48, 0xe0, 0x13, 0x69, 0x47, 0xf0,
+  0x14, 0x59, 0x2a, 0xe0, 0x15, 0x49, 0x29, 0xf0, 0x16, 0x39, 0x0c, 0xe0,
+  0x17, 0x29, 0x0b, 0xf0, 0x18, 0x22, 0x29, 0x60, 0x19, 0x08, 0xed, 0xf0,
+  0x1a, 0x02, 0x0b, 0x60, 0x1a, 0xf2, 0x0a, 0x70, 0x1b, 0xe1, 0xed, 0x60,
+  0x1c, 0xd1, 0xec, 0x70, 0x1d, 0xc1, 0xcf, 0x60, 0x1e, 0xb1, 0xce, 0x70,
+  0x1f, 0xa1, 0xb1, 0x60, 0x20, 0x76, 0x00, 0xf0, 0x21, 0x81, 0x93, 0x60,
+  0x22, 0x55, 0xe2, 0xf0, 0x23, 0x6a, 0xaf, 0xe0, 0x24, 0x35, 0xc4, 0xf0,
+  0x25, 0x4a, 0x91, 0xe0, 0x26, 0x15, 0xa6, 0xf0, 0x27, 0x2a, 0x73, 0xe0,
+  0x27, 0xfe, 0xc3, 0x70, 0x29, 0x0a, 0x55, 0xe0, 0x29, 0xde, 0xa5, 0x70,
+  0x2a, 0xea, 0x37, 0xe0, 0x2b, 0xbe, 0x87, 0x70, 0x2c, 0xd3, 0x54, 0x60,
+  0x2d, 0x9e, 0x69, 0x70, 0x2e, 0xb3, 0x36, 0x60, 0x2f, 0x7e, 0x4b, 0x70,
+  0x30, 0x93, 0x18, 0x60, 0x31, 0x67, 0x67, 0xf0, 0x32, 0x72, 0xfa, 0x60,
+  0x33, 0x47, 0x49, 0xf0, 0x34, 0x52, 0xdc, 0x60, 0x35, 0x27, 0x2b, 0xf0,
+  0x36, 0x32, 0xbe, 0x60, 0x37, 0x07, 0x0d, 0xf0, 0x38, 0x1b, 0xda, 0xe0,
+  0x38, 0xe6, 0xef, 0xf0, 0x39, 0xfb, 0xbc, 0xe0, 0x3a, 0xc6, 0xd1, 0xf0,
+  0x3b, 0xdb, 0x9e, 0xe0, 0x3c, 0xaf, 0xee, 0x70, 0x3d, 0xbb, 0x80, 0xe0,
+  0x3e, 0x8f, 0xd0, 0x70, 0x3f, 0x9b, 0x62, 0xe0, 0x40, 0x6f, 0xb2, 0x70,
+  0x41, 0x84, 0x7f, 0x60, 0x42, 0x4f, 0x94, 0x70, 0x43, 0x64, 0x61, 0x60,
+  0x44, 0x2f, 0x76, 0x70, 0x45, 0x44, 0x43, 0x60, 0x45, 0xf3, 0xa8, 0xf0,
+  0x47, 0x2d, 0x5f, 0xe0, 0x47, 0xd3, 0x8a, 0xf0, 0x49, 0x0d, 0x41, 0xe0,
+  0x49, 0xb3, 0x6c, 0xf0, 0x4a, 0xed, 0x23, 0xe0, 0x4b, 0x9c, 0x89, 0x70,
+  0x4c, 0xd6, 0x40, 0x60, 0x4d, 0x7c, 0x6b, 0x70, 0x4e, 0xb6, 0x22, 0x60,
+  0x4f, 0x5c, 0x4d, 0x70, 0x50, 0x96, 0x04, 0x60, 0x51, 0x3c, 0x2f, 0x70,
+  0x52, 0x75, 0xe6, 0x60, 0x53, 0x1c, 0x11, 0x70, 0x54, 0x55, 0xc8, 0x60,
+  0x54, 0xfb, 0xf3, 0x70, 0x56, 0x35, 0xaa, 0x60, 0x56, 0xe5, 0x0f, 0xf0,
+  0x58, 0x1e, 0xc6, 0xe0, 0x58, 0xc4, 0xf1, 0xf0, 0x59, 0xfe, 0xa8, 0xe0,
+  0x5a, 0xa4, 0xd3, 0xf0, 0x5b, 0xde, 0x8a, 0xe0, 0x5c, 0x84, 0xb5, 0xf0,
+  0x5d, 0xbe, 0x6c, 0xe0, 0x5e, 0x64, 0x97, 0xf0, 0x5f, 0x9e, 0x4e, 0xe0,
+  0x60, 0x4d, 0xb4, 0x70, 0x61, 0x87, 0x6b, 0x60, 0x62, 0x2d, 0x96, 0x70,
+  0x63, 0x67, 0x4d, 0x60, 0x64, 0x0d, 0x78, 0x70, 0x65, 0x47, 0x2f, 0x60,
+  0x65, 0xed, 0x5a, 0x70, 0x67, 0x27, 0x11, 0x60, 0x67, 0xcd, 0x3c, 0x70,
+  0x69, 0x06, 0xf3, 0x60, 0x69, 0xad, 0x1e, 0x70, 0x6a, 0xe6, 0xd5, 0x60,
+  0x6b, 0x96, 0x3a, 0xf0, 0x6c, 0xcf, 0xf1, 0xe0, 0x6d, 0x76, 0x1c, 0xf0,
+  0x6e, 0xaf, 0xd3, 0xe0, 0x6f, 0x55, 0xfe, 0xf0, 0x70, 0x8f, 0xb5, 0xe0,
+  0x71, 0x35, 0xe0, 0xf0, 0x72, 0x6f, 0x97, 0xe0, 0x73, 0x15, 0xc2, 0xf0,
+  0x74, 0x4f, 0x79, 0xe0, 0x74, 0xfe, 0xdf, 0x70, 0x76, 0x38, 0x96, 0x60,
+  0x76, 0xde, 0xc1, 0x70, 0x78, 0x18, 0x78, 0x60, 0x78, 0xbe, 0xa3, 0x70,
+  0x79, 0xf8, 0x5a, 0x60, 0x7a, 0x9e, 0x85, 0x70, 0x7b, 0xd8, 0x3c, 0x60,
+  0x7c, 0x7e, 0x67, 0x70, 0x7d, 0xb8, 0x1e, 0x60, 0x7e, 0x5e, 0x49, 0x70,
+  0x7f, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x04,
+  0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x0c,
+  0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x45, 0x44,
+  0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, 0x57, 0x54, 0x00, 0x45, 0x50,
+  0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x03, 0xf0, 0x90,
+  0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x1e, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0x9f, 0xba, 0xeb, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, 0x00, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xcd, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xa2, 0x65, 0xe2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x83, 0xe9, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xa4, 0x6a, 0xae, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xa5, 0x35, 0xa7, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x53, 0xca, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xa7, 0x15, 0x89, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xa8, 0x33, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xa8, 0xfe, 0xa5, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xaa, 0x13, 0x8e, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xaa, 0xde, 0x87, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xab, 0xf3, 0x70, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xac, 0xbe, 0x69, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xad, 0xd3, 0x52, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xae, 0x9e, 0x4b, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xaf, 0xb3, 0x34, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xb0, 0x7e, 0x2d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x9c, 0x51, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xb2, 0x67, 0x4a, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xb3, 0x7c, 0x33, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x47, 0x2c, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xb5, 0x5c, 0x15, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xb6, 0x27, 0x0e, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x3b, 0xf7, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xb8, 0x06, 0xf0, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xb9, 0x1b, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xe6, 0xd2, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xbb, 0x04, 0xf5, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xbb, 0xc6, 0xb4, 0x60, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe4, 0xd7, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xbd, 0xaf, 0xd0, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xbe, 0xc4, 0xb9, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8f, 0xb2, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xc0, 0xa4, 0x9b, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xc1, 0x6f, 0x94, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x84, 0x7d, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xc3, 0x4f, 0x76, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xc4, 0x64, 0x5f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc5, 0x2f, 0x58, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xc6, 0x4d, 0x7c, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xc7, 0x0f, 0x3a, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x2d, 0x5e, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xc8, 0xf8, 0x57, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xca, 0x0d, 0x40, 0x70, 0xff, 0xff, 0xff, 0xff, 0xca, 0xd8, 0x39, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xcb, 0x88, 0xf0, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xd2, 0x23, 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x60, 0xfb, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xd3, 0x75, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xd4, 0x40, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x55, 0xc6, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xd6, 0x20, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xd7, 0x35, 0xa8, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0xa1, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xd9, 0x15, 0x8a, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xd9, 0xe0, 0x83, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xa7, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xdb, 0xc0, 0x65, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xdc, 0xde, 0x89, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0x82, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xde, 0xbe, 0x6b, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xdf, 0x89, 0x64, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x4d, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xe1, 0x69, 0x46, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xe2, 0x7e, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x28, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0x11, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xe5, 0x57, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x2d, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xe7, 0x37, 0x10, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xe8, 0x27, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x16, 0xf2, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xea, 0x06, 0xf1, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xea, 0xf6, 0xd4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xd3, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xec, 0xd6, 0xb6, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xed, 0xc6, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xee, 0xbf, 0xd3, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xef, 0xaf, 0xd2, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xf0, 0x9f, 0xb5, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xb4, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xf2, 0x7f, 0x97, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xf3, 0x6f, 0x96, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0x79, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xf5, 0x4f, 0x78, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xf6, 0x3f, 0x5b, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x5a, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x77, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xf9, 0x0f, 0x3c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x59, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xfa, 0xf8, 0x58, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xfb, 0xe8, 0x3b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x3a, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xfd, 0xc8, 0x1d, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x87, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x77, 0xe0, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x70, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x60, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xe0, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x30, 0xc2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x19, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xa4, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x09, 0xad, 0x94, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0x86, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x0b, 0xe0, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0xd9, 0xa2, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x67, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0xb9, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0xa9, 0x83, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x66, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x65, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x12, 0x79, 0x48, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x47, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x14, 0x59, 0x2a, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x15, 0x49, 0x29, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x0c, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x17, 0x29, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x18, 0x22, 0x29, 0x60, 0x00, 0x00, 0x00, 0x00, 0x19, 0x08, 0xed, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x1a, 0xf2, 0x0a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0xed, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x1c, 0xd1, 0xec, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x1d, 0xc1, 0xcf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xce, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x1f, 0xa1, 0xb1, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x20, 0x76, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0x93, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x22, 0x55, 0xe2, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x23, 0x6a, 0xaf, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xc4, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x25, 0x4a, 0x91, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x26, 0x15, 0xa6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x73, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x27, 0xfe, 0xc3, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x29, 0x0a, 0x55, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xa5, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x2a, 0xea, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x2b, 0xbe, 0x87, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x54, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x2d, 0x9e, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x2e, 0xb3, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x4b, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x30, 0x93, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x31, 0x67, 0x67, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xfa, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x33, 0x47, 0x49, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x34, 0x52, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x2b, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0xbe, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x37, 0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0xda, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x38, 0xe6, 0xef, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x39, 0xfb, 0xbc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xd1, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x3b, 0xdb, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x3c, 0xaf, 0xee, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x80, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x3e, 0x8f, 0xd0, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x3f, 0x9b, 0x62, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb2, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x7f, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x42, 0x4f, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x61, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x44, 0x2f, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x45, 0x44, 0x43, 0x60, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xa8, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x2d, 0x5f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0xd3, 0x8a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x41, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x49, 0xb3, 0x6c, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x4a, 0xed, 0x23, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0x89, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x4c, 0xd6, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x4d, 0x7c, 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x22, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x4f, 0x5c, 0x4d, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x50, 0x96, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x2f, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x52, 0x75, 0xe6, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x53, 0x1c, 0x11, 0x70, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xc8, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x54, 0xfb, 0xf3, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x56, 0x35, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x0f, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x58, 0x1e, 0xc6, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x58, 0xc4, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xa8, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x5a, 0xa4, 0xd3, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x5b, 0xde, 0x8a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xb5, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0x6c, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x5e, 0x64, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x4e, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x60, 0x4d, 0xb4, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x61, 0x87, 0x6b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0x96, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x4d, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x64, 0x0d, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x2f, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x65, 0xed, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x67, 0x27, 0x11, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x3c, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x69, 0x06, 0xf3, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x69, 0xad, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xd5, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x6b, 0x96, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x6c, 0xcf, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x1c, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x6e, 0xaf, 0xd3, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x6f, 0x55, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xb5, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x71, 0x35, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x72, 0x6f, 0x97, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xc2, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x74, 0x4f, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x74, 0xfe, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0x96, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x76, 0xde, 0xc1, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x78, 0x18, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xa3, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x79, 0xf8, 0x5a, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x7a, 0x9e, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x3c, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x7c, 0x7e, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x7d, 0xb8, 0x1e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x49, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x7f, 0x98, 0x00, 0x60, 0x00, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff,
+  0xff, 0xc7, 0xc0, 0x01, 0x04, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff,
+  0xff, 0xc7, 0xc0, 0x01, 0x0c, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c,
+  0x4d, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45,
+  0x57, 0x54, 0x00, 0x45, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44,
+  0x54, 0x2c, 0x4d, 0x33, 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31,
+  0x2e, 0x31, 0x2e, 0x30, 0x0a
+};
+unsigned int America_New_York_len = 3545;
+unsigned char Australia_Sydney[] = {
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00,
+  0x9c, 0x4e, 0xa6, 0x9c, 0x9c, 0xbc, 0x20, 0xf0, 0xcb, 0x54, 0xb3, 0x00,
+  0xcb, 0xc7, 0x57, 0x70, 0xcc, 0xb7, 0x56, 0x80, 0xcd, 0xa7, 0x39, 0x70,
+  0xce, 0xa0, 0x73, 0x00, 0xcf, 0x87, 0x1b, 0x70, 0x03, 0x70, 0x39, 0x80,
+  0x04, 0x0d, 0x1c, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x05, 0xf6, 0x38, 0x80,
+  0x07, 0x2f, 0xfd, 0x80, 0x07, 0xd6, 0x1a, 0x80, 0x09, 0x0f, 0xdf, 0x80,
+  0x09, 0xb5, 0xfc, 0x80, 0x0a, 0xef, 0xc1, 0x80, 0x0b, 0x9f, 0x19, 0x00,
+  0x0c, 0xd8, 0xde, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x0e, 0xb8, 0xc0, 0x00,
+  0x0f, 0x5e, 0xdd, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x11, 0x3e, 0xbf, 0x00,
+  0x12, 0x78, 0x84, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x14, 0x58, 0x66, 0x00,
+  0x14, 0xfe, 0x83, 0x00, 0x16, 0x38, 0x48, 0x00, 0x17, 0x0c, 0x89, 0x80,
+  0x18, 0x21, 0x64, 0x80, 0x18, 0xc7, 0x81, 0x80, 0x1a, 0x01, 0x46, 0x80,
+  0x1a, 0xa7, 0x63, 0x80, 0x1b, 0xe1, 0x28, 0x80, 0x1c, 0x87, 0x45, 0x80,
+  0x1d, 0xc1, 0x0a, 0x80, 0x1e, 0x79, 0x9c, 0x80, 0x1f, 0x97, 0xb2, 0x00,
+  0x20, 0x59, 0x7e, 0x80, 0x21, 0x80, 0xce, 0x80, 0x22, 0x42, 0x9b, 0x00,
+  0x23, 0x69, 0xeb, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x25, 0x49, 0xcd, 0x00,
+  0x25, 0xef, 0xea, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x27, 0xcf, 0xcc, 0x00,
+  0x29, 0x09, 0x91, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x2a, 0xe9, 0x73, 0x00,
+  0x2b, 0x98, 0xca, 0x80, 0x2c, 0xd2, 0x8f, 0x80, 0x2d, 0x78, 0xac, 0x80,
+  0x2e, 0xb2, 0x71, 0x80, 0x2f, 0x58, 0x8e, 0x80, 0x30, 0x92, 0x53, 0x80,
+  0x31, 0x5d, 0x5a, 0x80, 0x32, 0x72, 0x35, 0x80, 0x33, 0x3d, 0x3c, 0x80,
+  0x34, 0x52, 0x17, 0x80, 0x35, 0x1d, 0x1e, 0x80, 0x36, 0x31, 0xf9, 0x80,
+  0x36, 0xfd, 0x00, 0x80, 0x38, 0x1b, 0x16, 0x00, 0x38, 0xdc, 0xe2, 0x80,
+  0x39, 0xa7, 0xe9, 0x80, 0x3a, 0xbc, 0xc4, 0x80, 0x3b, 0xda, 0xda, 0x00,
+  0x3c, 0xa5, 0xe1, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x3e, 0x85, 0xc3, 0x00,
+  0x3f, 0x9a, 0x9e, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x41, 0x83, 0xba, 0x80,
+  0x42, 0x45, 0x87, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x44, 0x2e, 0xa3, 0x80,
+  0x45, 0x43, 0x7e, 0x80, 0x46, 0x05, 0x4b, 0x00, 0x47, 0x23, 0x60, 0x80,
+  0x47, 0xf7, 0xa2, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x49, 0xd7, 0x84, 0x00,
+  0x4a, 0xc7, 0x75, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x4c, 0xa7, 0x57, 0x00,
+  0x4d, 0x97, 0x48, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x4f, 0x77, 0x2a, 0x00,
+  0x50, 0x70, 0x55, 0x80, 0x51, 0x60, 0x46, 0x80, 0x52, 0x50, 0x37, 0x80,
+  0x53, 0x40, 0x28, 0x80, 0x54, 0x30, 0x19, 0x80, 0x55, 0x20, 0x0a, 0x80,
+  0x56, 0x0f, 0xfb, 0x80, 0x56, 0xff, 0xec, 0x80, 0x57, 0xef, 0xdd, 0x80,
+  0x58, 0xdf, 0xce, 0x80, 0x59, 0xcf, 0xbf, 0x80, 0x5a, 0xbf, 0xb0, 0x80,
+  0x5b, 0xb8, 0xdc, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x5d, 0x98, 0xbe, 0x00,
+  0x5e, 0x88, 0xaf, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x60, 0x68, 0x91, 0x00,
+  0x61, 0x58, 0x82, 0x00, 0x62, 0x48, 0x73, 0x00, 0x63, 0x38, 0x64, 0x00,
+  0x64, 0x28, 0x55, 0x00, 0x65, 0x18, 0x46, 0x00, 0x66, 0x11, 0x71, 0x80,
+  0x67, 0x01, 0x62, 0x80, 0x67, 0xf1, 0x53, 0x80, 0x68, 0xe1, 0x44, 0x80,
+  0x69, 0xd1, 0x35, 0x80, 0x6a, 0xc1, 0x26, 0x80, 0x6b, 0xb1, 0x17, 0x80,
+  0x6c, 0xa1, 0x08, 0x80, 0x6d, 0x90, 0xf9, 0x80, 0x6e, 0x80, 0xea, 0x80,
+  0x6f, 0x70, 0xdb, 0x80, 0x70, 0x6a, 0x07, 0x00, 0x71, 0x59, 0xf8, 0x00,
+  0x72, 0x49, 0xe9, 0x00, 0x73, 0x39, 0xda, 0x00, 0x74, 0x29, 0xcb, 0x00,
+  0x75, 0x19, 0xbc, 0x00, 0x76, 0x09, 0xad, 0x00, 0x76, 0xf9, 0x9e, 0x00,
+  0x77, 0xe9, 0x8f, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x79, 0xc9, 0x71, 0x00,
+  0x7a, 0xb9, 0x62, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x7c, 0xa2, 0x7e, 0x80,
+  0x7d, 0x92, 0x6f, 0x80, 0x7e, 0x82, 0x60, 0x80, 0x7f, 0x72, 0x51, 0x80,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00,
+  0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00,
+  0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00,
+  0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x45, 0x44, 0x54,
+  0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e,
+  0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0x73, 0x16, 0x7f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x4e, 0xa6, 0x9c,
+  0xff, 0xff, 0xff, 0xff, 0x9c, 0xbc, 0x20, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xcb, 0x54, 0xb3, 0x00, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xc7, 0x57, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xcc, 0xb7, 0x56, 0x80, 0xff, 0xff, 0xff, 0xff,
+  0xcd, 0xa7, 0x39, 0x70, 0xff, 0xff, 0xff, 0xff, 0xce, 0xa0, 0x73, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0xcf, 0x87, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x70, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0d, 0x1c, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x05, 0xf6, 0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2f, 0xfd, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x07, 0xd6, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x09, 0x0f, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xb5, 0xfc, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x0a, 0xef, 0xc1, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x0b, 0x9f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd8, 0xde, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0xb8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5e, 0xdd, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x3e, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x78, 0x84, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x14, 0x58, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xfe, 0x83, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x16, 0x38, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x17, 0x0c, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x18, 0x21, 0x64, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x18, 0xc7, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x1a, 0x01, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xa7, 0x63, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x87, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, 0x0a, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x1e, 0x79, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x1f, 0x97, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x59, 0x7e, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x21, 0x80, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x22, 0x42, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0xeb, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x25, 0x49, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xef, 0xea, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x27, 0xcf, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x09, 0x91, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x2a, 0xe9, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x98, 0xca, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x2c, 0xd2, 0x8f, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x2d, 0x78, 0xac, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb2, 0x71, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x2f, 0x58, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x30, 0x92, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5d, 0x5a, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x33, 0x3d, 0x3c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x17, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x35, 0x1d, 0x1e, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x36, 0x31, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x36, 0xfd, 0x00, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x38, 0xdc, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa7, 0xe9, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x3a, 0xbc, 0xc4, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x3b, 0xda, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa5, 0xe1, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x3e, 0x85, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9a, 0x9e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x41, 0x83, 0xba, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x87, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x44, 0x2e, 0xa3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0x7e, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0x23, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0xf7, 0xa2, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x49, 0xd7, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xc7, 0x75, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x4c, 0xa7, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x97, 0x48, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x4f, 0x77, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x70, 0x55, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x51, 0x60, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x52, 0x50, 0x37, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x40, 0x28, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x54, 0x30, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x55, 0x20, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0x0f, 0xfb, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x56, 0xff, 0xec, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x57, 0xef, 0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x58, 0xdf, 0xce, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x59, 0xcf, 0xbf, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x5a, 0xbf, 0xb0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xb8, 0xdc, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x5d, 0x98, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x88, 0xaf, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x60, 0x68, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x58, 0x82, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x62, 0x48, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x63, 0x38, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0x55, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x65, 0x18, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x11, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x62, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x67, 0xf1, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x68, 0xe1, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xd1, 0x35, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x6a, 0xc1, 0x26, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x6b, 0xb1, 0x17, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xa1, 0x08, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x6d, 0x90, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x6e, 0x80, 0xea, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0xdb, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x70, 0x6a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x71, 0x59, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x49, 0xe9, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x73, 0x39, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x74, 0x29, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x19, 0xbc, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x76, 0x09, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x76, 0xf9, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xe9, 0x8f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x79, 0xc9, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xb9, 0x62, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x7c, 0xa2, 0x7e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x92, 0x6f, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x7f, 0x72, 0x51, 0x80, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x00, 0x00, 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a,
+  0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a,
+  0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54,
+  0x00, 0x41, 0x45, 0x44, 0x54, 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00,
+  0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x45,
+  0x53, 0x54, 0x2d, 0x31, 0x30, 0x41, 0x45, 0x44, 0x54, 0x2c, 0x4d, 0x31,
+  0x30, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x4d, 0x34, 0x2e, 0x31, 0x2e, 0x30,
+  0x2f, 0x33, 0x0a
+};
+unsigned int Australia_Sydney_len = 2223;
diff --git a/absl/time/time.cc b/absl/time/time.cc
new file mode 100644
index 0000000..71fd8ee
--- /dev/null
+++ b/absl/time/time.cc
@@ -0,0 +1,384 @@
+// Copyright 2017 The Abseil 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 implementation of the absl::Time class, which is declared in
+// //absl/time.h.
+//
+// The representation for an absl::Time is an absl::Duration offset from the
+// epoch.  We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)
+// for convenience, but this is not exposed in the API and could be changed.
+//
+// NOTE: To keep type verbosity to a minimum, the following variable naming
+// conventions are used throughout this file.
+//
+// cz: A cctz::time_zone
+// tz: An absl::TimeZone
+// cl: A cctz::time_zone::civil_lookup
+// al: A cctz::time_zone::absolute_lookup
+// cd: A cctz::civil_day
+// cs: A cctz::civil_second
+// bd: An absl::Time::Breakdown
+
+#include "absl/time/time.h"
+
+#include <cstring>
+#include <ctime>
+#include <limits>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace cctz = absl::time_internal::cctz;
+namespace absl {
+
+namespace {
+
+inline cctz::time_point<cctz::seconds> unix_epoch() {
+  return std::chrono::time_point_cast<cctz::seconds>(
+      std::chrono::system_clock::from_time_t(0));
+}
+
+// Floors d to the next unit boundary closer to negative infinity.
+inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
+  absl::Duration rem;
+  int64_t q = absl::IDivDuration(d, unit, &rem);
+  return (q > 0 ||
+          rem >= ZeroDuration() ||
+          q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
+}
+
+inline absl::Time::Breakdown InfiniteFutureBreakdown() {
+  absl::Time::Breakdown bd;
+  bd.year = std::numeric_limits<int64_t>::max();
+  bd.month = 12;
+  bd.day = 31;
+  bd.hour = 23;
+  bd.minute = 59;
+  bd.second = 59;
+  bd.subsecond = absl::InfiniteDuration();
+  bd.weekday = 4;
+  bd.yearday = 365;
+  bd.offset = 0;
+  bd.is_dst = false;
+  bd.zone_abbr = "-00";
+  return bd;
+}
+
+inline Time::Breakdown InfinitePastBreakdown() {
+  Time::Breakdown bd;
+  bd.year = std::numeric_limits<int64_t>::min();
+  bd.month = 1;
+  bd.day = 1;
+  bd.hour = 0;
+  bd.minute = 0;
+  bd.second = 0;
+  bd.subsecond = -absl::InfiniteDuration();
+  bd.weekday = 7;
+  bd.yearday = 1;
+  bd.offset = 0;
+  bd.is_dst = false;
+  bd.zone_abbr = "-00";
+  return bd;
+}
+
+inline absl::TimeConversion InfiniteFutureTimeConversion() {
+  absl::TimeConversion tc;
+  tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
+  tc.kind = absl::TimeConversion::UNIQUE;
+  tc.normalized = true;
+  return tc;
+}
+
+inline TimeConversion InfinitePastTimeConversion() {
+  absl::TimeConversion tc;
+  tc.pre = tc.trans = tc.post = absl::InfinitePast();
+  tc.kind = absl::TimeConversion::UNIQUE;
+  tc.normalized = true;
+  return tc;
+}
+
+// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
+// necessary. If sec is min/max, then consult cs+tz to check for overlow.
+Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
+                          const cctz::civil_second& cs,
+                          const cctz::time_zone& tz,
+                          bool* normalized = nullptr) {
+  const auto max = cctz::time_point<cctz::seconds>::max();
+  const auto min = cctz::time_point<cctz::seconds>::min();
+  if (sec == max) {
+    const auto al = tz.lookup(max);
+    if (cs > al.cs) {
+      if (normalized) *normalized = true;
+      return absl::InfiniteFuture();
+    }
+  }
+  if (sec == min) {
+    const auto al = tz.lookup(min);
+    if (cs < al.cs) {
+      if (normalized) *normalized = true;
+      return absl::InfinitePast();
+    }
+  }
+  const auto hi = (sec - unix_epoch()).count();
+  return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
+}
+
+inline absl::TimeConversion::Kind MapKind(
+    const cctz::time_zone::civil_lookup::civil_kind& kind) {
+  switch (kind) {
+    case cctz::time_zone::civil_lookup::UNIQUE:
+      return absl::TimeConversion::UNIQUE;
+    case cctz::time_zone::civil_lookup::SKIPPED:
+      return absl::TimeConversion::SKIPPED;
+    case cctz::time_zone::civil_lookup::REPEATED:
+      return absl::TimeConversion::REPEATED;
+  }
+  return absl::TimeConversion::UNIQUE;
+}
+
+// Returns Mon=1..Sun=7.
+inline int MapWeekday(const cctz::weekday& wd) {
+  switch (wd) {
+    case cctz::weekday::monday:
+      return 1;
+    case cctz::weekday::tuesday:
+      return 2;
+    case cctz::weekday::wednesday:
+      return 3;
+    case cctz::weekday::thursday:
+      return 4;
+    case cctz::weekday::friday:
+      return 5;
+    case cctz::weekday::saturday:
+      return 6;
+    case cctz::weekday::sunday:
+      return 7;
+  }
+  return 1;
+}
+
+}  // namespace
+
+absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
+  if (*this == absl::InfiniteFuture()) return absl::InfiniteFutureBreakdown();
+  if (*this == absl::InfinitePast()) return absl::InfinitePastBreakdown();
+
+  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
+  const auto al = cctz::time_zone(tz).lookup(tp);
+  const auto cs = al.cs;
+  const auto cd = cctz::civil_day(cs);
+
+  absl::Time::Breakdown bd;
+  bd.year = cs.year();
+  bd.month = cs.month();
+  bd.day = cs.day();
+  bd.hour = cs.hour();
+  bd.minute = cs.minute();
+  bd.second = cs.second();
+  bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
+  bd.weekday = MapWeekday(get_weekday(cd));
+  bd.yearday = get_yearday(cd);
+  bd.offset = al.offset;
+  bd.is_dst = al.is_dst;
+  bd.zone_abbr = al.abbr;
+  return bd;
+}
+
+absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
+  const auto cz = cctz::time_zone(tz);
+  const auto cs =
+      cctz::civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+                         tm.tm_hour, tm.tm_min, tm.tm_sec);
+  const auto cl = cz.lookup(cs);
+  const auto tp = tm.tm_isdst == 0 ? cl.post : cl.pre;
+  return MakeTimeWithOverflow(tp, cs, cz);
+}
+
+struct tm ToTM(absl::Time t, absl::TimeZone tz) {
+  const absl::Time::Breakdown bd = t.In(tz);
+  struct tm tm;
+  std::memset(&tm, 0, sizeof(tm));
+  tm.tm_sec = bd.second;
+  tm.tm_min = bd.minute;
+  tm.tm_hour = bd.hour;
+  tm.tm_mday = bd.day;
+  tm.tm_mon = bd.month - 1;
+
+  // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
+  // that tm.tm_year is years since 1900.
+  if (bd.year < std::numeric_limits<int>::min() + 1900) {
+    tm.tm_year = std::numeric_limits<int>::min();
+  } else if (bd.year > std::numeric_limits<int>::max()) {
+    tm.tm_year = std::numeric_limits<int>::max() - 1900;
+  } else {
+    tm.tm_year = static_cast<int>(bd.year - 1900);
+  }
+
+  tm.tm_wday = bd.weekday % 7;
+  tm.tm_yday = bd.yearday - 1;
+  tm.tm_isdst = bd.is_dst ? 1 : 0;
+
+  return tm;
+}
+
+//
+// Factory functions.
+//
+
+absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+                                     int min, int sec, TimeZone tz) {
+  // Avoids years that are too extreme for civil_second to normalize.
+  if (year > 300000000000) return InfiniteFutureTimeConversion();
+  if (year < -300000000000) return InfinitePastTimeConversion();
+  const auto cz = cctz::time_zone(tz);
+  const auto cs = cctz::civil_second(year, mon, day, hour, min, sec);
+  absl::TimeConversion tc;
+  tc.normalized = year != cs.year() || mon != cs.month() || day != cs.day() ||
+                  hour != cs.hour() || min != cs.minute() || sec != cs.second();
+  const auto cl = cz.lookup(cs);
+  // Converts the civil_lookup struct to a TimeConversion.
+  tc.pre = MakeTimeWithOverflow(cl.pre, cs, cz, &tc.normalized);
+  tc.trans = MakeTimeWithOverflow(cl.trans, cs, cz, &tc.normalized);
+  tc.post = MakeTimeWithOverflow(cl.post, cs, cz, &tc.normalized);
+  tc.kind = MapKind(cl.kind);
+  return tc;
+}
+
+absl::Time FromDateTime(int64_t year, int mon, int day, int hour, int min,
+                        int sec, TimeZone tz) {
+  if (year > 300000000000) return InfiniteFuture();
+  if (year < -300000000000) return InfinitePast();
+  const auto cz = cctz::time_zone(tz);
+  const auto cs = cctz::civil_second(year, mon, day, hour, min, sec);
+  const auto cl = cz.lookup(cs);
+  return MakeTimeWithOverflow(cl.pre, cs, cz);
+}
+
+absl::Time TimeFromTimespec(timespec ts) {
+  return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
+}
+
+absl::Time TimeFromTimeval(timeval tv) {
+  return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
+}
+
+absl::Time FromUDate(double udate) {
+  return time_internal::FromUnixDuration(absl::Milliseconds(udate));
+}
+
+absl::Time FromUniversal(int64_t universal) {
+  return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
+}
+
+//
+// Conversion to other time types.
+//
+
+int64_t ToUnixNanos(Time t) {
+  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
+            1000 * 1000 * 1000) +
+           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
+  }
+  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
+}
+
+int64_t ToUnixMicros(Time t) {
+  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
+            1000 * 1000) +
+           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
+  }
+  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
+}
+
+int64_t ToUnixMillis(Time t) {
+  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
+           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
+            (4000 * 1000));
+  }
+  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
+}
+
+int64_t ToUnixSeconds(Time t) {
+  return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
+}
+
+time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
+
+timespec ToTimespec(Time t) {
+  timespec ts;
+  absl::Duration d = time_internal::ToUnixDuration(t);
+  if (!time_internal::IsInfiniteDuration(d)) {
+    ts.tv_sec = time_internal::GetRepHi(d);
+    if (ts.tv_sec == time_internal::GetRepHi(d)) {  // no time_t narrowing
+      ts.tv_nsec = time_internal::GetRepLo(d) / 4;  // floor
+      return ts;
+    }
+  }
+  if (d >= absl::ZeroDuration()) {
+    ts.tv_sec = std::numeric_limits<time_t>::max();
+    ts.tv_nsec = 1000 * 1000 * 1000 - 1;
+  } else {
+    ts.tv_sec = std::numeric_limits<time_t>::min();
+    ts.tv_nsec = 0;
+  }
+  return ts;
+}
+
+timeval ToTimeval(Time t) {
+  timeval tv;
+  timespec ts = absl::ToTimespec(t);
+  tv.tv_sec = ts.tv_sec;
+  if (tv.tv_sec != ts.tv_sec) {  // narrowing
+    if (ts.tv_sec < 0) {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
+      tv.tv_usec = 0;
+    } else {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
+      tv.tv_usec = 1000 * 1000 - 1;
+    }
+    return tv;
+  }
+  tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t
+  return tv;
+}
+
+double ToUDate(Time t) {
+  return absl::FDivDuration(time_internal::ToUnixDuration(t),
+                            absl::Milliseconds(1));
+}
+
+int64_t ToUniversal(absl::Time t) {
+  return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
+}
+
+Time FromChrono(const std::chrono::system_clock::time_point& tp) {
+  return time_internal::FromUnixDuration(time_internal::FromChrono(
+      tp - std::chrono::system_clock::from_time_t(0)));
+}
+
+std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
+  using D = std::chrono::system_clock::duration;
+  auto d = time_internal::ToUnixDuration(t);
+  if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
+  return std::chrono::system_clock::from_time_t(0) +
+         time_internal::ToChronoDuration<D>(d);
+}
+
+}  // namespace absl
diff --git a/absl/time/time.h b/absl/time/time.h
new file mode 100644
index 0000000..ceec2de
--- /dev/null
+++ b/absl/time/time.h
@@ -0,0 +1,1336 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// File: time.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines abstractions for computing with absolute points
+// in time, durations of time, and formatting and parsing time within a given
+// time zone. The following abstractions are defined:
+//
+//  * `absl::Time` defines an absolute, specific instance in time
+//  * `absl::Duration` defines a signed, fixed-length span of time
+//  * `absl::TimeZone` defines geopolitical time zone regions (as collected
+//     within the IANA Time Zone database (https://www.iana.org/time-zones)).
+//
+// Example:
+//
+//   absl::TimeZone nyc;
+//
+//   // LoadTimeZone may fail so it's always better to check for success.
+//   if (!absl::LoadTimeZone("America/New_York", &nyc)) {
+//      // handle error case
+//   }
+//
+//   // My flight leaves NYC on Jan 2, 2017 at 03:04:05
+//   absl::Time takeoff = absl::FromDateTime(2017, 1, 2, 3, 4, 5, nyc);
+//   absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35);
+//   absl::Time landing = takeoff + flight_duration;
+//
+//   absl::TimeZone syd;
+//   if (!absl::LoadTimeZone("Australia/Sydney", &syd)) {
+//      // handle error case
+//   }
+//   std::string s = absl::FormatTime(
+//       "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S",
+//       landing, syd);
+//
+#ifndef ABSL_TIME_TIME_H_
+#define ABSL_TIME_TIME_H_
+
+#if !defined(_WIN32)
+#include <sys/time.h>
+#else
+#include <winsock2.h>
+#endif
+#include <chrono>  // NOLINT(build/c++11)
+#include <cstdint>
+#include <ctime>
+#include <ostream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/port.h"  // Needed for string vs std::string
+#include "absl/strings/string_view.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+
+class Duration;  // Defined below
+class Time;      // Defined below
+class TimeZone;  // Defined below
+
+namespace time_internal {
+int64_t IDivDuration(bool satq, Duration num, Duration den, Duration* rem);
+constexpr Time FromUnixDuration(Duration d);
+constexpr Duration ToUnixDuration(Time t);
+constexpr int64_t GetRepHi(Duration d);
+constexpr uint32_t GetRepLo(Duration d);
+constexpr Duration MakeDuration(int64_t hi, uint32_t lo);
+constexpr Duration MakeDuration(int64_t hi, int64_t lo);
+constexpr int64_t kTicksPerNanosecond = 4;
+constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
+template <std::intmax_t N>
+constexpr Duration FromInt64(int64_t v, std::ratio<1, N>);
+constexpr Duration FromInt64(int64_t v, std::ratio<60>);
+constexpr Duration FromInt64(int64_t v, std::ratio<3600>);
+template <typename T>
+using EnableIfIntegral = typename std::enable_if<
+    std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
+template <typename T>
+using EnableIfFloat =
+    typename std::enable_if<std::is_floating_point<T>::value, int>::type;
+}  // namespace time_internal
+
+// Duration
+//
+// The `absl::Duration` class represents a signed, fixed-length span of time.
+// A `Duration` is generated using a unit-specific factory function, or is
+// the result of subtracting one `absl::Time` from another. Durations behave
+// like unit-safe integers and they support all the natural integer-like
+// arithmetic operations. Arithmetic overflows and saturates at +/- infinity.
+// `Duration` should be passed by value rather than const reference.
+//
+// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`,
+// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for
+// creation of constexpr `Duration` values
+//
+// Examples:
+//
+//   constexpr absl::Duration ten_ns = absl::Nanoseconds(10);
+//   constexpr absl::Duration min = absl::Minutes(1);
+//   constexpr absl::Duration hour = absl::Hours(1);
+//   absl::Duration dur = 60 * min;  // dur == hour
+//   absl::Duration half_sec = absl::Milliseconds(500);
+//   absl::Duration quarter_sec = 0.25 * absl::Seconds(1);
+//
+// `Duration` values can be easily converted to an integral number of units
+// using the division operator.
+//
+// Example:
+//
+//   constexpr absl::Duration dur = absl::Milliseconds(1500);
+//   int64_t ns = dur / absl::Nanoseconds(1);   // ns == 1500000000
+//   int64_t ms = dur / absl::Milliseconds(1);  // ms == 1500
+//   int64_t sec = dur / absl::Seconds(1);    // sec == 1 (subseconds truncated)
+//   int64_t min = dur / absl::Minutes(1);    // min == 0
+//
+// See the `IDivDuration()` and `FDivDuration()` functions below for details on
+// how to access the fractional parts of the quotient.
+//
+// Alternatively, conversions can be performed using helpers such as
+// `ToInt64Microseconds()` and `ToDoubleSeconds()`.
+class Duration {
+ public:
+  // Value semantics.
+  constexpr Duration() : rep_hi_(0), rep_lo_(0) {}  // zero-length duration
+
+  // Compound assignment operators.
+  Duration& operator+=(Duration d);
+  Duration& operator-=(Duration d);
+  Duration& operator*=(int64_t r);
+  Duration& operator*=(double r);
+  Duration& operator/=(int64_t r);
+  Duration& operator/=(double r);
+  Duration& operator%=(Duration rhs);
+
+  // Overloads that forward to either the int64_t or double overloads above.
+  template <typename T>
+  Duration& operator*=(T r) {
+    int64_t x = r;
+    return *this *= x;
+  }
+  template <typename T>
+  Duration& operator/=(T r) {
+    int64_t x = r;
+    return *this /= x;
+  }
+  Duration& operator*=(float r) { return *this *= static_cast<double>(r); }
+  Duration& operator/=(float r) { return *this /= static_cast<double>(r); }
+
+ private:
+  friend constexpr int64_t time_internal::GetRepHi(Duration d);
+  friend constexpr uint32_t time_internal::GetRepLo(Duration d);
+  friend constexpr Duration time_internal::MakeDuration(int64_t hi,
+                                                        uint32_t lo);
+  constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {}
+  int64_t rep_hi_;
+  uint32_t rep_lo_;
+};
+
+// Relational Operators
+constexpr bool operator<(Duration lhs, Duration rhs);
+constexpr bool operator>(Duration lhs, Duration rhs) { return rhs < lhs; }
+constexpr bool operator>=(Duration lhs, Duration rhs) { return !(lhs < rhs); }
+constexpr bool operator<=(Duration lhs, Duration rhs) { return !(rhs < lhs); }
+constexpr bool operator==(Duration lhs, Duration rhs);
+constexpr bool operator!=(Duration lhs, Duration rhs) { return !(lhs == rhs); }
+
+// Additive Operators
+constexpr Duration operator-(Duration d);
+inline Duration operator+(Duration lhs, Duration rhs) { return lhs += rhs; }
+inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; }
+
+// Multiplicative Operators
+template <typename T>
+Duration operator*(Duration lhs, T rhs) {
+  return lhs *= rhs;
+}
+template <typename T>
+Duration operator*(T lhs, Duration rhs) {
+  return rhs *= lhs;
+}
+template <typename T>
+Duration operator/(Duration lhs, T rhs) {
+  return lhs /= rhs;
+}
+inline int64_t operator/(Duration lhs, Duration rhs) {
+  return time_internal::IDivDuration(true, lhs, rhs,
+                                     &lhs);  // trunc towards zero
+}
+inline Duration operator%(Duration lhs, Duration rhs) { return lhs %= rhs; }
+
+// IDivDuration()
+//
+// Divides a numerator `Duration` by a denominator `Duration`, returning the
+// quotient and remainder. The remainder always has the same sign as the
+// numerator. The returned quotient and remainder respect the identity:
+//
+//   numerator = denominator * quotient + remainder
+//
+// Returned quotients are capped to the range of `int64_t`, with the difference
+// spilling into the remainder to uphold the above identity. This means that the
+// remainder returned could differ from the remainder returned by
+// `Duration::operator%` for huge quotients.
+//
+// See also the notes on `InfiniteDuration()` below regarding the behavior of
+// division involving zero and infinite durations.
+//
+// Example:
+//
+//   constexpr absl::Duration a =
+//       absl::Seconds(std::numeric_limits<int64_t>::max());  // big
+//   constexpr absl::Duration b = absl::Nanoseconds(1);       // small
+//
+//   absl::Duration rem = a % b;
+//   // rem == absl::ZeroDuration()
+//
+//   // Here, q would overflow int64_t, so rem accounts for the difference.
+//   int64_t q = absl::IDivDuration(a, b, &rem);
+//   // q == std::numeric_limits<int64_t>::max(), rem == a - b * q
+inline int64_t IDivDuration(Duration num, Duration den, Duration* rem) {
+  return time_internal::IDivDuration(true, num, den,
+                                     rem);  // trunc towards zero
+}
+
+// FDivDuration()
+//
+// Divides a `Duration` numerator into a fractional number of units of a
+// `Duration` denominator.
+//
+// See also the notes on `InfiniteDuration()` below regarding the behavior of
+// division involving zero and infinite durations.
+//
+// Example:
+//
+//   double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1));
+//   // d == 1.5
+double FDivDuration(Duration num, Duration den);
+
+// ZeroDuration()
+//
+// Returns a zero-length duration. This function behaves just like the default
+// constructor, but the name helps make the semantics clear at call sites.
+constexpr Duration ZeroDuration() { return Duration(); }
+
+// AbsDuration()
+//
+// Returns the absolute value of a duration.
+inline Duration AbsDuration(Duration d) {
+  return (d < ZeroDuration()) ? -d : d;
+}
+
+// Trunc()
+//
+// Truncates a duration (toward zero) to a multiple of a non-zero unit.
+//
+// Example:
+//
+//   absl::Duration d = absl::Nanoseconds(123456789);
+//   absl::Duration a = absl::Trunc(d, absl::Microseconds(1));  // 123456us
+Duration Trunc(Duration d, Duration unit);
+
+// Floor()
+//
+// Floors a duration using the passed duration unit to its largest value not
+// greater than the duration.
+//
+// Example:
+//
+//   absl::Duration d = absl::Nanoseconds(123456789);
+//   absl::Duration b = absl::Floor(d, absl::Microseconds(1));  // 123456us
+Duration Floor(Duration d, Duration unit);
+
+// Ceil()
+//
+// Returns the ceiling of a duration using the passed duration unit to its
+// smallest value not less than the duration.
+//
+// Example:
+//
+//   absl::Duration d = absl::Nanoseconds(123456789);
+//   absl::Duration c = absl::Ceil(d, absl::Microseconds(1));   // 123457us
+Duration Ceil(Duration d, Duration unit);
+
+// Nanoseconds()
+// Microseconds()
+// Milliseconds()
+// Seconds()
+// Minutes()
+// Hours()
+//
+// Factory functions for constructing `Duration` values from an integral number
+// of the unit indicated by the factory function's name.
+//
+// Note: no "Days()" factory function exists because "a day" is ambiguous. Civil
+// days are not always 24 hours long, and a 24-hour duration often does not
+// correspond with a civil day. If a 24-hour duration is needed, use
+// `absl::Hours(24)`.
+//
+//
+// Example:
+//
+//   absl::Duration a = absl::Seconds(60);
+//   absl::Duration b = absl::Minutes(1);  // b == a
+constexpr Duration Nanoseconds(int64_t n);
+constexpr Duration Microseconds(int64_t n);
+constexpr Duration Milliseconds(int64_t n);
+constexpr Duration Seconds(int64_t n);
+constexpr Duration Minutes(int64_t n);
+constexpr Duration Hours(int64_t n);
+
+// Factory overloads for constructing `Duration` values from a floating-point
+// number of the unit indicated by the factory function's name. These functions
+// exist for convenience, but they are not as efficient as the integral
+// factories, which should be preferred.
+//
+// Example:
+//   auto a = absl::Seconds(1.5);        // OK
+//   auto b = absl::Milliseconds(1500);  // BETTER
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Nanoseconds(T n) {
+  return n * Nanoseconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Microseconds(T n) {
+  return n * Microseconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Milliseconds(T n) {
+  return n * Milliseconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Seconds(T n) {
+  return n * Seconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Minutes(T n) {
+  return n * Minutes(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Hours(T n) {
+  return n * Hours(1);
+}
+
+// ToInt64Nanoseconds()
+// ToInt64Microseconds()
+// ToInt64Milliseconds()
+// ToInt64Seconds()
+// ToInt64Minutes()
+// ToInt64Hours()
+//
+// Helper functions that convert a Duration to an integral count of the
+// indicated unit. These functions are shorthand for the `IDivDuration()`
+// function above; see its documentation for details about overflow, etc.
+//
+// Example:
+//
+//   absl::Duration d = absl::Milliseconds(1500);
+//   int64_t isec = absl::ToInt64Seconds(d);  // isec == 1
+int64_t ToInt64Nanoseconds(Duration d);
+int64_t ToInt64Microseconds(Duration d);
+int64_t ToInt64Milliseconds(Duration d);
+int64_t ToInt64Seconds(Duration d);
+int64_t ToInt64Minutes(Duration d);
+int64_t ToInt64Hours(Duration d);
+
+// ToDoubleNanoSeconds()
+// ToDoubleMicroseconds()
+// ToDoubleMilliseconds()
+// ToDoubleSeconds()
+// ToDoubleMinutes()
+// ToDoubleHours()
+//
+// Helper functions that convert a Duration to a floating point count of the
+// indicated unit. These functions are shorthand for the `FDivDuration()`
+// function above; see its documentation for details about overflow, etc.
+//
+// Example:
+//
+//   absl::Duration d = absl::Milliseconds(1500);
+//   double dsec = absl::ToDoubleSeconds(d);  // dsec == 1.5
+double ToDoubleNanoseconds(Duration d);
+double ToDoubleMicroseconds(Duration d);
+double ToDoubleMilliseconds(Duration d);
+double ToDoubleSeconds(Duration d);
+double ToDoubleMinutes(Duration d);
+double ToDoubleHours(Duration d);
+
+// FromChrono()
+//
+// Converts any of the pre-defined std::chrono durations to an absl::Duration.
+//
+// Example:
+//
+//   std::chrono::milliseconds ms(123);
+//   absl::Duration d = absl::FromChrono(ms);
+constexpr Duration FromChrono(const std::chrono::nanoseconds& d);
+constexpr Duration FromChrono(const std::chrono::microseconds& d);
+constexpr Duration FromChrono(const std::chrono::milliseconds& d);
+constexpr Duration FromChrono(const std::chrono::seconds& d);
+constexpr Duration FromChrono(const std::chrono::minutes& d);
+constexpr Duration FromChrono(const std::chrono::hours& d);
+
+// ToChronoNanoseconds()
+// ToChronoMicroseconds()
+// ToChronoMilliseconds()
+// ToChronoSeconds()
+// ToChronoMinutes()
+// ToChronoHours()
+//
+// Converts an absl::Duration to any of the pre-defined std::chrono durations.
+// If overflow would occur, the returned value will saturate at the min/max
+// chrono duration value instead.
+//
+// Example:
+//
+//   absl::Duration d = absl::Microseconds(123);
+//   auto x = absl::ToChronoMicroseconds(d);
+//   auto y = absl::ToChronoNanoseconds(d);  // x == y
+//   auto z = absl::ToChronoSeconds(absl::InfiniteDuration());
+//   // z == std::chrono::seconds::max()
+std::chrono::nanoseconds ToChronoNanoseconds(Duration d);
+std::chrono::microseconds ToChronoMicroseconds(Duration d);
+std::chrono::milliseconds ToChronoMilliseconds(Duration d);
+std::chrono::seconds ToChronoSeconds(Duration d);
+std::chrono::minutes ToChronoMinutes(Duration d);
+std::chrono::hours ToChronoHours(Duration d);
+
+// InfiniteDuration()
+//
+// Returns an infinite `Duration`.  To get a `Duration` representing negative
+// infinity, use `-InfiniteDuration()`.
+//
+// Duration arithmetic overflows to +/- infinity and saturates. In general,
+// arithmetic with `Duration` infinities is similar to IEEE 754 infinities
+// except where IEEE 754 NaN would be involved, in which case +/-
+// `InfiniteDuration()` is used in place of a "nan" Duration.
+//
+// Examples:
+//
+//   constexpr absl::Duration inf = absl::InfiniteDuration();
+//   const absl::Duration d = ... any finite duration ...
+//
+//   inf == inf + inf
+//   inf == inf + d
+//   inf == inf - inf
+//   -inf == d - inf
+//
+//   inf == d * 1e100
+//   inf == inf / 2
+//   0 == d / inf
+//   INT64_MAX == inf / d
+//
+//   // Division by zero returns infinity, or INT64_MIN/MAX where appropriate.
+//   inf == d / 0
+//   INT64_MAX == d / absl::ZeroDuration()
+//
+// The examples involving the `/` operator above also apply to `IDivDuration()`
+// and `FDivDuration()`.
+constexpr Duration InfiniteDuration();
+
+// FormatDuration()
+//
+// Returns a std::string representing the duration in the form "72h3m0.5s".
+// Returns "inf" or "-inf" for +/- `InfiniteDuration()`.
+std::string FormatDuration(Duration d);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Duration d) {
+  return os << FormatDuration(d);
+}
+
+// ParseDuration()
+//
+// Parses a duration std::string consisting of a possibly signed sequence of
+// decimal numbers, each with an optional fractional part and a unit
+// suffix.  The valid suffixes are "ns", "us" "ms", "s", "m", and "h".
+// Simple examples include "300ms", "-1.5h", and "2h45m".  Parses "0" as
+// `ZeroDuration()`.  Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
+bool ParseDuration(const std::string& dur_string, Duration* d);
+
+// ParseFlag()
+//
+bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
+
+// UnparseFlag()
+//
+std::string UnparseFlag(Duration d);
+
+// Time
+//
+// An `absl::Time` represents a specific instant in time. Arithmetic operators
+// are provided for naturally expressing time calculations. Instances are
+// created using `absl::Now()` and the `absl::From*()` factory functions that
+// accept the gamut of other time representations. Formatting and parsing
+// functions are provided for conversion to and from strings.  `absl::Time`
+// should be passed by value rather than const reference.
+//
+// `absl::Time` assumes there are 60 seconds in a minute, which means the
+// underlying time scales must be "smeared" to eliminate leap seconds.
+// See https://developers.google.com/time/smear.
+//
+// Even though `absl::Time` supports a wide range of timestamps, exercise
+// caution when using values in the distant past. `absl::Time` uses the
+// Proleptic Gregorian calendar, which extends the Gregorian calendar backward
+// to dates before its introduction in 1582.
+// See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
+// for more information. Use the ICU calendar classes to convert a date in
+// some other calendar (http://userguide.icu-project.org/datetime/calendar).
+//
+// Similarly, standardized time zones are a reasonably recent innovation, with
+// the Greenwich prime meridian being established in 1884. The TZ database
+// itself does not profess accurate offsets for timestamps prior to 1970. The
+// breakdown of future timestamps is subject to the whim of regional
+// governments.
+//
+// The `absl::Time` class represents an instant in time as a count of clock
+// ticks of some granularity (resolution) from some starting point (epoch).
+//
+//
+// `absl::Time` uses a resolution that is high enough to avoid loss in
+// precision, and a range that is wide enough to avoid overflow, when
+// converting between tick counts in most Google time scales (i.e., precision
+// of at least one nanosecond, and range +/-100 billion years).  Conversions
+// between the time scales are performed by truncating (towards negative
+// infinity) to the nearest representable point.
+//
+// Examples:
+//
+//   absl::Time t1 = ...;
+//   absl::Time t2 = t1 + absl::Minutes(2);
+//   absl::Duration d = t2 - t1;  // == absl::Minutes(2)
+//   absl::Time::Breakdown bd = t1.In(absl::LocalTimeZone());
+//
+class Time {
+ public:
+  // Value semantics.
+
+  // Returns the Unix epoch.  However, those reading your code may not know
+  // or expect the Unix epoch as the default value, so make your code more
+  // readable by explicitly initializing all instances before use.
+  //
+  // Example:
+  //   absl::Time t = absl::UnixEpoch();
+  //   absl::Time t = absl::Now();
+  //   absl::Time t = absl::TimeFromTimeval(tv);
+  //   absl::Time t = absl::InfinitePast();
+  constexpr Time() {}
+
+  // Assignment operators.
+  Time& operator+=(Duration d) {
+    rep_ += d;
+    return *this;
+  }
+  Time& operator-=(Duration d) {
+    rep_ -= d;
+    return *this;
+  }
+
+  // Time::Breakdown
+  //
+  // The calendar and wall-clock (aka "civil time") components of an
+  // `absl::Time` in a certain `absl::TimeZone`. This struct is not
+  // intended to represent an instant in time. So, rather than passing
+  // a `Time::Breakdown` to a function, pass an `absl::Time` and an
+  // `absl::TimeZone`.
+  struct Breakdown {
+    int64_t year;          // year (e.g., 2013)
+    int month;           // month of year [1:12]
+    int day;             // day of month [1:31]
+    int hour;            // hour of day [0:23]
+    int minute;          // minute of hour [0:59]
+    int second;          // second of minute [0:59]
+    Duration subsecond;  // [Seconds(0):Seconds(1)) if finite
+    int weekday;         // 1==Mon, ..., 7=Sun
+    int yearday;         // day of year [1:366]
+
+    // Note: The following fields exist for backward compatibility
+    // with older APIs.  Accessing these fields directly is a sign of
+    // imprudent logic in the calling code.  Modern time-related code
+    // should only access this data indirectly by way of FormatTime().
+    // These fields are undefined for InfiniteFuture() and InfinitePast().
+    int offset;             // seconds east of UTC
+    bool is_dst;            // is offset non-standard?
+    const char* zone_abbr;  // time-zone abbreviation (e.g., "PST")
+  };
+
+  // Time::In()
+  //
+  // Returns the breakdown of this instant in the given TimeZone.
+  Breakdown In(TimeZone tz) const;
+
+ private:
+  friend constexpr Time time_internal::FromUnixDuration(Duration d);
+  friend constexpr Duration time_internal::ToUnixDuration(Time t);
+  friend constexpr bool operator<(Time lhs, Time rhs);
+  friend constexpr bool operator==(Time lhs, Time rhs);
+  friend Duration operator-(Time lhs, Time rhs);
+  friend constexpr Time UniversalEpoch();
+  friend constexpr Time InfiniteFuture();
+  friend constexpr Time InfinitePast();
+  constexpr explicit Time(Duration rep) : rep_(rep) {}
+  Duration rep_;
+};
+
+// Relational Operators
+constexpr bool operator<(Time lhs, Time rhs) { return lhs.rep_ < rhs.rep_; }
+constexpr bool operator>(Time lhs, Time rhs) { return rhs < lhs; }
+constexpr bool operator>=(Time lhs, Time rhs) { return !(lhs < rhs); }
+constexpr bool operator<=(Time lhs, Time rhs) { return !(rhs < lhs); }
+constexpr bool operator==(Time lhs, Time rhs) { return lhs.rep_ == rhs.rep_; }
+constexpr bool operator!=(Time lhs, Time rhs) { return !(lhs == rhs); }
+
+// Additive Operators
+inline Time operator+(Time lhs, Duration rhs) { return lhs += rhs; }
+inline Time operator+(Duration lhs, Time rhs) { return rhs += lhs; }
+inline Time operator-(Time lhs, Duration rhs) { return lhs -= rhs; }
+inline Duration operator-(Time lhs, Time rhs) { return lhs.rep_ - rhs.rep_; }
+
+// UnixEpoch()
+//
+// Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000".
+constexpr Time UnixEpoch() { return Time(); }
+
+// UniversalEpoch()
+//
+// Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the
+// epoch of the ICU Universal Time Scale.
+constexpr Time UniversalEpoch() {
+  // 719162 is the number of days from 0001-01-01 to 1970-01-01,
+  // assuming the Gregorian calendar.
+  return Time(time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, 0U));
+}
+
+// InfiniteFuture()
+//
+// Returns an `absl::Time` that is infinitely far in the future.
+constexpr Time InfiniteFuture() {
+  return Time(
+      time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U));
+}
+
+// InfinitePast()
+//
+// Returns an `absl::Time` that is infinitely far in the past.
+constexpr Time InfinitePast() {
+  return Time(
+      time_internal::MakeDuration(std::numeric_limits<int64_t>::min(), ~0U));
+}
+
+// TimeConversion
+//
+// An `absl::TimeConversion` represents the conversion of year, month, day,
+// hour, minute, and second values (i.e., a civil time), in a particular
+// `absl::TimeZone`, to a time instant (an absolute time), as returned by
+// `absl::ConvertDateTime()`. (Subseconds must be handled separately.)
+//
+// It is possible, though, for a caller to try to convert values that
+// do not represent an actual or unique instant in time (due to a shift
+// in UTC offset in the `absl::TimeZone`, which results in a discontinuity in
+// the civil-time components). For example, a daylight-saving-time
+// transition skips or repeats civil times---in the United States, March
+// 13, 2011 02:15 never occurred, while November 6, 2011 01:15 occurred
+// twice---so requests for such times are not well-defined.
+//
+// To account for these possibilities, `absl::TimeConversion` is richer
+// than just a single `absl::Time`. When the civil time is skipped or
+// repeated, `absl::ConvertDateTime()` returns times calculated using the
+// pre-transition and post-transition UTC offsets, plus the transition
+// time itself.
+//
+// Examples:
+//
+//   absl::TimeZone lax;
+//   if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... }
+//
+//   // A unique civil time
+//   absl::TimeConversion jan01 =
+//       absl::ConvertDateTime(2011, 1, 1, 0, 0, 0, lax);
+//   // jan01.kind == TimeConversion::UNIQUE
+//   // jan01.pre    is 2011/01/01 00:00:00 -0800
+//   // jan01.trans  is 2011/01/01 00:00:00 -0800
+//   // jan01.post   is 2011/01/01 00:00:00 -0800
+//
+//   // A Spring DST transition, when there is a gap in civil time
+//   absl::TimeConversion mar13 =
+//       absl::ConvertDateTime(2011, 3, 13, 2, 15, 0, lax);
+//   // mar13.kind == TimeConversion::SKIPPED
+//   // mar13.pre   is 2011/03/13 03:15:00 -0700
+//   // mar13.trans is 2011/03/13 03:00:00 -0700
+//   // mar13.post  is 2011/03/13 01:15:00 -0800
+//
+//   // A Fall DST transition, when civil times are repeated
+//   absl::TimeConversion nov06 =
+//       absl::ConvertDateTime(2011, 11, 6, 1, 15, 0, lax);
+//   // nov06.kind == TimeConversion::REPEATED
+//   // nov06.pre   is 2011/11/06 01:15:00 -0700
+//   // nov06.trans is 2011/11/06 01:00:00 -0800
+//   // nov06.post  is 2011/11/06 01:15:00 -0800
+//
+// The input month, day, hour, minute, and second values can also be
+// outside of their valid ranges, in which case they will be "normalized"
+// during the conversion.
+//
+// Example:
+//
+//   // "October 32" normalizes to "November 1".
+//   absl::TimeZone tz = absl::LocalTimeZone();
+//   absl::TimeConversion tc =
+//       absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, tz);
+//   // tc.kind == TimeConversion::UNIQUE && tc.normalized == true
+//   // tc.pre.In(tz).month == 11 && tc.pre.In(tz).day == 1
+struct TimeConversion {
+  Time pre;    // time calculated using the pre-transition offset
+  Time trans;  // when the civil-time discontinuity occurred
+  Time post;   // time calculated using the post-transition offset
+
+  enum Kind {
+    UNIQUE,    // the civil time was singular (pre == trans == post)
+    SKIPPED,   // the civil time did not exist
+    REPEATED,  // the civil time was ambiguous
+  };
+  Kind kind;
+
+  bool normalized;  // input values were outside their valid ranges
+};
+
+// ConvertDateTime()
+//
+// The full generality of a civil time to absl::Time conversion.
+TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+                               int min, int sec, TimeZone tz);
+
+// FromDateTime()
+//
+// A convenience wrapper for `absl::ConvertDateTime()` that simply returns the
+// "pre" `absl::Time`.  That is, the unique result, or the instant that
+// is correct using the pre-transition offset (as if the transition
+// never happened). This is typically the answer that humans expected when
+// faced with non-unique times, such as near daylight-saving time transitions.
+//
+// Example:
+//
+//   absl::TimeZone seattle;
+//   if (!absl::LoadTimeZone("America/Los_Angeles", &seattle)) { ... }
+//   absl::Time t =  absl::FromDateTime(2017, 9, 26, 9, 30, 0, seattle);
+Time FromDateTime(int64_t year, int mon, int day, int hour, int min, int sec,
+                  TimeZone tz);
+
+// FromTM()
+//
+// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
+// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
+// for a description of the expected values of the tm fields. IFF the indicated
+// time instant is not unique (see `absl::ConvertDateTime()` above), the
+// `tm_isdst` field is consulted to select the desired instant (`tm_isdst` > 0
+// means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 means use the default
+// like `absl::FromDateTime()`).
+Time FromTM(const struct tm& tm, TimeZone tz);
+
+// ToTM()
+//
+// Converts the given `absl::Time` to a struct tm using the given time zone.
+// See ctime(3) for a description of the values of the tm fields.
+struct tm ToTM(Time t, TimeZone tz);
+
+// FromUnixNanos()
+// FromUnixMicros()
+// FromUnixMillis()
+// FromUnixSeconds()
+// FromTimeT()
+// FromUDate()
+// FromUniversal()
+//
+// Creates an `absl::Time` from a variety of other representations.
+constexpr Time FromUnixNanos(int64_t ns);
+constexpr Time FromUnixMicros(int64_t us);
+constexpr Time FromUnixMillis(int64_t ms);
+constexpr Time FromUnixSeconds(int64_t s);
+constexpr Time FromTimeT(time_t t);
+Time FromUDate(double udate);
+Time FromUniversal(int64_t universal);
+
+// ToUnixNanos()
+// ToUnixMicros()
+// ToUnixMillis()
+// ToUnixSeconds()
+// ToTimeT()
+// ToUDate()
+// ToUniversal()
+//
+// Converts an `absl::Time` to a variety of other representations.  Note that
+// these operations round down toward negative infinity where necessary to
+// adjust to the resolution of the result type.  Beware of possible time_t
+// over/underflow in ToTime{T,val,spec}() on 32-bit platforms.
+int64_t ToUnixNanos(Time t);
+int64_t ToUnixMicros(Time t);
+int64_t ToUnixMillis(Time t);
+int64_t ToUnixSeconds(Time t);
+time_t ToTimeT(Time t);
+double ToUDate(Time t);
+int64_t ToUniversal(Time t);
+
+// DurationFromTimespec()
+// DurationFromTimeval()
+// ToTimespec()
+// ToTimeval()
+// TimeFromTimespec()
+// TimeFromTimeval()
+// ToTimespec()
+// ToTimeval()
+//
+// Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2)
+// and select(2)), while others use them as a Time (e.g. clock_gettime(2)
+// and gettimeofday(2)), so conversion functions are provided for both cases.
+// The "to timespec/val" direction is easily handled via overloading, but
+// for "from timespec/val" the desired type is part of the function name.
+Duration DurationFromTimespec(timespec ts);
+Duration DurationFromTimeval(timeval tv);
+timespec ToTimespec(Duration d);
+timeval ToTimeval(Duration d);
+Time TimeFromTimespec(timespec ts);
+Time TimeFromTimeval(timeval tv);
+timespec ToTimespec(Time t);
+timeval ToTimeval(Time t);
+
+// FromChrono()
+//
+// Converts a std::chrono::system_clock::time_point to an absl::Time.
+//
+// Example:
+//
+//   auto tp = std::chrono::system_clock::from_time_t(123);
+//   absl::Time t = absl::FromChrono(tp);
+//   // t == absl::FromTimeT(123)
+Time FromChrono(const std::chrono::system_clock::time_point& tp);
+
+// ToChronoTime()
+//
+// Converts an absl::Time to a std::chrono::system_clock::time_point. If
+// overflow would occur, the returned value will saturate at the min/max time
+// point value instead.
+//
+// Example:
+//
+//   absl::Time t = absl::FromTimeT(123);
+//   auto tp = absl::ToChronoTime(t);
+//   // tp == std::chrono::system_clock::from_time_t(123);
+std::chrono::system_clock::time_point ToChronoTime(Time);
+
+// RFC3339_full
+// RFC3339_sec
+//
+// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings,
+// with trailing zeros trimmed or with fractional seconds omitted altogether.
+//
+// Note that RFC3339_sec[] matches an ISO 8601 extended format for date
+// and time with UTC offset.
+extern const char RFC3339_full[];  // %Y-%m-%dT%H:%M:%E*S%Ez
+extern const char RFC3339_sec[];   // %Y-%m-%dT%H:%M:%S%Ez
+
+// RFC1123_full
+// RFC1123_no_wday
+//
+// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
+extern const char RFC1123_full[];     // %a, %d %b %E4Y %H:%M:%S %z
+extern const char RFC1123_no_wday[];  // %d %b %E4Y %H:%M:%S %z
+
+// FormatTime()
+//
+// Formats the given `absl::Time` in the `absl::TimeZone` according to the
+// provided format std::string. Uses strftime()-like formatting options, with
+// the following extensions:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E#f - Fractional seconds with # digits of precision
+//   - %E*f - Fractional seconds with full precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//
+// Note that %E0S behaves like %S, and %E0f produces no characters.  In
+// contrast %E*f always produces at least one digit, which may be '0'.
+//
+// Note that %Y produces as many characters as it takes to fully render the
+// year.  A year outside of [-999:9999] when formatted with %E4Y will produce
+// more than four characters, just like %Y.
+//
+// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
+// so that the result uniquely identifies a time instant.
+//
+// Example:
+//
+//   absl::TimeZone lax;
+//   if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... }
+//   absl::Time t = absl::FromDateTime(2013, 1, 2, 3, 4, 5, lax);
+//
+//   std::string f = absl::FormatTime("%H:%M:%S", t, lax);  // "03:04:05"
+//   f = absl::FormatTime("%H:%M:%E3S", t, lax);  // "03:04:05.000"
+//
+// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
+// std::string will be exactly "infinite-future". If the given `absl::Time` is
+// `absl::InfinitePast()`, the returned std::string will be exactly "infinite-past".
+// In both cases the given format std::string and `absl::TimeZone` are ignored.
+//
+std::string FormatTime(const std::string& format, Time t, TimeZone tz);
+
+// Convenience functions that format the given time using the RFC3339_full
+// format.  The first overload uses the provided TimeZone, while the second
+// uses LocalTimeZone().
+std::string FormatTime(Time t, TimeZone tz);
+std::string FormatTime(Time t);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Time t) {
+  return os << FormatTime(t);
+}
+
+// ParseTime()
+//
+// Parses an input std::string according to the provided format std::string and
+// returns the corresponding `absl::Time`. Uses strftime()-like formatting
+// options, with the same extensions as FormatTime(), but with the
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.  %Ez
+// and %E*z also accept the same inputs.
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric.  %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+//   "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a std::string of "15:45" (%H:%M) will return an absl::Time
+// that represents "1970-01-01 15:45:00.0 +0000".
+//
+// Note that since ParseTime() returns time instants, it makes the most sense
+// to parse fully-specified date/time strings that include a UTC offset (%z,
+// %Ez, or %E*z).
+//
+// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
+// hour, minute, (fractional) second, and UTC offset.  Other fields, like
+// weekday (%a or %A), while parsed for syntactic validity, are ignored
+// in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors
+// rather than normalizing them like `absl::FromDateTime()` does.  For example,
+// it is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A leap second of ":60" is normalized to ":00" of the following minute
+// with fractional seconds discarded.  The following table shows how the
+// given seconds and subseconds will be parsed:
+//
+//   "59.x" -> 59.x  // exact
+//   "60.x" -> 00.0  // normalized
+//   "00.x" -> 00.x  // exact
+//
+// Errors are indicated by returning false and assigning an error message
+// to the "err" out param if it is non-null.
+//
+// Note: If the input std::string is exactly "infinite-future", the returned
+// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned.
+// If the input std::string is "infinite-past", the returned `absl::Time` will be
+// `absl::InfinitePast()` and `true` will be returned.
+//
+bool ParseTime(const std::string& format, const std::string& input, Time* time,
+               std::string* err);
+
+// Like ParseTime() above, but if the format std::string does not contain a UTC
+// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
+// given TimeZone.  This means that the input, by itself, does not identify a
+// unique instant.  Being time-zone dependent, it also admits the possibility
+// of ambiguity or non-existence, in which case the "pre" time (as defined
+// for ConvertDateTime()) is returned.  For these reasons we recommend that
+// all date/time strings include a UTC offset so they're context independent.
+bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
+               Time* time, std::string* err);
+
+// ParseFlag()
+// UnparseFlag()
+//
+// Support for flag values of type Time. Time flags must be specified in a
+// format that matches absl::RFC3339_full. For example:
+//
+//   --start_time=2016-01-02T03:04:05.678+08:00
+//
+// Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required.
+//
+// Additionally, if you'd like to specify a time as a count of
+// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag
+// and add that duration to absl::UnixEpoch() to get an absl::Time.
+bool ParseFlag(const std::string& text, Time* t, std::string* error);
+std::string UnparseFlag(Time t);
+
+// TimeZone
+//
+// The `absl::TimeZone` is an opaque, small, value-type class representing a
+// geo-political region within which particular rules are used for converting
+// between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone`
+// values are named using the TZ identifiers from the IANA Time Zone Database,
+// such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values
+// are created from factory functions such as `absl::LoadTimeZone()`. Note:
+// strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by
+// value rather than const reference.
+//
+// For more on the fundamental concepts of time zones, absolute times, and civil
+// times, see https://github.com/google/cctz#fundamental-concepts
+//
+// Examples:
+//
+//   absl::TimeZone utc = absl::UTCTimeZone();
+//   absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60);
+//   absl::TimeZone loc = absl::LocalTimeZone();
+//   absl::TimeZone lax;
+//   if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... }
+//
+// See also:
+// - https://github.com/google/cctz
+// - http://www.iana.org/time-zones
+// - http://en.wikipedia.org/wiki/Zoneinfo
+class TimeZone {
+ public:
+  explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {}
+  TimeZone() = default;  // UTC, but prefer UTCTimeZone() to be explicit.
+  TimeZone(const TimeZone&) = default;
+  TimeZone& operator=(const TimeZone&) = default;
+
+  explicit operator time_internal::cctz::time_zone() const { return cz_; }
+
+  std::string name() const { return cz_.name(); }
+
+ private:
+  friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; }
+  friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; }
+  friend std::ostream& operator<<(std::ostream& os, TimeZone tz) {
+    return os << tz.name();
+  }
+
+  time_internal::cctz::time_zone cz_;
+};
+
+// LoadTimeZone()
+//
+// Loads the named zone. May perform I/O on the initial load of the named
+// zone. If the name is invalid, or some other kind of error occurs, returns
+// `false` and `*tz` is set to the UTC time zone.
+inline bool LoadTimeZone(const std::string& name, TimeZone* tz) {
+  if (name == "localtime") {
+    *tz = TimeZone(time_internal::cctz::local_time_zone());
+    return true;
+  }
+  time_internal::cctz::time_zone cz;
+  const bool b = time_internal::cctz::load_time_zone(name, &cz);
+  *tz = TimeZone(cz);
+  return b;
+}
+
+// FixedTimeZone()
+//
+// Returns a TimeZone that is a fixed offset (seconds east) from UTC.
+// Note: If the absolute value of the offset is greater than 24 hours
+// you'll get UTC (i.e., no offset) instead.
+inline TimeZone FixedTimeZone(int seconds) {
+  return TimeZone(
+      time_internal::cctz::fixed_time_zone(std::chrono::seconds(seconds)));
+}
+
+// UTCTimeZone()
+//
+// Convenience method returning the UTC time zone.
+inline TimeZone UTCTimeZone() {
+  return TimeZone(time_internal::cctz::utc_time_zone());
+}
+
+// LocalTimeZone()
+//
+// Convenience method returning the local time zone, or UTC if there is
+// no configured local zone.  Warning: Be wary of using LocalTimeZone(),
+// and particularly so in a server process, as the zone configured for the
+// local machine should be irrelevant.  Prefer an explicit zone name.
+inline TimeZone LocalTimeZone() {
+  return TimeZone(time_internal::cctz::local_time_zone());
+}
+
+// ============================================================================
+// Implementation Details Follow
+// ============================================================================
+
+namespace time_internal {
+
+// Creates a Duration with a given representation.
+// REQUIRES: hi,lo is a valid representation of a Duration as specified
+// in time/duration.cc.
+constexpr Duration MakeDuration(int64_t hi, uint32_t lo = 0) {
+  return Duration(hi, lo);
+}
+
+constexpr Duration MakeDuration(int64_t hi, int64_t lo) {
+  return MakeDuration(hi, static_cast<uint32_t>(lo));
+}
+
+// Creates a normalized Duration from an almost-normalized (sec,ticks)
+// pair. sec may be positive or negative.  ticks must be in the range
+// -kTicksPerSecond < *ticks < kTicksPerSecond.  If ticks is negative it
+// will be normalized to a positive value in the resulting Duration.
+constexpr Duration MakeNormalizedDuration(int64_t sec, int64_t ticks) {
+  return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond)
+                     : MakeDuration(sec, ticks);
+}
+// Provide access to the Duration representation.
+constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; }
+constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; }
+constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; }
+
+// Returns an infinite Duration with the opposite sign.
+// REQUIRES: IsInfiniteDuration(d)
+constexpr Duration OppositeInfinity(Duration d) {
+  return GetRepHi(d) < 0
+             ? MakeDuration(std::numeric_limits<int64_t>::max(), ~0U)
+             : MakeDuration(std::numeric_limits<int64_t>::min(), ~0U);
+}
+
+// Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow.
+constexpr int64_t NegateAndSubtractOne(int64_t n) {
+  // Note: Good compilers will optimize this expression to ~n when using
+  // a two's-complement representation (which is required for int64_t).
+  return (n < 0) ? -(n + 1) : (-n) - 1;
+}
+
+// Map between a Time and a Duration since the Unix epoch.  Note that these
+// functions depend on the above mentioned choice of the Unix epoch for the
+// Time representation (and both need to be Time friends).  Without this
+// knowledge, we would need to add-in/subtract-out UnixEpoch() respectively.
+constexpr Time FromUnixDuration(Duration d) { return Time(d); }
+constexpr Duration ToUnixDuration(Time t) { return t.rep_; }
+
+template <std::intmax_t N>
+constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) {
+  static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio");
+  // Subsecond ratios cannot overflow.
+  return MakeNormalizedDuration(
+      v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
+}
+constexpr Duration FromInt64(int64_t v, std::ratio<60>) {
+  return (v <= std::numeric_limits<int64_t>::max() / 60 &&
+          v >= std::numeric_limits<int64_t>::min() / 60)
+             ? MakeDuration(v * 60)
+             : v > 0 ? InfiniteDuration() : -InfiniteDuration();
+}
+constexpr Duration FromInt64(int64_t v, std::ratio<3600>) {
+  return (v <= std::numeric_limits<int64_t>::max() / 3600 &&
+          v >= std::numeric_limits<int64_t>::min() / 3600)
+             ? MakeDuration(v * 3600)
+             : v > 0 ? InfiniteDuration() : -InfiniteDuration();
+}
+
+// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
+// valid. That is, if a T can be assigned to an int64_t without narrowing.
+template <typename T>
+constexpr auto IsValidRep64(int)
+    -> decltype(int64_t{std::declval<T>()}, bool()) {
+  return true;
+}
+template <typename T>
+constexpr auto IsValidRep64(char) -> bool {
+  return false;
+}
+
+// Converts a std::chrono::duration to an absl::Duration.
+template <typename Rep, typename Period>
+constexpr Duration FromChrono(const std::chrono::duration<Rep, Period>& d) {
+  static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
+  return FromInt64(int64_t{d.count()}, Period{});
+}
+
+template <typename Ratio>
+int64_t ToInt64(Duration d, Ratio) {
+  // Note: This may be used on MSVC, which may have a system_clock period of
+  // std::ratio<1, 10 * 1000 * 1000>
+  return ToInt64Seconds(d * Ratio::den / Ratio::num);
+}
+// Fastpath implementations for the 6 common duration units.
+inline int64_t ToInt64(Duration d, std::nano) {
+  return ToInt64Nanoseconds(d);
+}
+inline int64_t ToInt64(Duration d, std::micro) {
+  return ToInt64Microseconds(d);
+}
+inline int64_t ToInt64(Duration d, std::milli) {
+  return ToInt64Milliseconds(d);
+}
+inline int64_t ToInt64(Duration d, std::ratio<1>) {
+  return ToInt64Seconds(d);
+}
+inline int64_t ToInt64(Duration d, std::ratio<60>) {
+  return ToInt64Minutes(d);
+}
+inline int64_t ToInt64(Duration d, std::ratio<3600>) {
+  return ToInt64Hours(d);
+}
+
+// Converts an absl::Duration to a chrono duration of type T.
+template <typename T>
+T ToChronoDuration(Duration d) {
+  using Rep = typename T::rep;
+  using Period = typename T::period;
+  static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
+  if (time_internal::IsInfiniteDuration(d))
+    return d < ZeroDuration() ? T::min() : T::max();
+  const auto v = ToInt64(d, Period{});
+  if (v > std::numeric_limits<Rep>::max()) return T::max();
+  if (v < std::numeric_limits<Rep>::min()) return T::min();
+  return T{v};
+}
+
+}  // namespace time_internal
+constexpr Duration Nanoseconds(int64_t n) {
+  return time_internal::FromInt64(n, std::nano{});
+}
+constexpr Duration Microseconds(int64_t n) {
+  return time_internal::FromInt64(n, std::micro{});
+}
+constexpr Duration Milliseconds(int64_t n) {
+  return time_internal::FromInt64(n, std::milli{});
+}
+constexpr Duration Seconds(int64_t n) {
+  return time_internal::FromInt64(n, std::ratio<1>{});
+}
+constexpr Duration Minutes(int64_t n) {
+  return time_internal::FromInt64(n, std::ratio<60>{});
+}
+constexpr Duration Hours(int64_t n) {
+  return time_internal::FromInt64(n, std::ratio<3600>{});
+}
+
+constexpr bool operator<(Duration lhs, Duration rhs) {
+  return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
+             ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
+             : time_internal::GetRepHi(lhs) == std::numeric_limits<int64_t>::min()
+                   ? time_internal::GetRepLo(lhs) + 1 <
+                         time_internal::GetRepLo(rhs) + 1
+                   : time_internal::GetRepLo(lhs) <
+                         time_internal::GetRepLo(rhs);
+}
+
+constexpr bool operator==(Duration lhs, Duration rhs) {
+  return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) &&
+         time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs);
+}
+
+constexpr Duration operator-(Duration d) {
+  // This is a little interesting because of the special cases.
+  //
+  // If rep_lo_ is zero, we have it easy; it's safe to negate rep_hi_, we're
+  // dealing with an integral number of seconds, and the only special case is
+  // the maximum negative finite duration, which can't be negated.
+  //
+  // Infinities stay infinite, and just change direction.
+  //
+  // Finally we're in the case where rep_lo_ is non-zero, and we can borrow
+  // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1
+  // is safe).
+  return time_internal::GetRepLo(d) == 0
+             ? time_internal::GetRepHi(d) == std::numeric_limits<int64_t>::min()
+                   ? InfiniteDuration()
+                   : time_internal::MakeDuration(-time_internal::GetRepHi(d))
+             : time_internal::IsInfiniteDuration(d)
+                   ? time_internal::OppositeInfinity(d)
+                   : time_internal::MakeDuration(
+                         time_internal::NegateAndSubtractOne(
+                             time_internal::GetRepHi(d)),
+                         time_internal::kTicksPerSecond -
+                             time_internal::GetRepLo(d));
+}
+
+constexpr Duration InfiniteDuration() {
+  return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U);
+}
+
+constexpr Duration FromChrono(const std::chrono::nanoseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::microseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::milliseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::seconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::minutes& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::hours& d) {
+  return time_internal::FromChrono(d);
+}
+
+constexpr Time FromUnixNanos(int64_t ns) {
+  return time_internal::FromUnixDuration(Nanoseconds(ns));
+}
+
+constexpr Time FromUnixMicros(int64_t us) {
+  return time_internal::FromUnixDuration(Microseconds(us));
+}
+
+constexpr Time FromUnixMillis(int64_t ms) {
+  return time_internal::FromUnixDuration(Milliseconds(ms));
+}
+
+constexpr Time FromUnixSeconds(int64_t s) {
+  return time_internal::FromUnixDuration(Seconds(s));
+}
+
+constexpr Time FromTimeT(time_t t) {
+  return time_internal::FromUnixDuration(Seconds(t));
+}
+
+}  // namespace absl
+
+#endif  // ABSL_TIME_TIME_H_
diff --git a/absl/time/time_benchmark.cc b/absl/time/time_benchmark.cc
new file mode 100644
index 0000000..e100994
--- /dev/null
+++ b/absl/time/time_benchmark.cc
@@ -0,0 +1,316 @@
+// Copyright 2018 The Abseil 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 "absl/time/time.h"
+
+#if !defined(_WIN32)
+#include <sys/time.h>
+#endif  // _WIN32
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <ctime>
+#include <memory>
+#include <string>
+
+#include "absl/time/clock.h"
+#include "absl/time/internal/test_util.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+//
+// Addition/Subtraction of a duration
+//
+
+void BM_Time_Arithmetic(benchmark::State& state) {
+  const absl::Duration nano = absl::Nanoseconds(1);
+  const absl::Duration sec = absl::Seconds(1);
+  absl::Time t = absl::UnixEpoch();
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(t += nano);
+    benchmark::DoNotOptimize(t -= sec);
+  }
+}
+BENCHMARK(BM_Time_Arithmetic);
+
+//
+// Time difference
+//
+
+void BM_Time_Difference(benchmark::State& state) {
+  absl::Time start = absl::Now();
+  absl::Time end = start + absl::Nanoseconds(1);
+  absl::Duration diff;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(diff += end - start);
+  }
+}
+BENCHMARK(BM_Time_Difference);
+
+//
+// ToDateTime
+//
+// In each "ToDateTime" benchmark we switch between two instants
+// separated by at least one transition in order to defeat any
+// internal caching of previous results (e.g., see local_time_hint_).
+//
+// The "UTC" variants use UTC instead of the Google/local time zone.
+//
+
+void BM_Time_ToDateTime_Absl(benchmark::State& state) {
+  const absl::TimeZone tz =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  absl::Time t = absl::FromUnixSeconds(1384569027);
+  absl::Time t2 = absl::FromUnixSeconds(1418962578);
+  while (state.KeepRunning()) {
+    std::swap(t, t2);
+    t += absl::Seconds(1);
+    benchmark::DoNotOptimize(t.In(tz));
+  }
+}
+BENCHMARK(BM_Time_ToDateTime_Absl);
+
+void BM_Time_ToDateTime_Libc(benchmark::State& state) {
+  // No timezone support, so just use localtime.
+  time_t t = 1384569027;
+  time_t t2 = 1418962578;
+  while (state.KeepRunning()) {
+    std::swap(t, t2);
+    t += 1;
+    struct tm tm;
+#if !defined(_WIN32)
+    benchmark::DoNotOptimize(localtime_r(&t, &tm));
+#else   // _WIN32
+    benchmark::DoNotOptimize(localtime_s(&tm, &t));
+#endif  // _WIN32
+  }
+}
+BENCHMARK(BM_Time_ToDateTime_Libc);
+
+void BM_Time_ToDateTimeUTC_Absl(benchmark::State& state) {
+  const absl::TimeZone tz = absl::UTCTimeZone();
+  absl::Time t = absl::FromUnixSeconds(1384569027);
+  while (state.KeepRunning()) {
+    t += absl::Seconds(1);
+    benchmark::DoNotOptimize(t.In(tz));
+  }
+}
+BENCHMARK(BM_Time_ToDateTimeUTC_Absl);
+
+void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) {
+  time_t t = 1384569027;
+  while (state.KeepRunning()) {
+    t += 1;
+    struct tm tm;
+#if !defined(_WIN32)
+    benchmark::DoNotOptimize(gmtime_r(&t, &tm));
+#else   // _WIN32
+    benchmark::DoNotOptimize(gmtime_s(&tm, &t));
+#endif  // _WIN32
+  }
+}
+BENCHMARK(BM_Time_ToDateTimeUTC_Libc);
+
+//
+// FromUnixMicros
+//
+
+void BM_Time_FromUnixMicros(benchmark::State& state) {
+  int i = 0;
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::FromUnixMicros(i));
+    ++i;
+  }
+}
+BENCHMARK(BM_Time_FromUnixMicros);
+
+void BM_Time_ToUnixNanos(benchmark::State& state) {
+  const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(ToUnixNanos(t));
+  }
+}
+BENCHMARK(BM_Time_ToUnixNanos);
+
+void BM_Time_ToUnixMicros(benchmark::State& state) {
+  const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(ToUnixMicros(t));
+  }
+}
+BENCHMARK(BM_Time_ToUnixMicros);
+
+void BM_Time_ToUnixMillis(benchmark::State& state) {
+  const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(ToUnixMillis(t));
+  }
+}
+BENCHMARK(BM_Time_ToUnixMillis);
+
+void BM_Time_ToUnixSeconds(benchmark::State& state) {
+  const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToUnixSeconds(t));
+  }
+}
+BENCHMARK(BM_Time_ToUnixSeconds);
+
+//
+// FromDateTime
+//
+// In each "FromDateTime" benchmark we switch between two YMDhms
+// values separated by at least one transition in order to defeat any
+// internal caching of previous results (e.g., see time_local_hint_).
+//
+// The "UTC" variants use UTC instead of the Google/local time zone.
+// The "Day0" variants require normalization of the day of month.
+//
+
+void BM_Time_FromDateTime_Absl(benchmark::State& state) {
+  const absl::TimeZone tz =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  int i = 0;
+  while (state.KeepRunning()) {
+    if ((i & 1) == 0) {
+      absl::FromDateTime(2014, 12, 18, 20, 16, 18, tz);
+    } else {
+      absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz);
+    }
+    ++i;
+  }
+}
+BENCHMARK(BM_Time_FromDateTime_Absl);
+
+void BM_Time_FromDateTime_Libc(benchmark::State& state) {
+  // No timezone support, so just use localtime.
+  int i = 0;
+  while (state.KeepRunning()) {
+    struct tm tm;
+    if ((i & 1) == 0) {
+      tm.tm_year = 2014 - 1900;
+      tm.tm_mon = 12 - 1;
+      tm.tm_mday = 18;
+      tm.tm_hour = 20;
+      tm.tm_min = 16;
+      tm.tm_sec = 18;
+    } else {
+      tm.tm_year = 2013 - 1900;
+      tm.tm_mon = 11 - 1;
+      tm.tm_mday = 15;
+      tm.tm_hour = 18;
+      tm.tm_min = 30;
+      tm.tm_sec = 27;
+    }
+    tm.tm_isdst = -1;
+    mktime(&tm);
+    ++i;
+  }
+}
+BENCHMARK(BM_Time_FromDateTime_Libc);
+
+void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) {
+  const absl::TimeZone tz = absl::UTCTimeZone();
+  while (state.KeepRunning()) {
+    FromDateTime(2014, 12, 18, 20, 16, 18, tz);
+  }
+}
+BENCHMARK(BM_Time_FromDateTimeUTC_Absl);
+
+void BM_Time_FromDateTimeDay0_Absl(benchmark::State& state) {
+  const absl::TimeZone tz =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  int i = 0;
+  while (state.KeepRunning()) {
+    if ((i & 1) == 0) {
+      absl::FromDateTime(2014, 12, 0, 20, 16, 18, tz);
+    } else {
+      absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz);
+    }
+    ++i;
+  }
+}
+BENCHMARK(BM_Time_FromDateTimeDay0_Absl);
+
+void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) {
+  // No timezone support, so just use localtime.
+  int i = 0;
+  while (state.KeepRunning()) {
+    struct tm tm;
+    if ((i & 1) == 0) {
+      tm.tm_year = 2014 - 1900;
+      tm.tm_mon = 12 - 1;
+      tm.tm_mday = 0;
+      tm.tm_hour = 20;
+      tm.tm_min = 16;
+      tm.tm_sec = 18;
+    } else {
+      tm.tm_year = 2013 - 1900;
+      tm.tm_mon = 11 - 1;
+      tm.tm_mday = 0;
+      tm.tm_hour = 18;
+      tm.tm_min = 30;
+      tm.tm_sec = 27;
+    }
+    tm.tm_isdst = -1;
+    mktime(&tm);
+    ++i;
+  }
+}
+BENCHMARK(BM_Time_FromDateTimeDay0_Libc);
+
+//
+// To/FromTimespec
+//
+
+void BM_Time_ToTimespec(benchmark::State& state) {
+  absl::Time now = absl::Now();
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::ToTimespec(now));
+  }
+}
+BENCHMARK(BM_Time_ToTimespec);
+
+void BM_Time_FromTimespec(benchmark::State& state) {
+  timespec ts = absl::ToTimespec(absl::Now());
+  while (state.KeepRunning()) {
+    if (++ts.tv_nsec == 1000 * 1000 * 1000) {
+      ++ts.tv_sec;
+      ts.tv_nsec = 0;
+    }
+    benchmark::DoNotOptimize(absl::TimeFromTimespec(ts));
+  }
+}
+BENCHMARK(BM_Time_FromTimespec);
+
+//
+// Comparison with InfiniteFuture/Past
+//
+
+void BM_Time_InfiniteFuture(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::InfiniteFuture());
+  }
+}
+BENCHMARK(BM_Time_InfiniteFuture);
+
+void BM_Time_InfinitePast(benchmark::State& state) {
+  while (state.KeepRunning()) {
+    benchmark::DoNotOptimize(absl::InfinitePast());
+  }
+}
+BENCHMARK(BM_Time_InfinitePast);
+
+}  // namespace
diff --git a/absl/time/time_norm_test.cc b/absl/time/time_norm_test.cc
new file mode 100644
index 0000000..4436242
--- /dev/null
+++ b/absl/time/time_norm_test.cc
@@ -0,0 +1,306 @@
+// Copyright 2017 The Abseil 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.
+
+// This file contains tests for FromDateTime() normalization, which is
+// time-zone independent so we just use UTC throughout.
+
+#include <cstdint>
+#include <limits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+
+namespace {
+
+TEST(TimeNormCase, SimpleOverflow) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  absl::TimeConversion tc =
+      absl::ConvertDateTime(2013, 11, 15, 16, 32, 59 + 1, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false);
+}
+
+TEST(TimeNormCase, SimpleUnderflow) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  absl::TimeConversion tc = ConvertDateTime(2013, 11, 15, 16, 32, 0 - 1, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false);
+
+  tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false);
+
+  tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false);
+
+  tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false);
+
+  tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false);
+}
+
+TEST(TimeNormCase, MultipleOverflow) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  absl::TimeConversion tc = ConvertDateTime(2013, 12, 31, 23, 59, 59 + 1, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false);
+}
+
+TEST(TimeNormCase, MultipleUnderflow) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  absl::TimeConversion tc = absl::ConvertDateTime(2014, 1, 1, 0, 0, 0 - 1, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false);
+}
+
+TEST(TimeNormCase, OverflowLimits) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  absl::TimeConversion tc;
+  absl::Time::Breakdown bd;
+
+  const int kintmax = std::numeric_limits<int>::max();
+  tc = absl::ConvertDateTime(0, kintmax, kintmax, kintmax, kintmax, kintmax,
+                             utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false);
+
+  const int kintmin = std::numeric_limits<int>::min();
+  tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin,
+                             utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false);
+
+  const int64_t max_year = std::numeric_limits<int64_t>::max();
+  tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  EXPECT_EQ(absl::InfiniteFuture(), tc.pre);
+
+  const int64_t min_year = std::numeric_limits<int64_t>::min();
+  tc = absl::ConvertDateTime(min_year, 1, 1, 0, 0, 0, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  EXPECT_EQ(absl::InfinitePast(), tc.pre);
+}
+
+TEST(TimeNormCase, ComplexOverflow) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  absl::TimeConversion tc =
+      ConvertDateTime(2013, 11, 15, 16, 32, 14 + 123456789, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false);
+}
+
+TEST(TimeNormCase, ComplexUnderflow) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  absl::TimeConversion tc =
+      absl::ConvertDateTime(1999, 3, 0, 0, 0, 0, utc);  // year 400
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false);
+}
+
+TEST(TimeNormCase, Mishmash) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  absl::TimeConversion tc =
+      absl::ConvertDateTime(2013, 11 - 123, 15 + 1234, 16 - 123456,
+                            32 + 1234567, 14 - 123456789, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false);
+
+  tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456,
+                             32 - 1234567, 14 + 123456789, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false);
+
+  // Here is a normalization case we got wrong for a while.  Because the
+  // day is converted to "1" within a 400-year (146097-day) period, we
+  // didn't need to roll the month and so we didn't mark it as normalized.
+  tc = absl::ConvertDateTime(2013, 11, -146097 + 1, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false);
+
+  // Even though the month overflow compensates for the day underflow,
+  // this should still be marked as normalized.
+  tc = absl::ConvertDateTime(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false);
+}
+
+TEST(TimeNormCase, LeapYears) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  absl::TimeConversion tc =
+      absl::ConvertDateTime(2013, 2, 28 + 1, 0, 0, 0, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  absl::Time::Breakdown bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false);
+
+  tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc);
+  EXPECT_FALSE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false);
+
+  tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc);
+  EXPECT_FALSE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false);
+
+  tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc);
+  EXPECT_TRUE(tc.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+  bd = tc.pre.In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false);
+}
+
+// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
+// and check that they normalize to the expected time.  146097 days span
+// the 400-year Gregorian cycle used during normalization.
+TEST(TimeNormCase, AllTheDays) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  absl::Time exp_time = absl::UnixEpoch();
+
+  for (int day = 1; day <= 146097; ++day) {
+    absl::TimeConversion tc = absl::ConvertDateTime(1970, 1, day, 0, 0, 0, utc);
+    EXPECT_EQ(day > 31, tc.normalized);
+    EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+    EXPECT_EQ(exp_time, tc.pre);
+    exp_time += absl::Hours(24);
+  }
+}
+
+}  // namespace
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
new file mode 100644
index 0000000..4f8f58a
--- /dev/null
+++ b/absl/time/time_test.cc
@@ -0,0 +1,1088 @@
+// Copyright 2017 The Abseil 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 "absl/time/time.h"
+
+#include <chrono>  // NOLINT(build/c++11)
+#include <cstring>
+#include <ctime>
+#include <iomanip>
+#include <limits>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/clock.h"
+#include "absl/time/internal/test_util.h"
+
+namespace {
+
+// A gMock matcher to match timespec values. Use this matcher like:
+// timespec ts1, ts2;
+// EXPECT_THAT(ts1, TimespecMatcher(ts2));
+MATCHER_P(TimespecMatcher, ts, "") {
+  if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec)
+    return true;
+  *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} ";
+  *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}";
+  return false;
+}
+
+// A gMock matcher to match timeval values. Use this matcher like:
+// timeval tv1, tv2;
+// EXPECT_THAT(tv1, TimevalMatcher(tv2));
+MATCHER_P(TimevalMatcher, tv, "") {
+  if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec)
+    return true;
+  *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} ";
+  *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}";
+  return false;
+}
+
+TEST(Time, ConstExpr) {
+  constexpr absl::Time t0 = absl::UnixEpoch();
+  static_assert(t0 == absl::Time(), "UnixEpoch");
+  constexpr absl::Time t1 = absl::InfiniteFuture();
+  static_assert(t1 != absl::Time(), "InfiniteFuture");
+  constexpr absl::Time t2 = absl::InfinitePast();
+  static_assert(t2 != absl::Time(), "InfinitePast");
+  constexpr absl::Time t3 = absl::FromUnixNanos(0);
+  static_assert(t3 == absl::Time(), "FromUnixNanos");
+  constexpr absl::Time t4 = absl::FromUnixMicros(0);
+  static_assert(t4 == absl::Time(), "FromUnixMicros");
+  constexpr absl::Time t5 = absl::FromUnixMillis(0);
+  static_assert(t5 == absl::Time(), "FromUnixMillis");
+  constexpr absl::Time t6 = absl::FromUnixSeconds(0);
+  static_assert(t6 == absl::Time(), "FromUnixSeconds");
+  constexpr absl::Time t7 = absl::FromTimeT(0);
+  static_assert(t7 == absl::Time(), "FromTimeT");
+}
+
+TEST(Time, ValueSemantics) {
+  absl::Time a;      // Default construction
+  absl::Time b = a;  // Copy construction
+  EXPECT_EQ(a, b);
+  absl::Time c(a);  // Copy construction (again)
+  EXPECT_EQ(a, b);
+  EXPECT_EQ(a, c);
+  EXPECT_EQ(b, c);
+  b = c;       // Assignment
+  EXPECT_EQ(a, b);
+  EXPECT_EQ(a, c);
+  EXPECT_EQ(b, c);
+}
+
+TEST(Time, UnixEpoch) {
+  absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone());
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false);
+  EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+  EXPECT_EQ(4, bd.weekday);  // Thursday
+}
+
+TEST(Time, Breakdown) {
+  absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/New_York");
+  absl::Time t = absl::UnixEpoch();
+
+  // The Unix epoch as seen in NYC.
+  absl::Time::Breakdown bd = t.In(tz);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false);
+  EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+  EXPECT_EQ(3, bd.weekday);  // Wednesday
+
+  // Just before the epoch.
+  t -= absl::Nanoseconds(1);
+  bd = t.In(tz);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false);
+  EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond);
+  EXPECT_EQ(3, bd.weekday);  // Wednesday
+
+  // Some time later.
+  t += absl::Hours(24) * 2735;
+  t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) +
+       absl::Nanoseconds(9);
+  bd = t.In(tz);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true);
+  EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1));
+  EXPECT_EQ(2, bd.weekday);  // Tuesday
+}
+
+TEST(Time, AdditiveOperators) {
+  const absl::Duration d = absl::Nanoseconds(1);
+  const absl::Time t0;
+  const absl::Time t1 = t0 + d;
+
+  EXPECT_EQ(d, t1 - t0);
+  EXPECT_EQ(-d, t0 - t1);
+  EXPECT_EQ(t0, t1 - d);
+
+  absl::Time t(t0);
+  EXPECT_EQ(t0, t);
+  t += d;
+  EXPECT_EQ(t0 + d, t);
+  EXPECT_EQ(d, t - t0);
+  t -= d;
+  EXPECT_EQ(t0, t);
+
+  // Tests overflow between subseconds and seconds.
+  t = absl::UnixEpoch();
+  t += absl::Milliseconds(500);
+  EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t);
+  t += absl::Milliseconds(600);
+  EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(1100), t);
+  t -= absl::Milliseconds(600);
+  EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t);
+  t -= absl::Milliseconds(500);
+  EXPECT_EQ(absl::UnixEpoch(), t);
+}
+
+TEST(Time, RelationalOperators) {
+  constexpr absl::Time t1 = absl::FromUnixNanos(0);
+  constexpr absl::Time t2 = absl::FromUnixNanos(1);
+  constexpr absl::Time t3 = absl::FromUnixNanos(2);
+
+  static_assert(absl::Time() == t1, "");
+  static_assert(t1 == t1, "");
+  static_assert(t2 == t2, "");
+  static_assert(t3 == t3, "");
+
+  static_assert(t1 < t2, "");
+  static_assert(t2 < t3, "");
+  static_assert(t1 < t3, "");
+
+  static_assert(t1 <= t1, "");
+  static_assert(t1 <= t2, "");
+  static_assert(t2 <= t2, "");
+  static_assert(t2 <= t3, "");
+  static_assert(t3 <= t3, "");
+  static_assert(t1 <= t3, "");
+
+  static_assert(t2 > t1, "");
+  static_assert(t3 > t2, "");
+  static_assert(t3 > t1, "");
+
+  static_assert(t2 >= t2, "");
+  static_assert(t2 >= t1, "");
+  static_assert(t3 >= t3, "");
+  static_assert(t3 >= t2, "");
+  static_assert(t1 >= t1, "");
+  static_assert(t3 >= t1, "");
+}
+
+TEST(Time, Infinity) {
+  constexpr absl::Time ifuture = absl::InfiniteFuture();
+  constexpr absl::Time ipast = absl::InfinitePast();
+
+  static_assert(ifuture == ifuture, "");
+  static_assert(ipast == ipast, "");
+  static_assert(ipast < ifuture, "");
+  static_assert(ifuture > ipast, "");
+
+  // Arithmetic saturates
+  EXPECT_EQ(ifuture, ifuture + absl::Seconds(1));
+  EXPECT_EQ(ifuture, ifuture - absl::Seconds(1));
+  EXPECT_EQ(ipast, ipast + absl::Seconds(1));
+  EXPECT_EQ(ipast, ipast - absl::Seconds(1));
+
+  EXPECT_EQ(absl::InfiniteDuration(), ifuture - ifuture);
+  EXPECT_EQ(absl::InfiniteDuration(), ifuture - ipast);
+  EXPECT_EQ(-absl::InfiniteDuration(), ipast - ifuture);
+  EXPECT_EQ(-absl::InfiniteDuration(), ipast - ipast);
+
+  constexpr absl::Time t = absl::UnixEpoch();  // Any finite time.
+  static_assert(t < ifuture, "");
+  static_assert(t > ipast, "");
+}
+
+TEST(Time, FloorConversion) {
+#define TEST_FLOOR_CONVERSION(TO, FROM) \
+  EXPECT_EQ(1, TO(FROM(1001)));         \
+  EXPECT_EQ(1, TO(FROM(1000)));         \
+  EXPECT_EQ(0, TO(FROM(999)));          \
+  EXPECT_EQ(0, TO(FROM(1)));            \
+  EXPECT_EQ(0, TO(FROM(0)));            \
+  EXPECT_EQ(-1, TO(FROM(-1)));          \
+  EXPECT_EQ(-1, TO(FROM(-999)));        \
+  EXPECT_EQ(-1, TO(FROM(-1000)));       \
+  EXPECT_EQ(-2, TO(FROM(-1001)));
+
+  TEST_FLOOR_CONVERSION(absl::ToUnixMicros, absl::FromUnixNanos);
+  TEST_FLOOR_CONVERSION(absl::ToUnixMillis, absl::FromUnixMicros);
+  TEST_FLOOR_CONVERSION(absl::ToUnixSeconds, absl::FromUnixMillis);
+  TEST_FLOOR_CONVERSION(absl::ToTimeT, absl::FromUnixMillis);
+
+#undef TEST_FLOOR_CONVERSION
+
+  // Tests ToUnixNanos.
+  EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(3) / 2));
+  EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1)));
+  EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1) / 2));
+  EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(0)));
+  EXPECT_EQ(-1,
+            absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1) / 2));
+  EXPECT_EQ(-1, absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1)));
+  EXPECT_EQ(-2,
+            absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(3) / 2));
+
+  // Tests ToUniversal, which uses a different epoch than the tests above.
+  EXPECT_EQ(1,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(101)));
+  EXPECT_EQ(1,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(100)));
+  EXPECT_EQ(0,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(99)));
+  EXPECT_EQ(0,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(1)));
+  EXPECT_EQ(0,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(0)));
+  EXPECT_EQ(-1,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-1)));
+  EXPECT_EQ(-1,
+            absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-99)));
+  EXPECT_EQ(
+      -1, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-100)));
+  EXPECT_EQ(
+      -2, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-101)));
+
+  // Tests ToTimespec()/TimeFromTimespec()
+  const struct {
+    absl::Time t;
+    timespec ts;
+  } to_ts[] = {
+      {absl::FromUnixSeconds(1) + absl::Nanoseconds(1), {1, 1}},
+      {absl::FromUnixSeconds(1) + absl::Nanoseconds(1) / 2, {1, 0}},
+      {absl::FromUnixSeconds(1) + absl::Nanoseconds(0), {1, 0}},
+      {absl::FromUnixSeconds(0) + absl::Nanoseconds(0), {0, 0}},
+      {absl::FromUnixSeconds(0) - absl::Nanoseconds(1) / 2, {-1, 999999999}},
+      {absl::FromUnixSeconds(0) - absl::Nanoseconds(1), {-1, 999999999}},
+      {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1), {-1, 1}},
+      {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1) / 2, {-1, 0}},
+      {absl::FromUnixSeconds(-1) + absl::Nanoseconds(0), {-1, 0}},
+      {absl::FromUnixSeconds(-1) - absl::Nanoseconds(1) / 2, {-2, 999999999}},
+  };
+  for (const auto& test : to_ts) {
+    EXPECT_THAT(absl::ToTimespec(test.t), TimespecMatcher(test.ts));
+  }
+  const struct {
+    timespec ts;
+    absl::Time t;
+  } from_ts[] = {
+      {{1, 1}, absl::FromUnixSeconds(1) + absl::Nanoseconds(1)},
+      {{1, 0}, absl::FromUnixSeconds(1) + absl::Nanoseconds(0)},
+      {{0, 0}, absl::FromUnixSeconds(0) + absl::Nanoseconds(0)},
+      {{0, -1}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)},
+      {{-1, 999999999}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)},
+      {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(1)},
+      {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(0)},
+      {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)},
+      {{-2, 999999999}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)},
+  };
+  for (const auto& test : from_ts) {
+    EXPECT_EQ(test.t, absl::TimeFromTimespec(test.ts));
+  }
+
+  // Tests ToTimeval()/TimeFromTimeval() (same as timespec above)
+  const struct {
+    absl::Time t;
+    timeval tv;
+  } to_tv[] = {
+      {absl::FromUnixSeconds(1) + absl::Microseconds(1), {1, 1}},
+      {absl::FromUnixSeconds(1) + absl::Microseconds(1) / 2, {1, 0}},
+      {absl::FromUnixSeconds(1) + absl::Microseconds(0), {1, 0}},
+      {absl::FromUnixSeconds(0) + absl::Microseconds(0), {0, 0}},
+      {absl::FromUnixSeconds(0) - absl::Microseconds(1) / 2, {-1, 999999}},
+      {absl::FromUnixSeconds(0) - absl::Microseconds(1), {-1, 999999}},
+      {absl::FromUnixSeconds(-1) + absl::Microseconds(1), {-1, 1}},
+      {absl::FromUnixSeconds(-1) + absl::Microseconds(1) / 2, {-1, 0}},
+      {absl::FromUnixSeconds(-1) + absl::Microseconds(0), {-1, 0}},
+      {absl::FromUnixSeconds(-1) - absl::Microseconds(1) / 2, {-2, 999999}},
+  };
+  for (const auto& test : to_tv) {
+    EXPECT_THAT(ToTimeval(test.t), TimevalMatcher(test.tv));
+  }
+  const struct {
+    timeval tv;
+    absl::Time t;
+  } from_tv[] = {
+      {{1, 1}, absl::FromUnixSeconds(1) + absl::Microseconds(1)},
+      {{1, 0}, absl::FromUnixSeconds(1) + absl::Microseconds(0)},
+      {{0, 0}, absl::FromUnixSeconds(0) + absl::Microseconds(0)},
+      {{0, -1}, absl::FromUnixSeconds(0) - absl::Microseconds(1)},
+      {{-1, 999999}, absl::FromUnixSeconds(0) - absl::Microseconds(1)},
+      {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Microseconds(1)},
+      {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Microseconds(0)},
+      {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)},
+      {{-2, 999999}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)},
+  };
+  for (const auto& test : from_tv) {
+    EXPECT_EQ(test.t, absl::TimeFromTimeval(test.tv));
+  }
+
+  // Tests flooring near negative infinity.
+  const int64_t min_plus_1 = std::numeric_limits<int64_t>::min() + 1;
+  EXPECT_EQ(min_plus_1, absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1)));
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+            absl::ToUnixSeconds(
+                absl::FromUnixSeconds(min_plus_1) - absl::Nanoseconds(1) / 2));
+
+  // Tests flooring near positive infinity.
+  EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+            absl::ToUnixSeconds(absl::FromUnixSeconds(
+                std::numeric_limits<int64_t>::max()) + absl::Nanoseconds(1) / 2));
+  EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+            absl::ToUnixSeconds(
+                absl::FromUnixSeconds(std::numeric_limits<int64_t>::max())));
+  EXPECT_EQ(std::numeric_limits<int64_t>::max() - 1,
+            absl::ToUnixSeconds(absl::FromUnixSeconds(
+                std::numeric_limits<int64_t>::max()) - absl::Nanoseconds(1) / 2));
+}
+
+TEST(Time, RoundtripConversion) {
+#define TEST_CONVERSION_ROUND_TRIP(SOURCE, FROM, TO, MATCHER) \
+  EXPECT_THAT(TO(FROM(SOURCE)), MATCHER(SOURCE))
+
+  // FromUnixNanos() and ToUnixNanos()
+  int64_t now_ns = absl::GetCurrentTimeNanos();
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixNanos, absl::ToUnixNanos,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixNanos, absl::ToUnixNanos,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixNanos, absl::ToUnixNanos,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(now_ns, absl::FromUnixNanos, absl::ToUnixNanos,
+                             testing::Eq)
+      << now_ns;
+
+  // FromUnixMicros() and ToUnixMicros()
+  int64_t now_us = absl::GetCurrentTimeNanos() / 1000;
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMicros, absl::ToUnixMicros,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMicros, absl::ToUnixMicros,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMicros, absl::ToUnixMicros,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(now_us, absl::FromUnixMicros, absl::ToUnixMicros,
+                             testing::Eq)
+      << now_us;
+
+  // FromUnixMillis() and ToUnixMillis()
+  int64_t now_ms = absl::GetCurrentTimeNanos() / 1000000;
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMillis, absl::ToUnixMillis,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMillis, absl::ToUnixMillis,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMillis, absl::ToUnixMillis,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(now_ms, absl::FromUnixMillis, absl::ToUnixMillis,
+                             testing::Eq)
+      << now_ms;
+
+  // FromUnixSeconds() and ToUnixSeconds()
+  int64_t now_s = std::time(nullptr);
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixSeconds, absl::ToUnixSeconds,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixSeconds, absl::ToUnixSeconds,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixSeconds, absl::ToUnixSeconds,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(now_s, absl::FromUnixSeconds, absl::ToUnixSeconds,
+                             testing::Eq)
+      << now_s;
+
+  // FromTimeT() and ToTimeT()
+  time_t now_time_t = std::time(nullptr);
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromTimeT, absl::ToTimeT, testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromTimeT, absl::ToTimeT, testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromTimeT, absl::ToTimeT, testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(now_time_t, absl::FromTimeT, absl::ToTimeT,
+                             testing::Eq)
+      << now_time_t;
+
+  // TimeFromTimeval() and ToTimeval()
+  timeval tv;
+  tv.tv_sec = -1;
+  tv.tv_usec = 0;
+  TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+                             TimevalMatcher);
+  tv.tv_sec = -1;
+  tv.tv_usec = 999999;
+  TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+                             TimevalMatcher);
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+  TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+                             TimevalMatcher);
+  tv.tv_sec = 0;
+  tv.tv_usec = 1;
+  TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+                             TimevalMatcher);
+  tv.tv_sec = 1;
+  tv.tv_usec = 0;
+  TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+                             TimevalMatcher);
+
+  // TimeFromTimespec() and ToTimespec()
+  timespec ts;
+  ts.tv_sec = -1;
+  ts.tv_nsec = 0;
+  TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+                             TimespecMatcher);
+  ts.tv_sec = -1;
+  ts.tv_nsec = 999999999;
+  TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+                             TimespecMatcher);
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+  TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+                             TimespecMatcher);
+  ts.tv_sec = 0;
+  ts.tv_nsec = 1;
+  TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+                             TimespecMatcher);
+  ts.tv_sec = 1;
+  ts.tv_nsec = 0;
+  TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+                             TimespecMatcher);
+
+  // FromUDate() and ToUDate()
+  double now_ud = absl::GetCurrentTimeNanos() / 1000000;
+  TEST_CONVERSION_ROUND_TRIP(-1.5, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(-0.5, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(0.5, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(1.5, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq);
+  TEST_CONVERSION_ROUND_TRIP(now_ud, absl::FromUDate, absl::ToUDate,
+                             testing::DoubleEq)
+      << std::fixed << std::setprecision(17) << now_ud;
+
+  // FromUniversal() and ToUniversal()
+  int64_t now_uni = ((719162LL * (24 * 60 * 60)) * (1000 * 1000 * 10)) +
+                    (absl::GetCurrentTimeNanos() / 100);
+  TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUniversal, absl::ToUniversal,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(0, absl::FromUniversal, absl::ToUniversal,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(1, absl::FromUniversal, absl::ToUniversal,
+                             testing::Eq);
+  TEST_CONVERSION_ROUND_TRIP(now_uni, absl::FromUniversal, absl::ToUniversal,
+                             testing::Eq)
+      << now_uni;
+
+#undef TEST_CONVERSION_ROUND_TRIP
+}
+
+template <typename Duration>
+std::chrono::system_clock::time_point MakeChronoUnixTime(const Duration& d) {
+  return std::chrono::system_clock::from_time_t(0) + d;
+}
+
+TEST(Time, FromChrono) {
+  EXPECT_EQ(absl::FromTimeT(-1),
+            absl::FromChrono(std::chrono::system_clock::from_time_t(-1)));
+  EXPECT_EQ(absl::FromTimeT(0),
+            absl::FromChrono(std::chrono::system_clock::from_time_t(0)));
+  EXPECT_EQ(absl::FromTimeT(1),
+            absl::FromChrono(std::chrono::system_clock::from_time_t(1)));
+
+  EXPECT_EQ(
+      absl::FromUnixMillis(-1),
+      absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(-1))));
+  EXPECT_EQ(absl::FromUnixMillis(0),
+            absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(0))));
+  EXPECT_EQ(absl::FromUnixMillis(1),
+            absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(1))));
+
+  // Chrono doesn't define exactly its range and precision (neither does
+  // absl::Time), so let's simply test +/- ~100 years to make sure things work.
+  const auto century_sec = 60 * 60 * 24 * 365 * int64_t{100};
+  const auto century = std::chrono::seconds(century_sec);
+  const auto chrono_future = MakeChronoUnixTime(century);
+  const auto chrono_past = MakeChronoUnixTime(-century);
+  EXPECT_EQ(absl::FromUnixSeconds(century_sec),
+            absl::FromChrono(chrono_future));
+  EXPECT_EQ(absl::FromUnixSeconds(-century_sec), absl::FromChrono(chrono_past));
+
+  // Roundtrip them both back to chrono.
+  EXPECT_EQ(chrono_future,
+            absl::ToChronoTime(absl::FromUnixSeconds(century_sec)));
+  EXPECT_EQ(chrono_past,
+            absl::ToChronoTime(absl::FromUnixSeconds(-century_sec)));
+}
+
+TEST(Time, ToChronoTime) {
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(-1),
+            absl::ToChronoTime(absl::FromTimeT(-1)));
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(0),
+            absl::ToChronoTime(absl::FromTimeT(0)));
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(1),
+            absl::ToChronoTime(absl::FromTimeT(1)));
+
+  EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(-1)),
+            absl::ToChronoTime(absl::FromUnixMillis(-1)));
+  EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(0)),
+            absl::ToChronoTime(absl::FromUnixMillis(0)));
+  EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(1)),
+            absl::ToChronoTime(absl::FromUnixMillis(1)));
+
+  // Time before the Unix epoch should floor, not trunc.
+  const auto tick = absl::Nanoseconds(1) / 4;
+  EXPECT_EQ(std::chrono::system_clock::from_time_t(0) -
+                std::chrono::system_clock::duration(1),
+            absl::ToChronoTime(absl::UnixEpoch() - tick));
+}
+
+TEST(Time, ConvertDateTime) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  const absl::TimeZone goog =
+      absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  const absl::TimeZone nyc =
+      absl::time_internal::LoadTimeZone("America/New_York");
+  const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)";
+
+  // A simple case of normalization.
+  absl::TimeConversion oct32 = ConvertDateTime(2013, 10, 32, 8, 30, 0, goog);
+  EXPECT_TRUE(oct32.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, oct32.kind);
+  absl::TimeConversion nov01 = ConvertDateTime(2013, 11, 1, 8, 30, 0, goog);
+  EXPECT_FALSE(nov01.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, nov01.kind);
+  EXPECT_EQ(oct32.pre, nov01.pre);
+  EXPECT_EQ("Fri,  1 Nov 2013 08:30:00 -0700 (PDT)",
+            absl::FormatTime(fmt, nov01.pre, goog));
+
+  // A Spring DST transition, when there is a gap in civil time
+  // and we prefer the later of the possible interpretations of a
+  // non-existent time.
+  absl::TimeConversion mar13 = ConvertDateTime(2011, 3, 13, 2, 15, 0, nyc);
+  EXPECT_FALSE(mar13.normalized);
+  EXPECT_EQ(absl::TimeConversion::SKIPPED, mar13.kind);
+  EXPECT_EQ("Sun, 13 Mar 2011 03:15:00 -0400 (EDT)",
+            absl::FormatTime(fmt, mar13.pre, nyc));
+  EXPECT_EQ("Sun, 13 Mar 2011 03:00:00 -0400 (EDT)",
+            absl::FormatTime(fmt, mar13.trans, nyc));
+  EXPECT_EQ("Sun, 13 Mar 2011 01:15:00 -0500 (EST)",
+            absl::FormatTime(fmt, mar13.post, nyc));
+  EXPECT_EQ(mar13.pre, absl::FromDateTime(2011, 3, 13, 2, 15, 0, nyc));
+
+  // A Fall DST transition, when civil times are repeated and
+  // we prefer the earlier of the possible interpretations of an
+  // ambiguous time.
+  absl::TimeConversion nov06 = ConvertDateTime(2011, 11, 6, 1, 15, 0, nyc);
+  EXPECT_FALSE(nov06.normalized);
+  EXPECT_EQ(absl::TimeConversion::REPEATED, nov06.kind);
+  EXPECT_EQ("Sun,  6 Nov 2011 01:15:00 -0400 (EDT)",
+            absl::FormatTime(fmt, nov06.pre, nyc));
+  EXPECT_EQ("Sun,  6 Nov 2011 01:00:00 -0500 (EST)",
+            absl::FormatTime(fmt, nov06.trans, nyc));
+  EXPECT_EQ("Sun,  6 Nov 2011 01:15:00 -0500 (EST)",
+            absl::FormatTime(fmt, nov06.post, nyc));
+  EXPECT_EQ(nov06.pre, absl::FromDateTime(2011, 11, 6, 1, 15, 0, nyc));
+
+  // Check that (time_t) -1 is handled correctly.
+  absl::TimeConversion minus1 = ConvertDateTime(1969, 12, 31, 18, 59, 59, nyc);
+  EXPECT_FALSE(minus1.normalized);
+  EXPECT_EQ(absl::TimeConversion::UNIQUE, minus1.kind);
+  EXPECT_EQ(-1, absl::ToTimeT(minus1.pre));
+  EXPECT_EQ("Wed, 31 Dec 1969 18:59:59 -0500 (EST)",
+            absl::FormatTime(fmt, minus1.pre, nyc));
+  EXPECT_EQ("Wed, 31 Dec 1969 23:59:59 +0000 (UTC)",
+            absl::FormatTime(fmt, minus1.pre, utc));
+}
+
+// FromDateTime(year, mon, day, hour, min, sec, UTCTimeZone()) has
+// a specialized fastpath implementation which we exercise here.
+TEST(Time, FromDateTimeUTC) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)";
+  const int kMax = std::numeric_limits<int>::max();
+  const int kMin = std::numeric_limits<int>::min();
+  absl::Time t;
+
+  // 292091940881 is the last positive year to use the fastpath.
+  t = absl::FromDateTime(292091940881, kMax, kMax, kMax, kMax, kMax, utc);
+  EXPECT_EQ("Fri, 25 Nov 292277026596 12:21:07 +0000 (UTC)",
+            absl::FormatTime(fmt, t, utc));
+  t = absl::FromDateTime(292091940882, kMax, kMax, kMax, kMax, kMax, utc);
+  EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc));  // no overflow
+  t = absl::FromDateTime(
+      std::numeric_limits<int64_t>::max(), kMax, kMax, kMax, kMax, kMax, utc);
+  EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc));  // no overflow
+
+  // -292091936940 is the last negative year to use the fastpath.
+  t = absl::FromDateTime(-292091936940, kMin, kMin, kMin, kMin, kMin, utc);
+  EXPECT_EQ("Fri,  1 Nov -292277022657 10:37:52 +0000 (UTC)",
+            absl::FormatTime(fmt, t, utc));
+  t = absl::FromDateTime(-292091936941, kMin, kMin, kMin, kMin, kMin, utc);
+  EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc));  // no underflow
+  t = absl::FromDateTime(
+      std::numeric_limits<int64_t>::min(), kMin, kMin, kMin, kMin, kMin, utc);
+  EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc));  // no overflow
+
+  // Check that we're counting leap years correctly.
+  t = absl::FromDateTime(1900, 2, 28, 23, 59, 59, utc);
+  EXPECT_EQ("Wed, 28 Feb 1900 23:59:59 +0000 (UTC)",
+            absl::FormatTime(fmt, t, utc));
+  t = absl::FromDateTime(1900, 3, 1, 0, 0, 0, utc);
+  EXPECT_EQ("Thu,  1 Mar 1900 00:00:00 +0000 (UTC)",
+            absl::FormatTime(fmt, t, utc));
+  t = absl::FromDateTime(2000, 2, 29, 23, 59, 59, utc);
+  EXPECT_EQ("Tue, 29 Feb 2000 23:59:59 +0000 (UTC)",
+            absl::FormatTime(fmt, t, utc));
+  t = absl::FromDateTime(2000, 3, 1, 0, 0, 0, utc);
+  EXPECT_EQ("Wed,  1 Mar 2000 00:00:00 +0000 (UTC)",
+            absl::FormatTime(fmt, t, utc));
+
+  // Check normalization.
+  const std::string ymdhms = "%Y-%m-%d %H:%M:%S";
+  t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc);
+  EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc);
+  EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc);
+  EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc);
+  EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc);
+  EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc);
+  EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc);
+  EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc);
+  EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc);
+  EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc);
+  EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc);
+  EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+  t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc);
+  EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc));
+}
+
+TEST(Time, ToTM) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+
+  // Compares the results of ToTM() to gmtime_r() for lots of times over the
+  // course of a few days.
+  const absl::Time start = absl::FromDateTime(2014, 1, 2, 3, 4, 5, utc);
+  const absl::Time end = absl::FromDateTime(2014, 1, 5, 3, 4, 5, utc);
+  for (absl::Time t = start; t < end; t += absl::Seconds(30)) {
+    const struct tm tm_bt = ToTM(t, utc);
+    const time_t tt = absl::ToTimeT(t);
+    struct tm tm_lc;
+#ifdef _WIN32
+    gmtime_s(&tm_lc, &tt);
+#else
+    gmtime_r(&tt, &tm_lc);
+#endif
+    EXPECT_EQ(tm_lc.tm_year, tm_bt.tm_year);
+    EXPECT_EQ(tm_lc.tm_mon, tm_bt.tm_mon);
+    EXPECT_EQ(tm_lc.tm_mday, tm_bt.tm_mday);
+    EXPECT_EQ(tm_lc.tm_hour, tm_bt.tm_hour);
+    EXPECT_EQ(tm_lc.tm_min, tm_bt.tm_min);
+    EXPECT_EQ(tm_lc.tm_sec, tm_bt.tm_sec);
+    EXPECT_EQ(tm_lc.tm_wday, tm_bt.tm_wday);
+    EXPECT_EQ(tm_lc.tm_yday, tm_bt.tm_yday);
+    EXPECT_EQ(tm_lc.tm_isdst, tm_bt.tm_isdst);
+
+    ASSERT_FALSE(HasFailure());
+  }
+
+  // Checks that the tm_isdst field is correct when in standard time.
+  const absl::TimeZone nyc =
+      absl::time_internal::LoadTimeZone("America/New_York");
+  absl::Time t = absl::FromDateTime(2014, 3, 1, 0, 0, 0, nyc);
+  struct tm tm = ToTM(t, nyc);
+  EXPECT_FALSE(tm.tm_isdst);
+
+  // Checks that the tm_isdst field is correct when in daylight time.
+  t = absl::FromDateTime(2014, 4, 1, 0, 0, 0, nyc);
+  tm = ToTM(t, nyc);
+  EXPECT_TRUE(tm.tm_isdst);
+
+  // Checks overflow.
+  tm = ToTM(absl::InfiniteFuture(), nyc);
+  EXPECT_EQ(std::numeric_limits<int>::max() - 1900, tm.tm_year);
+  EXPECT_EQ(11, tm.tm_mon);
+  EXPECT_EQ(31, tm.tm_mday);
+  EXPECT_EQ(23, tm.tm_hour);
+  EXPECT_EQ(59, tm.tm_min);
+  EXPECT_EQ(59, tm.tm_sec);
+  EXPECT_EQ(4, tm.tm_wday);
+  EXPECT_EQ(364, tm.tm_yday);
+  EXPECT_FALSE(tm.tm_isdst);
+
+  // Checks underflow.
+  tm = ToTM(absl::InfinitePast(), nyc);
+  EXPECT_EQ(std::numeric_limits<int>::min(), tm.tm_year);
+  EXPECT_EQ(0, tm.tm_mon);
+  EXPECT_EQ(1, tm.tm_mday);
+  EXPECT_EQ(0, tm.tm_hour);
+  EXPECT_EQ(0, tm.tm_min);
+  EXPECT_EQ(0, tm.tm_sec);
+  EXPECT_EQ(0, tm.tm_wday);
+  EXPECT_EQ(0, tm.tm_yday);
+  EXPECT_FALSE(tm.tm_isdst);
+}
+
+TEST(Time, FromTM) {
+  const absl::TimeZone nyc =
+      absl::time_internal::LoadTimeZone("America/New_York");
+
+  // Verifies that tm_isdst doesn't affect anything when the time is unique.
+  struct tm tm;
+  std::memset(&tm, 0, sizeof(tm));
+  tm.tm_year = 2014 - 1900;
+  tm.tm_mon = 6 - 1;
+  tm.tm_mday = 28;
+  tm.tm_hour = 1;
+  tm.tm_min = 2;
+  tm.tm_sec = 3;
+  tm.tm_isdst = -1;
+  absl::Time t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc));  // DST
+  tm.tm_isdst = 0;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc));  // DST
+  tm.tm_isdst = 1;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc));  // DST
+
+  // Adjusts tm to refer to an ambiguous time.
+  tm.tm_year = 2014 - 1900;
+  tm.tm_mon = 11 - 1;
+  tm.tm_mday = 2;
+  tm.tm_hour = 1;
+  tm.tm_min = 30;
+  tm.tm_sec = 42;
+  tm.tm_isdst = -1;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc));  // DST
+  tm.tm_isdst = 0;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-11-02T01:30:42-05:00", absl::FormatTime(t, nyc));  // STD
+  tm.tm_isdst = 1;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc));  // DST
+
+  // Adjusts tm to refer to a skipped time.
+  tm.tm_year = 2014 - 1900;
+  tm.tm_mon = 3 - 1;
+  tm.tm_mday = 9;
+  tm.tm_hour = 2;
+  tm.tm_min = 30;
+  tm.tm_sec = 42;
+  tm.tm_isdst = -1;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc));  // DST
+  tm.tm_isdst = 0;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-03-09T01:30:42-05:00", absl::FormatTime(t, nyc));  // STD
+  tm.tm_isdst = 1;
+  t = FromTM(tm, nyc);
+  EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc));  // DST
+}
+
+TEST(Time, TMRoundTrip) {
+  const absl::TimeZone nyc =
+      absl::time_internal::LoadTimeZone("America/New_York");
+
+  // Test round-tripping across a skipped transition
+  absl::Time start = absl::FromDateTime(2014, 3, 9, 0, 0, 0, nyc);
+  absl::Time end = absl::FromDateTime(2014, 3, 9, 4, 0, 0, nyc);
+  for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
+    struct tm tm = ToTM(t, nyc);
+    absl::Time rt = FromTM(tm, nyc);
+    EXPECT_EQ(rt, t);
+  }
+
+  // Test round-tripping across an ambiguous transition
+  start = absl::FromDateTime(2014, 11, 2, 0, 0, 0, nyc);
+  end = absl::FromDateTime(2014, 11, 2, 4, 0, 0, nyc);
+  for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
+    struct tm tm = ToTM(t, nyc);
+    absl::Time rt = FromTM(tm, nyc);
+    EXPECT_EQ(rt, t);
+  }
+
+  // Test round-tripping of unique instants crossing a day boundary
+  start = absl::FromDateTime(2014, 6, 27, 22, 0, 0, nyc);
+  end = absl::FromDateTime(2014, 6, 28, 4, 0, 0, nyc);
+  for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
+    struct tm tm = ToTM(t, nyc);
+    absl::Time rt = FromTM(tm, nyc);
+    EXPECT_EQ(rt, t);
+  }
+}
+
+TEST(Time, Range) {
+  // The API's documented range is +/- 100 billion years.
+  const absl::Duration range = absl::Hours(24) * 365.2425 * 100000000000;
+
+  // Arithmetic and comparison still works at +/-range around base values.
+  absl::Time bases[2] = {absl::UnixEpoch(), absl::Now()};
+  for (const auto base : bases) {
+    absl::Time bottom = base - range;
+    EXPECT_GT(bottom, bottom - absl::Nanoseconds(1));
+    EXPECT_LT(bottom, bottom + absl::Nanoseconds(1));
+    absl::Time top = base + range;
+    EXPECT_GT(top, top - absl::Nanoseconds(1));
+    EXPECT_LT(top, top + absl::Nanoseconds(1));
+    absl::Duration full_range = 2 * range;
+    EXPECT_EQ(full_range, top - bottom);
+    EXPECT_EQ(-full_range, bottom - top);
+  }
+}
+
+TEST(Time, Limits) {
+  // It is an implementation detail that Time().rep_ == ZeroDuration(),
+  // and that the resolution of a Duration is 1/4 of a nanosecond.
+  const absl::Time zero;
+  const absl::Time max =
+      zero + absl::Seconds(std::numeric_limits<int64_t>::max()) +
+      absl::Nanoseconds(999999999) + absl::Nanoseconds(3) / 4;
+  const absl::Time min =
+      zero + absl::Seconds(std::numeric_limits<int64_t>::min());
+
+  // Some simple max/min bounds checks.
+  EXPECT_LT(max, absl::InfiniteFuture());
+  EXPECT_GT(min, absl::InfinitePast());
+  EXPECT_LT(zero, max);
+  EXPECT_GT(zero, min);
+  EXPECT_GE(absl::UnixEpoch(), min);
+  EXPECT_LT(absl::UnixEpoch(), max);
+
+  // Check sign of Time differences.
+  EXPECT_LT(absl::ZeroDuration(), max - zero);
+  EXPECT_LT(absl::ZeroDuration(),
+            zero - absl::Nanoseconds(1) / 4 - min);  // avoid zero - min
+
+  // Arithmetic works at max - 0.25ns and min + 0.25ns.
+  EXPECT_GT(max, max - absl::Nanoseconds(1) / 4);
+  EXPECT_LT(min, min + absl::Nanoseconds(1) / 4);
+}
+
+TEST(Time, ConversionSaturation) {
+  const absl::TimeZone utc = absl::UTCTimeZone();
+  absl::Time t;
+
+  const auto max_time_t = std::numeric_limits<time_t>::max();
+  const auto min_time_t = std::numeric_limits<time_t>::min();
+  time_t tt = max_time_t - 1;
+  t = absl::FromTimeT(tt);
+  tt = absl::ToTimeT(t);
+  EXPECT_EQ(max_time_t - 1, tt);
+  t += absl::Seconds(1);
+  tt = absl::ToTimeT(t);
+  EXPECT_EQ(max_time_t, tt);
+  t += absl::Seconds(1);  // no effect
+  tt = absl::ToTimeT(t);
+  EXPECT_EQ(max_time_t, tt);
+
+  tt = min_time_t + 1;
+  t = absl::FromTimeT(tt);
+  tt = absl::ToTimeT(t);
+  EXPECT_EQ(min_time_t + 1, tt);
+  t -= absl::Seconds(1);
+  tt = absl::ToTimeT(t);
+  EXPECT_EQ(min_time_t, tt);
+  t -= absl::Seconds(1);  // no effect
+  tt = absl::ToTimeT(t);
+  EXPECT_EQ(min_time_t, tt);
+
+  const auto max_timeval_sec =
+      std::numeric_limits<decltype(timeval::tv_sec)>::max();
+  const auto min_timeval_sec =
+      std::numeric_limits<decltype(timeval::tv_sec)>::min();
+  timeval tv;
+  tv.tv_sec = max_timeval_sec;
+  tv.tv_usec = 999998;
+  t = absl::TimeFromTimeval(tv);
+  tv = ToTimeval(t);
+  EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(999998, tv.tv_usec);
+  t += absl::Microseconds(1);
+  tv = ToTimeval(t);
+  EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(999999, tv.tv_usec);
+  t += absl::Microseconds(1);  // no effect
+  tv = ToTimeval(t);
+  EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(999999, tv.tv_usec);
+
+  tv.tv_sec = min_timeval_sec;
+  tv.tv_usec = 1;
+  t = absl::TimeFromTimeval(tv);
+  tv = ToTimeval(t);
+  EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(1, tv.tv_usec);
+  t -= absl::Microseconds(1);
+  tv = ToTimeval(t);
+  EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(0, tv.tv_usec);
+  t -= absl::Microseconds(1);  // no effect
+  tv = ToTimeval(t);
+  EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+  EXPECT_EQ(0, tv.tv_usec);
+
+  const auto max_timespec_sec =
+      std::numeric_limits<decltype(timespec::tv_sec)>::max();
+  const auto min_timespec_sec =
+      std::numeric_limits<decltype(timespec::tv_sec)>::min();
+  timespec ts;
+  ts.tv_sec = max_timespec_sec;
+  ts.tv_nsec = 999999998;
+  t = absl::TimeFromTimespec(ts);
+  ts = absl::ToTimespec(t);
+  EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(999999998, ts.tv_nsec);
+  t += absl::Nanoseconds(1);
+  ts = absl::ToTimespec(t);
+  EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(999999999, ts.tv_nsec);
+  t += absl::Nanoseconds(1);  // no effect
+  ts = absl::ToTimespec(t);
+  EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(999999999, ts.tv_nsec);
+
+  ts.tv_sec = min_timespec_sec;
+  ts.tv_nsec = 1;
+  t = absl::TimeFromTimespec(ts);
+  ts = absl::ToTimespec(t);
+  EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(1, ts.tv_nsec);
+  t -= absl::Nanoseconds(1);
+  ts = absl::ToTimespec(t);
+  EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(0, ts.tv_nsec);
+  t -= absl::Nanoseconds(1);  // no effect
+  ts = absl::ToTimespec(t);
+  EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+  EXPECT_EQ(0, ts.tv_nsec);
+
+  // Checks how Time::In() saturates on infinities.
+  absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23,
+                            59, 59, 0, false);
+  EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond);
+  EXPECT_EQ(4, bd.weekday);  // Thursday
+  EXPECT_EQ(365, bd.yearday);
+  EXPECT_STREQ("-00", bd.zone_abbr);  // artifact of absl::Time::In()
+  bd = absl::InfinitePast().In(utc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
+                            0, 0, false);
+  EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond);
+  EXPECT_EQ(7, bd.weekday);  // Sunday
+  EXPECT_EQ(1, bd.yearday);
+  EXPECT_STREQ("-00", bd.zone_abbr);  // artifact of absl::Time::In()
+
+  // Approach the maximal Time value from below.
+  t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc);
+  EXPECT_EQ("292277026596-12-04T15:30:06+00:00",
+            absl::FormatTime(absl::RFC3339_full, t, utc));
+  t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 7, utc);
+  EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
+            absl::FormatTime(absl::RFC3339_full, t, utc));
+  EXPECT_EQ(
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+
+  // Checks that we can also get the maximal Time value for a far-east zone.
+  const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
+  t = absl::FromDateTime(292277026596, 12, 5, 5, 30, 7, plus14);
+  EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
+            absl::FormatTime(absl::RFC3339_full, t, plus14));
+  EXPECT_EQ(
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+
+  // One second later should push us to infinity.
+  t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 8, utc);
+  EXPECT_EQ("infinite-future", absl::FormatTime(absl::RFC3339_full, t, utc));
+
+  // Approach the minimal Time value from above.
+  t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 53, utc);
+  EXPECT_EQ("-292277022657-01-27T08:29:53+00:00",
+            absl::FormatTime(absl::RFC3339_full, t, utc));
+  t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 52, utc);
+  EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
+            absl::FormatTime(absl::RFC3339_full, t, utc));
+  EXPECT_EQ(
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+
+  // Checks that we can also get the minimal Time value for a far-west zone.
+  const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
+  t = absl::FromDateTime(-292277022657, 1, 26, 20, 29, 52, minus12);
+  EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
+            absl::FormatTime(absl::RFC3339_full, t, minus12));
+  EXPECT_EQ(
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+
+  // One second before should push us to -infinity.
+  t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 51, utc);
+  EXPECT_EQ("infinite-past", absl::FormatTime(absl::RFC3339_full, t, utc));
+}
+
+// In zones with POSIX-style recurring rules we use special logic to
+// handle conversions in the distant future.  Here we check the limits
+// of those conversions, particularly with respect to integer overflow.
+TEST(Time, ExtendedConversionSaturation) {
+  const absl::TimeZone syd =
+      absl::time_internal::LoadTimeZone("Australia/Sydney");
+  const absl::TimeZone nyc =
+      absl::time_internal::LoadTimeZone("America/New_York");
+  const absl::Time max =
+      absl::FromUnixSeconds(std::numeric_limits<int64_t>::max());
+  absl::Time::Breakdown bd;
+  absl::Time t;
+
+  // The maximal time converted in each zone.
+  bd = max.In(syd);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true);
+  t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd);
+  EXPECT_EQ(max, t);
+  bd = max.In(nyc);
+  ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false);
+  t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc);
+  EXPECT_EQ(max, t);
+
+  // One second later should push us to infinity.
+  t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 8, syd);
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+  t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 8, nyc);
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+
+  // And we should stick there.
+  t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 9, syd);
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+  t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 9, nyc);
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+
+  // All the way up to a saturated date/time, without overflow.
+  t = absl::FromDateTime(
+      std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, syd);
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+  t = absl::FromDateTime(
+      std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, nyc);
+  EXPECT_EQ(absl::InfiniteFuture(), t);
+}
+
+}  // namespace
diff --git a/absl/time/time_zone_test.cc b/absl/time/time_zone_test.cc
new file mode 100644
index 0000000..43d9190
--- /dev/null
+++ b/absl/time/time_zone_test.cc
@@ -0,0 +1,97 @@
+// Copyright 2017 The Abseil 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 "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#include "gtest/gtest.h"
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+
+namespace cctz = absl::time_internal::cctz;
+
+namespace {
+
+TEST(TimeZone, ValueSemantics) {
+  absl::TimeZone tz;
+  absl::TimeZone tz2 = tz;  // Copy-construct
+  EXPECT_EQ(tz, tz2);
+  tz2 = tz;  // Copy-assign
+  EXPECT_EQ(tz, tz2);
+}
+
+TEST(TimeZone, Equality) {
+  absl::TimeZone a, b;
+  EXPECT_EQ(a, b);
+  EXPECT_EQ(a.name(), b.name());
+
+  absl::TimeZone implicit_utc;
+  absl::TimeZone explicit_utc = absl::UTCTimeZone();
+  EXPECT_EQ(implicit_utc, explicit_utc);
+  EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
+
+  absl::TimeZone la = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York");
+  EXPECT_NE(la, nyc);
+}
+
+TEST(TimeZone, CCTZConversion) {
+  const cctz::time_zone cz = cctz::utc_time_zone();
+  const absl::TimeZone tz(cz);
+  EXPECT_EQ(cz, cctz::time_zone(tz));
+}
+
+TEST(TimeZone, DefaultTimeZones) {
+  absl::TimeZone tz;
+  EXPECT_EQ("UTC", absl::TimeZone().name());
+  EXPECT_EQ("UTC", absl::UTCTimeZone().name());
+}
+
+TEST(TimeZone, FixedTimeZone) {
+  const absl::TimeZone tz = absl::FixedTimeZone(123);
+  const cctz::time_zone cz = cctz::fixed_time_zone(cctz::seconds(123));
+  EXPECT_EQ(tz, absl::TimeZone(cz));
+}
+
+TEST(TimeZone, LocalTimeZone) {
+  const absl::TimeZone local_tz = absl::LocalTimeZone();
+  absl::TimeZone tz = absl::time_internal::LoadTimeZone("localtime");
+  EXPECT_EQ(tz, local_tz);
+}
+
+TEST(TimeZone, NamedTimeZones) {
+  absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York");
+  EXPECT_EQ("America/New_York", nyc.name());
+  absl::TimeZone syd = absl::time_internal::LoadTimeZone("Australia/Sydney");
+  EXPECT_EQ("Australia/Sydney", syd.name());
+  absl::TimeZone fixed = absl::FixedTimeZone((((3 * 60) + 25) * 60) + 45);
+  EXPECT_EQ("Fixed/UTC+03:25:45", fixed.name());
+}
+
+TEST(TimeZone, Failures) {
+  absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz));
+  EXPECT_EQ(absl::UTCTimeZone(), tz);  // guaranteed fallback to UTC
+
+  // Ensures that the load still fails on a subsequent attempt.
+  tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz));
+  EXPECT_EQ(absl::UTCTimeZone(), tz);  // guaranteed fallback to UTC
+
+  // Loading an empty std::string timezone should fail.
+  tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+  EXPECT_FALSE(LoadTimeZone("", &tz));
+  EXPECT_EQ(absl::UTCTimeZone(), tz);  // guaranteed fallback to UTC
+}
+
+}  // namespace
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
new file mode 100644
index 0000000..096c119
--- /dev/null
+++ b/absl/types/BUILD.bazel
@@ -0,0 +1,280 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+    "ABSL_EXCEPTIONS_FLAG",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "any",
+    hdrs = ["any.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":bad_any_cast",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/meta:type_traits",
+        "//absl/utility",
+    ],
+)
+
+cc_library(
+    name = "bad_any_cast",
+    hdrs = ["bad_any_cast.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":bad_any_cast_impl",
+        "//absl/base:config",
+    ],
+)
+
+cc_library(
+    name = "bad_any_cast_impl",
+    srcs = [
+        "bad_any_cast.cc",
+        "bad_any_cast.h",
+    ],
+    copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        "//absl/base",
+        "//absl/base:config",
+    ],
+)
+
+cc_test(
+    name = "any_test",
+    size = "small",
+    srcs = [
+        "any_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":any",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:exception_testing",
+        "//absl/container:test_instance_tracker",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "any_test_noexceptions",
+    size = "small",
+    srcs = [
+        "any_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":any",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:exception_testing",
+        "//absl/container:test_instance_tracker",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "any_exception_safety_test",
+    srcs = ["any_exception_safety_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":any",
+        "//absl/base:exception_safety_testing",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "span",
+    hdrs = ["span.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/algorithm",
+        "//absl/base:core_headers",
+        "//absl/base:throw_delegate",
+        "//absl/meta:type_traits",
+    ],
+)
+
+cc_test(
+    name = "span_test",
+    size = "small",
+    srcs = ["span_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":span",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:exception_testing",
+        "//absl/container:fixed_array",
+        "//absl/container:inlined_vector",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "span_test_noexceptions",
+    size = "small",
+    srcs = ["span_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":span",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:exception_testing",
+        "//absl/container:fixed_array",
+        "//absl/container:inlined_vector",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "optional",
+    srcs = ["optional.cc"],
+    hdrs = ["optional.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":bad_optional_access",
+        "//absl/base:config",
+        "//absl/memory",
+        "//absl/meta:type_traits",
+        "//absl/utility",
+    ],
+)
+
+cc_library(
+    name = "bad_optional_access",
+    srcs = ["bad_optional_access.cc"],
+    hdrs = ["bad_optional_access.h"],
+    copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        "//absl/base",
+        "//absl/base:config",
+    ],
+)
+
+cc_library(
+    name = "bad_variant_access",
+    srcs = ["bad_variant_access.cc"],
+    hdrs = ["bad_variant_access.h"],
+    copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base",
+        "//absl/base:config",
+    ],
+)
+
+cc_test(
+    name = "optional_test",
+    size = "small",
+    srcs = [
+        "optional_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":optional",
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/meta:type_traits",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "optional_exception_safety_test",
+    srcs = [
+        "optional_exception_safety_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":optional",
+        "//absl/base:exception_safety_testing",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_library(
+    name = "variant",
+    srcs = ["internal/variant.h"],
+    hdrs = ["variant.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        ":bad_variant_access",
+        "//absl/base:base_internal",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/meta:type_traits",
+        "//absl/utility",
+    ],
+)
+
+cc_test(
+    name = "variant_test",
+    size = "small",
+    srcs = ["variant_test.cc"],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":variant",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "//absl/meta:type_traits",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_test(
+    name = "variant_benchmark",
+    srcs = [
+        "variant_benchmark.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    deps = [
+        ":variant",
+        "//absl/utility",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
+    name = "variant_exception_safety_test",
+    size = "small",
+    srcs = [
+        "variant_exception_safety_test.cc",
+    ],
+    copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+    deps = [
+        ":variant",
+        "//absl/base:exception_safety_testing",
+        "//absl/memory",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/types/BUILD.gn b/absl/types/BUILD.gn
new file mode 100644
index 0000000..fd7e89d
--- /dev/null
+++ b/absl/types/BUILD.gn
@@ -0,0 +1,172 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("any") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "any.h",
+  ]
+  deps = [
+    ":bad_any_cast",
+    "../base:config",
+    "../base:core_headers",
+    "../meta:type_traits",
+    "../utility",
+  ]
+}
+
+source_set("bad_any_cast") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "bad_any_cast.h",
+  ]
+  deps = [
+    ":bad_any_cast_impl",
+    "../base:config",
+  ]
+}
+
+source_set("bad_any_cast_impl") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "bad_any_cast.cc",
+  ]
+  public = [
+    "bad_any_cast.h",
+  ]
+  deps = [
+    "../base",
+    "../base:config",
+  ]
+  visibility = []
+  visibility += [ ":*" ]
+}
+
+source_set("span") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "span.h",
+  ]
+  deps = [
+    "../algorithm",
+    "../base:core_headers",
+    "../base:throw_delegate",
+    "../meta:type_traits",
+  ]
+}
+
+source_set("optional") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "optional.cc",
+  ]
+  public = [
+    "optional.h",
+  ]
+  deps = [
+    ":bad_optional_access",
+    "../base:config",
+    "../memory",
+    "../meta:type_traits",
+    "../utility",
+  ]
+}
+
+source_set("bad_optional_access") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "bad_optional_access.cc",
+  ]
+  public = [
+    "bad_optional_access.h",
+  ]
+  deps = [
+    "../base",
+    "../base:config",
+  ]
+}
+
+source_set("bad_variant_access") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "bad_variant_access.cc",
+  ]
+  public = [
+    "bad_variant_access.h",
+  ]
+  deps = [
+    "../base",
+    "../base:config",
+  ]
+}
+
+source_set("variant") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  sources = [
+    "internal/variant.h",
+  ]
+  public = [
+    "variant.h",
+  ]
+  deps = [
+    ":bad_variant_access",
+    "../base:base_internal",
+    "../base:config",
+    "../base:core_headers",
+    "../meta:type_traits",
+    "../utility",
+  ]
+}
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
new file mode 100644
index 0000000..2f2e3a7
--- /dev/null
+++ b/absl/types/CMakeLists.txt
@@ -0,0 +1,228 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+list(APPEND TYPES_PUBLIC_HEADERS
+  "any.h"
+  "bad_any_cast.h"
+  "bad_optional_access.h"
+  "optional.h"
+  "span.h"
+  "variant.h"
+)
+
+
+# any library
+absl_header_library(
+  TARGET
+    absl_any
+  PUBLIC_LIBRARIES
+    absl::bad_any_cast
+    absl::base
+    absl::meta
+    absl::utility
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+  EXPORT_NAME
+    any
+)
+
+# span library
+absl_header_library(
+  TARGET
+    absl_span
+  PUBLIC_LIBRARIES
+    absl::utility
+  EXPORT_NAME
+    span
+)
+
+
+# bad_any_cast library
+list(APPEND BAD_ANY_CAST_SRC
+  "bad_any_cast.cc"
+  ${TYPES_PUBLIC_HEADERS}
+)
+
+absl_library(
+  TARGET
+    absl_bad_any_cast
+  SOURCES
+    ${BAD_ANY_CAST_SRC}
+  PUBLIC_LIBRARIES
+  EXPORT_NAME
+    bad_any_cast
+)
+
+
+# optional library
+list(APPEND OPTIONAL_SRC
+  "optional.cc"
+)
+
+absl_library(
+  TARGET
+    absl_optional
+  SOURCES
+    ${OPTIONAL_SRC}
+  PUBLIC_LIBRARIES
+    absl::bad_optional_access
+    absl::base
+    absl::memory
+    absl::meta
+    absl::utility
+  EXPORT_NAME
+    optional
+)
+
+
+set(BAD_OPTIONAL_ACCESS_SRC "bad_optional_access.cc")
+set(BAD_OPTIONAL_ACCESS_LIBRARIES absl::base)
+
+absl_library(
+  TARGET
+    absl_bad_optional_access
+  SOURCES
+    ${BAD_OPTIONAL_ACCESS_SRC}
+  PUBLIC_LIBRARIES
+    ${BAD_OPTIONAL_ACCESS_PUBLIC_LIBRARIES}
+  EXPORT_NAME
+    bad_optional_access
+)
+
+# variant library
+absl_library(
+  TARGET
+    absl_variant
+  SOURCES
+    "bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h"
+  PUBLIC_LIBRARIES
+    absl::base absl::meta absl::utility
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+  EXPORT_NAME
+    variant
+)
+
+#
+## TESTS
+#
+
+
+# test any_test
+set(ANY_TEST_SRC "any_test.cc")
+set(ANY_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::any absl::bad_any_cast test_instance_tracker_lib)
+
+absl_test(
+  TARGET
+    any_test
+  SOURCES
+    ${ANY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ANY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
+
+# test any_test_noexceptions
+absl_test(
+  TARGET
+    any_test_noexceptions
+  SOURCES
+    ${ANY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ANY_TEST_PUBLIC_LIBRARIES}
+)
+
+# test any_exception_safety_test
+set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
+set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
+  absl::any
+  absl::base
+  absl_base_internal_exception_safety_testing
+)
+
+absl_test(
+  TARGET
+    any_exception_safety_test
+  SOURCES
+    ${ANY_EXCEPTION_SAFETY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
+
+# test span_test
+set(SPAN_TEST_SRC "span_test.cc")
+set(SPAN_TEST_PUBLIC_LIBRARIES absl::base absl::strings absl::throw_delegate absl::span test_instance_tracker_lib)
+
+absl_test(
+  TARGET
+    span_test
+  SOURCES
+    ${SPAN_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${SPAN_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
+
+
+# test span_test_noexceptions
+absl_test(
+  TARGET
+    span_test_noexceptions
+  SOURCES
+    ${SPAN_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${SPAN_TEST_PUBLIC_LIBRARIES}
+)
+
+
+
+# test optional_test
+set(OPTIONAL_TEST_SRC "optional_test.cc")
+set(OPTIONAL_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::optional absl_bad_optional_access)
+
+absl_test(
+  TARGET
+    optional_test
+  SOURCES
+    ${OPTIONAL_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${OPTIONAL_TEST_PUBLIC_LIBRARIES}
+)
+
+
+# test optional_exception_safety_test
+set(OPTIONAL_EXCEPTION_SAFETY_TEST_SRC "optional_exception_safety_test.cc")
+set(OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
+  absl::optional
+  absl_base_internal_exception_safety_testing
+)
+
+absl_test(
+  TARGET
+    optional_exception_safety_test
+  SOURCES
+    ${OPTIONAL_EXCEPTION_SAFETY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
+  PRIVATE_COMPILE_FLAGS
+    ${ABSL_EXCEPTIONS_FLAG}
+)
diff --git a/absl/types/any.h b/absl/types/any.h
new file mode 100644
index 0000000..a973c6d
--- /dev/null
+++ b/absl/types/any.h
@@ -0,0 +1,539 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// any.h
+// -----------------------------------------------------------------------------
+//
+// This header file define the `absl::any` type for holding a type-safe value
+// of any type. The 'absl::any` type is useful for providing a way to hold
+// something that is, as yet, unspecified. Such unspecified types
+// traditionally are passed between API boundaries until they are later cast to
+// their "destination" types. To cast to such a destination type, use
+// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
+// to an explicit type; implicit conversions will throw.
+//
+// Example:
+//
+//   auto a = absl::any(65);
+//   absl::any_cast<int>(a);         // 65
+//   absl::any_cast<char>(a);        // throws absl::bad_any_cast
+//   absl::any_cast<std::string>(a); // throws absl::bad_any_cast
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+//
+// Traditionally, the behavior of casting to a temporary unspecified type has
+// been accomplished with the `void *` paradigm, where the pointer was to some
+// other unspecified type. `absl::any` provides an "owning" version of `void *`
+// that avoids issues of pointer management.
+//
+// Note: just as in the case of `void *`, use of `absl::any` (and its C++17
+// version `std::any`) is a code smell indicating that your API might not be
+// constructed correctly. We have seen that most uses of `any` are unwarranted,
+// and `absl::any`, like `std::any`, is difficult to use properly. Before using
+// this abstraction, make sure that you should not instead be rewriting your
+// code to be more specific.
+//
+// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
+// version of the C++17 `std::variant), which is generally preferred for use
+// over `absl::any`.
+#ifndef ABSL_TYPES_ANY_H_
+#define ABSL_TYPES_ANY_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_ANY
+
+#include <any>
+
+namespace absl {
+using std::any;
+using std::any_cast;
+using std::bad_any_cast;
+using std::make_any;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_ANY
+
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_any_cast.h"
+
+// NOTE: This macro is an implementation detail that is undefined at the bottom
+// of the file. It is not intended for expansion directly from user code.
+#ifdef ABSL_ANY_DETAIL_HAS_RTTI
+#error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set
+#elif !defined(__GNUC__) || defined(__GXX_RTTI)
+#define ABSL_ANY_DETAIL_HAS_RTTI 1
+#endif  // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+namespace absl {
+
+namespace any_internal {
+
+template <typename Type>
+struct TypeTag {
+  constexpr static char dummy_var = 0;
+};
+
+template <typename Type>
+constexpr char TypeTag<Type>::dummy_var;
+
+// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
+// passed in type. These are meant to be good match for keys into maps or
+// straight up comparisons.
+template<typename Type>
+constexpr inline const void* FastTypeId() {
+  return &TypeTag<Type>::dummy_var;
+}
+
+}  // namespace any_internal
+
+class any;
+
+// swap()
+//
+// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
+// `absl::any` types.
+void swap(any& x, any& y) noexcept;
+
+// make_any()
+//
+// Constructs an `absl::any` of type `T` with the given arguments.
+template <typename T, typename... Args>
+any make_any(Args&&... args);
+
+// Overload of `absl::make_any()` for constructing an `absl::any` type from an
+// initializer list.
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args);
+
+// any_cast()
+//
+// Statically casts the value of a `const absl::any` type to the given type.
+// This function will throw `absl::bad_any_cast` if the stored value type of the
+// `absl::any` does not match the cast.
+//
+// `any_cast()` can also be used to get a reference to the internal storage iff
+// a reference type is passed as its `ValueType`:
+//
+// Example:
+//
+//   absl::any my_any = std::vector<int>();
+//   absl::any_cast<std::vector<int>&>(my_any).push_back(42);
+template <typename ValueType>
+ValueType any_cast(const any& operand);
+
+// Overload of `any_cast()` to statically cast the value of a non-const
+// `absl::any` type to the given type. This function will throw
+// `absl::bad_any_cast` if the stored value type of the `absl::any` does not
+// match the cast.
+template <typename ValueType>
+ValueType any_cast(any& operand);  // NOLINT(runtime/references)
+
+// Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
+// type. This function will throw `absl::bad_any_cast` if the stored value type
+// of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType any_cast(any&& operand);
+
+// Overload of `any_cast()` to statically cast the value of a const pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+const ValueType* any_cast(const any* operand) noexcept;
+
+// Overload of `any_cast()` to statically cast the value of a pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType* any_cast(any* operand) noexcept;
+
+// -----------------------------------------------------------------------------
+// absl::any
+// -----------------------------------------------------------------------------
+//
+// An `absl::any` object provides the facility to either store an instance of a
+// type, known as the "contained object", or no value. An `absl::any` is used to
+// store values of types that are unknown at compile time. The `absl::any`
+// object, when containing a value, must contain a value type; storing a
+// reference type is neither desired nor supported.
+//
+// An `absl::any` can only store a type that is copy-constructable; move-only
+// types are not allowed within an `any` object.
+//
+// Example:
+//
+//   auto a = absl::any(65);                 // Literal, copyable
+//   auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
+//   std::unique_ptr<Foo> my_foo;
+//   auto c = absl::any(std::move(my_foo));  // Error, not copy-constructable
+//
+// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
+// context) to remove const-volatile qualifiers (known as "cv qualifiers"),
+// decay functions to function pointers, etc. We essentially "decay" a given
+// type into its essential type.
+//
+// `absl::any` makes use of decayed types when determining the basic type `T` of
+// the value to store in the any's contained object. In the documentation below,
+// we explicitly denote this by using the phrase "a decayed type of `T`".
+//
+// Example:
+//
+//   const int a = 4;
+//   absl::any foo(a);  // Decay ensures we store an "int", not a "const int&".
+//
+//   void my_function() {}
+//   absl::any bar(my_function);  // Decay ensures we store a function pointer.
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+class any {
+ private:
+  template <typename T>
+  struct IsInPlaceType;
+
+ public:
+  // Constructors
+
+  // Constructs an empty `absl::any` object (`any::has_value()` will return
+  // `false`).
+  constexpr any() noexcept;
+
+  // Copy constructs an `absl::any` object with a "contained object" of the
+  // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+  // `false`.
+  any(const any& other)
+      : obj_(other.has_value() ? other.obj_->Clone()
+                               : std::unique_ptr<ObjInterface>()) {}
+
+  // Move constructs an `absl::any` object with a "contained object" of the
+  // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+  // `false`).
+  any(any&& other) noexcept = default;
+
+  // Constructs an `absl::any` object with a "contained object" of the decayed
+  // type of `T`, which is initialized via `std::forward<T>(value)`.
+  //
+  // This constructor will not participate in overload resolution if the
+  // decayed type of `T` is not copy-constructible.
+  template <
+      typename T, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<!absl::disjunction<
+          std::is_same<any, VT>, IsInPlaceType<VT>,
+          absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
+  any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
+
+  // Constructs an `absl::any` object with a "contained object" of the decayed
+  // type of `T`, which is initialized via `std::forward<T>(value)`.
+  template <typename T, typename... Args, typename VT = absl::decay_t<T>,
+            absl::enable_if_t<absl::conjunction<
+                std::is_copy_constructible<VT>,
+                std::is_constructible<VT, Args...>>::value>* = nullptr>
+  explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
+      : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
+
+  // Constructs an `absl::any` object with a "contained object" of the passed
+  // type `VT` as a decayed type of `T`. `VT` is initialized as if
+  // direct-non-list-initializing an object of type `VT` with the arguments
+  // `initializer_list, std::forward<Args>(args)...`.
+  template <
+      typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<
+          absl::conjunction<std::is_copy_constructible<VT>,
+                            std::is_constructible<VT, std::initializer_list<U>&,
+                                                  Args...>>::value>* = nullptr>
+  explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
+               Args&&... args)
+      : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
+
+  // Assignment operators
+
+  // Copy assigns an `absl::any` object with a "contained object" of the
+  // passed type.
+  any& operator=(const any& rhs) {
+    any(rhs).swap(*this);
+    return *this;
+  }
+
+  // Move assigns an `absl::any` object with a "contained object" of the
+  // passed type. `rhs` is left in a valid but otherwise unspecified state.
+  any& operator=(any&& rhs) noexcept {
+    any(std::move(rhs)).swap(*this);
+    return *this;
+  }
+
+  // Assigns an `absl::any` object with a "contained object" of the passed type.
+  template <typename T, typename VT = absl::decay_t<T>,
+            absl::enable_if_t<absl::conjunction<
+                absl::negation<std::is_same<VT, any>>,
+                std::is_copy_constructible<VT>>::value>* = nullptr>
+  any& operator=(T&& rhs) {
+    any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
+    tmp.swap(*this);
+    return *this;
+  }
+
+  // Modifiers
+
+  // any::emplace()
+  //
+  // Emplaces a value within an `absl::any` object by calling `any::reset()`,
+  // initializing the contained value as if direct-non-list-initializing an
+  // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
+  // returning a reference to the new contained value.
+  //
+  // Note: If an exception is thrown during the call to `VT`'s constructor,
+  // `*this` does not contain a value, and any previously contained value has
+  // been destroyed.
+  template <
+      typename T, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+                        std::is_constructible<VT, Args...>::value>* = nullptr>
+  VT& emplace(Args&&... args) {
+    reset();  // NOTE: reset() is required here even in the world of exceptions.
+    Obj<VT>* const object_ptr =
+        new Obj<VT>(in_place, std::forward<Args>(args)...);
+    obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+    return object_ptr->value;
+  }
+
+  // Overload of `any::emplace()` to emplace a value within an `absl::any`
+  // object by calling `any::reset()`, initializing the contained value as if
+  // direct-non-list-initializing an object of type `VT` with the arguments
+  // `initializer_list, std::forward<Args>(args)...`, and returning a reference
+  // to the new contained value.
+  //
+  // Note: If an exception is thrown during the call to `VT`'s constructor,
+  // `*this` does not contain a value, and any previously contained value has
+  // been destroyed. The function shall not participate in overload resolution
+  // unless `is_copy_constructible_v<VT>` is `true` and
+  // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
+  template <
+      typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+                        std::is_constructible<VT, std::initializer_list<U>&,
+                                              Args...>::value>* = nullptr>
+  VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
+    reset();  // NOTE: reset() is required here even in the world of exceptions.
+    Obj<VT>* const object_ptr =
+        new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
+    obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+    return object_ptr->value;
+  }
+
+  // any::reset()
+  //
+  // Resets the state of the `absl::any` object, destroying the contained object
+  // if present.
+  void reset() noexcept { obj_ = nullptr; }
+
+  // any::swap()
+  //
+  // Swaps the passed value and the value of this `absl::any` object.
+  void swap(any& other) noexcept { obj_.swap(other.obj_); }
+
+  // Observers
+
+  // any::has_value()
+  //
+  // Returns `true` if the `any` object has a contained value, otherwise
+  // returns `false`.
+  bool has_value() const noexcept { return obj_ != nullptr; }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+  // Returns: typeid(T) if *this has a contained object of type T, otherwise
+  // typeid(void).
+  const std::type_info& type() const noexcept {
+    if (has_value()) {
+      return obj_->Type();
+    }
+
+    return typeid(void);
+  }
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+
+ private:
+  // Tagged type-erased abstraction for holding a cloneable object.
+  class ObjInterface {
+   public:
+    virtual ~ObjInterface() = default;
+    virtual std::unique_ptr<ObjInterface> Clone() const = 0;
+    virtual const void* ObjTypeId() const noexcept = 0;
+#if ABSL_ANY_DETAIL_HAS_RTTI
+    virtual const std::type_info& Type() const noexcept = 0;
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+  };
+
+  // Hold a value of some queryable type, with an ability to Clone it.
+  template <typename T>
+  class Obj : public ObjInterface {
+   public:
+    template <typename... Args>
+    explicit Obj(in_place_t /*tag*/, Args&&... args)
+        : value(std::forward<Args>(args)...) {}
+
+    std::unique_ptr<ObjInterface> Clone() const final {
+      return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
+    }
+
+    const void* ObjTypeId() const noexcept final { return IdForType<T>(); }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+    const std::type_info& Type() const noexcept final { return typeid(T); }
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+
+    T value;
+  };
+
+  std::unique_ptr<ObjInterface> CloneObj() const {
+    if (!obj_) return nullptr;
+    return obj_->Clone();
+  }
+
+  template <typename T>
+  constexpr static const void* IdForType() {
+    // Note: This type dance is to make the behavior consistent with typeid.
+    using NormalizedType =
+        typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+    return any_internal::FastTypeId<NormalizedType>();
+  }
+
+  const void* GetObjTypeId() const {
+    return obj_ ? obj_->ObjTypeId() : any_internal::FastTypeId<void>();
+  }
+
+  // `absl::any` nonmember functions //
+
+  // Description at the declaration site (top of file).
+  template <typename ValueType>
+  friend ValueType any_cast(const any& operand);
+
+  // Description at the declaration site (top of file).
+  template <typename ValueType>
+  friend ValueType any_cast(any& operand);  // NOLINT(runtime/references)
+
+  // Description at the declaration site (top of file).
+  template <typename T>
+  friend const T* any_cast(const any* operand) noexcept;
+
+  // Description at the declaration site (top of file).
+  template <typename T>
+  friend T* any_cast(any* operand) noexcept;
+
+  std::unique_ptr<ObjInterface> obj_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+constexpr any::any() noexcept = default;
+
+template <typename T>
+struct any::IsInPlaceType : std::false_type {};
+
+template <typename T>
+struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
+
+inline void swap(any& x, any& y) noexcept { x.swap(y); }
+
+// Description at the declaration site (top of file).
+template <typename T, typename... Args>
+any make_any(Args&&... args) {
+  return any(in_place_type_t<T>(), std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args) {
+  return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(const any& operand) {
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, const U&>::value,
+                "Invalid ValueType");
+  auto* const result = (any_cast<U>)(&operand);
+  if (result == nullptr) {
+    any_internal::ThrowBadAnyCast();
+  }
+  return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any& operand) {  // NOLINT(runtime/references)
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, U&>::value,
+                "Invalid ValueType");
+  auto* result = (any_cast<U>)(&operand);
+  if (result == nullptr) {
+    any_internal::ThrowBadAnyCast();
+  }
+  return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any&& operand) {
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, U>::value,
+                "Invalid ValueType");
+  return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+const T* any_cast(const any* operand) noexcept {
+  return operand && operand->GetObjTypeId() == any::IdForType<T>()
+             ? std::addressof(
+                   static_cast<const any::Obj<T>*>(operand->obj_.get())->value)
+             : nullptr;
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+T* any_cast(any* operand) noexcept {
+  return operand && operand->GetObjTypeId() == any::IdForType<T>()
+             ? std::addressof(
+                   static_cast<any::Obj<T>*>(operand->obj_.get())->value)
+             : nullptr;
+}
+
+}  // namespace absl
+
+#undef ABSL_ANY_DETAIL_HAS_RTTI
+
+#endif  // ABSL_HAVE_STD_ANY
+
+#endif  // ABSL_TYPES_ANY_H_
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc
new file mode 100644
index 0000000..36955f6
--- /dev/null
+++ b/absl/types/any_exception_safety_test.cc
@@ -0,0 +1,167 @@
+// Copyright 2017 The Abseil 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 "absl/types/any.h"
+
+#include <typeinfo>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+
+using Thrower = testing::ThrowingValue<>;
+using NoThrowMoveThrower =
+    testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using ThrowerList = std::initializer_list<Thrower>;
+using ThrowerVec = std::vector<Thrower>;
+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
+using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
+
+namespace {
+
+testing::AssertionResult AnyInvariants(absl::any* a) {
+  using testing::AssertionFailure;
+  using testing::AssertionSuccess;
+
+  if (a->has_value()) {
+    if (a->type() == typeid(void)) {
+      return AssertionFailure()
+             << "A non-empty any should not have type `void`";
+    }
+  } else {
+    if (a->type() != typeid(void)) {
+      return AssertionFailure()
+             << "An empty any should have type void, but has type "
+             << a->type().name();
+    }
+  }
+
+  //  Make sure that reset() changes any to a valid state.
+  a->reset();
+  if (a->has_value()) {
+    return AssertionFailure() << "A reset `any` should be valueless";
+  }
+  if (a->type() != typeid(void)) {
+    return AssertionFailure() << "A reset `any` should have type() of `void`, "
+                                 "but instead has type "
+                              << a->type().name();
+  }
+  try {
+    auto unused = absl::any_cast<Thrower>(*a);
+    static_cast<void>(unused);
+    return AssertionFailure()
+           << "A reset `any` should not be able to be any_cast";
+  } catch (absl::bad_any_cast) {
+  } catch (...) {
+    return AssertionFailure()
+           << "Unexpected exception thrown from absl::any_cast";
+  }
+  return AssertionSuccess();
+}
+
+testing::AssertionResult AnyIsEmpty(absl::any* a) {
+  if (!a->has_value()) {
+    return testing::AssertionSuccess();
+  }
+  return testing::AssertionFailure()
+         << "a should be empty, but instead has value "
+         << absl::any_cast<Thrower>(*a).Get();
+}
+
+TEST(AnyExceptionSafety, Ctors) {
+  Thrower val(1);
+  testing::TestThrowingCtor<absl::any>(val);
+
+  Thrower copy(val);
+  testing::TestThrowingCtor<absl::any>(copy);
+
+  testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
+
+  testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<ThrowerVec>(),
+                                       ThrowerList{val});
+
+  testing::TestThrowingCtor<absl::any,
+                            absl::in_place_type_t<ThrowingThrowerVec>,
+                            ThrowerList, ThrowingAlloc>(
+      absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
+}
+
+TEST(AnyExceptionSafety, Assignment) {
+  auto original =
+      absl::any(absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor);
+  auto any_is_strong = [original](absl::any* ap) {
+    return testing::AssertionResult(ap->has_value() &&
+                                    absl::any_cast<Thrower>(original) ==
+                                        absl::any_cast<Thrower>(*ap));
+  };
+  auto any_strong_tester = testing::MakeExceptionSafetyTester()
+                               .WithInitialValue(original)
+                               .WithInvariants(AnyInvariants, any_is_strong);
+
+  Thrower val(2);
+  absl::any any_val(val);
+  NoThrowMoveThrower mv_val(2);
+
+  auto assign_any = [&any_val](absl::any* ap) { *ap = any_val; };
+  auto assign_val = [&val](absl::any* ap) { *ap = val; };
+  auto move = [&val](absl::any* ap) { *ap = std::move(val); };
+  auto move_movable = [&mv_val](absl::any* ap) { *ap = std::move(mv_val); };
+
+  EXPECT_TRUE(any_strong_tester.Test(assign_any));
+  EXPECT_TRUE(any_strong_tester.Test(assign_val));
+  EXPECT_TRUE(any_strong_tester.Test(move));
+  EXPECT_TRUE(any_strong_tester.Test(move_movable));
+
+  auto empty_any_is_strong = [](absl::any* ap) {
+    return testing::AssertionResult{!ap->has_value()};
+  };
+  auto strong_empty_any_tester =
+      testing::MakeExceptionSafetyTester()
+          .WithInitialValue(absl::any{})
+          .WithInvariants(AnyInvariants, empty_any_is_strong);
+
+  EXPECT_TRUE(strong_empty_any_tester.Test(assign_any));
+  EXPECT_TRUE(strong_empty_any_tester.Test(assign_val));
+  EXPECT_TRUE(strong_empty_any_tester.Test(move));
+}
+// libstdc++ std::any fails this test
+#if !defined(ABSL_HAVE_STD_ANY)
+TEST(AnyExceptionSafety, Emplace) {
+  auto initial_val =
+      absl::any{absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor};
+  auto one_tester = testing::MakeExceptionSafetyTester()
+                        .WithInitialValue(initial_val)
+                        .WithInvariants(AnyInvariants, AnyIsEmpty);
+
+  auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); };
+  auto emp_throwervec = [](absl::any* ap) {
+    std::initializer_list<Thrower> il{Thrower(2, testing::nothrow_ctor)};
+    ap->emplace<ThrowerVec>(il);
+  };
+  auto emp_movethrower = [](absl::any* ap) {
+    ap->emplace<NoThrowMoveThrower>(2);
+  };
+
+  EXPECT_TRUE(one_tester.Test(emp_thrower));
+  EXPECT_TRUE(one_tester.Test(emp_throwervec));
+  EXPECT_TRUE(one_tester.Test(emp_movethrower));
+
+  auto empty_tester = one_tester.WithInitialValue(absl::any{});
+
+  EXPECT_TRUE(empty_tester.Test(emp_thrower));
+  EXPECT_TRUE(empty_tester.Test(emp_throwervec));
+}
+#endif  // ABSL_HAVE_STD_ANY
+
+}  // namespace
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc
new file mode 100644
index 0000000..115e78d
--- /dev/null
+++ b/absl/types/any_test.cc
@@ -0,0 +1,724 @@
+// Copyright 2017 The Abseil 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 "absl/types/any.h"
+
+#include <initializer_list>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/test_instance_tracker.h"
+
+namespace {
+using absl::test_internal::CopyableOnlyInstance;
+using absl::test_internal::InstanceTracker;
+
+template <typename T>
+const T& AsConst(const T& t) {
+  return t;
+}
+
+struct MoveOnly {
+  MoveOnly() = default;
+  explicit MoveOnly(int value) : value(value) {}
+  MoveOnly(MoveOnly&&) = default;
+  MoveOnly& operator=(MoveOnly&&) = default;
+
+  int value = 0;
+};
+
+struct CopyOnly {
+  CopyOnly() = default;
+  explicit CopyOnly(int value) : value(value) {}
+  CopyOnly(CopyOnly&&) = delete;
+  CopyOnly& operator=(CopyOnly&&) = delete;
+  CopyOnly(const CopyOnly&) = default;
+  CopyOnly& operator=(const CopyOnly&) = default;
+
+  int value = 0;
+};
+
+struct MoveOnlyWithListConstructor {
+  MoveOnlyWithListConstructor() = default;
+  explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
+                                       int value)
+      : value(value) {}
+  MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
+  MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
+      default;
+
+  int value = 0;
+};
+
+struct IntMoveOnlyCopyOnly {
+  IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/)
+      : value(value) {}
+
+  int value;
+};
+
+struct ListMoveOnlyCopyOnly {
+  ListMoveOnlyCopyOnly(std::initializer_list<int> ilist, MoveOnly /*move_only*/,
+                       CopyOnly /*copy_only*/)
+      : values(ilist) {}
+
+  std::vector<int> values;
+};
+
+using FunctionType = void();
+void FunctionToEmplace() {}
+
+using ArrayType = int[2];
+using DecayedArray = absl::decay_t<ArrayType>;
+
+TEST(AnyTest, Noexcept) {
+  static_assert(std::is_nothrow_default_constructible<absl::any>(), "");
+  static_assert(std::is_nothrow_move_constructible<absl::any>(), "");
+  static_assert(std::is_nothrow_move_assignable<absl::any>(), "");
+  static_assert(noexcept(std::declval<absl::any&>().has_value()), "");
+  static_assert(noexcept(std::declval<absl::any&>().type()), "");
+  static_assert(noexcept(absl::any_cast<int>(std::declval<absl::any*>())), "");
+  static_assert(
+      noexcept(std::declval<absl::any&>().swap(std::declval<absl::any&>())),
+      "");
+
+  using std::swap;
+  static_assert(
+      noexcept(swap(std::declval<absl::any&>(), std::declval<absl::any&>())),
+      "");
+}
+
+TEST(AnyTest, HasValue) {
+  absl::any o;
+  EXPECT_FALSE(o.has_value());
+  o.emplace<int>();
+  EXPECT_TRUE(o.has_value());
+  o.reset();
+  EXPECT_FALSE(o.has_value());
+}
+
+TEST(AnyTest, Type) {
+  absl::any o;
+  EXPECT_EQ(typeid(void), o.type());
+  o.emplace<int>(5);
+  EXPECT_EQ(typeid(int), o.type());
+  o.emplace<float>(5.f);
+  EXPECT_EQ(typeid(float), o.type());
+  o.reset();
+  EXPECT_EQ(typeid(void), o.type());
+}
+
+TEST(AnyTest, EmptyPointerCast) {
+  // pointer-to-unqualified overload
+  {
+    absl::any o;
+    EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
+    o.emplace<int>();
+    EXPECT_NE(nullptr, absl::any_cast<int>(&o));
+    o.reset();
+    EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
+  }
+
+  // pointer-to-const overload
+  {
+    absl::any o;
+    EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
+    o.emplace<int>();
+    EXPECT_NE(nullptr, absl::any_cast<int>(&AsConst(o)));
+    o.reset();
+    EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
+  }
+}
+
+TEST(AnyTest, InPlaceConstruction) {
+  const CopyOnly copy_only{};
+  absl::any o(absl::in_place_type_t<IntMoveOnlyCopyOnly>(), 5, MoveOnly(),
+              copy_only);
+  IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+  EXPECT_EQ(5, v.value);
+}
+
+TEST(AnyTest, InPlaceConstructionWithCV) {
+  const CopyOnly copy_only{};
+  absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5,
+              MoveOnly(), copy_only);
+  IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+  EXPECT_EQ(5, v.value);
+}
+
+TEST(AnyTest, InPlaceConstructionWithFunction) {
+  absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace);
+  FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o);
+  EXPECT_EQ(&FunctionToEmplace, construction_result);
+}
+
+TEST(AnyTest, InPlaceConstructionWithArray) {
+  ArrayType ar = {5, 42};
+  absl::any o(absl::in_place_type_t<ArrayType>(), ar);
+  DecayedArray& construction_result = absl::any_cast<DecayedArray&>(o);
+  EXPECT_EQ(&ar[0], construction_result);
+}
+
+TEST(AnyTest, InPlaceConstructionIlist) {
+  const CopyOnly copy_only{};
+  absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4},
+              MoveOnly(), copy_only);
+  ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+  std::vector<int> expected_values = {1, 2, 3, 4};
+  EXPECT_EQ(expected_values, v.values);
+}
+
+TEST(AnyTest, InPlaceConstructionIlistWithCV) {
+  const CopyOnly copy_only{};
+  absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(),
+              {1, 2, 3, 4}, MoveOnly(), copy_only);
+  ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+  std::vector<int> expected_values = {1, 2, 3, 4};
+  EXPECT_EQ(expected_values, v.values);
+}
+
+TEST(AnyTest, InPlaceNoArgs) {
+  absl::any o(absl::in_place_type_t<int>{});
+  EXPECT_EQ(0, absl::any_cast<int&>(o));
+}
+
+template <typename Enabler, typename T, typename... Args>
+struct CanEmplaceAnyImpl : std::false_type {};
+
+template <typename T, typename... Args>
+struct CanEmplaceAnyImpl<
+    absl::void_t<decltype(
+        std::declval<absl::any&>().emplace<T>(std::declval<Args>()...))>,
+    T, Args...> : std::true_type {};
+
+template <typename T, typename... Args>
+using CanEmplaceAny = CanEmplaceAnyImpl<void, T, Args...>;
+
+TEST(AnyTest, Emplace) {
+  const CopyOnly copy_only{};
+  absl::any o;
+  EXPECT_TRUE((std::is_same<decltype(o.emplace<IntMoveOnlyCopyOnly>(
+                                5, MoveOnly(), copy_only)),
+                            IntMoveOnlyCopyOnly&>::value));
+  IntMoveOnlyCopyOnly& emplace_result =
+      o.emplace<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
+  EXPECT_EQ(5, emplace_result.value);
+  IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+  EXPECT_EQ(5, v.value);
+  EXPECT_EQ(&emplace_result, &v);
+
+  static_assert(!CanEmplaceAny<int, int, int>::value, "");
+  static_assert(!CanEmplaceAny<MoveOnly, MoveOnly>::value, "");
+}
+
+TEST(AnyTest, EmplaceWithCV) {
+  const CopyOnly copy_only{};
+  absl::any o;
+  EXPECT_TRUE(
+      (std::is_same<decltype(o.emplace<const volatile IntMoveOnlyCopyOnly>(
+                        5, MoveOnly(), copy_only)),
+                    IntMoveOnlyCopyOnly&>::value));
+  IntMoveOnlyCopyOnly& emplace_result =
+      o.emplace<const volatile IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
+  EXPECT_EQ(5, emplace_result.value);
+  IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+  EXPECT_EQ(5, v.value);
+  EXPECT_EQ(&emplace_result, &v);
+}
+
+TEST(AnyTest, EmplaceWithFunction) {
+  absl::any o;
+  EXPECT_TRUE(
+      (std::is_same<decltype(o.emplace<FunctionType>(FunctionToEmplace)),
+                    FunctionType*&>::value));
+  FunctionType*& emplace_result = o.emplace<FunctionType>(FunctionToEmplace);
+  EXPECT_EQ(&FunctionToEmplace, emplace_result);
+}
+
+TEST(AnyTest, EmplaceWithArray) {
+  absl::any o;
+  ArrayType ar = {5, 42};
+  EXPECT_TRUE(
+      (std::is_same<decltype(o.emplace<ArrayType>(ar)), DecayedArray&>::value));
+  DecayedArray& emplace_result = o.emplace<ArrayType>(ar);
+  EXPECT_EQ(&ar[0], emplace_result);
+}
+
+TEST(AnyTest, EmplaceIlist) {
+  const CopyOnly copy_only{};
+  absl::any o;
+  EXPECT_TRUE((std::is_same<decltype(o.emplace<ListMoveOnlyCopyOnly>(
+                                {1, 2, 3, 4}, MoveOnly(), copy_only)),
+                            ListMoveOnlyCopyOnly&>::value));
+  ListMoveOnlyCopyOnly& emplace_result =
+      o.emplace<ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), copy_only);
+  ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+  EXPECT_EQ(&v, &emplace_result);
+  std::vector<int> expected_values = {1, 2, 3, 4};
+  EXPECT_EQ(expected_values, v.values);
+
+  static_assert(!CanEmplaceAny<int, std::initializer_list<int>>::value, "");
+  static_assert(!CanEmplaceAny<MoveOnlyWithListConstructor,
+                               std::initializer_list<int>, int>::value,
+                "");
+}
+
+TEST(AnyTest, EmplaceIlistWithCV) {
+  const CopyOnly copy_only{};
+  absl::any o;
+  EXPECT_TRUE(
+      (std::is_same<decltype(o.emplace<const volatile ListMoveOnlyCopyOnly>(
+                        {1, 2, 3, 4}, MoveOnly(), copy_only)),
+                    ListMoveOnlyCopyOnly&>::value));
+  ListMoveOnlyCopyOnly& emplace_result =
+      o.emplace<const volatile ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(),
+                                                     copy_only);
+  ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+  EXPECT_EQ(&v, &emplace_result);
+  std::vector<int> expected_values = {1, 2, 3, 4};
+  EXPECT_EQ(expected_values, v.values);
+}
+
+TEST(AnyTest, EmplaceNoArgs) {
+  absl::any o;
+  o.emplace<int>();
+  EXPECT_EQ(0, absl::any_cast<int>(o));
+}
+
+TEST(AnyTest, ConversionConstruction) {
+  {
+    absl::any o = 5;
+    EXPECT_EQ(5, absl::any_cast<int>(o));
+  }
+
+  {
+    const CopyOnly copy_only(5);
+    absl::any o = copy_only;
+    EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
+  }
+
+  static_assert(!std::is_convertible<MoveOnly, absl::any>::value, "");
+}
+
+TEST(AnyTest, ConversionAssignment) {
+  {
+    absl::any o;
+    o = 5;
+    EXPECT_EQ(5, absl::any_cast<int>(o));
+  }
+
+  {
+    const CopyOnly copy_only(5);
+    absl::any o;
+    o = copy_only;
+    EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
+  }
+
+  static_assert(!std::is_assignable<MoveOnly, absl::any>::value, "");
+}
+
+// Suppress MSVC warnings.
+// 4521: multiple copy constructors specified
+// We wrote multiple of them to test that the correct overloads are selected.
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4521)
+#endif
+
+// Weird type for testing, only used to make sure we "properly" perfect-forward
+// when being placed into an absl::any (use the l-value constructor if given an
+// l-value rather than use the copy constructor).
+struct WeirdConstructor42 {
+  explicit WeirdConstructor42(int value) : value(value) {}
+
+  // Copy-constructor
+  WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {}
+
+  // L-value "weird" constructor (used when given an l-value)
+  WeirdConstructor42(
+      WeirdConstructor42& /*other*/)  // NOLINT(runtime/references)
+      : value(42) {}
+
+  int value;
+};
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+TEST(AnyTest, WeirdConversionConstruction) {
+  {
+    const WeirdConstructor42 source(5);
+    absl::any o = source;  // Actual copy
+    EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
+  }
+
+  {
+    WeirdConstructor42 source(5);
+    absl::any o = source;  // Weird "conversion"
+    EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
+  }
+}
+
+TEST(AnyTest, WeirdConversionAssignment) {
+  {
+    const WeirdConstructor42 source(5);
+    absl::any o;
+    o = source;  // Actual copy
+    EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
+  }
+
+  {
+    WeirdConstructor42 source(5);
+    absl::any o;
+    o = source;  // Weird "conversion"
+    EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
+  }
+}
+
+struct Value {};
+
+TEST(AnyTest, AnyCastValue) {
+  {
+    absl::any o;
+    o.emplace<int>(5);
+    EXPECT_EQ(5, absl::any_cast<int>(o));
+    EXPECT_EQ(5, absl::any_cast<int>(AsConst(o)));
+    static_assert(
+        std::is_same<decltype(absl::any_cast<Value>(o)), Value>::value, "");
+  }
+
+  {
+    absl::any o;
+    o.emplace<int>(5);
+    EXPECT_EQ(5, absl::any_cast<const int>(o));
+    EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
+    static_assert(std::is_same<decltype(absl::any_cast<const Value>(o)),
+                               const Value>::value,
+                  "");
+  }
+}
+
+TEST(AnyTest, AnyCastReference) {
+  {
+    absl::any o;
+    o.emplace<int>(5);
+    EXPECT_EQ(5, absl::any_cast<int&>(o));
+    EXPECT_EQ(5, absl::any_cast<const int&>(AsConst(o)));
+    static_assert(
+        std::is_same<decltype(absl::any_cast<Value&>(o)), Value&>::value, "");
+  }
+
+  {
+    absl::any o;
+    o.emplace<int>(5);
+    EXPECT_EQ(5, absl::any_cast<const int>(o));
+    EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
+    static_assert(std::is_same<decltype(absl::any_cast<const Value&>(o)),
+                               const Value&>::value,
+                  "");
+  }
+
+  {
+    absl::any o;
+    o.emplace<int>(5);
+    EXPECT_EQ(5, absl::any_cast<int&&>(std::move(o)));
+    static_assert(std::is_same<decltype(absl::any_cast<Value&&>(std::move(o))),
+                               Value&&>::value,
+                  "");
+  }
+
+  {
+    absl::any o;
+    o.emplace<int>(5);
+    EXPECT_EQ(5, absl::any_cast<const int>(std::move(o)));
+    static_assert(
+        std::is_same<decltype(absl::any_cast<const Value&&>(std::move(o))),
+                     const Value&&>::value,
+        "");
+  }
+}
+
+TEST(AnyTest, AnyCastPointer) {
+  {
+    absl::any o;
+    EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
+    o.emplace<int>(5);
+    EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
+    o.emplace<char>('a');
+    EXPECT_EQ('a', *absl::any_cast<char>(&o));
+    static_assert(
+        std::is_same<decltype(absl::any_cast<Value>(&o)), Value*>::value, "");
+  }
+
+  {
+    absl::any o;
+    EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
+    o.emplace<int>(5);
+    EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
+    o.emplace<char>('a');
+    EXPECT_EQ('a', *absl::any_cast<const char>(&o));
+    static_assert(std::is_same<decltype(absl::any_cast<const Value>(&o)),
+                               const Value*>::value,
+                  "");
+  }
+}
+
+TEST(AnyTest, MakeAny) {
+  const CopyOnly copy_only{};
+  auto o = absl::make_any<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
+  static_assert(std::is_same<decltype(o), absl::any>::value, "");
+  EXPECT_EQ(5, absl::any_cast<IntMoveOnlyCopyOnly&>(o).value);
+}
+
+TEST(AnyTest, MakeAnyIList) {
+  const CopyOnly copy_only{};
+  auto o =
+      absl::make_any<ListMoveOnlyCopyOnly>({1, 2, 3}, MoveOnly(), copy_only);
+  static_assert(std::is_same<decltype(o), absl::any>::value, "");
+  ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+  std::vector<int> expected_values = {1, 2, 3};
+  EXPECT_EQ(expected_values, v.values);
+}
+
+// Test the use of copy constructor and operator=
+TEST(AnyTest, Copy) {
+  InstanceTracker tracker_raii;
+
+  {
+    absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123);
+    CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o);
+
+    absl::any o2(o);
+    const CopyableOnlyInstance* f2 = absl::any_cast<CopyableOnlyInstance>(&o2);
+    EXPECT_EQ(123, f2->value());
+    EXPECT_NE(f1, f2);
+
+    absl::any o3;
+    o3 = o2;
+    const CopyableOnlyInstance* f3 = absl::any_cast<CopyableOnlyInstance>(&o3);
+    EXPECT_EQ(123, f3->value());
+    EXPECT_NE(f2, f3);
+
+    const absl::any o4(4);
+    // copy construct from const lvalue ref.
+    absl::any o5 = o4;
+    EXPECT_EQ(4, absl::any_cast<int>(o4));
+    EXPECT_EQ(4, absl::any_cast<int>(o5));
+
+    // Copy construct from const rvalue ref.
+    absl::any o6 = std::move(o4);  // NOLINT
+    EXPECT_EQ(4, absl::any_cast<int>(o4));
+    EXPECT_EQ(4, absl::any_cast<int>(o6));
+  }
+}
+
+TEST(AnyTest, Move) {
+  InstanceTracker tracker_raii;
+
+  absl::any any1;
+  any1.emplace<CopyableOnlyInstance>(5);
+
+  // This is a copy, so copy count increases to 1.
+  absl::any any2 = any1;
+  EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any1).value());
+  EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any2).value());
+  EXPECT_EQ(1, tracker_raii.copies());
+
+  // This isn't a copy, so copy count doesn't increase.
+  absl::any any3 = std::move(any2);
+  EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any3).value());
+  EXPECT_EQ(1, tracker_raii.copies());
+
+  absl::any any4;
+  any4 = std::move(any3);
+  EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any4).value());
+  EXPECT_EQ(1, tracker_raii.copies());
+
+  absl::any tmp4(4);
+  absl::any o4(std::move(tmp4));  // move construct
+  EXPECT_EQ(4, absl::any_cast<int>(o4));
+  o4 = *&o4;  // self assign
+  EXPECT_EQ(4, absl::any_cast<int>(o4));
+  EXPECT_TRUE(o4.has_value());
+
+  absl::any o5;
+  absl::any tmp5(5);
+  o5 = std::move(tmp5);  // move assign
+  EXPECT_EQ(5, absl::any_cast<int>(o5));
+}
+
+// Reset the ObjectOwner with an object of a different type
+TEST(AnyTest, Reset) {
+  absl::any o;
+  o.emplace<int>();
+
+  o.reset();
+  EXPECT_FALSE(o.has_value());
+
+  o.emplace<char>();
+  EXPECT_TRUE(o.has_value());
+}
+
+TEST(AnyTest, ConversionConstructionCausesOneCopy) {
+  InstanceTracker tracker_raii;
+  CopyableOnlyInstance counter(5);
+  absl::any o(counter);
+  EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(o).value());
+  EXPECT_EQ(1, tracker_raii.copies());
+}
+
+//////////////////////////////////
+// Tests for Exception Behavior //
+//////////////////////////////////
+
+#if defined(ABSL_HAVE_STD_ANY)
+
+// If using a std `any` implementation, we can't check for a specific message.
+#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...)                      \
+  ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
+                                 "")
+
+#else
+
+// If using the absl `any` implementation, we can rely on a specific message.
+#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...)                      \
+  ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
+                                 "Bad any cast")
+
+#endif  // defined(ABSL_HAVE_STD_ANY)
+
+TEST(AnyTest, ThrowBadAlloc) {
+  {
+    absl::any a;
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&&>(absl::any{}));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&&>(absl::any{}));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(absl::any{}));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(absl::any{}));
+
+    // const absl::any operand
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(AsConst(a)));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(AsConst(a)));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(AsConst(a)));
+  }
+
+  {
+    absl::any a(absl::in_place_type_t<int>{});
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{}));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(
+        absl::any_cast<const float&&>(absl::any{}));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(a));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(absl::any{}));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(absl::any{}));
+
+    // const absl::any operand
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(AsConst(a)));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(AsConst(a)));
+    ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(AsConst(a)));
+  }
+}
+
+class BadCopy {};
+
+struct BadCopyable {
+  BadCopyable() = default;
+  BadCopyable(BadCopyable&&) = default;
+  BadCopyable(const BadCopyable&) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+    throw BadCopy();
+#else
+    ABSL_RAW_LOG(FATAL, "Bad copy");
+#endif
+  }
+};
+
+#define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \
+  ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy")
+
+// Test the guarantees regarding exceptions in copy/assign.
+TEST(AnyTest, FailedCopy) {
+  {
+    const BadCopyable bad{};
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad});
+  }
+
+  {
+    absl::any src(absl::in_place_type_t<BadCopyable>{});
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src});
+  }
+
+  {
+    BadCopyable bad;
+    absl::any target;
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
+  }
+
+  {
+    BadCopyable bad;
+    absl::any target(absl::in_place_type_t<BadCopyable>{});
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
+    EXPECT_TRUE(target.has_value());
+  }
+
+  {
+    absl::any src(absl::in_place_type_t<BadCopyable>{});
+    absl::any target;
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
+    EXPECT_FALSE(target.has_value());
+  }
+
+  {
+    absl::any src(absl::in_place_type_t<BadCopyable>{});
+    absl::any target(absl::in_place_type_t<BadCopyable>{});
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
+    EXPECT_TRUE(target.has_value());
+  }
+}
+
+// Test the guarantees regarding exceptions in emplace.
+TEST(AnyTest, FailedEmplace) {
+  {
+    BadCopyable bad;
+    absl::any target;
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
+  }
+
+  {
+    BadCopyable bad;
+    absl::any target(absl::in_place_type_t<int>{});
+    ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
+#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__)
+    // libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an
+    // exception is thrown, *this contains a value.
+#define ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG 1
+#endif
+#if defined(ABSL_HAVE_EXCEPTIONS) && \
+    !defined(ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG)
+    EXPECT_FALSE(target.has_value());
+#endif
+  }
+}
+
+}  // namespace
diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc
new file mode 100644
index 0000000..2e2fd29
--- /dev/null
+++ b/absl/types/bad_any_cast.cc
@@ -0,0 +1,44 @@
+// Copyright 2017 The Abseil 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 "absl/types/bad_any_cast.h"
+
+#ifndef ABSL_HAVE_STD_ANY
+
+#include <cstdlib>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+bad_any_cast::~bad_any_cast() = default;
+
+const char* bad_any_cast::what() const noexcept { return "Bad any cast"; }
+
+namespace any_internal {
+
+void ThrowBadAnyCast() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw bad_any_cast();
+#else
+  ABSL_RAW_LOG(FATAL, "Bad any cast");
+  std::abort();
+#endif
+}
+
+}  // namespace any_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_ANY
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h
new file mode 100644
index 0000000..6039013
--- /dev/null
+++ b/absl/types/bad_any_cast.h
@@ -0,0 +1,71 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// bad_any_cast.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_any_cast` type.
+
+#ifndef ABSL_TYPES_BAD_ANY_CAST_H_
+#define ABSL_TYPES_BAD_ANY_CAST_H_
+
+#include <typeinfo>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_HAVE_STD_ANY
+
+#include <any>
+
+namespace absl {
+using std::bad_any_cast;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_ANY
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// bad_any_cast
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_any_cast` type is an exception type that is thrown when
+// failing to successfully cast the return value of an `absl::any` object.
+//
+// Example:
+//
+//   auto a = absl::any(65);
+//   absl::any_cast<int>(a);         // 65
+//   try {
+//     absl::any_cast<char>(a);
+//   } catch(const absl::bad_any_cast& e) {
+//     std::cout << "Bad any cast: " << e.what() << '\n';
+//   }
+class bad_any_cast : public std::bad_cast {
+ public:
+  ~bad_any_cast() override;
+  const char* what() const noexcept override;
+};
+
+namespace any_internal {
+
+[[noreturn]] void ThrowBadAnyCast();
+
+}  // namespace any_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_ANY
+
+#endif  // ABSL_TYPES_BAD_ANY_CAST_H_
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc
new file mode 100644
index 0000000..5587077
--- /dev/null
+++ b/absl/types/bad_optional_access.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Abseil 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 "absl/types/bad_optional_access.h"
+
+#ifndef ABSL_HAVE_STD_OPTIONAL
+
+#include <cstdlib>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+bad_optional_access::~bad_optional_access() = default;
+
+const char* bad_optional_access::what() const noexcept {
+  return "optional has no value";
+}
+
+namespace optional_internal {
+
+void throw_bad_optional_access() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw bad_optional_access();
+#else
+  ABSL_RAW_LOG(FATAL, "Bad optional access");
+  abort();
+#endif
+}
+
+}  // namespace optional_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h
new file mode 100644
index 0000000..c6c2746
--- /dev/null
+++ b/absl/types/bad_optional_access.h
@@ -0,0 +1,74 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// bad_optional_access.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_optional_access` type.
+
+#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
+#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
+
+#include <stdexcept>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+
+#include <optional>
+
+namespace absl {
+using std::bad_optional_access;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_OPTIONAL
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// bad_optional_access
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_optional_access` type is an exception type that is thrown when
+// attempting to access an `absl::optional` object that does not contain a
+// value.
+//
+// Example:
+//
+//   absl::optional<int> o;
+//
+//   try {
+//     int n = o.value();
+//   } catch(const absl::bad_optional_access& e) {
+//     std::cout << "Bad optional access: " << e.what() << '\n';
+//   }
+class bad_optional_access : public std::exception {
+ public:
+  bad_optional_access() = default;
+  ~bad_optional_access() override;
+  const char* what() const noexcept override;
+};
+
+namespace optional_internal {
+
+// throw delegator
+[[noreturn]] void throw_bad_optional_access();
+
+}  // namespace optional_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_OPTIONAL
+
+#endif  // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc
new file mode 100644
index 0000000..d27d775
--- /dev/null
+++ b/absl/types/bad_variant_access.cc
@@ -0,0 +1,62 @@
+// Copyright 2017 The Abseil 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 "absl/types/bad_variant_access.h"
+
+#ifndef ABSL_HAVE_STD_VARIANT
+
+#include <cstdlib>
+#include <stdexcept>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+//////////////////////////
+// [variant.bad.access] //
+//////////////////////////
+
+bad_variant_access::~bad_variant_access() = default;
+
+const char* bad_variant_access::what() const noexcept {
+  return "Bad variant access";
+}
+
+namespace variant_internal {
+
+void ThrowBadVariantAccess() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw bad_variant_access();
+#else
+  ABSL_RAW_LOG(FATAL, "Bad variant access");
+  abort();  // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
+#endif
+}
+
+void Rethrow() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw;
+#else
+  ABSL_RAW_LOG(FATAL,
+               "Internal error in absl::variant implementation. Attempted to "
+               "rethrow an exception when building with exceptions disabled.");
+  abort();  // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
+#endif
+}
+
+}  // namespace variant_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_VARIANT
diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h
new file mode 100644
index 0000000..e7355a5
--- /dev/null
+++ b/absl/types/bad_variant_access.h
@@ -0,0 +1,78 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// bad_variant_access.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_variant_access` type.
+
+#ifndef ABSL_TYPES_BAD_VARIANT_ACCESS_H_
+#define ABSL_TYPES_BAD_VARIANT_ACCESS_H_
+
+#include <stdexcept>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_HAVE_STD_VARIANT
+
+#include <variant>
+
+namespace absl {
+using std::bad_variant_access;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_VARIANT
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// bad_variant_access
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_variant_access` type is an exception type that is thrown in
+// the following cases:
+//
+//   * Calling `absl::get(absl::variant) with an index or type that does not
+//     match the currently selected alternative type
+//   * Calling `absl::visit on an `absl::variant` that is in the
+//     `variant::valueless_by_exception` state.
+//
+// Example:
+//
+//   absl::variant<int, std::string> v;
+//   v = 1;
+//   try {
+//     absl::get<std::string>(v);
+//   } catch(const absl::bad_variant_access& e) {
+//     std::cout << "Bad variant access: " << e.what() << '\n';
+//   }
+class bad_variant_access : public std::exception {
+ public:
+  bad_variant_access() noexcept = default;
+  ~bad_variant_access() override;
+  const char* what() const noexcept override;
+};
+
+namespace variant_internal {
+
+[[noreturn]] void ThrowBadVariantAccess();
+[[noreturn]] void Rethrow();
+
+}  // namespace variant_internal
+}  // namespace absl
+
+#endif  // ABSL_HAVE_STD_VARIANT
+
+#endif  // ABSL_TYPES_BAD_VARIANT_ACCESS_H_
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
new file mode 100644
index 0000000..7db5e05
--- /dev/null
+++ b/absl/types/internal/variant.h
@@ -0,0 +1,1639 @@
+// Copyright 2017 The Abseil 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.
+//
+// Implementation details of absl/types/variant.h, pulled into a
+// separate file to avoid cluttering the top of the API header with
+// implementation details.
+
+#ifndef ABSL_TYPES_variant_internal_H_
+#define ABSL_TYPES_variant_internal_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <memory>
+#include <stdexcept>
+#include <tuple>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/identity.h"
+#include "absl/base/internal/inline_variable.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_variant_access.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+
+template <class... Types>
+class variant;
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+
+template <class T>
+struct variant_size;
+
+template <std::size_t I, class T>
+struct variant_alternative;
+
+namespace variant_internal {
+
+// NOTE: See specializations below for details.
+template <std::size_t I, class T>
+struct VariantAlternativeSfinae {};
+
+// Requires: I < variant_size_v<T>.
+//
+// Value: The Ith type of Types...
+template <std::size_t I, class T0, class... Tn>
+struct VariantAlternativeSfinae<I, variant<T0, Tn...>>
+    : VariantAlternativeSfinae<I - 1, variant<Tn...>> {};
+
+// Value: T0
+template <class T0, class... Ts>
+struct VariantAlternativeSfinae<0, variant<T0, Ts...>> {
+  using type = T0;
+};
+
+template <std::size_t I, class T>
+using VariantAlternativeSfinaeT = typename VariantAlternativeSfinae<I, T>::type;
+
+// NOTE: Requires T to be a reference type.
+template <class T, class U>
+struct GiveQualsTo;
+
+template <class T, class U>
+struct GiveQualsTo<T&, U> {
+  using type = U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<T&&, U> {
+  using type = U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<const T&, U> {
+  using type = const U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<const T&&, U> {
+  using type = const U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile T&, U> {
+  using type = volatile U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile T&&, U> {
+  using type = volatile U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile const T&, U> {
+  using type = volatile const U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile const T&&, U> {
+  using type = volatile const U&&;
+};
+
+template <class T, class U>
+using GiveQualsToT = typename GiveQualsTo<T, U>::type;
+
+// Convenience alias, since size_t integral_constant is used a lot in this file.
+template <std::size_t I>
+using SizeT = std::integral_constant<std::size_t, I>;
+
+using NPos = SizeT<variant_npos>;
+
+template <class Variant, class T, class = void>
+struct IndexOfConstructedType {};
+
+template <std::size_t I, class Variant>
+struct VariantAccessResultImpl;
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, Variantemplate<T...>&> {
+  using type = typename absl::variant_alternative<I, variant<T...>>::type&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, const Variantemplate<T...>&> {
+  using type =
+      const typename absl::variant_alternative<I, variant<T...>>::type&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, Variantemplate<T...>&&> {
+  using type = typename absl::variant_alternative<I, variant<T...>>::type&&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, const Variantemplate<T...>&&> {
+  using type =
+      const typename absl::variant_alternative<I, variant<T...>>::type&&;
+};
+
+template <std::size_t I, class Variant>
+using VariantAccessResult =
+    typename VariantAccessResultImpl<I, Variant&&>::type;
+
+// NOTE: This is used instead of std::array to reduce instantiation overhead.
+template <class T, std::size_t Size>
+struct SimpleArray {
+  static_assert(Size != 0, "");
+  T value[Size];
+};
+
+template <class T>
+struct AccessedType {
+  using type = T;
+};
+
+template <class T>
+using AccessedTypeT = typename AccessedType<T>::type;
+
+template <class T, std::size_t Size>
+struct AccessedType<SimpleArray<T, Size>> {
+  using type = AccessedTypeT<T>;
+};
+
+template <class T>
+constexpr T AccessSimpleArray(const T& value) {
+  return value;
+}
+
+template <class T, std::size_t Size, class... SizeT>
+constexpr AccessedTypeT<T> AccessSimpleArray(const SimpleArray<T, Size>& table,
+                                             std::size_t head_index,
+                                             SizeT... tail_indices) {
+  return AccessSimpleArray(table.value[head_index], tail_indices...);
+}
+
+// Note: Intentionally is an alias.
+template <class T>
+using AlwaysZero = SizeT<0>;
+
+template <class Op, class... Vs>
+struct VisitIndicesResultImpl {
+  using type = absl::result_of_t<Op(AlwaysZero<Vs>...)>;
+};
+
+template <class Op, class... Vs>
+using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type;
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+          std::size_t... BoundIndices>
+struct MakeVisitationMatrix;
+
+template <class ReturnType, class FunctionObject, std::size_t... Indices>
+constexpr ReturnType call_with_indices(FunctionObject&& function) {
+  static_assert(
+      std::is_same<ReturnType, decltype(std::declval<FunctionObject>()(
+                                   SizeT<Indices>()...))>::value,
+      "Not all visitation overloads have the same return type.");
+  return absl::forward<FunctionObject>(function)(SizeT<Indices>()...);
+}
+
+template <class ReturnType, class FunctionObject, std::size_t... BoundIndices>
+struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>,
+                            BoundIndices...> {
+  using ResultType = ReturnType (*)(FunctionObject&&);
+  static constexpr ResultType Run() {
+    return &call_with_indices<ReturnType, FunctionObject,
+                              (BoundIndices - 1)...>;
+  }
+};
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+          class CurrIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrixImpl;
+
+template <class ReturnType, class FunctionObject, std::size_t... EndIndices,
+          std::size_t... CurrIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrixImpl<
+    ReturnType, FunctionObject, index_sequence<EndIndices...>,
+    index_sequence<CurrIndices...>, BoundIndices...> {
+  using ResultType = SimpleArray<
+      typename MakeVisitationMatrix<ReturnType, FunctionObject,
+                                    index_sequence<EndIndices...>>::ResultType,
+      sizeof...(CurrIndices)>;
+
+  static constexpr ResultType Run() {
+    return {{MakeVisitationMatrix<ReturnType, FunctionObject,
+                                  index_sequence<EndIndices...>,
+                                  BoundIndices..., CurrIndices>::Run()...}};
+  }
+};
+
+template <class ReturnType, class FunctionObject, std::size_t HeadEndIndex,
+          std::size_t... TailEndIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrix<ReturnType, FunctionObject,
+                            index_sequence<HeadEndIndex, TailEndIndices...>,
+                            BoundIndices...>
+    : MakeVisitationMatrixImpl<
+          ReturnType, FunctionObject, index_sequence<TailEndIndices...>,
+          absl::make_index_sequence<HeadEndIndex>, BoundIndices...> {};
+
+struct UnreachableSwitchCase {
+  template <class Op>
+  [[noreturn]] static VisitIndicesResultT<Op, std::size_t> Run(
+      Op&& /*ignored*/) {
+#if ABSL_HAVE_BUILTIN(__builtin_unreachable) || \
+    (defined(__GNUC__) && !defined(__clang__))
+    __builtin_unreachable();
+#elif defined(_MSC_VER)
+    __assume(false);
+#else
+    // Try to use assert of false being identified as an unreachable intrinsic.
+    // NOTE: We use assert directly to increase chances of exploiting an assume
+    //       intrinsic.
+    assert(false);  // NOLINT
+
+    // Hack to silence potential no return warning -- cause an infinite loop.
+    return Run(absl::forward<Op>(op));
+#endif  // Checks for __builtin_unreachable
+  }
+};
+
+template <class Op, std::size_t I>
+struct ReachableSwitchCase {
+  static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) {
+    return absl::base_internal::Invoke(absl::forward<Op>(op), SizeT<I>());
+  }
+};
+
+// The number 33 is just a guess at a reasonable maximum to our switch. It is
+// not based on any analysis. The reason it is a power of 2 plus 1 instead of a
+// power of 2 is because the number was picked to correspond to a power of 2
+// amount of "normal" alternatives, plus one for the possibility of the user
+// providing "monostate" in addition to the more natural alternatives.
+ABSL_INTERNAL_INLINE_CONSTEXPR(std::size_t, MaxUnrolledVisitCases, 33);
+
+// Note: The default-definition is for unreachable cases.
+template <bool IsReachable>
+struct PickCaseImpl {
+  template <class Op, std::size_t I>
+  using Apply = UnreachableSwitchCase;
+};
+
+template <>
+struct PickCaseImpl</*IsReachable =*/true> {
+  template <class Op, std::size_t I>
+  using Apply = ReachableSwitchCase<Op, I>;
+};
+
+// Note: This form of dance with template aliases is to make sure that we
+//       instantiate a number of templates proportional to the number of variant
+//       alternatives rather than a number of templates proportional to our
+//       maximum unrolled amount of visitation cases (aliases are effectively
+//       "free" whereas other template instantiations are costly).
+template <class Op, std::size_t I, std::size_t EndIndex>
+using PickCase = typename PickCaseImpl<(I < EndIndex)>::template Apply<Op, I>;
+
+template <class ReturnType>
+[[noreturn]] ReturnType TypedThrowBadVariantAccess() {
+  absl::variant_internal::ThrowBadVariantAccess();
+}
+
+// Given N variant sizes, determine the number of cases there would need to be
+// in a single switch-statement that would cover every possibility in the
+// corresponding N-ary visit operation.
+template <std::size_t... NumAlternatives>
+struct NumCasesOfSwitch;
+
+template <std::size_t HeadNumAlternatives, std::size_t... TailNumAlternatives>
+struct NumCasesOfSwitch<HeadNumAlternatives, TailNumAlternatives...> {
+  static constexpr std::size_t value =
+      (HeadNumAlternatives + 1) *
+      NumCasesOfSwitch<TailNumAlternatives...>::value;
+};
+
+template <>
+struct NumCasesOfSwitch<> {
+  static constexpr std::size_t value = 1;
+};
+
+// A switch statement optimizes better than the table of function pointers.
+template <std::size_t EndIndex>
+struct VisitIndicesSwitch {
+  static_assert(EndIndex <= MaxUnrolledVisitCases,
+                "Maximum unrolled switch size exceeded.");
+
+  template <class Op>
+  static VisitIndicesResultT<Op, std::size_t> Run(Op&& op, std::size_t i) {
+    switch (i) {
+      case 0:
+        return PickCase<Op, 0, EndIndex>::Run(absl::forward<Op>(op));
+      case 1:
+        return PickCase<Op, 1, EndIndex>::Run(absl::forward<Op>(op));
+      case 2:
+        return PickCase<Op, 2, EndIndex>::Run(absl::forward<Op>(op));
+      case 3:
+        return PickCase<Op, 3, EndIndex>::Run(absl::forward<Op>(op));
+      case 4:
+        return PickCase<Op, 4, EndIndex>::Run(absl::forward<Op>(op));
+      case 5:
+        return PickCase<Op, 5, EndIndex>::Run(absl::forward<Op>(op));
+      case 6:
+        return PickCase<Op, 6, EndIndex>::Run(absl::forward<Op>(op));
+      case 7:
+        return PickCase<Op, 7, EndIndex>::Run(absl::forward<Op>(op));
+      case 8:
+        return PickCase<Op, 8, EndIndex>::Run(absl::forward<Op>(op));
+      case 9:
+        return PickCase<Op, 9, EndIndex>::Run(absl::forward<Op>(op));
+      case 10:
+        return PickCase<Op, 10, EndIndex>::Run(absl::forward<Op>(op));
+      case 11:
+        return PickCase<Op, 11, EndIndex>::Run(absl::forward<Op>(op));
+      case 12:
+        return PickCase<Op, 12, EndIndex>::Run(absl::forward<Op>(op));
+      case 13:
+        return PickCase<Op, 13, EndIndex>::Run(absl::forward<Op>(op));
+      case 14:
+        return PickCase<Op, 14, EndIndex>::Run(absl::forward<Op>(op));
+      case 15:
+        return PickCase<Op, 15, EndIndex>::Run(absl::forward<Op>(op));
+      case 16:
+        return PickCase<Op, 16, EndIndex>::Run(absl::forward<Op>(op));
+      case 17:
+        return PickCase<Op, 17, EndIndex>::Run(absl::forward<Op>(op));
+      case 18:
+        return PickCase<Op, 18, EndIndex>::Run(absl::forward<Op>(op));
+      case 19:
+        return PickCase<Op, 19, EndIndex>::Run(absl::forward<Op>(op));
+      case 20:
+        return PickCase<Op, 20, EndIndex>::Run(absl::forward<Op>(op));
+      case 21:
+        return PickCase<Op, 21, EndIndex>::Run(absl::forward<Op>(op));
+      case 22:
+        return PickCase<Op, 22, EndIndex>::Run(absl::forward<Op>(op));
+      case 23:
+        return PickCase<Op, 23, EndIndex>::Run(absl::forward<Op>(op));
+      case 24:
+        return PickCase<Op, 24, EndIndex>::Run(absl::forward<Op>(op));
+      case 25:
+        return PickCase<Op, 25, EndIndex>::Run(absl::forward<Op>(op));
+      case 26:
+        return PickCase<Op, 26, EndIndex>::Run(absl::forward<Op>(op));
+      case 27:
+        return PickCase<Op, 27, EndIndex>::Run(absl::forward<Op>(op));
+      case 28:
+        return PickCase<Op, 28, EndIndex>::Run(absl::forward<Op>(op));
+      case 29:
+        return PickCase<Op, 29, EndIndex>::Run(absl::forward<Op>(op));
+      case 30:
+        return PickCase<Op, 30, EndIndex>::Run(absl::forward<Op>(op));
+      case 31:
+        return PickCase<Op, 31, EndIndex>::Run(absl::forward<Op>(op));
+      case 32:
+        return PickCase<Op, 32, EndIndex>::Run(absl::forward<Op>(op));
+      default:
+        ABSL_ASSERT(i == variant_npos);
+        return absl::base_internal::Invoke(absl::forward<Op>(op), NPos());
+    }
+  }
+};
+
+template <std::size_t... EndIndices>
+struct VisitIndicesFallback {
+  template <class Op, class... SizeT>
+  static VisitIndicesResultT<Op, SizeT...> Run(Op&& op, SizeT... indices) {
+    return AccessSimpleArray(
+        MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op,
+                             index_sequence<(EndIndices + 1)...>>::Run(),
+        (indices + 1)...)(absl::forward<Op>(op));
+  }
+};
+
+// Take an N-dimensional series of indices and convert them into a single index
+// without loss of information. The purpose of this is to be able to convert an
+// N-ary visit operation into a single switch statement.
+template <std::size_t...>
+struct FlattenIndices;
+
+template <std::size_t HeadSize, std::size_t... TailSize>
+struct FlattenIndices<HeadSize, TailSize...> {
+  template<class... SizeType>
+  static constexpr std::size_t Run(std::size_t head, SizeType... tail) {
+    return head + HeadSize * FlattenIndices<TailSize...>::Run(tail...);
+  }
+};
+
+template <>
+struct FlattenIndices<> {
+  static constexpr std::size_t Run() { return 0; }
+};
+
+// Take a single "flattened" index (flattened by FlattenIndices) and determine
+// the value of the index of one of the logically represented dimensions.
+template <std::size_t I, std::size_t IndexToGet, std::size_t HeadSize,
+          std::size_t... TailSize>
+struct UnflattenIndex {
+  static constexpr std::size_t value =
+      UnflattenIndex<I / HeadSize, IndexToGet - 1, TailSize...>::value;
+};
+
+template <std::size_t I, std::size_t HeadSize, std::size_t... TailSize>
+struct UnflattenIndex<I, 0, HeadSize, TailSize...> {
+  static constexpr std::size_t value = (I % HeadSize);
+};
+
+// The backend for converting an N-ary visit operation into a unary visit.
+template <class IndexSequence, std::size_t... EndIndices>
+struct VisitIndicesVariadicImpl;
+
+template <std::size_t... N, std::size_t... EndIndices>
+struct VisitIndicesVariadicImpl<absl::index_sequence<N...>, EndIndices...> {
+  // A type that can take an N-ary function object and converts it to a unary
+  // function object that takes a single, flattened index, and "unflattens" it
+  // into its individual dimensions when forwarding to the wrapped object.
+  template <class Op>
+  struct FlattenedOp {
+    template <std::size_t I>
+    VisitIndicesResultT<Op, decltype(EndIndices)...> operator()(
+        SizeT<I> /*index*/) && {
+      return base_internal::Invoke(
+          absl::forward<Op>(op),
+          SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value -
+                std::size_t{1}>()...);
+    }
+
+    Op&& op;
+  };
+
+  template <class Op, class... SizeType>
+  static VisitIndicesResultT<Op, decltype(EndIndices)...> Run(
+      Op&& op, SizeType... i) {
+    return VisitIndicesSwitch<NumCasesOfSwitch<EndIndices...>::value>::Run(
+        FlattenedOp<Op>{absl::forward<Op>(op)},
+        FlattenIndices<(EndIndices + std::size_t{1})...>::Run(
+            (i + std::size_t{1})...));
+  }
+};
+
+template <std::size_t... EndIndices>
+struct VisitIndicesVariadic
+    : VisitIndicesVariadicImpl<absl::make_index_sequence<sizeof...(EndIndices)>,
+                               EndIndices...> {};
+
+// This implementation will flatten N-ary visit operations into a single switch
+// statement when the number of cases would be less than our maximum specified
+// switch-statement size.
+// TODO(calabrese)
+//   Based on benchmarks, determine whether the function table approach actually
+//   does optimize better than a chain of switch statements and possibly update
+//   the implementation accordingly. Also consider increasing the maximum switch
+//   size.
+template <std::size_t... EndIndices>
+struct VisitIndices
+    : absl::conditional_t<(NumCasesOfSwitch<EndIndices...>::value <=
+                           MaxUnrolledVisitCases),
+                          VisitIndicesVariadic<EndIndices...>,
+                          VisitIndicesFallback<EndIndices...>> {};
+
+template <std::size_t EndIndex>
+struct VisitIndices<EndIndex>
+    : absl::conditional_t<(EndIndex <= MaxUnrolledVisitCases),
+                          VisitIndicesSwitch<EndIndex>,
+                          VisitIndicesFallback<EndIndex>> {};
+
+// Suppress bogus warning on MSVC: MSVC complains that the `reinterpret_cast`
+// below is returning the address of a temporary or local object.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4172)
+#endif  // _MSC_VER
+
+// TODO(calabrese) std::launder
+// TODO(calabrese) constexpr
+// NOTE: DO NOT REMOVE the `inline` keyword as it is necessary to work around a
+// MSVC bug. See https://github.com/abseil/abseil-cpp/issues/129 for details.
+template <class Self, std::size_t I>
+inline VariantAccessResult<I, Self> AccessUnion(Self&& self, SizeT<I> /*i*/) {
+  return reinterpret_cast<VariantAccessResult<I, Self>>(self);
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+template <class T>
+void DeducedDestroy(T& self) {  // NOLINT
+  self.~T();
+}
+
+// NOTE: This type exists as a single entity for variant and its bases to
+// befriend. It contains helper functionality that manipulates the state of the
+// variant, such as the implementation of things like assignment and emplace
+// operations.
+struct VariantCoreAccess {
+  template <class VariantType>
+  static typename VariantType::Variant& Derived(VariantType& self) {  // NOLINT
+    return static_cast<typename VariantType::Variant&>(self);
+  }
+
+  template <class VariantType>
+  static const typename VariantType::Variant& Derived(
+      const VariantType& self) {  // NOLINT
+    return static_cast<const typename VariantType::Variant&>(self);
+  }
+
+  template <class VariantType>
+  static void Destroy(VariantType& self) {  // NOLINT
+    Derived(self).destroy();
+    self.index_ = absl::variant_npos;
+  }
+
+  template <class Variant>
+  static void SetIndex(Variant& self, std::size_t i) {  // NOLINT
+    self.index_ = i;
+  }
+
+  template <class Variant>
+  static void InitFrom(Variant& self, Variant&& other) {  // NOLINT
+    VisitIndices<absl::variant_size<Variant>::value>::Run(
+        InitFromVisitor<Variant, Variant&&>{&self,
+                                            std::forward<Variant>(other)},
+        other.index());
+    self.index_ = other.index();
+  }
+
+  // Access a variant alternative, assuming the index is correct.
+  template <std::size_t I, class Variant>
+  static VariantAccessResult<I, Variant> Access(Variant&& self) {
+    // This cast instead of invocation of AccessUnion with an rvalue is a
+    // workaround for msvc. Without this there is a runtime failure when dealing
+    // with rvalues.
+    // TODO(calabrese) Reduce test case and find a simpler workaround.
+    return static_cast<VariantAccessResult<I, Variant>>(
+        variant_internal::AccessUnion(self.state_, SizeT<I>()));
+  }
+
+  // Access a variant alternative, throwing if the index is incorrect.
+  template <std::size_t I, class Variant>
+  static VariantAccessResult<I, Variant> CheckedAccess(Variant&& self) {
+    if (ABSL_PREDICT_FALSE(self.index_ != I)) {
+      TypedThrowBadVariantAccess<VariantAccessResult<I, Variant>>();
+    }
+
+    return Access<I>(absl::forward<Variant>(self));
+  }
+
+  // The implementation of the move-assignment operation for a variant.
+  template <class VType>
+  struct MoveAssignVisitor {
+    using DerivedType = typename VType::Variant;
+    template <std::size_t NewIndex>
+    void operator()(SizeT<NewIndex> /*new_i*/) const {
+      if (left->index_ == NewIndex) {
+        Access<NewIndex>(*left) = std::move(Access<NewIndex>(*right));
+      } else {
+        Derived(*left).template emplace<NewIndex>(
+            std::move(Access<NewIndex>(*right)));
+      }
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+      Destroy(*left);
+    }
+
+    VType* left;
+    VType* right;
+  };
+
+  template <class VType>
+  static MoveAssignVisitor<VType> MakeMoveAssignVisitor(VType* left,
+                                                        VType* other) {
+    return {left, other};
+  }
+
+  // The implementation of the assignment operation for a variant.
+  template <class VType>
+  struct CopyAssignVisitor {
+    using DerivedType = typename VType::Variant;
+    template <std::size_t NewIndex>
+    void operator()(SizeT<NewIndex> /*new_i*/) const {
+      using New =
+          typename absl::variant_alternative<NewIndex, DerivedType>::type;
+
+      if (left->index_ == NewIndex) {
+        Access<NewIndex>(*left) = Access<NewIndex>(*right);
+      } else if (std::is_nothrow_copy_constructible<New>::value ||
+                 !std::is_nothrow_move_constructible<New>::value) {
+        Derived(*left).template emplace<NewIndex>(Access<NewIndex>(*right));
+      } else {
+        Derived(*left) = DerivedType(Derived(*right));
+      }
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+      Destroy(*left);
+    }
+
+    VType* left;
+    const VType* right;
+  };
+
+  template <class VType>
+  static CopyAssignVisitor<VType> MakeCopyAssignVisitor(VType* left,
+                                                        const VType& other) {
+    return {left, &other};
+  }
+
+  // The implementation of conversion-assignment operations for variant.
+  template <class Left, class QualifiedNew>
+  struct ConversionAssignVisitor {
+    using NewIndex =
+        variant_internal::IndexOfConstructedType<Left, QualifiedNew>;
+
+    void operator()(SizeT<NewIndex::value> /*old_i*/
+                    ) const {
+      Access<NewIndex::value>(*left) = absl::forward<QualifiedNew>(other);
+    }
+
+    template <std::size_t OldIndex>
+    void operator()(SizeT<OldIndex> /*old_i*/
+                    ) const {
+      using New =
+          typename absl::variant_alternative<NewIndex::value, Left>::type;
+      if (std::is_nothrow_constructible<New, QualifiedNew>::value ||
+          !std::is_nothrow_move_constructible<New>::value) {
+        left->template emplace<NewIndex::value>(
+            absl::forward<QualifiedNew>(other));
+      } else {
+        // the standard says "equivalent to
+        // operator=(variant(std::forward<T>(t)))", but we use `emplace` here
+        // because the variant's move assignment operator could be deleted.
+        left->template emplace<NewIndex::value>(
+            New(absl::forward<QualifiedNew>(other)));
+      }
+    }
+
+    Left* left;
+    QualifiedNew&& other;
+  };
+
+  template <class Left, class QualifiedNew>
+  static ConversionAssignVisitor<Left, QualifiedNew>
+  MakeConversionAssignVisitor(Left* left, QualifiedNew&& qual) {
+    return {left, absl::forward<QualifiedNew>(qual)};
+  }
+
+  // Backend for operations for `emplace()` which destructs `*self` then
+  // construct a new alternative with `Args...`.
+  template <std::size_t NewIndex, class Self, class... Args>
+  static typename absl::variant_alternative<NewIndex, Self>::type& Replace(
+      Self* self, Args&&... args) {
+    Destroy(*self);
+    using New = typename absl::variant_alternative<NewIndex, Self>::type;
+    New* const result = ::new (static_cast<void*>(&self->state_))
+        New(absl::forward<Args>(args)...);
+    self->index_ = NewIndex;
+    return *result;
+  }
+
+  template <class LeftVariant, class QualifiedRightVariant>
+  struct InitFromVisitor {
+    template <std::size_t NewIndex>
+    void operator()(SizeT<NewIndex> /*new_i*/) const {
+      using Alternative =
+          typename variant_alternative<NewIndex, LeftVariant>::type;
+      ::new (static_cast<void*>(&left->state_)) Alternative(
+          Access<NewIndex>(std::forward<QualifiedRightVariant>(right)));
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+      // This space intentionally left blank.
+    }
+    LeftVariant* left;
+    QualifiedRightVariant&& right;
+  };
+};
+
+template <class Expected, class... T>
+struct IndexOfImpl;
+
+template <class Expected>
+struct IndexOfImpl<Expected> {
+  using IndexFromEnd = SizeT<0>;
+  using MatchedIndexFromEnd = IndexFromEnd;
+  using MultipleMatches = std::false_type;
+};
+
+template <class Expected, class Head, class... Tail>
+struct IndexOfImpl<Expected, Head, Tail...> : IndexOfImpl<Expected, Tail...> {
+  using IndexFromEnd =
+      SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
+};
+
+template <class Expected, class... Tail>
+struct IndexOfImpl<Expected, Expected, Tail...>
+    : IndexOfImpl<Expected, Tail...> {
+  using IndexFromEnd =
+      SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
+  using MatchedIndexFromEnd = IndexFromEnd;
+  using MultipleMatches = std::integral_constant<
+      bool, IndexOfImpl<Expected, Tail...>::MatchedIndexFromEnd::value != 0>;
+};
+
+template <class Expected, class... Types>
+struct IndexOfMeta {
+  using Results = IndexOfImpl<Expected, Types...>;
+  static_assert(!Results::MultipleMatches::value,
+                "Attempted to access a variant by specifying a type that "
+                "matches more than one alternative.");
+  static_assert(Results::MatchedIndexFromEnd::value != 0,
+                "Attempted to access a variant by specifying a type that does "
+                "not match any alternative.");
+  using type = SizeT<sizeof...(Types) - Results::MatchedIndexFromEnd::value>;
+};
+
+template <class Expected, class... Types>
+using IndexOf = typename IndexOfMeta<Expected, Types...>::type;
+
+template <class Variant, class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl;
+
+// Terminating case encountered once we've checked all of the alternatives
+template <class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<>, T, CurrIndex> : SizeT<CurrIndex> {};
+
+// Case where T is not Head
+template <class Head, class... Tail, class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, T, CurrIndex>
+    : UnambiguousIndexOfImpl<variant<Tail...>, T, CurrIndex + 1>::type {};
+
+// Case where T is Head
+template <class Head, class... Tail, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, Head, CurrIndex>
+    : SizeT<UnambiguousIndexOfImpl<variant<Tail...>, Head, 0>::value ==
+                    sizeof...(Tail)
+                ? CurrIndex
+                : CurrIndex + sizeof...(Tail) + 1> {};
+
+template <class Variant, class T>
+struct UnambiguousIndexOf;
+
+struct NoMatch {
+  struct type {};
+};
+
+template <class... Alts, class T>
+struct UnambiguousIndexOf<variant<Alts...>, T>
+    : std::conditional<UnambiguousIndexOfImpl<variant<Alts...>, T, 0>::value !=
+                           sizeof...(Alts),
+                       UnambiguousIndexOfImpl<variant<Alts...>, T, 0>,
+                       NoMatch>::type::type {};
+
+template <class T, std::size_t /*Dummy*/>
+using UnambiguousTypeOfImpl = T;
+
+template <class Variant, class T>
+using UnambiguousTypeOfT =
+    UnambiguousTypeOfImpl<T, UnambiguousIndexOf<Variant, T>::value>;
+
+template <class H, class... T>
+class VariantStateBase;
+
+// This is an implementation of the "imaginary function" that is described in
+// [variant.ctor]
+// It is used in order to determine which alternative to construct during
+// initialization from some type T.
+template <class Variant, std::size_t I = 0>
+struct ImaginaryFun;
+
+template <std::size_t I>
+struct ImaginaryFun<variant<>, I> {
+  static void Run() = delete;
+};
+
+template <class H, class... T, std::size_t I>
+struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> {
+  using ImaginaryFun<variant<T...>, I + 1>::Run;
+
+  // NOTE: const& and && are used instead of by-value due to lack of guaranteed
+  // move elision of C++17. This may have other minor differences, but tests
+  // pass.
+  static SizeT<I> Run(const H&);
+  static SizeT<I> Run(H&&);
+};
+
+// The following metafunctions are used in constructor and assignment
+// constraints.
+template <class Self, class T>
+struct IsNeitherSelfNorInPlace : std::true_type {};
+
+template <class Self>
+struct IsNeitherSelfNorInPlace<Self, Self> : std::false_type {};
+
+template <class Self, class T>
+struct IsNeitherSelfNorInPlace<Self, in_place_type_t<T>> : std::false_type {};
+
+template <class Self, std::size_t I>
+struct IsNeitherSelfNorInPlace<Self, in_place_index_t<I>> : std::false_type {};
+
+template <class Variant, class T, class = void>
+struct ConversionIsPossibleImpl : std::false_type {};
+
+template <class Variant, class T>
+struct ConversionIsPossibleImpl<
+    Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+    : std::true_type {};
+
+template <class Variant, class T>
+struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::type {};
+
+template <class Variant, class T>
+struct IndexOfConstructedType<
+    Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+    : decltype(ImaginaryFun<Variant>::Run(std::declval<T>())) {};
+
+template <std::size_t... Is>
+struct ContainsVariantNPos
+    : absl::negation<std::is_same<  // NOLINT
+          absl::integer_sequence<bool, 0 <= Is...>,
+          absl::integer_sequence<bool, Is != absl::variant_npos...>>> {};
+
+template <class Op, class... QualifiedVariants>
+using RawVisitResult =
+    absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
+
+// NOTE: The spec requires that all return-paths yield the same type and is not
+// SFINAE-friendly, so we can deduce the return type by examining the first
+// result. If it's not callable, then we get an error, but are compliant and
+// fast to compile.
+// TODO(calabrese) Possibly rewrite in a way that yields better compile errors
+// at the cost of longer compile-times.
+template <class Op, class... QualifiedVariants>
+struct VisitResultImpl {
+  using type =
+      absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
+};
+
+// Done in two steps intentionally so that we don't cause substitution to fail.
+template <class Op, class... QualifiedVariants>
+using VisitResult = typename VisitResultImpl<Op, QualifiedVariants...>::type;
+
+template <class Op, class... QualifiedVariants>
+struct PerformVisitation {
+  using ReturnType = VisitResult<Op, QualifiedVariants...>;
+
+  template <std::size_t... Is>
+  constexpr ReturnType operator()(SizeT<Is>... indices) const {
+    return Run(typename ContainsVariantNPos<Is...>::type{},
+               absl::index_sequence_for<QualifiedVariants...>(), indices...);
+  }
+
+  template <std::size_t... TupIs, std::size_t... Is>
+  constexpr ReturnType Run(std::false_type /*has_valueless*/,
+                           index_sequence<TupIs...>, SizeT<Is>...) const {
+    return absl::base_internal::Invoke(
+        absl::forward<Op>(op),
+        VariantCoreAccess::Access<Is>(
+            absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...);
+  }
+
+  template <std::size_t... TupIs, std::size_t... Is>
+  [[noreturn]] ReturnType Run(std::true_type /*has_valueless*/,
+                              index_sequence<TupIs...>, SizeT<Is>...) const {
+    absl::variant_internal::ThrowBadVariantAccess();
+  }
+
+  // TODO(calabrese) Avoid using a tuple, which causes lots of instantiations
+  // Attempts using lambda variadic captures fail on current GCC.
+  std::tuple<QualifiedVariants&&...> variant_tup;
+  Op&& op;
+};
+
+template <class... T>
+union Union;
+
+// We want to allow for variant<> to be trivial. For that, we need the default
+// constructor to be trivial, which means we can't define it ourselves.
+// Instead, we use a non-default constructor that takes NoopConstructorTag
+// that doesn't affect the triviality of the types.
+struct NoopConstructorTag {};
+
+template <std::size_t I>
+struct EmplaceTag {};
+
+template <>
+union Union<> {
+  constexpr explicit Union(NoopConstructorTag) noexcept {}
+};
+
+// Suppress bogus warning on MSVC: MSVC complains that Union<T...> has a defined
+// deleted destructor from the `std::is_destructible` check below.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif  // _MSC_VER
+
+template <class Head, class... Tail>
+union Union<Head, Tail...> {
+  using TailUnion = Union<Tail...>;
+
+  explicit constexpr Union(NoopConstructorTag /*tag*/) noexcept
+      : tail(NoopConstructorTag()) {}
+
+  template <class... P>
+  explicit constexpr Union(EmplaceTag<0>, P&&... args)
+      : head(absl::forward<P>(args)...) {}
+
+  template <std::size_t I, class... P>
+  explicit constexpr Union(EmplaceTag<I>, P&&... args)
+      : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {}
+
+  Head head;
+  TailUnion tail;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+// TODO(calabrese) Just contain a Union in this union (certain configs fail).
+template <class... T>
+union DestructibleUnionImpl;
+
+template <>
+union DestructibleUnionImpl<> {
+  constexpr explicit DestructibleUnionImpl(NoopConstructorTag) noexcept {}
+};
+
+template <class Head, class... Tail>
+union DestructibleUnionImpl<Head, Tail...> {
+  using TailUnion = DestructibleUnionImpl<Tail...>;
+
+  explicit constexpr DestructibleUnionImpl(NoopConstructorTag /*tag*/) noexcept
+      : tail(NoopConstructorTag()) {}
+
+  template <class... P>
+  explicit constexpr DestructibleUnionImpl(EmplaceTag<0>, P&&... args)
+      : head(absl::forward<P>(args)...) {}
+
+  template <std::size_t I, class... P>
+  explicit constexpr DestructibleUnionImpl(EmplaceTag<I>, P&&... args)
+      : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {}
+
+  ~DestructibleUnionImpl() {}
+
+  Head head;
+  TailUnion tail;
+};
+
+// This union type is destructible even if one or more T are not trivially
+// destructible. In the case that all T are trivially destructible, then so is
+// this resultant type.
+template <class... T>
+using DestructibleUnion =
+    absl::conditional_t<std::is_destructible<Union<T...>>::value, Union<T...>,
+                        DestructibleUnionImpl<T...>>;
+
+// Deepest base, containing the actual union and the discriminator
+template <class H, class... T>
+class VariantStateBase {
+ protected:
+  using Variant = variant<H, T...>;
+
+  template <class LazyH = H,
+            class ConstructibleH = absl::enable_if_t<
+                std::is_default_constructible<LazyH>::value, LazyH>>
+  constexpr VariantStateBase() noexcept(
+      std::is_nothrow_default_constructible<ConstructibleH>::value)
+      : state_(EmplaceTag<0>()), index_(0) {}
+
+  template <std::size_t I, class... P>
+  explicit constexpr VariantStateBase(EmplaceTag<I> tag, P&&... args)
+      : state_(tag, absl::forward<P>(args)...), index_(I) {}
+
+  explicit constexpr VariantStateBase(NoopConstructorTag)
+      : state_(NoopConstructorTag()), index_(variant_npos) {}
+
+  void destroy() {}  // Does nothing (shadowed in child if non-trivial)
+
+  DestructibleUnion<H, T...> state_;
+  std::size_t index_;
+};
+
+using absl::internal::identity;
+
+// OverloadSet::Overload() is a unary function which is overloaded to
+// take any of the element types of the variant, by reference-to-const.
+// The return type of the overload on T is identity<T>, so that you
+// can statically determine which overload was called.
+//
+// Overload() is not defined, so it can only be called in unevaluated
+// contexts.
+template <typename... Ts>
+struct OverloadSet;
+
+template <typename T, typename... Ts>
+struct OverloadSet<T, Ts...> : OverloadSet<Ts...> {
+  using Base = OverloadSet<Ts...>;
+  static identity<T> Overload(const T&);
+  using Base::Overload;
+};
+
+template <>
+struct OverloadSet<> {
+  // For any case not handled above.
+  static void Overload(...);
+};
+
+////////////////////////////////
+// Library Fundamentals V2 TS //
+////////////////////////////////
+
+// TODO(calabrese): Consider moving this to absl/meta/type_traits.h
+
+// The following is a rough implementation of parts of the detection idiom.
+// It is used for the comparison operator checks.
+
+template <class Enabler, class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl {
+  using type = std::false_type;
+};
+
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl<
+    absl::enable_if_t<std::is_convertible<Op<Args...>, To>::value>, To, Op,
+    Args...> {
+  using type = std::true_type;
+};
+
+// NOTE: This differs from library fundamentals by being lazy.
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible
+    : is_detected_convertible_impl<void, To, Op, Args...>::type {};
+
+template <class T>
+using LessThanResult = decltype(std::declval<T>() < std::declval<T>());
+
+template <class T>
+using GreaterThanResult = decltype(std::declval<T>() > std::declval<T>());
+
+template <class T>
+using LessThanOrEqualResult = decltype(std::declval<T>() <= std::declval<T>());
+
+template <class T>
+using GreaterThanOrEqualResult =
+    decltype(std::declval<T>() >= std::declval<T>());
+
+template <class T>
+using EqualResult = decltype(std::declval<T>() == std::declval<T>());
+
+template <class T>
+using NotEqualResult = decltype(std::declval<T>() != std::declval<T>());
+
+template <class... T>
+using RequireAllHaveEqualT = absl::enable_if_t<
+    absl::conjunction<is_detected_convertible<bool, EqualResult, T>...>::value,
+    bool>;
+
+template <class... T>
+using RequireAllHaveNotEqualT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, NotEqualResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveLessThanT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, LessThanResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveLessThanOrEqualT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, LessThanOrEqualResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveGreaterThanOrEqualT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, GreaterThanOrEqualResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveGreaterThanT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, GreaterThanResult, T>...>::value,
+                      bool>;
+
+// Helper template containing implementations details of variant that can't go
+// in the private section. For convenience, this takes the variant type as a
+// single template parameter.
+template <typename T>
+struct VariantHelper;
+
+template <typename... Ts>
+struct VariantHelper<variant<Ts...>> {
+  // Type metafunction which returns the element type selected if
+  // OverloadSet::Overload() is well-formed when called with argument type U.
+  template <typename U>
+  using BestMatch = decltype(
+      variant_internal::OverloadSet<Ts...>::Overload(std::declval<U>()));
+
+  // Type metafunction which returns true if OverloadSet::Overload() is
+  // well-formed when called with argument type U.
+  // CanAccept can't be just an alias because there is a MSVC bug on parameter
+  // pack expansion involving decltype.
+  template <typename U>
+  struct CanAccept :
+      std::integral_constant<bool, !std::is_void<BestMatch<U>>::value> {};
+
+  // Type metafunction which returns true if Other is an instantiation of
+  // variant, and variants's converting constructor from Other will be
+  // well-formed. We will use this to remove constructors that would be
+  // ill-formed from the overload set.
+  template <typename Other>
+  struct CanConvertFrom;
+
+  template <typename... Us>
+  struct CanConvertFrom<variant<Us...>>
+      : public absl::conjunction<CanAccept<Us>...> {};
+};
+
+// A type with nontrivial copy ctor and trivial move ctor.
+struct TrivialMoveOnly {
+  TrivialMoveOnly(TrivialMoveOnly&&) = default;
+};
+
+// Trait class to detect whether a type is trivially move constructible.
+// A union's defaulted copy/move constructor is deleted if any variant member's
+// copy/move constructor is nontrivial.
+template <typename T>
+struct IsTriviallyMoveConstructible:
+  std::is_move_constructible<Union<T, TrivialMoveOnly>> {};
+
+// To guarantee triviality of all special-member functions that can be trivial,
+// we use a chain of conditional bases for each one.
+// The order of inheritance of bases from child to base are logically:
+//
+// variant
+// VariantCopyAssignBase
+// VariantMoveAssignBase
+// VariantCopyBase
+// VariantMoveBase
+// VariantStateBaseDestructor
+// VariantStateBase
+//
+// Note that there is a separate branch at each base that is dependent on
+// whether or not that corresponding special-member-function can be trivial in
+// the resultant variant type.
+
+template <class... T>
+class VariantStateBaseDestructorNontrivial;
+
+template <class... T>
+class VariantMoveBaseNontrivial;
+
+template <class... T>
+class VariantCopyBaseNontrivial;
+
+template <class... T>
+class VariantMoveAssignBaseNontrivial;
+
+template <class... T>
+class VariantCopyAssignBaseNontrivial;
+
+// Base that is dependent on whether or not the destructor can be trivial.
+template <class... T>
+using VariantStateBaseDestructor =
+    absl::conditional_t<std::is_destructible<Union<T...>>::value,
+                        VariantStateBase<T...>,
+                        VariantStateBaseDestructorNontrivial<T...>>;
+
+// Base that is dependent on whether or not the move-constructor can be
+// implicitly generated by the compiler (trivial or deleted).
+// Previously we were using `std::is_move_constructible<Union<T...>>` to check
+// whether all Ts have trivial move constructor, but it ran into a GCC bug:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84866
+// So we have to use a different approach (i.e. `HasTrivialMoveConstructor`) to
+// work around the bug.
+template <class... T>
+using VariantMoveBase = absl::conditional_t<
+    absl::disjunction<
+        absl::negation<absl::conjunction<std::is_move_constructible<T>...>>,
+        absl::conjunction<IsTriviallyMoveConstructible<T>...>>::value,
+    VariantStateBaseDestructor<T...>, VariantMoveBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the copy-constructor can be trivial.
+template <class... T>
+using VariantCopyBase = absl::conditional_t<
+    absl::disjunction<
+        absl::negation<absl::conjunction<std::is_copy_constructible<T>...>>,
+        std::is_copy_constructible<Union<T...>>>::value,
+    VariantMoveBase<T...>, VariantCopyBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the move-assign can be trivial.
+template <class... T>
+using VariantMoveAssignBase = absl::conditional_t<
+    absl::disjunction<absl::conjunction<std::is_move_assignable<Union<T...>>,
+                                        std::is_move_constructible<Union<T...>>,
+                                        std::is_destructible<Union<T...>>>,
+                      absl::negation<absl::conjunction<
+                          std::is_move_constructible<T>...,
+                          std::is_move_assignable<T>...>>>::value,
+    VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the copy-assign can be trivial.
+template <class... T>
+using VariantCopyAssignBase = absl::conditional_t<
+    absl::disjunction<absl::conjunction<std::is_copy_assignable<Union<T...>>,
+                                        std::is_copy_constructible<Union<T...>>,
+                                        std::is_destructible<Union<T...>>>,
+                      absl::negation<absl::conjunction<
+                          std::is_copy_constructible<T>...,
+                          std::is_copy_assignable<T>...>>>::value,
+    VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>;
+
+template <class... T>
+using VariantBase = VariantCopyAssignBase<T...>;
+
+template <class... T>
+class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> {
+ private:
+  using Base = VariantStateBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantStateBaseDestructorNontrivial() = default;
+  VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) =
+      default;
+  VariantStateBaseDestructorNontrivial(
+      const VariantStateBaseDestructorNontrivial&) = default;
+  VariantStateBaseDestructorNontrivial& operator=(
+      VariantStateBaseDestructorNontrivial&&) = default;
+  VariantStateBaseDestructorNontrivial& operator=(
+      const VariantStateBaseDestructorNontrivial&) = default;
+
+  struct Destroyer {
+    template <std::size_t I>
+    void operator()(SizeT<I> i) const {
+      using Alternative =
+          typename absl::variant_alternative<I, variant<T...>>::type;
+      variant_internal::AccessUnion(self->state_, i).~Alternative();
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*i*/) const {
+      // This space intentionally left blank
+    }
+
+    VariantStateBaseDestructorNontrivial* self;
+  };
+
+  void destroy() { VisitIndices<sizeof...(T)>::Run(Destroyer{this}, index_); }
+
+  ~VariantStateBaseDestructorNontrivial() { destroy(); }
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantMoveBaseNontrivial : protected VariantStateBaseDestructor<T...> {
+ private:
+  using Base = VariantStateBaseDestructor<T...>;
+
+ protected:
+  using Base::Base;
+
+  struct Construct {
+    template <std::size_t I>
+    void operator()(SizeT<I> i) const {
+      using Alternative =
+          typename absl::variant_alternative<I, variant<T...>>::type;
+      ::new (static_cast<void*>(&self->state_)) Alternative(
+          variant_internal::AccessUnion(absl::move(other->state_), i));
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*i*/) const {}
+
+    VariantMoveBaseNontrivial* self;
+    VariantMoveBaseNontrivial* other;
+  };
+
+  VariantMoveBaseNontrivial() = default;
+  VariantMoveBaseNontrivial(VariantMoveBaseNontrivial&& other) noexcept(
+      absl::conjunction<std::is_nothrow_move_constructible<T>...>::value)
+      : Base(NoopConstructorTag()) {
+    VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_);
+    index_ = other.index_;
+  }
+
+  VariantMoveBaseNontrivial(VariantMoveBaseNontrivial const&) = default;
+
+  VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial&&) = default;
+  VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial const&) =
+      default;
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantCopyBaseNontrivial : protected VariantMoveBase<T...> {
+ private:
+  using Base = VariantMoveBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantCopyBaseNontrivial() = default;
+  VariantCopyBaseNontrivial(VariantCopyBaseNontrivial&&) = default;
+
+  struct Construct {
+    template <std::size_t I>
+    void operator()(SizeT<I> i) const {
+      using Alternative =
+          typename absl::variant_alternative<I, variant<T...>>::type;
+      ::new (static_cast<void*>(&self->state_))
+          Alternative(variant_internal::AccessUnion(other->state_, i));
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*i*/) const {}
+
+    VariantCopyBaseNontrivial* self;
+    const VariantCopyBaseNontrivial* other;
+  };
+
+  VariantCopyBaseNontrivial(VariantCopyBaseNontrivial const& other)
+      : Base(NoopConstructorTag()) {
+    VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_);
+    index_ = other.index_;
+  }
+
+  VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial&&) = default;
+  VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial const&) =
+      default;
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantMoveAssignBaseNontrivial : protected VariantCopyBase<T...> {
+  friend struct VariantCoreAccess;
+
+ private:
+  using Base = VariantCopyBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantMoveAssignBaseNontrivial() = default;
+  VariantMoveAssignBaseNontrivial(VariantMoveAssignBaseNontrivial&&) = default;
+  VariantMoveAssignBaseNontrivial(const VariantMoveAssignBaseNontrivial&) =
+      default;
+  VariantMoveAssignBaseNontrivial& operator=(
+      VariantMoveAssignBaseNontrivial const&) = default;
+
+    VariantMoveAssignBaseNontrivial&
+    operator=(VariantMoveAssignBaseNontrivial&& other) noexcept(
+        absl::conjunction<std::is_nothrow_move_constructible<T>...,
+                          std::is_nothrow_move_assignable<T>...>::value) {
+      VisitIndices<sizeof...(T)>::Run(
+          VariantCoreAccess::MakeMoveAssignVisitor(this, &other), other.index_);
+      return *this;
+    }
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantCopyAssignBaseNontrivial : protected VariantMoveAssignBase<T...> {
+  friend struct VariantCoreAccess;
+
+ private:
+  using Base = VariantMoveAssignBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantCopyAssignBaseNontrivial() = default;
+  VariantCopyAssignBaseNontrivial(VariantCopyAssignBaseNontrivial&&) = default;
+  VariantCopyAssignBaseNontrivial(const VariantCopyAssignBaseNontrivial&) =
+      default;
+  VariantCopyAssignBaseNontrivial& operator=(
+      VariantCopyAssignBaseNontrivial&&) = default;
+
+    VariantCopyAssignBaseNontrivial& operator=(
+        const VariantCopyAssignBaseNontrivial& other) {
+      VisitIndices<sizeof...(T)>::Run(
+          VariantCoreAccess::MakeCopyAssignVisitor(this, other), other.index_);
+      return *this;
+    }
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+////////////////////////////////////////
+// Visitors for Comparison Operations //
+////////////////////////////////////////
+
+template <class... Types>
+struct EqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return true;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) == VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct NotEqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return false;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) != VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct LessThanOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return false;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) < VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct GreaterThanOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return false;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) > VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct LessThanOrEqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return true;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) <= VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct GreaterThanOrEqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return true;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) >= VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+// Precondition: v.index() == w.index();
+template <class... Types>
+struct SwapSameIndex {
+  variant<Types...>* v;
+  variant<Types...>* w;
+  template <std::size_t I>
+  void operator()(SizeT<I>) const {
+    using std::swap;
+    swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w));
+  }
+
+  void operator()(SizeT<variant_npos>) const {}
+};
+
+// TODO(calabrese) do this from a different namespace for proper adl usage
+template <class... Types>
+struct Swap {
+  variant<Types...>* v;
+  variant<Types...>* w;
+
+  void generic_swap() const {
+    variant<Types...> tmp(std::move(*w));
+    VariantCoreAccess::Destroy(*w);
+    VariantCoreAccess::InitFrom(*w, std::move(*v));
+    VariantCoreAccess::Destroy(*v);
+    VariantCoreAccess::InitFrom(*v, std::move(tmp));
+  }
+
+  void operator()(SizeT<absl::variant_npos> /*w_i*/) const {
+    if (!v->valueless_by_exception()) {
+      generic_swap();
+    }
+  }
+
+  template <std::size_t Wi>
+  void operator()(SizeT<Wi> /*w_i*/) {
+    if (v->index() == Wi) {
+      VisitIndices<sizeof...(Types)>::Run(SwapSameIndex<Types...>{v, w}, Wi);
+    } else {
+      generic_swap();
+    }
+  }
+};
+
+template <typename Variant, typename = void, typename... Ts>
+struct VariantHashBase {
+  VariantHashBase() = delete;
+  VariantHashBase(const VariantHashBase&) = delete;
+  VariantHashBase(VariantHashBase&&) = delete;
+  VariantHashBase& operator=(const VariantHashBase&) = delete;
+  VariantHashBase& operator=(VariantHashBase&&) = delete;
+};
+
+struct VariantHashVisitor {
+  template <typename T>
+  size_t operator()(const T& t) {
+    return std::hash<T>{}(t);
+  }
+};
+
+template <typename Variant, typename... Ts>
+struct VariantHashBase<Variant,
+                       absl::enable_if_t<absl::conjunction<
+                           type_traits_internal::IsHashEnabled<Ts>...>::value>,
+                       Ts...> {
+  using argument_type = Variant;
+  using result_type = size_t;
+  size_t operator()(const Variant& var) const {
+    if (var.valueless_by_exception()) {
+      return 239799884;
+    }
+    size_t result = VisitIndices<variant_size<Variant>::value>::Run(
+        PerformVisitation<VariantHashVisitor, const Variant&>{
+            std::forward_as_tuple(var), VariantHashVisitor{}},
+        var.index());
+    // Combine the index and the hash result in order to distinguish
+    // std::variant<int, int> holding the same value as different alternative.
+    return result ^ var.index();
+  }
+};
+
+}  // namespace variant_internal
+}  // namespace absl
+
+#endif  // ABSL_TYPES_variant_internal_H_
diff --git a/absl/types/module.mk b/absl/types/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/absl/types/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/absl/types/optional.cc b/absl/types/optional.cc
new file mode 100644
index 0000000..ef27290
--- /dev/null
+++ b/absl/types/optional.cc
@@ -0,0 +1,24 @@
+// Copyright 2017 The Abseil 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 "absl/types/optional.h"
+
+#ifndef ABSL_HAVE_STD_OPTIONAL
+namespace absl {
+
+nullopt_t::init_t nullopt_t::init;
+extern const nullopt_t nullopt{nullopt_t::init};
+
+}  // namespace absl
+#endif  // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/optional.h b/absl/types/optional.h
new file mode 100644
index 0000000..c837cdd
--- /dev/null
+++ b/absl/types/optional.h
@@ -0,0 +1,1141 @@
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// optional.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::optional` type for holding a value which
+// may or may not be present. This type is useful for providing value semantics
+// for operations that may either wish to return or hold "something-or-nothing".
+//
+// Example:
+//
+//   // A common way to signal operation failure is to provide an output
+//   // parameter and a bool return type:
+//   bool AcquireResource(const Input&, Resource * out);
+//
+//   // Providing an absl::optional return type provides a cleaner API:
+//   absl::optional<Resource> AcquireResource(const Input&);
+//
+// `absl::optional` is a C++11 compatible version of the C++17 `std::optional`
+// abstraction and is designed to be a drop-in replacement for code compliant
+// with C++17.
+#ifndef ABSL_TYPES_OPTIONAL_H_
+#define ABSL_TYPES_OPTIONAL_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+
+#include <optional>
+
+namespace absl {
+using std::bad_optional_access;
+using std::optional;
+using std::make_optional;
+using std::nullopt_t;
+using std::nullopt;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_OPTIONAL
+
+#include <cassert>
+#include <functional>
+#include <initializer_list>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_optional_access.h"
+
+// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+//
+// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
+// __cpp_inheriting_constructors is a predefined macro and a recommended way to
+// check for this language feature, but GCC doesn't support it until 5.0 and
+// Clang doesn't support it until 3.6.
+// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
+// constructor. For example, the following code won't work on MSVC 2015 Update3:
+// struct Base {
+//   int t;
+//   template <typename T>
+//   constexpr Base(T t_) : t(t_) {}
+// };
+// struct Foo : Base {
+//   using Base::Base;
+// }
+// constexpr Foo foo(0);  // doesn't work on MSVC 2015
+#if defined(__clang__)
+#if __has_feature(cxx_inheriting_constructors)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+#elif (defined(__GNUC__) &&                                       \
+       (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
+    (__cpp_inheriting_constructors >= 200802) ||                  \
+    (defined(_MSC_VER) && _MSC_VER >= 1910)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// absl::optional
+// -----------------------------------------------------------------------------
+//
+// A value of type `absl::optional<T>` holds either a value of `T` or an
+// "empty" value.  When it holds a value of `T`, it stores it as a direct
+// sub-object, so `sizeof(optional<T>)` is approximately
+// `sizeof(T) + sizeof(bool)`.
+//
+// This implementation is based on the specification in the latest draft of the
+// C++17 `std::optional` specification as of May 2017, section 20.6.
+//
+// Differences between `absl::optional<T>` and `std::optional<T>` include:
+//
+//    * `constexpr` is not used for non-const member functions.
+//      (dependency on some differences between C++11 and C++14.)
+//    * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We
+//      need the inline variable support in C++17 for external linkage.
+//    * Throws `absl::bad_optional_access` instead of
+//      `std::bad_optional_access`.
+//    * `optional::swap()` and `absl::swap()` relies on
+//      `std::is_(nothrow_)swappable()`, which has been introduced in C++17.
+//      As a workaround, we assume `is_swappable()` is always `true`
+//      and `is_nothrow_swappable()` is the same as `std::is_trivial()`.
+//    * `make_optional()` cannot be declared `constexpr` due to the absence of
+//      guaranteed copy elision.
+//    * The move constructor's `noexcept` specification is stronger, i.e. if the
+//      default allocator is non-throwing (via setting
+//      `ABSL_ALLOCATOR_NOTHROW`), it evaluates to `noexcept(true)`, because
+//      we assume
+//       a) move constructors should only throw due to allocation failure and
+//       b) if T's move constructor allocates, it uses the same allocation
+//          function as the default allocator.
+template <typename T>
+class optional;
+
+// nullopt_t
+//
+// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
+// that does not contain a value.
+struct nullopt_t {
+  struct init_t {};
+  static init_t init;
+
+  // It must not be default-constructible to avoid ambiguity for opt = {}.
+  // Note the non-const reference, which is to eliminate ambiguity for code
+  // like:
+  //
+  // struct S { int value; };
+  //
+  // void Test() {
+  //   optional<S> opt;
+  //   opt = {{}};
+  // }
+  explicit constexpr nullopt_t(init_t& /*unused*/) {}
+};
+
+// nullopt
+//
+// A tag constant of type `absl::nullopt_t` used to indicate an empty
+// `absl::optional` in certain functions, such as construction or assignment.
+extern const nullopt_t nullopt;
+
+namespace optional_internal {
+
+struct empty_struct {};
+// This class stores the data in optional<T>.
+// It is specialized based on whether T is trivially destructible.
+// This is the specialization for non trivially destructible type.
+template <typename T, bool = std::is_trivially_destructible<T>::value>
+class optional_data_dtor_base {
+  struct dummy_type {
+    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+    // Use an array to avoid GCC 6 placement-new warning.
+    empty_struct data[sizeof(T) / sizeof(empty_struct)];
+  };
+
+ protected:
+  // Whether there is data or not.
+  bool engaged_;
+  // Data storage
+  union {
+    dummy_type dummy_;
+    T data_;
+  };
+
+  void destruct() noexcept {
+    if (engaged_) {
+      data_.~T();
+      engaged_ = false;
+    }
+  }
+
+  // dummy_ must be initialized for constexpr constructor.
+  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+  template <typename... Args>
+  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+      : engaged_(true), data_(absl::forward<Args>(args)...) {}
+
+  ~optional_data_dtor_base() { destruct(); }
+};
+
+// Specialization for trivially destructible type.
+template <typename T>
+class optional_data_dtor_base<T, true> {
+  struct dummy_type {
+    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+    // Use array to avoid GCC 6 placement-new warning.
+    empty_struct data[sizeof(T) / sizeof(empty_struct)];
+  };
+
+ protected:
+  // Whether there is data or not.
+  bool engaged_;
+  // Data storage
+  union {
+    dummy_type dummy_;
+    T data_;
+  };
+  void destruct() noexcept { engaged_ = false; }
+
+  // dummy_ must be initialized for constexpr constructor.
+  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+  template <typename... Args>
+  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+      : engaged_(true), data_(absl::forward<Args>(args)...) {}
+};
+
+template <typename T>
+class optional_data_base : public optional_data_dtor_base<T> {
+ protected:
+  using base = optional_data_dtor_base<T>;
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using base::base;
+#else
+  optional_data_base() = default;
+
+  template <typename... Args>
+  constexpr explicit optional_data_base(in_place_t t, Args&&... args)
+      : base(t, absl::forward<Args>(args)...) {}
+#endif
+
+  template <typename... Args>
+  void construct(Args&&... args) {
+    // Use dummy_'s address to work around casting cv-qualified T* to void*.
+    ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
+    this->engaged_ = true;
+  }
+
+  template <typename U>
+  void assign(U&& u) {
+    if (this->engaged_) {
+      this->data_ = std::forward<U>(u);
+    } else {
+      construct(std::forward<U>(u));
+    }
+  }
+};
+
+// TODO(absl-team): Add another class using
+// std::is_trivially_move_constructible trait when available to match
+// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
+// have trivial move but nontrivial copy.
+// Also, we should be checking is_trivially_copyable here, which is not
+// supported now, so we use is_trivially_* traits instead.
+template <typename T, bool = absl::is_trivially_copy_constructible<T>::value&&
+                          absl::is_trivially_copy_assignable<
+                              typename std::remove_cv<T>::type>::value&&
+                              std::is_trivially_destructible<T>::value>
+class optional_data;
+
+// Trivially copyable types
+template <typename T>
+class optional_data<T, true> : public optional_data_base<T> {
+ protected:
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using optional_data_base<T>::optional_data_base;
+#else
+  optional_data() = default;
+
+  template <typename... Args>
+  constexpr explicit optional_data(in_place_t t, Args&&... args)
+      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+};
+
+template <typename T>
+class optional_data<T, false> : public optional_data_base<T> {
+ protected:
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using optional_data_base<T>::optional_data_base;
+#else
+  template <typename... Args>
+  constexpr explicit optional_data(in_place_t t, Args&&... args)
+      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+
+  optional_data() = default;
+
+  optional_data(const optional_data& rhs) {
+    if (rhs.engaged_) {
+      this->construct(rhs.data_);
+    }
+  }
+
+  optional_data(optional_data&& rhs) noexcept(
+      absl::default_allocator_is_nothrow::value ||
+      std::is_nothrow_move_constructible<T>::value) {
+    if (rhs.engaged_) {
+      this->construct(std::move(rhs.data_));
+    }
+  }
+
+  optional_data& operator=(const optional_data& rhs) {
+    if (rhs.engaged_) {
+      this->assign(rhs.data_);
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  optional_data& operator=(optional_data&& rhs) noexcept(
+      std::is_nothrow_move_assignable<T>::value&&
+          std::is_nothrow_move_constructible<T>::value) {
+    if (rhs.engaged_) {
+      this->assign(std::move(rhs.data_));
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+};
+
+// Ordered by level of restriction, from low to high.
+// Copyable implies movable.
+enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
+
+// Base class for enabling/disabling copy/move constructor.
+template <copy_traits>
+class optional_ctor_base;
+
+template <>
+class optional_ctor_base<copy_traits::copyable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = default;
+  optional_ctor_base(optional_ctor_base&&) = default;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::movable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = delete;
+  optional_ctor_base(optional_ctor_base&&) = default;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::non_movable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = delete;
+  optional_ctor_base(optional_ctor_base&&) = delete;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+// Base class for enabling/disabling copy/move assignment.
+template <copy_traits>
+class optional_assign_base;
+
+template <>
+class optional_assign_base<copy_traits::copyable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = default;
+  optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::movable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = delete;
+  optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::non_movable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = delete;
+  optional_assign_base& operator=(optional_assign_base&&) = delete;
+};
+
+template <typename T>
+constexpr copy_traits get_ctor_copy_traits() {
+  return std::is_copy_constructible<T>::value
+             ? copy_traits::copyable
+             : std::is_move_constructible<T>::value ? copy_traits::movable
+                                                    : copy_traits::non_movable;
+}
+
+template <typename T>
+constexpr copy_traits get_assign_copy_traits() {
+  return std::is_copy_assignable<T>::value &&
+                 std::is_copy_constructible<T>::value
+             ? copy_traits::copyable
+             : std::is_move_assignable<T>::value &&
+                       std::is_move_constructible<T>::value
+                   ? copy_traits::movable
+                   : copy_traits::non_movable;
+}
+
+// Whether T is constructible or convertible from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_from_optional
+    : std::integral_constant<
+          bool, std::is_constructible<T, optional<U>&>::value ||
+                    std::is_constructible<T, optional<U>&&>::value ||
+                    std::is_constructible<T, const optional<U>&>::value ||
+                    std::is_constructible<T, const optional<U>&&>::value ||
+                    std::is_convertible<optional<U>&, T>::value ||
+                    std::is_convertible<optional<U>&&, T>::value ||
+                    std::is_convertible<const optional<U>&, T>::value ||
+                    std::is_convertible<const optional<U>&&, T>::value> {};
+
+// Whether T is constructible or convertible or assignable from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_assignable_from_optional
+    : std::integral_constant<
+          bool, is_constructible_convertible_from_optional<T, U>::value ||
+                    std::is_assignable<T&, optional<U>&>::value ||
+                    std::is_assignable<T&, optional<U>&&>::value ||
+                    std::is_assignable<T&, const optional<U>&>::value ||
+                    std::is_assignable<T&, const optional<U>&&>::value> {};
+
+// Helper function used by [optional.relops], [optional.comp_with_t],
+// for checking whether an expression is convertible to bool.
+bool convertible_to_bool(bool);
+
+// Base class for std::hash<absl::optional<T>>:
+// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
+// compute the hash; Otherwise, it is disabled.
+// Reference N4659 23.14.15 [unord.hash].
+template <typename T, typename = size_t>
+struct optional_hash_base {
+  optional_hash_base() = delete;
+  optional_hash_base(const optional_hash_base&) = delete;
+  optional_hash_base(optional_hash_base&&) = delete;
+  optional_hash_base& operator=(const optional_hash_base&) = delete;
+  optional_hash_base& operator=(optional_hash_base&&) = delete;
+};
+
+template <typename T>
+struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
+                                 std::declval<absl::remove_const_t<T> >()))> {
+  using argument_type = absl::optional<T>;
+  using result_type = size_t;
+  size_t operator()(const absl::optional<T>& opt) const {
+    if (opt) {
+      return std::hash<absl::remove_const_t<T> >()(*opt);
+    } else {
+      return static_cast<size_t>(0x297814aaad196e6dULL);
+    }
+  }
+};
+
+}  // namespace optional_internal
+
+// -----------------------------------------------------------------------------
+// absl::optional class definition
+// -----------------------------------------------------------------------------
+
+template <typename T>
+class optional : private optional_internal::optional_data<T>,
+                 private optional_internal::optional_ctor_base<
+                     optional_internal::get_ctor_copy_traits<T>()>,
+                 private optional_internal::optional_assign_base<
+                     optional_internal::get_assign_copy_traits<T>()> {
+  using data_base = optional_internal::optional_data<T>;
+
+ public:
+  typedef T value_type;
+
+  // Constructors
+
+  // Constructs an `optional` holding an empty value, NOT a default constructed
+  // `T`.
+  constexpr optional() noexcept {}
+
+  // Constructs an `optional` initialized with `nullopt` to hold an empty value.
+  constexpr optional(nullopt_t) noexcept {}  // NOLINT(runtime/explicit)
+
+  // Copy constructor, standard semantics
+  optional(const optional& src) = default;
+
+  // Move constructor, standard semantics
+  optional(optional&& src) = default;
+
+  // Constructs a non-empty `optional` direct-initialized value of type `T` from
+  // the arguments `std::forward<Args>(args)...`  within the `optional`.
+  // (The `in_place_t` is a tag used to indicate that the contained object
+  // should be constructed in-place.)
+  //
+  // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE.
+  template <typename... Args>
+  constexpr explicit optional(in_place_t, Args&&... args)
+      : data_base(in_place_t(), absl::forward<Args>(args)...) {}
+
+  // Constructs a non-empty `optional` direct-initialized value of type `T` from
+  // the arguments of an initializer_list and `std::forward<Args>(args)...`.
+  // (The `in_place_t` is a tag used to indicate that the contained object
+  // should be constructed in-place.)
+  template <typename U, typename... Args,
+            typename = typename std::enable_if<std::is_constructible<
+                T, std::initializer_list<U>&, Args&&...>::value>::type>
+  constexpr explicit optional(in_place_t, std::initializer_list<U> il,
+                              Args&&... args)
+      : data_base(in_place_t(), il, absl::forward<Args>(args)...) {
+  }
+
+  // Value constructor (implicit)
+  template <
+      typename U = T,
+      typename std::enable_if<
+          absl::conjunction<absl::negation<std::is_same<
+                                in_place_t, typename std::decay<U>::type> >,
+                            absl::negation<std::is_same<
+                                optional<T>, typename std::decay<U>::type> >,
+                            std::is_convertible<U&&, T>,
+                            std::is_constructible<T, U&&> >::value,
+          bool>::type = false>
+  constexpr optional(U&& v) : data_base(in_place_t(), absl::forward<U>(v)) {}
+
+  // Value constructor (explicit)
+  template <
+      typename U = T,
+      typename std::enable_if<
+          absl::conjunction<absl::negation<std::is_same<
+                                in_place_t, typename std::decay<U>::type>>,
+                            absl::negation<std::is_same<
+                                optional<T>, typename std::decay<U>::type>>,
+                            absl::negation<std::is_convertible<U&&, T>>,
+                            std::is_constructible<T, U&&>>::value,
+          bool>::type = false>
+  explicit constexpr optional(U&& v)
+      : data_base(in_place_t(), absl::forward<U>(v)) {}
+
+  // Converting copy constructor (implicit)
+  template <typename U,
+            typename std::enable_if<
+                absl::conjunction<
+                    absl::negation<std::is_same<T, U> >,
+                    std::is_constructible<T, const U&>,
+                    absl::negation<
+                        optional_internal::
+                            is_constructible_convertible_from_optional<T, U> >,
+                    std::is_convertible<const U&, T> >::value,
+                bool>::type = false>
+  optional(const optional<U>& rhs) {
+    if (rhs) {
+      this->construct(*rhs);
+    }
+  }
+
+  // Converting copy constructor (explicit)
+  template <typename U,
+            typename std::enable_if<
+                absl::conjunction<
+                    absl::negation<std::is_same<T, U>>,
+                    std::is_constructible<T, const U&>,
+                    absl::negation<
+                        optional_internal::
+                            is_constructible_convertible_from_optional<T, U>>,
+                    absl::negation<std::is_convertible<const U&, T>>>::value,
+                bool>::type = false>
+  explicit optional(const optional<U>& rhs) {
+    if (rhs) {
+      this->construct(*rhs);
+    }
+  }
+
+  // Converting move constructor (implicit)
+  template <typename U,
+            typename std::enable_if<
+                absl::conjunction<
+                    absl::negation<std::is_same<T, U> >,
+                    std::is_constructible<T, U&&>,
+                    absl::negation<
+                        optional_internal::
+                            is_constructible_convertible_from_optional<T, U> >,
+                    std::is_convertible<U&&, T> >::value,
+                bool>::type = false>
+  optional(optional<U>&& rhs) {
+    if (rhs) {
+      this->construct(std::move(*rhs));
+    }
+  }
+
+  // Converting move constructor (explicit)
+  template <
+      typename U,
+      typename std::enable_if<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+              absl::negation<
+                  optional_internal::is_constructible_convertible_from_optional<
+                      T, U>>,
+              absl::negation<std::is_convertible<U&&, T>>>::value,
+          bool>::type = false>
+  explicit optional(optional<U>&& rhs) {
+    if (rhs) {
+      this->construct(std::move(*rhs));
+    }
+  }
+
+  // Destructor. Trivial if `T` is trivially destructible.
+  ~optional() = default;
+
+  // Assignment Operators
+
+  // Assignment from `nullopt`
+  //
+  // Example:
+  //
+  //   struct S { int value; };
+  //   optional<S> opt = absl::nullopt;  // Could also use opt = { };
+  optional& operator=(nullopt_t) noexcept {
+    this->destruct();
+    return *this;
+  }
+
+  // Copy assignment operator, standard semantics
+  optional& operator=(const optional& src) = default;
+
+  // Move assignment operator, standard semantics
+  optional& operator=(optional&& src) = default;
+
+  // Value assignment operators
+  template <
+      typename U = T,
+      typename = typename std::enable_if<absl::conjunction<
+          absl::negation<
+              std::is_same<optional<T>, typename std::decay<U>::type>>,
+          absl::negation<
+              absl::conjunction<std::is_scalar<T>,
+                                std::is_same<T, typename std::decay<U>::type>>>,
+          std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
+  optional& operator=(U&& v) {
+    this->assign(std::forward<U>(v));
+    return *this;
+  }
+
+  template <
+      typename U,
+      typename = typename std::enable_if<absl::conjunction<
+          absl::negation<std::is_same<T, U>>,
+          std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
+          absl::negation<
+              optional_internal::
+                  is_constructible_convertible_assignable_from_optional<
+                      T, U>>>::value>::type>
+  optional& operator=(const optional<U>& rhs) {
+    if (rhs) {
+      this->assign(*rhs);
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  template <typename U,
+            typename = typename std::enable_if<absl::conjunction<
+                absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
+                std::is_assignable<T&, U>,
+                absl::negation<
+                    optional_internal::
+                        is_constructible_convertible_assignable_from_optional<
+                            T, U>>>::value>::type>
+  optional& operator=(optional<U>&& rhs) {
+    if (rhs) {
+      this->assign(std::move(*rhs));
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  // Modifiers
+
+  // optional::reset()
+  //
+  // Destroys the inner `T` value of an `absl::optional` if one is present.
+  void reset() noexcept { this->destruct(); }
+
+  // optional::emplace()
+  //
+  // (Re)constructs the underlying `T` in-place with the given forwarded
+  // arguments.
+  //
+  // Example:
+  //
+  //   optional<Foo> opt;
+  //   opt.emplace(arg1,arg2,arg3);  // Constructs Foo(arg1,arg2,arg3)
+  //
+  // If the optional is non-empty, and the `args` refer to subobjects of the
+  // current object, then behaviour is undefined, because the current object
+  // will be destructed before the new object is constructed with `args`.
+  template <typename... Args,
+            typename = typename std::enable_if<
+                std::is_constructible<T, Args&&...>::value>::type>
+  T& emplace(Args&&... args) {
+    this->destruct();
+    this->construct(std::forward<Args>(args)...);
+    return reference();
+  }
+
+  // Emplace reconstruction overload for an initializer list and the given
+  // forwarded arguments.
+  //
+  // Example:
+  //
+  //   struct Foo {
+  //     Foo(std::initializer_list<int>);
+  //   };
+  //
+  //   optional<Foo> opt;
+  //   opt.emplace({1,2,3});  // Constructs Foo({1,2,3})
+  template <typename U, typename... Args,
+            typename = typename std::enable_if<std::is_constructible<
+                T, std::initializer_list<U>&, Args&&...>::value>::type>
+  T& emplace(std::initializer_list<U> il, Args&&... args) {
+    this->destruct();
+    this->construct(il, std::forward<Args>(args)...);
+    return reference();
+  }
+
+  // Swaps
+
+  // Swap, standard semantics
+  void swap(optional& rhs) noexcept(
+      std::is_nothrow_move_constructible<T>::value&&
+          std::is_trivial<T>::value) {
+    if (*this) {
+      if (rhs) {
+        using std::swap;
+        swap(**this, *rhs);
+      } else {
+        rhs.construct(std::move(**this));
+        this->destruct();
+      }
+    } else {
+      if (rhs) {
+        this->construct(std::move(*rhs));
+        rhs.destruct();
+      } else {
+        // No effect (swap(disengaged, disengaged)).
+      }
+    }
+  }
+
+  // Observers
+
+  // optional::operator->()
+  //
+  // Accesses the underlying `T` value's member `m` of an `optional`. If the
+  // `optional` is empty, behavior is undefined.
+  //
+  // If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
+  const T* operator->() const {
+    assert(this->engaged_);
+    return std::addressof(this->data_);
+  }
+  T* operator->() {
+    assert(this->engaged_);
+    return std::addressof(this->data_);
+  }
+
+  // optional::operator*()
+  //
+  // Accesses the underlying `T` value of an `optional`. If the `optional` is
+  // empty, behavior is undefined.
+  constexpr const T& operator*() const & { return reference(); }
+  T& operator*() & {
+    assert(this->engaged_);
+    return reference();
+  }
+  constexpr const T&& operator*() const && {
+    return absl::move(reference());
+  }
+  T&& operator*() && {
+    assert(this->engaged_);
+    return std::move(reference());
+  }
+
+  // optional::operator bool()
+  //
+  // Returns false if and only if the `optional` is empty.
+  //
+  //   if (opt) {
+  //     // do something with opt.value();
+  //   } else {
+  //     // opt is empty.
+  //   }
+  //
+  constexpr explicit operator bool() const noexcept { return this->engaged_; }
+
+  // optional::has_value()
+  //
+  // Determines whether the `optional` contains a value. Returns `false` if and
+  // only if `*this` is empty.
+  constexpr bool has_value() const noexcept { return this->engaged_; }
+
+// Suppress bogus warning on MSVC: MSVC complains call to reference() after
+// throw_bad_optional_access() is unreachable.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4702)
+#endif  // _MSC_VER
+  // optional::value()
+  //
+  // Returns a reference to an `optional`s underlying value. The constness
+  // and lvalue/rvalue-ness of the `optional` is preserved to the view of
+  // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional`
+  // is empty.
+  constexpr const T& value() const & {
+    return static_cast<bool>(*this)
+               ? reference()
+               : (optional_internal::throw_bad_optional_access(), reference());
+  }
+  T& value() & {
+    return static_cast<bool>(*this)
+               ? reference()
+               : (optional_internal::throw_bad_optional_access(), reference());
+  }
+  T&& value() && {  // NOLINT(build/c++11)
+    return std::move(
+        static_cast<bool>(*this)
+            ? reference()
+            : (optional_internal::throw_bad_optional_access(), reference()));
+  }
+  constexpr const T&& value() const && {  // NOLINT(build/c++11)
+    return absl::move(
+        static_cast<bool>(*this)
+            ? reference()
+            : (optional_internal::throw_bad_optional_access(), reference()));
+  }
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+  // optional::value_or()
+  //
+  // Returns either the value of `T` or a passed default `v` if the `optional`
+  // is empty.
+  template <typename U>
+  constexpr T value_or(U&& v) const& {
+    static_assert(std::is_copy_constructible<value_type>::value,
+                  "optional<T>::value_or: T must by copy constructible");
+    static_assert(std::is_convertible<U&&, value_type>::value,
+                  "optional<T>::value_or: U must be convertible to T");
+    return static_cast<bool>(*this)
+               ? **this
+               : static_cast<T>(absl::forward<U>(v));
+  }
+  template <typename U>
+  T value_or(U&& v) && {  // NOLINT(build/c++11)
+    static_assert(std::is_move_constructible<value_type>::value,
+                  "optional<T>::value_or: T must by copy constructible");
+    static_assert(std::is_convertible<U&&, value_type>::value,
+                  "optional<T>::value_or: U must be convertible to T");
+    return static_cast<bool>(*this) ? std::move(**this)
+                                    : static_cast<T>(std::forward<U>(v));
+  }
+
+ private:
+  // Private accessors for internal storage viewed as reference to T.
+  constexpr const T& reference() const { return this->data_; }
+  T& reference() { return this->data_; }
+
+  // T constraint checks.  You can't have an optional of nullopt_t, in_place_t
+  // or a reference.
+  static_assert(
+      !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value,
+      "optional<nullopt_t> is not allowed.");
+  static_assert(
+      !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value,
+      "optional<in_place_t> is not allowed.");
+  static_assert(!std::is_reference<T>::value,
+                "optional<reference> is not allowed.");
+};
+
+// Non-member functions
+
+// swap()
+//
+// Performs a swap between two `absl::optional` objects, using standard
+// semantics.
+//
+// NOTE: we assume `is_swappable()` is always `true`. A compile error will
+// result if this is not the case.
+template <typename T,
+          typename std::enable_if<std::is_move_constructible<T>::value,
+                                  bool>::type = false>
+void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
+  a.swap(b);
+}
+
+// make_optional()
+//
+// Creates a non-empty `optional<T>` where the type of `T` is deduced. An
+// `absl::optional` can also be explicitly instantiated with
+// `make_optional<T>(v)`.
+//
+// Note: `make_optional()` constructions may be declared `constexpr` for
+// trivially copyable types `T`. Non-trivial types require copy elision
+// support in C++17 for `make_optional` to support `constexpr` on such
+// non-trivial types.
+//
+// Example:
+//
+//   constexpr absl::optional<int> opt = absl::make_optional(1);
+//   static_assert(opt.value() == 1, "");
+template <typename T>
+constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
+  return optional<typename std::decay<T>::type>(absl::forward<T>(v));
+}
+
+template <typename T, typename... Args>
+constexpr optional<T> make_optional(Args&&... args) {
+  return optional<T>(in_place_t(), absl::forward<Args>(args)...);
+}
+
+template <typename T, typename U, typename... Args>
+constexpr optional<T> make_optional(std::initializer_list<U> il,
+                                    Args&&... args) {
+  return optional<T>(in_place_t(), il,
+                     absl::forward<Args>(args)...);
+}
+
+// Relational operators [optional.relops]
+
+// Empty optionals are considered equal to each other and less than non-empty
+// optionals. Supports relations between optional<T> and optional<U>, between
+// optional<T> and U, and between optional<T> and nullopt.
+//
+// Note: We're careful to support T having non-bool relationals.
+
+// Requires: The expression, e.g. "*x == *y" shall be well-formed and its result
+// shall be convertible to bool.
+// The C++17 (N4606) "Returns:" statements are translated into
+// code in an obvious way here, and the original text retained as function docs.
+// Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true;
+// otherwise *x == *y.
+template <typename T, typename U>
+constexpr auto operator==(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x == *y)) {
+  return static_cast<bool>(x) != static_cast<bool>(y)
+             ? false
+             : static_cast<bool>(x) == false ? true
+                                             : static_cast<bool>(*x == *y);
+}
+
+// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
+// otherwise *x != *y.
+template <typename T, typename U>
+constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x != *y)) {
+  return static_cast<bool>(x) != static_cast<bool>(y)
+             ? true
+             : static_cast<bool>(x) == false ? false
+                                             : static_cast<bool>(*x != *y);
+}
+// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
+template <typename T, typename U>
+constexpr auto operator<(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x < *y)) {
+  return !y ? false : !x ? true : static_cast<bool>(*x < *y);
+}
+// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
+template <typename T, typename U>
+constexpr auto operator>(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x > *y)) {
+  return !x ? false : !y ? true : static_cast<bool>(*x > *y);
+}
+// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
+template <typename T, typename U>
+constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
+  return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
+}
+// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
+template <typename T, typename U>
+constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
+  return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
+}
+
+// Comparison with nullopt [optional.nullops]
+// The C++17 (N4606) "Returns:" statements are used directly here.
+template <typename T>
+constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
+  return !x;
+}
+template <typename T>
+constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
+  return !x;
+}
+template <typename T>
+constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
+  return false;
+}
+template <typename T>
+constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
+  return !x;
+}
+template <typename T>
+constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
+  return true;
+}
+template <typename T>
+constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
+  return false;
+}
+template <typename T>
+constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
+  return true;
+}
+template <typename T>
+constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
+  return !x;
+}
+
+// Comparison with T [optional.comp_with_t]
+
+// Requires: The expression, e.g. "*x == v" shall be well-formed and its result
+// shall be convertible to bool.
+// The C++17 (N4606) "Equivalent to:" statements are used directly here.
+template <typename T, typename U>
+constexpr auto operator==(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x == v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
+}
+template <typename T, typename U>
+constexpr auto operator==(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v == *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
+}
+template <typename T, typename U>
+constexpr auto operator!=(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x != v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
+}
+template <typename T, typename U>
+constexpr auto operator!=(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v != *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
+}
+template <typename T, typename U>
+constexpr auto operator<(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x < v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
+}
+template <typename T, typename U>
+constexpr auto operator<(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v < *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
+}
+template <typename T, typename U>
+constexpr auto operator<=(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x <= v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
+}
+template <typename T, typename U>
+constexpr auto operator<=(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v <= *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
+}
+template <typename T, typename U>
+constexpr auto operator>(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x > v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
+}
+template <typename T, typename U>
+constexpr auto operator>(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v > *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
+}
+template <typename T, typename U>
+constexpr auto operator>=(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x >= v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
+}
+template <typename T, typename U>
+constexpr auto operator>=(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v >= *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
+}
+
+}  // namespace absl
+
+namespace std {
+
+// std::hash specialization for absl::optional.
+template <typename T>
+struct hash<absl::optional<T> >
+    : absl::optional_internal::optional_hash_base<T> {};
+
+}  // namespace std
+
+#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS
+
+#endif  // ABSL_HAVE_STD_OPTIONAL
+
+#endif  // ABSL_TYPES_OPTIONAL_H_
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc
new file mode 100644
index 0000000..d2ef04b
--- /dev/null
+++ b/absl/types/optional_exception_safety_test.cc
@@ -0,0 +1,282 @@
+// Copyright 2017 The Abseil 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 "absl/types/optional.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+
+namespace absl {
+
+namespace {
+
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using ::testing::MakeExceptionSafetyTester;
+
+using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
+using Optional = absl::optional<Thrower>;
+
+using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using MoveOptional = absl::optional<MoveThrower>;
+
+constexpr int kInitialInteger = 5;
+constexpr int kUpdatedInteger = 10;
+
+template <typename OptionalT>
+bool ValueThrowsBadOptionalAccess(const OptionalT& optional) try {
+  return (static_cast<void>(optional.value()), false);
+} catch (absl::bad_optional_access) {
+  return true;
+}
+
+template <typename OptionalT>
+AssertionResult CheckInvariants(OptionalT* optional_ptr) {
+  // Check the current state post-throw for validity
+  auto& optional = *optional_ptr;
+
+  if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) {
+    return AssertionFailure()
+           << "Optional with value should not throw bad_optional_access when "
+              "accessing the value.";
+  }
+  if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) {
+    return AssertionFailure()
+           << "Optional without a value should throw bad_optional_access when "
+              "accessing the value.";
+  }
+
+  // Reset to a known state
+  optional.reset();
+
+  // Confirm that the known post-reset state is valid
+  if (optional.has_value()) {
+    return AssertionFailure()
+           << "Optional should not contain a value after being reset.";
+  }
+  if (!ValueThrowsBadOptionalAccess(optional)) {
+    return AssertionFailure() << "Optional should throw bad_optional_access "
+                                 "when accessing the value after being reset.";
+  }
+
+  return AssertionSuccess();
+}
+
+template <typename OptionalT>
+AssertionResult CheckDisengaged(OptionalT* optional_ptr) {
+  auto& optional = *optional_ptr;
+
+  if (optional.has_value()) {
+    return AssertionFailure()
+           << "Expected optional to not contain a value but a value was found.";
+  }
+
+  return AssertionSuccess();
+}
+
+template <typename OptionalT>
+AssertionResult CheckEngaged(OptionalT* optional_ptr) {
+  auto& optional = *optional_ptr;
+
+  if (!optional.has_value()) {
+    return AssertionFailure()
+           << "Expected optional to contain a value but no value was found.";
+  }
+
+  return AssertionSuccess();
+}
+
+TEST(OptionalExceptionSafety, ThrowingConstructors) {
+  auto thrower_nonempty = Optional(Thrower(kInitialInteger));
+  testing::TestThrowingCtor<Optional>(thrower_nonempty);
+
+  auto integer_nonempty = absl::optional<int>(kInitialInteger);
+  testing::TestThrowingCtor<Optional>(integer_nonempty);
+  testing::TestThrowingCtor<Optional>(std::move(integer_nonempty));  // NOLINT
+
+  testing::TestThrowingCtor<Optional>(kInitialInteger);
+  using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>;
+  testing::TestThrowingCtor<absl::optional<ThrowerVec>>(
+      absl::in_place,
+      std::initializer_list<Thrower>{Thrower(), Thrower(), Thrower()},
+      testing::ThrowingAllocator<Thrower>());
+}
+
+TEST(OptionalExceptionSafety, NothrowConstructors) {
+  // This constructor is marked noexcept. If it throws, the program will
+  // terminate.
+  testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger));
+}
+
+TEST(OptionalExceptionSafety, Emplace) {
+  // Test the basic guarantee plus test the result of optional::has_value()
+  // is false in all cases
+  auto disengaged_test = MakeExceptionSafetyTester().WithInvariants(
+      CheckInvariants<Optional>, CheckDisengaged<Optional>);
+  auto disengaged_test_empty = disengaged_test.WithInitialValue(Optional());
+  auto disengaged_test_nonempty =
+      disengaged_test.WithInitialValue(Optional(kInitialInteger));
+
+  auto emplace_thrower_directly = [](Optional* optional_ptr) {
+    optional_ptr->emplace(kUpdatedInteger);
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly));
+  EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly));
+
+  auto emplace_thrower_copy = [](Optional* optional_ptr) {
+    auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
+    optional_ptr->emplace(thrower);
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy));
+  EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy));
+}
+
+TEST(OptionalExceptionSafety, EverythingThrowsSwap) {
+  // Test the basic guarantee plus test the result of optional::has_value()
+  // remains the same
+  auto test =
+      MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>);
+  auto disengaged_test_empty = test.WithInitialValue(Optional())
+                                   .WithInvariants(CheckDisengaged<Optional>);
+  auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
+                                   .WithInvariants(CheckEngaged<Optional>);
+
+  auto swap_empty = [](Optional* optional_ptr) {
+    auto empty = Optional();
+    optional_ptr->swap(empty);
+  };
+  EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty));
+
+  auto swap_nonempty = [](Optional* optional_ptr) {
+    auto nonempty =
+        Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
+    optional_ptr->swap(nonempty);
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty));
+  EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty));
+}
+
+TEST(OptionalExceptionSafety, NoThrowMoveSwap) {
+  // Tests the nothrow guarantee for optional of T with non-throwing move
+  {
+    auto empty = MoveOptional();
+    auto nonempty = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); }));
+  }
+  {
+    auto nonempty = MoveOptional(kUpdatedInteger);
+    auto empty = MoveOptional();
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); }));
+  }
+  {
+    auto nonempty_from = MoveOptional(kUpdatedInteger);
+    auto nonempty_to = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(
+        testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); }));
+  }
+}
+
+TEST(OptionalExceptionSafety, CopyAssign) {
+  // Test the basic guarantee plus test the result of optional::has_value()
+  // remains the same
+  auto test =
+      MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>);
+  auto disengaged_test_empty = test.WithInitialValue(Optional())
+                                   .WithInvariants(CheckDisengaged<Optional>);
+  auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
+                                   .WithInvariants(CheckEngaged<Optional>);
+
+  auto copyassign_nonempty = [](Optional* optional_ptr) {
+    auto nonempty =
+        Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
+    *optional_ptr = nonempty;
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty));
+  EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty));
+
+  auto copyassign_thrower = [](Optional* optional_ptr) {
+    auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
+    *optional_ptr = thrower;
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower));
+  EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower));
+}
+
+TEST(OptionalExceptionSafety, MoveAssign) {
+  // Test the basic guarantee plus test the result of optional::has_value()
+  // remains the same
+  auto test =
+      MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>);
+  auto disengaged_test_empty = test.WithInitialValue(Optional())
+                                   .WithInvariants(CheckDisengaged<Optional>);
+  auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
+                                   .WithInvariants(CheckEngaged<Optional>);
+
+  auto moveassign_empty = [](Optional* optional_ptr) {
+    auto empty = Optional();
+    *optional_ptr = std::move(empty);
+  };
+  EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty));
+
+  auto moveassign_nonempty = [](Optional* optional_ptr) {
+    auto nonempty =
+        Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
+    *optional_ptr = std::move(nonempty);
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty));
+  EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty));
+
+  auto moveassign_thrower = [](Optional* optional_ptr) {
+    auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
+    *optional_ptr = std::move(thrower);
+  };
+  EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower));
+  EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower));
+}
+
+TEST(OptionalExceptionSafety, NothrowMoveAssign) {
+  // Tests the nothrow guarantee for optional of T with non-throwing move
+  {
+    auto empty = MoveOptional();
+    auto nonempty = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); }));
+  }
+  {
+    auto nonempty = MoveOptional(kInitialInteger);
+    auto empty = MoveOptional();
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); }));
+  }
+  {
+    auto nonempty_from = MoveOptional(kUpdatedInteger);
+    auto nonempty_to = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(testing::TestNothrowOp(
+        [&]() { nonempty_to = std::move(nonempty_from); }));
+  }
+  {
+    auto thrower = MoveThrower(kUpdatedInteger);
+    auto empty = MoveOptional();
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); }));
+  }
+  {
+    auto thrower = MoveThrower(kUpdatedInteger);
+    auto nonempty = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(
+        testing::TestNothrowOp([&]() { nonempty = std::move(thrower); }));
+  }
+}
+
+}  // namespace
+
+}  // namespace absl
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
new file mode 100644
index 0000000..179bfd6
--- /dev/null
+++ b/absl/types/optional_test.cc
@@ -0,0 +1,1625 @@
+// Copyright 2017 The Abseil 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 "absl/types/optional.h"
+
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+struct Hashable {};
+
+namespace std {
+template <>
+struct hash<Hashable> {
+  size_t operator()(const Hashable&) { return 0; }
+};
+}  // namespace std
+
+struct NonHashable {};
+
+namespace {
+
+std::string TypeQuals(std::string&) { return "&"; }
+std::string TypeQuals(std::string&&) { return "&&"; }
+std::string TypeQuals(const std::string&) { return "c&"; }
+std::string TypeQuals(const std::string&&) { return "c&&"; }
+
+struct StructorListener {
+  int construct0 = 0;
+  int construct1 = 0;
+  int construct2 = 0;
+  int listinit = 0;
+  int copy = 0;
+  int move = 0;
+  int copy_assign = 0;
+  int move_assign = 0;
+  int destruct = 0;
+  int volatile_copy = 0;
+  int volatile_move = 0;
+  int volatile_copy_assign = 0;
+  int volatile_move_assign = 0;
+};
+
+// Suppress MSVC warnings.
+// 4521: multiple copy constructors specified
+// 4522: multiple assignment operators specified
+// We wrote multiple of them to test that the correct overloads are selected.
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4521)
+#pragma warning( disable : 4522)
+#endif
+struct Listenable {
+  static StructorListener* listener;
+
+  Listenable() { ++listener->construct0; }
+  explicit Listenable(int /*unused*/) { ++listener->construct1; }
+  Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; }
+  Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; }
+  Listenable(const Listenable& /*unused*/) { ++listener->copy; }
+  Listenable(const volatile Listenable& /*unused*/) {
+    ++listener->volatile_copy;
+  }
+  Listenable(volatile Listenable&& /*unused*/) { ++listener->volatile_move; }
+  Listenable(Listenable&& /*unused*/) { ++listener->move; }
+  Listenable& operator=(const Listenable& /*unused*/) {
+    ++listener->copy_assign;
+    return *this;
+  }
+  Listenable& operator=(Listenable&& /*unused*/) {
+    ++listener->move_assign;
+    return *this;
+  }
+  // use void return type instead of volatile T& to work around GCC warning
+  // when the assignment's returned reference is ignored.
+  void operator=(const volatile Listenable& /*unused*/) volatile {
+    ++listener->volatile_copy_assign;
+  }
+  void operator=(volatile Listenable&& /*unused*/) volatile {
+    ++listener->volatile_move_assign;
+  }
+  ~Listenable() { ++listener->destruct; }
+};
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+StructorListener* Listenable::listener = nullptr;
+
+// ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST is defined to 1 when the standard
+// library implementation doesn't marked initializer_list's default constructor
+// constexpr. The C++11 standard doesn't specify constexpr on it, but C++14
+// added it. However, libstdc++ 4.7 marked it constexpr.
+#if defined(_LIBCPP_VERSION) && \
+    (_LIBCPP_STD_VER <= 11 || defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR))
+#define ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST 1
+#endif
+
+struct ConstexprType {
+  enum CtorTypes {
+    kCtorDefault,
+    kCtorInt,
+    kCtorInitializerList,
+    kCtorConstChar
+  };
+  constexpr ConstexprType() : x(kCtorDefault) {}
+  constexpr explicit ConstexprType(int i) : x(kCtorInt) {}
+#ifndef ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST
+  constexpr ConstexprType(std::initializer_list<int> il)
+      : x(kCtorInitializerList) {}
+#endif
+  constexpr ConstexprType(const char*)  // NOLINT(runtime/explicit)
+      : x(kCtorConstChar) {}
+  int x;
+};
+
+struct Copyable {
+  Copyable() {}
+  Copyable(const Copyable&) {}
+  Copyable& operator=(const Copyable&) { return *this; }
+};
+
+struct MoveableThrow {
+  MoveableThrow() {}
+  MoveableThrow(MoveableThrow&&) {}
+  MoveableThrow& operator=(MoveableThrow&&) { return *this; }
+};
+
+struct MoveableNoThrow {
+  MoveableNoThrow() {}
+  MoveableNoThrow(MoveableNoThrow&&) noexcept {}
+  MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; }
+};
+
+struct NonMovable {
+  NonMovable() {}
+  NonMovable(const NonMovable&) = delete;
+  NonMovable& operator=(const NonMovable&) = delete;
+  NonMovable(NonMovable&&) = delete;
+  NonMovable& operator=(NonMovable&&) = delete;
+};
+
+TEST(optionalTest, DefaultConstructor) {
+  absl::optional<int> empty;
+  EXPECT_FALSE(empty);
+  constexpr absl::optional<int> cempty;
+  static_assert(!cempty.has_value(), "");
+  EXPECT_TRUE(
+      std::is_nothrow_default_constructible<absl::optional<int>>::value);
+}
+
+TEST(optionalTest, nulloptConstructor) {
+  absl::optional<int> empty(absl::nullopt);
+  EXPECT_FALSE(empty);
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+  constexpr absl::optional<int> cempty{absl::nullopt};
+#else
+  // Creating a temporary absl::nullopt_t object instead of using absl::nullopt
+  // because absl::nullopt cannot be constexpr and have external linkage at the
+  // same time.
+  constexpr absl::optional<int> cempty{absl::nullopt_t(absl::nullopt_t::init)};
+#endif
+  static_assert(!cempty.has_value(), "");
+  EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>,
+                                             absl::nullopt_t>::value));
+}
+
+TEST(optionalTest, CopyConstructor) {
+  {
+    absl::optional<int> empty, opt42 = 42;
+    absl::optional<int> empty_copy(empty);
+    EXPECT_FALSE(empty_copy);
+    absl::optional<int> opt42_copy(opt42);
+    EXPECT_TRUE(opt42_copy);
+    EXPECT_EQ(42, *opt42_copy);
+  }
+  {
+    absl::optional<const int> empty, opt42 = 42;
+    absl::optional<const int> empty_copy(empty);
+    EXPECT_FALSE(empty_copy);
+    absl::optional<const int> opt42_copy(opt42);
+    EXPECT_TRUE(opt42_copy);
+    EXPECT_EQ(42, *opt42_copy);
+  }
+  {
+    absl::optional<volatile int> empty, opt42 = 42;
+    absl::optional<volatile int> empty_copy(empty);
+    EXPECT_FALSE(empty_copy);
+    absl::optional<volatile int> opt42_copy(opt42);
+    EXPECT_TRUE(opt42_copy);
+    EXPECT_EQ(42, *opt42_copy);
+  }
+  // test copyablility
+  EXPECT_TRUE(std::is_copy_constructible<absl::optional<int>>::value);
+  EXPECT_TRUE(std::is_copy_constructible<absl::optional<Copyable>>::value);
+  EXPECT_FALSE(
+      std::is_copy_constructible<absl::optional<MoveableThrow>>::value);
+  EXPECT_FALSE(
+      std::is_copy_constructible<absl::optional<MoveableNoThrow>>::value);
+  EXPECT_FALSE(std::is_copy_constructible<absl::optional<NonMovable>>::value);
+
+  EXPECT_FALSE(
+      absl::is_trivially_copy_constructible<absl::optional<Copyable>>::value);
+#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(__GLIBCXX__)
+  // libstdc++ std::optional implementation (as of 7.2) has a bug: when T is
+  // trivially copyable, optional<T> is not trivially copyable (due to one of
+  // its base class is unconditionally nontrivial).
+#define ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG 1
+#endif
+#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
+  EXPECT_TRUE(
+      absl::is_trivially_copy_constructible<absl::optional<int>>::value);
+  EXPECT_TRUE(
+      absl::is_trivially_copy_constructible<absl::optional<const int>>::value);
+#ifndef _MSC_VER
+  // See defect report "Trivial copy/move constructor for class with volatile
+  // member" at
+  // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094
+  // A class with non-static data member of volatile-qualified type should still
+  // have a trivial copy constructor if the data member is trivial.
+  // Also a cv-qualified scalar type should be trivially copyable.
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<
+              absl::optional<volatile int>>::value);
+#endif  // _MSC_VER
+#endif  // ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
+
+  // constexpr copy constructor for trivially copyable types
+  {
+    constexpr absl::optional<int> o1;
+    constexpr absl::optional<int> o2 = o1;
+    static_assert(!o2, "");
+  }
+  {
+    constexpr absl::optional<int> o1 = 42;
+    constexpr absl::optional<int> o2 = o1;
+    static_assert(o2, "");
+    static_assert(*o2 == 42, "");
+  }
+  {
+    struct TrivialCopyable {
+      constexpr TrivialCopyable() : x(0) {}
+      constexpr explicit TrivialCopyable(int i) : x(i) {}
+      int x;
+    };
+    constexpr absl::optional<TrivialCopyable> o1(42);
+    constexpr absl::optional<TrivialCopyable> o2 = o1;
+    static_assert(o2, "");
+    static_assert((*o2).x == 42, "");
+#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
+    EXPECT_TRUE(absl::is_trivially_copy_constructible<
+                absl::optional<TrivialCopyable>>::value);
+    EXPECT_TRUE(absl::is_trivially_copy_constructible<
+                absl::optional<const TrivialCopyable>>::value);
+#endif
+    // When testing with VS 2017 15.3, there seems to be a bug in MSVC
+    // std::optional when T is volatile-qualified. So skipping this test.
+    // Bug report:
+    // https://connect.microsoft.com/VisualStudio/feedback/details/3142534
+#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(_MSC_VER) && _MSC_VER >= 1911
+#define ABSL_MSVC_OPTIONAL_VOLATILE_COPY_BUG 1
+#endif
+#ifndef ABSL_MSVC_OPTIONAL_VOLATILE_COPY_BUG
+    EXPECT_FALSE(std::is_copy_constructible<
+                 absl::optional<volatile TrivialCopyable>>::value);
+#endif
+  }
+}
+
+TEST(optionalTest, MoveConstructor) {
+  absl::optional<int> empty, opt42 = 42;
+  absl::optional<int> empty_move(std::move(empty));
+  EXPECT_FALSE(empty_move);
+  absl::optional<int> opt42_move(std::move(opt42));
+  EXPECT_TRUE(opt42_move);
+  EXPECT_EQ(42, opt42_move);
+  // test movability
+  EXPECT_TRUE(std::is_move_constructible<absl::optional<int>>::value);
+  EXPECT_TRUE(std::is_move_constructible<absl::optional<Copyable>>::value);
+  EXPECT_TRUE(std::is_move_constructible<absl::optional<MoveableThrow>>::value);
+  EXPECT_TRUE(
+      std::is_move_constructible<absl::optional<MoveableNoThrow>>::value);
+  EXPECT_FALSE(std::is_move_constructible<absl::optional<NonMovable>>::value);
+  // test noexcept
+  EXPECT_TRUE(std::is_nothrow_move_constructible<absl::optional<int>>::value);
+#ifndef ABSL_HAVE_STD_OPTIONAL
+  EXPECT_EQ(
+      absl::default_allocator_is_nothrow::value,
+      std::is_nothrow_move_constructible<absl::optional<MoveableThrow>>::value);
+#endif
+  EXPECT_TRUE(std::is_nothrow_move_constructible<
+              absl::optional<MoveableNoThrow>>::value);
+}
+
+TEST(optionalTest, Destructor) {
+  struct Trivial {};
+
+  struct NonTrivial {
+    NonTrivial(const NonTrivial&) {}
+    NonTrivial& operator=(const NonTrivial&) { return *this; }
+    ~NonTrivial() {}
+  };
+
+  EXPECT_TRUE(std::is_trivially_destructible<absl::optional<int>>::value);
+  EXPECT_TRUE(std::is_trivially_destructible<absl::optional<Trivial>>::value);
+  EXPECT_FALSE(
+      std::is_trivially_destructible<absl::optional<NonTrivial>>::value);
+}
+
+TEST(optionalTest, InPlaceConstructor) {
+  constexpr absl::optional<ConstexprType> opt0{absl::in_place_t()};
+  static_assert(opt0, "");
+  static_assert((*opt0).x == ConstexprType::kCtorDefault, "");
+  constexpr absl::optional<ConstexprType> opt1{absl::in_place_t(), 1};
+  static_assert(opt1, "");
+  static_assert((*opt1).x == ConstexprType::kCtorInt, "");
+#ifndef ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST
+  constexpr absl::optional<ConstexprType> opt2{absl::in_place_t(), {1, 2}};
+  static_assert(opt2, "");
+  static_assert((*opt2).x == ConstexprType::kCtorInitializerList, "");
+#endif
+
+  // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...>
+  // SFINAE is added to optional::optional(absl::in_place_t, Args&&...).
+  // struct I {
+  //   I(absl::in_place_t);
+  // };
+
+  // EXPECT_FALSE((std::is_constructible<absl::optional<I>,
+  // absl::in_place_t>::value));
+  // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const
+  // absl::in_place_t&>::value));
+}
+
+// template<U=T> optional(U&&);
+TEST(optionalTest, ValueConstructor) {
+  constexpr absl::optional<int> opt0(0);
+  static_assert(opt0, "");
+  static_assert(*opt0 == 0, "");
+  EXPECT_TRUE((std::is_convertible<int, absl::optional<int>>::value));
+  // Copy initialization ( = "abc") won't work due to optional(optional&&)
+  // is not constexpr. Use list initialization instead. This invokes
+  // absl::optional<ConstexprType>::absl::optional<U>(U&&), with U = const char
+  // (&) [4], which direct-initializes the ConstexprType value held by the
+  // optional via ConstexprType::ConstexprType(const char*).
+  constexpr absl::optional<ConstexprType> opt1 = {"abc"};
+  static_assert(opt1, "");
+  static_assert(ConstexprType::kCtorConstChar == (*opt1).x, "");
+  EXPECT_TRUE(
+      (std::is_convertible<const char*, absl::optional<ConstexprType>>::value));
+  // direct initialization
+  constexpr absl::optional<ConstexprType> opt2{2};
+  static_assert(opt2, "");
+  static_assert(ConstexprType::kCtorInt == (*opt2).x, "");
+  EXPECT_FALSE(
+      (std::is_convertible<int, absl::optional<ConstexprType>>::value));
+
+  // this invokes absl::optional<int>::optional(int&&)
+  // NOTE: this has different behavior than assignment, e.g.
+  // "opt3 = {};" clears the optional rather than setting the value to 0
+  // According to C++17 standard N4659 [over.ics.list] 16.3.3.1.5, (9.2)- "if
+  // the initializer list has no elements, the implicit conversion is the
+  // identity conversion", so `optional(int&&)` should be a better match than
+  // `optional(optional&&)` which is a user-defined conversion.
+  // Note: GCC 7 has a bug with this overload selection when compiled with
+  // `-std=c++17`.
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7 && \
+    __cplusplus == 201703L
+#define ABSL_GCC7_OVER_ICS_LIST_BUG 1
+#endif
+#ifndef ABSL_GCC7_OVER_ICS_LIST_BUG
+  constexpr absl::optional<int> opt3({});
+  static_assert(opt3, "");
+  static_assert(*opt3 == 0, "");
+#endif
+
+  // this invokes the move constructor with a default constructed optional
+  // because non-template function is a better match than template function.
+  absl::optional<ConstexprType> opt4({});
+  EXPECT_FALSE(opt4);
+}
+
+struct Implicit {};
+
+struct Explicit {};
+
+struct Convert {
+  Convert(const Implicit&)  // NOLINT(runtime/explicit)
+      : implicit(true), move(false) {}
+  Convert(Implicit&&)  // NOLINT(runtime/explicit)
+      : implicit(true), move(true) {}
+  explicit Convert(const Explicit&) : implicit(false), move(false) {}
+  explicit Convert(Explicit&&) : implicit(false), move(true) {}
+
+  bool implicit;
+  bool move;
+};
+
+struct ConvertFromOptional {
+  ConvertFromOptional(const Implicit&)  // NOLINT(runtime/explicit)
+      : implicit(true), move(false), from_optional(false) {}
+  ConvertFromOptional(Implicit&&)  // NOLINT(runtime/explicit)
+      : implicit(true), move(true), from_optional(false) {}
+  ConvertFromOptional(
+      const absl::optional<Implicit>&)  // NOLINT(runtime/explicit)
+      : implicit(true), move(false), from_optional(true) {}
+  ConvertFromOptional(absl::optional<Implicit>&&)  // NOLINT(runtime/explicit)
+      : implicit(true), move(true), from_optional(true) {}
+  explicit ConvertFromOptional(const Explicit&)
+      : implicit(false), move(false), from_optional(false) {}
+  explicit ConvertFromOptional(Explicit&&)
+      : implicit(false), move(true), from_optional(false) {}
+  explicit ConvertFromOptional(const absl::optional<Explicit>&)
+      : implicit(false), move(false), from_optional(true) {}
+  explicit ConvertFromOptional(absl::optional<Explicit>&&)
+      : implicit(false), move(true), from_optional(true) {}
+
+  bool implicit;
+  bool move;
+  bool from_optional;
+};
+
+TEST(optionalTest, ConvertingConstructor) {
+  absl::optional<Implicit> i_empty;
+  absl::optional<Implicit> i(absl::in_place);
+  absl::optional<Explicit> e_empty;
+  absl::optional<Explicit> e(absl::in_place);
+  {
+    // implicitly constructing absl::optional<Convert> from
+    // absl::optional<Implicit>
+    absl::optional<Convert> empty = i_empty;
+    EXPECT_FALSE(empty);
+    absl::optional<Convert> opt_copy = i;
+    EXPECT_TRUE(opt_copy);
+    EXPECT_TRUE(opt_copy->implicit);
+    EXPECT_FALSE(opt_copy->move);
+    absl::optional<Convert> opt_move = absl::optional<Implicit>(absl::in_place);
+    EXPECT_TRUE(opt_move);
+    EXPECT_TRUE(opt_move->implicit);
+    EXPECT_TRUE(opt_move->move);
+  }
+  {
+    // explicitly constructing absl::optional<Convert> from
+    // absl::optional<Explicit>
+    absl::optional<Convert> empty(e_empty);
+    EXPECT_FALSE(empty);
+    absl::optional<Convert> opt_copy(e);
+    EXPECT_TRUE(opt_copy);
+    EXPECT_FALSE(opt_copy->implicit);
+    EXPECT_FALSE(opt_copy->move);
+    EXPECT_FALSE((std::is_convertible<const absl::optional<Explicit>&,
+                                      absl::optional<Convert>>::value));
+    absl::optional<Convert> opt_move{absl::optional<Explicit>(absl::in_place)};
+    EXPECT_TRUE(opt_move);
+    EXPECT_FALSE(opt_move->implicit);
+    EXPECT_TRUE(opt_move->move);
+    EXPECT_FALSE((std::is_convertible<absl::optional<Explicit>&&,
+                                      absl::optional<Convert>>::value));
+  }
+  {
+    // implicitly constructing absl::optional<ConvertFromOptional> from
+    // absl::optional<Implicit> via
+    // ConvertFromOptional(absl::optional<Implicit>&&) check that
+    // ConvertFromOptional(Implicit&&) is NOT called
+    static_assert(
+        std::is_convertible<absl::optional<Implicit>,
+                            absl::optional<ConvertFromOptional>>::value,
+        "");
+    absl::optional<ConvertFromOptional> opt0 = i_empty;
+    EXPECT_TRUE(opt0);
+    EXPECT_TRUE(opt0->implicit);
+    EXPECT_FALSE(opt0->move);
+    EXPECT_TRUE(opt0->from_optional);
+    absl::optional<ConvertFromOptional> opt1 = absl::optional<Implicit>();
+    EXPECT_TRUE(opt1);
+    EXPECT_TRUE(opt1->implicit);
+    EXPECT_TRUE(opt1->move);
+    EXPECT_TRUE(opt1->from_optional);
+  }
+  {
+    // implicitly constructing absl::optional<ConvertFromOptional> from
+    // absl::optional<Explicit> via
+    // ConvertFromOptional(absl::optional<Explicit>&&) check that
+    // ConvertFromOptional(Explicit&&) is NOT called
+    absl::optional<ConvertFromOptional> opt0(e_empty);
+    EXPECT_TRUE(opt0);
+    EXPECT_FALSE(opt0->implicit);
+    EXPECT_FALSE(opt0->move);
+    EXPECT_TRUE(opt0->from_optional);
+    EXPECT_FALSE(
+        (std::is_convertible<const absl::optional<Explicit>&,
+                             absl::optional<ConvertFromOptional>>::value));
+    absl::optional<ConvertFromOptional> opt1{absl::optional<Explicit>()};
+    EXPECT_TRUE(opt1);
+    EXPECT_FALSE(opt1->implicit);
+    EXPECT_TRUE(opt1->move);
+    EXPECT_TRUE(opt1->from_optional);
+    EXPECT_FALSE(
+        (std::is_convertible<absl::optional<Explicit>&&,
+                             absl::optional<ConvertFromOptional>>::value));
+  }
+}
+
+TEST(optionalTest, StructorBasic) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+  {
+    absl::optional<Listenable> empty;
+    EXPECT_FALSE(empty);
+    absl::optional<Listenable> opt0(absl::in_place);
+    EXPECT_TRUE(opt0);
+    absl::optional<Listenable> opt1(absl::in_place, 1);
+    EXPECT_TRUE(opt1);
+    absl::optional<Listenable> opt2(absl::in_place, 1, 2);
+    EXPECT_TRUE(opt2);
+  }
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(1, listener.construct1);
+  EXPECT_EQ(1, listener.construct2);
+  EXPECT_EQ(3, listener.destruct);
+}
+
+TEST(optionalTest, CopyMoveStructor) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+  absl::optional<Listenable> original(absl::in_place);
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(0, listener.copy);
+  EXPECT_EQ(0, listener.move);
+  absl::optional<Listenable> copy(original);
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(1, listener.copy);
+  EXPECT_EQ(0, listener.move);
+  absl::optional<Listenable> move(std::move(original));
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(1, listener.copy);
+  EXPECT_EQ(1, listener.move);
+}
+
+TEST(optionalTest, ListInit) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+  absl::optional<Listenable> listinit1(absl::in_place, {1});
+  absl::optional<Listenable> listinit2(absl::in_place, {1, 2});
+  EXPECT_EQ(2, listener.listinit);
+}
+
+TEST(optionalTest, AssignFromNullopt) {
+  absl::optional<int> opt(1);
+  opt = absl::nullopt;
+  EXPECT_FALSE(opt);
+
+  StructorListener listener;
+  Listenable::listener = &listener;
+  absl::optional<Listenable> opt1(absl::in_place);
+  opt1 = absl::nullopt;
+  EXPECT_FALSE(opt1);
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(1, listener.destruct);
+
+  EXPECT_TRUE((
+      std::is_nothrow_assignable<absl::optional<int>, absl::nullopt_t>::value));
+  EXPECT_TRUE((std::is_nothrow_assignable<absl::optional<Listenable>,
+                                          absl::nullopt_t>::value));
+}
+
+TEST(optionalTest, CopyAssignment) {
+  const absl::optional<int> empty, opt1 = 1, opt2 = 2;
+  absl::optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty;
+
+  EXPECT_FALSE(empty_to_opt1);
+  empty_to_opt1 = empty;
+  EXPECT_FALSE(empty_to_opt1);
+  empty_to_opt1 = opt1;
+  EXPECT_TRUE(empty_to_opt1);
+  EXPECT_EQ(1, empty_to_opt1.value());
+
+  EXPECT_FALSE(opt1_to_opt2);
+  opt1_to_opt2 = opt1;
+  EXPECT_TRUE(opt1_to_opt2);
+  EXPECT_EQ(1, opt1_to_opt2.value());
+  opt1_to_opt2 = opt2;
+  EXPECT_TRUE(opt1_to_opt2);
+  EXPECT_EQ(2, opt1_to_opt2.value());
+
+  EXPECT_FALSE(opt2_to_empty);
+  opt2_to_empty = opt2;
+  EXPECT_TRUE(opt2_to_empty);
+  EXPECT_EQ(2, opt2_to_empty.value());
+  opt2_to_empty = empty;
+  EXPECT_FALSE(opt2_to_empty);
+
+  EXPECT_FALSE(std::is_copy_assignable<absl::optional<const int>>::value);
+  EXPECT_TRUE(std::is_copy_assignable<absl::optional<Copyable>>::value);
+  EXPECT_FALSE(std::is_copy_assignable<absl::optional<MoveableThrow>>::value);
+  EXPECT_FALSE(std::is_copy_assignable<absl::optional<MoveableNoThrow>>::value);
+  EXPECT_FALSE(std::is_copy_assignable<absl::optional<NonMovable>>::value);
+
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<volatile int>::value);
+
+  struct Trivial {
+    int i;
+  };
+  struct NonTrivial {
+    NonTrivial& operator=(const NonTrivial&) { return *this; }
+    int i;
+  };
+
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value);
+  EXPECT_FALSE(std::is_copy_assignable<const Trivial>::value);
+  EXPECT_FALSE(std::is_copy_assignable<volatile Trivial>::value);
+  EXPECT_TRUE(std::is_copy_assignable<NonTrivial>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<NonTrivial>::value);
+
+  // std::optional doesn't support volatile nontrivial types.
+#ifndef ABSL_HAVE_STD_OPTIONAL
+  {
+    StructorListener listener;
+    Listenable::listener = &listener;
+
+    absl::optional<volatile Listenable> empty, set(absl::in_place);
+    EXPECT_EQ(1, listener.construct0);
+    absl::optional<volatile Listenable> empty_to_empty, empty_to_set,
+        set_to_empty(absl::in_place), set_to_set(absl::in_place);
+    EXPECT_EQ(3, listener.construct0);
+    empty_to_empty = empty;  // no effect
+    empty_to_set = set;      // copy construct
+    set_to_empty = empty;    // destruct
+    set_to_set = set;        // copy assign
+    EXPECT_EQ(1, listener.volatile_copy);
+    EXPECT_EQ(0, listener.volatile_move);
+    EXPECT_EQ(1, listener.destruct);
+    EXPECT_EQ(1, listener.volatile_copy_assign);
+  }
+#endif  // ABSL_HAVE_STD_OPTIONAL
+}
+
+TEST(optionalTest, MoveAssignment) {
+  {
+    StructorListener listener;
+    Listenable::listener = &listener;
+
+    absl::optional<Listenable> empty1, empty2, set1(absl::in_place),
+        set2(absl::in_place);
+    EXPECT_EQ(2, listener.construct0);
+    absl::optional<Listenable> empty_to_empty, empty_to_set,
+        set_to_empty(absl::in_place), set_to_set(absl::in_place);
+    EXPECT_EQ(4, listener.construct0);
+    empty_to_empty = std::move(empty1);
+    empty_to_set = std::move(set1);
+    set_to_empty = std::move(empty2);
+    set_to_set = std::move(set2);
+    EXPECT_EQ(0, listener.copy);
+    EXPECT_EQ(1, listener.move);
+    EXPECT_EQ(1, listener.destruct);
+    EXPECT_EQ(1, listener.move_assign);
+  }
+  // std::optional doesn't support volatile nontrivial types.
+#ifndef ABSL_HAVE_STD_OPTIONAL
+  {
+    StructorListener listener;
+    Listenable::listener = &listener;
+
+    absl::optional<volatile Listenable> empty1, empty2, set1(absl::in_place),
+        set2(absl::in_place);
+    EXPECT_EQ(2, listener.construct0);
+    absl::optional<volatile Listenable> empty_to_empty, empty_to_set,
+        set_to_empty(absl::in_place), set_to_set(absl::in_place);
+    EXPECT_EQ(4, listener.construct0);
+    empty_to_empty = std::move(empty1);  // no effect
+    empty_to_set = std::move(set1);      // move construct
+    set_to_empty = std::move(empty2);    // destruct
+    set_to_set = std::move(set2);        // move assign
+    EXPECT_EQ(0, listener.volatile_copy);
+    EXPECT_EQ(1, listener.volatile_move);
+    EXPECT_EQ(1, listener.destruct);
+    EXPECT_EQ(1, listener.volatile_move_assign);
+  }
+#endif  // ABSL_HAVE_STD_OPTIONAL
+  EXPECT_FALSE(std::is_move_assignable<absl::optional<const int>>::value);
+  EXPECT_TRUE(std::is_move_assignable<absl::optional<Copyable>>::value);
+  EXPECT_TRUE(std::is_move_assignable<absl::optional<MoveableThrow>>::value);
+  EXPECT_TRUE(std::is_move_assignable<absl::optional<MoveableNoThrow>>::value);
+  EXPECT_FALSE(std::is_move_assignable<absl::optional<NonMovable>>::value);
+
+  EXPECT_FALSE(
+      std::is_nothrow_move_assignable<absl::optional<MoveableThrow>>::value);
+  EXPECT_TRUE(
+      std::is_nothrow_move_assignable<absl::optional<MoveableNoThrow>>::value);
+}
+
+struct NoConvertToOptional {
+  // disable implicit conversion from const NoConvertToOptional&
+  // to absl::optional<NoConvertToOptional>.
+  NoConvertToOptional(const NoConvertToOptional&) = delete;
+};
+
+struct CopyConvert {
+  CopyConvert(const NoConvertToOptional&);
+  CopyConvert& operator=(const CopyConvert&) = delete;
+  CopyConvert& operator=(const NoConvertToOptional&);
+};
+
+struct CopyConvertFromOptional {
+  CopyConvertFromOptional(const NoConvertToOptional&);
+  CopyConvertFromOptional(const absl::optional<NoConvertToOptional>&);
+  CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete;
+  CopyConvertFromOptional& operator=(const NoConvertToOptional&);
+  CopyConvertFromOptional& operator=(
+      const absl::optional<NoConvertToOptional>&);
+};
+
+struct MoveConvert {
+  MoveConvert(NoConvertToOptional&&);
+  MoveConvert& operator=(const MoveConvert&) = delete;
+  MoveConvert& operator=(NoConvertToOptional&&);
+};
+
+struct MoveConvertFromOptional {
+  MoveConvertFromOptional(NoConvertToOptional&&);
+  MoveConvertFromOptional(absl::optional<NoConvertToOptional>&&);
+  MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete;
+  MoveConvertFromOptional& operator=(NoConvertToOptional&&);
+  MoveConvertFromOptional& operator=(absl::optional<NoConvertToOptional>&&);
+};
+
+// template <typename U = T> absl::optional<T>& operator=(U&& v);
+TEST(optionalTest, ValueAssignment) {
+  absl::optional<int> opt;
+  EXPECT_FALSE(opt);
+  opt = 42;
+  EXPECT_TRUE(opt);
+  EXPECT_EQ(42, opt.value());
+  opt = absl::nullopt;
+  EXPECT_FALSE(opt);
+  opt = 42;
+  EXPECT_TRUE(opt);
+  EXPECT_EQ(42, opt.value());
+  opt = 43;
+  EXPECT_TRUE(opt);
+  EXPECT_EQ(43, opt.value());
+  opt = {};  // this should clear optional
+  EXPECT_FALSE(opt);
+
+  opt = {44};
+  EXPECT_TRUE(opt);
+  EXPECT_EQ(44, opt.value());
+
+  // U = const NoConvertToOptional&
+  EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvert>&,
+                                  const NoConvertToOptional&>::value));
+  // U = const absl::optional<NoConvertToOptional>&
+  EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvertFromOptional>&,
+                                  const NoConvertToOptional&>::value));
+  // U = const NoConvertToOptional& triggers SFINAE because
+  // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
+  EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvert>&,
+                                   const NoConvertToOptional&>::value));
+  // U = NoConvertToOptional
+  EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvert>&,
+                                  NoConvertToOptional&&>::value));
+  // U = const NoConvertToOptional& triggers SFINAE because
+  // std::is_constructible_v<MoveConvertFromOptional, const
+  // NoConvertToOptional&> is false
+  EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+                                   const NoConvertToOptional&>::value));
+  // U = NoConvertToOptional
+  EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+                                  NoConvertToOptional&&>::value));
+  // U = const absl::optional<NoConvertToOptional>&
+  EXPECT_TRUE(
+      (std::is_assignable<absl::optional<CopyConvertFromOptional>&,
+                          const absl::optional<NoConvertToOptional>&>::value));
+  // U = absl::optional<NoConvertToOptional>
+  EXPECT_TRUE(
+      (std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+                          absl::optional<NoConvertToOptional>&&>::value));
+}
+
+// template <typename U> absl::optional<T>& operator=(const absl::optional<U>&
+// rhs); template <typename U> absl::optional<T>& operator=(absl::optional<U>&&
+// rhs);
+TEST(optionalTest, ConvertingAssignment) {
+  absl::optional<int> opt_i;
+  absl::optional<char> opt_c('c');
+  opt_i = opt_c;
+  EXPECT_TRUE(opt_i);
+  EXPECT_EQ(*opt_c, *opt_i);
+  opt_i = absl::optional<char>();
+  EXPECT_FALSE(opt_i);
+  opt_i = absl::optional<char>('d');
+  EXPECT_TRUE(opt_i);
+  EXPECT_EQ('d', *opt_i);
+
+  absl::optional<std::string> opt_str;
+  absl::optional<const char*> opt_cstr("abc");
+  opt_str = opt_cstr;
+  EXPECT_TRUE(opt_str);
+  EXPECT_EQ(std::string("abc"), *opt_str);
+  opt_str = absl::optional<const char*>();
+  EXPECT_FALSE(opt_str);
+  opt_str = absl::optional<const char*>("def");
+  EXPECT_TRUE(opt_str);
+  EXPECT_EQ(std::string("def"), *opt_str);
+
+  // operator=(const absl::optional<U>&) with U = NoConvertToOptional
+  EXPECT_TRUE(
+      (std::is_assignable<absl::optional<CopyConvert>,
+                          const absl::optional<NoConvertToOptional>&>::value));
+  // operator=(const absl::optional<U>&) with U = NoConvertToOptional
+  // triggers SFINAE because
+  // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
+  EXPECT_FALSE(
+      (std::is_assignable<absl::optional<MoveConvert>&,
+                          const absl::optional<NoConvertToOptional>&>::value));
+  // operator=(absl::optional<U>&&) with U = NoConvertToOptional
+  EXPECT_TRUE(
+      (std::is_assignable<absl::optional<MoveConvert>&,
+                          absl::optional<NoConvertToOptional>&&>::value));
+  // operator=(const absl::optional<U>&) with U = NoConvertToOptional triggers
+  // SFINAE because std::is_constructible_v<MoveConvertFromOptional, const
+  // NoConvertToOptional&> is false. operator=(U&&) with U = const
+  // absl::optional<NoConverToOptional>& triggers SFINAE because
+  // std::is_constructible<MoveConvertFromOptional,
+  // absl::optional<NoConvertToOptional>&&> is true.
+  EXPECT_FALSE(
+      (std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+                          const absl::optional<NoConvertToOptional>&>::value));
+}
+
+TEST(optionalTest, ResetAndHasValue) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+  absl::optional<Listenable> opt;
+  EXPECT_FALSE(opt);
+  EXPECT_FALSE(opt.has_value());
+  opt.emplace();
+  EXPECT_TRUE(opt);
+  EXPECT_TRUE(opt.has_value());
+  opt.reset();
+  EXPECT_FALSE(opt);
+  EXPECT_FALSE(opt.has_value());
+  EXPECT_EQ(1, listener.destruct);
+  opt.reset();
+  EXPECT_FALSE(opt);
+  EXPECT_FALSE(opt.has_value());
+
+  constexpr absl::optional<int> empty;
+  static_assert(!empty.has_value(), "");
+  constexpr absl::optional<int> nonempty(1);
+  static_assert(nonempty.has_value(), "");
+}
+
+TEST(optionalTest, Emplace) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+  absl::optional<Listenable> opt;
+  EXPECT_FALSE(opt);
+  opt.emplace(1);
+  EXPECT_TRUE(opt);
+  opt.emplace(1, 2);
+  EXPECT_EQ(1, listener.construct1);
+  EXPECT_EQ(1, listener.construct2);
+  EXPECT_EQ(1, listener.destruct);
+
+  absl::optional<std::string> o;
+  EXPECT_TRUE((std::is_same<std::string&, decltype(o.emplace("abc"))>::value));
+  std::string& ref = o.emplace("abc");
+  EXPECT_EQ(&ref, &o.value());
+}
+
+TEST(optionalTest, ListEmplace) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+  absl::optional<Listenable> opt;
+  EXPECT_FALSE(opt);
+  opt.emplace({1});
+  EXPECT_TRUE(opt);
+  opt.emplace({1, 2});
+  EXPECT_EQ(2, listener.listinit);
+  EXPECT_EQ(1, listener.destruct);
+
+  absl::optional<Listenable> o;
+  EXPECT_TRUE((std::is_same<Listenable&, decltype(o.emplace({1}))>::value));
+  Listenable& ref = o.emplace({1});
+  EXPECT_EQ(&ref, &o.value());
+}
+
+TEST(optionalTest, Swap) {
+  absl::optional<int> opt_empty, opt1 = 1, opt2 = 2;
+  EXPECT_FALSE(opt_empty);
+  EXPECT_TRUE(opt1);
+  EXPECT_EQ(1, opt1.value());
+  EXPECT_TRUE(opt2);
+  EXPECT_EQ(2, opt2.value());
+  swap(opt_empty, opt1);
+  EXPECT_FALSE(opt1);
+  EXPECT_TRUE(opt_empty);
+  EXPECT_EQ(1, opt_empty.value());
+  EXPECT_TRUE(opt2);
+  EXPECT_EQ(2, opt2.value());
+  swap(opt_empty, opt1);
+  EXPECT_FALSE(opt_empty);
+  EXPECT_TRUE(opt1);
+  EXPECT_EQ(1, opt1.value());
+  EXPECT_TRUE(opt2);
+  EXPECT_EQ(2, opt2.value());
+  swap(opt1, opt2);
+  EXPECT_FALSE(opt_empty);
+  EXPECT_TRUE(opt1);
+  EXPECT_EQ(2, opt1.value());
+  EXPECT_TRUE(opt2);
+  EXPECT_EQ(1, opt2.value());
+
+  EXPECT_TRUE(noexcept(opt1.swap(opt2)));
+  EXPECT_TRUE(noexcept(swap(opt1, opt2)));
+}
+
+template <int v>
+struct DeletedOpAddr {
+  constexpr static const int value = v;
+  constexpr DeletedOpAddr() = default;
+  constexpr const DeletedOpAddr<v>* operator&() const = delete;  // NOLINT
+  DeletedOpAddr<v>* operator&() = delete;                        // NOLINT
+};
+
+// The static_assert featuring a constexpr call to operator->() is commented out
+// to document the fact that the current implementation of absl::optional<T>
+// expects such usecases to be malformed and not compile.
+TEST(optionalTest, OperatorAddr) {
+  constexpr const int v = -1;
+  {  // constexpr
+    constexpr const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{});
+    static_assert(opt.has_value(), "");
+    // static_assert(opt->value == v, "");
+    static_assert((*opt).value == v, "");
+  }
+  {  // non-constexpr
+    const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{});
+    EXPECT_TRUE(opt.has_value());
+    EXPECT_TRUE(opt->value == v);
+    EXPECT_TRUE((*opt).value == v);
+  }
+}
+
+TEST(optionalTest, PointerStuff) {
+  absl::optional<std::string> opt(absl::in_place, "foo");
+  EXPECT_EQ("foo", *opt);
+  const auto& opt_const = opt;
+  EXPECT_EQ("foo", *opt_const);
+  EXPECT_EQ(opt->size(), 3);
+  EXPECT_EQ(opt_const->size(), 3);
+
+  constexpr absl::optional<ConstexprType> opt1(1);
+  static_assert((*opt1).x == ConstexprType::kCtorInt, "");
+}
+
+// gcc has a bug pre 4.9.1 where it doesn't do correct overload resolution
+// when overloads are const-qualified and *this is an raluve.
+// Skip that test to make the build green again when using the old compiler.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59296 is fixed in 4.9.1.
+#if defined(__GNUC__) && !defined(__clang__)
+#define GCC_VERSION (__GNUC__ * 10000 \
+                     + __GNUC_MINOR__ * 100 \
+                     + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION < 40901
+#define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
+#endif
+#endif
+
+// MSVC has a bug with "cv-qualifiers in class construction", fixed in 2017. See
+// https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017#bug-fixes
+// The compiler some incorrectly ingores the cv-qualifier when generating a
+// class object via a constructor call. For example:
+//
+// class optional {
+//   constexpr T&& value() &&;
+//   constexpr const T&& value() const &&;
+// }
+//
+// using COI = const absl::optional<int>;
+// static_assert(2 == COI(2).value(), "");  // const &&
+//
+// This should invoke the "const &&" overload but since it ignores the const
+// qualifier it finds the "&&" overload the best candidate.
+#if defined(_MSC_VER) && _MSC_VER < 1910
+#define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG
+#endif
+
+TEST(optionalTest, Value) {
+  using O = absl::optional<std::string>;
+  using CO = const absl::optional<std::string>;
+  using OC = absl::optional<const std::string>;
+  O lvalue(absl::in_place, "lvalue");
+  CO clvalue(absl::in_place, "clvalue");
+  OC lvalue_c(absl::in_place, "lvalue_c");
+  EXPECT_EQ("lvalue", lvalue.value());
+  EXPECT_EQ("clvalue", clvalue.value());
+  EXPECT_EQ("lvalue_c", lvalue_c.value());
+  EXPECT_EQ("xvalue", O(absl::in_place, "xvalue").value());
+  EXPECT_EQ("xvalue_c", OC(absl::in_place, "xvalue_c").value());
+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
+  EXPECT_EQ("cxvalue", CO(absl::in_place, "cxvalue").value());
+#endif
+  EXPECT_EQ("&", TypeQuals(lvalue.value()));
+  EXPECT_EQ("c&", TypeQuals(clvalue.value()));
+  EXPECT_EQ("c&", TypeQuals(lvalue_c.value()));
+  EXPECT_EQ("&&", TypeQuals(O(absl::in_place, "xvalue").value()));
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+    !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+  EXPECT_EQ("c&&", TypeQuals(CO(absl::in_place, "cxvalue").value()));
+#endif
+  EXPECT_EQ("c&&", TypeQuals(OC(absl::in_place, "xvalue_c").value()));
+
+  // test on volatile type
+  using OV = absl::optional<volatile int>;
+  OV lvalue_v(absl::in_place, 42);
+  EXPECT_EQ(42, lvalue_v.value());
+  EXPECT_EQ(42, OV(42).value());
+  EXPECT_TRUE((std::is_same<volatile int&, decltype(lvalue_v.value())>::value));
+  EXPECT_TRUE((std::is_same<volatile int&&, decltype(OV(42).value())>::value));
+
+  // test exception throw on value()
+  absl::optional<int> empty;
+#ifdef ABSL_HAVE_EXCEPTIONS
+  EXPECT_THROW(empty.value(), absl::bad_optional_access);
+#else
+  EXPECT_DEATH(empty.value(), "Bad optional access");
+#endif
+
+  // test constexpr value()
+  constexpr absl::optional<int> o1(1);
+  static_assert(1 == o1.value(), "");  // const &
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+    !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+  using COI = const absl::optional<int>;
+  static_assert(2 == COI(2).value(), "");  // const &&
+#endif
+}
+
+TEST(optionalTest, DerefOperator) {
+  using O = absl::optional<std::string>;
+  using CO = const absl::optional<std::string>;
+  using OC = absl::optional<const std::string>;
+  O lvalue(absl::in_place, "lvalue");
+  CO clvalue(absl::in_place, "clvalue");
+  OC lvalue_c(absl::in_place, "lvalue_c");
+  EXPECT_EQ("lvalue", *lvalue);
+  EXPECT_EQ("clvalue", *clvalue);
+  EXPECT_EQ("lvalue_c", *lvalue_c);
+  EXPECT_EQ("xvalue", *O(absl::in_place, "xvalue"));
+  EXPECT_EQ("xvalue_c", *OC(absl::in_place, "xvalue_c"));
+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
+  EXPECT_EQ("cxvalue", *CO(absl::in_place, "cxvalue"));
+#endif
+  EXPECT_EQ("&", TypeQuals(*lvalue));
+  EXPECT_EQ("c&", TypeQuals(*clvalue));
+  EXPECT_EQ("&&", TypeQuals(*O(absl::in_place, "xvalue")));
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+    !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+  EXPECT_EQ("c&&", TypeQuals(*CO(absl::in_place, "cxvalue")));
+#endif
+  EXPECT_EQ("c&&", TypeQuals(*OC(absl::in_place, "xvalue_c")));
+
+  // test on volatile type
+  using OV = absl::optional<volatile int>;
+  OV lvalue_v(absl::in_place, 42);
+  EXPECT_EQ(42, *lvalue_v);
+  EXPECT_EQ(42, *OV(42));
+  EXPECT_TRUE((std::is_same<volatile int&, decltype(*lvalue_v)>::value));
+  EXPECT_TRUE((std::is_same<volatile int&&, decltype(*OV(42))>::value));
+
+  constexpr absl::optional<int> opt1(1);
+  static_assert(*opt1 == 1, "");
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+    !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+  using COI = const absl::optional<int>;
+  static_assert(*COI(2) == 2, "");
+#endif
+}
+
+TEST(optionalTest, ValueOr) {
+  absl::optional<double> opt_empty, opt_set = 1.2;
+  EXPECT_EQ(42.0, opt_empty.value_or(42));
+  EXPECT_EQ(1.2, opt_set.value_or(42));
+  EXPECT_EQ(42.0, absl::optional<double>().value_or(42));
+  EXPECT_EQ(1.2, absl::optional<double>(1.2).value_or(42));
+
+  constexpr absl::optional<double> copt_empty, copt_set = {1.2};
+  static_assert(42.0 == copt_empty.value_or(42), "");
+  static_assert(1.2 == copt_set.value_or(42), "");
+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG
+  using COD = const absl::optional<double>;
+  static_assert(42.0 == COD().value_or(42), "");
+  static_assert(1.2 == COD(1.2).value_or(42), "");
+#endif
+}
+
+// make_optional cannot be constexpr until C++17
+TEST(optionalTest, make_optional) {
+  auto opt_int = absl::make_optional(42);
+  EXPECT_TRUE((std::is_same<decltype(opt_int), absl::optional<int>>::value));
+  EXPECT_EQ(42, opt_int);
+
+  StructorListener listener;
+  Listenable::listener = &listener;
+
+  absl::optional<Listenable> opt0 = absl::make_optional<Listenable>();
+  EXPECT_EQ(1, listener.construct0);
+  absl::optional<Listenable> opt1 = absl::make_optional<Listenable>(1);
+  EXPECT_EQ(1, listener.construct1);
+  absl::optional<Listenable> opt2 = absl::make_optional<Listenable>(1, 2);
+  EXPECT_EQ(1, listener.construct2);
+  absl::optional<Listenable> opt3 = absl::make_optional<Listenable>({1});
+  absl::optional<Listenable> opt4 = absl::make_optional<Listenable>({1, 2});
+  EXPECT_EQ(2, listener.listinit);
+
+  // Constexpr tests on trivially copyable types
+  // optional<T> has trivial copy/move ctors when T is trivially copyable.
+  // For nontrivial types with constexpr constructors, we need copy elision in
+  // C++17 for make_optional to be constexpr.
+  {
+    constexpr absl::optional<int> c_opt = absl::make_optional(42);
+    static_assert(c_opt.value() == 42, "");
+  }
+  {
+    struct TrivialCopyable {
+      constexpr TrivialCopyable() : x(0) {}
+      constexpr explicit TrivialCopyable(int i) : x(i) {}
+      int x;
+    };
+
+    constexpr TrivialCopyable v;
+    constexpr absl::optional<TrivialCopyable> c_opt0 = absl::make_optional(v);
+    static_assert((*c_opt0).x == 0, "");
+    constexpr absl::optional<TrivialCopyable> c_opt1 =
+        absl::make_optional<TrivialCopyable>();
+    static_assert((*c_opt1).x == 0, "");
+    constexpr absl::optional<TrivialCopyable> c_opt2 =
+        absl::make_optional<TrivialCopyable>(42);
+    static_assert((*c_opt2).x == 42, "");
+  }
+}
+
+template <typename T, typename U>
+void optionalTest_Comparisons_EXPECT_LESS(T x, U y) {
+  EXPECT_FALSE(x == y);
+  EXPECT_TRUE(x != y);
+  EXPECT_TRUE(x < y);
+  EXPECT_FALSE(x > y);
+  EXPECT_TRUE(x <= y);
+  EXPECT_FALSE(x >= y);
+}
+
+template <typename T, typename U>
+void optionalTest_Comparisons_EXPECT_SAME(T x, U y) {
+  EXPECT_TRUE(x == y);
+  EXPECT_FALSE(x != y);
+  EXPECT_FALSE(x < y);
+  EXPECT_FALSE(x > y);
+  EXPECT_TRUE(x <= y);
+  EXPECT_TRUE(x >= y);
+}
+
+template <typename T, typename U>
+void optionalTest_Comparisons_EXPECT_GREATER(T x, U y) {
+  EXPECT_FALSE(x == y);
+  EXPECT_TRUE(x != y);
+  EXPECT_FALSE(x < y);
+  EXPECT_TRUE(x > y);
+  EXPECT_FALSE(x <= y);
+  EXPECT_TRUE(x >= y);
+}
+
+
+template <typename T, typename U, typename V>
+void TestComparisons() {
+  absl::optional<T> ae, a2{2}, a4{4};
+  absl::optional<U> be, b2{2}, b4{4};
+  V v3 = 3;
+
+  // LHS: absl::nullopt, ae, a2, v3, a4
+  // RHS: absl::nullopt, be, b2, v3, b4
+
+  // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,absl::nullopt);
+  optionalTest_Comparisons_EXPECT_SAME(absl::nullopt, be);
+  optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b2);
+  // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,v3);
+  optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b4);
+
+  optionalTest_Comparisons_EXPECT_SAME(ae, absl::nullopt);
+  optionalTest_Comparisons_EXPECT_SAME(ae, be);
+  optionalTest_Comparisons_EXPECT_LESS(ae, b2);
+  optionalTest_Comparisons_EXPECT_LESS(ae, v3);
+  optionalTest_Comparisons_EXPECT_LESS(ae, b4);
+
+  optionalTest_Comparisons_EXPECT_GREATER(a2, absl::nullopt);
+  optionalTest_Comparisons_EXPECT_GREATER(a2, be);
+  optionalTest_Comparisons_EXPECT_SAME(a2, b2);
+  optionalTest_Comparisons_EXPECT_LESS(a2, v3);
+  optionalTest_Comparisons_EXPECT_LESS(a2, b4);
+
+  // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(v3,absl::nullopt);
+  optionalTest_Comparisons_EXPECT_GREATER(v3, be);
+  optionalTest_Comparisons_EXPECT_GREATER(v3, b2);
+  optionalTest_Comparisons_EXPECT_SAME(v3, v3);
+  optionalTest_Comparisons_EXPECT_LESS(v3, b4);
+
+  optionalTest_Comparisons_EXPECT_GREATER(a4, absl::nullopt);
+  optionalTest_Comparisons_EXPECT_GREATER(a4, be);
+  optionalTest_Comparisons_EXPECT_GREATER(a4, b2);
+  optionalTest_Comparisons_EXPECT_GREATER(a4, v3);
+  optionalTest_Comparisons_EXPECT_SAME(a4, b4);
+}
+
+struct Int1 {
+  Int1() = default;
+  Int1(int i) : i(i) {}  // NOLINT(runtime/explicit)
+  int i;
+};
+
+struct Int2 {
+  Int2() = default;
+  Int2(int i) : i(i) {}  // NOLINT(runtime/explicit)
+  int i;
+};
+
+// comparison between Int1 and Int2
+constexpr bool operator==(const Int1& lhs, const Int2& rhs) {
+  return lhs.i == rhs.i;
+}
+constexpr bool operator!=(const Int1& lhs, const Int2& rhs) {
+  return !(lhs == rhs);
+}
+constexpr bool operator<(const Int1& lhs, const Int2& rhs) {
+  return lhs.i < rhs.i;
+}
+constexpr bool operator<=(const Int1& lhs, const Int2& rhs) {
+  return lhs < rhs || lhs == rhs;
+}
+constexpr bool operator>(const Int1& lhs, const Int2& rhs) {
+  return !(lhs <= rhs);
+}
+constexpr bool operator>=(const Int1& lhs, const Int2& rhs) {
+  return !(lhs < rhs);
+}
+
+TEST(optionalTest, Comparisons) {
+  TestComparisons<int, int, int>();
+  TestComparisons<const int, int, int>();
+  TestComparisons<Int1, int, int>();
+  TestComparisons<int, Int2, int>();
+  TestComparisons<Int1, Int2, int>();
+
+  // compare absl::optional<std::string> with const char*
+  absl::optional<std::string> opt_str = "abc";
+  const char* cstr = "abc";
+  EXPECT_TRUE(opt_str == cstr);
+  // compare absl::optional<std::string> with absl::optional<const char*>
+  absl::optional<const char*> opt_cstr = cstr;
+  EXPECT_TRUE(opt_str == opt_cstr);
+  // compare absl::optional<std::string> with absl::optional<absl::string_view>
+  absl::optional<absl::string_view> e1;
+  absl::optional<std::string> e2;
+  EXPECT_TRUE(e1 == e2);
+}
+
+
+TEST(optionalTest, SwapRegression) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+
+  {
+    absl::optional<Listenable> a;
+    absl::optional<Listenable> b(absl::in_place);
+    a.swap(b);
+  }
+
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(1, listener.move);
+  EXPECT_EQ(2, listener.destruct);
+
+  {
+    absl::optional<Listenable> a(absl::in_place);
+    absl::optional<Listenable> b;
+    a.swap(b);
+  }
+
+  EXPECT_EQ(2, listener.construct0);
+  EXPECT_EQ(2, listener.move);
+  EXPECT_EQ(4, listener.destruct);
+}
+
+TEST(optionalTest, BigStringLeakCheck) {
+  constexpr size_t n = 1 << 16;
+
+  using OS = absl::optional<std::string>;
+
+  OS a;
+  OS b = absl::nullopt;
+  OS c = std::string(n, 'c');
+  std::string sd(n, 'd');
+  OS d = sd;
+  OS e(absl::in_place, n, 'e');
+  OS f;
+  f.emplace(n, 'f');
+
+  OS ca(a);
+  OS cb(b);
+  OS cc(c);
+  OS cd(d);
+  OS ce(e);
+
+  OS oa;
+  OS ob = absl::nullopt;
+  OS oc = std::string(n, 'c');
+  std::string sod(n, 'd');
+  OS od = sod;
+  OS oe(absl::in_place, n, 'e');
+  OS of;
+  of.emplace(n, 'f');
+
+  OS ma(std::move(oa));
+  OS mb(std::move(ob));
+  OS mc(std::move(oc));
+  OS md(std::move(od));
+  OS me(std::move(oe));
+  OS mf(std::move(of));
+
+  OS aa1;
+  OS ab1 = absl::nullopt;
+  OS ac1 = std::string(n, 'c');
+  std::string sad1(n, 'd');
+  OS ad1 = sad1;
+  OS ae1(absl::in_place, n, 'e');
+  OS af1;
+  af1.emplace(n, 'f');
+
+  OS aa2;
+  OS ab2 = absl::nullopt;
+  OS ac2 = std::string(n, 'c');
+  std::string sad2(n, 'd');
+  OS ad2 = sad2;
+  OS ae2(absl::in_place, n, 'e');
+  OS af2;
+  af2.emplace(n, 'f');
+
+  aa1 = af2;
+  ab1 = ae2;
+  ac1 = ad2;
+  ad1 = ac2;
+  ae1 = ab2;
+  af1 = aa2;
+
+  OS aa3;
+  OS ab3 = absl::nullopt;
+  OS ac3 = std::string(n, 'c');
+  std::string sad3(n, 'd');
+  OS ad3 = sad3;
+  OS ae3(absl::in_place, n, 'e');
+  OS af3;
+  af3.emplace(n, 'f');
+
+  aa3 = absl::nullopt;
+  ab3 = absl::nullopt;
+  ac3 = absl::nullopt;
+  ad3 = absl::nullopt;
+  ae3 = absl::nullopt;
+  af3 = absl::nullopt;
+
+  OS aa4;
+  OS ab4 = absl::nullopt;
+  OS ac4 = std::string(n, 'c');
+  std::string sad4(n, 'd');
+  OS ad4 = sad4;
+  OS ae4(absl::in_place, n, 'e');
+  OS af4;
+  af4.emplace(n, 'f');
+
+  aa4 = OS(absl::in_place, n, 'a');
+  ab4 = OS(absl::in_place, n, 'b');
+  ac4 = OS(absl::in_place, n, 'c');
+  ad4 = OS(absl::in_place, n, 'd');
+  ae4 = OS(absl::in_place, n, 'e');
+  af4 = OS(absl::in_place, n, 'f');
+
+  OS aa5;
+  OS ab5 = absl::nullopt;
+  OS ac5 = std::string(n, 'c');
+  std::string sad5(n, 'd');
+  OS ad5 = sad5;
+  OS ae5(absl::in_place, n, 'e');
+  OS af5;
+  af5.emplace(n, 'f');
+
+  std::string saa5(n, 'a');
+  std::string sab5(n, 'a');
+  std::string sac5(n, 'a');
+  std::string sad52(n, 'a');
+  std::string sae5(n, 'a');
+  std::string saf5(n, 'a');
+
+  aa5 = saa5;
+  ab5 = sab5;
+  ac5 = sac5;
+  ad5 = sad52;
+  ae5 = sae5;
+  af5 = saf5;
+
+  OS aa6;
+  OS ab6 = absl::nullopt;
+  OS ac6 = std::string(n, 'c');
+  std::string sad6(n, 'd');
+  OS ad6 = sad6;
+  OS ae6(absl::in_place, n, 'e');
+  OS af6;
+  af6.emplace(n, 'f');
+
+  aa6 = std::string(n, 'a');
+  ab6 = std::string(n, 'b');
+  ac6 = std::string(n, 'c');
+  ad6 = std::string(n, 'd');
+  ae6 = std::string(n, 'e');
+  af6 = std::string(n, 'f');
+
+  OS aa7;
+  OS ab7 = absl::nullopt;
+  OS ac7 = std::string(n, 'c');
+  std::string sad7(n, 'd');
+  OS ad7 = sad7;
+  OS ae7(absl::in_place, n, 'e');
+  OS af7;
+  af7.emplace(n, 'f');
+
+  aa7.emplace(n, 'A');
+  ab7.emplace(n, 'B');
+  ac7.emplace(n, 'C');
+  ad7.emplace(n, 'D');
+  ae7.emplace(n, 'E');
+  af7.emplace(n, 'F');
+}
+
+TEST(optionalTest, MoveAssignRegression) {
+  StructorListener listener;
+  Listenable::listener = &listener;
+
+  {
+    absl::optional<Listenable> a;
+    Listenable b;
+    a = std::move(b);
+  }
+
+  EXPECT_EQ(1, listener.construct0);
+  EXPECT_EQ(1, listener.move);
+  EXPECT_EQ(2, listener.destruct);
+}
+
+TEST(optionalTest, ValueType) {
+  EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value));
+  EXPECT_TRUE(
+      (std::is_same<absl::optional<std::string>::value_type, std::string>::value));
+  EXPECT_FALSE(
+      (std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value));
+}
+
+template <typename T>
+struct is_hash_enabled_for {
+  template <typename U, typename = decltype(std::hash<U>()(std::declval<U>()))>
+  static std::true_type test(int);
+
+  template <typename U>
+  static std::false_type test(...);
+
+  static constexpr bool value = decltype(test<T>(0))::value;
+};
+
+TEST(optionalTest, Hash) {
+  std::hash<absl::optional<int>> hash;
+  std::set<size_t> hashcodes;
+  hashcodes.insert(hash(absl::nullopt));
+  for (int i = 0; i < 100; ++i) {
+    hashcodes.insert(hash(i));
+  }
+  EXPECT_GT(hashcodes.size(), 90);
+
+  static_assert(is_hash_enabled_for<absl::optional<int>>::value, "");
+  static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, "");
+
+#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
+                          _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
+  // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
+  // static_assert to catch any user-defined type that doesn't provide a hash
+  // specialization. So instantiating std::hash<absl::optional<T>> will result
+  // in a hard error which is not SFINAE friendly.
+#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
+#endif
+
+#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
+  static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, "");
+#endif
+
+  // libstdc++ std::optional is missing remove_const_t, i.e. it's using
+  // std::hash<T> rather than std::hash<std::remove_const_t<T>>.
+  // Reference: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82262
+#ifndef __GLIBCXX__
+  static_assert(is_hash_enabled_for<absl::optional<const int>>::value, "");
+  static_assert(is_hash_enabled_for<absl::optional<const Hashable>>::value, "");
+  std::hash<absl::optional<const int>> c_hash;
+  for (int i = 0; i < 100; ++i) {
+    EXPECT_EQ(hash(i), c_hash(i));
+  }
+#endif
+}
+
+struct MoveMeNoThrow {
+  MoveMeNoThrow() : x(0) {}
+  [[noreturn]] MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) {
+    ABSL_RAW_LOG(FATAL, "Should not be called.");
+    abort();
+  }
+  MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {}
+  int x;
+};
+
+struct MoveMeThrow {
+  MoveMeThrow() : x(0) {}
+  MoveMeThrow(const MoveMeThrow& other) : x(other.x) {}
+  MoveMeThrow(MoveMeThrow&& other) : x(other.x) {}
+  int x;
+};
+
+TEST(optionalTest, NoExcept) {
+  static_assert(
+      std::is_nothrow_move_constructible<absl::optional<MoveMeNoThrow>>::value,
+      "");
+#ifndef ABSL_HAVE_STD_OPTIONAL
+  static_assert(absl::default_allocator_is_nothrow::value ==
+                    std::is_nothrow_move_constructible<
+                        absl::optional<MoveMeThrow>>::value,
+                "");
+#endif
+  std::vector<absl::optional<MoveMeNoThrow>> v;
+  for (int i = 0; i < 10; ++i) v.emplace_back();
+}
+
+struct AnyLike {
+  AnyLike(AnyLike&&) = default;
+  AnyLike(const AnyLike&) = default;
+
+  template <typename ValueType,
+            typename T = typename std::decay<ValueType>::type,
+            typename std::enable_if<
+                !absl::disjunction<
+                    std::is_same<AnyLike, T>,
+                    absl::negation<std::is_copy_constructible<T>>>::value,
+                int>::type = 0>
+  AnyLike(ValueType&&) {}  // NOLINT(runtime/explicit)
+
+  AnyLike& operator=(AnyLike&&) = default;
+  AnyLike& operator=(const AnyLike&) = default;
+
+  template <typename ValueType,
+            typename T = typename std::decay<ValueType>::type>
+  typename std::enable_if<
+      absl::conjunction<absl::negation<std::is_same<AnyLike, T>>,
+                        std::is_copy_constructible<T>>::value,
+      AnyLike&>::type
+  operator=(ValueType&& /* rhs */) {
+    return *this;
+  }
+};
+
+TEST(optionalTest, ConstructionConstraints) {
+  EXPECT_TRUE((std::is_constructible<AnyLike, absl::optional<AnyLike>>::value));
+
+  EXPECT_TRUE(
+      (std::is_constructible<AnyLike, const absl::optional<AnyLike>&>::value));
+
+  EXPECT_TRUE((std::is_constructible<absl::optional<AnyLike>, AnyLike>::value));
+  EXPECT_TRUE(
+      (std::is_constructible<absl::optional<AnyLike>, const AnyLike&>::value));
+
+  EXPECT_TRUE((std::is_convertible<absl::optional<AnyLike>, AnyLike>::value));
+
+  EXPECT_TRUE(
+      (std::is_convertible<const absl::optional<AnyLike>&, AnyLike>::value));
+
+  EXPECT_TRUE((std::is_convertible<AnyLike, absl::optional<AnyLike>>::value));
+  EXPECT_TRUE(
+      (std::is_convertible<const AnyLike&, absl::optional<AnyLike>>::value));
+
+  EXPECT_TRUE(std::is_move_constructible<absl::optional<AnyLike>>::value);
+  EXPECT_TRUE(std::is_copy_constructible<absl::optional<AnyLike>>::value);
+}
+
+TEST(optionalTest, AssignmentConstraints) {
+  EXPECT_TRUE((std::is_assignable<AnyLike&, absl::optional<AnyLike>>::value));
+  EXPECT_TRUE(
+      (std::is_assignable<AnyLike&, const absl::optional<AnyLike>&>::value));
+  EXPECT_TRUE((std::is_assignable<absl::optional<AnyLike>&, AnyLike>::value));
+  EXPECT_TRUE(
+      (std::is_assignable<absl::optional<AnyLike>&, const AnyLike&>::value));
+  EXPECT_TRUE(std::is_move_assignable<absl::optional<AnyLike>>::value);
+  EXPECT_TRUE(std::is_copy_assignable<absl::optional<AnyLike>>::value);
+}
+
+}  // namespace
diff --git a/absl/types/span.h b/absl/types/span.h
new file mode 100644
index 0000000..76be819
--- /dev/null
+++ b/absl/types/span.h
@@ -0,0 +1,749 @@
+//
+// Copyright 2017 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// span.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Span<T>` type for holding a view of an existing
+// array of data. The `Span` object, much like the `absl::string_view` object,
+// does not own such data itself. A span provides a lightweight way to pass
+// around view of such data.
+//
+// Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()`
+// factory functions, for clearly creating spans of type `Span<T>` or read-only
+// `Span<const T>` when such types may be difficult to identify due to issues
+// with implicit conversion.
+//
+// The C++ standards committee currently has a proposal for a `std::span` type,
+// (http://wg21.link/p0122), which is not yet part of the standard (though may
+// become part of C++20). As of August 2017, the differences between
+// `absl::Span` and this proposal are:
+//    * `absl::Span` uses `size_t` for `size_type`
+//    * `absl::Span` has no `operator()`
+//    * `absl::Span` has no constructors for `std::unique_ptr` or
+//      `std::shared_ptr`
+//    * `absl::Span` has the factory functions `MakeSpan()` and
+//      `MakeConstSpan()`
+//    * `absl::Span` has `front()` and `back()` methods
+//    * bounds-checked access to `absl::Span` is accomplished with `at()`
+//    * `absl::Span` has compiler-provided move and copy constructors and
+//      assignment. This is due to them being specified as `constexpr`, but that
+//      implies const in C++11.
+//    * `absl::Span` has no `element_type` or `index_type` typedefs
+//    * A read-only `absl::Span<const T>` can be implicitly constructed from an
+//      initializer list.
+//    * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or
+//      `as_mutable_bytes()` methods
+//    * `absl::Span` has no static extent template parameter, nor constructors
+//      which exist only because of the static extent parameter.
+//    * `absl::Span` has an explicit mutable-reference constructor
+//
+// For more information, see the class comments below.
+#ifndef ABSL_TYPES_SPAN_H_
+#define ABSL_TYPES_SPAN_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+template <typename T>
+class Span;
+
+namespace span_internal {
+// A constexpr min function
+constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
+
+// Wrappers for access to container data pointers.
+template <typename C>
+constexpr auto GetDataImpl(C& c, char) noexcept  // NOLINT(runtime/references)
+    -> decltype(c.data()) {
+  return c.data();
+}
+
+// Before C++17, std::string::data returns a const char* in all cases.
+inline char* GetDataImpl(std::string& s,  // NOLINT(runtime/references)
+                         int) noexcept {
+  return &s[0];
+}
+
+template <typename C>
+constexpr auto GetData(C& c) noexcept  // NOLINT(runtime/references)
+    -> decltype(GetDataImpl(c, 0)) {
+  return GetDataImpl(c, 0);
+}
+
+// Detection idioms for size() and data().
+template <typename C>
+using HasSize =
+    std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
+
+// We want to enable conversion from vector<T*> to Span<const T* const> but
+// disable conversion from vector<Derived> to Span<Base>. Here we use
+// the fact that U** is convertible to Q* const* if and only if Q is the same
+// type or a more cv-qualified version of U.  We also decay the result type of
+// data() to avoid problems with classes which have a member function data()
+// which returns a reference.
+template <typename T, typename C>
+using HasData =
+    std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
+                        T* const*>;
+
+// Extracts value type from a Container
+template <typename C>
+struct ElementType {
+  using type = typename absl::remove_reference_t<C>::value_type;
+};
+
+template <typename T, size_t N>
+struct ElementType<T (&)[N]> {
+  using type = T;
+};
+
+template <typename C>
+using ElementT = typename ElementType<C>::type;
+
+template <typename T>
+using EnableIfMutable =
+    typename std::enable_if<!std::is_const<T>::value, int>::type;
+
+template <typename T>
+bool EqualImpl(Span<T> a, Span<T> b) {
+  static_assert(std::is_const<T>::value, "");
+  return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+template <typename T>
+bool LessThanImpl(Span<T> a, Span<T> b) {
+  static_assert(std::is_const<T>::value, "");
+  return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// The `IsConvertible` classes here are needed because of the
+// `std::is_convertible` bug in libcxx when compiled with GCC. This build
+// configuration is used by Android NDK toolchain. Reference link:
+// https://bugs.llvm.org/show_bug.cgi?id=27538.
+template <typename From, typename To>
+struct IsConvertibleHelper {
+ private:
+  static std::true_type testval(To);
+  static std::false_type testval(...);
+
+ public:
+  using type = decltype(testval(std::declval<From>()));
+};
+
+template <typename From, typename To>
+struct IsConvertible : IsConvertibleHelper<From, To>::type {};
+
+// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
+// older version of libcxx is not supported.
+template <typename From, typename To>
+using EnableIfConvertibleToSpanConst =
+    typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type;
+}  // namespace span_internal
+
+//------------------------------------------------------------------------------
+// Span
+//------------------------------------------------------------------------------
+//
+// A `Span` is an "array view" type for holding a view of a contiguous data
+// array; the `Span` object does not and cannot own such data itself. A span
+// provides an easy way to provide overloads for anything operating on
+// contiguous sequences without needing to manage pointers and array lengths
+// manually.
+
+// A span is conceptually a pointer (ptr) and a length (size) into an already
+// existing array of contiguous memory; the array it represents references the
+// elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span`
+// instead of raw pointers avoids many issues related to index out of bounds
+// errors.
+//
+// Spans may also be constructed from containers holding contiguous sequences.
+// Such containers must supply `data()` and `size() const` methods (e.g
+// `std::vector<T>`, `absl::InlinedVector<T, N>`). All implicit conversions to
+// `absl::Span` from such containers will create spans of type `const T`;
+// spans which can mutate their values (of type `T`) must use explicit
+// constructors.
+//
+// A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array
+// of elements of type `T`. A user of `Span` must ensure that the data being
+// pointed to outlives the `Span` itself.
+//
+// You can construct a `Span<T>` in several ways:
+//
+//   * Explicitly from a reference to a container type
+//   * Explicitly from a pointer and size
+//   * Implicitly from a container type (but only for spans of type `const T`)
+//   * Using the `MakeSpan()` or `MakeConstSpan()` factory functions.
+//
+// Examples:
+//
+//   // Construct a Span explicitly from a container:
+//   std::vector<int> v = {1, 2, 3, 4, 5};
+//   auto span = absl::Span<const int>(v);
+//
+//   // Construct a Span explicitly from a C-style array:
+//   int a[5] =  {1, 2, 3, 4, 5};
+//   auto span = absl::Span<const int>(a);
+//
+//   // Construct a Span implicitly from a container
+//   void MyRoutine(absl::Span<const int> a) {
+//     ...
+//   }
+//   std::vector v = {1,2,3,4,5};
+//   MyRoutine(v)                     // convert to Span<const T>
+//
+// Note that `Span` objects, in addition to requiring that the memory they
+// point to remains alive, must also ensure that such memory does not get
+// reallocated. Therefore, to avoid undefined behavior, containers with
+// associated span views should not invoke operations that may reallocate memory
+// (such as resizing) or invalidate iterators into the container.
+//
+// One common use for a `Span` is when passing arguments to a routine that can
+// accept a variety of array types (e.g. a `std::vector`, `absl::InlinedVector`,
+// a C-style array, etc.). Instead of creating overloads for each case, you
+// can simply specify a `Span` as the argument to such a routine.
+//
+// Example:
+//
+//   void MyRoutine(absl::Span<const int> a) {
+//     ...
+//   }
+//
+//   std::vector v = {1,2,3,4,5};
+//   MyRoutine(v);
+//
+//   absl::InlinedVector<int, 4> my_inline_vector;
+//   MyRoutine(my_inline_vector);
+//
+//   // Explicit constructor from pointer,size
+//   int* my_array = new int[10];
+//   MyRoutine(absl::Span<const int>(my_array, 10));
+template <typename T>
+class Span {
+ private:
+  // Used to determine whether a Span can be constructed from a container of
+  // type C.
+  template <typename C>
+  using EnableIfConvertibleFrom =
+      typename std::enable_if<span_internal::HasData<T, C>::value &&
+                              span_internal::HasSize<C>::value>::type;
+
+  // Used to SFINAE-enable a function when the slice elements are const.
+  template <typename U>
+  using EnableIfConstView =
+      typename std::enable_if<std::is_const<T>::value, U>::type;
+
+  // Used to SFINAE-enable a function when the slice elements are mutable.
+  template <typename U>
+  using EnableIfMutableView =
+      typename std::enable_if<!std::is_const<T>::value, U>::type;
+
+ public:
+  using value_type = absl::remove_cv_t<T>;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using reference = T&;
+  using const_reference = const T&;
+  using iterator = pointer;
+  using const_iterator = const_pointer;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  static const size_type npos = ~(size_type(0));
+
+  constexpr Span() noexcept : Span(nullptr, 0) {}
+  constexpr Span(pointer array, size_type length) noexcept
+      : ptr_(array), len_(length) {}
+
+  // Implicit conversion constructors
+  template <size_t N>
+  constexpr Span(T (&a)[N]) noexcept  // NOLINT(runtime/explicit)
+      : Span(a, N) {}
+
+  // Explicit reference constructor for a mutable `Span<T>` type. Can be
+  // replaced with MakeSpan() to infer the type parameter.
+  template <typename V, typename = EnableIfConvertibleFrom<V>,
+            typename = EnableIfMutableView<V>>
+  explicit Span(V& v) noexcept  // NOLINT(runtime/references)
+      : Span(span_internal::GetData(v), v.size()) {}
+
+  // Implicit reference constructor for a read-only `Span<const T>` type
+  template <typename V, typename = EnableIfConvertibleFrom<V>,
+            typename = EnableIfConstView<V>>
+  constexpr Span(const V& v) noexcept  // NOLINT(runtime/explicit)
+      : Span(span_internal::GetData(v), v.size()) {}
+
+  // Implicit constructor from an initializer list, making it possible to pass a
+  // brace-enclosed initializer list to a function expecting a `Span`. Such
+  // spans constructed from an initializer list must be of type `Span<const T>`.
+  //
+  //   void Process(absl::Span<const int> x);
+  //   Process({1, 2, 3});
+  //
+  // Note that as always the array referenced by the span must outlive the span.
+  // Since an initializer list constructor acts as if it is fed a temporary
+  // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this
+  // constructor only when the `std::initializer_list` itself outlives the span.
+  // In order to meet this requirement it's sufficient to ensure that neither
+  // the span nor a copy of it is used outside of the expression in which it's
+  // created:
+  //
+  //   // Assume that this function uses the array directly, not retaining any
+  //   // copy of the span or pointer to any of its elements.
+  //   void Process(absl::Span<const int> ints);
+  //
+  //   // Okay: the std::initializer_list<int> will reference a temporary array
+  //   // that isn't destroyed until after the call to Process returns.
+  //   Process({ 17, 19 });
+  //
+  //   // Not okay: the storage used by the std::initializer_list<int> is not
+  //   // allowed to be referenced after the first line.
+  //   absl::Span<const int> ints = { 17, 19 };
+  //   Process(ints);
+  //
+  //   // Not okay for the same reason as above: even when the elements of the
+  //   // initializer list expression are not temporaries the underlying array
+  //   // is, so the initializer list must still outlive the span.
+  //   const int foo = 17;
+  //   absl::Span<const int> ints = { foo };
+  //   Process(ints);
+  //
+  template <typename LazyT = T,
+            typename = EnableIfConstView<LazyT>>
+  Span(
+      std::initializer_list<value_type> v) noexcept  // NOLINT(runtime/explicit)
+      : Span(v.begin(), v.size()) {}
+
+  // Accessors
+
+  // Span::data()
+  //
+  // Returns a pointer to the span's underlying array of data (which is held
+  // outside the span).
+  constexpr pointer data() const noexcept { return ptr_; }
+
+  // Span::size()
+  //
+  // Returns the size of this span.
+  constexpr size_type size() const noexcept { return len_; }
+
+  // Span::length()
+  //
+  // Returns the length (size) of this span.
+  constexpr size_type length() const noexcept { return size(); }
+
+  // Span::empty()
+  //
+  // Returns a boolean indicating whether or not this span is considered empty.
+  constexpr bool empty() const noexcept { return size() == 0; }
+
+  // Span::operator[]
+  //
+  // Returns a reference to the i'th element of this span.
+  constexpr reference operator[](size_type i) const noexcept {
+    // MSVC 2015 accepts this as constexpr, but not ptr_[i]
+    return *(data() + i);
+  }
+
+  // Span::at()
+  //
+  // Returns a reference to the i'th element of this span.
+  constexpr reference at(size_type i) const {
+    return ABSL_PREDICT_TRUE(i < size())
+               ? ptr_[i]
+               : (base_internal::ThrowStdOutOfRange(
+                      "Span::at failed bounds check"),
+                  ptr_[i]);
+  }
+
+  // Span::front()
+  //
+  // Returns a reference to the first element of this span.
+  reference front() const noexcept { return ABSL_ASSERT(size() > 0), ptr_[0]; }
+
+  // Span::back()
+  //
+  // Returns a reference to the last element of this span.
+  reference back() const noexcept {
+    return ABSL_ASSERT(size() > 0), ptr_[size() - 1];
+  }
+
+  // Span::begin()
+  //
+  // Returns an iterator to the first element of this span.
+  constexpr iterator begin() const noexcept { return ptr_; }
+
+  // Span::cbegin()
+  //
+  // Returns a const iterator to the first element of this span.
+  constexpr const_iterator cbegin() const noexcept { return ptr_; }
+
+  // Span::end()
+  //
+  // Returns an iterator to the last element of this span.
+  iterator end() const noexcept { return ptr_ + len_; }
+
+  // Span::cend()
+  //
+  // Returns a const iterator to the last element of this span.
+  const_iterator cend() const noexcept { return end(); }
+
+  // Span::rbegin()
+  //
+  // Returns a reverse iterator starting at the last element of this span.
+  reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
+
+  // Span::crbegin()
+  //
+  // Returns a reverse const iterator starting at the last element of this span.
+  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+  // Span::rend()
+  //
+  // Returns a reverse iterator starting at the first element of this span.
+  reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
+
+  // Span::crend()
+  //
+  // Returns a reverse iterator starting at the first element of this span.
+  const_reverse_iterator crend() const noexcept { return rend(); }
+
+  // Span mutations
+
+  // Span::remove_prefix()
+  //
+  // Removes the first `n` elements from the span.
+  void remove_prefix(size_type n) noexcept {
+    assert(len_ >= n);
+    ptr_ += n;
+    len_ -= n;
+  }
+
+  // Span::remove_suffix()
+  //
+  // Removes the last `n` elements from the span.
+  void remove_suffix(size_type n) noexcept {
+    assert(len_ >= n);
+    len_ -= n;
+  }
+
+  // Span::subspan()
+  //
+  // Returns a `Span` starting at element `pos` and of length `len`. Both `pos`
+  // and `len` are of type `size_type` and thus non-negative. Parameter `pos`
+  // must be <= size(). Any `len` value that points past the end of the span
+  // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
+  // ensures the returned subspan continues until the end of the span.
+  //
+  // Examples:
+  //
+  //   std::vector<int> vec = {10, 11, 12, 13};
+  //   absl::MakeSpan(vec).subspan(1, 2);  // {11, 12}
+  //   absl::MakeSpan(vec).subspan(2, 8);  // {12, 13}
+  //   absl::MakeSpan(vec).subspan(1);     // {11, 12, 13}
+  //   absl::MakeSpan(vec).subspan(4);     // {}
+  //   absl::MakeSpan(vec).subspan(5);     // throws std::out_of_range
+  constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
+    return (pos <= len_)
+               ? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
+               : (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
+  }
+
+ private:
+  pointer ptr_;
+  size_type len_;
+};
+
+template <typename T>
+const typename Span<T>::size_type Span<T>::npos;
+
+// Span relationals
+
+// Equality is compared element-by-element, while ordering is lexicographical.
+// We provide three overloads for each operator to cover any combination on the
+// left or right hand side of mutable Span<T>, read-only Span<const T>, and
+// convertible-to-read-only Span<T>.
+// TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering
+// template functions, 5 overloads per operator is needed as a workaround. We
+// should update them to 3 overloads per operator using non-deduced context like
+// string_view, i.e.
+// - (Span<T>, Span<T>)
+// - (Span<T>, non_deduced<Span<const T>>)
+// - (non_deduced<Span<const T>>, Span<T>)
+
+// operator==
+template <typename T>
+bool operator==(Span<T> a, Span<T> b) {
+  return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T>
+bool operator==(Span<const T> a, Span<T> b) {
+  return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T>
+bool operator==(Span<T> a, Span<const T> b) {
+  return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator==(const U& a, Span<T> b) {
+  return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator==(Span<T> a, const U& b) {
+  return span_internal::EqualImpl<const T>(a, b);
+}
+
+// operator!=
+template <typename T>
+bool operator!=(Span<T> a, Span<T> b) {
+  return !(a == b);
+}
+template <typename T>
+bool operator!=(Span<const T> a, Span<T> b) {
+  return !(a == b);
+}
+template <typename T>
+bool operator!=(Span<T> a, Span<const T> b) {
+  return !(a == b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator!=(const U& a, Span<T> b) {
+  return !(a == b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator!=(Span<T> a, const U& b) {
+  return !(a == b);
+}
+
+// operator<
+template <typename T>
+bool operator<(Span<T> a, Span<T> b) {
+  return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T>
+bool operator<(Span<const T> a, Span<T> b) {
+  return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T>
+bool operator<(Span<T> a, Span<const T> b) {
+  return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<(const U& a, Span<T> b) {
+  return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<(Span<T> a, const U& b) {
+  return span_internal::LessThanImpl<const T>(a, b);
+}
+
+// operator>
+template <typename T>
+bool operator>(Span<T> a, Span<T> b) {
+  return b < a;
+}
+template <typename T>
+bool operator>(Span<const T> a, Span<T> b) {
+  return b < a;
+}
+template <typename T>
+bool operator>(Span<T> a, Span<const T> b) {
+  return b < a;
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>(const U& a, Span<T> b) {
+  return b < a;
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>(Span<T> a, const U& b) {
+  return b < a;
+}
+
+// operator<=
+template <typename T>
+bool operator<=(Span<T> a, Span<T> b) {
+  return !(b < a);
+}
+template <typename T>
+bool operator<=(Span<const T> a, Span<T> b) {
+  return !(b < a);
+}
+template <typename T>
+bool operator<=(Span<T> a, Span<const T> b) {
+  return !(b < a);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<=(const U& a, Span<T> b) {
+  return !(b < a);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<=(Span<T> a, const U& b) {
+  return !(b < a);
+}
+
+// operator>=
+template <typename T>
+bool operator>=(Span<T> a, Span<T> b) {
+  return !(a < b);
+}
+template <typename T>
+bool operator>=(Span<const T> a, Span<T> b) {
+  return !(a < b);
+}
+template <typename T>
+bool operator>=(Span<T> a, Span<const T> b) {
+  return !(a < b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>=(const U& a, Span<T> b) {
+  return !(a < b);
+}
+template <typename T, typename U,
+          typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>=(Span<T> a, const U& b) {
+  return !(a < b);
+}
+
+// MakeSpan()
+//
+// Constructs a mutable `Span<T>`, deducing `T` automatically from either a
+// container or pointer+size.
+//
+// Because a read-only `Span<const T>` is implicitly constructed from container
+// types regardless of whether the container itself is a const container,
+// constructing mutable spans of type `Span<T>` from containers requires
+// explicit constructors. The container-accepting version of `MakeSpan()`
+// deduces the type of `T` by the constness of the pointer received from the
+// container's `data()` member. Similarly, the pointer-accepting version returns
+// a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise.
+//
+// Examples:
+//
+//   void MyRoutine(absl::Span<MyComplicatedType> a) {
+//     ...
+//   };
+//   // my_vector is a container of non-const types
+//   std::vector<MyComplicatedType> my_vector;
+//
+//   // Constructing a Span implicitly attempts to create a Span of type
+//   // `Span<const T>`
+//   MyRoutine(my_vector);                // error, type mismatch
+//
+//   // Explicitly constructing the Span is verbose
+//   MyRoutine(absl::Span<MyComplicatedType>(my_vector));
+//
+//   // Use MakeSpan() to make an absl::Span<T>
+//   MyRoutine(absl::MakeSpan(my_vector));
+//
+//   // Construct a span from an array ptr+size
+//   absl::Span<T> my_span() {
+//     return absl::MakeSpan(&array[0], num_elements_);
+//   }
+//
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept {
+  return Span<T>(ptr, size);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+Span<T> MakeSpan(T* begin, T* end) noexcept {
+  return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeSpan(C& c) noexcept  // NOLINT(runtime/references)
+    -> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) {
+  return MakeSpan(span_internal::GetData(c), c.size());
+}
+
+template <int&... ExplicitArgumentBarrier, typename T, size_t N>
+constexpr Span<T> MakeSpan(T (&array)[N]) noexcept {
+  return Span<T>(array, N);
+}
+
+// MakeConstSpan()
+//
+// Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically,
+// but always returning a `Span<const T>`.
+//
+// Examples:
+//
+//   void ProcessInts(absl::Span<const int> some_ints);
+//
+//   // Call with a pointer and size.
+//   int array[3] = { 0, 0, 0 };
+//   ProcessInts(absl::MakeConstSpan(&array[0], 3));
+//
+//   // Call with a [begin, end) pair.
+//   ProcessInts(absl::MakeConstSpan(&array[0], &array[3]));
+//
+//   // Call directly with an array.
+//   ProcessInts(absl::MakeConstSpan(array));
+//
+//   // Call with a contiguous container.
+//   std::vector<int> some_ints = ...;
+//   ProcessInts(absl::MakeConstSpan(some_ints));
+//   ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
+//
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept {
+  return Span<const T>(ptr, size);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
+  return ABSL_ASSERT(begin <= end), Span<const T>(begin, end - begin);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) {
+  return MakeSpan(c);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T, size_t N>
+constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
+  return Span<const T>(array, N);
+}
+}  // namespace absl
+#endif  // ABSL_TYPES_SPAN_H_
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
new file mode 100644
index 0000000..5a4f001
--- /dev/null
+++ b/absl/types/span_test.cc
@@ -0,0 +1,781 @@
+// Copyright 2017 The Abseil 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 "absl/types/span.h"
+
+#include <array>
+#include <initializer_list>
+#include <numeric>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/container/fixed_array.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+MATCHER_P(DataIs, data,
+          absl::StrCat("data() is ", negation ? "is " : "isn't ",
+                       testing::PrintToString(data))) {
+  return arg.data() == data;
+}
+
+template <typename T>
+auto SpanIs(T data, size_t size)
+    -> decltype(testing::AllOf(DataIs(data), testing::SizeIs(size))) {
+  return testing::AllOf(DataIs(data), testing::SizeIs(size));
+}
+
+template <typename Container>
+auto SpanIs(const Container& c) -> decltype(SpanIs(c.data(), c.size())) {
+  return SpanIs(c.data(), c.size());
+}
+
+std::vector<int> MakeRamp(int len, int offset = 0) {
+  std::vector<int> v(len);
+  std::iota(v.begin(), v.end(), offset);
+  return v;
+}
+
+TEST(IntSpan, EmptyCtors) {
+  absl::Span<int> s;
+  EXPECT_THAT(s, SpanIs(nullptr, 0));
+}
+
+TEST(IntSpan, PtrLenCtor) {
+  int a[] = {1, 2, 3};
+  absl::Span<int> s(&a[0], 2);
+  EXPECT_THAT(s, SpanIs(a, 2));
+}
+
+TEST(IntSpan, ArrayCtor) {
+  int a[] = {1, 2, 3};
+  absl::Span<int> s(a);
+  EXPECT_THAT(s, SpanIs(a, 3));
+
+  EXPECT_TRUE((std::is_constructible<absl::Span<const int>, int[3]>::value));
+  EXPECT_TRUE(
+      (std::is_constructible<absl::Span<const int>, const int[3]>::value));
+  EXPECT_FALSE((std::is_constructible<absl::Span<int>, const int[3]>::value));
+  EXPECT_TRUE((std::is_convertible<int[3], absl::Span<const int>>::value));
+  EXPECT_TRUE(
+      (std::is_convertible<const int[3], absl::Span<const int>>::value));
+}
+
+template <typename T>
+void TakesGenericSpan(absl::Span<T>) {}
+
+TEST(IntSpan, ContainerCtor) {
+  std::vector<int> empty;
+  absl::Span<int> s_empty(empty);
+  EXPECT_THAT(s_empty, SpanIs(empty));
+
+  std::vector<int> filled{1, 2, 3};
+  absl::Span<int> s_filled(filled);
+  EXPECT_THAT(s_filled, SpanIs(filled));
+
+  absl::Span<int> s_from_span(filled);
+  EXPECT_THAT(s_from_span, SpanIs(s_filled));
+
+  absl::Span<const int> const_filled = filled;
+  EXPECT_THAT(const_filled, SpanIs(filled));
+
+  absl::Span<const int> const_from_span = s_filled;
+  EXPECT_THAT(const_from_span, SpanIs(s_filled));
+
+  EXPECT_TRUE(
+      (std::is_convertible<std::vector<int>&, absl::Span<const int>>::value));
+  EXPECT_TRUE(
+      (std::is_convertible<absl::Span<int>&, absl::Span<const int>>::value));
+
+  TakesGenericSpan(absl::Span<int>(filled));
+}
+
+// A struct supplying shallow data() const.
+struct ContainerWithShallowConstData {
+  std::vector<int> storage;
+  int* data() const { return const_cast<int*>(storage.data()); }
+  int size() const { return storage.size(); }
+};
+
+TEST(IntSpan, ShallowConstness) {
+  const ContainerWithShallowConstData c{MakeRamp(20)};
+  absl::Span<int> s(
+      c);  // We should be able to do this even though data() is const.
+  s[0] = -1;
+  EXPECT_EQ(c.storage[0], -1);
+}
+
+TEST(CharSpan, StringCtor) {
+  std::string empty = "";
+  absl::Span<char> s_empty(empty);
+  EXPECT_THAT(s_empty, SpanIs(empty));
+
+  std::string abc = "abc";
+  absl::Span<char> s_abc(abc);
+  EXPECT_THAT(s_abc, SpanIs(abc));
+
+  absl::Span<const char> s_const_abc = abc;
+  EXPECT_THAT(s_const_abc, SpanIs(abc));
+
+  EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value));
+  EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value));
+  EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value));
+}
+
+TEST(IntSpan, FromConstPointer) {
+  EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>,
+                                     std::vector<int*>>::value));
+  EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>,
+                                     std::vector<const int*>>::value));
+  EXPECT_FALSE((
+      std::is_constructible<absl::Span<const int*>, std::vector<int*>>::value));
+  EXPECT_FALSE((
+      std::is_constructible<absl::Span<int*>, std::vector<const int*>>::value));
+}
+
+struct TypeWithMisleadingData {
+  int& data() { return i; }
+  int size() { return 1; }
+  int i;
+};
+
+struct TypeWithMisleadingSize {
+  int* data() { return &i; }
+  const char* size() { return "1"; }
+  int i;
+};
+
+TEST(IntSpan, EvilTypes) {
+  EXPECT_FALSE(
+      (std::is_constructible<absl::Span<int>, TypeWithMisleadingData&>::value));
+  EXPECT_FALSE(
+      (std::is_constructible<absl::Span<int>, TypeWithMisleadingSize&>::value));
+}
+
+struct Base {
+  int* data() { return &i; }
+  int size() { return 1; }
+  int i;
+};
+struct Derived : Base {};
+
+TEST(IntSpan, SpanOfDerived) {
+  EXPECT_TRUE((std::is_constructible<absl::Span<int>, Base&>::value));
+  EXPECT_TRUE((std::is_constructible<absl::Span<int>, Derived&>::value));
+  EXPECT_FALSE(
+      (std::is_constructible<absl::Span<Base>, std::vector<Derived>>::value));
+}
+
+void TestInitializerList(absl::Span<const int> s, const std::vector<int>& v) {
+  EXPECT_TRUE(absl::equal(s.begin(), s.end(), v.begin(), v.end()));
+}
+
+TEST(ConstIntSpan, InitializerListConversion) {
+  TestInitializerList({}, {});
+  TestInitializerList({1}, {1});
+  TestInitializerList({1, 2, 3}, {1, 2, 3});
+
+  EXPECT_FALSE((std::is_constructible<absl::Span<int>,
+                                      std::initializer_list<int>>::value));
+  EXPECT_FALSE((
+      std::is_convertible<absl::Span<int>, std::initializer_list<int>>::value));
+}
+
+TEST(IntSpan, Data) {
+  int i;
+  absl::Span<int> s(&i, 1);
+  EXPECT_EQ(&i, s.data());
+}
+
+TEST(IntSpan, SizeLengthEmpty) {
+  absl::Span<int> empty;
+  EXPECT_EQ(empty.size(), 0);
+  EXPECT_TRUE(empty.empty());
+  EXPECT_EQ(empty.size(), empty.length());
+
+  auto v = MakeRamp(10);
+  absl::Span<int> s(v);
+  EXPECT_EQ(s.size(), 10);
+  EXPECT_FALSE(s.empty());
+  EXPECT_EQ(s.size(), s.length());
+}
+
+TEST(IntSpan, ElementAccess) {
+  auto v = MakeRamp(10);
+  absl::Span<int> s(v);
+  for (int i = 0; i < s.size(); ++i) {
+    EXPECT_EQ(s[i], s.at(i));
+  }
+
+  EXPECT_EQ(s.front(), s[0]);
+  EXPECT_EQ(s.back(), s[9]);
+}
+
+TEST(IntSpan, AtThrows) {
+  auto v = MakeRamp(10);
+  absl::Span<int> s(v);
+
+  EXPECT_EQ(s.at(9), 9);
+  ABSL_BASE_INTERNAL_EXPECT_FAIL(s.at(10), std::out_of_range,
+                                 "failed bounds check");
+}
+
+TEST(IntSpan, RemovePrefixAndSuffix) {
+  auto v = MakeRamp(20, 1);
+  absl::Span<int> s(v);
+  EXPECT_EQ(s.size(), 20);
+
+  s.remove_suffix(0);
+  s.remove_prefix(0);
+  EXPECT_EQ(s.size(), 20);
+
+  s.remove_prefix(1);
+  EXPECT_EQ(s.size(), 19);
+  EXPECT_EQ(s[0], 2);
+
+  s.remove_suffix(1);
+  EXPECT_EQ(s.size(), 18);
+  EXPECT_EQ(s.back(), 19);
+
+  s.remove_prefix(7);
+  EXPECT_EQ(s.size(), 11);
+  EXPECT_EQ(s[0], 9);
+
+  s.remove_suffix(11);
+  EXPECT_EQ(s.size(), 0);
+
+  EXPECT_EQ(v, MakeRamp(20, 1));
+}
+
+TEST(IntSpan, Subspan) {
+  std::vector<int> empty;
+  EXPECT_EQ(absl::MakeSpan(empty).subspan(), empty);
+  EXPECT_THAT(absl::MakeSpan(empty).subspan(0, 0), SpanIs(empty));
+  EXPECT_THAT(absl::MakeSpan(empty).subspan(0, absl::Span<const int>::npos),
+              SpanIs(empty));
+
+  auto ramp = MakeRamp(10);
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(), SpanIs(ramp));
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 10), SpanIs(ramp));
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, absl::Span<const int>::npos),
+              SpanIs(ramp));
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 3), SpanIs(ramp.data(), 3));
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(5, absl::Span<const int>::npos),
+              SpanIs(ramp.data() + 5, 5));
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(3, 3), SpanIs(ramp.data() + 3, 3));
+  EXPECT_THAT(absl::MakeSpan(ramp).subspan(10, 5), SpanIs(ramp.data() + 10, 0));
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+  EXPECT_THROW(absl::MakeSpan(ramp).subspan(11, 5), std::out_of_range);
+#else
+  EXPECT_DEATH(absl::MakeSpan(ramp).subspan(11, 5), "");
+#endif
+}
+
+TEST(IntSpan, MakeSpanPtrLength) {
+  std::vector<int> empty;
+  auto s_empty = absl::MakeSpan(empty.data(), empty.size());
+  EXPECT_THAT(s_empty, SpanIs(empty));
+
+  std::array<int, 3> a{{1, 2, 3}};
+  auto s = absl::MakeSpan(a.data(), a.size());
+  EXPECT_THAT(s, SpanIs(a));
+
+  EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.size()), SpanIs(s_empty));
+  EXPECT_THAT(absl::MakeConstSpan(a.data(), a.size()), SpanIs(s));
+}
+
+TEST(IntSpan, MakeSpanTwoPtrs) {
+  std::vector<int> empty;
+  auto s_empty = absl::MakeSpan(empty.data(), empty.data());
+  EXPECT_THAT(s_empty, SpanIs(empty));
+
+  std::vector<int> v{1, 2, 3};
+  auto s = absl::MakeSpan(v.data(), v.data() + 1);
+  EXPECT_THAT(s, SpanIs(v.data(), 1));
+
+  EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.data()), SpanIs(s_empty));
+  EXPECT_THAT(absl::MakeConstSpan(v.data(), v.data() + 1), SpanIs(s));
+}
+
+TEST(IntSpan, MakeSpanContainer) {
+  std::vector<int> empty;
+  auto s_empty = absl::MakeSpan(empty);
+  EXPECT_THAT(s_empty, SpanIs(empty));
+
+  std::vector<int> v{1, 2, 3};
+  auto s = absl::MakeSpan(v);
+  EXPECT_THAT(s, SpanIs(v));
+
+  EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty));
+  EXPECT_THAT(absl::MakeConstSpan(v), SpanIs(s));
+
+  EXPECT_THAT(absl::MakeSpan(s), SpanIs(s));
+  EXPECT_THAT(absl::MakeConstSpan(s), SpanIs(s));
+}
+
+TEST(CharSpan, MakeSpanString) {
+  std::string empty = "";
+  auto s_empty = absl::MakeSpan(empty);
+  EXPECT_THAT(s_empty, SpanIs(empty));
+
+  std::string str = "abc";
+  auto s_str = absl::MakeSpan(str);
+  EXPECT_THAT(s_str, SpanIs(str));
+
+  EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty));
+  EXPECT_THAT(absl::MakeConstSpan(str), SpanIs(s_str));
+}
+
+TEST(IntSpan, MakeSpanArray) {
+  int a[] = {1, 2, 3};
+  auto s = absl::MakeSpan(a);
+  EXPECT_THAT(s, SpanIs(a, 3));
+
+  const int ca[] = {1, 2, 3};
+  auto s_ca = absl::MakeSpan(ca);
+  EXPECT_THAT(s_ca, SpanIs(ca, 3));
+
+  EXPECT_THAT(absl::MakeConstSpan(a), SpanIs(s));
+  EXPECT_THAT(absl::MakeConstSpan(ca), SpanIs(s_ca));
+}
+
+// Compile-asserts that the argument has the expected decayed type.
+template <typename Expected, typename T>
+void CheckType(const T& /* value */) {
+  testing::StaticAssertTypeEq<Expected, T>();
+}
+
+TEST(IntSpan, MakeSpanTypes) {
+  std::vector<int> vec;
+  const std::vector<int> cvec;
+  int a[1];
+  const int ca[] = {1};
+  int* ip = a;
+  const int* cip = ca;
+  std::string s = "";
+  const std::string cs = "";
+  CheckType<absl::Span<int>>(absl::MakeSpan(vec));
+  CheckType<absl::Span<const int>>(absl::MakeSpan(cvec));
+  CheckType<absl::Span<int>>(absl::MakeSpan(ip, ip + 1));
+  CheckType<absl::Span<int>>(absl::MakeSpan(ip, 1));
+  CheckType<absl::Span<const int>>(absl::MakeSpan(cip, cip + 1));
+  CheckType<absl::Span<const int>>(absl::MakeSpan(cip, 1));
+  CheckType<absl::Span<int>>(absl::MakeSpan(a));
+  CheckType<absl::Span<int>>(absl::MakeSpan(a, a + 1));
+  CheckType<absl::Span<int>>(absl::MakeSpan(a, 1));
+  CheckType<absl::Span<const int>>(absl::MakeSpan(ca));
+  CheckType<absl::Span<const int>>(absl::MakeSpan(ca, ca + 1));
+  CheckType<absl::Span<const int>>(absl::MakeSpan(ca, 1));
+  CheckType<absl::Span<char>>(absl::MakeSpan(s));
+  CheckType<absl::Span<const char>>(absl::MakeSpan(cs));
+}
+
+TEST(ConstIntSpan, MakeConstSpanTypes) {
+  std::vector<int> vec;
+  const std::vector<int> cvec;
+  int array[1];
+  const int carray[] = {0};
+  int* ptr = array;
+  const int* cptr = carray;
+  std::string s = "";
+  std::string cs = "";
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(vec));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(cvec));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, ptr + 1));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, 1));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, cptr + 1));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, 1));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(array));
+  CheckType<absl::Span<const int>>(absl::MakeConstSpan(carray));
+  CheckType<absl::Span<const char>>(absl::MakeConstSpan(s));
+  CheckType<absl::Span<const char>>(absl::MakeConstSpan(cs));
+}
+
+TEST(IntSpan, Equality) {
+  const int arr1[] = {1, 2, 3, 4, 5};
+  int arr2[] = {1, 2, 3, 4, 5};
+  std::vector<int> vec1(std::begin(arr1), std::end(arr1));
+  std::vector<int> vec2 = vec1;
+  std::vector<int> other_vec = {2, 4, 6, 8, 10};
+  // These two slices are from different vectors, but have the same size and
+  // have the same elements (right now).  They should compare equal. Test both
+  // == and !=.
+  const absl::Span<const int> from1 = vec1;
+  const absl::Span<const int> from2 = vec2;
+  EXPECT_EQ(from1, from1);
+  EXPECT_FALSE(from1 != from1);
+  EXPECT_EQ(from1, from2);
+  EXPECT_FALSE(from1 != from2);
+
+  // These two slices have different underlying vector values. They should be
+  // considered not equal. Test both == and !=.
+  const absl::Span<const int> from_other = other_vec;
+  EXPECT_NE(from1, from_other);
+  EXPECT_FALSE(from1 == from_other);
+
+  // Comparison between a vector and its slice should be equal. And vice-versa.
+  // This ensures implicit conversion to Span works on both sides of ==.
+  EXPECT_EQ(vec1, from1);
+  EXPECT_FALSE(vec1 != from1);
+  EXPECT_EQ(from1, vec1);
+  EXPECT_FALSE(from1 != vec1);
+
+  // This verifies that absl::Span<T> can be compared freely with
+  // absl::Span<const T>.
+  const absl::Span<int> mutable_from1(vec1);
+  const absl::Span<int> mutable_from2(vec2);
+  EXPECT_EQ(from1, mutable_from1);
+  EXPECT_EQ(mutable_from1, from1);
+  EXPECT_EQ(mutable_from1, mutable_from2);
+  EXPECT_EQ(mutable_from2, mutable_from1);
+
+  // Comparison between a vector and its slice should be equal for mutable
+  // Spans as well.
+  EXPECT_EQ(vec1, mutable_from1);
+  EXPECT_FALSE(vec1 != mutable_from1);
+  EXPECT_EQ(mutable_from1, vec1);
+  EXPECT_FALSE(mutable_from1 != vec1);
+
+  // Comparison between convertible-to-Span-of-const and Span-of-mutable. Arrays
+  // are used because they're the only value type which converts to a
+  // Span-of-mutable. EXPECT_TRUE is used instead of EXPECT_EQ to avoid
+  // array-to-pointer decay.
+  EXPECT_TRUE(arr1 == mutable_from1);
+  EXPECT_FALSE(arr1 != mutable_from1);
+  EXPECT_TRUE(mutable_from1 == arr1);
+  EXPECT_FALSE(mutable_from1 != arr1);
+
+  // Comparison between convertible-to-Span-of-mutable and Span-of-const
+  EXPECT_TRUE(arr2 == from1);
+  EXPECT_FALSE(arr2 != from1);
+  EXPECT_TRUE(from1 == arr2);
+  EXPECT_FALSE(from1 != arr2);
+
+  // With a different size, the array slices should not be equal.
+  EXPECT_NE(from1, absl::Span<const int>(from1).subspan(0, from1.size() - 1));
+
+  // With different contents, the array slices should not be equal.
+  ++vec2.back();
+  EXPECT_NE(from1, from2);
+}
+
+class IntSpanOrderComparisonTest : public testing::Test {
+ public:
+  IntSpanOrderComparisonTest()
+      : arr_before_{1, 2, 3},
+        arr_after_{1, 2, 4},
+        carr_after_{1, 2, 4},
+        vec_before_(std::begin(arr_before_), std::end(arr_before_)),
+        vec_after_(std::begin(arr_after_), std::end(arr_after_)),
+        before_(vec_before_),
+        after_(vec_after_),
+        cbefore_(vec_before_),
+        cafter_(vec_after_) {}
+
+ protected:
+  int arr_before_[3], arr_after_[3];
+  const int carr_after_[3];
+  std::vector<int> vec_before_, vec_after_;
+  absl::Span<int> before_, after_;
+  absl::Span<const int> cbefore_, cafter_;
+};
+
+TEST_F(IntSpanOrderComparisonTest, CompareSpans) {
+  EXPECT_TRUE(cbefore_ < cafter_);
+  EXPECT_TRUE(cbefore_ <= cafter_);
+  EXPECT_TRUE(cafter_ > cbefore_);
+  EXPECT_TRUE(cafter_ >= cbefore_);
+
+  EXPECT_FALSE(cbefore_ > cafter_);
+  EXPECT_FALSE(cafter_ < cbefore_);
+
+  EXPECT_TRUE(before_ < after_);
+  EXPECT_TRUE(before_ <= after_);
+  EXPECT_TRUE(after_ > before_);
+  EXPECT_TRUE(after_ >= before_);
+
+  EXPECT_FALSE(before_ > after_);
+  EXPECT_FALSE(after_ < before_);
+
+  EXPECT_TRUE(cbefore_ < after_);
+  EXPECT_TRUE(cbefore_ <= after_);
+  EXPECT_TRUE(after_ > cbefore_);
+  EXPECT_TRUE(after_ >= cbefore_);
+
+  EXPECT_FALSE(cbefore_ > after_);
+  EXPECT_FALSE(after_ < cbefore_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, SpanOfConstAndContainer) {
+  EXPECT_TRUE(cbefore_ < vec_after_);
+  EXPECT_TRUE(cbefore_ <= vec_after_);
+  EXPECT_TRUE(vec_after_ > cbefore_);
+  EXPECT_TRUE(vec_after_ >= cbefore_);
+
+  EXPECT_FALSE(cbefore_ > vec_after_);
+  EXPECT_FALSE(vec_after_ < cbefore_);
+
+  EXPECT_TRUE(arr_before_ < cafter_);
+  EXPECT_TRUE(arr_before_ <= cafter_);
+  EXPECT_TRUE(cafter_ > arr_before_);
+  EXPECT_TRUE(cafter_ >= arr_before_);
+
+  EXPECT_FALSE(arr_before_ > cafter_);
+  EXPECT_FALSE(cafter_ < arr_before_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, SpanOfMutableAndContainer) {
+  EXPECT_TRUE(vec_before_ < after_);
+  EXPECT_TRUE(vec_before_ <= after_);
+  EXPECT_TRUE(after_ > vec_before_);
+  EXPECT_TRUE(after_ >= vec_before_);
+
+  EXPECT_FALSE(vec_before_ > after_);
+  EXPECT_FALSE(after_ < vec_before_);
+
+  EXPECT_TRUE(before_ < carr_after_);
+  EXPECT_TRUE(before_ <= carr_after_);
+  EXPECT_TRUE(carr_after_ > before_);
+  EXPECT_TRUE(carr_after_ >= before_);
+
+  EXPECT_FALSE(before_ > carr_after_);
+  EXPECT_FALSE(carr_after_ < before_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, EqualSpans) {
+  EXPECT_FALSE(before_ < before_);
+  EXPECT_TRUE(before_ <= before_);
+  EXPECT_FALSE(before_ > before_);
+  EXPECT_TRUE(before_ >= before_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, Subspans) {
+  auto subspan = before_.subspan(0, 1);
+  EXPECT_TRUE(subspan < before_);
+  EXPECT_TRUE(subspan <= before_);
+  EXPECT_TRUE(before_ > subspan);
+  EXPECT_TRUE(before_ >= subspan);
+
+  EXPECT_FALSE(subspan > before_);
+  EXPECT_FALSE(before_ < subspan);
+}
+
+TEST_F(IntSpanOrderComparisonTest, EmptySpans) {
+  absl::Span<int> empty;
+  EXPECT_FALSE(empty < empty);
+  EXPECT_TRUE(empty <= empty);
+  EXPECT_FALSE(empty > empty);
+  EXPECT_TRUE(empty >= empty);
+
+  EXPECT_TRUE(empty < before_);
+  EXPECT_TRUE(empty <= before_);
+  EXPECT_TRUE(before_ > empty);
+  EXPECT_TRUE(before_ >= empty);
+
+  EXPECT_FALSE(empty > before_);
+  EXPECT_FALSE(before_ < empty);
+}
+
+TEST(IntSpan, ExposesContainerTypesAndConsts) {
+  absl::Span<int> slice;
+  CheckType<absl::Span<int>::iterator>(slice.begin());
+  EXPECT_TRUE((std::is_convertible<decltype(slice.begin()),
+                                   absl::Span<int>::const_iterator>::value));
+  CheckType<absl::Span<int>::const_iterator>(slice.cbegin());
+  EXPECT_TRUE((std::is_convertible<decltype(slice.end()),
+                                   absl::Span<int>::const_iterator>::value));
+  CheckType<absl::Span<int>::const_iterator>(slice.cend());
+  CheckType<absl::Span<int>::reverse_iterator>(slice.rend());
+  EXPECT_TRUE(
+      (std::is_convertible<decltype(slice.rend()),
+                           absl::Span<int>::const_reverse_iterator>::value));
+  CheckType<absl::Span<int>::const_reverse_iterator>(slice.crend());
+  testing::StaticAssertTypeEq<int, absl::Span<int>::value_type>();
+  testing::StaticAssertTypeEq<int, absl::Span<const int>::value_type>();
+  testing::StaticAssertTypeEq<int*, absl::Span<int>::pointer>();
+  testing::StaticAssertTypeEq<const int*, absl::Span<const int>::pointer>();
+  testing::StaticAssertTypeEq<int&, absl::Span<int>::reference>();
+  testing::StaticAssertTypeEq<const int&, absl::Span<const int>::reference>();
+  testing::StaticAssertTypeEq<const int&, absl::Span<int>::const_reference>();
+  testing::StaticAssertTypeEq<const int&,
+                              absl::Span<const int>::const_reference>();
+  EXPECT_EQ(static_cast<absl::Span<int>::size_type>(-1), absl::Span<int>::npos);
+}
+
+TEST(IntSpan, IteratorsAndReferences) {
+  auto accept_pointer = [](int*) {};
+  auto accept_reference = [](int&) {};
+  auto accept_iterator = [](absl::Span<int>::iterator) {};
+  auto accept_const_iterator = [](absl::Span<int>::const_iterator) {};
+  auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {};
+  auto accept_const_reverse_iterator =
+      [](absl::Span<int>::const_reverse_iterator) {};
+
+  int a[1];
+  absl::Span<int> s = a;
+
+  accept_pointer(s.data());
+  accept_iterator(s.begin());
+  accept_const_iterator(s.begin());
+  accept_const_iterator(s.cbegin());
+  accept_iterator(s.end());
+  accept_const_iterator(s.end());
+  accept_const_iterator(s.cend());
+  accept_reverse_iterator(s.rbegin());
+  accept_const_reverse_iterator(s.rbegin());
+  accept_const_reverse_iterator(s.crbegin());
+  accept_reverse_iterator(s.rend());
+  accept_const_reverse_iterator(s.rend());
+  accept_const_reverse_iterator(s.crend());
+
+  accept_reference(s[0]);
+  accept_reference(s.at(0));
+  accept_reference(s.front());
+  accept_reference(s.back());
+}
+
+TEST(IntSpan, IteratorsAndReferences_Const) {
+  auto accept_pointer = [](int*) {};
+  auto accept_reference = [](int&) {};
+  auto accept_iterator = [](absl::Span<int>::iterator) {};
+  auto accept_const_iterator = [](absl::Span<int>::const_iterator) {};
+  auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {};
+  auto accept_const_reverse_iterator =
+      [](absl::Span<int>::const_reverse_iterator) {};
+
+  int a[1];
+  const absl::Span<int> s = a;
+
+  accept_pointer(s.data());
+  accept_iterator(s.begin());
+  accept_const_iterator(s.begin());
+  accept_const_iterator(s.cbegin());
+  accept_iterator(s.end());
+  accept_const_iterator(s.end());
+  accept_const_iterator(s.cend());
+  accept_reverse_iterator(s.rbegin());
+  accept_const_reverse_iterator(s.rbegin());
+  accept_const_reverse_iterator(s.crbegin());
+  accept_reverse_iterator(s.rend());
+  accept_const_reverse_iterator(s.rend());
+  accept_const_reverse_iterator(s.crend());
+
+  accept_reference(s[0]);
+  accept_reference(s.at(0));
+  accept_reference(s.front());
+  accept_reference(s.back());
+}
+
+TEST(IntSpan, NoexceptTest) {
+  int a[] = {1, 2, 3};
+  std::vector<int> v;
+  EXPECT_TRUE(noexcept(absl::Span<const int>()));
+  EXPECT_TRUE(noexcept(absl::Span<const int>(a, 2)));
+  EXPECT_TRUE(noexcept(absl::Span<const int>(a)));
+  EXPECT_TRUE(noexcept(absl::Span<const int>(v)));
+  EXPECT_TRUE(noexcept(absl::Span<int>(v)));
+  EXPECT_TRUE(noexcept(absl::Span<const int>({1, 2, 3})));
+  EXPECT_TRUE(noexcept(absl::MakeSpan(v)));
+  EXPECT_TRUE(noexcept(absl::MakeSpan(a)));
+  EXPECT_TRUE(noexcept(absl::MakeSpan(a, 2)));
+  EXPECT_TRUE(noexcept(absl::MakeSpan(a, a + 1)));
+  EXPECT_TRUE(noexcept(absl::MakeConstSpan(v)));
+  EXPECT_TRUE(noexcept(absl::MakeConstSpan(a)));
+  EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, 2)));
+  EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, a + 1)));
+
+  absl::Span<int> s(v);
+  EXPECT_TRUE(noexcept(s.data()));
+  EXPECT_TRUE(noexcept(s.size()));
+  EXPECT_TRUE(noexcept(s.length()));
+  EXPECT_TRUE(noexcept(s.empty()));
+  EXPECT_TRUE(noexcept(s[0]));
+  EXPECT_TRUE(noexcept(s.front()));
+  EXPECT_TRUE(noexcept(s.back()));
+  EXPECT_TRUE(noexcept(s.begin()));
+  EXPECT_TRUE(noexcept(s.cbegin()));
+  EXPECT_TRUE(noexcept(s.end()));
+  EXPECT_TRUE(noexcept(s.cend()));
+  EXPECT_TRUE(noexcept(s.rbegin()));
+  EXPECT_TRUE(noexcept(s.crbegin()));
+  EXPECT_TRUE(noexcept(s.rend()));
+  EXPECT_TRUE(noexcept(s.crend()));
+  EXPECT_TRUE(noexcept(s.remove_prefix(0)));
+  EXPECT_TRUE(noexcept(s.remove_suffix(0)));
+}
+
+// ConstexprTester exercises expressions in a constexpr context. Simply placing
+// the expression in a constexpr function is not enough, as some compilers will
+// simply compile the constexpr function as runtime code. Using template
+// parameters forces compile-time execution.
+template <int i>
+struct ConstexprTester {};
+
+#define ABSL_TEST_CONSTEXPR(expr)                       \
+  do {                                                  \
+    ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \
+  } while (0)
+
+struct ContainerWithConstexprMethods {
+  constexpr int size() const { return 1; }
+  constexpr const int* data() const { return &i; }
+  const int i;
+};
+
+TEST(ConstIntSpan, ConstexprTest) {
+  static constexpr int a[] = {1, 2, 3};
+  static constexpr int sized_arr[2] = {1, 2};
+  static constexpr ContainerWithConstexprMethods c{1};
+  ABSL_TEST_CONSTEXPR(absl::Span<const int>());
+  ABSL_TEST_CONSTEXPR(absl::Span<const int>(a, 2));
+  ABSL_TEST_CONSTEXPR(absl::Span<const int>(sized_arr));
+  ABSL_TEST_CONSTEXPR(absl::Span<const int>(c));
+  ABSL_TEST_CONSTEXPR(absl::MakeSpan(&a[0], 1));
+  ABSL_TEST_CONSTEXPR(absl::MakeSpan(c));
+  ABSL_TEST_CONSTEXPR(absl::MakeSpan(a));
+  ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(&a[0], 1));
+  ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(c));
+  ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(a));
+
+  constexpr absl::Span<const int> span = c;
+  ABSL_TEST_CONSTEXPR(span.data());
+  ABSL_TEST_CONSTEXPR(span.size());
+  ABSL_TEST_CONSTEXPR(span.length());
+  ABSL_TEST_CONSTEXPR(span.empty());
+  ABSL_TEST_CONSTEXPR(span.begin());
+  ABSL_TEST_CONSTEXPR(span.cbegin());
+  ABSL_TEST_CONSTEXPR(span.subspan(0, 0));
+  ABSL_TEST_CONSTEXPR(span[0]);
+}
+
+struct BigStruct {
+  char bytes[10000];
+};
+
+TEST(Span, SpanSize) {
+  EXPECT_LE(sizeof(absl::Span<int>), 2 * sizeof(void*));
+  EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
+}
+
+}  // namespace
diff --git a/absl/types/variant.h b/absl/types/variant.h
new file mode 100644
index 0000000..fd1d49a
--- /dev/null
+++ b/absl/types/variant.h
@@ -0,0 +1,844 @@
+// Copyright 2018 The Abseil 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.
+//
+// -----------------------------------------------------------------------------
+// variant.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines an `absl::variant` type for holding a type-safe
+// value of some prescribed set of types (noted as alternative types), and
+// associated functions for managing variants.
+//
+// The `absl::variant` type is a form of type-safe union. An `absl::variant`
+// should always hold a value of one of its alternative types (except in the
+// "valueless by exception state" -- see below). A default-constructed
+// `absl::variant` will hold the value of its first alternative type, provided
+// it is default-constructable.
+//
+// In exceptional cases due to error, an `absl::variant` can hold no
+// value (known as a "valueless by exception" state), though this is not the
+// norm.
+//
+// As with `absl::optional`, an `absl::variant` -- when it holds a value --
+// allocates a value of that type directly within the `variant` itself; it
+// cannot hold a reference, array, or the type `void`; it can, however, hold a
+// pointer to externally managed memory.
+//
+// `absl::variant` is a C++11 compatible version of the C++17 `std::variant`
+// abstraction and is designed to be a drop-in replacement for code compliant
+// with C++17.
+
+#ifndef ABSL_TYPES_VARIANT_H_
+#define ABSL_TYPES_VARIANT_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_VARIANT
+
+#include <variant>
+
+namespace absl {
+using std::bad_variant_access;
+using std::get;
+using std::get_if;
+using std::holds_alternative;
+using std::monostate;
+using std::variant;
+using std::variant_alternative;
+using std::variant_alternative_t;
+using std::variant_npos;
+using std::variant_size;
+using std::variant_size_v;
+using std::visit;
+}  // namespace absl
+
+#else  // ABSL_HAVE_STD_VARIANT
+
+#include <functional>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/variant.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// absl::variant
+// -----------------------------------------------------------------------------
+//
+// An 'absl::variant` type is a form of type-safe union. An `absl::variant` --
+// except in exceptional cases -- always holds a value of one of its alternative
+// types.
+//
+// Example:
+//
+//   // Construct a variant that holds either an integer or a std::string and
+//   // assign it to a std::string.
+//   absl::variant<int, std::string> v = std::string("abc");
+//
+//   // A default-contructed variant will hold a value-initialized value of
+//   // the first alternative type.
+//   auto a = absl::variant<int, std::string>();   // Holds an int of value '0'.
+//
+//   // variants are assignable.
+//
+//   // copy assignment
+//   auto v1 = absl::variant<int, std::string>("abc");
+//   auto v2 = absl::variant<int, std::string>(10);
+//   v2 = v1;  // copy assign
+//
+//   // move assignment
+//   auto v1 = absl::variant<int, std::string>("abc");
+//   v1 = absl::variant<int, std::string>(10);
+//
+//   // assignment through type conversion
+//   a = 128;         // variant contains int
+//   a = "128";       // variant contains std::string
+//
+// An `absl::variant` holding a value of one of its alternative types `T` holds
+// an allocation of `T` directly within the variant itself. An `absl::variant`
+// is not allowed to allocate additional storage, such as dynamic memory, to
+// allocate the contained value. The contained value shall be allocated in a
+// region of the variant storage suitably aligned for all alternative types.
+template <typename... Ts>
+class variant;
+
+// swap()
+//
+// Swaps two `absl::variant` values. This function is equivalent to `v.swap(w)`
+// where `v` and `w` are `absl::variant` types.
+//
+// Note that this function requires all alternative types to be both swappable
+// and move-constructible, because any two variants may refer to either the same
+// type (in which case, they will be swapped) or to two different types (in
+// which case the values will need to be moved).
+//
+template <typename... Ts>
+void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) {
+  v.swap(w);
+}
+
+// variant_size
+//
+// Returns the number of alterative types available for a given `absl::variant`
+// type as a compile-time constant expression. As this is a class template, it
+// is not generally useful for accessing the number of alternative types of
+// any given `absl::variant` instance.
+//
+// Example:
+//
+//   auto a = absl::variant<int, std::string>;
+//   constexpr int num_types =
+//       absl::variant_size<absl::variant<int, std::string>>();
+//
+//   // You can also use the member constant `value`.
+//   constexpr int num_types =
+//       absl::variant_size<absl::variant<int, std::string>>::value;
+//
+//   // `absl::variant_size` is more valuable for use in generic code:
+//   template <typename Variant>
+//   constexpr bool IsVariantMultivalue() {
+//       return absl::variant_size<Variant>() > 1;
+//   }
+//
+// Note that the set of cv-qualified specializations of `variant_size` are
+// provided to ensure that those specializations compile (especially when passed
+// within template logic).
+template <class T>
+struct variant_size;
+
+template <class... Ts>
+struct variant_size<variant<Ts...>>
+    : std::integral_constant<std::size_t, sizeof...(Ts)> {};
+
+// Specialization of `variant_size` for const qualified variants.
+template <class T>
+struct variant_size<const T> : variant_size<T>::type {};
+
+// Specialization of `variant_size` for volatile qualified variants.
+template <class T>
+struct variant_size<volatile T> : variant_size<T>::type {};
+
+// Specialization of `variant_size` for const volatile qualified variants.
+template <class T>
+struct variant_size<const volatile T> : variant_size<T>::type {};
+
+// variant_alternative
+//
+// Returns the alternative type for a given `absl::variant` at the passed
+// index value as a compile-time constant expression. As this is a class
+// template resulting in a type, it is not useful for access of the run-time
+// value of any given `absl::variant` variable.
+//
+// Example:
+//
+//   // The type of the 0th alternative is "int".
+//   using alternative_type_0
+//     = absl::variant_alternative<0, absl::variant<int, std::string>>::type;
+//
+//   static_assert(std::is_same<alternative_type_0, int>::value, "");
+//
+//   // `absl::variant_alternative` is more valuable for use in generic code:
+//   template <typename Variant>
+//   constexpr bool IsFirstElementTrivial() {
+//       return std::is_trivial_v<variant_alternative<0, Variant>::type>;
+//   }
+//
+// Note that the set of cv-qualified specializations of `variant_alternative`
+// are provided to ensure that those specializations compile (especially when
+// passed within template logic).
+template <std::size_t I, class T>
+struct variant_alternative;
+
+template <std::size_t I, class... Types>
+struct variant_alternative<I, variant<Types...>> {
+  using type =
+      variant_internal::VariantAlternativeSfinaeT<I, variant<Types...>>;
+};
+
+// Specialization of `variant_alternative` for const qualified variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, const T> {
+  using type = const typename variant_alternative<I, T>::type;
+};
+
+// Specialization of `variant_alternative` for volatile qualified variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, volatile T> {
+  using type = volatile typename variant_alternative<I, T>::type;
+};
+
+// Specialization of `variant_alternative` for const volatile qualified
+// variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, const volatile T> {
+  using type = const volatile typename variant_alternative<I, T>::type;
+};
+
+// Template type alias for variant_alternative<I, T>::type.
+//
+// Example:
+//
+//   using alternative_type_0
+//     = absl::variant_alternative_t<0, absl::variant<int, std::string>>;
+//   static_assert(std::is_same<alternative_type_0, int>::value, "");
+template <std::size_t I, class T>
+using variant_alternative_t = typename variant_alternative<I, T>::type;
+
+// holds_alternative()
+//
+// Checks whether the given variant currently holds a given alternative type,
+// returning `true` if so.
+//
+// Example:
+//
+//   absl::variant<int, std::string> bar = 42;
+//   if (absl::holds_alternative<int>(foo)) {
+//       std::cout << "The variant holds an integer";
+//   }
+template <class T, class... Types>
+constexpr bool holds_alternative(const variant<Types...>& v) noexcept {
+  static_assert(
+      variant_internal::UnambiguousIndexOfImpl<variant<Types...>, T,
+                                               0>::value != sizeof...(Types),
+      "The type T must occur exactly once in Types...");
+  return v.index() ==
+         variant_internal::UnambiguousIndexOf<variant<Types...>, T>::value;
+}
+
+// get()
+//
+// Returns a reference to the value currently within a given variant, using
+// either a unique alternative type amongst the variant's set of alternative
+// types, or the variant's index value. Attempting to get a variant's value
+// using a type that is not unique within the variant's set of alternative types
+// is a compile-time error. If the index of the alternative being specified is
+// different from the index of the alternative that is currently stored, throws
+// `absl::bad_variant_access`.
+//
+// Example:
+//
+//   auto a = absl::variant<int, std::string>;
+//
+//   // Get the value by type (if unique).
+//   int i = absl::get<int>(a);
+//
+//   auto b = absl::variant<int, int>;
+//
+//   // Getting the value by a type that is not unique is ill-formed.
+//   int j = absl::get<int>(b);     // Compile Error!
+//
+//   // Getting value by index not ambiguous and allowed.
+//   int k = absl::get<1>(b);
+
+// Overload for getting a variant's lvalue by type.
+template <class T, class... Types>
+constexpr T& get(variant<Types...>& v) {  // NOLINT
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a variant's rvalue by type.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <class T, class... Types>
+constexpr T&& get(variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(absl::move(v));
+}
+
+// Overload for getting a variant's const lvalue by type.
+template <class T, class... Types>
+constexpr const T& get(const variant<Types...>& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a variant's const rvalue by type.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <class T, class... Types>
+constexpr const T&& get(const variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(absl::move(v));
+}
+
+// Overload for getting a variant's lvalue by index.
+template <std::size_t I, class... Types>
+constexpr variant_alternative_t<I, variant<Types...>>& get(
+    variant<Types...>& v) {  // NOLINT
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(v);
+}
+
+// Overload for getting a variant's rvalue by index.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <std::size_t I, class... Types>
+constexpr variant_alternative_t<I, variant<Types...>>&& get(
+    variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(absl::move(v));
+}
+
+// Overload for getting a variant's const lvalue by index.
+template <std::size_t I, class... Types>
+constexpr const variant_alternative_t<I, variant<Types...>>& get(
+    const variant<Types...>& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(v);
+}
+
+// Overload for getting a variant's const rvalue by index.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <std::size_t I, class... Types>
+constexpr const variant_alternative_t<I, variant<Types...>>&& get(
+    const variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(absl::move(v));
+}
+
+// get_if()
+//
+// Returns a pointer to the value currently stored within a given variant, if
+// present, using either a unique alternative type amongst the variant's set of
+// alternative types, or the variant's index value. If such a value does not
+// exist, returns `nullptr`.
+//
+// As with `get`, attempting to get a variant's value using a type that is not
+// unique within the variant's set of alternative types is a compile-time error.
+
+// Overload for getting a pointer to the value stored in the given variant by
+// index.
+template <std::size_t I, class... Types>
+constexpr absl::add_pointer_t<variant_alternative_t<I, variant<Types...>>>
+get_if(variant<Types...>* v) noexcept {
+  return (v != nullptr && v->index() == I)
+             ? std::addressof(
+                   variant_internal::VariantCoreAccess::Access<I>(*v))
+             : nullptr;
+}
+
+// Overload for getting a pointer to the const value stored in the given
+// variant by index.
+template <std::size_t I, class... Types>
+constexpr absl::add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
+get_if(const variant<Types...>* v) noexcept {
+  return (v != nullptr && v->index() == I)
+             ? std::addressof(
+                   variant_internal::VariantCoreAccess::Access<I>(*v))
+             : nullptr;
+}
+
+// Overload for getting a pointer to the value stored in the given variant by
+// type.
+template <class T, class... Types>
+constexpr absl::add_pointer_t<T> get_if(variant<Types...>* v) noexcept {
+  return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a pointer to the const value stored in the given variant
+// by type.
+template <class T, class... Types>
+constexpr absl::add_pointer_t<const T> get_if(
+    const variant<Types...>* v) noexcept {
+  return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// visit()
+//
+// Calls a provided functor on a given set of variants. `absl::visit()` is
+// commonly used to conditionally inspect the state of a given variant (or set
+// of variants).
+// Requires: The expression in the Effects: element shall be a valid expression
+// of the same type and value category, for all combinations of alternative
+// types of all variants. Otherwise, the program is ill-formed.
+//
+// Example:
+//
+//   // Define a visitor functor
+//   struct GetVariant {
+//       template<typename T>
+//       void operator()(const T& i) const {
+//         std::cout << "The variant's value is: " << i;
+//       }
+//   };
+//
+//   // Declare our variant, and call `absl::visit()` on it.
+//   std::variant<int, std::string> foo = std::string("foo");
+//   GetVariant visitor;
+//   std::visit(visitor, foo);  // Prints `The variant's value is: foo'
+template <typename Visitor, typename... Variants>
+variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis,
+                                                          Variants&&... vars) {
+  return variant_internal::
+      VisitIndices<variant_size<absl::decay_t<Variants> >::value...>::Run(
+          variant_internal::PerformVisitation<Visitor, Variants...>{
+              std::forward_as_tuple(absl::forward<Variants>(vars)...),
+              absl::forward<Visitor>(vis)},
+          vars.index()...);
+}
+
+// monostate
+//
+// The monostate class serves as a first alternative type for a variant for
+// which the first variant type is otherwise not default-constructible.
+struct monostate {};
+
+// `absl::monostate` Relational Operators
+
+constexpr bool operator<(monostate, monostate) noexcept { return false; }
+constexpr bool operator>(monostate, monostate) noexcept { return false; }
+constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+constexpr bool operator==(monostate, monostate) noexcept { return true; }
+constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+
+
+//------------------------------------------------------------------------------
+// `absl::variant` Template Definition
+//------------------------------------------------------------------------------
+template <typename T0, typename... Tn>
+class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
+  // Intentionally not qualifing `negation` with `absl::` to work around a bug
+  // in MSVC 2015 with inline namespace and variadic template.
+  static_assert(absl::conjunction<std::is_object<T0>, std::is_object<Tn>...,
+                                  negation<std::is_array<T0> >,
+                                  negation<std::is_array<Tn> >...,
+                                  std::is_nothrow_destructible<T0>,
+                                  std::is_nothrow_destructible<Tn>...>::value,
+                "Attempted to instantiate a variant with an unsupported type.");
+
+  friend struct variant_internal::VariantCoreAccess;
+
+ private:
+  using Base = variant_internal::VariantBase<T0, Tn...>;
+
+ public:
+  // Constructors
+
+  // Constructs a variant holding a default-initialized value of the first
+  // alternative type.
+  constexpr variant() /*noexcept(see 111above)*/ = default;
+
+  // Copy constructor, standard semantics
+  variant(const variant& other) = default;
+
+  // Move constructor, standard semantics
+  variant(variant&& other) /*noexcept(see above)*/ = default;
+
+  // Constructs a variant of an alternative type specified by overload
+  // resolution of the provided forwarding arguments through
+  // direct-initialization.
+  //
+  // Note: If the selected constructor is a constexpr constructor, this
+  // constructor shall be a constexpr constructor.
+  //
+  // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
+  // has been voted passed the design phase in the C++ standard meeting in Mar
+  // 2018. It will be implemented and integrated into `absl::variant`.
+  template <
+      class T,
+      std::size_t I = std::enable_if<
+          variant_internal::IsNeitherSelfNorInPlace<variant,
+                                                    absl::decay_t<T>>::value,
+          variant_internal::IndexOfConstructedType<variant, T>>::type::value,
+      class Tj = absl::variant_alternative_t<I, variant>,
+      absl::enable_if_t<std::is_constructible<Tj, T>::value>* =
+          nullptr>
+  constexpr variant(T&& t) noexcept(std::is_nothrow_constructible<Tj, T>::value)
+      : Base(variant_internal::EmplaceTag<I>(), absl::forward<T>(t)) {}
+
+  // Constructs a variant of an alternative type from the arguments through
+  // direct-initialization.
+  //
+  // Note: If the selected constructor is a constexpr constructor, this
+  // constructor shall be a constexpr constructor.
+  template <class T, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::UnambiguousTypeOfT<variant, T>,
+                Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_type_t<T>, Args&&... args)
+      : Base(variant_internal::EmplaceTag<
+                 variant_internal::UnambiguousIndexOf<variant, T>::value>(),
+             absl::forward<Args>(args)...) {}
+
+  // Constructs a variant of an alternative type from an initializer list
+  // and other arguments through direct-initialization.
+  //
+  // Note: If the selected constructor is a constexpr constructor, this
+  // constructor shall be a constexpr constructor.
+  template <class T, class U, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::UnambiguousTypeOfT<variant, T>,
+                std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il,
+                             Args&&... args)
+      : Base(variant_internal::EmplaceTag<
+                 variant_internal::UnambiguousIndexOf<variant, T>::value>(),
+             il, absl::forward<Args>(args)...) {}
+
+  // Constructs a variant of an alternative type from a provided index,
+  // through value-initialization using the provided forwarded arguments.
+  template <std::size_t I, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::VariantAlternativeSfinaeT<I, variant>,
+                Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_index_t<I>, Args&&... args)
+      : Base(variant_internal::EmplaceTag<I>(), absl::forward<Args>(args)...) {}
+
+  // Constructs a variant of an alternative type from a provided index,
+  // through value-initialization of an initializer list and the provided
+  // forwarded arguments.
+  template <std::size_t I, class U, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::VariantAlternativeSfinaeT<I, variant>,
+                std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il,
+                             Args&&... args)
+      : Base(variant_internal::EmplaceTag<I>(), il,
+             absl::forward<Args>(args)...) {}
+
+  // Destructors
+
+  // Destroys the variant's currently contained value, provided that
+  // `absl::valueless_by_exception()` is false.
+  ~variant() = default;
+
+  // Assignment Operators
+
+  // Copy assignement operator
+  variant& operator=(const variant& other) = default;
+
+  // Move assignment operator
+  variant& operator=(variant&& other) /*noexcept(see above)*/ = default;
+
+  // Converting assignment operator
+  //
+  // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
+  // has been voted passed the design phase in the C++ standard meeting in Mar
+  // 2018. It will be implemented and integrated into `absl::variant`.
+  template <
+      class T,
+      std::size_t I = std::enable_if<
+          !std::is_same<absl::decay_t<T>, variant>::value,
+          variant_internal::IndexOfConstructedType<variant, T>>::type::value,
+      class Tj = absl::variant_alternative_t<I, variant>,
+      typename std::enable_if<std::is_assignable<Tj&, T>::value &&
+                              std::is_constructible<Tj, T>::value>::type* =
+          nullptr>
+  variant& operator=(T&& t) noexcept(
+      std::is_nothrow_assignable<Tj&, T>::value&&
+          std::is_nothrow_constructible<Tj, T>::value) {
+    variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
+        variant_internal::VariantCoreAccess::MakeConversionAssignVisitor(
+            this, absl::forward<T>(t)),
+        index());
+
+    return *this;
+  }
+
+
+  // emplace() Functions
+
+  // Constructs a value of the given alternative type T within the variant.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, std::string> v;
+  //   v.emplace<int>(99);
+  //   v.emplace<std::string>("abc");
+  template <
+      class T, class... Args,
+      typename std::enable_if<std::is_constructible<
+          absl::variant_alternative_t<
+              variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
+          Args...>::value>::type* = nullptr>
+  T& emplace(Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<
+        variant_internal::UnambiguousIndexOf<variant, T>::value>(
+        this, absl::forward<Args>(args)...);
+  }
+
+  // Constructs a value of the given alternative type T within the variant using
+  // an initializer list.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, std::string> v;
+  //   v.emplace<std::vector<int>>({0, 1, 2});
+  template <
+      class T, class U, class... Args,
+      typename std::enable_if<std::is_constructible<
+          absl::variant_alternative_t<
+              variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
+          std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  T& emplace(std::initializer_list<U> il, Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<
+        variant_internal::UnambiguousIndexOf<variant, T>::value>(
+        this, il, absl::forward<Args>(args)...);
+  }
+
+  // Destroys the current value of the variant (provided that
+  // `absl::valueless_by_exception()` is false, and constructs a new value at
+  // the given index.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, int> v;
+  //   v.emplace<1>(99);
+  //   v.emplace<2>(98);
+  //   v.emplace<int>(99);  // Won't compile. 'int' isn't a unique type.
+  template <std::size_t I, class... Args,
+            typename std::enable_if<
+                std::is_constructible<absl::variant_alternative_t<I, variant>,
+                                      Args...>::value>::type* = nullptr>
+  absl::variant_alternative_t<I, variant>& emplace(Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<I>(
+        this, absl::forward<Args>(args)...);
+  }
+
+  // Destroys the current value of the variant (provided that
+  // `absl::valueless_by_exception()` is false, and constructs a new value at
+  // the given index using an initializer list and the provided arguments.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, int> v;
+  //   v.emplace<0>({0, 1, 2});
+  template <std::size_t I, class U, class... Args,
+            typename std::enable_if<std::is_constructible<
+                absl::variant_alternative_t<I, variant>,
+                std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  absl::variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il,
+                                                   Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<I>(
+        this, il, absl::forward<Args>(args)...);
+  }
+
+  // variant::valueless_by_exception()
+  //
+  // Returns false if and only if the variant currently holds a valid value.
+  constexpr bool valueless_by_exception() const noexcept {
+    return this->index_ == absl::variant_npos;
+  }
+
+  // variant::index()
+  //
+  // Returns the index value of the variant's currently selected alternative
+  // type.
+  constexpr std::size_t index() const noexcept { return this->index_; }
+
+  // variant::swap()
+  //
+  // Swaps the values of two variant objects.
+  //
+  // TODO(calabrese)
+  //   `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()`
+  //   which is introduced in C++17. So we assume `is_swappable()` is always
+  //   true and `is_nothrow_swappable()` is same as `std::is_trivial()`.
+  void swap(variant& rhs) noexcept(
+      absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) {
+    return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
+        variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index());
+  }
+};
+
+// We need a valid declaration of variant<> for SFINAE and overload resolution
+// to work properly above, but we don't need a full declaration since this type
+// will never be constructed. This declaration, though incomplete, suffices.
+template <>
+class variant<>;
+
+//------------------------------------------------------------------------------
+// Relational Operators
+//------------------------------------------------------------------------------
+//
+// If neither operand is in the `variant::valueless_by_exception` state:
+//
+//   * If the index of both variants is the same, the relational operator
+//     returns the result of the corresponding relational operator for the
+//     corresponding alternative type.
+//   * If the index of both variants is not the same, the relational operator
+//     returns the result of that operation applied to the value of the left
+//     operand's index and the value of the right operand's index.
+//   * If at least one operand is in the valueless_by_exception state:
+//     - A variant in the valueless_by_exception state is only considered equal
+//       to another variant in the valueless_by_exception state.
+//     - If exactly one operand is in the valueless_by_exception state, the
+//       variant in the valueless_by_exception state is less than the variant
+//       that is not in the valueless_by_exception state.
+//
+// Note: The value 1 is added to each index in the relational comparisons such
+// that the index corresponding to the valueless_by_exception state wraps around
+// to 0 (the lowest value for the index type), and the remaining indices stay in
+// the same relative order.
+
+// Equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() == b.index()) &&
+         variant_internal::VisitIndices<sizeof...(Types)>::Run(
+             variant_internal::EqualsOp<Types...>{&a, &b}, a.index());
+}
+
+// Not equal operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index()) ||
+         variant_internal::VisitIndices<sizeof...(Types)>::Run(
+             variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index());
+}
+
+// Less-than operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) < (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::LessThanOp<Types...>{&a, &b}, a.index());
+}
+
+// Greater-than operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) > (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::GreaterThanOp<Types...>{&a, &b},
+                   a.index());
+}
+
+// Less-than or equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) < (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::LessThanOrEqualsOp<Types...>{&a, &b},
+                   a.index());
+}
+
+// Greater-than or equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...>
+operator>=(const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) > (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b},
+                   a.index());
+}
+
+}  // namespace absl
+
+namespace std {
+
+// hash()
+template <>  // NOLINT
+struct hash<absl::monostate> {
+  std::size_t operator()(absl::monostate) const { return 0; }
+};
+
+template <class... T>  // NOLINT
+struct hash<absl::variant<T...>>
+    : absl::variant_internal::VariantHashBase<absl::variant<T...>, void,
+                                              absl::remove_const_t<T>...> {};
+
+}  // namespace std
+
+#endif  // ABSL_HAVE_STD_VARIANT
+
+namespace absl {
+namespace variant_internal {
+
+// Helper visitor for converting a variant<Ts...>` into another type (mostly
+// variant) that can be constructed from any type.
+template <typename To>
+struct ConversionVisitor {
+  template <typename T>
+  To operator()(T&& v) const {
+    return To(std::forward<T>(v));
+  }
+};
+
+}  // namespace variant_internal
+
+// ConvertVariantTo()
+//
+// Helper functions to convert an `absl::variant` to a variant of another set of
+// types, provided that the alternative type of the new variant type can be
+// converted from any type in the source variant.
+//
+// Example:
+//
+//   absl::variant<name1, name2, float> InternalReq(const Req&);
+//
+//   // name1 and name2 are convertible to name
+//   absl::variant<name, float> ExternalReq(const Req& req) {
+//     return absl::ConvertVariantTo<absl::variant<name, float>>(
+//              InternalReq(req));
+//   }
+template <typename To, typename Variant>
+To ConvertVariantTo(Variant&& variant) {
+  return absl::visit(variant_internal::ConversionVisitor<To>{},
+                     std::forward<Variant>(variant));
+}
+
+}  // namespace absl
+
+#endif  // ABSL_TYPES_VARIANT_H_
diff --git a/absl/types/variant_benchmark.cc b/absl/types/variant_benchmark.cc
new file mode 100644
index 0000000..99658ac
--- /dev/null
+++ b/absl/types/variant_benchmark.cc
@@ -0,0 +1,220 @@
+// Copyright 2017 The Abseil 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.
+
+// Unit tests for the variant template. The 'is' and 'IsEmpty' methods
+// of variant are not explicitly tested because they are used repeatedly
+// in building other tests. All other public variant methods should have
+// explicit tests.
+
+#include "absl/types/variant.h"
+
+#include <cstddef>
+#include <cstdlib>
+#include <string>
+#include <tuple>
+
+#include "benchmark/benchmark.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+namespace {
+
+template <std::size_t I>
+struct VariantAlternative {
+  char member;
+};
+
+template <class Indices>
+struct VariantOfAlternativesImpl;
+
+template <std::size_t... Indices>
+struct VariantOfAlternativesImpl<absl::index_sequence<Indices...>> {
+  using type = absl::variant<VariantAlternative<Indices>...>;
+};
+
+template <std::size_t NumAlternatives>
+using VariantOfAlternatives = typename VariantOfAlternativesImpl<
+    absl::make_index_sequence<NumAlternatives>>::type;
+
+struct Empty {};
+
+template <class... T>
+void Ignore(T...) noexcept {}
+
+template <class T>
+Empty DoNotOptimizeAndReturnEmpty(T&& arg) noexcept {
+  benchmark::DoNotOptimize(arg);
+  return {};
+}
+
+struct VisitorApplier {
+  struct Visitor {
+    template <class... T>
+    void operator()(T&&... args) const noexcept {
+      Ignore(DoNotOptimizeAndReturnEmpty(args)...);
+    }
+  };
+
+  template <class... Vars>
+  void operator()(const Vars&... vars) const noexcept {
+    absl::visit(Visitor(), vars...);
+  }
+};
+
+template <std::size_t NumIndices, std::size_t CurrIndex = NumIndices - 1>
+struct MakeWithIndex {
+  using Variant = VariantOfAlternatives<NumIndices>;
+
+  static Variant Run(std::size_t index) {
+    return index == CurrIndex
+               ? Variant(absl::in_place_index_t<CurrIndex>())
+               : MakeWithIndex<NumIndices, CurrIndex - 1>::Run(index);
+  }
+};
+
+template <std::size_t NumIndices>
+struct MakeWithIndex<NumIndices, 0> {
+  using Variant = VariantOfAlternatives<NumIndices>;
+
+  static Variant Run(std::size_t /*index*/) { return Variant(); }
+};
+
+template <std::size_t NumIndices, class Dimensions>
+struct MakeVariantTuple;
+
+template <class T, std::size_t /*I*/>
+using always_t = T;
+
+template <std::size_t NumIndices>
+VariantOfAlternatives<NumIndices> MakeVariant(std::size_t dimension,
+                                              std::size_t index) {
+  return dimension == 0
+             ? MakeWithIndex<NumIndices>::Run(index % NumIndices)
+             : MakeVariant<NumIndices>(dimension - 1, index / NumIndices);
+}
+
+template <std::size_t NumIndices, std::size_t... Dimensions>
+struct MakeVariantTuple<NumIndices, absl::index_sequence<Dimensions...>> {
+  using VariantTuple =
+      std::tuple<always_t<VariantOfAlternatives<NumIndices>, Dimensions>...>;
+
+  static VariantTuple Run(int index) {
+    return std::make_tuple(MakeVariant<NumIndices>(Dimensions, index)...);
+  }
+};
+
+constexpr std::size_t integral_pow(std::size_t base, std::size_t power) {
+  return power == 0 ? 1 : base * integral_pow(base, power - 1);
+}
+
+template <std::size_t End, std::size_t I = 0>
+struct VisitTestBody {
+  template <class Vars, class State>
+  static bool Run(Vars& vars, State& state) {
+    if (state.KeepRunning()) {
+      absl::apply(VisitorApplier(), vars[I]);
+      return VisitTestBody<End, I + 1>::Run(vars, state);
+    }
+    return false;
+  }
+};
+
+template <std::size_t End>
+struct VisitTestBody<End, End> {
+  template <class Vars, class State>
+  static bool Run(Vars& /*vars*/, State& /*state*/) {
+    return true;
+  }
+};
+
+// Visit operations where branch prediction is likely to give a boost.
+template <std::size_t NumIndices, std::size_t NumDimensions = 1>
+void BM_RedundantVisit(benchmark::State& state) {
+  auto vars =
+      MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>::
+          Run(static_cast<std::size_t>(state.range(0)));
+
+  for (auto _ : state) {  // NOLINT
+    benchmark::DoNotOptimize(vars);
+    absl::apply(VisitorApplier(), vars);
+  }
+}
+
+// Visit operations where branch prediction is unlikely to give a boost.
+template <std::size_t NumIndices, std::size_t NumDimensions = 1>
+void BM_Visit(benchmark::State& state) {
+  constexpr std::size_t num_possibilities =
+      integral_pow(NumIndices, NumDimensions);
+
+  using VariantTupleMaker =
+      MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>;
+  using Tuple = typename VariantTupleMaker::VariantTuple;
+
+  Tuple vars[num_possibilities];
+  for (std::size_t i = 0; i < num_possibilities; ++i)
+    vars[i] = VariantTupleMaker::Run(i);
+
+  while (VisitTestBody<num_possibilities>::Run(vars, state)) {
+  }
+}
+
+// Visitation
+//   Each visit is on a different variant with a different active alternative)
+
+// Unary visit
+BENCHMARK_TEMPLATE(BM_Visit, 1);
+BENCHMARK_TEMPLATE(BM_Visit, 2);
+BENCHMARK_TEMPLATE(BM_Visit, 3);
+BENCHMARK_TEMPLATE(BM_Visit, 4);
+BENCHMARK_TEMPLATE(BM_Visit, 5);
+BENCHMARK_TEMPLATE(BM_Visit, 6);
+BENCHMARK_TEMPLATE(BM_Visit, 7);
+BENCHMARK_TEMPLATE(BM_Visit, 8);
+BENCHMARK_TEMPLATE(BM_Visit, 16);
+BENCHMARK_TEMPLATE(BM_Visit, 32);
+BENCHMARK_TEMPLATE(BM_Visit, 64);
+
+// Binary visit
+BENCHMARK_TEMPLATE(BM_Visit, 1, 2);
+BENCHMARK_TEMPLATE(BM_Visit, 2, 2);
+BENCHMARK_TEMPLATE(BM_Visit, 3, 2);
+BENCHMARK_TEMPLATE(BM_Visit, 4, 2);
+BENCHMARK_TEMPLATE(BM_Visit, 5, 2);
+
+// Ternary visit
+BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
+BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
+BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
+
+// Quaternary visit
+BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
+BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
+
+// Redundant Visitation
+//   Each visit consistently has the same alternative active
+
+// Unary visit
+BENCHMARK_TEMPLATE(BM_RedundantVisit, 1)->Arg(0);
+BENCHMARK_TEMPLATE(BM_RedundantVisit, 2)->DenseRange(0, 1);
+BENCHMARK_TEMPLATE(BM_RedundantVisit, 8)->DenseRange(0, 7);
+
+// Binary visit
+BENCHMARK_TEMPLATE(BM_RedundantVisit, 1, 2)->Arg(0);
+BENCHMARK_TEMPLATE(BM_RedundantVisit, 2, 2)
+    ->DenseRange(0, integral_pow(2, 2) - 1);
+BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2)
+    ->DenseRange(0, integral_pow(4, 2) - 1);
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
new file mode 100644
index 0000000..27c0b96
--- /dev/null
+++ b/absl/types/variant_exception_safety_test.cc
@@ -0,0 +1,508 @@
+// Copyright 2017 The Abseil 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 "absl/types/variant.h"
+
+#include <iostream>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+namespace {
+
+using ::testing::MakeExceptionSafetyTester;
+using ::testing::strong_guarantee;
+using ::testing::TestNothrowOp;
+using ::testing::TestThrowingCtor;
+
+using Thrower = testing::ThrowingValue<>;
+using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
+using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
+using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
+using ThrowingVariant =
+    absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
+
+struct ConversionException {};
+
+template <class T>
+struct ExceptionOnConversion {
+  operator T() const {  // NOLINT
+    throw ConversionException();
+  }
+};
+
+// Forces a variant into the valueless by exception state.
+void ToValuelessByException(ThrowingVariant& v) {  // NOLINT
+  try {
+    v.emplace<Thrower>();
+    v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
+  } catch (ConversionException& /*e*/) {
+    // This space intentionally left blank.
+  }
+}
+
+// Check that variant is still in a usable state after an exception is thrown.
+testing::AssertionResult CheckInvariants(ThrowingVariant* v) {
+  using testing::AssertionFailure;
+  using testing::AssertionSuccess;
+
+  // Try using the active alternative
+  if (absl::holds_alternative<Thrower>(*v)) {
+    auto& t = absl::get<Thrower>(*v);
+    t = Thrower{-100};
+    if (t.Get() != -100) {
+      return AssertionFailure() << "Thrower should be assigned -100";
+    }
+  } else if (absl::holds_alternative<ThrowerVec>(*v)) {
+    auto& tv = absl::get<ThrowerVec>(*v);
+    tv.clear();
+    tv.emplace_back(-100);
+    if (tv.size() != 1 || tv[0].Get() != -100) {
+      return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
+    }
+  } else if (absl::holds_alternative<CopyNothrow>(*v)) {
+    auto& t = absl::get<CopyNothrow>(*v);
+    t = CopyNothrow{-100};
+    if (t.Get() != -100) {
+      return AssertionFailure() << "CopyNothrow should be assigned -100";
+    }
+  } else if (absl::holds_alternative<MoveNothrow>(*v)) {
+    auto& t = absl::get<MoveNothrow>(*v);
+    t = MoveNothrow{-100};
+    if (t.Get() != -100) {
+      return AssertionFailure() << "MoveNothrow should be assigned -100";
+    }
+  }
+
+  // Try making variant valueless_by_exception
+  if (!v->valueless_by_exception()) ToValuelessByException(*v);
+  if (!v->valueless_by_exception()) {
+    return AssertionFailure() << "Variant should be valueless_by_exception";
+  }
+  try {
+    auto unused = absl::get<Thrower>(*v);
+    static_cast<void>(unused);
+    return AssertionFailure() << "Variant should not contain Thrower";
+  } catch (absl::bad_variant_access) {
+  } catch (...) {
+    return AssertionFailure() << "Unexpected exception throw from absl::get";
+  }
+
+  // Try using the variant
+  v->emplace<Thrower>(100);
+  if (!absl::holds_alternative<Thrower>(*v) ||
+      absl::get<Thrower>(*v) != Thrower(100)) {
+    return AssertionFailure() << "Variant should contain Thrower(100)";
+  }
+  v->emplace<ThrowerVec>({Thrower(100)});
+  if (!absl::holds_alternative<ThrowerVec>(*v) ||
+      absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
+    return AssertionFailure()
+           << "Variant should contain ThrowerVec{Thrower(100)}";
+  }
+  return AssertionSuccess();
+}
+
+template <typename... Args>
+Thrower ExpectedThrower(Args&&... args) {
+  return Thrower(42, args...);
+}
+
+ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
+ThrowingVariant ValuelessByException() {
+  ThrowingVariant v;
+  ToValuelessByException(v);
+  return v;
+}
+ThrowingVariant WithThrower() { return Thrower(39); }
+ThrowingVariant WithThrowerVec() {
+  return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
+}
+ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
+ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
+
+TEST(VariantExceptionSafetyTest, DefaultConstructor) {
+  TestThrowingCtor<ThrowingVariant>();
+}
+
+TEST(VariantExceptionSafetyTest, CopyConstructor) {
+  {
+    ThrowingVariant v(ExpectedThrower());
+    TestThrowingCtor<ThrowingVariant>(v);
+  }
+  {
+    ThrowingVariant v(ExpectedThrowerVec());
+    TestThrowingCtor<ThrowingVariant>(v);
+  }
+  {
+    ThrowingVariant v(ValuelessByException());
+    TestThrowingCtor<ThrowingVariant>(v);
+  }
+}
+
+TEST(VariantExceptionSafetyTest, MoveConstructor) {
+  {
+    ThrowingVariant v(ExpectedThrower());
+    TestThrowingCtor<ThrowingVariant>(std::move(v));
+  }
+  {
+    ThrowingVariant v(ExpectedThrowerVec());
+    TestThrowingCtor<ThrowingVariant>(std::move(v));
+  }
+  {
+    ThrowingVariant v(ValuelessByException());
+    TestThrowingCtor<ThrowingVariant>(std::move(v));
+  }
+}
+
+TEST(VariantExceptionSafetyTest, ValueConstructor) {
+  TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
+  TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
+                                    ExpectedThrower());
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
+                                    ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
+                                    ExpectedThrower());
+  TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
+                                    ExpectedThrowerVec());
+}
+
+TEST(VariantExceptionSafetyTest, CopyAssign) {
+  // variant& operator=(const variant& rhs);
+  // Let j be rhs.index()
+  {
+    // - neither *this nor rhs holds a value
+    const ThrowingVariant rhs = ValuelessByException();
+    ThrowingVariant lhs = ValuelessByException();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
+  }
+  {
+    // - *this holds a value but rhs does not
+    const ThrowingVariant rhs = ValuelessByException();
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
+  }
+  // - index() == j
+  {
+    const ThrowingVariant rhs(ExpectedThrower());
+    auto tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrower())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+  {
+    const ThrowingVariant rhs(ExpectedThrowerVec());
+    auto tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrowerVec())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+  // libstdc++ std::variant has bugs on copy assignment regarding exception
+  // safety.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  // index() != j
+  // if is_nothrow_copy_constructible_v<Tj> or
+  // !is_nothrow_move_constructible<Tj> is true, equivalent to
+  // emplace<j>(get<j>(rhs))
+  {
+    // is_nothrow_copy_constructible_v<Tj> == true
+    // should not throw because emplace() invokes Tj's copy ctor
+    // which should not throw.
+    const ThrowingVariant rhs(CopyNothrow{});
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
+  }
+  {
+    // is_nothrow_copy_constructible<Tj> == false &&
+    // is_nothrow_move_constructible<Tj> == false
+    // should provide basic guarantee because emplace() invokes Tj's copy ctor
+    // which may throw.
+    const ThrowingVariant rhs(ExpectedThrower());
+    auto tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithCopyNoThrow())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+#endif  // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  {
+    // is_nothrow_copy_constructible_v<Tj> == false &&
+    // is_nothrow_move_constructible_v<Tj> == true
+    // should provide strong guarantee because it is equivalent to
+    // operator=(variant(rhs)) which creates a temporary then invoke the move
+    // ctor which shouldn't throw.
+    const ThrowingVariant rhs(MoveNothrow{});
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants, strong_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+}
+
+TEST(VariantExceptionSafetyTest, MoveAssign) {
+  // variant& operator=(variant&& rhs);
+  // Let j be rhs.index()
+  {
+    // - neither *this nor rhs holds a value
+    ThrowingVariant rhs = ValuelessByException();
+    ThrowingVariant lhs = ValuelessByException();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
+  }
+  {
+    // - *this holds a value but rhs does not
+    ThrowingVariant rhs = ValuelessByException();
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
+  }
+  {
+    // - index() == j
+    // assign get<j>(std::move(rhs)) to the value contained in *this.
+    // If an exception is thrown during call to Tj's move assignment, the state
+    // of the contained value is as defined by the exception safety guarantee of
+    // Tj's move assignment; index() will be j.
+    ThrowingVariant rhs(ExpectedThrower());
+    size_t j = rhs.index();
+    // Since Thrower's move assignment has basic guarantee, so should variant's.
+    auto tester = MakeExceptionSafetyTester()
+                      .WithInitialValue(WithThrower())
+                      .WithOperation([&](ThrowingVariant* lhs) {
+                        auto copy = rhs;
+                        *lhs = std::move(copy);
+                      });
+    EXPECT_TRUE(tester
+                    .WithInvariants(
+                        CheckInvariants,
+                        [&](ThrowingVariant* lhs) { return lhs->index() == j; })
+                    .Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+  {
+    // - otherwise (index() != j), equivalent to
+    // emplace<j>(get<j>(std::move(rhs)))
+    // - If an exception is thrown during the call to Tj's move construction
+    // (with j being rhs.index()), the variant will hold no value.
+    ThrowingVariant rhs(CopyNothrow{});
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      *lhs = std::move(copy);
+                    }));
+  }
+}
+
+TEST(VariantExceptionSafetyTest, ValueAssign) {
+  // template<class T> variant& operator=(T&& t);
+  // Let Tj be the type that is selected by overload resolution to be assigned.
+  {
+    // If *this holds a Tj, assigns std::forward<T>(t) to the value contained in
+    // *this. If  an exception is thrown during the assignment of
+    // std::forward<T>(t) to the value contained in *this, the state of the
+    // contained value and t are as defined by the exception safety guarantee of
+    // the assignment expression; valueless_by_exception() will be false.
+    // Since Thrower's copy/move assignment has basic guarantee, so should
+    // variant's.
+    Thrower rhs = ExpectedThrower();
+    // copy assign
+    auto copy_tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithThrower())
+            .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(copy_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return !lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
+    // move assign
+    auto move_tester = MakeExceptionSafetyTester()
+                           .WithInitialValue(WithThrower())
+                           .WithOperation([&](ThrowingVariant* lhs) {
+                             auto copy = rhs;
+                             *lhs = std::move(copy);
+                           });
+    EXPECT_TRUE(move_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return !lhs->valueless_by_exception();
+                                    })
+                    .Test());
+
+    EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
+  }
+  // Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj,
+  // T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to
+  // emplace<j>(std::forward<T>(t)).
+  // We simplify the test by letting T = `const Tj&`  or `Tj&&`, so we can reuse
+  // the CopyNothrow and MoveNothrow types.
+
+  // if is_nothrow_constructible_v<Tj, T>
+  // (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just
+  // invokes the copy/move constructor and it should not throw.
+  {
+    const CopyNothrow rhs;
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
+  }
+  {
+    MoveNothrow rhs;
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
+  }
+  // if is_nothrow_constructible_v<Tj, T> == false &&
+  // is_nothrow_move_constructible<Tj> == false
+  // emplace() invokes the copy/move constructor which may throw so it should
+  // provide basic guarantee and variant object might not hold a value.
+  {
+    Thrower rhs = ExpectedThrower();
+    // copy
+    auto copy_tester =
+        MakeExceptionSafetyTester()
+            .WithInitialValue(WithCopyNoThrow())
+            .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
+    EXPECT_TRUE(copy_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
+    // move
+    auto move_tester = MakeExceptionSafetyTester()
+                           .WithInitialValue(WithCopyNoThrow())
+                           .WithOperation([](ThrowingVariant* lhs) {
+                             *lhs = ExpectedThrower(testing::nothrow_ctor);
+                           });
+    EXPECT_TRUE(move_tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* lhs) {
+                                      return lhs->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
+  }
+  // Otherwise (if is_nothrow_constructible_v<Tj, T> == false &&
+  // is_nothrow_move_constructible<Tj> == true),
+  // equivalent to operator=(variant(std::forward<T>(t)))
+  // This should have strong guarantee because it creates a temporary variant
+  // and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
+  // libstdc++ std::variant has bugs on conversion assignment regarding
+  // exception safety.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  {
+    MoveNothrow rhs;
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants, strong_guarantee)
+                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+  }
+#endif  // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+}
+
+TEST(VariantExceptionSafetyTest, Emplace) {
+  // If an exception during the initialization of the contained value, the
+  // variant might not hold a value. The standard requires emplace() to provide
+  // only basic guarantee.
+  {
+    Thrower args = ExpectedThrower();
+    auto tester = MakeExceptionSafetyTester()
+                      .WithInitialValue(WithThrower())
+                      .WithOperation([&args](ThrowingVariant* v) {
+                        v->emplace<Thrower>(args);
+                      });
+    EXPECT_TRUE(tester
+                    .WithInvariants(CheckInvariants,
+                                    [](ThrowingVariant* v) {
+                                      return v->valueless_by_exception();
+                                    })
+                    .Test());
+    EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
+  }
+}
+
+TEST(VariantExceptionSafetyTest, Swap) {
+  // if both are valueless_by_exception(), no effect
+  {
+    ThrowingVariant rhs = ValuelessByException();
+    ThrowingVariant lhs = ValuelessByException();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); }));
+  }
+  // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
+  // where i is index().
+  {
+    ThrowingVariant rhs = ExpectedThrower();
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants)
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      lhs->swap(copy);
+                    }));
+  }
+  // Otherwise, exchanges the value of rhs and *this. The exception safety
+  // involves variant in moved-from state which is not specified in the
+  // standard, and since swap is 3-step it's impossible for it to provide a
+  // overall strong guarantee. So, we are only checking basic guarantee here.
+  {
+    ThrowingVariant rhs = ExpectedThrower();
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithCopyNoThrow())
+                    .WithInvariants(CheckInvariants)
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      lhs->swap(copy);
+                    }));
+  }
+  {
+    ThrowingVariant rhs = ExpectedThrower();
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithCopyNoThrow())
+                    .WithInvariants(CheckInvariants)
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      copy.swap(*lhs);
+                    }));
+  }
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
new file mode 100644
index 0000000..262bd94
--- /dev/null
+++ b/absl/types/variant_test.cc
@@ -0,0 +1,2612 @@
+// Copyright 2017 The Abseil 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.
+
+// Unit tests for the variant template. The 'is' and 'IsEmpty' methods
+// of variant are not explicitly tested because they are used repeatedly
+// in building other tests. All other public variant methods should have
+// explicit tests.
+
+#include "absl/types/variant.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <functional>
+#include <initializer_list>
+#include <memory>
+#include <ostream>
+#include <queue>
+#include <type_traits>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/port.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
+  EXPECT_THROW(expr, exception_t)
+
+#else
+
+#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
+  EXPECT_DEATH(expr, text)
+
+#endif  // ABSL_HAVE_EXCEPTIONS
+
+#define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...)                 \
+  ABSL_VARIANT_TEST_EXPECT_FAIL((__VA_ARGS__), absl::bad_variant_access, \
+                                "Bad variant access")
+
+struct Hashable {};
+
+namespace std {
+template <>
+struct hash<Hashable> {
+  size_t operator()(const Hashable&);
+};
+}  // namespace std
+
+struct NonHashable {};
+
+namespace absl {
+namespace {
+
+using ::testing::DoubleEq;
+using ::testing::Pointee;
+using ::testing::VariantWith;
+
+struct MoveCanThrow {
+  MoveCanThrow() : v(0) {}
+  MoveCanThrow(int v) : v(v) {}  // NOLINT(runtime/explicit)
+  MoveCanThrow(const MoveCanThrow& other) : v(other.v) {}
+  MoveCanThrow& operator=(const MoveCanThrow& /*other*/) { return *this; }
+  int v;
+};
+
+bool operator==(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v == rhs.v; }
+bool operator!=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v != rhs.v; }
+bool operator<(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v < rhs.v; }
+bool operator<=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v <= rhs.v; }
+bool operator>=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v >= rhs.v; }
+bool operator>(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v > rhs.v; }
+
+// This helper class allows us to determine if it was swapped with std::swap()
+// or with its friend swap() function.
+struct SpecialSwap {
+  explicit SpecialSwap(int i) : i(i) {}
+  friend void swap(SpecialSwap& a, SpecialSwap& b) {
+    a.special_swap = b.special_swap = true;
+    std::swap(a.i, b.i);
+  }
+  bool operator==(SpecialSwap other) const { return i == other.i; }
+  int i;
+  bool special_swap = false;
+};
+
+struct MoveOnlyWithListConstructor {
+  MoveOnlyWithListConstructor() = default;
+  explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
+                                       int value)
+      : value(value) {}
+  MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
+  MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
+      default;
+
+  int value = 0;
+};
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+struct ConversionException {};
+
+template <class T>
+struct ExceptionOnConversion {
+  operator T() const {  // NOLINT(runtime/explicit)
+    throw ConversionException();
+  }
+};
+
+// Forces a variant into the valueless by exception state.
+template <class H, class... T>
+void ToValuelessByException(absl::variant<H, T...>& v) {  // NOLINT
+  try {
+    v.template emplace<0>(ExceptionOnConversion<H>());
+  } catch (ConversionException& /*e*/) {
+    // This space intentionally left blank.
+  }
+}
+
+#endif  // ABSL_HAVE_EXCEPTIONS
+
+// An indexed sequence of distinct structures holding a single
+// value of type T
+template<typename T, size_t N>
+struct ValueHolder {
+  explicit ValueHolder(const T& x) : value(x) {}
+  typedef T value_type;
+  value_type value;
+  static const size_t kIndex = N;
+};
+template<typename T, size_t N>
+const size_t ValueHolder<T, N>::kIndex;
+
+// The following three functions make ValueHolder compatible with
+// EXPECT_EQ and EXPECT_NE
+template<typename T, size_t N>
+inline bool operator==(const ValueHolder<T, N>& left,
+                       const ValueHolder<T, N>& right) {
+  return left.value == right.value;
+}
+
+template<typename T, size_t N>
+inline bool operator!=(const ValueHolder<T, N>& left,
+                       const ValueHolder<T, N>& right) {
+  return left.value != right.value;
+}
+
+template<typename T, size_t N>
+inline std::ostream& operator<<(
+    std::ostream& stream, const ValueHolder<T, N>& object) {
+  return stream << object.value;
+}
+
+// Makes a variant holding twelve uniquely typed T wrappers.
+template<typename T>
+struct VariantFactory {
+  typedef variant<ValueHolder<T, 1>, ValueHolder<T, 2>, ValueHolder<T, 3>,
+                  ValueHolder<T, 4>>
+      Type;
+};
+
+// A typelist in 1:1 with VariantFactory, to use type driven unit tests.
+typedef ::testing::Types<ValueHolder<size_t, 1>, ValueHolder<size_t, 2>,
+                         ValueHolder<size_t, 3>,
+                         ValueHolder<size_t, 4>> VariantTypes;
+
+// Increments the provided counter pointer in the destructor
+struct IncrementInDtor {
+  explicit IncrementInDtor(int* counter) : counter(counter) {}
+  ~IncrementInDtor() { *counter += 1; }
+  int* counter;
+};
+
+struct IncrementInDtorCopyCanThrow {
+  explicit IncrementInDtorCopyCanThrow(int* counter) : counter(counter) {}
+  IncrementInDtorCopyCanThrow(IncrementInDtorCopyCanThrow&& other) noexcept =
+      default;
+  IncrementInDtorCopyCanThrow(const IncrementInDtorCopyCanThrow& other)
+      : counter(other.counter) {}
+  IncrementInDtorCopyCanThrow& operator=(
+      IncrementInDtorCopyCanThrow&&) noexcept = default;
+  IncrementInDtorCopyCanThrow& operator=(
+      IncrementInDtorCopyCanThrow const& other) {
+    counter = other.counter;
+    return *this;
+  }
+  ~IncrementInDtorCopyCanThrow() { *counter += 1; }
+  int* counter;
+};
+
+// This is defined so operator== for ValueHolder<IncrementInDtor> will
+// return true if two IncrementInDtor objects increment the same
+// counter
+inline bool operator==(const IncrementInDtor& left,
+                       const IncrementInDtor& right) {
+  return left.counter == right.counter;
+}
+
+// This is defined so EXPECT_EQ can work with IncrementInDtor
+inline std::ostream& operator<<(
+    std::ostream& stream, const IncrementInDtor& object) {
+  return stream << object.counter;
+}
+
+// A class that can be copied, but not assigned.
+class CopyNoAssign {
+ public:
+  explicit CopyNoAssign(int value) : foo(value) {}
+  CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
+  int foo;
+ private:
+  const CopyNoAssign& operator=(const CopyNoAssign&);
+};
+
+// A class that can neither be copied nor assigned. We provide
+// overloads for the constructor with up to four parameters so we can
+// test the overloads of variant::emplace.
+class NonCopyable {
+ public:
+  NonCopyable()
+      : value(0) {}
+  explicit NonCopyable(int value1)
+      : value(value1) {}
+
+  NonCopyable(int value1, int value2)
+      : value(value1 + value2) {}
+
+  NonCopyable(int value1, int value2, int value3)
+      : value(value1 + value2 + value3) {}
+
+  NonCopyable(int value1, int value2, int value3, int value4)
+      : value(value1 + value2 + value3 + value4) {}
+  NonCopyable(const NonCopyable&) = delete;
+  NonCopyable& operator=(const NonCopyable&) = delete;
+  int value;
+};
+
+// A typed test and typed test case over the VariantTypes typelist,
+// from which we derive a number of tests that will execute for one of
+// each type.
+template <typename T>
+class VariantTypesTest : public ::testing::Test {};
+TYPED_TEST_CASE(VariantTypesTest, VariantTypes);
+
+////////////////////
+// [variant.ctor] //
+////////////////////
+
+struct NonNoexceptDefaultConstructible {
+  NonNoexceptDefaultConstructible() {}
+  int value = 5;
+};
+
+struct NonDefaultConstructible {
+  NonDefaultConstructible() = delete;
+};
+
+TEST(VariantTest, TestDefaultConstructor) {
+  {
+    using X = variant<int>;
+    constexpr variant<int> x{};
+    ASSERT_FALSE(x.valueless_by_exception());
+    ASSERT_EQ(0, x.index());
+    EXPECT_EQ(0, absl::get<0>(x));
+    EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value);
+  }
+
+  {
+    using X = variant<NonNoexceptDefaultConstructible>;
+    X x{};
+    ASSERT_FALSE(x.valueless_by_exception());
+    ASSERT_EQ(0, x.index());
+    EXPECT_EQ(5, absl::get<0>(x).value);
+    EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value);
+  }
+
+  {
+    using X = variant<int, NonNoexceptDefaultConstructible>;
+    X x{};
+    ASSERT_FALSE(x.valueless_by_exception());
+    ASSERT_EQ(0, x.index());
+    EXPECT_EQ(0, absl::get<0>(x));
+    EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value);
+  }
+
+  {
+    using X = variant<NonNoexceptDefaultConstructible, int>;
+    X x{};
+    ASSERT_FALSE(x.valueless_by_exception());
+    ASSERT_EQ(0, x.index());
+    EXPECT_EQ(5, absl::get<0>(x).value);
+    EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value);
+  }
+  EXPECT_FALSE(
+      std::is_default_constructible<variant<NonDefaultConstructible>>::value);
+  EXPECT_FALSE((std::is_default_constructible<
+                variant<NonDefaultConstructible, int>>::value));
+  EXPECT_TRUE((std::is_default_constructible<
+               variant<int, NonDefaultConstructible>>::value));
+}
+
+// Test that for each slot, copy constructing a variant with that type
+// produces a sensible object that correctly reports its type, and
+// that copies the provided value.
+TYPED_TEST(VariantTypesTest, TestCopyCtor) {
+  typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  using value_type2 = absl::variant_alternative_t<1, Variant>;
+  using value_type3 = absl::variant_alternative_t<2, Variant>;
+  using value_type4 = absl::variant_alternative_t<3, Variant>;
+  const TypeParam value(TypeParam::kIndex);
+  Variant original(value);
+  Variant copied(original);
+  EXPECT_TRUE(absl::holds_alternative<value_type1>(copied) ||
+              TypeParam::kIndex != 1);
+  EXPECT_TRUE(absl::holds_alternative<value_type2>(copied) ||
+              TypeParam::kIndex != 2);
+  EXPECT_TRUE(absl::holds_alternative<value_type3>(copied) ||
+              TypeParam::kIndex != 3);
+  EXPECT_TRUE(absl::holds_alternative<value_type4>(copied) ||
+              TypeParam::kIndex != 4);
+  EXPECT_TRUE((absl::get_if<value_type1>(&original) ==
+               absl::get_if<value_type1>(&copied)) ||
+              TypeParam::kIndex == 1);
+  EXPECT_TRUE((absl::get_if<value_type2>(&original) ==
+               absl::get_if<value_type2>(&copied)) ||
+              TypeParam::kIndex == 2);
+  EXPECT_TRUE((absl::get_if<value_type3>(&original) ==
+               absl::get_if<value_type3>(&copied)) ||
+              TypeParam::kIndex == 3);
+  EXPECT_TRUE((absl::get_if<value_type4>(&original) ==
+               absl::get_if<value_type4>(&copied)) ||
+              TypeParam::kIndex == 4);
+  EXPECT_TRUE((absl::get_if<value_type1>(&original) ==
+               absl::get_if<value_type1>(&copied)) ||
+              TypeParam::kIndex == 1);
+  EXPECT_TRUE((absl::get_if<value_type2>(&original) ==
+               absl::get_if<value_type2>(&copied)) ||
+              TypeParam::kIndex == 2);
+  EXPECT_TRUE((absl::get_if<value_type3>(&original) ==
+               absl::get_if<value_type3>(&copied)) ||
+              TypeParam::kIndex == 3);
+  EXPECT_TRUE((absl::get_if<value_type4>(&original) ==
+               absl::get_if<value_type4>(&copied)) ||
+              TypeParam::kIndex == 4);
+  const TypeParam* ovalptr = absl::get_if<TypeParam>(&original);
+  const TypeParam* cvalptr = absl::get_if<TypeParam>(&copied);
+  ASSERT_TRUE(ovalptr != nullptr);
+  ASSERT_TRUE(cvalptr != nullptr);
+  EXPECT_EQ(*ovalptr, *cvalptr);
+  TypeParam* mutable_ovalptr = absl::get_if<TypeParam>(&original);
+  TypeParam* mutable_cvalptr = absl::get_if<TypeParam>(&copied);
+  ASSERT_TRUE(mutable_ovalptr != nullptr);
+  ASSERT_TRUE(mutable_cvalptr != nullptr);
+  EXPECT_EQ(*mutable_ovalptr, *mutable_cvalptr);
+}
+
+template <class>
+struct MoveOnly {
+  MoveOnly() = default;
+  explicit MoveOnly(int value) : value(value) {}
+  MoveOnly(MoveOnly&&) = default;
+  MoveOnly& operator=(MoveOnly&&) = default;
+  int value = 5;
+};
+
+TEST(VariantTest, TestMoveConstruct) {
+  using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>;
+
+  V v(in_place_index_t<1>{}, 10);
+  V v2 = absl::move(v);
+  EXPECT_EQ(10, absl::get<1>(v2).value);
+}
+
+// Used internally to emulate missing triviality traits for tests.
+template <class T>
+union SingleUnion {
+  T member;
+};
+
+// NOTE: These don't work with types that can't be union members.
+//       They are just for testing.
+template <class T>
+struct is_trivially_move_constructible
+    : std::is_move_constructible<SingleUnion<T>>::type {};
+
+template <class T>
+struct is_trivially_move_assignable
+    : std::is_move_assignable<SingleUnion<T>>::type {};
+
+TEST(VariantTest, NothrowMoveConstructible) {
+  // Verify that variant is nothrow move constructible iff its template
+  // arguments are.
+  using U = std::unique_ptr<int>;
+  struct E {
+    E(E&&) {}
+  };
+  static_assert(std::is_nothrow_move_constructible<variant<U>>::value, "");
+  static_assert(std::is_nothrow_move_constructible<variant<U, int>>::value, "");
+  static_assert(!std::is_nothrow_move_constructible<variant<U, E>>::value, "");
+}
+
+// Test that for each slot, constructing a variant with that type
+// produces a sensible object that correctly reports its type, and
+// that copies the provided value.
+TYPED_TEST(VariantTypesTest, TestValueCtor) {
+  typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  using value_type2 = absl::variant_alternative_t<1, Variant>;
+  using value_type3 = absl::variant_alternative_t<2, Variant>;
+  using value_type4 = absl::variant_alternative_t<3, Variant>;
+  const TypeParam value(TypeParam::kIndex);
+  Variant v(value);
+  EXPECT_TRUE(absl::holds_alternative<value_type1>(v) ||
+              TypeParam::kIndex != 1);
+  EXPECT_TRUE(absl::holds_alternative<value_type2>(v) ||
+              TypeParam::kIndex != 2);
+  EXPECT_TRUE(absl::holds_alternative<value_type3>(v) ||
+              TypeParam::kIndex != 3);
+  EXPECT_TRUE(absl::holds_alternative<value_type4>(v) ||
+              TypeParam::kIndex != 4);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) ||
+              TypeParam::kIndex != 1);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) ||
+              TypeParam::kIndex != 2);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) ||
+              TypeParam::kIndex != 3);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) ||
+              TypeParam::kIndex != 4);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) ||
+              TypeParam::kIndex != 1);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) ||
+              TypeParam::kIndex != 2);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) ||
+              TypeParam::kIndex != 3);
+  EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) ||
+              TypeParam::kIndex != 4);
+  const TypeParam* valptr = absl::get_if<TypeParam>(&v);
+  ASSERT_TRUE(nullptr != valptr);
+  EXPECT_EQ(value.value, valptr->value);
+  const TypeParam* mutable_valptr = absl::get_if<TypeParam>(&v);
+  ASSERT_TRUE(nullptr != mutable_valptr);
+  EXPECT_EQ(value.value, mutable_valptr->value);
+}
+
+TEST(VariantTest, InPlaceType) {
+  using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
+
+  Var v1(in_place_type_t<int>(), 7);
+  ASSERT_TRUE(absl::holds_alternative<int>(v1));
+  EXPECT_EQ(7, absl::get<int>(v1));
+
+  Var v2(in_place_type_t<std::string>(), "ABC");
+  ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
+  EXPECT_EQ("ABC", absl::get<std::string>(v2));
+
+  Var v3(in_place_type_t<std::string>(), "ABC", 2);
+  ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
+  EXPECT_EQ("AB", absl::get<std::string>(v3));
+
+  Var v4(in_place_type_t<NonCopyable>{});
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4));
+
+  Var v5(in_place_type_t<std::vector<int>>(), {1, 2, 3});
+  ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
+  EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
+}
+
+TEST(VariantTest, InPlaceTypeInitializerList) {
+  using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+  Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6);
+  ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+  EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+}
+
+TEST(VariantTest, InPlaceIndex) {
+  using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
+
+  Var v1(in_place_index_t<0>(), 7);
+  ASSERT_TRUE(absl::holds_alternative<int>(v1));
+  EXPECT_EQ(7, absl::get<int>(v1));
+
+  Var v2(in_place_index_t<1>(), "ABC");
+  ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
+  EXPECT_EQ("ABC", absl::get<std::string>(v2));
+
+  Var v3(in_place_index_t<1>(), "ABC", 2);
+  ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
+  EXPECT_EQ("AB", absl::get<std::string>(v3));
+
+  Var v4(in_place_index_t<2>{});
+  EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4));
+
+  // Verify that a variant with only non-copyables can still be constructed.
+  EXPECT_TRUE(absl::holds_alternative<NonCopyable>(
+      variant<NonCopyable>(in_place_index_t<0>{})));
+
+  Var v5(in_place_index_t<3>(), {1, 2, 3});
+  ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
+  EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
+}
+
+TEST(VariantTest, InPlaceIndexInitializerList) {
+  using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+  Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6);
+  ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+  EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+}
+
+////////////////////
+// [variant.dtor] //
+////////////////////
+
+// Make sure that the destructor destroys the contained value
+TEST(VariantTest, TestDtor) {
+  typedef VariantFactory<IncrementInDtor>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  using value_type2 = absl::variant_alternative_t<1, Variant>;
+  using value_type3 = absl::variant_alternative_t<2, Variant>;
+  using value_type4 = absl::variant_alternative_t<3, Variant>;
+  int counter = 0;
+  IncrementInDtor counter_adjuster(&counter);
+  EXPECT_EQ(0, counter);
+
+  value_type1 value1(counter_adjuster);
+  { Variant object(value1); }
+  EXPECT_EQ(1, counter);
+
+  value_type2 value2(counter_adjuster);
+  { Variant object(value2); }
+  EXPECT_EQ(2, counter);
+
+  value_type3 value3(counter_adjuster);
+  { Variant object(value3); }
+  EXPECT_EQ(3, counter);
+
+  value_type4 value4(counter_adjuster);
+  { Variant object(value4); }
+  EXPECT_EQ(4, counter);
+}
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+// Test destruction when in the valueless_by_exception state.
+TEST(VariantTest, TestDtorValuelessByException) {
+  int counter = 0;
+  IncrementInDtor counter_adjuster(&counter);
+
+  {
+    using Variant = VariantFactory<IncrementInDtor>::Type;
+
+    Variant v(in_place_index_t<0>(), counter_adjuster);
+    EXPECT_EQ(0, counter);
+
+    ToValuelessByException(v);
+    ASSERT_TRUE(v.valueless_by_exception());
+    EXPECT_EQ(1, counter);
+  }
+  EXPECT_EQ(1, counter);
+}
+
+#endif  // ABSL_HAVE_EXCEPTIONS
+
+//////////////////////
+// [variant.assign] //
+//////////////////////
+
+// Test that self-assignment doesn't destroy the current value
+TEST(VariantTest, TestSelfAssignment) {
+  typedef VariantFactory<IncrementInDtor>::Type Variant;
+  int counter = 0;
+  IncrementInDtor counter_adjuster(&counter);
+  absl::variant_alternative_t<0, Variant> value(counter_adjuster);
+  Variant object(value);
+  object.operator=(object);
+  EXPECT_EQ(0, counter);
+
+  // A std::string long enough that it's likely to defeat any inline representation
+  // optimization.
+  const std::string long_str(128, 'a');
+
+  std::string foo = long_str;
+  foo = *&foo;
+  EXPECT_EQ(long_str, foo);
+
+  variant<int, std::string> so = long_str;
+  ASSERT_EQ(1, so.index());
+  EXPECT_EQ(long_str, absl::get<1>(so));
+  so = *&so;
+
+  ASSERT_EQ(1, so.index());
+  EXPECT_EQ(long_str, absl::get<1>(so));
+}
+
+// Test that assigning a variant<..., T, ...> to a variant<..., T, ...> produces
+// a variant<..., T, ...> with the correct value.
+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValueSameTypes) {
+  typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+  const TypeParam value(TypeParam::kIndex);
+  const Variant source(value);
+  Variant target(TypeParam(value.value + 1));
+  ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
+  ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
+  ASSERT_NE(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
+  target = source;
+  ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
+  ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
+  EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
+}
+
+// Test that assisnging a variant<..., T, ...> to a variant<1, ...>
+// produces a variant<..., T, ...> with the correct value.
+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingSourceType) {
+  typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  const TypeParam value(TypeParam::kIndex);
+  const Variant source(value);
+  ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
+  Variant target(value_type1(1));
+  ASSERT_TRUE(absl::holds_alternative<value_type1>(target));
+  target = source;
+  EXPECT_TRUE(absl::holds_alternative<TypeParam>(source));
+  EXPECT_TRUE(absl::holds_alternative<TypeParam>(target));
+  EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
+}
+
+// Test that assigning a variant<1, ...> to a variant<..., T, ...>
+// produces a variant<1, ...> with the correct value.
+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingTargetType) {
+  typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  const Variant source(value_type1(1));
+  ASSERT_TRUE(absl::holds_alternative<value_type1>(source));
+  const TypeParam value(TypeParam::kIndex);
+  Variant target(value);
+  ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
+  target = source;
+  EXPECT_TRUE(absl::holds_alternative<value_type1>(target));
+  EXPECT_TRUE(absl::holds_alternative<value_type1>(source));
+  EXPECT_EQ(absl::get<value_type1>(source), absl::get<value_type1>(target));
+}
+
+// Test that operator=<T> works, that assigning a new value destroys
+// the old and that assigning the new value again does not redestroy
+// the old
+TEST(VariantTest, TestAssign) {
+  typedef VariantFactory<IncrementInDtor>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  using value_type2 = absl::variant_alternative_t<1, Variant>;
+  using value_type3 = absl::variant_alternative_t<2, Variant>;
+  using value_type4 = absl::variant_alternative_t<3, Variant>;
+
+  const int kSize = 4;
+  int counter[kSize];
+  std::unique_ptr<IncrementInDtor> counter_adjustor[kSize];
+  for (int i = 0; i != kSize; i++) {
+    counter[i] = 0;
+    counter_adjustor[i] = absl::make_unique<IncrementInDtor>(&counter[i]);
+  }
+
+  value_type1 v1(*counter_adjustor[0]);
+  value_type2 v2(*counter_adjustor[1]);
+  value_type3 v3(*counter_adjustor[2]);
+  value_type4 v4(*counter_adjustor[3]);
+
+  // Test that reassignment causes destruction of old value
+  {
+    Variant object(v1);
+    object = v2;
+    object = v3;
+    object = v4;
+    object = v1;
+  }
+
+  EXPECT_EQ(2, counter[0]);
+  EXPECT_EQ(1, counter[1]);
+  EXPECT_EQ(1, counter[2]);
+  EXPECT_EQ(1, counter[3]);
+
+  std::fill(std::begin(counter), std::end(counter), 0);
+
+  // Test that self-assignment does not cause destruction of old value
+  {
+    Variant object(v1);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[0]);
+  }
+  {
+    Variant object(v2);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[1]);
+  }
+  {
+    Variant object(v3);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[2]);
+  }
+  {
+    Variant object(v4);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[3]);
+  }
+
+  EXPECT_EQ(1, counter[0]);
+  EXPECT_EQ(1, counter[1]);
+  EXPECT_EQ(1, counter[2]);
+  EXPECT_EQ(1, counter[3]);
+}
+
+// This tests that we perform a backup if the copy-assign can throw but the move
+// cannot throw.
+TEST(VariantTest, TestBackupAssign) {
+  typedef VariantFactory<IncrementInDtorCopyCanThrow>::Type Variant;
+  using value_type1 = absl::variant_alternative_t<0, Variant>;
+  using value_type2 = absl::variant_alternative_t<1, Variant>;
+  using value_type3 = absl::variant_alternative_t<2, Variant>;
+  using value_type4 = absl::variant_alternative_t<3, Variant>;
+
+  const int kSize = 4;
+  int counter[kSize];
+  std::unique_ptr<IncrementInDtorCopyCanThrow> counter_adjustor[kSize];
+  for (int i = 0; i != kSize; i++) {
+    counter[i] = 0;
+    counter_adjustor[i].reset(new IncrementInDtorCopyCanThrow(&counter[i]));
+  }
+
+  value_type1 v1(*counter_adjustor[0]);
+  value_type2 v2(*counter_adjustor[1]);
+  value_type3 v3(*counter_adjustor[2]);
+  value_type4 v4(*counter_adjustor[3]);
+
+  // Test that reassignment causes destruction of old value
+  {
+    Variant object(v1);
+    object = v2;
+    object = v3;
+    object = v4;
+    object = v1;
+  }
+
+  // libstdc++ doesn't pass this test
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+  EXPECT_EQ(3, counter[0]);
+  EXPECT_EQ(2, counter[1]);
+  EXPECT_EQ(2, counter[2]);
+  EXPECT_EQ(2, counter[3]);
+#endif
+
+  std::fill(std::begin(counter), std::end(counter), 0);
+
+  // Test that self-assignment does not cause destruction of old value
+  {
+    Variant object(v1);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[0]);
+  }
+  {
+    Variant object(v2);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[1]);
+  }
+  {
+    Variant object(v3);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[2]);
+  }
+  {
+    Variant object(v4);
+    object.operator=(object);
+    EXPECT_EQ(0, counter[3]);
+  }
+
+  EXPECT_EQ(1, counter[0]);
+  EXPECT_EQ(1, counter[1]);
+  EXPECT_EQ(1, counter[2]);
+  EXPECT_EQ(1, counter[3]);
+}
+
+///////////////////
+// [variant.mod] //
+///////////////////
+
+TEST(VariantTest, TestEmplaceBasic) {
+  using Variant = variant<int, char>;
+
+  Variant v(absl::in_place_index_t<0>{}, 0);
+
+  {
+    char& emplace_result = v.emplace<char>();
+    ASSERT_TRUE(absl::holds_alternative<char>(v));
+    EXPECT_EQ(absl::get<char>(v), 0);
+    EXPECT_EQ(&emplace_result, &absl::get<char>(v));
+  }
+
+  // Make sure that another emplace does zero-initialization
+  absl::get<char>(v) = 'a';
+  v.emplace<char>('b');
+  ASSERT_TRUE(absl::holds_alternative<char>(v));
+  EXPECT_EQ(absl::get<char>(v), 'b');
+
+  {
+    int& emplace_result = v.emplace<int>();
+    EXPECT_TRUE(absl::holds_alternative<int>(v));
+    EXPECT_EQ(absl::get<int>(v), 0);
+    EXPECT_EQ(&emplace_result, &absl::get<int>(v));
+  }
+}
+
+TEST(VariantTest, TestEmplaceInitializerList) {
+  using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+  Var v1(absl::in_place_index_t<0>{}, 555);
+  MoveOnlyWithListConstructor& emplace_result =
+      v1.emplace<MoveOnlyWithListConstructor>({1, 2, 3, 4, 5}, 6);
+  ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+  EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+  EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1));
+}
+
+TEST(VariantTest, TestEmplaceIndex) {
+  using Variant = variant<int, char>;
+
+  Variant v(absl::in_place_index_t<0>{}, 555);
+
+  {
+    char& emplace_result = v.emplace<1>();
+    ASSERT_TRUE(absl::holds_alternative<char>(v));
+    EXPECT_EQ(absl::get<char>(v), 0);
+    EXPECT_EQ(&emplace_result, &absl::get<char>(v));
+  }
+
+  // Make sure that another emplace does zero-initialization
+  absl::get<char>(v) = 'a';
+  v.emplace<1>('b');
+  ASSERT_TRUE(absl::holds_alternative<char>(v));
+  EXPECT_EQ(absl::get<char>(v), 'b');
+
+  {
+    int& emplace_result = v.emplace<0>();
+    EXPECT_TRUE(absl::holds_alternative<int>(v));
+    EXPECT_EQ(absl::get<int>(v), 0);
+    EXPECT_EQ(&emplace_result, &absl::get<int>(v));
+  }
+}
+
+TEST(VariantTest, TestEmplaceIndexInitializerList) {
+  using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+
+  Var v1(absl::in_place_index_t<0>{}, 555);
+  MoveOnlyWithListConstructor& emplace_result =
+      v1.emplace<3>({1, 2, 3, 4, 5}, 6);
+  ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
+  EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
+  EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1));
+}
+
+//////////////////////
+// [variant.status] //
+//////////////////////
+
+TEST(VariantTest, Index) {
+  using Var = variant<int, std::string, double>;
+
+  Var v = 1;
+  EXPECT_EQ(0, v.index());
+  v = "str";
+  EXPECT_EQ(1, v.index());
+  v = 0.;
+  EXPECT_EQ(2, v.index());
+
+  Var v2 = v;
+  EXPECT_EQ(2, v2.index());
+  v2.emplace<int>(3);
+  EXPECT_EQ(0, v2.index());
+}
+
+TEST(VariantTest, NotValuelessByException) {
+  using Var = variant<int, std::string, double>;
+
+  Var v = 1;
+  EXPECT_FALSE(v.valueless_by_exception());
+  v = "str";
+  EXPECT_FALSE(v.valueless_by_exception());
+  v = 0.;
+  EXPECT_FALSE(v.valueless_by_exception());
+
+  Var v2 = v;
+  EXPECT_FALSE(v.valueless_by_exception());
+  v2.emplace<int>(3);
+  EXPECT_FALSE(v.valueless_by_exception());
+}
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+TEST(VariantTest, IndexValuelessByException) {
+  using Var = variant<MoveCanThrow, std::string, double>;
+
+  Var v(absl::in_place_index_t<0>{});
+  EXPECT_EQ(0, v.index());
+  ToValuelessByException(v);
+  EXPECT_EQ(absl::variant_npos, v.index());
+  v = "str";
+  EXPECT_EQ(1, v.index());
+}
+
+TEST(VariantTest, ValuelessByException) {
+  using Var = variant<MoveCanThrow, std::string, double>;
+
+  Var v(absl::in_place_index_t<0>{});
+  EXPECT_FALSE(v.valueless_by_exception());
+  ToValuelessByException(v);
+  EXPECT_TRUE(v.valueless_by_exception());
+  v = "str";
+  EXPECT_FALSE(v.valueless_by_exception());
+}
+
+#endif  // ABSL_HAVE_EXCEPTIONS
+
+////////////////////
+// [variant.swap] //
+////////////////////
+
+TEST(VariantTest, MemberSwap) {
+  SpecialSwap v1(3);
+  SpecialSwap v2(7);
+
+  variant<SpecialSwap> a = v1, b = v2;
+
+  EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
+  EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
+
+  a.swap(b);
+  EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
+  EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
+  EXPECT_TRUE(absl::get<SpecialSwap>(a).special_swap);
+
+  using V = variant<MoveCanThrow, std::string, int>;
+  int i = 33;
+  std::string s = "abc";
+  V valueless(in_place_index_t<0>{});
+  ToValuelessByException(valueless);
+  {
+    // lhs and rhs holds different alternative
+    V lhs(i), rhs(s);
+    lhs.swap(rhs);
+    EXPECT_THAT(lhs, VariantWith<std::string>(s));
+    EXPECT_THAT(rhs, VariantWith<int>(i));
+  }
+  {
+    // lhs is valueless
+    V lhs(valueless), rhs(i);
+    lhs.swap(rhs);
+    EXPECT_THAT(lhs, VariantWith<int>(i));
+    EXPECT_TRUE(rhs.valueless_by_exception());
+  }
+  {
+    // rhs is valueless
+    V lhs(s), rhs(valueless);
+    lhs.swap(rhs);
+    EXPECT_THAT(rhs, VariantWith<std::string>(s));
+    EXPECT_TRUE(lhs.valueless_by_exception());
+  }
+  {
+    // both are valueless
+    V lhs(valueless), rhs(valueless);
+    lhs.swap(rhs);
+    EXPECT_TRUE(lhs.valueless_by_exception());
+    EXPECT_TRUE(rhs.valueless_by_exception());
+  }
+}
+
+//////////////////////
+// [variant.helper] //
+//////////////////////
+
+TEST(VariantTest, VariantSize) {
+  {
+    using Size1Variant = absl::variant<int>;
+    EXPECT_EQ(1, absl::variant_size<Size1Variant>::value);
+    EXPECT_EQ(1, absl::variant_size<const Size1Variant>::value);
+    EXPECT_EQ(1, absl::variant_size<volatile Size1Variant>::value);
+    EXPECT_EQ(1, absl::variant_size<const volatile Size1Variant>::value);
+  }
+
+  {
+    using Size3Variant = absl::variant<int, float, int>;
+    EXPECT_EQ(3, absl::variant_size<Size3Variant>::value);
+    EXPECT_EQ(3, absl::variant_size<const Size3Variant>::value);
+    EXPECT_EQ(3, absl::variant_size<volatile Size3Variant>::value);
+    EXPECT_EQ(3, absl::variant_size<const volatile Size3Variant>::value);
+  }
+}
+
+TEST(VariantTest, VariantAlternative) {
+  {
+    using V = absl::variant<float, int, const char*>;
+    EXPECT_TRUE(
+        (std::is_same<float, absl::variant_alternative_t<0, V>>::value));
+    EXPECT_TRUE((std::is_same<const float,
+                              absl::variant_alternative_t<0, const V>>::value));
+    EXPECT_TRUE(
+        (std::is_same<volatile float,
+                      absl::variant_alternative_t<0, volatile V>>::value));
+    EXPECT_TRUE((
+        std::is_same<const volatile float,
+                     absl::variant_alternative_t<0, const volatile V>>::value));
+
+    EXPECT_TRUE((std::is_same<int, absl::variant_alternative_t<1, V>>::value));
+    EXPECT_TRUE((std::is_same<const int,
+                              absl::variant_alternative_t<1, const V>>::value));
+    EXPECT_TRUE(
+        (std::is_same<volatile int,
+                      absl::variant_alternative_t<1, volatile V>>::value));
+    EXPECT_TRUE((
+        std::is_same<const volatile int,
+                     absl::variant_alternative_t<1, const volatile V>>::value));
+
+    EXPECT_TRUE(
+        (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value));
+    EXPECT_TRUE((std::is_same<const char* const,
+                              absl::variant_alternative_t<2, const V>>::value));
+    EXPECT_TRUE(
+        (std::is_same<const char* volatile,
+                      absl::variant_alternative_t<2, volatile V>>::value));
+    EXPECT_TRUE((
+        std::is_same<const char* const volatile,
+                     absl::variant_alternative_t<2, const volatile V>>::value));
+  }
+
+  {
+    using V = absl::variant<float, volatile int, const char*>;
+    EXPECT_TRUE(
+        (std::is_same<float, absl::variant_alternative_t<0, V>>::value));
+    EXPECT_TRUE((std::is_same<const float,
+                              absl::variant_alternative_t<0, const V>>::value));
+    EXPECT_TRUE(
+        (std::is_same<volatile float,
+                      absl::variant_alternative_t<0, volatile V>>::value));
+    EXPECT_TRUE((
+        std::is_same<const volatile float,
+                     absl::variant_alternative_t<0, const volatile V>>::value));
+
+    EXPECT_TRUE(
+        (std::is_same<volatile int, absl::variant_alternative_t<1, V>>::value));
+    EXPECT_TRUE((std::is_same<const volatile int,
+                              absl::variant_alternative_t<1, const V>>::value));
+    EXPECT_TRUE(
+        (std::is_same<volatile int,
+                      absl::variant_alternative_t<1, volatile V>>::value));
+    EXPECT_TRUE((
+        std::is_same<const volatile int,
+                     absl::variant_alternative_t<1, const volatile V>>::value));
+
+    EXPECT_TRUE(
+        (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value));
+    EXPECT_TRUE((std::is_same<const char* const,
+                              absl::variant_alternative_t<2, const V>>::value));
+    EXPECT_TRUE(
+        (std::is_same<const char* volatile,
+                      absl::variant_alternative_t<2, volatile V>>::value));
+    EXPECT_TRUE((
+        std::is_same<const char* const volatile,
+                     absl::variant_alternative_t<2, const volatile V>>::value));
+  }
+}
+
+///////////////////
+// [variant.get] //
+///////////////////
+
+TEST(VariantTest, HoldsAlternative) {
+  using Var = variant<int, std::string, double>;
+
+  Var v = 1;
+  EXPECT_TRUE(absl::holds_alternative<int>(v));
+  EXPECT_FALSE(absl::holds_alternative<std::string>(v));
+  EXPECT_FALSE(absl::holds_alternative<double>(v));
+  v = "str";
+  EXPECT_FALSE(absl::holds_alternative<int>(v));
+  EXPECT_TRUE(absl::holds_alternative<std::string>(v));
+  EXPECT_FALSE(absl::holds_alternative<double>(v));
+  v = 0.;
+  EXPECT_FALSE(absl::holds_alternative<int>(v));
+  EXPECT_FALSE(absl::holds_alternative<std::string>(v));
+  EXPECT_TRUE(absl::holds_alternative<double>(v));
+
+  Var v2 = v;
+  EXPECT_FALSE(absl::holds_alternative<int>(v2));
+  EXPECT_FALSE(absl::holds_alternative<std::string>(v2));
+  EXPECT_TRUE(absl::holds_alternative<double>(v2));
+  v2.emplace<int>(3);
+  EXPECT_TRUE(absl::holds_alternative<int>(v2));
+  EXPECT_FALSE(absl::holds_alternative<std::string>(v2));
+  EXPECT_FALSE(absl::holds_alternative<double>(v2));
+}
+
+TEST(VariantTest, GetIndex) {
+  using Var = variant<int, std::string, double, int>;
+
+  {
+    Var v(absl::in_place_index_t<0>{}, 0);
+
+    using LValueGetType = decltype(absl::get<0>(v));
+    using RValueGetType = decltype(absl::get<0>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
+    EXPECT_EQ(absl::get<0>(v), 0);
+    EXPECT_EQ(absl::get<0>(absl::move(v)), 0);
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<0>(const_v));
+    using ConstRValueGetType = decltype(absl::get<0>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
+    EXPECT_EQ(absl::get<0>(const_v), 0);
+    EXPECT_EQ(absl::get<0>(absl::move(const_v)), 0);
+  }
+
+  {
+    Var v = std::string("Hello");
+
+    using LValueGetType = decltype(absl::get<1>(v));
+    using RValueGetType = decltype(absl::get<1>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value));
+    EXPECT_EQ(absl::get<1>(v), "Hello");
+    EXPECT_EQ(absl::get<1>(absl::move(v)), "Hello");
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<1>(const_v));
+    using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value));
+    EXPECT_EQ(absl::get<1>(const_v), "Hello");
+    EXPECT_EQ(absl::get<1>(absl::move(const_v)), "Hello");
+  }
+
+  {
+    Var v = 2.0;
+
+    using LValueGetType = decltype(absl::get<2>(v));
+    using RValueGetType = decltype(absl::get<2>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, double&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value));
+    EXPECT_EQ(absl::get<2>(v), 2.);
+    EXPECT_EQ(absl::get<2>(absl::move(v)), 2.);
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<2>(const_v));
+    using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value));
+    EXPECT_EQ(absl::get<2>(const_v), 2.);
+    EXPECT_EQ(absl::get<2>(absl::move(const_v)), 2.);
+  }
+
+  {
+    Var v(absl::in_place_index_t<0>{}, 0);
+    v.emplace<3>(1);
+
+    using LValueGetType = decltype(absl::get<3>(v));
+    using RValueGetType = decltype(absl::get<3>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
+    EXPECT_EQ(absl::get<3>(v), 1);
+    EXPECT_EQ(absl::get<3>(absl::move(v)), 1);
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<3>(const_v));
+    using ConstRValueGetType = decltype(absl::get<3>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
+    EXPECT_EQ(absl::get<3>(const_v), 1);
+    EXPECT_EQ(absl::get<3>(absl::move(const_v)), 1);  // NOLINT
+  }
+}
+
+TEST(VariantTest, BadGetIndex) {
+  using Var = variant<int, std::string, double>;
+
+  {
+    Var v = 1;
+
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(std::move(v)));
+
+    const Var& const_v = v;
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(const_v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+        absl::get<1>(std::move(const_v)));  // NOLINT
+  }
+
+  {
+    Var v = std::string("Hello");
+
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(std::move(v)));
+
+    const Var& const_v = v;
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(const_v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+        absl::get<0>(std::move(const_v)));  // NOLINT
+  }
+}
+
+TEST(VariantTest, GetType) {
+  using Var = variant<int, std::string, double>;
+
+  {
+    Var v = 1;
+
+    using LValueGetType = decltype(absl::get<int>(v));
+    using RValueGetType = decltype(absl::get<int>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
+    EXPECT_EQ(absl::get<int>(v), 1);
+    EXPECT_EQ(absl::get<int>(absl::move(v)), 1);
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<int>(const_v));
+    using ConstRValueGetType = decltype(absl::get<int>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
+    EXPECT_EQ(absl::get<int>(const_v), 1);
+    EXPECT_EQ(absl::get<int>(absl::move(const_v)), 1);
+  }
+
+  {
+    Var v = std::string("Hello");
+
+    using LValueGetType = decltype(absl::get<1>(v));
+    using RValueGetType = decltype(absl::get<1>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value));
+    EXPECT_EQ(absl::get<std::string>(v), "Hello");
+    EXPECT_EQ(absl::get<std::string>(absl::move(v)), "Hello");
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<1>(const_v));
+    using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value));
+    EXPECT_EQ(absl::get<std::string>(const_v), "Hello");
+    EXPECT_EQ(absl::get<std::string>(absl::move(const_v)), "Hello");
+  }
+
+  {
+    Var v = 2.0;
+
+    using LValueGetType = decltype(absl::get<2>(v));
+    using RValueGetType = decltype(absl::get<2>(absl::move(v)));
+
+    EXPECT_TRUE((std::is_same<LValueGetType, double&>::value));
+    EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value));
+    EXPECT_EQ(absl::get<double>(v), 2.);
+    EXPECT_EQ(absl::get<double>(absl::move(v)), 2.);
+
+    const Var& const_v = v;
+    using ConstLValueGetType = decltype(absl::get<2>(const_v));
+    using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v)));
+    EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value));
+    EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value));
+    EXPECT_EQ(absl::get<double>(const_v), 2.);
+    EXPECT_EQ(absl::get<double>(absl::move(const_v)), 2.);
+  }
+}
+
+TEST(VariantTest, BadGetType) {
+  using Var = variant<int, std::string, double>;
+
+  {
+    Var v = 1;
+
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+        absl::get<std::string>(std::move(v)));
+
+    const Var& const_v = v;
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(const_v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+        absl::get<std::string>(std::move(const_v)));  // NOLINT
+  }
+
+  {
+    Var v = std::string("Hello");
+
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(std::move(v)));
+
+    const Var& const_v = v;
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(const_v));
+    ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
+        absl::get<int>(std::move(const_v)));  // NOLINT
+  }
+}
+
+TEST(VariantTest, GetIfIndex) {
+  using Var = variant<int, std::string, double, int>;
+
+  {
+    Var v(absl::in_place_index_t<0>{}, 0);
+    EXPECT_TRUE(noexcept(absl::get_if<0>(&v)));
+
+    {
+      auto* elem = absl::get_if<0>(&v);
+      EXPECT_TRUE((std::is_same<decltype(elem), int*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, 0);
+      {
+        auto* bad_elem = absl::get_if<1>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<2>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<3>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+    }
+
+    const Var& const_v = v;
+    EXPECT_TRUE(noexcept(absl::get_if<0>(&const_v)));
+
+    {
+      auto* elem = absl::get_if<0>(&const_v);
+      EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, 0);
+      {
+        auto* bad_elem = absl::get_if<1>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<2>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<3>(&const_v);
+        EXPECT_EQ(bad_elem, nullptr);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+      }
+    }
+  }
+
+  {
+    Var v = std::string("Hello");
+    EXPECT_TRUE(noexcept(absl::get_if<1>(&v)));
+
+    {
+      auto* elem = absl::get_if<1>(&v);
+      EXPECT_TRUE((std::is_same<decltype(elem), std::string*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, "Hello");
+      {
+        auto* bad_elem = absl::get_if<0>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<2>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<3>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+    }
+
+    const Var& const_v = v;
+    EXPECT_TRUE(noexcept(absl::get_if<1>(&const_v)));
+
+    {
+      auto* elem = absl::get_if<1>(&const_v);
+      EXPECT_TRUE((std::is_same<decltype(elem), const std::string*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, "Hello");
+      {
+        auto* bad_elem = absl::get_if<0>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<2>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<3>(&const_v);
+        EXPECT_EQ(bad_elem, nullptr);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+      }
+    }
+  }
+
+  {
+    Var v = 2.0;
+    EXPECT_TRUE(noexcept(absl::get_if<2>(&v)));
+
+    {
+      auto* elem = absl::get_if<2>(&v);
+      EXPECT_TRUE((std::is_same<decltype(elem), double*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, 2.0);
+      {
+        auto* bad_elem = absl::get_if<0>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<1>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<3>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+    }
+
+    const Var& const_v = v;
+    EXPECT_TRUE(noexcept(absl::get_if<2>(&const_v)));
+
+    {
+      auto* elem = absl::get_if<2>(&const_v);
+      EXPECT_TRUE((std::is_same<decltype(elem), const double*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, 2.0);
+      {
+        auto* bad_elem = absl::get_if<0>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<1>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<3>(&const_v);
+        EXPECT_EQ(bad_elem, nullptr);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+      }
+    }
+  }
+
+  {
+    Var v(absl::in_place_index_t<0>{}, 0);
+    v.emplace<3>(1);
+    EXPECT_TRUE(noexcept(absl::get_if<3>(&v)));
+
+    {
+      auto* elem = absl::get_if<3>(&v);
+      EXPECT_TRUE((std::is_same<decltype(elem), int*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, 1);
+      {
+        auto* bad_elem = absl::get_if<0>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<1>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<2>(&v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+    }
+
+    const Var& const_v = v;
+    EXPECT_TRUE(noexcept(absl::get_if<3>(&const_v)));
+
+    {
+      auto* elem = absl::get_if<3>(&const_v);
+      EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value));
+      ASSERT_NE(elem, nullptr);
+      EXPECT_EQ(*elem, 1);
+      {
+        auto* bad_elem = absl::get_if<0>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<1>(&const_v);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+        EXPECT_EQ(bad_elem, nullptr);
+      }
+      {
+        auto* bad_elem = absl::get_if<2>(&const_v);
+        EXPECT_EQ(bad_elem, nullptr);
+        EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
+      }
+    }
+  }
+}
+
+//////////////////////
+// [variant.relops] //
+//////////////////////
+
+TEST(VariantTest, OperatorEquals) {
+  variant<int, std::string> a(1), b(1);
+  EXPECT_TRUE(a == b);
+  EXPECT_TRUE(b == a);
+  EXPECT_FALSE(a != b);
+  EXPECT_FALSE(b != a);
+
+  b = "str";
+  EXPECT_FALSE(a == b);
+  EXPECT_FALSE(b == a);
+  EXPECT_TRUE(a != b);
+  EXPECT_TRUE(b != a);
+
+  b = 0;
+  EXPECT_FALSE(a == b);
+  EXPECT_FALSE(b == a);
+  EXPECT_TRUE(a != b);
+  EXPECT_TRUE(b != a);
+
+  a = b = "foo";
+  EXPECT_TRUE(a == b);
+  EXPECT_TRUE(b == a);
+  EXPECT_FALSE(a != b);
+  EXPECT_FALSE(b != a);
+
+  a = "bar";
+  EXPECT_FALSE(a == b);
+  EXPECT_FALSE(b == a);
+  EXPECT_TRUE(a != b);
+  EXPECT_TRUE(b != a);
+}
+
+TEST(VariantTest, OperatorRelational) {
+  variant<int, std::string> a(1), b(1);
+  EXPECT_FALSE(a < b);
+  EXPECT_FALSE(b < a);
+  EXPECT_FALSE(a > b);
+  EXPECT_FALSE(b > a);
+  EXPECT_TRUE(a <= b);
+  EXPECT_TRUE(b <= a);
+  EXPECT_TRUE(a >= b);
+  EXPECT_TRUE(b >= a);
+
+  b = "str";
+  EXPECT_TRUE(a < b);
+  EXPECT_FALSE(b < a);
+  EXPECT_FALSE(a > b);
+  EXPECT_TRUE(b > a);
+  EXPECT_TRUE(a <= b);
+  EXPECT_FALSE(b <= a);
+  EXPECT_FALSE(a >= b);
+  EXPECT_TRUE(b >= a);
+
+  b = 0;
+  EXPECT_FALSE(a < b);
+  EXPECT_TRUE(b < a);
+  EXPECT_TRUE(a > b);
+  EXPECT_FALSE(b > a);
+  EXPECT_FALSE(a <= b);
+  EXPECT_TRUE(b <= a);
+  EXPECT_TRUE(a >= b);
+  EXPECT_FALSE(b >= a);
+
+  a = b = "foo";
+  EXPECT_FALSE(a < b);
+  EXPECT_FALSE(b < a);
+  EXPECT_FALSE(a > b);
+  EXPECT_FALSE(b > a);
+  EXPECT_TRUE(a <= b);
+  EXPECT_TRUE(b <= a);
+  EXPECT_TRUE(a >= b);
+  EXPECT_TRUE(b >= a);
+
+  a = "bar";
+  EXPECT_TRUE(a < b);
+  EXPECT_FALSE(b < a);
+  EXPECT_FALSE(a > b);
+  EXPECT_TRUE(b > a);
+  EXPECT_TRUE(a <= b);
+  EXPECT_FALSE(b <= a);
+  EXPECT_FALSE(a >= b);
+  EXPECT_TRUE(b >= a);
+}
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+
+TEST(VariantTest, ValuelessOperatorEquals) {
+  variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
+      valueless(absl::in_place_index_t<0>{}),
+      other_valueless(absl::in_place_index_t<0>{});
+  ToValuelessByException(valueless);
+  ToValuelessByException(other_valueless);
+
+  EXPECT_TRUE(valueless == other_valueless);
+  EXPECT_TRUE(other_valueless == valueless);
+  EXPECT_FALSE(valueless == int_v);
+  EXPECT_FALSE(valueless == string_v);
+  EXPECT_FALSE(int_v == valueless);
+  EXPECT_FALSE(string_v == valueless);
+
+  EXPECT_FALSE(valueless != other_valueless);
+  EXPECT_FALSE(other_valueless != valueless);
+  EXPECT_TRUE(valueless != int_v);
+  EXPECT_TRUE(valueless != string_v);
+  EXPECT_TRUE(int_v != valueless);
+  EXPECT_TRUE(string_v != valueless);
+}
+
+TEST(VariantTest, ValuelessOperatorRelational) {
+  variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
+      valueless(absl::in_place_index_t<0>{}),
+      other_valueless(absl::in_place_index_t<0>{});
+  ToValuelessByException(valueless);
+  ToValuelessByException(other_valueless);
+
+  EXPECT_FALSE(valueless < other_valueless);
+  EXPECT_FALSE(other_valueless < valueless);
+  EXPECT_TRUE(valueless < int_v);
+  EXPECT_TRUE(valueless < string_v);
+  EXPECT_FALSE(int_v < valueless);
+  EXPECT_FALSE(string_v < valueless);
+
+  EXPECT_TRUE(valueless <= other_valueless);
+  EXPECT_TRUE(other_valueless <= valueless);
+  EXPECT_TRUE(valueless <= int_v);
+  EXPECT_TRUE(valueless <= string_v);
+  EXPECT_FALSE(int_v <= valueless);
+  EXPECT_FALSE(string_v <= valueless);
+
+  EXPECT_TRUE(valueless >= other_valueless);
+  EXPECT_TRUE(other_valueless >= valueless);
+  EXPECT_FALSE(valueless >= int_v);
+  EXPECT_FALSE(valueless >= string_v);
+  EXPECT_TRUE(int_v >= valueless);
+  EXPECT_TRUE(string_v >= valueless);
+
+  EXPECT_FALSE(valueless > other_valueless);
+  EXPECT_FALSE(other_valueless > valueless);
+  EXPECT_FALSE(valueless > int_v);
+  EXPECT_FALSE(valueless > string_v);
+  EXPECT_TRUE(int_v > valueless);
+  EXPECT_TRUE(string_v > valueless);
+}
+
+#endif
+
+/////////////////////
+// [variant.visit] //
+/////////////////////
+
+template <typename T>
+struct ConvertTo {
+  template <typename U>
+  T operator()(const U& u) const {
+    return u;
+  }
+};
+
+TEST(VariantTest, VisitSimple) {
+  variant<std::string, const char*> v = "A";
+
+  std::string str = absl::visit(ConvertTo<std::string>{}, v);
+  EXPECT_EQ("A", str);
+
+  v = std::string("B");
+
+  absl::string_view piece = absl::visit(ConvertTo<absl::string_view>{}, v);
+  EXPECT_EQ("B", piece);
+
+  struct StrLen {
+    int operator()(const std::string& s) const { return s.size(); }
+    int operator()(const char* s) const { return strlen(s); }
+  };
+
+  v = "SomeStr";
+  EXPECT_EQ(7, absl::visit(StrLen{}, v));
+  v = std::string("VeryLargeThisTime");
+  EXPECT_EQ(17, absl::visit(StrLen{}, v));
+}
+
+TEST(VariantTest, VisitRValue) {
+  variant<std::string> v = std::string("X");
+  struct Visitor {
+    bool operator()(const std::string&) const { return false; }
+    bool operator()(std::string&&) const { return true; }  // NOLINT
+
+    int operator()(const std::string&, const std::string&) const { return 0; }
+    int operator()(const std::string&, std::string&&) const { return 1; }  // NOLINT
+    int operator()(std::string&&, const std::string&) const { return 2; }  // NOLINT
+    int operator()(std::string&&, std::string&&) const { return 3; }       // NOLINT
+  };
+  EXPECT_FALSE(absl::visit(Visitor{}, v));
+  EXPECT_TRUE(absl::visit(Visitor{}, absl::move(v)));
+
+  // Also test the variadic overload.
+  EXPECT_EQ(0, absl::visit(Visitor{}, v, v));
+  EXPECT_EQ(1, absl::visit(Visitor{}, v, absl::move(v)));
+  EXPECT_EQ(2, absl::visit(Visitor{}, absl::move(v), v));
+  EXPECT_EQ(3, absl::visit(Visitor{}, absl::move(v), absl::move(v)));
+}
+
+TEST(VariantTest, VisitRValueVisitor) {
+  variant<std::string> v = std::string("X");
+  struct Visitor {
+    bool operator()(const std::string&) const& { return false; }
+    bool operator()(const std::string&) && { return true; }
+  };
+  Visitor visitor;
+  EXPECT_FALSE(absl::visit(visitor, v));
+  EXPECT_TRUE(absl::visit(Visitor{}, v));
+}
+
+TEST(VariantTest, VisitResultTypeDifferent) {
+  variant<std::string> v = std::string("X");
+  struct LValue_LValue {};
+  struct RValue_LValue {};
+  struct LValue_RValue {};
+  struct RValue_RValue {};
+  struct Visitor {
+    LValue_LValue operator()(const std::string&) const& { return {}; }
+    RValue_LValue operator()(std::string&&) const& { return {}; }  // NOLINT
+    LValue_RValue operator()(const std::string&) && { return {}; }
+    RValue_RValue operator()(std::string&&) && { return {}; }  // NOLINT
+  } visitor;
+
+  EXPECT_TRUE(
+      (std::is_same<LValue_LValue, decltype(absl::visit(visitor, v))>::value));
+  EXPECT_TRUE(
+      (std::is_same<RValue_LValue,
+                    decltype(absl::visit(visitor, absl::move(v)))>::value));
+  EXPECT_TRUE((
+      std::is_same<LValue_RValue, decltype(absl::visit(Visitor{}, v))>::value));
+  EXPECT_TRUE(
+      (std::is_same<RValue_RValue,
+                    decltype(absl::visit(Visitor{}, absl::move(v)))>::value));
+}
+
+TEST(VariantTest, VisitVariadic) {
+  using A = variant<int, std::string>;
+  using B = variant<std::unique_ptr<int>, absl::string_view>;
+
+  struct Visitor {
+    std::pair<int, int> operator()(int a, std::unique_ptr<int> b) const {
+      return {a, *b};
+    }
+    std::pair<int, int> operator()(absl::string_view a,
+                                   std::unique_ptr<int> b) const {
+      return {static_cast<int>(a.size()), static_cast<int>(*b)};
+    }
+    std::pair<int, int> operator()(int a, absl::string_view b) const {
+      return {a, static_cast<int>(b.size())};
+    }
+    std::pair<int, int> operator()(absl::string_view a,
+                                   absl::string_view b) const {
+      return {static_cast<int>(a.size()), static_cast<int>(b.size())};
+    }
+  };
+
+  EXPECT_THAT(absl::visit(Visitor(), A(1), B(std::unique_ptr<int>(new int(7)))),
+              ::testing::Pair(1, 7));
+  EXPECT_THAT(absl::visit(Visitor(), A(1), B(absl::string_view("ABC"))),
+              ::testing::Pair(1, 3));
+  EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
+                          B(std::unique_ptr<int>(new int(7)))),
+              ::testing::Pair(5, 7));
+  EXPECT_THAT(
+      absl::visit(Visitor(), A(std::string("BBBBB")), B(absl::string_view("ABC"))),
+      ::testing::Pair(5, 3));
+}
+
+TEST(VariantTest, VisitNoArgs) {
+  EXPECT_EQ(5, absl::visit([] { return 5; }));
+}
+
+struct ConstFunctor {
+  int operator()(int a, int b) const { return a - b; }
+};
+
+struct MutableFunctor {
+  int operator()(int a, int b) { return a - b; }
+};
+
+struct Class {
+  int Method(int a, int b) { return a - b; }
+  int ConstMethod(int a, int b) const { return a - b; }
+
+  int member;
+};
+
+TEST(VariantTest, VisitReferenceWrapper) {
+  ConstFunctor cf;
+  MutableFunctor mf;
+  absl::variant<int> three = 3;
+  absl::variant<int> two = 2;
+
+  EXPECT_EQ(1, absl::visit(std::cref(cf), three, two));
+  EXPECT_EQ(1, absl::visit(std::ref(cf), three, two));
+  EXPECT_EQ(1, absl::visit(std::ref(mf), three, two));
+}
+
+// libstdc++ std::variant doesn't support the INVOKE semantics.
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+TEST(VariantTest, VisitMemberFunction) {
+  absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>());
+  absl::variant<std::unique_ptr<const Class>> cp(
+      absl::make_unique<const Class>());
+  absl::variant<int> three = 3;
+  absl::variant<int> two = 2;
+
+  EXPECT_EQ(1, absl::visit(&Class::Method, p, three, two));
+  EXPECT_EQ(1, absl::visit(&Class::ConstMethod, p, three, two));
+  EXPECT_EQ(1, absl::visit(&Class::ConstMethod, cp, three, two));
+}
+
+TEST(VariantTest, VisitDataMember) {
+  absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>(Class{42}));
+  absl::variant<std::unique_ptr<const Class>> cp(
+      absl::make_unique<const Class>(Class{42}));
+  EXPECT_EQ(42, absl::visit(&Class::member, p));
+
+  absl::visit(&Class::member, p) = 5;
+  EXPECT_EQ(5, absl::visit(&Class::member, p));
+
+  EXPECT_EQ(42, absl::visit(&Class::member, cp));
+}
+#endif  // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+
+/////////////////////////
+// [variant.monostate] //
+/////////////////////////
+
+TEST(VariantTest, MonostateBasic) {
+  absl::monostate mono;
+  (void)mono;
+
+  // TODO(mattcalabrese) Expose move triviality metafunctions in absl.
+  EXPECT_TRUE(absl::is_trivially_default_constructible<absl::monostate>::value);
+  EXPECT_TRUE(is_trivially_move_constructible<absl::monostate>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<absl::monostate>::value);
+  EXPECT_TRUE(is_trivially_move_assignable<absl::monostate>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<absl::monostate>::value);
+  EXPECT_TRUE(absl::is_trivially_destructible<absl::monostate>::value);
+}
+
+TEST(VariantTest, VariantMonostateDefaultConstruction) {
+  absl::variant<absl::monostate, NonDefaultConstructible> var;
+  EXPECT_EQ(var.index(), 0);
+}
+
+////////////////////////////////
+// [variant.monostate.relops] //
+////////////////////////////////
+
+TEST(VariantTest, MonostateComparisons) {
+  absl::monostate lhs, rhs;
+
+  EXPECT_EQ(lhs, lhs);
+  EXPECT_EQ(lhs, rhs);
+
+  EXPECT_FALSE(lhs != lhs);
+  EXPECT_FALSE(lhs != rhs);
+  EXPECT_FALSE(lhs < lhs);
+  EXPECT_FALSE(lhs < rhs);
+  EXPECT_FALSE(lhs > lhs);
+  EXPECT_FALSE(lhs > rhs);
+
+  EXPECT_LE(lhs, lhs);
+  EXPECT_LE(lhs, rhs);
+  EXPECT_GE(lhs, lhs);
+  EXPECT_GE(lhs, rhs);
+
+  EXPECT_TRUE(noexcept(std::declval<absl::monostate>() ==
+                       std::declval<absl::monostate>()));
+  EXPECT_TRUE(noexcept(std::declval<absl::monostate>() !=
+                       std::declval<absl::monostate>()));
+  EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <
+                       std::declval<absl::monostate>()));
+  EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >
+                       std::declval<absl::monostate>()));
+  EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <=
+                       std::declval<absl::monostate>()));
+  EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >=
+                       std::declval<absl::monostate>()));
+}
+
+///////////////////////
+// [variant.specalg] //
+///////////////////////
+
+TEST(VariantTest, NonmemberSwap) {
+  using std::swap;
+
+  SpecialSwap v1(3);
+  SpecialSwap v2(7);
+
+  variant<SpecialSwap> a = v1, b = v2;
+
+  EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
+  EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
+
+  std::swap(a, b);
+  EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
+  EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
+#ifndef ABSL_HAVE_STD_VARIANT
+  EXPECT_FALSE(absl::get<SpecialSwap>(a).special_swap);
+#endif
+
+  swap(a, b);
+  EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
+  EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
+  EXPECT_TRUE(absl::get<SpecialSwap>(b).special_swap);
+}
+
+//////////////////////////
+// [variant.bad.access] //
+//////////////////////////
+
+TEST(VariantTest, BadAccess) {
+  EXPECT_TRUE(noexcept(absl::bad_variant_access()));
+  absl::bad_variant_access exception_obj;
+  std::exception* base = &exception_obj;
+  (void)base;
+}
+
+////////////////////
+// [variant.hash] //
+////////////////////
+
+TEST(VariantTest, MonostateHash) {
+  absl::monostate mono, other_mono;
+  std::hash<absl::monostate> const hasher{};
+  static_assert(std::is_same<decltype(hasher(mono)), std::size_t>::value, "");
+  EXPECT_EQ(hasher(mono), hasher(other_mono));
+}
+
+TEST(VariantTest, Hash) {
+  static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, "");
+  static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value,
+                "");
+  static_assert(
+      type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, "");
+
+#if defined(_MSC_VER) ||                                   \
+    (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \
+     _LIBCPP_STD_VER > 11) ||                              \
+    defined(__APPLE__)
+  // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
+  // static_assert to catch any user-defined type T that doesn't provide a hash
+  // specialization. So instantiating std::hash<variant<T>> will result
+  // in a hard error which is not SFINAE friendly.
+#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
+#endif
+
+#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
+  static_assert(
+      !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, "");
+  static_assert(!type_traits_internal::IsHashEnabled<
+                    variant<Hashable, NonHashable>>::value,
+                "");
+#endif
+
+// MSVC std::hash<std::variant> does not use the index, thus produce the same
+// result on the same value as different alternative.
+#if !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
+  {
+    // same value as different alternative
+    variant<int, int> v0(in_place_index_t<0>{}, 42);
+    variant<int, int> v1(in_place_index_t<1>{}, 42);
+    std::hash<variant<int, int>> hash;
+    EXPECT_NE(hash(v0), hash(v1));
+  }
+#endif  // !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
+
+  {
+    std::hash<variant<int>> hash;
+    std::set<size_t> hashcodes;
+    for (int i = 0; i < 100; ++i) {
+      hashcodes.insert(hash(i));
+    }
+    EXPECT_GT(hashcodes.size(), 90);
+
+    // test const-qualified
+    static_assert(
+        type_traits_internal::IsHashEnabled<variant<const int>>::value, "");
+    static_assert(
+        type_traits_internal::IsHashEnabled<variant<const Hashable>>::value,
+        "");
+    std::hash<absl::variant<const int>> c_hash;
+    for (int i = 0; i < 100; ++i) {
+      EXPECT_EQ(hash(i), c_hash(i));
+    }
+  }
+}
+
+////////////////////////////////////////
+// Miscellaneous and deprecated tests //
+////////////////////////////////////////
+
+// Test that a set requiring a basic type conversion works correctly.
+TEST(VariantTest, TestConvertingSet) {
+  typedef variant<double> Variant;
+  Variant v(1.0);
+  const int two = 2;
+  v = two;
+  EXPECT_TRUE(absl::holds_alternative<double>(v));
+  ASSERT_TRUE(nullptr != absl::get_if<double>(&v));
+  EXPECT_DOUBLE_EQ(2, absl::get<double>(v));
+}
+
+// Test that a vector of variants behaves reasonably.
+TEST(VariantTest, Container) {
+  typedef variant<int, float> Variant;
+
+  // Creation of vector should work
+  std::vector<Variant> vec;
+  vec.push_back(Variant(10));
+  vec.push_back(Variant(20.0f));
+
+  // Vector resizing should work if we supply a value for new slots
+  vec.resize(10, Variant(0));
+}
+
+// Test that a variant with a non-copyable type can be constructed and
+// manipulated to some degree.
+TEST(VariantTest, TestVariantWithNonCopyableType) {
+  typedef variant<int, NonCopyable> Variant;
+  const int kValue = 1;
+  Variant v(kValue);
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+  EXPECT_EQ(kValue, absl::get<int>(v));
+}
+
+// Test that a variant with a non-copyable type can be transformed to
+// the non-copyable type with a call to `emplace` for different numbers
+// of arguments. We do not need to test this for each of T1 ... T8
+// because `emplace` does not overload on T1 ... to T8, so if this
+// works for any one of T1 ... T8, then it works for all of them. We
+// do need to test that it works with varying numbers of parameters
+// though.
+TEST(VariantTest, TestEmplace) {
+  typedef variant<int, NonCopyable> Variant;
+  const int kValue = 1;
+  Variant v(kValue);
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+  EXPECT_EQ(kValue, absl::get<int>(v));
+
+  // emplace with zero arguments, then back to 'int'
+  v.emplace<NonCopyable>();
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+  EXPECT_EQ(0, absl::get<NonCopyable>(v).value);
+  v = kValue;
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+  // emplace with one argument:
+  v.emplace<NonCopyable>(1);
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+  EXPECT_EQ(1, absl::get<NonCopyable>(v).value);
+  v = kValue;
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+  // emplace with two arguments:
+  v.emplace<NonCopyable>(1, 2);
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+  EXPECT_EQ(3, absl::get<NonCopyable>(v).value);
+  v = kValue;
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+  // emplace with three arguments
+  v.emplace<NonCopyable>(1, 2, 3);
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+  EXPECT_EQ(6, absl::get<NonCopyable>(v).value);
+  v = kValue;
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+
+  // emplace with four arguments
+  v.emplace<NonCopyable>(1, 2, 3, 4);
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+  EXPECT_EQ(10, absl::get<NonCopyable>(v).value);
+  v = kValue;
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+}
+
+TEST(VariantTest, TestEmplaceDestroysCurrentValue) {
+  typedef variant<int, IncrementInDtor, NonCopyable> Variant;
+  int counter = 0;
+  Variant v(0);
+  ASSERT_TRUE(absl::holds_alternative<int>(v));
+  v.emplace<IncrementInDtor>(&counter);
+  ASSERT_TRUE(absl::holds_alternative<IncrementInDtor>(v));
+  ASSERT_EQ(0, counter);
+  v.emplace<NonCopyable>();
+  ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
+  EXPECT_EQ(1, counter);
+}
+
+TEST(VariantTest, TestMoveSemantics) {
+  typedef variant<std::unique_ptr<int>, std::unique_ptr<std::string>> Variant;
+
+  // Construct a variant by moving from an element value.
+  Variant v(absl::WrapUnique(new int(10)));
+  EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v));
+
+  // Construct a variant by moving from another variant.
+  Variant v2(absl::move(v));
+  ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v2));
+  ASSERT_NE(nullptr, absl::get<std::unique_ptr<int>>(v2));
+  EXPECT_EQ(10, *absl::get<std::unique_ptr<int>>(v2));
+
+  // Moving from a variant object leaves it holding moved-from value of the
+  // same element type.
+  EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v));
+  ASSERT_NE(nullptr, absl::get_if<std::unique_ptr<int>>(&v));
+  EXPECT_EQ(nullptr, absl::get<std::unique_ptr<int>>(v));
+
+  // Assign a variant from an element value by move.
+  v = absl::make_unique<std::string>("foo");
+  ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v));
+  EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v));
+
+  // Move-assign a variant.
+  v2 = absl::move(v);
+  ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v2));
+  EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v2));
+  EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v));
+}
+
+variant<int, std::string> PassThrough(const variant<int, std::string>& arg) {
+  return arg;
+}
+
+TEST(VariantTest, TestImplicitConversion) {
+  EXPECT_TRUE(absl::holds_alternative<int>(PassThrough(0)));
+
+  // We still need the explicit cast for std::string, because C++ won't apply
+  // two user-defined implicit conversions in a row.
+  EXPECT_TRUE(absl::holds_alternative<std::string>(PassThrough(std::string("foo"))));
+}
+
+struct Convertible2;
+struct Convertible1 {
+  Convertible1() {}
+  Convertible1(const Convertible1&) {}
+  Convertible1& operator=(const Convertible1&) { return *this; }
+
+  // implicit conversion from Convertible2
+  Convertible1(const Convertible2&) {}  // NOLINT(runtime/explicit)
+};
+
+struct Convertible2 {
+  Convertible2() {}
+  Convertible2(const Convertible2&) {}
+  Convertible2& operator=(const Convertible2&) { return *this; }
+
+  // implicit conversion from Convertible1
+  Convertible2(const Convertible1&) {}  // NOLINT(runtime/explicit)
+};
+
+TEST(VariantTest, TestRvalueConversion) {
+  variant<double, std::string> var(
+      ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(0)));
+  ASSERT_TRUE(absl::holds_alternative<double>(var));
+  EXPECT_EQ(0.0, absl::get<double>(var));
+
+  var = ConvertVariantTo<variant<double, std::string>>(
+      variant<const char*, float>("foo"));
+  ASSERT_TRUE(absl::holds_alternative<std::string>(var));
+  EXPECT_EQ("foo", absl::get<std::string>(var));
+
+  variant<double> singleton(
+      ConvertVariantTo<variant<double>>(variant<int, float>(42)));
+  ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+  EXPECT_EQ(42.0, absl::get<double>(singleton));
+
+  singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f));
+  ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+  EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
+
+  singleton = ConvertVariantTo<variant<double>>(variant<int>(0));
+  ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+  EXPECT_EQ(0.0, absl::get<double>(singleton));
+
+  variant<int32_t, uint32_t> variant2(
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
+  ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
+  EXPECT_EQ(42, absl::get<int32_t>(variant2));
+
+  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
+  EXPECT_EQ(42, absl::get<uint32_t>(variant2));
+
+  variant<Convertible1, Convertible2> variant3(
+      ConvertVariantTo<variant<Convertible1, Convertible2>>(
+          (variant<Convertible2, Convertible1>(Convertible1()))));
+  ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+  variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(
+      variant<Convertible2, Convertible1>(Convertible2()));
+  ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestLvalueConversion) {
+  variant<std::string, int> source1 = 0;
+  variant<double, std::string> destination(
+      ConvertVariantTo<variant<double, std::string>>(source1));
+  ASSERT_TRUE(absl::holds_alternative<double>(destination));
+  EXPECT_EQ(0.0, absl::get<double>(destination));
+
+  variant<const char*, float> source2 = "foo";
+  destination = ConvertVariantTo<variant<double, std::string>>(source2);
+  ASSERT_TRUE(absl::holds_alternative<std::string>(destination));
+  EXPECT_EQ("foo", absl::get<std::string>(destination));
+
+  variant<int, float> source3(42);
+  variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
+  ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+  EXPECT_EQ(42.0, absl::get<double>(singleton));
+
+  source3 = 3.14f;
+  singleton = ConvertVariantTo<variant<double>>(source3);
+  ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+  EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
+
+  variant<int> source4(0);
+  singleton = ConvertVariantTo<variant<double>>(source4);
+  ASSERT_TRUE(absl::holds_alternative<double>(singleton));
+  EXPECT_EQ(0.0, absl::get<double>(singleton));
+
+  variant<int32_t> source5(42);
+  variant<int32_t, uint32_t> variant2(
+      ConvertVariantTo<variant<int32_t, uint32_t>>(source5));
+  ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
+  EXPECT_EQ(42, absl::get<int32_t>(variant2));
+
+  variant<uint32_t> source6(42);
+  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
+  ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
+  EXPECT_EQ(42, absl::get<uint32_t>(variant2));
+
+  variant<Convertible2, Convertible1> source7((Convertible1()));
+  variant<Convertible1, Convertible2> variant3(
+      ConvertVariantTo<variant<Convertible1, Convertible2>>(source7));
+  ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+  source7 = Convertible2();
+  variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7);
+  ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestMoveConversion) {
+  using Variant =
+      variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
+  using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+
+  Variant var(
+      ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)}));
+  ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const int>>(var));
+  ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr);
+  EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var));
+
+  var =
+      ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo")));
+  ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var));
+  EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var));
+}
+
+TEST(VariantTest, DoesNotMoveFromLvalues) {
+  // We use shared_ptr here because it's both copyable and movable, and
+  // a moved-from shared_ptr is guaranteed to be null, so we can detect
+  // whether moving or copying has occurred.
+  using Variant =
+      variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>;
+  using OtherVariant = variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
+
+  Variant v1(std::make_shared<const int>(0));
+
+  // Test copy constructor
+  Variant v2(v1);
+  EXPECT_EQ(absl::get<std::shared_ptr<const int>>(v1),
+            absl::get<std::shared_ptr<const int>>(v2));
+
+  // Test copy-assignment operator
+  v1 = std::make_shared<const std::string>("foo");
+  v2 = v1;
+  EXPECT_EQ(absl::get<std::shared_ptr<const std::string>>(v1),
+            absl::get<std::shared_ptr<const std::string>>(v2));
+
+  // Test converting copy constructor
+  OtherVariant other(std::make_shared<int>(0));
+  Variant v3(ConvertVariantTo<Variant>(other));
+  EXPECT_EQ(absl::get<std::shared_ptr<int>>(other),
+            absl::get<std::shared_ptr<const int>>(v3));
+
+  other = std::make_shared<std::string>("foo");
+  v3 = ConvertVariantTo<Variant>(other);
+  EXPECT_EQ(absl::get<std::shared_ptr<std::string>>(other),
+            absl::get<std::shared_ptr<const std::string>>(v3));
+}
+
+TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
+  variant<double, std::string> var(
+      ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(3)));
+  EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0));
+
+  var = ConvertVariantTo<variant<double, std::string>>(
+      variant<const char*, float>("foo"));
+  EXPECT_THAT(absl::get_if<std::string>(&var), Pointee(std::string("foo")));
+
+  variant<double> singleton(
+      ConvertVariantTo<variant<double>>(variant<int, float>(42)));
+  EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0));
+
+  singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f));
+  EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f)));
+
+  singleton = ConvertVariantTo<variant<double>>(variant<int>(3));
+  EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0));
+
+  variant<int32_t, uint32_t> variant2(
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
+  EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
+
+  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
+
+  variant<Convertible1, Convertible2> variant3(
+      ConvertVariantTo<variant<Convertible1, Convertible2>>(
+          (variant<Convertible2, Convertible1>(Convertible1()))));
+  ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+  variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(
+      variant<Convertible2, Convertible1>(Convertible2()));
+  ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
+  variant<std::string, int> source1 = 3;
+  variant<double, std::string> destination(
+      ConvertVariantTo<variant<double, std::string>>(source1));
+  EXPECT_THAT(absl::get_if<double>(&destination), Pointee(3.0));
+
+  variant<const char*, float> source2 = "foo";
+  destination = ConvertVariantTo<variant<double, std::string>>(source2);
+  EXPECT_THAT(absl::get_if<std::string>(&destination), Pointee(std::string("foo")));
+
+  variant<int, float> source3(42);
+  variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
+  EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0));
+
+  source3 = 3.14f;
+  singleton = ConvertVariantTo<variant<double>>(source3);
+  EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
+  EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f)));
+
+  variant<int> source4(3);
+  singleton = ConvertVariantTo<variant<double>>(source4);
+  EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0));
+
+  variant<int32_t> source5(42);
+  variant<int32_t, uint32_t> variant2(
+      ConvertVariantTo<variant<int32_t, uint32_t>>(source5));
+  EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
+
+  variant<uint32_t> source6(42);
+  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
+  EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
+
+  variant<Convertible2, Convertible1> source7((Convertible1()));
+  variant<Convertible1, Convertible2> variant3(
+      ConvertVariantTo<variant<Convertible1, Convertible2>>(source7));
+  ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
+
+  source7 = Convertible2();
+  variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7);
+  ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+}
+
+TEST(VariantTest, TestMoveConversionViaConvertVariantTo) {
+  using Variant =
+      variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
+  using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+
+  Variant var(
+      ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)}));
+  EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var),
+              Pointee(Pointee(3)));
+
+  var =
+      ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo")));
+  EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var),
+              Pointee(Pointee(std::string("foo"))));
+}
+
+// If all alternatives are trivially copy/move constructible, variant should
+// also be trivially copy/move constructible. This is not required by the
+// standard and we know that libstdc++ variant doesn't have this feature.
+// For more details see the paper:
+// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0602r0.html
+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#define ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY 1
+#endif
+
+TEST(VariantTest, TestCopyAndMoveTypeTraits) {
+  EXPECT_TRUE(std::is_copy_constructible<variant<std::string>>::value);
+  EXPECT_TRUE(std::is_copy_assignable<variant<std::string>>::value);
+  EXPECT_TRUE(std::is_move_constructible<variant<std::string>>::value);
+  EXPECT_TRUE(std::is_move_assignable<variant<std::string>>::value);
+  EXPECT_TRUE(std::is_move_constructible<variant<std::unique_ptr<int>>>::value);
+  EXPECT_TRUE(std::is_move_assignable<variant<std::unique_ptr<int>>>::value);
+  EXPECT_FALSE(
+      std::is_copy_constructible<variant<std::unique_ptr<int>>>::value);
+  EXPECT_FALSE(std::is_copy_assignable<variant<std::unique_ptr<int>>>::value);
+
+  EXPECT_FALSE(
+      absl::is_trivially_copy_constructible<variant<std::string>>::value);
+  EXPECT_FALSE(absl::is_trivially_copy_assignable<variant<std::string>>::value);
+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+  EXPECT_TRUE(absl::is_trivially_copy_constructible<variant<int>>::value);
+  EXPECT_TRUE(absl::is_trivially_copy_assignable<variant<int>>::value);
+  EXPECT_TRUE(is_trivially_move_constructible<variant<int>>::value);
+  EXPECT_TRUE(is_trivially_move_assignable<variant<int>>::value);
+#endif  // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+}
+
+TEST(VariantTest, TestVectorOfMoveonlyVariant) {
+  // Verify that variant<MoveonlyType> works correctly as a std::vector element.
+  std::vector<variant<std::unique_ptr<int>, std::string>> vec;
+  vec.push_back(absl::make_unique<int>(42));
+  vec.emplace_back("Hello");
+  vec.reserve(3);
+  auto another_vec = absl::move(vec);
+  // As a sanity check, verify vector contents.
+  ASSERT_EQ(2, another_vec.size());
+  EXPECT_EQ(42, *absl::get<std::unique_ptr<int>>(another_vec[0]));
+  EXPECT_EQ("Hello", absl::get<std::string>(another_vec[1]));
+}
+
+TEST(VariantTest, NestedVariant) {
+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+  static_assert(absl::is_trivially_copy_constructible<variant<int>>(), "");
+  static_assert(absl::is_trivially_copy_assignable<variant<int>>(), "");
+  static_assert(is_trivially_move_constructible<variant<int>>(), "");
+  static_assert(is_trivially_move_assignable<variant<int>>(), "");
+
+  static_assert(absl::is_trivially_copy_constructible<variant<variant<int>>>(),
+                "");
+  static_assert(absl::is_trivially_copy_assignable<variant<variant<int>>>(),
+                "");
+  static_assert(is_trivially_move_constructible<variant<variant<int>>>(), "");
+  static_assert(is_trivially_move_assignable<variant<variant<int>>>(), "");
+#endif  // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+
+  variant<int> x(42);
+  variant<variant<int>> y(x);
+  variant<variant<int>> z(y);
+  EXPECT_TRUE(absl::holds_alternative<variant<int>>(z));
+  EXPECT_EQ(x, absl::get<variant<int>>(z));
+}
+
+struct TriviallyDestructible {
+  TriviallyDestructible(TriviallyDestructible&&) {}
+  TriviallyDestructible(const TriviallyDestructible&) {}
+  TriviallyDestructible& operator=(TriviallyDestructible&&) { return *this; }
+  TriviallyDestructible& operator=(const TriviallyDestructible&) {
+    return *this;
+  }
+};
+
+struct TriviallyMovable {
+  TriviallyMovable(TriviallyMovable&&) = default;
+  TriviallyMovable(TriviallyMovable const&) {}
+  TriviallyMovable& operator=(const TriviallyMovable&) { return *this; }
+};
+
+struct TriviallyCopyable {
+  TriviallyCopyable(const TriviallyCopyable&) = default;
+  TriviallyCopyable& operator=(const TriviallyCopyable&) { return *this; }
+};
+
+struct TriviallyMoveAssignable {
+  TriviallyMoveAssignable(TriviallyMoveAssignable&&) = default;
+  TriviallyMoveAssignable(const TriviallyMoveAssignable&) {}
+  TriviallyMoveAssignable& operator=(TriviallyMoveAssignable&&) = default;
+  TriviallyMoveAssignable& operator=(const TriviallyMoveAssignable&) {
+    return *this;
+  }
+};
+
+struct TriviallyCopyAssignable {};
+
+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+TEST(VariantTest, TestTriviality) {
+  {
+    using TrivDestVar = absl::variant<TriviallyDestructible>;
+
+    EXPECT_FALSE(is_trivially_move_constructible<TrivDestVar>::value);
+    EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivDestVar>::value);
+    EXPECT_FALSE(is_trivially_move_assignable<TrivDestVar>::value);
+    EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivDestVar>::value);
+    EXPECT_TRUE(absl::is_trivially_destructible<TrivDestVar>::value);
+  }
+
+  {
+    using TrivMoveVar = absl::variant<TriviallyMovable>;
+
+    EXPECT_TRUE(is_trivially_move_constructible<TrivMoveVar>::value);
+    EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivMoveVar>::value);
+    EXPECT_FALSE(is_trivially_move_assignable<TrivMoveVar>::value);
+    EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveVar>::value);
+    EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveVar>::value);
+  }
+
+  {
+    using TrivCopyVar = absl::variant<TriviallyCopyable>;
+
+    EXPECT_TRUE(is_trivially_move_constructible<TrivCopyVar>::value);
+    EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivCopyVar>::value);
+    EXPECT_FALSE(is_trivially_move_assignable<TrivCopyVar>::value);
+    EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivCopyVar>::value);
+    EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyVar>::value);
+  }
+
+  {
+    using TrivMoveAssignVar = absl::variant<TriviallyMoveAssignable>;
+
+    EXPECT_TRUE(is_trivially_move_constructible<TrivMoveAssignVar>::value);
+    EXPECT_FALSE(
+        absl::is_trivially_copy_constructible<TrivMoveAssignVar>::value);
+    EXPECT_TRUE(is_trivially_move_assignable<TrivMoveAssignVar>::value);
+    EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveAssignVar>::value);
+    EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveAssignVar>::value);
+  }
+
+  {
+    using TrivCopyAssignVar = absl::variant<TriviallyCopyAssignable>;
+
+    EXPECT_TRUE(is_trivially_move_constructible<TrivCopyAssignVar>::value);
+    EXPECT_TRUE(
+        absl::is_trivially_copy_constructible<TrivCopyAssignVar>::value);
+    EXPECT_TRUE(is_trivially_move_assignable<TrivCopyAssignVar>::value);
+    EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivCopyAssignVar>::value);
+    EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyAssignVar>::value);
+  }
+}
+#endif  // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
+
+// To verify that absl::variant correctly use the nontrivial move ctor of its
+// member rather than use the trivial copy constructor.
+TEST(VariantTest, MoveCtorBug) {
+  // To simulate std::tuple in libstdc++.
+  struct TrivialCopyNontrivialMove {
+    TrivialCopyNontrivialMove() = default;
+    TrivialCopyNontrivialMove(const TrivialCopyNontrivialMove&) = default;
+    TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) { called = true; }
+    bool called = false;
+  };
+  {
+    using V = absl::variant<TrivialCopyNontrivialMove, int>;
+    V v1(absl::in_place_index_t<0>{});
+    // this should invoke the move ctor, rather than the trivial copy ctor.
+    V v2(std::move(v1));
+    EXPECT_TRUE(absl::get<0>(v2).called);
+  }
+  {
+    // this case failed to compile before our fix due to a GCC bug.
+    using V = absl::variant<int, TrivialCopyNontrivialMove>;
+    V v1(absl::in_place_index_t<1>{});
+    // this should invoke the move ctor, rather than the trivial copy ctor.
+    V v2(std::move(v1));
+    EXPECT_TRUE(absl::get<1>(v2).called);
+  }
+}
+
+}  // namespace
+}  // namespace absl
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
new file mode 100644
index 0000000..c01b49b
--- /dev/null
+++ b/absl/utility/BUILD.bazel
@@ -0,0 +1,33 @@
+load(
+    "//absl:copts.bzl",
+    "ABSL_DEFAULT_COPTS",
+    "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache 2.0
+
+cc_library(
+    name = "utility",
+    hdrs = ["utility.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [
+        "//absl/base:base_internal",
+        "//absl/base:config",
+        "//absl/meta:type_traits",
+    ],
+)
+
+cc_test(
+    name = "utility_test",
+    srcs = ["utility_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    deps = [
+        ":utility",
+        "//absl/base:core_headers",
+        "//absl/memory",
+        "//absl/strings",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/utility/BUILD.gn b/absl/utility/BUILD.gn
new file mode 100644
index 0000000..4cf3c81
--- /dev/null
+++ b/absl/utility/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build_overrides/build.gni")
+
+if (build_with_chromium) {
+  visibility = [
+    "//third_party/webrtc/*",
+    "//third_party/abseil-cpp/*",
+    "//third_party/googletest:gtest",
+  ]
+} else {
+  visibility = [ "*" ]
+}
+
+source_set("utility") {
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/abseil-cpp:absl_default_cflags_cc",
+  ]
+  public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
+  public = [
+    "utility.h",
+  ]
+  deps = [
+    "../base:base_internal",
+    "../base:config",
+    "../meta:type_traits",
+  ]
+}
diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt
new file mode 100644
index 0000000..dc3a631
--- /dev/null
+++ b/absl/utility/CMakeLists.txt
@@ -0,0 +1,52 @@
+#
+# Copyright 2017 The Abseil 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.
+#
+
+
+list(APPEND UTILITY_PUBLIC_HEADERS
+  "utility.h"
+)
+
+absl_header_library(
+  TARGET
+    absl_utility
+  PUBLIC_LIBRARIES
+    absl::base
+  EXPORT_NAME
+    utility
+)
+
+
+#
+## TESTS
+#
+
+# test utility_test
+set(UTILITY_TEST_SRC "utility_test.cc")
+set(UTILITY_TEST_PUBLIC_LIBRARIES
+  absl::base
+  absl::memory
+  absl::strings
+  absl::utility
+)
+
+absl_test(
+  TARGET
+    utility_test
+  SOURCES
+    ${UTILITY_TEST_SRC}
+  PUBLIC_LIBRARIES
+    ${UTILITY_TEST_PUBLIC_LIBRARIES}
+)
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
new file mode 100644
index 0000000..d73602c
--- /dev/null
+++ b/absl/utility/utility.h
@@ -0,0 +1,291 @@
+// Copyright 2017 The Abseil 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.
+//
+// This header file contains C++11 versions of standard <utility> header
+// abstractions available within C++14 and C++17, and are designed to be drop-in
+// replacement for code compliant with C++14 and C++17.
+//
+// The following abstractions are defined:
+//
+//   * integer_sequence<T, Ints...>  == std::integer_sequence<T, Ints...>
+//   * index_sequence<Ints...>       == std::index_sequence<Ints...>
+//   * make_integer_sequence<T, N>   == std::make_integer_sequence<T, N>
+//   * make_index_sequence<N>        == std::make_index_sequence<N>
+//   * index_sequence_for<Ts...>     == std::index_sequence_for<Ts...>
+//   * apply<Functor, Tuple>         == std::apply<Functor, Tuple>
+//   * exchange<T>                   == std::exchange<T>
+//
+// This header file also provides the tag types `in_place_t`, `in_place_type_t`,
+// and `in_place_index_t`, as well as the constant `in_place`, and
+// `constexpr` `std::move()` and `std::forward()` implementations in C++11.
+//
+// References:
+//
+//  http://en.cppreference.com/w/cpp/utility/integer_sequence
+//  http://en.cppreference.com/w/cpp/utility/apply
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html
+//
+
+#ifndef ABSL_UTILITY_UTILITY_H_
+#define ABSL_UTILITY_UTILITY_H_
+
+#include <cstddef>
+#include <cstdlib>
+#include <tuple>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/inline_variable.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+// integer_sequence
+//
+// Class template representing a compile-time integer sequence. An instantiation
+// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
+// type through its template arguments (which is a common need when
+// working with C++11 variadic templates). `absl::integer_sequence` is designed
+// to be a drop-in replacement for C++14's `std::integer_sequence`.
+//
+// Example:
+//
+//   template< class T, T... Ints >
+//   void user_function(integer_sequence<T, Ints...>);
+//
+//   int main()
+//   {
+//     // user_function's `T` will be deduced to `int` and `Ints...`
+//     // will be deduced to `0, 1, 2, 3, 4`.
+//     user_function(make_integer_sequence<int, 5>());
+//   }
+template <typename T, T... Ints>
+struct integer_sequence {
+  using value_type = T;
+  static constexpr size_t size() noexcept { return sizeof...(Ints); }
+};
+
+// index_sequence
+//
+// A helper template for an `integer_sequence` of `size_t`,
+// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
+// `std::index_sequence`.
+template <size_t... Ints>
+using index_sequence = integer_sequence<size_t, Ints...>;
+
+namespace utility_internal {
+
+template <typename Seq, size_t SeqSize, size_t Rem>
+struct Extend;
+
+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> {
+  using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>;
+};
+
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> {
+  using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>;
+};
+
+// Recursion helper for 'make_integer_sequence<T, N>'.
+// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
+template <typename T, size_t N>
+struct Gen {
+  using type =
+      typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type;
+};
+
+template <typename T>
+struct Gen<T, 0> {
+  using type = integer_sequence<T>;
+};
+
+}  // namespace utility_internal
+
+// Compile-time sequences of integers
+
+// make_integer_sequence
+//
+// This template alias is equivalent to
+// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
+// replacement for C++14's `std::make_integer_sequence`.
+template <typename T, T N>
+using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
+
+// make_index_sequence
+//
+// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
+// and is designed to be a drop-in replacement for C++14's
+// `std::make_index_sequence`.
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
+// index_sequence_for
+//
+// Converts a typename pack into an index sequence of the same length, and
+// is designed to be a drop-in replacement for C++14's
+// `std::index_sequence_for()`
+template <typename... Ts>
+using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
+
+// Tag types
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+
+using std::in_place_t;
+using std::in_place;
+
+#else  // ABSL_HAVE_STD_OPTIONAL
+
+// in_place_t
+//
+// Tag type used to specify in-place construction, such as with
+// `absl::optional`, designed to be a drop-in replacement for C++17's
+// `std::in_place_t`.
+struct in_place_t {};
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
+
+#endif  // ABSL_HAVE_STD_OPTIONAL
+
+#if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT)
+using std::in_place_type_t;
+#else
+
+// in_place_type_t
+//
+// Tag type used for in-place construction when the type to construct needs to
+// be specified, such as with `absl::any`, designed to be a drop-in replacement
+// for C++17's `std::in_place_type_t`.
+template <typename T>
+struct in_place_type_t {};
+#endif  // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT
+
+#ifdef ABSL_HAVE_STD_VARIANT
+using std::in_place_index_t;
+#else
+
+// in_place_index_t
+//
+// Tag type used for in-place construction when the type to construct needs to
+// be specified, such as with `absl::any`, designed to be a drop-in replacement
+// for C++17's `std::in_place_index_t`.
+template <size_t I>
+struct in_place_index_t {};
+#endif  // ABSL_HAVE_STD_VARIANT
+
+// Constexpr move and forward
+
+// move()
+//
+// A constexpr version of `std::move()`, designed to be a drop-in replacement
+// for C++14's `std::move()`.
+template <typename T>
+constexpr absl::remove_reference_t<T>&& move(T&& t) noexcept {
+  return static_cast<absl::remove_reference_t<T>&&>(t);
+}
+
+// forward()
+//
+// A constexpr version of `std::forward()`, designed to be a drop-in replacement
+// for C++14's `std::forward()`.
+template <typename T>
+constexpr T&& forward(
+    absl::remove_reference_t<T>& t) noexcept {  // NOLINT(runtime/references)
+  return static_cast<T&&>(t);
+}
+
+namespace utility_internal {
+// Helper method for expanding tuple into a called method.
+template <typename Functor, typename Tuple, std::size_t... Indexes>
+auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
+    -> decltype(absl::base_internal::Invoke(
+        absl::forward<Functor>(functor),
+        std::get<Indexes>(absl::forward<Tuple>(t))...)) {
+  return absl::base_internal::Invoke(
+      absl::forward<Functor>(functor),
+      std::get<Indexes>(absl::forward<Tuple>(t))...);
+}
+
+}  // namespace utility_internal
+
+// apply
+//
+// Invokes a Callable using elements of a tuple as its arguments.
+// Each element of the tuple corresponds to an argument of the call (in order).
+// Both the Callable argument and the tuple argument are perfect-forwarded.
+// For member-function Callables, the first tuple element acts as the `this`
+// pointer. `absl::apply` is designed to be a drop-in replacement for C++17's
+// `std::apply`. Unlike C++17's `std::apply`, this is not currently `constexpr`.
+//
+// Example:
+//
+//   class Foo{void Bar(int);};
+//   void user_function(int, std::string);
+//   void user_function(std::unique_ptr<Foo>);
+//
+//   int main()
+//   {
+//       std::tuple<int, std::string> tuple1(42, "bar");
+//       // Invokes the user function overload on int, std::string.
+//       absl::apply(&user_function, tuple1);
+//
+//       auto foo = absl::make_unique<Foo>();
+//       std::tuple<Foo*, int> tuple2(foo.get(), 42);
+//       // Invokes the method Bar on foo with one argument 42.
+//       absl::apply(&Foo::Bar, foo.get(), 42);
+//
+//       std::tuple<std::unique_ptr<Foo>> tuple3(absl::make_unique<Foo>());
+//       // Invokes the user function that takes ownership of the unique
+//       // pointer.
+//       absl::apply(&user_function, std::move(tuple));
+//   }
+template <typename Functor, typename Tuple>
+auto apply(Functor&& functor, Tuple&& t)
+    -> decltype(utility_internal::apply_helper(
+        absl::forward<Functor>(functor), absl::forward<Tuple>(t),
+        absl::make_index_sequence<std::tuple_size<
+            typename std::remove_reference<Tuple>::type>::value>{})) {
+  return utility_internal::apply_helper(
+      absl::forward<Functor>(functor), absl::forward<Tuple>(t),
+      absl::make_index_sequence<std::tuple_size<
+          typename std::remove_reference<Tuple>::type>::value>{});
+}
+
+// exchange
+//
+// Replaces the value of `obj` with `new_value` and returns the old value of
+// `obj`.  `absl::exchange` is designed to be a drop-in replacement for C++14's
+// `std::exchange`.
+//
+// Example:
+//
+//   Foo& operator=(Foo&& other) {
+//     ptr1_ = absl::exchange(other.ptr1_, nullptr);
+//     int1_ = absl::exchange(other.int1_, -1);
+//     return *this;
+//   }
+template <typename T, typename U = T>
+T exchange(T& obj, U&& new_value) {
+  T old_value = absl::move(obj);
+  obj = absl::forward<U>(new_value);
+  return old_value;
+}
+
+}  // namespace absl
+
+#endif  // ABSL_UTILITY_UTILITY_H_
diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc
new file mode 100644
index 0000000..3c447b2
--- /dev/null
+++ b/absl/utility/utility_test.cc
@@ -0,0 +1,345 @@
+// Copyright 2017 The Abseil 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 "absl/utility/utility.h"
+
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+#ifdef _MSC_VER
+// Warnings for unused variables in this test are false positives.  On other
+// platforms, they are suppressed by ABSL_ATTRIBUTE_UNUSED, but that doesn't
+// work on MSVC.
+// Both the unused variables and the name length warnings are due to calls
+// to absl::make_index_sequence with very large values, creating very long type
+// names. The resulting warnings are so long they make build output unreadable.
+#pragma warning( push )
+#pragma warning( disable : 4503 )  // decorated name length exceeded
+#pragma warning( disable : 4101 )  // unreferenced local variable
+#endif  // _MSC_VER
+
+using ::testing::ElementsAre;
+using ::testing::Pointee;
+using ::testing::StaticAssertTypeEq;
+
+TEST(IntegerSequenceTest, ValueType) {
+  StaticAssertTypeEq<int, absl::integer_sequence<int>::value_type>();
+  StaticAssertTypeEq<char, absl::integer_sequence<char>::value_type>();
+}
+
+TEST(IntegerSequenceTest, Size) {
+  EXPECT_EQ(0, (absl::integer_sequence<int>::size()));
+  EXPECT_EQ(1, (absl::integer_sequence<int, 0>::size()));
+  EXPECT_EQ(1, (absl::integer_sequence<int, 1>::size()));
+  EXPECT_EQ(2, (absl::integer_sequence<int, 1, 2>::size()));
+  EXPECT_EQ(3, (absl::integer_sequence<int, 0, 1, 2>::size()));
+  EXPECT_EQ(3, (absl::integer_sequence<int, -123, 123, 456>::size()));
+  constexpr size_t sz = absl::integer_sequence<int, 0, 1>::size();
+  EXPECT_EQ(2, sz);
+}
+
+TEST(IntegerSequenceTest, MakeIndexSequence) {
+  StaticAssertTypeEq<absl::index_sequence<>, absl::make_index_sequence<0>>();
+  StaticAssertTypeEq<absl::index_sequence<0>, absl::make_index_sequence<1>>();
+  StaticAssertTypeEq<absl::index_sequence<0, 1>,
+                     absl::make_index_sequence<2>>();
+  StaticAssertTypeEq<absl::index_sequence<0, 1, 2>,
+                     absl::make_index_sequence<3>>();
+}
+
+TEST(IntegerSequenceTest, MakeIntegerSequence) {
+  StaticAssertTypeEq<absl::integer_sequence<int>,
+                     absl::make_integer_sequence<int, 0>>();
+  StaticAssertTypeEq<absl::integer_sequence<int, 0>,
+                     absl::make_integer_sequence<int, 1>>();
+  StaticAssertTypeEq<absl::integer_sequence<int, 0, 1>,
+                     absl::make_integer_sequence<int, 2>>();
+  StaticAssertTypeEq<absl::integer_sequence<int, 0, 1, 2>,
+                     absl::make_integer_sequence<int, 3>>();
+}
+
+template <typename... Ts>
+class Counter {};
+
+template <size_t... Is>
+void CountAll(absl::index_sequence<Is...>) {
+  // We only need an alias here, but instantiate a variable to silence warnings
+  // for unused typedefs in some compilers.
+  ABSL_ATTRIBUTE_UNUSED Counter<absl::make_index_sequence<Is>...> seq;
+}
+
+// This test verifies that absl::make_index_sequence can handle large arguments
+// without blowing up template instantiation stack, going OOM or taking forever
+// to compile (there is hard 15 minutes limit imposed by forge).
+TEST(IntegerSequenceTest, MakeIndexSequencePerformance) {
+  // O(log N) template instantiations.
+  // We only need an alias here, but instantiate a variable to silence warnings
+  // for unused typedefs in some compilers.
+  ABSL_ATTRIBUTE_UNUSED absl::make_index_sequence<(1 << 16) - 1> seq;
+  // O(N) template instantiations.
+  CountAll(absl::make_index_sequence<(1 << 8) - 1>());
+}
+
+template <typename F, typename Tup, size_t... Is>
+auto ApplyFromTupleImpl(F f, const Tup& tup, absl::index_sequence<Is...>)
+    -> decltype(f(std::get<Is>(tup)...)) {
+  return f(std::get<Is>(tup)...);
+}
+
+template <typename Tup>
+using TupIdxSeq = absl::make_index_sequence<std::tuple_size<Tup>::value>;
+
+template <typename F, typename Tup>
+auto ApplyFromTuple(F f, const Tup& tup)
+    -> decltype(ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{})) {
+  return ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{});
+}
+
+template <typename T>
+std::string Fmt(const T& x) {
+  std::ostringstream os;
+  os << x;
+  return os.str();
+}
+
+struct PoorStrCat {
+  template <typename... Args>
+  std::string operator()(const Args&... args) const {
+    std::string r;
+    for (const auto& e : {Fmt(args)...}) r += e;
+    return r;
+  }
+};
+
+template <typename Tup, size_t... Is>
+std::vector<std::string> TupStringVecImpl(const Tup& tup,
+                                     absl::index_sequence<Is...>) {
+  return {Fmt(std::get<Is>(tup))...};
+}
+
+template <typename... Ts>
+std::vector<std::string> TupStringVec(const std::tuple<Ts...>& tup) {
+  return TupStringVecImpl(tup, absl::index_sequence_for<Ts...>());
+}
+
+TEST(MakeIndexSequenceTest, ApplyFromTupleExample) {
+  PoorStrCat f{};
+  EXPECT_EQ("12abc3.14", f(12, "abc", 3.14));
+  EXPECT_EQ("12abc3.14", ApplyFromTuple(f, std::make_tuple(12, "abc", 3.14)));
+}
+
+TEST(IndexSequenceForTest, Basic) {
+  StaticAssertTypeEq<absl::index_sequence<>, absl::index_sequence_for<>>();
+  StaticAssertTypeEq<absl::index_sequence<0>, absl::index_sequence_for<int>>();
+  StaticAssertTypeEq<absl::index_sequence<0, 1, 2, 3>,
+                     absl::index_sequence_for<int, void, char, int>>();
+}
+
+TEST(IndexSequenceForTest, Example) {
+  EXPECT_THAT(TupStringVec(std::make_tuple(12, "abc", 3.14)),
+              ElementsAre("12", "abc", "3.14"));
+}
+
+int Function(int a, int b) { return a - b; }
+
+int Sink(std::unique_ptr<int> p) { return *p; }
+
+std::unique_ptr<int> Factory(int n) { return absl::make_unique<int>(n); }
+
+void NoOp() {}
+
+struct ConstFunctor {
+  int operator()(int a, int b) const { return a - b; }
+};
+
+struct MutableFunctor {
+  int operator()(int a, int b) { return a - b; }
+};
+
+struct EphemeralFunctor {
+  EphemeralFunctor() {}
+  EphemeralFunctor(const EphemeralFunctor&) {}
+  EphemeralFunctor(EphemeralFunctor&&) {}
+  int operator()(int a, int b) && { return a - b; }
+};
+
+struct OverloadedFunctor {
+  OverloadedFunctor() {}
+  OverloadedFunctor(const OverloadedFunctor&) {}
+  OverloadedFunctor(OverloadedFunctor&&) {}
+  template <typename... Args>
+  std::string operator()(const Args&... args) & {
+    return absl::StrCat("&", args...);
+  }
+  template <typename... Args>
+  std::string operator()(const Args&... args) const& {
+    return absl::StrCat("const&", args...);
+  }
+  template <typename... Args>
+  std::string operator()(const Args&... args) && {
+    return absl::StrCat("&&", args...);
+  }
+};
+
+struct Class {
+  int Method(int a, int b) { return a - b; }
+  int ConstMethod(int a, int b) const { return a - b; }
+
+  int member;
+};
+
+struct FlipFlop {
+  int ConstMethod() const { return member; }
+  FlipFlop operator*() const { return {-member}; }
+
+  int member;
+};
+
+TEST(ApplyTest, Function) {
+  EXPECT_EQ(1, absl::apply(Function, std::make_tuple(3, 2)));
+  EXPECT_EQ(1, absl::apply(&Function, std::make_tuple(3, 2)));
+}
+
+TEST(ApplyTest, NonCopyableArgument) {
+  EXPECT_EQ(42, absl::apply(Sink, std::make_tuple(absl::make_unique<int>(42))));
+}
+
+TEST(ApplyTest, NonCopyableResult) {
+  EXPECT_THAT(absl::apply(Factory, std::make_tuple(42)),
+              ::testing::Pointee(42));
+}
+
+TEST(ApplyTest, VoidResult) { absl::apply(NoOp, std::tuple<>()); }
+
+TEST(ApplyTest, ConstFunctor) {
+  EXPECT_EQ(1, absl::apply(ConstFunctor(), std::make_tuple(3, 2)));
+}
+
+TEST(ApplyTest, MutableFunctor) {
+  MutableFunctor f;
+  EXPECT_EQ(1, absl::apply(f, std::make_tuple(3, 2)));
+  EXPECT_EQ(1, absl::apply(MutableFunctor(), std::make_tuple(3, 2)));
+}
+TEST(ApplyTest, EphemeralFunctor) {
+  EphemeralFunctor f;
+  EXPECT_EQ(1, absl::apply(std::move(f), std::make_tuple(3, 2)));
+  EXPECT_EQ(1, absl::apply(EphemeralFunctor(), std::make_tuple(3, 2)));
+}
+TEST(ApplyTest, OverloadedFunctor) {
+  OverloadedFunctor f;
+  const OverloadedFunctor& cf = f;
+
+  EXPECT_EQ("&", absl::apply(f, std::tuple<>{}));
+  EXPECT_EQ("& 42", absl::apply(f, std::make_tuple(" 42")));
+
+  EXPECT_EQ("const&", absl::apply(cf, std::tuple<>{}));
+  EXPECT_EQ("const& 42", absl::apply(cf, std::make_tuple(" 42")));
+
+  EXPECT_EQ("&&", absl::apply(std::move(f), std::tuple<>{}));
+  OverloadedFunctor f2;
+  EXPECT_EQ("&& 42", absl::apply(std::move(f2), std::make_tuple(" 42")));
+}
+
+TEST(ApplyTest, ReferenceWrapper) {
+  ConstFunctor cf;
+  MutableFunctor mf;
+  EXPECT_EQ(1, absl::apply(std::cref(cf), std::make_tuple(3, 2)));
+  EXPECT_EQ(1, absl::apply(std::ref(cf), std::make_tuple(3, 2)));
+  EXPECT_EQ(1, absl::apply(std::ref(mf), std::make_tuple(3, 2)));
+}
+
+TEST(ApplyTest, MemberFunction) {
+  std::unique_ptr<Class> p(new Class);
+  std::unique_ptr<const Class> cp(new Class);
+  EXPECT_EQ(
+      1, absl::apply(&Class::Method,
+                     std::tuple<std::unique_ptr<Class>&, int, int>(p, 3, 2)));
+  EXPECT_EQ(1, absl::apply(&Class::Method,
+                           std::tuple<Class*, int, int>(p.get(), 3, 2)));
+  EXPECT_EQ(
+      1, absl::apply(&Class::Method, std::tuple<Class&, int, int>(*p, 3, 2)));
+
+  EXPECT_EQ(
+      1, absl::apply(&Class::ConstMethod,
+                     std::tuple<std::unique_ptr<Class>&, int, int>(p, 3, 2)));
+  EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
+                           std::tuple<Class*, int, int>(p.get(), 3, 2)));
+  EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
+                           std::tuple<Class&, int, int>(*p, 3, 2)));
+
+  EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
+                           std::tuple<std::unique_ptr<const Class>&, int, int>(
+                               cp, 3, 2)));
+  EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
+                           std::tuple<const Class*, int, int>(cp.get(), 3, 2)));
+  EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
+                           std::tuple<const Class&, int, int>(*cp, 3, 2)));
+
+  EXPECT_EQ(1, absl::apply(&Class::Method,
+                           std::make_tuple(absl::make_unique<Class>(), 3, 2)));
+  EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
+                           std::make_tuple(absl::make_unique<Class>(), 3, 2)));
+  EXPECT_EQ(
+      1, absl::apply(&Class::ConstMethod,
+                     std::make_tuple(absl::make_unique<const Class>(), 3, 2)));
+}
+
+TEST(ApplyTest, DataMember) {
+  std::unique_ptr<Class> p(new Class{42});
+  std::unique_ptr<const Class> cp(new Class{42});
+  EXPECT_EQ(
+      42, absl::apply(&Class::member, std::tuple<std::unique_ptr<Class>&>(p)));
+  EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<Class&>(*p)));
+  EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<Class*>(p.get())));
+
+  absl::apply(&Class::member, std::tuple<std::unique_ptr<Class>&>(p)) = 42;
+  absl::apply(&Class::member, std::tuple<Class*>(p.get())) = 42;
+  absl::apply(&Class::member, std::tuple<Class&>(*p)) = 42;
+
+  EXPECT_EQ(42, absl::apply(&Class::member,
+                            std::tuple<std::unique_ptr<const Class>&>(cp)));
+  EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<const Class&>(*cp)));
+  EXPECT_EQ(42,
+            absl::apply(&Class::member, std::tuple<const Class*>(cp.get())));
+}
+
+TEST(ApplyTest, FlipFlop) {
+  FlipFlop obj = {42};
+  // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
+  // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
+  EXPECT_EQ(42, absl::apply(&FlipFlop::ConstMethod, std::make_tuple(obj)));
+  EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj)));
+}
+
+TEST(ExchangeTest, MoveOnly) {
+  auto a = Factory(1);
+  EXPECT_EQ(1, *a);
+  auto b = absl::exchange(a, Factory(2));
+  EXPECT_EQ(2, *a);
+  EXPECT_EQ(1, *b);
+}
+
+}  // namespace
+
diff --git a/api/array_view.h b/api/array_view.h
index d951d0f..efc642d 100644
--- a/api/array_view.h
+++ b/api/array_view.h
@@ -12,6 +12,7 @@
 #define API_ARRAY_VIEW_H_
 
 #include <algorithm>
+#include <array>
 #include <type_traits>
 
 #include "rtc_base/checks.h"
@@ -169,7 +170,7 @@
     RTC_DCHECK_EQ(0, size);
   }
 
-  // Construct an ArrayView from an array.
+  // Construct an ArrayView from a C-style array.
   template <typename U, size_t N>
   ArrayView(U (&array)[N])  // NOLINT
       : ArrayView(array, N) {
@@ -177,6 +178,26 @@
                   "Array size must match ArrayView size");
   }
 
+  // (Only if size is fixed.) Construct a fixed size ArrayView<T, N> from a
+  // non-const std::array instance. For an ArrayView with variable size, the
+  // used ctor is ArrayView(U& u) instead.
+  template <typename U,
+            size_t N,
+            typename std::enable_if<
+                Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
+  ArrayView(std::array<U, N>& u)  // NOLINT
+      : ArrayView(u.data(), u.size()) {}
+
+  // (Only if size is fixed.) Construct a fixed size ArrayView<T, N> where T is
+  // const from a const(expr) std::array instance. For an ArrayView with
+  // variable size, the used ctor is ArrayView(U& u) instead.
+  template <typename U,
+            size_t N,
+            typename std::enable_if<
+                Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
+  ArrayView(const std::array<U, N>& u)  // NOLINT
+      : ArrayView(u.data(), u.size()) {}
+
   // (Only if size is fixed.) Construct an ArrayView from any type U that has a
   // static constexpr size() method whose return value is equal to Size, and a
   // data() method whose return value converts implicitly to T*. In particular,
diff --git a/api/array_view_unittest.cc b/api/array_view_unittest.cc
index 48dff2c..694ed0b 100644
--- a/api/array_view_unittest.cc
+++ b/api/array_view_unittest.cc
@@ -9,6 +9,7 @@
  */
 
 #include <algorithm>
+#include <array>
 #include <string>
 #include <utility>
 #include <vector>
@@ -180,6 +181,38 @@
   // v = z;  // Compile error, because can't drop const.
 }
 
+TEST(ArrayViewTest, TestStdArray) {
+  constexpr size_t size = 5;
+  std::array<float, size> arr{};
+  // Fixed size view.
+  rtc::ArrayView<float, size> arr_view_fixed(arr);
+  EXPECT_EQ(arr.data(), arr_view_fixed.data());
+  static_assert(size == arr_view_fixed.size(), "");
+  // Variable size view.
+  rtc::ArrayView<float> arr_view(arr);
+  EXPECT_EQ(arr.data(), arr_view.data());
+  EXPECT_EQ(size, arr_view.size());
+}
+
+TEST(ArrayViewTest, TestConstStdArray) {
+  constexpr size_t size = 5;
+
+  constexpr std::array<float, size> constexpr_arr{};
+  rtc::ArrayView<const float, size> constexpr_arr_view(constexpr_arr);
+  EXPECT_EQ(constexpr_arr.data(), constexpr_arr_view.data());
+  static_assert(constexpr_arr.size() == constexpr_arr_view.size(), "");
+
+  const std::array<float, size> const_arr{};
+  rtc::ArrayView<const float, size> const_arr_view(const_arr);
+  EXPECT_EQ(const_arr.data(), const_arr_view.data());
+  static_assert(const_arr.size() == const_arr_view.size(), "");
+
+  std::array<float, size> non_const_arr{};
+  rtc::ArrayView<const float, size> non_const_arr_view(non_const_arr);
+  EXPECT_EQ(non_const_arr.data(), non_const_arr_view.data());
+  static_assert(non_const_arr.size() == non_const_arr_view.size(), "");
+}
+
 TEST(ArrayViewTest, TestStdVector) {
   std::vector<int> v;
   v.push_back(3);
diff --git a/api/audio/audio_frame.cc b/api/audio/audio_frame.cc
index b477a17..75d30b0 100644
--- a/api/audio/audio_frame.cc
+++ b/api/audio/audio_frame.cc
@@ -66,7 +66,8 @@
 }
 
 void AudioFrame::CopyFrom(const AudioFrame& src) {
-  if (this == &src) return;
+  if (this == &src)
+    return;
 
   timestamp_ = src.timestamp_;
   elapsed_time_ms_ = src.elapsed_time_ms_;
@@ -116,7 +117,9 @@
   muted_ = true;
 }
 
-bool AudioFrame::muted() const { return muted_; }
+bool AudioFrame::muted() const {
+  return muted_;
+}
 
 // static
 const int16_t* AudioFrame::empty_data() {
diff --git a/api/audio/audio_frame.h b/api/audio/audio_frame.h
index 39840e5..4c9aa9c 100644
--- a/api/audio/audio_frame.h
+++ b/api/audio/audio_frame.h
@@ -43,11 +43,7 @@
     kMaxDataSizeBytes = kMaxDataSizeSamples * sizeof(int16_t),
   };
 
-  enum VADActivity {
-    kVadActive = 0,
-    kVadPassive = 1,
-    kVadUnknown = 2
-  };
+  enum VADActivity { kVadActive = 0, kVadPassive = 1, kVadUnknown = 2 };
   enum SpeechType {
     kNormalSpeech = 0,
     kPLC = 1,
@@ -66,9 +62,12 @@
   // ResetWithoutMuting() to skip this wasteful zeroing.
   void ResetWithoutMuting();
 
-  void UpdateFrame(uint32_t timestamp, const int16_t* data,
-                   size_t samples_per_channel, int sample_rate_hz,
-                   SpeechType speech_type, VADActivity vad_activity,
+  void UpdateFrame(uint32_t timestamp,
+                   const int16_t* data,
+                   size_t samples_per_channel,
+                   int sample_rate_hz,
+                   SpeechType speech_type,
+                   VADActivity vad_activity,
                    size_t num_channels = 1);
 
   void CopyFrom(const AudioFrame& src);
@@ -111,7 +110,7 @@
   // Monotonically increasing timestamp intended for profiling of audio frames.
   // Typically used for measuring elapsed time between two different points in
   // the audio path. No lock is used to save resources and we are thread safe
-  // by design. Also, rtc::Optional is not used since it will cause a "complex
+  // by design. Also, absl::optional is not used since it will cause a "complex
   // class/struct needs an explicit out-of-line destructor" build error.
   int64_t profile_timestamp_ms_ = 0;
 
diff --git a/api/audio/echo_canceller3_config.cc b/api/audio/echo_canceller3_config.cc
index c17b0d5..9af7f11 100644
--- a/api/audio/echo_canceller3_config.cc
+++ b/api/audio/echo_canceller3_config.cc
@@ -17,4 +17,8 @@
 EchoCanceller3Config::Mask::Mask() = default;
 EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default;
 
+EchoCanceller3Config::EchoModel::EchoModel() = default;
+EchoCanceller3Config::EchoModel::EchoModel(
+    const EchoCanceller3Config::EchoModel& e) = default;
+
 }  // namespace webrtc
diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h
index 174ef6c..d633d04 100644
--- a/api/audio/echo_canceller3_config.h
+++ b/api/audio/echo_canceller3_config.h
@@ -22,13 +22,13 @@
   struct Delay {
     size_t default_delay = 5;
     size_t down_sampling_factor = 4;
-    size_t num_filters = 5;
+    size_t num_filters = 6;
     size_t api_call_jitter_blocks = 26;
     size_t min_echo_path_delay_blocks = 0;
     size_t delay_headroom_blocks = 2;
     size_t hysteresis_limit_1_blocks = 1;
     size_t hysteresis_limit_2_blocks = 1;
-    size_t skew_hysteresis_blocks = 1;
+    size_t skew_hysteresis_blocks = 3;
   } delay;
 
   struct Filter {
@@ -46,10 +46,10 @@
       float noise_gate;
     };
 
-    MainConfiguration main = {13, 0.005f, 0.1f, 0.001f, 20075344.f};
+    MainConfiguration main = {13, 0.00005f, 0.01f, 0.1f, 20075344.f};
     ShadowConfiguration shadow = {13, 0.7f, 20075344.f};
 
-    MainConfiguration main_initial = {12, 0.05f, 5.f, 0.001f, 20075344.f};
+    MainConfiguration main_initial = {12, 0.005f, 0.5f, 0.001f, 20075344.f};
     ShadowConfiguration shadow_initial = {12, 0.9f, 20075344.f};
 
     size_t config_change_duration_blocks = 250;
@@ -62,10 +62,11 @@
   } erle;
 
   struct EpStrength {
-    float lf = 10.f;
-    float mf = 10.f;
-    float hf = 10.f;
-    float default_len = 0.f;
+    float lf = 1.f;
+    float mf = 1.f;
+    float hf = 1.f;
+    float default_len = 0.88f;
+    bool reverb_based_on_render = true;
     bool echo_can_saturate = true;
     bool bounded_erl = false;
   } ep_strength;
@@ -73,6 +74,7 @@
   struct Mask {
     Mask();
     Mask(const Mask& m);
+    float m0 = 0.1f;
     float m1 = 0.01f;
     float m2 = 0.0001f;
     float m3 = 0.01f;
@@ -96,12 +98,13 @@
     float audibility_threshold_lf = 10;
     float audibility_threshold_mf = 10;
     float audibility_threshold_hf = 10;
-    bool use_stationary_properties = false;
+    bool use_stationary_properties = true;
   } echo_audibility;
 
   struct RenderLevels {
     float active_render_limit = 100.f;
     float poor_excitation_render_limit = 150.f;
+    float poor_excitation_render_limit_ds8 = 20.f;
   } render_levels;
 
   struct GainUpdates {
@@ -120,20 +123,25 @@
     GainChanges saturation = {1.2f, 1.2f, 1.5f, 1.5f, 1.f, 1.f};
     GainChanges nonlinear = {1.5f, 1.5f, 1.2f, 1.2f, 1.1f, 1.1f};
 
+    float max_inc_factor = 2.0f;
+    float max_dec_factor_lf = 0.25f;
     float floor_first_increase = 0.00001f;
   } gain_updates;
 
   struct EchoRemovalControl {
     struct GainRampup {
+      float initial_gain = 0.0f;
       float first_non_zero_gain = 0.001f;
       int non_zero_gain_blocks = 187;
       int full_gain_blocks = 312;
     } gain_rampup;
-
     bool has_clock_drift = false;
+    bool linear_and_stable_echo_path = false;
   } echo_removal_control;
 
   struct EchoModel {
+    EchoModel();
+    EchoModel(const EchoModel& e);
     size_t noise_floor_hold = 50;
     float min_noise_floor_power = 1638400.f;
     float stationary_gate_slope = 10.f;
@@ -141,12 +149,23 @@
     float noise_gate_slope = 0.3f;
     size_t render_pre_window_size = 1;
     size_t render_post_window_size = 1;
+    size_t render_pre_window_size_init = 10;
+    size_t render_post_window_size_init = 10;
     float nonlinear_hold = 1;
     float nonlinear_release = 0.001f;
   } echo_model;
 
   struct Suppressor {
     size_t bands_with_reliable_coherence = 5;
+    size_t nearend_average_blocks = 4;
+
+    struct MaskingThresholds {
+      float enr_transparent;
+      float enr_suppress;
+      float emr_transparent;
+    };
+    MaskingThresholds mask_lf = {.2f, .3f, .3f};
+    MaskingThresholds mask_hf = {.07f, .1f, .3f};
   } suppressor;
 };
 }  // namespace webrtc
diff --git a/api/audio/echo_canceller3_factory.cc b/api/audio/echo_canceller3_factory.cc
index 7e2c143..07f295f 100644
--- a/api/audio/echo_canceller3_factory.cc
+++ b/api/audio/echo_canceller3_factory.cc
@@ -11,8 +11,8 @@
 
 #include <memory>
 
+#include "absl/memory/memory.h"
 #include "modules/audio_processing/aec3/echo_canceller3.h"
-#include "rtc_base/ptr_util.h"
 
 namespace webrtc {
 
@@ -22,6 +22,6 @@
     : config_(config) {}
 
 std::unique_ptr<EchoControl> EchoCanceller3Factory::Create(int sample_rate_hz) {
-  return rtc::MakeUnique<EchoCanceller3>(config_, sample_rate_hz, true);
+  return absl::make_unique<EchoCanceller3>(config_, sample_rate_hz, true);
 }
 }  // namespace webrtc
diff --git a/api/audio_options.h b/api/audio_options.h
index 5d69842..df66d36 100644
--- a/api/audio_options.h
+++ b/api/audio_options.h
@@ -13,7 +13,7 @@
 
 #include <string>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/stringencode.h"
 
 namespace cricket {
@@ -112,7 +112,7 @@
     ost << ToStringIfSet("residual_echo_detector", residual_echo_detector);
     ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
     ost << ToStringIfSet("tx_agc_digital_compression_gain",
-        tx_agc_digital_compression_gain);
+                         tx_agc_digital_compression_gain);
     ost << ToStringIfSet("tx_agc_limiter", tx_agc_limiter);
     ost << ToStringIfSet("combined_audio_video_bwe", combined_audio_video_bwe);
     ost << ToStringIfSet("audio_network_adaptor", audio_network_adaptor);
@@ -126,53 +126,53 @@
 
   // Audio processing that attempts to filter away the output signal from
   // later inbound pickup.
-  rtc::Optional<bool> echo_cancellation;
+  absl::optional<bool> echo_cancellation;
 #if defined(WEBRTC_IOS)
   // Forces software echo cancellation on iOS. This is a temporary workaround
   // (until Apple fixes the bug) for a device with non-functioning AEC. May
   // improve performance on that particular device, but will cause unpredictable
   // behavior in all other cases. See http://bugs.webrtc.org/8682.
-  rtc::Optional<bool> ios_force_software_aec_HACK;
+  absl::optional<bool> ios_force_software_aec_HACK;
 #endif
   // Audio processing to adjust the sensitivity of the local mic dynamically.
-  rtc::Optional<bool> auto_gain_control;
+  absl::optional<bool> auto_gain_control;
   // Audio processing to filter out background noise.
-  rtc::Optional<bool> noise_suppression;
+  absl::optional<bool> noise_suppression;
   // Audio processing to remove background noise of lower frequencies.
-  rtc::Optional<bool> highpass_filter;
+  absl::optional<bool> highpass_filter;
   // Audio processing to swap the left and right channels.
-  rtc::Optional<bool> stereo_swapping;
+  absl::optional<bool> stereo_swapping;
   // Audio receiver jitter buffer (NetEq) max capacity in number of packets.
-  rtc::Optional<int> audio_jitter_buffer_max_packets;
+  absl::optional<int> audio_jitter_buffer_max_packets;
   // Audio receiver jitter buffer (NetEq) fast accelerate mode.
-  rtc::Optional<bool> audio_jitter_buffer_fast_accelerate;
+  absl::optional<bool> audio_jitter_buffer_fast_accelerate;
   // Audio processing to detect typing.
-  rtc::Optional<bool> typing_detection;
-  rtc::Optional<bool> aecm_generate_comfort_noise;
-  rtc::Optional<bool> experimental_agc;
-  rtc::Optional<bool> extended_filter_aec;
-  rtc::Optional<bool> delay_agnostic_aec;
-  rtc::Optional<bool> experimental_ns;
-  rtc::Optional<bool> intelligibility_enhancer;
+  absl::optional<bool> typing_detection;
+  absl::optional<bool> aecm_generate_comfort_noise;
+  absl::optional<bool> experimental_agc;
+  absl::optional<bool> extended_filter_aec;
+  absl::optional<bool> delay_agnostic_aec;
+  absl::optional<bool> experimental_ns;
+  absl::optional<bool> intelligibility_enhancer;
   // Note that tx_agc_* only applies to non-experimental AGC.
-  rtc::Optional<bool> residual_echo_detector;
-  rtc::Optional<uint16_t> tx_agc_target_dbov;
-  rtc::Optional<uint16_t> tx_agc_digital_compression_gain;
-  rtc::Optional<bool> tx_agc_limiter;
+  absl::optional<bool> residual_echo_detector;
+  absl::optional<uint16_t> tx_agc_target_dbov;
+  absl::optional<uint16_t> tx_agc_digital_compression_gain;
+  absl::optional<bool> tx_agc_limiter;
   // Enable combined audio+bandwidth BWE.
   // TODO(pthatcher): This flag is set from the
   // "googCombinedAudioVideoBwe", but not used anywhere. So delete it,
   // and check if any other AudioOptions members are unused.
-  rtc::Optional<bool> combined_audio_video_bwe;
+  absl::optional<bool> combined_audio_video_bwe;
   // Enable audio network adaptor.
-  rtc::Optional<bool> audio_network_adaptor;
+  absl::optional<bool> audio_network_adaptor;
   // Config string for audio network adaptor.
-  rtc::Optional<std::string> audio_network_adaptor_config;
+  absl::optional<std::string> audio_network_adaptor_config;
 
  private:
   template <class T>
   static std::string ToStringIfSet(const char* key,
-                                   const rtc::Optional<T>& val) {
+                                   const absl::optional<T>& val) {
     std::string str;
     if (val) {
       str = key;
@@ -184,7 +184,7 @@
   }
 
   template <typename T>
-  static void SetFrom(rtc::Optional<T>* s, const rtc::Optional<T>& o) {
+  static void SetFrom(absl::optional<T>* s, const absl::optional<T>& o) {
     if (o) {
       *s = o;
     }
diff --git a/api/bitrate_constraints.h b/api/bitrate_constraints.h
new file mode 100644
index 0000000..98e89c0
--- /dev/null
+++ b/api/bitrate_constraints.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_BITRATE_CONSTRAINTS_H_
+#define API_BITRATE_CONSTRAINTS_H_
+
+#include <algorithm>
+
+namespace webrtc {
+// TODO(srte): BitrateConstraints and BitrateSettings should be merged.
+// Both represent the same kind data, but are using different default
+// initializer and representation of unset values.
+struct BitrateConstraints {
+  int min_bitrate_bps = 0;
+  int start_bitrate_bps = kDefaultStartBitrateBps;
+  int max_bitrate_bps = -1;
+
+ private:
+  static constexpr int kDefaultStartBitrateBps = 300000;
+};
+
+// Like std::min, but considers non-positive values to be unset.
+template <typename T>
+static T MinPositive(T a, T b) {
+  if (a <= 0) {
+    return b;
+  }
+  if (b <= 0) {
+    return a;
+  }
+  return std::min(a, b);
+}
+}  // namespace webrtc
+#endif  // API_BITRATE_CONSTRAINTS_H_
diff --git a/api/candidate.h b/api/candidate.h
index a1f45c2..6e0547b 100644
--- a/api/candidate.h
+++ b/api/candidate.h
@@ -46,14 +46,14 @@
   Candidate(const Candidate&);
   ~Candidate();
 
-  const std::string & id() const { return id_; }
-  void set_id(const std::string & id) { id_ = id; }
+  const std::string& id() const { return id_; }
+  void set_id(const std::string& id) { id_ = id; }
 
   int component() const { return component_; }
   void set_component(int component) { component_ = component; }
 
-  const std::string & protocol() const { return protocol_; }
-  void set_protocol(const std::string & protocol) { protocol_ = protocol; }
+  const std::string& protocol() const { return protocol_; }
+  void set_protocol(const std::string& protocol) { protocol_ = protocol; }
 
   // The protocol used to talk to relay.
   const std::string& relay_protocol() const { return relay_protocol_; }
@@ -61,10 +61,8 @@
     relay_protocol_ = protocol;
   }
 
-  const rtc::SocketAddress & address() const { return address_; }
-  void set_address(const rtc::SocketAddress & address) {
-    address_ = address;
-  }
+  const rtc::SocketAddress& address() const { return address_; }
+  void set_address(const rtc::SocketAddress& address) { address_ = address; }
 
   uint32_t priority() const { return priority_; }
   void set_priority(const uint32_t priority) { priority_ = priority; }
@@ -91,17 +89,17 @@
   }
 
   // TODO(honghaiz): Change to usernameFragment or ufrag.
-  const std::string & username() const { return username_; }
-  void set_username(const std::string & username) { username_ = username; }
+  const std::string& username() const { return username_; }
+  void set_username(const std::string& username) { username_ = username; }
 
-  const std::string & password() const { return password_; }
-  void set_password(const std::string & password) { password_ = password; }
+  const std::string& password() const { return password_; }
+  void set_password(const std::string& password) { password_ = password; }
 
-  const std::string & type() const { return type_; }
-  void set_type(const std::string & type) { type_ = type; }
+  const std::string& type() const { return type_; }
+  void set_type(const std::string& type) { type_ = type; }
 
-  const std::string & network_name() const { return network_name_; }
-  void set_network_name(const std::string & network_name) {
+  const std::string& network_name() const { return network_name_; }
+  void set_network_name(const std::string& network_name) {
     network_name_ = network_name;
   }
 
@@ -127,24 +125,17 @@
   uint16_t network_id() const { return network_id_; }
   void set_network_id(uint16_t network_id) { network_id_ = network_id; }
 
-  const std::string& foundation() const {
-    return foundation_;
-  }
+  const std::string& foundation() const { return foundation_; }
   void set_foundation(const std::string& foundation) {
     foundation_ = foundation;
   }
 
-  const rtc::SocketAddress & related_address() const {
-    return related_address_;
-  }
-  void set_related_address(
-      const rtc::SocketAddress & related_address) {
+  const rtc::SocketAddress& related_address() const { return related_address_; }
+  void set_related_address(const rtc::SocketAddress& related_address) {
     related_address_ = related_address;
   }
   const std::string& tcptype() const { return tcptype_; }
-  void set_tcptype(const std::string& tcptype) {
-    tcptype_ = tcptype;
-  }
+  void set_tcptype(const std::string& tcptype) { tcptype_ = tcptype; }
 
   // The name of the transport channel of this candidate.
   // TODO(phoglund): remove.
@@ -164,13 +155,9 @@
   // given one when looking for a matching candidate to remove.
   bool MatchesForRemoval(const Candidate& c) const;
 
-  std::string ToString() const {
-    return ToStringInternal(false);
-  }
+  std::string ToString() const { return ToStringInternal(false); }
 
-  std::string ToSensitiveString() const {
-    return ToStringInternal(true);
-  }
+  std::string ToSensitiveString() const { return ToStringInternal(true); }
 
   uint32_t GetPriority(uint32_t type_preference,
                        int network_adapter_preference,
diff --git a/api/datachannelinterface.h b/api/datachannelinterface.h
index 4ab7efb..5cbe717 100644
--- a/api/datachannelinterface.h
+++ b/api/datachannelinterface.h
@@ -16,7 +16,6 @@
 
 #include <string>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/copyonwritebuffer.h"
 #include "rtc_base/refcount.h"
@@ -24,7 +23,7 @@
 namespace webrtc {
 
 // C++ version of: https://www.w3.org/TR/webrtc/#idl-def-rtcdatachannelinit
-// TODO(deadbeef): Use rtc::Optional for the "-1 if unset" things.
+// TODO(deadbeef): Use absl::optional for the "-1 if unset" things.
 struct DataChannelInit {
   // Deprecated. Reliability is assumed, and channel will be unreliable if
   // maxRetransmitTime or MaxRetransmits is set.
@@ -62,14 +61,10 @@
 // as binary or text.
 struct DataBuffer {
   DataBuffer(const rtc::CopyOnWriteBuffer& data, bool binary)
-      : data(data),
-        binary(binary) {
-  }
+      : data(data), binary(binary) {}
   // For convenience for unit tests.
   explicit DataBuffer(const std::string& text)
-      : data(text.data(), text.length()),
-        binary(false) {
-  }
+      : data(text.data(), text.length()), binary(false) {}
   size_t size() const { return data.size(); }
 
   rtc::CopyOnWriteBuffer data;
diff --git a/api/dtmfsenderinterface.h b/api/dtmfsenderinterface.h
index 8f0ab71..217f9d2 100644
--- a/api/dtmfsenderinterface.h
+++ b/api/dtmfsenderinterface.h
@@ -67,14 +67,10 @@
   // If InsertDtmf is called on the same object while an existing task for this
   // object to generate DTMF is still running, the previous task is canceled.
   // Returns true on success and false on failure.
-  virtual bool InsertDtmf(const std::string& tones, int duration,
+  virtual bool InsertDtmf(const std::string& tones,
+                          int duration,
                           int inter_tone_gap) = 0;
 
-  // Returns the track given as argument to the constructor. Only exists for
-  // backwards compatibilty; now that DtmfSenders are tied to RtpSenders, it's
-  // no longer relevant.
-  virtual const AudioTrackInterface* track() const = 0;
-
   // Returns the tones remaining to be played out.
   virtual std::string tones() const = 0;
 
diff --git a/api/jsep.h b/api/jsep.h
index 8fd2dac..dbf97f6 100644
--- a/api/jsep.h
+++ b/api/jsep.h
@@ -26,7 +26,7 @@
 #include <string>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "api/rtcerror.h"
 #include "rtc_base/refcount.h"
 
@@ -107,7 +107,7 @@
 // Returns the SdpType from its string form. The string form can be one of the
 // constants defined in SessionDescriptionInterface. Passing in any other string
 // results in nullopt.
-rtc::Optional<SdpType> SdpTypeFromString(const std::string& type_str);
+absl::optional<SdpType> SdpTypeFromString(const std::string& type_str);
 
 // Class representation of an SDP session description.
 //
@@ -205,9 +205,7 @@
   // is deprecated; in order to let clients remove the old version, it has a
   // default implementation. If both versions are unimplemented, the
   // result will be a runtime error (stack overflow). This is intentional.
-  virtual void OnFailure(RTCError error) {
-    OnFailure(error.message());
-  }
+  virtual void OnFailure(RTCError error) { OnFailure(error.message()); }
   virtual void OnFailure(const std::string& error) {
     OnFailure(RTCError(RTCErrorType::INTERNAL_ERROR, std::string(error)));
   }
diff --git a/api/jsepicecandidate.h b/api/jsepicecandidate.h
index dae6121..4801a04 100644
--- a/api/jsepicecandidate.h
+++ b/api/jsepicecandidate.h
@@ -28,7 +28,8 @@
 class JsepIceCandidate : public IceCandidateInterface {
  public:
   JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index);
-  JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index,
+  JsepIceCandidate(const std::string& sdp_mid,
+                   int sdp_mline_index,
                    const cricket::Candidate& candidate);
   ~JsepIceCandidate();
   // |err| may be null.
@@ -39,9 +40,7 @@
 
   virtual std::string sdp_mid() const { return sdp_mid_; }
   virtual int sdp_mline_index() const { return sdp_mline_index_; }
-  virtual const cricket::Candidate& candidate() const {
-    return candidate_;
-  }
+  virtual const cricket::Candidate& candidate() const { return candidate_; }
 
   virtual std::string server_url() const { return candidate_.url(); }
 
@@ -64,9 +63,7 @@
   JsepCandidateCollection(JsepCandidateCollection&& o)
       : candidates_(std::move(o.candidates_)) {}
   ~JsepCandidateCollection();
-  virtual size_t count() const {
-    return candidates_.size();
-  }
+  virtual size_t count() const { return candidates_.size(); }
   virtual bool HasCandidate(const IceCandidateInterface* candidate) const;
   // Adds and takes ownership of the JsepIceCandidate.
   // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is
diff --git a/api/jsepsessiondescription.h b/api/jsepsessiondescription.h
index 70bb277..d70829e 100644
--- a/api/jsepsessiondescription.h
+++ b/api/jsepsessiondescription.h
@@ -41,8 +41,8 @@
   // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is
   // more clear.
   bool Initialize(cricket::SessionDescription* description,
-      const std::string& session_id,
-      const std::string& session_version);
+                  const std::string& session_id,
+                  const std::string& session_version);
 
   virtual cricket::SessionDescription* description() {
     return description_.get();
@@ -50,12 +50,8 @@
   virtual const cricket::SessionDescription* description() const {
     return description_.get();
   }
-  virtual std::string session_id() const {
-    return session_id_;
-  }
-  virtual std::string session_version() const {
-    return session_version_;
-  }
+  virtual std::string session_id() const { return session_id_; }
+  virtual std::string session_version() const { return session_version_; }
   virtual SdpType GetType() const { return type_; }
   virtual std::string type() const { return SdpTypeToString(type_); }
   // Allows changing the type. Used for testing.
diff --git a/api/mediaconstraintsinterface.cc b/api/mediaconstraintsinterface.cc
index 8358644..fb4481f 100644
--- a/api/mediaconstraintsinterface.cc
+++ b/api/mediaconstraintsinterface.cc
@@ -59,11 +59,11 @@
 }
 
 // Converts a constraint (mandatory takes precedence over optional) to an
-// rtc::Optional.
+// absl::optional.
 template <typename T>
 void ConstraintToOptional(const webrtc::MediaConstraintsInterface* constraints,
                           const std::string& key,
-                          rtc::Optional<T>* value_out) {
+                          absl::optional<T>* value_out) {
   T value;
   bool present = FindConstraint<T>(constraints, key, &value, nullptr);
   if (present) {
@@ -89,8 +89,7 @@
 const char MediaConstraintsInterface::kMinFrameRate[] = "minFrameRate";
 
 // Audio constraints.
-const char MediaConstraintsInterface::kEchoCancellation[] =
-    "echoCancellation";
+const char MediaConstraintsInterface::kEchoCancellation[] = "echoCancellation";
 const char MediaConstraintsInterface::kGoogEchoCancellation[] =
     "googEchoCancellation";
 const char MediaConstraintsInterface::kExtendedFilterEchoCancellation[] =
@@ -107,8 +106,7 @@
     "googNoiseSuppression2";
 const char MediaConstraintsInterface::kIntelligibilityEnhancer[] =
     "intelligibilityEnhancer";
-const char MediaConstraintsInterface::kHighpassFilter[] =
-    "googHighpassFilter";
+const char MediaConstraintsInterface::kHighpassFilter[] = "googHighpassFilter";
 const char MediaConstraintsInterface::kTypingNoiseDetection[] =
     "googTypingNoiseDetection";
 const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
@@ -125,11 +123,9 @@
     "OfferToReceiveVideo";
 const char MediaConstraintsInterface::kVoiceActivityDetection[] =
     "VoiceActivityDetection";
-const char MediaConstraintsInterface::kIceRestart[] =
-    "IceRestart";
+const char MediaConstraintsInterface::kIceRestart[] = "IceRestart";
 // Google specific constraint for BUNDLE enable/disable.
-const char MediaConstraintsInterface::kUseRtpMux[] =
-    "googUseRtpMUX";
+const char MediaConstraintsInterface::kUseRtpMux[] = "googUseRtpMUX";
 
 // Below constraints should be used during PeerConnection construction.
 const char MediaConstraintsInterface::kEnableDtlsSrtp[] =
@@ -150,11 +146,11 @@
     "googCpuOveruseDetection";
 const char MediaConstraintsInterface::kPayloadPadding[] = "googPayloadPadding";
 
-
 // Set |value| to the value associated with the first appearance of |key|, or
 // return false if |key| is not found.
 bool MediaConstraintsInterface::Constraints::FindFirst(
-    const std::string& key, std::string* value) const {
+    const std::string& key,
+    std::string* value) const {
   for (Constraints::const_iterator iter = begin(); iter != end(); ++iter) {
     if (iter->key == key) {
       *value = iter->value;
@@ -165,7 +161,8 @@
 }
 
 bool FindConstraint(const MediaConstraintsInterface* constraints,
-                    const std::string& key, bool* value,
+                    const std::string& key,
+                    bool* value,
                     size_t* mandatory_constraints) {
   return ::FindConstraint<bool>(constraints, key, value, mandatory_constraints);
 }
@@ -192,9 +189,9 @@
   }
   FindConstraint(constraints, MediaConstraintsInterface::kEnableDscp,
                  &configuration->media_config.enable_dscp, nullptr);
-  FindConstraint(
-      constraints, MediaConstraintsInterface::kCpuOveruseDetection,
-      &configuration->media_config.video.enable_cpu_adaptation, nullptr);
+  FindConstraint(constraints, MediaConstraintsInterface::kCpuOveruseDetection,
+                 &configuration->media_config.video.enable_cpu_adaptation,
+                 nullptr);
   FindConstraint(constraints, MediaConstraintsInterface::kEnableRtpDataChannels,
                  &configuration->enable_rtp_data_channel, nullptr);
   // Find Suspend Below Min Bitrate constraint.
diff --git a/api/mediaconstraintsinterface.h b/api/mediaconstraintsinterface.h
index 90661b8..54ab706 100644
--- a/api/mediaconstraintsinterface.h
+++ b/api/mediaconstraintsinterface.h
@@ -23,7 +23,7 @@
 #include <string>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "api/peerconnectioninterface.h"
 
 namespace webrtc {
@@ -39,8 +39,7 @@
   struct Constraint {
     Constraint() {}
     Constraint(const std::string& key, const std::string value)
-        : key(key), value(value) {
-    }
+        : key(key), value(value) {}
     std::string key;
     std::string value;
   };
@@ -54,12 +53,12 @@
   // Specified by draft-alvestrand-constraints-resolution-00b
   static const char kMinAspectRatio[];  // minAspectRatio
   static const char kMaxAspectRatio[];  // maxAspectRatio
-  static const char kMaxWidth[];  // maxWidth
-  static const char kMinWidth[];  // minWidth
-  static const char kMaxHeight[];  // maxHeight
-  static const char kMinHeight[];  // minHeight
-  static const char kMaxFrameRate[];  // maxFrameRate
-  static const char kMinFrameRate[];  // minFrameRate
+  static const char kMaxWidth[];        // maxWidth
+  static const char kMinWidth[];        // minWidth
+  static const char kMaxHeight[];       // maxHeight
+  static const char kMinHeight[];       // minHeight
+  static const char kMaxFrameRate[];    // maxFrameRate
+  static const char kMinFrameRate[];    // minFrameRate
 
   // Constraint keys used by a local audio source.
   static const char kEchoCancellation[];  // echoCancellation
@@ -68,15 +67,15 @@
   static const char kGoogEchoCancellation[];  // googEchoCancellation
 
   static const char kExtendedFilterEchoCancellation[];  // googEchoCancellation2
-  static const char kDAEchoCancellation[];  // googDAEchoCancellation
-  static const char kAutoGainControl[];  // googAutoGainControl
-  static const char kExperimentalAutoGainControl[];  // googAutoGainControl2
-  static const char kNoiseSuppression[];  // googNoiseSuppression
+  static const char kDAEchoCancellation[];            // googDAEchoCancellation
+  static const char kAutoGainControl[];               // googAutoGainControl
+  static const char kExperimentalAutoGainControl[];   // googAutoGainControl2
+  static const char kNoiseSuppression[];              // googNoiseSuppression
   static const char kExperimentalNoiseSuppression[];  // googNoiseSuppression2
-  static const char kIntelligibilityEnhancer[];  // intelligibilityEnhancer
-  static const char kHighpassFilter[];  // googHighpassFilter
+  static const char kIntelligibilityEnhancer[];       // intelligibilityEnhancer
+  static const char kHighpassFilter[];                // googHighpassFilter
   static const char kTypingNoiseDetection[];  // googTypingNoiseDetection
-  static const char kAudioMirroring[];  // googAudioMirroring
+  static const char kAudioMirroring[];        // googAudioMirroring
   static const char
       kAudioNetworkAdaptorConfig[];  // goodAudioNetworkAdaptorConfig
 
@@ -85,15 +84,15 @@
 
   // Constraint keys for CreateOffer / CreateAnswer
   // Specified by the W3C PeerConnection spec
-  static const char kOfferToReceiveVideo[];  // OfferToReceiveVideo
-  static const char kOfferToReceiveAudio[];  // OfferToReceiveAudio
+  static const char kOfferToReceiveVideo[];     // OfferToReceiveVideo
+  static const char kOfferToReceiveAudio[];     // OfferToReceiveAudio
   static const char kVoiceActivityDetection[];  // VoiceActivityDetection
-  static const char kIceRestart[];  // IceRestart
+  static const char kIceRestart[];              // IceRestart
   // These keys are google specific.
   static const char kUseRtpMux[];  // googUseRtpMUX
 
   // Constraints values.
-  static const char kValueTrue[];  // true
+  static const char kValueTrue[];   // true
   static const char kValueFalse[];  // false
 
   // PeerConnection constraint keys.
@@ -108,12 +107,12 @@
   static const char kEnableIPv6[];  // googIPv6
   // Temporary constraint to enable suspend below min bitrate feature.
   static const char kEnableVideoSuspendBelowMinBitrate[];
-      // googSuspendBelowMinBitrate
+  // googSuspendBelowMinBitrate
   // Constraint to enable combined audio+video bandwidth estimation.
   static const char kCombinedAudioVideoBwe[];  // googCombinedAudioVideoBwe
-  static const char kScreencastMinBitrate[];  // googScreencastMinBitrate
-  static const char kCpuOveruseDetection[];  // googCpuOveruseDetection
-  static const char kPayloadPadding[];  // googPayloadPadding
+  static const char kScreencastMinBitrate[];   // googScreencastMinBitrate
+  static const char kCpuOveruseDetection[];    // googCpuOveruseDetection
+  static const char kPayloadPadding[];         // googPayloadPadding
 
   // The prefix of internal-only constraints whose JS set values should be
   // stripped by Chrome before passed down to Libjingle.
@@ -126,7 +125,8 @@
 };
 
 bool FindConstraint(const MediaConstraintsInterface* constraints,
-                    const std::string& key, bool* value,
+                    const std::string& key,
+                    bool* value,
                     size_t* mandatory_constraints);
 
 bool FindConstraint(const MediaConstraintsInterface* constraints,
diff --git a/api/mediastreaminterface.h b/api/mediastreaminterface.h
index 2e2cff0..b661351 100644
--- a/api/mediastreaminterface.h
+++ b/api/mediastreaminterface.h
@@ -22,13 +22,13 @@
 #include <string>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "api/video/video_frame.h"
 // TODO(zhihuang): Remove unrelated headers once downstream applications stop
 // relying on them; they were previously transitively included by
 // mediachannel.h, which is no longer a dependency of this file.
-#include "api/videosinkinterface.h"
-#include "api/videosourceinterface.h"
+#include "api/video/video_sink_interface.h"
+#include "api/video/video_source_interface.h"
 #include "modules/audio_processing/include/audio_processing_statistics.h"
 #include "rtc_base/ratetracker.h"
 #include "rtc_base/refcount.h"
@@ -60,12 +60,7 @@
 class MediaSourceInterface : public rtc::RefCountInterface,
                              public NotifierInterface {
  public:
-  enum SourceState {
-    kInitializing,
-    kLive,
-    kEnded,
-    kMuted
-  };
+  enum SourceState { kInitializing, kLive, kEnded, kMuted };
 
   virtual SourceState state() const = 0;
 
@@ -116,9 +111,8 @@
 // on the worker thread via a VideoTrack. A custom implementation of a source
 // can inherit AdaptedVideoTrackSource instead of directly implementing this
 // interface.
-class VideoTrackSourceInterface
-    : public MediaSourceInterface,
-      public rtc::VideoSourceInterface<VideoFrame> {
+class VideoTrackSourceInterface : public MediaSourceInterface,
+                                  public rtc::VideoSourceInterface<VideoFrame> {
  public:
   struct Stats {
     // Original size of captured frame, before video adaptation.
@@ -138,7 +132,7 @@
   // depending on video codec.
   // TODO(perkj): Remove this once denoising is done by the source, and not by
   // the encoder.
-  virtual rtc::Optional<bool> needs_denoising() const = 0;
+  virtual absl::optional<bool> needs_denoising() const = 0;
 
   // Returns false if no stats are available, e.g, for a remote source, or a
   // source which has not seen its first frame yet.
@@ -156,14 +150,13 @@
 // PeerConnectionFactory::CreateVideoTrack can be used for creating a VideoTrack
 // that ensures thread safety and that all methods are called on the right
 // thread.
-class VideoTrackInterface
-    : public MediaStreamTrackInterface,
-      public rtc::VideoSourceInterface<VideoFrame> {
+class VideoTrackInterface : public MediaStreamTrackInterface,
+                            public rtc::VideoSourceInterface<VideoFrame> {
  public:
   // Video track content hint, used to override the source is_screencast
   // property.
-  // See https://crbug.com/653531 and https://github.com/WICG/mst-content-hint.
-  enum class ContentHint { kNone, kFluid, kDetailed };
+  // See https://crbug.com/653531 and https://w3c.github.io/mst-content-hint.
+  enum class ContentHint { kNone, kFluid, kDetailed, kText };
 
   // Register a video sink for this track. Used to connect the track to the
   // underlying video engine.
@@ -276,7 +269,7 @@
  public:
   // TODO(deadbeef): Figure out if the following interface should be const or
   // not.
-  virtual AudioSourceInterface* GetSource() const =  0;
+  virtual AudioSourceInterface* GetSource() const = 0;
 
   // Add/Remove a sink that will receive the audio data from the track.
   virtual void AddSink(AudioTrackSinkInterface* sink) = 0;
@@ -297,10 +290,8 @@
   ~AudioTrackInterface() override = default;
 };
 
-typedef std::vector<rtc::scoped_refptr<AudioTrackInterface> >
-    AudioTrackVector;
-typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> >
-    VideoTrackVector;
+typedef std::vector<rtc::scoped_refptr<AudioTrackInterface> > AudioTrackVector;
+typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> > VideoTrackVector;
 
 // C++ version of https://www.w3.org/TR/mediacapture-streams/#mediastream.
 //
@@ -317,10 +308,10 @@
 
   virtual AudioTrackVector GetAudioTracks() = 0;
   virtual VideoTrackVector GetVideoTracks() = 0;
-  virtual rtc::scoped_refptr<AudioTrackInterface>
-      FindAudioTrack(const std::string& track_id) = 0;
-  virtual rtc::scoped_refptr<VideoTrackInterface>
-      FindVideoTrack(const std::string& track_id) = 0;
+  virtual rtc::scoped_refptr<AudioTrackInterface> FindAudioTrack(
+      const std::string& track_id) = 0;
+  virtual rtc::scoped_refptr<VideoTrackInterface> FindVideoTrack(
+      const std::string& track_id) = 0;
 
   virtual bool AddTrack(AudioTrackInterface* track) = 0;
   virtual bool AddTrack(VideoTrackInterface* track) = 0;
diff --git a/api/mediastreamproxy.h b/api/mediastreamproxy.h
index 3f261db..4c54459 100644
--- a/api/mediastreamproxy.h
+++ b/api/mediastreamproxy.h
@@ -21,22 +21,22 @@
 // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
 // are called on is an implementation detail.
 BEGIN_SIGNALING_PROXY_MAP(MediaStream)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_CONSTMETHOD0(std::string, id)
-  PROXY_METHOD0(AudioTrackVector, GetAudioTracks)
-  PROXY_METHOD0(VideoTrackVector, GetVideoTracks)
-  PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>,
-                FindAudioTrack,
-                const std::string&)
-  PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>,
-                FindVideoTrack,
-                const std::string&)
-  PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*)
-  PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*)
-  PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*)
-  PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*)
-  PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
-  PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_METHOD0(AudioTrackVector, GetAudioTracks)
+PROXY_METHOD0(VideoTrackVector, GetVideoTracks)
+PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>,
+              FindAudioTrack,
+              const std::string&)
+PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>,
+              FindVideoTrack,
+              const std::string&)
+PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*)
+PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*)
+PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*)
+PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
 END_PROXY_MAP()
 
 }  // namespace webrtc
diff --git a/api/mediastreamtrackproxy.h b/api/mediastreamtrackproxy.h
index 57a7695..77b7bad 100644
--- a/api/mediastreamtrackproxy.h
+++ b/api/mediastreamtrackproxy.h
@@ -25,39 +25,39 @@
 // are called on is an implementation detail.
 
 BEGIN_SIGNALING_PROXY_MAP(AudioTrack)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_CONSTMETHOD0(std::string, kind)
-  PROXY_CONSTMETHOD0(std::string, id)
-  PROXY_CONSTMETHOD0(TrackState, state)
-  PROXY_CONSTMETHOD0(bool, enabled)
-  PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource)
-  PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*)
-  PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*)
-  PROXY_METHOD1(bool, GetSignalLevel, int*)
-  PROXY_METHOD0(rtc::scoped_refptr<AudioProcessorInterface>, GetAudioProcessor)
-  PROXY_METHOD1(bool, set_enabled, bool)
-  PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
-  PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(std::string, kind)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(TrackState, state)
+PROXY_CONSTMETHOD0(bool, enabled)
+PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource)
+PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*)
+PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*)
+PROXY_METHOD1(bool, GetSignalLevel, int*)
+PROXY_METHOD0(rtc::scoped_refptr<AudioProcessorInterface>, GetAudioProcessor)
+PROXY_METHOD1(bool, set_enabled, bool)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
 END_PROXY_MAP()
 
 BEGIN_PROXY_MAP(VideoTrack)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_CONSTMETHOD0(std::string, kind)
-  PROXY_CONSTMETHOD0(std::string, id)
-  PROXY_CONSTMETHOD0(TrackState, state)
-  PROXY_CONSTMETHOD0(bool, enabled)
-  PROXY_METHOD1(bool, set_enabled, bool)
-  PROXY_CONSTMETHOD0(ContentHint, content_hint)
-  PROXY_METHOD1(void, set_content_hint, ContentHint)
-  PROXY_WORKER_METHOD2(void,
-                       AddOrUpdateSink,
-                       rtc::VideoSinkInterface<VideoFrame>*,
-                       const rtc::VideoSinkWants&)
-  PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*)
-  PROXY_CONSTMETHOD0(VideoTrackSourceInterface*, GetSource)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(std::string, kind)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(TrackState, state)
+PROXY_CONSTMETHOD0(bool, enabled)
+PROXY_METHOD1(bool, set_enabled, bool)
+PROXY_CONSTMETHOD0(ContentHint, content_hint)
+PROXY_METHOD1(void, set_content_hint, ContentHint)
+PROXY_WORKER_METHOD2(void,
+                     AddOrUpdateSink,
+                     rtc::VideoSinkInterface<VideoFrame>*,
+                     const rtc::VideoSinkWants&)
+PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*)
+PROXY_CONSTMETHOD0(VideoTrackSourceInterface*, GetSource)
 
-  PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
-  PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
 END_PROXY_MAP()
 
 }  // namespace webrtc
diff --git a/api/mediatypes.h b/api/mediatypes.h
index 93ce1a2..f281276 100644
--- a/api/mediatypes.h
+++ b/api/mediatypes.h
@@ -13,13 +13,12 @@
 
 #include <string>
 
+// The cricket and webrtc have separate definitions for what a media type is.
+// They're not compatible. Watch out for this.
+
 namespace cricket {
 
-enum MediaType {
-  MEDIA_TYPE_AUDIO,
-  MEDIA_TYPE_VIDEO,
-  MEDIA_TYPE_DATA
-};
+enum MediaType { MEDIA_TYPE_AUDIO, MEDIA_TYPE_VIDEO, MEDIA_TYPE_DATA };
 
 std::string MediaTypeToString(MediaType type);
 // Aborts on invalid string. Only expected to be used on strings that are
@@ -28,4 +27,10 @@
 
 }  // namespace cricket
 
+namespace webrtc {
+
+enum class MediaType { ANY, AUDIO, VIDEO, DATA };
+
+}  // namespace webrtc
+
 #endif  // API_MEDIATYPES_H_
diff --git a/api/notifier.h b/api/notifier.h
index ceeda4d..e5c61c9 100644
--- a/api/notifier.h
+++ b/api/notifier.h
@@ -23,8 +23,7 @@
 template <class T>
 class Notifier : public T {
  public:
-  Notifier() {
-  }
+  Notifier() {}
 
   virtual void RegisterObserver(ObserverInterface* observer) {
     RTC_DCHECK(observer != nullptr);
diff --git a/api/peerconnectionfactoryproxy.h b/api/peerconnectionfactoryproxy.h
index 7777809..db52083 100644
--- a/api/peerconnectionfactoryproxy.h
+++ b/api/peerconnectionfactoryproxy.h
@@ -24,52 +24,59 @@
 // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
 // are called on is an implementation detail.
 BEGIN_SIGNALING_PROXY_MAP(PeerConnectionFactory)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  // Use the overloads of CreateVideoSource that take raw VideoCapturer
-  // pointers from PeerConnectionFactoryInterface.
-  // TODO(deadbeef): Remove this using statement once those overloads are
-  // removed.
-  using PeerConnectionFactoryInterface::CreateVideoSource;
-  PROXY_METHOD1(void, SetOptions, const Options&)
-  PROXY_METHOD5(rtc::scoped_refptr<PeerConnectionInterface>,
-                CreatePeerConnection,
-                const PeerConnectionInterface::RTCConfiguration&,
-                const MediaConstraintsInterface*,
-                std::unique_ptr<cricket::PortAllocator>,
-                std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
-                PeerConnectionObserver*);
-  PROXY_METHOD4(rtc::scoped_refptr<PeerConnectionInterface>,
-                CreatePeerConnection,
-                const PeerConnectionInterface::RTCConfiguration&,
-                std::unique_ptr<cricket::PortAllocator>,
-                std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
-                PeerConnectionObserver*);
-  PROXY_METHOD2(rtc::scoped_refptr<PeerConnectionInterface>,
-                CreatePeerConnection,
-                const PeerConnectionInterface::RTCConfiguration&,
-                PeerConnectionDependencies);
-  PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>,
-                CreateLocalMediaStream, const std::string&)
-  PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>,
-                CreateAudioSource, const MediaConstraintsInterface*)
-  PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>,
-                CreateAudioSource,
-                const cricket::AudioOptions&)
-  PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>,
-                CreateVideoSource,
-                std::unique_ptr<cricket::VideoCapturer>,
-                const MediaConstraintsInterface*)
-  PROXY_METHOD1(rtc::scoped_refptr<VideoTrackSourceInterface>,
-                CreateVideoSource,
-                std::unique_ptr<cricket::VideoCapturer>)
-  PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>,
-                CreateVideoTrack,
-                const std::string&,
-                VideoTrackSourceInterface*)
-  PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>,
-                CreateAudioTrack, const std::string&,  AudioSourceInterface*)
-  PROXY_METHOD2(bool, StartAecDump, rtc::PlatformFile, int64_t)
-  PROXY_METHOD0(void, StopAecDump)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+// Use the overloads of CreateVideoSource that take raw VideoCapturer
+// pointers from PeerConnectionFactoryInterface.
+// TODO(deadbeef): Remove this using statement once those overloads are
+// removed.
+using PeerConnectionFactoryInterface::CreateVideoSource;
+PROXY_METHOD1(void, SetOptions, const Options&)
+PROXY_METHOD5(rtc::scoped_refptr<PeerConnectionInterface>,
+              CreatePeerConnection,
+              const PeerConnectionInterface::RTCConfiguration&,
+              const MediaConstraintsInterface*,
+              std::unique_ptr<cricket::PortAllocator>,
+              std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
+              PeerConnectionObserver*);
+PROXY_METHOD4(rtc::scoped_refptr<PeerConnectionInterface>,
+              CreatePeerConnection,
+              const PeerConnectionInterface::RTCConfiguration&,
+              std::unique_ptr<cricket::PortAllocator>,
+              std::unique_ptr<rtc::RTCCertificateGeneratorInterface>,
+              PeerConnectionObserver*);
+PROXY_METHOD2(rtc::scoped_refptr<PeerConnectionInterface>,
+              CreatePeerConnection,
+              const PeerConnectionInterface::RTCConfiguration&,
+              PeerConnectionDependencies);
+PROXY_CONSTMETHOD1(webrtc::RtpCapabilities,
+                   GetRtpSenderCapabilities,
+                   cricket::MediaType);
+PROXY_CONSTMETHOD1(webrtc::RtpCapabilities,
+                   GetRtpReceiverCapabilities,
+                   cricket::MediaType);
+PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>,
+              CreateLocalMediaStream,
+              const std::string&)
+PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>,
+              CreateAudioSource,
+              const cricket::AudioOptions&)
+PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>,
+              CreateVideoSource,
+              std::unique_ptr<cricket::VideoCapturer>,
+              const MediaConstraintsInterface*)
+PROXY_METHOD1(rtc::scoped_refptr<VideoTrackSourceInterface>,
+              CreateVideoSource,
+              std::unique_ptr<cricket::VideoCapturer>)
+PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>,
+              CreateVideoTrack,
+              const std::string&,
+              VideoTrackSourceInterface*)
+PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>,
+              CreateAudioTrack,
+              const std::string&,
+              AudioSourceInterface*)
+PROXY_METHOD2(bool, StartAecDump, rtc::PlatformFile, int64_t)
+PROXY_METHOD0(void, StopAecDump)
 END_PROXY_MAP()
 
 }  // namespace webrtc
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index 6e39b4f..90a99a6 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -90,6 +90,8 @@
 #include "api/setremotedescriptionobserverinterface.h"
 #include "api/stats/rtcstatscollectorcallback.h"
 #include "api/statstypes.h"
+#include "api/transport/bitrate_settings.h"
+#include "api/transport/network_control.h"
 #include "api/turncustomizer.h"
 #include "api/umametrics.h"
 #include "logging/rtc_event_log/rtc_event_log_factory_interface.h"
@@ -108,18 +110,19 @@
 #include "rtc_base/rtccertificate.h"
 #include "rtc_base/rtccertificategenerator.h"
 #include "rtc_base/socketaddress.h"
+#include "rtc_base/sslcertificate.h"
 #include "rtc_base/sslstreamadapter.h"
 
 namespace rtc {
 class SSLIdentity;
 class Thread;
-}
+}  // namespace rtc
 
 namespace cricket {
 class MediaEngineInterface;
 class WebRtcVideoDecoderFactory;
 class WebRtcVideoEncoderFactory;
-}
+}  // namespace cricket
 
 namespace webrtc {
 class AudioDeviceModule;
@@ -136,10 +139,8 @@
   virtual size_t count() = 0;
   virtual MediaStreamInterface* at(size_t index) = 0;
   virtual MediaStreamInterface* find(const std::string& label) = 0;
-  virtual MediaStreamTrackInterface* FindAudioTrack(
-      const std::string& id) = 0;
-  virtual MediaStreamTrackInterface* FindVideoTrack(
-      const std::string& id) = 0;
+  virtual MediaStreamTrackInterface* FindAudioTrack(const std::string& id) = 0;
+  virtual MediaStreamTrackInterface* FindVideoTrack(const std::string& id) = 0;
 
  protected:
   // Dtor protected as objects shouldn't be deleted via this interface.
@@ -259,10 +260,7 @@
     kCandidateNetworkPolicyLowCost
   };
 
-  enum ContinualGatheringPolicy {
-    GATHER_ONCE,
-    GATHER_CONTINUALLY
-  };
+  enum ContinualGatheringPolicy { GATHER_ONCE, GATHER_CONTINUALLY };
 
   enum class RTCConfigurationType {
     // A configuration that is safer to use, despite not having the best
@@ -336,6 +334,7 @@
     void set_experiment_cpu_load_estimator(bool enable) {
       media_config.video.experiment_cpu_load_estimator = enable;
     }
+
     static const int kUndefined = -1;
     // Default maximum number of packets in the audio jitter buffer.
     static const int kAudioJitterBufferMaxPackets = 50;
@@ -362,7 +361,7 @@
     // The below fields correspond to constraints from the deprecated
     // constraints interface for constructing a PeerConnection.
     //
-    // rtc::Optional fields can be "missing", in which case the implementation
+    // absl::optional fields can be "missing", in which case the implementation
     // default will be used.
     //////////////////////////////////////////////////////////////////////////
 
@@ -397,15 +396,15 @@
     // Minimum bitrate at which screencast video tracks will be encoded at.
     // This means adding padding bits up to this bitrate, which can help
     // when switching from a static scene to one with motion.
-    rtc::Optional<int> screencast_min_bitrate;
+    absl::optional<int> screencast_min_bitrate;
 
     // Use new combined audio/video bandwidth estimation?
-    rtc::Optional<bool> combined_audio_video_bwe;
+    absl::optional<bool> combined_audio_video_bwe;
 
     // Can be used to disable DTLS-SRTP. This should never be done, but can be
     // useful for testing purposes, for example in setting up a loopback call
     // with a single PeerConnection.
-    rtc::Optional<bool> enable_dtls_srtp;
+    absl::optional<bool> enable_dtls_srtp;
 
     /////////////////////////////////////////////////
     // The below fields are not part of the standard.
@@ -505,29 +504,29 @@
     // 3) ice_check_min_interval defines the minimal interval (equivalently the
     // maximum rate) that overrides the above two intervals when either of them
     // is less.
-    rtc::Optional<int> ice_check_interval_strong_connectivity;
-    rtc::Optional<int> ice_check_interval_weak_connectivity;
-    rtc::Optional<int> ice_check_min_interval;
+    absl::optional<int> ice_check_interval_strong_connectivity;
+    absl::optional<int> ice_check_interval_weak_connectivity;
+    absl::optional<int> ice_check_min_interval;
 
     // The min time period for which a candidate pair must wait for response to
     // connectivity checks before it becomes unwritable. This parameter
     // overrides the default value in the ICE implementation if set.
-    rtc::Optional<int> ice_unwritable_timeout;
+    absl::optional<int> ice_unwritable_timeout;
 
     // The min number of connectivity checks that a candidate pair must sent
     // without receiving response before it becomes unwritable. This parameter
     // overrides the default value in the ICE implementation if set.
-    rtc::Optional<int> ice_unwritable_min_checks;
+    absl::optional<int> ice_unwritable_min_checks;
 
     // The interval in milliseconds at which STUN candidates will resend STUN
     // binding requests to keep NAT bindings open.
-    rtc::Optional<int> stun_candidate_keepalive_interval;
+    absl::optional<int> stun_candidate_keepalive_interval;
 
     // ICE Periodic Regathering
     // If set, WebRTC will periodically create and propose candidates without
     // starting a new ICE generation. The regathering happens continuously with
     // interval specified in milliseconds by the uniform distribution [a, b].
-    rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
+    absl::optional<rtc::IntervalRange> ice_regather_interval_range;
 
     // Optional TurnCustomizer.
     // With this class one can modify outgoing TURN messages.
@@ -539,7 +538,7 @@
     // A candidate pair on a preferred network has a higher precedence in ICE
     // than one on an un-preferred network, regardless of priority or network
     // cost.
-    rtc::Optional<rtc::AdapterType> network_preference;
+    absl::optional<rtc::AdapterType> network_preference;
 
     // Configure the SDP semantics used by this PeerConnection. Note that the
     // WebRTC 1.0 specification requires kUnifiedPlan semantics. The
@@ -564,6 +563,13 @@
     // For all other users, specify kUnifiedPlan.
     SdpSemantics sdp_semantics = SdpSemantics::kPlanB;
 
+    // Actively reset the SRTP parameters whenever the DTLS transports
+    // underneath are reset for every offer/answer negotiation.
+    // This is only intended to be a workaround for crbug.com/835958
+    // WARNING: This would cause RTP/RTCP packets decryption failure if not used
+    // correctly. This flag will be deprecated soon. Do not rely on it.
+    bool active_reset_srtp_params = false;
+
     //
     // Don't forget to update operator== if adding something.
     //
@@ -623,14 +629,12 @@
   // Accessor methods to active local streams.
   // This method is not supported with kUnifiedPlan semantics. Please use
   // GetSenders() instead.
-  virtual rtc::scoped_refptr<StreamCollectionInterface>
-      local_streams() = 0;
+  virtual rtc::scoped_refptr<StreamCollectionInterface> local_streams() = 0;
 
   // Accessor methods to remote streams.
   // This method is not supported with kUnifiedPlan semantics. Please use
   // GetReceivers() instead.
-  virtual rtc::scoped_refptr<StreamCollectionInterface>
-      remote_streams() = 0;
+  virtual rtc::scoped_refptr<StreamCollectionInterface> remote_streams() = 0;
 
   // Add a new MediaStream to be sent on this PeerConnection.
   // Note that a SessionDescription negotiation is needed before the
@@ -662,24 +666,9 @@
   // - INVALID_PARAMETER: |track| is null, has a kind other than audio or video,
   //       or a sender already exists for the track.
   // - INVALID_STATE: The PeerConnection is closed.
-  // TODO(steveanton): Remove default implementation once downstream
-  // implementations have been updated.
   virtual RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
       rtc::scoped_refptr<MediaStreamTrackInterface> track,
-      const std::vector<std::string>& stream_ids) {
-    return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented");
-  }
-  // |streams| indicates which stream ids the track should be associated
-  // with.
-  // TODO(steveanton): Remove this overload once callers have moved to the
-  // signature with stream ids.
-  virtual rtc::scoped_refptr<RtpSenderInterface> AddTrack(
-      MediaStreamTrackInterface* track,
-      std::vector<MediaStreamInterface*> streams) {
-    // Default implementation provided so downstream implementations can remove
-    // this.
-    return nullptr;
-  }
+      const std::vector<std::string>& stream_ids) = 0;
 
   // Remove an RtpSender from this PeerConnection.
   // Returns true on success.
@@ -736,14 +725,6 @@
     return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented");
   }
 
-  // Returns pointer to a DtmfSender on success. Otherwise returns null.
-  //
-  // This API is no longer part of the standard; instead DtmfSenders are
-  // obtained from RtpSenders. Which is what the implementation does; it finds
-  // an RtpSender for |track| and just returns its DtmfSender.
-  virtual rtc::scoped_refptr<DtmfSenderInterface> CreateDtmfSender(
-      AudioTrackInterface* track) = 0;
-
   // TODO(deadbeef): Make these pure virtual once all subclasses implement them.
 
   // Creates a sender without a track. Can be used for "early media"/"warmup"
@@ -979,13 +960,16 @@
   // this method takes a reference. RegisterUMAObserver(nullptr) will release
   // the reference.
   // TODO(deadbeef): Take argument as scoped_refptr?
-  virtual void RegisterUMAObserver(UMAObserver* observer) = 0;
+  //
+  // This method is soon to be deprecated. This no-op default implementation
+  // allows the implementations of the interface to remove this method.
+  virtual void RegisterUMAObserver(UMAObserver* observer) {}
 
   // 0 <= min <= current <= max should hold for set parameters.
   struct BitrateParameters {
-    rtc::Optional<int> min_bitrate_bps;
-    rtc::Optional<int> current_bitrate_bps;
-    rtc::Optional<int> max_bitrate_bps;
+    absl::optional<int> min_bitrate_bps;
+    absl::optional<int> current_bitrate_bps;
+    absl::optional<int> max_bitrate_bps;
   };
 
   // SetBitrate limits the bandwidth allocated for all RTP streams sent by
@@ -994,7 +978,24 @@
   //
   // Setting |current_bitrate_bps| will reset the current bitrate estimate
   // to the provided value.
-  virtual RTCError SetBitrate(const BitrateParameters& bitrate) = 0;
+  virtual RTCError SetBitrate(const BitrateSettings& bitrate) {
+    BitrateParameters bitrate_parameters;
+    bitrate_parameters.min_bitrate_bps = bitrate.min_bitrate_bps;
+    bitrate_parameters.current_bitrate_bps = bitrate.start_bitrate_bps;
+    bitrate_parameters.max_bitrate_bps = bitrate.max_bitrate_bps;
+    return SetBitrate(bitrate_parameters);
+  }
+
+  // TODO(nisse): Deprecated - use version above. These two default
+  // implementations require subclasses to implement one or the other
+  // of the methods.
+  virtual RTCError SetBitrate(const BitrateParameters& bitrate_parameters) {
+    BitrateSettings bitrate;
+    bitrate.min_bitrate_bps = bitrate_parameters.min_bitrate_bps;
+    bitrate.start_bitrate_bps = bitrate_parameters.current_bitrate_bps;
+    bitrate.max_bitrate_bps = bitrate_parameters.max_bitrate_bps;
+    return SetBitrate(bitrate);
+  }
 
   // Sets current strategy. If not set default WebRTC allocator will be used.
   // May be changed during an active session. The strategy
@@ -1080,9 +1081,7 @@
   // Triggered when media is received on a new stream from remote peer.
   virtual void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) {}
 
-  // Triggered when a remote peer close a stream.
-  // Deprecated: This callback will no longer be fired with Unified Plan
-  // semantics.
+  // Triggered when a remote peer closes a stream.
   virtual void OnRemoveStream(rtc::scoped_refptr<MediaStreamInterface> stream) {
   }
 
@@ -1140,14 +1139,13 @@
   virtual void OnTrack(
       rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {}
 
-  // Called when a receiver is completely removed. This is current (Plan B SDP)
-  // behavior that occurs when processing the removal of a remote track, and is
-  // called when the receiver is removed and the track is muted. When Unified
-  // Plan SDP is supported, transceivers can change direction (and receivers
-  // stopped) but receivers are never removed, so this is never called.
+  // Called when signaling indicates that media will no longer be received on a
+  // track.
+  // With Plan B semantics, the given receiver will have been removed from the
+  // PeerConnection and the track muted.
+  // With Unified Plan semantics, the receiver will remain but the transceiver
+  // will have changed direction to either sendonly or inactive.
   // https://w3c.github.io/webrtc-pc/#process-remote-track-removal
-  // TODO(hbos,deadbeef): When Unified Plan SDP is supported and receivers are
-  // no longer removed, deprecate and remove this callback.
   // TODO(hbos,deadbeef): Make pure virtual when all subclasses implement it.
   virtual void OnRemoveTrack(
       rtc::scoped_refptr<RtpReceiverInterface> receiver) {}
@@ -1175,6 +1173,37 @@
   // Optional dependencies
   std::unique_ptr<cricket::PortAllocator> allocator;
   std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator;
+  std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier;
+};
+
+// PeerConnectionFactoryDependencies holds all of the PeerConnectionFactory
+// dependencies. All new dependencies should be added here instead of
+// overloading the function. This simplifies dependency injection and makes it
+// clear which are mandatory and optional. If possible please allow the peer
+// connection factory to take ownership of the dependency by adding a unique_ptr
+// to this structure.
+struct PeerConnectionFactoryDependencies final {
+  PeerConnectionFactoryDependencies() = default;
+  // This object is not copyable or assignable.
+  PeerConnectionFactoryDependencies(const PeerConnectionFactoryDependencies&) =
+      delete;
+  PeerConnectionFactoryDependencies& operator=(
+      const PeerConnectionFactoryDependencies&) = delete;
+  // This object is only moveable.
+  PeerConnectionFactoryDependencies(PeerConnectionFactoryDependencies&&) =
+      default;
+  PeerConnectionFactoryDependencies& operator=(
+      PeerConnectionFactoryDependencies&&) = default;
+
+  // Optional dependencies
+  rtc::Thread* network_thread = nullptr;
+  rtc::Thread* worker_thread = nullptr;
+  rtc::Thread* signaling_thread = nullptr;
+  std::unique_ptr<cricket::MediaEngineInterface> media_engine;
+  std::unique_ptr<CallFactoryInterface> call_factory;
+  std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory;
+  std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory;
+  std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory;
 };
 
 // PeerConnectionFactoryInterface is the factory interface used for creating
@@ -1252,8 +1281,9 @@
       const PeerConnectionInterface::RTCConfiguration& configuration,
       std::unique_ptr<cricket::PortAllocator> allocator,
       std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
-      PeerConnectionObserver* observer) = 0;
-
+      PeerConnectionObserver* observer) {
+    return nullptr;
+  }
   // Deprecated; should use RTCConfiguration for everything that previously
   // used constraints.
   virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
@@ -1261,7 +1291,25 @@
       const MediaConstraintsInterface* constraints,
       std::unique_ptr<cricket::PortAllocator> allocator,
       std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
-      PeerConnectionObserver* observer) = 0;
+      PeerConnectionObserver* observer) {
+    return nullptr;
+  }
+
+  // Returns the capabilities of an RTP sender of type |kind|.
+  // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure.
+  // TODO(orphis): Make pure virtual when all subclasses implement it.
+  virtual RtpCapabilities GetRtpSenderCapabilities(
+      cricket::MediaType kind) const {
+    return {};
+  }
+
+  // Returns the capabilities of an RTP receiver of type |kind|.
+  // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure.
+  // TODO(orphis): Make pure virtual when all subclasses implement it.
+  virtual RtpCapabilities GetRtpReceiverCapabilities(
+      cricket::MediaType kind) const {
+    return {};
+  }
 
   virtual rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream(
       const std::string& stream_id) = 0;
@@ -1270,10 +1318,6 @@
   // |options| decides audio processing settings.
   virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource(
       const cricket::AudioOptions& options) = 0;
-  // Deprecated - use version above.
-  // Can use CopyConstraintsIntoAudioOptions to bridge the gap.
-  virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource(
-      const MediaConstraintsInterface* constraints) = 0;
 
   // Creates a VideoTrackSourceInterface from |capturer|.
   // TODO(deadbeef): We should aim to remove cricket::VideoCapturer from the
@@ -1319,9 +1363,9 @@
       VideoTrackSourceInterface* source) = 0;
 
   // Creates an new AudioTrack. At the moment |source| can be null.
-  virtual rtc::scoped_refptr<AudioTrackInterface>
-      CreateAudioTrack(const std::string& label,
-                       AudioSourceInterface* source) = 0;
+  virtual rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(
+      const std::string& label,
+      AudioSourceInterface* source) = 0;
 
   // Starts AEC dump using existing file. Takes ownership of |file| and passes
   // it on to VoiceEngine (via other objects) immediately, which will take
@@ -1339,7 +1383,7 @@
   // Dtor and ctor protected as objects shouldn't be created or deleted via
   // this interface.
   PeerConnectionFactoryInterface() {}
-  ~PeerConnectionFactoryInterface() {} // NOLINT
+  ~PeerConnectionFactoryInterface() {}  // NOLINT
 };
 
 // Create a new instance of PeerConnectionFactoryInterface.
@@ -1402,6 +1446,8 @@
 // created and used.
 // If |fec_controller_factory| is null, an internal fec controller module will
 // be created and used.
+// If |network_controller_factory| is provided, it will be used if enabled via
+// field trial.
 rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
     rtc::Thread* network_thread,
     rtc::Thread* worker_thread,
@@ -1413,11 +1459,15 @@
     cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
     rtc::scoped_refptr<AudioMixer> audio_mixer,
     rtc::scoped_refptr<AudioProcessing> audio_processing,
-    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory,
+    std::unique_ptr<NetworkControllerFactoryInterface>
+        network_controller_factory = nullptr);
 
 // Create a new instance of PeerConnectionFactoryInterface with optional video
 // codec factories. These video factories represents all video codecs, i.e. no
 // extra internal video codecs will be added.
+// When building WebRTC with rtc_use_builtin_sw_codecs = false, this is the
+// only available CreatePeerConnectionFactory overload.
 rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
     rtc::Thread* network_thread,
     rtc::Thread* worker_thread,
@@ -1512,7 +1562,13 @@
     std::unique_ptr<cricket::MediaEngineInterface> media_engine,
     std::unique_ptr<CallFactoryInterface> call_factory,
     std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory,
-    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory,
+    std::unique_ptr<NetworkControllerFactoryInterface>
+        network_controller_factory = nullptr);
+
+rtc::scoped_refptr<PeerConnectionFactoryInterface>
+CreateModularPeerConnectionFactory(
+    PeerConnectionFactoryDependencies dependencies);
 
 }  // namespace webrtc
 
diff --git a/api/peerconnectionproxy.h b/api/peerconnectionproxy.h
index 9325adc..6855975 100644
--- a/api/peerconnectionproxy.h
+++ b/api/peerconnectionproxy.h
@@ -23,132 +23,125 @@
 // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
 // are called on is an implementation detail.
 BEGIN_SIGNALING_PROXY_MAP(PeerConnection)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams)
-  PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams)
-  PROXY_METHOD1(bool, AddStream, MediaStreamInterface*)
-  PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*)
-  PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
-                AddTrack,
-                rtc::scoped_refptr<MediaStreamTrackInterface>,
-                const std::vector<std::string>&);
-  PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>,
-                AddTrack,
-                MediaStreamTrackInterface*,
-                std::vector<MediaStreamInterface*>)
-  PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*)
-  PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
-                AddTransceiver,
-                rtc::scoped_refptr<MediaStreamTrackInterface>)
-  PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
-                AddTransceiver,
-                rtc::scoped_refptr<MediaStreamTrackInterface>,
-                const RtpTransceiverInit&)
-  PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
-                AddTransceiver,
-                cricket::MediaType)
-  PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
-                AddTransceiver,
-                cricket::MediaType,
-                const RtpTransceiverInit&)
-  PROXY_METHOD1(rtc::scoped_refptr<DtmfSenderInterface>,
-                CreateDtmfSender,
-                AudioTrackInterface*)
-  PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>,
-                CreateSender,
-                const std::string&,
-                const std::string&)
-  PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>,
-                     GetSenders)
-  PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
-                     GetReceivers)
-  PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
-                     GetTransceivers)
-  PROXY_METHOD3(bool,
-                GetStats,
-                StatsObserver*,
-                MediaStreamTrackInterface*,
-                StatsOutputLevel)
-  PROXY_METHOD1(void, GetStats, RTCStatsCollectorCallback*)
-  PROXY_METHOD2(void,
-                GetStats,
-                rtc::scoped_refptr<RtpSenderInterface>,
-                rtc::scoped_refptr<RTCStatsCollectorCallback>);
-  PROXY_METHOD2(void,
-                GetStats,
-                rtc::scoped_refptr<RtpReceiverInterface>,
-                rtc::scoped_refptr<RTCStatsCollectorCallback>);
-  PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>,
-                CreateDataChannel,
-                const std::string&,
-                const DataChannelInit*)
-  PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
-  PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description)
-  PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
-                     pending_local_description)
-  PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
-                     pending_remote_description)
-  PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
-                     current_local_description)
-  PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
-                     current_remote_description)
-  PROXY_METHOD2(void,
-                CreateOffer,
-                CreateSessionDescriptionObserver*,
-                const MediaConstraintsInterface*)
-  PROXY_METHOD2(void,
-                CreateAnswer,
-                CreateSessionDescriptionObserver*,
-                const MediaConstraintsInterface*)
-  PROXY_METHOD2(void,
-                CreateOffer,
-                CreateSessionDescriptionObserver*,
-                const RTCOfferAnswerOptions&)
-  PROXY_METHOD2(void,
-                CreateAnswer,
-                CreateSessionDescriptionObserver*,
-                const RTCOfferAnswerOptions&)
-  PROXY_METHOD2(void,
-                SetLocalDescription,
-                SetSessionDescriptionObserver*,
-                SessionDescriptionInterface*)
-  PROXY_METHOD2(void,
-                SetRemoteDescription,
-                SetSessionDescriptionObserver*,
-                SessionDescriptionInterface*)
-  PROXY_METHOD2(void,
-                SetRemoteDescription,
-                std::unique_ptr<SessionDescriptionInterface>,
-                rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>);
-  PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration);
-  PROXY_METHOD2(bool,
-                SetConfiguration,
-                const PeerConnectionInterface::RTCConfiguration&,
-                RTCError*);
-  PROXY_METHOD1(bool,
-                SetConfiguration,
-                const PeerConnectionInterface::RTCConfiguration&);
-  PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*)
-  PROXY_METHOD1(bool,
-                RemoveIceCandidates,
-                const std::vector<cricket::Candidate>&);
-  PROXY_METHOD1(void, SetAudioPlayout, bool)
-  PROXY_METHOD1(void, SetAudioRecording, bool)
-  PROXY_METHOD1(void, RegisterUMAObserver, UMAObserver*)
-  PROXY_METHOD1(RTCError, SetBitrate, const BitrateParameters&);
-  PROXY_METHOD1(void,
-                SetBitrateAllocationStrategy,
-                std::unique_ptr<rtc::BitrateAllocationStrategy>);
-  PROXY_METHOD0(SignalingState, signaling_state)
-  PROXY_METHOD0(IceConnectionState, ice_connection_state)
-  PROXY_METHOD0(IceGatheringState, ice_gathering_state)
-  PROXY_METHOD2(bool, StartRtcEventLog, rtc::PlatformFile, int64_t)
-  PROXY_METHOD2(bool,
-                StartRtcEventLog,
-                std::unique_ptr<RtcEventLogOutput>,
-                int64_t);
-  PROXY_METHOD0(void, StopRtcEventLog)
-  PROXY_METHOD0(void, Close)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams)
+PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams)
+PROXY_METHOD1(bool, AddStream, MediaStreamInterface*)
+PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*)
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>,
+              AddTrack,
+              rtc::scoped_refptr<MediaStreamTrackInterface>,
+              const std::vector<std::string>&);
+PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*)
+PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+              AddTransceiver,
+              rtc::scoped_refptr<MediaStreamTrackInterface>)
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+              AddTransceiver,
+              rtc::scoped_refptr<MediaStreamTrackInterface>,
+              const RtpTransceiverInit&)
+PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+              AddTransceiver,
+              cricket::MediaType)
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>,
+              AddTransceiver,
+              cricket::MediaType,
+              const RtpTransceiverInit&)
+PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>,
+              CreateSender,
+              const std::string&,
+              const std::string&)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>,
+                   GetSenders)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>,
+                   GetReceivers)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>,
+                   GetTransceivers)
+PROXY_METHOD3(bool,
+              GetStats,
+              StatsObserver*,
+              MediaStreamTrackInterface*,
+              StatsOutputLevel)
+PROXY_METHOD1(void, GetStats, RTCStatsCollectorCallback*)
+PROXY_METHOD2(void,
+              GetStats,
+              rtc::scoped_refptr<RtpSenderInterface>,
+              rtc::scoped_refptr<RTCStatsCollectorCallback>);
+PROXY_METHOD2(void,
+              GetStats,
+              rtc::scoped_refptr<RtpReceiverInterface>,
+              rtc::scoped_refptr<RTCStatsCollectorCallback>);
+PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>,
+              CreateDataChannel,
+              const std::string&,
+              const DataChannelInit*)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+                   pending_local_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+                   pending_remote_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+                   current_local_description)
+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*,
+                   current_remote_description)
+PROXY_METHOD2(void,
+              CreateOffer,
+              CreateSessionDescriptionObserver*,
+              const MediaConstraintsInterface*)
+PROXY_METHOD2(void,
+              CreateAnswer,
+              CreateSessionDescriptionObserver*,
+              const MediaConstraintsInterface*)
+PROXY_METHOD2(void,
+              CreateOffer,
+              CreateSessionDescriptionObserver*,
+              const RTCOfferAnswerOptions&)
+PROXY_METHOD2(void,
+              CreateAnswer,
+              CreateSessionDescriptionObserver*,
+              const RTCOfferAnswerOptions&)
+PROXY_METHOD2(void,
+              SetLocalDescription,
+              SetSessionDescriptionObserver*,
+              SessionDescriptionInterface*)
+PROXY_METHOD2(void,
+              SetRemoteDescription,
+              SetSessionDescriptionObserver*,
+              SessionDescriptionInterface*)
+PROXY_METHOD2(void,
+              SetRemoteDescription,
+              std::unique_ptr<SessionDescriptionInterface>,
+              rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>);
+PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration);
+PROXY_METHOD2(bool,
+              SetConfiguration,
+              const PeerConnectionInterface::RTCConfiguration&,
+              RTCError*);
+PROXY_METHOD1(bool,
+              SetConfiguration,
+              const PeerConnectionInterface::RTCConfiguration&);
+PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*)
+PROXY_METHOD1(bool,
+              RemoveIceCandidates,
+              const std::vector<cricket::Candidate>&);
+PROXY_METHOD1(void, SetAudioPlayout, bool)
+PROXY_METHOD1(void, SetAudioRecording, bool)
+PROXY_METHOD1(void, RegisterUMAObserver, UMAObserver*)
+PROXY_METHOD1(RTCError, SetBitrate, const BitrateSettings&);
+PROXY_METHOD1(void,
+              SetBitrateAllocationStrategy,
+              std::unique_ptr<rtc::BitrateAllocationStrategy>);
+PROXY_METHOD0(SignalingState, signaling_state)
+PROXY_METHOD0(IceConnectionState, ice_connection_state)
+PROXY_METHOD0(IceGatheringState, ice_gathering_state)
+PROXY_METHOD2(bool, StartRtcEventLog, rtc::PlatformFile, int64_t)
+PROXY_METHOD2(bool,
+              StartRtcEventLog,
+              std::unique_ptr<RtcEventLogOutput>,
+              int64_t);
+PROXY_METHOD0(void, StopRtcEventLog)
+PROXY_METHOD0(void, Close)
 END_PROXY_MAP()
 
 }  // namespace webrtc
diff --git a/api/proxy.h b/api/proxy.h
index dd7182e..c8962ef 100644
--- a/api/proxy.h
+++ b/api/proxy.h
@@ -64,8 +64,10 @@
 template <typename R>
 class ReturnType {
  public:
-  template<typename C, typename M>
-  void Invoke(C* c, M m) { r_ = (c->*m)(); }
+  template <typename C, typename M>
+  void Invoke(C* c, M m) {
+    r_ = (c->*m)();
+  }
   template <typename C, typename M, typename T1>
   void Invoke(C* c, M m, T1 a1) {
     r_ = (c->*m)(std::move(a1));
@@ -78,13 +80,22 @@
   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3) {
     r_ = (c->*m)(std::move(a1), std::move(a2), std::move(a3));
   }
-  template<typename C, typename M, typename T1, typename T2, typename T3,
-      typename T4>
+  template <typename C,
+            typename M,
+            typename T1,
+            typename T2,
+            typename T3,
+            typename T4>
   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3, T4 a4) {
     r_ = (c->*m)(std::move(a1), std::move(a2), std::move(a3), std::move(a4));
   }
-  template<typename C, typename M, typename T1, typename T2, typename T3,
-     typename T4, typename T5>
+  template <typename C,
+            typename M,
+            typename T1,
+            typename T2,
+            typename T3,
+            typename T4,
+            typename T5>
   void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
     r_ = (c->*m)(std::move(a1), std::move(a2), std::move(a3), std::move(a4),
                  std::move(a5));
@@ -99,8 +110,10 @@
 template <>
 class ReturnType<void> {
  public:
-  template<typename C, typename M>
-  void Invoke(C* c, M m) { (c->*m)(); }
+  template <typename C, typename M>
+  void Invoke(C* c, M m) {
+    (c->*m)();
+  }
   template <typename C, typename M, typename T1>
   void Invoke(C* c, M m, T1 a1) {
     (c->*m)(std::move(a1));
@@ -119,9 +132,8 @@
 
 namespace internal {
 
-class SynchronousMethodCall
-    : public rtc::MessageData,
-      public rtc::MessageHandler {
+class SynchronousMethodCall : public rtc::MessageData,
+                              public rtc::MessageHandler {
  public:
   explicit SynchronousMethodCall(rtc::MessageHandler* proxy);
   ~SynchronousMethodCall() override;
@@ -138,8 +150,7 @@
 }  // namespace internal
 
 template <typename C, typename R>
-class MethodCall0 : public rtc::Message,
-                    public rtc::MessageHandler {
+class MethodCall0 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)();
   MethodCall0(C* c, Method m) : c_(c), m_(m) {}
@@ -150,7 +161,7 @@
   }
 
  private:
-  void OnMessage(rtc::Message*) {  r_.Invoke(c_, m_); }
+  void OnMessage(rtc::Message*) { r_.Invoke(c_, m_); }
 
   C* c_;
   Method m_;
@@ -158,8 +169,7 @@
 };
 
 template <typename C, typename R>
-class ConstMethodCall0 : public rtc::Message,
-                         public rtc::MessageHandler {
+class ConstMethodCall0 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)() const;
   ConstMethodCall0(C* c, Method m) : c_(c), m_(m) {}
@@ -177,9 +187,8 @@
   ReturnType<R> r_;
 };
 
-template <typename C, typename R,  typename T1>
-class MethodCall1 : public rtc::Message,
-                    public rtc::MessageHandler {
+template <typename C, typename R, typename T1>
+class MethodCall1 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)(T1 a1);
   MethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(std::move(a1)) {}
@@ -198,9 +207,8 @@
   T1 a1_;
 };
 
-template <typename C, typename R,  typename T1>
-class ConstMethodCall1 : public rtc::Message,
-                         public rtc::MessageHandler {
+template <typename C, typename R, typename T1>
+class ConstMethodCall1 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)(T1 a1) const;
   ConstMethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(std::move(a1)) {}
@@ -220,8 +228,7 @@
 };
 
 template <typename C, typename R, typename T1, typename T2>
-class MethodCall2 : public rtc::Message,
-                    public rtc::MessageHandler {
+class MethodCall2 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)(T1 a1, T2 a2);
   MethodCall2(C* c, Method m, T1 a1, T2 a2)
@@ -245,8 +252,7 @@
 };
 
 template <typename C, typename R, typename T1, typename T2, typename T3>
-class MethodCall3 : public rtc::Message,
-                    public rtc::MessageHandler {
+class MethodCall3 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)(T1 a1, T2 a2, T3 a3);
   MethodCall3(C* c, Method m, T1 a1, T2 a2, T3 a3)
@@ -274,10 +280,13 @@
   T3 a3_;
 };
 
-template <typename C, typename R, typename T1, typename T2, typename T3,
-    typename T4>
-class MethodCall4 : public rtc::Message,
-                    public rtc::MessageHandler {
+template <typename C,
+          typename R,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4>
+class MethodCall4 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)(T1 a1, T2 a2, T3 a3, T4 a4);
   MethodCall4(C* c, Method m, T1 a1, T2 a2, T3 a3, T4 a4)
@@ -308,10 +317,14 @@
   T4 a4_;
 };
 
-template <typename C, typename R, typename T1, typename T2, typename T3,
-    typename T4, typename T5>
-class MethodCall5 : public rtc::Message,
-                    public rtc::MessageHandler {
+template <typename C,
+          typename R,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4,
+          typename T5>
+class MethodCall5 : public rtc::Message, public rtc::MessageHandler {
  public:
   typedef R (C::*Method)(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   MethodCall5(C* c, Method m, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
@@ -344,7 +357,6 @@
   T5 a5_;
 };
 
-
 // Helper macros to reduce code duplication.
 #define PROXY_MAP_BOILERPLATE(c)                          \
   template <class INTERNAL_CLASS>                         \
@@ -359,8 +371,12 @@
     const INTERNAL_CLASS* internal() const { return c_; } \
     INTERNAL_CLASS* internal() { return c_; }
 
+// clang-format off
+// clang-format would put the semicolon alone,
+// leading to a presubmit error (cpplint.py)
 #define END_PROXY_MAP() \
   };
+// clang-format on
 
 #define SIGNALING_PROXY_MAP_BOILERPLATE(c)                               \
  protected:                                                              \
diff --git a/api/rtp_headers.h b/api/rtp_headers.h
index c5496b6..ded6c4b 100644
--- a/api/rtp_headers.h
+++ b/api/rtp_headers.h
@@ -13,19 +13,18 @@
 
 #include <stddef.h>
 #include <string.h>
-#include <ostream>
 #include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "api/video/video_content_type.h"
 #include "api/video/video_rotation.h"
 #include "api/video/video_timing.h"
 
+#include "common_types.h"  // NOLINT(build/include)
 #include "rtc_base/checks.h"
 #include "rtc_base/deprecation.h"
-#include "common_types.h"  // NOLINT(build/include)
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
@@ -103,7 +102,7 @@
   bool hasVideoRotation;
   VideoRotation videoRotation;
 
-  // TODO(ilnik): Refactor this and one above to be rtc::Optional() and remove
+  // TODO(ilnik): Refactor this and one above to be absl::optional() and remove
   // a corresponding bool flag.
   bool hasVideoContentType;
   VideoContentType videoContentType;
diff --git a/api/rtpparameters.cc b/api/rtpparameters.cc
index cb9c1cf..5a873de 100644
--- a/api/rtpparameters.cc
+++ b/api/rtpparameters.cc
@@ -10,10 +10,10 @@
 #include "api/rtpparameters.h"
 
 #include <algorithm>
-#include <sstream>
 #include <string>
 
 #include "rtc_base/checks.h"
+#include "rtc_base/strings/string_builder.h"
 
 namespace webrtc {
 
@@ -65,18 +65,22 @@
 RtpCapabilities::RtpCapabilities() {}
 RtpCapabilities::~RtpCapabilities() {}
 
+RtcpParameters::RtcpParameters() {}
+RtcpParameters::~RtcpParameters() {}
+
 RtpParameters::RtpParameters() {}
 RtpParameters::~RtpParameters() {}
 
 std::string RtpExtension::ToString() const {
-  std::stringstream ss;
-  ss << "{uri: " << uri;
-  ss << ", id: " << id;
+  char buf[256];
+  rtc::SimpleStringBuilder sb(buf);
+  sb << "{uri: " << uri;
+  sb << ", id: " << id;
   if (encrypt) {
-    ss << ", encrypt";
+    sb << ", encrypt";
   }
-  ss << '}';
-  return ss.str();
+  sb << '}';
+  return sb.str();
 }
 
 const char RtpExtension::kAudioLevelUri[] =
diff --git a/api/rtpparameters.h b/api/rtpparameters.h
index 12e0419..ba318ca 100644
--- a/api/rtpparameters.h
+++ b/api/rtpparameters.h
@@ -15,8 +15,8 @@
 #include <unordered_map>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/mediatypes.h"
-#include "api/optional.h"
 
 namespace webrtc {
 
@@ -66,9 +66,22 @@
   ENABLED,
 };
 
+// Based on the spec in
+// https://w3c.github.io/webrtc-pc/#idl-def-rtcdegradationpreference.
+// These options are enforced on a best-effort basis. For instance, all of
+// these options may suffer some frame drops in order to avoid queuing.
+// TODO(sprang): Look into possibility of more strictly enforcing the
+// maintain-framerate option.
+// TODO(deadbeef): Default to "balanced", as the spec indicates?
 enum class DegradationPreference {
+  // Don't take any actions based on over-utilization signals. Not part of the
+  // web API.
+  DISABLED,
+  // On over-use, request lower frame rate, possibly causing frame drops.
   MAINTAIN_FRAMERATE,
+  // On over-use, request lower resolution, possibly causing down-scaling.
   MAINTAIN_RESOLUTION,
+  // Try to strike a "pleasing" balance between frame rate or resolution.
   BALANCED,
 };
 
@@ -81,7 +94,7 @@
   // 1. It's an enum instead of a string.
   // 2. Generic NACK feedback is represented by a GENERIC_NACK message type,
   //    rather than an unset "parameter" value.
-  rtc::Optional<RtcpFeedbackMessageType> message_type;
+  absl::optional<RtcpFeedbackMessageType> message_type;
 
   // Constructors for convenience.
   RtcpFeedback();
@@ -112,23 +125,23 @@
   cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO;
 
   // Clock rate in Hertz. If unset, the codec is applicable to any clock rate.
-  rtc::Optional<int> clock_rate;
+  absl::optional<int> clock_rate;
 
   // Default payload type for this codec. Mainly needed for codecs that use
   // that have statically assigned payload types.
-  rtc::Optional<int> preferred_payload_type;
+  absl::optional<int> preferred_payload_type;
 
   // Maximum packetization time supported by an RtpReceiver for this codec.
   // TODO(deadbeef): Not implemented.
-  rtc::Optional<int> max_ptime;
+  absl::optional<int> max_ptime;
 
   // Preferred packetization time for an RtpReceiver or RtpSender of this
   // codec.
   // TODO(deadbeef): Not implemented.
-  rtc::Optional<int> ptime;
+  absl::optional<int> ptime;
 
   // The number of audio channels supported. Unused for video codecs.
-  rtc::Optional<int> num_channels;
+  absl::optional<int> num_channels;
 
   // Feedback mechanisms supported for this codec.
   std::vector<RtcpFeedback> rtcp_feedback;
@@ -191,7 +204,7 @@
   std::string uri;
 
   // Preferred value of ID that goes in the packet.
-  rtc::Optional<int> preferred_id;
+  absl::optional<int> preferred_id;
 
   // If true, it's preferred that the value in the header is encrypted.
   // TODO(deadbeef): Not implemented.
@@ -300,7 +313,7 @@
 struct RtpFecParameters {
   // If unset, a value is chosen by the implementation.
   // Works just like RtpEncodingParameters::ssrc.
-  rtc::Optional<uint32_t> ssrc;
+  absl::optional<uint32_t> ssrc;
 
   FecMechanism mechanism = FecMechanism::RED;
 
@@ -319,7 +332,7 @@
 struct RtpRtxParameters {
   // If unset, a value is chosen by the implementation.
   // Works just like RtpEncodingParameters::ssrc.
-  rtc::Optional<uint32_t> ssrc;
+  absl::optional<uint32_t> ssrc;
 
   // Constructors for convenience.
   RtpRtxParameters();
@@ -340,7 +353,7 @@
   // may change due to an SSRC conflict, in which case the conflict is handled
   // internally without any event. Another way of looking at this is that an
   // unset SSRC acts as a "wildcard" SSRC.
-  rtc::Optional<uint32_t> ssrc;
+  absl::optional<uint32_t> ssrc;
 
   // Can be used to reference a codec in the |codecs| member of the
   // RtpParameters that contains this RtpEncodingParameters. If unset, the
@@ -348,23 +361,23 @@
   // prepare to receive any codec (for a receiver).
   // TODO(deadbeef): Not implemented. Implementation of RtpSender will always
   // choose the first codec from the list.
-  rtc::Optional<int> codec_payload_type;
+  absl::optional<int> codec_payload_type;
 
   // Specifies the FEC mechanism, if set.
   // TODO(deadbeef): Not implemented. Current implementation will use whatever
   // FEC codecs are available, including red+ulpfec.
-  rtc::Optional<RtpFecParameters> fec;
+  absl::optional<RtpFecParameters> fec;
 
   // Specifies the RTX parameters, if set.
   // TODO(deadbeef): Not implemented with PeerConnection senders/receivers.
-  rtc::Optional<RtpRtxParameters> rtx;
+  absl::optional<RtpRtxParameters> rtx;
 
   // Only used for audio. If set, determines whether or not discontinuous
   // transmission will be used, if an available codec supports it. If not
   // set, the implementation default setting will be used.
   // TODO(deadbeef): Not implemented. Current implementation will use a CN
   // codec as long as it's present.
-  rtc::Optional<DtxStatus> dtx;
+  absl::optional<DtxStatus> dtx;
 
   // The relative bitrate priority of this encoding. Currently this is
   // implemented for the entire rtp sender by using the value of the first
@@ -381,39 +394,35 @@
   // creates a ptime for a specific codec, which is later changed in the
   // RtpEncodingParameters by the application.
   // TODO(bugs.webrtc.org/8819): Not implemented.
-  rtc::Optional<int> ptime;
+  absl::optional<int> ptime;
 
   // If set, this represents the Transport Independent Application Specific
   // maximum bandwidth defined in RFC3890. If unset, there is no maximum
   // bitrate. Currently this is implemented for the entire rtp sender by using
   // the value of the first encoding parameter.
   //
-  // TODO(webrtc.bugs.org/8655): Implement this per encoding parameter.
-  // Current implementation for a sender:
-  // The max bitrate is decided by taking the minimum of the first encoding
-  // parameter's max_bitrate_bps and the max bitrate specified by the sdp with
-  // the b=AS attribute. In the case of simulcast video, default values are used
-  // for each simulcast layer, and if there is some bitrate left over from the
-  // sender's max bitrate then it will roll over into the highest quality layer.
-  //
   // Just called "maxBitrate" in ORTC spec.
   //
   // TODO(deadbeef): With ORTC RtpSenders, this currently sets the total
   // bandwidth for the entire bandwidth estimator (audio and video). This is
   // just always how "b=AS" was handled, but it's not correct and should be
   // fixed.
-  rtc::Optional<int> max_bitrate_bps;
+  absl::optional<int> max_bitrate_bps;
+
+  // Specifies the minimum bitrate in bps for video.
+  // TODO(asapersson): Not implemented for ORTC API.
+  absl::optional<int> min_bitrate_bps;
 
   // TODO(deadbeef): Not implemented.
-  rtc::Optional<int> max_framerate;
+  absl::optional<int> max_framerate;
 
   // For video, scale the resolution down by this factor.
   // TODO(deadbeef): Not implemented.
-  double scale_resolution_down_by = 1.0;
+  absl::optional<double> scale_resolution_down_by;
 
   // Scale the framerate down by this factor.
   // TODO(deadbeef): Not implemented.
-  double scale_framerate_down_by = 1.0;
+  absl::optional<double> scale_framerate_down_by;
 
   // For an RtpSender, set to true to cause this encoding to be encoded and
   // sent, and false for it not to be encoded and sent. This allows control
@@ -468,24 +477,24 @@
   int payload_type = 0;
 
   // If unset, the implementation default is used.
-  rtc::Optional<int> clock_rate;
+  absl::optional<int> clock_rate;
 
   // The number of audio channels used. Unset for video codecs. If unset for
   // audio, the implementation default is used.
   // TODO(deadbeef): The "implementation default" part isn't fully implemented.
   // Only defaults to 1, even though some codecs (such as opus) should really
   // default to 2.
-  rtc::Optional<int> num_channels;
+  absl::optional<int> num_channels;
 
   // The maximum packetization time to be used by an RtpSender.
   // If |ptime| is also set, this will be ignored.
   // TODO(deadbeef): Not implemented.
-  rtc::Optional<int> max_ptime;
+  absl::optional<int> max_ptime;
 
   // The packetization time to be used by an RtpSender.
   // If unset, will use any time up to max_ptime.
   // TODO(deadbeef): Not implemented.
-  rtc::Optional<int> ptime;
+  absl::optional<int> ptime;
 
   // Feedback mechanisms to be used for this codec.
   // TODO(deadbeef): Not implemented with PeerConnection senders/receivers.
@@ -498,8 +507,6 @@
   // Contrary to ORTC, these parameters are named using all lowercase strings.
   // This helps make the mapping to SDP simpler, if an application is using
   // SDP. Boolean values are represented by the string "1".
-  //
-  // TODO(deadbeef): Not implemented with PeerConnection senders/receivers.
   std::unordered_map<std::string, std::string> parameters;
 
   bool operator==(const RtpCodecParameters& o) const {
@@ -536,9 +543,40 @@
   bool operator!=(const RtpCapabilities& o) const { return !(*this == o); }
 };
 
-// Note that unlike in ORTC, an RtcpParameters structure is not included in
-// RtpParameters, because our API includes an additional "RtpTransport"
-// abstraction on which RTCP parameters are set.
+struct RtcpParameters final {
+  RtcpParameters();
+  ~RtcpParameters();
+
+  // The SSRC to be used in the "SSRC of packet sender" field. If not set, one
+  // will be chosen by the implementation.
+  // TODO(deadbeef): Not implemented.
+  absl::optional<uint32_t> ssrc;
+
+  // The Canonical Name (CNAME) used by RTCP (e.g. in SDES messages).
+  //
+  // If empty in the construction of the RtpTransport, one will be generated by
+  // the implementation, and returned in GetRtcpParameters. Multiple
+  // RtpTransports created by the same OrtcFactory will use the same generated
+  // CNAME.
+  //
+  // If empty when passed into SetParameters, the CNAME simply won't be
+  // modified.
+  std::string cname;
+
+  // Send reduced-size RTCP?
+  bool reduced_size = false;
+
+  // Send RTCP multiplexed on the RTP transport?
+  // Not used with PeerConnection senders/receivers
+  bool mux = true;
+
+  bool operator==(const RtcpParameters& o) const {
+    return ssrc == o.ssrc && cname == o.cname &&
+           reduced_size == o.reduced_size && mux == o.mux;
+  }
+  bool operator!=(const RtcpParameters& o) const { return !(*this == o); }
+};
+
 struct RtpParameters {
   RtpParameters();
   ~RtpParameters();
@@ -546,7 +584,6 @@
   // Used when calling getParameters/setParameters with a PeerConnection
   // RtpSender, to ensure that outdated parameters are not unintentionally
   // applied successfully.
-  // TODO(deadbeef): Not implemented.
   std::string transaction_id;
 
   // Value to use for MID RTP header extension.
@@ -556,11 +593,15 @@
 
   std::vector<RtpCodecParameters> codecs;
 
-  // TODO(deadbeef): Not implemented with PeerConnection senders/receivers.
   std::vector<RtpHeaderExtensionParameters> header_extensions;
 
   std::vector<RtpEncodingParameters> encodings;
 
+  // Only available with a Peerconnection RtpSender.
+  // In ORTC, our API includes an additional "RtpTransport"
+  // abstraction on which RTCP parameters are set.
+  RtcpParameters rtcp;
+
   // TODO(deadbeef): Not implemented.
   DegradationPreference degradation_preference =
       DegradationPreference::BALANCED;
@@ -568,7 +609,7 @@
   bool operator==(const RtpParameters& o) const {
     return mid == o.mid && codecs == o.codecs &&
            header_extensions == o.header_extensions &&
-           encodings == o.encodings &&
+           encodings == o.encodings && rtcp == o.rtcp &&
            degradation_preference == o.degradation_preference;
   }
   bool operator!=(const RtpParameters& o) const { return !(*this == o); }
diff --git a/api/rtpreceiverinterface.cc b/api/rtpreceiverinterface.cc
index 96815a9..fcdca69 100644
--- a/api/rtpreceiverinterface.cc
+++ b/api/rtpreceiverinterface.cc
@@ -32,6 +32,10 @@
 RtpSource& RtpSource::operator=(const RtpSource&) = default;
 RtpSource::~RtpSource() = default;
 
+std::vector<std::string> RtpReceiverInterface::stream_ids() const {
+  return {};
+}
+
 std::vector<rtc::scoped_refptr<MediaStreamInterface>>
 RtpReceiverInterface::streams() const {
   return {};
diff --git a/api/rtpreceiverinterface.h b/api/rtpreceiverinterface.h
index 0e32eae..b2499b4 100644
--- a/api/rtpreceiverinterface.h
+++ b/api/rtpreceiverinterface.h
@@ -57,8 +57,8 @@
   // The source can be either a contributing source or a synchronization source.
   RtpSourceType source_type() const { return source_type_; }
 
-  rtc::Optional<uint8_t> audio_level() const { return audio_level_; }
-  void set_audio_level(const rtc::Optional<uint8_t>& level) {
+  absl::optional<uint8_t> audio_level() const { return audio_level_; }
+  void set_audio_level(const absl::optional<uint8_t>& level) {
     audio_level_ = level;
   }
 
@@ -71,7 +71,7 @@
   int64_t timestamp_ms_;
   uint32_t source_id_;
   RtpSourceType source_type_;
-  rtc::Optional<uint8_t> audio_level_;
+  absl::optional<uint8_t> audio_level_;
 };
 
 class RtpReceiverObserverInterface {
@@ -93,8 +93,12 @@
   virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0;
   // The list of streams that |track| is associated with. This is the same as
   // the [[AssociatedRemoteMediaStreams]] internal slot in the spec.
-  // https://w3c.github.io/webrtc-pc/#dfn-x%5B%5Bassociatedremotemediastreams%5D%5D
+  // https://w3c.github.io/webrtc-pc/#dfn-associatedremotemediastreams
   // TODO(hbos): Make pure virtual as soon as Chromium's mock implements this.
+  // TODO(https://crbug.com/webrtc/9480): Remove streams() in favor of
+  // stream_ids() as soon as downstream projects are no longer dependent on
+  // stream objects.
+  virtual std::vector<std::string> stream_ids() const;
   virtual std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams() const;
 
   // Audio or video receiver?
@@ -128,17 +132,17 @@
 // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
 // are called on is an implementation detail.
 BEGIN_SIGNALING_PROXY_MAP(RtpReceiver)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
-  PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<MediaStreamInterface>>,
-                     streams)
-  PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
-  PROXY_CONSTMETHOD0(std::string, id)
-  PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
-  PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
-  PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*);
-  PROXY_CONSTMETHOD0(std::vector<RtpSource>, GetSources);
-  END_PROXY_MAP()
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<MediaStreamInterface>>,
+                   streams)
+PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
+PROXY_METHOD1(bool, SetParameters, const RtpParameters&)
+PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*);
+PROXY_CONSTMETHOD0(std::vector<RtpSource>, GetSources);
+END_PROXY_MAP()
 
 }  // namespace webrtc
 
diff --git a/api/rtpsenderinterface.h b/api/rtpsenderinterface.h
index 01279a5..6003aa0 100644
--- a/api/rtpsenderinterface.h
+++ b/api/rtpsenderinterface.h
@@ -23,6 +23,7 @@
 #include "api/proxy.h"
 #include "api/rtcerror.h"
 #include "api/rtpparameters.h"
+#include "rtc_base/deprecation.h"
 #include "rtc_base/refcount.h"
 #include "rtc_base/scoped_ref_ptr.h"
 
@@ -37,7 +38,7 @@
 
   // Returns primary SSRC used by this sender for sending media.
   // Returns 0 if not yet determined.
-  // TODO(deadbeef): Change to rtc::Optional.
+  // TODO(deadbeef): Change to absl::optional.
   // TODO(deadbeef): Remove? With GetParameters this should be redundant.
   virtual uint32_t ssrc() const = 0;
 
@@ -53,9 +54,10 @@
   // tracks.
   virtual std::vector<std::string> stream_ids() const = 0;
 
-  virtual RtpParameters GetParameters() const = 0;
+  virtual RtpParameters GetParameters() = 0;
   // Note that only a subset of the parameters can currently be changed. See
   // rtpparameters.h
+  // The encodings are in increasing quality order for simulcast.
   virtual RTCError SetParameters(const RtpParameters& parameters) = 0;
 
   // Returns null for a video sender.
@@ -69,17 +71,17 @@
 // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
 // are called on is an implementation detail.
 BEGIN_SIGNALING_PROXY_MAP(RtpSender)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*)
-  PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
-  PROXY_CONSTMETHOD0(uint32_t, ssrc)
-  PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
-  PROXY_CONSTMETHOD0(std::string, id)
-  PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
-  PROXY_CONSTMETHOD0(RtpParameters, GetParameters);
-  PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&)
-  PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender);
-  END_PROXY_MAP()
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track)
+PROXY_CONSTMETHOD0(uint32_t, ssrc)
+PROXY_CONSTMETHOD0(cricket::MediaType, media_type)
+PROXY_CONSTMETHOD0(std::string, id)
+PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
+PROXY_METHOD0(RtpParameters, GetParameters);
+PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&)
+PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender);
+END_PROXY_MAP()
 
 }  // namespace webrtc
 
diff --git a/api/rtptransceiverinterface.h b/api/rtptransceiverinterface.h
index 7d2a1df..26f1fdf 100644
--- a/api/rtptransceiverinterface.h
+++ b/api/rtptransceiverinterface.h
@@ -14,8 +14,8 @@
 #include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "api/rtpreceiverinterface.h"
 #include "api/rtpsenderinterface.h"
 #include "rtc_base/refcount.h"
@@ -68,7 +68,7 @@
   // remote descriptions. Before negotiation is complete, the mid value may be
   // null. After rollbacks, the value may change from a non-null value to null.
   // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid
-  virtual rtc::Optional<std::string> mid() const = 0;
+  virtual absl::optional<std::string> mid() const = 0;
 
   // The sender attribute exposes the RtpSender corresponding to the RTP media
   // that may be sent with the transceiver's mid. The sender is always present,
@@ -105,7 +105,16 @@
   // for this transceiver. If this transceiver has never been represented in an
   // offer/answer exchange, or if the transceiver is stopped, the value is null.
   // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection
-  virtual rtc::Optional<RtpTransceiverDirection> current_direction() const = 0;
+  virtual absl::optional<RtpTransceiverDirection> current_direction() const = 0;
+
+  // An internal slot designating for which direction the relevant
+  // PeerConnection events have been fired. This is to ensure that events like
+  // OnAddTrack only get fired once even if the same session description is
+  // applied again.
+  // Exposed in the public interface for use by Chromium.
+  virtual absl::optional<RtpTransceiverDirection> fired_direction() const {
+    return absl::nullopt;
+  }
 
   // The Stop method irreversibly stops the RtpTransceiver. The sender of this
   // transceiver will no longer send, the receiver will no longer receive.
diff --git a/api/statstypes.cc b/api/statstypes.cc
index 49a00bb..ceba28d 100644
--- a/api/statstypes.cc
+++ b/api/statstypes.cc
@@ -98,8 +98,7 @@
   }
 
   std::string ToString() const override {
-    return std::string(InternalTypeToString(type_)) +
-           kSeparator +
+    return std::string(InternalTypeToString(type_)) + kSeparator +
            rtc::ToString<int>(id_);
   }
 
@@ -109,7 +108,8 @@
 
 class IdWithDirection : public TypedId {
  public:
-  IdWithDirection(StatsReport::StatsType type, const std::string& id,
+  IdWithDirection(StatsReport::StatsType type,
+                  const std::string& id,
                   StatsReport::Direction direction)
       : TypedId(type, id), direction_(direction) {}
 
@@ -132,39 +132,34 @@
 class CandidateId : public TypedId {
  public:
   CandidateId(bool local, const std::string& id)
-      : TypedId(local ?
-                    StatsReport::kStatsReportTypeIceLocalCandidate :
-                    StatsReport::kStatsReportTypeIceRemoteCandidate,
-                id) {
-  }
+      : TypedId(local ? StatsReport::kStatsReportTypeIceLocalCandidate
+                      : StatsReport::kStatsReportTypeIceRemoteCandidate,
+                id) {}
 
-  std::string ToString() const override {
-    return "Cand-" + id_;
-  }
+  std::string ToString() const override { return "Cand-" + id_; }
 };
 
 class ComponentId : public StatsReport::IdBase {
  public:
   ComponentId(const std::string& content_name, int component)
-      : ComponentId(StatsReport::kStatsReportTypeComponent, content_name,
-            component) {}
+      : ComponentId(StatsReport::kStatsReportTypeComponent,
+                    content_name,
+                    component) {}
 
   bool Equals(const IdBase& other) const override {
     return IdBase::Equals(other) &&
-        static_cast<const ComponentId&>(other).component_ == component_ &&
-        static_cast<const ComponentId&>(other).content_name_ == content_name_;
+           static_cast<const ComponentId&>(other).component_ == component_ &&
+           static_cast<const ComponentId&>(other).content_name_ ==
+               content_name_;
   }
 
-  std::string ToString() const override {
-    return ToString("Channel-");
-  }
+  std::string ToString() const override { return ToString("Channel-"); }
 
  protected:
-  ComponentId(StatsReport::StatsType type, const std::string& content_name,
+  ComponentId(StatsReport::StatsType type,
+              const std::string& content_name,
               int component)
-      : IdBase(type),
-        content_name_(content_name),
-        component_(component) {}
+      : IdBase(type), content_name_(content_name), component_(component) {}
 
   std::string ToString(const char* prefix) const {
     std::string ret(prefix);
@@ -182,13 +177,14 @@
 class CandidatePairId : public ComponentId {
  public:
   CandidatePairId(const std::string& content_name, int component, int index)
-      : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name,
-            component),
+      : ComponentId(StatsReport::kStatsReportTypeCandidatePair,
+                    content_name,
+                    component),
         index_(index) {}
 
   bool Equals(const IdBase& other) const override {
     return ComponentId::Equals(other) &&
-        static_cast<const CandidatePairId&>(other).index_ == index_;
+           static_cast<const CandidatePairId&>(other).index_ == index_;
   }
 
   std::string ToString() const override {
@@ -207,7 +203,9 @@
 StatsReport::IdBase::IdBase(StatsType type) : type_(type) {}
 StatsReport::IdBase::~IdBase() {}
 
-StatsReport::StatsType StatsReport::IdBase::type() const { return type_; }
+StatsReport::StatsType StatsReport::IdBase::type() const {
+  return type_;
+}
 
 bool StatsReport::IdBase::Equals(const IdBase& other) const {
   return other.type_ == type_;
@@ -316,8 +314,8 @@
 }
 
 bool StatsReport::Value::operator==(int64_t value) const {
-  return type_ == kInt ? value_.int_ == static_cast<int>(value) :
-      (type_ == kInt64 ? value_.int64_ == value : false);
+  return type_ == kInt ? value_.int_ == static_cast<int>(value)
+                       : (type_ == kInt64 ? value_.int64_ == value : false);
 }
 
 bool StatsReport::Value::operator==(bool value) const {
@@ -699,7 +697,9 @@
 
 // static
 StatsReport::Id StatsReport::NewIdWithDirection(
-    StatsType type, const std::string& id, StatsReport::Direction direction) {
+    StatsType type,
+    const std::string& id,
+    StatsReport::Direction direction) {
   return Id(new RefCountedObject<IdWithDirection>(type, id, direction));
 }
 
@@ -709,16 +709,17 @@
 }
 
 // static
-StatsReport::Id StatsReport::NewComponentId(
-    const std::string& content_name, int component) {
+StatsReport::Id StatsReport::NewComponentId(const std::string& content_name,
+                                            int component) {
   return Id(new RefCountedObject<ComponentId>(content_name, component));
 }
 
 // static
-StatsReport::Id StatsReport::NewCandidatePairId(
-    const std::string& content_name, int component, int index) {
-  return Id(new RefCountedObject<CandidatePairId>(
-      content_name, component, index));
+StatsReport::Id StatsReport::NewCandidatePairId(const std::string& content_name,
+                                                int component,
+                                                int index) {
+  return Id(
+      new RefCountedObject<CandidatePairId>(content_name, component, index));
 }
 
 const char* StatsReport::TypeToString() const {
@@ -763,8 +764,7 @@
     values_[name] = ValuePtr(new Value(name, value));
 }
 
-void StatsReport::AddId(StatsReport::StatsValueName name,
-                        const Id& value) {
+void StatsReport::AddId(StatsReport::StatsValueName name, const Id& value) {
   const Value* found = FindValue(name);
   if (!found || !(*found == value))
     values_[name] = ValuePtr(new Value(name, value));
@@ -775,8 +775,7 @@
   return it == values_.end() ? nullptr : it->second.get();
 }
 
-StatsCollection::StatsCollection() {
-}
+StatsCollection::StatsCollection() {}
 
 StatsCollection::~StatsCollection() {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
@@ -816,8 +815,9 @@
 StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   RTC_DCHECK(id.get());
-  Container::iterator it = std::find_if(list_.begin(), list_.end(),
-      [&id](const StatsReport* r)->bool { return r->id()->Equals(id); });
+  Container::iterator it = std::find_if(
+      list_.begin(), list_.end(),
+      [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); });
   if (it != end()) {
     StatsReport* report = new StatsReport((*it)->id());
     delete *it;
@@ -831,8 +831,9 @@
 // will be returned.
 StatsReport* StatsCollection::Find(const StatsReport::Id& id) {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
-  Container::iterator it = std::find_if(list_.begin(), list_.end(),
-      [&id](const StatsReport* r)->bool { return r->id()->Equals(id); });
+  Container::iterator it = std::find_if(
+      list_.begin(), list_.end(),
+      [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); });
   return it == list_.end() ? nullptr : *it;
 }
 
diff --git a/api/statstypes.h b/api/statstypes.h
index 2e3de06..857b1af 100644
--- a/api/statstypes.h
+++ b/api/statstypes.h
@@ -20,7 +20,6 @@
 #include <string>
 #include <vector>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/refcount.h"
 #include "rtc_base/scoped_ref_ptr.h"
@@ -370,13 +369,14 @@
   static Id NewBandwidthEstimationId();
   static Id NewTypedId(StatsType type, const std::string& id);
   static Id NewTypedIntId(StatsType type, int id);
-  static Id NewIdWithDirection(
-      StatsType type, const std::string& id, Direction direction);
+  static Id NewIdWithDirection(StatsType type,
+                               const std::string& id,
+                               Direction direction);
   static Id NewCandidateId(bool local, const std::string& id);
-  static Id NewComponentId(
-      const std::string& content_name, int component);
-  static Id NewCandidatePairId(
-      const std::string& content_name, int component, int index);
+  static Id NewComponentId(const std::string& content_name, int component);
+  static Id NewCandidatePairId(const std::string& content_name,
+                               int component,
+                               int index);
 
   const Id& id() const { return id_; }
   StatsType type() const { return id_->type(); }
diff --git a/api/transport/bitrate_settings.cc b/api/transport/bitrate_settings.cc
new file mode 100644
index 0000000..c72bd82
--- /dev/null
+++ b/api/transport/bitrate_settings.cc
@@ -0,0 +1,19 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/transport/bitrate_settings.h"
+
+namespace webrtc {
+
+BitrateSettings::BitrateSettings() = default;
+BitrateSettings::~BitrateSettings() = default;
+BitrateSettings::BitrateSettings(const BitrateSettings&) = default;
+
+}  // namespace webrtc
diff --git a/api/transport/bitrate_settings.h b/api/transport/bitrate_settings.h
new file mode 100644
index 0000000..77654bc
--- /dev/null
+++ b/api/transport/bitrate_settings.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_TRANSPORT_BITRATE_SETTINGS_H_
+#define API_TRANSPORT_BITRATE_SETTINGS_H_
+
+#include "absl/types/optional.h"
+
+namespace webrtc {
+
+// Configuration of send bitrate. The |start_bitrate_bps| value is
+// used for multiple purposes, both as a prior in the bandwidth
+// estimator, and for initial configuration of the encoder. We may
+// want to create separate apis for those, and use a smaller struct
+// with only the min and max constraints.
+struct BitrateSettings {
+  BitrateSettings();
+  ~BitrateSettings();
+  BitrateSettings(const BitrateSettings&);
+  // 0 <= min <= start <= max should hold for set parameters.
+  absl::optional<int> min_bitrate_bps;
+  absl::optional<int> start_bitrate_bps;
+  absl::optional<int> max_bitrate_bps;
+};
+
+}  // namespace webrtc
+
+#endif  // API_TRANSPORT_BITRATE_SETTINGS_H_
diff --git a/api/transport/network_control.h b/api/transport/network_control.h
new file mode 100644
index 0000000..abd945d
--- /dev/null
+++ b/api/transport/network_control.h
@@ -0,0 +1,93 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_TRANSPORT_NETWORK_CONTROL_H_
+#define API_TRANSPORT_NETWORK_CONTROL_H_
+#include <stdint.h>
+#include <memory>
+
+#include "api/transport/network_types.h"
+
+namespace webrtc {
+
+class TargetTransferRateObserver {
+ public:
+  virtual ~TargetTransferRateObserver() = default;
+  // Called to indicate target transfer rate as well as giving information about
+  // the current estimate of network parameters.
+  virtual void OnTargetTransferRate(TargetTransferRate) = 0;
+};
+
+// Configuration sent to factory create function. The parameters here are
+// optional to use for a network controller implementation.
+struct NetworkControllerConfig {
+  // The initial constraints to start with, these can be changed at any later
+  // time by calls to OnTargetRateConstraints.
+  TargetRateConstraints constraints;
+  // Initial stream specific configuration, these are changed at any later time
+  // by calls to OnStreamsConfig.
+  StreamsConfig stream_based_config;
+  // The initial bandwidth estimate to base target rate on. This should be used
+  // as the basis for initial OnTargetTransferRate and OnPacerConfig callbacks.
+  // Note that starting rate is only provided on construction.
+  DataRate starting_bandwidth = DataRate::Infinity();
+};
+
+// NetworkControllerInterface is implemented by network controllers. A network
+// controller is a class that uses information about network state and traffic
+// to estimate network parameters such as round trip time and bandwidth. Network
+// controllers does not guarantee thread safety, the interface must be used in a
+// non-concurrent fashion.
+class NetworkControllerInterface {
+ public:
+  virtual ~NetworkControllerInterface() = default;
+
+  // Called when network availabilty changes.
+  virtual NetworkControlUpdate OnNetworkAvailability(NetworkAvailability) = 0;
+  // Called when the receiving or sending endpoint changes address.
+  virtual NetworkControlUpdate OnNetworkRouteChange(NetworkRouteChange) = 0;
+  // Called periodically with a periodicy as specified by
+  // NetworkControllerFactoryInterface::GetProcessInterval.
+  virtual NetworkControlUpdate OnProcessInterval(ProcessInterval) = 0;
+  // Called when remotely calculated bitrate is received.
+  virtual NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport) = 0;
+  // Called round trip time has been calculated by protocol specific mechanisms.
+  virtual NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0;
+  // Called when a packet is sent on the network.
+  virtual NetworkControlUpdate OnSentPacket(SentPacket) = 0;
+  // Called when the stream specific configuration has been updated.
+  virtual NetworkControlUpdate OnStreamsConfig(StreamsConfig) = 0;
+  // Called when target transfer rate constraints has been changed.
+  virtual NetworkControlUpdate OnTargetRateConstraints(
+      TargetRateConstraints) = 0;
+  // Called when a protocol specific calculation of packet loss has been made.
+  virtual NetworkControlUpdate OnTransportLossReport(TransportLossReport) = 0;
+  // Called with per packet feedback regarding receive time.
+  virtual NetworkControlUpdate OnTransportPacketsFeedback(
+      TransportPacketsFeedback) = 0;
+};
+
+// NetworkControllerFactoryInterface is an interface for creating a network
+// controller.
+class NetworkControllerFactoryInterface {
+ public:
+  virtual ~NetworkControllerFactoryInterface() = default;
+
+  // Used to create a new network controller, requires an observer to be
+  // provided to handle callbacks.
+  virtual std::unique_ptr<NetworkControllerInterface> Create(
+      NetworkControllerConfig config) = 0;
+  // Returns the interval by which the network controller expects
+  // OnProcessInterval calls.
+  virtual TimeDelta GetProcessInterval() const = 0;
+};
+}  // namespace webrtc
+
+#endif  // API_TRANSPORT_NETWORK_CONTROL_H_
diff --git a/api/transport/network_types.cc b/api/transport/network_types.cc
new file mode 100644
index 0000000..b4c09d4
--- /dev/null
+++ b/api/transport/network_types.cc
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/transport/network_types.h"
+
+namespace webrtc {
+
+StreamsConfig::StreamsConfig() = default;
+StreamsConfig::StreamsConfig(const StreamsConfig&) = default;
+StreamsConfig::~StreamsConfig() = default;
+
+TargetRateConstraints::TargetRateConstraints() = default;
+TargetRateConstraints::TargetRateConstraints(const TargetRateConstraints&) =
+    default;
+TargetRateConstraints::~TargetRateConstraints() = default;
+
+NetworkRouteChange::NetworkRouteChange() = default;
+NetworkRouteChange::NetworkRouteChange(const NetworkRouteChange&) = default;
+NetworkRouteChange::~NetworkRouteChange() = default;
+
+PacketResult::PacketResult() = default;
+PacketResult::PacketResult(const PacketResult& other) = default;
+PacketResult::~PacketResult() = default;
+
+TransportPacketsFeedback::TransportPacketsFeedback() = default;
+TransportPacketsFeedback::TransportPacketsFeedback(
+    const TransportPacketsFeedback& other) = default;
+TransportPacketsFeedback::~TransportPacketsFeedback() = default;
+
+std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo()
+    const {
+  std::vector<PacketResult> res;
+  for (const PacketResult& fb : packet_feedbacks) {
+    if (fb.receive_time.IsFinite() && fb.sent_packet.has_value()) {
+      res.push_back(fb);
+    }
+  }
+  return res;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const {
+  std::vector<PacketResult> res;
+  for (const PacketResult& fb : packet_feedbacks) {
+    if (fb.receive_time.IsInfinite() && fb.sent_packet.has_value()) {
+      res.push_back(fb);
+    }
+  }
+  return res;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback()
+    const {
+  return packet_feedbacks;
+}
+
+NetworkControlUpdate::NetworkControlUpdate() = default;
+NetworkControlUpdate::NetworkControlUpdate(const NetworkControlUpdate&) =
+    default;
+NetworkControlUpdate::~NetworkControlUpdate() = default;
+
+PacedPacketInfo::PacedPacketInfo() = default;
+
+PacedPacketInfo::PacedPacketInfo(int probe_cluster_id,
+                                 int probe_cluster_min_probes,
+                                 int probe_cluster_min_bytes)
+    : probe_cluster_id(probe_cluster_id),
+      probe_cluster_min_probes(probe_cluster_min_probes),
+      probe_cluster_min_bytes(probe_cluster_min_bytes) {}
+
+bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const {
+  return send_bitrate_bps == rhs.send_bitrate_bps &&
+         probe_cluster_id == rhs.probe_cluster_id &&
+         probe_cluster_min_probes == rhs.probe_cluster_min_probes &&
+         probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
+}
+
+}  // namespace webrtc
diff --git a/api/transport/network_types.h b/api/transport/network_types.h
new file mode 100644
index 0000000..a389716
--- /dev/null
+++ b/api/transport/network_types.h
@@ -0,0 +1,200 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_TRANSPORT_NETWORK_TYPES_H_
+#define API_TRANSPORT_NETWORK_TYPES_H_
+#include <stdint.h>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+
+namespace webrtc {
+
+// Configuration
+
+// Use StreamsConfig for information about streams that is required for specific
+// adjustments to the algorithms in network controllers. Especially useful
+// for experiments.
+struct StreamsConfig {
+  StreamsConfig();
+  StreamsConfig(const StreamsConfig&);
+  ~StreamsConfig();
+  Timestamp at_time = Timestamp::Infinity();
+  bool requests_alr_probing = false;
+  absl::optional<double> pacing_factor;
+  absl::optional<DataRate> min_pacing_rate;
+  absl::optional<DataRate> max_padding_rate;
+  absl::optional<DataRate> max_total_allocated_bitrate;
+};
+
+struct TargetRateConstraints {
+  TargetRateConstraints();
+  TargetRateConstraints(const TargetRateConstraints&);
+  ~TargetRateConstraints();
+  Timestamp at_time = Timestamp::Infinity();
+  absl::optional<DataRate> min_data_rate;
+  absl::optional<DataRate> max_data_rate;
+};
+
+// Send side information
+
+struct NetworkAvailability {
+  Timestamp at_time = Timestamp::Infinity();
+  bool network_available = false;
+};
+
+struct NetworkRouteChange {
+  NetworkRouteChange();
+  NetworkRouteChange(const NetworkRouteChange&);
+  ~NetworkRouteChange();
+  Timestamp at_time = Timestamp::Infinity();
+  // The TargetRateConstraints are set here so they can be changed synchronously
+  // when network route changes.
+  TargetRateConstraints constraints;
+  absl::optional<DataRate> starting_rate;
+};
+
+struct PacedPacketInfo {
+  PacedPacketInfo();
+  PacedPacketInfo(int probe_cluster_id,
+                  int probe_cluster_min_probes,
+                  int probe_cluster_min_bytes);
+
+  bool operator==(const PacedPacketInfo& rhs) const;
+
+  // TODO(srte): Move probing info to a separate, optional struct.
+  static constexpr int kNotAProbe = -1;
+  int send_bitrate_bps = -1;
+  int probe_cluster_id = kNotAProbe;
+  int probe_cluster_min_probes = -1;
+  int probe_cluster_min_bytes = -1;
+};
+
+struct SentPacket {
+  Timestamp send_time = Timestamp::Infinity();
+  DataSize size = DataSize::Zero();
+  PacedPacketInfo pacing_info;
+  // Transport independent sequence number, any tracked packet should have a
+  // sequence number that is unique over the whole call and increasing by 1 for
+  // each packet.
+  int64_t sequence_number;
+  // Data in flight when the packet was sent, including the packet.
+  DataSize data_in_flight = DataSize::Zero();
+};
+
+// Transport level feedback
+
+struct RemoteBitrateReport {
+  Timestamp receive_time = Timestamp::Infinity();
+  DataRate bandwidth = DataRate::Infinity();
+};
+
+struct RoundTripTimeUpdate {
+  Timestamp receive_time = Timestamp::Infinity();
+  TimeDelta round_trip_time = TimeDelta::PlusInfinity();
+  bool smoothed = false;
+};
+
+struct TransportLossReport {
+  Timestamp receive_time = Timestamp::Infinity();
+  Timestamp start_time = Timestamp::Infinity();
+  Timestamp end_time = Timestamp::Infinity();
+  uint64_t packets_lost_delta = 0;
+  uint64_t packets_received_delta = 0;
+};
+
+// Packet level feedback
+
+struct PacketResult {
+  PacketResult();
+  PacketResult(const PacketResult&);
+  ~PacketResult();
+
+  absl::optional<SentPacket> sent_packet;
+  Timestamp receive_time = Timestamp::Infinity();
+};
+
+struct TransportPacketsFeedback {
+  TransportPacketsFeedback();
+  TransportPacketsFeedback(const TransportPacketsFeedback& other);
+  ~TransportPacketsFeedback();
+
+  Timestamp feedback_time = Timestamp::Infinity();
+  DataSize data_in_flight = DataSize::Zero();
+  DataSize prior_in_flight = DataSize::Zero();
+  std::vector<PacketResult> packet_feedbacks;
+
+  std::vector<PacketResult> ReceivedWithSendInfo() const;
+  std::vector<PacketResult> LostWithSendInfo() const;
+  std::vector<PacketResult> PacketsWithFeedback() const;
+};
+
+// Network estimation
+
+struct NetworkEstimate {
+  Timestamp at_time = Timestamp::Infinity();
+  DataRate bandwidth = DataRate::Infinity();
+  TimeDelta round_trip_time = TimeDelta::PlusInfinity();
+  TimeDelta bwe_period = TimeDelta::PlusInfinity();
+
+  float loss_rate_ratio = 0;
+};
+
+// Network control
+
+struct PacerConfig {
+  Timestamp at_time = Timestamp::Infinity();
+  // Pacer should send at most data_window data over time_window duration.
+  DataSize data_window = DataSize::Infinity();
+  TimeDelta time_window = TimeDelta::PlusInfinity();
+  // Pacer should send at least pad_window data over time_window duration.
+  DataSize pad_window = DataSize::Zero();
+  DataRate data_rate() const { return data_window / time_window; }
+  DataRate pad_rate() const { return pad_window / time_window; }
+};
+
+struct ProbeClusterConfig {
+  Timestamp at_time = Timestamp::Infinity();
+  DataRate target_data_rate = DataRate::Zero();
+  TimeDelta target_duration = TimeDelta::Zero();
+  int32_t target_probe_count = 0;
+};
+
+struct TargetTransferRate {
+  Timestamp at_time = Timestamp::Infinity();
+  // The estimate on which the target rate is based on.
+  NetworkEstimate network_estimate;
+  DataRate target_rate = DataRate::Zero();
+};
+
+// Contains updates of network controller comand state. Using optionals to
+// indicate whether a member has been updated. The array of probe clusters
+// should be used to send out probes if not empty.
+struct NetworkControlUpdate {
+  NetworkControlUpdate();
+  NetworkControlUpdate(const NetworkControlUpdate&);
+  ~NetworkControlUpdate();
+  absl::optional<DataSize> congestion_window;
+  absl::optional<PacerConfig> pacer_config;
+  std::vector<ProbeClusterConfig> probe_cluster_configs;
+  absl::optional<TargetTransferRate> target_rate;
+};
+
+// Process control
+struct ProcessInterval {
+  Timestamp at_time = Timestamp::Infinity();
+};
+}  // namespace webrtc
+
+#endif  // API_TRANSPORT_NETWORK_TYPES_H_
diff --git a/api/turncustomizer.h b/api/turncustomizer.h
index 517abcc..85c4e77 100644
--- a/api/turncustomizer.h
+++ b/api/turncustomizer.h
@@ -18,7 +18,6 @@
 class StunMessage;
 }  // namespace cricket
 
-
 namespace webrtc {
 
 class TurnCustomizer {
diff --git a/api/umametrics.h b/api/umametrics.h
index f885416..b999b64 100644
--- a/api/umametrics.h
+++ b/api/umametrics.h
@@ -45,6 +45,7 @@
   // The next 2 counters log the value of srtp_err_status_t defined in libsrtp.
   kEnumCounterSrtpUnprotectError,
   kEnumCounterSrtcpUnprotectError,
+  kEnumCounterUsagePattern,
   kPeerConnectionEnumCounterMax
 };
 
@@ -175,13 +176,13 @@
   // number after the highest counter.
   virtual void IncrementEnumCounter(PeerConnectionEnumCounterType type,
                                     int counter,
-                                    int counter_max) {}
+                                    int counter_max) = 0;
 
   // This is used to handle sparse counters like SSL cipher suites.
   // TODO(guoweis): Remove the implementation once the dependency's interface
   // definition is updated.
   virtual void IncrementSparseEnumCounter(PeerConnectionEnumCounterType type,
-                                          int counter);
+                                          int counter) = 0;
 
   virtual void AddHistogramSample(PeerConnectionMetricsName type,
                                   int value) = 0;
diff --git a/api/units/data_rate.cc b/api/units/data_rate.cc
new file mode 100644
index 0000000..4e31d51
--- /dev/null
+++ b/api/units/data_rate.cc
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/data_rate.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+std::string ToString(const DataRate& value) {
+  char buf[64];
+  rtc::SimpleStringBuilder sb(buf);
+  if (value.IsInfinite()) {
+    sb << "inf bps";
+  } else {
+    sb << value.bps() << " bps";
+  }
+  return sb.str();
+}
+}  // namespace webrtc
diff --git a/api/units/data_rate.h b/api/units/data_rate.h
new file mode 100644
index 0000000..c7164e3
--- /dev/null
+++ b/api/units/data_rate.h
@@ -0,0 +1,182 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_UNITS_DATA_RATE_H_
+#define API_UNITS_DATA_RATE_H_
+#include <stdint.h>
+#include <cmath>
+#include <limits>
+#include <string>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+
+namespace webrtc {
+namespace data_rate_impl {
+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
+
+inline int64_t Microbits(const DataSize& size) {
+  constexpr int64_t kMaxBeforeConversion =
+      std::numeric_limits<int64_t>::max() / 8000000;
+  RTC_DCHECK_LE(size.bytes(), kMaxBeforeConversion)
+      << "size is too large to be expressed in microbytes";
+  return size.bytes() * 8000000;
+}
+}  // namespace data_rate_impl
+
+// DataRate is a class that represents a given data rate. This can be used to
+// represent bandwidth, encoding bitrate, etc. The internal storage is bits per
+// second (bps).
+class DataRate {
+ public:
+  DataRate() = delete;
+  static DataRate Zero() { return DataRate(0); }
+  static DataRate Infinity() {
+    return DataRate(data_rate_impl::kPlusInfinityVal);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static DataRate bps(T bits_per_second) {
+    RTC_DCHECK_GE(bits_per_second, 0);
+    RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal);
+    return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second));
+  }
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static DataRate kbps(T kilobits_per_sec) {
+    RTC_DCHECK_GE(kilobits_per_sec, 0);
+    RTC_DCHECK_LT(kilobits_per_sec, data_rate_impl::kPlusInfinityVal / 1000);
+    return DataRate::bps(rtc::dchecked_cast<int64_t>(kilobits_per_sec) * 1000);
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static DataRate bps(T bits_per_second) {
+    if (bits_per_second == std::numeric_limits<T>::infinity()) {
+      return Infinity();
+    } else {
+      RTC_DCHECK(!std::isnan(bits_per_second));
+      RTC_DCHECK_GE(bits_per_second, 0);
+      RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal);
+      return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second));
+    }
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static DataRate kbps(T kilobits_per_sec) {
+    return DataRate::bps(kilobits_per_sec * 1e3);
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type bps() const {
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(bits_per_sec_);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type kbps() const {
+    return rtc::dchecked_cast<T>((bps() + 500) / 1000);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type bps()
+      const {
+    if (IsInfinite()) {
+      return std::numeric_limits<T>::infinity();
+    } else {
+      return bits_per_sec_;
+    }
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type kbps()
+      const {
+    return bps<T>() * 1e-3;
+  }
+
+  bool IsZero() const { return bits_per_sec_ == 0; }
+  bool IsInfinite() const {
+    return bits_per_sec_ == data_rate_impl::kPlusInfinityVal;
+  }
+  bool IsFinite() const { return !IsInfinite(); }
+
+  double operator/(const DataRate& other) const {
+    return bps<double>() / other.bps<double>();
+  }
+  bool operator==(const DataRate& other) const {
+    return bits_per_sec_ == other.bits_per_sec_;
+  }
+  bool operator!=(const DataRate& other) const {
+    return bits_per_sec_ != other.bits_per_sec_;
+  }
+  bool operator<=(const DataRate& other) const {
+    return bits_per_sec_ <= other.bits_per_sec_;
+  }
+  bool operator>=(const DataRate& other) const {
+    return bits_per_sec_ >= other.bits_per_sec_;
+  }
+  bool operator>(const DataRate& other) const {
+    return bits_per_sec_ > other.bits_per_sec_;
+  }
+  bool operator<(const DataRate& other) const {
+    return bits_per_sec_ < other.bits_per_sec_;
+  }
+
+ private:
+  // Bits per second used internally to simplify debugging by making the value
+  // more recognizable.
+  explicit DataRate(int64_t bits_per_second) : bits_per_sec_(bits_per_second) {}
+  int64_t bits_per_sec_;
+};
+
+inline DataRate operator*(const DataRate& rate, const double& scalar) {
+  return DataRate::bps(std::round(rate.bps() * scalar));
+}
+inline DataRate operator*(const double& scalar, const DataRate& rate) {
+  return rate * scalar;
+}
+inline DataRate operator*(const DataRate& rate, const int64_t& scalar) {
+  return DataRate::bps(rate.bps() * scalar);
+}
+inline DataRate operator*(const int64_t& scalar, const DataRate& rate) {
+  return rate * scalar;
+}
+inline DataRate operator*(const DataRate& rate, const int32_t& scalar) {
+  return DataRate::bps(rate.bps() * scalar);
+}
+inline DataRate operator*(const int32_t& scalar, const DataRate& rate) {
+  return rate * scalar;
+}
+
+inline DataRate operator/(const DataSize& size, const TimeDelta& duration) {
+  return DataRate::bps(data_rate_impl::Microbits(size) / duration.us());
+}
+inline TimeDelta operator/(const DataSize& size, const DataRate& rate) {
+  return TimeDelta::us(data_rate_impl::Microbits(size) / rate.bps());
+}
+inline DataSize operator*(const DataRate& rate, const TimeDelta& duration) {
+  int64_t microbits = rate.bps() * duration.us();
+  return DataSize::bytes((microbits + 4000000) / 8000000);
+}
+inline DataSize operator*(const TimeDelta& duration, const DataRate& rate) {
+  return rate * duration;
+}
+
+std::string ToString(const DataRate& value);
+
+}  // namespace webrtc
+
+#endif  // API_UNITS_DATA_RATE_H_
diff --git a/api/units/data_rate_unittest.cc b/api/units/data_rate_unittest.cc
new file mode 100644
index 0000000..073e80e
--- /dev/null
+++ b/api/units/data_rate_unittest.cc
@@ -0,0 +1,125 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/data_rate.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+TEST(DataRateTest, GetBackSameValues) {
+  const int64_t kValue = 123 * 8;
+  EXPECT_EQ(DataRate::bps(kValue).bps(), kValue);
+  EXPECT_EQ(DataRate::kbps(kValue).kbps(), kValue);
+}
+
+TEST(DataRateTest, GetDifferentPrefix) {
+  const int64_t kValue = 123 * 8000;
+  EXPECT_EQ(DataRate::bps(kValue).kbps(), kValue / 1000);
+}
+
+TEST(DataRateTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+  EXPECT_TRUE(DataRate::Zero().IsZero());
+  EXPECT_FALSE(DataRate::bps(kValue).IsZero());
+
+  EXPECT_TRUE(DataRate::Infinity().IsInfinite());
+  EXPECT_FALSE(DataRate::Zero().IsInfinite());
+  EXPECT_FALSE(DataRate::bps(kValue).IsInfinite());
+
+  EXPECT_FALSE(DataRate::Infinity().IsFinite());
+  EXPECT_TRUE(DataRate::bps(kValue).IsFinite());
+  EXPECT_TRUE(DataRate::Zero().IsFinite());
+}
+
+TEST(DataRateTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+  const DataRate small = DataRate::bps(kSmall);
+  const DataRate large = DataRate::bps(kLarge);
+
+  EXPECT_EQ(DataRate::Zero(), DataRate::bps(0));
+  EXPECT_EQ(DataRate::Infinity(), DataRate::Infinity());
+  EXPECT_EQ(small, small);
+  EXPECT_LE(small, small);
+  EXPECT_GE(small, small);
+  EXPECT_NE(small, large);
+  EXPECT_LE(small, large);
+  EXPECT_LT(small, large);
+  EXPECT_GE(large, small);
+  EXPECT_GT(large, small);
+  EXPECT_LT(DataRate::Zero(), small);
+  EXPECT_GT(DataRate::Infinity(), large);
+}
+
+TEST(DataRateTest, ConvertsToAndFromDouble) {
+  const int64_t kValue = 128;
+  const double kDoubleValue = static_cast<double>(kValue);
+  const double kDoubleKbps = kValue * 1e-3;
+  const double kFloatKbps = static_cast<float>(kDoubleKbps);
+
+  EXPECT_EQ(DataRate::bps(kValue).bps<double>(), kDoubleValue);
+  EXPECT_EQ(DataRate::bps(kValue).kbps<double>(), kDoubleKbps);
+  EXPECT_EQ(DataRate::bps(kValue).kbps<float>(), kFloatKbps);
+  EXPECT_EQ(DataRate::bps(kDoubleValue).bps(), kValue);
+  EXPECT_EQ(DataRate::kbps(kDoubleKbps).bps(), kValue);
+
+  const double kInfinity = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(DataRate::Infinity().bps<double>(), kInfinity);
+  EXPECT_TRUE(DataRate::bps(kInfinity).IsInfinite());
+  EXPECT_TRUE(DataRate::kbps(kInfinity).IsInfinite());
+}
+
+TEST(DataRateTest, MathOperations) {
+  const int64_t kValueA = 450;
+  const int64_t kValueB = 267;
+  const DataRate rate_a = DataRate::bps(kValueA);
+  const DataRate rate_b = DataRate::bps(kValueB);
+  const int32_t kInt32Value = 123;
+  const double kFloatValue = 123.0;
+  EXPECT_EQ((rate_a * kValueB).bps(), kValueA * kValueB);
+  EXPECT_EQ((rate_a * kInt32Value).bps(), kValueA * kInt32Value);
+  EXPECT_EQ((rate_a * kFloatValue).bps(), kValueA * kFloatValue);
+
+  EXPECT_EQ(rate_a / rate_b, static_cast<double>(kValueA) / kValueB);
+}
+
+TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) {
+  const int64_t kSeconds = 5;
+  const int64_t kBitsPerSecond = 440;
+  const int64_t kBytes = 44000;
+  const TimeDelta delta_a = TimeDelta::seconds(kSeconds);
+  const DataRate rate_b = DataRate::bps(kBitsPerSecond);
+  const DataSize size_c = DataSize::bytes(kBytes);
+  EXPECT_EQ((delta_a * rate_b).bytes(), kSeconds * kBitsPerSecond / 8);
+  EXPECT_EQ((rate_b * delta_a).bytes(), kSeconds * kBitsPerSecond / 8);
+  EXPECT_EQ((size_c / delta_a).bps(), kBytes * 8 / kSeconds);
+  EXPECT_EQ((size_c / rate_b).seconds(), kBytes * 8 / kBitsPerSecond);
+}
+
+TEST(UnitConversionTest, DivisionFailsOnLargeSize) {
+  // Note that the failure is expected since the current implementation  is
+  // implementated in a way that does not support division of large sizes. If
+  // the implementation is changed, this test can safely be removed.
+  const int64_t kJustSmallEnoughForDivision =
+      std::numeric_limits<int64_t>::max() / 8000000;
+  const DataSize large_size = DataSize::bytes(kJustSmallEnoughForDivision);
+  const DataRate data_rate = DataRate::kbps(100);
+  const TimeDelta time_delta = TimeDelta::ms(100);
+  EXPECT_TRUE((large_size / data_rate).IsFinite());
+  EXPECT_TRUE((large_size / time_delta).IsFinite());
+#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) && RTC_DCHECK_IS_ON
+  const int64_t kToolargeForDivision = kJustSmallEnoughForDivision + 1;
+  const DataSize too_large_size = DataSize::bytes(kToolargeForDivision);
+  EXPECT_DEATH(too_large_size / data_rate, "");
+  EXPECT_DEATH(too_large_size / time_delta, "");
+#endif  // GTEST_HAS_DEATH_TEST && !!defined(WEBRTC_ANDROID) && RTC_DCHECK_IS_ON
+}
+}  // namespace test
+}  // namespace webrtc
diff --git a/api/units/data_size.cc b/api/units/data_size.cc
new file mode 100644
index 0000000..4440f89
--- /dev/null
+++ b/api/units/data_size.cc
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/data_size.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+std::string ToString(const DataSize& value) {
+  char buf[64];
+  rtc::SimpleStringBuilder sb(buf);
+  if (value.IsInfinite()) {
+    sb << "inf bytes";
+  } else {
+    sb << value.bytes() << " bytes";
+  }
+  return sb.str();
+}
+}  // namespace webrtc
diff --git a/api/units/data_size.h b/api/units/data_size.h
new file mode 100644
index 0000000..8c35766
--- /dev/null
+++ b/api/units/data_size.h
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_UNITS_DATA_SIZE_H_
+#define API_UNITS_DATA_SIZE_H_
+
+#include <stdint.h>
+#include <cmath>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace data_size_impl {
+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
+}  // namespace data_size_impl
+
+// DataSize is a class represeting a count of bytes.
+class DataSize {
+ public:
+  DataSize() = delete;
+  static DataSize Zero() { return DataSize(0); }
+  static DataSize Infinity() {
+    return DataSize(data_size_impl::kPlusInfinityVal);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static DataSize bytes(T bytes) {
+    RTC_DCHECK_GE(bytes, 0);
+    RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal);
+    return DataSize(rtc::dchecked_cast<int64_t>(bytes));
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static DataSize bytes(T bytes) {
+    if (bytes == std::numeric_limits<T>::infinity()) {
+      return Infinity();
+    } else {
+      RTC_DCHECK(!std::isnan(bytes));
+      RTC_DCHECK_GE(bytes, 0);
+      RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal);
+      return DataSize(rtc::dchecked_cast<int64_t>(bytes));
+    }
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type bytes() const {
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(bytes_);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type bytes()
+      const {
+    if (IsInfinite()) {
+      return std::numeric_limits<T>::infinity();
+    } else {
+      return bytes_;
+    }
+  }
+
+  bool IsZero() const { return bytes_ == 0; }
+  bool IsInfinite() const { return bytes_ == data_size_impl::kPlusInfinityVal; }
+  bool IsFinite() const { return !IsInfinite(); }
+  DataSize operator-(const DataSize& other) const {
+    return DataSize::bytes(bytes() - other.bytes());
+  }
+  DataSize operator+(const DataSize& other) const {
+    return DataSize::bytes(bytes() + other.bytes());
+  }
+  DataSize& operator-=(const DataSize& other) {
+    bytes_ -= other.bytes();
+    return *this;
+  }
+  DataSize& operator+=(const DataSize& other) {
+    bytes_ += other.bytes();
+    return *this;
+  }
+  double operator/(const DataSize& other) const {
+    return bytes<double>() / other.bytes<double>();
+  }
+  bool operator==(const DataSize& other) const {
+    return bytes_ == other.bytes_;
+  }
+  bool operator!=(const DataSize& other) const {
+    return bytes_ != other.bytes_;
+  }
+  bool operator<=(const DataSize& other) const {
+    return bytes_ <= other.bytes_;
+  }
+  bool operator>=(const DataSize& other) const {
+    return bytes_ >= other.bytes_;
+  }
+  bool operator>(const DataSize& other) const { return bytes_ > other.bytes_; }
+  bool operator<(const DataSize& other) const { return bytes_ < other.bytes_; }
+
+ private:
+  explicit DataSize(int64_t bytes) : bytes_(bytes) {}
+  int64_t bytes_;
+};
+
+inline DataSize operator*(const DataSize& size, const double& scalar) {
+  return DataSize::bytes(std::round(size.bytes() * scalar));
+}
+inline DataSize operator*(const double& scalar, const DataSize& size) {
+  return size * scalar;
+}
+inline DataSize operator*(const DataSize& size, const int64_t& scalar) {
+  return DataSize::bytes(size.bytes() * scalar);
+}
+inline DataSize operator*(const int64_t& scalar, const DataSize& size) {
+  return size * scalar;
+}
+inline DataSize operator*(const DataSize& size, const int32_t& scalar) {
+  return DataSize::bytes(size.bytes() * scalar);
+}
+inline DataSize operator*(const int32_t& scalar, const DataSize& size) {
+  return size * scalar;
+}
+inline DataSize operator/(const DataSize& size, const int64_t& scalar) {
+  return DataSize::bytes(size.bytes() / scalar);
+}
+
+std::string ToString(const DataSize& value);
+
+}  // namespace webrtc
+
+#endif  // API_UNITS_DATA_SIZE_H_
diff --git a/api/units/data_size_unittest.cc b/api/units/data_size_unittest.cc
new file mode 100644
index 0000000..7747258
--- /dev/null
+++ b/api/units/data_size_unittest.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/data_size.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+
+TEST(DataSizeTest, GetBackSameValues) {
+  const int64_t kValue = 123 * 8;
+  EXPECT_EQ(DataSize::bytes(kValue).bytes(), kValue);
+}
+
+TEST(DataSizeTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+  EXPECT_TRUE(DataSize::Zero().IsZero());
+  EXPECT_FALSE(DataSize::bytes(kValue).IsZero());
+
+  EXPECT_TRUE(DataSize::Infinity().IsInfinite());
+  EXPECT_FALSE(DataSize::Zero().IsInfinite());
+  EXPECT_FALSE(DataSize::bytes(kValue).IsInfinite());
+
+  EXPECT_FALSE(DataSize::Infinity().IsFinite());
+  EXPECT_TRUE(DataSize::bytes(kValue).IsFinite());
+  EXPECT_TRUE(DataSize::Zero().IsFinite());
+}
+
+TEST(DataSizeTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+  const DataSize small = DataSize::bytes(kSmall);
+  const DataSize large = DataSize::bytes(kLarge);
+
+  EXPECT_EQ(DataSize::Zero(), DataSize::bytes(0));
+  EXPECT_EQ(DataSize::Infinity(), DataSize::Infinity());
+  EXPECT_EQ(small, small);
+  EXPECT_LE(small, small);
+  EXPECT_GE(small, small);
+  EXPECT_NE(small, large);
+  EXPECT_LE(small, large);
+  EXPECT_LT(small, large);
+  EXPECT_GE(large, small);
+  EXPECT_GT(large, small);
+  EXPECT_LT(DataSize::Zero(), small);
+  EXPECT_GT(DataSize::Infinity(), large);
+}
+
+TEST(DataSizeTest, ConvertsToAndFromDouble) {
+  const int64_t kValue = 128;
+  const double kDoubleValue = static_cast<double>(kValue);
+
+  EXPECT_EQ(DataSize::bytes(kValue).bytes<double>(), kDoubleValue);
+  EXPECT_EQ(DataSize::bytes(kDoubleValue).bytes(), kValue);
+
+  const double kInfinity = std::numeric_limits<double>::infinity();
+  EXPECT_EQ(DataSize::Infinity().bytes<double>(), kInfinity);
+  EXPECT_TRUE(DataSize::bytes(kInfinity).IsInfinite());
+}
+
+TEST(DataSizeTest, MathOperations) {
+  const int64_t kValueA = 450;
+  const int64_t kValueB = 267;
+  const DataSize size_a = DataSize::bytes(kValueA);
+  const DataSize size_b = DataSize::bytes(kValueB);
+  EXPECT_EQ((size_a + size_b).bytes(), kValueA + kValueB);
+  EXPECT_EQ((size_a - size_b).bytes(), kValueA - kValueB);
+
+  const int32_t kInt32Value = 123;
+  const double kFloatValue = 123.0;
+  EXPECT_EQ((size_a * kValueB).bytes(), kValueA * kValueB);
+  EXPECT_EQ((size_a * kInt32Value).bytes(), kValueA * kInt32Value);
+  EXPECT_EQ((size_a * kFloatValue).bytes(), kValueA * kFloatValue);
+
+  EXPECT_EQ((size_a / 10).bytes(), kValueA / 10);
+  EXPECT_EQ(size_a / size_b, static_cast<double>(kValueA) / kValueB);
+
+  DataSize mutable_size = DataSize::bytes(kValueA);
+  mutable_size += size_b;
+  EXPECT_EQ(mutable_size.bytes(), kValueA + kValueB);
+  mutable_size -= size_a;
+  EXPECT_EQ(mutable_size.bytes(), kValueB);
+}
+}  // namespace test
+}  // namespace webrtc
diff --git a/api/units/time_delta.cc b/api/units/time_delta.cc
new file mode 100644
index 0000000..398df77
--- /dev/null
+++ b/api/units/time_delta.cc
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/time_delta.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+std::string ToString(const TimeDelta& value) {
+  char buf[64];
+  rtc::SimpleStringBuilder sb(buf);
+  if (value.IsPlusInfinity()) {
+    sb << "+inf ms";
+  } else if (value.IsMinusInfinity()) {
+    sb << "-inf ms";
+  } else {
+    sb << value.ms() << " ms";
+  }
+  return sb.str();
+}
+}  // namespace webrtc
diff --git a/api/units/time_delta.h b/api/units/time_delta.h
new file mode 100644
index 0000000..0f99e80
--- /dev/null
+++ b/api/units/time_delta.h
@@ -0,0 +1,227 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_UNITS_TIME_DELTA_H_
+#define API_UNITS_TIME_DELTA_H_
+
+#include <stdint.h>
+#include <cmath>
+#include <limits>
+#include <string>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace timedelta_impl {
+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
+constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
+}  // namespace timedelta_impl
+
+// TimeDelta represents the difference between two timestamps. Commonly this can
+// be a duration. However since two Timestamps are not guaranteed to have the
+// same epoch (they might come from different computers, making exact
+// synchronisation infeasible), the duration covered by a TimeDelta can be
+// undefined. To simplify usage, it can be constructed and converted to
+// different units, specifically seconds (s), milliseconds (ms) and
+// microseconds (us).
+class TimeDelta {
+ public:
+  TimeDelta() = delete;
+  static TimeDelta Zero() { return TimeDelta(0); }
+  static TimeDelta PlusInfinity() {
+    return TimeDelta(timedelta_impl::kPlusInfinityVal);
+  }
+  static TimeDelta MinusInfinity() {
+    return TimeDelta(timedelta_impl::kMinusInfinityVal);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static TimeDelta seconds(T seconds) {
+    RTC_DCHECK_GT(seconds, timedelta_impl::kMinusInfinityVal / 1000000);
+    RTC_DCHECK_LT(seconds, timedelta_impl::kPlusInfinityVal / 1000000);
+    return TimeDelta(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
+  }
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static TimeDelta ms(T milliseconds) {
+    RTC_DCHECK_GT(milliseconds, timedelta_impl::kMinusInfinityVal / 1000);
+    RTC_DCHECK_LT(milliseconds, timedelta_impl::kPlusInfinityVal / 1000);
+    return TimeDelta(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
+  }
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static TimeDelta us(T microseconds) {
+    RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
+    RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
+    return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static TimeDelta seconds(T seconds) {
+    return TimeDelta::us(seconds * 1e6);
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static TimeDelta ms(T milliseconds) {
+    return TimeDelta::us(milliseconds * 1e3);
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static TimeDelta us(T microseconds) {
+    if (microseconds == std::numeric_limits<T>::infinity()) {
+      return PlusInfinity();
+    } else if (microseconds == -std::numeric_limits<T>::infinity()) {
+      return MinusInfinity();
+    } else {
+      RTC_DCHECK(!std::isnan(microseconds));
+      RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
+      RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
+      return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
+    }
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
+    return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500000 : -500000)) /
+                                 1000000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
+    return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500 : -500)) / 1000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(microseconds_);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type ns() const {
+    RTC_DCHECK_GE(us(), std::numeric_limits<T>::min() / 1000);
+    RTC_DCHECK_LE(us(), std::numeric_limits<T>::max() / 1000);
+    return rtc::dchecked_cast<T>(us() * 1000);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
+      const {
+    return us<T>() * 1e-6;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
+      const {
+    return us<T>() * 1e-3;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
+      const {
+    if (IsPlusInfinity()) {
+      return std::numeric_limits<T>::infinity();
+    } else if (IsMinusInfinity()) {
+      return -std::numeric_limits<T>::infinity();
+    } else {
+      return microseconds_;
+    }
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type ns()
+      const {
+    return us<T>() * 1e3;
+  }
+
+  TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
+  bool IsZero() const { return microseconds_ == 0; }
+  bool IsFinite() const { return !IsInfinite(); }
+  bool IsInfinite() const {
+    return microseconds_ == timedelta_impl::kPlusInfinityVal ||
+           microseconds_ == timedelta_impl::kMinusInfinityVal;
+  }
+  bool IsPlusInfinity() const {
+    return microseconds_ == timedelta_impl::kPlusInfinityVal;
+  }
+  bool IsMinusInfinity() const {
+    return microseconds_ == timedelta_impl::kMinusInfinityVal;
+  }
+  TimeDelta operator+(const TimeDelta& other) const {
+    return TimeDelta::us(us() + other.us());
+  }
+  TimeDelta operator-(const TimeDelta& other) const {
+    return TimeDelta::us(us() - other.us());
+  }
+  TimeDelta& operator-=(const TimeDelta& other) {
+    microseconds_ -= other.us();
+    return *this;
+  }
+  TimeDelta& operator+=(const TimeDelta& other) {
+    microseconds_ += other.us();
+    return *this;
+  }
+  double operator/(const TimeDelta& other) const {
+    return us<double>() / other.us<double>();
+  }
+  bool operator==(const TimeDelta& other) const {
+    return microseconds_ == other.microseconds_;
+  }
+  bool operator!=(const TimeDelta& other) const {
+    return microseconds_ != other.microseconds_;
+  }
+  bool operator<=(const TimeDelta& other) const {
+    return microseconds_ <= other.microseconds_;
+  }
+  bool operator>=(const TimeDelta& other) const {
+    return microseconds_ >= other.microseconds_;
+  }
+  bool operator>(const TimeDelta& other) const {
+    return microseconds_ > other.microseconds_;
+  }
+  bool operator<(const TimeDelta& other) const {
+    return microseconds_ < other.microseconds_;
+  }
+
+ private:
+  explicit TimeDelta(int64_t us) : microseconds_(us) {}
+  int64_t microseconds_;
+};
+
+inline TimeDelta operator*(const TimeDelta& delta, const double& scalar) {
+  return TimeDelta::us(std::round(delta.us() * scalar));
+}
+inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) {
+  return delta * scalar;
+}
+inline TimeDelta operator*(const TimeDelta& delta, const int64_t& scalar) {
+  return TimeDelta::us(delta.us() * scalar);
+}
+inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) {
+  return delta * scalar;
+}
+inline TimeDelta operator*(const TimeDelta& delta, const int32_t& scalar) {
+  return TimeDelta::us(delta.us() * scalar);
+}
+inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) {
+  return delta * scalar;
+}
+
+inline TimeDelta operator/(const TimeDelta& delta, const int64_t& scalar) {
+  return TimeDelta::us(delta.us() / scalar);
+}
+
+std::string ToString(const TimeDelta& value);
+}  // namespace webrtc
+
+#endif  // API_UNITS_TIME_DELTA_H_
diff --git a/api/units/time_delta_unittest.cc b/api/units/time_delta_unittest.cc
new file mode 100644
index 0000000..94a27f2
--- /dev/null
+++ b/api/units/time_delta_unittest.cc
@@ -0,0 +1,149 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/time_delta.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+
+TEST(TimeDeltaTest, GetBackSameValues) {
+  const int64_t kValue = 499;
+  for (int sign = -1; sign <= 1; ++sign) {
+    int64_t value = kValue * sign;
+    EXPECT_EQ(TimeDelta::ms(value).ms(), value);
+    EXPECT_EQ(TimeDelta::us(value).us(), value);
+    EXPECT_EQ(TimeDelta::seconds(value).seconds(), value);
+    EXPECT_EQ(TimeDelta::seconds(value).seconds(), value);
+  }
+  EXPECT_EQ(TimeDelta::Zero().us(), 0);
+}
+
+TEST(TimeDeltaTest, GetDifferentPrefix) {
+  const int64_t kValue = 3000000;
+  EXPECT_EQ(TimeDelta::us(kValue).seconds(), kValue / 1000000);
+  EXPECT_EQ(TimeDelta::ms(kValue).seconds(), kValue / 1000);
+  EXPECT_EQ(TimeDelta::us(kValue).ms(), kValue / 1000);
+
+  EXPECT_EQ(TimeDelta::ms(kValue).us(), kValue * 1000);
+  EXPECT_EQ(TimeDelta::seconds(kValue).ms(), kValue * 1000);
+  EXPECT_EQ(TimeDelta::seconds(kValue).us(), kValue * 1000000);
+}
+
+TEST(TimeDeltaTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+  EXPECT_TRUE(TimeDelta::Zero().IsZero());
+  EXPECT_FALSE(TimeDelta::ms(kValue).IsZero());
+
+  EXPECT_TRUE(TimeDelta::PlusInfinity().IsInfinite());
+  EXPECT_TRUE(TimeDelta::MinusInfinity().IsInfinite());
+  EXPECT_FALSE(TimeDelta::Zero().IsInfinite());
+  EXPECT_FALSE(TimeDelta::ms(-kValue).IsInfinite());
+  EXPECT_FALSE(TimeDelta::ms(kValue).IsInfinite());
+
+  EXPECT_FALSE(TimeDelta::PlusInfinity().IsFinite());
+  EXPECT_FALSE(TimeDelta::MinusInfinity().IsFinite());
+  EXPECT_TRUE(TimeDelta::ms(-kValue).IsFinite());
+  EXPECT_TRUE(TimeDelta::ms(kValue).IsFinite());
+  EXPECT_TRUE(TimeDelta::Zero().IsFinite());
+}
+
+TEST(TimeDeltaTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+  const TimeDelta small = TimeDelta::ms(kSmall);
+  const TimeDelta large = TimeDelta::ms(kLarge);
+
+  EXPECT_EQ(TimeDelta::Zero(), TimeDelta::ms(0));
+  EXPECT_EQ(TimeDelta::PlusInfinity(), TimeDelta::PlusInfinity());
+  EXPECT_EQ(small, TimeDelta::ms(kSmall));
+  EXPECT_LE(small, TimeDelta::ms(kSmall));
+  EXPECT_GE(small, TimeDelta::ms(kSmall));
+  EXPECT_NE(small, TimeDelta::ms(kLarge));
+  EXPECT_LE(small, TimeDelta::ms(kLarge));
+  EXPECT_LT(small, TimeDelta::ms(kLarge));
+  EXPECT_GE(large, TimeDelta::ms(kSmall));
+  EXPECT_GT(large, TimeDelta::ms(kSmall));
+  EXPECT_LT(TimeDelta::Zero(), small);
+  EXPECT_GT(TimeDelta::Zero(), TimeDelta::ms(-kSmall));
+  EXPECT_GT(TimeDelta::Zero(), TimeDelta::ms(-kSmall));
+
+  EXPECT_GT(TimeDelta::PlusInfinity(), large);
+  EXPECT_LT(TimeDelta::MinusInfinity(), TimeDelta::Zero());
+}
+
+TEST(TimeDeltaTest, CanBeInititializedFromLargeInt) {
+  const int kMaxInt = std::numeric_limits<int>::max();
+  EXPECT_EQ(TimeDelta::seconds(kMaxInt).us(),
+            static_cast<int64_t>(kMaxInt) * 1000000);
+  EXPECT_EQ(TimeDelta::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000);
+}
+
+TEST(TimeDeltaTest, ConvertsToAndFromDouble) {
+  const int64_t kMicros = 17017;
+  const double kNanosDouble = kMicros * 1e3;
+  const double kMicrosDouble = kMicros;
+  const double kMillisDouble = kMicros * 1e-3;
+  const double kSecondsDouble = kMillisDouble * 1e-3;
+
+  EXPECT_EQ(TimeDelta::us(kMicros).seconds<double>(), kSecondsDouble);
+  EXPECT_EQ(TimeDelta::seconds(kSecondsDouble).us(), kMicros);
+
+  EXPECT_EQ(TimeDelta::us(kMicros).ms<double>(), kMillisDouble);
+  EXPECT_EQ(TimeDelta::ms(kMillisDouble).us(), kMicros);
+
+  EXPECT_EQ(TimeDelta::us(kMicros).us<double>(), kMicrosDouble);
+  EXPECT_EQ(TimeDelta::us(kMicrosDouble).us(), kMicros);
+
+  EXPECT_NEAR(TimeDelta::us(kMicros).ns<double>(), kNanosDouble, 1);
+
+  const double kPlusInfinity = std::numeric_limits<double>::infinity();
+  const double kMinusInfinity = -kPlusInfinity;
+
+  EXPECT_EQ(TimeDelta::PlusInfinity().seconds<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().seconds<double>(), kMinusInfinity);
+  EXPECT_EQ(TimeDelta::PlusInfinity().ms<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().ms<double>(), kMinusInfinity);
+  EXPECT_EQ(TimeDelta::PlusInfinity().us<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().us<double>(), kMinusInfinity);
+  EXPECT_EQ(TimeDelta::PlusInfinity().ns<double>(), kPlusInfinity);
+  EXPECT_EQ(TimeDelta::MinusInfinity().ns<double>(), kMinusInfinity);
+
+  EXPECT_TRUE(TimeDelta::seconds(kPlusInfinity).IsPlusInfinity());
+  EXPECT_TRUE(TimeDelta::seconds(kMinusInfinity).IsMinusInfinity());
+  EXPECT_TRUE(TimeDelta::ms(kPlusInfinity).IsPlusInfinity());
+  EXPECT_TRUE(TimeDelta::ms(kMinusInfinity).IsMinusInfinity());
+  EXPECT_TRUE(TimeDelta::us(kPlusInfinity).IsPlusInfinity());
+  EXPECT_TRUE(TimeDelta::us(kMinusInfinity).IsMinusInfinity());
+}
+
+TEST(TimeDeltaTest, MathOperations) {
+  const int64_t kValueA = 267;
+  const int64_t kValueB = 450;
+  const TimeDelta delta_a = TimeDelta::ms(kValueA);
+  const TimeDelta delta_b = TimeDelta::ms(kValueB);
+  EXPECT_EQ((delta_a + delta_b).ms(), kValueA + kValueB);
+  EXPECT_EQ((delta_a - delta_b).ms(), kValueA - kValueB);
+
+  const int32_t kInt32Value = 123;
+  const double kFloatValue = 123.0;
+  EXPECT_EQ((TimeDelta::us(kValueA) * kValueB).us(), kValueA * kValueB);
+  EXPECT_EQ((TimeDelta::us(kValueA) * kInt32Value).us(), kValueA * kInt32Value);
+  EXPECT_EQ((TimeDelta::us(kValueA) * kFloatValue).us(), kValueA * kFloatValue);
+
+  EXPECT_EQ((delta_b / 10).ms(), kValueB / 10);
+  EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA);
+
+  EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA);
+  EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA);
+}
+}  // namespace test
+}  // namespace webrtc
diff --git a/api/units/timestamp.cc b/api/units/timestamp.cc
new file mode 100644
index 0000000..4b2c44b
--- /dev/null
+++ b/api/units/timestamp.cc
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/timestamp.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+std::string ToString(const Timestamp& value) {
+  char buf[64];
+  rtc::SimpleStringBuilder sb(buf);
+  if (value.IsInfinite()) {
+    sb << "inf ms";
+  } else {
+    sb << value.ms() << " ms";
+  }
+  return sb.str();
+}
+}  // namespace webrtc
diff --git a/api/units/timestamp.h b/api/units/timestamp.h
new file mode 100644
index 0000000..a66e061
--- /dev/null
+++ b/api/units/timestamp.h
@@ -0,0 +1,176 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_UNITS_TIMESTAMP_H_
+#define API_UNITS_TIMESTAMP_H_
+
+#include <stdint.h>
+#include <limits>
+#include <string>
+
+#include "api/units/time_delta.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace timestamp_impl {
+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
+constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
+}  // namespace timestamp_impl
+
+// Timestamp represents the time that has passed since some unspecified epoch.
+// The epoch is assumed to be before any represented timestamps, this means that
+// negative values are not valid. The most notable feature is that the
+// difference of two Timestamps results in a TimeDelta.
+class Timestamp {
+ public:
+  Timestamp() = delete;
+  static Timestamp Infinity() {
+    return Timestamp(timestamp_impl::kPlusInfinityVal);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static Timestamp seconds(T seconds) {
+    RTC_DCHECK_GE(seconds, 0);
+    RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
+    return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static Timestamp ms(T milliseconds) {
+    RTC_DCHECK_GE(milliseconds, 0);
+    RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
+    return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
+  }
+
+  template <
+      typename T,
+      typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+  static Timestamp us(T microseconds) {
+    RTC_DCHECK_GE(microseconds, 0);
+    RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
+    return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static Timestamp seconds(T seconds) {
+    return Timestamp::us(seconds * 1e6);
+  }
+
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static Timestamp ms(T milliseconds) {
+    return Timestamp::us(milliseconds * 1e3);
+  }
+  template <typename T,
+            typename std::enable_if<std::is_floating_point<T>::value>::type* =
+                nullptr>
+  static Timestamp us(T microseconds) {
+    if (microseconds == std::numeric_limits<double>::infinity()) {
+      return Infinity();
+    } else {
+      RTC_DCHECK(!std::isnan(microseconds));
+      RTC_DCHECK_GE(microseconds, 0);
+      RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
+      return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
+    }
+  }
+
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
+    return rtc::dchecked_cast<T>((us() + 500000) / 1000000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
+    return rtc::dchecked_cast<T>((us() + 500) / 1000);
+  }
+  template <typename T = int64_t>
+  typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(microseconds_);
+  }
+
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
+      const {
+    return us<T>() * 1e-6;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
+      const {
+    return us<T>() * 1e-3;
+  }
+  template <typename T>
+  typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
+      const {
+    if (IsInfinite()) {
+      return std::numeric_limits<T>::infinity();
+    } else {
+      return microseconds_;
+    }
+  }
+
+  bool IsInfinite() const {
+    return microseconds_ == timestamp_impl::kPlusInfinityVal;
+  }
+  bool IsFinite() const { return !IsInfinite(); }
+  TimeDelta operator-(const Timestamp& other) const {
+    return TimeDelta::us(us() - other.us());
+  }
+  Timestamp operator-(const TimeDelta& delta) const {
+    return Timestamp::us(us() - delta.us());
+  }
+  Timestamp operator+(const TimeDelta& delta) const {
+    return Timestamp::us(us() + delta.us());
+  }
+  Timestamp& operator-=(const TimeDelta& other) {
+    microseconds_ -= other.us();
+    return *this;
+  }
+  Timestamp& operator+=(const TimeDelta& other) {
+    microseconds_ += other.us();
+    return *this;
+  }
+  bool operator==(const Timestamp& other) const {
+    return microseconds_ == other.microseconds_;
+  }
+  bool operator!=(const Timestamp& other) const {
+    return microseconds_ != other.microseconds_;
+  }
+  bool operator<=(const Timestamp& other) const {
+    return microseconds_ <= other.microseconds_;
+  }
+  bool operator>=(const Timestamp& other) const {
+    return microseconds_ >= other.microseconds_;
+  }
+  bool operator>(const Timestamp& other) const {
+    return microseconds_ > other.microseconds_;
+  }
+  bool operator<(const Timestamp& other) const {
+    return microseconds_ < other.microseconds_;
+  }
+
+ private:
+  explicit Timestamp(int64_t us) : microseconds_(us) {}
+  int64_t microseconds_;
+};
+
+std::string ToString(const Timestamp& value);
+
+}  // namespace webrtc
+
+#endif  // API_UNITS_TIMESTAMP_H_
diff --git a/api/units/timestamp_unittest.cc b/api/units/timestamp_unittest.cc
new file mode 100644
index 0000000..eecfe02
--- /dev/null
+++ b/api/units/timestamp_unittest.cc
@@ -0,0 +1,106 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/units/timestamp.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+TEST(TimestampTest, GetBackSameValues) {
+  const int64_t kValue = 499;
+  EXPECT_EQ(Timestamp::ms(kValue).ms(), kValue);
+  EXPECT_EQ(Timestamp::us(kValue).us(), kValue);
+  EXPECT_EQ(Timestamp::seconds(kValue).seconds(), kValue);
+}
+
+TEST(TimestampTest, GetDifferentPrefix) {
+  const int64_t kValue = 3000000;
+  EXPECT_EQ(Timestamp::us(kValue).seconds(), kValue / 1000000);
+  EXPECT_EQ(Timestamp::ms(kValue).seconds(), kValue / 1000);
+  EXPECT_EQ(Timestamp::us(kValue).ms(), kValue / 1000);
+
+  EXPECT_EQ(Timestamp::ms(kValue).us(), kValue * 1000);
+  EXPECT_EQ(Timestamp::seconds(kValue).ms(), kValue * 1000);
+  EXPECT_EQ(Timestamp::seconds(kValue).us(), kValue * 1000000);
+}
+
+TEST(TimestampTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+
+  EXPECT_TRUE(Timestamp::Infinity().IsInfinite());
+  EXPECT_FALSE(Timestamp::ms(kValue).IsInfinite());
+
+  EXPECT_FALSE(Timestamp::Infinity().IsFinite());
+  EXPECT_TRUE(Timestamp::ms(kValue).IsFinite());
+}
+
+TEST(TimestampTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+
+  EXPECT_EQ(Timestamp::Infinity(), Timestamp::Infinity());
+  EXPECT_GE(Timestamp::Infinity(), Timestamp::Infinity());
+  EXPECT_GT(Timestamp::Infinity(), Timestamp::ms(kLarge));
+  EXPECT_EQ(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
+  EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
+  EXPECT_GE(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
+  EXPECT_NE(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
+  EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
+  EXPECT_LT(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
+  EXPECT_GE(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
+  EXPECT_GT(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
+}
+
+TEST(TimestampTest, CanBeInititializedFromLargeInt) {
+  const int kMaxInt = std::numeric_limits<int>::max();
+  EXPECT_EQ(Timestamp::seconds(kMaxInt).us(),
+            static_cast<int64_t>(kMaxInt) * 1000000);
+  EXPECT_EQ(Timestamp::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000);
+}
+
+TEST(TimestampTest, ConvertsToAndFromDouble) {
+  const int64_t kMicros = 17017;
+  const double kMicrosDouble = kMicros;
+  const double kMillisDouble = kMicros * 1e-3;
+  const double kSecondsDouble = kMillisDouble * 1e-3;
+
+  EXPECT_EQ(Timestamp::us(kMicros).seconds<double>(), kSecondsDouble);
+  EXPECT_EQ(Timestamp::seconds(kSecondsDouble).us(), kMicros);
+
+  EXPECT_EQ(Timestamp::us(kMicros).ms<double>(), kMillisDouble);
+  EXPECT_EQ(Timestamp::ms(kMillisDouble).us(), kMicros);
+
+  EXPECT_EQ(Timestamp::us(kMicros).us<double>(), kMicrosDouble);
+  EXPECT_EQ(Timestamp::us(kMicrosDouble).us(), kMicros);
+
+  const double kPlusInfinity = std::numeric_limits<double>::infinity();
+
+  EXPECT_EQ(Timestamp::Infinity().seconds<double>(), kPlusInfinity);
+  EXPECT_EQ(Timestamp::Infinity().ms<double>(), kPlusInfinity);
+  EXPECT_EQ(Timestamp::Infinity().us<double>(), kPlusInfinity);
+
+  EXPECT_TRUE(Timestamp::seconds(kPlusInfinity).IsInfinite());
+  EXPECT_TRUE(Timestamp::ms(kPlusInfinity).IsInfinite());
+  EXPECT_TRUE(Timestamp::us(kPlusInfinity).IsInfinite());
+}
+
+TEST(UnitConversionTest, TimestampAndTimeDeltaMath) {
+  const int64_t kValueA = 267;
+  const int64_t kValueB = 450;
+  const Timestamp time_a = Timestamp::ms(kValueA);
+  const Timestamp time_b = Timestamp::ms(kValueB);
+  const TimeDelta delta_a = TimeDelta::ms(kValueA);
+
+  EXPECT_EQ((time_a - time_b), TimeDelta::ms(kValueA - kValueB));
+  EXPECT_EQ((time_b - delta_a), Timestamp::ms(kValueB - kValueA));
+  EXPECT_EQ((time_b + delta_a), Timestamp::ms(kValueB + kValueA));
+}
+}  // namespace test
+}  // namespace webrtc
diff --git a/api/video/color_space.cc b/api/video/color_space.cc
new file mode 100644
index 0000000..a8be5cd
--- /dev/null
+++ b/api/video/color_space.cc
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "api/video/color_space.h"
+
+namespace webrtc {
+
+ColorSpace::ColorSpace() = default;
+
+ColorSpace::ColorSpace(PrimaryID primaries,
+                       TransferID transfer,
+                       MatrixID matrix,
+                       RangeID range)
+    : primaries_(primaries),
+      transfer_(transfer),
+      matrix_(matrix),
+      range_(range) {}
+
+ColorSpace::PrimaryID ColorSpace::primaries() const {
+  return primaries_;
+}
+
+ColorSpace::TransferID ColorSpace::transfer() const {
+  return transfer_;
+}
+
+ColorSpace::MatrixID ColorSpace::matrix() const {
+  return matrix_;
+}
+
+ColorSpace::RangeID ColorSpace::range() const {
+  return range_;
+}
+
+}  // namespace webrtc
diff --git a/api/video/color_space.h b/api/video/color_space.h
new file mode 100644
index 0000000..736a170
--- /dev/null
+++ b/api/video/color_space.h
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_VIDEO_COLOR_SPACE_H_
+#define API_VIDEO_COLOR_SPACE_H_
+
+namespace webrtc {
+
+// Used to represent a color space for the purpose of color conversion. This
+// class only represents color information that can be transferred through the
+// bitstream of WebRTC's internal supported codecs:
+// - VP9 supports color profiles, see VP9 Bitstream & Decoding Process
+// Specification Version 0.6 Section 7.2.2 "Color config semantics" available
+// from https://www.webmproject.org.
+// TODO(emircan): Extract these values from decode and add to the existing ones.
+// - VP8 only supports BT.601, see
+// https://tools.ietf.org/html/rfc6386#section-9.2
+// - H264 supports different color primaries, transfer characteristics, matrix
+// coefficients and range. See T-REC-H.264 E.2.1, "VUI parameters semantics",
+// available from https://www.itu.int/rec/T-REC-H.264.
+class ColorSpace {
+ public:
+  enum class PrimaryID {
+    kInvalid,
+    kBT709,
+    kSMPTE170M,  // Identical to BT601
+    kSMPTE240M,
+    kBT2020,
+  };
+
+  enum class TransferID {
+    kInvalid,
+    kBT709,
+    kSMPTE170M,
+    kSMPTE240M,
+    kBT2020,
+    kBT2020_10,
+    kIEC61966_2_1,
+  };
+
+  enum class MatrixID {
+    kInvalid,
+    kBT709,
+    kSMPTE170M,
+    kSMPTE240M,
+    kBT2020_NCL,
+  };
+
+  enum class RangeID {
+    kInvalid,
+    // Limited Rec. 709 color range with RGB values ranging from 16 to 235.
+    kLimited,
+    // Full RGB color range with RGB valees from 0 to 255.
+    kFull,
+  };
+
+  ColorSpace();
+  ColorSpace(PrimaryID primaries,
+             TransferID transfer,
+             MatrixID matrix,
+             RangeID full_range);
+
+  PrimaryID primaries() const;
+  TransferID transfer() const;
+  MatrixID matrix() const;
+  RangeID range() const;
+
+ private:
+  PrimaryID primaries_ = PrimaryID::kInvalid;
+  TransferID transfer_ = TransferID::kInvalid;
+  MatrixID matrix_ = MatrixID::kInvalid;
+  RangeID range_ = RangeID::kInvalid;
+};
+
+}  // namespace webrtc
+
+#endif  // API_VIDEO_COLOR_SPACE_H_
diff --git a/api/video/encoded_frame.cc b/api/video/encoded_frame.cc
index 37da35f..f9152b2 100644
--- a/api/video/encoded_frame.cc
+++ b/api/video/encoded_frame.cc
@@ -13,7 +13,17 @@
 namespace webrtc {
 namespace video_coding {
 
-bool EncodedFrame::delayed_by_retransmission() const { return 0; }
+bool EncodedFrame::delayed_by_retransmission() const {
+  return 0;
+}
+
+uint32_t EncodedFrame::Timestamp() const {
+  return timestamp;
+}
+
+void EncodedFrame::SetTimestamp(uint32_t rtp_timestamp) {
+  timestamp = rtp_timestamp;
+}
 
 }  // namespace video_coding
 }  // namespace webrtc
diff --git a/api/video/encoded_frame.h b/api/video/encoded_frame.h
index 1e919d0..1b0a26a 100644
--- a/api/video/encoded_frame.h
+++ b/api/video/encoded_frame.h
@@ -58,8 +58,9 @@
 
   virtual bool GetBitstream(uint8_t* destination) const = 0;
 
-  // The capture timestamp of this frame.
-  virtual uint32_t Timestamp() const = 0;
+  // The capture timestamp of this frame, using the 90 kHz RTP clock.
+  virtual uint32_t Timestamp() const;
+  virtual void SetTimestamp(uint32_t rtp_timestamp);
 
   // When this frame was received.
   virtual int64_t ReceivedTime() const = 0;
diff --git a/api/video/i010_buffer.cc b/api/video/i010_buffer.cc
new file mode 100644
index 0000000..adb5a5e
--- /dev/null
+++ b/api/video/i010_buffer.cc
@@ -0,0 +1,237 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+#include "api/video/i010_buffer.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "api/video/i420_buffer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/refcountedobject.h"
+#include "third_party/libyuv/include/libyuv/convert.h"
+#include "third_party/libyuv/include/libyuv/planar_functions.h"
+#include "third_party/libyuv/include/libyuv/scale.h"
+
+// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
+static const int kBufferAlignment = 64;
+static const int kBytesPerPixel = 2;
+
+namespace webrtc {
+
+namespace {
+
+int I010DataSize(int height, int stride_y, int stride_u, int stride_v) {
+  return kBytesPerPixel *
+         (stride_y * height + (stride_u + stride_v) * ((height + 1) / 2));
+}
+
+}  // namespace
+
+I010Buffer::I010Buffer(int width,
+                       int height,
+                       int stride_y,
+                       int stride_u,
+                       int stride_v)
+    : width_(width),
+      height_(height),
+      stride_y_(stride_y),
+      stride_u_(stride_u),
+      stride_v_(stride_v),
+      data_(static_cast<uint16_t*>(
+          AlignedMalloc(I010DataSize(height, stride_y, stride_u, stride_v),
+                        kBufferAlignment))) {
+  RTC_DCHECK_GT(width, 0);
+  RTC_DCHECK_GT(height, 0);
+  RTC_DCHECK_GE(stride_y, width);
+  RTC_DCHECK_GE(stride_u, (width + 1) / 2);
+  RTC_DCHECK_GE(stride_v, (width + 1) / 2);
+}
+
+I010Buffer::~I010Buffer() {}
+
+// static
+rtc::scoped_refptr<I010Buffer> I010Buffer::Create(int width, int height) {
+  return new rtc::RefCountedObject<I010Buffer>(
+      width, height, width, (width + 1) / 2, (width + 1) / 2);
+}
+
+// static
+rtc::scoped_refptr<I010Buffer> I010Buffer::Copy(
+    const I010BufferInterface& source) {
+  const int width = source.width();
+  const int height = source.height();
+  rtc::scoped_refptr<I010Buffer> buffer = Create(width, height);
+  RTC_CHECK_EQ(
+      0, libyuv::I010Copy(
+             source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
+             source.DataV(), source.StrideV(), buffer->MutableDataY(),
+             buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
+             buffer->MutableDataV(), buffer->StrideV(), width, height));
+  return buffer;
+}
+
+// static
+rtc::scoped_refptr<I010Buffer> I010Buffer::Copy(
+    const I420BufferInterface& source) {
+  const int width = source.width();
+  const int height = source.height();
+  rtc::scoped_refptr<I010Buffer> buffer = Create(width, height);
+  RTC_CHECK_EQ(
+      0, libyuv::I420ToI010(
+             source.DataY(), source.StrideY(), source.DataU(), source.StrideU(),
+             source.DataV(), source.StrideV(), buffer->MutableDataY(),
+             buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
+             buffer->MutableDataV(), buffer->StrideV(), width, height));
+  return buffer;
+}
+
+// static
+rtc::scoped_refptr<I010Buffer> I010Buffer::Rotate(
+    const I010BufferInterface& src,
+    VideoRotation rotation) {
+  if (rotation == webrtc::kVideoRotation_0)
+    return Copy(src);
+
+  RTC_CHECK(src.DataY());
+  RTC_CHECK(src.DataU());
+  RTC_CHECK(src.DataV());
+  int rotated_width = src.width();
+  int rotated_height = src.height();
+  if (rotation == webrtc::kVideoRotation_90 ||
+      rotation == webrtc::kVideoRotation_270) {
+    std::swap(rotated_width, rotated_height);
+  }
+
+  rtc::scoped_refptr<webrtc::I010Buffer> buffer =
+      Create(rotated_width, rotated_height);
+  // TODO(emircan): Remove this when there is libyuv::I010Rotate().
+  for (int x = 0; x < src.width(); x++) {
+    for (int y = 0; y < src.height(); y++) {
+      int dest_x = x;
+      int dest_y = y;
+      switch (rotation) {
+        // This case is covered by the early return.
+        case webrtc::kVideoRotation_0:
+          RTC_NOTREACHED();
+          break;
+        case webrtc::kVideoRotation_90:
+          dest_x = src.height() - y - 1;
+          dest_y = x;
+          break;
+        case webrtc::kVideoRotation_180:
+          dest_x = src.width() - x - 1;
+          dest_y = src.height() - y - 1;
+          break;
+        case webrtc::kVideoRotation_270:
+          dest_x = y;
+          dest_y = src.width() - x - 1;
+          break;
+      }
+      buffer->MutableDataY()[dest_x + buffer->StrideY() * dest_y] =
+          src.DataY()[x + src.StrideY() * y];
+      dest_x /= 2;
+      dest_y /= 2;
+      int src_x = x / 2;
+      int src_y = y / 2;
+      buffer->MutableDataU()[dest_x + buffer->StrideU() * dest_y] =
+          src.DataU()[src_x + src.StrideU() * src_y];
+      buffer->MutableDataV()[dest_x + buffer->StrideV() * dest_y] =
+          src.DataV()[src_x + src.StrideV() * src_y];
+    }
+  }
+  return buffer;
+}
+
+rtc::scoped_refptr<I420BufferInterface> I010Buffer::ToI420() {
+  rtc::scoped_refptr<I420Buffer> i420_buffer =
+      I420Buffer::Create(width(), height());
+  libyuv::I010ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(),
+                     i420_buffer->MutableDataY(), i420_buffer->StrideY(),
+                     i420_buffer->MutableDataU(), i420_buffer->StrideU(),
+                     i420_buffer->MutableDataV(), i420_buffer->StrideV(),
+                     width(), height());
+  return i420_buffer;
+}
+
+int I010Buffer::width() const {
+  return width_;
+}
+
+int I010Buffer::height() const {
+  return height_;
+}
+
+const uint16_t* I010Buffer::DataY() const {
+  return data_.get();
+}
+const uint16_t* I010Buffer::DataU() const {
+  return data_.get() + stride_y_ * height_;
+}
+const uint16_t* I010Buffer::DataV() const {
+  return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2);
+}
+
+int I010Buffer::StrideY() const {
+  return stride_y_;
+}
+int I010Buffer::StrideU() const {
+  return stride_u_;
+}
+int I010Buffer::StrideV() const {
+  return stride_v_;
+}
+
+uint16_t* I010Buffer::MutableDataY() {
+  return const_cast<uint16_t*>(DataY());
+}
+uint16_t* I010Buffer::MutableDataU() {
+  return const_cast<uint16_t*>(DataU());
+}
+uint16_t* I010Buffer::MutableDataV() {
+  return const_cast<uint16_t*>(DataV());
+}
+
+void I010Buffer::CropAndScaleFrom(const I010BufferInterface& src,
+                                  int offset_x,
+                                  int offset_y,
+                                  int crop_width,
+                                  int crop_height) {
+  RTC_CHECK_LE(crop_width, src.width());
+  RTC_CHECK_LE(crop_height, src.height());
+  RTC_CHECK_LE(crop_width + offset_x, src.width());
+  RTC_CHECK_LE(crop_height + offset_y, src.height());
+  RTC_CHECK_GE(offset_x, 0);
+  RTC_CHECK_GE(offset_y, 0);
+
+  // Make sure offset is even so that u/v plane becomes aligned.
+  const int uv_offset_x = offset_x / 2;
+  const int uv_offset_y = offset_y / 2;
+  offset_x = uv_offset_x * 2;
+  offset_y = uv_offset_y * 2;
+
+  const uint16_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
+  const uint16_t* u_plane =
+      src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x;
+  const uint16_t* v_plane =
+      src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x;
+  int res = libyuv::I420Scale_16(
+      y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane, src.StrideV(),
+      crop_width, crop_height, MutableDataY(), StrideY(), MutableDataU(),
+      StrideU(), MutableDataV(), StrideV(), width(), height(),
+      libyuv::kFilterBox);
+
+  RTC_DCHECK_EQ(res, 0);
+}
+
+void I010Buffer::ScaleFrom(const I010BufferInterface& src) {
+  CropAndScaleFrom(src, 0, 0, src.width(), src.height());
+}
+
+}  // namespace webrtc
diff --git a/api/video/i010_buffer.h b/api/video/i010_buffer.h
new file mode 100644
index 0000000..1208b31
--- /dev/null
+++ b/api/video/i010_buffer.h
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 API_VIDEO_I010_BUFFER_H_
+#define API_VIDEO_I010_BUFFER_H_
+
+#include <memory>
+
+#include "api/video/video_frame_buffer.h"
+#include "api/video/video_rotation.h"
+#include "rtc_base/memory/aligned_malloc.h"
+
+namespace webrtc {
+
+// Plain I010 buffer in standard memory.
+class I010Buffer : public I010BufferInterface {
+ public:
+  // Create a new buffer.
+  static rtc::scoped_refptr<I010Buffer> Create(int width, int height);
+
+  // Create a new buffer and copy the pixel data.
+  static rtc::scoped_refptr<I010Buffer> Copy(const I010BufferInterface& buffer);
+
+  // Convert and put I420 buffer into a new buffer.
+  static rtc::scoped_refptr<I010Buffer> Copy(const I420BufferInterface& buffer);
+
+  // Return a rotated copy of |src|.
+  static rtc::scoped_refptr<I010Buffer> Rotate(const I010BufferInterface& src,
+                                               VideoRotation rotation);
+
+  // VideoFrameBuffer implementation.
+  rtc::scoped_refptr<I420BufferInterface> ToI420() override;
+
+  // PlanarYuv16BBuffer implementation.
+  int width() const override;
+  int height() const override;
+  const uint16_t* DataY() const override;
+  const uint16_t* DataU() const override;
+  const uint16_t* DataV() const override;
+  int StrideY() const override;
+  int StrideU() const override;
+  int StrideV() const override;
+
+  uint16_t* MutableDataY();
+  uint16_t* MutableDataU();
+  uint16_t* MutableDataV();
+
+  // Scale the cropped area of |src| to the size of |this| buffer, and
+  // write the result into |this|.
+  void CropAndScaleFrom(const I010BufferInterface& src,
+                        int offset_x,
+                        int offset_y,
+                        int crop_width,
+                        int crop_height);
+
+  // Scale all of |src| to the size of |this| buffer, with no cropping.
+  void ScaleFrom(const I010BufferInterface& src);
+
+ protected:
+  I010Buffer(int width, int height, int stride_y, int stride_u, int stride_v);
+  ~I010Buffer() override;
+
+ private:
+  const int width_;
+  const int height_;
+  const int stride_y_;
+  const int stride_u_;
+  const int stride_v_;
+  const std::unique_ptr<uint16_t, AlignedFreeDeleter> data_;
+};
+
+}  // namespace webrtc
+
+#endif  // API_VIDEO_I010_BUFFER_H_
diff --git a/api/video/i420_buffer.cc b/api/video/i420_buffer.cc
index 66071e1..8d239f3 100644
--- a/api/video/i420_buffer.cc
+++ b/api/video/i420_buffer.cc
@@ -34,8 +34,7 @@
 }  // namespace
 
 I420Buffer::I420Buffer(int width, int height)
-    : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
-}
+    : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {}
 
 I420Buffer::I420Buffer(int width,
                        int height,
@@ -47,9 +46,9 @@
       stride_y_(stride_y),
       stride_u_(stride_u),
       stride_v_(stride_v),
-      data_(static_cast<uint8_t*>(AlignedMalloc(
-          I420DataSize(height, stride_y, stride_u, stride_v),
-          kBufferAlignment))) {
+      data_(static_cast<uint8_t*>(
+          AlignedMalloc(I420DataSize(height, stride_y, stride_u, stride_v),
+                        kBufferAlignment))) {
   RTC_DCHECK_GT(width, 0);
   RTC_DCHECK_GT(height, 0);
   RTC_DCHECK_GE(stride_y, width);
@@ -57,8 +56,7 @@
   RTC_DCHECK_GE(stride_v, (width + 1) / 2);
 }
 
-I420Buffer::~I420Buffer() {
-}
+I420Buffer::~I420Buffer() {}
 
 // static
 rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width, int height) {
@@ -71,34 +69,34 @@
                                                   int stride_y,
                                                   int stride_u,
                                                   int stride_v) {
-  return new rtc::RefCountedObject<I420Buffer>(
-      width, height, stride_y, stride_u, stride_v);
+  return new rtc::RefCountedObject<I420Buffer>(width, height, stride_y,
+                                               stride_u, stride_v);
 }
 
 // static
 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(
     const I420BufferInterface& source) {
-  return Copy(source.width(), source.height(),
-              source.DataY(), source.StrideY(),
-              source.DataU(), source.StrideU(),
-              source.DataV(), source.StrideV());
+  return Copy(source.width(), source.height(), source.DataY(), source.StrideY(),
+              source.DataU(), source.StrideU(), source.DataV(),
+              source.StrideV());
 }
 
 // static
-rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(
-      int width, int height,
-      const uint8_t* data_y, int stride_y,
-      const uint8_t* data_u, int stride_u,
-      const uint8_t* data_v, int stride_v) {
+rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(int width,
+                                                int height,
+                                                const uint8_t* data_y,
+                                                int stride_y,
+                                                const uint8_t* data_u,
+                                                int stride_u,
+                                                const uint8_t* data_v,
+                                                int stride_v) {
   // Note: May use different strides than the input data.
   rtc::scoped_refptr<I420Buffer> buffer = Create(width, height);
-  RTC_CHECK_EQ(0, libyuv::I420Copy(data_y, stride_y,
-                                   data_u, stride_u,
-                                   data_v, stride_v,
-                                   buffer->MutableDataY(), buffer->StrideY(),
-                                   buffer->MutableDataU(), buffer->StrideU(),
-                                   buffer->MutableDataV(), buffer->StrideV(),
-                                   width, height));
+  RTC_CHECK_EQ(0, libyuv::I420Copy(data_y, stride_y, data_u, stride_u, data_v,
+                                   stride_v, buffer->MutableDataY(),
+                                   buffer->StrideY(), buffer->MutableDataU(),
+                                   buffer->StrideU(), buffer->MutableDataV(),
+                                   buffer->StrideV(), width, height));
   return buffer;
 }
 
@@ -120,14 +118,13 @@
   rtc::scoped_refptr<webrtc::I420Buffer> buffer =
       I420Buffer::Create(rotated_width, rotated_height);
 
-  RTC_CHECK_EQ(0, libyuv::I420Rotate(
-      src.DataY(), src.StrideY(),
-      src.DataU(), src.StrideU(),
-      src.DataV(), src.StrideV(),
-      buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(),
-      buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(),
-      src.width(), src.height(),
-      static_cast<libyuv::RotationMode>(rotation)));
+  RTC_CHECK_EQ(0,
+               libyuv::I420Rotate(
+                   src.DataY(), src.StrideY(), src.DataU(), src.StrideU(),
+                   src.DataV(), src.StrideV(), buffer->MutableDataY(),
+                   buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(),
+                   buffer->MutableDataV(), buffer->StrideV(), src.width(),
+                   src.height(), static_cast<libyuv::RotationMode>(rotation)));
 
   return buffer;
 }
@@ -179,9 +176,9 @@
 void I420Buffer::SetBlack(I420Buffer* buffer) {
   RTC_CHECK(libyuv::I420Rect(buffer->MutableDataY(), buffer->StrideY(),
                              buffer->MutableDataU(), buffer->StrideU(),
-                             buffer->MutableDataV(), buffer->StrideV(),
-                             0, 0, buffer->width(), buffer->height(),
-                             0, 128, 128) == 0);
+                             buffer->MutableDataV(), buffer->StrideV(), 0, 0,
+                             buffer->width(), buffer->height(), 0, 128,
+                             128) == 0);
 }
 
 void I420Buffer::CropAndScaleFrom(const I420BufferInterface& src,
@@ -202,20 +199,16 @@
   offset_x = uv_offset_x * 2;
   offset_y = uv_offset_y * 2;
 
-  const uint8_t* y_plane =
-      src.DataY() + src.StrideY() * offset_y + offset_x;
+  const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
   const uint8_t* u_plane =
       src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x;
   const uint8_t* v_plane =
       src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x;
-  int res = libyuv::I420Scale(y_plane, src.StrideY(),
-                              u_plane, src.StrideU(),
-                              v_plane, src.StrideV(),
-                              crop_width, crop_height,
-                              MutableDataY(), StrideY(),
-                              MutableDataU(), StrideU(),
-                              MutableDataV(), StrideV(),
-                              width(), height(), libyuv::kFilterBox);
+  int res =
+      libyuv::I420Scale(y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane,
+                        src.StrideV(), crop_width, crop_height, MutableDataY(),
+                        StrideY(), MutableDataU(), StrideU(), MutableDataV(),
+                        StrideV(), width(), height(), libyuv::kFilterBox);
 
   RTC_DCHECK_EQ(res, 0);
 }
@@ -226,10 +219,8 @@
   const int crop_height =
       std::min(src.height(), height() * src.width() / width());
 
-  CropAndScaleFrom(
-      src,
-      (src.width() - crop_width) / 2, (src.height() - crop_height) / 2,
-      crop_width, crop_height);
+  CropAndScaleFrom(src, (src.width() - crop_width) / 2,
+                   (src.height() - crop_height) / 2, crop_width, crop_height);
 }
 
 void I420Buffer::ScaleFrom(const I420BufferInterface& src) {
diff --git a/api/video/i420_buffer.h b/api/video/i420_buffer.h
index 2bd37bd..282b242 100644
--- a/api/video/i420_buffer.h
+++ b/api/video/i420_buffer.h
@@ -36,11 +36,14 @@
     return Copy(*buffer.GetI420());
   }
 
-  static rtc::scoped_refptr<I420Buffer> Copy(
-      int width, int height,
-      const uint8_t* data_y, int stride_y,
-      const uint8_t* data_u, int stride_u,
-      const uint8_t* data_v, int stride_v);
+  static rtc::scoped_refptr<I420Buffer> Copy(int width,
+                                             int height,
+                                             const uint8_t* data_y,
+                                             int stride_y,
+                                             const uint8_t* data_u,
+                                             int stride_u,
+                                             const uint8_t* data_v,
+                                             int stride_v);
 
   // Returns a rotated copy of |src|.
   static rtc::scoped_refptr<I420Buffer> Rotate(const I420BufferInterface& src,
diff --git a/api/video/video_bitrate_allocation.cc b/api/video/video_bitrate_allocation.cc
index 059eb8f..6c5ad1e 100644
--- a/api/video/video_bitrate_allocation.cc
+++ b/api/video/video_bitrate_allocation.cc
@@ -27,7 +27,7 @@
   RTC_CHECK_LT(spatial_index, kMaxSpatialLayers);
   RTC_CHECK_LT(temporal_index, kMaxTemporalStreams);
   int64_t new_bitrate_sum_bps = sum_;
-  rtc::Optional<uint32_t>& layer_bitrate =
+  absl::optional<uint32_t>& layer_bitrate =
       bitrates_[spatial_index][temporal_index];
   if (layer_bitrate) {
     RTC_DCHECK_LE(*layer_bitrate, sum_);
@@ -107,6 +107,23 @@
   return temporal_rates;
 }
 
+std::vector<absl::optional<VideoBitrateAllocation>>
+VideoBitrateAllocation::GetSimulcastAllocations() const {
+  std::vector<absl::optional<VideoBitrateAllocation>> bitrates;
+  for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
+    absl::optional<VideoBitrateAllocation> layer_bitrate;
+    if (IsSpatialLayerUsed(si)) {
+      layer_bitrate = VideoBitrateAllocation();
+      for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
+        if (HasBitrate(si, tl))
+          layer_bitrate->SetBitrate(0, tl, GetBitrate(si, tl));
+      }
+    }
+    bitrates.push_back(layer_bitrate);
+  }
+  return bitrates;
+}
+
 bool VideoBitrateAllocation::operator==(
     const VideoBitrateAllocation& other) const {
   for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
diff --git a/api/video/video_bitrate_allocation.h b/api/video/video_bitrate_allocation.h
index b748b67..ce61734 100644
--- a/api/video/video_bitrate_allocation.h
+++ b/api/video/video_bitrate_allocation.h
@@ -15,7 +15,7 @@
 #include <string>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
@@ -62,6 +62,12 @@
   // layer with a defined bitrate.
   std::vector<uint32_t> GetTemporalLayerAllocation(size_t spatial_index) const;
 
+  // Returns one VideoBitrateAllocation for each spatial layer. This is used to
+  // configure simulcast streams. Note that the length of the returned vector is
+  // always kMaxSpatialLayers, the optional is unset for unused layers.
+  std::vector<absl::optional<VideoBitrateAllocation>> GetSimulcastAllocations()
+      const;
+
   uint32_t get_sum_bps() const { return sum_; }  // Sum of all bitrates.
   uint32_t get_sum_kbps() const {
     // Round down to not exceed the allocated bitrate.
@@ -77,7 +83,7 @@
 
  private:
   uint32_t sum_;
-  rtc::Optional<uint32_t> bitrates_[kMaxSpatialLayers][kMaxTemporalStreams];
+  absl::optional<uint32_t> bitrates_[kMaxSpatialLayers][kMaxTemporalStreams];
 };
 
 }  // namespace webrtc
diff --git a/api/video/video_content_type.cc b/api/video/video_content_type.cc
index 149b4f9..9ba3ece 100644
--- a/api/video/video_content_type.cc
+++ b/api/video/video_content_type.cc
@@ -68,19 +68,16 @@
   return true;
 }
 
-uint8_t GetExperimentId(
-    const VideoContentType& content_type) {
+uint8_t GetExperimentId(const VideoContentType& content_type) {
   return (static_cast<uint8_t>(content_type) & kExperimentBitsMask) >>
          kExperimentShift;
 }
-uint8_t GetSimulcastId(
-    const VideoContentType& content_type) {
+uint8_t GetSimulcastId(const VideoContentType& content_type) {
   return (static_cast<uint8_t>(content_type) & kSimulcastBitsMask) >>
          kSimulcastShift;
 }
 
-bool IsScreenshare(
-    const VideoContentType& content_type) {
+bool IsScreenshare(const VideoContentType& content_type) {
   return (static_cast<uint8_t>(content_type) & kScreenshareBitsMask) > 0;
 }
 
diff --git a/api/video/video_frame.cc b/api/video/video_frame.cc
index 93b3c9c..5521ad8 100644
--- a/api/video/video_frame.cc
+++ b/api/video/video_frame.cc
@@ -15,6 +15,55 @@
 
 namespace webrtc {
 
+VideoFrame::Builder::Builder() = default;
+
+VideoFrame::Builder::~Builder() = default;
+
+VideoFrame VideoFrame::Builder::build() {
+  return VideoFrame(video_frame_buffer_, timestamp_us_, timestamp_rtp_,
+                    ntp_time_ms_, rotation_, color_space_);
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_video_frame_buffer(
+    const rtc::scoped_refptr<VideoFrameBuffer>& buffer) {
+  video_frame_buffer_ = buffer;
+  return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_timestamp_ms(
+    int64_t timestamp_ms) {
+  timestamp_us_ = timestamp_ms * rtc::kNumMicrosecsPerMillisec;
+  return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_timestamp_us(
+    int64_t timestamp_us) {
+  timestamp_us_ = timestamp_us;
+  return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_timestamp_rtp(
+    uint32_t timestamp_rtp) {
+  timestamp_rtp_ = timestamp_rtp;
+  return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_ntp_time_ms(int64_t ntp_time_ms) {
+  ntp_time_ms_ = ntp_time_ms;
+  return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_rotation(VideoRotation rotation) {
+  rotation_ = rotation;
+  return *this;
+}
+
+VideoFrame::Builder& VideoFrame::Builder::set_color_space(
+    const ColorSpace& color_space) {
+  color_space_ = color_space;
+  return *this;
+}
+
 VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
                        webrtc::VideoRotation rotation,
                        int64_t timestamp_us)
@@ -25,17 +74,30 @@
       rotation_(rotation) {}
 
 VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
-                       uint32_t timestamp,
+                       uint32_t timestamp_rtp,
                        int64_t render_time_ms,
                        VideoRotation rotation)
     : video_frame_buffer_(buffer),
-      timestamp_rtp_(timestamp),
+      timestamp_rtp_(timestamp_rtp),
       ntp_time_ms_(0),
       timestamp_us_(render_time_ms * rtc::kNumMicrosecsPerMillisec),
       rotation_(rotation) {
   RTC_DCHECK(buffer);
 }
 
+VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
+                       int64_t timestamp_us,
+                       uint32_t timestamp_rtp,
+                       int64_t ntp_time_ms,
+                       VideoRotation rotation,
+                       const absl::optional<ColorSpace>& color_space)
+    : video_frame_buffer_(buffer),
+      timestamp_rtp_(timestamp_rtp),
+      ntp_time_ms_(ntp_time_ms),
+      timestamp_us_(timestamp_us),
+      rotation_(rotation),
+      color_space_(color_space) {}
+
 VideoFrame::~VideoFrame() = default;
 
 VideoFrame::VideoFrame(const VideoFrame&) = default;
diff --git a/api/video/video_frame.h b/api/video/video_frame.h
index a72bef1..dcb533e 100644
--- a/api/video/video_frame.h
+++ b/api/video/video_frame.h
@@ -13,23 +13,46 @@
 
 #include <stdint.h>
 
-#include "api/video/video_rotation.h"
+#include "absl/types/optional.h"
+#include "api/video/color_space.h"
 #include "api/video/video_frame_buffer.h"
+#include "api/video/video_rotation.h"
 
 namespace webrtc {
 
 class VideoFrame {
  public:
-  // TODO(nisse): This constructor is consistent with the now deleted
-  // cricket::WebRtcVideoFrame. We should consider whether or not we
-  // want to stick to this style and deprecate the other constructor.
+  // Preferred way of building VideoFrame objects.
+  class Builder {
+   public:
+    Builder();
+    ~Builder();
+
+    VideoFrame build();
+    Builder& set_video_frame_buffer(
+        const rtc::scoped_refptr<VideoFrameBuffer>& buffer);
+    Builder& set_timestamp_ms(int64_t timestamp_ms);
+    Builder& set_timestamp_us(int64_t timestamp_us);
+    Builder& set_timestamp_rtp(uint32_t timestamp_rtp);
+    Builder& set_ntp_time_ms(int64_t ntp_time_ms);
+    Builder& set_rotation(VideoRotation rotation);
+    Builder& set_color_space(const ColorSpace& color_space);
+
+   private:
+    rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_;
+    int64_t timestamp_us_ = 0;
+    uint32_t timestamp_rtp_ = 0;
+    int64_t ntp_time_ms_ = 0;
+    VideoRotation rotation_ = kVideoRotation_0;
+    absl::optional<ColorSpace> color_space_;
+  };
+
+  // To be deprecated. Migrate all use to Builder.
   VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
              webrtc::VideoRotation rotation,
              int64_t timestamp_us);
-
-  // Preferred constructor.
   VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
-             uint32_t timestamp,
+             uint32_t timestamp_rtp,
              int64_t render_time_ms,
              VideoRotation rotation);
 
@@ -87,6 +110,9 @@
   VideoRotation rotation() const { return rotation_; }
   void set_rotation(VideoRotation rotation) { rotation_ = rotation; }
 
+  // Set Color space when available.
+  absl::optional<ColorSpace> color_space() const { return color_space_; }
+
   // Get render time in milliseconds.
   // TODO(nisse): Deprecated. Migrate all users to timestamp_us().
   int64_t render_time_ms() const;
@@ -102,12 +128,20 @@
   }
 
  private:
+  VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
+             int64_t timestamp_us,
+             uint32_t timestamp_rtp,
+             int64_t ntp_time_ms,
+             VideoRotation rotation,
+             const absl::optional<ColorSpace>& color_space);
+
   // An opaque reference counted handle that stores the pixel data.
   rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_;
   uint32_t timestamp_rtp_;
   int64_t ntp_time_ms_;
   int64_t timestamp_us_;
   VideoRotation rotation_;
+  absl::optional<ColorSpace> color_space_;
 };
 
 }  // namespace webrtc
diff --git a/api/video/video_frame_buffer.cc b/api/video/video_frame_buffer.cc
index 867f249..41276be 100644
--- a/api/video/video_frame_buffer.cc
+++ b/api/video/video_frame_buffer.cc
@@ -45,6 +45,16 @@
   return static_cast<const I444BufferInterface*>(this);
 }
 
+I010BufferInterface* VideoFrameBuffer::GetI010() {
+  RTC_CHECK(type() == Type::kI010);
+  return static_cast<I010BufferInterface*>(this);
+}
+
+const I010BufferInterface* VideoFrameBuffer::GetI010() const {
+  RTC_CHECK(type() == Type::kI010);
+  return static_cast<const I010BufferInterface*>(this);
+}
+
 VideoFrameBuffer::Type I420BufferInterface::type() const {
   return Type::kI420;
 }
@@ -77,4 +87,16 @@
   return height();
 }
 
+VideoFrameBuffer::Type I010BufferInterface::type() const {
+  return Type::kI010;
+}
+
+int I010BufferInterface::ChromaWidth() const {
+  return (width() + 1) / 2;
+}
+
+int I010BufferInterface::ChromaHeight() const {
+  return (height() + 1) / 2;
+}
+
 }  // namespace webrtc
diff --git a/api/video/video_frame_buffer.h b/api/video/video_frame_buffer.h
index 2be7e0b..1e8169a 100644
--- a/api/video/video_frame_buffer.h
+++ b/api/video/video_frame_buffer.h
@@ -21,6 +21,7 @@
 class I420BufferInterface;
 class I420ABufferInterface;
 class I444BufferInterface;
+class I010BufferInterface;
 
 // Base class for frame buffers of different types of pixel format and storage.
 // The tag in type() indicates how the data is represented, and each type is
@@ -47,6 +48,7 @@
     kI420,
     kI420A,
     kI444,
+    kI010,
   };
 
   // This function specifies in what pixel format the data is stored in.
@@ -73,24 +75,21 @@
   const I420ABufferInterface* GetI420A() const;
   I444BufferInterface* GetI444();
   const I444BufferInterface* GetI444() const;
+  I010BufferInterface* GetI010();
+  const I010BufferInterface* GetI010() const;
 
  protected:
   ~VideoFrameBuffer() override {}
 };
 
-// This interface represents Type::kI420 and Type::kI444.
+// This interface represents planar formats.
 class PlanarYuvBuffer : public VideoFrameBuffer {
  public:
   virtual int ChromaWidth() const = 0;
   virtual int ChromaHeight() const = 0;
 
-  // Returns pointer to the pixel data for a given plane. The memory is owned by
-  // the VideoFrameBuffer object and must not be freed by the caller.
-  virtual const uint8_t* DataY() const = 0;
-  virtual const uint8_t* DataU() const = 0;
-  virtual const uint8_t* DataV() const = 0;
-
-  // Returns the number of bytes between successive rows for a given plane.
+  // Returns the number of steps(in terms of Data*() return type) between
+  // successive rows for a given plane.
   virtual int StrideY() const = 0;
   virtual int StrideU() const = 0;
   virtual int StrideV() const = 0;
@@ -99,7 +98,21 @@
   ~PlanarYuvBuffer() override {}
 };
 
-class I420BufferInterface : public PlanarYuvBuffer {
+// This interface represents 8-bit color depth formats: Type::kI420,
+// Type::kI420A and Type::kI444.
+class PlanarYuv8Buffer : public PlanarYuvBuffer {
+ public:
+  // Returns pointer to the pixel data for a given plane. The memory is owned by
+  // the VideoFrameBuffer object and must not be freed by the caller.
+  virtual const uint8_t* DataY() const = 0;
+  virtual const uint8_t* DataU() const = 0;
+  virtual const uint8_t* DataV() const = 0;
+
+ protected:
+  ~PlanarYuv8Buffer() override {}
+};
+
+class I420BufferInterface : public PlanarYuv8Buffer {
  public:
   Type type() const override;
 
@@ -122,7 +135,7 @@
   ~I420ABufferInterface() override {}
 };
 
-class I444BufferInterface : public PlanarYuvBuffer {
+class I444BufferInterface : public PlanarYuv8Buffer {
  public:
   Type type() const final;
 
@@ -133,6 +146,32 @@
   ~I444BufferInterface() override {}
 };
 
+// This interface represents 8-bit to 16-bit color depth formats: Type::kI010.
+class PlanarYuv16BBuffer : public PlanarYuvBuffer {
+ public:
+  // Returns pointer to the pixel data for a given plane. The memory is owned by
+  // the VideoFrameBuffer object and must not be freed by the caller.
+  virtual const uint16_t* DataY() const = 0;
+  virtual const uint16_t* DataU() const = 0;
+  virtual const uint16_t* DataV() const = 0;
+
+ protected:
+  ~PlanarYuv16BBuffer() override {}
+};
+
+// Represents Type::kI010, allocates 16 bits per pixel and fills 10 least
+// significant bits with color information.
+class I010BufferInterface : public PlanarYuv16BBuffer {
+ public:
+  Type type() const override;
+
+  int ChromaWidth() const final;
+  int ChromaHeight() const final;
+
+ protected:
+  ~I010BufferInterface() override {}
+};
+
 }  // namespace webrtc
 
 #endif  // API_VIDEO_VIDEO_FRAME_BUFFER_H_
diff --git a/api/video/video_sink_interface.h b/api/video/video_sink_interface.h
new file mode 100644
index 0000000..aac8b4a
--- /dev/null
+++ b/api/video/video_sink_interface.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 API_VIDEO_VIDEO_SINK_INTERFACE_H_
+#define API_VIDEO_VIDEO_SINK_INTERFACE_H_
+
+#include <rtc_base/checks.h>
+
+namespace rtc {
+
+template <typename VideoFrameT>
+class VideoSinkInterface {
+ public:
+  virtual ~VideoSinkInterface() = default;
+
+  virtual void OnFrame(const VideoFrameT& frame) = 0;
+
+  // Should be called by the source when it discards the frame due to rate
+  // limiting.
+  virtual void OnDiscardedFrame() {}
+};
+
+}  // namespace rtc
+
+#endif  // API_VIDEO_VIDEO_SINK_INTERFACE_H_
diff --git a/api/video/video_source_interface.cc b/api/video/video_source_interface.cc
new file mode 100644
index 0000000..70a86c3
--- /dev/null
+++ b/api/video/video_source_interface.cc
@@ -0,0 +1,19 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "api/video/video_source_interface.h"
+
+namespace rtc {
+
+VideoSinkWants::VideoSinkWants() = default;
+VideoSinkWants::VideoSinkWants(const VideoSinkWants&) = default;
+VideoSinkWants::~VideoSinkWants() = default;
+
+}  // namespace rtc
diff --git a/api/video/video_source_interface.h b/api/video/video_source_interface.h
new file mode 100644
index 0000000..4ee4719
--- /dev/null
+++ b/api/video/video_source_interface.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 API_VIDEO_VIDEO_SOURCE_INTERFACE_H_
+#define API_VIDEO_VIDEO_SOURCE_INTERFACE_H_
+
+#include <limits>
+
+#include "absl/types/optional.h"
+#include "api/video/video_sink_interface.h"
+
+namespace rtc {
+
+// VideoSinkWants is used for notifying the source of properties a video frame
+// should have when it is delivered to a certain sink.
+struct VideoSinkWants {
+  VideoSinkWants();
+  VideoSinkWants(const VideoSinkWants&);
+  ~VideoSinkWants();
+  // Tells the source whether the sink wants frames with rotation applied.
+  // By default, any rotation must be applied by the sink.
+  bool rotation_applied = false;
+
+  // Tells the source that the sink only wants black frames.
+  bool black_frames = false;
+
+  // Tells the source the maximum number of pixels the sink wants.
+  int max_pixel_count = std::numeric_limits<int>::max();
+  // Tells the source the desired number of pixels the sinks wants. This will
+  // typically be used when stepping the resolution up again when conditions
+  // have improved after an earlier downgrade. The source should select the
+  // closest resolution to this pixel count, but if max_pixel_count is set, it
+  // still sets the absolute upper bound.
+  absl::optional<int> target_pixel_count;
+  // Tells the source the maximum framerate the sink wants.
+  int max_framerate_fps = std::numeric_limits<int>::max();
+};
+
+template <typename VideoFrameT>
+class VideoSourceInterface {
+ public:
+  virtual void AddOrUpdateSink(VideoSinkInterface<VideoFrameT>* sink,
+                               const VideoSinkWants& wants) = 0;
+  // RemoveSink must guarantee that at the time the method returns,
+  // there is no current and no future calls to VideoSinkInterface::OnFrame.
+  virtual void RemoveSink(VideoSinkInterface<VideoFrameT>* sink) = 0;
+
+ protected:
+  // Non-public, since one shouldn't own sources via this interface.
+  virtual ~VideoSourceInterface() {}
+};
+
+}  // namespace rtc
+#endif  // API_VIDEO_VIDEO_SOURCE_INTERFACE_H_
diff --git a/api/video/video_stream_decoder.h b/api/video/video_stream_decoder.h
index 1c4c5ff..dff60d8 100644
--- a/api/video/video_stream_decoder.h
+++ b/api/video/video_stream_decoder.h
@@ -37,8 +37,8 @@
 
     // Called with the decoded frame.
     virtual void OnDecodedFrame(VideoFrame decodedImage,
-                                rtc::Optional<int> decode_time_ms,
-                                rtc::Optional<int> qp) = 0;
+                                absl::optional<int> decode_time_ms,
+                                absl::optional<int> qp) = 0;
   };
 
   virtual ~VideoStreamDecoder() = default;
diff --git a/api/video/video_stream_decoder_create.cc b/api/video/video_stream_decoder_create.cc
index e756096..d579255 100644
--- a/api/video/video_stream_decoder_create.cc
+++ b/api/video/video_stream_decoder_create.cc
@@ -10,7 +10,7 @@
 
 #include "api/video/video_stream_decoder_create.h"
 
-#include "rtc_base/ptr_util.h"
+#include "absl/memory/memory.h"
 #include "video/video_stream_decoder_impl.h"
 
 namespace webrtc {
@@ -18,7 +18,7 @@
     VideoStreamDecoder::Callbacks* callbacks,
     VideoDecoderFactory* decoder_factory,
     std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings) {
-  return rtc::MakeUnique<VideoStreamDecoderImpl>(callbacks, decoder_factory,
-                                                 std::move(decoder_settings));
+  return absl::make_unique<VideoStreamDecoderImpl>(callbacks, decoder_factory,
+                                                   std::move(decoder_settings));
 }
 }  // namespace webrtc
diff --git a/api/video/video_stream_encoder_interface.h b/api/video/video_stream_encoder_interface.h
new file mode 100644
index 0000000..44dc6f4
--- /dev/null
+++ b/api/video/video_stream_encoder_interface.h
@@ -0,0 +1,107 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 API_VIDEO_VIDEO_STREAM_ENCODER_INTERFACE_H_
+#define API_VIDEO_VIDEO_STREAM_ENCODER_INTERFACE_H_
+
+#include <vector>
+
+#include "api/rtpparameters.h"  // For DegradationPreference.
+#include "api/video/video_sink_interface.h"
+#include "api/video/video_source_interface.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/video_encoder_config.h"
+
+namespace webrtc {
+
+// TODO(nisse): Move full declaration to api/.
+class VideoBitrateAllocationObserver;
+
+// This interface represents a class responsible for creating and driving the
+// encoder(s) for a single video stream. It is also responsible for adaptation
+// decisions related to video quality, requesting reduced frame rate or
+// resolution from the VideoSource when needed.
+// TODO(bugs.webrtc.org/8830): This interface is under development. Changes
+// under consideration include:
+//
+// 1. Taking out responsibility for adaptation decisions, instead only reporting
+//    per-frame measurements to the decision maker.
+//
+// 2. Moving responsibility for simulcast and for software fallback into this
+//    class.
+class VideoStreamEncoderInterface : public rtc::VideoSinkInterface<VideoFrame> {
+ public:
+  // Interface for receiving encoded video frames and notifications about
+  // configuration changes.
+  class EncoderSink : public EncodedImageCallback {
+   public:
+    virtual void OnEncoderConfigurationChanged(
+        std::vector<VideoStream> streams,
+        int min_transmit_bitrate_bps) = 0;
+  };
+
+  ~VideoStreamEncoderInterface() override = default;
+
+  // Sets the source that will provide video frames to the VideoStreamEncoder's
+  // OnFrame method. |degradation_preference| control whether or not resolution
+  // or frame rate may be reduced. The VideoStreamEncoder registers itself with
+  // |source|, and signals adaptation decisions to the source in the form of
+  // VideoSinkWants.
+  // TODO(nisse): When adaptation logic is extracted from this class,
+  // it no longer needs to know the source.
+  virtual void SetSource(
+      rtc::VideoSourceInterface<VideoFrame>* source,
+      const DegradationPreference& degradation_preference) = 0;
+
+  // Sets the |sink| that gets the encoded frames. |rotation_applied| means
+  // that the source must support rotation. Only set |rotation_applied| if the
+  // remote side does not support the rotation extension.
+  virtual void SetSink(EncoderSink* sink, bool rotation_applied) = 0;
+
+  // Sets an initial bitrate, later overriden by OnBitrateUpdated. Mainly
+  // affects the resolution of the initial key frame: If incoming frames are
+  // larger than reasonable for the start bitrate, and scaling is enabled,
+  // VideoStreamEncoder asks the source to scale down and drops a few initial
+  // frames.
+  // TODO(nisse): This is a poor interface, and mixes bandwidth estimation and
+  // codec configuration in an undesired way. For the actual send bandwidth, we
+  // should always be somewhat conservative, but we may nevertheless want to let
+  // the application configure a more optimistic quality for the initial
+  // resolution. Should be replaced by a construction time setting.
+  virtual void SetStartBitrate(int start_bitrate_bps) = 0;
+
+  // Request a key frame. Used for signalling from the remote receiver.
+  virtual void SendKeyFrame() = 0;
+
+  // Set the currently estimated network properties. A |bitrate_bps|
+  // of zero pauses the encoder.
+  virtual void OnBitrateUpdated(uint32_t bitrate_bps,
+                                uint8_t fraction_lost,
+                                int64_t round_trip_time_ms) = 0;
+
+  // Register observer for the bitrate allocation between the temporal
+  // and spatial layers.
+  virtual void SetBitrateAllocationObserver(
+      VideoBitrateAllocationObserver* bitrate_observer) = 0;
+
+  // Creates and configures an encoder with the given |config|. The
+  // |max_data_payload_length| is used to support single NAL unit
+  // packetization for H.264.
+  virtual void ConfigureEncoder(VideoEncoderConfig config,
+                                size_t max_data_payload_length) = 0;
+
+  // Permanently stop encoding. After this method has returned, it is
+  // guaranteed that no encoded frames will be delivered to the sink.
+  virtual void Stop() = 0;
+};
+
+}  // namespace webrtc
+
+#endif  // API_VIDEO_VIDEO_STREAM_ENCODER_INTERFACE_H_
diff --git a/api/video/video_timing.cc b/api/video/video_timing.cc
index 3ccbe4e..40de011 100644
--- a/api/video/video_timing.cc
+++ b/api/video/video_timing.cc
@@ -10,7 +10,7 @@
 
 #include "api/video/video_timing.h"
 
-#include <sstream>
+#include "rtc_base/strings/string_builder.h"
 
 namespace webrtc {
 
@@ -28,7 +28,7 @@
       decode_start_ms(-1),
       decode_finish_ms(-1),
       render_time_ms(-1),
-      flags(TimingFrameFlags::kDefault) {}
+      flags(VideoSendTiming::kNotTriggered) {}
 
 int64_t TimingFrameInfo::EndToEndDelay() const {
   return capture_time_ms >= 0 ? decode_finish_ms - capture_time_ms : -1;
@@ -48,31 +48,34 @@
 }
 
 bool TimingFrameInfo::IsOutlier() const {
-  return !IsInvalid() && (flags & TimingFrameFlags::kTriggeredBySize);
+  return !IsInvalid() && (flags & VideoSendTiming::kTriggeredBySize);
 }
 
 bool TimingFrameInfo::IsTimerTriggered() const {
-  return !IsInvalid() && (flags & TimingFrameFlags::kTriggeredByTimer);
+  return !IsInvalid() && (flags & VideoSendTiming::kTriggeredByTimer);
 }
 
 bool TimingFrameInfo::IsInvalid() const {
-  return flags == TimingFrameFlags::kInvalid;
+  return flags == VideoSendTiming::kInvalid;
 }
 
 std::string TimingFrameInfo::ToString() const {
-  std::stringstream out;
   if (IsInvalid()) {
-    out << "";
-  } else {
-    out << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms
-        << ',' << encode_finish_ms << ',' << packetization_finish_ms << ','
-        << pacer_exit_ms << ',' << network_timestamp_ms << ','
-        << network2_timestamp_ms << ',' << receive_start_ms << ','
-        << receive_finish_ms << ',' << decode_start_ms << ','
-        << decode_finish_ms << ',' << render_time_ms << ','
-        << IsOutlier() << ',' << IsTimerTriggered();
+    return "";
   }
-  return out.str();
+
+  char buf[1024];
+  rtc::SimpleStringBuilder sb(buf);
+
+  sb << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms << ','
+     << encode_finish_ms << ',' << packetization_finish_ms << ','
+     << pacer_exit_ms << ',' << network_timestamp_ms << ','
+     << network2_timestamp_ms << ',' << receive_start_ms << ','
+     << receive_finish_ms << ',' << decode_start_ms << ',' << decode_finish_ms
+     << ',' << render_time_ms << ',' << IsOutlier() << ','
+     << IsTimerTriggered();
+
+  return sb.str();
 }
 
 }  // namespace webrtc
diff --git a/api/video/video_timing.h b/api/video/video_timing.h
index ab8cd99..e787a45 100644
--- a/api/video/video_timing.h
+++ b/api/video/video_timing.h
@@ -21,20 +21,17 @@
 
 namespace webrtc {
 
-enum TimingFrameFlags : uint8_t {
-  kNotTriggered = 0,           // Timing info valid, but not to be transmitted.
-                               // Used on send-side only.
-  // TODO(ilnik): Delete compatibility alias.
-  // Used to be sent over the wire, for the old protocol.
-  kDefault = 0,                // Old name, for API compatibility.
-  kTriggeredByTimer = 1 << 0,  // Frame marked for tracing by periodic timer.
-  kTriggeredBySize = 1 << 1,   // Frame marked for tracing due to size.
-  kInvalid = std::numeric_limits<uint8_t>::max()  // Invalid, ignore!
-};
-
 // Video timing timestamps in ms counted from capture_time_ms of a frame.
 // This structure represents data sent in video-timing RTP header extension.
 struct VideoSendTiming {
+  enum TimingFrameFlags : uint8_t {
+    kNotTriggered = 0,  // Timing info valid, but not to be transmitted.
+                        // Used on send-side only.
+    kTriggeredByTimer = 1 << 0,  // Frame marked for tracing by periodic timer.
+    kTriggeredBySize = 1 << 1,   // Frame marked for tracing due to size.
+    kInvalid = std::numeric_limits<uint8_t>::max()  // Invalid, ignore!
+  };
+
   // Offsets of the fields in the RTP header extension, counting from the first
   // byte after the one-byte header.
   static constexpr uint8_t kFlagsOffset = 0;
diff --git a/api/videosinkinterface.h b/api/videosinkinterface.h
index 2399320..21957b4 100644
--- a/api/videosinkinterface.h
+++ b/api/videosinkinterface.h
@@ -11,22 +11,8 @@
 #ifndef API_VIDEOSINKINTERFACE_H_
 #define API_VIDEOSINKINTERFACE_H_
 
-#include <rtc_base/checks.h>
-
-namespace rtc {
-
-template <typename VideoFrameT>
-class VideoSinkInterface {
- public:
-  virtual ~VideoSinkInterface() {}
-
-  virtual void OnFrame(const VideoFrameT& frame) = 0;
-
-  // Should be called by the source when it discards the frame due to rate
-  // limiting.
-  virtual void OnDiscardedFrame() {}
-};
-
-}  // namespace rtc
+// TODO(nisse): Place holder for moved file. Delete after applications are
+// updated.
+#include "api/video/video_sink_interface.h"
 
 #endif  // API_VIDEOSINKINTERFACE_H_
diff --git a/api/videosourceinterface.h b/api/videosourceinterface.h
index 065e2dc..aabe379 100644
--- a/api/videosourceinterface.h
+++ b/api/videosourceinterface.h
@@ -11,50 +11,8 @@
 #ifndef API_VIDEOSOURCEINTERFACE_H_
 #define API_VIDEOSOURCEINTERFACE_H_
 
-#include <limits>
+// TODO(nisse): Place holder for moved file. Delete after applications are
+// updated.
+#include "api/video/video_source_interface.h"
 
-#include "api/optional.h"
-#include "api/videosinkinterface.h"
-
-namespace rtc {
-
-// VideoSinkWants is used for notifying the source of properties a video frame
-// should have when it is delivered to a certain sink.
-struct VideoSinkWants {
-  VideoSinkWants();
-  VideoSinkWants(const VideoSinkWants&);
-  ~VideoSinkWants();
-  // Tells the source whether the sink wants frames with rotation applied.
-  // By default, any rotation must be applied by the sink.
-  bool rotation_applied = false;
-
-  // Tells the source that the sink only wants black frames.
-  bool black_frames = false;
-
-  // Tells the source the maximum number of pixels the sink wants.
-  int max_pixel_count = std::numeric_limits<int>::max();
-  // Tells the source the desired number of pixels the sinks wants. This will
-  // typically be used when stepping the resolution up again when conditions
-  // have improved after an earlier downgrade. The source should select the
-  // closest resolution to this pixel count, but if max_pixel_count is set, it
-  // still sets the absolute upper bound.
-  rtc::Optional<int> target_pixel_count;
-  // Tells the source the maximum framerate the sink wants.
-  int max_framerate_fps = std::numeric_limits<int>::max();
-};
-
-template <typename VideoFrameT>
-class VideoSourceInterface {
- public:
-  virtual void AddOrUpdateSink(VideoSinkInterface<VideoFrameT>* sink,
-                               const VideoSinkWants& wants) = 0;
-  // RemoveSink must guarantee that at the time the method returns,
-  // there is no current and no future calls to VideoSinkInterface::OnFrame.
-  virtual void RemoveSink(VideoSinkInterface<VideoFrameT>* sink) = 0;
-
- protected:
-  virtual ~VideoSourceInterface() {}
-};
-
-}  // namespace rtc
 #endif  // API_VIDEOSOURCEINTERFACE_H_
diff --git a/api/videosourceproxy.h b/api/videosourceproxy.h
index f2d8be0..dbd9045 100644
--- a/api/videosourceproxy.h
+++ b/api/videosourceproxy.h
@@ -11,8 +11,8 @@
 #ifndef API_VIDEOSOURCEPROXY_H_
 #define API_VIDEOSOURCEPROXY_H_
 
-#include "api/proxy.h"
 #include "api/mediastreaminterface.h"
+#include "api/proxy.h"
 
 namespace webrtc {
 
@@ -21,19 +21,19 @@
 // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods
 // are called on is an implementation detail.
 BEGIN_PROXY_MAP(VideoTrackSource)
-  PROXY_SIGNALING_THREAD_DESTRUCTOR()
-  PROXY_CONSTMETHOD0(SourceState, state)
-  PROXY_CONSTMETHOD0(bool, remote)
-  PROXY_CONSTMETHOD0(bool, is_screencast)
-  PROXY_CONSTMETHOD0(rtc::Optional<bool>, needs_denoising)
-  PROXY_METHOD1(bool, GetStats, Stats*)
-  PROXY_WORKER_METHOD2(void,
-                       AddOrUpdateSink,
-                       rtc::VideoSinkInterface<VideoFrame>*,
-                       const rtc::VideoSinkWants&)
-  PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*)
-  PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
-  PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(SourceState, state)
+PROXY_CONSTMETHOD0(bool, remote)
+PROXY_CONSTMETHOD0(bool, is_screencast)
+PROXY_CONSTMETHOD0(absl::optional<bool>, needs_denoising)
+PROXY_METHOD1(bool, GetStats, Stats*)
+PROXY_WORKER_METHOD2(void,
+                     AddOrUpdateSink,
+                     rtc::VideoSinkInterface<VideoFrame>*,
+                     const rtc::VideoSinkWants&)
+PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*)
+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*)
+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*)
 END_PROXY_MAP()
 
 }  // namespace webrtc
diff --git a/audio/BUILD.gn b/audio/BUILD.gn
index 8981dd3..22ceeb6 100644
--- a/audio/BUILD.gn
+++ b/audio/BUILD.gn
@@ -49,7 +49,6 @@
     "../api:array_view",
     "../api:call_api",
     "../api:libjingle_peerconnection_api",
-    "../api:optional",
     "../api:transport_api",
     "../api/audio:aec3_factory",
     "../api/audio:audio_frame_api",
@@ -87,6 +86,8 @@
     "../system_wrappers:field_trial_api",
     "../system_wrappers:metrics_api",
     "utility:audio_frame_operations",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 if (rtc_include_tests) {
@@ -128,6 +129,7 @@
       ":audio_end_to_end_test",
       "../api:mock_audio_mixer",
       "../api/audio:audio_frame_api",
+      "../api/units:time_delta",
       "../call:mock_call_interfaces",
       "../call:mock_rtp_interfaces",
       "../call:rtp_interfaces",
@@ -154,6 +156,7 @@
       "../test:test_support",
       "utility:utility_tests",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/memory",
     ]
 
     if (!rtc_use_memcheck) {
@@ -257,6 +260,7 @@
       "../test:test_common",
       "../test:test_main",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/memory",
     ]
 
     data = [
diff --git a/audio/audio_level.cc b/audio/audio_level.cc
index f1c5b68..3b8df97 100644
--- a/audio/audio_level.cc
+++ b/audio/audio_level.cc
@@ -47,10 +47,12 @@
 
 void AudioLevel::ComputeLevel(const AudioFrame& audioFrame, double duration) {
   // Check speech level (works for 2 channels as well)
-  int16_t abs_value = audioFrame.muted() ? 0 :
-      WebRtcSpl_MaxAbsValueW16(
-          audioFrame.data(),
-          audioFrame.samples_per_channel_ * audioFrame.num_channels_);
+  int16_t abs_value =
+      audioFrame.muted()
+          ? 0
+          : WebRtcSpl_MaxAbsValueW16(
+                audioFrame.data(),
+                audioFrame.samples_per_channel_ * audioFrame.num_channels_);
 
   // Protect member access using a lock since this method is called on a
   // dedicated audio thread in the RecordedDataIsAvailable() callback.
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index 352261e..6f43576 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -102,8 +102,7 @@
     const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
     webrtc::RtcEventLog* event_log,
     std::unique_ptr<voe::ChannelProxy> channel_proxy)
-    : audio_state_(audio_state),
-      channel_proxy_(std::move(channel_proxy)) {
+    : audio_state_(audio_state), channel_proxy_(std::move(channel_proxy)) {
   RTC_LOG(LS_INFO) << "AudioReceiveStream: " << config.rtp.remote_ssrc;
   RTC_DCHECK(receiver_controller);
   RTC_DCHECK(packet_router);
@@ -120,9 +119,8 @@
   channel_proxy_->RegisterReceiverCongestionControlObjects(packet_router);
 
   // Register with transport.
-  rtp_stream_receiver_ =
-      receiver_controller->CreateReceiver(config.rtp.remote_ssrc,
-                                          channel_proxy_.get());
+  rtp_stream_receiver_ = receiver_controller->CreateReceiver(
+      config.rtp.remote_ssrc, channel_proxy_.get());
 
   ConfigureStream(this, config, true);
 }
@@ -257,7 +255,7 @@
   return config_.rtp.remote_ssrc;
 }
 
-rtc::Optional<Syncable::Info> AudioReceiveStream::GetInfo() const {
+absl::optional<Syncable::Info> AudioReceiveStream::GetInfo() const {
   RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
   Syncable::Info info;
 
@@ -270,14 +268,12 @@
   if (!rtp_receiver->GetLatestTimestamps(
           &info.latest_received_capture_timestamp,
           &info.latest_receive_time_ms)) {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
   if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs,
-                          &info.capture_time_ntp_frac,
-                          nullptr,
-                          nullptr,
+                          &info.capture_time_ntp_frac, nullptr, nullptr,
                           &info.capture_time_source_clock) != 0) {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
 
   info.current_delay_ms = channel_proxy_->GetDelayEstimate();
@@ -329,8 +325,8 @@
   return config_;
 }
 
-const AudioSendStream*
-    AudioReceiveStream::GetAssociatedSendStreamForTesting() const {
+const AudioSendStream* AudioReceiveStream::GetAssociatedSendStreamForTesting()
+    const {
   RTC_DCHECK_RUN_ON(&worker_thread_checker_);
   return associated_send_stream_;
 }
@@ -363,6 +359,14 @@
   if (first_time || old_config.rtp.local_ssrc != new_config.rtp.local_ssrc) {
     channel_proxy->SetLocalSSRC(new_config.rtp.local_ssrc);
   }
+
+  if (first_time) {
+    channel_proxy->SetRemoteSSRC(new_config.rtp.remote_ssrc);
+  } else {
+    // Remote ssrc can't be changed mid-stream.
+    RTC_DCHECK_EQ(old_config.rtp.remote_ssrc, new_config.rtp.remote_ssrc);
+  }
+
   // TODO(solenberg): Config NACK history window (which is a packet count),
   // using the actual packet size for the configured codec.
   if (first_time || old_config.rtp.nack.rtp_history_ms !=
diff --git a/audio/audio_receive_stream.h b/audio/audio_receive_stream.h
index 09007f0..64552e3 100644
--- a/audio/audio_receive_stream.h
+++ b/audio/audio_receive_stream.h
@@ -80,7 +80,7 @@
 
   // Syncable
   int id() const override;
-  rtc::Optional<Syncable::Info> GetInfo() const override;
+  absl::optional<Syncable::Info> GetInfo() const override;
   uint32_t GetPlayoutTimestamp() const override;
   void SetMinimumPlayoutDelay(int delay_ms) override;
 
diff --git a/audio/audio_receive_stream_unittest.cc b/audio/audio_receive_stream_unittest.cc
index fa663fe..51635f6 100644
--- a/audio/audio_receive_stream_unittest.cc
+++ b/audio/audio_receive_stream_unittest.cc
@@ -59,18 +59,16 @@
 const double kTotalOutputEnergy = 0.25;
 const double kTotalOutputDuration = 0.5;
 
-const CallStatistics kCallStats = {
-    345,  678,  901, 234, -12, 3456, 7890, 567, 890, 123};
-const CodecInst kCodecInst = {
-    123, "codec_name_recv", 96000, -187, 0, -103};
+const CallStatistics kCallStats = {345,  678,  901, 234, -12,
+                                   3456, 7890, 567, 890, 123};
+const CodecInst kCodecInst = {123, "codec_name_recv", 96000, -187, 0, -103};
 const NetworkStatistics kNetworkStats = {
     123, 456, false, 789012, 3456, 123, 456, 0,  {}, 789, 12,
     345, 678, 901,   0,      -1,   -1,  -1,  -1, -1, 0};
 const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
 
 struct ConfigHelper {
-  ConfigHelper()
-      : ConfigHelper(new rtc::RefCountedObject<MockAudioMixer>()) {}
+  ConfigHelper() : ConfigHelper(new rtc::RefCountedObject<MockAudioMixer>()) {}
 
   explicit ConfigHelper(rtc::scoped_refptr<MockAudioMixer> audio_mixer)
       : audio_mixer_(audio_mixer) {
@@ -85,25 +83,24 @@
 
     channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>();
     EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kLocalSsrc)).Times(1);
+    EXPECT_CALL(*channel_proxy_, SetRemoteSSRC(kRemoteSsrc)).Times(1);
     EXPECT_CALL(*channel_proxy_, SetNACKStatus(true, 15)).Times(1);
     EXPECT_CALL(*channel_proxy_,
-        RegisterReceiverCongestionControlObjects(&packet_router_))
-            .Times(1);
+                RegisterReceiverCongestionControlObjects(&packet_router_))
+        .Times(1);
     EXPECT_CALL(*channel_proxy_, ResetReceiverCongestionControlObjects())
         .Times(1);
     EXPECT_CALL(*channel_proxy_, RegisterTransport(nullptr)).Times(2);
     testing::Expectation expect_set =
-        EXPECT_CALL(*channel_proxy_, SetRtcEventLog(&event_log_))
-            .Times(1);
+        EXPECT_CALL(*channel_proxy_, SetRtcEventLog(&event_log_)).Times(1);
     EXPECT_CALL(*channel_proxy_, SetRtcEventLog(testing::IsNull()))
         .Times(1)
         .After(expect_set);
     EXPECT_CALL(*channel_proxy_, DisassociateSendChannel()).Times(1);
     EXPECT_CALL(*channel_proxy_, SetReceiveCodecs(_))
-        .WillRepeatedly(
-            Invoke([](const std::map<int, SdpAudioFormat>& codecs) {
-              EXPECT_THAT(codecs, testing::IsEmpty());
-            }));
+        .WillRepeatedly(Invoke([](const std::map<int, SdpAudioFormat>& codecs) {
+          EXPECT_THAT(codecs, testing::IsEmpty());
+        }));
 
     stream_config_.rtp.local_ssrc = kLocalSsrc;
     stream_config_.rtp.remote_ssrc = kRemoteSsrc;
@@ -119,11 +116,8 @@
   std::unique_ptr<internal::AudioReceiveStream> CreateAudioReceiveStream() {
     return std::unique_ptr<internal::AudioReceiveStream>(
         new internal::AudioReceiveStream(
-            &rtp_stream_receiver_controller_,
-            &packet_router_,
-            stream_config_,
-            audio_state_,
-            &event_log_,
+            &rtp_stream_receiver_controller_, &packet_router_, stream_config_,
+            audio_state_, &event_log_,
             std::unique_ptr<voe::ChannelProxy>(channel_proxy_)));
   }
 
@@ -322,7 +316,7 @@
   ConfigHelper helper;
   auto recv_stream = helper.CreateAudioReceiveStream();
   EXPECT_CALL(*helper.channel_proxy(),
-      SetChannelOutputVolumeScaling(FloatEq(0.765f)));
+              SetChannelOutputVolumeScaling(FloatEq(0.765f)));
   recv_stream->SetGain(0.765f);
 }
 
@@ -370,10 +364,10 @@
   new_config.rtp.nack.rtp_history_ms = 300 + 20;
   new_config.rtp.extensions.clear();
   new_config.rtp.extensions.push_back(
-        RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId + 1));
-  new_config.rtp.extensions.push_back(RtpExtension(
-        RtpExtension::kTransportSequenceNumberUri,
-        kTransportSequenceNumberId + 1));
+      RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId + 1));
+  new_config.rtp.extensions.push_back(
+      RtpExtension(RtpExtension::kTransportSequenceNumberUri,
+                   kTransportSequenceNumberId + 1));
   new_config.decoder_map.emplace(1, SdpAudioFormat("foo", 8000, 1));
 
   MockVoEChannelProxy& channel_proxy = *helper.channel_proxy();
diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc
index 8798d43..de1be2c 100644
--- a/audio/audio_send_stream.cc
+++ b/audio/audio_send_stream.cc
@@ -91,7 +91,7 @@
     BitrateAllocator* bitrate_allocator,
     RtcEventLog* event_log,
     RtcpRttStats* rtcp_rtt_stats,
-    const rtc::Optional<RtpState>& suspended_rtp_state,
+    const absl::optional<RtpState>& suspended_rtp_state,
     TimeInterval* overall_call_lifetime)
     : AudioSendStream(config,
                       audio_state,
@@ -115,7 +115,7 @@
     BitrateAllocator* bitrate_allocator,
     RtcEventLog* event_log,
     RtcpRttStats* rtcp_rtt_stats,
-    const rtc::Optional<RtpState>& suspended_rtp_state,
+    const absl::optional<RtpState>& suspended_rtp_state,
     TimeInterval* overall_call_lifetime,
     std::unique_ptr<voe::ChannelProxy> channel_proxy)
     : worker_queue_(worker_queue),
@@ -218,8 +218,7 @@
                                  new_config.rtp.nack.rtp_history_ms / 20);
   }
 
-  if (first_time ||
-      new_config.send_transport != old_config.send_transport) {
+  if (first_time || new_config.send_transport != old_config.send_transport) {
     if (old_config.send_transport) {
       channel_proxy->RegisterTransport(nullptr);
     }
@@ -242,13 +241,17 @@
   }
   bool transport_seq_num_id_changed =
       new_ids.transport_sequence_number != old_ids.transport_sequence_number;
-  if (first_time || transport_seq_num_id_changed) {
+  if (first_time ||
+      (transport_seq_num_id_changed &&
+       !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"))) {
     if (!first_time) {
       channel_proxy->ResetSenderCongestionControlObjects();
     }
 
     RtcpBandwidthObserver* bandwidth_observer = nullptr;
-    bool has_transport_sequence_number = new_ids.transport_sequence_number != 0;
+    bool has_transport_sequence_number =
+        new_ids.transport_sequence_number != 0 &&
+        !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC");
     if (has_transport_sequence_number) {
       channel_proxy->EnableSendTransportSequenceNumber(
           new_ids.transport_sequence_number);
@@ -287,10 +290,12 @@
   }
 
   bool has_transport_sequence_number =
-      FindExtensionIds(config_.rtp.extensions).transport_sequence_number != 0;
+      FindExtensionIds(config_.rtp.extensions).transport_sequence_number != 0 &&
+      !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC");
   if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1 &&
       (has_transport_sequence_number ||
-       !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) {
+       !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe") ||
+       webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC"))) {
     // Audio BWE is enabled.
     transport_->packet_sender()->SetAccountForAudioPackets(true);
     ConfigureBitrateObserver(config_.min_bitrate_bps, config_.max_bitrate_bps,
@@ -321,7 +326,8 @@
 }
 
 bool AudioSendStream::SendTelephoneEvent(int payload_type,
-                                         int payload_frequency, int event,
+                                         int payload_frequency,
+                                         int event,
                                          int duration_ms) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type,
@@ -404,14 +410,19 @@
                                            uint8_t fraction_loss,
                                            int64_t rtt,
                                            int64_t bwe_period_ms) {
+  // Audio transport feedback will not be reported in this mode, instead update
+  // acknowledged bitrate estimator with the bitrate allocated for audio.
+  if (webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC")) {
+    transport_->SetAllocatedBitrateWithoutFeedback(bitrate_bps);
+  }
+
   // A send stream may be allocated a bitrate of zero if the allocator decides
   // to disable it. For now we ignore this decision and keep sending on min
   // bitrate.
   if (bitrate_bps == 0) {
     bitrate_bps = config_.min_bitrate_bps;
   }
-  RTC_DCHECK_GE(bitrate_bps,
-                static_cast<uint32_t>(config_.min_bitrate_bps));
+  RTC_DCHECK_GE(bitrate_bps, static_cast<uint32_t>(config_.min_bitrate_bps));
   // The bitrate allocator might allocate an higher than max configured bitrate
   // if there is room, to allow for, as example, extra FEC. Ignore that for now.
   const uint32_t max_bitrate_bps = config_.max_bitrate_bps;
@@ -440,8 +451,8 @@
 void AudioSendStream::OnPacketFeedbackVector(
     const std::vector<PacketFeedback>& packet_feedback_vector) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
-  rtc::Optional<float> plr;
-  rtc::Optional<float> rplr;
+  absl::optional<float> plr;
+  absl::optional<float> rplr;
   {
     rtc::CritScope lock(&packet_loss_tracker_cs_);
     packet_loss_tracker_.OnPacketFeedbackVector(packet_feedback_vector);
@@ -514,9 +525,17 @@
                        << rtc::ToString(spec.format);
     return false;
   }
+
+  // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is
+  // not enabled, do not update target audio bitrate if we are in
+  // WebRTC-Audio-SendSideBwe-For-Video experiment
+  const bool do_not_update_target_bitrate =
+      !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") &&
+      webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") &&
+      !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number;
   // If a bitrate has been specified for the codec, use it over the
   // codec's default.
-  if (spec.target_bitrate_bps) {
+  if (!do_not_update_target_bitrate && spec.target_bitrate_bps) {
     encoder->OnReceivedTargetAudioBitrate(*spec.target_bitrate_bps);
   }
 
@@ -579,11 +598,19 @@
     return SetupSendCodec(stream, new_config);
   }
 
-  const rtc::Optional<int>& new_target_bitrate_bps =
+  // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is
+  // not enabled, do not update target audio bitrate if we are in
+  // WebRTC-Audio-SendSideBwe-For-Video experiment
+  const bool do_not_update_target_bitrate =
+      !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") &&
+      webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") &&
+      !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number;
+
+  const absl::optional<int>& new_target_bitrate_bps =
       new_config.send_codec_spec->target_bitrate_bps;
   // If a bitrate has been specified for the codec, use it over the
   // codec's default.
-  if (new_target_bitrate_bps &&
+  if (!do_not_update_target_bitrate && new_target_bitrate_bps &&
       new_target_bitrate_bps !=
           old_config.send_codec_spec->target_bitrate_bps) {
     CallEncoder(stream->channel_proxy_, [&](AudioEncoder* encoder) {
diff --git a/audio/audio_send_stream.h b/audio/audio_send_stream.h
index c51c7a3..ba87202 100644
--- a/audio/audio_send_stream.h
+++ b/audio/audio_send_stream.h
@@ -49,7 +49,7 @@
                   BitrateAllocator* bitrate_allocator,
                   RtcEventLog* event_log,
                   RtcpRttStats* rtcp_rtt_stats,
-                  const rtc::Optional<RtpState>& suspended_rtp_state,
+                  const absl::optional<RtpState>& suspended_rtp_state,
                   TimeInterval* overall_call_lifetime);
   // For unit tests, which need to supply a mock channel proxy.
   AudioSendStream(const webrtc::AudioSendStream::Config& config,
@@ -59,7 +59,7 @@
                   BitrateAllocator* bitrate_allocator,
                   RtcEventLog* event_log,
                   RtcpRttStats* rtcp_rtt_stats,
-                  const rtc::Optional<RtpState>& suspended_rtp_state,
+                  const absl::optional<RtpState>& suspended_rtp_state,
                   TimeInterval* overall_call_lifetime,
                   std::unique_ptr<voe::ChannelProxy> channel_proxy);
   ~AudioSendStream() override;
@@ -70,7 +70,9 @@
   void Start() override;
   void Stop() override;
   void SendAudioData(std::unique_ptr<AudioFrame> audio_frame) override;
-  bool SendTelephoneEvent(int payload_type, int payload_frequency, int event,
+  bool SendTelephoneEvent(int payload_type,
+                          int payload_frequency,
+                          int event,
                           int duration_ms) override;
   void SetMuted(bool muted) override;
   webrtc::AudioSendStream::Stats GetStats() const override;
@@ -146,7 +148,7 @@
       RTC_GUARDED_BY(&packet_loss_tracker_cs_);
 
   RtpRtcp* rtp_rtcp_module_;
-  rtc::Optional<RtpState> const suspended_rtp_state_;
+  absl::optional<RtpState> const suspended_rtp_state_;
 
   std::unique_ptr<TimedTransport> timed_send_transport_adapter_;
   TimeInterval active_lifetime_;
diff --git a/audio/audio_send_stream_tests.cc b/audio/audio_send_stream_tests.cc
index 3f96c33..7deeff3 100644
--- a/audio/audio_send_stream_tests.cc
+++ b/audio/audio_send_stream_tests.cc
@@ -20,15 +20,9 @@
  public:
   AudioSendTest() : SendTest(CallTest::kDefaultTimeoutMs) {}
 
-  size_t GetNumVideoStreams() const override {
-    return 0;
-  }
-  size_t GetNumAudioStreams() const override {
-    return 1;
-  }
-  size_t GetNumFlexfecStreams() const override {
-    return 0;
-  }
+  size_t GetNumVideoStreams() const override { return 0; }
+  size_t GetNumAudioStreams() const override { return 1; }
+  size_t GetNumFlexfecStreams() const override { return 0; }
 };
 }  // namespace
 
diff --git a/audio/audio_send_stream_unittest.cc b/audio/audio_send_stream_unittest.cc
index 8fb7e7e..2341d4e 100644
--- a/audio/audio_send_stream_unittest.cc
+++ b/audio/audio_send_stream_unittest.cc
@@ -12,6 +12,8 @@
 #include <utility>
 #include <vector>
 
+#include "absl/memory/memory.h"
+#include "api/units/time_delta.h"
 #include "audio/audio_send_stream.h"
 #include "audio/audio_state.h"
 #include "audio/conversion.h"
@@ -26,9 +28,7 @@
 #include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h"
 #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
 #include "rtc_base/fakeclock.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/task_queue.h"
-#include "rtc_base/timedelta.h"
 #include "test/gtest.h"
 #include "test/mock_audio_encoder.h"
 #include "test/mock_audio_encoder_factory.h"
@@ -56,8 +56,8 @@
 const double kEchoReturnLossEnhancement = 101;
 const double kResidualEchoLikelihood = -1.0f;
 const double kResidualEchoLikelihoodMax = 23.0f;
-const CallStatistics kCallStats = {
-    1345,  1678,  1901, 1234,  112, 13456, 17890, 1567, -1890, -1123};
+const CallStatistics kCallStats = {1345,  1678,  1901, 1234,  112,
+                                   13456, 17890, 1567, -1890, -1123};
 const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354};
 const int kTelephoneEventPayloadType = 123;
 const int kTelephoneEventPayloadFrequency = 65432;
@@ -109,17 +109,17 @@
           std::begin(kCodecSpecs), std::end(kCodecSpecs))));
   ON_CALL(*factory.get(), QueryAudioEncoder(_))
       .WillByDefault(Invoke(
-          [](const SdpAudioFormat& format) -> rtc::Optional<AudioCodecInfo> {
+          [](const SdpAudioFormat& format) -> absl::optional<AudioCodecInfo> {
             for (const auto& spec : kCodecSpecs) {
               if (format == spec.format) {
                 return spec.info;
               }
             }
-            return rtc::nullopt;
+            return absl::nullopt;
           }));
   ON_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _, _))
       .WillByDefault(Invoke([](int payload_type, const SdpAudioFormat& format,
-                               rtc::Optional<AudioCodecPairId> codec_pair_id,
+                               absl::optional<AudioCodecPairId> codec_pair_id,
                                std::unique_ptr<AudioEncoder>* return_value) {
         *return_value = SetupAudioEncoderMock(payload_type, format);
       }));
@@ -166,7 +166,7 @@
     return std::unique_ptr<internal::AudioSendStream>(
         new internal::AudioSendStream(
             stream_config_, audio_state_, &worker_queue_, &rtp_transport_,
-            &bitrate_allocator_, &event_log_, &rtcp_rtt_stats_, rtc::nullopt,
+            &bitrate_allocator_, &event_log_, &rtcp_rtt_stats_, absl::nullopt,
             &active_lifetime_,
             std::unique_ptr<voe::ChannelProxy>(channel_proxy_)));
   }
@@ -181,9 +181,8 @@
   TimeInterval* active_lifetime() { return &active_lifetime_; }
 
   static void AddBweToConfig(AudioSendStream::Config* config) {
-    config->rtp.extensions.push_back(
-        RtpExtension(RtpExtension::kTransportSequenceNumberUri,
-                     kTransportSequenceNumberId));
+    config->rtp.extensions.push_back(RtpExtension(
+        RtpExtension::kTransportSequenceNumberUri, kTransportSequenceNumberId));
     config->send_codec_spec->transport_cc_enabled = true;
   }
 
@@ -254,13 +253,14 @@
 
   void SetupMockForSendTelephoneEvent() {
     EXPECT_TRUE(channel_proxy_);
-    EXPECT_CALL(*channel_proxy_,
-        SetSendTelephoneEventPayloadType(kTelephoneEventPayloadType,
-                                         kTelephoneEventPayloadFrequency))
-            .WillOnce(Return(true));
-    EXPECT_CALL(*channel_proxy_,
+    EXPECT_CALL(*channel_proxy_, SetSendTelephoneEventPayloadType(
+                                     kTelephoneEventPayloadType,
+                                     kTelephoneEventPayloadFrequency))
+        .WillOnce(Return(true));
+    EXPECT_CALL(
+        *channel_proxy_,
         SendTelephoneEventOutband(kTelephoneEventCode, kTelephoneEventDuration))
-            .WillOnce(Return(true));
+        .WillOnce(Return(true));
   }
 
   void SetupMockForGetStats() {
@@ -355,9 +355,9 @@
   ConfigHelper helper(false, true);
   auto send_stream = helper.CreateAudioSendStream();
   helper.SetupMockForSendTelephoneEvent();
-  EXPECT_TRUE(send_stream->SendTelephoneEvent(kTelephoneEventPayloadType,
-      kTelephoneEventPayloadFrequency, kTelephoneEventCode,
-      kTelephoneEventDuration));
+  EXPECT_TRUE(send_stream->SendTelephoneEvent(
+      kTelephoneEventPayloadType, kTelephoneEventPayloadFrequency,
+      kTelephoneEventCode, kTelephoneEventDuration));
 }
 
 TEST(AudioSendStreamTest, SetMuted) {
@@ -424,7 +424,7 @@
   EXPECT_CALL(helper.mock_encoder_factory(), MakeAudioEncoderMock(_, _, _, _))
       .WillOnce(Invoke([&kAnaConfigString, &kAnaReconfigString](
                            int payload_type, const SdpAudioFormat& format,
-                           rtc::Optional<AudioCodecPairId> codec_pair_id,
+                           absl::optional<AudioCodecPairId> codec_pair_id,
                            std::unique_ptr<AudioEncoder>* return_value) {
         auto mock_encoder = SetupAudioEncoderMock(payload_type, format);
         EXPECT_CALL(*mock_encoder,
@@ -518,7 +518,7 @@
     EXPECT_CALL(*helper.channel_proxy(), ResetSenderCongestionControlObjects())
         .Times(1);
     EXPECT_CALL(*helper.channel_proxy(), RegisterSenderCongestionControlObjects(
-        helper.transport(), Ne(nullptr)))
+                                             helper.transport(), Ne(nullptr)))
         .Times(1);
   }
   send_stream->Reconfigure(new_config);
@@ -545,8 +545,7 @@
     EXPECT_CALL(mock_transport, SendRtp(_, _, _)).Times(2);
     const PacketOptions options;
     registered_transport->SendRtp(nullptr, 0, options);
-    fake_clock.AdvanceTime(
-        rtc::TimeDelta::FromMilliseconds(kTimeBetweenSendRtpCallsMs));
+    fake_clock.AdvanceTime(TimeDelta::ms(kTimeBetweenSendRtpCallsMs));
     registered_transport->SendRtp(nullptr, 0, options);
   }
   EXPECT_TRUE(!helper.active_lifetime()->Empty());
diff --git a/audio/audio_state.cc b/audio/audio_state.cc
index d738884..35ea03d 100644
--- a/audio/audio_state.cc
+++ b/audio/audio_state.cc
@@ -14,12 +14,12 @@
 #include <utility>
 #include <vector>
 
+#include "absl/memory/memory.h"
 #include "audio/audio_receive_stream.h"
 #include "modules/audio_device/include/audio_device.h"
 #include "rtc_base/atomicops.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/thread.h"
 
 namespace webrtc {
@@ -27,8 +27,7 @@
 
 AudioState::AudioState(const AudioState::Config& config)
     : config_(config),
-      audio_transport_(config_.audio_mixer,
-                       config_.audio_processing.get()) {
+      audio_transport_(config_.audio_mixer, config_.audio_processing.get()) {
   process_thread_checker_.DetachFromThread();
   RTC_DCHECK(config_.audio_mixer);
   RTC_DCHECK(config_.audio_device_module);
@@ -50,7 +49,7 @@
   RTC_DCHECK_EQ(0, receiving_streams_.count(stream));
   receiving_streams_.insert(stream);
   if (!config_.audio_mixer->AddSource(
-      static_cast<internal::AudioReceiveStream*>(stream))) {
+          static_cast<internal::AudioReceiveStream*>(stream))) {
     RTC_DLOG(LS_ERROR) << "Failed to add source to mixer.";
   }
 
@@ -79,7 +78,8 @@
 }
 
 void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
-                                  int sample_rate_hz, size_t num_channels) {
+                                  int sample_rate_hz,
+                                  size_t num_channels) {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   auto& properties = sending_streams_[stream];
   properties.sample_rate_hz = sample_rate_hz;
@@ -122,7 +122,7 @@
     } else {
       config_.audio_device_module->StopPlayout();
       null_audio_poller_ =
-          rtc::MakeUnique<NullAudioPoller>(&audio_transport_);
+          absl::make_unique<NullAudioPoller>(&audio_transport_);
     }
   }
 }
diff --git a/audio/audio_state.h b/audio/audio_state.h
index d4e4e3f..689534b 100644
--- a/audio/audio_state.h
+++ b/audio/audio_state.h
@@ -39,9 +39,7 @@
     RTC_DCHECK(config_.audio_processing);
     return config_.audio_processing.get();
   }
-  AudioTransport* audio_transport() override {
-    return &audio_transport_;
-  }
+  AudioTransport* audio_transport() override { return &audio_transport_; }
 
   void SetPlayout(bool enabled) override;
   void SetRecording(bool enabled) override;
@@ -60,7 +58,8 @@
   void RemoveReceivingStream(webrtc::AudioReceiveStream* stream);
 
   void AddSendingStream(webrtc::AudioSendStream* stream,
-                        int sample_rate_hz, size_t num_channels);
+                        int sample_rate_hz,
+                        size_t num_channels);
   void RemoveSendingStream(webrtc::AudioSendStream* stream);
 
  private:
diff --git a/audio/audio_state_unittest.cc b/audio/audio_state_unittest.cc
index e825ec6..dc622df 100644
--- a/audio/audio_state_unittest.cc
+++ b/audio/audio_state_unittest.cc
@@ -71,8 +71,7 @@
   const float inc = (2 * 3.14159265f * 1000) / sample_rate_hz;
   float w = 0.f;
   for (int i = 0; i < samples_per_channel; ++i) {
-    audio_data[i * num_channels] =
-        static_cast<int16_t>(32767.f * std::sin(w));
+    audio_data[i * num_channels] = static_cast<int16_t>(32767.f * std::sin(w));
     w += inc;
   }
   return audio_data;
@@ -111,16 +110,18 @@
   MockAudioSendStream stream;
   audio_state->AddSendingStream(&stream, 8000, 2);
 
-  EXPECT_CALL(stream, SendAudioDataForMock(testing::AllOf(
-      testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(8000)),
-      testing::Field(&AudioFrame::num_channels_, testing::Eq(2u)))))
-          .WillOnce(
-              // Verify that channels are not swapped by default.
-              testing::Invoke([](AudioFrame* audio_frame) {
-                auto levels = ComputeChannelLevels(audio_frame);
-                EXPECT_LT(0u, levels[0]);
-                EXPECT_EQ(0u, levels[1]);
-              }));
+  EXPECT_CALL(
+      stream,
+      SendAudioDataForMock(testing::AllOf(
+          testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(8000)),
+          testing::Field(&AudioFrame::num_channels_, testing::Eq(2u)))))
+      .WillOnce(
+          // Verify that channels are not swapped by default.
+          testing::Invoke([](AudioFrame* audio_frame) {
+            auto levels = ComputeChannelLevels(audio_frame);
+            EXPECT_LT(0u, levels[0]);
+            EXPECT_EQ(0u, levels[1]);
+          }));
   MockAudioProcessing* ap =
       static_cast<MockAudioProcessing*>(audio_state->audio_processing());
   EXPECT_CALL(*ap, set_stream_delay_ms(0));
@@ -132,8 +133,8 @@
   auto audio_data = Create10msTestData(kSampleRate, kNumChannels);
   uint32_t new_mic_level = 667;
   audio_state->audio_transport()->RecordedDataIsAvailable(
-      &audio_data[0], kSampleRate / 100, kNumChannels * 2,
-      kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level);
+      &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
+      kSampleRate, 0, 0, 0, false, new_mic_level);
   EXPECT_EQ(667u, new_mic_level);
 
   audio_state->RemoveSendingStream(&stream);
@@ -149,24 +150,28 @@
   audio_state->AddSendingStream(&stream_1, 8001, 2);
   audio_state->AddSendingStream(&stream_2, 32000, 1);
 
-  EXPECT_CALL(stream_1, SendAudioDataForMock(testing::AllOf(
-      testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)),
-      testing::Field(&AudioFrame::num_channels_, testing::Eq(1u)))))
-          .WillOnce(
-              // Verify that there is output signal.
-              testing::Invoke([](AudioFrame* audio_frame) {
-                auto levels = ComputeChannelLevels(audio_frame);
-                EXPECT_LT(0u, levels[0]);
-              }));
-  EXPECT_CALL(stream_2, SendAudioDataForMock(testing::AllOf(
-      testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)),
-      testing::Field(&AudioFrame::num_channels_, testing::Eq(1u)))))
-          .WillOnce(
-              // Verify that there is output signal.
-              testing::Invoke([](AudioFrame* audio_frame) {
-                auto levels = ComputeChannelLevels(audio_frame);
-                EXPECT_LT(0u, levels[0]);
-              }));
+  EXPECT_CALL(
+      stream_1,
+      SendAudioDataForMock(testing::AllOf(
+          testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)),
+          testing::Field(&AudioFrame::num_channels_, testing::Eq(1u)))))
+      .WillOnce(
+          // Verify that there is output signal.
+          testing::Invoke([](AudioFrame* audio_frame) {
+            auto levels = ComputeChannelLevels(audio_frame);
+            EXPECT_LT(0u, levels[0]);
+          }));
+  EXPECT_CALL(
+      stream_2,
+      SendAudioDataForMock(testing::AllOf(
+          testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)),
+          testing::Field(&AudioFrame::num_channels_, testing::Eq(1u)))))
+      .WillOnce(
+          // Verify that there is output signal.
+          testing::Invoke([](AudioFrame* audio_frame) {
+            auto levels = ComputeChannelLevels(audio_frame);
+            EXPECT_LT(0u, levels[0]);
+          }));
   MockAudioProcessing* ap =
       static_cast<MockAudioProcessing*>(audio_state->audio_processing());
   EXPECT_CALL(*ap, set_stream_delay_ms(5));
@@ -178,8 +183,8 @@
   auto audio_data = Create10msTestData(kSampleRate, kNumChannels);
   uint32_t new_mic_level = 667;
   audio_state->audio_transport()->RecordedDataIsAvailable(
-      &audio_data[0], kSampleRate / 100, kNumChannels * 2,
-      kNumChannels, kSampleRate, 5, 0, 0, true, new_mic_level);
+      &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
+      kSampleRate, 5, 0, 0, true, new_mic_level);
   EXPECT_EQ(667u, new_mic_level);
 
   audio_state->RemoveSendingStream(&stream_1);
@@ -210,8 +215,8 @@
   auto audio_data = Create10msTestData(kSampleRate, kNumChannels);
   uint32_t new_mic_level = 667;
   audio_state->audio_transport()->RecordedDataIsAvailable(
-      &audio_data[0], kSampleRate / 100, kNumChannels * 2,
-      kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level);
+      &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
+      kSampleRate, 0, 0, 0, false, new_mic_level);
   EXPECT_EQ(667u, new_mic_level);
 
   audio_state->RemoveSendingStream(&stream);
@@ -230,8 +235,8 @@
     auto audio_data = Create10msSilentTestData(kSampleRate, kNumChannels);
     uint32_t new_mic_level = 667;
     audio_state->audio_transport()->RecordedDataIsAvailable(
-        &audio_data[0], kSampleRate / 100, kNumChannels * 2,
-        kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level);
+        &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
+        kSampleRate, 0, 0, 0, false, new_mic_level);
     auto stats = audio_state->GetAudioInputStats();
     EXPECT_EQ(0, stats.audio_level);
     EXPECT_THAT(stats.total_energy, testing::DoubleEq(0.0));
@@ -244,8 +249,8 @@
     uint32_t new_mic_level = 667;
     for (int i = 0; i < 10; ++i) {
       audio_state->audio_transport()->RecordedDataIsAvailable(
-          &audio_data[0], kSampleRate / 100, kNumChannels * 2,
-          kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level);
+          &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
+          kSampleRate, 0, 0, 0, false, new_mic_level);
     }
     auto stats = audio_state->GetAudioInputStats();
     EXPECT_EQ(32767, stats.audio_level);
diff --git a/audio/audio_transport_impl.cc b/audio/audio_transport_impl.cc
index f9b0311..44e95aa 100644
--- a/audio/audio_transport_impl.cc
+++ b/audio/audio_transport_impl.cc
@@ -83,8 +83,7 @@
 
 AudioTransportImpl::AudioTransportImpl(AudioMixer* mixer,
                                        AudioProcessing* audio_processing)
-    : audio_processing_(audio_processing),
-      mixer_(mixer) {
+    : audio_processing_(audio_processing), mixer_(mixer) {
   RTC_DCHECK(mixer);
   RTC_DCHECK(audio_processing);
 }
@@ -125,9 +124,8 @@
   }
 
   std::unique_ptr<AudioFrame> audio_frame(new AudioFrame());
-  InitializeCaptureFrame(sample_rate, send_sample_rate_hz,
-                         number_of_channels, send_num_channels,
-                         audio_frame.get());
+  InitializeCaptureFrame(sample_rate, send_sample_rate_hz, number_of_channels,
+                         send_num_channels, audio_frame.get());
   voe::RemixAndResample(static_cast<const int16_t*>(audio_data),
                         number_of_frames, number_of_channels, sample_rate,
                         &capture_resampler_, audio_frame.get());
@@ -175,13 +173,13 @@
 // Mix all received streams, feed the result to the AudioProcessing module, then
 // resample the result to the requested output rate.
 int32_t AudioTransportImpl::NeedMorePlayData(const size_t nSamples,
-                                              const size_t nBytesPerSample,
-                                              const size_t nChannels,
-                                              const uint32_t samplesPerSec,
-                                              void* audioSamples,
-                                              size_t& nSamplesOut,
-                                              int64_t* elapsed_time_ms,
-                                              int64_t* ntp_time_ms) {
+                                             const size_t nBytesPerSample,
+                                             const size_t nChannels,
+                                             const uint32_t samplesPerSec,
+                                             void* audioSamples,
+                                             size_t& nSamplesOut,
+                                             int64_t* elapsed_time_ms,
+                                             int64_t* ntp_time_ms) {
   RTC_DCHECK_EQ(sizeof(int16_t) * nChannels, nBytesPerSample);
   RTC_DCHECK_GE(nChannels, 1);
   RTC_DCHECK_LE(nChannels, 2);
@@ -210,12 +208,12 @@
 // Used by Chromium - same as NeedMorePlayData() but because Chrome has its
 // own APM instance, does not call audio_processing_->ProcessReverseStream().
 void AudioTransportImpl::PullRenderData(int bits_per_sample,
-                                         int sample_rate,
-                                         size_t number_of_channels,
-                                         size_t number_of_frames,
-                                         void* audio_data,
-                                         int64_t* elapsed_time_ms,
-                                         int64_t* ntp_time_ms) {
+                                        int sample_rate,
+                                        size_t number_of_channels,
+                                        size_t number_of_frames,
+                                        void* audio_data,
+                                        int64_t* elapsed_time_ms,
+                                        int64_t* ntp_time_ms) {
   RTC_DCHECK_EQ(bits_per_sample, 16);
   RTC_DCHECK_GE(number_of_channels, 1);
   RTC_DCHECK_LE(number_of_channels, 2);
@@ -237,7 +235,8 @@
 }
 
 void AudioTransportImpl::UpdateSendingStreams(
-    std::vector<AudioSendStream*> streams, int send_sample_rate_hz,
+    std::vector<AudioSendStream*> streams,
+    int send_sample_rate_hz,
     size_t send_num_channels) {
   rtc::CritScope lock(&capture_lock_);
   sending_streams_ = std::move(streams);
diff --git a/audio/audio_transport_impl.h b/audio/audio_transport_impl.h
index 4e6e047..3a3155c 100644
--- a/audio/audio_transport_impl.h
+++ b/audio/audio_transport_impl.h
@@ -30,8 +30,7 @@
 
 class AudioTransportImpl : public AudioTransport {
  public:
-  AudioTransportImpl(AudioMixer* mixer,
-                     AudioProcessing* audio_processing);
+  AudioTransportImpl(AudioMixer* mixer, AudioProcessing* audio_processing);
   ~AudioTransportImpl() override;
 
   int32_t RecordedDataIsAvailable(const void* audioSamples,
@@ -63,12 +62,11 @@
                       int64_t* ntp_time_ms) override;
 
   void UpdateSendingStreams(std::vector<AudioSendStream*> streams,
-                            int send_sample_rate_hz, size_t send_num_channels);
+                            int send_sample_rate_hz,
+                            size_t send_num_channels);
   void SetStereoChannelSwapping(bool enable);
   bool typing_noise_detected() const;
-  const voe::AudioLevel& audio_level() const {
-    return audio_level_;
-  }
+  const voe::AudioLevel& audio_level() const { return audio_level_; }
 
  private:
   // Shared.
diff --git a/audio/channel.cc b/audio/channel.cc
index df34ca2..6acc65e 100644
--- a/audio/channel.cc
+++ b/audio/channel.cc
@@ -17,11 +17,12 @@
 #include <utility>
 #include <vector>
 
+#include "absl/memory/memory.h"
 #include "api/array_view.h"
 #include "audio/utility/audio_frame_operations.h"
 #include "call/rtp_transport_controller_send_interface.h"
-#include "logging/rtc_event_log/rtc_event_log.h"
 #include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
 #include "modules/audio_coding/codecs/audio_format_conversion.h"
 #include "modules/audio_device/include/audio_device.h"
@@ -38,7 +39,6 @@
 #include "rtc_base/format_macros.h"
 #include "rtc_base/location.h"
 #include "rtc_base/logging.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/rate_limiter.h"
 #include "rtc_base/task_queue.h"
 #include "rtc_base/thread_checker.h"
@@ -356,11 +356,6 @@
   return true;
 }
 
-void Channel::OnIncomingSSRCChanged(uint32_t ssrc) {
-  // Update ssrc so that NTP for AV sync can be updated.
-  _rtpRtcpModule->SetRemoteSSRC(ssrc);
-}
-
 int32_t Channel::OnReceivedPayloadData(const uint8_t* payloadData,
                                        size_t payloadSize,
                                        const WebRtcRTPHeader* rtpHeader) {
@@ -398,7 +393,7 @@
 
   unsigned int ssrc;
   RTC_CHECK_EQ(GetRemoteSSRC(ssrc), 0);
-  event_log_proxy_->Log(rtc::MakeUnique<RtcEventAudioPlayout>(ssrc));
+  event_log_proxy_->Log(absl::make_unique<RtcEventAudioPlayout>(ssrc));
   // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
   bool muted;
   if (audio_coding_->PlayoutData10Ms(audio_frame->sample_rate_hz_, audio_frame,
@@ -514,7 +509,7 @@
               0,
               false,
               rtc::scoped_refptr<AudioDecoderFactory>(),
-              rtc::nullopt) {
+              absl::nullopt) {
   RTC_DCHECK(encoder_queue);
   encoder_queue_ = encoder_queue;
 }
@@ -525,7 +520,7 @@
                  size_t jitter_buffer_max_packets,
                  bool jitter_buffer_fast_playout,
                  rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
-                 rtc::Optional<AudioCodecPairId> codec_pair_id)
+                 absl::optional<AudioCodecPairId> codec_pair_id)
     : event_log_proxy_(new RtcEventLogProxy()),
       rtp_payload_registry_(new RTPPayloadRegistry()),
       rtp_receive_statistics_(
@@ -533,7 +528,6 @@
       rtp_receiver_(
           RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
                                            this,
-                                           this,
                                            rtp_payload_registry_.get())),
       telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
       _outputAudioLevel(),
@@ -878,9 +872,8 @@
   header.payload_type_frequency =
       rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
   if (header.payload_type_frequency >= 0) {
-    bool in_order = IsPacketInOrder(header);
-    rtp_receive_statistics_->IncomingPacket(
-        header, packet.size(), IsPacketRetransmitted(header, in_order));
+    rtp_receive_statistics_->IncomingPacket(header, packet.size(),
+                                            IsPacketRetransmitted(header));
 
     ReceivePacket(packet.data(), packet.size(), header);
   }
@@ -901,24 +894,13 @@
                                           pl->typeSpecific);
 }
 
-bool Channel::IsPacketInOrder(const RTPHeader& header) const {
-  StreamStatistician* statistician =
-      rtp_receive_statistics_->GetStatistician(header.ssrc);
-  if (!statistician)
-    return false;
-  return statistician->IsPacketInOrder(header.sequenceNumber);
-}
-
-bool Channel::IsPacketRetransmitted(const RTPHeader& header,
-                                    bool in_order) const {
+bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
   StreamStatistician* statistician =
       rtp_receive_statistics_->GetStatistician(header.ssrc);
   if (!statistician)
     return false;
   // Check if this is a retransmission.
-  int64_t min_rtt = 0;
-  _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
-  return !in_order && statistician->IsRetransmitOfOldPacket(header, min_rtt);
+  return statistician->IsRetransmitOfOldPacket(header);
 }
 
 int32_t Channel::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
@@ -951,9 +933,8 @@
   uint32_t ntp_secs = 0;
   uint32_t ntp_frac = 0;
   uint32_t rtp_timestamp = 0;
-  if (0 !=
-      _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
-                                &rtp_timestamp)) {
+  if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
+                                     &rtp_timestamp)) {
     // Waiting for RTCP.
     return 0;
   }
@@ -1001,7 +982,7 @@
     return -1;
   }
   if (_rtpRtcpModule->SendTelephoneEventOutband(
-      event, duration_ms, kTelephoneEventAttenuationdB) != 0) {
+          event, duration_ms, kTelephoneEventAttenuationdB) != 0) {
     RTC_DLOG(LS_ERROR) << "SendTelephoneEventOutband() failed to send event";
     return -1;
   }
@@ -1037,6 +1018,11 @@
   return 0;
 }
 
+void Channel::SetRemoteSSRC(uint32_t ssrc) {
+  // Update ssrc so that NTP for AV sync can be updated.
+  _rtpRtcpModule->SetRemoteSSRC(ssrc);
+}
+
 void Channel::SetMid(const std::string& mid, int extension_id) {
   int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id);
   RTC_DCHECK_EQ(0, ret);
diff --git a/audio/channel.h b/audio/channel.h
index ab25aad..8d1a26b 100644
--- a/audio/channel.h
+++ b/audio/channel.h
@@ -16,11 +16,11 @@
 #include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio/audio_mixer.h"
 #include "api/audio_codecs/audio_encoder.h"
 #include "api/call/audio_sink.h"
 #include "api/call/transport.h"
-#include "api/optional.h"
 #include "audio/audio_level.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/include/audio_coding_module.h"
@@ -137,7 +137,6 @@
 
 class Channel
     : public RtpData,
-      public RtpFeedback,
       public Transport,
       public AudioPacketizationCallback,  // receive encoded packets from the
                                           // ACM
@@ -159,7 +158,7 @@
           size_t jitter_buffer_max_packets,
           bool jitter_buffer_fast_playout,
           rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
-          rtc::Optional<AudioCodecPairId> codec_pair_id);
+          absl::optional<AudioCodecPairId> codec_pair_id);
   virtual ~Channel();
 
   void SetSink(AudioSinkInterface* sink);
@@ -219,6 +218,8 @@
 
   // RTP+RTCP
   int SetLocalSSRC(unsigned int ssrc);
+  void SetRemoteSSRC(uint32_t ssrc);
+
   void SetMid(const std::string& mid, int extension_id);
   int SetSendAudioLevelIndicationStatus(bool enable, unsigned char id);
   void EnableSendTransportSequenceNumber(int id);
@@ -248,9 +249,6 @@
                                 size_t payloadSize,
                                 const WebRtcRTPHeader* rtpHeader) override;
 
-  // From RtpFeedback in the RTP/RTCP module
-  void OnIncomingSSRCChanged(uint32_t ssrc) override;
-
   // From Transport (called by the RTP/RTCP module)
   bool SendRtp(const uint8_t* data,
                size_t len,
@@ -316,8 +314,7 @@
   bool ReceivePacket(const uint8_t* packet,
                      size_t packet_length,
                      const RTPHeader& header);
-  bool IsPacketInOrder(const RTPHeader& header) const;
-  bool IsPacketRetransmitted(const RTPHeader& header, bool in_order) const;
+  bool IsPacketRetransmitted(const RTPHeader& header) const;
   int ResendPackets(const uint16_t* sequence_numbers, int length);
   void UpdatePlayoutTimestamp(bool rtcp);
 
@@ -355,7 +352,7 @@
   RemoteNtpTimeEstimator ntp_estimator_ RTC_GUARDED_BY(ts_stats_lock_);
 
   // Timestamp of the audio pulled from NetEq.
-  rtc::Optional<uint32_t> jitter_buffer_playout_timestamp_;
+  absl::optional<uint32_t> jitter_buffer_playout_timestamp_;
 
   rtc::CriticalSection video_sync_lock_;
   uint32_t playout_timestamp_rtp_ RTC_GUARDED_BY(video_sync_lock_);
diff --git a/audio/channel_proxy.cc b/audio/channel_proxy.cc
index b8d520d..bac681f 100644
--- a/audio/channel_proxy.cc
+++ b/audio/channel_proxy.cc
@@ -22,8 +22,8 @@
 namespace voe {
 ChannelProxy::ChannelProxy() {}
 
-ChannelProxy::ChannelProxy(std::unique_ptr<Channel> channel) :
-    channel_(std::move(channel)) {
+ChannelProxy::ChannelProxy(std::unique_ptr<Channel> channel)
+    : channel_(std::move(channel)) {
   RTC_DCHECK(channel_);
   module_process_thread_checker_.DetachFromThread();
 }
@@ -53,6 +53,11 @@
   RTC_DCHECK_EQ(0, error);
 }
 
+void ChannelProxy::SetRemoteSSRC(uint32_t ssrc) {
+  RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+  channel_->SetRemoteSSRC(ssrc);
+}
+
 void ChannelProxy::SetMid(const std::string& mid, int extension_id) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   channel_->SetMid(mid, extension_id);
@@ -87,7 +92,7 @@
     RtcpBandwidthObserver* bandwidth_observer) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   channel_->RegisterSenderCongestionControlObjects(transport,
-                                                    bandwidth_observer);
+                                                   bandwidth_observer);
 }
 
 void ChannelProxy::RegisterReceiverCongestionControlObjects(
@@ -167,7 +172,7 @@
                                                     int payload_frequency) {
   RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
   return channel_->SetSendTelephoneEventPayloadType(payload_type,
-                                                     payload_frequency) == 0;
+                                                    payload_frequency) == 0;
 }
 
 bool ChannelProxy::SendTelephoneEventOutband(int event, int duration_ms) {
diff --git a/audio/channel_proxy.h b/audio/channel_proxy.h
index eadd686..0029851 100644
--- a/audio/channel_proxy.h
+++ b/audio/channel_proxy.h
@@ -62,6 +62,7 @@
 
   virtual void SetRTCPStatus(bool enable);
   virtual void SetLocalSSRC(uint32_t ssrc);
+  virtual void SetRemoteSSRC(uint32_t ssrc);
   virtual void SetMid(const std::string& mid, int extension_id);
   virtual void SetRTCP_CNAME(const std::string& c_name);
   virtual void SetNACKStatus(bool enable, int max_packets);
@@ -107,8 +108,7 @@
   virtual void SetTransportOverhead(int transport_overhead_per_packet);
   virtual void AssociateSendChannel(const ChannelProxy& send_channel_proxy);
   virtual void DisassociateSendChannel();
-  virtual void GetRtpRtcp(RtpRtcp** rtp_rtcp,
-                          RtpReceiver** rtp_receiver) const;
+  virtual void GetRtpRtcp(RtpRtcp** rtp_rtcp, RtpReceiver** rtp_receiver) const;
   virtual uint32_t GetPlayoutTimestamp() const;
   virtual void SetMinimumPlayoutDelay(int delay_ms);
   virtual bool GetRecCodec(CodecInst* codec_inst) const;
diff --git a/audio/mock_voe_channel_proxy.h b/audio/mock_voe_channel_proxy.h
index e12b034..7396dd1 100644
--- a/audio/mock_voe_channel_proxy.h
+++ b/audio/mock_voe_channel_proxy.h
@@ -31,13 +31,13 @@
     return SetEncoderForMock(payload_type, &encoder);
   }
   MOCK_METHOD2(SetEncoderForMock,
-               bool(int payload_type,
-                    std::unique_ptr<AudioEncoder>* encoder));
+               bool(int payload_type, std::unique_ptr<AudioEncoder>* encoder));
   MOCK_METHOD1(
       ModifyEncoder,
       void(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier));
   MOCK_METHOD1(SetRTCPStatus, void(bool enable));
   MOCK_METHOD1(SetLocalSSRC, void(uint32_t ssrc));
+  MOCK_METHOD1(SetRemoteSSRC, void(uint32_t ssrc));
   MOCK_METHOD1(SetRTCP_CNAME, void(const std::string& c_name));
   MOCK_METHOD2(SetNACKStatus, void(bool enable, int max_packets));
   MOCK_METHOD2(SetSendAudioLevelIndicationStatus, void(bool enable, int id));
@@ -58,8 +58,8 @@
   MOCK_CONST_METHOD0(GetTotalOutputEnergy, double());
   MOCK_CONST_METHOD0(GetTotalOutputDuration, double());
   MOCK_CONST_METHOD0(GetDelayEstimate, uint32_t());
-  MOCK_METHOD2(SetSendTelephoneEventPayloadType, bool(int payload_type,
-                                                      int payload_frequency));
+  MOCK_METHOD2(SetSendTelephoneEventPayloadType,
+               bool(int payload_type, int payload_frequency));
   MOCK_METHOD2(SendTelephoneEventOutband, bool(int event, int duration_ms));
   MOCK_METHOD2(SetBitrate, void(int bitrate_bps, int64_t probing_interval_ms));
   MOCK_METHOD1(SetSink, void(AudioSinkInterface* sink));
@@ -70,8 +70,8 @@
   MOCK_METHOD1(SetChannelOutputVolumeScaling, void(float scaling));
   MOCK_METHOD1(SetRtcEventLog, void(RtcEventLog* event_log));
   MOCK_METHOD2(GetAudioFrameWithInfo,
-      AudioMixer::Source::AudioFrameInfo(int sample_rate_hz,
-                                         AudioFrame* audio_frame));
+               AudioMixer::Source::AudioFrameInfo(int sample_rate_hz,
+                                                  AudioFrame* audio_frame));
   MOCK_CONST_METHOD0(PreferredSampleRate, int());
   // GMock doesn't like move-only types, like std::unique_ptr.
   virtual void ProcessAndEncodeAudio(std::unique_ptr<AudioFrame> audio_frame) {
@@ -83,8 +83,8 @@
   MOCK_METHOD1(AssociateSendChannel,
                void(const ChannelProxy& send_channel_proxy));
   MOCK_METHOD0(DisassociateSendChannel, void());
-  MOCK_CONST_METHOD2(GetRtpRtcp, void(RtpRtcp** rtp_rtcp,
-                                      RtpReceiver** rtp_receiver));
+  MOCK_CONST_METHOD2(GetRtpRtcp,
+                     void(RtpRtcp** rtp_rtcp, RtpReceiver** rtp_receiver));
   MOCK_CONST_METHOD0(GetPlayoutTimestamp, uint32_t());
   MOCK_METHOD1(SetMinimumPlayoutDelay, void(int delay_ms));
   MOCK_CONST_METHOD1(GetRecCodec, bool(CodecInst* codec_inst));
diff --git a/audio/remix_resample.cc b/audio/remix_resample.cc
index 69038cd..eda70c7 100644
--- a/audio/remix_resample.cc
+++ b/audio/remix_resample.cc
@@ -68,9 +68,9 @@
   // how much to zero here; or 2) make resampler accept a hint that the input is
   // zeroed.
   const size_t src_length = samples_per_channel * audio_ptr_num_channels;
-  int out_length = resampler->Resample(audio_ptr, src_length,
-                                       dst_frame->mutable_data(),
-                                       AudioFrame::kMaxDataSizeSamples);
+  int out_length =
+      resampler->Resample(audio_ptr, src_length, dst_frame->mutable_data(),
+                          AudioFrame::kMaxDataSizeSamples);
   if (out_length == -1) {
     FATAL() << "Resample failed: audio_ptr = " << audio_ptr
             << ", src_length = " << src_length
diff --git a/audio/remix_resample_unittest.cc b/audio/remix_resample_unittest.cc
index 1d8cce7..f1fb5f7 100644
--- a/audio/remix_resample_unittest.cc
+++ b/audio/remix_resample_unittest.cc
@@ -113,7 +113,8 @@
 // Computes the best SNR based on the error between |ref_frame| and
 // |test_frame|. It allows for up to a |max_delay| in samples between the
 // signals to compensate for the resampling delay.
-float ComputeSNR(const AudioFrame& ref_frame, const AudioFrame& test_frame,
+float ComputeSNR(const AudioFrame& ref_frame,
+                 const AudioFrame& test_frame,
                  size_t max_delay) {
   VerifyParams(ref_frame, test_frame);
   float best_snr = 0;
@@ -123,8 +124,9 @@
     float variance = 0;
     const int16_t* ref_frame_data = ref_frame.data();
     const int16_t* test_frame_data = test_frame.data();
-    for (size_t i = 0; i < ref_frame.samples_per_channel_ *
-        ref_frame.num_channels_ - delay; i++) {
+    for (size_t i = 0;
+         i < ref_frame.samples_per_channel_ * ref_frame.num_channels_ - delay;
+         i++) {
       int error = ref_frame_data[i] - test_frame_data[i + delay];
       mse += error * error;
       variance += ref_frame_data[i] * ref_frame_data[i];
@@ -145,7 +147,7 @@
                           const AudioFrame& test_frame) {
   VerifyParams(ref_frame, test_frame);
   const int16_t* ref_frame_data = ref_frame.data();
-  const int16_t* test_frame_data  = test_frame.data();
+  const int16_t* test_frame_data = test_frame.data();
   for (size_t i = 0;
        i < ref_frame.samples_per_channel_ * ref_frame.num_channels_; i++) {
     EXPECT_EQ(ref_frame_data[i], test_frame_data[i]);
@@ -161,8 +163,8 @@
   const int16_t kSrcCh2 = 15;
   const int16_t kSrcCh3 = 22;
   const int16_t kSrcCh4 = 8;
-  const float resampling_factor = (1.0 * src_sample_rate_hz) /
-      dst_sample_rate_hz;
+  const float resampling_factor =
+      (1.0 * src_sample_rate_hz) / dst_sample_rate_hz;
   const float dst_ch1 = resampling_factor * kSrcCh1;
   const float dst_ch2 = resampling_factor * kSrcCh2;
   const float dst_ch3 = resampling_factor * kSrcCh3;
@@ -206,7 +208,7 @@
       static_cast<double>(dst_sample_rate_hz) / src_sample_rate_hz *
       kInputKernelDelaySamples * dst_channels * 2);
   printf("(%d, %d Hz) -> (%d, %d Hz) ",  // SNR reported on the same line later.
-      src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
+         src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
   RemixAndResample(src_frame_, &resampler, &dst_frame_);
 
   if (src_sample_rate_hz == 96000 && dst_sample_rate_hz == 8000) {
@@ -258,8 +260,7 @@
 
   for (int src_rate = 0; src_rate < kSampleRatesSize; src_rate++) {
     for (int dst_rate = 0; dst_rate < kSampleRatesSize; dst_rate++) {
-      for (int src_channel = 0; src_channel < kSrcChannelsSize;
-           src_channel++) {
+      for (int src_channel = 0; src_channel < kSrcChannelsSize; src_channel++) {
         for (int dst_channel = 0; dst_channel < kDstChannelsSize;
              dst_channel++) {
           RunResampleTest(kSrcChannels[src_channel], kSampleRates[src_rate],
diff --git a/audio/time_interval.h b/audio/time_interval.h
index 88b2f7d..79fe29d 100644
--- a/audio/time_interval.h
+++ b/audio/time_interval.h
@@ -13,7 +13,7 @@
 
 #include <stdint.h>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace webrtc {
 
@@ -57,7 +57,7 @@
 
     int64_t first, last;
   };
-  rtc::Optional<Interval> interval_;
+  absl::optional<Interval> interval_;
 };
 
 }  // namespace webrtc
diff --git a/audio/time_interval_unittest.cc b/audio/time_interval_unittest.cc
index 7f8b44e..deff6e3 100644
--- a/audio/time_interval_unittest.cc
+++ b/audio/time_interval_unittest.cc
@@ -9,8 +9,8 @@
  */
 
 #include "audio/time_interval.h"
+#include "api/units/time_delta.h"
 #include "rtc_base/fakeclock.h"
-#include "rtc_base/timedelta.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -19,7 +19,7 @@
   rtc::ScopedFakeClock fake_clock;
   TimeInterval interval;
   interval.Extend();
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(100));
+  fake_clock.AdvanceTime(TimeDelta::ms(100));
   interval.Extend();
   EXPECT_EQ(interval.Length(), 100);
 }
diff --git a/audio/transport_feedback_packet_loss_tracker.cc b/audio/transport_feedback_packet_loss_tracker.cc
index 101b6b4..7e0c5c5 100644
--- a/audio/transport_feedback_packet_loss_tracker.cc
+++ b/audio/transport_feedback_packet_loss_tracker.cc
@@ -116,12 +116,12 @@
   }
 }
 
-rtc::Optional<float>
-TransportFeedbackPacketLossTracker::GetPacketLossRate() const {
+absl::optional<float> TransportFeedbackPacketLossTracker::GetPacketLossRate()
+    const {
   return plr_state_.GetMetric();
 }
 
-rtc::Optional<float>
+absl::optional<float>
 TransportFeedbackPacketLossTracker::GetRecoverablePacketLossRate() const {
   return rplr_state_.GetMetric();
 }
@@ -344,20 +344,20 @@
   RTC_CHECK_EQ(rplr_state_.num_recoverable_losses_, recoverable_losses);
 }
 
-rtc::Optional<float>
-TransportFeedbackPacketLossTracker::PlrState::GetMetric() const {
+absl::optional<float> TransportFeedbackPacketLossTracker::PlrState::GetMetric()
+    const {
   const size_t total = num_lost_packets_ + num_received_packets_;
   if (total < min_num_acked_packets_) {
-    return rtc::nullopt;
+    return absl::nullopt;
   } else {
     return static_cast<float>(num_lost_packets_) / total;
   }
 }
 
-rtc::Optional<float>
-TransportFeedbackPacketLossTracker::RplrState::GetMetric() const {
+absl::optional<float> TransportFeedbackPacketLossTracker::RplrState::GetMetric()
+    const {
   if (num_acked_pairs_ < min_num_acked_pairs_) {
-    return rtc::nullopt;
+    return absl::nullopt;
   } else {
     return static_cast<float>(num_recoverable_losses_) / num_acked_pairs_;
   }
diff --git a/audio/transport_feedback_packet_loss_tracker.h b/audio/transport_feedback_packet_loss_tracker.h
index 4ad4902..7d58d6c 100644
--- a/audio/transport_feedback_packet_loss_tracker.h
+++ b/audio/transport_feedback_packet_loss_tracker.h
@@ -14,7 +14,7 @@
 #include <map>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace webrtc {
 
@@ -43,11 +43,11 @@
 
   // Returns the packet loss rate, if the window has enough packet statuses to
   // reliably compute it. Otherwise, returns empty.
-  rtc::Optional<float> GetPacketLossRate() const;
+  absl::optional<float> GetPacketLossRate() const;
 
   // Returns the first-order-FEC recoverable packet loss rate, if the window has
   // enough status pairs to reliably compute it. Otherwise, returns empty.
-  rtc::Optional<float> GetRecoverablePacketLossRate() const;
+  absl::optional<float> GetRecoverablePacketLossRate() const;
 
   // Verifies that the internal states are correct. Only used for tests.
   void Validate() const;
@@ -108,7 +108,7 @@
       num_received_packets_ = 0;
       num_lost_packets_ = 0;
     }
-    rtc::Optional<float> GetMetric() const;
+    absl::optional<float> GetMetric() const;
     const size_t min_num_acked_packets_;
     size_t num_received_packets_;
     size_t num_lost_packets_;
@@ -124,7 +124,7 @@
       num_acked_pairs_ = 0;
       num_recoverable_losses_ = 0;
     }
-    rtc::Optional<float> GetMetric() const;
+    absl::optional<float> GetMetric() const;
     // Recoverable packets are those which were lost, but immediately followed
     // by a properly received packet. If that second packet carried FEC,
     // the data from the former (lost) packet could be recovered.
diff --git a/audio/transport_feedback_packet_loss_tracker_unittest.cc b/audio/transport_feedback_packet_loss_tracker_unittest.cc
index 8f8fe05..2f9bf68 100644
--- a/audio/transport_feedback_packet_loss_tracker_unittest.cc
+++ b/audio/transport_feedback_packet_loss_tracker_unittest.cc
@@ -94,18 +94,18 @@
   // value is as expected.
   void ValidatePacketLossStatistics(
       const TransportFeedbackPacketLossTracker& tracker,
-      rtc::Optional<float> expected_plr,
-      rtc::Optional<float> expected_rplr) {
-    // TODO(eladalon): Comparing the rtc::Optional<float> directly would have
+      absl::optional<float> expected_plr,
+      absl::optional<float> expected_rplr) {
+    // TODO(eladalon): Comparing the absl::optional<float> directly would have
     // given concise code, but less readable error messages. If we modify
-    // the way rtc::Optional is printed, we can get rid of this.
-    rtc::Optional<float> plr = tracker.GetPacketLossRate();
+    // the way absl::optional is printed, we can get rid of this.
+    absl::optional<float> plr = tracker.GetPacketLossRate();
     EXPECT_EQ(static_cast<bool>(expected_plr), static_cast<bool>(plr));
     if (expected_plr && plr) {
       EXPECT_EQ(*expected_plr, *plr);
     }
 
-    rtc::Optional<float> rplr = tracker.GetRecoverablePacketLossRate();
+    absl::optional<float> rplr = tracker.GetRecoverablePacketLossRate();
     EXPECT_EQ(static_cast<bool>(expected_rplr), static_cast<bool>(rplr));
     if (expected_rplr && rplr) {
       EXPECT_EQ(*expected_rplr, *rplr);
@@ -127,7 +127,7 @@
   TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
 
   // PLR and RPLR reported as unknown before reception of first feedback.
-  ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt);
 }
 
 // A feedback received for an empty window has no effect.
@@ -136,7 +136,7 @@
 
   // Feedback doesn't correspond to any packets - ignored.
   AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
-  ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt);
 
   // After the packets are transmitted, acking them would have an effect.
   SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs);
@@ -153,7 +153,7 @@
   // Expected window contents: [] -> [1001].
   SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs);
   AddTransportFeedbackAndValidate(&tracker, base_, {true, false, false, true});
-  ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt);
 }
 
 // Sanity check on minimum filled window - PLR known, RPLR unknown.
@@ -166,7 +166,7 @@
   SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
   AddTransportFeedbackAndValidate(&tracker, base_,
                                   {true, false, false, true, true});
-  ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, absl::nullopt);
 }
 
 // Sanity check on minimum filled window - PLR unknown, RPLR known.
@@ -179,7 +179,7 @@
   SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
   AddTransportFeedbackAndValidate(&tracker, base_,
                                   {true, false, false, true, true});
-  ValidatePacketLossStatistics(tracker, rtc::nullopt, 1.0f / 4.0f);
+  ValidatePacketLossStatistics(tracker, absl::nullopt, 1.0f / 4.0f);
 }
 
 // If packets are sent close enough together that the clock reading for both
@@ -203,7 +203,7 @@
   // Expected window contents: [] -> [10011].
   AddTransportFeedbackAndValidate(&tracker, base_,
                                   {true, false, false, true, true});
-  ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, absl::nullopt);
 
   // Expected window contents: [10011] -> [1001110101].
   AddTransportFeedbackAndValidate(&tracker, base_ + 5,
@@ -412,34 +412,30 @@
 TEST_P(TransportFeedbackPacketLossTrackerTest, SanityGapsInSequenceNumbers) {
   TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 5, 1);
 
-  SendPackets(&tracker,
-              {static_cast<uint16_t>(base_),
-               static_cast<uint16_t>(base_ + 2),
-               static_cast<uint16_t>(base_ + 4),
-               static_cast<uint16_t>(base_ + 6),
-               static_cast<uint16_t>(base_ + 8)},
-              kDefaultSendIntervalMs);
+  SendPackets(
+      &tracker,
+      {static_cast<uint16_t>(base_), static_cast<uint16_t>(base_ + 2),
+       static_cast<uint16_t>(base_ + 4), static_cast<uint16_t>(base_ + 6),
+       static_cast<uint16_t>(base_ + 8)},
+      kDefaultSendIntervalMs);
 
   // Gaps in sequence numbers not considered as gaps in window, because  only
   // those sequence numbers which were associated with the stream count.
   // Expected window contents: [] -> [11011].
   AddTransportFeedbackAndValidate(
       // Note: Left packets belong to this stream, right ones ignored.
-      &tracker, base_, {true, false,
-                        true, false,
-                        false, false,
-                        true, false,
-                        true, true});
+      &tracker, base_,
+      {true, false, true, false, false, false, true, false, true, true});
   ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
 
   // Create gap by sending [base + 10] but not acking it.
   // Note: Acks for [base + 11] and [base + 13] ignored (other stream).
   // Expected window contents: [11011] -> [11011-GAP-01].
-  SendPackets(&tracker,
-              {static_cast<uint16_t>(base_ + 10),
-               static_cast<uint16_t>(base_ + 12),
-               static_cast<uint16_t>(base_ + 14)},
-              kDefaultSendIntervalMs);
+  SendPackets(
+      &tracker,
+      {static_cast<uint16_t>(base_ + 10), static_cast<uint16_t>(base_ + 12),
+       static_cast<uint16_t>(base_ + 14)},
+      kDefaultSendIntervalMs);
   AddTransportFeedbackAndValidate(&tracker, base_ + 11,
                                   {false, false, false, true, true});
   ValidatePacketLossStatistics(tracker, 2.0f / 7.0f, 2.0f / 5.0f);
@@ -520,7 +516,7 @@
   // A reset occurs.
   SendPackets(&tracker, {static_cast<uint16_t>(base_ + 2)},
               kDefaultSendIntervalMs);
-  ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt);
 }
 
 // The window is reset by the sending of a packet which is 0x8000 or more
@@ -539,7 +535,7 @@
   // A reset occurs.
   SendPackets(&tracker, {static_cast<uint16_t>(base_ + 5 + 0x8000)},
               kDefaultSendIntervalMs);
-  ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
+  ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt);
 }
 
 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
diff --git a/audio/utility/audio_frame_operations.cc b/audio/utility/audio_frame_operations.cc
index ed7b7a8..fb1f3b0 100644
--- a/audio/utility/audio_frame_operations.cc
+++ b/audio/utility/audio_frame_operations.cc
@@ -159,7 +159,8 @@
   for (size_t i = 0; i < samples_per_channel; i++) {
     dst_audio[i] =
         (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] +
-         src_audio[4 * i + 2] + src_audio[4 * i + 3]) >> 2;
+         src_audio[4 * i + 2] + src_audio[4 * i + 3]) >>
+        2;
   }
 }
 
diff --git a/audio/utility/audio_frame_operations_unittest.cc b/audio/utility/audio_frame_operations_unittest.cc
index 1d08d7e..76f1dcd 100644
--- a/audio/utility/audio_frame_operations_unittest.cc
+++ b/audio/utility/audio_frame_operations_unittest.cc
@@ -50,27 +50,29 @@
 
 void SetFrameData(int16_t data, AudioFrame* frame) {
   int16_t* frame_data = frame->mutable_data();
-  for (size_t i = 0;
-       i < frame->samples_per_channel_ * frame->num_channels_; i++) {
+  for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
+       i++) {
     frame_data[i] = data;
   }
 }
 
 void VerifyFramesAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
   EXPECT_EQ(frame1.num_channels_, frame2.num_channels_);
-  EXPECT_EQ(frame1.samples_per_channel_,
-            frame2.samples_per_channel_);
+  EXPECT_EQ(frame1.samples_per_channel_, frame2.samples_per_channel_);
   const int16_t* frame1_data = frame1.data();
   const int16_t* frame2_data = frame2.data();
   for (size_t i = 0; i < frame1.samples_per_channel_ * frame1.num_channels_;
-      i++) {
+       i++) {
     EXPECT_EQ(frame1_data[i], frame2_data[i]);
   }
   EXPECT_EQ(frame1.muted(), frame2.muted());
 }
 
-void InitFrame(AudioFrame* frame, size_t channels, size_t samples_per_channel,
-               int16_t left_data, int16_t right_data) {
+void InitFrame(AudioFrame* frame,
+               size_t channels,
+               size_t samples_per_channel,
+               int16_t left_data,
+               int16_t right_data) {
   RTC_DCHECK(frame);
   RTC_DCHECK_GE(2, channels);
   RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples,
@@ -90,7 +92,9 @@
   return frame.data()[index * frame.num_channels_ + channel];
 }
 
-void VerifyFrameDataBounds(const AudioFrame& frame, size_t channel, int16_t max,
+void VerifyFrameDataBounds(const AudioFrame& frame,
+                           size_t channel,
+                           int16_t max,
                            int16_t min) {
   for (size_t i = 0; i < frame.samples_per_channel_; ++i) {
     int16_t s = GetChannelData(frame, channel, i);
diff --git a/common_audio/BUILD.gn b/common_audio/BUILD.gn
index 057b11c..57cf699 100644
--- a/common_audio/BUILD.gn
+++ b/common_audio/BUILD.gn
@@ -6,7 +6,6 @@
 # in the file PATENTS.  All contributing project authors may
 # be found in the AUTHORS file in the root of the source tree.
 
-import("//build/config/arm.gni")
 import("../webrtc.gni")
 
 visibility = [ ":*" ]
@@ -61,10 +60,10 @@
 
   deps = [
     ":common_audio_c",
+    ":fft4g",
     ":sinc_resampler",
     "..:webrtc_common",
     "../:typedefs",
-    "../api:optional",
     "../rtc_base:checks",
     "../rtc_base:gtest_prod",
     "../rtc_base:rtc_base_approved",
@@ -72,35 +71,17 @@
     "../rtc_base/memory:aligned_malloc",
     "../system_wrappers",
     "../system_wrappers:cpu_features_api",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 
   defines = []
-  if (rtc_use_openmax_dl) {
-    sources += [
-      "real_fourier_openmax.cc",
-      "real_fourier_openmax.h",
-    ]
-    defines += [ "RTC_USE_OPENMAX_DL" ]
-    if (rtc_build_openmax_dl) {
-      deps += [ "//third_party/openmax_dl/dl" ]
-    }
-  }
 
   if (rtc_build_with_neon) {
     deps += [ ":common_audio_neon" ]
   }
 
-  if (is_win) {
-    cflags = [ "/wd4334" ]  # Ignore warning on shift operator promotion.
-  }
-
   public_configs = [ ":common_audio_config" ]
 
-  if (!build_with_chromium && is_clang) {
-    # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-    suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-  }
-
   if (current_cpu == "x86" || current_cpu == "x64") {
     deps += [ ":common_audio_sse2" ]
   }
@@ -140,8 +121,6 @@
 rtc_source_set("common_audio_c") {
   visibility += webrtc_default_visibility
   sources = [
-    "fft4g.c",
-    "fft4g.h",
     "ring_buffer.c",
     "ring_buffer.h",
     "signal_processing/auto_corr_to_refl_coef.c",
@@ -218,14 +197,11 @@
     ]
   }
 
-  if (is_win) {
-    cflags = [ "/wd4334" ]  # Ignore warning on shift operator promotion.
-  }
-
   public_configs = [ ":common_audio_config" ]
   deps = [
     ":common_audio_c_arm_asm",
     ":common_audio_cc",
+    ":fft4g",
     "..:webrtc_common",
     "../:typedefs",
     "../rtc_base:checks",
@@ -237,6 +213,14 @@
   ]
 }
 
+rtc_source_set("fft4g") {
+  visibility += webrtc_default_visibility
+  sources = [
+    "fft4g.c",
+    "fft4g.h",
+  ]
+}
+
 rtc_source_set("common_audio_cc") {
   sources = [
     "signal_processing/dot_product_with_scale.cc",
@@ -307,10 +291,6 @@
       cflags = [ "-msse2" ]
     }
 
-    if (!build_with_chromium && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-    }
     deps = [
       ":fir_filter",
       ":sinc_resampler",
@@ -346,11 +326,6 @@
       ]
     }
 
-    if (!build_with_chromium && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-    }
-
     deps = [
       ":common_audio_neon_c",
       ":fir_filter",
@@ -386,10 +361,6 @@
       ]
     }
 
-    if (!build_with_chromium && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-    }
     deps = [
       ":common_audio_c",
       "../rtc_base:checks",
@@ -438,15 +409,6 @@
       sources += [ "resampler/sinc_resampler_unittest.cc" ]
     }
 
-    if (rtc_use_openmax_dl) {
-      defines = [ "RTC_USE_OPENMAX_DL" ]
-    }
-
-    if (!build_with_chromium && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-    }
-
     deps = [
       ":common_audio",
       ":common_audio_c",
diff --git a/common_audio/DEPS b/common_audio/DEPS
index 47ce4c3..8a9adf1 100644
--- a/common_audio/DEPS
+++ b/common_audio/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
-  "+dl/sp/api",  # For openmax_dl.
   "+system_wrappers",
 ]
diff --git a/common_audio/audio_converter.cc b/common_audio/audio_converter.cc
index 47d2be2..0f97abb 100644
--- a/common_audio/audio_converter.cc
+++ b/common_audio/audio_converter.cc
@@ -26,12 +26,16 @@
 
 class CopyConverter : public AudioConverter {
  public:
-  CopyConverter(size_t src_channels, size_t src_frames, size_t dst_channels,
+  CopyConverter(size_t src_channels,
+                size_t src_frames,
+                size_t dst_channels,
                 size_t dst_frames)
       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
-  ~CopyConverter() override {};
+  ~CopyConverter() override{};
 
-  void Convert(const float* const* src, size_t src_size, float* const* dst,
+  void Convert(const float* const* src,
+               size_t src_size,
+               float* const* dst,
                size_t dst_capacity) override {
     CheckSizes(src_size, dst_capacity);
     if (src != dst) {
@@ -43,12 +47,16 @@
 
 class UpmixConverter : public AudioConverter {
  public:
-  UpmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels,
+  UpmixConverter(size_t src_channels,
+                 size_t src_frames,
+                 size_t dst_channels,
                  size_t dst_frames)
       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
-  ~UpmixConverter() override {};
+  ~UpmixConverter() override{};
 
-  void Convert(const float* const* src, size_t src_size, float* const* dst,
+  void Convert(const float* const* src,
+               size_t src_size,
+               float* const* dst,
                size_t dst_capacity) override {
     CheckSizes(src_size, dst_capacity);
     for (size_t i = 0; i < dst_frames(); ++i) {
@@ -61,13 +69,16 @@
 
 class DownmixConverter : public AudioConverter {
  public:
-  DownmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels,
+  DownmixConverter(size_t src_channels,
+                   size_t src_frames,
+                   size_t dst_channels,
                    size_t dst_frames)
-      : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {
-  }
-  ~DownmixConverter() override {};
+      : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
+  ~DownmixConverter() override{};
 
-  void Convert(const float* const* src, size_t src_size, float* const* dst,
+  void Convert(const float* const* src,
+               size_t src_size,
+               float* const* dst,
                size_t dst_capacity) override {
     CheckSizes(src_size, dst_capacity);
     float* dst_mono = dst[0];
@@ -82,7 +93,9 @@
 
 class ResampleConverter : public AudioConverter {
  public:
-  ResampleConverter(size_t src_channels, size_t src_frames, size_t dst_channels,
+  ResampleConverter(size_t src_channels,
+                    size_t src_frames,
+                    size_t dst_channels,
                     size_t dst_frames)
       : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {
     resamplers_.reserve(src_channels);
@@ -90,9 +103,11 @@
       resamplers_.push_back(std::unique_ptr<PushSincResampler>(
           new PushSincResampler(src_frames, dst_frames)));
   }
-  ~ResampleConverter() override {};
+  ~ResampleConverter() override{};
 
-  void Convert(const float* const* src, size_t src_size, float* const* dst,
+  void Convert(const float* const* src,
+               size_t src_size,
+               float* const* dst,
                size_t dst_capacity) override {
     CheckSizes(src_size, dst_capacity);
     for (size_t i = 0; i < resamplers_.size(); ++i)
@@ -108,7 +123,7 @@
 class CompositionConverter : public AudioConverter {
  public:
   explicit CompositionConverter(
-    std::vector<std::unique_ptr<AudioConverter>> converters)
+      std::vector<std::unique_ptr<AudioConverter>> converters)
       : converters_(std::move(converters)) {
     RTC_CHECK_GE(converters_.size(), 2);
     // We need an intermediate buffer after every converter.
@@ -117,19 +132,19 @@
           std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>(
               (*it)->dst_frames(), (*it)->dst_channels())));
   }
-  ~CompositionConverter() override {};
+  ~CompositionConverter() override{};
 
-  void Convert(const float* const* src, size_t src_size, float* const* dst,
+  void Convert(const float* const* src,
+               size_t src_size,
+               float* const* dst,
                size_t dst_capacity) override {
     converters_.front()->Convert(src, src_size, buffers_.front()->channels(),
                                  buffers_.front()->size());
     for (size_t i = 2; i < converters_.size(); ++i) {
       auto& src_buffer = buffers_[i - 2];
       auto& dst_buffer = buffers_[i - 1];
-      converters_[i]->Convert(src_buffer->channels(),
-                              src_buffer->size(),
-                              dst_buffer->channels(),
-                              dst_buffer->size());
+      converters_[i]->Convert(src_buffer->channels(), src_buffer->size(),
+                              dst_buffer->channels(), dst_buffer->size());
     }
     converters_.back()->Convert(buffers_.back()->channels(),
                                 buffers_.back()->size(), dst, dst_capacity);
@@ -175,8 +190,8 @@
     sp.reset(new ResampleConverter(src_channels, src_frames, dst_channels,
                                    dst_frames));
   } else {
-    sp.reset(new CopyConverter(src_channels, src_frames, dst_channels,
-                               dst_frames));
+    sp.reset(
+        new CopyConverter(src_channels, src_frames, dst_channels, dst_frames));
   }
 
   return sp;
@@ -184,13 +199,12 @@
 
 // For CompositionConverter.
 AudioConverter::AudioConverter()
-    : src_channels_(0),
-      src_frames_(0),
-      dst_channels_(0),
-      dst_frames_(0) {}
+    : src_channels_(0), src_frames_(0), dst_channels_(0), dst_frames_(0) {}
 
-AudioConverter::AudioConverter(size_t src_channels, size_t src_frames,
-                               size_t dst_channels, size_t dst_frames)
+AudioConverter::AudioConverter(size_t src_channels,
+                               size_t src_frames,
+                               size_t dst_channels,
+                               size_t dst_frames)
     : src_channels_(src_channels),
       src_frames_(src_frames),
       dst_channels_(dst_channels),
diff --git a/common_audio/audio_converter.h b/common_audio/audio_converter.h
index 3f7b9a8..769d724 100644
--- a/common_audio/audio_converter.h
+++ b/common_audio/audio_converter.h
@@ -37,8 +37,10 @@
   // capacity of |dst_capacity|. Both point to a series of buffers containing
   // the samples for each channel. The sizes must correspond to the format
   // passed to Create().
-  virtual void Convert(const float* const* src, size_t src_size,
-                       float* const* dst, size_t dst_capacity) = 0;
+  virtual void Convert(const float* const* src,
+                       size_t src_size,
+                       float* const* dst,
+                       size_t dst_capacity) = 0;
 
   size_t src_channels() const { return src_channels_; }
   size_t src_frames() const { return src_frames_; }
@@ -47,7 +49,9 @@
 
  protected:
   AudioConverter();
-  AudioConverter(size_t src_channels, size_t src_frames, size_t dst_channels,
+  AudioConverter(size_t src_channels,
+                 size_t src_frames,
+                 size_t dst_channels,
                  size_t dst_frames);
 
   // Helper to RTC_CHECK that inputs are correctly sized.
diff --git a/common_audio/audio_converter_unittest.cc b/common_audio/audio_converter_unittest.cc
index e9937fd..b99d825 100644
--- a/common_audio/audio_converter_unittest.cc
+++ b/common_audio/audio_converter_unittest.cc
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <cmath>
 #include <algorithm>
+#include <cmath>
 #include <memory>
 #include <vector>
 
@@ -52,8 +52,7 @@
 
   // Search within one sample of the expected delay.
   for (size_t delay = std::max(expected_delay, static_cast<size_t>(1)) - 1;
-       delay <= std::min(expected_delay + 1, ref.num_frames());
-       ++delay) {
+       delay <= std::min(expected_delay + 1, ref.num_frames()); ++delay) {
     float mse = 0;
     float variance = 0;
     float mean = 0;
@@ -92,8 +91,8 @@
                            int dst_sample_rate_hz) {
   const float kSrcLeft = 0.0002f;
   const float kSrcRight = 0.0001f;
-  const float resampling_factor = (1.f * src_sample_rate_hz) /
-      dst_sample_rate_hz;
+  const float resampling_factor =
+      (1.f * src_sample_rate_hz) / dst_sample_rate_hz;
   const float dst_left = resampling_factor * kSrcLeft;
   const float dst_right = resampling_factor * kSrcRight;
   const float dst_mono = (dst_left + dst_right) / 2;
@@ -124,13 +123,15 @@
   ScopedBuffer ref_buffer = CreateBuffer(ref_data, dst_frames);
 
   // The sinc resampler has a known delay, which we compute here.
-  const size_t delay_frames = src_sample_rate_hz == dst_sample_rate_hz ? 0 :
-      static_cast<size_t>(
-          PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) *
-          dst_sample_rate_hz);
+  const size_t delay_frames =
+      src_sample_rate_hz == dst_sample_rate_hz
+          ? 0
+          : static_cast<size_t>(
+                PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) *
+                dst_sample_rate_hz);
   // SNR reported on the same line later.
-  printf("(%" PRIuS ", %d Hz) -> (%" PRIuS ", %d Hz) ",
-         src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
+  printf("(%" PRIuS ", %d Hz) -> (%" PRIuS ", %d Hz) ", src_channels,
+         src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
 
   std::unique_ptr<AudioConverter> converter = AudioConverter::Create(
       src_channels, src_frames, dst_channels, dst_frames);
diff --git a/common_audio/audio_ring_buffer.cc b/common_audio/audio_ring_buffer.cc
index e7b5d81..b3bdc25 100644
--- a/common_audio/audio_ring_buffer.cc
+++ b/common_audio/audio_ring_buffer.cc
@@ -24,11 +24,12 @@
 }
 
 AudioRingBuffer::~AudioRingBuffer() {
-  for (auto buf : buffers_)
+  for (auto* buf : buffers_)
     WebRtc_FreeBuffer(buf);
 }
 
-void AudioRingBuffer::Write(const float* const* data, size_t channels,
+void AudioRingBuffer::Write(const float* const* data,
+                            size_t channels,
                             size_t frames) {
   RTC_DCHECK_EQ(buffers_.size(), channels);
   for (size_t i = 0; i < channels; ++i) {
@@ -57,7 +58,7 @@
 }
 
 void AudioRingBuffer::MoveReadPositionForward(size_t frames) {
-  for (auto buf : buffers_) {
+  for (auto* buf : buffers_) {
     const size_t moved =
         static_cast<size_t>(WebRtc_MoveReadPtr(buf, static_cast<int>(frames)));
     RTC_CHECK_EQ(moved, frames);
@@ -65,7 +66,7 @@
 }
 
 void AudioRingBuffer::MoveReadPositionBackward(size_t frames) {
-  for (auto buf : buffers_) {
+  for (auto* buf : buffers_) {
     const size_t moved = static_cast<size_t>(
         -WebRtc_MoveReadPtr(buf, -static_cast<int>(frames)));
     RTC_CHECK_EQ(moved, frames);
diff --git a/common_audio/audio_ring_buffer_unittest.cc b/common_audio/audio_ring_buffer_unittest.cc
index 2fcf800..d411195 100644
--- a/common_audio/audio_ring_buffer_unittest.cc
+++ b/common_audio/audio_ring_buffer_unittest.cc
@@ -17,8 +17,8 @@
 
 namespace webrtc {
 
-class AudioRingBufferTest :
-    public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > {
+class AudioRingBufferTest
+    : public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > {
 };
 
 void ReadAndWriteTest(const ChannelBuffer<float>& input,
@@ -72,10 +72,8 @@
       input.channels()[i][j] = (i + 1) * (j + 1);
 
   ChannelBuffer<float> output(kFrames, static_cast<int>(num_channels));
-  ReadAndWriteTest(input,
-                   ::testing::get<0>(GetParam()),
-                   ::testing::get<1>(GetParam()),
-                   ::testing::get<2>(GetParam()),
+  ReadAndWriteTest(input, ::testing::get<0>(GetParam()),
+                   ::testing::get<1>(GetParam()), ::testing::get<2>(GetParam()),
                    &output);
 
   // Verify the read data matches the input.
@@ -85,7 +83,8 @@
 }
 
 INSTANTIATE_TEST_CASE_P(
-    AudioRingBufferTest, AudioRingBufferTest,
+    AudioRingBufferTest,
+    AudioRingBufferTest,
     ::testing::Combine(::testing::Values(10, 20, 42),  // num_write_chunk_frames
                        ::testing::Values(1, 10, 17),   // num_read_chunk_frames
                        ::testing::Values(100, 256),    // buffer_frames
diff --git a/common_audio/blocker.cc b/common_audio/blocker.cc
index 7d09d21..3dc8ed8 100644
--- a/common_audio/blocker.cc
+++ b/common_audio/blocker.cc
@@ -41,8 +41,7 @@
                 float* const* dst,
                 size_t dst_start_index) {
   for (size_t i = 0; i < num_channels; ++i) {
-    memcpy(&dst[i][dst_start_index],
-           &src[i][src_start_index],
+    memcpy(&dst[i][dst_start_index], &src[i][src_start_index],
            num_frames * sizeof(dst[i][dst_start_index]));
   }
 }
@@ -55,8 +54,7 @@
                 float* const* dst,
                 size_t dst_start_index) {
   for (size_t i = 0; i < num_channels; ++i) {
-    memmove(&dst[i][dst_start_index],
-            &src[i][src_start_index],
+    memmove(&dst[i][dst_start_index], &src[i][src_start_index],
             num_frames * sizeof(dst[i][dst_start_index]));
   }
 }
@@ -87,9 +85,9 @@
 size_t gcd(size_t a, size_t b) {
   size_t tmp;
   while (b) {
-     tmp = a;
-     a = b;
-     b = tmp % b;
+    tmp = a;
+    a = b;
+    b = tmp % b;
   }
   return a;
 }
@@ -184,51 +182,30 @@
                        block_size_);
     input_buffer_.MoveReadPositionBackward(block_size_ - shift_amount_);
 
-    ApplyWindow(window_.get(),
-                block_size_,
-                num_input_channels_,
+    ApplyWindow(window_.get(), block_size_, num_input_channels_,
                 input_block_.channels());
-    callback_->ProcessBlock(input_block_.channels(),
-                            block_size_,
-                            num_input_channels_,
-                            num_output_channels_,
+    callback_->ProcessBlock(input_block_.channels(), block_size_,
+                            num_input_channels_, num_output_channels_,
                             output_block_.channels());
-    ApplyWindow(window_.get(),
-                block_size_,
-                num_output_channels_,
+    ApplyWindow(window_.get(), block_size_, num_output_channels_,
                 output_block_.channels());
 
-    AddFrames(output_buffer_.channels(),
-              first_frame_in_block,
-              output_block_.channels(),
-              0,
-              block_size_,
-              num_output_channels_,
-              output_buffer_.channels(),
-              first_frame_in_block);
+    AddFrames(output_buffer_.channels(), first_frame_in_block,
+              output_block_.channels(), 0, block_size_, num_output_channels_,
+              output_buffer_.channels(), first_frame_in_block);
 
     first_frame_in_block += shift_amount_;
   }
 
   // Copy output buffer to output
-  CopyFrames(output_buffer_.channels(),
-             0,
-             chunk_size_,
-             num_output_channels_,
-             output,
-             0);
+  CopyFrames(output_buffer_.channels(), 0, chunk_size_, num_output_channels_,
+             output, 0);
 
   // Copy output buffer [chunk_size_, chunk_size_ + initial_delay]
   // to output buffer [0, initial_delay], zero the rest.
-  MoveFrames(output_buffer_.channels(),
-             chunk_size,
-             initial_delay_,
-             num_output_channels_,
-             output_buffer_.channels(),
-             0);
-  ZeroOut(output_buffer_.channels(),
-          initial_delay_,
-          chunk_size_,
+  MoveFrames(output_buffer_.channels(), chunk_size, initial_delay_,
+             num_output_channels_, output_buffer_.channels(), 0);
+  ZeroOut(output_buffer_.channels(), initial_delay_, chunk_size_,
           num_output_channels_);
 
   // Calculate new starting frames.
diff --git a/common_audio/blocker_unittest.cc b/common_audio/blocker_unittest.cc
index 296efab..85a24f6 100644
--- a/common_audio/blocker_unittest.cc
+++ b/common_audio/blocker_unittest.cc
@@ -71,11 +71,8 @@
     size_t end = chunk_size - 1;
     while (end < num_frames) {
       CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input);
-      blocker->ProcessChunk(input_chunk,
-                            chunk_size,
-                            num_input_channels,
-                            num_output_channels,
-                            output_chunk);
+      blocker->ProcessChunk(input_chunk, chunk_size, num_input_channels,
+                            num_output_channels, output_chunk);
       CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk);
 
       start += chunk_size;
@@ -116,8 +113,7 @@
                      size_t num_frames,
                      const float* const* src) {
     for (size_t i = 0; i < num_channels; ++i) {
-      memcpy(&dst[i][start_index_dst],
-             &src[i][start_index_src],
+      memcpy(&dst[i][start_index_dst], &src[i][start_index_src],
              num_frames * sizeof(float));
     }
   }
@@ -152,27 +148,15 @@
   ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
 
   PlusThreeBlockerCallback callback;
-  Blocker blocker(kChunkSize,
-                  kBlockSize,
-                  kNumInputChannels,
-                  kNumOutputChannels,
-                  kWindow,
-                  kShiftAmount,
-                  &callback);
+  Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels,
+                  kWindow, kShiftAmount, &callback);
 
-  RunTest(&blocker,
-          kChunkSize,
-          kNumFrames,
-          input_cb.channels(),
-          input_chunk_cb.channels(),
-          actual_output_cb.channels(),
-          output_chunk_cb.channels(),
-          kNumInputChannels,
-          kNumOutputChannels);
+  RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(),
+          input_chunk_cb.channels(), actual_output_cb.channels(),
+          output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels);
 
   ValidateSignalEquality(expected_output_cb.channels(),
-                         actual_output_cb.channels(),
-                         kNumOutputChannels,
+                         actual_output_cb.channels(), kNumOutputChannels,
                          kNumFrames);
 }
 
@@ -205,27 +189,15 @@
   ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
 
   PlusThreeBlockerCallback callback;
-  Blocker blocker(kChunkSize,
-                  kBlockSize,
-                  kNumInputChannels,
-                  kNumOutputChannels,
-                  kWindow,
-                  kShiftAmount,
-                  &callback);
+  Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels,
+                  kWindow, kShiftAmount, &callback);
 
-  RunTest(&blocker,
-          kChunkSize,
-          kNumFrames,
-          input_cb.channels(),
-          input_chunk_cb.channels(),
-          actual_output_cb.channels(),
-          output_chunk_cb.channels(),
-          kNumInputChannels,
-          kNumOutputChannels);
+  RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(),
+          input_chunk_cb.channels(), actual_output_cb.channels(),
+          output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels);
 
   ValidateSignalEquality(expected_output_cb.channels(),
-                         actual_output_cb.channels(),
-                         kNumOutputChannels,
+                         actual_output_cb.channels(), kNumOutputChannels,
                          kNumFrames);
 }
 
@@ -258,27 +230,15 @@
   ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
 
   PlusThreeBlockerCallback callback;
-  Blocker blocker(kChunkSize,
-                  kBlockSize,
-                  kNumInputChannels,
-                  kNumOutputChannels,
-                  kWindow,
-                  kShiftAmount,
-                  &callback);
+  Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels,
+                  kWindow, kShiftAmount, &callback);
 
-  RunTest(&blocker,
-          kChunkSize,
-          kNumFrames,
-          input_cb.channels(),
-          input_chunk_cb.channels(),
-          actual_output_cb.channels(),
-          output_chunk_cb.channels(),
-          kNumInputChannels,
-          kNumOutputChannels);
+  RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(),
+          input_chunk_cb.channels(), actual_output_cb.channels(),
+          output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels);
 
   ValidateSignalEquality(expected_output_cb.channels(),
-                         actual_output_cb.channels(),
-                         kNumOutputChannels,
+                         actual_output_cb.channels(), kNumOutputChannels,
                          kNumFrames);
 }
 
@@ -286,14 +246,14 @@
   const size_t kNumInputChannels = 3;
   const size_t kNumOutputChannels = 2;
   const size_t kNumFrames = 1280;
-  const size_t kChunkSize[] =
-      {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160};
-  const size_t kBlockSize[] =
-      {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256};
-  const size_t kShiftAmount[] =
-      {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256};
-  const size_t kInitialDelay[] =
-      {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224};
+  const size_t kChunkSize[] = {80,  80,  80,  80,  80,  80,
+                               160, 160, 160, 160, 160, 160};
+  const size_t kBlockSize[] = {64,  64,  64,  128, 128, 128,
+                               128, 128, 128, 256, 256, 256};
+  const size_t kShiftAmount[] = {16, 32, 64,  32, 64,  128,
+                                 32, 64, 128, 64, 128, 256};
+  const size_t kInitialDelay[] = {48, 48, 48, 112, 112, 112,
+                                  96, 96, 96, 224, 224, 224};
 
   float input[kNumInputChannels][kNumFrames];
   for (size_t i = 0; i < kNumInputChannels; ++i) {
@@ -317,27 +277,15 @@
     ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels);
     ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels);
 
-    Blocker blocker(kChunkSize[i],
-                    kBlockSize[i],
-                    kNumInputChannels,
-                    kNumOutputChannels,
-                    window.get(),
-                    kShiftAmount[i],
+    Blocker blocker(kChunkSize[i], kBlockSize[i], kNumInputChannels,
+                    kNumOutputChannels, window.get(), kShiftAmount[i],
                     &callback);
 
-    RunTest(&blocker,
-            kChunkSize[i],
-            kNumFrames,
-            input_cb.channels(),
-            input_chunk_cb.channels(),
-            output_cb.channels(),
-            output_chunk_cb.channels(),
-            kNumInputChannels,
-            kNumOutputChannels);
+    RunTest(&blocker, kChunkSize[i], kNumFrames, input_cb.channels(),
+            input_chunk_cb.channels(), output_cb.channels(),
+            output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels);
 
-    ValidateInitialDelay(output_cb.channels(),
-                         kNumOutputChannels,
-                         kNumFrames,
+    ValidateInitialDelay(output_cb.channels(), kNumOutputChannels, kNumFrames,
                          kInitialDelay[i]);
   }
 }
diff --git a/common_audio/channel_buffer.cc b/common_audio/channel_buffer.cc
index df45f6d..38d231e 100644
--- a/common_audio/channel_buffer.cc
+++ b/common_audio/channel_buffer.cc
@@ -68,9 +68,7 @@
     ibuf_.set_num_channels(fbuf_.num_channels());
     const float* const* float_channels = fbuf_.channels();
     for (size_t i = 0; i < fbuf_.num_channels(); ++i) {
-      FloatS16ToS16(float_channels[i],
-                    ibuf_.num_frames(),
-                    int_channels[i]);
+      FloatS16ToS16(float_channels[i], ibuf_.num_frames(), int_channels[i]);
     }
     ivalid_ = true;
   }
diff --git a/common_audio/channel_buffer.h b/common_audio/channel_buffer.h
index 024868c..3f9ba9c 100644
--- a/common_audio/channel_buffer.h
+++ b/common_audio/channel_buffer.h
@@ -40,9 +40,7 @@
 template <typename T>
 class ChannelBuffer {
  public:
-  ChannelBuffer(size_t num_frames,
-                size_t num_channels,
-                size_t num_bands = 1)
+  ChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1)
       : data_(new T[num_frames * num_channels]()),
         channels_(new T*[num_channels * num_bands]),
         bands_(new T*[num_channels * num_bands]),
@@ -119,7 +117,7 @@
   size_t num_frames_per_band() const { return num_frames_per_band_; }
   size_t num_channels() const { return num_channels_; }
   size_t num_bands() const { return num_bands_; }
-  size_t size() const {return num_frames_ * num_allocated_channels_; }
+  size_t size() const { return num_frames_ * num_allocated_channels_; }
 
   void set_num_channels(size_t num_channels) {
     RTC_DCHECK_LE(num_channels, num_allocated_channels_);
diff --git a/common_audio/fft4g.h b/common_audio/fft4g.h
index 1f0e29d..1750e27 100644
--- a/common_audio/fft4g.h
+++ b/common_audio/fft4g.h
@@ -16,7 +16,7 @@
 #endif
 
 // Refer to fft4g.c for documentation.
-void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w);
+void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w);
 
 #if defined(__cplusplus)
 }
diff --git a/common_audio/fir_filter_c.cc b/common_audio/fir_filter_c.cc
index 6fe2470..3418434 100644
--- a/common_audio/fir_filter_c.cc
+++ b/common_audio/fir_filter_c.cc
@@ -20,8 +20,7 @@
 
 namespace webrtc {
 
-FIRFilterC::~FIRFilterC() {
-}
+FIRFilterC::~FIRFilterC() {}
 
 FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length)
     : coefficients_length_(coefficients_length),
@@ -52,11 +51,10 @@
 
   // Update current state.
   if (length >= state_length_) {
-    memcpy(
-        state_.get(), &in[length - state_length_], state_length_ * sizeof(*in));
+    memcpy(state_.get(), &in[length - state_length_],
+           state_length_ * sizeof(*in));
   } else {
-    memmove(state_.get(),
-            &state_[length],
+    memmove(state_.get(), &state_[length],
             (state_length_ - length) * sizeof(state_[0]));
     memcpy(&state_[state_length_ - length], in, length * sizeof(*in));
   }
diff --git a/common_audio/fir_filter_c.h b/common_audio/fir_filter_c.h
index ffce838..d263e1b 100644
--- a/common_audio/fir_filter_c.h
+++ b/common_audio/fir_filter_c.h
@@ -20,8 +20,7 @@
 
 class FIRFilterC : public FIRFilter {
  public:
-  FIRFilterC(const float* coefficients,
-             size_t coefficients_length);
+  FIRFilterC(const float* coefficients, size_t coefficients_length);
   ~FIRFilterC() override;
 
   void Filter(const float* in, size_t length, float* out) override;
diff --git a/common_audio/fir_filter_factory.h b/common_audio/fir_filter_factory.h
index 2e7ca9b..a952541 100644
--- a/common_audio/fir_filter_factory.h
+++ b/common_audio/fir_filter_factory.h
@@ -1,4 +1,4 @@
-  /*
+/*
  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
  *
  *  Use of this source code is governed by a BSD-style license
diff --git a/common_audio/fir_filter_neon.cc b/common_audio/fir_filter_neon.cc
index e27f21b..f668841 100644
--- a/common_audio/fir_filter_neon.cc
+++ b/common_audio/fir_filter_neon.cc
@@ -18,8 +18,7 @@
 
 namespace webrtc {
 
-FIRFilterNEON::~FIRFilterNEON() {
-}
+FIRFilterNEON::~FIRFilterNEON() {}
 
 FIRFilterNEON::FIRFilterNEON(const float* coefficients,
                              size_t coefficients_length,
@@ -40,8 +39,7 @@
   for (size_t i = 0; i < coefficients_length; ++i) {
     coefficients_[i + padding] = coefficients[coefficients_length - i - 1];
   }
-  memset(state_.get(),
-         0.f,
+  memset(state_.get(), 0.f,
          (max_input_length + state_length_) * sizeof(state_[0]));
 }
 
@@ -60,8 +58,8 @@
     float32x4_t m_in;
 
     for (size_t j = 0; j < coefficients_length_; j += 4) {
-       m_in = vld1q_f32(in_ptr + j);
-       m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j));
+      m_in = vld1q_f32(in_ptr + j);
+      m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j));
     }
 
     float32x2_t m_half = vadd_f32(vget_high_f32(m_sum), vget_low_f32(m_sum));
diff --git a/common_audio/fir_filter_sse.cc b/common_audio/fir_filter_sse.cc
index 0da23fc..ee75fb3 100644
--- a/common_audio/fir_filter_sse.cc
+++ b/common_audio/fir_filter_sse.cc
@@ -19,8 +19,7 @@
 
 namespace webrtc {
 
-FIRFilterSSE2::~FIRFilterSSE2() {
-}
+FIRFilterSSE2::~FIRFilterSSE2() {}
 
 FIRFilterSSE2::FIRFilterSSE2(const float* coefficients,
                              size_t coefficients_length,
@@ -41,8 +40,7 @@
   for (size_t i = 0; i < coefficients_length; ++i) {
     coefficients_[i + padding] = coefficients[coefficients_length - i - 1];
   }
-  memset(state_.get(),
-         0,
+  memset(state_.get(), 0,
          (max_input_length + state_length_) * sizeof(state_[0]));
 }
 
diff --git a/common_audio/fir_filter_unittest.cc b/common_audio/fir_filter_unittest.cc
index 4696621..07abf20 100644
--- a/common_audio/fir_filter_unittest.cc
+++ b/common_audio/fir_filter_unittest.cc
@@ -21,20 +21,18 @@
 namespace {
 
 static const float kCoefficients[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
-static const size_t kCoefficientsLength = sizeof(kCoefficients) /
-                                       sizeof(kCoefficients[0]);
+static const size_t kCoefficientsLength =
+    sizeof(kCoefficients) / sizeof(kCoefficients[0]);
 
-static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,
-                                      8.f, 9.f, 10.f};
-static const size_t kInputLength = sizeof(kInput) /
-                                      sizeof(kInput[0]);
+static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f,
+                               6.f, 7.f, 8.f, 9.f, 10.f};
+static const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
 void VerifyOutput(const float* expected_output,
                   const float* output,
                   size_t length) {
-  EXPECT_EQ(0, memcmp(expected_output,
-                      output,
-                      length * sizeof(expected_output[0])));
+  EXPECT_EQ(
+      0, memcmp(expected_output, output, length * sizeof(expected_output[0])));
 }
 
 }  // namespace
@@ -97,8 +95,8 @@
 
   EXPECT_FLOAT_EQ(0.2f, output[0]);
   EXPECT_FLOAT_EQ(0.7f, output[1]);
-  filter.reset(CreateFirFilter(
-      kCoefficients, kCoefficientsLength, kCoefficientsLength));
+  filter.reset(
+      CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength));
   filter->Filter(kInput, kCoefficientsLength, output);
 
   EXPECT_FLOAT_EQ(0.2f, output[0]);
@@ -149,19 +147,17 @@
     filter->Filter(&kInput[i], 1, &output_sample_based[i]);
   }
 
-  EXPECT_EQ(0, memcmp(output_sample_based,
-                      output_block_based,
-                      kInputLength));
+  EXPECT_EQ(0, memcmp(output_sample_based, output_block_based, kInputLength));
 }
 
 TEST(FIRFilterTest, SimplestHighPassFilter) {
   const float kCoefficients[] = {1.f, -1.f};
-  const size_t kCoefficientsLength = sizeof(kCoefficients) /
-                                  sizeof(kCoefficients[0]);
+  const size_t kCoefficientsLength =
+      sizeof(kCoefficients) / sizeof(kCoefficients[0]);
 
   float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
-  const size_t kConstantInputLength = sizeof(kConstantInput) /
-      sizeof(kConstantInput[0]);
+  const size_t kConstantInputLength =
+      sizeof(kConstantInput) / sizeof(kConstantInput[0]);
 
   float output[kConstantInputLength];
   std::unique_ptr<FIRFilter> filter(CreateFirFilter(
@@ -175,12 +171,12 @@
 
 TEST(FIRFilterTest, SimplestLowPassFilter) {
   const float kCoefficients[] = {1.f, 1.f};
-  const size_t kCoefficientsLength = sizeof(kCoefficients) /
-                                  sizeof(kCoefficients[0]);
+  const size_t kCoefficientsLength =
+      sizeof(kCoefficients) / sizeof(kCoefficients[0]);
 
   float kHighFrequencyInput[] = {-1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f};
-  const size_t kHighFrequencyInputLength = sizeof(kHighFrequencyInput) /
-                                        sizeof(kHighFrequencyInput[0]);
+  const size_t kHighFrequencyInputLength =
+      sizeof(kHighFrequencyInput) / sizeof(kHighFrequencyInput[0]);
 
   float output[kHighFrequencyInputLength];
   std::unique_ptr<FIRFilter> filter(CreateFirFilter(
@@ -195,16 +191,16 @@
 TEST(FIRFilterTest, SameOutputWhenSwapedCoefficientsAndInput) {
   float output[kCoefficientsLength];
   float output_swaped[kCoefficientsLength];
-  std::unique_ptr<FIRFilter> filter(CreateFirFilter(
-      kCoefficients, kCoefficientsLength, kCoefficientsLength));
+  std::unique_ptr<FIRFilter> filter(
+      CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength));
   // Use kCoefficientsLength for in_length to get same-length outputs.
   filter->Filter(kInput, kCoefficientsLength, output);
 
-  filter.reset(CreateFirFilter(
-      kInput, kCoefficientsLength, kCoefficientsLength));
+  filter.reset(
+      CreateFirFilter(kInput, kCoefficientsLength, kCoefficientsLength));
   filter->Filter(kCoefficients, kCoefficientsLength, output_swaped);
 
-  for (size_t i = 0 ; i < kCoefficientsLength; ++i) {
+  for (size_t i = 0; i < kCoefficientsLength; ++i) {
     EXPECT_FLOAT_EQ(output[i], output_swaped[i]);
   }
 }
diff --git a/common_audio/lapped_transform.cc b/common_audio/lapped_transform.cc
index 517709f..72c2ad7 100644
--- a/common_audio/lapped_transform.cc
+++ b/common_audio/lapped_transform.cc
@@ -29,20 +29,17 @@
   RTC_CHECK_EQ(parent_->block_length_, num_frames);
 
   for (size_t i = 0; i < num_input_channels; ++i) {
-    memcpy(parent_->real_buf_.Row(i), input[i],
-           num_frames * sizeof(*input[0]));
+    memcpy(parent_->real_buf_.Row(i), input[i], num_frames * sizeof(*input[0]));
     parent_->fft_->Forward(parent_->real_buf_.Row(i),
                            parent_->cplx_pre_.Row(i));
   }
 
-  size_t block_length = RealFourier::ComplexLength(
-      RealFourier::FftOrder(num_frames));
+  size_t block_length =
+      RealFourier::ComplexLength(RealFourier::FftOrder(num_frames));
   RTC_CHECK_EQ(parent_->cplx_length_, block_length);
-  parent_->block_processor_->ProcessAudioBlock(parent_->cplx_pre_.Array(),
-                                               num_input_channels,
-                                               parent_->cplx_length_,
-                                               num_output_channels,
-                                               parent_->cplx_post_.Array());
+  parent_->block_processor_->ProcessAudioBlock(
+      parent_->cplx_pre_.Array(), num_input_channels, parent_->cplx_length_,
+      num_output_channels, parent_->cplx_post_.Array());
 
   for (size_t i = 0; i < num_output_channels; ++i) {
     parent_->fft_->Inverse(parent_->cplx_post_.Row(i),
diff --git a/common_audio/lapped_transform.h b/common_audio/lapped_transform.h
index c97cd16..1ab2a9f 100644
--- a/common_audio/lapped_transform.h
+++ b/common_audio/lapped_transform.h
@@ -35,7 +35,8 @@
     virtual ~Callback() {}
 
     virtual void ProcessAudioBlock(const std::complex<float>* const* in_block,
-                                   size_t num_in_channels, size_t frames,
+                                   size_t num_in_channels,
+                                   size_t frames,
                                    size_t num_out_channels,
                                    std::complex<float>* const* out_block) = 0;
   };
@@ -128,4 +129,3 @@
 }  // namespace webrtc
 
 #endif  // COMMON_AUDIO_LAPPED_TRANSFORM_H_
-
diff --git a/common_audio/lapped_transform_unittest.cc b/common_audio/lapped_transform_unittest.cc
index d6a312d..687df89 100644
--- a/common_audio/lapped_transform_unittest.cc
+++ b/common_audio/lapped_transform_unittest.cc
@@ -24,11 +24,11 @@
  public:
   NoopCallback() : block_num_(0) {}
 
-  virtual void ProcessAudioBlock(const complex<float>* const* in_block,
-                                 size_t in_channels,
-                                 size_t frames,
-                                 size_t out_channels,
-                                 complex<float>* const* out_block) {
+  void ProcessAudioBlock(const complex<float>* const* in_block,
+                         size_t in_channels,
+                         size_t frames,
+                         size_t out_channels,
+                         complex<float>* const* out_block) override {
     RTC_CHECK_EQ(in_channels, out_channels);
     for (size_t i = 0; i < out_channels; ++i) {
       memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames);
@@ -36,9 +36,7 @@
     ++block_num_;
   }
 
-  size_t block_num() {
-    return block_num_;
-  }
+  size_t block_num() { return block_num_; }
 
  private:
   size_t block_num_;
@@ -48,11 +46,11 @@
  public:
   FftCheckerCallback() : block_num_(0) {}
 
-  virtual void ProcessAudioBlock(const complex<float>* const* in_block,
-                                 size_t in_channels,
-                                 size_t frames,
-                                 size_t out_channels,
-                                 complex<float>* const* out_block) {
+  void ProcessAudioBlock(const complex<float>* const* in_block,
+                         size_t in_channels,
+                         size_t frames,
+                         size_t out_channels,
+                         complex<float>* const* out_block) override {
     RTC_CHECK_EQ(in_channels, out_channels);
 
     size_t full_length = (frames - 1) * 2;
@@ -69,9 +67,7 @@
     }
   }
 
-  size_t block_num() {
-    return block_num_;
-  }
+  size_t block_num() { return block_num_; }
 
  private:
   size_t block_num_;
@@ -150,8 +146,7 @@
   trans.ProcessChunk(&in_chunk, &out_chunk);
 
   for (size_t i = 0; i < kChunkLength; ++i) {
-    ASSERT_NEAR(out_chunk[i],
-                (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
+    ASSERT_NEAR(out_chunk[i], (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
                 1e-5f);
   }
 
@@ -167,8 +162,8 @@
   float window[kBlockLength];
   std::fill(window, &window[kBlockLength], 1.0f);
 
-  LappedTransform trans(1, 1, kChunkLength, window, kBlockLength,
-                        kBlockLength, &call);
+  LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kBlockLength,
+                        &call);
   float in_buffer[kChunkLength];
   float* in_chunk = in_buffer;
   float out_buffer[kChunkLength];
diff --git a/common_audio/mocks/mock_smoothing_filter.h b/common_audio/mocks/mock_smoothing_filter.h
index dec6ea5..712049f 100644
--- a/common_audio/mocks/mock_smoothing_filter.h
+++ b/common_audio/mocks/mock_smoothing_filter.h
@@ -19,7 +19,7 @@
 class MockSmoothingFilter : public SmoothingFilter {
  public:
   MOCK_METHOD1(AddSample, void(float));
-  MOCK_METHOD0(GetAverage, rtc::Optional<float>());
+  MOCK_METHOD0(GetAverage, absl::optional<float>());
   MOCK_METHOD1(SetTimeConstantMs, bool(int));
 };
 
diff --git a/common_audio/real_fourier.cc b/common_audio/real_fourier.cc
index f01c8eb..7365844 100644
--- a/common_audio/real_fourier.cc
+++ b/common_audio/real_fourier.cc
@@ -31,7 +31,7 @@
 
 size_t RealFourier::FftLength(int order) {
   RTC_CHECK_GE(order, 0);
-  return static_cast<size_t>(1 << order);
+  return size_t{1} << order;
 }
 
 size_t RealFourier::ComplexLength(int order) {
diff --git a/common_audio/real_fourier.h b/common_audio/real_fourier.h
index d16149b..a3e4dd1 100644
--- a/common_audio/real_fourier.h
+++ b/common_audio/real_fourier.h
@@ -72,4 +72,3 @@
 }  // namespace webrtc
 
 #endif  // COMMON_AUDIO_REAL_FOURIER_H_
-
diff --git a/common_audio/real_fourier_ooura.cc b/common_audio/real_fourier_ooura.cc
index 5d75717..db65d26 100644
--- a/common_audio/real_fourier_ooura.cc
+++ b/common_audio/real_fourier_ooura.cc
@@ -10,8 +10,8 @@
 
 #include "common_audio/real_fourier_ooura.h"
 
-#include <cmath>
 #include <algorithm>
+#include <cmath>
 
 #include "common_audio/fft4g.h"
 #include "rtc_base/checks.h"
@@ -28,8 +28,8 @@
 }
 
 size_t ComputeWorkIpSize(size_t fft_length) {
-  return static_cast<size_t>(2 + std::ceil(std::sqrt(
-      static_cast<float>(fft_length))));
+  return static_cast<size_t>(
+      2 + std::ceil(std::sqrt(static_cast<float>(fft_length))));
 }
 
 }  // namespace
@@ -45,11 +45,13 @@
   RTC_CHECK_GE(fft_order, 1);
 }
 
+RealFourierOoura::~RealFourierOoura() = default;
+
 void RealFourierOoura::Forward(const float* src, complex<float>* dest) const {
   {
     // This cast is well-defined since C++11. See "Non-static data members" at:
     // http://en.cppreference.com/w/cpp/numeric/complex
-    auto dest_float = reinterpret_cast<float*>(dest);
+    auto* dest_float = reinterpret_cast<float*>(dest);
     std::copy(src, src + length_, dest_float);
     WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get());
   }
@@ -63,7 +65,7 @@
 
 void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
   {
-    auto dest_complex = reinterpret_cast<complex<float>*>(dest);
+    auto* dest_complex = reinterpret_cast<complex<float>*>(dest);
     // The real output array is shorter than the input complex array by one
     // complex element.
     const size_t dest_complex_length = complex_length_ - 1;
@@ -71,8 +73,8 @@
     // Restore Ooura's conjugate definition.
     Conjugate(dest_complex, dest_complex_length);
     // Restore real[n/2] to imag[0].
-    dest_complex[0] = complex<float>(dest_complex[0].real(),
-                                     src[complex_length_ - 1].real());
+    dest_complex[0] =
+        complex<float>(dest_complex[0].real(), src[complex_length_ - 1].real());
   }
 
   WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get());
@@ -82,4 +84,8 @@
   std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; });
 }
 
+int RealFourierOoura::order() const {
+  return order_;
+}
+
 }  // namespace webrtc
diff --git a/common_audio/real_fourier_ooura.h b/common_audio/real_fourier_ooura.h
index f885a34..bb8eef9 100644
--- a/common_audio/real_fourier_ooura.h
+++ b/common_audio/real_fourier_ooura.h
@@ -21,13 +21,12 @@
 class RealFourierOoura : public RealFourier {
  public:
   explicit RealFourierOoura(int fft_order);
+  ~RealFourierOoura() override;
 
   void Forward(const float* src, std::complex<float>* dest) const override;
   void Inverse(const std::complex<float>* src, float* dest) const override;
 
-  int order() const override {
-    return order_;
-  }
+  int order() const override;
 
  private:
   const int order_;
@@ -42,4 +41,3 @@
 }  // namespace webrtc
 
 #endif  // COMMON_AUDIO_REAL_FOURIER_OOURA_H_
-
diff --git a/common_audio/real_fourier_openmax.cc b/common_audio/real_fourier_openmax.cc
deleted file mode 100644
index 3c4d0e5..0000000
--- a/common_audio/real_fourier_openmax.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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.
- */
-
-// TODO(http://bugs.webrtc.org/9071): Required by downstream projects.
-#ifdef RTC_USE_OPENMAX_DL
-
-#include "common_audio/real_fourier_openmax.h"
-
-#include <cstdlib>
-
-#include "dl/sp/api/omxSP.h"
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-
-using std::complex;
-
-namespace {
-
-// Creates and initializes the Openmax state. Transfers ownership to caller.
-OMXFFTSpec_R_F32* CreateOpenmaxState(int order) {
-  RTC_CHECK_GE(order, 1);
-  // The omx implementation uses this macro to check order validity.
-  RTC_CHECK_LE(order, TWIDDLE_TABLE_ORDER);
-
-  OMX_INT buffer_size;
-  OMXResult r = omxSP_FFTGetBufSize_R_F32(order, &buffer_size);
-  RTC_CHECK_EQ(r, OMX_Sts_NoErr);
-
-  OMXFFTSpec_R_F32* omx_spec = malloc(buffer_size);
-  RTC_DCHECK(omx_spec);
-
-  r = omxSP_FFTInit_R_F32(omx_spec, order);
-  RTC_CHECK_EQ(r, OMX_Sts_NoErr);
-  return omx_spec;
-}
-
-}  // namespace
-
-RealFourierOpenmax::RealFourierOpenmax(int fft_order)
-    : order_(fft_order),
-      omx_spec_(CreateOpenmaxState(order_)) {
-}
-
-RealFourierOpenmax::~RealFourierOpenmax() {
-  free(omx_spec_);
-}
-
-void RealFourierOpenmax::Forward(const float* src, complex<float>* dest) const {
-  // This cast is well-defined since C++11. See "Non-static data members" at:
-  // http://en.cppreference.com/w/cpp/numeric/complex
-  OMXResult r =
-      omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast<OMX_F32*>(dest), omx_spec_);
-  RTC_CHECK_EQ(r, OMX_Sts_NoErr);
-}
-
-void RealFourierOpenmax::Inverse(const complex<float>* src, float* dest) const {
-  OMXResult r =
-      omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest,
-                              omx_spec_);
-  RTC_CHECK_EQ(r, OMX_Sts_NoErr);
-}
-
-}  // namespace webrtc
-
-#endif  // 0
diff --git a/common_audio/real_fourier_openmax.h b/common_audio/real_fourier_openmax.h
deleted file mode 100644
index e132280..0000000
--- a/common_audio/real_fourier_openmax.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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 COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
-#define COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
-
-// TODO(http://bugs.webrtc.org/9071): Required by downstream projects.
-#ifdef RTC_USE_OPENMAX_DL
-
-#include <complex>
-
-#include "common_audio/real_fourier.h"
-
-namespace webrtc {
-
-class RealFourierOpenmax : public RealFourier {
- public:
-  explicit RealFourierOpenmax(int fft_order);
-  ~RealFourierOpenmax() override;
-
-  void Forward(const float* src, std::complex<float>* dest) const override;
-  void Inverse(const std::complex<float>* src, float* dest) const override;
-
-  int order() const override {
-    return order_;
-  }
-
- private:
-  // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the
-  // dependency on openmax.
-  typedef void OMXFFTSpec_R_F32_;
-  const int order_;
-
-  OMXFFTSpec_R_F32_* const omx_spec_;
-};
-
-}  // namespace webrtc
-
-#endif  // RTC_USE_OPENMAX_DL
-
-#endif  // COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
diff --git a/common_audio/real_fourier_unittest.cc b/common_audio/real_fourier_unittest.cc
index e6ec012..1324887 100644
--- a/common_audio/real_fourier_unittest.cc
+++ b/common_audio/real_fourier_unittest.cc
@@ -15,10 +15,6 @@
 #include "common_audio/real_fourier_ooura.h"
 #include "test/gtest.h"
 
-#ifdef RTC_USE_OPENMAX_DL
-#include "common_audio/real_fourier_openmax.h"
-#endif
-
 namespace webrtc {
 
 using std::complex;
@@ -64,8 +60,7 @@
         real_buffer_(RealFourier::AllocRealBuffer(4)),
         cplx_buffer_(RealFourier::AllocCplxBuffer(3)) {}
 
-  ~RealFourierTest() {
-  }
+  ~RealFourierTest() {}
 
   T rf_;
   const RealFourier::fft_real_scoper real_buffer_;
diff --git a/common_audio/resampler/include/push_resampler.h b/common_audio/resampler/include/push_resampler.h
index 046415b..05b93d1 100644
--- a/common_audio/resampler/include/push_resampler.h
+++ b/common_audio/resampler/include/push_resampler.h
@@ -29,7 +29,8 @@
 
   // Must be called whenever the parameters change. Free to be called at any
   // time as it is a no-op if parameters have not changed since the last call.
-  int InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz,
+  int InitializeIfNeeded(int src_sample_rate_hz,
+                         int dst_sample_rate_hz,
                          size_t num_channels);
 
   // Returns the total number of samples provided in destination (e.g. 32 kHz,
diff --git a/common_audio/resampler/include/resampler.h b/common_audio/resampler/include/resampler.h
index fec2c1a..f923b46 100644
--- a/common_audio/resampler/include/resampler.h
+++ b/common_audio/resampler/include/resampler.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /*
  * A wrapper for resampling a numerous amount of sampling combinations.
  */
@@ -36,8 +35,11 @@
   int ResetIfNeeded(int inFreq, int outFreq, size_t num_channels);
 
   // Resample samplesIn to samplesOut.
-  int Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut,
-           size_t maxLen, size_t& outLen);  // NOLINT: to avoid changing APIs
+  int Push(const int16_t* samplesIn,
+           size_t lengthIn,
+           int16_t* samplesOut,
+           size_t maxLen,
+           size_t& outLen);  // NOLINT: to avoid changing APIs
 
  private:
   enum ResamplerMode {
diff --git a/common_audio/resampler/push_resampler.cc b/common_audio/resampler/push_resampler.cc
index 3930624..cc24c4b 100644
--- a/common_audio/resampler/push_resampler.cc
+++ b/common_audio/resampler/push_resampler.cc
@@ -25,7 +25,8 @@
 // caused the compiler to generate code that threw off the linker.
 // TODO(tommi): Re-enable when we've figured out what the problem is.
 // http://crbug.com/615050
-void CheckValidInitParams(int src_sample_rate_hz, int dst_sample_rate_hz,
+void CheckValidInitParams(int src_sample_rate_hz,
+                          int dst_sample_rate_hz,
                           size_t num_channels) {
 // The below checks are temporarily disabled on WEBRTC_WIN due to problems
 // with clang debug builds.
@@ -57,14 +58,10 @@
 
 template <typename T>
 PushResampler<T>::PushResampler()
-    : src_sample_rate_hz_(0),
-      dst_sample_rate_hz_(0),
-      num_channels_(0) {
-}
+    : src_sample_rate_hz_(0), dst_sample_rate_hz_(0), num_channels_(0) {}
 
 template <typename T>
-PushResampler<T>::~PushResampler() {
-}
+PushResampler<T>::~PushResampler() {}
 
 template <typename T>
 int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz,
@@ -92,22 +89,24 @@
       static_cast<size_t>(src_sample_rate_hz / 100);
   const size_t dst_size_10ms_mono =
       static_cast<size_t>(dst_sample_rate_hz / 100);
-  sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono,
-                                              dst_size_10ms_mono));
+  sinc_resampler_.reset(
+      new PushSincResampler(src_size_10ms_mono, dst_size_10ms_mono));
   if (num_channels_ == 2) {
     src_left_.reset(new T[src_size_10ms_mono]);
     src_right_.reset(new T[src_size_10ms_mono]);
     dst_left_.reset(new T[dst_size_10ms_mono]);
     dst_right_.reset(new T[dst_size_10ms_mono]);
-    sinc_resampler_right_.reset(new PushSincResampler(src_size_10ms_mono,
-                                                      dst_size_10ms_mono));
+    sinc_resampler_right_.reset(
+        new PushSincResampler(src_size_10ms_mono, dst_size_10ms_mono));
   }
 
   return 0;
 }
 
 template <typename T>
-int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst,
+int PushResampler<T>::Resample(const T* src,
+                               size_t src_length,
+                               T* dst,
                                size_t dst_capacity) {
   CheckExpectedBufferSizes(src_length, dst_capacity, num_channels_,
                            src_sample_rate_hz_, dst_sample_rate_hz_);
@@ -124,9 +123,8 @@
     T* deinterleaved[] = {src_left_.get(), src_right_.get()};
     Deinterleave(src, src_length_mono, num_channels_, deinterleaved);
 
-    size_t dst_length_mono =
-        sinc_resampler_->Resample(src_left_.get(), src_length_mono,
-                                  dst_left_.get(), dst_capacity_mono);
+    size_t dst_length_mono = sinc_resampler_->Resample(
+        src_left_.get(), src_length_mono, dst_left_.get(), dst_capacity_mono);
     sinc_resampler_right_->Resample(src_right_.get(), src_length_mono,
                                     dst_right_.get(), dst_capacity_mono);
 
diff --git a/common_audio/resampler/push_sinc_resampler.cc b/common_audio/resampler/push_sinc_resampler.cc
index 14ab330..3bfead2 100644
--- a/common_audio/resampler/push_sinc_resampler.cc
+++ b/common_audio/resampler/push_sinc_resampler.cc
@@ -28,8 +28,7 @@
       first_pass_(true),
       source_available_(0) {}
 
-PushSincResampler::~PushSincResampler() {
-}
+PushSincResampler::~PushSincResampler() {}
 
 size_t PushSincResampler::Resample(const int16_t* source,
                                    size_t source_length,
diff --git a/common_audio/resampler/push_sinc_resampler.h b/common_audio/resampler/push_sinc_resampler.h
index bdc03a2..ad51471 100644
--- a/common_audio/resampler/push_sinc_resampler.h
+++ b/common_audio/resampler/push_sinc_resampler.h
@@ -36,8 +36,10 @@
   // at least as large as |destination_frames|. Returns the number of samples
   // provided in destination (for convenience, since this will always be equal
   // to |destination_frames|).
-  size_t Resample(const int16_t* source, size_t source_frames,
-                  int16_t* destination, size_t destination_capacity);
+  size_t Resample(const int16_t* source,
+                  size_t source_frames,
+                  int16_t* destination,
+                  size_t destination_capacity);
   size_t Resample(const float* source,
                   size_t source_frames,
                   float* destination,
diff --git a/common_audio/resampler/push_sinc_resampler_unittest.cc b/common_audio/resampler/push_sinc_resampler_unittest.cc
index 3be7c0a..487a09f 100644
--- a/common_audio/resampler/push_sinc_resampler_unittest.cc
+++ b/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -36,14 +36,13 @@
 }  // namespace
 
 class PushSincResamplerTest : public ::testing::TestWithParam<
-    ::testing::tuple<int, int, double, double>> {
+                                  ::testing::tuple<int, int, double, double>> {
  public:
   PushSincResamplerTest()
       : input_rate_(::testing::get<0>(GetParam())),
         output_rate_(::testing::get<1>(GetParam())),
         rms_error_(::testing::get<2>(GetParam())),
-        low_freq_error_(::testing::get<3>(GetParam())) {
-  }
+        low_freq_error_(::testing::get<3>(GetParam())) {}
 
   ~PushSincResamplerTest() override {}
 
@@ -59,7 +58,7 @@
 
 class ZeroSource : public SincResamplerCallback {
  public:
-  void Run(size_t frames, float* destination) {
+  void Run(size_t frames, float* destination) override {
     std::memset(destination, 0, sizeof(float) * frames);
   }
 };
@@ -82,8 +81,8 @@
     source_int[i] = static_cast<int16_t>(floor(32767 * source[i] + 0.5));
   }
 
-  printf("Benchmarking %d iterations of %d Hz -> %d Hz:\n",
-         kResampleIterations, input_rate_, output_rate_);
+  printf("Benchmarking %d iterations of %d Hz -> %d Hz:\n", kResampleIterations,
+         input_rate_, output_rate_);
   const double io_ratio = input_rate_ / static_cast<double>(output_rate_);
   SincResampler sinc_resampler(io_ratio, SincResampler::kDefaultRequestSize,
                                &resampler_source);
@@ -101,25 +100,23 @@
   if (int_format) {
     for (int i = 0; i < kResampleIterations; ++i) {
       EXPECT_EQ(output_samples,
-                resampler.Resample(source_int.get(),
-                                   input_samples,
-                                   destination_int.get(),
-                                   output_samples));
+                resampler.Resample(source_int.get(), input_samples,
+                                   destination_int.get(), output_samples));
     }
   } else {
     for (int i = 0; i < kResampleIterations; ++i) {
-      EXPECT_EQ(output_samples,
-                resampler.Resample(source.get(),
-                                   input_samples,
-                                   resampled_destination.get(),
-                                   output_samples));
+      EXPECT_EQ(output_samples, resampler.Resample(source.get(), input_samples,
+                                                   resampled_destination.get(),
+                                                   output_samples));
     }
   }
   double total_time_us =
       (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec;
-  printf("PushSincResampler took %.2f us per frame; which is a %.1f%% overhead "
-         "on SincResampler.\n\n", total_time_us / kResampleIterations,
-         (total_time_us - total_time_sinc_us) / total_time_sinc_us * 100);
+  printf(
+      "PushSincResampler took %.2f us per frame; which is a %.1f%% overhead "
+      "on SincResampler.\n\n",
+      total_time_us / kResampleIterations,
+      (total_time_us - total_time_sinc_us) / total_time_sinc_us * 100);
 }
 
 // Disabled because it takes too long to run routinely. Use for performance
@@ -149,8 +146,8 @@
   const double input_nyquist_freq = 0.5 * input_rate_;
 
   // Source for data to be resampled.
-  SinusoidalLinearChirpSource resampler_source(
-      input_rate_, input_samples, input_nyquist_freq, 0);
+  SinusoidalLinearChirpSource resampler_source(input_rate_, input_samples,
+                                               input_nyquist_freq, 0);
 
   PushSincResampler resampler(input_block_size, output_block_size);
 
@@ -168,8 +165,8 @@
   // deal with it in the test by delaying the "pure" source to match. It must be
   // checked before the first call to Resample(), because ChunkSize() will
   // change afterwards.
-  const size_t output_delay_samples = output_block_size -
-      resampler.get_resampler_for_testing()->ChunkSize();
+  const size_t output_delay_samples =
+      output_block_size - resampler.get_resampler_for_testing()->ChunkSize();
 
   // Generate resampled signal.
   // With the PushSincResampler, we produce the signal block-by-10ms-block
@@ -178,21 +175,18 @@
   if (int_format) {
     for (size_t i = 0; i < kNumBlocks; ++i) {
       FloatToS16(&source[i * input_block_size], input_block_size,
-               source_int.get());
+                 source_int.get());
       EXPECT_EQ(output_block_size,
-                resampler.Resample(source_int.get(),
-                                   input_block_size,
-                                   destination_int.get(),
-                                   output_block_size));
+                resampler.Resample(source_int.get(), input_block_size,
+                                   destination_int.get(), output_block_size));
       S16ToFloat(destination_int.get(), output_block_size,
-               &resampled_destination[i * output_block_size]);
+                 &resampled_destination[i * output_block_size]);
     }
   } else {
     for (size_t i = 0; i < kNumBlocks; ++i) {
       EXPECT_EQ(
           output_block_size,
-          resampler.Resample(&source[i * input_block_size],
-                             input_block_size,
+          resampler.Resample(&source[i * input_block_size], input_block_size,
                              &resampled_destination[i * output_block_size],
                              output_block_size));
     }
@@ -252,9 +246,13 @@
   EXPECT_LE(high_freq_max_error, kHighFrequencyMaxError);
 }
 
-TEST_P(PushSincResamplerTest, ResampleInt) { ResampleTest(true); }
+TEST_P(PushSincResamplerTest, ResampleInt) {
+  ResampleTest(true);
+}
 
-TEST_P(PushSincResamplerTest, ResampleFloat) { ResampleTest(false); }
+TEST_P(PushSincResamplerTest, ResampleFloat) {
+  ResampleTest(false);
+}
 
 // Thresholds chosen arbitrarily based on what each resampling reported during
 // testing.  All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS.
diff --git a/common_audio/resampler/resampler.cc b/common_audio/resampler/resampler.cc
index ea85d82..aa3a4ba 100644
--- a/common_audio/resampler/resampler.cc
+++ b/common_audio/resampler/resampler.cc
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /*
  * A wrapper for resampling a numerous amount of sampling combinations.
  */
@@ -37,8 +36,7 @@
       my_mode_(kResamplerMode1To1),
       num_channels_(0),
       slave_left_(nullptr),
-      slave_right_(nullptr) {
-}
+      slave_right_(nullptr) {}
 
 Resampler::Resampler(int inFreq, int outFreq, size_t num_channels)
     : Resampler() {
@@ -73,9 +71,9 @@
   int tmpInFreq_kHz = inFreq / 1000;
   int tmpOutFreq_kHz = outFreq / 1000;
 
-  if ((tmpInFreq_kHz != my_in_frequency_khz_)
-      || (tmpOutFreq_kHz != my_out_frequency_khz_)
-      || (num_channels != num_channels_)) {
+  if ((tmpInFreq_kHz != my_in_frequency_khz_) ||
+      (tmpOutFreq_kHz != my_out_frequency_khz_) ||
+      (num_channels != num_channels_)) {
     return Reset(inFreq, outFreq, num_channels);
   } else {
     return 0;
@@ -191,7 +189,7 @@
       // 2:6
       state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
       WebRtcSpl_ResetResample16khzTo48khz(
-        static_cast<WebRtcSpl_State16khzTo48khz*>(state1_));
+          static_cast<WebRtcSpl_State16khzTo48khz*>(state1_));
       // 6:3
       state2_ = malloc(8 * sizeof(int32_t));
       memset(state2_, 0, 8 * sizeof(int32_t));
@@ -395,8 +393,11 @@
 }
 
 // Synchronous resampling, all output samples are written to samplesOut
-int Resampler::Push(const int16_t * samplesIn, size_t lengthIn,
-                    int16_t* samplesOut, size_t maxLen, size_t& outLen) {
+int Resampler::Push(const int16_t* samplesIn,
+                    size_t lengthIn,
+                    int16_t* samplesOut,
+                    size_t maxLen,
+                    size_t& outLen) {
   if (num_channels_ == 2) {
     // Split up the signal and call the slave object for each channel
     int16_t* left =
@@ -575,7 +576,7 @@
       if ((lengthIn % 160) != 0) {
         return -1;
       }
-      tmp = static_cast<int16_t*> (malloc(sizeof(int16_t) * lengthIn * 3));
+      tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 3));
       tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t)));
       for (size_t i = 0; i < lengthIn; i += 160) {
         WebRtcSpl_Resample16khzTo48khz(
@@ -827,7 +828,7 @@
         return -1;
       }
       // 3:6
-      tmp = static_cast<int16_t*> (malloc(sizeof(int16_t) * lengthIn * 2));
+      tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 2));
       WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp,
                             static_cast<int32_t*>(state1_));
       lengthIn *= 2;
@@ -858,8 +859,8 @@
         return -1;
       }
       tmp_mem = static_cast<int32_t*>(malloc(126 * sizeof(int32_t)));
-      tmp = static_cast<int16_t*>(
-          malloc((lengthIn * 4) / 11 * sizeof(int16_t)));
+      tmp =
+          static_cast<int16_t*>(malloc((lengthIn * 4) / 11 * sizeof(int16_t)));
 
       for (size_t i = 0; i < lengthIn; i += 220) {
         WebRtcSpl_Resample22khzTo8khz(
diff --git a/common_audio/resampler/resampler_unittest.cc b/common_audio/resampler/resampler_unittest.cc
index 0300719..fd636e2 100644
--- a/common_audio/resampler/resampler_unittest.cc
+++ b/common_audio/resampler/resampler_unittest.cc
@@ -23,17 +23,10 @@
 
 // Rates we must support.
 const int kMaxRate = 96000;
-const int kRates[] = {
-  8000,
-  16000,
-  32000,
-  44000,
-  48000,
-  kMaxRate
-};
+const int kRates[] = {8000, 16000, 32000, 44000, 48000, kMaxRate};
 const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates);
 const int kMaxChannels = 2;
-const size_t kDataSize = static_cast<size_t> (kMaxChannels * kMaxRate / 100);
+const size_t kDataSize = static_cast<size_t>(kMaxChannels * kMaxRate / 100);
 
 // TODO(andrew): should we be supporting these combinations?
 bool ValidRates(int in_rate, int out_rate) {
@@ -49,8 +42,8 @@
 class ResamplerTest : public testing::Test {
  protected:
   ResamplerTest();
-  virtual void SetUp();
-  virtual void TearDown();
+  void SetUp() override;
+  void TearDown() override;
 
   void ResetIfNeededAndPush(int in_rate, int out_rate, int num_channels);
 
@@ -99,7 +92,7 @@
       for (size_t k = 0; k < kNumChannelsSize; ++k) {
         std::ostringstream ss;
         ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j]
-            << ", channels: " << kNumChannels[k];
+           << ", channels: " << kNumChannels[k];
         SCOPED_TRACE(ss.str());
         if (ValidRates(kRates[i], kRates[j]))
           EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kNumChannels[k]));
@@ -124,8 +117,8 @@
         size_t in_length = static_cast<size_t>(kRates[i] / 100);
         size_t out_length = 0;
         EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels));
-        EXPECT_EQ(0, rs_.Push(data_in_, in_length, data_out_, kDataSize,
-                              out_length));
+        EXPECT_EQ(
+            0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length));
         EXPECT_EQ(static_cast<size_t>(kRates[j] / 100), out_length);
       } else {
         EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels));
@@ -145,14 +138,12 @@
       if (ValidRates(kRates[i], kRates[j])) {
         size_t in_length = static_cast<size_t>(kChannels * kRates[i] / 100);
         size_t out_length = 0;
-        EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j],
-                               kChannels));
-        EXPECT_EQ(0, rs_.Push(data_in_, in_length, data_out_, kDataSize,
-                              out_length));
+        EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels));
+        EXPECT_EQ(
+            0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length));
         EXPECT_EQ(static_cast<size_t>(kChannels * kRates[j] / 100), out_length);
       } else {
-        EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j],
-                                kChannels));
+        EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels));
       }
     }
   }
diff --git a/common_audio/resampler/sinc_resampler.cc b/common_audio/resampler/sinc_resampler.cc
index c857755..c3d1ea4 100644
--- a/common_audio/resampler/sinc_resampler.cc
+++ b/common_audio/resampler/sinc_resampler.cc
@@ -160,12 +160,12 @@
           AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
       input_buffer_(static_cast<float*>(
           AlignedMalloc(sizeof(float) * input_buffer_size_, 16))),
-#if defined(WEBRTC_CPU_DETECTION)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)
       convolve_proc_(nullptr),
 #endif
       r1_(input_buffer_.get()),
       r2_(input_buffer_.get() + kKernelSize / 2) {
-#if defined(WEBRTC_CPU_DETECTION)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)
   InitializeCPUSpecificFeatures();
   RTC_DCHECK(convolve_proc_);
 #endif
@@ -217,23 +217,23 @@
 
     for (size_t i = 0; i < kKernelSize; ++i) {
       const size_t idx = i + offset_idx * kKernelSize;
-      const float pre_sinc = static_cast<float>(M_PI *
-          (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) -
-           subsample_offset));
+      const float pre_sinc = static_cast<float>(
+          M_PI * (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) -
+                  subsample_offset));
       kernel_pre_sinc_storage_[idx] = pre_sinc;
 
       // Compute Blackman window, matching the offset of the sinc().
       const float x = (i - subsample_offset) / kKernelSize;
       const float window = static_cast<float>(kA0 - kA1 * cos(2.0 * M_PI * x) +
-          kA2 * cos(4.0 * M_PI * x));
+                                              kA2 * cos(4.0 * M_PI * x));
       kernel_window_storage_[idx] = window;
 
       // Compute the sinc with offset, then window the sinc() function and store
       // at the correct offset.
-      kernel_storage_[idx] = static_cast<float>(window *
-          ((pre_sinc == 0) ?
-              sinc_scale_factor :
-              (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
+      kernel_storage_[idx] = static_cast<float>(
+          window * ((pre_sinc == 0)
+                        ? sinc_scale_factor
+                        : (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
     }
   }
 }
@@ -255,10 +255,10 @@
       const float window = kernel_window_storage_[idx];
       const float pre_sinc = kernel_pre_sinc_storage_[idx];
 
-      kernel_storage_[idx] = static_cast<float>(window *
-          ((pre_sinc == 0) ?
-              sinc_scale_factor :
-              (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
+      kernel_storage_[idx] = static_cast<float>(
+          window * ((pre_sinc == 0)
+                        ? sinc_scale_factor
+                        : (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
     }
   }
 }
@@ -312,8 +312,8 @@
       // Figure out how much to weight each kernel's "convolution".
       const double kernel_interpolation_factor =
           virtual_offset_idx - offset_idx;
-      *destination++ = CONVOLVE_FUNC(
-          input_ptr, k1, k2, kernel_interpolation_factor);
+      *destination++ =
+          CONVOLVE_FUNC(input_ptr, k1, k2, kernel_interpolation_factor);
 
       // Advance the virtual index.
       virtual_source_idx_ += current_io_ratio;
@@ -352,7 +352,8 @@
   UpdateRegions(false);
 }
 
-float SincResampler::Convolve_C(const float* input_ptr, const float* k1,
+float SincResampler::Convolve_C(const float* input_ptr,
+                                const float* k1,
                                 const float* k2,
                                 double kernel_interpolation_factor) {
   float sum1 = 0;
@@ -368,7 +369,7 @@
 
   // Linearly interpolate the two "convolutions".
   return static_cast<float>((1.0 - kernel_interpolation_factor) * sum1 +
-      kernel_interpolation_factor * sum2);
+                            kernel_interpolation_factor * sum2);
 }
 
 }  // namespace webrtc
diff --git a/common_audio/resampler/sinc_resampler.h b/common_audio/resampler/sinc_resampler.h
index 774a9b7..6306bc9 100644
--- a/common_audio/resampler/sinc_resampler.h
+++ b/common_audio/resampler/sinc_resampler.h
@@ -101,14 +101,18 @@
   // Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are
   // linearly interpolated using |kernel_interpolation_factor|.  On x86 and ARM
   // the underlying implementation is chosen at run time.
-  static float Convolve_C(const float* input_ptr, const float* k1,
-                          const float* k2, double kernel_interpolation_factor);
+  static float Convolve_C(const float* input_ptr,
+                          const float* k1,
+                          const float* k2,
+                          double kernel_interpolation_factor);
 #if defined(WEBRTC_ARCH_X86_FAMILY)
-  static float Convolve_SSE(const float* input_ptr, const float* k1,
+  static float Convolve_SSE(const float* input_ptr,
+                            const float* k1,
                             const float* k2,
                             double kernel_interpolation_factor);
 #elif defined(WEBRTC_HAS_NEON)
-  static float Convolve_NEON(const float* input_ptr, const float* k1,
+  static float Convolve_NEON(const float* input_ptr,
+                             const float* k1,
                              const float* k2,
                              double kernel_interpolation_factor);
 #endif
@@ -145,12 +149,14 @@
   // Data from the source is copied into this buffer for each processing pass.
   std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_;
 
-  // Stores the runtime selection of which Convolve function to use.
-  // TODO(ajm): Move to using a global static which must only be initialized
-  // once by the user. We're not doing this initially, because we don't have
-  // e.g. a LazyInstance helper in webrtc.
-#if defined(WEBRTC_CPU_DETECTION)
-  typedef float (*ConvolveProc)(const float*, const float*, const float*,
+// Stores the runtime selection of which Convolve function to use.
+// TODO(ajm): Move to using a global static which must only be initialized
+// once by the user. We're not doing this initially, because we don't have
+// e.g. a LazyInstance helper in webrtc.
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)
+  typedef float (*ConvolveProc)(const float*,
+                                const float*,
+                                const float*,
                                 double);
   ConvolveProc convolve_proc_;
 #endif
diff --git a/common_audio/resampler/sinc_resampler_neon.cc b/common_audio/resampler/sinc_resampler_neon.cc
index 9d77f0d..3649324 100644
--- a/common_audio/resampler/sinc_resampler_neon.cc
+++ b/common_audio/resampler/sinc_resampler_neon.cc
@@ -17,7 +17,8 @@
 
 namespace webrtc {
 
-float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1,
+float SincResampler::Convolve_NEON(const float* input_ptr,
+                                   const float* k1,
                                    const float* k2,
                                    double kernel_interpolation_factor) {
   float32x4_t m_input;
@@ -25,7 +26,7 @@
   float32x4_t m_sums2 = vmovq_n_f32(0);
 
   const float* upper = input_ptr + kKernelSize;
-  for (; input_ptr < upper; ) {
+  for (; input_ptr < upper;) {
     m_input = vld1q_f32(input_ptr);
     input_ptr += 4;
     m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1));
diff --git a/common_audio/resampler/sinc_resampler_sse.cc b/common_audio/resampler/sinc_resampler_sse.cc
index 7111108..3906a79 100644
--- a/common_audio/resampler/sinc_resampler_sse.cc
+++ b/common_audio/resampler/sinc_resampler_sse.cc
@@ -17,7 +17,8 @@
 
 namespace webrtc {
 
-float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1,
+float SincResampler::Convolve_SSE(const float* input_ptr,
+                                  const float* k1,
                                   const float* k2,
                                   double kernel_interpolation_factor) {
   __m128 m_input;
@@ -41,17 +42,18 @@
   }
 
   // Linearly interpolate the two "convolutions".
-  m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1(
-      static_cast<float>(1.0 - kernel_interpolation_factor)));
-  m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1(
-      static_cast<float>(kernel_interpolation_factor)));
+  m_sums1 = _mm_mul_ps(
+      m_sums1,
+      _mm_set_ps1(static_cast<float>(1.0 - kernel_interpolation_factor)));
+  m_sums2 = _mm_mul_ps(
+      m_sums2, _mm_set_ps1(static_cast<float>(kernel_interpolation_factor)));
   m_sums1 = _mm_add_ps(m_sums1, m_sums2);
 
   // Sum components together.
   float result;
   m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1);
-  _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps(
-      m_sums2, m_sums2, 1)));
+  _mm_store_ss(&result,
+               _mm_add_ss(m_sums2, _mm_shuffle_ps(m_sums2, m_sums2, 1)));
 
   return result;
 }
diff --git a/common_audio/resampler/sinc_resampler_unittest.cc b/common_audio/resampler/sinc_resampler_unittest.cc
index 87e991d..90bdf31 100644
--- a/common_audio/resampler/sinc_resampler_unittest.cc
+++ b/common_audio/resampler/sinc_resampler_unittest.cc
@@ -67,14 +67,14 @@
   std::unique_ptr<float[]> resampled_destination(new float[max_chunk_size]);
 
   // Verify requesting ChunkSize() frames causes a single callback.
-  EXPECT_CALL(mock_source, Run(_, _))
-      .Times(1).WillOnce(ClearBuffer());
+  EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(ClearBuffer());
   resampler.Resample(resampler.ChunkSize(), resampled_destination.get());
 
   // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks.
   testing::Mock::VerifyAndClear(&mock_source);
   EXPECT_CALL(mock_source, Run(_, _))
-      .Times(kChunks).WillRepeatedly(ClearBuffer());
+      .Times(kChunks)
+      .WillRepeatedly(ClearBuffer());
   resampler.Resample(max_chunk_size, resampled_destination.get());
 }
 
@@ -87,16 +87,14 @@
       new float[resampler.ChunkSize()]);
 
   // Fill the resampler with junk data.
-  EXPECT_CALL(mock_source, Run(_, _))
-      .Times(1).WillOnce(FillBuffer());
+  EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(FillBuffer());
   resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get());
   ASSERT_NE(resampled_destination[0], 0);
 
   // Flush and request more data, which should all be zeros now.
   resampler.Flush();
   testing::Mock::VerifyAndClear(&mock_source);
-  EXPECT_CALL(mock_source, Run(_, _))
-      .Times(1).WillOnce(ClearBuffer());
+  EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(ClearBuffer());
   resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get());
   for (size_t i = 0; i < resampler.ChunkSize() / 2; ++i)
     ASSERT_FLOAT_EQ(resampled_destination[i], 0);
@@ -116,7 +114,6 @@
   printf("SetRatio() took %.2fms.\n", total_time_c_us / 1000);
 }
 
-
 // Define platform independent function name for Convolve* tests.
 #if defined(WEBRTC_ARCH_X86_FAMILY)
 #define CONVOLVE_FUNC Convolve_SSE
@@ -232,8 +229,7 @@
 #undef CONVOLVE_FUNC
 
 typedef std::tuple<int, int, double, double> SincResamplerTestData;
-class SincResamplerTest
-    : public testing::TestWithParam<SincResamplerTestData> {
+class SincResamplerTest : public testing::TestWithParam<SincResamplerTestData> {
  public:
   SincResamplerTest()
       : input_rate_(std::get<0>(GetParam())),
@@ -263,8 +259,8 @@
   const double input_nyquist_freq = 0.5 * input_rate_;
 
   // Source for data to be resampled.
-  SinusoidalLinearChirpSource resampler_source(
-      input_rate_, input_samples, input_nyquist_freq, 0);
+  SinusoidalLinearChirpSource resampler_source(input_rate_, input_samples,
+                                               input_nyquist_freq, 0);
 
   const double io_ratio = input_rate_ / static_cast<double>(output_rate_);
   SincResampler resampler(io_ratio, SincResampler::kDefaultRequestSize,
@@ -291,8 +287,8 @@
   resampler.Resample(output_samples, resampled_destination.get());
 
   // Generate pure signal.
-  SinusoidalLinearChirpSource pure_source(
-      output_rate_, output_samples, input_nyquist_freq, 0);
+  SinusoidalLinearChirpSource pure_source(output_rate_, output_samples,
+                                          input_nyquist_freq, 0);
   pure_source.Run(output_samples, pure_destination.get());
 
   // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which
@@ -324,8 +320,8 @@
 
   double rms_error = sqrt(sum_of_squares / output_samples);
 
-  // Convert each error to dbFS.
-  #define DBFS(x) 20 * log10(x)
+// Convert each error to dbFS.
+#define DBFS(x) 20 * log10(x)
   rms_error = DBFS(rms_error);
   low_freq_max_error = DBFS(low_freq_max_error);
   high_freq_max_error = DBFS(high_freq_max_error);
diff --git a/common_audio/resampler/sinusoidal_linear_chirp_source.cc b/common_audio/resampler/sinusoidal_linear_chirp_source.cc
index 134044e..2afdd1b 100644
--- a/common_audio/resampler/sinusoidal_linear_chirp_source.cc
+++ b/common_audio/resampler/sinusoidal_linear_chirp_source.cc
@@ -43,8 +43,7 @@
       } else {
         // Sinusoidal linear chirp.
         double t = (current_index_ - delay_samples_) / sample_rate_;
-        destination[i] =
-            sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t));
+        destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t));
       }
     }
   }
@@ -52,7 +51,7 @@
 
 double SinusoidalLinearChirpSource::Frequency(size_t position) {
   return kMinFrequency + (position - delay_samples_) *
-      (max_frequency_ - kMinFrequency) / total_samples_;
+                             (max_frequency_ - kMinFrequency) / total_samples_;
 }
 
 }  // namespace webrtc
diff --git a/common_audio/resampler/sinusoidal_linear_chirp_source.h b/common_audio/resampler/sinusoidal_linear_chirp_source.h
index 7fcbaa0..71dcff5 100644
--- a/common_audio/resampler/sinusoidal_linear_chirp_source.h
+++ b/common_audio/resampler/sinusoidal_linear_chirp_source.h
@@ -26,19 +26,19 @@
  public:
   // |delay_samples| can be used to insert a fractional sample delay into the
   // source.  It will produce zeros until non-negative time is reached.
-  SinusoidalLinearChirpSource(int sample_rate, size_t samples,
-                              double max_frequency, double delay_samples);
+  SinusoidalLinearChirpSource(int sample_rate,
+                              size_t samples,
+                              double max_frequency,
+                              double delay_samples);
 
-  virtual ~SinusoidalLinearChirpSource() {}
+  ~SinusoidalLinearChirpSource() override {}
 
   void Run(size_t frames, float* destination) override;
 
   double Frequency(size_t position);
 
  private:
-  enum {
-    kMinFrequency = 5
-  };
+  enum { kMinFrequency = 5 };
 
   int sample_rate_;
   size_t total_samples_;
diff --git a/common_audio/ring_buffer.h b/common_audio/ring_buffer.h
index aa2ac27..0bbe879 100644
--- a/common_audio/ring_buffer.h
+++ b/common_audio/ring_buffer.h
@@ -53,7 +53,8 @@
                          size_t element_count);
 
 // Writes |data| to buffer and returns the number of elements written.
-size_t WebRtc_WriteBuffer(RingBuffer* handle, const void* data,
+size_t WebRtc_WriteBuffer(RingBuffer* handle,
+                          const void* data,
                           size_t element_count);
 
 // Moves the buffer read position and returns the number of elements moved.
diff --git a/common_audio/ring_buffer_unittest.cc b/common_audio/ring_buffer_unittest.cc
index 4bb1497..130e124 100644
--- a/common_audio/ring_buffer_unittest.cc
+++ b/common_audio/ring_buffer_unittest.cc
@@ -21,9 +21,7 @@
 namespace webrtc {
 
 struct FreeBufferDeleter {
-  inline void operator()(void* ptr) const {
-    WebRtc_FreeBuffer(ptr);
-  }
+  inline void operator()(void* ptr) const { WebRtc_FreeBuffer(ptr); }
 };
 typedef std::unique_ptr<RingBuffer, FreeBufferDeleter> scoped_ring_buffer;
 
@@ -31,7 +29,8 @@
   ASSERT_EQ(expected, actual);
 }
 
-static int SetIncrementingData(int* data, int num_elements,
+static int SetIncrementingData(int* data,
+                               int num_elements,
                                int starting_value) {
   for (int i = 0; i < num_elements; i++) {
     data[i] = starting_value++;
@@ -39,7 +38,8 @@
   return starting_value;
 }
 
-static int CheckIncrementingData(int* data, int num_elements,
+static int CheckIncrementingData(int* data,
+                                 int num_elements,
                                  int starting_value) {
   for (int i = 0; i < num_elements; i++) {
     AssertElementEq(starting_value++, data[i]);
@@ -70,35 +70,33 @@
     int read_element = 0;
     for (int j = 0; j < kNumOps; j++) {
       const bool write = rand() % 2 == 0 ? true : false;  // NOLINT
-      const int num_elements = rand() % buffer_size;  // NOLINT
+      const int num_elements = rand() % buffer_size;      // NOLINT
       if (write) {
         const int buffer_available = buffer_size - buffer_consumed;
         ASSERT_EQ(static_cast<size_t>(buffer_available),
                   WebRtc_available_write(buffer.get()));
         const int expected_elements = std::min(num_elements, buffer_available);
         write_element = SetIncrementingData(write_data.get(), expected_elements,
-                                     write_element);
-        ASSERT_EQ(static_cast<size_t>(expected_elements),
-                  WebRtc_WriteBuffer(buffer.get(), write_data.get(),
-                                     num_elements));
-        buffer_consumed = std::min(buffer_consumed + expected_elements,
-                                   buffer_size);
+                                            write_element);
+        ASSERT_EQ(
+            static_cast<size_t>(expected_elements),
+            WebRtc_WriteBuffer(buffer.get(), write_data.get(), num_elements));
+        buffer_consumed =
+            std::min(buffer_consumed + expected_elements, buffer_size);
       } else {
-        const int expected_elements = std::min(num_elements,
-                                               buffer_consumed);
+        const int expected_elements = std::min(num_elements, buffer_consumed);
         ASSERT_EQ(static_cast<size_t>(buffer_consumed),
                   WebRtc_available_read(buffer.get()));
-        ASSERT_EQ(static_cast<size_t>(expected_elements),
-                  WebRtc_ReadBuffer(buffer.get(),
-                                    reinterpret_cast<void**>(data_ptr),
-                                    read_data.get(),
-                                    num_elements));
+        ASSERT_EQ(
+            static_cast<size_t>(expected_elements),
+            WebRtc_ReadBuffer(buffer.get(), reinterpret_cast<void**>(data_ptr),
+                              read_data.get(), num_elements));
         int* check_ptr = read_data.get();
         if (data_ptr) {
           check_ptr = *data_ptr;
         }
-        read_element = CheckIncrementingData(check_ptr, expected_elements,
-                                             read_element);
+        read_element =
+            CheckIncrementingData(check_ptr, expected_elements, read_element);
         buffer_consumed = std::max(buffer_consumed - expected_elements, 0);
       }
     }
@@ -127,8 +125,9 @@
   SetIncrementingData(write_data, kDataSize, 0);
   EXPECT_EQ(kDataSize, WebRtc_WriteBuffer(buffer.get(), write_data, kDataSize));
   SetIncrementingData(read_data, kDataSize, kDataSize);
-  EXPECT_EQ(kDataSize, WebRtc_ReadBuffer(buffer.get(),
-      reinterpret_cast<void**>(&data_ptr), read_data, kDataSize));
+  EXPECT_EQ(kDataSize,
+            WebRtc_ReadBuffer(buffer.get(), reinterpret_cast<void**>(&data_ptr),
+                              read_data, kDataSize));
   // Copying was not necessary, so |read_data| has not been updated.
   CheckIncrementingData(data_ptr, kDataSize, 0);
   CheckIncrementingData(read_data, kDataSize, kDataSize);
diff --git a/common_audio/signal_processing/complex_fft.c b/common_audio/signal_processing/complex_fft.c
index 36689b3..e2ac206 100644
--- a/common_audio/signal_processing/complex_fft.c
+++ b/common_audio/signal_processing/complex_fft.c
@@ -166,7 +166,7 @@
     /* The 1024-value is a constant given from the size of kSinTable1024[],
      * and should not be changed depending on the input parameter 'stages'
      */
-    n = 1 << stages;
+    n = ((size_t)1) << stages;
     if (n > 1024)
         return -1;
 
diff --git a/common_audio/signal_processing/complex_fft_tables.h b/common_audio/signal_processing/complex_fft_tables.h
index 6c3fcfd..5171040 100644
--- a/common_audio/signal_processing/complex_fft_tables.h
+++ b/common_audio/signal_processing/complex_fft_tables.h
@@ -8,141 +8,125 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
 #define COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
 
 #include "typedefs.h"  // NOLINT(build/include)
 
 static const int16_t kSinTable1024[] = {
-       0,    201,    402,    603,    804,   1005,   1206,   1406,
-    1607,   1808,   2009,   2209,   2410,   2610,   2811,   3011,
-    3211,   3411,   3611,   3811,   4011,   4210,   4409,   4608,
-    4807,   5006,   5205,   5403,   5601,   5799,   5997,   6195,
-    6392,   6589,   6786,   6982,   7179,   7375,   7571,   7766,
-    7961,   8156,   8351,   8545,   8739,   8932,   9126,   9319,
-    9511,   9703,   9895,  10087,  10278,  10469,  10659,  10849,
-   11038,  11227,  11416,  11604,  11792,  11980,  12166,  12353,
-   12539,  12724,  12909,  13094,  13278,  13462,  13645,  13827,
-   14009,  14191,  14372,  14552,  14732,  14911,  15090,  15268,
-   15446,  15623,  15799,  15975,  16150,  16325,  16499,  16672,
-   16845,  17017,  17189,  17360,  17530,  17699,  17868,  18036,
-   18204,  18371,  18537,  18702,  18867,  19031,  19194,  19357,
-   19519,  19680,  19840,  20000,  20159,  20317,  20474,  20631,
-   20787,  20942,  21096,  21249,  21402,  21554,  21705,  21855,
-   22004,  22153,  22301,  22448,  22594,  22739,  22883,  23027,
-   23169,  23311,  23452,  23592,  23731,  23869,  24006,  24143,
-   24278,  24413,  24546,  24679,  24811,  24942,  25072,  25201,
-   25329,  25456,  25582,  25707,  25831,  25954,  26077,  26198,
-   26318,  26437,  26556,  26673,  26789,  26905,  27019,  27132,
-   27244,  27355,  27466,  27575,  27683,  27790,  27896,  28001,
-   28105,  28208,  28309,  28410,  28510,  28608,  28706,  28802,
-   28897,  28992,  29085,  29177,  29268,  29358,  29446,  29534,
-   29621,  29706,  29790,  29873,  29955,  30036,  30116,  30195,
-   30272,  30349,  30424,  30498,  30571,  30643,  30713,  30783,
-   30851,  30918,  30984,  31049,  31113,  31175,  31236,  31297,
-   31356,  31413,  31470,  31525,  31580,  31633,  31684,  31735,
-   31785,  31833,  31880,  31926,  31970,  32014,  32056,  32097,
-   32137,  32176,  32213,  32249,  32284,  32318,  32350,  32382,
-   32412,  32441,  32468,  32495,  32520,  32544,  32567,  32588,
-   32609,  32628,  32646,  32662,  32678,  32692,  32705,  32717,
-   32727,  32736,  32744,  32751,  32757,  32761,  32764,  32766,
-   32767,  32766,  32764,  32761,  32757,  32751,  32744,  32736,
-   32727,  32717,  32705,  32692,  32678,  32662,  32646,  32628,
-   32609,  32588,  32567,  32544,  32520,  32495,  32468,  32441,
-   32412,  32382,  32350,  32318,  32284,  32249,  32213,  32176,
-   32137,  32097,  32056,  32014,  31970,  31926,  31880,  31833,
-   31785,  31735,  31684,  31633,  31580,  31525,  31470,  31413,
-   31356,  31297,  31236,  31175,  31113,  31049,  30984,  30918,
-   30851,  30783,  30713,  30643,  30571,  30498,  30424,  30349,
-   30272,  30195,  30116,  30036,  29955,  29873,  29790,  29706,
-   29621,  29534,  29446,  29358,  29268,  29177,  29085,  28992,
-   28897,  28802,  28706,  28608,  28510,  28410,  28309,  28208,
-   28105,  28001,  27896,  27790,  27683,  27575,  27466,  27355,
-   27244,  27132,  27019,  26905,  26789,  26673,  26556,  26437,
-   26318,  26198,  26077,  25954,  25831,  25707,  25582,  25456,
-   25329,  25201,  25072,  24942,  24811,  24679,  24546,  24413,
-   24278,  24143,  24006,  23869,  23731,  23592,  23452,  23311,
-   23169,  23027,  22883,  22739,  22594,  22448,  22301,  22153,
-   22004,  21855,  21705,  21554,  21402,  21249,  21096,  20942,
-   20787,  20631,  20474,  20317,  20159,  20000,  19840,  19680,
-   19519,  19357,  19194,  19031,  18867,  18702,  18537,  18371,
-   18204,  18036,  17868,  17699,  17530,  17360,  17189,  17017,
-   16845,  16672,  16499,  16325,  16150,  15975,  15799,  15623,
-   15446,  15268,  15090,  14911,  14732,  14552,  14372,  14191,
-   14009,  13827,  13645,  13462,  13278,  13094,  12909,  12724,
-   12539,  12353,  12166,  11980,  11792,  11604,  11416,  11227,
-   11038,  10849,  10659,  10469,  10278,  10087,   9895,   9703,
-    9511,   9319,   9126,   8932,   8739,   8545,   8351,   8156,
-    7961,   7766,   7571,   7375,   7179,   6982,   6786,   6589,
-    6392,   6195,   5997,   5799,   5601,   5403,   5205,   5006,
-    4807,   4608,   4409,   4210,   4011,   3811,   3611,   3411,
-    3211,   3011,   2811,   2610,   2410,   2209,   2009,   1808,
-    1607,   1406,   1206,   1005,    804,    603,    402,    201,
-       0,   -201,   -402,   -603,   -804,  -1005,  -1206,  -1406,
-   -1607,  -1808,  -2009,  -2209,  -2410,  -2610,  -2811,  -3011,
-   -3211,  -3411,  -3611,  -3811,  -4011,  -4210,  -4409,  -4608,
-   -4807,  -5006,  -5205,  -5403,  -5601,  -5799,  -5997,  -6195,
-   -6392,  -6589,  -6786,  -6982,  -7179,  -7375,  -7571,  -7766,
-   -7961,  -8156,  -8351,  -8545,  -8739,  -8932,  -9126,  -9319,
-   -9511,  -9703,  -9895, -10087, -10278, -10469, -10659, -10849,
-  -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
-  -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
-  -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
-  -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
-  -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
-  -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
-  -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
-  -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
-  -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
-  -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
-  -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
-  -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
-  -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
-  -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
-  -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
-  -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
-  -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
-  -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
-  -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
-  -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
-  -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
-  -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
-  -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
-  -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
-  -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
-  -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
-  -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
-  -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
-  -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
-  -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
-  -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
-  -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
-  -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
-  -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
-  -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
-  -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
-  -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
-  -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
-  -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
-  -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
-  -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
-  -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
-  -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
-  -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
-  -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
-  -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
-  -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
-  -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
-  -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
-  -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
-  -11038, -10849, -10659, -10469, -10278, -10087,  -9895,  -9703,
-   -9511,  -9319,  -9126,  -8932,  -8739,  -8545,  -8351,  -8156,
-   -7961,  -7766,  -7571,  -7375,  -7179,  -6982,  -6786,  -6589,
-   -6392,  -6195,  -5997,  -5799,  -5601,  -5403,  -5205,  -5006,
-   -4807,  -4608,  -4409,  -4210,  -4011,  -3811,  -3611,  -3411,
-   -3211,  -3011,  -2811,  -2610,  -2410,  -2209,  -2009,  -1808,
-   -1607,  -1406,  -1206,  -1005,   -804,   -603,   -402,   -201
-};
+    0,      201,    402,    603,    804,    1005,   1206,   1406,   1607,
+    1808,   2009,   2209,   2410,   2610,   2811,   3011,   3211,   3411,
+    3611,   3811,   4011,   4210,   4409,   4608,   4807,   5006,   5205,
+    5403,   5601,   5799,   5997,   6195,   6392,   6589,   6786,   6982,
+    7179,   7375,   7571,   7766,   7961,   8156,   8351,   8545,   8739,
+    8932,   9126,   9319,   9511,   9703,   9895,   10087,  10278,  10469,
+    10659,  10849,  11038,  11227,  11416,  11604,  11792,  11980,  12166,
+    12353,  12539,  12724,  12909,  13094,  13278,  13462,  13645,  13827,
+    14009,  14191,  14372,  14552,  14732,  14911,  15090,  15268,  15446,
+    15623,  15799,  15975,  16150,  16325,  16499,  16672,  16845,  17017,
+    17189,  17360,  17530,  17699,  17868,  18036,  18204,  18371,  18537,
+    18702,  18867,  19031,  19194,  19357,  19519,  19680,  19840,  20000,
+    20159,  20317,  20474,  20631,  20787,  20942,  21096,  21249,  21402,
+    21554,  21705,  21855,  22004,  22153,  22301,  22448,  22594,  22739,
+    22883,  23027,  23169,  23311,  23452,  23592,  23731,  23869,  24006,
+    24143,  24278,  24413,  24546,  24679,  24811,  24942,  25072,  25201,
+    25329,  25456,  25582,  25707,  25831,  25954,  26077,  26198,  26318,
+    26437,  26556,  26673,  26789,  26905,  27019,  27132,  27244,  27355,
+    27466,  27575,  27683,  27790,  27896,  28001,  28105,  28208,  28309,
+    28410,  28510,  28608,  28706,  28802,  28897,  28992,  29085,  29177,
+    29268,  29358,  29446,  29534,  29621,  29706,  29790,  29873,  29955,
+    30036,  30116,  30195,  30272,  30349,  30424,  30498,  30571,  30643,
+    30713,  30783,  30851,  30918,  30984,  31049,  31113,  31175,  31236,
+    31297,  31356,  31413,  31470,  31525,  31580,  31633,  31684,  31735,
+    31785,  31833,  31880,  31926,  31970,  32014,  32056,  32097,  32137,
+    32176,  32213,  32249,  32284,  32318,  32350,  32382,  32412,  32441,
+    32468,  32495,  32520,  32544,  32567,  32588,  32609,  32628,  32646,
+    32662,  32678,  32692,  32705,  32717,  32727,  32736,  32744,  32751,
+    32757,  32761,  32764,  32766,  32767,  32766,  32764,  32761,  32757,
+    32751,  32744,  32736,  32727,  32717,  32705,  32692,  32678,  32662,
+    32646,  32628,  32609,  32588,  32567,  32544,  32520,  32495,  32468,
+    32441,  32412,  32382,  32350,  32318,  32284,  32249,  32213,  32176,
+    32137,  32097,  32056,  32014,  31970,  31926,  31880,  31833,  31785,
+    31735,  31684,  31633,  31580,  31525,  31470,  31413,  31356,  31297,
+    31236,  31175,  31113,  31049,  30984,  30918,  30851,  30783,  30713,
+    30643,  30571,  30498,  30424,  30349,  30272,  30195,  30116,  30036,
+    29955,  29873,  29790,  29706,  29621,  29534,  29446,  29358,  29268,
+    29177,  29085,  28992,  28897,  28802,  28706,  28608,  28510,  28410,
+    28309,  28208,  28105,  28001,  27896,  27790,  27683,  27575,  27466,
+    27355,  27244,  27132,  27019,  26905,  26789,  26673,  26556,  26437,
+    26318,  26198,  26077,  25954,  25831,  25707,  25582,  25456,  25329,
+    25201,  25072,  24942,  24811,  24679,  24546,  24413,  24278,  24143,
+    24006,  23869,  23731,  23592,  23452,  23311,  23169,  23027,  22883,
+    22739,  22594,  22448,  22301,  22153,  22004,  21855,  21705,  21554,
+    21402,  21249,  21096,  20942,  20787,  20631,  20474,  20317,  20159,
+    20000,  19840,  19680,  19519,  19357,  19194,  19031,  18867,  18702,
+    18537,  18371,  18204,  18036,  17868,  17699,  17530,  17360,  17189,
+    17017,  16845,  16672,  16499,  16325,  16150,  15975,  15799,  15623,
+    15446,  15268,  15090,  14911,  14732,  14552,  14372,  14191,  14009,
+    13827,  13645,  13462,  13278,  13094,  12909,  12724,  12539,  12353,
+    12166,  11980,  11792,  11604,  11416,  11227,  11038,  10849,  10659,
+    10469,  10278,  10087,  9895,   9703,   9511,   9319,   9126,   8932,
+    8739,   8545,   8351,   8156,   7961,   7766,   7571,   7375,   7179,
+    6982,   6786,   6589,   6392,   6195,   5997,   5799,   5601,   5403,
+    5205,   5006,   4807,   4608,   4409,   4210,   4011,   3811,   3611,
+    3411,   3211,   3011,   2811,   2610,   2410,   2209,   2009,   1808,
+    1607,   1406,   1206,   1005,   804,    603,    402,    201,    0,
+    -201,   -402,   -603,   -804,   -1005,  -1206,  -1406,  -1607,  -1808,
+    -2009,  -2209,  -2410,  -2610,  -2811,  -3011,  -3211,  -3411,  -3611,
+    -3811,  -4011,  -4210,  -4409,  -4608,  -4807,  -5006,  -5205,  -5403,
+    -5601,  -5799,  -5997,  -6195,  -6392,  -6589,  -6786,  -6982,  -7179,
+    -7375,  -7571,  -7766,  -7961,  -8156,  -8351,  -8545,  -8739,  -8932,
+    -9126,  -9319,  -9511,  -9703,  -9895,  -10087, -10278, -10469, -10659,
+    -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
+    -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009,
+    -14191, -14372, -14552, -14732, -14911, -15090, -15268, -15446, -15623,
+    -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189,
+    -17360, -17530, -17699, -17868, -18036, -18204, -18371, -18537, -18702,
+    -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159,
+    -20317, -20474, -20631, -20787, -20942, -21096, -21249, -21402, -21554,
+    -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883,
+    -23027, -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
+    -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, -25329,
+    -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437,
+    -26556, -26673, -26789, -26905, -27019, -27132, -27244, -27355, -27466,
+    -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410,
+    -28510, -28608, -28706, -28802, -28897, -28992, -29085, -29177, -29268,
+    -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036,
+    -30116, -30195, -30272, -30349, -30424, -30498, -30571, -30643, -30713,
+    -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
+    -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785,
+    -31833, -31880, -31926, -31970, -32014, -32056, -32097, -32137, -32176,
+    -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468,
+    -32495, -32520, -32544, -32567, -32588, -32609, -32628, -32646, -32662,
+    -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757,
+    -32761, -32764, -32766, -32767, -32766, -32764, -32761, -32757, -32751,
+    -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646,
+    -32628, -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
+    -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, -32137,
+    -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735,
+    -31684, -31633, -31580, -31525, -31470, -31413, -31356, -31297, -31236,
+    -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643,
+    -30571, -30498, -30424, -30349, -30272, -30195, -30116, -30036, -29955,
+    -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177,
+    -29085, -28992, -28897, -28802, -28706, -28608, -28510, -28410, -28309,
+    -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
+    -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318,
+    -26198, -26077, -25954, -25831, -25707, -25582, -25456, -25329, -25201,
+    -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006,
+    -23869, -23731, -23592, -23452, -23311, -23169, -23027, -22883, -22739,
+    -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402,
+    -21249, -21096, -20942, -20787, -20631, -20474, -20317, -20159, -20000,
+    -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537,
+    -18371, -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
+    -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, -15446,
+    -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827,
+    -13645, -13462, -13278, -13094, -12909, -12724, -12539, -12353, -12166,
+    -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469,
+    -10278, -10087, -9895,  -9703,  -9511,  -9319,  -9126,  -8932,  -8739,
+    -8545,  -8351,  -8156,  -7961,  -7766,  -7571,  -7375,  -7179,  -6982,
+    -6786,  -6589,  -6392,  -6195,  -5997,  -5799,  -5601,  -5403,  -5205,
+    -5006,  -4807,  -4608,  -4409,  -4210,  -4011,  -3811,  -3611,  -3411,
+    -3211,  -3011,  -2811,  -2610,  -2410,  -2209,  -2009,  -1808,  -1607,
+    -1406,  -1206,  -1005,  -804,   -603,   -402,   -201};
 
 #endif  // COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
diff --git a/common_audio/signal_processing/include/real_fft.h b/common_audio/signal_processing/include/real_fft.h
index 7d21072..8da243d 100644
--- a/common_audio/signal_processing/include/real_fft.h
+++ b/common_audio/signal_processing/include/real_fft.h
@@ -14,9 +14,8 @@
 #include "typedefs.h"  // NOLINT(build/include)
 
 // For ComplexFFT(), the maximum fft order is 10;
-// for OpenMax FFT in ARM, it is 12;
 // WebRTC APM uses orders of only 7 and 8.
-enum {kMaxFFTOrder = 10};
+enum { kMaxFFTOrder = 10 };
 
 struct RealFFT;
 
diff --git a/common_audio/signal_processing/include/signal_processing_library.h b/common_audio/signal_processing/include/signal_processing_library.h
index 27fea6f..4d6edbf 100644
--- a/common_audio/signal_processing/include/signal_processing_library.h
+++ b/common_audio/signal_processing/include/signal_processing_library.h
@@ -8,11 +8,10 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /*
- * This header file includes all of the fix point signal processing library (SPL) function
- * descriptions and declarations.
- * For specific function calls, see bottom of file.
+ * This header file includes all of the fix point signal processing library
+ * (SPL) function descriptions and declarations. For specific function calls,
+ * see bottom of file.
  */
 
 #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_
@@ -23,63 +22,58 @@
 #include "typedefs.h"  // NOLINT(build/include)
 
 // Macros specific for the fixed point implementation
-#define WEBRTC_SPL_WORD16_MAX       32767
-#define WEBRTC_SPL_WORD16_MIN       -32768
-#define WEBRTC_SPL_WORD32_MAX       (int32_t)0x7fffffff
-#define WEBRTC_SPL_WORD32_MIN       (int32_t)0x80000000
-#define WEBRTC_SPL_MAX_LPC_ORDER    14
-#define WEBRTC_SPL_MIN(A, B)        (A < B ? A : B)  // Get min value
-#define WEBRTC_SPL_MAX(A, B)        (A > B ? A : B)  // Get max value
+#define WEBRTC_SPL_WORD16_MAX 32767
+#define WEBRTC_SPL_WORD16_MIN -32768
+#define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff
+#define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000
+#define WEBRTC_SPL_MAX_LPC_ORDER 14
+#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B)  // Get min value
+#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B)  // Get max value
 // TODO(kma/bjorn): For the next two macros, investigate how to correct the code
 // for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN.
-#define WEBRTC_SPL_ABS_W16(a) \
-    (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a))
-#define WEBRTC_SPL_ABS_W32(a) \
-    (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a))
+#define WEBRTC_SPL_ABS_W16(a) (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a))
+#define WEBRTC_SPL_ABS_W32(a) (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a))
 
-#define WEBRTC_SPL_MUL(a, b) \
-    ((int32_t) ((int32_t)(a) * (int32_t)(b)))
-#define WEBRTC_SPL_UMUL(a, b) \
-    ((uint32_t) ((uint32_t)(a) * (uint32_t)(b)))
-#define WEBRTC_SPL_UMUL_32_16(a, b) \
-    ((uint32_t) ((uint32_t)(a) * (uint16_t)(b)))
-#define WEBRTC_SPL_MUL_16_U16(a, b) \
-    ((int32_t)(int16_t)(a) * (uint16_t)(b))
+#define WEBRTC_SPL_MUL(a, b) ((int32_t)((int32_t)(a) * (int32_t)(b)))
+#define WEBRTC_SPL_UMUL(a, b) ((uint32_t)((uint32_t)(a) * (uint32_t)(b)))
+#define WEBRTC_SPL_UMUL_32_16(a, b) ((uint32_t)((uint32_t)(a) * (uint16_t)(b)))
+#define WEBRTC_SPL_MUL_16_U16(a, b) ((int32_t)(int16_t)(a) * (uint16_t)(b))
 
+// clang-format off
+// clang-format would choose some identation
+// leading to presubmit error (cpplint.py)
 #ifndef WEBRTC_ARCH_ARM_V7
 // For ARMv7 platforms, these are inline functions in spl_inl_armv7.h
 #ifndef MIPS32_LE
 // For MIPS platforms, these are inline functions in spl_inl_mips.h
-#define WEBRTC_SPL_MUL_16_16(a, b) \
-    ((int32_t) (((int16_t)(a)) * ((int16_t)(b))))
+#define WEBRTC_SPL_MUL_16_16(a, b) ((int32_t)(((int16_t)(a)) * ((int16_t)(b))))
 #define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \
-    (WEBRTC_SPL_MUL_16_16(a, b >> 16) \
-     + ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15))
+        (WEBRTC_SPL_MUL_16_16(a, b >> 16) +     \
+        ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15))
 #endif
 #endif
 
 #define WEBRTC_SPL_MUL_16_32_RSFT11(a, b)          \
-  (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \
-    (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10))
+        (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \
+        (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10))
 #define WEBRTC_SPL_MUL_16_32_RSFT14(a, b)          \
-  (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \
-    (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13))
+        (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \
+        (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13))
 #define WEBRTC_SPL_MUL_16_32_RSFT15(a, b)            \
-  ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \
-    (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14))
+        ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \
+        (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14))
+// clang-format on
 
-#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) \
-    (WEBRTC_SPL_MUL_16_16(a, b) >> (c))
+#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) (WEBRTC_SPL_MUL_16_16(a, b) >> (c))
 
 #define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \
-    ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t) \
-                                  (((int32_t)1) << ((c) - 1)))) >> (c))
+  ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t)(((int32_t)1) << ((c)-1)))) >> (c))
 
 // C + the 32 most significant bits of A * B
 #define WEBRTC_SPL_SCALEDIFF32(A, B, C) \
-    (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16))
+  (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16))
 
-#define WEBRTC_SPL_SAT(a, b, c)         (b > a ? a : b < c ? c : b)
+#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b)
 
 // Shifting with negative numbers allowed
 // Positive means left shift
@@ -87,12 +81,11 @@
 
 // Shifting with negative numbers not allowed
 // We cannot do casting here due to signed/unsigned problem
-#define WEBRTC_SPL_LSHIFT_W32(x, c)     ((x) << (c))
+#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c))
 
-#define WEBRTC_SPL_RSHIFT_U32(x, c)     ((uint32_t)(x) >> (c))
+#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c))
 
-#define WEBRTC_SPL_RAND(a) \
-    ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff))
+#define WEBRTC_SPL_RAND(a) ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff))
 
 #ifdef __cplusplus
 extern "C" {
@@ -131,13 +124,10 @@
                               size_t in_vector_length,
                               size_t samples,
                               int16_t* out_vector);
-void WebRtcSpl_ZerosArrayW16(int16_t* vector,
-                             size_t vector_length);
-void WebRtcSpl_ZerosArrayW32(int32_t* vector,
-                             size_t vector_length);
+void WebRtcSpl_ZerosArrayW16(int16_t* vector, size_t vector_length);
+void WebRtcSpl_ZerosArrayW32(int32_t* vector, size_t vector_length);
 // End: Copy and set operations.
 
-
 // Minimum and maximum operation functions and their pointers.
 // Implementation in min_max_operations.c.
 
@@ -297,7 +287,6 @@
 
 // End: Minimum and maximum operations.
 
-
 // Vector scaling operations. Implementation in vector_scaling_operations.c.
 // Description at bottom of file.
 void WebRtcSpl_VectorBitShiftW16(int16_t* out_vector,
@@ -323,9 +312,11 @@
                                   size_t vector_length,
                                   int16_t right_shifts);
 void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1,
-                                  int16_t gain1, int right_shifts1,
+                                  int16_t gain1,
+                                  int right_shifts1,
                                   const int16_t* in_vector2,
-                                  int16_t gain2, int right_shifts2,
+                                  int16_t gain2,
+                                  int right_shifts2,
                                   int16_t* out_vector,
                                   size_t vector_length);
 
@@ -777,7 +768,8 @@
   int32_t S_16_8[8];
 } WebRtcSpl_State22khzTo8khz;
 
-void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample22khzTo8khz(const int16_t* in,
+                                   int16_t* out,
                                    WebRtcSpl_State22khzTo8khz* state,
                                    int32_t* tmpmem);
 
@@ -790,7 +782,8 @@
   int32_t S_11_22[8];
 } WebRtcSpl_State8khzTo22khz;
 
-void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample8khzTo22khz(const int16_t* in,
+                                   int16_t* out,
                                    WebRtcSpl_State8khzTo22khz* state,
                                    int32_t* tmpmem);
 
@@ -830,7 +823,8 @@
   int32_t S_32_16[8];
 } WebRtcSpl_State48khzTo16khz;
 
-void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample48khzTo16khz(const int16_t* in,
+                                    int16_t* out,
                                     WebRtcSpl_State48khzTo16khz* state,
                                     int32_t* tmpmem);
 
@@ -842,7 +836,8 @@
   int32_t S_24_48[8];
 } WebRtcSpl_State16khzTo48khz;
 
-void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample16khzTo48khz(const int16_t* in,
+                                    int16_t* out,
                                     WebRtcSpl_State16khzTo48khz* state,
                                     int32_t* tmpmem);
 
@@ -855,7 +850,8 @@
   int32_t S_16_8[8];
 } WebRtcSpl_State48khzTo8khz;
 
-void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample48khzTo8khz(const int16_t* in,
+                                   int16_t* out,
                                    WebRtcSpl_State48khzTo8khz* state,
                                    int32_t* tmpmem);
 
@@ -868,7 +864,8 @@
   int32_t S_24_48[8];
 } WebRtcSpl_State8khzTo48khz;
 
-void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample8khzTo48khz(const int16_t* in,
+                                   int16_t* out,
                                    WebRtcSpl_State8khzTo48khz* state,
                                    int32_t* tmpmem);
 
@@ -881,11 +878,15 @@
  *
  ******************************************************************/
 
-void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len,
-                             int16_t* out, int32_t* filtState);
+void WebRtcSpl_DownsampleBy2(const int16_t* in,
+                             size_t len,
+                             int16_t* out,
+                             int32_t* filtState);
 
-void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len,
-                           int16_t* out, int32_t* filtState);
+void WebRtcSpl_UpsampleBy2(const int16_t* in,
+                           size_t len,
+                           int16_t* out,
+                           int32_t* filtState);
 
 /************************************************************
  * END OF RESAMPLING FUNCTIONS
diff --git a/common_audio/signal_processing/include/spl_inl.h b/common_audio/signal_processing/include/spl_inl.h
index ba3a113..656a312 100644
--- a/common_audio/signal_processing/include/spl_inl.h
+++ b/common_audio/signal_processing/include/spl_inl.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 // This header file includes the inline functions in
 // the fix point signal processing library.
 
@@ -73,7 +72,7 @@
 
 #if !defined(MIPS_DSP_R1_LE)
 static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
-  int16_t out16 = (int16_t) value32;
+  int16_t out16 = (int16_t)value32;
 
   if (value32 > 32767)
     out16 = 32767;
@@ -112,11 +111,11 @@
 }
 
 static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
-  return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b);
+  return WebRtcSpl_SatW32ToW16((int32_t)a + (int32_t)b);
 }
 
 static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
-  return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2);
+  return WebRtcSpl_SatW32ToW16((int32_t)var1 - (int32_t)var2);
 }
 #endif  // #if !defined(MIPS_DSP_R1_LE)
 
diff --git a/common_audio/signal_processing/include/spl_inl_armv7.h b/common_audio/signal_processing/include/spl_inl_armv7.h
index 97179f9..930e91e 100644
--- a/common_audio/signal_processing/include/spl_inl_armv7.h
+++ b/common_audio/signal_processing/include/spl_inl_armv7.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /* This header file includes the inline functions for ARM processors in
  * the fix point signal processing library.
  */
@@ -26,35 +25,37 @@
  */
 static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) {
   int32_t tmp = 0;
-  __asm __volatile ("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a));
+  __asm __volatile("smulwb %0, %1, %2" : "=r"(tmp) : "r"(b), "r"(a));
   return tmp;
 }
 
 static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) {
   int32_t tmp = 0;
-  __asm __volatile ("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
+  __asm __volatile("smulbb %0, %1, %2" : "=r"(tmp) : "r"(a), "r"(b));
   return tmp;
 }
 
 // TODO(kma): add unit test.
 static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
   int32_t tmp = 0;
-  __asm __volatile ("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c));
+  __asm __volatile("smlabb %0, %1, %2, %3"
+                   : "=r"(tmp)
+                   : "r"(a), "r"(b), "r"(c));
   return tmp;
 }
 
 static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
   int32_t s_sum = 0;
 
-  __asm __volatile ("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b));
+  __asm __volatile("qadd16 %0, %1, %2" : "=r"(s_sum) : "r"(a), "r"(b));
 
-  return (int16_t) s_sum;
+  return (int16_t)s_sum;
 }
 
 static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
   int32_t l_sum = 0;
 
-  __asm __volatile ("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2));
+  __asm __volatile("qadd %0, %1, %2" : "=r"(l_sum) : "r"(l_var1), "r"(l_var2));
 
   return l_sum;
 }
@@ -62,7 +63,7 @@
 static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
   int32_t l_sub = 0;
 
-  __asm __volatile ("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2));
+  __asm __volatile("qsub %0, %1, %2" : "=r"(l_sub) : "r"(l_var1), "r"(l_var2));
 
   return l_sub;
 }
@@ -70,7 +71,7 @@
 static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
   int32_t s_sub = 0;
 
-  __asm __volatile ("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2));
+  __asm __volatile("qsub16 %0, %1, %2" : "=r"(s_sub) : "r"(var1), "r"(var2));
 
   return (int16_t)s_sub;
 }
@@ -78,7 +79,7 @@
 static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
   int32_t tmp = 0;
 
-  __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(n));
+  __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(n));
 
   return (int16_t)(32 - tmp);
 }
@@ -92,7 +93,7 @@
     a ^= 0xFFFFFFFF;
   }
 
-  __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
+  __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a));
 
   return (int16_t)(tmp - 1);
 }
@@ -100,9 +101,10 @@
 static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
   int tmp = 0;
 
-  if (a == 0) return 0;
+  if (a == 0)
+    return 0;
 
-  __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
+  __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a));
 
   return (int16_t)tmp;
 }
@@ -117,7 +119,7 @@
     a_32 ^= 0xFFFFFFFF;
   }
 
-  __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a_32));
+  __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a_32));
 
   return (int16_t)(tmp - 17);
 }
@@ -126,7 +128,7 @@
 static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
   int32_t out = 0;
 
-  __asm __volatile ("ssat %0, #16, %1" : "=r"(out) : "r"(value32));
+  __asm __volatile("ssat %0, #16, %1" : "=r"(out) : "r"(value32));
 
   return (int16_t)out;
 }
diff --git a/common_audio/signal_processing/include/spl_inl_mips.h b/common_audio/signal_processing/include/spl_inl_mips.h
index 5819d0f..1db95e8 100644
--- a/common_audio/signal_processing/include/spl_inl_mips.h
+++ b/common_audio/signal_processing/include/spl_inl_mips.h
@@ -8,69 +8,65 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 // This header file includes the inline functions in
 // the fix point signal processing library.
 
 #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_
 #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_
 
-static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a,
-                                             int32_t b) {
+static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, int32_t b) {
   int32_t value32 = 0;
   int32_t a1 = 0, b1 = 0;
 
   __asm __volatile(
 #if defined(MIPS32_R2_LE)
-    "seh    %[a1],          %[a]                \n\t"
-    "seh    %[b1],          %[b]                \n\t"
+      "seh    %[a1],          %[a]                \n\t"
+      "seh    %[b1],          %[b]                \n\t"
 #else
-    "sll    %[a1],          %[a],         16    \n\t"
-    "sll    %[b1],          %[b],         16    \n\t"
-    "sra    %[a1],          %[a1],        16    \n\t"
-    "sra    %[b1],          %[b1],        16    \n\t"
+      "sll    %[a1],          %[a],         16    \n\t"
+      "sll    %[b1],          %[b],         16    \n\t"
+      "sra    %[a1],          %[a1],        16    \n\t"
+      "sra    %[b1],          %[b1],        16    \n\t"
 #endif
-    "mul    %[value32],     %[a1],  %[b1]       \n\t"
-    : [value32] "=r" (value32), [a1] "=&r" (a1), [b1] "=&r" (b1)
-    : [a] "r" (a), [b] "r" (b)
-    : "hi", "lo");
+      "mul    %[value32],     %[a1],  %[b1]       \n\t"
+      : [value32] "=r"(value32), [a1] "=&r"(a1), [b1] "=&r"(b1)
+      : [a] "r"(a), [b] "r"(b)
+      : "hi", "lo");
   return value32;
 }
 
-static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a,
-                                                    int32_t b) {
+static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) {
   int32_t value32 = 0, b1 = 0, b2 = 0;
   int32_t a1 = 0;
 
   __asm __volatile(
 #if defined(MIPS32_R2_LE)
-    "seh    %[a1],          %[a]                        \n\t"
+      "seh    %[a1],          %[a]                        \n\t"
 #else
-    "sll    %[a1],          %[a],           16          \n\t"
-    "sra    %[a1],          %[a1],          16          \n\t"
+      "sll    %[a1],          %[a],           16          \n\t"
+      "sra    %[a1],          %[a1],          16          \n\t"
 #endif
-    "andi   %[b2],          %[b],           0xFFFF      \n\t"
-    "sra    %[b1],          %[b],           16          \n\t"
-    "sra    %[b2],          %[b2],          1           \n\t"
-    "mul    %[value32],     %[a1],          %[b1]       \n\t"
-    "mul    %[b2],          %[a1],          %[b2]       \n\t"
-    "addiu  %[b2],          %[b2],          0x4000      \n\t"
-    "sra    %[b2],          %[b2],          15          \n\t"
-    "addu   %[value32],     %[value32],     %[b2]       \n\t"
-    : [value32] "=&r" (value32), [b1] "=&r" (b1), [b2] "=&r" (b2),
-      [a1] "=&r" (a1)
-    : [a] "r" (a), [b] "r" (b)
-    : "hi", "lo");
+      "andi   %[b2],          %[b],           0xFFFF      \n\t"
+      "sra    %[b1],          %[b],           16          \n\t"
+      "sra    %[b2],          %[b2],          1           \n\t"
+      "mul    %[value32],     %[a1],          %[b1]       \n\t"
+      "mul    %[b2],          %[a1],          %[b2]       \n\t"
+      "addiu  %[b2],          %[b2],          0x4000      \n\t"
+      "sra    %[b2],          %[b2],          15          \n\t"
+      "addu   %[value32],     %[value32],     %[b2]       \n\t"
+      : [value32] "=&r"(value32), [b1] "=&r"(b1), [b2] "=&r"(b2), [a1] "=&r"(a1)
+      : [a] "r"(a), [b] "r"(b)
+      : "hi", "lo");
   return value32;
 }
 
 #if defined(MIPS_DSP_R1_LE)
 static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
   __asm __volatile(
-    "shll_s.w   %[value32], %[value32], 16      \n\t"
-    "sra        %[value32], %[value32], 16      \n\t"
-    : [value32] "+r" (value32)
-    :);
+      "shll_s.w   %[value32], %[value32], 16      \n\t"
+      "sra        %[value32], %[value32], 16      \n\t"
+      : [value32] "+r"(value32)
+      :);
   int16_t out16 = (int16_t)value32;
   return out16;
 }
@@ -78,10 +74,9 @@
 static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
   int32_t value32 = 0;
 
-  __asm __volatile(
-    "addq_s.ph      %[value32],     %[a],   %[b]    \n\t"
-    : [value32] "=r" (value32)
-    : [a] "r" (a), [b] "r" (b) );
+  __asm __volatile("addq_s.ph      %[value32],     %[a],   %[b]    \n\t"
+                   : [value32] "=r"(value32)
+                   : [a] "r"(a), [b] "r"(b));
   return (int16_t)value32;
 }
 
@@ -89,9 +84,9 @@
   int32_t l_sum;
 
   __asm __volatile(
-    "addq_s.w   %[l_sum],       %[l_var1],      %[l_var2]    \n\t"
-    : [l_sum] "=r" (l_sum)
-    : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2) );
+      "addq_s.w   %[l_sum],       %[l_var1],      %[l_var2]    \n\t"
+      : [l_sum] "=r"(l_sum)
+      : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2));
 
   return l_sum;
 }
@@ -99,10 +94,9 @@
 static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
   int32_t value32;
 
-  __asm __volatile(
-    "subq_s.ph  %[value32], %[var1],    %[var2]     \n\t"
-    : [value32] "=r" (value32)
-    : [var1] "r" (var1), [var2] "r" (var2) );
+  __asm __volatile("subq_s.ph  %[value32], %[var1],    %[var2]     \n\t"
+                   : [value32] "=r"(value32)
+                   : [var1] "r"(var1), [var2] "r"(var2));
 
   return (int16_t)value32;
 }
@@ -111,9 +105,9 @@
   int32_t l_diff;
 
   __asm __volatile(
-    "subq_s.w   %[l_diff],      %[l_var1],      %[l_var2]    \n\t"
-    : [l_diff] "=r" (l_diff)
-    : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2) );
+      "subq_s.w   %[l_diff],      %[l_var1],      %[l_var2]    \n\t"
+      : [l_diff] "=r"(l_diff)
+      : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2));
 
   return l_diff;
 }
@@ -124,10 +118,10 @@
   int i32 = 32;
 
   __asm __volatile(
-    "clz    %[bits],    %[n]                    \n\t"
-    "subu   %[bits],    %[i32],     %[bits]     \n\t"
-    : [bits] "=&r" (bits)
-    : [n] "r" (n), [i32] "r" (i32) );
+      "clz    %[bits],    %[n]                    \n\t"
+      "subu   %[bits],    %[i32],     %[bits]     \n\t"
+      : [bits] "=&r"(bits)
+      : [n] "r"(n), [i32] "r"(i32));
 
   return (int16_t)bits;
 }
@@ -136,20 +130,20 @@
   int zeros = 0;
 
   __asm __volatile(
-    ".set       push                                \n\t"
-    ".set       noreorder                           \n\t"
-    "bnez       %[a],       1f                      \n\t"
-    " sra       %[zeros],   %[a],       31          \n\t"
-    "b          2f                                  \n\t"
-    " move      %[zeros],   $zero                   \n\t"
-   "1:                                              \n\t"
-    "xor        %[zeros],   %[a],       %[zeros]    \n\t"
-    "clz        %[zeros],   %[zeros]                \n\t"
-    "addiu      %[zeros],   %[zeros],   -1          \n\t"
-   "2:                                              \n\t"
-    ".set       pop                                 \n\t"
-    : [zeros]"=&r"(zeros)
-    : [a] "r" (a) );
+      ".set       push                                \n\t"
+      ".set       noreorder                           \n\t"
+      "bnez       %[a],       1f                      \n\t"
+      " sra       %[zeros],   %[a],       31          \n\t"
+      "b          2f                                  \n\t"
+      " move      %[zeros],   $zero                   \n\t"
+      "1:                                              \n\t"
+      "xor        %[zeros],   %[a],       %[zeros]    \n\t"
+      "clz        %[zeros],   %[zeros]                \n\t"
+      "addiu      %[zeros],   %[zeros],   -1          \n\t"
+      "2:                                              \n\t"
+      ".set       pop                                 \n\t"
+      : [zeros] "=&r"(zeros)
+      : [a] "r"(a));
 
   return (int16_t)zeros;
 }
@@ -157,10 +151,9 @@
 static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
   int zeros = 0;
 
-  __asm __volatile(
-    "clz    %[zeros],   %[a]    \n\t"
-    : [zeros] "=r" (zeros)
-    : [a] "r" (a) );
+  __asm __volatile("clz    %[zeros],   %[a]    \n\t"
+                   : [zeros] "=r"(zeros)
+                   : [a] "r"(a));
 
   return (int16_t)(zeros & 0x1f);
 }
@@ -170,43 +163,41 @@
   int a0 = a << 16;
 
   __asm __volatile(
-    ".set       push                                \n\t"
-    ".set       noreorder                           \n\t"
-    "bnez       %[a0],      1f                      \n\t"
-    " sra       %[zeros],   %[a0],      31          \n\t"
-    "b          2f                                  \n\t"
-    " move      %[zeros],   $zero                   \n\t"
-   "1:                                              \n\t"
-    "xor        %[zeros],   %[a0],      %[zeros]    \n\t"
-    "clz        %[zeros],   %[zeros]                \n\t"
-    "addiu      %[zeros],   %[zeros],   -1          \n\t"
-   "2:                                              \n\t"
-    ".set       pop                                 \n\t"
-    : [zeros]"=&r"(zeros)
-    : [a0] "r" (a0) );
+      ".set       push                                \n\t"
+      ".set       noreorder                           \n\t"
+      "bnez       %[a0],      1f                      \n\t"
+      " sra       %[zeros],   %[a0],      31          \n\t"
+      "b          2f                                  \n\t"
+      " move      %[zeros],   $zero                   \n\t"
+      "1:                                              \n\t"
+      "xor        %[zeros],   %[a0],      %[zeros]    \n\t"
+      "clz        %[zeros],   %[zeros]                \n\t"
+      "addiu      %[zeros],   %[zeros],   -1          \n\t"
+      "2:                                              \n\t"
+      ".set       pop                                 \n\t"
+      : [zeros] "=&r"(zeros)
+      : [a0] "r"(a0));
 
   return (int16_t)zeros;
 }
 
-static __inline int32_t WebRtc_MulAccumW16(int16_t a,
-                                           int16_t b,
-                                           int32_t c) {
+static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
   int32_t res = 0, c1 = 0;
   __asm __volatile(
 #if defined(MIPS32_R2_LE)
-    "seh    %[a],       %[a]            \n\t"
-    "seh    %[b],       %[b]            \n\t"
+      "seh    %[a],       %[a]            \n\t"
+      "seh    %[b],       %[b]            \n\t"
 #else
-    "sll    %[a],       %[a],   16      \n\t"
-    "sll    %[b],       %[b],   16      \n\t"
-    "sra    %[a],       %[a],   16      \n\t"
-    "sra    %[b],       %[b],   16      \n\t"
+      "sll    %[a],       %[a],   16      \n\t"
+      "sll    %[b],       %[b],   16      \n\t"
+      "sra    %[a],       %[a],   16      \n\t"
+      "sra    %[b],       %[b],   16      \n\t"
 #endif
-    "mul    %[res],     %[a],   %[b]    \n\t"
-    "addu   %[c1],      %[c],   %[res]  \n\t"
-    : [c1] "=r" (c1), [res] "=&r" (res)
-    : [a] "r" (a), [b] "r" (b), [c] "r" (c)
-    : "hi", "lo");
+      "mul    %[res],     %[a],   %[b]    \n\t"
+      "addu   %[c1],      %[c],   %[res]  \n\t"
+      : [c1] "=r"(c1), [res] "=&r"(res)
+      : [a] "r"(a), [b] "r"(b), [c] "r"(c)
+      : "hi", "lo");
   return (c1);
 }
 
diff --git a/common_audio/signal_processing/real_fft_unittest.cc b/common_audio/signal_processing/real_fft_unittest.cc
index 4f5b5c7..2d6b7d1 100644
--- a/common_audio/signal_processing/real_fft_unittest.cc
+++ b/common_audio/signal_processing/real_fft_unittest.cc
@@ -27,17 +27,14 @@
 const int kComplexFftDataLength = 2 << kOrder;
 // Reference data for time signal.
 const int16_t kRefData[kTimeDataLength] = {
-  11739, 6848, -8688, 31980, -30295, 25242, 27085, 19410,
-  -26299, 15607, -10791, 11778, -23819, 14498, -25772, 10076,
-  1173, 6848, -8688, 31980, -30295, 2522, 27085, 19410,
-  -2629, 5607, -3, 1178, -23819, 1498, -25772, 10076
-};
+    11739,  6848,  -8688,  31980, -30295, 25242, 27085,  19410,
+    -26299, 15607, -10791, 11778, -23819, 14498, -25772, 10076,
+    1173,   6848,  -8688,  31980, -30295, 2522,  27085,  19410,
+    -2629,  5607,  -3,     1178,  -23819, 1498,  -25772, 10076};
 
 class RealFFTTest : public ::testing::Test {
  protected:
-  RealFFTTest() {
-    WebRtcSpl_Init();
-  }
+  RealFFTTest() { WebRtcSpl_Init(); }
 };
 
 TEST_F(RealFFTTest, CreateFailsOnBadInput) {
diff --git a/common_audio/signal_processing/resample_by_2_internal.h b/common_audio/signal_processing/resample_by_2_internal.h
index b0d1969..5483e2e 100644
--- a/common_audio/signal_processing/resample_by_2_internal.h
+++ b/common_audio/signal_processing/resample_by_2_internal.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /*
  * This header file contains some internal resampling functions.
  *
@@ -23,25 +22,39 @@
  * resample_by_2_fast.c
  * Functions for internal use in the other resample functions
  ******************************************************************/
-void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
-                                 int32_t *state);
+void WebRtcSpl_DownBy2IntToShort(int32_t* in,
+                                 int32_t len,
+                                 int16_t* out,
+                                 int32_t* state);
 
-void WebRtcSpl_DownBy2ShortToInt(const int16_t *in, int32_t len,
-                                 int32_t *out, int32_t *state);
+void WebRtcSpl_DownBy2ShortToInt(const int16_t* in,
+                                 int32_t len,
+                                 int32_t* out,
+                                 int32_t* state);
 
-void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len,
-                               int32_t *out, int32_t *state);
+void WebRtcSpl_UpBy2ShortToInt(const int16_t* in,
+                               int32_t len,
+                               int32_t* out,
+                               int32_t* state);
 
-void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out,
-                             int32_t *state);
+void WebRtcSpl_UpBy2IntToInt(const int32_t* in,
+                             int32_t len,
+                             int32_t* out,
+                             int32_t* state);
 
-void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len,
-                               int16_t *out, int32_t *state);
+void WebRtcSpl_UpBy2IntToShort(const int32_t* in,
+                               int32_t len,
+                               int16_t* out,
+                               int32_t* state);
 
-void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len,
-                               int32_t* out, int32_t* state);
+void WebRtcSpl_LPBy2ShortToInt(const int16_t* in,
+                               int32_t len,
+                               int32_t* out,
+                               int32_t* state);
 
-void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
+void WebRtcSpl_LPBy2IntToInt(const int32_t* in,
+                             int32_t len,
+                             int32_t* out,
                              int32_t* state);
 
 #endif  // COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_
diff --git a/common_audio/signal_processing/signal_processing_unittest.cc b/common_audio/signal_processing/signal_processing_unittest.cc
index b9efe01..8e65ebd 100644
--- a/common_audio/signal_processing/signal_processing_unittest.cc
+++ b/common_audio/signal_processing/signal_processing_unittest.cc
@@ -15,111 +15,113 @@
 #include "test/gtest.h"
 
 static const size_t kVector16Size = 9;
-static const int16_t vector16[kVector16Size] = {1, -15511, 4323, 1963,
-  WEBRTC_SPL_WORD16_MAX, 0, WEBRTC_SPL_WORD16_MIN + 5, -3333, 345};
+static const int16_t vector16[kVector16Size] = {1,
+                                                -15511,
+                                                4323,
+                                                1963,
+                                                WEBRTC_SPL_WORD16_MAX,
+                                                0,
+                                                WEBRTC_SPL_WORD16_MIN + 5,
+                                                -3333,
+                                                345};
 
 class SplTest : public testing::Test {
  protected:
-  SplTest() {
-    WebRtcSpl_Init();
-  }
-  virtual ~SplTest() {
-  }
+  SplTest() { WebRtcSpl_Init(); }
+  ~SplTest() override {}
 };
 
 TEST_F(SplTest, MacroTest) {
-    // Macros with inputs.
-    int A = 10;
-    int B = 21;
-    int a = -3;
-    int b = WEBRTC_SPL_WORD32_MAX;
+  // Macros with inputs.
+  int A = 10;
+  int B = 21;
+  int a = -3;
+  int b = WEBRTC_SPL_WORD32_MAX;
 
-    EXPECT_EQ(10, WEBRTC_SPL_MIN(A, B));
-    EXPECT_EQ(21, WEBRTC_SPL_MAX(A, B));
+  EXPECT_EQ(10, WEBRTC_SPL_MIN(A, B));
+  EXPECT_EQ(21, WEBRTC_SPL_MAX(A, B));
 
-    EXPECT_EQ(3, WEBRTC_SPL_ABS_W16(a));
-    EXPECT_EQ(3, WEBRTC_SPL_ABS_W32(a));
+  EXPECT_EQ(3, WEBRTC_SPL_ABS_W16(a));
+  EXPECT_EQ(3, WEBRTC_SPL_ABS_W32(a));
 
-    EXPECT_EQ(-63, WEBRTC_SPL_MUL(a, B));
-    EXPECT_EQ(2147483651u, WEBRTC_SPL_UMUL(a, b));
-    b = WEBRTC_SPL_WORD16_MAX >> 1;
-    EXPECT_EQ(4294918147u, WEBRTC_SPL_UMUL_32_16(a, b));
-    EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_U16(a, b));
+  EXPECT_EQ(-63, WEBRTC_SPL_MUL(a, B));
+  EXPECT_EQ(2147483651u, WEBRTC_SPL_UMUL(a, b));
+  b = WEBRTC_SPL_WORD16_MAX >> 1;
+  EXPECT_EQ(4294918147u, WEBRTC_SPL_UMUL_32_16(a, b));
+  EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_U16(a, b));
 
-    a = b;
-    b = -3;
+  a = b;
+  b = -3;
 
-    EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT16(a, b));
-    EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT15(a, b));
-    EXPECT_EQ(-3, WEBRTC_SPL_MUL_16_32_RSFT14(a, b));
-    EXPECT_EQ(-24, WEBRTC_SPL_MUL_16_32_RSFT11(a, b));
+  EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT16(a, b));
+  EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT15(a, b));
+  EXPECT_EQ(-3, WEBRTC_SPL_MUL_16_32_RSFT14(a, b));
+  EXPECT_EQ(-24, WEBRTC_SPL_MUL_16_32_RSFT11(a, b));
 
-    EXPECT_EQ(-12288, WEBRTC_SPL_MUL_16_16_RSFT(a, b, 2));
-    EXPECT_EQ(-12287, WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, 2));
+  EXPECT_EQ(-12288, WEBRTC_SPL_MUL_16_16_RSFT(a, b, 2));
+  EXPECT_EQ(-12287, WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, 2));
 
-    EXPECT_EQ(21, WEBRTC_SPL_SAT(a, A, B));
-    EXPECT_EQ(21, WEBRTC_SPL_SAT(a, B, A));
+  EXPECT_EQ(21, WEBRTC_SPL_SAT(a, A, B));
+  EXPECT_EQ(21, WEBRTC_SPL_SAT(a, B, A));
 
-    // Shifting with negative numbers allowed
-    int shift_amount = 1;  // Workaround compiler warning using variable here.
-    // Positive means left shift
-    EXPECT_EQ(32766, WEBRTC_SPL_SHIFT_W32(a, shift_amount));
+  // Shifting with negative numbers allowed
+  int shift_amount = 1;  // Workaround compiler warning using variable here.
+  // Positive means left shift
+  EXPECT_EQ(32766, WEBRTC_SPL_SHIFT_W32(a, shift_amount));
 
-    // Shifting with negative numbers not allowed
-    // We cannot do casting here due to signed/unsigned problem
-    EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1));
+  // Shifting with negative numbers not allowed
+  // We cannot do casting here due to signed/unsigned problem
+  EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1));
 
-    EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1));
+  EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1));
 
-    EXPECT_EQ(1470, WEBRTC_SPL_RAND(A));
+  EXPECT_EQ(1470, WEBRTC_SPL_RAND(A));
 
-    EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_16(a, b));
-    EXPECT_EQ(1073676289, WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX,
-                                               WEBRTC_SPL_WORD16_MAX));
-    EXPECT_EQ(1073709055, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MAX,
-                                                      WEBRTC_SPL_WORD32_MAX));
-    EXPECT_EQ(1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN,
-                                                      WEBRTC_SPL_WORD32_MIN));
+  EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_16(a, b));
+  EXPECT_EQ(1073676289,
+            WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MAX));
+  EXPECT_EQ(1073709055, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MAX,
+                                                    WEBRTC_SPL_WORD32_MAX));
+  EXPECT_EQ(1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN,
+                                                    WEBRTC_SPL_WORD32_MIN));
 #ifdef WEBRTC_ARCH_ARM_V7
-    EXPECT_EQ(-1073741824,
-              WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN,
-                                          WEBRTC_SPL_WORD32_MAX));
+  EXPECT_EQ(-1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN,
+                                                     WEBRTC_SPL_WORD32_MAX));
 #else
-    EXPECT_EQ(-1073741823,
-              WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN,
-                                          WEBRTC_SPL_WORD32_MAX));
+  EXPECT_EQ(-1073741823, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN,
+                                                     WEBRTC_SPL_WORD32_MAX));
 #endif
 }
 
 TEST_F(SplTest, InlineTest) {
-    int16_t a16 = 121;
-    int16_t b16 = -17;
-    int32_t a32 = 111121;
-    int32_t b32 = -1711;
+  int16_t a16 = 121;
+  int16_t b16 = -17;
+  int32_t a32 = 111121;
+  int32_t b32 = -1711;
 
-    EXPECT_EQ(17, WebRtcSpl_GetSizeInBits(a32));
+  EXPECT_EQ(17, WebRtcSpl_GetSizeInBits(a32));
 
-    EXPECT_EQ(0, WebRtcSpl_NormW32(0));
-    EXPECT_EQ(31, WebRtcSpl_NormW32(-1));
-    EXPECT_EQ(0, WebRtcSpl_NormW32(WEBRTC_SPL_WORD32_MIN));
-    EXPECT_EQ(14, WebRtcSpl_NormW32(a32));
+  EXPECT_EQ(0, WebRtcSpl_NormW32(0));
+  EXPECT_EQ(31, WebRtcSpl_NormW32(-1));
+  EXPECT_EQ(0, WebRtcSpl_NormW32(WEBRTC_SPL_WORD32_MIN));
+  EXPECT_EQ(14, WebRtcSpl_NormW32(a32));
 
-    EXPECT_EQ(0, WebRtcSpl_NormW16(0));
-    EXPECT_EQ(15, WebRtcSpl_NormW16(-1));
-    EXPECT_EQ(0, WebRtcSpl_NormW16(WEBRTC_SPL_WORD16_MIN));
-    EXPECT_EQ(4, WebRtcSpl_NormW16(b32));
-    for (int ii = 0; ii < 15; ++ii) {
-      int16_t value = 1 << ii;
-      EXPECT_EQ(14 - ii, WebRtcSpl_NormW16(value));
-      EXPECT_EQ(15 - ii, WebRtcSpl_NormW16(-value));
-    }
+  EXPECT_EQ(0, WebRtcSpl_NormW16(0));
+  EXPECT_EQ(15, WebRtcSpl_NormW16(-1));
+  EXPECT_EQ(0, WebRtcSpl_NormW16(WEBRTC_SPL_WORD16_MIN));
+  EXPECT_EQ(4, WebRtcSpl_NormW16(b32));
+  for (int ii = 0; ii < 15; ++ii) {
+    int16_t value = 1 << ii;
+    EXPECT_EQ(14 - ii, WebRtcSpl_NormW16(value));
+    EXPECT_EQ(15 - ii, WebRtcSpl_NormW16(-value));
+  }
 
-    EXPECT_EQ(0, WebRtcSpl_NormU32(0u));
-    EXPECT_EQ(0, WebRtcSpl_NormU32(0xffffffff));
-    EXPECT_EQ(15, WebRtcSpl_NormU32(static_cast<uint32_t>(a32)));
+  EXPECT_EQ(0, WebRtcSpl_NormU32(0u));
+  EXPECT_EQ(0, WebRtcSpl_NormU32(0xffffffff));
+  EXPECT_EQ(15, WebRtcSpl_NormU32(static_cast<uint32_t>(a32)));
 
-    EXPECT_EQ(104, WebRtcSpl_AddSatW16(a16, b16));
-    EXPECT_EQ(138, WebRtcSpl_SubSatW16(a16, b16));
+  EXPECT_EQ(104, WebRtcSpl_AddSatW16(a16, b16));
+  EXPECT_EQ(138, WebRtcSpl_SubSatW16(a16, b16));
 }
 
 TEST_F(SplTest, AddSubSatW32) {
@@ -168,84 +170,83 @@
 }
 
 TEST_F(SplTest, MathOperationsTest) {
-    int A = 1134567892;
-    int32_t num = 117;
-    int32_t den = -5;
-    uint16_t denU = 5;
-    EXPECT_EQ(33700, WebRtcSpl_Sqrt(A));
-    EXPECT_EQ(33683, WebRtcSpl_SqrtFloor(A));
+  int A = 1134567892;
+  int32_t num = 117;
+  int32_t den = -5;
+  uint16_t denU = 5;
+  EXPECT_EQ(33700, WebRtcSpl_Sqrt(A));
+  EXPECT_EQ(33683, WebRtcSpl_SqrtFloor(A));
 
-
-    EXPECT_EQ(-91772805, WebRtcSpl_DivResultInQ31(den, num));
-    EXPECT_EQ(-23, WebRtcSpl_DivW32W16ResW16(num, (int16_t)den));
-    EXPECT_EQ(-23, WebRtcSpl_DivW32W16(num, (int16_t)den));
-    EXPECT_EQ(23u, WebRtcSpl_DivU32U16(num, denU));
-    EXPECT_EQ(0, WebRtcSpl_DivW32HiLow(128, 0, 256));
+  EXPECT_EQ(-91772805, WebRtcSpl_DivResultInQ31(den, num));
+  EXPECT_EQ(-23, WebRtcSpl_DivW32W16ResW16(num, (int16_t)den));
+  EXPECT_EQ(-23, WebRtcSpl_DivW32W16(num, (int16_t)den));
+  EXPECT_EQ(23u, WebRtcSpl_DivU32U16(num, denU));
+  EXPECT_EQ(0, WebRtcSpl_DivW32HiLow(128, 0, 256));
 }
 
 TEST_F(SplTest, BasicArrayOperationsTest) {
-    const size_t kVectorSize = 4;
-    int B[] = {4, 12, 133, 1100};
-    int16_t b16[kVectorSize];
-    int32_t b32[kVectorSize];
+  const size_t kVectorSize = 4;
+  int B[] = {4, 12, 133, 1100};
+  int16_t b16[kVectorSize];
+  int32_t b32[kVectorSize];
 
-    int16_t bTmp16[kVectorSize];
-    int32_t bTmp32[kVectorSize];
+  int16_t bTmp16[kVectorSize];
+  int32_t bTmp32[kVectorSize];
 
-    WebRtcSpl_MemSetW16(b16, 3, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(3, b16[kk]);
-    }
-    WebRtcSpl_ZerosArrayW16(b16, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(0, b16[kk]);
-    }
-    WebRtcSpl_MemSetW32(b32, 3, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(3, b32[kk]);
-    }
-    WebRtcSpl_ZerosArrayW32(b32, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(0, b32[kk]);
-    }
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        bTmp16[kk] = (int16_t)kk;
-        bTmp32[kk] = (int32_t)kk;
-    }
-    WEBRTC_SPL_MEMCPY_W16(b16, bTmp16, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(b16[kk], bTmp16[kk]);
-    }
-//    WEBRTC_SPL_MEMCPY_W32(b32, bTmp32, kVectorSize);
-//    for (int kk = 0; kk < kVectorSize; ++kk) {
-//        EXPECT_EQ(b32[kk], bTmp32[kk]);
-//    }
-    WebRtcSpl_CopyFromEndW16(b16, kVectorSize, 2, bTmp16);
-    for (size_t kk = 0; kk < 2; ++kk) {
-        EXPECT_EQ(static_cast<int16_t>(kk+2), bTmp16[kk]);
-    }
+  WebRtcSpl_MemSetW16(b16, 3, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(3, b16[kk]);
+  }
+  WebRtcSpl_ZerosArrayW16(b16, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(0, b16[kk]);
+  }
+  WebRtcSpl_MemSetW32(b32, 3, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(3, b32[kk]);
+  }
+  WebRtcSpl_ZerosArrayW32(b32, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(0, b32[kk]);
+  }
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    bTmp16[kk] = (int16_t)kk;
+    bTmp32[kk] = (int32_t)kk;
+  }
+  WEBRTC_SPL_MEMCPY_W16(b16, bTmp16, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(b16[kk], bTmp16[kk]);
+  }
+  //    WEBRTC_SPL_MEMCPY_W32(b32, bTmp32, kVectorSize);
+  //    for (int kk = 0; kk < kVectorSize; ++kk) {
+  //        EXPECT_EQ(b32[kk], bTmp32[kk]);
+  //    }
+  WebRtcSpl_CopyFromEndW16(b16, kVectorSize, 2, bTmp16);
+  for (size_t kk = 0; kk < 2; ++kk) {
+    EXPECT_EQ(static_cast<int16_t>(kk + 2), bTmp16[kk]);
+  }
 
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        b32[kk] = B[kk];
-        b16[kk] = (int16_t)B[kk];
-    }
-    WebRtcSpl_VectorBitShiftW32ToW16(bTmp16, kVectorSize, b32, 1);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((B[kk]>>1), bTmp16[kk]);
-    }
-    WebRtcSpl_VectorBitShiftW16(bTmp16, kVectorSize, b16, 1);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((B[kk]>>1), bTmp16[kk]);
-    }
-    WebRtcSpl_VectorBitShiftW32(bTmp32, kVectorSize, b32, 1);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((B[kk]>>1), bTmp32[kk]);
-    }
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    b32[kk] = B[kk];
+    b16[kk] = (int16_t)B[kk];
+  }
+  WebRtcSpl_VectorBitShiftW32ToW16(bTmp16, kVectorSize, b32, 1);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((B[kk] >> 1), bTmp16[kk]);
+  }
+  WebRtcSpl_VectorBitShiftW16(bTmp16, kVectorSize, b16, 1);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((B[kk] >> 1), bTmp16[kk]);
+  }
+  WebRtcSpl_VectorBitShiftW32(bTmp32, kVectorSize, b32, 1);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((B[kk] >> 1), bTmp32[kk]);
+  }
 
-    WebRtcSpl_MemCpyReversedOrder(&bTmp16[3], b16, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(b16[3-kk], bTmp16[kk]);
-    }
+  WebRtcSpl_MemCpyReversedOrder(&bTmp16[3], b16, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(b16[3 - kk], bTmp16[kk]);
+  }
 }
 
 TEST_F(SplTest, MinMaxOperationsTest) {
@@ -253,12 +254,40 @@
 
   // Vectors to test the cases where minimum values have to be caught
   // outside of the unrolled loops in ARM-Neon.
-  int16_t vector16[kVectorSize] = {-1, 7485, 0, 3333,
-      -18283, 0, 12334, -29871, 988, -3333,
-      345, -456, 222, 999,  888, 8774, WEBRTC_SPL_WORD16_MIN};
-  int32_t vector32[kVectorSize] = {-1, 0, 283211, 3333,
-      8712345, 0, -3333, 89345, -374585456, 222, 999, 122345334,
-      -12389756, -987329871, 888, -2, WEBRTC_SPL_WORD32_MIN};
+  int16_t vector16[kVectorSize] = {-1,
+                                   7485,
+                                   0,
+                                   3333,
+                                   -18283,
+                                   0,
+                                   12334,
+                                   -29871,
+                                   988,
+                                   -3333,
+                                   345,
+                                   -456,
+                                   222,
+                                   999,
+                                   888,
+                                   8774,
+                                   WEBRTC_SPL_WORD16_MIN};
+  int32_t vector32[kVectorSize] = {-1,
+                                   0,
+                                   283211,
+                                   3333,
+                                   8712345,
+                                   0,
+                                   -3333,
+                                   89345,
+                                   -374585456,
+                                   222,
+                                   999,
+                                   122345334,
+                                   -12389756,
+                                   -987329871,
+                                   888,
+                                   -2,
+                                   WEBRTC_SPL_WORD32_MIN};
 
   EXPECT_EQ(WEBRTC_SPL_WORD16_MIN,
             WebRtcSpl_MinValueW16(vector16, kVectorSize));
@@ -312,76 +341,75 @@
 }
 
 TEST_F(SplTest, VectorOperationsTest) {
-    const size_t kVectorSize = 4;
-    int B[] = {4, 12, 133, 1100};
-    int16_t a16[kVectorSize];
-    int16_t b16[kVectorSize];
-    int16_t bTmp16[kVectorSize];
+  const size_t kVectorSize = 4;
+  int B[] = {4, 12, 133, 1100};
+  int16_t a16[kVectorSize];
+  int16_t b16[kVectorSize];
+  int16_t bTmp16[kVectorSize];
 
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        a16[kk] = B[kk];
-        b16[kk] = B[kk];
-    }
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    a16[kk] = B[kk];
+    b16[kk] = B[kk];
+  }
 
-    WebRtcSpl_AffineTransformVector(bTmp16, b16, 3, 7, 2, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((B[kk]*3+7)>>2, bTmp16[kk]);
-    }
-    WebRtcSpl_ScaleAndAddVectorsWithRound(b16, 3, b16, 2, 2, bTmp16,
-                                          kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((B[kk]*3+B[kk]*2+2)>>2, bTmp16[kk]);
-    }
+  WebRtcSpl_AffineTransformVector(bTmp16, b16, 3, 7, 2, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((B[kk] * 3 + 7) >> 2, bTmp16[kk]);
+  }
+  WebRtcSpl_ScaleAndAddVectorsWithRound(b16, 3, b16, 2, 2, bTmp16, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((B[kk] * 3 + B[kk] * 2 + 2) >> 2, bTmp16[kk]);
+  }
 
-    WebRtcSpl_AddAffineVectorToVector(bTmp16, b16, 3, 7, 2, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(((B[kk]*3+B[kk]*2+2)>>2)+((b16[kk]*3+7)>>2), bTmp16[kk]);
-    }
+  WebRtcSpl_AddAffineVectorToVector(bTmp16, b16, 3, 7, 2, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(((B[kk] * 3 + B[kk] * 2 + 2) >> 2) + ((b16[kk] * 3 + 7) >> 2),
+              bTmp16[kk]);
+  }
 
-    WebRtcSpl_ScaleVector(b16, bTmp16, 13, kVectorSize, 2);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((b16[kk]*13)>>2, bTmp16[kk]);
-    }
-    WebRtcSpl_ScaleVectorWithSat(b16, bTmp16, 13, kVectorSize, 2);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((b16[kk]*13)>>2, bTmp16[kk]);
-    }
-    WebRtcSpl_ScaleAndAddVectors(a16, 13, 2, b16, 7, 2, bTmp16, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(((a16[kk]*13)>>2)+((b16[kk]*7)>>2), bTmp16[kk]);
-    }
+  WebRtcSpl_ScaleVector(b16, bTmp16, 13, kVectorSize, 2);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((b16[kk] * 13) >> 2, bTmp16[kk]);
+  }
+  WebRtcSpl_ScaleVectorWithSat(b16, bTmp16, 13, kVectorSize, 2);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((b16[kk] * 13) >> 2, bTmp16[kk]);
+  }
+  WebRtcSpl_ScaleAndAddVectors(a16, 13, 2, b16, 7, 2, bTmp16, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(((a16[kk] * 13) >> 2) + ((b16[kk] * 7) >> 2), bTmp16[kk]);
+  }
 
-    WebRtcSpl_AddVectorsAndShift(bTmp16, a16, b16, kVectorSize, 2);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(B[kk] >> 1, bTmp16[kk]);
-    }
-    WebRtcSpl_ReverseOrderMultArrayElements(bTmp16, a16, &b16[3],
-                                            kVectorSize, 2);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((a16[kk]*b16[3-kk])>>2, bTmp16[kk]);
-    }
-    WebRtcSpl_ElementwiseVectorMult(bTmp16, a16, b16, kVectorSize, 6);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ((a16[kk]*b16[kk])>>6, bTmp16[kk]);
-    }
+  WebRtcSpl_AddVectorsAndShift(bTmp16, a16, b16, kVectorSize, 2);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(B[kk] >> 1, bTmp16[kk]);
+  }
+  WebRtcSpl_ReverseOrderMultArrayElements(bTmp16, a16, &b16[3], kVectorSize, 2);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((a16[kk] * b16[3 - kk]) >> 2, bTmp16[kk]);
+  }
+  WebRtcSpl_ElementwiseVectorMult(bTmp16, a16, b16, kVectorSize, 6);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ((a16[kk] * b16[kk]) >> 6, bTmp16[kk]);
+  }
 
-    WebRtcSpl_SqrtOfOneMinusXSquared(b16, kVectorSize, bTmp16);
-    for (size_t kk = 0; kk < kVectorSize - 1; ++kk) {
-        EXPECT_EQ(32767, bTmp16[kk]);
-    }
-    EXPECT_EQ(32749, bTmp16[kVectorSize - 1]);
+  WebRtcSpl_SqrtOfOneMinusXSquared(b16, kVectorSize, bTmp16);
+  for (size_t kk = 0; kk < kVectorSize - 1; ++kk) {
+    EXPECT_EQ(32767, bTmp16[kk]);
+  }
+  EXPECT_EQ(32749, bTmp16[kVectorSize - 1]);
 
-    EXPECT_EQ(0, WebRtcSpl_GetScalingSquare(b16, kVectorSize, 1));
+  EXPECT_EQ(0, WebRtcSpl_GetScalingSquare(b16, kVectorSize, 1));
 }
 
 TEST_F(SplTest, EstimatorsTest) {
   const size_t kOrder = 2;
-  const int32_t unstable_filter[] = { 4, 12, 133, 1100 };
-  const int32_t stable_filter[] = { 1100, 133, 12, 4 };
-  int16_t lpc[kOrder + 2] = { 0 };
-  int16_t refl[kOrder + 2] = { 0 };
-  int16_t lpc_result[] = { 4096, -497, 15, 0 };
-  int16_t refl_result[] = { -3962, 123, 0, 0 };
+  const int32_t unstable_filter[] = {4, 12, 133, 1100};
+  const int32_t stable_filter[] = {1100, 133, 12, 4};
+  int16_t lpc[kOrder + 2] = {0};
+  int16_t refl[kOrder + 2] = {0};
+  int16_t lpc_result[] = {4096, -497, 15, 0};
+  int16_t refl_result[] = {-3962, 123, 0, 0};
 
   EXPECT_EQ(0, WebRtcSpl_LevinsonDurbin(unstable_filter, lpc, refl, kOrder));
   EXPECT_EQ(1, WebRtcSpl_LevinsonDurbin(stable_filter, lpc, refl, kOrder));
@@ -392,69 +420,61 @@
 }
 
 TEST_F(SplTest, FilterTest) {
-    const size_t kVectorSize = 4;
-    const size_t kFilterOrder = 3;
-    int16_t A[] = {1, 2, 33, 100};
-    int16_t A5[] = {1, 2, 33, 100, -5};
-    int16_t B[] = {4, 12, 133, 110};
-    int16_t data_in[kVectorSize];
-    int16_t data_out[kVectorSize];
-    int16_t bTmp16Low[kVectorSize];
-    int16_t bState[kVectorSize];
-    int16_t bStateLow[kVectorSize];
+  const size_t kVectorSize = 4;
+  const size_t kFilterOrder = 3;
+  int16_t A[] = {1, 2, 33, 100};
+  int16_t A5[] = {1, 2, 33, 100, -5};
+  int16_t B[] = {4, 12, 133, 110};
+  int16_t data_in[kVectorSize];
+  int16_t data_out[kVectorSize];
+  int16_t bTmp16Low[kVectorSize];
+  int16_t bState[kVectorSize];
+  int16_t bStateLow[kVectorSize];
 
-    WebRtcSpl_ZerosArrayW16(bState, kVectorSize);
-    WebRtcSpl_ZerosArrayW16(bStateLow, kVectorSize);
+  WebRtcSpl_ZerosArrayW16(bState, kVectorSize);
+  WebRtcSpl_ZerosArrayW16(bStateLow, kVectorSize);
 
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        data_in[kk] = A[kk];
-        data_out[kk] = 0;
-    }
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    data_in[kk] = A[kk];
+    data_out[kk] = 0;
+  }
 
-    // MA filters.
-    // Note that the input data has |kFilterOrder| states before the actual
-    // data (one sample).
-    WebRtcSpl_FilterMAFastQ12(&data_in[kFilterOrder], data_out, B,
-                              kFilterOrder + 1, 1);
-    EXPECT_EQ(0, data_out[0]);
-    // AR filters.
-    // Note that the output data has |kFilterOrder| states before the actual
-    // data (one sample).
-    WebRtcSpl_FilterARFastQ12(data_in, &data_out[kFilterOrder], A,
-                              kFilterOrder + 1, 1);
-    EXPECT_EQ(0, data_out[kFilterOrder]);
+  // MA filters.
+  // Note that the input data has |kFilterOrder| states before the actual
+  // data (one sample).
+  WebRtcSpl_FilterMAFastQ12(&data_in[kFilterOrder], data_out, B,
+                            kFilterOrder + 1, 1);
+  EXPECT_EQ(0, data_out[0]);
+  // AR filters.
+  // Note that the output data has |kFilterOrder| states before the actual
+  // data (one sample).
+  WebRtcSpl_FilterARFastQ12(data_in, &data_out[kFilterOrder], A,
+                            kFilterOrder + 1, 1);
+  EXPECT_EQ(0, data_out[kFilterOrder]);
 
-    EXPECT_EQ(kVectorSize, WebRtcSpl_FilterAR(A5,
-                                              5,
-                                              data_in,
-                                              kVectorSize,
-                                              bState,
-                                              kVectorSize,
-                                              bStateLow,
-                                              kVectorSize,
-                                              data_out,
-                                              bTmp16Low,
-                                              kVectorSize));
+  EXPECT_EQ(kVectorSize, WebRtcSpl_FilterAR(A5, 5, data_in, kVectorSize, bState,
+                                            kVectorSize, bStateLow, kVectorSize,
+                                            data_out, bTmp16Low, kVectorSize));
 }
 
 TEST_F(SplTest, RandTest) {
-    const int kVectorSize = 4;
-    int16_t BU[] = {3653, 12446, 8525, 30691};
-    int16_t b16[kVectorSize];
-    uint32_t bSeed = 100000;
+  const int kVectorSize = 4;
+  int16_t BU[] = {3653, 12446, 8525, 30691};
+  int16_t b16[kVectorSize];
+  uint32_t bSeed = 100000;
 
-    EXPECT_EQ(7086, WebRtcSpl_RandU(&bSeed));
-    EXPECT_EQ(31565, WebRtcSpl_RandU(&bSeed));
-    EXPECT_EQ(-9786, WebRtcSpl_RandN(&bSeed));
-    EXPECT_EQ(kVectorSize, WebRtcSpl_RandUArray(b16, kVectorSize, &bSeed));
-    for (int kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(BU[kk], b16[kk]);
-    }
+  EXPECT_EQ(7086, WebRtcSpl_RandU(&bSeed));
+  EXPECT_EQ(31565, WebRtcSpl_RandU(&bSeed));
+  EXPECT_EQ(-9786, WebRtcSpl_RandN(&bSeed));
+  EXPECT_EQ(kVectorSize, WebRtcSpl_RandUArray(b16, kVectorSize, &bSeed));
+  for (int kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(BU[kk], b16[kk]);
+  }
 }
 
 TEST_F(SplTest, DotProductWithScaleTest) {
-  EXPECT_EQ(605362796, WebRtcSpl_DotProductWithScale(vector16,
-      vector16, kVector16Size, 2));
+  EXPECT_EQ(605362796, WebRtcSpl_DotProductWithScale(vector16, vector16,
+                                                     kVector16Size, 2));
 }
 
 TEST_F(SplTest, CrossCorrelationTest) {
@@ -464,8 +484,9 @@
   const int kStep = 1;
   const size_t kSeqDimension = 6;
 
-  const int16_t kVector16[kVector16Size] = {1, 4323, 1963,
-    WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MIN + 5, -3333, -876, 8483, 142};
+  const int16_t kVector16[kVector16Size] = {
+      1,    4323, 1963, WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MIN + 5, -3333,
+      -876, 8483, 142};
   int32_t vector32[kCrossCorrelationDimension] = {0};
 
   WebRtcSpl_CrossCorrelation(vector32, vector16, kVector16, kSeqDimension,
@@ -473,12 +494,12 @@
 
   // WebRtcSpl_CrossCorrelationC() and WebRtcSpl_CrossCorrelationNeon()
   // are not bit-exact.
-  const int32_t kExpected[kCrossCorrelationDimension] =
-      {-266947903, -15579555, -171282001};
+  const int32_t kExpected[kCrossCorrelationDimension] = {-266947903, -15579555,
+                                                         -171282001};
   const int32_t* expected = kExpected;
 #if !defined(MIPS32_LE)
-  const int32_t kExpectedNeon[kCrossCorrelationDimension] =
-      {-266947901, -15579553, -171281999};
+  const int32_t kExpectedNeon[kCrossCorrelationDimension] = {
+      -266947901, -15579553, -171281999};
   if (WebRtcSpl_CrossCorrelation != WebRtcSpl_CrossCorrelationC) {
     expected = kExpectedNeon;
   }
@@ -491,8 +512,9 @@
 TEST_F(SplTest, AutoCorrelationTest) {
   int scale = 0;
   int32_t vector32[kVector16Size];
-  const int32_t expected[kVector16Size] = {302681398, 14223410, -121705063,
-    -85221647, -17104971, 61806945, 6644603, -669329, 43};
+  const int32_t expected[kVector16Size] = {302681398, 14223410,  -121705063,
+                                           -85221647, -17104971, 61806945,
+                                           6644603,   -669329,   43};
 
   EXPECT_EQ(kVector16Size,
             WebRtcSpl_AutoCorrelation(vector16, kVector16Size,
@@ -504,63 +526,60 @@
 }
 
 TEST_F(SplTest, SignalProcessingTest) {
-    const size_t kVectorSize = 4;
-    int A[] = {1, 2, 33, 100};
-    const int16_t kHanning[4] = { 2399, 8192, 13985, 16384 };
-    int16_t b16[kVectorSize];
+  const size_t kVectorSize = 4;
+  int A[] = {1, 2, 33, 100};
+  const int16_t kHanning[4] = {2399, 8192, 13985, 16384};
+  int16_t b16[kVectorSize];
 
-    int16_t bTmp16[kVectorSize];
+  int16_t bTmp16[kVectorSize];
 
-    int bScale = 0;
+  int bScale = 0;
 
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        b16[kk] = A[kk];
-    }
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    b16[kk] = A[kk];
+  }
 
-    // TODO(bjornv): Activate the Reflection Coefficient tests when refactoring.
-//    WebRtcSpl_ReflCoefToLpc(b16, kVectorSize, bTmp16);
-////    for (int kk = 0; kk < kVectorSize; ++kk) {
-////        EXPECT_EQ(aTmp16[kk], bTmp16[kk]);
-////    }
-//    WebRtcSpl_LpcToReflCoef(bTmp16, kVectorSize, b16);
-////    for (int kk = 0; kk < kVectorSize; ++kk) {
-////        EXPECT_EQ(a16[kk], b16[kk]);
-////    }
-//    WebRtcSpl_AutoCorrToReflCoef(b32, kVectorSize, bTmp16);
-////    for (int kk = 0; kk < kVectorSize; ++kk) {
-////        EXPECT_EQ(aTmp16[kk], bTmp16[kk]);
-////    }
+  // TODO(bjornv): Activate the Reflection Coefficient tests when refactoring.
+  //    WebRtcSpl_ReflCoefToLpc(b16, kVectorSize, bTmp16);
+  ////    for (int kk = 0; kk < kVectorSize; ++kk) {
+  ////        EXPECT_EQ(aTmp16[kk], bTmp16[kk]);
+  ////    }
+  //    WebRtcSpl_LpcToReflCoef(bTmp16, kVectorSize, b16);
+  ////    for (int kk = 0; kk < kVectorSize; ++kk) {
+  ////        EXPECT_EQ(a16[kk], b16[kk]);
+  ////    }
+  //    WebRtcSpl_AutoCorrToReflCoef(b32, kVectorSize, bTmp16);
+  ////    for (int kk = 0; kk < kVectorSize; ++kk) {
+  ////        EXPECT_EQ(aTmp16[kk], bTmp16[kk]);
+  ////    }
 
-    WebRtcSpl_GetHanningWindow(bTmp16, kVectorSize);
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        EXPECT_EQ(kHanning[kk], bTmp16[kk]);
-    }
+  WebRtcSpl_GetHanningWindow(bTmp16, kVectorSize);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    EXPECT_EQ(kHanning[kk], bTmp16[kk]);
+  }
 
-    for (size_t kk = 0; kk < kVectorSize; ++kk) {
-        b16[kk] = A[kk];
-    }
-    EXPECT_EQ(11094 , WebRtcSpl_Energy(b16, kVectorSize, &bScale));
-    EXPECT_EQ(0, bScale);
+  for (size_t kk = 0; kk < kVectorSize; ++kk) {
+    b16[kk] = A[kk];
+  }
+  EXPECT_EQ(11094, WebRtcSpl_Energy(b16, kVectorSize, &bScale));
+  EXPECT_EQ(0, bScale);
 }
 
 TEST_F(SplTest, FFTTest) {
-    int16_t B[] = {1, 2, 33, 100,
-            2, 3, 34, 101,
-            3, 4, 35, 102,
-            4, 5, 36, 103};
+  int16_t B[] = {1, 2, 33, 100, 2, 3, 34, 101, 3, 4, 35, 102, 4, 5, 36, 103};
 
-    EXPECT_EQ(0, WebRtcSpl_ComplexFFT(B, 3, 1));
-//    for (int kk = 0; kk < 16; ++kk) {
-//        EXPECT_EQ(A[kk], B[kk]);
-//    }
-    EXPECT_EQ(0, WebRtcSpl_ComplexIFFT(B, 3, 1));
-//    for (int kk = 0; kk < 16; ++kk) {
-//        EXPECT_EQ(A[kk], B[kk]);
-//    }
-    WebRtcSpl_ComplexBitReverse(B, 3);
-    for (int kk = 0; kk < 16; ++kk) {
-//      EXPECT_EQ(A[kk], B[kk]);
-    }
+  EXPECT_EQ(0, WebRtcSpl_ComplexFFT(B, 3, 1));
+  //    for (int kk = 0; kk < 16; ++kk) {
+  //        EXPECT_EQ(A[kk], B[kk]);
+  //    }
+  EXPECT_EQ(0, WebRtcSpl_ComplexIFFT(B, 3, 1));
+  //    for (int kk = 0; kk < 16; ++kk) {
+  //        EXPECT_EQ(A[kk], B[kk]);
+  //    }
+  WebRtcSpl_ComplexBitReverse(B, 3);
+  for (int kk = 0; kk < 16; ++kk) {
+    //      EXPECT_EQ(A[kk], B[kk]);
+  }
 }
 
 TEST_F(SplTest, Resample48WithSaturationTest) {
@@ -570,14 +589,13 @@
 
   // Saturated input vector of 48 samples.
   const int32_t kVectorSaturated[3 * kBlockSize + 7] = {
-     -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
-     -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
-     -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
-     32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767,
-     32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767,
-     32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767,
-     32767, 32767, 32767, 32767, 32767, 32767, 32767
-  };
+      -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
+      -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
+      -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768,
+      32767,  32767,  32767,  32767,  32767,  32767,  32767,  32767,
+      32767,  32767,  32767,  32767,  32767,  32767,  32767,  32767,
+      32767,  32767,  32767,  32767,  32767,  32767,  32767,  32767,
+      32767,  32767,  32767,  32767,  32767,  32767,  32767};
 
   // All values in |out_vector| should be |kRefValue32kHz|.
   const int32_t kRefValue32kHz1 = -1077493760;
diff --git a/common_audio/smoothing_filter.cc b/common_audio/smoothing_filter.cc
index ecfb5c2..d426bda 100644
--- a/common_audio/smoothing_filter.cc
+++ b/common_audio/smoothing_filter.cc
@@ -52,10 +52,10 @@
   last_sample_ = sample;
 }
 
-rtc::Optional<float> SmoothingFilterImpl::GetAverage() {
+absl::optional<float> SmoothingFilterImpl::GetAverage() {
   if (!init_end_time_ms_) {
     // |init_end_time_ms_| undefined since we have not received any sample.
-    return rtc::nullopt;
+    return absl::nullopt;
   }
   ExtrapolateLastSample(rtc::TimeMillis());
   return state_;
diff --git a/common_audio/smoothing_filter.h b/common_audio/smoothing_filter.h
index b8ab4e5..cff7469 100644
--- a/common_audio/smoothing_filter.h
+++ b/common_audio/smoothing_filter.h
@@ -11,7 +11,7 @@
 #ifndef COMMON_AUDIO_SMOOTHING_FILTER_H_
 #define COMMON_AUDIO_SMOOTHING_FILTER_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/constructormagic.h"
 #include "system_wrappers/include/clock.h"
 
@@ -21,7 +21,7 @@
  public:
   virtual ~SmoothingFilter() = default;
   virtual void AddSample(float sample) = 0;
-  virtual rtc::Optional<float> GetAverage() = 0;
+  virtual absl::optional<float> GetAverage() = 0;
   virtual bool SetTimeConstantMs(int time_constant_ms) = 0;
 };
 
@@ -44,7 +44,7 @@
   ~SmoothingFilterImpl() override;
 
   void AddSample(float sample) override;
-  rtc::Optional<float> GetAverage() override;
+  absl::optional<float> GetAverage() override;
   bool SetTimeConstantMs(int time_constant_ms) override;
 
   // Methods used for unittests.
@@ -58,7 +58,7 @@
   const float init_factor_;
   const float init_const_;
 
-  rtc::Optional<int64_t> init_end_time_ms_;
+  absl::optional<int64_t> init_end_time_ms_;
   float last_sample_;
   float alpha_;
   float state_;
diff --git a/common_audio/smoothing_filter_unittest.cc b/common_audio/smoothing_filter_unittest.cc
index d173c9a..abe4272 100644
--- a/common_audio/smoothing_filter_unittest.cc
+++ b/common_audio/smoothing_filter_unittest.cc
@@ -25,7 +25,7 @@
 struct SmoothingFilterStates {
   explicit SmoothingFilterStates(int init_time_ms)
       : smoothing_filter(init_time_ms) {
-    fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kClockInitialTime));
+    fake_clock.AdvanceTime(TimeDelta::ms(kClockInitialTime));
   }
   rtc::ScopedFakeClock fake_clock;
   SmoothingFilterImpl smoothing_filter;
@@ -41,8 +41,7 @@
                  int advance_time_ms,
                  float expected_ouput) {
   states->smoothing_filter.AddSample(sample);
-  states->fake_clock.AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(advance_time_ms));
+  states->fake_clock.AdvanceTime(TimeDelta::ms(advance_time_ms));
   auto output = states->smoothing_filter.GetAverage();
   EXPECT_TRUE(output);
   EXPECT_NEAR(expected_ouput, *output, kMaxAbsError);
@@ -141,14 +140,13 @@
   states.smoothing_filter.AddSample(0.0);
 
   // During initialization, |SetTimeConstantMs| does not take effect.
-  states.fake_clock.AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(kInitTimeMs - 1));
+  states.fake_clock.AdvanceTime(TimeDelta::ms(kInitTimeMs - 1));
   states.smoothing_filter.AddSample(0.0);
 
   EXPECT_FALSE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2));
   EXPECT_NE(exp(-1.0f / (kInitTimeMs * 2)), states.smoothing_filter.alpha());
 
-  states.fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1));
+  states.fake_clock.AdvanceTime(TimeDelta::ms(1));
   states.smoothing_filter.AddSample(0.0);
   // When initialization finishes, the time constant should be come
   // |kInitTimeConstantMs|.
diff --git a/common_audio/sparse_fir_filter.cc b/common_audio/sparse_fir_filter.cc
index ed2d79b..0fc0327 100644
--- a/common_audio/sparse_fir_filter.cc
+++ b/common_audio/sparse_fir_filter.cc
@@ -34,8 +34,8 @@
   for (size_t i = 0; i < length; ++i) {
     out[i] = 0.f;
     size_t j;
-    for (j = 0; i >= j * sparsity_ + offset_ &&
-                j < nonzero_coeffs_.size(); ++j) {
+    for (j = 0; i >= j * sparsity_ + offset_ && j < nonzero_coeffs_.size();
+         ++j) {
       out[i] += in[i - j * sparsity_ - offset_] * nonzero_coeffs_[j];
     }
     for (; j < nonzero_coeffs_.size(); ++j) {
@@ -47,12 +47,10 @@
   // Update current state.
   if (state_.size() > 0u) {
     if (length >= state_.size()) {
-      std::memcpy(&state_[0],
-                  &in[length - state_.size()],
+      std::memcpy(&state_[0], &in[length - state_.size()],
                   state_.size() * sizeof(*in));
     } else {
-      std::memmove(&state_[0],
-                   &state_[length],
+      std::memmove(&state_[0], &state_[length],
                    (state_.size() - length) * sizeof(state_[0]));
       std::memcpy(&state_[state_.size() - length], in, length * sizeof(*in));
     }
diff --git a/common_audio/sparse_fir_filter_unittest.cc b/common_audio/sparse_fir_filter_unittest.cc
index 434daaa..b6cd6f9 100644
--- a/common_audio/sparse_fir_filter_unittest.cc
+++ b/common_audio/sparse_fir_filter_unittest.cc
@@ -21,8 +21,8 @@
 namespace {
 
 static const float kCoeffs[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
-static const float kInput[] =
-    {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f};
+static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f,
+                               6.f, 7.f, 8.f, 9.f, 10.f};
 
 template <size_t N>
 void VerifyOutput(const float (&expected_output)[N], const float (&output)[N]) {
@@ -50,13 +50,9 @@
   const size_t kOffset = 0;
   float low_sparsity_output[arraysize(kInput)];
   float high_sparsity_output[arraysize(kInput)];
-  SparseFIRFilter low_sparsity_filter(&kCoeff,
-                                      kNumCoeff,
-                                      kLowSparsity,
+  SparseFIRFilter low_sparsity_filter(&kCoeff, kNumCoeff, kLowSparsity,
                                       kOffset);
-  SparseFIRFilter high_sparsity_filter(&kCoeff,
-                                       kNumCoeff,
-                                       kHighSparsity,
+  SparseFIRFilter high_sparsity_filter(&kCoeff, kNumCoeff, kHighSparsity,
                                        kOffset);
   low_sparsity_filter.Filter(kInput, arraysize(kInput), low_sparsity_output);
   high_sparsity_filter.Filter(kInput, arraysize(kInput), high_sparsity_output);
@@ -146,15 +142,10 @@
   const size_t kSparsity = 3;
   const size_t kOffset = 1;
   float output_block_based[arraysize(kInput)];
-  SparseFIRFilter filter_block(kCoeffs,
-                               arraysize(kCoeffs),
-                               kSparsity,
-                               kOffset);
+  SparseFIRFilter filter_block(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
   filter_block.Filter(kInput, arraysize(kInput), output_block_based);
   float output_sample_based[arraysize(kInput)];
-  SparseFIRFilter filter_sample(kCoeffs,
-                                arraysize(kCoeffs),
-                                kSparsity,
+  SparseFIRFilter filter_sample(kCoeffs, arraysize(kCoeffs), kSparsity,
                                 kOffset);
   for (size_t i = 0; i < arraysize(kInput); ++i)
     filter_sample.Filter(&kInput[i], 1, &output_sample_based[i]);
@@ -165,8 +156,8 @@
   const size_t kSparsity = 2;
   const size_t kOffset = 2;
   const float kHPCoeffs[] = {1.f, -1.f};
-  const float kConstantInput[] =
-      {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
+  const float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f,
+                                  1.f, 1.f, 1.f, 1.f, 1.f};
   float output[arraysize(kConstantInput)];
   SparseFIRFilter filter(kHPCoeffs, arraysize(kHPCoeffs), kSparsity, kOffset);
   filter.Filter(kConstantInput, arraysize(kConstantInput), output);
@@ -182,8 +173,8 @@
   const size_t kSparsity = 2;
   const size_t kOffset = 2;
   const float kLPCoeffs[] = {1.f, 1.f};
-  const float kHighFrequencyInput[] =
-      {1.f, 1.f, -1.f, -1.f, 1.f, 1.f, -1.f, -1.f, 1.f, 1.f};
+  const float kHighFrequencyInput[] = {1.f, 1.f,  -1.f, -1.f, 1.f,
+                                       1.f, -1.f, -1.f, 1.f,  1.f};
   float output[arraysize(kHighFrequencyInput)];
   SparseFIRFilter filter(kLPCoeffs, arraysize(kLPCoeffs), kSparsity, kOffset);
   filter.Filter(kHighFrequencyInput, arraysize(kHighFrequencyInput), output);
@@ -203,9 +194,7 @@
   SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
   // Use arraysize(kCoeffs) for in_length to get same-length outputs.
   filter.Filter(kInput, arraysize(kCoeffs), output);
-  SparseFIRFilter filter_swapped(kInput,
-                                 arraysize(kCoeffs),
-                                 kSparsity,
+  SparseFIRFilter filter_swapped(kInput, arraysize(kCoeffs), kSparsity,
                                  kOffset);
   filter_swapped.Filter(kCoeffs, arraysize(kCoeffs), output_swapped);
   VerifyOutput(output, output_swapped);
@@ -218,9 +207,7 @@
   float sparse_output[arraysize(kInput)];
   std::unique_ptr<FIRFilter> filter(
       CreateFirFilter(kCoeffs, arraysize(kCoeffs), arraysize(kInput)));
-  SparseFIRFilter sparse_filter(kCoeffs,
-                                arraysize(kCoeffs),
-                                kSparsity,
+  SparseFIRFilter sparse_filter(kCoeffs, arraysize(kCoeffs), kSparsity,
                                 kOffset);
   filter->Filter(kInput, arraysize(kInput), output);
   sparse_filter.Filter(kInput, arraysize(kInput), sparse_output);
diff --git a/common_audio/vad/include/webrtc_vad.h b/common_audio/vad/include/webrtc_vad.h
index 353dbf0..a6c539c 100644
--- a/common_audio/vad/include/webrtc_vad.h
+++ b/common_audio/vad/include/webrtc_vad.h
@@ -8,9 +8,9 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /*
- * This header file includes the VAD API calls. Specific function calls are given below.
+ * This header file includes the VAD API calls. Specific function calls are
+ * given below.
  */
 
 #ifndef COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_  // NOLINT
@@ -67,7 +67,9 @@
 // returns              : 1 - (Active Voice),
 //                        0 - (Non-active Voice),
 //                       -1 - (Error)
-int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame,
+int WebRtcVad_Process(VadInst* handle,
+                      int fs,
+                      const int16_t* audio_frame,
                       size_t frame_length);
 
 // Checks for valid combinations of |rate| and |frame_length|. We support 10,
diff --git a/common_audio/vad/vad_core.h b/common_audio/vad/vad_core.h
index 6541819..0eb8de3 100644
--- a/common_audio/vad/vad_core.h
+++ b/common_audio/vad/vad_core.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 /*
  * This header file includes the descriptions of the core VAD calls.
  */
@@ -19,37 +18,37 @@
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
-enum { kNumChannels = 6 };  // Number of frequency bands (named channels).
+enum { kNumChannels = 6 };   // Number of frequency bands (named channels).
 enum { kNumGaussians = 2 };  // Number of Gaussians per channel in the GMM.
 enum { kTableSize = kNumChannels * kNumGaussians };
 enum { kMinEnergy = 10 };  // Minimum energy required to trigger audio signal.
 
 typedef struct VadInstT_ {
-    int vad;
-    int32_t downsampling_filter_states[4];
-    WebRtcSpl_State48khzTo8khz state_48_to_8;
-    int16_t noise_means[kTableSize];
-    int16_t speech_means[kTableSize];
-    int16_t noise_stds[kTableSize];
-    int16_t speech_stds[kTableSize];
-    // TODO(bjornv): Change to |frame_count|.
-    int32_t frame_counter;
-    int16_t over_hang;  // Over Hang
-    int16_t num_of_speech;
-    // TODO(bjornv): Change to |age_vector|.
-    int16_t index_vector[16 * kNumChannels];
-    int16_t low_value_vector[16 * kNumChannels];
-    // TODO(bjornv): Change to |median|.
-    int16_t mean_value[kNumChannels];
-    int16_t upper_state[5];
-    int16_t lower_state[5];
-    int16_t hp_filter_state[4];
-    int16_t over_hang_max_1[3];
-    int16_t over_hang_max_2[3];
-    int16_t individual[3];
-    int16_t total[3];
+  int vad;
+  int32_t downsampling_filter_states[4];
+  WebRtcSpl_State48khzTo8khz state_48_to_8;
+  int16_t noise_means[kTableSize];
+  int16_t speech_means[kTableSize];
+  int16_t noise_stds[kTableSize];
+  int16_t speech_stds[kTableSize];
+  // TODO(bjornv): Change to |frame_count|.
+  int32_t frame_counter;
+  int16_t over_hang;  // Over Hang
+  int16_t num_of_speech;
+  // TODO(bjornv): Change to |age_vector|.
+  int16_t index_vector[16 * kNumChannels];
+  int16_t low_value_vector[16 * kNumChannels];
+  // TODO(bjornv): Change to |median|.
+  int16_t mean_value[kNumChannels];
+  int16_t upper_state[5];
+  int16_t lower_state[5];
+  int16_t hp_filter_state[4];
+  int16_t over_hang_max_1[3];
+  int16_t over_hang_max_2[3];
+  int16_t individual[3];
+  int16_t total[3];
 
-    int init_flag;
+  int init_flag;
 } VadInstT;
 
 // Initializes the core VAD component. The default aggressiveness mode is
@@ -100,13 +99,17 @@
  *                        0 - No active speech
  *                        1-6 - Active speech
  */
-int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad48khz(VadInstT* inst,
+                           const int16_t* speech_frame,
                            size_t frame_length);
-int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad32khz(VadInstT* inst,
+                           const int16_t* speech_frame,
                            size_t frame_length);
-int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad16khz(VadInstT* inst,
+                           const int16_t* speech_frame,
                            size_t frame_length);
-int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad8khz(VadInstT* inst,
+                          const int16_t* speech_frame,
                           size_t frame_length);
 
 #endif  // COMMON_AUDIO_VAD_VAD_CORE_H_
diff --git a/common_audio/vad/vad_filterbank.h b/common_audio/vad/vad_filterbank.h
index 620f96a..60b785b 100644
--- a/common_audio/vad/vad_filterbank.h
+++ b/common_audio/vad/vad_filterbank.h
@@ -38,7 +38,9 @@
 // - features     [o]   : 10 * log10(energy in each frequency band), Q4.
 // - returns            : Total energy of the signal (NOTE! This value is not
 //                        exact. It is only used in a comparison.)
-int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
-                                    size_t data_length, int16_t* features);
+int16_t WebRtcVad_CalculateFeatures(VadInstT* self,
+                                    const int16_t* data_in,
+                                    size_t data_length,
+                                    int16_t* features);
 
 #endif  // COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
diff --git a/common_audio/vad/vad_filterbank_unittest.cc b/common_audio/vad/vad_filterbank_unittest.cc
index 55b1279..b800044 100644
--- a/common_audio/vad/vad_filterbank_unittest.cc
+++ b/common_audio/vad/vad_filterbank_unittest.cc
@@ -26,14 +26,12 @@
 
 TEST_F(VadTest, vad_filterbank) {
   VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT)));
-  static const int16_t kReference[kNumValidFrameLengths] = { 48, 11, 11 };
+  static const int16_t kReference[kNumValidFrameLengths] = {48, 11, 11};
   static const int16_t kFeatures[kNumValidFrameLengths * kNumChannels] = {
-      1213, 759, 587, 462, 434, 272,
-      1479, 1385, 1291, 1200, 1103, 1099,
-      1732, 1692, 1681, 1629, 1436, 1436
-  };
-  static const int16_t kOffsetVector[kNumChannels] = {
-      368, 368, 272, 176, 176, 176 };
+      1213, 759,  587,  462,  434,  272,  1479, 1385, 1291,
+      1200, 1103, 1099, 1732, 1692, 1681, 1629, 1436, 1436};
+  static const int16_t kOffsetVector[kNumChannels] = {368, 368, 272,
+                                                      176, 176, 176};
   int16_t features[kNumChannels];
 
   // Construct a speech signal that will trigger the VAD in all modes. It is
diff --git a/common_audio/vad/vad_sp.h b/common_audio/vad/vad_sp.h
index 21fed11..8586ccd 100644
--- a/common_audio/vad/vad_sp.h
+++ b/common_audio/vad/vad_sp.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 // This file includes specific signal processing tools used in vad_core.c.
 
 #ifndef COMMON_AUDIO_VAD_VAD_SP_H_
diff --git a/common_audio/vad/vad_sp_unittest.cc b/common_audio/vad/vad_sp_unittest.cc
index 7eb6794..ebe25cf 100644
--- a/common_audio/vad/vad_sp_unittest.cc
+++ b/common_audio/vad/vad_sp_unittest.cc
@@ -25,19 +25,17 @@
 TEST_F(VadTest, vad_sp) {
   VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT)));
   const size_t kMaxFrameLenSp = 960;  // Maximum frame length in this unittest.
-  int16_t zeros[kMaxFrameLenSp] = { 0 };
-  int32_t state[2] = { 0 };
+  int16_t zeros[kMaxFrameLenSp] = {0};
+  int32_t state[2] = {0};
   int16_t data_in[kMaxFrameLenSp];
   int16_t data_out[kMaxFrameLenSp];
 
   // We expect the first value to be 1600 as long as |frame_counter| is zero,
   // which is true for the first iteration.
   static const int16_t kReferenceMin[32] = {
-      1600, 720, 509, 512, 532, 552, 570, 588,
-       606, 624, 642, 659, 675, 691, 707, 723,
-      1600, 544, 502, 522, 542, 561, 579, 597,
-       615, 633, 651, 667, 683, 699, 715, 731
-  };
+      1600, 720, 509, 512, 532, 552,  570, 588, 606, 624, 642,
+      659,  675, 691, 707, 723, 1600, 544, 502, 522, 542, 561,
+      579,  597, 615, 633, 651, 667,  683, 699, 715, 731};
 
   // Construct a speech signal that will trigger the VAD in all modes. It is
   // known that (i * i) will wrap around, but that doesn't matter in this case.
diff --git a/common_audio/vad/vad_unittest.cc b/common_audio/vad/vad_unittest.cc
index f79678b..1cef8e9 100644
--- a/common_audio/vad/vad_unittest.cc
+++ b/common_audio/vad/vad_unittest.cc
@@ -60,7 +60,7 @@
   // combinations.
 
   VadInst* handle = WebRtcVad_Create();
-  int16_t zeros[kMaxFrameLength] = { 0 };
+  int16_t zeros[kMaxFrameLength] = {0};
 
   // Construct a speech signal that will trigger the VAD in all modes. It is
   // known that (i * i) will wrap around, but that doesn't matter in this case.
@@ -87,12 +87,10 @@
 
   // WebRtcVad_set_mode() invalid modes tests. Tries smallest supported value
   // minus one and largest supported value plus one.
-  EXPECT_EQ(-1, WebRtcVad_set_mode(handle,
-                                   WebRtcSpl_MinValueW32(kModes,
-                                                         kModesSize) - 1));
-  EXPECT_EQ(-1, WebRtcVad_set_mode(handle,
-                                   WebRtcSpl_MaxValueW32(kModes,
-                                                         kModesSize) + 1));
+  EXPECT_EQ(-1, WebRtcVad_set_mode(
+                    handle, WebRtcSpl_MinValueW32(kModes, kModesSize) - 1));
+  EXPECT_EQ(-1, WebRtcVad_set_mode(
+                    handle, WebRtcSpl_MaxValueW32(kModes, kModesSize) + 1));
 
   // WebRtcVad_Process() tests
   // nullptr as speech pointer
@@ -109,14 +107,10 @@
     for (size_t i = 0; i < kRatesSize; i++) {
       for (size_t j = 0; j < kFrameLengthsSize; j++) {
         if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) {
-          EXPECT_EQ(1, WebRtcVad_Process(handle,
-                                         kRates[i],
-                                         speech,
+          EXPECT_EQ(1, WebRtcVad_Process(handle, kRates[i], speech,
                                          kFrameLengths[j]));
         } else {
-          EXPECT_EQ(-1, WebRtcVad_Process(handle,
-                                          kRates[i],
-                                          speech,
+          EXPECT_EQ(-1, WebRtcVad_Process(handle, kRates[i], speech,
                                           kFrameLengths[j]));
         }
       }
@@ -130,22 +124,20 @@
   // This test verifies valid and invalid rate/frame_length combinations. We
   // loop through some sampling rates and frame lengths from negative values to
   // values larger than possible.
-  const int kRates[] = {
-    -8000, -4000, 0, 4000, 8000, 8001, 15999, 16000, 32000, 48000, 48001, 96000
-  };
+  const int kRates[] = {-8000, -4000, 0,     4000,  8000,  8001,
+                        15999, 16000, 32000, 48000, 48001, 96000};
 
-  const size_t kFrameLengths[] = {
-    0, 80, 81, 159, 160, 240, 320, 480, 640, 960, 1440, 2000
-  };
+  const size_t kFrameLengths[] = {0,   80,  81,  159, 160,  240,
+                                  320, 480, 640, 960, 1440, 2000};
 
   for (size_t i = 0; i < arraysize(kRates); i++) {
     for (size_t j = 0; j < arraysize(kFrameLengths); j++) {
       if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) {
-        EXPECT_EQ(0, WebRtcVad_ValidRateAndFrameLength(kRates[i],
-                                                       kFrameLengths[j]));
+        EXPECT_EQ(
+            0, WebRtcVad_ValidRateAndFrameLength(kRates[i], kFrameLengths[j]));
       } else {
-        EXPECT_EQ(-1, WebRtcVad_ValidRateAndFrameLength(kRates[i],
-                                                        kFrameLengths[j]));
+        EXPECT_EQ(
+            -1, WebRtcVad_ValidRateAndFrameLength(kRates[i], kFrameLengths[j]));
       }
     }
   }
diff --git a/common_audio/vad/vad_unittest.h b/common_audio/vad/vad_unittest.h
index f982f52..5521983 100644
--- a/common_audio/vad/vad_unittest.h
+++ b/common_audio/vad/vad_unittest.h
@@ -20,17 +20,17 @@
 namespace test {
 
 // Modes we support
-const int kModes[] = { 0, 1, 2, 3 };
+const int kModes[] = {0, 1, 2, 3};
 const size_t kModesSize = sizeof(kModes) / sizeof(*kModes);
 
 // Rates we support.
-const int kRates[] = { 8000, 12000, 16000, 24000, 32000, 48000 };
+const int kRates[] = {8000, 12000, 16000, 24000, 32000, 48000};
 const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates);
 
 // Frame lengths we support.
 const size_t kMaxFrameLength = 1440;
-const size_t kFrameLengths[] = { 80, 120, 160, 240, 320, 480, 640, 960,
-    kMaxFrameLength };
+const size_t kFrameLengths[] = {
+    80, 120, 160, 240, 320, 480, 640, 960, kMaxFrameLength};
 const size_t kFrameLengthsSize = sizeof(kFrameLengths) / sizeof(*kFrameLengths);
 
 }  // namespace test
@@ -39,8 +39,8 @@
 class VadTest : public ::testing::Test {
  protected:
   VadTest();
-  virtual void SetUp();
-  virtual void TearDown();
+  void SetUp() override;
+  void TearDown() override;
 
   // Returns true if the rate and frame length combination is valid.
   bool ValidRatesAndFrameLengths(int rate, size_t frame_length);
diff --git a/common_audio/wav_file.cc b/common_audio/wav_file.cc
index 1217e40..21b64a8 100644
--- a/common_audio/wav_file.cc
+++ b/common_audio/wav_file.cc
@@ -13,7 +13,6 @@
 #include <algorithm>
 #include <cstdio>
 #include <limits>
-#include <sstream>
 
 #include "common_audio/include/audio_util.h"
 #include "common_audio/wav_header.h"
@@ -31,7 +30,7 @@
 class ReadableWavFile : public ReadableWav {
  public:
   explicit ReadableWavFile(FILE* file) : file_(file) {}
-  virtual size_t Read(void* buf, size_t num_bytes) {
+  size_t Read(void* buf, size_t num_bytes) override {
     return fread(buf, 1, num_bytes, file_);
   }
 
@@ -39,14 +38,6 @@
   FILE* file_;
 };
 
-std::string WavFile::FormatAsString() const {
-  std::ostringstream s;
-  s << "Sample rate: " << sample_rate() << " Hz, Channels: " << num_channels()
-    << ", Duration: "
-    << (1.f * num_samples()) / (num_channels() * sample_rate()) << " s";
-  return s.str();
-}
-
 WavReader::WavReader(const std::string& filename)
     : WavReader(rtc::OpenPlatformFileReadOnly(filename)) {}
 
diff --git a/common_audio/wav_file.h b/common_audio/wav_file.h
index befe733..cbce59d 100644
--- a/common_audio/wav_file.h
+++ b/common_audio/wav_file.h
@@ -30,9 +30,6 @@
   virtual int sample_rate() const = 0;
   virtual size_t num_channels() const = 0;
   virtual size_t num_samples() const = 0;
-
-  // Returns a human-readable string containing the audio format.
-  std::string FormatAsString() const;
 };
 
 // Simple C++ class for writing 16-bit PCM WAV files. All error handling is
@@ -63,7 +60,7 @@
   const int sample_rate_;
   const size_t num_channels_;
   size_t num_samples_;  // Total number of samples written to file.
-  FILE* file_handle_;  // Output file, owned by this class
+  FILE* file_handle_;   // Output file, owned by this class
 
   RTC_DISALLOW_COPY_AND_ASSIGN(WavWriter);
 };
diff --git a/common_audio/wav_file_unittest.cc b/common_audio/wav_file_unittest.cc
index 248273b..d40229a 100644
--- a/common_audio/wav_file_unittest.cc
+++ b/common_audio/wav_file_unittest.cc
@@ -19,12 +19,22 @@
 #include "test/gtest.h"
 #include "test/testsupport/fileutils.h"
 
+// WavWriterTest.CPPFileDescriptor and WavWriterTest.CPP flaky on Mac.
+// See webrtc:9247.
+#if defined(WEBRTC_MAC)
+#define MAYBE_CPP DISABLED_CPP
+#define MAYBE_CPPFileDescriptor DISABLED_CPPFileDescriptor
+#else
+#define MAYBE_CPP CPP
+#define MAYBE_CPPFileDescriptor CPPFileDescriptor
+#endif
+
 namespace webrtc {
 
 static const float kSamples[] = {0.0, 10.0, 4e4, -1e9};
 
 // Write a tiny WAV file with the C++ interface and verify the result.
-TEST(WavWriterTest, CPP) {
+TEST(WavWriterTest, MAYBE_CPP) {
   const std::string outfile = test::OutputPath() + "wavtest1.wav";
   static const size_t kNumSamples = 3;
   {
@@ -46,6 +56,8 @@
     fclose(f);
   }
   static const uint8_t kExpectedContents[] = {
+      // clang-format off
+      // clang formatting doesn't respect inline comments.
     'R', 'I', 'F', 'F',
     42, 0, 0, 0,  // size of whole file - 8: 6 + 44 - 8
     'W', 'A', 'V', 'E',
@@ -63,6 +75,7 @@
     10, 0,  // second sample: 10.0
     0xff, 0x7f,  // third sample: 4e4 (saturated)
     kMetadata[0], kMetadata[1],
+      // clang-format on
   };
   static const size_t kContentSize =
       kWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata);
@@ -102,6 +115,8 @@
   EXPECT_EQ(kNumSamples, rtc_WavNumSamples(w));
   rtc_WavClose(w);
   static const uint8_t kExpectedContents[] = {
+      // clang-format off
+      // clang formatting doesn't respect inline comments.
     'R', 'I', 'F', 'F',
     44, 0, 0, 0,  // size of whole file - 8: 8 + 44 - 8
     'W', 'A', 'V', 'E',
@@ -119,6 +134,7 @@
     10, 0,  // second sample: 10.0
     0xff, 0x7f,  // third sample: 4e4 (saturated)
     0, 0x80,  // fourth sample: -1e9 (saturated)
+      // clang-format on
   };
   static const size_t kContentSize =
       kWavHeaderSize + kNumSamples * sizeof(int16_t);
@@ -176,7 +192,7 @@
 
 // Write a tiny WAV file with the the std::FILE interface and verify the
 // result.
-TEST(WavWriterTest, CPPFileDescriptor) {
+TEST(WavWriterTest, MAYBE_CPPFileDescriptor) {
   const std::string outfile = test::OutputPath() + "wavtest1.wav";
   static constexpr size_t kNumSamples = 3;
   {
@@ -199,6 +215,7 @@
   }
   static const uint8_t kExpectedContents[] = {
       // clang-format off
+      // clang formatting doesn't respect inline comments.
     'R', 'I', 'F', 'F',
     42, 0, 0, 0,       // size of whole file - 8: 6 + 44 - 8
     'W', 'A', 'V', 'E',
diff --git a/common_audio/wav_header.cc b/common_audio/wav_header.cc
index a57e917..d093fa0 100644
--- a/common_audio/wav_header.cc
+++ b/common_audio/wav_header.cc
@@ -112,17 +112,23 @@
 }
 
 #ifdef WEBRTC_ARCH_LITTLE_ENDIAN
-static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; }
-static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; }
+static inline void WriteLE16(uint16_t* f, uint16_t x) {
+  *f = x;
+}
+static inline void WriteLE32(uint32_t* f, uint32_t x) {
+  *f = x;
+}
 static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
-  *f = static_cast<uint32_t>(a)
-      | static_cast<uint32_t>(b) << 8
-      | static_cast<uint32_t>(c) << 16
-      | static_cast<uint32_t>(d) << 24;
+  *f = static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 |
+       static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24;
 }
 
-static inline uint16_t ReadLE16(uint16_t x) { return x; }
-static inline uint32_t ReadLE32(uint32_t x) { return x; }
+static inline uint16_t ReadLE16(uint16_t x) {
+  return x;
+}
+static inline uint32_t ReadLE32(uint32_t x) {
+  return x;
+}
 static inline std::string ReadFourCC(uint32_t x) {
   return std::string(reinterpret_cast<char*>(&x), 4);
 }
@@ -131,11 +137,12 @@
 #endif
 
 static inline uint32_t RiffChunkSize(size_t bytes_in_payload) {
-  return static_cast<uint32_t>(
-      bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader));
+  return static_cast<uint32_t>(bytes_in_payload + kWavHeaderSize -
+                               sizeof(ChunkHeader));
 }
 
-static inline uint32_t ByteRate(size_t num_channels, int sample_rate,
+static inline uint32_t ByteRate(size_t num_channels,
+                                int sample_rate,
                                 size_t bytes_per_sample) {
   return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample);
 }
@@ -166,8 +173,8 @@
   WriteLE16(&header.fmt.AudioFormat, format);
   WriteLE16(&header.fmt.NumChannels, static_cast<uint16_t>(num_channels));
   WriteLE32(&header.fmt.SampleRate, sample_rate);
-  WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
-                                           bytes_per_sample));
+  WriteLE32(&header.fmt.ByteRate,
+            ByteRate(num_channels, sample_rate, bytes_per_sample));
   WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
   WriteLE16(&header.fmt.BitsPerSample,
             static_cast<uint16_t>(8 * bytes_per_sample));
@@ -239,5 +246,4 @@
                             *bytes_per_sample, *num_samples);
 }
 
-
 }  // namespace webrtc
diff --git a/common_audio/wav_header.h b/common_audio/wav_header.h
index 2295fbe..872d3ab 100644
--- a/common_audio/wav_header.h
+++ b/common_audio/wav_header.h
@@ -26,8 +26,8 @@
 };
 
 enum WavFormat {
-  kWavFormatPcm   = 1,  // PCM, each sample of size bytes_per_sample
-  kWavFormatALaw  = 6,  // 8-bit ITU-T G.711 A-law
+  kWavFormatPcm = 1,    // PCM, each sample of size bytes_per_sample
+  kWavFormatALaw = 6,   // 8-bit ITU-T G.711 A-law
   kWavFormatMuLaw = 7,  // 8-bit ITU-T G.711 mu-law
 };
 
diff --git a/common_audio/wav_header_unittest.cc b/common_audio/wav_header_unittest.cc
index 8b30530..b7169b5 100644
--- a/common_audio/wav_header_unittest.cc
+++ b/common_audio/wav_header_unittest.cc
@@ -32,13 +32,13 @@
         buf_exhausted_(false),
         check_read_size_(check_read_size) {}
 
-  virtual ~ReadableWavBuffer() {
+  ~ReadableWavBuffer() override {
     // Verify the entire buffer has been read.
     if (check_read_size_)
       EXPECT_EQ(size_, pos_);
   }
 
-  virtual size_t Read(void* buf, size_t num_bytes) {
+  size_t Read(void* buf, size_t num_bytes) override {
     // Verify we don't try to read outside of a properly sized header.
     if (size_ >= kWavHeaderSize)
       EXPECT_GE(size_, pos_ + num_bytes);
@@ -84,8 +84,8 @@
 
   // Too large values.
   EXPECT_FALSE(CheckWavParameters(1 << 20, 1 << 20, kWavFormatPcm, 1, 0));
-  EXPECT_FALSE(CheckWavParameters(
-      1, 8000, kWavFormatPcm, 1, std::numeric_limits<uint32_t>::max()));
+  EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 1,
+                                  std::numeric_limits<uint32_t>::max()));
 
   // Not the same number of samples for each channel.
   EXPECT_FALSE(CheckWavParameters(3, 8000, kWavFormatPcm, 1, 5));
@@ -104,6 +104,8 @@
   // *BAD*.
   {
     static const uint8_t kBadRiffID[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'i', 'f', 'f',  // *BAD*
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
@@ -117,14 +119,16 @@
       8, 0,  // bits per sample: 1 * 8
       'd', 'a', 't', 'a',
       0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+        // clang-format on
     };
     ReadableWavBuffer r(kBadRiffID, sizeof(kBadRiffID));
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
   {
     static const uint8_t kBadBitsPerSample[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'I', 'F', 'F',
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
@@ -138,14 +142,16 @@
       1, 0,  // bits per sample: *BAD*
       'd', 'a', 't', 'a',
       0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+        // clang-format on
     };
     ReadableWavBuffer r(kBadBitsPerSample, sizeof(kBadBitsPerSample));
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
   {
     static const uint8_t kBadByteRate[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'I', 'F', 'F',
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
@@ -159,14 +165,16 @@
       8, 0,  // bits per sample: 1 * 8
       'd', 'a', 't', 'a',
       0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+        // clang-format on
     };
     ReadableWavBuffer r(kBadByteRate, sizeof(kBadByteRate));
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
   {
     static const uint8_t kBadFmtHeaderSize[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'I', 'F', 'F',
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
@@ -181,14 +189,16 @@
       0,  // extra (though invalid) header byte
       'd', 'a', 't', 'a',
       0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+        // clang-format on
     };
     ReadableWavBuffer r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), false);
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
   {
     static const uint8_t kNonZeroExtensionField[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'I', 'F', 'F',
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
@@ -203,15 +213,17 @@
       1, 0,  // non-zero extension field *BAD*
       'd', 'a', 't', 'a',
       0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+        // clang-format on
     };
     ReadableWavBuffer r(kNonZeroExtensionField, sizeof(kNonZeroExtensionField),
                         false);
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
   {
     static const uint8_t kMissingDataChunk[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'I', 'F', 'F',
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
@@ -223,23 +235,25 @@
       0xc9, 0x33, 0x03, 0,  // byte rate: 1 * 17 * 12345
       17, 0,  // block align: NumChannels * BytesPerSample
       8, 0,  // bits per sample: 1 * 8
+        // clang-format on
     };
     ReadableWavBuffer r(kMissingDataChunk, sizeof(kMissingDataChunk));
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
   {
     static const uint8_t kMissingFmtAndDataChunks[] = {
+        // clang-format off
+        // clang formatting doesn't respect inline comments.
       'R', 'I', 'F', 'F',
       0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
       'W', 'A', 'V', 'E',
+        // clang-format on
     };
     ReadableWavBuffer r(kMissingFmtAndDataChunks,
                         sizeof(kMissingFmtAndDataChunks));
-    EXPECT_FALSE(
-        ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                      &bytes_per_sample, &num_samples));
+    EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                               &bytes_per_sample, &num_samples));
   }
 }
 
@@ -250,6 +264,8 @@
   memset(buf, 0xa4, sizeof(buf));
   WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689);
   static const uint8_t kExpectedBuf[] = {
+      // clang-format off
+      // clang formatting doesn't respect inline comments.
     0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes before header
     'R', 'I', 'F', 'F',
     0xbd, 0xd0, 0x5b, 0x07,  // size of whole file - 8: 123457689 + 44 - 8
@@ -265,6 +281,7 @@
     'd', 'a', 't', 'a',
     0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
     0xa4, 0xa4, 0xa4, 0xa4,  // untouched bytes after header
+      // clang-format on
   };
   static_assert(sizeof(kExpectedBuf) == kSize, "buffer size");
   EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
@@ -275,9 +292,8 @@
   size_t bytes_per_sample = 0;
   size_t num_samples = 0;
   ReadableWavBuffer r(buf + 4, sizeof(buf) - 8);
-  EXPECT_TRUE(
-      ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                    &bytes_per_sample, &num_samples));
+  EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                            &bytes_per_sample, &num_samples));
   EXPECT_EQ(17u, num_channels);
   EXPECT_EQ(12345, sample_rate);
   EXPECT_EQ(kWavFormatALaw, format);
@@ -288,6 +304,8 @@
 // Try reading an atypical but valid WAV header and make sure it's parsed OK.
 TEST(WavHeaderTest, ReadAtypicalWavHeader) {
   static const uint8_t kBuf[] = {
+      // clang-format off
+      // clang formatting doesn't respect inline comments.
     'R', 'I', 'F', 'F',
     0x3d, 0xd1, 0x5b, 0x07,  // size of whole file - 8 + an extra 128 bytes of
                              // "metadata": 123457689 + 44 - 8 + 128. (atypical)
@@ -303,6 +321,7 @@
     0, 0,  // zero extension size field (atypical)
     'd', 'a', 't', 'a',
     0x99, 0xd0, 0x5b, 0x07,  // size of payload: 123457689
+      // clang-format on
   };
 
   size_t num_channels = 0;
@@ -311,9 +330,8 @@
   size_t bytes_per_sample = 0;
   size_t num_samples = 0;
   ReadableWavBuffer r(kBuf, sizeof(kBuf));
-  EXPECT_TRUE(
-      ReadWavHeader(&r, &num_channels, &sample_rate, &format,
-                    &bytes_per_sample, &num_samples));
+  EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+                            &bytes_per_sample, &num_samples));
   EXPECT_EQ(17u, num_channels);
   EXPECT_EQ(12345, sample_rate);
   EXPECT_EQ(kWavFormatALaw, format);
diff --git a/common_audio/window_generator.cc b/common_audio/window_generator.cc
index 823d2b7..da5603d 100644
--- a/common_audio/window_generator.cc
+++ b/common_audio/window_generator.cc
@@ -25,12 +25,11 @@
 complex<float> I0(complex<float> x) {
   complex<float> y = x / 3.75f;
   y *= y;
-  return 1.0f + y * (
-    3.5156229f + y * (
-      3.0899424f + y * (
-        1.2067492f + y * (
-          0.2659732f + y * (
-            0.360768e-1f + y * 0.45813e-2f)))));
+  return 1.0f + y * (3.5156229f +
+                     y * (3.0899424f +
+                          y * (1.2067492f +
+                               y * (0.2659732f +
+                                    y * (0.360768e-1f + y * 0.45813e-2f)))));
 }
 
 }  // namespace
@@ -41,12 +40,13 @@
   RTC_CHECK_GT(length, 1);
   RTC_CHECK(window != nullptr);
   for (int i = 0; i < length; ++i) {
-    window[i] = 0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i /
-                                 (length - 1)));
+    window[i] =
+        0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i / (length - 1)));
   }
 }
 
-void WindowGenerator::KaiserBesselDerived(float alpha, size_t length,
+void WindowGenerator::KaiserBesselDerived(float alpha,
+                                          size_t length,
                                           float* window) {
   RTC_CHECK_GT(length, 1U);
   RTC_CHECK(window != nullptr);
@@ -69,4 +69,3 @@
 }
 
 }  // namespace webrtc
-
diff --git a/common_audio/window_generator.h b/common_audio/window_generator.h
index 5fc738e..ad3b445 100644
--- a/common_audio/window_generator.h
+++ b/common_audio/window_generator.h
@@ -30,4 +30,3 @@
 }  // namespace webrtc
 
 #endif  // COMMON_AUDIO_WINDOW_GENERATOR_H_
-
diff --git a/common_audio/window_generator_unittest.cc b/common_audio/window_generator_unittest.cc
index b2089d4..cf33932 100644
--- a/common_audio/window_generator_unittest.cc
+++ b/common_audio/window_generator_unittest.cc
@@ -89,4 +89,3 @@
 }
 
 }  // namespace webrtc
-
diff --git a/common_types.h b/common_types.h
index f717094..919a947 100644
--- a/common_types.h
+++ b/common_types.h
@@ -17,7 +17,6 @@
 #include <vector>
 
 #include "api/array_view.h"
-#include "api/optional.h"
 // TODO(sprang): Remove this include when all usage includes it directly.
 #include "api/video/video_bitrate_allocation.h"
 #include "rtc_base/checks.h"
@@ -30,10 +29,6 @@
 #pragma warning(disable : 4351)
 #endif
 
-#ifndef NULL
-#define NULL 0
-#endif
-
 #define RTP_PAYLOAD_NAME_SIZE 32u
 
 #if defined(WEBRTC_WIN) || defined(WIN32)
@@ -300,7 +295,7 @@
   int decoded_normal;  // Number of calls where audio RTP packet decoded.
   int decoded_plc;     // Number of calls resulted in PLC.
   int decoded_cng;  // Number of calls where comfort noise generated due to DTX.
-  int decoded_plc_cng;  // Number of calls resulted where PLC faded to CNG.
+  int decoded_plc_cng;       // Number of calls resulted where PLC faded to CNG.
   int decoded_muted_output;  // Number of calls returning a muted state output.
 };
 
@@ -329,55 +324,6 @@
   kBGRA,
 };
 
-// Video codec
-enum VideoCodecComplexity {
-  kComplexityNormal = 0,
-  kComplexityHigh = 1,
-  kComplexityHigher = 2,
-  kComplexityMax = 3
-};
-
-// VP8 specific
-struct VideoCodecVP8 {
-  bool operator==(const VideoCodecVP8& other) const;
-  bool operator!=(const VideoCodecVP8& other) const {
-    return !(*this == other);
-  }
-  VideoCodecComplexity complexity;
-  unsigned char numberOfTemporalLayers;
-  bool denoisingOn;
-  bool automaticResizeOn;
-  bool frameDroppingOn;
-  int keyFrameInterval;
-};
-
-enum class InterLayerPredMode {
-  kOn,       // Allow inter-layer prediction for all frames.
-             // Frame of low spatial layer can be used for
-             // prediction of next spatial layer frame.
-  kOff,      // Encoder produces independent spatial layers.
-  kOnKeyPic  // Allow inter-layer prediction only for frames
-             // within key picture.
-};
-
-// VP9 specific.
-struct VideoCodecVP9 {
-  bool operator==(const VideoCodecVP9& other) const;
-  bool operator!=(const VideoCodecVP9& other) const {
-    return !(*this == other);
-  }
-  VideoCodecComplexity complexity;
-  unsigned char numberOfTemporalLayers;
-  bool denoisingOn;
-  bool frameDroppingOn;
-  int keyFrameInterval;
-  bool adaptiveQpMode;
-  bool automaticResizeOn;
-  unsigned char numberOfSpatialLayers;
-  bool flexibleMode;
-  InterLayerPredMode interLayerPred;
-};
-
 // TODO(magjed): Move this and other H264 related classes out to their own file.
 namespace H264 {
 
@@ -391,46 +337,30 @@
 
 }  // namespace H264
 
-// H264 specific.
-struct VideoCodecH264 {
-  bool operator==(const VideoCodecH264& other) const;
-  bool operator!=(const VideoCodecH264& other) const {
-    return !(*this == other);
-  }
-  bool frameDroppingOn;
-  int keyFrameInterval;
-  // These are NULL/0 if not externally negotiated.
-  const uint8_t* spsData;
-  size_t spsLen;
-  const uint8_t* ppsData;
-  size_t ppsLen;
-  H264::Profile profile;
-};
-
 // Video codec types
 enum VideoCodecType {
+  // There are various memset(..., 0, ...) calls in the code that rely on
+  // kVideoCodecUnknown being zero.
+  kVideoCodecUnknown = 0,
   kVideoCodecVP8,
   kVideoCodecVP9,
   kVideoCodecH264,
   kVideoCodecI420,
-  kVideoCodecRED,
-  kVideoCodecULPFEC,
-  kVideoCodecFlexfec,
   kVideoCodecGeneric,
   kVideoCodecMultiplex,
-  kVideoCodecUnknown
+
+  // TODO(nisse): Deprecated aliases, for code expecting RtpVideoCodecTypes.
+  kRtpVideoNone = kVideoCodecUnknown,
+  kRtpVideoGeneric = kVideoCodecGeneric,
+  kRtpVideoVp8 = kVideoCodecVP8,
+  kRtpVideoVp9 = kVideoCodecVP9,
+  kRtpVideoH264 = kVideoCodecH264,
 };
 
 // Translates from name of codec to codec type and vice versa.
 const char* CodecTypeToPayloadString(VideoCodecType type);
 VideoCodecType PayloadStringToCodecType(const std::string& name);
 
-union VideoCodecUnion {
-  VideoCodecVP8 VP8;
-  VideoCodecVP9 VP9;
-  VideoCodecH264 H264;
-};
-
 struct SpatialLayer {
   bool operator==(const SpatialLayer& other) const;
   bool operator!=(const SpatialLayer& other) const { return !(*this == other); }
@@ -449,72 +379,6 @@
 // settings such as resolution.
 typedef SpatialLayer SimulcastStream;
 
-enum VideoCodecMode { kRealtimeVideo, kScreensharing };
-
-// Common video codec properties
-class VideoCodec {
- public:
-  VideoCodec();
-
-  // Public variables. TODO(hta): Make them private with accessors.
-  VideoCodecType codecType;
-  unsigned char plType;
-
-  unsigned short width;
-  unsigned short height;
-
-  unsigned int startBitrate;   // kilobits/sec.
-  unsigned int maxBitrate;     // kilobits/sec.
-  unsigned int minBitrate;     // kilobits/sec.
-  unsigned int targetBitrate;  // kilobits/sec.
-
-  uint32_t maxFramerate;
-
-  // This enables/disables encoding and sending when there aren't multiple
-  // simulcast streams,by allocating 0 bitrate if inactive.
-  bool active;
-
-  unsigned int qpMax;
-  unsigned char numberOfSimulcastStreams;
-  SimulcastStream simulcastStream[kMaxSimulcastStreams];
-  SpatialLayer spatialLayers[kMaxSpatialLayers];
-
-  VideoCodecMode mode;
-  bool expect_encode_from_texture;
-
-  // Timing frames configuration. There is delay of delay_ms between two
-  // consequent timing frames, excluding outliers. Frame is always made a
-  // timing frame if it's at least outlier_ratio in percent of "ideal" average
-  // frame given bitrate and framerate, i.e. if it's bigger than
-  // |outlier_ratio / 100.0 * bitrate_bps / fps| in bits. This way, timing
-  // frames will not be sent too often usually. Yet large frames will always
-  // have timing information for debug purposes because they are more likely to
-  // cause extra delays.
-  struct TimingFrameTriggerThresholds {
-    int64_t delay_ms;
-    uint16_t outlier_ratio_percent;
-  } timing_frame_thresholds;
-
-  bool operator==(const VideoCodec& other) const = delete;
-  bool operator!=(const VideoCodec& other) const = delete;
-
-  // Accessors for codec specific information.
-  // There is a const version of each that returns a reference,
-  // and a non-const version that returns a pointer, in order
-  // to allow modification of the parameters.
-  VideoCodecVP8* VP8();
-  const VideoCodecVP8& VP8() const;
-  VideoCodecVP9* VP9();
-  const VideoCodecVP9& VP9() const;
-  VideoCodecH264* H264();
-  const VideoCodecH264& H264() const;
-
- private:
-  // TODO(hta): Consider replacing the union with a pointer type.
-  // This will allow removing the VideoCodec* types from this file.
-  VideoCodecUnion codec_specific_;
-};
-
 // TODO(sprang): Remove this when downstream projects have been updated.
 using BitrateAllocation = VideoBitrateAllocation;
 
diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn
index 7dfe70b..82cde8e 100644
--- a/modules/audio_coding/BUILD.gn
+++ b/modules/audio_coding/BUILD.gn
@@ -8,7 +8,6 @@
 
 import("../../webrtc.gni")
 import("audio_coding.gni")
-import("//build/config/arm.gni")
 if (!build_with_mozilla) {
   import("//third_party/protobuf/proto_library.gni")
 }
@@ -50,11 +49,11 @@
   deps = [
     "../..:webrtc_common",
     "../../api:array_view",
-    "../../api:optional",
     "../../api/audio_codecs:audio_codecs_api",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
     "../../rtc_base:sanitizer",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -70,7 +69,7 @@
            "../..:typedefs",
            "../../rtc_base:checks",
            "../../api:array_view",
-           "../../api:optional",
+           "//third_party/abseil-cpp/absl/types:optional",
            "../../api/audio_codecs:audio_codecs_api",
            "../..:webrtc_common",
            "../../rtc_base:protobuf_utils",
@@ -128,13 +127,6 @@
     ]
   }
 
-  if (is_win) {
-    cflags = [
-      # TODO(kjellander): Bug 261: fix this warning.
-      "/wd4373",  # virtual function override.
-    ]
-  }
-
   deps = audio_coding_deps + [
            "../../api/audio:audio_frame_api",
            "..:module_api",
@@ -150,7 +142,7 @@
            ":rent_a_codec",
            "../../rtc_base:audio_format_to_string",
            "../../rtc_base:rtc_base_approved",
-           "../../api:optional",
+           "//third_party/abseil-cpp/absl/types:optional",
            "../../logging:rtc_event_log_api",
          ]
   defines = audio_coding_defines
@@ -246,17 +238,24 @@
 rtc_source_set("g711_c") {
   poisonous = [ "audio_codecs" ]
   sources = [
-    "codecs/g711/g711.c",
-    "codecs/g711/g711.h",
     "codecs/g711/g711_interface.c",
     "codecs/g711/g711_interface.h",
   ]
   deps = [
+    ":g711_3p",
     "../..:typedefs",
     "../..:webrtc_common",
   ]
 }
 
+rtc_source_set("g711_3p") {
+  poisonous = [ "audio_codecs" ]
+  sources = [
+    "codecs/g711/g711.c",
+    "codecs/g711/g711.h",
+  ]
+}
+
 config("g722_config") {
   include_dirs = [ "codecs/g722/include" ]
 }
@@ -289,18 +288,25 @@
 rtc_source_set("g722_c") {
   poisonous = [ "audio_codecs" ]
   sources = [
-    "codecs/g722/g722_decode.c",
-    "codecs/g722/g722_enc_dec.h",
-    "codecs/g722/g722_encode.c",
     "codecs/g722/g722_interface.c",
     "codecs/g722/g722_interface.h",
   ]
   deps = [
+    ":g722_3p",
     "../..:typedefs",
     "../..:webrtc_common",
   ]
 }
 
+rtc_source_set("g722_3p") {
+  poisonous = [ "audio_codecs" ]
+  sources = [
+    "codecs/g722/g722_decode.c",
+    "codecs/g722/g722_enc_dec.h",
+    "codecs/g722/g722_encode.c",
+  ]
+}
+
 config("ilbc_config") {
   include_dirs = [ "codecs/ilbc/include" ]
 }
@@ -496,17 +502,17 @@
     "codecs/isac/audio_decoder_isac_t_impl.h",
     "codecs/isac/audio_encoder_isac_t.h",
     "codecs/isac/audio_encoder_isac_t_impl.h",
-    "codecs/isac/bandwidth_info.h",
     "codecs/isac/locked_bandwidth_info.cc",
     "codecs/isac/locked_bandwidth_info.h",
   ]
   deps = [
+    ":isac_bwinfo",
     "../..:typedefs",
     "../..:webrtc_common",
-    "../../api:optional",
     "../../api/audio_codecs:audio_codecs_api",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -533,6 +539,38 @@
   ]
 }
 
+rtc_source_set("isac_bwinfo") {
+  sources = [
+    "codecs/isac/bandwidth_info.h",
+  ]
+  deps = [
+    "../..:typedefs",
+  ]
+}
+
+rtc_source_set("isac_vad") {
+  visibility += webrtc_default_visibility
+  sources = [
+    "codecs/isac/main/source/filter_functions.c",
+    "codecs/isac/main/source/filter_functions.h",
+    "codecs/isac/main/source/isac_vad.c",
+    "codecs/isac/main/source/isac_vad.h",
+    "codecs/isac/main/source/os_specific_inline.h",
+    "codecs/isac/main/source/pitch_estimator.c",
+    "codecs/isac/main/source/pitch_estimator.h",
+    "codecs/isac/main/source/pitch_filter.c",
+    "codecs/isac/main/source/pitch_filter.h",
+    "codecs/isac/main/source/settings.h",
+    "codecs/isac/main/source/structs.h",
+  ]
+  deps = [
+    ":isac_bwinfo",
+    "../..:typedefs",
+    "../../rtc_base:compile_assert_c",
+    "../../rtc_base/system:ignore_warnings",
+  ]
+}
+
 rtc_static_library("isac_c") {
   poisonous = [ "audio_codecs" ]
   sources = [
@@ -553,11 +591,6 @@
     "codecs/isac/main/source/encode_lpc_swb.h",
     "codecs/isac/main/source/entropy_coding.c",
     "codecs/isac/main/source/entropy_coding.h",
-    "codecs/isac/main/source/fft.c",
-    "codecs/isac/main/source/fft.h",
-    "codecs/isac/main/source/filter_functions.c",
-    "codecs/isac/main/source/filterbank_tables.c",
-    "codecs/isac/main/source/filterbank_tables.h",
     "codecs/isac/main/source/filterbanks.c",
     "codecs/isac/main/source/intialize.c",
     "codecs/isac/main/source/isac.c",
@@ -573,18 +606,12 @@
     "codecs/isac/main/source/lpc_shape_swb16_tables.h",
     "codecs/isac/main/source/lpc_tables.c",
     "codecs/isac/main/source/lpc_tables.h",
-    "codecs/isac/main/source/os_specific_inline.h",
-    "codecs/isac/main/source/pitch_estimator.c",
-    "codecs/isac/main/source/pitch_estimator.h",
-    "codecs/isac/main/source/pitch_filter.c",
     "codecs/isac/main/source/pitch_gain_tables.c",
     "codecs/isac/main/source/pitch_gain_tables.h",
     "codecs/isac/main/source/pitch_lag_tables.c",
     "codecs/isac/main/source/pitch_lag_tables.h",
-    "codecs/isac/main/source/settings.h",
     "codecs/isac/main/source/spectrum_ar_model_tables.c",
     "codecs/isac/main/source/spectrum_ar_model_tables.h",
-    "codecs/isac/main/source/structs.h",
     "codecs/isac/main/source/transform.c",
   ]
 
@@ -595,7 +622,9 @@
   public_configs = [ ":isac_config" ]
 
   deps = [
-    ":isac_common",
+    ":fft",
+    ":isac_bwinfo",
+    ":isac_vad",
     "../..:typedefs",
     "../..:webrtc_common",
     "../../common_audio",
@@ -606,6 +635,17 @@
   ]
 }
 
+rtc_source_set("fft") {
+  poisonous = [ "audio_codecs" ]
+  sources = [
+    "codecs/isac/main/source/fft.c",
+    "codecs/isac/main/source/fft.h",
+  ]
+  deps = [
+    ":isac_vad",
+  ]
+}
+
 config("isac_fix_config") {
   include_dirs = [ "codecs/isac/fix/include" ]
 }
@@ -649,7 +689,7 @@
   ]
   public_configs = [ ":isac_fix_config" ]
   deps = [
-    ":isac_common",
+    ":isac_bwinfo",
     "../..:typedefs",
     "../../common_audio",
     "../../common_audio:common_audio_c",
@@ -718,6 +758,7 @@
   public_configs = [ ":isac_fix_config" ]
 
   deps = [
+    ":isac_bwinfo",
     ":isac_common",
     "../..:typedefs",
     "../..:webrtc_common",
@@ -867,7 +908,6 @@
   deps = [
     ":audio_network_adaptor",
     "../..:webrtc_common",
-    "../../api:optional",
     "../../api/audio_codecs:audio_codecs_api",
     "../../api/audio_codecs/opus:audio_encoder_opus_config",
     "../../common_audio",
@@ -876,6 +916,8 @@
     "../../rtc_base:rtc_numerics",
     "../../rtc_base:safe_minmax",
     "../../system_wrappers:field_trial_api",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
   public_deps = [
     ":webrtc_opus_c",
@@ -943,7 +985,7 @@
     "audio_network_adaptor/include/audio_network_adaptor_config.h",
   ]
   deps = [
-    "../../api:optional",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -982,7 +1024,6 @@
 
   deps = [
     "../..:webrtc_common",
-    "../../api:optional",
     "../../api/audio_codecs:audio_codecs_api",
     "../../common_audio",
     "../../logging:rtc_event_audio",
@@ -993,6 +1034,8 @@
     "../../rtc_base/system:file_wrapper",
     "../../system_wrappers",
     "../../system_wrappers:field_trial_api",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 
   if (rtc_enable_protobuf) {
@@ -1014,9 +1057,9 @@
     "neteq/neteq_decoder_enum.h",
   ]
   deps = [
-    "../../api:optional",
     "../../api/audio_codecs:audio_codecs_api",
     "../../rtc_base:rtc_base_approved",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -1039,10 +1082,6 @@
     "neteq/cross_correlation.h",
     "neteq/decision_logic.cc",
     "neteq/decision_logic.h",
-    "neteq/decision_logic_fax.cc",
-    "neteq/decision_logic_fax.h",
-    "neteq/decision_logic_normal.cc",
-    "neteq/decision_logic_normal.h",
     "neteq/decoder_database.cc",
     "neteq/decoder_database.h",
     "neteq/defines.h",
@@ -1104,7 +1143,6 @@
     "../..:typedefs",
     "../..:webrtc_common",
     "../../api:libjingle_peerconnection_api",
-    "../../api:optional",
     "../../api/audio:audio_frame_api",
     "../../api/audio_codecs:audio_codecs_api",
     "../../common_audio",
@@ -1118,6 +1156,7 @@
     "../../rtc_base/system:fallthrough",
     "../../system_wrappers:field_trial_api",
     "../../system_wrappers:metrics_api",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -1152,13 +1191,13 @@
     "../..:typedefs",
     "../..:webrtc_common",
     "../../api:libjingle_peerconnection_api",
-    "../../api:optional",
     "../../api/audio:audio_frame_api",
     "../../api/audio_codecs:audio_codecs_api",
     "../../api/audio_codecs:builtin_audio_decoder_factory",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
     "../rtp_rtcp",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -1171,6 +1210,8 @@
     "neteq/tools/audio_loop.h",
     "neteq/tools/constant_pcm_packet_source.cc",
     "neteq/tools/constant_pcm_packet_source.h",
+    "neteq/tools/neteq_packet_source_input.cc",
+    "neteq/tools/neteq_packet_source_input.h",
     "neteq/tools/output_audio_file.h",
     "neteq/tools/output_wav_file.h",
     "neteq/tools/rtp_file_source.cc",
@@ -1209,8 +1250,8 @@
 
   if (rtc_enable_protobuf) {
     sources += [
-      "neteq/tools/neteq_packet_source_input.cc",
-      "neteq/tools/neteq_packet_source_input.h",
+      "neteq/tools/neteq_event_log_input.cc",
+      "neteq/tools/neteq_event_log_input.h",
     ]
     deps += [ ":rtc_event_log_source" ]
   }
@@ -1245,12 +1286,12 @@
     "../..:typedefs",
     "../..:webrtc_common",
     "../../api:array_view",
-    "../../api:optional",
     "../../api/audio_codecs:audio_codecs_api",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
     "../rtp_rtcp",
     "../rtp_rtcp:rtp_rtcp_format",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 
   public_deps = [
@@ -1333,7 +1374,6 @@
       ":g711_test",
       ":g722_test",
       ":ilbc_test",
-      ":insert_packet_with_timing",
       ":isac_api_test",
       ":isac_fix_test",
       ":isac_switch_samprate_test",
@@ -1361,8 +1401,6 @@
 
     sources = [
       "test/ACMTest.h",
-      "test/APITest.cc",
-      "test/APITest.h",
       "test/Channel.cc",
       "test/Channel.h",
       "test/EncodeDecodeTest.cc",
@@ -1400,7 +1438,6 @@
       "..:module_api",
       "../..:typedefs",
       "../..:webrtc_common",
-      "../../api:optional",
       "../../api/audio:audio_frame_api",
       "../../api/audio_codecs:builtin_audio_decoder_factory",
       "../../rtc_base:checks",
@@ -1409,14 +1446,9 @@
       "../../system_wrappers",
       "../../test:fileutils",
       "../../test:test_support",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
     defines = audio_coding_defines
-    if (is_win) {
-      cflags = [
-        # TODO(kjellander): bugs.webrtc.org/261: Fix this warning.
-        "/wd4373",  # virtual function override.
-      ]
-    }
     if (!build_with_chromium && is_clang) {
       # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
       suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
@@ -1515,7 +1547,6 @@
       "..:module_api",
       "../..:typedefs",
       "../../:webrtc_common",
-      "../../api:optional",
       "../../api/audio:audio_frame_api",
       "../../api/audio_codecs:builtin_audio_decoder_factory",
       "../../rtc_base:checks",
@@ -1526,44 +1557,10 @@
       "../../test:test_support",
       "../rtp_rtcp",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
   }  # delay_test
 
-  rtc_executable("insert_packet_with_timing") {
-    testonly = true
-    sources = [
-      "test/Channel.cc",
-      "test/Channel.h",
-      "test/PCMFile.cc",
-      "test/PCMFile.h",
-      "test/insert_packet_with_timing.cc",
-    ]
-
-    if (!build_with_chromium && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-    }
-
-    deps = [
-      ":audio_coding",
-      ":audio_format_conversion",
-      "..:module_api",
-      "../..:typedefs",
-      "../../:webrtc_common",
-      "../../api:optional",
-      "../../api/audio:audio_frame_api",
-      "../../api/audio_codecs:builtin_audio_decoder_factory",
-      "../../rtc_base:checks",
-      "../../rtc_base:rtc_base_approved",
-      "../../system_wrappers",
-      "../../system_wrappers:system_wrappers_default",
-      "../../test:fileutils",
-      "../../test:test_support",
-      "../rtp_rtcp",
-      "//testing/gtest",
-    ]
-  }  # insert_packet_with_timing
-
   audio_decoder_unittests_resources =
       [ "../../resources/audio_coding/testfile32kHz.pcm" ]
 
@@ -1645,13 +1642,6 @@
         suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
       }
 
-      if (is_win) {
-        cflags = [
-          # TODO(kjellander): bugs.webrtc.org/261: Fix this warning.
-          "/wd4373",  # virtual function override.
-        ]
-      }
-
       deps += [
         ":neteq",
         ":neteq_test_tools",
@@ -1786,6 +1776,7 @@
     testonly = true
 
     deps = audio_coding_deps + [
+             "//third_party/abseil-cpp/absl/memory",
              "../..:typedefs",
              ":audio_coding",
              ":neteq_input_audio_tools",
@@ -1993,23 +1984,6 @@
     data = [
       "../../resources/speech_and_misc_wb.pcm",
     ]
-
-    if (is_win) {
-      cflags = [
-        # Disable warnings to enable Win64 build, issue 1323.
-        "/wd4267",  # size_t to int truncation
-      ]
-    }
-  }
-
-  config("isac_test_warnings_config") {
-    if (is_win && is_clang) {
-      cflags = [
-        # Disable warnings failing when compiling with Clang on Windows.
-        # https://bugs.chromium.org/p/webrtc/issues/detail?id=5366
-        "-Wno-format",
-      ]
-    }
   }
 
   rtc_source_set("isac_test_util") {
@@ -2038,8 +2012,6 @@
       ":isac_test_util",
       "../../rtc_base:rtc_base_approved",
     ]
-
-    configs += [ ":isac_test_warnings_config" ]
   }
 
   rtc_executable("g711_test") {
@@ -2278,6 +2250,7 @@
       "../../test:test_common",
       "../../test:test_support",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/memory",
     ]
 
     defines = audio_coding_defines
diff --git a/modules/audio_coding/acm2/acm_codec_database.cc b/modules/audio_coding/acm2/acm_codec_database.cc
index 4553b52..a322c95 100644
--- a/modules/audio_coding/acm2/acm_codec_database.cc
+++ b/modules/audio_coding/acm2/acm_codec_database.cc
@@ -42,7 +42,7 @@
       (rate == 13300)) {
     return true;
   } else if (((frame_size_samples == 160) || (frame_size_samples == 320)) &&
-      (rate == 15200)) {
+             (rate == 15200)) {
     return true;
   } else {
     return false;
@@ -62,55 +62,54 @@
 
 const CodecInst ACMCodecDB::database_[] = {
 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
-  {103, "ISAC", 16000, 480, 1, 32000},
-# if (defined(WEBRTC_CODEC_ISAC))
-  {104, "ISAC", 32000, 960, 1, 56000},
-# endif
+    {103, "ISAC", 16000, 480, 1, 32000},
+#if (defined(WEBRTC_CODEC_ISAC))
+    {104, "ISAC", 32000, 960, 1, 56000},
 #endif
-  // Mono
-  {107, "L16", 8000, 80, 1, 128000},
-  {108, "L16", 16000, 160, 1, 256000},
-  {109, "L16", 32000, 320, 1, 512000},
-  // Stereo
-  {111, "L16", 8000, 80, 2, 128000},
-  {112, "L16", 16000, 160, 2, 256000},
-  {113, "L16", 32000, 320, 2, 512000},
-  // G.711, PCM mu-law and A-law.
-  // Mono
-  {0, "PCMU", 8000, 160, 1, 64000},
-  {8, "PCMA", 8000, 160, 1, 64000},
-  // Stereo
-  {110, "PCMU", 8000, 160, 2, 64000},
-  {118, "PCMA", 8000, 160, 2, 64000},
+#endif
+    // Mono
+    {107, "L16", 8000, 80, 1, 128000},
+    {108, "L16", 16000, 160, 1, 256000},
+    {109, "L16", 32000, 320, 1, 512000},
+    // Stereo
+    {111, "L16", 8000, 80, 2, 128000},
+    {112, "L16", 16000, 160, 2, 256000},
+    {113, "L16", 32000, 320, 2, 512000},
+    // G.711, PCM mu-law and A-law.
+    // Mono
+    {0, "PCMU", 8000, 160, 1, 64000},
+    {8, "PCMA", 8000, 160, 1, 64000},
+    // Stereo
+    {110, "PCMU", 8000, 160, 2, 64000},
+    {118, "PCMA", 8000, 160, 2, 64000},
 #ifdef WEBRTC_CODEC_ILBC
-  {102, "ILBC", 8000, 240, 1, 13300},
+    {102, "ILBC", 8000, 240, 1, 13300},
 #endif
-  // Mono
-  {9, "G722", 16000, 320, 1, 64000},
-  // Stereo
-  {119, "G722", 16000, 320, 2, 64000},
+    // Mono
+    {9, "G722", 16000, 320, 1, 64000},
+    // Stereo
+    {119, "G722", 16000, 320, 2, 64000},
 #ifdef WEBRTC_CODEC_OPUS
-  // Opus internally supports 48, 24, 16, 12, 8 kHz.
-  // Mono and stereo.
-  {120, "opus", 48000, 960, 2, 64000},
+    // Opus internally supports 48, 24, 16, 12, 8 kHz.
+    // Mono and stereo.
+    {120, "opus", 48000, 960, 2, 64000},
 #endif
-  // Comfort noise for four different sampling frequencies.
-  {13, "CN", 8000, 240, 1, 0},
-  {98, "CN", 16000, 480, 1, 0},
-  {99, "CN", 32000, 960, 1, 0},
+    // Comfort noise for four different sampling frequencies.
+    {13, "CN", 8000, 240, 1, 0},
+    {98, "CN", 16000, 480, 1, 0},
+    {99, "CN", 32000, 960, 1, 0},
 #ifdef ENABLE_48000_HZ
-  {100, "CN", 48000, 1440, 1, 0},
+    {100, "CN", 48000, 1440, 1, 0},
 #endif
-  {106, "telephone-event", 8000, 240, 1, 0},
-  {114, "telephone-event", 16000, 240, 1, 0},
-  {115, "telephone-event", 32000, 240, 1, 0},
-  {116, "telephone-event", 48000, 240, 1, 0},
+    {106, "telephone-event", 8000, 240, 1, 0},
+    {114, "telephone-event", 16000, 240, 1, 0},
+    {115, "telephone-event", 32000, 240, 1, 0},
+    {116, "telephone-event", 48000, 240, 1, 0},
 #ifdef WEBRTC_CODEC_RED
-  {127, "red", 8000, 0, 1, 0},
+    {127, "red", 8000, 0, 1, 0},
 #endif
-  // To prevent compile errors due to trailing commas.
-  {-1, "Null", -1, -1, 0, -1}
-};
+    // To prevent compile errors due to trailing commas.
+    {-1, "Null", -1, -1, 0, -1}};
 
 // Create database with all codec settings at compile time.
 // Each entry needs the following parameters in the given order:
@@ -119,9 +118,9 @@
 const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = {
 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
     {2, {480, 960}, 0, 1},
-# if (defined(WEBRTC_CODEC_ISAC))
+#if (defined(WEBRTC_CODEC_ISAC))
     {1, {960}, 0, 1},
-# endif
+#endif
 #endif
     // Mono
     {4, {80, 160, 240, 320}, 0, 2},
@@ -146,9 +145,9 @@
     // Stereo
     {6, {160, 320, 480, 640, 800, 960}, 0, 2},
 #ifdef WEBRTC_CODEC_OPUS
-    // Opus supports frames shorter than 10ms,
-    // but it doesn't help us to use them.
-    // Mono and stereo.
+// Opus supports frames shorter than 10ms,
+// but it doesn't help us to use them.
+// Mono and stereo.
 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME
     {5, {480, 960, 1920, 2880, 5760}, 0, 2},
 #else
@@ -171,16 +170,15 @@
     {1, {0}, 0, 1},
 #endif
     // To prevent compile errors due to trailing commas.
-    {-1, {-1}, -1, 0}
-};
+    {-1, {-1}, -1, 0}};
 
 // Create a database of all NetEQ decoders at compile time.
 const NetEqDecoder ACMCodecDB::neteq_decoders_[] = {
 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
     NetEqDecoder::kDecoderISAC,
-# if (defined(WEBRTC_CODEC_ISAC))
+#if (defined(WEBRTC_CODEC_ISAC))
     NetEqDecoder::kDecoderISACswb,
-# endif
+#endif
 #endif
     // Mono
     NetEqDecoder::kDecoderPCM16B, NetEqDecoder::kDecoderPCM16Bwb,
@@ -210,10 +208,8 @@
 #ifdef ENABLE_48000_HZ
     NetEqDecoder::kDecoderCNGswb48kHz,
 #endif
-    NetEqDecoder::kDecoderAVT,
-    NetEqDecoder::kDecoderAVT16kHz,
-    NetEqDecoder::kDecoderAVT32kHz,
-    NetEqDecoder::kDecoderAVT48kHz,
+    NetEqDecoder::kDecoderAVT, NetEqDecoder::kDecoderAVT16kHz,
+    NetEqDecoder::kDecoderAVT32kHz, NetEqDecoder::kDecoderAVT48kHz,
 #ifdef WEBRTC_CODEC_RED
     NetEqDecoder::kDecoderRED,
 #endif
@@ -260,8 +256,7 @@
     int i;
     int packet_size_samples;
     for (i = 0; i < codec_settings_[codec_id].num_packet_sizes; i++) {
-      packet_size_samples =
-          codec_settings_[codec_id].packet_sizes_samples[i];
+      packet_size_samples = codec_settings_[codec_id].packet_sizes_samples[i];
       if (codec_inst.pacsize == packet_size_samples) {
         packet_size_ok = true;
         break;
@@ -282,11 +277,10 @@
   if (STR_CASE_CMP("isac", codec_inst.plname) == 0) {
     return IsISACRateValid(codec_inst.rate) ? codec_id : kInvalidRate;
   } else if (STR_CASE_CMP("ilbc", codec_inst.plname) == 0) {
-    return IsILBCRateValid(codec_inst.rate, codec_inst.pacsize)
-        ? codec_id : kInvalidRate;
+    return IsILBCRateValid(codec_inst.rate, codec_inst.pacsize) ? codec_id
+                                                                : kInvalidRate;
   } else if (STR_CASE_CMP("opus", codec_inst.plname) == 0) {
-    return IsOpusRateValid(codec_inst.rate)
-        ? codec_id : kInvalidRate;
+    return IsOpusRateValid(codec_inst.rate) ? codec_id : kInvalidRate;
   }
 
   return database_[codec_id].rate == codec_inst.rate ? codec_id : kInvalidRate;
@@ -298,8 +292,7 @@
 // Does not check other codec settings, such as payload type and packet size.
 // Returns the id of the codec, or -1 if no match is found.
 int ACMCodecDB::CodecId(const CodecInst& codec_inst) {
-  return (CodecId(codec_inst.plname, codec_inst.plfreq,
-                  codec_inst.channels));
+  return (CodecId(codec_inst.plname, codec_inst.plfreq, codec_inst.channels));
 }
 
 int ACMCodecDB::CodecId(const char* payload_name,
diff --git a/modules/audio_coding/acm2/acm_codec_database.h b/modules/audio_coding/acm2/acm_codec_database.h
index 81cd4be..8b7c68a 100644
--- a/modules/audio_coding/acm2/acm_codec_database.h
+++ b/modules/audio_coding/acm2/acm_codec_database.h
@@ -31,7 +31,7 @@
   //                 build.
   // kMaxNumPacketSize - Maximum number of allowed packet sizes for one codec.
   // These might need to be increased if adding a new codec to the database
-  static const int kMaxNumCodecs =  50;
+  static const int kMaxNumCodecs = 50;
   static const int kMaxNumPacketSize = 6;
 
   // Codec specific settings
diff --git a/modules/audio_coding/acm2/acm_receive_test.cc b/modules/audio_coding/acm2/acm_receive_test.cc
index 473b651..ba8937e 100644
--- a/modules/audio_coding/acm2/acm_receive_test.cc
+++ b/modules/audio_coding/acm2/acm_receive_test.cc
@@ -156,8 +156,7 @@
       continue;
     }
 
-    if (RemapPltypeAndUseThisCodec(my_codec_param.plname,
-                                   my_codec_param.plfreq,
+    if (RemapPltypeAndUseThisCodec(my_codec_param.plname, my_codec_param.plfreq,
                                    my_codec_param.channels,
                                    &my_codec_param.pltype)) {
       ASSERT_EQ(true,
@@ -200,12 +199,10 @@
     WebRtcRTPHeader header;
     header.header = packet->header();
     header.frameType = kAudioFrameSpeech;
-    memset(&header.type.Audio, 0, sizeof(RTPAudioHeader));
     EXPECT_EQ(0,
               acm_->IncomingPacket(
                   packet->payload(),
-                  static_cast<int32_t>(packet->payload_length_bytes()),
-                  header))
+                  static_cast<int32_t>(packet->payload_length_bytes()), header))
         << "Failure when inserting packet:" << std::endl
         << "  PT = " << static_cast<int>(header.header.payloadType) << std::endl
         << "  TS = " << header.header.timestamp << std::endl
diff --git a/modules/audio_coding/acm2/acm_receive_test.h b/modules/audio_coding/acm2/acm_receive_test.h
index c7e7da6..83ffcb3 100644
--- a/modules/audio_coding/acm2/acm_receive_test.h
+++ b/modules/audio_coding/acm2/acm_receive_test.h
@@ -11,7 +11,7 @@
 #ifndef MODULES_AUDIO_CODING_ACM2_ACM_RECEIVE_TEST_H_
 #define MODULES_AUDIO_CODING_ACM2_ACM_RECEIVE_TEST_H_
 
-#include <stddef.h> // for size_t
+#include <stddef.h>  // for size_t
 #include <memory>
 #include <string>
 
diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc
index 41a23a7..0a88e70 100644
--- a/modules/audio_coding/acm2/acm_receiver.cc
+++ b/modules/audio_coding/acm2/acm_receiver.cc
@@ -40,7 +40,8 @@
       clock_(config.clock),
       resampled_last_output_frame_(true) {
   RTC_DCHECK(clock_);
-  memset(last_audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples);
+  memset(last_audio_buffer_.get(), 0,
+         sizeof(int16_t) * AudioFrame::kMaxDataSizeSamples);
 }
 
 AcmReceiver::~AcmReceiver() = default;
@@ -63,7 +64,7 @@
   return neteq_->LeastRequiredDelayMs();
 }
 
-rtc::Optional<int> AcmReceiver::last_packet_sample_rate_hz() const {
+absl::optional<int> AcmReceiver::last_packet_sample_rate_hz() const {
   rtc::CritScope lock(&crit_sect_);
   return last_packet_sample_rate_hz_;
 }
@@ -85,7 +86,7 @@
   {
     rtc::CritScope lock(&crit_sect_);
 
-    const rtc::Optional<CodecInst> ci =
+    const absl::optional<CodecInst> ci =
         RtpHeaderToDecoder(*header, incoming_payload[0]);
     if (!ci) {
       RTC_LOG_F(LS_ERROR) << "Payload-type "
@@ -201,15 +202,15 @@
   const auto neteq_decoder = [acm_codec_id, channels]() -> NetEqDecoder {
     if (acm_codec_id == -1)
       return NetEqDecoder::kDecoderArbitrary;  // External decoder.
-    const rtc::Optional<RentACodec::CodecId> cid =
+    const absl::optional<RentACodec::CodecId> cid =
         RentACodec::CodecIdFromIndex(acm_codec_id);
     RTC_DCHECK(cid) << "Invalid codec index: " << acm_codec_id;
-    const rtc::Optional<NetEqDecoder> ned =
+    const absl::optional<NetEqDecoder> ned =
         RentACodec::NetEqDecoderFromCodecId(*cid, channels);
     RTC_DCHECK(ned) << "Invalid codec ID: " << static_cast<int>(*cid);
     return *ned;
   }();
-  const rtc::Optional<SdpAudioFormat> new_format =
+  const absl::optional<SdpAudioFormat> new_format =
       NetEqDecoderToSdpAudioFormat(neteq_decoder);
 
   rtc::CritScope lock(&crit_sect_);
@@ -230,8 +231,8 @@
   if (!audio_decoder) {
     ret_val = neteq_->RegisterPayloadType(neteq_decoder, name, payload_type);
   } else {
-    ret_val = neteq_->RegisterExternalDecoder(
-        audio_decoder, neteq_decoder, name, payload_type);
+    ret_val = neteq_->RegisterExternalDecoder(audio_decoder, neteq_decoder,
+                                              name, payload_type);
   }
   if (ret_val != NetEq::kOK) {
     RTC_LOG(LERROR) << "AcmReceiver::AddCodec " << acm_codec_id
@@ -275,9 +276,9 @@
 void AcmReceiver::RemoveAllCodecs() {
   rtc::CritScope lock(&crit_sect_);
   neteq_->RemoveAllPayloadTypes();
-  last_audio_decoder_ = rtc::nullopt;
-  last_audio_format_ = rtc::nullopt;
-  last_packet_sample_rate_hz_ = rtc::nullopt;
+  last_audio_decoder_ = absl::nullopt;
+  last_audio_format_ = absl::nullopt;
+  last_packet_sample_rate_hz_ = absl::nullopt;
 }
 
 int AcmReceiver::RemoveCodec(uint8_t payload_type) {
@@ -288,14 +289,14 @@
     return -1;
   }
   if (last_audio_decoder_ && payload_type == last_audio_decoder_->pltype) {
-    last_audio_decoder_ = rtc::nullopt;
-    last_audio_format_ = rtc::nullopt;
-    last_packet_sample_rate_hz_ = rtc::nullopt;
+    last_audio_decoder_ = absl::nullopt;
+    last_audio_format_ = absl::nullopt;
+    last_packet_sample_rate_hz_ = absl::nullopt;
   }
   return 0;
 }
 
-rtc::Optional<uint32_t> AcmReceiver::GetPlayoutTimestamp() {
+absl::optional<uint32_t> AcmReceiver::GetPlayoutTimestamp() {
   return neteq_->GetPlayoutTimestamp();
 }
 
@@ -316,7 +317,7 @@
   return 0;
 }
 
-rtc::Optional<SdpAudioFormat> AcmReceiver::LastAudioFormat() const {
+absl::optional<SdpAudioFormat> AcmReceiver::LastAudioFormat() const {
   rtc::CritScope lock(&crit_sect_);
   return last_audio_format_;
 }
@@ -353,7 +354,7 @@
 int AcmReceiver::DecoderByPayloadType(uint8_t payload_type,
                                       CodecInst* codec) const {
   rtc::CritScope lock(&crit_sect_);
-  const rtc::Optional<CodecInst> ci = neteq_->GetDecoder(payload_type);
+  const absl::optional<CodecInst> ci = neteq_->GetDecoder(payload_type);
   if (ci) {
     *codec = *ci;
     return 0;
@@ -383,10 +384,10 @@
   // TODO(turajs): Should NetEq Buffer be flushed?
 }
 
-const rtc::Optional<CodecInst> AcmReceiver::RtpHeaderToDecoder(
+const absl::optional<CodecInst> AcmReceiver::RtpHeaderToDecoder(
     const RTPHeader& rtp_header,
     uint8_t first_payload_byte) const {
-  const rtc::Optional<CodecInst> ci =
+  const absl::optional<CodecInst> ci =
       neteq_->GetDecoder(rtp_header.payloadType);
   if (ci && STR_CASE_CMP(ci->plname, "red") == 0) {
     // This is a RED packet. Get the payload of the audio codec.
@@ -401,10 +402,9 @@
   // the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms.
   // We masked 6 most significant bits of 32-bit so there is no overflow in
   // the conversion from milliseconds to timestamp.
-  const uint32_t now_in_ms = static_cast<uint32_t>(
-      clock_->TimeInMilliseconds() & 0x03ffffff);
-  return static_cast<uint32_t>(
-      (decoder_sampling_rate / 1000) * now_in_ms);
+  const uint32_t now_in_ms =
+      static_cast<uint32_t>(clock_->TimeInMilliseconds() & 0x03ffffff);
+  return static_cast<uint32_t>((decoder_sampling_rate / 1000) * now_in_ms);
 }
 
 void AcmReceiver::GetDecodingCallStatistics(
diff --git a/modules/audio_coding/acm2/acm_receiver.h b/modules/audio_coding/acm2/acm_receiver.h
index ce1e1f2..c0afbb1 100644
--- a/modules/audio_coding/acm2/acm_receiver.h
+++ b/modules/audio_coding/acm2/acm_receiver.h
@@ -16,9 +16,9 @@
 #include <string>
 #include <vector>
 
-#include "api/audio/audio_frame.h"
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
+#include "api/audio/audio_frame.h"
 #include "common_audio/vad/include/webrtc_vad.h"
 #include "modules/audio_coding/acm2/acm_resampler.h"
 #include "modules/audio_coding/acm2/call_statistics.h"
@@ -159,7 +159,7 @@
   // packet. If no packet of a registered non-CNG codec has been received, the
   // return value is empty. Also, if the decoder was unregistered since the last
   // packet was inserted, the return value is empty.
-  rtc::Optional<int> last_packet_sample_rate_hz() const;
+  absl::optional<int> last_packet_sample_rate_hz() const;
 
   // Returns last_output_sample_rate_hz from the NetEq instance.
   int last_output_sample_rate_hz() const;
@@ -195,7 +195,7 @@
 
   // Returns the RTP timestamp for the last sample delivered by GetAudio().
   // The return value will be empty if no valid timestamp is available.
-  rtc::Optional<uint32_t> GetPlayoutTimestamp();
+  absl::optional<uint32_t> GetPlayoutTimestamp();
 
   // Returns the current total delay from NetEq (packet buffer and sync buffer)
   // in ms, with smoothing applied to even out short-time fluctuations due to
@@ -215,7 +215,7 @@
   //
   int LastAudioCodec(CodecInst* codec) const;
 
-  rtc::Optional<SdpAudioFormat> LastAudioFormat() const;
+  absl::optional<SdpAudioFormat> LastAudioFormat() const;
 
   //
   // Get a decoder given its registered payload-type.
@@ -273,22 +273,23 @@
     int sample_rate_hz;
   };
 
-  const rtc::Optional<CodecInst> RtpHeaderToDecoder(const RTPHeader& rtp_header,
-                                                    uint8_t first_payload_byte)
-      const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+  const absl::optional<CodecInst> RtpHeaderToDecoder(
+      const RTPHeader& rtp_header,
+      uint8_t first_payload_byte) const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
 
   uint32_t NowInTimestamp(int decoder_sampling_rate) const;
 
   rtc::CriticalSection crit_sect_;
-  rtc::Optional<CodecInst> last_audio_decoder_ RTC_GUARDED_BY(crit_sect_);
-  rtc::Optional<SdpAudioFormat> last_audio_format_ RTC_GUARDED_BY(crit_sect_);
+  absl::optional<CodecInst> last_audio_decoder_ RTC_GUARDED_BY(crit_sect_);
+  absl::optional<SdpAudioFormat> last_audio_format_ RTC_GUARDED_BY(crit_sect_);
   ACMResampler resampler_ RTC_GUARDED_BY(crit_sect_);
   std::unique_ptr<int16_t[]> last_audio_buffer_ RTC_GUARDED_BY(crit_sect_);
   CallStatistics call_stats_ RTC_GUARDED_BY(crit_sect_);
   const std::unique_ptr<NetEq> neteq_;  // NetEq is thread-safe; no lock needed.
   const Clock* const clock_;
   bool resampled_last_output_frame_ RTC_GUARDED_BY(crit_sect_);
-  rtc::Optional<int> last_packet_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_);
+  absl::optional<int> last_packet_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_);
 };
 
 }  // namespace acm2
diff --git a/modules/audio_coding/acm2/acm_receiver_unittest.cc b/modules/audio_coding/acm2/acm_receiver_unittest.cc
index 7877821..457ea1d 100644
--- a/modules/audio_coding/acm2/acm_receiver_unittest.cc
+++ b/modules/audio_coding/acm2/acm_receiver_unittest.cc
@@ -30,12 +30,11 @@
 namespace {
 
 bool CodecsEqual(const CodecInst& codec_a, const CodecInst& codec_b) {
-    if (strcmp(codec_a.plname, codec_b.plname) != 0 ||
-        codec_a.plfreq != codec_b.plfreq ||
-        codec_a.pltype != codec_b.pltype ||
-        codec_b.channels != codec_a.channels)
-      return false;
-    return true;
+  if (strcmp(codec_a.plname, codec_b.plname) != 0 ||
+      codec_a.plfreq != codec_b.plfreq || codec_a.pltype != codec_b.pltype ||
+      codec_b.channels != codec_a.channels)
+    return false;
+  return true;
 }
 
 struct CodecIdInst {
@@ -83,7 +82,6 @@
     rtp_header_.header.numCSRCs = 0;
     rtp_header_.header.payloadType = 0;
     rtp_header_.frameType = kAudioFrameSpeech;
-    rtp_header_.type.Audio.isCNG = false;
   }
 
   void TearDown() override {}
@@ -115,7 +113,7 @@
   }
 
   template <size_t N>
-  void AddSetOfCodecs(const RentACodec::CodecId(&ids)[N]) {
+  void AddSetOfCodecs(const RentACodec::CodecId (&ids)[N]) {
     for (auto id : ids) {
       const auto i = RentACodec::CodecIndexFromId(id);
       ASSERT_TRUE(i);
@@ -136,10 +134,6 @@
 
     rtp_header_.header.payloadType = payload_type;
     rtp_header_.frameType = frame_type;
-    if (frame_type == kAudioFrameSpeech)
-      rtp_header_.type.Audio.isCNG = false;
-    else
-      rtp_header_.type.Audio.isCNG = true;
     rtp_header_.header.timestamp = timestamp;
 
     int ret_val = receiver_->InsertPacket(
@@ -186,13 +180,13 @@
     CodecInst my_codec;
     if (n & 0x1) {
       // Codecs with odd index should match the reference.
-      EXPECT_EQ(0, receiver_->DecoderByPayloadType(codecs_[n].pltype,
-                                                   &my_codec));
+      EXPECT_EQ(0,
+                receiver_->DecoderByPayloadType(codecs_[n].pltype, &my_codec));
       EXPECT_TRUE(CodecsEqual(codecs_[n], my_codec));
     } else {
       // Codecs with even index are not registered.
-      EXPECT_EQ(-1, receiver_->DecoderByPayloadType(codecs_[n].pltype,
-                                                    &my_codec));
+      EXPECT_EQ(-1,
+                receiver_->DecoderByPayloadType(codecs_[n].pltype, &my_codec));
     }
   }
 }
@@ -298,7 +292,7 @@
 class AcmReceiverTestFaxModeOldApi : public AcmReceiverTestOldApi {
  protected:
   AcmReceiverTestFaxModeOldApi() {
-    config_.neteq_config.playout_mode = kPlayoutFax;
+    config_.neteq_config.for_test_no_time_stretching = true;
   }
 
   void RunVerifyAudioFrame(RentACodec::CodecId codec_id) {
@@ -307,7 +301,7 @@
     // timestamp increments predictable; in normal mode, NetEq may decide to do
     // accelerate or pre-emptive expand operations after some time, offsetting
     // the timestamp.
-    EXPECT_EQ(kPlayoutFax, config_.neteq_config.playout_mode);
+    EXPECT_TRUE(config_.neteq_config.for_test_no_time_stretching);
 
     const RentACodec::CodecId kCodecId[] = {codec_id};
     AddSetOfCodecs(kCodecId);
@@ -326,7 +320,8 @@
     // Expect the first output timestamp to be 5*fs/8000 samples before the
     // first inserted timestamp (because of NetEq's look-ahead). (This value is
     // defined in Expand::overlap_length_.)
-    uint32_t expected_output_ts = last_packet_send_timestamp_ -
+    uint32_t expected_output_ts =
+        last_packet_send_timestamp_ -
         rtc::CheckedDivExact(5 * output_sample_rate_hz, 8000);
 
     AudioFrame frame;
diff --git a/modules/audio_coding/acm2/acm_resampler.cc b/modules/audio_coding/acm2/acm_resampler.cc
index b97ced2..c0b2064 100644
--- a/modules/audio_coding/acm2/acm_resampler.cc
+++ b/modules/audio_coding/acm2/acm_resampler.cc
@@ -19,11 +19,9 @@
 namespace webrtc {
 namespace acm2 {
 
-ACMResampler::ACMResampler() {
-}
+ACMResampler::ACMResampler() {}
 
-ACMResampler::~ACMResampler() {
-}
+ACMResampler::~ACMResampler() {}
 
 int ACMResampler::Resample10Msec(const int16_t* in_audio,
                                  int in_freq_hz,
diff --git a/modules/audio_coding/acm2/acm_send_test.cc b/modules/audio_coding/acm2/acm_send_test.cc
index 09a6c80..b1a3e98 100644
--- a/modules/audio_coding/acm2/acm_send_test.cc
+++ b/modules/audio_coding/acm2/acm_send_test.cc
@@ -95,10 +95,9 @@
     RTC_CHECK(audio_source_->Read(input_block_size_samples_,
                                   input_frame_.mutable_data()));
     if (input_frame_.num_channels_ > 1) {
-      InputAudioFile::DuplicateInterleaved(input_frame_.data(),
-                                           input_block_size_samples_,
-                                           input_frame_.num_channels_,
-                                           input_frame_.mutable_data());
+      InputAudioFile::DuplicateInterleaved(
+          input_frame_.data(), input_block_size_samples_,
+          input_frame_.num_channels_, input_frame_.mutable_data());
     }
     data_to_send_ = false;
     RTC_CHECK_GE(acm_->Add10MsData(input_frame_), 0);
@@ -138,7 +137,7 @@
   packet_memory[0] = 0x80;
   packet_memory[1] = static_cast<uint8_t>(payload_type_);
   packet_memory[2] = (sequence_number_ >> 8) & 0xFF;
-  packet_memory[3] = (sequence_number_) & 0xFF;
+  packet_memory[3] = (sequence_number_)&0xFF;
   packet_memory[4] = (timestamp_ >> 24) & 0xFF;
   packet_memory[5] = (timestamp_ >> 16) & 0xFF;
   packet_memory[6] = (timestamp_ >> 8) & 0xFF;
@@ -152,8 +151,7 @@
   ++sequence_number_;
 
   // Copy the payload data.
-  memcpy(packet_memory + kRtpHeaderSize,
-         &last_payload_vec_[0],
+  memcpy(packet_memory + kRtpHeaderSize, &last_payload_vec_[0],
          last_payload_vec_.size());
   std::unique_ptr<Packet> packet(
       new Packet(packet_memory, allocated_bytes, clock_.TimeInMilliseconds()));
diff --git a/modules/audio_coding/acm2/audio_coding_module.cc b/modules/audio_coding/acm2/audio_coding_module.cc
index 4545810..7f652a2 100644
--- a/modules/audio_coding/acm2/audio_coding_module.cc
+++ b/modules/audio_coding/acm2/audio_coding_module.cc
@@ -54,7 +54,7 @@
       rtc::FunctionView<void(const AudioEncoder*)> query) override;
 
   // Get current send codec.
-  rtc::Optional<CodecInst> SendCodec() const override;
+  absl::optional<CodecInst> SendCodec() const override;
 
   // Get current send frequency.
   int SendFrequency() const override;
@@ -142,7 +142,7 @@
   // Get current received codec.
   int ReceiveCodec(CodecInst* current_codec) const override;
 
-  rtc::Optional<SdpAudioFormat> ReceiveFormat() const override;
+  absl::optional<SdpAudioFormat> ReceiveFormat() const override;
 
   // Incoming packet from network parsed and ready for decode.
   int IncomingPacket(const uint8_t* incoming_payload,
@@ -160,7 +160,7 @@
 
   RTC_DEPRECATED int32_t PlayoutTimestamp(uint32_t* timestamp) override;
 
-  rtc::Optional<uint32_t> PlayoutTimestamp() override;
+  absl::optional<uint32_t> PlayoutTimestamp() override;
 
   int FilteredCurrentDelayMs() const override;
 
@@ -323,9 +323,10 @@
   if (!frame.muted()) {
     const int16_t* frame_data = frame.data();
     for (size_t n = 0; n < frame.samples_per_channel_; ++n) {
-      out_buff[n] = static_cast<int16_t>(
-          (static_cast<int32_t>(frame_data[2 * n]) +
-           static_cast<int32_t>(frame_data[2 * n + 1])) >> 1);
+      out_buff[n] =
+          static_cast<int16_t>((static_cast<int32_t>(frame_data[2 * n]) +
+                                static_cast<int32_t>(frame_data[2 * n + 1])) >>
+                               1);
     }
   } else {
     std::fill(out_buff, out_buff + frame.samples_per_channel_, 0);
@@ -472,7 +473,7 @@
   if (!HaveValidEncoder("Process"))
     return -1;
 
-  if(!first_frame_) {
+  if (!first_frame_) {
     RTC_DCHECK(IsNewerTimestamp(input_data.input_timestamp, last_timestamp_))
         << "Time should not move backwards";
   }
@@ -493,9 +494,10 @@
   // Clear the buffer before reuse - encoded data will get appended.
   encode_buffer_.Clear();
   encoded_info = encoder_stack_->Encode(
-      rtp_timestamp, rtc::ArrayView<const int16_t>(
-                         input_data.audio, input_data.audio_channel *
-                                               input_data.length_per_channel),
+      rtp_timestamp,
+      rtc::ArrayView<const int16_t>(
+          input_data.audio,
+          input_data.audio_channel * input_data.length_per_channel),
       &encode_buffer_);
 
   bitrate_logger_.MaybeLog(encoder_stack_->GetTargetBitrate() / 1000);
@@ -603,7 +605,7 @@
 }
 
 // Get current send codec.
-rtc::Optional<CodecInst> AudioCodingModuleImpl::SendCodec() const {
+absl::optional<CodecInst> AudioCodingModuleImpl::SendCodec() const {
   rtc::CritScope lock(&acm_crit_sect_);
   if (encoder_factory_) {
     auto* ci = encoder_factory_->codec_manager.GetCodecInst();
@@ -616,12 +618,12 @@
     if (enc) {
       return acm2::CodecManager::ForgeCodecInst(enc.get());
     }
-    return rtc::nullopt;
+    return absl::nullopt;
   } else {
     return encoder_stack_
-               ? rtc::Optional<CodecInst>(
+               ? absl::optional<CodecInst>(
                      acm2::CodecManager::ForgeCodecInst(encoder_stack_.get()))
-               : rtc::nullopt;
+               : absl::nullopt;
   }
 }
 
@@ -640,7 +642,7 @@
 void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) {
   rtc::CritScope lock(&acm_crit_sect_);
   if (encoder_stack_) {
-    encoder_stack_->OnReceivedUplinkBandwidth(bitrate_bps, rtc::nullopt);
+    encoder_stack_->OnReceivedUplinkBandwidth(bitrate_bps, absl::nullopt);
   }
 }
 
@@ -767,7 +769,6 @@
     expected_in_ts_ = in_frame.timestamp_;
   }
 
-
   if (!down_mix && !resample) {
     // No pre-processing is required.
     if (expected_in_ts_ == expected_codec_ts_) {
@@ -793,8 +794,8 @@
   if (down_mix) {
     // If a resampling is required the output of a down-mix is written into a
     // local buffer, otherwise, it will be written to the output frame.
-    int16_t* dest_ptr_audio = resample ?
-        audio : preprocess_frame_.mutable_data();
+    int16_t* dest_ptr_audio =
+        resample ? audio : preprocess_frame_.mutable_data();
     if (DownMix(in_frame, WEBRTC_10MS_PCM_AUDIO, dest_ptr_audio) < 0)
       return -1;
     preprocess_frame_.num_channels_ = 1;
@@ -912,7 +913,8 @@
 }
 
 // Get VAD/DTX settings.
-int AudioCodingModuleImpl::VAD(bool* dtx_enabled, bool* vad_enabled,
+int AudioCodingModuleImpl::VAD(bool* dtx_enabled,
+                               bool* vad_enabled,
                                ACMVADMode* mode) const {
   rtc::CritScope lock(&acm_crit_sect_);
   const auto* sp = encoder_factory_->codec_manager.GetStackParams();
@@ -1062,7 +1064,7 @@
   return receiver_.LastAudioCodec(current_codec);
 }
 
-rtc::Optional<SdpAudioFormat> AudioCodingModuleImpl::ReceiveFormat() const {
+absl::optional<SdpAudioFormat> AudioCodingModuleImpl::ReceiveFormat() const {
   rtc::CritScope lock(&acm_crit_sect_);
   return receiver_.LastAudioFormat();
 }
@@ -1180,14 +1182,14 @@
 }
 
 int32_t AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) {
-  rtc::Optional<uint32_t> ts = PlayoutTimestamp();
+  absl::optional<uint32_t> ts = PlayoutTimestamp();
   if (!ts)
     return -1;
   *timestamp = *ts;
   return 0;
 }
 
-rtc::Optional<uint32_t> AudioCodingModuleImpl::PlayoutTimestamp() {
+absl::optional<uint32_t> AudioCodingModuleImpl::PlayoutTimestamp() {
   return receiver_.GetPlayoutTimestamp();
 }
 
@@ -1229,7 +1231,7 @@
 }
 
 void AudioCodingModuleImpl::GetDecodingCallStatistics(
-      AudioDecodingCallStats* call_stats) const {
+    AudioDecodingCallStats* call_stats) const {
   receiver_.GetDecodingCallStatistics(call_stats);
 }
 
@@ -1279,7 +1281,7 @@
                              CodecInst* codec,
                              int sampling_freq_hz,
                              size_t channels) {
-  rtc::Optional<CodecInst> ci = acm2::RentACodec::CodecInstByParams(
+  absl::optional<CodecInst> ci = acm2::RentACodec::CodecInstByParams(
       payload_name, sampling_freq_hz, channels);
   if (ci) {
     *codec = *ci;
@@ -1299,12 +1301,12 @@
 int AudioCodingModule::Codec(const char* payload_name,
                              int sampling_freq_hz,
                              size_t channels) {
-  rtc::Optional<acm2::RentACodec::CodecId> ci =
+  absl::optional<acm2::RentACodec::CodecId> ci =
       acm2::RentACodec::CodecIdByParams(payload_name, sampling_freq_hz,
                                         channels);
   if (!ci)
     return -1;
-  rtc::Optional<int> i = acm2::RentACodec::CodecIndexFromId(*ci);
+  absl::optional<int> i = acm2::RentACodec::CodecIndexFromId(*ci);
   return i ? *i : -1;
 }
 
diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
index ff5431d..ce2832a 100644
--- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc
+++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -78,8 +78,6 @@
     rtp_header->frameType = kAudioFrameSpeech;
 
     rtp_header->header.payload_type_frequency = kSampleRateHz;
-    rtp_header->type.Audio.channel = 1;
-    rtp_header->type.Audio.isCNG = false;
   }
 
   void Forward(WebRtcRTPHeader* rtp_header) {
@@ -241,7 +239,7 @@
 
   // These two have to be kept in sync for now. In the future, we'll be able to
   // eliminate the CodecInst and keep only the SdpAudioFormat.
-  rtc::Optional<SdpAudioFormat> audio_format_;
+  absl::optional<SdpAudioFormat> audio_format_;
   CodecInst codec_;
 
   Clock* clock_;
@@ -425,19 +423,12 @@
     const struct {
       int ix;
       FrameType type;
-    } expectation[] = {{2, kAudioFrameCN},
-                       {5, kEmptyFrame},
-                       {8, kEmptyFrame},
-                       {11, kAudioFrameCN},
-                       {14, kEmptyFrame},
-                       {17, kEmptyFrame},
-                       {20, kAudioFrameCN},
-                       {23, kEmptyFrame},
-                       {26, kEmptyFrame},
-                       {29, kEmptyFrame},
-                       {32, kAudioFrameCN},
-                       {35, kEmptyFrame},
-                       {38, kEmptyFrame}};
+    } expectation[] = {
+        {2, kAudioFrameCN},  {5, kEmptyFrame},    {8, kEmptyFrame},
+        {11, kAudioFrameCN}, {14, kEmptyFrame},   {17, kEmptyFrame},
+        {20, kAudioFrameCN}, {23, kEmptyFrame},   {26, kEmptyFrame},
+        {29, kEmptyFrame},   {32, kAudioFrameCN}, {35, kEmptyFrame},
+        {38, kEmptyFrame}};
     for (int i = 0; i < kLoops; ++i) {
       int num_calls_before = packet_cb_.num_calls();
       EXPECT_EQ(i / blocks_per_packet, num_calls_before);
@@ -686,10 +677,8 @@
       last_packet_number_ = num_calls;
     }
     ASSERT_GT(last_payload_vec_.size(), 0u);
-    ASSERT_EQ(
-        0,
-        acm_->IncomingPacket(
-            &last_payload_vec_[0], last_payload_vec_.size(), rtp_header_));
+    ASSERT_EQ(0, acm_->IncomingPacket(&last_payload_vec_[0],
+                                      last_payload_vec_.size(), rtp_header_));
   }
 
   void InsertAudio() override {
@@ -819,9 +808,8 @@
       // Encode new frame.
       uint32_t input_timestamp = rtp_header_.header.timestamp;
       while (info.encoded_bytes == 0) {
-        info =
-            isac_encoder_->Encode(input_timestamp, audio_loop_.GetNextBlock(),
-                                  &encoded);
+        info = isac_encoder_->Encode(input_timestamp,
+                                     audio_loop_.GetNextBlock(), &encoded);
         input_timestamp += 160;  // 10 ms at 16 kHz.
       }
       EXPECT_EQ(rtp_header_.header.timestamp + kPacketSizeSamples,
@@ -984,35 +972,35 @@
 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \
     defined(WEBRTC_CODEC_ILBC)
 TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) {
-  Run(8000, PlatformChecksum("2adede965c6f87de7142c51552111d08",
-                             "028c0fc414b1c9ab7e582dccdf381e98",
-                             "36c95170c1393d4b765d1c17b61ef977",
+  Run(8000, PlatformChecksum("7294941b62293e143d6d6c84955923fd",
+                             "f26b8c9aa8257c7185925fa5b102f46a",
+                             "65e5ef5c3de9c2abf3c8d0989772e9fc",
                              "4598140b5e4f7ee66c5adad609e65a3e",
-                             "bac5db6dff44323be401060f1279a532"));
+                             "04a1d3e735730b6d7dbd5df10f717d27"));
 }
 
 TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) {
-  Run(16000, PlatformChecksum("c2550a3db7632de409e8db0093df1c12",
-                              "edd31f4b6665cd5b9041fb93f2316594",
-                              "22128bca51650cb61c80bed63b595603",
+  Run(16000, PlatformChecksum("de8143dd3cc23241f1e1d5cf14e04b8a",
+                              "eada3f321120d8d5afffbe4170a55d2f",
+                              "135d8c3c7b92aa13d45cad7c91068e3e",
                               "f2aad418af974a3b1694d5ae5cc2c3c7",
-                              "61c3cb9386b9503feebcb829c9be54bd"));
+                              "728b69068332efade35b1a9c32029e1b"));
 }
 
 TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) {
-  Run(32000, PlatformChecksum("85e28d7950132d56f90b099c90f82153",
-                              "7b903f5c89997f271b405e63c245ef45",
-                              "8b8fc6c6fd1dcdcfb3dd90e1ce597f10",
+  Run(32000, PlatformChecksum("521d336237bdcc9ab44050e9da8917fc",
+                              "73d44a7bedb6dfa7c70cf997223d8c10",
+                              "f3ee2f14b03fb8e98f526f82583f84d9",
                               "100869c8dcde51346c2073e52a272d98",
-                              "fdec5301dc649a47d407382b587e14da"));
+                              "5f338b4bc38707d0a14d75a357e1546e"));
 }
 
 TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) {
-  Run(48000, PlatformChecksum("ab611510e8fd6d5210a23cc04d3f0e8e",
-                              "d8609bc9b495d81f29779344c68bcc47",
-                              "ec5ebb90cda0ea5bb89e79d698af65de",
+  Run(48000, PlatformChecksum("5955e31373828969de7fb308fb58a84e",
+                              "83c0eca235b1a806426ff6ca8655cdf7",
+                              "1126a8c03d1ebc6aa7348b9c541e2082",
                               "bd44bf97e7899186532f91235cef444d",
-                              "0baae2972cca142027d4af44f95f0bd5"));
+                              "9d092dbc96e7ef6870b78c1056e87315"));
 }
 
 TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) {
@@ -1058,7 +1046,7 @@
     }
     std::unique_ptr<AudioDecoder> MakeAudioDecoder(
         const SdpAudioFormat& format,
-        rtc::Optional<AudioCodecPairId> codec_pair_id) override {
+        absl::optional<AudioCodecPairId> codec_pair_id) override {
       return format.name == "MockPCMu"
                  ? std::move(mock_decoder_)
                  : fact_->MakeAudioDecoder(format, codec_pair_id);
@@ -1094,11 +1082,12 @@
 
   rtc::scoped_refptr<rtc::RefCountedObject<ADFactory>> factory(
       new rtc::RefCountedObject<ADFactory>);
-  Run(48000, PlatformChecksum("ab611510e8fd6d5210a23cc04d3f0e8e",
-                              "d8609bc9b495d81f29779344c68bcc47",
-                              "ec5ebb90cda0ea5bb89e79d698af65de",
-                              "bd44bf97e7899186532f91235cef444d",
-                              "0baae2972cca142027d4af44f95f0bd5"),
+  Run(48000,
+      PlatformChecksum("5955e31373828969de7fb308fb58a84e",
+                       "83c0eca235b1a806426ff6ca8655cdf7",
+                       "1126a8c03d1ebc6aa7348b9c541e2082",
+                       "bd44bf97e7899186532f91235cef444d",
+                       "9d092dbc96e7ef6870b78c1056e87315"),
       factory, [](AudioCodingModule* acm) {
         acm->RegisterReceiveCodec(0, {"MockPCMu", 8000, 1});
       });
@@ -1154,11 +1143,8 @@
                          int frame_size_rtp_timestamps) {
     payload_type_ = payload_type;
     frame_size_rtp_timestamps_ = frame_size_rtp_timestamps;
-    return send_test_->RegisterCodec(payload_name,
-                                     sampling_freq_hz,
-                                     channels,
-                                     payload_type,
-                                     frame_size_samples);
+    return send_test_->RegisterCodec(payload_name, sampling_freq_hz, channels,
+                                     payload_type, frame_size_samples);
   }
 
   bool RegisterExternalSendCodec(AudioEncoder* external_speech_encoder,
@@ -1257,11 +1243,8 @@
                  int codec_frame_size_samples,
                  int codec_frame_size_rtp_timestamps) {
     ASSERT_TRUE(SetUpSender());
-    ASSERT_TRUE(RegisterSendCodec(codec_name,
-                                  codec_sample_rate_hz,
-                                  channels,
-                                  payload_type,
-                                  codec_frame_size_samples,
+    ASSERT_TRUE(RegisterSendCodec(codec_name, codec_sample_rate_hz, channels,
+                                  payload_type, codec_frame_size_samples,
                                   codec_frame_size_rtp_timestamps));
   }
 
@@ -1342,82 +1325,62 @@
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_8000khz_10ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
-  Run("de4a98e1406f8b798d99cd0704e862e2",
-      "c1edd36339ce0326cc4550041ad719a0",
-      100,
-      test::AcmReceiveTestOldApi::kMonoOutput);
+  Run("de4a98e1406f8b798d99cd0704e862e2", "c1edd36339ce0326cc4550041ad719a0",
+      100, test::AcmReceiveTestOldApi::kMonoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_16000khz_10ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 1, 108, 160, 160));
-  Run("ae646d7b68384a1269cc080dd4501916",
-      "ad786526383178b08d80d6eee06e9bad",
-      100,
-      test::AcmReceiveTestOldApi::kMonoOutput);
+  Run("ae646d7b68384a1269cc080dd4501916", "ad786526383178b08d80d6eee06e9bad",
+      100, test::AcmReceiveTestOldApi::kMonoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_32000khz_10ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 1, 109, 320, 320));
-  Run("7fe325e8fbaf755e3c5df0b11a4774fb",
-      "5ef82ea885e922263606c6fdbc49f651",
-      100,
-      test::AcmReceiveTestOldApi::kMonoOutput);
+  Run("7fe325e8fbaf755e3c5df0b11a4774fb", "5ef82ea885e922263606c6fdbc49f651",
+      100, test::AcmReceiveTestOldApi::kMonoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_8000khz_10ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 2, 111, 80, 80));
-  Run("fb263b74e7ac3de915474d77e4744ceb",
-      "62ce5adb0d4965d0a52ec98ae7f98974",
-      100,
-      test::AcmReceiveTestOldApi::kStereoOutput);
+  Run("fb263b74e7ac3de915474d77e4744ceb", "62ce5adb0d4965d0a52ec98ae7f98974",
+      100, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_16000khz_10ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 2, 112, 160, 160));
-  Run("d09e9239553649d7ac93e19d304281fd",
-      "41ca8edac4b8c71cd54fd9f25ec14870",
-      100,
-      test::AcmReceiveTestOldApi::kStereoOutput);
+  Run("d09e9239553649d7ac93e19d304281fd", "41ca8edac4b8c71cd54fd9f25ec14870",
+      100, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_32000khz_10ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 2, 113, 320, 320));
-  Run("5f025d4f390982cc26b3d92fe02e3044",
-      "50e58502fb04421bf5b857dda4c96879",
-      100,
-      test::AcmReceiveTestOldApi::kStereoOutput);
+  Run("5f025d4f390982cc26b3d92fe02e3044", "50e58502fb04421bf5b857dda4c96879",
+      100, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcmu_20ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMU", 8000, 1, 0, 160, 160));
-  Run("81a9d4c0bb72e9becc43aef124c981e9",
-      "8f9b8750bd80fe26b6cbf6659b89f0f9",
-      50,
-      test::AcmReceiveTestOldApi::kMonoOutput);
+  Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9",
+      50, test::AcmReceiveTestOldApi::kMonoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcma_20ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMA", 8000, 1, 8, 160, 160));
-  Run("39611f798969053925a49dc06d08de29",
-      "6ad745e55aa48981bfc790d0eeef2dd1",
-      50,
-      test::AcmReceiveTestOldApi::kMonoOutput);
+  Run("39611f798969053925a49dc06d08de29", "6ad745e55aa48981bfc790d0eeef2dd1",
+      50, test::AcmReceiveTestOldApi::kMonoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcmu_stereo_20ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMU", 8000, 2, 110, 160, 160));
-  Run("437bec032fdc5cbaa0d5175430af7b18",
-      "60b6f25e8d1e74cb679cfe756dd9bca5",
-      50,
-      test::AcmReceiveTestOldApi::kStereoOutput);
+  Run("437bec032fdc5cbaa0d5175430af7b18", "60b6f25e8d1e74cb679cfe756dd9bca5",
+      50, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
 TEST_F(AcmSenderBitExactnessOldApi, Pcma_stereo_20ms) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMA", 8000, 2, 118, 160, 160));
-  Run("a5c6d83c5b7cedbeff734238220a4b0c",
-      "92b282c83efd20e7eeef52ba40842cf7",
-      50,
-      test::AcmReceiveTestOldApi::kStereoOutput);
+  Run("a5c6d83c5b7cedbeff734238220a4b0c", "92b282c83efd20e7eeef52ba40842cf7",
+      50, test::AcmReceiveTestOldApi::kStereoOutput);
 }
 
 #if defined(WEBRTC_ANDROID)
@@ -1591,13 +1554,14 @@
     return send_test_->RegisterExternalCodec(external_speech_encoder);
   }
 
-  void RunInner(int expected_total_bits) {
+  void RunInner(int min_expected_total_bits, int max_expected_total_bits) {
     int nr_bytes = 0;
     while (std::unique_ptr<test::Packet> next_packet =
                send_test_->NextPacket()) {
       nr_bytes += rtc::checked_cast<int>(next_packet->payload_length_bytes());
     }
-    EXPECT_EQ(expected_total_bits, nr_bytes * 8);
+    EXPECT_LE(min_expected_total_bits, nr_bytes * 8);
+    EXPECT_GE(max_expected_total_bits, nr_bytes * 8);
   }
 
   void SetUpTest(const char* codec_name,
@@ -1620,10 +1584,12 @@
  protected:
   // Runs the test. SetUpSender() must have been called and a codec must be set
   // up before calling this method.
-  void Run(int target_bitrate_bps, int expected_total_bits) {
+  void Run(int target_bitrate_bps,
+           int min_expected_total_bits,
+           int max_expected_total_bits) {
     ASSERT_TRUE(send_test_->acm());
     send_test_->acm()->SetBitRate(target_bitrate_bps);
-    RunInner(expected_total_bits);
+    RunInner(min_expected_total_bits, max_expected_total_bits);
   }
 };
 
@@ -1631,16 +1597,14 @@
  protected:
   // Runs the test. SetUpSender() must have been called and a codec must be set
   // up before calling this method.
-  void Run(int expected_total_bits) { RunInner(expected_total_bits); }
+  void Run(int min_expected_total_bits, int max_expected_total_bits) {
+    RunInner(min_expected_total_bits, max_expected_total_bits);
+  }
 };
 
 TEST_F(AcmSetBitRateOldApi, Opus_48khz_20ms_10kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
-#if defined(WEBRTC_ANDROID)
-  Run(10000, 8640);
-#else
-  Run(10000, 8680);
-#endif  // WEBRTC_ANDROID
+  Run(10000, 8000, 12000);
 }
 
 TEST_F(AcmSetBitRateNewApi, OpusFromFormat_48khz_20ms_10kbps) {
@@ -1649,20 +1613,12 @@
   const auto encoder = AudioEncoderOpus::MakeAudioEncoder(*config, 107);
   ASSERT_TRUE(SetUpSender());
   ASSERT_TRUE(RegisterExternalSendCodec(encoder.get(), 107));
-#if defined(WEBRTC_ANDROID)
-  RunInner(8640);
-#else
-  RunInner(8680);
-#endif  // WEBRTC_ANDROID
+  RunInner(8000, 12000);
 }
 
 TEST_F(AcmSetBitRateOldApi, Opus_48khz_20ms_50kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
-#if defined(WEBRTC_ANDROID)
-  Run(50000, 45792);
-#else
-  Run(50000, 45520);
-#endif  // WEBRTC_ANDROID
+  Run(50000, 40000, 60000);
 }
 
 TEST_F(AcmSetBitRateNewApi, OpusFromFormat_48khz_20ms_50kbps) {
@@ -1671,11 +1627,7 @@
   const auto encoder = AudioEncoderOpus::MakeAudioEncoder(*config, 107);
   ASSERT_TRUE(SetUpSender());
   ASSERT_TRUE(RegisterExternalSendCodec(encoder.get(), 107));
-#if defined(WEBRTC_ANDROID)
-  RunInner(45792);
-#else
-  RunInner(45520);
-#endif  // WEBRTC_ANDROID
+  RunInner(40000, 60000);
 }
 
 // The result on the Android platforms is inconsistent for this test case.
@@ -1691,7 +1643,7 @@
 #endif
 TEST_F(AcmSetBitRateOldApi, MAYBE_Opus_48khz_20ms_100kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
-  Run(100000, 100832);
+  Run(100000, 80000, 120000);
 }
 
 TEST_F(AcmSetBitRateNewApi, MAYBE_OpusFromFormat_48khz_20ms_100kbps) {
@@ -1700,18 +1652,18 @@
   const auto encoder = AudioEncoderOpus::MakeAudioEncoder(*config, 107);
   ASSERT_TRUE(SetUpSender());
   ASSERT_TRUE(RegisterExternalSendCodec(encoder.get(), 107));
-  RunInner(100832);
+  RunInner(80000, 120000);
 }
 
 // These next 2 tests ensure that the SetBitRate function has no effect on PCM
 TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_8kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
-  Run(8000, 128000);
+  Run(8000, 128000, 128000);
 }
 
 TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_32kbps) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
-  Run(32000, 128000);
+  Run(32000, 128000, 128000);
 }
 
 // This test is for verifying the SetBitRate function. The bitrate is changed
@@ -1751,15 +1703,18 @@
       if (packet_counter == nr_packets / 2)
         send_test_->acm()->SetBitRate(target_bitrate_bps);
       if (packet_counter < nr_packets / 2)
-        nr_bytes_before += rtc::checked_cast<int>(
-            next_packet->payload_length_bytes());
+        nr_bytes_before +=
+            rtc::checked_cast<int>(next_packet->payload_length_bytes());
       else
-        nr_bytes_after += rtc::checked_cast<int>(
-            next_packet->payload_length_bytes());
+        nr_bytes_after +=
+            rtc::checked_cast<int>(next_packet->payload_length_bytes());
       packet_counter++;
     }
-    EXPECT_EQ(expected_before_switch_bits, nr_bytes_before * 8);
-    EXPECT_EQ(expected_after_switch_bits, nr_bytes_after * 8);
+    // Check that bitrate is 80-120 percent of expected value.
+    EXPECT_GE(expected_before_switch_bits, nr_bytes_before * 8 * 8 / 10);
+    EXPECT_LE(expected_before_switch_bits, nr_bytes_before * 8 * 12 / 10);
+    EXPECT_GE(expected_after_switch_bits, nr_bytes_after * 8 * 8 / 10);
+    EXPECT_LE(expected_after_switch_bits, nr_bytes_after * 8 * 12 / 10);
   }
 
   uint32_t sampling_freq_hz_;
@@ -1768,33 +1723,17 @@
 
 TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_10kbps_2) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
-#if defined(WEBRTC_ANDROID)
-  Run(10000, 29512, 4800);
-#else
-  Run(10000, 32200, 5368);
-#endif  // WEBRTC_ANDROID
+  Run(10000, 32200, 5208);
 }
 
 TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_50kbps_2) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
-#if defined(WEBRTC_ANDROID)
-  Run(50000, 29512, 23304);
-#else
-  Run(50000, 32200, 23920);
-#endif  // WEBRTC_ANDROID
+  Run(50000, 32200, 23928);
 }
 
 TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_100kbps_2) {
   ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960));
-#if defined(WEBRTC_ANDROID)
-  #if defined(WEBRTC_ARCH_ARM64)
-    Run(100000, 29512, 50440);
-  #else
-    Run(100000, 29512, 50496);
-  #endif  // WEBRTC_ARCH_ARM64
-#else
   Run(100000, 32200, 50448);
-#endif  // WEBRTC_ANDROID
 }
 
 // These next 2 tests ensure that the SetBitRate function has no effect on PCM
@@ -1835,12 +1774,10 @@
       .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::GetTargetBitrate));
   EXPECT_CALL(mock_encoder, EncodeImpl(_, _, _))
       .Times(AtLeast(1))
-      .WillRepeatedly(Invoke(&encoder,
-                             static_cast<
-                             AudioEncoder::EncodedInfo(AudioEncoder::*)(
-                                 uint32_t,
-                                 rtc::ArrayView<const int16_t>,
-                                 rtc::Buffer*)>(&AudioEncoderPcmU::Encode)));
+      .WillRepeatedly(Invoke(
+          &encoder, static_cast<AudioEncoder::EncodedInfo (AudioEncoder::*)(
+                        uint32_t, rtc::ArrayView<const int16_t>, rtc::Buffer*)>(
+                        &AudioEncoderPcmU::Encode)));
   EXPECT_CALL(mock_encoder, SetFec(_))
       .Times(AtLeast(1))
       .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::SetFec));
@@ -1890,11 +1827,7 @@
     // this class.
     test::AudioSinkFork output(this, &output_file);
     test::AcmReceiveTestToggleOutputFreqOldApi receive_test(
-        this,
-        &output,
-        output_freq_1,
-        output_freq_2,
-        toggle_period_ms,
+        this, &output, output_freq_1, output_freq_2, toggle_period_ms,
         test::AcmReceiveTestOldApi::kMonoOutput);
     ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs());
     output_freq_2_ = output_freq_2;
diff --git a/modules/audio_coding/acm2/call_statistics_unittest.cc b/modules/audio_coding/acm2/call_statistics_unittest.cc
index 77c3863..528708f 100644
--- a/modules/audio_coding/acm2/call_statistics_unittest.cc
+++ b/modules/audio_coding/acm2/call_statistics_unittest.cc
@@ -52,6 +52,3 @@
 }  // namespace acm2
 
 }  // namespace webrtc
-
-
-
diff --git a/modules/audio_coding/acm2/codec_manager.h b/modules/audio_coding/acm2/codec_manager.h
index 7485426..ffbad96 100644
--- a/modules/audio_coding/acm2/codec_manager.h
+++ b/modules/audio_coding/acm2/codec_manager.h
@@ -13,7 +13,7 @@
 
 #include <map>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/acm2/rent_a_codec.h"
 #include "modules/audio_coding/include/audio_coding_module.h"
@@ -43,7 +43,7 @@
     return send_codec_inst_ ? &*send_codec_inst_ : nullptr;
   }
 
-  void UnsetCodecInst() { send_codec_inst_ = rtc::nullopt; }
+  void UnsetCodecInst() { send_codec_inst_ = absl::nullopt; }
 
   const RentACodec::StackParameters* GetStackParams() const {
     return &codec_stack_params_;
@@ -63,7 +63,7 @@
 
  private:
   rtc::ThreadChecker thread_checker_;
-  rtc::Optional<CodecInst> send_codec_inst_;
+  absl::optional<CodecInst> send_codec_inst_;
   RentACodec::StackParameters codec_stack_params_;
   bool recreate_encoder_ = true;  // Need to recreate encoder?
 
diff --git a/modules/audio_coding/acm2/rent_a_codec.cc b/modules/audio_coding/acm2/rent_a_codec.cc
index 78db38d..818e17f 100644
--- a/modules/audio_coding/acm2/rent_a_codec.cc
+++ b/modules/audio_coding/acm2/rent_a_codec.cc
@@ -44,7 +44,7 @@
 namespace webrtc {
 namespace acm2 {
 
-rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByParams(
+absl::optional<RentACodec::CodecId> RentACodec::CodecIdByParams(
     const char* payload_name,
     int sampling_freq_hz,
     size_t channels) {
@@ -52,25 +52,25 @@
       ACMCodecDB::CodecId(payload_name, sampling_freq_hz, channels));
 }
 
-rtc::Optional<CodecInst> RentACodec::CodecInstById(CodecId codec_id) {
-  rtc::Optional<int> mi = CodecIndexFromId(codec_id);
-  return mi ? rtc::Optional<CodecInst>(Database()[*mi])
-            : rtc::nullopt;
+absl::optional<CodecInst> RentACodec::CodecInstById(CodecId codec_id) {
+  absl::optional<int> mi = CodecIndexFromId(codec_id);
+  return mi ? absl::optional<CodecInst>(Database()[*mi]) : absl::nullopt;
 }
 
-rtc::Optional<RentACodec::CodecId> RentACodec::CodecIdByInst(
+absl::optional<RentACodec::CodecId> RentACodec::CodecIdByInst(
     const CodecInst& codec_inst) {
   return CodecIdFromIndex(ACMCodecDB::CodecNumber(codec_inst));
 }
 
-rtc::Optional<CodecInst> RentACodec::CodecInstByParams(const char* payload_name,
-                                                       int sampling_freq_hz,
-                                                       size_t channels) {
-  rtc::Optional<CodecId> codec_id =
+absl::optional<CodecInst> RentACodec::CodecInstByParams(
+    const char* payload_name,
+    int sampling_freq_hz,
+    size_t channels) {
+  absl::optional<CodecId> codec_id =
       CodecIdByParams(payload_name, sampling_freq_hz, channels);
   if (!codec_id)
-    return rtc::nullopt;
-  rtc::Optional<CodecInst> ci = CodecInstById(*codec_id);
+    return absl::nullopt;
+  absl::optional<CodecInst> ci = CodecInstById(*codec_id);
   RTC_DCHECK(ci);
 
   // Keep the number of channels from the function call. For most codecs it
@@ -84,13 +84,13 @@
   return ACMCodecDB::CodecNumber(codec_inst) >= 0;
 }
 
-rtc::Optional<bool> RentACodec::IsSupportedNumChannels(CodecId codec_id,
-                                                       size_t num_channels) {
+absl::optional<bool> RentACodec::IsSupportedNumChannels(CodecId codec_id,
+                                                        size_t num_channels) {
   auto i = CodecIndexFromId(codec_id);
-  return i ? rtc::Optional<bool>(
+  return i ? absl::optional<bool>(
                  ACMCodecDB::codec_settings_[*i].channel_support >=
                  num_channels)
-           : rtc::nullopt;
+           : absl::nullopt;
 }
 
 rtc::ArrayView<const CodecInst> RentACodec::Database() {
@@ -98,12 +98,12 @@
                                          NumberOfCodecs());
 }
 
-rtc::Optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId(
+absl::optional<NetEqDecoder> RentACodec::NetEqDecoderFromCodecId(
     CodecId codec_id,
     size_t num_channels) {
-  rtc::Optional<int> i = CodecIndexFromId(codec_id);
+  absl::optional<int> i = CodecIndexFromId(codec_id);
   if (!i)
-    return rtc::nullopt;
+    return absl::nullopt;
   const NetEqDecoder ned = ACMCodecDB::neteq_decoders_[*i];
   return (ned == NetEqDecoder::kDecoderOpus && num_channels == 2)
              ? NetEqDecoder::kDecoderOpus_2ch
@@ -276,8 +276,7 @@
 
   auto pt = [&param](const std::map<int, int>& m) {
     auto it = m.find(param->speech_encoder->SampleRateHz());
-    return it == m.end() ? rtc::nullopt
-                         : rtc::Optional<int>(it->second);
+    return it == m.end() ? absl::nullopt : absl::optional<int>(it->second);
   };
   auto cng_pt = pt(param->cng_payload_types);
   param->use_cng =
diff --git a/modules/audio_coding/acm2/rent_a_codec.h b/modules/audio_coding/acm2/rent_a_codec.h
index f8fac4c..02f9d03 100644
--- a/modules/audio_coding/acm2/rent_a_codec.h
+++ b/modules/audio_coding/acm2/rent_a_codec.h
@@ -15,10 +15,10 @@
 #include <map>
 #include <memory>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/audio_codecs/audio_decoder.h"
 #include "api/audio_codecs/audio_encoder.h"
-#include "api/optional.h"
 #include "modules/audio_coding/include/audio_coding_module_typedefs.h"
 #include "modules/audio_coding/neteq/neteq_decoder_enum.h"
 #include "rtc_base/constructormagic.h"
@@ -107,28 +107,28 @@
     return static_cast<size_t>(CodecId::kNumCodecs);
   }
 
-  static inline rtc::Optional<int> CodecIndexFromId(CodecId codec_id) {
+  static inline absl::optional<int> CodecIndexFromId(CodecId codec_id) {
     const int i = static_cast<int>(codec_id);
     return i >= 0 && i < static_cast<int>(NumberOfCodecs())
-               ? rtc::Optional<int>(i)
-               : rtc::nullopt;
+               ? absl::optional<int>(i)
+               : absl::nullopt;
   }
 
-  static inline rtc::Optional<CodecId> CodecIdFromIndex(int codec_index) {
+  static inline absl::optional<CodecId> CodecIdFromIndex(int codec_index) {
     return static_cast<size_t>(codec_index) < NumberOfCodecs()
-               ? rtc::Optional<RentACodec::CodecId>(
+               ? absl::optional<RentACodec::CodecId>(
                      static_cast<RentACodec::CodecId>(codec_index))
-               : rtc::nullopt;
+               : absl::nullopt;
   }
 
-  static rtc::Optional<CodecId> CodecIdByParams(const char* payload_name,
-                                                int sampling_freq_hz,
-                                                size_t channels);
-  static rtc::Optional<CodecInst> CodecInstById(CodecId codec_id);
-  static rtc::Optional<CodecId> CodecIdByInst(const CodecInst& codec_inst);
-  static rtc::Optional<CodecInst> CodecInstByParams(const char* payload_name,
-                                                    int sampling_freq_hz,
-                                                    size_t channels);
+  static absl::optional<CodecId> CodecIdByParams(const char* payload_name,
+                                                 int sampling_freq_hz,
+                                                 size_t channels);
+  static absl::optional<CodecInst> CodecInstById(CodecId codec_id);
+  static absl::optional<CodecId> CodecIdByInst(const CodecInst& codec_inst);
+  static absl::optional<CodecInst> CodecInstByParams(const char* payload_name,
+                                                     int sampling_freq_hz,
+                                                     size_t channels);
   static bool IsCodecValid(const CodecInst& codec_inst);
 
   static inline bool IsPayloadTypeValid(int payload_type) {
@@ -137,10 +137,10 @@
 
   static rtc::ArrayView<const CodecInst> Database();
 
-  static rtc::Optional<bool> IsSupportedNumChannels(CodecId codec_id,
-                                                    size_t num_channels);
+  static absl::optional<bool> IsSupportedNumChannels(CodecId codec_id,
+                                                     size_t num_channels);
 
-  static rtc::Optional<NetEqDecoder> NetEqDecoderFromCodecId(
+  static absl::optional<NetEqDecoder> NetEqDecoderFromCodecId(
       CodecId codec_id,
       size_t num_channels);
 
diff --git a/modules/audio_coding/acm2/rent_a_codec_unittest.cc b/modules/audio_coding/acm2/rent_a_codec_unittest.cc
index ca469e7..fd3329c 100644
--- a/modules/audio_coding/acm2/rent_a_codec_unittest.cc
+++ b/modules/audio_coding/acm2/rent_a_codec_unittest.cc
@@ -54,8 +54,7 @@
                        int expected_send_even_if_empty) {
     rtc::Buffer out;
     AudioEncoder::EncodedInfo encoded_info;
-    encoded_info =
-        encoder_->Encode(timestamp_, kZeroData, &out);
+    encoded_info = encoder_->Encode(timestamp_, kZeroData, &out);
     timestamp_ += kDataLengthSamples;
     EXPECT_TRUE(encoded_info.redundant.empty());
     EXPECT_EQ(expected_out_length, encoded_info.encoded_bytes);
@@ -132,9 +131,8 @@
   {
     ::testing::InSequence s;
     info.encoded_timestamp = 0;
-    EXPECT_CALL(
-        *external_encoder,
-        EncodeImpl(0, rtc::ArrayView<const int16_t>(audio), &encoded))
+    EXPECT_CALL(*external_encoder,
+                EncodeImpl(0, rtc::ArrayView<const int16_t>(audio), &encoded))
         .WillOnce(Return(info));
     EXPECT_CALL(marker, Mark("A"));
     EXPECT_CALL(marker, Mark("B"));
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
index 55e5309..c4832a3 100644
--- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
+++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc
@@ -123,7 +123,7 @@
     controller->MakeDecision(&config);
 
   // Update ANA stats.
-  auto increment_opt = [](rtc::Optional<uint32_t>& a) {
+  auto increment_opt = [](absl::optional<uint32_t>& a) {
     a = a.value_or(0) + 1;
   };
   if (prev_config_) {
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
index 14000fe..e208ed2 100644
--- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
+++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h
@@ -75,7 +75,7 @@
 
   Controller::NetworkMetrics last_metrics_;
 
-  rtc::Optional<AudioEncoderRuntimeConfig> prev_config_;
+  absl::optional<AudioEncoderRuntimeConfig> prev_config_;
 
   ANAStats stats_;
 
diff --git a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
index 574b699..5948ac3 100644
--- a/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc
@@ -102,8 +102,7 @@
   config.event_log = states.event_log.get();
   // AudioNetworkAdaptorImpl governs the lifetime of controller manager.
   states.audio_network_adaptor.reset(new AudioNetworkAdaptorImpl(
-      config,
-      std::move(controller_manager), std::move(debug_dump_writer)));
+      config, std::move(controller_manager), std::move(debug_dump_writer)));
 
   return states;
 }
@@ -192,7 +191,7 @@
       "WebRTC-Audio-BitrateAdaptation/Enabled/WebRTC-Audio-FecAdaptation/"
       "Enabled/");
   rtc::ScopedFakeClock fake_clock;
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kClockInitialTimeMs));
+  fake_clock.AdvanceTime(TimeDelta::ms(kClockInitialTimeMs));
   auto states = CreateAudioNetworkAdaptor();
   AudioEncoderRuntimeConfig config;
   config.bitrate_bps = 32000;
@@ -210,7 +209,7 @@
 TEST(AudioNetworkAdaptorImplTest,
      DumpNetworkMetricsIsCalledOnSetNetworkMetrics) {
   rtc::ScopedFakeClock fake_clock;
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kClockInitialTimeMs));
+  fake_clock.AdvanceTime(TimeDelta::ms(kClockInitialTimeMs));
 
   auto states = CreateAudioNetworkAdaptor();
 
@@ -229,14 +228,14 @@
               DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check));
   states.audio_network_adaptor->SetUplinkBandwidth(kBandwidth);
 
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(100));
+  fake_clock.AdvanceTime(TimeDelta::ms(100));
   timestamp_check += 100;
   check.uplink_packet_loss_fraction = kPacketLoss;
   EXPECT_CALL(*states.mock_debug_dump_writer,
               DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check));
   states.audio_network_adaptor->SetUplinkPacketLossFraction(kPacketLoss);
 
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(50));
+  fake_clock.AdvanceTime(TimeDelta::ms(50));
   timestamp_check += 50;
   check.uplink_recoverable_packet_loss_fraction = kRecoverablePacketLoss;
   EXPECT_CALL(*states.mock_debug_dump_writer,
@@ -244,21 +243,21 @@
   states.audio_network_adaptor->SetUplinkRecoverablePacketLossFraction(
       kRecoverablePacketLoss);
 
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(200));
+  fake_clock.AdvanceTime(TimeDelta::ms(200));
   timestamp_check += 200;
   check.rtt_ms = kRtt;
   EXPECT_CALL(*states.mock_debug_dump_writer,
               DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check));
   states.audio_network_adaptor->SetRtt(kRtt);
 
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(150));
+  fake_clock.AdvanceTime(TimeDelta::ms(150));
   timestamp_check += 150;
   check.target_audio_bitrate_bps = kTargetAudioBitrate;
   EXPECT_CALL(*states.mock_debug_dump_writer,
               DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check));
   states.audio_network_adaptor->SetTargetAudioBitrate(kTargetAudioBitrate);
 
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(50));
+  fake_clock.AdvanceTime(TimeDelta::ms(50));
   timestamp_check += 50;
   check.overhead_bytes_per_packet = kOverhead;
   EXPECT_CALL(*states.mock_debug_dump_writer,
diff --git a/modules/audio_coding/audio_network_adaptor/bitrate_controller.h b/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
index 601f794..282f599 100644
--- a/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/bitrate_controller.h
@@ -43,8 +43,8 @@
   const Config config_;
   int bitrate_bps_;
   int frame_length_ms_;
-  rtc::Optional<int> target_audio_bitrate_bps_;
-  rtc::Optional<size_t> overhead_bytes_per_packet_;
+  absl::optional<int> target_audio_bitrate_bps_;
+  absl::optional<size_t> overhead_bytes_per_packet_;
   RTC_DISALLOW_COPY_AND_ASSIGN(BitrateController);
 };
 
diff --git a/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc
index 9864511..f077357 100644
--- a/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/bitrate_controller_unittest.cc
@@ -20,8 +20,8 @@
 
 void UpdateNetworkMetrics(
     BitrateController* controller,
-    const rtc::Optional<int>& target_audio_bitrate_bps,
-    const rtc::Optional<size_t>& overhead_bytes_per_packet) {
+    const absl::optional<int>& target_audio_bitrate_bps,
+    const absl::optional<size_t>& overhead_bytes_per_packet) {
   // UpdateNetworkMetrics can accept multiple network metric updates at once.
   // However, currently, the most used case is to update one metric at a time.
   // To reflect this fact, we separate the calls.
@@ -38,7 +38,7 @@
 }
 
 void CheckDecision(BitrateController* controller,
-                   const rtc::Optional<int>& frame_length_ms,
+                   const absl::optional<int>& frame_length_ms,
                    int expected_bitrate_bps) {
   AudioEncoderRuntimeConfig config;
   config.frame_length_ms = frame_length_ms;
@@ -58,7 +58,7 @@
   constexpr size_t kOverheadBytesPerPacket = 64;
   BitrateController controller(BitrateController::Config(
       kInitialBitrateBps, kInitialFrameLengthMs, 0, 0));
-  UpdateNetworkMetrics(&controller, rtc::nullopt, kOverheadBytesPerPacket);
+  UpdateNetworkMetrics(&controller, absl::nullopt, kOverheadBytesPerPacket);
   CheckDecision(&controller, kInitialFrameLengthMs * 2, kInitialBitrateBps);
 }
 
@@ -68,7 +68,7 @@
   constexpr int kTargetBitrateBps = 48000;
   BitrateController controller(BitrateController::Config(
       kInitialBitrateBps, kInitialFrameLengthMs, 0, 0));
-  UpdateNetworkMetrics(&controller, kTargetBitrateBps, rtc::nullopt);
+  UpdateNetworkMetrics(&controller, kTargetBitrateBps, absl::nullopt);
   CheckDecision(&controller, kInitialFrameLengthMs * 2, kInitialBitrateBps);
 }
 
@@ -80,9 +80,9 @@
       BitrateController::Config(32000, kInitialFrameLengthMs, 0, 0));
   constexpr int kTargetBitrateBps = 48000;
   constexpr size_t kOverheadBytesPerPacket = 64;
-  constexpr int kBitrateBps =
-      kTargetBitrateBps -
-      kOverheadBytesPerPacket * 8 * 1000 / kInitialFrameLengthMs;
+  constexpr int kBitrateBps = kTargetBitrateBps - kOverheadBytesPerPacket * 8 *
+                                                      1000 /
+                                                      kInitialFrameLengthMs;
   // Frame length unchanged, bitrate changes in accordance with
   // |metrics.target_audio_bitrate_bps| and |metrics.overhead_bytes_per_packet|.
   UpdateNetworkMetrics(&controller, kTargetBitrateBps, kOverheadBytesPerPacket);
@@ -104,9 +104,9 @@
       BitrateController::Config(32000, kInitialFrameLengthMs, 0, 0));
   constexpr int kTargetBitrateBps = 48000;
   constexpr size_t kOverheadBytesPerPacket = 64;
-  constexpr int kBitrateBps =
-      kTargetBitrateBps -
-      kOverheadBytesPerPacket * 8 * 1000 / kInitialFrameLengthMs;
+  constexpr int kBitrateBps = kTargetBitrateBps - kOverheadBytesPerPacket * 8 *
+                                                      1000 /
+                                                      kInitialFrameLengthMs;
   Controller::NetworkMetrics network_metrics;
   network_metrics.target_audio_bitrate_bps = kTargetBitrateBps;
   network_metrics.overhead_bytes_per_packet = kOverheadBytesPerPacket;
@@ -122,11 +122,11 @@
       BitrateController::Config(32000, kInitialFrameLengthMs, 0, 0));
   constexpr int kTargetBitrateBps = 48000;
   constexpr size_t kOverheadBytesPerPacket = 64;
-  constexpr int kBitrateBps =
-      kTargetBitrateBps -
-      kOverheadBytesPerPacket * 8 * 1000 / kInitialFrameLengthMs;
+  constexpr int kBitrateBps = kTargetBitrateBps - kOverheadBytesPerPacket * 8 *
+                                                      1000 /
+                                                      kInitialFrameLengthMs;
   UpdateNetworkMetrics(&controller, kTargetBitrateBps, kOverheadBytesPerPacket);
-  CheckDecision(&controller, rtc::nullopt, kBitrateBps);
+  CheckDecision(&controller, absl::nullopt, kBitrateBps);
 }
 
 TEST(AnaBitrateControllerTest, IncreaseBitrateOnFrameLengthIncreased) {
@@ -138,11 +138,11 @@
 
   constexpr int kTargetBitrateBps = 48000;
   constexpr size_t kOverheadBytesPerPacket = 64;
-  constexpr int kBitrateBps =
-      kTargetBitrateBps -
-      kOverheadBytesPerPacket * 8 * 1000 / kInitialFrameLengthMs;
+  constexpr int kBitrateBps = kTargetBitrateBps - kOverheadBytesPerPacket * 8 *
+                                                      1000 /
+                                                      kInitialFrameLengthMs;
   UpdateNetworkMetrics(&controller, kTargetBitrateBps, kOverheadBytesPerPacket);
-  CheckDecision(&controller, rtc::nullopt, kBitrateBps);
+  CheckDecision(&controller, absl::nullopt, kBitrateBps);
 
   constexpr int kFrameLengthMs = 60;
   constexpr size_t kPacketOverheadRateDiff =
@@ -162,11 +162,11 @@
 
   constexpr int kTargetBitrateBps = 48000;
   constexpr size_t kOverheadBytesPerPacket = 64;
-  constexpr int kBitrateBps =
-      kTargetBitrateBps -
-      kOverheadBytesPerPacket * 8 * 1000 / kInitialFrameLengthMs;
+  constexpr int kBitrateBps = kTargetBitrateBps - kOverheadBytesPerPacket * 8 *
+                                                      1000 /
+                                                      kInitialFrameLengthMs;
   UpdateNetworkMetrics(&controller, kTargetBitrateBps, kOverheadBytesPerPacket);
-  CheckDecision(&controller, rtc::nullopt, kBitrateBps);
+  CheckDecision(&controller, absl::nullopt, kBitrateBps);
 
   constexpr int kFrameLengthMs = 20;
   constexpr size_t kPacketOverheadRateDiff =
@@ -213,9 +213,9 @@
 
   // Next: change frame length.
   frame_length_ms = 60;
-  current_bitrate += rtc::checked_cast<int>(
-      overhead_bytes_per_packet * 8 * 1000 / 20 -
-      overhead_bytes_per_packet * 8 * 1000 / 60);
+  current_bitrate +=
+      rtc::checked_cast<int>(overhead_bytes_per_packet * 8 * 1000 / 20 -
+                             overhead_bytes_per_packet * 8 * 1000 / 60);
   UpdateNetworkMetrics(&controller, overall_bitrate, overhead_bytes_per_packet);
   CheckDecision(&controller, frame_length_ms, current_bitrate);
 
@@ -227,9 +227,9 @@
 
   // Next: change frame length.
   frame_length_ms = 20;
-  current_bitrate -= rtc::checked_cast<int>(
-      overhead_bytes_per_packet * 8 * 1000 / 20 -
-      overhead_bytes_per_packet * 8 * 1000 / 60);
+  current_bitrate -=
+      rtc::checked_cast<int>(overhead_bytes_per_packet * 8 * 1000 / 20 -
+                             overhead_bytes_per_packet * 8 * 1000 / 60);
   UpdateNetworkMetrics(&controller, overall_bitrate, overhead_bytes_per_packet);
   CheckDecision(&controller, frame_length_ms, current_bitrate);
 
@@ -237,9 +237,9 @@
   overall_bitrate -= 100;
   current_bitrate -= 100;
   frame_length_ms = 60;
-  current_bitrate += rtc::checked_cast<int>(
-      overhead_bytes_per_packet * 8 * 1000 / 20 -
-      overhead_bytes_per_packet * 8 * 1000 / 60);
+  current_bitrate +=
+      rtc::checked_cast<int>(overhead_bytes_per_packet * 8 * 1000 / 20 -
+                             overhead_bytes_per_packet * 8 * 1000 / 60);
 
   UpdateNetworkMetrics(&controller, overall_bitrate, overhead_bytes_per_packet);
   CheckDecision(&controller, frame_length_ms, current_bitrate);
diff --git a/modules/audio_coding/audio_network_adaptor/channel_controller.h b/modules/audio_coding/audio_network_adaptor/channel_controller.h
index f53ddd6..23cbef6 100644
--- a/modules/audio_coding/audio_network_adaptor/channel_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/channel_controller.h
@@ -44,7 +44,7 @@
  private:
   const Config config_;
   size_t channels_to_encode_;
-  rtc::Optional<int> uplink_bandwidth_bps_;
+  absl::optional<int> uplink_bandwidth_bps_;
   RTC_DISALLOW_COPY_AND_ASSIGN(ChannelController);
 };
 
diff --git a/modules/audio_coding/audio_network_adaptor/channel_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/channel_controller_unittest.cc
index 64e5dae..bfa6f01 100644
--- a/modules/audio_coding/audio_network_adaptor/channel_controller_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/channel_controller_unittest.cc
@@ -32,7 +32,7 @@
 }
 
 void CheckDecision(ChannelController* controller,
-                   const rtc::Optional<int>& uplink_bandwidth_bps,
+                   const absl::optional<int>& uplink_bandwidth_bps,
                    size_t expected_num_channels) {
   if (uplink_bandwidth_bps) {
     Controller::NetworkMetrics network_metrics;
@@ -49,7 +49,7 @@
 TEST(ChannelControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) {
   constexpr int kInitChannels = 2;
   auto controller = CreateChannelController(kInitChannels);
-  CheckDecision(controller.get(), rtc::nullopt, kInitChannels);
+  CheckDecision(controller.get(), absl::nullopt, kInitChannels);
 }
 
 TEST(ChannelControllerTest, SwitchTo2ChannelsOnHighUplinkBandwidth) {
diff --git a/modules/audio_coding/audio_network_adaptor/controller.h b/modules/audio_coding/audio_network_adaptor/controller.h
index af2f569..19d8599 100644
--- a/modules/audio_coding/audio_network_adaptor/controller.h
+++ b/modules/audio_coding/audio_network_adaptor/controller.h
@@ -11,7 +11,7 @@
 #ifndef MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_CONTROLLER_H_
 #define MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_CONTROLLER_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
 
 namespace webrtc {
@@ -21,12 +21,12 @@
   struct NetworkMetrics {
     NetworkMetrics();
     ~NetworkMetrics();
-    rtc::Optional<int> uplink_bandwidth_bps;
-    rtc::Optional<float> uplink_packet_loss_fraction;
-    rtc::Optional<float> uplink_recoverable_packet_loss_fraction;
-    rtc::Optional<int> target_audio_bitrate_bps;
-    rtc::Optional<int> rtt_ms;
-    rtc::Optional<size_t> overhead_bytes_per_packet;
+    absl::optional<int> uplink_bandwidth_bps;
+    absl::optional<float> uplink_packet_loss_fraction;
+    absl::optional<float> uplink_recoverable_packet_loss_fraction;
+    absl::optional<int> target_audio_bitrate_bps;
+    absl::optional<int> rtt_ms;
+    absl::optional<size_t> overhead_bytes_per_packet;
   };
 
   virtual ~Controller() = default;
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.cc b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
index 313aa62..32f9fcb 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager.cc
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager.cc
@@ -296,9 +296,9 @@
   }
 
   if (scoring_points.size() == 0) {
-    return std::unique_ptr<ControllerManagerImpl>(new ControllerManagerImpl(
-        ControllerManagerImpl::Config(0, 0), std::move(controllers),
-        scoring_points));
+    return std::unique_ptr<ControllerManagerImpl>(
+        new ControllerManagerImpl(ControllerManagerImpl::Config(0, 0),
+                                  std::move(controllers), scoring_points));
   } else {
     RTC_CHECK(controller_manager_config.has_min_reordering_time_ms());
     RTC_CHECK(controller_manager_config.has_min_reordering_squared_distance());
@@ -327,7 +327,7 @@
     const std::map<const Controller*, std::pair<int, float>>& scoring_points)
     : config_(config),
       controllers_(std::move(controllers)),
-      last_reordering_time_ms_(rtc::nullopt),
+      last_reordering_time_ms_(absl::nullopt),
       last_scoring_point_(0, 0.0) {
   for (auto& controller : controllers_)
     default_sorted_controllers_.push_back(controller.get());
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager.h b/modules/audio_coding/audio_network_adaptor/controller_manager.h
index 5c63f2f..1ff9bbf 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager.h
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager.h
@@ -104,7 +104,7 @@
 
   std::vector<std::unique_ptr<Controller>> controllers_;
 
-  rtc::Optional<int64_t> last_reordering_time_ms_;
+  absl::optional<int64_t> last_reordering_time_ms_;
   ScoringPoint last_scoring_point_;
 
   std::vector<Controller*> default_sorted_controllers_;
diff --git a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
index 576661c..061e4aa 100644
--- a/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/controller_manager_unittest.cc
@@ -87,8 +87,8 @@
 // exists in the vector.
 void CheckControllersOrder(
     ControllerManagerStates* states,
-    const rtc::Optional<int>& uplink_bandwidth_bps,
-    const rtc::Optional<float>& uplink_packet_loss_fraction,
+    const absl::optional<int>& uplink_bandwidth_bps,
+    const absl::optional<float>& uplink_packet_loss_fraction,
     const std::vector<int>& expected_order) {
   RTC_DCHECK_EQ(kNumControllers, expected_order.size());
   Controller::NetworkMetrics metrics;
@@ -124,8 +124,7 @@
   auto states = CreateControllerManager();
   // |network_metrics| are empty, and the controllers are supposed to follow the
   // default order.
-  CheckControllersOrder(&states, rtc::nullopt, rtc::nullopt,
-                        {0, 1, 2, 3});
+  CheckControllersOrder(&states, absl::nullopt, absl::nullopt, {0, 1, 2, 3});
 }
 
 TEST(ControllerManagerTest, ControllersWithoutCharPointAtEndAndInDefaultOrder) {
@@ -148,8 +147,7 @@
   CheckControllersOrder(&states, kChracteristicBandwithBps[0],
                         kChracteristicPacketLossFraction[0],
                         {kNumControllers - 2, kNumControllers - 1, 0, 1});
-  fake_clock.AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(kMinReorderingTimeMs - 1));
+  fake_clock.AdvanceTime(TimeDelta::ms(kMinReorderingTimeMs - 1));
   // Move uplink bandwidth and packet loss fraction to the other controller's
   // characteristic point, which would cause controller manager to reorder the
   // controllers if time had reached min reordering time.
@@ -170,8 +168,7 @@
   // of two controllers.
   CheckControllersOrder(&states, kBandwidthBps, kPacketLossFraction,
                         {kNumControllers - 2, kNumControllers - 1, 0, 1});
-  fake_clock.AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(kMinReorderingTimeMs));
+  fake_clock.AdvanceTime(TimeDelta::ms(kMinReorderingTimeMs));
   // Then let network metrics move a little towards the other controller.
   CheckControllersOrder(&states, kBandwidthBps - kMinBandwithChangeBps - 1,
                         kPacketLossFraction,
@@ -190,8 +187,7 @@
   // of two controllers.
   CheckControllersOrder(&states, kBandwidthBps, kPacketLossFraction,
                         {kNumControllers - 2, kNumControllers - 1, 0, 1});
-  fake_clock.AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(kMinReorderingTimeMs));
+  fake_clock.AdvanceTime(TimeDelta::ms(kMinReorderingTimeMs));
   // Then let network metrics move a little towards the other controller.
   CheckControllersOrder(&states, kBandwidthBps - kMinBandwithChangeBps + 1,
                         kPacketLossFraction,
@@ -351,7 +347,7 @@
 
   constexpr int64_t kClockInitialTimeMs = 12345678;
   rtc::ScopedFakeClock fake_clock;
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kClockInitialTimeMs));
+  fake_clock.AdvanceTime(TimeDelta::ms(kClockInitialTimeMs));
   auto debug_dump_writer =
       std::unique_ptr<MockDebugDumpWriter>(new NiceMock<MockDebugDumpWriter>());
   EXPECT_CALL(*debug_dump_writer, Die());
@@ -448,8 +444,7 @@
 
   metrics.uplink_bandwidth_bps = kChracteristicBandwithBps[1];
   metrics.uplink_packet_loss_fraction = kChracteristicPacketLossFraction[1];
-  fake_clock.AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(kMinReorderingTimeMs - 1));
+  fake_clock.AdvanceTime(TimeDelta::ms(kMinReorderingTimeMs - 1));
   controllers = states.controller_manager->GetSortedControllers(metrics);
   // Should not reorder since min reordering time is not met.
   CheckControllersOrder(controllers,
@@ -458,7 +453,7 @@
                             ControllerType::CHANNEL, ControllerType::DTX,
                             ControllerType::BIT_RATE});
 
-  fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1));
+  fake_clock.AdvanceTime(TimeDelta::ms(1));
   controllers = states.controller_manager->GetSortedControllers(metrics);
   // Reorder now.
   CheckControllersOrder(controllers,
diff --git a/modules/audio_coding/audio_network_adaptor/dtx_controller.h b/modules/audio_coding/audio_network_adaptor/dtx_controller.h
index 8a2427e..fb40db2 100644
--- a/modules/audio_coding/audio_network_adaptor/dtx_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/dtx_controller.h
@@ -40,7 +40,7 @@
  private:
   const Config config_;
   bool dtx_enabled_;
-  rtc::Optional<int> uplink_bandwidth_bps_;
+  absl::optional<int> uplink_bandwidth_bps_;
   RTC_DISALLOW_COPY_AND_ASSIGN(DtxController);
 };
 
diff --git a/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc
index e38e65d..67bf9e5 100644
--- a/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/dtx_controller_unittest.cc
@@ -30,7 +30,7 @@
 }
 
 void CheckDecision(DtxController* controller,
-                   const rtc::Optional<int>& uplink_bandwidth_bps,
+                   const absl::optional<int>& uplink_bandwidth_bps,
                    bool expected_dtx_enabled) {
   if (uplink_bandwidth_bps) {
     Controller::NetworkMetrics network_metrics;
@@ -47,7 +47,7 @@
 TEST(DtxControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) {
   constexpr bool kInitialDtxEnabled = true;
   auto controller = CreateController(kInitialDtxEnabled);
-  CheckDecision(controller.get(), rtc::nullopt, kInitialDtxEnabled);
+  CheckDecision(controller.get(), absl::nullopt, kInitialDtxEnabled);
 }
 
 TEST(DtxControllerTest, TurnOnDtxForLowUplinkBandwidth) {
diff --git a/modules/audio_coding/audio_network_adaptor/event_log_writer.cc b/modules/audio_coding/audio_network_adaptor/event_log_writer.cc
index 9cdbc54..4a92343 100644
--- a/modules/audio_coding/audio_network_adaptor/event_log_writer.cc
+++ b/modules/audio_coding/audio_network_adaptor/event_log_writer.cc
@@ -12,10 +12,10 @@
 
 #include <algorithm>
 
+#include "absl/memory/memory.h"
 #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h"
 #include "logging/rtc_event_log/rtc_event_log.h"
 #include "modules/audio_coding/audio_network_adaptor/event_log_writer.h"
-#include "rtc_base/ptr_util.h"
 
 namespace webrtc {
 
@@ -63,9 +63,9 @@
 }
 
 void EventLogWriter::LogEncoderConfig(const AudioEncoderRuntimeConfig& config) {
-  auto config_copy = rtc::MakeUnique<AudioEncoderRuntimeConfig>(config);
-  event_log_->Log(
-      rtc::MakeUnique<RtcEventAudioNetworkAdaptation>(std::move(config_copy)));
+  auto config_copy = absl::make_unique<AudioEncoderRuntimeConfig>(config);
+  event_log_->Log(absl::make_unique<RtcEventAudioNetworkAdaptation>(
+      std::move(config_copy)));
   last_logged_config_ = config;
 }
 
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.cc
index 62f356d..7ab72c9 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.cc
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.cc
@@ -23,7 +23,7 @@
  public:
   void AddSample(float sample) override { last_sample_ = sample; }
 
-  rtc::Optional<float> GetAverage() override { return last_sample_; }
+  absl::optional<float> GetAverage() override { return last_sample_; }
 
   bool SetTimeConstantMs(int time_constant_ms) override {
     RTC_NOTREACHED();
@@ -31,9 +31,9 @@
   }
 
  private:
-  rtc::Optional<float> last_sample_;
+  absl::optional<float> last_sample_;
 };
-}
+}  // namespace
 
 FecControllerPlrBased::Config::Config(
     bool initial_fec_enabled,
@@ -89,7 +89,7 @@
 }
 
 bool FecControllerPlrBased::FecEnablingDecision(
-    const rtc::Optional<float>& packet_loss) const {
+    const absl::optional<float>& packet_loss) const {
   if (!uplink_bandwidth_bps_ || !packet_loss) {
     return false;
   } else {
@@ -100,7 +100,7 @@
 }
 
 bool FecControllerPlrBased::FecDisablingDecision(
-    const rtc::Optional<float>& packet_loss) const {
+    const absl::optional<float>& packet_loss) const {
   if (!uplink_bandwidth_bps_ || !packet_loss) {
     return false;
   } else {
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
index c273537..b66883e 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h
@@ -56,12 +56,12 @@
   void MakeDecision(AudioEncoderRuntimeConfig* config) override;
 
  private:
-  bool FecEnablingDecision(const rtc::Optional<float>& packet_loss) const;
-  bool FecDisablingDecision(const rtc::Optional<float>& packet_loss) const;
+  bool FecEnablingDecision(const absl::optional<float>& packet_loss) const;
+  bool FecDisablingDecision(const absl::optional<float>& packet_loss) const;
 
   const Config config_;
   bool fec_enabled_;
-  rtc::Optional<int> uplink_bandwidth_bps_;
+  absl::optional<int> uplink_bandwidth_bps_;
   const std::unique_ptr<SmoothingFilter> packet_loss_smoother_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(FecControllerPlrBased);
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
index 8636aa9..de66717 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
@@ -78,8 +78,8 @@
 }
 
 void UpdateNetworkMetrics(FecControllerPlrBasedTestStates* states,
-                          const rtc::Optional<int>& uplink_bandwidth_bps,
-                          const rtc::Optional<float>& uplink_packet_loss) {
+                          const absl::optional<int>& uplink_bandwidth_bps,
+                          const absl::optional<float>& uplink_packet_loss) {
   // UpdateNetworkMetrics can accept multiple network metric updates at once.
   // However, currently, the most used case is to update one metric at a time.
   // To reflect this fact, we separate the calls.
@@ -131,7 +131,7 @@
           kEnablingPacketLossAtLowBw - kEpsilon, kEnablingPacketLossAtLowBw,
           kEnablingPacketLossAtLowBw + kEpsilon}) {
       auto states = CreateFecControllerPlrBased(initial_fec_enabled);
-      UpdateNetworkMetrics(&states, rtc::nullopt, packet_loss);
+      UpdateNetworkMetrics(&states, absl::nullopt, packet_loss);
       CheckDecision(&states, initial_fec_enabled, packet_loss);
     }
   }
@@ -146,7 +146,7 @@
                           kDisablingBandwidthLow + 1, kEnablingBandwidthLow - 1,
                           kEnablingBandwidthLow, kEnablingBandwidthLow + 1}) {
       auto states = CreateFecControllerPlrBased(initial_fec_enabled);
-      UpdateNetworkMetrics(&states, bandwidth, rtc::nullopt);
+      UpdateNetworkMetrics(&states, bandwidth, absl::nullopt);
       CheckDecision(&states, initial_fec_enabled, 0.0);
     }
   }
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
index ade55ae..9a3c37c 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h
@@ -55,8 +55,8 @@
 
   const Config config_;
   bool fec_enabled_;
-  rtc::Optional<int> uplink_bandwidth_bps_;
-  rtc::Optional<float> uplink_recoverable_packet_loss_;
+  absl::optional<int> uplink_bandwidth_bps_;
+  absl::optional<float> uplink_recoverable_packet_loss_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(FecControllerRplrBased);
 };
diff --git a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
index 0fc003b..8e8704e 100644
--- a/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
@@ -44,14 +44,14 @@
 
 constexpr float kEpsilon = 1e-5f;
 
-rtc::Optional<float> GetRandomProbabilityOrUnknown() {
+absl::optional<float> GetRandomProbabilityOrUnknown() {
   std::random_device rd;
   std::mt19937 generator(rd());
   std::uniform_real_distribution<> distribution(0, 1);
 
   return (distribution(generator) < 0.2)
-             ? rtc::nullopt
-             : rtc::Optional<float>(distribution(generator));
+             ? absl::nullopt
+             : absl::optional<float>(distribution(generator));
 }
 
 std::unique_ptr<FecControllerRplrBased> CreateFecControllerRplrBased(
@@ -70,9 +70,9 @@
 
 void UpdateNetworkMetrics(
     FecControllerRplrBased* controller,
-    const rtc::Optional<int>& uplink_bandwidth_bps,
-    const rtc::Optional<float>& uplink_packet_loss,
-    const rtc::Optional<float>& uplink_recoveralbe_packet_loss) {
+    const absl::optional<int>& uplink_bandwidth_bps,
+    const absl::optional<float>& uplink_packet_loss,
+    const absl::optional<float>& uplink_recoveralbe_packet_loss) {
   // UpdateNetworkMetrics can accept multiple network metric updates at once.
   // However, currently, the most used case is to update one metric at a time.
   // To reflect this fact, we separate the calls.
@@ -96,8 +96,8 @@
 
 void UpdateNetworkMetrics(
     FecControllerRplrBased* controller,
-    const rtc::Optional<int>& uplink_bandwidth_bps,
-    const rtc::Optional<float>& uplink_recoveralbe_packet_loss) {
+    const absl::optional<int>& uplink_bandwidth_bps,
+    const absl::optional<float>& uplink_recoveralbe_packet_loss) {
   // FecControllerRplrBased doesn't currently use the PLR (general packet-loss
   // rate) at all. (This might be changed in the future.) The unit-tests will
   // use a random value (including unknown), to show this does not interfere.
@@ -148,7 +148,7 @@
           kEnablingRecoverablePacketLossAtHighBw,
           kEnablingRecoverablePacketLossAtHighBw + kEpsilon}) {
       auto controller = CreateFecControllerRplrBased(initial_fec_enabled);
-      UpdateNetworkMetrics(controller.get(), rtc::nullopt,
+      UpdateNetworkMetrics(controller.get(), absl::nullopt,
                            recoverable_packet_loss);
       CheckDecision(controller.get(), initial_fec_enabled,
                     recoverable_packet_loss);
@@ -165,7 +165,7 @@
                           kDisablingBandwidthLow + 1, kEnablingBandwidthLow - 1,
                           kEnablingBandwidthLow, kEnablingBandwidthLow + 1}) {
       auto controller = CreateFecControllerRplrBased(initial_fec_enabled);
-      UpdateNetworkMetrics(controller.get(), bandwidth, rtc::nullopt);
+      UpdateNetworkMetrics(controller.get(), bandwidth, absl::nullopt);
       CheckDecision(controller.get(), initial_fec_enabled, 0.0);
     }
   }
@@ -209,11 +209,11 @@
   auto controller = CreateFecControllerRplrBased(false);
   constexpr float kRecoverablePacketLoss =
       (kEnablingRecoverablePacketLossAtLowBw +
-       kEnablingRecoverablePacketLossAtHighBw) / 2.0;
-  UpdateNetworkMetrics(
-      controller.get(),
-      (kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2,
-      kRecoverablePacketLoss);
+       kEnablingRecoverablePacketLossAtHighBw) /
+      2.0;
+  UpdateNetworkMetrics(controller.get(),
+                       (kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2,
+                       kRecoverablePacketLoss);
   CheckDecision(controller.get(), true, kRecoverablePacketLoss);
 }
 
@@ -274,11 +274,12 @@
   auto controller = CreateFecControllerRplrBased(true);
   constexpr float kRecoverablePacketLoss =
       ((kDisablingRecoverablePacketLossAtLowBw +
-        kDisablingRecoverablePacketLossAtHighBw) / 2.0f) - kEpsilon;
-  UpdateNetworkMetrics(
-      controller.get(),
-      (kDisablingBandwidthHigh + kDisablingBandwidthLow) / 2,
-      kRecoverablePacketLoss);
+        kDisablingRecoverablePacketLossAtHighBw) /
+       2.0f) -
+      kEpsilon;
+  UpdateNetworkMetrics(controller.get(),
+                       (kDisablingBandwidthHigh + kDisablingBandwidthLow) / 2,
+                       kRecoverablePacketLoss);
   CheckDecision(controller.get(), false, kRecoverablePacketLoss);
 }
 
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
index 6c3cae0..40e97cb 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller.cc
@@ -25,7 +25,7 @@
   return static_cast<int>(overhead_bytes_per_packet * 8 * 1000 /
                           frame_length_ms);
 }
-}
+}  // namespace
 
 FrameLengthController::Config::Config(
     const std::vector<int>& encoder_frame_lengths_ms,
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller.h b/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
index c254b3d..f084fd0 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller.h
@@ -73,11 +73,11 @@
 
   std::vector<int>::const_iterator frame_length_ms_;
 
-  rtc::Optional<int> uplink_bandwidth_bps_;
+  absl::optional<int> uplink_bandwidth_bps_;
 
-  rtc::Optional<float> uplink_packet_loss_fraction_;
+  absl::optional<float> uplink_packet_loss_fraction_;
 
-  rtc::Optional<size_t> overhead_bytes_per_packet_;
+  absl::optional<size_t> overhead_bytes_per_packet_;
 
   // True if the previous frame length decision was an increase, otherwise
   // false.
diff --git a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
index 1f98447..f97ad4f 100644
--- a/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
+++ b/modules/audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc
@@ -78,9 +78,9 @@
 
 void UpdateNetworkMetrics(
     FrameLengthController* controller,
-    const rtc::Optional<int>& uplink_bandwidth_bps,
-    const rtc::Optional<float>& uplink_packet_loss_fraction,
-    const rtc::Optional<size_t>& overhead_bytes_per_packet) {
+    const absl::optional<int>& uplink_bandwidth_bps,
+    const absl::optional<float>& uplink_packet_loss_fraction,
+    const absl::optional<size_t>& overhead_bytes_per_packet) {
   // UpdateNetworkMetrics can accept multiple network metric updates at once.
   // However, currently, the most used case is to update one metric at a time.
   // To reflect this fact, we separate the calls.
@@ -114,14 +114,14 @@
   auto controller =
       CreateController(CreateChangeCriteriaFor20msAnd60ms(), {20, 60}, 60);
   UpdateNetworkMetrics(controller.get(), kFl60msTo20msBandwidthBps,
-                       rtc::nullopt, kOverheadBytesPerPacket);
+                       absl::nullopt, kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 20);
 }
 
 TEST(FrameLengthControllerTest, DecreaseTo20MsOnHighUplinkPacketLossFraction) {
   auto controller =
       CreateController(CreateChangeCriteriaFor20msAnd60ms(), {20, 60}, 60);
-  UpdateNetworkMetrics(controller.get(), rtc::nullopt,
+  UpdateNetworkMetrics(controller.get(), absl::nullopt,
                        kFlDecreasingPacketLossFraction,
                        kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 20);
@@ -252,16 +252,12 @@
   auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
                                      {20, 60, 120}, 120);
   // It takes two steps for frame length to go from 120ms to 20ms.
-  UpdateNetworkMetrics(controller.get(),
-                       kFl60msTo20msBandwidthBps,
-                       rtc::nullopt,
-                       kOverheadBytesPerPacket);
+  UpdateNetworkMetrics(controller.get(), kFl60msTo20msBandwidthBps,
+                       absl::nullopt, kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 60);
 
-  UpdateNetworkMetrics(controller.get(),
-                       kFl60msTo20msBandwidthBps,
-                       rtc::nullopt,
-                       kOverheadBytesPerPacket);
+  UpdateNetworkMetrics(controller.get(), kFl60msTo20msBandwidthBps,
+                       absl::nullopt, kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 20);
 }
 
@@ -269,12 +265,12 @@
   auto controller = CreateController(CreateChangeCriteriaFor20ms60msAnd120ms(),
                                      {20, 60, 120}, 120);
   // It takes two steps for frame length to go from 120ms to 20ms.
-  UpdateNetworkMetrics(controller.get(), rtc::nullopt,
+  UpdateNetworkMetrics(controller.get(), absl::nullopt,
                        kFlDecreasingPacketLossFraction,
                        kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 60);
 
-  UpdateNetworkMetrics(controller.get(), rtc::nullopt,
+  UpdateNetworkMetrics(controller.get(), absl::nullopt,
                        kFlDecreasingPacketLossFraction,
                        kOverheadBytesPerPacket);
   CheckDecision(controller.get(), 20);
diff --git a/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h b/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h
index 7687446..c11279e 100644
--- a/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h
+++ b/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_INCLUDE_AUDIO_NETWORK_ADAPTOR_H_
 #define MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_INCLUDE_AUDIO_NETWORK_ADAPTOR_H_
 
+#include "absl/types/optional.h"
 #include "api/audio_codecs/audio_encoder.h"
-#include "api/optional.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
 
 namespace webrtc {
diff --git a/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h b/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h
index 874fc97..257a79a 100644
--- a/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h
+++ b/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h
@@ -11,7 +11,7 @@
 #ifndef MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_INCLUDE_AUDIO_NETWORK_ADAPTOR_CONFIG_H_
 #define MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_INCLUDE_AUDIO_NETWORK_ADAPTOR_CONFIG_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace webrtc {
 
@@ -21,18 +21,18 @@
   ~AudioEncoderRuntimeConfig();
   AudioEncoderRuntimeConfig& operator=(const AudioEncoderRuntimeConfig& other);
   bool operator==(const AudioEncoderRuntimeConfig& other) const;
-  rtc::Optional<int> bitrate_bps;
-  rtc::Optional<int> frame_length_ms;
+  absl::optional<int> bitrate_bps;
+  absl::optional<int> frame_length_ms;
   // Note: This is what we tell the encoder. It doesn't have to reflect
   // the actual NetworkMetrics; it's subject to our decision.
-  rtc::Optional<float> uplink_packet_loss_fraction;
-  rtc::Optional<bool> enable_fec;
-  rtc::Optional<bool> enable_dtx;
+  absl::optional<float> uplink_packet_loss_fraction;
+  absl::optional<bool> enable_fec;
+  absl::optional<bool> enable_dtx;
 
   // Some encoders can encode fewer channels than the actual input to make
   // better use of the bandwidth. |num_channels| sets the number of channels
   // to encode.
-  rtc::Optional<size_t> num_channels;
+  absl::optional<size_t> num_channels;
 
   // This is true if the last frame length change was an increase, and otherwise
   // false.
diff --git a/modules/audio_coding/codecs/audio_format_conversion.cc b/modules/audio_coding/codecs/audio_format_conversion.cc
index a99a28c..e38aa33 100644
--- a/modules/audio_coding/codecs/audio_format_conversion.cc
+++ b/modules/audio_coding/codecs/audio_format_conversion.cc
@@ -12,8 +12,8 @@
 
 #include <string.h>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/numerics/safe_conversions.h"
 #include "rtc_base/sanitizer.h"
diff --git a/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc b/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc
index 158a58b..9b36dfd 100644
--- a/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc
+++ b/modules/audio_coding/codecs/builtin_audio_decoder_factory_unittest.cc
@@ -20,7 +20,7 @@
       CreateBuiltinAudioDecoderFactory();
   ASSERT_TRUE(adf);
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("rey", 8000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("rey", 8000, 1), absl::nullopt));
 }
 
 TEST(AudioDecoderFactoryTest, CreatePcmu) {
@@ -29,15 +29,15 @@
   ASSERT_TRUE(adf);
   // PCMu supports 8 kHz, and any number of channels.
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 0), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 0), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 1), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 2), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 2), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 3), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 8000, 3), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 16000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcmu", 16000, 1), absl::nullopt));
 }
 
 TEST(AudioDecoderFactoryTest, CreatePcma) {
@@ -46,15 +46,15 @@
   ASSERT_TRUE(adf);
   // PCMa supports 8 kHz, and any number of channels.
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 0), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 0), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 1), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 2), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 2), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 3), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 8000, 3), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 16000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("pcma", 16000, 1), absl::nullopt));
 }
 
 TEST(AudioDecoderFactoryTest, CreateIlbc) {
@@ -63,15 +63,15 @@
   ASSERT_TRUE(adf);
   // iLBC supports 8 kHz, 1 channel.
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 8000, 0), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 8000, 0), absl::nullopt));
 #ifdef WEBRTC_CODEC_ILBC
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 8000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 8000, 1), absl::nullopt));
 #endif
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 8000, 2), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 8000, 2), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 16000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("ilbc", 16000, 1), absl::nullopt));
 }
 
 TEST(AudioDecoderFactoryTest, CreateIsac) {
@@ -81,21 +81,21 @@
   // iSAC supports 16 kHz, 1 channel. The float implementation additionally
   // supports 32 kHz, 1 channel.
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 16000, 0), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 16000, 0), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 16000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 16000, 1), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 16000, 2), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 16000, 2), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 8000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 8000, 1), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 48000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 48000, 1), absl::nullopt));
 #ifdef WEBRTC_ARCH_ARM
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 32000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 32000, 1), absl::nullopt));
 #else
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("isac", 32000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("isac", 32000, 1), absl::nullopt));
 #endif
 }
 
@@ -108,10 +108,10 @@
   const int num_channels[] = {1, 2, 3, 4711};
   for (int clockrate : clockrates) {
     EXPECT_FALSE(adf->MakeAudioDecoder(SdpAudioFormat("l16", clockrate, 0),
-                                       rtc::nullopt));
+                                       absl::nullopt));
     for (int channels : num_channels) {
       EXPECT_TRUE(adf->MakeAudioDecoder(
-          SdpAudioFormat("l16", clockrate, channels), rtc::nullopt));
+          SdpAudioFormat("l16", clockrate, channels), absl::nullopt));
     }
   }
 }
@@ -122,21 +122,21 @@
   ASSERT_TRUE(adf);
   // g722 supports 8 kHz, 1-2 channels.
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 0), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 0), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 1), absl::nullopt));
   EXPECT_TRUE(
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 2), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 2), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 3), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 3), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 16000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 16000, 1), absl::nullopt));
   EXPECT_FALSE(
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 32000, 1), rtc::nullopt));
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 32000, 1), absl::nullopt));
 
   // g722 actually uses a 16 kHz sample rate instead of the nominal 8 kHz.
   std::unique_ptr<AudioDecoder> dec =
-      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 1), rtc::nullopt);
+      adf->MakeAudioDecoder(SdpAudioFormat("g722", 8000, 1), absl::nullopt);
   EXPECT_EQ(16000, dec->SampleRateHz());
 }
 
@@ -158,7 +158,7 @@
         EXPECT_EQ(good,
                   static_cast<bool>(adf->MakeAudioDecoder(
                       SdpAudioFormat("opus", hz, channels, std::move(params)),
-                      rtc::nullopt)));
+                      absl::nullopt)));
       }
     }
   }
diff --git a/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc b/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
index d371149..64f0159 100644
--- a/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
+++ b/modules/audio_coding/codecs/builtin_audio_encoder_factory_unittest.cc
@@ -43,7 +43,7 @@
   auto supported_encoders = factory->GetSupportedEncoders();
   for (const auto& spec : supported_encoders) {
     auto info = factory->QueryAudioEncoder(spec.format);
-    auto encoder = factory->MakeAudioEncoder(127, spec.format, rtc::nullopt);
+    auto encoder = factory->MakeAudioEncoder(127, spec.format, absl::nullopt);
     EXPECT_TRUE(encoder);
     EXPECT_EQ(encoder->SampleRateHz(), info->sample_rate_hz);
     EXPECT_EQ(encoder->NumChannels(), info->num_channels);
@@ -57,7 +57,7 @@
   auto supported_encoders = factory->GetSupportedEncoders();
   for (const auto& spec : supported_encoders) {
     auto encoder =
-        factory->MakeAudioEncoder(kTestPayloadType, spec.format, rtc::nullopt);
+        factory->MakeAudioEncoder(kTestPayloadType, spec.format, absl::nullopt);
     EXPECT_TRUE(encoder);
     encoder->Reset();
     const int num_samples = rtc::checked_cast<int>(
diff --git a/modules/audio_coding/codecs/cng/audio_encoder_cng.cc b/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
index dc4c21e..4cda340 100644
--- a/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
+++ b/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
@@ -11,8 +11,8 @@
 #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
 
 #include <algorithm>
-#include <memory>
 #include <limits>
+#include <memory>
 #include <utility>
 
 namespace webrtc {
@@ -158,9 +158,8 @@
   rtp_timestamps_.clear();
   last_frame_active_ = true;
   vad_->Reset();
-  cng_encoder_.reset(
-      new ComfortNoiseEncoder(SampleRateHz(), sid_frame_interval_ms_,
-                              num_cng_coefficients_));
+  cng_encoder_.reset(new ComfortNoiseEncoder(
+      SampleRateHz(), sid_frame_interval_ms_, num_cng_coefficients_));
 }
 
 bool AudioEncoderCng::SetFec(bool enable) {
@@ -198,7 +197,7 @@
 
 void AudioEncoderCng::OnReceivedUplinkBandwidth(
     int target_audio_bitrate_bps,
-    rtc::Optional<int64_t> bwe_period_ms) {
+    absl::optional<int64_t> bwe_period_ms) {
   speech_encoder_->OnReceivedUplinkBandwidth(target_audio_bitrate_bps,
                                              bwe_period_ms);
 }
@@ -217,11 +216,10 @@
     // that value, in which case we don't want to overwrite any value from
     // an earlier iteration.
     size_t encoded_bytes_tmp =
-        cng_encoder_->Encode(
-            rtc::ArrayView<const int16_t>(
-                &speech_buffer_[i * samples_per_10ms_frame],
-                samples_per_10ms_frame),
-            force_sid, encoded);
+        cng_encoder_->Encode(rtc::ArrayView<const int16_t>(
+                                 &speech_buffer_[i * samples_per_10ms_frame],
+                                 samples_per_10ms_frame),
+                             force_sid, encoded);
 
     if (encoded_bytes_tmp > 0) {
       RTC_CHECK(!output_produced);
@@ -238,9 +236,8 @@
   return info;
 }
 
-AudioEncoder::EncodedInfo AudioEncoderCng::EncodeActive(
-    size_t frames_to_encode,
-    rtc::Buffer* encoded) {
+AudioEncoder::EncodedInfo AudioEncoderCng::EncodeActive(size_t frames_to_encode,
+                                                        rtc::Buffer* encoded) {
   const size_t samples_per_10ms_frame = SamplesPer10msFrame();
   AudioEncoder::EncodedInfo info;
   for (size_t i = 0; i < frames_to_encode; ++i) {
diff --git a/modules/audio_coding/codecs/cng/audio_encoder_cng.h b/modules/audio_coding/codecs/cng/audio_encoder_cng.h
index 4491289..e4c6507 100644
--- a/modules/audio_coding/codecs/cng/audio_encoder_cng.h
+++ b/modules/audio_coding/codecs/cng/audio_encoder_cng.h
@@ -69,7 +69,7 @@
       float uplink_recoverable_packet_loss_fraction) override;
   void OnReceivedUplinkBandwidth(
       int target_audio_bitrate_bps,
-      rtc::Optional<int64_t> bwe_period_ms) override;
+      absl::optional<int64_t> bwe_period_ms) override;
 
  private:
   EncodedInfo EncodePassive(size_t frames_to_encode,
diff --git a/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc b/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
index f85abe2..a76dcbd 100644
--- a/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
+++ b/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
@@ -30,7 +30,7 @@
 static const size_t kMaxNumSamples = 48 * 10 * 2;  // 10 ms @ 48 kHz stereo.
 static const size_t kMockReturnEncodedBytes = 17;
 static const int kCngPayloadType = 18;
-}
+}  // namespace
 
 class AudioEncoderCngTest : public ::testing::Test {
  protected:
@@ -94,8 +94,7 @@
     InSequence s;
     AudioEncoder::EncodedInfo info;
     for (size_t j = 0; j < num_calls - 1; ++j) {
-      EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
-          .WillOnce(Return(info));
+      EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _)).WillOnce(Return(info));
     }
     info.encoded_bytes = kMockReturnEncodedBytes;
     EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
@@ -155,12 +154,14 @@
     EXPECT_CALL(
         *mock_vad_,
         VoiceActivity(_, expected_first_block_size_ms * sample_rate_hz_ / 1000,
-                      sample_rate_hz_)).WillOnce(Return(Vad::kPassive));
+                      sample_rate_hz_))
+        .WillOnce(Return(Vad::kPassive));
     if (expected_second_block_size_ms > 0) {
       EXPECT_CALL(*mock_vad_,
                   VoiceActivity(
                       _, expected_second_block_size_ms * sample_rate_hz_ / 1000,
-                      sample_rate_hz_)).WillOnce(Return(Vad::kPassive));
+                      sample_rate_hz_))
+          .WillOnce(Return(Vad::kPassive));
     }
 
     // With this call to Encode(), |mock_vad_| should be called according to the
@@ -220,8 +221,8 @@
 TEST_F(AudioEncoderCngTest, CheckTargetAudioBitratePropagation) {
   CreateCng(MakeCngConfig());
   EXPECT_CALL(*mock_encoder_,
-              OnReceivedUplinkBandwidth(4711, rtc::Optional<int64_t>()));
-  cng_->OnReceivedUplinkBandwidth(4711, rtc::nullopt);
+              OnReceivedUplinkBandwidth(4711, absl::optional<int64_t>()));
+  cng_->OnReceivedUplinkBandwidth(4711, absl::nullopt);
 }
 
 TEST_F(AudioEncoderCngTest, CheckPacketLossFractionPropagation) {
@@ -429,9 +430,7 @@
   // Override AudioEncoderCngTest::TearDown, since that one expects a call to
   // the destructor of |mock_vad_|. In this case, that object is already
   // deleted.
-  void TearDown() override {
-    cng_.reset();
-  }
+  void TearDown() override { cng_.reset(); }
 
   AudioEncoderCng::Config MakeCngConfig() {
     // Don't provide a Vad mock object, since it would leak when the test dies.
diff --git a/modules/audio_coding/codecs/cng/cng_unittest.cc b/modules/audio_coding/codecs/cng/cng_unittest.cc
index 54e5189..81688b1 100644
--- a/modules/audio_coding/codecs/cng/cng_unittest.cc
+++ b/modules/audio_coding/codecs/cng/cng_unittest.cc
@@ -29,10 +29,7 @@
   kCNGNumParamsTooHigh = WEBRTC_CNG_MAX_LPC_ORDER + 1
 };
 
-enum {
-  kNoSid,
-  kForceSid
-};
+enum { kNoSid, kForceSid };
 
 class CngTest : public ::testing::Test {
  protected:
@@ -46,11 +43,11 @@
 void CngTest::SetUp() {
   FILE* input_file;
   const std::string file_name =
-        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+      webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
   input_file = fopen(file_name.c_str(), "rb");
   ASSERT_TRUE(input_file != NULL);
-  ASSERT_EQ(640, static_cast<int32_t>(fread(speech_data_, sizeof(int16_t),
-                                             640, input_file)));
+  ASSERT_EQ(640, static_cast<int32_t>(
+                     fread(speech_data_, sizeof(int16_t), 640, input_file)));
   fclose(input_file);
   input_file = NULL;
 }
@@ -74,11 +71,18 @@
 // Create CNG encoder, init with faulty values, free CNG encoder.
 TEST_F(CngTest, CngInitFail) {
   // Call with too few parameters.
-  EXPECT_DEATH({ ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate,
-                                     kCNGNumParamsLow); }, "");
+  EXPECT_DEATH(
+      {
+        ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate, kCNGNumParamsLow);
+      },
+      "");
   // Call with too many parameters.
-  EXPECT_DEATH({ ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate,
-                                     kCNGNumParamsTooHigh); }, "");
+  EXPECT_DEATH(
+      {
+        ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate,
+                            kCNGNumParamsTooHigh);
+      },
+      "");
 }
 
 // Encode Cng with too long input vector.
@@ -209,13 +213,15 @@
 
   // Normal Encode, 100 msec, where no SID data should be generated.
   for (int i = 0; i < 10; i++) {
-    EXPECT_EQ(0U, cng_encoder.Encode(
-        rtc::ArrayView<const int16_t>(speech_data_, 160), kNoSid, &sid_data));
+    EXPECT_EQ(
+        0U, cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
+                               kNoSid, &sid_data));
   }
 
   // We have reached 100 msec, and SID data should be generated.
-  EXPECT_EQ(kCNGNumParamsNormal + 1, cng_encoder.Encode(
-      rtc::ArrayView<const int16_t>(speech_data_, 160), kNoSid, &sid_data));
+  EXPECT_EQ(kCNGNumParamsNormal + 1,
+            cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
+                               kNoSid, &sid_data));
 }
 
 // Test automatic SID, with very short interval.
@@ -228,13 +234,16 @@
   ComfortNoiseDecoder cng_decoder;
 
   // First call will never generate SID, unless forced to.
-  EXPECT_EQ(0U, cng_encoder.Encode(
-      rtc::ArrayView<const int16_t>(speech_data_, 160), kNoSid, &sid_data));
+  EXPECT_EQ(0U,
+            cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
+                               kNoSid, &sid_data));
 
   // Normal Encode, 100 msec, SID data should be generated all the time.
   for (int i = 0; i < 10; i++) {
-    EXPECT_EQ(kCNGNumParamsNormal + 1, cng_encoder.Encode(
-        rtc::ArrayView<const int16_t>(speech_data_, 160), kNoSid, &sid_data));
+    EXPECT_EQ(
+        kCNGNumParamsNormal + 1,
+        cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
+                           kNoSid, &sid_data));
   }
 }
 
diff --git a/modules/audio_coding/codecs/cng/webrtc_cng.cc b/modules/audio_coding/codecs/cng/webrtc_cng.cc
index bd17a61..a07b093 100644
--- a/modules/audio_coding/codecs/cng/webrtc_cng.cc
+++ b/modules/audio_coding/codecs/cng/webrtc_cng.cc
@@ -25,28 +25,26 @@
 void WebRtcCng_K2a16(int16_t* k, int useOrder, int16_t* a);
 
 const int32_t WebRtcCng_kDbov[94] = {
-  1081109975, 858756178, 682134279, 541838517, 430397633, 341876992,
-  271562548,  215709799, 171344384, 136103682, 108110997, 85875618,
-  68213428,   54183852,  43039763,  34187699,  27156255,  21570980,
-  17134438,   13610368,  10811100,  8587562,   6821343,   5418385,
-  4303976,    3418770,   2715625,   2157098,   1713444,   1361037,
-  1081110,    858756,    682134,    541839,    430398,    341877,
-  271563,     215710,    171344,    136104,    108111,    85876,
-  68213,      54184,     43040,     34188,     27156,     21571,
-  17134,      13610,     10811,     8588,      6821,      5418,
-  4304,       3419,      2716,      2157,      1713,      1361,
-  1081,       859,       682,       542,       430,       342,
-  272,        216,       171,       136,       108,       86,
-  68,         54,        43,        34,        27,        22,
-  17,         14,        11,        9,         7,         5,
-  4,          3,         3,         2,         2,         1,
-  1,          1,         1,         1
-};
+    1081109975, 858756178, 682134279, 541838517, 430397633, 341876992,
+    271562548,  215709799, 171344384, 136103682, 108110997, 85875618,
+    68213428,   54183852,  43039763,  34187699,  27156255,  21570980,
+    17134438,   13610368,  10811100,  8587562,   6821343,   5418385,
+    4303976,    3418770,   2715625,   2157098,   1713444,   1361037,
+    1081110,    858756,    682134,    541839,    430398,    341877,
+    271563,     215710,    171344,    136104,    108111,    85876,
+    68213,      54184,     43040,     34188,     27156,     21571,
+    17134,      13610,     10811,     8588,      6821,      5418,
+    4304,       3419,      2716,      2157,      1713,      1361,
+    1081,       859,       682,       542,       430,       342,
+    272,        216,       171,       136,       108,       86,
+    68,         54,        43,        34,        27,        22,
+    17,         14,        11,        9,         7,         5,
+    4,          3,         3,         2,         2,         1,
+    1,          1,         1,         1};
 
 const int16_t WebRtcCng_kCorrWindow[WEBRTC_CNG_MAX_LPC_ORDER] = {
-  32702, 32636, 32570, 32505, 32439, 32374,
-  32309, 32244, 32179, 32114, 32049, 31985
-};
+    32702, 32636, 32570, 32505, 32439, 32374,
+    32309, 32244, 32179, 32114, 32049, 31985};
 
 }  // namespace
 
@@ -57,7 +55,7 @@
 }
 
 void ComfortNoiseDecoder::Reset() {
-  dec_seed_ = 7777;  /* For debugging only. */
+  dec_seed_ = 7777; /* For debugging only. */
   dec_target_energy_ = 0;
   dec_used_energy_ = 0;
   for (auto& c : dec_target_reflCoefs_)
@@ -115,11 +113,11 @@
   int16_t excitation[kCngMaxOutsizeOrder];
   int16_t low[kCngMaxOutsizeOrder];
   int16_t lpPoly[WEBRTC_CNG_MAX_LPC_ORDER + 1];
-  int16_t ReflBetaStd = 26214;  /* 0.8 in q15. */
-  int16_t ReflBetaCompStd = 6553;  /* 0.2 in q15. */
-  int16_t ReflBetaNewP = 19661;  /* 0.6 in q15. */
-  int16_t ReflBetaCompNewP = 13107;  /* 0.4 in q15. */
-  int16_t Beta, BetaC;  /* These are in Q15. */
+  int16_t ReflBetaStd = 26214;      /* 0.8 in q15. */
+  int16_t ReflBetaCompStd = 6553;   /* 0.2 in q15. */
+  int16_t ReflBetaNewP = 19661;     /* 0.6 in q15. */
+  int16_t ReflBetaCompNewP = 13107; /* 0.4 in q15. */
+  int16_t Beta, BetaC;              /* These are in Q15. */
   int32_t targetEnergy;
   int16_t En;
   int16_t temp16;
@@ -139,30 +137,28 @@
   }
 
   /* Calculate new scale factor in Q13 */
-  dec_used_scale_factor_ =
-      rtc::checked_cast<int16_t>(
-          WEBRTC_SPL_MUL_16_16_RSFT(dec_used_scale_factor_, Beta >> 2, 13) +
-          WEBRTC_SPL_MUL_16_16_RSFT(dec_target_scale_factor_, BetaC >> 2, 13));
+  dec_used_scale_factor_ = rtc::checked_cast<int16_t>(
+      WEBRTC_SPL_MUL_16_16_RSFT(dec_used_scale_factor_, Beta >> 2, 13) +
+      WEBRTC_SPL_MUL_16_16_RSFT(dec_target_scale_factor_, BetaC >> 2, 13));
 
-  dec_used_energy_  = dec_used_energy_ >> 1;
+  dec_used_energy_ = dec_used_energy_ >> 1;
   dec_used_energy_ += dec_target_energy_ >> 1;
 
   /* Do the same for the reflection coeffs, albeit in Q15. */
   for (size_t i = 0; i < WEBRTC_CNG_MAX_LPC_ORDER; i++) {
-    dec_used_reflCoefs_[i] = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(
-        dec_used_reflCoefs_[i], Beta, 15);
-    dec_used_reflCoefs_[i] += (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(
-        dec_target_reflCoefs_[i], BetaC, 15);
+    dec_used_reflCoefs_[i] =
+        (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(dec_used_reflCoefs_[i], Beta, 15);
+    dec_used_reflCoefs_[i] +=
+        (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(dec_target_reflCoefs_[i], BetaC, 15);
   }
 
   /* Compute the polynomial coefficients. */
   WebRtcCng_K2a16(dec_used_reflCoefs_, WEBRTC_CNG_MAX_LPC_ORDER, lpPoly);
 
-
   targetEnergy = dec_used_energy_;
 
   /* Calculate scaling factor based on filter energy. */
-  En = 8192;  /* 1.0 in Q13. */
+  En = 8192; /* 1.0 in Q13. */
   for (size_t i = 0; i < (WEBRTC_CNG_MAX_LPC_ORDER); i++) {
     /* Floating point value for reference.
        E *= 1.0 - (dec_used_reflCoefs_[i] / 32768.0) *
@@ -171,11 +167,11 @@
 
     /* Same in fixed point. */
     /* K(i).^2 in Q15. */
-    temp16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(
-        dec_used_reflCoefs_[i], dec_used_reflCoefs_[i], 15);
+    temp16 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(dec_used_reflCoefs_[i],
+                                                dec_used_reflCoefs_[i], 15);
     /* 1 - K(i).^2 in Q15. */
     temp16 = 0x7fff - temp16;
-    En = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(En, temp16, 15);
+    En = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(En, temp16, 15);
   }
 
   /* float scaling= sqrt(E * dec_target_energy_ / (1 << 24)); */
@@ -183,8 +179,8 @@
   /* Calculate sqrt(En * target_energy / excitation energy) */
   targetEnergy = WebRtcSpl_Sqrt(dec_used_energy_);
 
-  En = (int16_t) WebRtcSpl_Sqrt(En) << 6;
-  En = (En * 3) >> 1;  /* 1.5 estimates sqrt(2). */
+  En = (int16_t)WebRtcSpl_Sqrt(En) << 6;
+  En = (En * 3) >> 1; /* 1.5 estimates sqrt(2). */
   dec_used_scale_factor_ = (int16_t)((En * targetEnergy) >> 12);
 
   /* Generate excitation. */
@@ -217,7 +213,7 @@
       enc_Energy_(0),
       enc_reflCoefs_{0},
       enc_corrVector_{0},
-      enc_seed_(7777)  /* For debugging only. */ {
+      enc_seed_(7777) /* For debugging only. */ {
   RTC_CHECK_GT(quality, 0);
   RTC_CHECK_LE(quality, WEBRTC_CNG_MAX_LPC_ORDER);
   /* Needed to get the right function pointers in SPLIB. */
@@ -236,7 +232,7 @@
     c = 0;
   for (auto& c : enc_corrVector_)
     c = 0;
-  enc_seed_ = 7777;  /* For debugging only. */
+  enc_seed_ = 7777; /* For debugging only. */
 }
 
 size_t ComfortNoiseEncoder::Encode(rtc::ArrayView<const int16_t> speech,
@@ -312,20 +308,19 @@
       if (negate)
         *bptr = -*bptr;
 
-      blo = (int32_t) * aptr * (*bptr & 0xffff);
-      bhi = ((blo >> 16) & 0xffff)
-          + ((int32_t)(*aptr++) * ((*bptr >> 16) & 0xffff));
+      blo = (int32_t)*aptr * (*bptr & 0xffff);
+      bhi = ((blo >> 16) & 0xffff) +
+            ((int32_t)(*aptr++) * ((*bptr >> 16) & 0xffff));
       blo = (blo & 0xffff) | ((bhi & 0xffff) << 16);
 
-      *bptr = (((bhi >> 16) & 0x7fff) << 17) | ((uint32_t) blo >> 15);
+      *bptr = (((bhi >> 16) & 0x7fff) << 17) | ((uint32_t)blo >> 15);
       if (negate)
         *bptr = -*bptr;
       bptr++;
     }
     /* End of bandwidth expansion. */
 
-    stab = WebRtcSpl_LevinsonDurbin(corrVector, arCoefs, refCs,
-                                    enc_nrOfCoefs_);
+    stab = WebRtcSpl_LevinsonDurbin(corrVector, arCoefs, refCs, enc_nrOfCoefs_);
 
     if (!stab) {
       /* Disregard from this frame */
@@ -345,13 +340,12 @@
   } else {
     /* Average history with new values. */
     for (i = 0; i < enc_nrOfCoefs_; i++) {
-      enc_reflCoefs_[i] = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(
-          enc_reflCoefs_[i], ReflBeta, 15);
+      enc_reflCoefs_[i] =
+          (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(enc_reflCoefs_[i], ReflBeta, 15);
       enc_reflCoefs_[i] +=
-          (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(refCs[i], ReflBetaComp, 15);
+          (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(refCs[i], ReflBetaComp, 15);
     }
-    enc_Energy_ =
-        (outEnergy >> 2) + (enc_Energy_ >> 1) + (enc_Energy_ >> 2);
+    enc_Energy_ = (outEnergy >> 2) + (enc_Energy_ >> 1) + (enc_Energy_ >> 2);
   }
 
   if (enc_Energy_ < 1) {
@@ -372,25 +366,25 @@
       index = 94;
 
     const size_t output_coefs = enc_nrOfCoefs_ + 1;
-    output->AppendData(output_coefs, [&] (rtc::ArrayView<uint8_t> output) {
-        output[0] = (uint8_t)index;
+    output->AppendData(output_coefs, [&](rtc::ArrayView<uint8_t> output) {
+      output[0] = (uint8_t)index;
 
-        /* Quantize coefficients with tweak for WebRtc implementation of
-         * RFC3389. */
-        if (enc_nrOfCoefs_ == WEBRTC_CNG_MAX_LPC_ORDER) {
-          for (i = 0; i < enc_nrOfCoefs_; i++) {
-            /* Q15 to Q7 with rounding. */
-            output[i + 1] = ((enc_reflCoefs_[i] + 128) >> 8);
-          }
-        } else {
-          for (i = 0; i < enc_nrOfCoefs_; i++) {
-            /* Q15 to Q7 with rounding. */
-            output[i + 1] = (127 + ((enc_reflCoefs_[i] + 128) >> 8));
-          }
+      /* Quantize coefficients with tweak for WebRtc implementation of
+       * RFC3389. */
+      if (enc_nrOfCoefs_ == WEBRTC_CNG_MAX_LPC_ORDER) {
+        for (i = 0; i < enc_nrOfCoefs_; i++) {
+          /* Q15 to Q7 with rounding. */
+          output[i + 1] = ((enc_reflCoefs_[i] + 128) >> 8);
         }
+      } else {
+        for (i = 0; i < enc_nrOfCoefs_; i++) {
+          /* Q15 to Q7 with rounding. */
+          output[i + 1] = (127 + ((enc_reflCoefs_[i] + 128) >> 8));
+        }
+      }
 
-        return output_coefs;
-      });
+      return output_coefs;
+    });
 
     enc_msSinceSid_ =
         static_cast<int16_t>((1000 * num_samples) / enc_sampfreq_);
diff --git a/modules/audio_coding/codecs/cng/webrtc_cng.h b/modules/audio_coding/codecs/cng/webrtc_cng.h
index 5e21b8f..684480a 100644
--- a/modules/audio_coding/codecs/cng/webrtc_cng.h
+++ b/modules/audio_coding/codecs/cng/webrtc_cng.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 #ifndef MODULES_AUDIO_CODING_CODECS_CNG_WEBRTC_CNG_H_
 #define MODULES_AUDIO_CODING_CODECS_CNG_WEBRTC_CNG_H_
 
@@ -54,8 +53,8 @@
   int16_t dec_filtstate_[WEBRTC_CNG_MAX_LPC_ORDER + 1];
   int16_t dec_filtstateLow_[WEBRTC_CNG_MAX_LPC_ORDER + 1];
   uint16_t dec_order_;
-  int16_t dec_target_scale_factor_;  /* Q29 */
-  int16_t dec_used_scale_factor_;  /* Q29 */
+  int16_t dec_target_scale_factor_; /* Q29 */
+  int16_t dec_used_scale_factor_;   /* Q29 */
 };
 
 class ComfortNoiseEncoder {
diff --git a/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc b/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc
index a620a3e..25f495f 100644
--- a/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc
+++ b/modules/audio_coding/codecs/g711/audio_decoder_pcm.cc
@@ -10,8 +10,8 @@
 
 #include "modules/audio_coding/codecs/g711/audio_decoder_pcm.h"
 
-#include "modules/audio_coding/codecs/legacy_encoded_audio_frame.h"
 #include "modules/audio_coding/codecs/g711/g711_interface.h"
+#include "modules/audio_coding/codecs/legacy_encoded_audio_frame.h"
 
 namespace webrtc {
 
diff --git a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
index 9fb94fd..c14287e 100644
--- a/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -42,8 +42,8 @@
       payload_type_(config.payload_type),
       num_10ms_frames_per_packet_(
           static_cast<size_t>(config.frame_size_ms / 10)),
-      full_frame_samples_(
-          config.num_channels * config.frame_size_ms * sample_rate_hz / 1000),
+      full_frame_samples_(config.num_channels * config.frame_size_ms *
+                          sample_rate_hz / 1000),
       first_timestamp_in_buffer_(0) {
   RTC_CHECK_GT(sample_rate_hz, 0) << "Sample rate must be larger than 0 Hz";
   RTC_CHECK_EQ(config.frame_size_ms % 10, 0)
@@ -70,8 +70,8 @@
 }
 
 int AudioEncoderPcm::GetTargetBitrate() const {
-  return static_cast<int>(
-      8 * BytesPerSample() * SampleRateHz() * NumChannels());
+  return static_cast<int>(8 * BytesPerSample() * SampleRateHz() *
+                          NumChannels());
 }
 
 AudioEncoder::EncodedInfo AudioEncoderPcm::EncodeImpl(
@@ -89,13 +89,12 @@
   EncodedInfo info;
   info.encoded_timestamp = first_timestamp_in_buffer_;
   info.payload_type = payload_type_;
-  info.encoded_bytes =
-      encoded->AppendData(full_frame_samples_ * BytesPerSample(),
-                          [&] (rtc::ArrayView<uint8_t> encoded) {
-                            return EncodeCall(&speech_buffer_[0],
-                                              full_frame_samples_,
-                                              encoded.data());
-                          });
+  info.encoded_bytes = encoded->AppendData(
+      full_frame_samples_ * BytesPerSample(),
+      [&](rtc::ArrayView<uint8_t> encoded) {
+        return EncodeCall(&speech_buffer_[0], full_frame_samples_,
+                          encoded.data());
+      });
   speech_buffer_.clear();
   info.encoder_type = GetCodecType();
   return info;
diff --git a/modules/audio_coding/codecs/g711/g711.c b/modules/audio_coding/codecs/g711/g711.c
index 0c65764..46a21f4 100644
--- a/modules/audio_coding/codecs/g711/g711.c
+++ b/modules/audio_coding/codecs/g711/g711.c
@@ -21,7 +21,6 @@
  */
 
 #include "modules/audio_coding/codecs/g711/g711.h"
-#include "typedefs.h"  // NOLINT(build/include)
 
 /* Copied from the CCITT G.711 specification */
 static const uint8_t ulaw_to_alaw_table[256] = {
diff --git a/modules/audio_coding/codecs/g711/g711.h b/modules/audio_coding/codecs/g711/g711.h
index 8b1fc81..ac43377 100644
--- a/modules/audio_coding/codecs/g711/g711.h
+++ b/modules/audio_coding/codecs/g711/g711.h
@@ -17,7 +17,8 @@
  * Modifications for WebRtc, 2011/04/28, by tlegrand:
  * -Changed to use WebRtc types
  * -Changed __inline__ to __inline
- * -Two changes to make implementation bitexact with ITU-T reference implementation
+ * -Two changes to make implementation bitexact with ITU-T reference
+ * implementation
  */
 
 /*! \page g711_page A-law and mu-law handling
@@ -49,7 +50,7 @@
 extern "C" {
 #endif
 
-#include "typedefs.h"  // NOLINT(build/include)
+#include <stdint.h>
 
 #if defined(__i386__)
 /*! \brief Find the bit position of the highest set bit in a word
@@ -58,10 +59,11 @@
 static __inline__ int top_bit(unsigned int bits) {
   int res;
 
-  __asm__ __volatile__(" movl $-1,%%edx;\n"
-                       " bsrl %%eax,%%edx;\n"
-                       : "=d" (res)
-                       : "a" (bits));
+  __asm__ __volatile__(
+      " movl $-1,%%edx;\n"
+      " bsrl %%eax,%%edx;\n"
+      : "=d"(res)
+      : "a"(bits));
   return res;
 }
 
@@ -71,30 +73,33 @@
 static __inline__ int bottom_bit(unsigned int bits) {
   int res;
 
-  __asm__ __volatile__(" movl $-1,%%edx;\n"
-                       " bsfl %%eax,%%edx;\n"
-                       : "=d" (res)
-                       : "a" (bits));
+  __asm__ __volatile__(
+      " movl $-1,%%edx;\n"
+      " bsfl %%eax,%%edx;\n"
+      : "=d"(res)
+      : "a"(bits));
   return res;
 }
 #elif defined(__x86_64__)
 static __inline__ int top_bit(unsigned int bits) {
   int res;
 
-  __asm__ __volatile__(" movq $-1,%%rdx;\n"
-                       " bsrq %%rax,%%rdx;\n"
-                       : "=d" (res)
-                       : "a" (bits));
+  __asm__ __volatile__(
+      " movq $-1,%%rdx;\n"
+      " bsrq %%rax,%%rdx;\n"
+      : "=d"(res)
+      : "a"(bits));
   return res;
 }
 
 static __inline__ int bottom_bit(unsigned int bits) {
   int res;
 
-  __asm__ __volatile__(" movq $-1,%%rdx;\n"
-                       " bsfq %%rax,%%rdx;\n"
-                       : "=d" (res)
-                       : "a" (bits));
+  __asm__ __volatile__(
+      " movq $-1,%%rdx;\n"
+      " bsfq %%rax,%%rdx;\n"
+      : "=d"(res)
+      : "a"(bits));
   return res;
 }
 #else
@@ -166,8 +171,8 @@
  *      linear sound like peanuts these days, and shouldn't an array lookup be
  *      real fast? No! When the cache sloshes as badly as this one will, a tight
  *      calculation may be better. The messiest part is normally finding the
- *      segment, but a little inline assembly can fix that on an i386, x86_64 and
- *      many other modern processors.
+ *      segment, but a little inline assembly can fix that on an i386, x86_64
+ * and many other modern processors.
  */
 
 /*
@@ -196,8 +201,9 @@
  * John Wiley & Sons, pps 98-111 and 472-476.
  */
 
-//#define ULAW_ZEROTRAP                 /* turn on the trap as per the MIL-STD */
-#define ULAW_BIAS 0x84  /* Bias for linear code. */
+//#define ULAW_ZEROTRAP                 /* turn on the trap as per the MIL-STD
+//*/
+#define ULAW_BIAS 0x84 /* Bias for linear code. */
 
 /*! \brief Encode a linear sample to u-law
     \param linear The sample to encode.
@@ -249,7 +255,7 @@
    * Extract and bias the quantization bits. Then
    * shift up by the segment number and subtract out the bias.
    */
-  t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
+  t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int)ulaw & 0x70) >> 4);
   return (int16_t)((ulaw & 0x80) ? (ULAW_BIAS - t) : (t - ULAW_BIAS));
 }
 
@@ -317,7 +323,7 @@
 
   alaw ^= ALAW_AMI_MASK;
   i = ((alaw & 0x0F) << 4);
-  seg = (((int) alaw & 0x70) >> 4);
+  seg = (((int)alaw & 0x70) >> 4);
   if (seg)
     i = (i + 0x108) << (seg - 1);
   else
diff --git a/modules/audio_coding/codecs/g711/g711_interface.h b/modules/audio_coding/codecs/g711/g711_interface.h
index 1f23da6..f206f30 100644
--- a/modules/audio_coding/codecs/g711/g711_interface.h
+++ b/modules/audio_coding/codecs/g711/g711_interface.h
@@ -112,19 +112,19 @@
                           int16_t* speechType);
 
 /**********************************************************************
-* WebRtcG711_Version(...)
-*
-* This function gives the version string of the G.711 codec.
-*
-* Input:
-*      - lenBytes:     the size of Allocated space (in Bytes) where
-*                      the version number is written to (in string format).
-*
-* Output:
-*      - version:      Pointer to a buffer where the version number is
-*                      written to.
-*
-*/
+ * WebRtcG711_Version(...)
+ *
+ * This function gives the version string of the G.711 codec.
+ *
+ * Input:
+ *      - lenBytes:     the size of Allocated space (in Bytes) where
+ *                      the version number is written to (in string format).
+ *
+ * Output:
+ *      - version:      Pointer to a buffer where the version number is
+ *                      written to.
+ *
+ */
 
 int16_t WebRtcG711_Version(char* version, int16_t lenBytes);
 
diff --git a/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
index ec97ee3..cb96c3c 100644
--- a/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
+++ b/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -123,7 +123,7 @@
   const size_t bytes_to_encode = samples_per_channel / 2 * num_channels_;
   EncodedInfo info;
   info.encoded_bytes = encoded->AppendData(
-      bytes_to_encode, [&] (rtc::ArrayView<uint8_t> encoded) {
+      bytes_to_encode, [&](rtc::ArrayView<uint8_t> encoded) {
         // Interleave the encoded bytes of the different channels. Each separate
         // channel and the interleaved stream encodes two samples per byte, most
         // significant half first.
diff --git a/modules/audio_coding/codecs/g722/audio_encoder_g722.h b/modules/audio_coding/codecs/g722/audio_encoder_g722.h
index 1f4b943..3cf1439 100644
--- a/modules/audio_coding/codecs/g722/audio_encoder_g722.h
+++ b/modules/audio_coding/codecs/g722/audio_encoder_g722.h
@@ -46,8 +46,8 @@
   // The encoder state for one channel.
   struct EncoderState {
     G722EncInst* encoder;
-    std::unique_ptr<int16_t[]> speech_buffer;   // Queued up for encoding.
-    rtc::Buffer encoded_buffer;                 // Already encoded.
+    std::unique_ptr<int16_t[]> speech_buffer;  // Queued up for encoding.
+    rtc::Buffer encoded_buffer;                // Already encoded.
     EncoderState();
     ~EncoderState();
   };
diff --git a/modules/audio_coding/codecs/g722/g722_decode.c b/modules/audio_coding/codecs/g722/g722_decode.c
index 06b3485..d638f50 100644
--- a/modules/audio_coding/codecs/g722/g722_decode.c
+++ b/modules/audio_coding/codecs/g722/g722_decode.c
@@ -35,7 +35,6 @@
 #include <stdlib.h>
 
 #include "modules/audio_coding/codecs/g722/g722_enc_dec.h"
-#include "typedefs.h"  // NOLINT(build/include)
 
 #if !defined(FALSE)
 #define FALSE 0
diff --git a/modules/audio_coding/codecs/g722/g722_enc_dec.h b/modules/audio_coding/codecs/g722/g722_enc_dec.h
index ccda09b..cc3aa98 100644
--- a/modules/audio_coding/codecs/g722/g722_enc_dec.h
+++ b/modules/audio_coding/codecs/g722/g722_enc_dec.h
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 2005 Steve Underwood
  *
- *  Despite my general liking of the GPL, I place my own contributions 
+ *  Despite my general liking of the GPL, I place my own contributions
  *  to this code in the public domain for the benefit of all mankind -
  *  even the slimy ones who might try to proprietize my work and use it
  *  to my detriment.
@@ -25,22 +25,23 @@
  * -Added new defines for minimum and maximum values of short int
  */
 
-
 /*! \file */
 
 #if !defined(_G722_ENC_DEC_H_)
 #define _G722_ENC_DEC_H_
 
-#include "typedefs.h"  // NOLINT(build/include)
+#include <stdint.h>
 
 /*! \page g722_page G.722 encoding and decoding
 \section g722_page_sec_1 What does it do?
-The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
-specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
+The G.722 module is a bit exact implementation of the ITU G.722 specification
+for all three specified bit rates - 64000bps, 56000bps and 48000bps. It passes
+the ITU tests.
 
-To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
-support an option for the linear audio to be an 8k samples/second stream. In this mode the
-codec is considerably faster, and still fully compatible with wideband terminals using G.722.
+To allow fast and flexible interworking with narrow band telephony, the encoder
+and decoder support an option for the linear audio to be an 8k samples/second
+stream. In this mode the codec is considerably faster, and still fully
+compatible with wideband terminals using G.722.
 
 \section g722_page_sec_2 How does it work?
 ???.
@@ -49,86 +50,78 @@
 #define WEBRTC_INT16_MAX 32767
 #define WEBRTC_INT16_MIN -32768
 
-enum
-{
-    G722_SAMPLE_RATE_8000 = 0x0001,
-    G722_PACKED = 0x0002
-};
+enum { G722_SAMPLE_RATE_8000 = 0x0001, G722_PACKED = 0x0002 };
 
-typedef struct
-{
-    /*! TRUE if the operating in the special ITU test mode, with the band split filters
-             disabled. */
-    int itu_test_mode;
-    /*! TRUE if the G.722 data is packed */
-    int packed;
-    /*! TRUE if encode from 8k samples/second */
-    int eight_k;
-    /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
-    int bits_per_sample;
+typedef struct {
+  /*! TRUE if the operating in the special ITU test mode, with the band split
+     filters disabled. */
+  int itu_test_mode;
+  /*! TRUE if the G.722 data is packed */
+  int packed;
+  /*! TRUE if encode from 8k samples/second */
+  int eight_k;
+  /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
+  int bits_per_sample;
 
-    /*! Signal history for the QMF */
-    int x[24];
+  /*! Signal history for the QMF */
+  int x[24];
 
-    struct
-    {
-        int s;
-        int sp;
-        int sz;
-        int r[3];
-        int a[3];
-        int ap[3];
-        int p[3];
-        int d[7];
-        int b[7];
-        int bp[7];
-        int sg[7];
-        int nb;
-        int det;
-    } band[2];
+  struct {
+    int s;
+    int sp;
+    int sz;
+    int r[3];
+    int a[3];
+    int ap[3];
+    int p[3];
+    int d[7];
+    int b[7];
+    int bp[7];
+    int sg[7];
+    int nb;
+    int det;
+  } band[2];
 
-    unsigned int in_buffer;
-    int in_bits;
-    unsigned int out_buffer;
-    int out_bits;
+  unsigned int in_buffer;
+  int in_bits;
+  unsigned int out_buffer;
+  int out_bits;
 } G722EncoderState;
 
-typedef struct
-{
-    /*! TRUE if the operating in the special ITU test mode, with the band split filters
-             disabled. */
-    int itu_test_mode;
-    /*! TRUE if the G.722 data is packed */
-    int packed;
-    /*! TRUE if decode to 8k samples/second */
-    int eight_k;
-    /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
-    int bits_per_sample;
+typedef struct {
+  /*! TRUE if the operating in the special ITU test mode, with the band split
+     filters disabled. */
+  int itu_test_mode;
+  /*! TRUE if the G.722 data is packed */
+  int packed;
+  /*! TRUE if decode to 8k samples/second */
+  int eight_k;
+  /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
+  int bits_per_sample;
 
-    /*! Signal history for the QMF */
-    int x[24];
+  /*! Signal history for the QMF */
+  int x[24];
 
-    struct
-    {
-        int s;
-        int sp;
-        int sz;
-        int r[3];
-        int a[3];
-        int ap[3];
-        int p[3];
-        int d[7];
-        int b[7];
-        int bp[7];
-        int sg[7];
-        int nb;
-        int det;
-    } band[2];
-    
-    unsigned int in_buffer;
-    int in_bits;
-    unsigned int out_buffer;
-    int out_bits;
+  struct {
+    int s;
+    int sp;
+    int sz;
+    int r[3];
+    int a[3];
+    int ap[3];
+    int p[3];
+    int d[7];
+    int b[7];
+    int bp[7];
+    int sg[7];
+    int nb;
+    int det;
+  } band[2];
+
+  unsigned int in_buffer;
+  int in_bits;
+  unsigned int out_buffer;
+  int out_bits;
 } G722DecoderState;
 
 #ifdef __cplusplus
@@ -138,8 +131,8 @@
 G722EncoderState* WebRtc_g722_encode_init(G722EncoderState* s,
                                           int rate,
                                           int options);
-int WebRtc_g722_encode_release(G722EncoderState *s);
-size_t WebRtc_g722_encode(G722EncoderState *s,
+int WebRtc_g722_encode_release(G722EncoderState* s);
+size_t WebRtc_g722_encode(G722EncoderState* s,
                           uint8_t g722_data[],
                           const int16_t amp[],
                           size_t len);
@@ -147,8 +140,8 @@
 G722DecoderState* WebRtc_g722_decode_init(G722DecoderState* s,
                                           int rate,
                                           int options);
-int WebRtc_g722_decode_release(G722DecoderState *s);
-size_t WebRtc_g722_decode(G722DecoderState *s,
+int WebRtc_g722_decode_release(G722DecoderState* s);
+size_t WebRtc_g722_decode(G722DecoderState* s,
                           int16_t amp[],
                           const uint8_t g722_data[],
                           size_t len);
diff --git a/modules/audio_coding/codecs/g722/g722_encode.c b/modules/audio_coding/codecs/g722/g722_encode.c
index eeb7649..cd19252 100644
--- a/modules/audio_coding/codecs/g722/g722_encode.c
+++ b/modules/audio_coding/codecs/g722/g722_encode.c
@@ -35,7 +35,6 @@
 #include <stdlib.h>
 
 #include "modules/audio_coding/codecs/g722/g722_enc_dec.h"
-#include "typedefs.h"  // NOLINT(build/include)
 
 #if !defined(FALSE)
 #define FALSE 0
diff --git a/modules/audio_coding/codecs/g722/g722_interface.h b/modules/audio_coding/codecs/g722/g722_interface.h
index d957223..3b73f85 100644
--- a/modules/audio_coding/codecs/g722/g722_interface.h
+++ b/modules/audio_coding/codecs/g722/g722_interface.h
@@ -17,21 +17,20 @@
  * Solution to support multiple instances
  */
 
-typedef struct WebRtcG722EncInst    G722EncInst;
-typedef struct WebRtcG722DecInst    G722DecInst;
+typedef struct WebRtcG722EncInst G722EncInst;
+typedef struct WebRtcG722DecInst G722DecInst;
 
 /*
  * Comfort noise constants
  */
 
-#define G722_WEBRTC_SPEECH     1
-#define G722_WEBRTC_CNG        2
+#define G722_WEBRTC_SPEECH 1
+#define G722_WEBRTC_CNG 2
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-
 /****************************************************************************
  * WebRtcG722_CreateEncoder(...)
  *
@@ -43,8 +42,7 @@
  * Return value               :  0 - Ok
  *                              -1 - Error
  */
-int16_t WebRtcG722_CreateEncoder(G722EncInst **G722enc_inst);
-
+int16_t WebRtcG722_CreateEncoder(G722EncInst** G722enc_inst);
 
 /****************************************************************************
  * WebRtcG722_EncoderInit(...)
@@ -59,8 +57,7 @@
  *                              -1 - Error
  */
 
-int16_t WebRtcG722_EncoderInit(G722EncInst *G722enc_inst);
-
+int16_t WebRtcG722_EncoderInit(G722EncInst* G722enc_inst);
 
 /****************************************************************************
  * WebRtcG722_FreeEncoder(...)
@@ -73,9 +70,7 @@
  * Return value               :  0 - Ok
  *                              -1 - Error
  */
-int WebRtcG722_FreeEncoder(G722EncInst *G722enc_inst);
-
-
+int WebRtcG722_FreeEncoder(G722EncInst* G722enc_inst);
 
 /****************************************************************************
  * WebRtcG722_Encode(...)
@@ -99,7 +94,6 @@
                          size_t len,
                          uint8_t* encoded);
 
-
 /****************************************************************************
  * WebRtcG722_CreateDecoder(...)
  *
@@ -111,7 +105,7 @@
  * Return value               :  0 - Ok
  *                              -1 - Error
  */
-int16_t WebRtcG722_CreateDecoder(G722DecInst **G722dec_inst);
+int16_t WebRtcG722_CreateDecoder(G722DecInst** G722dec_inst);
 
 /****************************************************************************
  * WebRtcG722_DecoderInit(...)
@@ -136,8 +130,7 @@
  *                              -1 - Error
  */
 
-int WebRtcG722_FreeDecoder(G722DecInst *G722dec_inst);
-
+int WebRtcG722_FreeDecoder(G722DecInst* G722dec_inst);
 
 /****************************************************************************
  * WebRtcG722_Decode(...)
@@ -159,11 +152,11 @@
  * Return value             : Samples in decoded vector
  */
 
-size_t WebRtcG722_Decode(G722DecInst *G722dec_inst,
+size_t WebRtcG722_Decode(G722DecInst* G722dec_inst,
                          const uint8_t* encoded,
                          size_t len,
-                         int16_t *decoded,
-                         int16_t *speechType);
+                         int16_t* decoded,
+                         int16_t* speechType);
 
 /****************************************************************************
  * WebRtcG722_Version(...)
@@ -171,12 +164,10 @@
  * Get a string with the current version of the codec
  */
 
-int16_t WebRtcG722_Version(char *versionStr, short len);
-
+int16_t WebRtcG722_Version(char* versionStr, short len);
 
 #ifdef __cplusplus
 }
 #endif
 
-
 #endif /* MODULES_AUDIO_CODING_CODECS_G722_G722_INTERFACE_H_ */
diff --git a/modules/audio_coding/codecs/ilbc/abs_quant.h b/modules/audio_coding/codecs/ilbc/abs_quant.h
index 3a98a6e..331921c 100644
--- a/modules/audio_coding/codecs/ilbc/abs_quant.h
+++ b/modules/audio_coding/codecs/ilbc/abs_quant.h
@@ -27,13 +27,13 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_AbsQuant(
-    IlbcEncoder *iLBCenc_inst,
+    IlbcEncoder* iLBCenc_inst,
     /* (i) Encoder instance */
-    iLBC_bits *iLBC_encbits, /* (i/o) Encoded bits (outputs idxForMax
+    iLBC_bits* iLBC_encbits, /* (i/o) Encoded bits (outputs idxForMax
                                    and idxVec, uses state_first as
                                    input) */
-    int16_t *in,     /* (i) vector to encode */
-    int16_t *weightDenum   /* (i) denominator of synthesis filter */
-                            );
+    int16_t* in,             /* (i) vector to encode */
+    int16_t* weightDenum     /* (i) denominator of synthesis filter */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/abs_quant_loop.h b/modules/audio_coding/codecs/ilbc/abs_quant_loop.h
index 5116bfd..a193a07 100644
--- a/modules/audio_coding/codecs/ilbc/abs_quant_loop.h
+++ b/modules/audio_coding/codecs/ilbc/abs_quant_loop.h
@@ -26,8 +26,10 @@
  *  (subrutine for WebRtcIlbcfix_StateSearch)
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_AbsQuantLoop(int16_t *syntOutIN, int16_t *in_weightedIN,
-                                int16_t *weightDenumIN, size_t *quantLenIN,
-                                int16_t *idxVecIN);
+void WebRtcIlbcfix_AbsQuantLoop(int16_t* syntOutIN,
+                                int16_t* in_weightedIN,
+                                int16_t* weightDenumIN,
+                                size_t* quantLenIN,
+                                int16_t* idxVecIN);
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc b/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc
index 08d21f4..9e58ce0 100644
--- a/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc
+++ b/modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.cc
@@ -33,10 +33,10 @@
 }
 
 int AudioDecoderIlbcImpl::DecodeInternal(const uint8_t* encoded,
-                                     size_t encoded_len,
-                                     int sample_rate_hz,
-                                     int16_t* decoded,
-                                     SpeechType* speech_type) {
+                                         size_t encoded_len,
+                                         int sample_rate_hz,
+                                         int16_t* decoded,
+                                         SpeechType* speech_type) {
   RTC_DCHECK_EQ(sample_rate_hz, 8000);
   int16_t temp_type = 1;  // Default is speech.
   int ret = WebRtcIlbcfix_Decode(dec_state_, encoded, encoded_len, decoded,
@@ -86,10 +86,9 @@
   } else {
     size_t byte_offset;
     uint32_t timestamp_offset;
-    for (byte_offset = 0, timestamp_offset = 0;
-         byte_offset < payload.size();
+    for (byte_offset = 0, timestamp_offset = 0; byte_offset < payload.size();
          byte_offset += bytes_per_frame,
-             timestamp_offset += timestamps_per_frame) {
+        timestamp_offset += timestamps_per_frame) {
       std::unique_ptr<EncodedAudioFrame> frame(new LegacyEncodedAudioFrame(
           this, rtc::Buffer(payload.data() + byte_offset, bytes_per_frame)));
       results.emplace_back(timestamp + timestamp_offset, 0, std::move(frame));
diff --git a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
index 6ddc078..84695e3 100644
--- a/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
+++ b/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -89,7 +89,6 @@
     uint32_t rtp_timestamp,
     rtc::ArrayView<const int16_t> audio,
     rtc::Buffer* encoded) {
-
   // Save timestamp if starting a new packet.
   if (num_10ms_frames_buffered_ == 0)
     first_timestamp_in_buffer_ = rtp_timestamp;
@@ -107,19 +106,15 @@
   // Encode buffered input.
   RTC_DCHECK_EQ(num_10ms_frames_buffered_, num_10ms_frames_per_packet_);
   num_10ms_frames_buffered_ = 0;
-  size_t encoded_bytes =
-      encoded->AppendData(
-          RequiredOutputSizeBytes(),
-          [&] (rtc::ArrayView<uint8_t> encoded) {
-            const int r = WebRtcIlbcfix_Encode(
-                encoder_,
-                input_buffer_,
-                kSampleRateHz / 100 * num_10ms_frames_per_packet_,
-                encoded.data());
-            RTC_CHECK_GE(r, 0);
+  size_t encoded_bytes = encoded->AppendData(
+      RequiredOutputSizeBytes(), [&](rtc::ArrayView<uint8_t> encoded) {
+        const int r = WebRtcIlbcfix_Encode(
+            encoder_, input_buffer_,
+            kSampleRateHz / 100 * num_10ms_frames_per_packet_, encoded.data());
+        RTC_CHECK_GE(r, 0);
 
-            return static_cast<size_t>(r);
-          });
+        return static_cast<size_t>(r);
+      });
 
   RTC_DCHECK_EQ(encoded_bytes, RequiredOutputSizeBytes());
 
@@ -135,20 +130,24 @@
   if (encoder_)
     RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderFree(encoder_));
   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderCreate(&encoder_));
-  const int encoder_frame_size_ms = frame_size_ms_ > 30
-                                        ? frame_size_ms_ / 2
-                                        : frame_size_ms_;
+  const int encoder_frame_size_ms =
+      frame_size_ms_ > 30 ? frame_size_ms_ / 2 : frame_size_ms_;
   RTC_CHECK_EQ(0, WebRtcIlbcfix_EncoderInit(encoder_, encoder_frame_size_ms));
   num_10ms_frames_buffered_ = 0;
 }
 
 size_t AudioEncoderIlbcImpl::RequiredOutputSizeBytes() const {
   switch (num_10ms_frames_per_packet_) {
-    case 2:   return 38;
-    case 3:   return 50;
-    case 4:   return 2 * 38;
-    case 6:   return 2 * 50;
-    default:  FATAL();
+    case 2:
+      return 38;
+    case 3:
+      return 50;
+    case 4:
+      return 2 * 38;
+    case 6:
+      return 2 * 50;
+    default:
+      FATAL();
   }
 }
 
diff --git a/modules/audio_coding/codecs/ilbc/augmented_cb_corr.h b/modules/audio_coding/codecs/ilbc/augmented_cb_corr.h
index 581f0d6..646e564 100644
--- a/modules/audio_coding/codecs/ilbc/augmented_cb_corr.h
+++ b/modules/audio_coding/codecs/ilbc/augmented_cb_corr.h
@@ -26,16 +26,16 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_AugmentedCbCorr(
-    int16_t *target,   /* (i) Target vector */
-    int16_t *buffer,   /* (i) Memory buffer */
-    int16_t *interpSamples, /* (i) buffer with
+    int16_t* target,        /* (i) Target vector */
+    int16_t* buffer,        /* (i) Memory buffer */
+    int16_t* interpSamples, /* (i) buffer with
                                            interpolated samples */
-    int32_t *crossDot,  /* (o) The cross correlation between
-                                           the target and the Augmented
-                                           vector */
-    size_t low,    /* (i) Lag to start from (typically
-                                                   20) */
-    size_t high,   /* (i) Lag to end at (typically 39 */
-    int scale);   /* (i) Scale factor to use for the crossDot */
+    int32_t* crossDot,      /* (o) The cross correlation between
+                                               the target and the Augmented
+                                               vector */
+    size_t low,             /* (i) Lag to start from (typically
+                                                            20) */
+    size_t high,            /* (i) Lag to end at (typically 39 */
+    int scale);             /* (i) Scale factor to use for the crossDot */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/bw_expand.h b/modules/audio_coding/codecs/ilbc/bw_expand.h
index ee9e45a..d25325c 100644
--- a/modules/audio_coding/codecs/ilbc/bw_expand.h
+++ b/modules/audio_coding/codecs/ilbc/bw_expand.h
@@ -26,11 +26,11 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_BwExpand(
-    int16_t *out, /* (o) the bandwidth expanded lpc coefficients */
-    int16_t *in,  /* (i) the lpc coefficients before bandwidth
-                                   expansion */
-    int16_t *coef, /* (i) the bandwidth expansion factor Q15 */
+    int16_t* out,  /* (o) the bandwidth expanded lpc coefficients */
+    int16_t* in,   /* (i) the lpc coefficients before bandwidth
+                                    expansion */
+    int16_t* coef, /* (i) the bandwidth expansion factor Q15 */
     int16_t length /* (i) the length of lpc coefficient vectors */
-                            );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/cb_mem_energy.h b/modules/audio_coding/codecs/ilbc/cb_mem_energy.h
index e8e2fe9..894f5d0 100644
--- a/modules/audio_coding/codecs/ilbc/cb_mem_energy.h
+++ b/modules/audio_coding/codecs/ilbc/cb_mem_energy.h
@@ -21,14 +21,14 @@
 
 void WebRtcIlbcfix_CbMemEnergy(
     size_t range,
-    int16_t *CB,   /* (i) The CB memory (1:st section) */
-    int16_t *filteredCB,  /* (i) The filtered CB memory (2:nd section) */
-    size_t lMem,   /* (i) Length of the CB memory */
-    size_t lTarget,   /* (i) Length of the target vector */
-    int16_t *energyW16,  /* (o) Energy in the CB vectors */
-    int16_t *energyShifts, /* (o) Shift value of the energy */
-    int scale,   /* (i) The scaling of all energy values */
-    size_t base_size  /* (i) Index to where energy values should be stored */
-                               );
+    int16_t* CB,           /* (i) The CB memory (1:st section) */
+    int16_t* filteredCB,   /* (i) The filtered CB memory (2:nd section) */
+    size_t lMem,           /* (i) Length of the CB memory */
+    size_t lTarget,        /* (i) Length of the target vector */
+    int16_t* energyW16,    /* (o) Energy in the CB vectors */
+    int16_t* energyShifts, /* (o) Shift value of the energy */
+    int scale,             /* (i) The scaling of all energy values */
+    size_t base_size /* (i) Index to where energy values should be stored */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h b/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h
index 00eb017..b7b972f 100644
--- a/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h
+++ b/modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h
@@ -20,12 +20,12 @@
 #define MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_CB_MEM_ENERGY_AUGMENTATION_H_
 
 void WebRtcIlbcfix_CbMemEnergyAugmentation(
-    int16_t *interpSamples, /* (i) The interpolated samples */
-    int16_t *CBmem,   /* (i) The CB memory */
-    int scale,   /* (i) The scaling of all energy values */
-    size_t base_size,  /* (i) Index to where energy values should be stored */
-    int16_t *energyW16,  /* (o) Energy in the CB vectors */
-    int16_t *energyShifts /* (o) Shift value of the energy */
-                                           );
+    int16_t* interpSamples, /* (i) The interpolated samples */
+    int16_t* CBmem,         /* (i) The CB memory */
+    int scale,              /* (i) The scaling of all energy values */
+    size_t base_size,   /* (i) Index to where energy values should be stored */
+    int16_t* energyW16, /* (o) Energy in the CB vectors */
+    int16_t* energyShifts /* (o) Shift value of the energy */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.h b/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.h
index af8e658..5511ef1 100644
--- a/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.h
+++ b/modules/audio_coding/codecs/ilbc/cb_mem_energy_calc.h
@@ -20,14 +20,14 @@
 #define MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_CB_MEM_ENERGY_CALC_H_
 
 void WebRtcIlbcfix_CbMemEnergyCalc(
-    int32_t energy,   /* (i) input start energy */
-    size_t range,   /* (i) number of iterations */
-    int16_t *ppi,   /* (i) input pointer 1 */
-    int16_t *ppo,   /* (i) input pointer 2 */
-    int16_t *energyW16,  /* (o) Energy in the CB vectors */
-    int16_t *energyShifts, /* (o) Shift value of the energy */
-    int scale,   /* (i) The scaling of all energy values */
-    size_t base_size  /* (i) Index to where energy values should be stored */
-                                   );
+    int32_t energy,        /* (i) input start energy */
+    size_t range,          /* (i) number of iterations */
+    int16_t* ppi,          /* (i) input pointer 1 */
+    int16_t* ppo,          /* (i) input pointer 2 */
+    int16_t* energyW16,    /* (o) Energy in the CB vectors */
+    int16_t* energyShifts, /* (o) Shift value of the energy */
+    int scale,             /* (i) The scaling of all energy values */
+    size_t base_size /* (i) Index to where energy values should be stored */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/cb_search.h b/modules/audio_coding/codecs/ilbc/cb_search.h
index c8626c5..393a2de 100644
--- a/modules/audio_coding/codecs/ilbc/cb_search.h
+++ b/modules/audio_coding/codecs/ilbc/cb_search.h
@@ -20,16 +20,16 @@
 #define MODULES_AUDIO_CODING_CODECS_ILBC_MAIN_SOURCE_CB_SEARCH_H_
 
 void WebRtcIlbcfix_CbSearch(
-    IlbcEncoder *iLBCenc_inst,
+    IlbcEncoder* iLBCenc_inst,
     /* (i) the encoder state structure */
-    int16_t *index,  /* (o) Codebook indices */
-    int16_t *gain_index, /* (o) Gain quantization indices */
-    int16_t *intarget, /* (i) Target vector for encoding */
-    int16_t *decResidual,/* (i) Decoded residual for codebook construction */
-    size_t lMem,  /* (i) Length of buffer */
-    size_t lTarget,  /* (i) Length of vector */
-    int16_t *weightDenum,/* (i) weighting filter coefficients in Q12 */
-    size_t block  /* (i) the subblock number */
-                            );
+    int16_t* index,       /* (o) Codebook indices */
+    int16_t* gain_index,  /* (o) Gain quantization indices */
+    int16_t* intarget,    /* (i) Target vector for encoding */
+    int16_t* decResidual, /* (i) Decoded residual for codebook construction */
+    size_t lMem,          /* (i) Length of buffer */
+    size_t lTarget,       /* (i) Length of vector */
+    int16_t* weightDenum, /* (i) weighting filter coefficients in Q12 */
+    size_t block          /* (i) the subblock number */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/cb_search_core.h b/modules/audio_coding/codecs/ilbc/cb_search_core.h
index 3210668..af5a1db 100644
--- a/modules/audio_coding/codecs/ilbc/cb_search_core.h
+++ b/modules/audio_coding/codecs/ilbc/cb_search_core.h
@@ -22,19 +22,19 @@
 #include "modules/audio_coding/codecs/ilbc/defines.h"
 
 void WebRtcIlbcfix_CbSearchCore(
-    int32_t *cDot,    /* (i) Cross Correlation */
-    size_t range,    /* (i) Search range */
-    int16_t stage,    /* (i) Stage of this search */
-    int16_t *inverseEnergy,  /* (i) Inversed energy */
-    int16_t *inverseEnergyShift, /* (i) Shifts of inversed energy
+    int32_t* cDot,               /* (i) Cross Correlation */
+    size_t range,                /* (i) Search range */
+    int16_t stage,               /* (i) Stage of this search */
+    int16_t* inverseEnergy,      /* (i) Inversed energy */
+    int16_t* inverseEnergyShift, /* (i) Shifts of inversed energy
                                           with the offset 2*16-29 */
-    int32_t *Crit,    /* (o) The criteria */
-    size_t *bestIndex,   /* (o) Index that corresponds to
-                                   maximum criteria (in this
-                                   vector) */
-    int32_t *bestCrit,   /* (o) Value of critera for the
-                                  chosen index */
-    int16_t *bestCritSh);  /* (o) The domain of the chosen
-                                    criteria */
+    int32_t* Crit,               /* (o) The criteria */
+    size_t* bestIndex,           /* (o) Index that corresponds to
+                                           maximum criteria (in this
+                                           vector) */
+    int32_t* bestCrit, /* (o) Value of critera for the
+                                chosen index */
+    int16_t* bestCritSh); /* (o) The domain of the chosen
+                                   criteria */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/cb_update_best_index.h b/modules/audio_coding/codecs/ilbc/cb_update_best_index.h
index a4a4cde..3f57d48 100644
--- a/modules/audio_coding/codecs/ilbc/cb_update_best_index.h
+++ b/modules/audio_coding/codecs/ilbc/cb_update_best_index.h
@@ -22,17 +22,17 @@
 #include "modules/audio_coding/codecs/ilbc/defines.h"
 
 void WebRtcIlbcfix_CbUpdateBestIndex(
-    int32_t CritNew,    /* (i) New Potentially best Criteria */
-    int16_t CritNewSh,   /* (i) Shift value of above Criteria */
-    size_t IndexNew,   /* (i) Index of new Criteria */
-    int32_t cDotNew,    /* (i) Cross dot of new index */
-    int16_t invEnergyNew,  /* (i) Inversed energy new index */
-    int16_t energyShiftNew,  /* (i) Energy shifts of new index */
-    int32_t *CritMax,   /* (i/o) Maximum Criteria (so far) */
-    int16_t *shTotMax,   /* (i/o) Shifts of maximum criteria */
-    size_t *bestIndex,   /* (i/o) Index that corresponds to
-                                   maximum criteria */
-    int16_t *bestGain);   /* (i/o) Gain in Q14 that corresponds
-                                   to maximum criteria */
+    int32_t CritNew,        /* (i) New Potentially best Criteria */
+    int16_t CritNewSh,      /* (i) Shift value of above Criteria */
+    size_t IndexNew,        /* (i) Index of new Criteria */
+    int32_t cDotNew,        /* (i) Cross dot of new index */
+    int16_t invEnergyNew,   /* (i) Inversed energy new index */
+    int16_t energyShiftNew, /* (i) Energy shifts of new index */
+    int32_t* CritMax,       /* (i/o) Maximum Criteria (so far) */
+    int16_t* shTotMax,      /* (i/o) Shifts of maximum criteria */
+    size_t* bestIndex,      /* (i/o) Index that corresponds to
+                                      maximum criteria */
+    int16_t* bestGain);     /* (i/o) Gain in Q14 that corresponds
+                                     to maximum criteria */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/chebyshev.h b/modules/audio_coding/codecs/ilbc/chebyshev.h
index 46eef6b..64b2f49 100644
--- a/modules/audio_coding/codecs/ilbc/chebyshev.h
+++ b/modules/audio_coding/codecs/ilbc/chebyshev.h
@@ -30,8 +30,8 @@
 
 int16_t WebRtcIlbcfix_Chebyshev(
     /* (o) Result of C(x) */
-    int16_t x,  /* (i) Value to the Chevyshev polynomial */
-    int16_t *f  /* (i) The coefficients in the polynomial */
-                                      );
+    int16_t x, /* (i) Value to the Chevyshev polynomial */
+    int16_t* f /* (i) The coefficients in the polynomial */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/comp_corr.h b/modules/audio_coding/codecs/ilbc/comp_corr.h
index f54dca2..1e6b296 100644
--- a/modules/audio_coding/codecs/ilbc/comp_corr.h
+++ b/modules/audio_coding/codecs/ilbc/comp_corr.h
@@ -26,14 +26,13 @@
  *  of last subframe at given lag.
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_CompCorr(
-    int32_t *corr, /* (o) cross correlation */
-    int32_t *ener, /* (o) energy */
-    int16_t *buffer, /* (i) signal buffer */
-    size_t lag,  /* (i) pitch lag */
-    size_t bLen, /* (i) length of buffer */
-    size_t sRange, /* (i) correlation search length */
-    int16_t scale /* (i) number of rightshifts to use */
+void WebRtcIlbcfix_CompCorr(int32_t* corr,   /* (o) cross correlation */
+                            int32_t* ener,   /* (o) energy */
+                            int16_t* buffer, /* (i) signal buffer */
+                            size_t lag,      /* (i) pitch lag */
+                            size_t bLen,     /* (i) length of buffer */
+                            size_t sRange,   /* (i) correlation search length */
+                            int16_t scale /* (i) number of rightshifts to use */
                             );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/constants.h b/modules/audio_coding/codecs/ilbc/constants.h
index 6864f16..3c32c62 100644
--- a/modules/audio_coding/codecs/ilbc/constants.h
+++ b/modules/audio_coding/codecs/ilbc/constants.h
@@ -79,7 +79,8 @@
 
 /* enhancer definitions */
 
-extern const int16_t WebRtcIlbcfix_kEnhPolyPhaser[ENH_UPS0][ENH_FLO_MULT2_PLUS1];
+extern const int16_t WebRtcIlbcfix_kEnhPolyPhaser[ENH_UPS0]
+                                                 [ENH_FLO_MULT2_PLUS1];
 extern const int16_t WebRtcIlbcfix_kEnhWt[];
 extern const size_t WebRtcIlbcfix_kEnhPlocs[];
 
diff --git a/modules/audio_coding/codecs/ilbc/create_augmented_vec.h b/modules/audio_coding/codecs/ilbc/create_augmented_vec.h
index ca8b371..28c9400 100644
--- a/modules/audio_coding/codecs/ilbc/create_augmented_vec.h
+++ b/modules/audio_coding/codecs/ilbc/create_augmented_vec.h
@@ -27,8 +27,8 @@
  *----------------------------------------------------------------*/
 
 void WebRtcIlbcfix_CreateAugmentedVec(
-    size_t index,          /* (i) Index for the augmented vector to be
-                              created */
+    size_t index, /* (i) Index for the augmented vector to be
+                     created */
     const int16_t* buffer, /* (i) Pointer to the end of the codebook memory
                               that is used for creation of the augmented
                               codebook */
diff --git a/modules/audio_coding/codecs/ilbc/decode.h b/modules/audio_coding/codecs/ilbc/decode.h
index ecc968e..c5f35f4 100644
--- a/modules/audio_coding/codecs/ilbc/decode.h
+++ b/modules/audio_coding/codecs/ilbc/decode.h
@@ -31,8 +31,8 @@
     const uint16_t* bytes,     /* (i) encoded signal bits */
     IlbcDecoder* iLBCdec_inst, /* (i/o) the decoder state
                                            structure */
-    int16_t mode               /* (i) 0: bad packet, PLC,
-                                      1: normal */
+    int16_t mode /* (i) 0: bad packet, PLC,
+                        1: normal */
     ) RTC_WARN_UNUSED_RESULT;
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h b/modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h
index 416fc36..48d43ec 100644
--- a/modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h
+++ b/modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h
@@ -26,13 +26,13 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_DecoderInterpolateLsp(
-    int16_t *syntdenum,  /* (o) synthesis filter coefficients */
-    int16_t *weightdenum, /* (o) weighting denumerator
+    int16_t* syntdenum, /* (o) synthesis filter coefficients */
+    int16_t* weightdenum, /* (o) weighting denumerator
                                    coefficients */
-    int16_t *lsfdeq,   /* (i) dequantized lsf coefficients */
-    int16_t length,   /* (i) length of lsf coefficient vector */
-    IlbcDecoder *iLBCdec_inst
+    int16_t* lsfdeq, /* (i) dequantized lsf coefficients */
+    int16_t length,  /* (i) length of lsf coefficient vector */
+    IlbcDecoder* iLBCdec_inst
     /* (i) the decoder state structure */
-                                          );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/defines.h b/modules/audio_coding/codecs/ilbc/defines.h
index 6100801..9a4a196 100644
--- a/modules/audio_coding/codecs/ilbc/defines.h
+++ b/modules/audio_coding/codecs/ilbc/defines.h
@@ -25,103 +25,109 @@
 
 /* general codec settings */
 
-#define FS       8000
-#define BLOCKL_20MS     160
-#define BLOCKL_30MS     240
-#define BLOCKL_MAX     240
-#define NSUB_20MS     4
-#define NSUB_30MS     6
-#define NSUB_MAX     6
-#define NASUB_20MS     2
-#define NASUB_30MS     4
-#define NASUB_MAX     4
-#define SUBL      40
-#define STATE_LEN     80
-#define STATE_SHORT_LEN_30MS  58
-#define STATE_SHORT_LEN_20MS  57
+#define FS 8000
+#define BLOCKL_20MS 160
+#define BLOCKL_30MS 240
+#define BLOCKL_MAX 240
+#define NSUB_20MS 4
+#define NSUB_30MS 6
+#define NSUB_MAX 6
+#define NASUB_20MS 2
+#define NASUB_30MS 4
+#define NASUB_MAX 4
+#define SUBL 40
+#define STATE_LEN 80
+#define STATE_SHORT_LEN_30MS 58
+#define STATE_SHORT_LEN_20MS 57
 
 /* LPC settings */
 
-#define LPC_FILTERORDER    10
-#define LPC_LOOKBACK    60
-#define LPC_N_20MS     1
-#define LPC_N_30MS     2
-#define LPC_N_MAX     2
-#define LPC_ASYMDIFF    20
-#define LSF_NSPLIT     3
-#define LSF_NUMBER_OF_STEPS   4
-#define LPC_HALFORDER    5
+#define LPC_FILTERORDER 10
+#define LPC_LOOKBACK 60
+#define LPC_N_20MS 1
+#define LPC_N_30MS 2
+#define LPC_N_MAX 2
+#define LPC_ASYMDIFF 20
+#define LSF_NSPLIT 3
+#define LSF_NUMBER_OF_STEPS 4
+#define LPC_HALFORDER 5
 #define COS_GRID_POINTS 60
 
 /* cb settings */
 
-#define CB_NSTAGES     3
-#define CB_EXPAND     2
-#define CB_MEML      147
-#define CB_FILTERLEN    (2*4)
-#define CB_HALFFILTERLEN   4
-#define CB_RESRANGE     34
-#define CB_MAXGAIN_FIXQ6   83 /* error = -0.24% */
-#define CB_MAXGAIN_FIXQ14   21299
+#define CB_NSTAGES 3
+#define CB_EXPAND 2
+#define CB_MEML 147
+#define CB_FILTERLEN (2 * 4)
+#define CB_HALFFILTERLEN 4
+#define CB_RESRANGE 34
+#define CB_MAXGAIN_FIXQ6 83 /* error = -0.24% */
+#define CB_MAXGAIN_FIXQ14 21299
 
 /* enhancer */
 
-#define ENH_BLOCKL     80  /* block length */
-#define ENH_BLOCKL_HALF    (ENH_BLOCKL/2)
-#define ENH_HL      3  /* 2*ENH_HL+1 is number blocks
-                                                                           in said second sequence */
-#define ENH_SLOP     2  /* max difference estimated and
-                                                                           correct pitch period */
-#define ENH_PLOCSL     8  /* pitch-estimates and
-                                                                           pitch-locations buffer length */
-#define ENH_OVERHANG    2
-#define ENH_UPS0     4  /* upsampling rate */
-#define ENH_FL0      3  /* 2*FLO+1 is the length of each filter */
-#define ENH_FLO_MULT2_PLUS1   7
-#define ENH_VECTL     (ENH_BLOCKL+2*ENH_FL0)
-#define ENH_CORRDIM     (2*ENH_SLOP+1)
-#define ENH_NBLOCKS     (BLOCKL/ENH_BLOCKL)
-#define ENH_NBLOCKS_EXTRA   5
-#define ENH_NBLOCKS_TOT    8 /* ENH_NBLOCKS+ENH_NBLOCKS_EXTRA */
-#define ENH_BUFL     (ENH_NBLOCKS_TOT)*ENH_BLOCKL
-#define ENH_BUFL_FILTEROVERHEAD  3
-#define ENH_A0      819   /* Q14 */
-#define ENH_A0_MINUS_A0A0DIV4  848256041 /* Q34 */
-#define ENH_A0DIV2     26843546 /* Q30 */
+#define ENH_BLOCKL 80 /* block length */
+#define ENH_BLOCKL_HALF (ENH_BLOCKL / 2)
+#define ENH_HL                                                         \
+  3 /* 2*ENH_HL+1 is number blocks                                     \
+                                                        in said second \
+       sequence */
+#define ENH_SLOP                    \
+  2 /* max difference estimated and \
+                                                       correct pitch period */
+#define ENH_PLOCSL                                                          \
+  8 /* pitch-estimates and                                                  \
+                                                     pitch-locations buffer \
+       length */
+#define ENH_OVERHANG 2
+#define ENH_UPS0 4 /* upsampling rate */
+#define ENH_FL0 3  /* 2*FLO+1 is the length of each filter */
+#define ENH_FLO_MULT2_PLUS1 7
+#define ENH_VECTL (ENH_BLOCKL + 2 * ENH_FL0)
+#define ENH_CORRDIM (2 * ENH_SLOP + 1)
+#define ENH_NBLOCKS (BLOCKL / ENH_BLOCKL)
+#define ENH_NBLOCKS_EXTRA 5
+#define ENH_NBLOCKS_TOT 8 /* ENH_NBLOCKS+ENH_NBLOCKS_EXTRA */
+#define ENH_BUFL (ENH_NBLOCKS_TOT) * ENH_BLOCKL
+#define ENH_BUFL_FILTEROVERHEAD 3
+#define ENH_A0 819                      /* Q14 */
+#define ENH_A0_MINUS_A0A0DIV4 848256041 /* Q34 */
+#define ENH_A0DIV2 26843546             /* Q30 */
 
 /* PLC */
 
 /* Down sampling */
 
-#define FILTERORDER_DS_PLUS1  7
-#define DELAY_DS     3
-#define FACTOR_DS     2
+#define FILTERORDER_DS_PLUS1 7
+#define DELAY_DS 3
+#define FACTOR_DS 2
 
 /* bit stream defs */
 
-#define NO_OF_BYTES_20MS   38
-#define NO_OF_BYTES_30MS   50
-#define NO_OF_WORDS_20MS   19
-#define NO_OF_WORDS_30MS   25
-#define STATE_BITS     3
-#define BYTE_LEN     8
-#define ULP_CLASSES     3
+#define NO_OF_BYTES_20MS 38
+#define NO_OF_BYTES_30MS 50
+#define NO_OF_WORDS_20MS 19
+#define NO_OF_WORDS_30MS 25
+#define STATE_BITS 3
+#define BYTE_LEN 8
+#define ULP_CLASSES 3
 
 /* help parameters */
 
-#define TWO_PI_FIX     25736 /* Q12 */
+#define TWO_PI_FIX 25736 /* Q12 */
 
 /* Constants for codebook search and creation */
 
-#define ST_MEM_L_TBL  85
-#define MEM_LF_TBL  147
-
+#define ST_MEM_L_TBL 85
+#define MEM_LF_TBL 147
 
 /* Struct for the bits */
 typedef struct iLBC_bits_t_ {
-  int16_t lsf[LSF_NSPLIT*LPC_N_MAX];
-  int16_t cb_index[CB_NSTAGES*(NASUB_MAX+1)];  /* First CB_NSTAGES values contains extra CB index */
-  int16_t gain_index[CB_NSTAGES*(NASUB_MAX+1)]; /* First CB_NSTAGES values contains extra CB gain */
+  int16_t lsf[LSF_NSPLIT * LPC_N_MAX];
+  int16_t cb_index[CB_NSTAGES * (NASUB_MAX + 1)];   /* First CB_NSTAGES values
+                                                       contains extra CB index */
+  int16_t gain_index[CB_NSTAGES * (NASUB_MAX + 1)]; /* First CB_NSTAGES values
+                                                       contains extra CB gain */
   size_t idxForMax;
   int16_t state_first;
   int16_t idxVec[STATE_SHORT_LEN_30MS];
@@ -131,7 +137,6 @@
 
 /* type definition encoder instance */
 typedef struct IlbcEncoder_ {
-
   /* flag for frame size mode */
   int16_t mode;
 
@@ -172,7 +177,6 @@
 
 /* type definition decoder instance */
 typedef struct IlbcDecoder_ {
-
   /* flag for frame size mode */
   int16_t mode;
 
@@ -199,13 +203,13 @@
 
   int16_t prevScale, prevPLI;
   size_t prevLag;
-  int16_t prevLpc[LPC_FILTERORDER+1];
-  int16_t prevResidual[NSUB_MAX*SUBL];
+  int16_t prevLpc[LPC_FILTERORDER + 1];
+  int16_t prevResidual[NSUB_MAX * SUBL];
   int16_t seed;
 
   /* previous synthesis filter parameters */
 
-  int16_t old_syntdenum[(LPC_FILTERORDER + 1)*NSUB_MAX];
+  int16_t old_syntdenum[(LPC_FILTERORDER + 1) * NSUB_MAX];
 
   /* state of output HP filter */
   int16_t hpimemx[2];
@@ -213,7 +217,7 @@
 
   /* enhancer state information */
   int use_enhancer;
-  int16_t enh_buf[ENH_BUFL+ENH_BUFL_FILTEROVERHEAD];
+  int16_t enh_buf[ENH_BUFL + ENH_BUFL_FILTEROVERHEAD];
   size_t enh_period[ENH_NBLOCKS_TOT];
 
 } IlbcDecoder;
diff --git a/modules/audio_coding/codecs/ilbc/do_plc.c b/modules/audio_coding/codecs/ilbc/do_plc.c
index 5d3e896..26ec03f 100644
--- a/modules/audio_coding/codecs/ilbc/do_plc.c
+++ b/modules/audio_coding/codecs/ilbc/do_plc.c
@@ -40,6 +40,7 @@
   size_t i;
   int32_t cross, ener, cross_comp, ener_comp = 0;
   int32_t measure, maxMeasure, energy;
+  int32_t noise_energy_threshold_30dB;
   int16_t max, crossSquareMax, crossSquare;
   size_t j, lag, randlag;
   int16_t tmp1, tmp2;
@@ -231,8 +232,8 @@
     }
 
     /* compute concealed residual */
+    noise_energy_threshold_30dB = (int32_t)iLBCdec_inst->blockl * 900;
     energy = 0;
-
     for (i=0; i<iLBCdec_inst->blockl; i++) {
 
       /* noise component -  52 < randlagFIX < 117 */
@@ -268,15 +269,14 @@
           ((pitchfact * PLCresidual[i] + (32767 - pitchfact) * randvec[i] +
               16384) >> 15)) >> 15);
 
-      /* Shifting down the result one step extra to ensure that no overflow
-         will occur */
-      energy += (PLCresidual[i] * PLCresidual[i]) >>
-          (iLBCdec_inst->prevScale + 1);
+      /* Compute energy until threshold for noise energy is reached */
+      if (energy < noise_energy_threshold_30dB) {
+        energy += PLCresidual[i] * PLCresidual[i];
+      }
     }
 
     /* less than 30 dB, use only noise */
-    if (energy < (WEBRTC_SPL_SHIFT_W32(((int32_t)iLBCdec_inst->blockl*900),-(iLBCdec_inst->prevScale+1)))) {
-      energy = 0;
+    if (energy < noise_energy_threshold_30dB) {
       for (i=0; i<iLBCdec_inst->blockl; i++) {
         PLCresidual[i] = randvec[i];
       }
diff --git a/modules/audio_coding/codecs/ilbc/do_plc.h b/modules/audio_coding/codecs/ilbc/do_plc.h
index 37af305..2fbae1d 100644
--- a/modules/audio_coding/codecs/ilbc/do_plc.h
+++ b/modules/audio_coding/codecs/ilbc/do_plc.h
@@ -27,15 +27,15 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_DoThePlc(
-    int16_t *PLCresidual,  /* (o) concealed residual */
-    int16_t *PLClpc,    /* (o) concealed LP parameters */
-    int16_t PLI,     /* (i) packet loss indicator
-                                                           0 - no PL, 1 = PL */
-    int16_t *decresidual,  /* (i) decoded residual */
-    int16_t *lpc,    /* (i) decoded LPC (only used for no PL) */
-    size_t inlag,    /* (i) pitch lag */
-    IlbcDecoder *iLBCdec_inst
+    int16_t* PLCresidual, /* (o) concealed residual */
+    int16_t* PLClpc,      /* (o) concealed LP parameters */
+    int16_t PLI,          /* (i) packet loss indicator
+                                                                0 - no PL, 1 = PL */
+    int16_t* decresidual, /* (i) decoded residual */
+    int16_t* lpc,         /* (i) decoded LPC (only used for no PL) */
+    size_t inlag,         /* (i) pitch lag */
+    IlbcDecoder* iLBCdec_inst
     /* (i/o) decoder instance */
-                            );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/encode.h b/modules/audio_coding/codecs/ilbc/encode.h
index 8a3928c..db00e2c 100644
--- a/modules/audio_coding/codecs/ilbc/encode.h
+++ b/modules/audio_coding/codecs/ilbc/encode.h
@@ -26,10 +26,10 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_EncodeImpl(
-    uint16_t *bytes,     /* (o) encoded data bits iLBC */
-    const int16_t *block, /* (i) speech vector to encode */
-    IlbcEncoder *iLBCenc_inst /* (i/o) the general encoder
+    uint16_t* bytes,      /* (o) encoded data bits iLBC */
+    const int16_t* block, /* (i) speech vector to encode */
+    IlbcEncoder* iLBCenc_inst /* (i/o) the general encoder
                                            state */
-                          );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/energy_inverse.h b/modules/audio_coding/codecs/ilbc/energy_inverse.h
index 0404f7d..359a9e2 100644
--- a/modules/audio_coding/codecs/ilbc/energy_inverse.h
+++ b/modules/audio_coding/codecs/ilbc/energy_inverse.h
@@ -24,9 +24,10 @@
 /* Inverses the in vector in into Q29 domain */
 
 void WebRtcIlbcfix_EnergyInverse(
-    int16_t *energy,     /* (i/o) Energy and inverse
-                                                                   energy (in Q29) */
-    size_t noOfEnergies);   /* (i)   The length of the energy
-                                   vector */
+    int16_t*
+        energy, /* (i/o) Energy and inverse
+                                                          energy (in Q29) */
+    size_t noOfEnergies); /* (i)   The length of the energy
+                                 vector */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/enh_upsample.h b/modules/audio_coding/codecs/ilbc/enh_upsample.h
index e9a68f4..b427eca 100644
--- a/modules/audio_coding/codecs/ilbc/enh_upsample.h
+++ b/modules/audio_coding/codecs/ilbc/enh_upsample.h
@@ -26,8 +26,8 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_EnhUpsample(
-    int32_t *useq1, /* (o) upsampled output sequence */
-    int16_t *seq1 /* (i) unupsampled sequence */
-                                );
+    int32_t* useq1, /* (o) upsampled output sequence */
+    int16_t* seq1   /* (i) unupsampled sequence */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/enhancer.h b/modules/audio_coding/codecs/ilbc/enhancer.h
index 7e20eb1..1a6131b 100644
--- a/modules/audio_coding/codecs/ilbc/enhancer.h
+++ b/modules/audio_coding/codecs/ilbc/enhancer.h
@@ -27,13 +27,13 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Enhancer(
-    int16_t *odata,   /* (o) smoothed block, dimension blockl */
-    int16_t *idata,   /* (i) data buffer used for enhancing */
-    size_t idatal,   /* (i) dimension idata */
+    int16_t* odata,        /* (o) smoothed block, dimension blockl */
+    int16_t* idata,        /* (i) data buffer used for enhancing */
+    size_t idatal,         /* (i) dimension idata */
     size_t centerStartPos, /* (i) first sample current block within idata */
-    size_t *period,   /* (i) pitch period array (pitch bward-in time) */
-    const size_t *plocs,   /* (i) locations where period array values valid */
-    size_t periodl   /* (i) dimension of period and plocs */
-                            );
+    size_t* period,        /* (i) pitch period array (pitch bward-in time) */
+    const size_t* plocs,   /* (i) locations where period array values valid */
+    size_t periodl         /* (i) dimension of period and plocs */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/enhancer_interface.h b/modules/audio_coding/codecs/ilbc/enhancer_interface.h
index e305161..de45715 100644
--- a/modules/audio_coding/codecs/ilbc/enhancer_interface.h
+++ b/modules/audio_coding/codecs/ilbc/enhancer_interface.h
@@ -26,9 +26,8 @@
  *---------------------------------------------------------------*/
 
 size_t  // (o) Estimated lag in end of in[]
-    WebRtcIlbcfix_EnhancerInterface(
-        int16_t* out,                // (o) enhanced signal
-        const int16_t* in,           // (i) unenhanced signal
-        IlbcDecoder* iLBCdec_inst);  // (i) buffers etc
+WebRtcIlbcfix_EnhancerInterface(int16_t* out,       // (o) enhanced signal
+                                const int16_t* in,  // (i) unenhanced signal
+                                IlbcDecoder* iLBCdec_inst);  // (i) buffers etc
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/filtered_cb_vecs.h b/modules/audio_coding/codecs/ilbc/filtered_cb_vecs.h
index f57e9c4..c51ac39 100644
--- a/modules/audio_coding/codecs/ilbc/filtered_cb_vecs.h
+++ b/modules/audio_coding/codecs/ilbc/filtered_cb_vecs.h
@@ -28,11 +28,11 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_FilteredCbVecs(
-    int16_t *cbvectors, /* (o) Codebook vector for the higher section */
-    int16_t *CBmem,  /* (i) Codebook memory that is filtered to create a
-                                           second CB section */
-    size_t lMem,  /* (i) Length of codebook memory */
-    size_t samples    /* (i) Number of samples to filter */
-                                  );
+    int16_t* cbvectors, /* (o) Codebook vector for the higher section */
+    int16_t* CBmem,     /* (i) Codebook memory that is filtered to create a
+                                              second CB section */
+    size_t lMem,        /* (i) Length of codebook memory */
+    size_t samples      /* (i) Number of samples to filter */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/frame_classify.h b/modules/audio_coding/codecs/ilbc/frame_classify.h
index 60b3249..43c6e57 100644
--- a/modules/audio_coding/codecs/ilbc/frame_classify.h
+++ b/modules/audio_coding/codecs/ilbc/frame_classify.h
@@ -21,9 +21,9 @@
 
 size_t WebRtcIlbcfix_FrameClassify(
     /* (o) Index to the max-energy sub frame */
-    IlbcEncoder *iLBCenc_inst,
+    IlbcEncoder* iLBCenc_inst,
     /* (i/o) the encoder state structure */
-    int16_t *residualFIX /* (i) lpc residual signal */
-                                                );
+    int16_t* residualFIX /* (i) lpc residual signal */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/gain_dequant.h b/modules/audio_coding/codecs/ilbc/gain_dequant.h
index 6989372..86cc787 100644
--- a/modules/audio_coding/codecs/ilbc/gain_dequant.h
+++ b/modules/audio_coding/codecs/ilbc/gain_dequant.h
@@ -30,7 +30,7 @@
     /* (o) quantized gain value (Q14) */
     int16_t index, /* (i) quantization index */
     int16_t maxIn, /* (i) maximum of unquantized gain (Q14) */
-    int16_t stage /* (i) The stage of the search */
-                                         );
+    int16_t stage  /* (i) The stage of the search */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/gain_quant.h b/modules/audio_coding/codecs/ilbc/gain_quant.h
index bc5a936..51c0bc9 100644
--- a/modules/audio_coding/codecs/ilbc/gain_quant.h
+++ b/modules/audio_coding/codecs/ilbc/gain_quant.h
@@ -25,11 +25,12 @@
  *  quantizer for the gain in the gain-shape coding of residual
  *---------------------------------------------------------------*/
 
-int16_t WebRtcIlbcfix_GainQuant( /* (o) quantized gain value */
-    int16_t gain, /* (i) gain value Q14 */
-    int16_t maxIn, /* (i) maximum of gain value Q14 */
-    int16_t stage, /* (i) The stage of the search */
-    int16_t *index /* (o) quantization index */
-                                       );
+int16_t
+WebRtcIlbcfix_GainQuant(               /* (o) quantized gain value */
+                        int16_t gain,  /* (i) gain value Q14 */
+                        int16_t maxIn, /* (i) maximum of gain value Q14 */
+                        int16_t stage, /* (i) The stage of the search */
+                        int16_t* index /* (o) quantization index */
+                        );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/get_lsp_poly.h b/modules/audio_coding/codecs/ilbc/get_lsp_poly.h
index 1351b8b..d469409 100644
--- a/modules/audio_coding/codecs/ilbc/get_lsp_poly.h
+++ b/modules/audio_coding/codecs/ilbc/get_lsp_poly.h
@@ -40,8 +40,7 @@
  * }
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_GetLspPoly(
-    int16_t *lsp, /* (i) LSP in Q15 */
-    int32_t *f);  /* (o) polonymial in Q24 */
+void WebRtcIlbcfix_GetLspPoly(int16_t* lsp, /* (i) LSP in Q15 */
+                              int32_t* f);  /* (o) polonymial in Q24 */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/get_sync_seq.h b/modules/audio_coding/codecs/ilbc/get_sync_seq.h
index 5c72956..2281b06 100644
--- a/modules/audio_coding/codecs/ilbc/get_sync_seq.h
+++ b/modules/audio_coding/codecs/ilbc/get_sync_seq.h
@@ -26,15 +26,15 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_GetSyncSeq(
-    int16_t *idata,   /* (i) original data */
-    size_t idatal,   /* (i) dimension of data */
+    int16_t* idata,        /* (i) original data */
+    size_t idatal,         /* (i) dimension of data */
     size_t centerStartPos, /* (i) where current block starts */
-    size_t *period,   /* (i) rough-pitch-period array       (Q-2) */
-    const size_t *plocs, /* (i) where periods of period array are taken (Q-2) */
-    size_t periodl,   /* (i) dimension period array */
-    size_t hl,    /* (i) 2*hl+1 is the number of sequences */
-    int16_t *surround  /* (i/o) The contribution from this sequence
-                                summed with earlier contributions */
-                              );
+    size_t* period,        /* (i) rough-pitch-period array       (Q-2) */
+    const size_t* plocs, /* (i) where periods of period array are taken (Q-2) */
+    size_t periodl,      /* (i) dimension period array */
+    size_t hl,           /* (i) 2*hl+1 is the number of sequences */
+    int16_t* surround    /* (i/o) The contribution from this sequence
+                                  summed with earlier contributions */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/hp_input.h b/modules/audio_coding/codecs/ilbc/hp_input.h
index f354dd9..ac0d26b 100644
--- a/modules/audio_coding/codecs/ilbc/hp_input.h
+++ b/modules/audio_coding/codecs/ilbc/hp_input.h
@@ -22,13 +22,13 @@
 #include "modules/audio_coding/codecs/ilbc/defines.h"
 
 void WebRtcIlbcfix_HpInput(
-    int16_t *signal,     /* (i/o) signal vector */
-    int16_t *ba,      /* (i)   B- and A-coefficients (2:nd order)
-                                                                   {b[0] b[1] b[2] -a[1] -a[2]} a[0]
-                                                                   is assumed to be 1.0 */
-    int16_t *y,      /* (i/o) Filter state yhi[n-1] ylow[n-1]
-                                                                   yhi[n-2] ylow[n-2] */
-    int16_t *x,      /* (i/o) Filter state x[n-1] x[n-2] */
+    int16_t* signal, /* (i/o) signal vector */
+    int16_t* ba,     /* (i)   B- and A-coefficients (2:nd order)
+                              {b[0] b[1] b[2] -a[1] -a[2]}
+                              a[0] is assumed to be 1.0 */
+    int16_t* y,      /* (i/o) Filter state yhi[n-1] ylow[n-1]
+                              yhi[n-2] ylow[n-2] */
+    int16_t* x,      /* (i/o) Filter state x[n-1] x[n-2] */
     size_t len);     /* (i)   Number of samples to filter */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/hp_output.h b/modules/audio_coding/codecs/ilbc/hp_output.h
index a060a9d..88ecdb5 100644
--- a/modules/audio_coding/codecs/ilbc/hp_output.h
+++ b/modules/audio_coding/codecs/ilbc/hp_output.h
@@ -22,13 +22,13 @@
 #include "modules/audio_coding/codecs/ilbc/defines.h"
 
 void WebRtcIlbcfix_HpOutput(
-    int16_t *signal,     /* (i/o) signal vector */
-    int16_t *ba,      /* (i)   B- and A-coefficients (2:nd order)
-                               {b[0] b[1] b[2] -a[1] -a[2]} a[0]
-                               is assumed to be 1.0 */
-    int16_t *y,      /* (i/o) Filter state yhi[n-1] ylow[n-1]
+    int16_t* signal, /* (i/o) signal vector */
+    int16_t* ba,     /* (i)   B- and A-coefficients (2:nd order)
+                              {b[0] b[1] b[2] -a[1] -a[2]} a[0]
+                              is assumed to be 1.0 */
+    int16_t* y,      /* (i/o) Filter state yhi[n-1] ylow[n-1]
                               yhi[n-2] ylow[n-2] */
-    int16_t *x,      /* (i/o) Filter state x[n-1] x[n-2] */
-    size_t len);      /* (i)   Number of samples to filter */
+    int16_t* x,      /* (i/o) Filter state x[n-1] x[n-2] */
+    size_t len);     /* (i)   Number of samples to filter */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/ilbc.h b/modules/audio_coding/codecs/ilbc/ilbc.h
index 7836489..4c12665 100644
--- a/modules/audio_coding/codecs/ilbc/ilbc.h
+++ b/modules/audio_coding/codecs/ilbc/ilbc.h
@@ -40,216 +40,214 @@
  */
 
 #define ILBC_SPEECH 1
-#define ILBC_CNG  2
+#define ILBC_CNG 2
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-  /****************************************************************************
-   * WebRtcIlbcfix_XxxAssign(...)
-   *
-   * These functions assigns the encoder/decoder instance to the specified
-   * memory location
-   *
-   * Input:
-   *     - XXX_xxxinst       : Pointer to created instance that should be
-   *                           assigned
-   *     - ILBCXXX_inst_Addr : Pointer to the desired memory space
-   *     - size              : The size that this structure occupies (in Word16)
-   *
-   * Return value             :  0 - Ok
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_XxxAssign(...)
+ *
+ * These functions assigns the encoder/decoder instance to the specified
+ * memory location
+ *
+ * Input:
+ *     - XXX_xxxinst       : Pointer to created instance that should be
+ *                           assigned
+ *     - ILBCXXX_inst_Addr : Pointer to the desired memory space
+ *     - size              : The size that this structure occupies (in Word16)
+ *
+ * Return value             :  0 - Ok
+ *                            -1 - Error
+ */
 
-  int16_t WebRtcIlbcfix_EncoderAssign(IlbcEncoderInstance **iLBC_encinst,
-                                      int16_t *ILBCENC_inst_Addr,
-                                      int16_t *size);
-  int16_t WebRtcIlbcfix_DecoderAssign(IlbcDecoderInstance **iLBC_decinst,
-                                      int16_t *ILBCDEC_inst_Addr,
-                                      int16_t *size);
+int16_t WebRtcIlbcfix_EncoderAssign(IlbcEncoderInstance** iLBC_encinst,
+                                    int16_t* ILBCENC_inst_Addr,
+                                    int16_t* size);
+int16_t WebRtcIlbcfix_DecoderAssign(IlbcDecoderInstance** iLBC_decinst,
+                                    int16_t* ILBCDEC_inst_Addr,
+                                    int16_t* size);
 
+/****************************************************************************
+ * WebRtcIlbcfix_XxxAssign(...)
+ *
+ * These functions create a instance to the specified structure
+ *
+ * Input:
+ *      - XXX_inst        : Pointer to created instance that should be created
+ *
+ * Return value           :  0 - Ok
+ *                          -1 - Error
+ */
 
-  /****************************************************************************
-   * WebRtcIlbcfix_XxxAssign(...)
-   *
-   * These functions create a instance to the specified structure
-   *
-   * Input:
-   *      - XXX_inst        : Pointer to created instance that should be created
-   *
-   * Return value           :  0 - Ok
-   *                          -1 - Error
-   */
+int16_t WebRtcIlbcfix_EncoderCreate(IlbcEncoderInstance** iLBC_encinst);
+int16_t WebRtcIlbcfix_DecoderCreate(IlbcDecoderInstance** iLBC_decinst);
 
-  int16_t WebRtcIlbcfix_EncoderCreate(IlbcEncoderInstance **iLBC_encinst);
-  int16_t WebRtcIlbcfix_DecoderCreate(IlbcDecoderInstance **iLBC_decinst);
+/****************************************************************************
+ * WebRtcIlbcfix_XxxFree(...)
+ *
+ * These functions frees the dynamic memory of a specified instance
+ *
+ * Input:
+ *      - XXX_inst          : Pointer to created instance that should be freed
+ *
+ * Return value             :  0 - Ok
+ *                            -1 - Error
+ */
 
-  /****************************************************************************
-   * WebRtcIlbcfix_XxxFree(...)
-   *
-   * These functions frees the dynamic memory of a specified instance
-   *
-   * Input:
-   *      - XXX_inst          : Pointer to created instance that should be freed
-   *
-   * Return value             :  0 - Ok
-   *                            -1 - Error
-   */
+int16_t WebRtcIlbcfix_EncoderFree(IlbcEncoderInstance* iLBC_encinst);
+int16_t WebRtcIlbcfix_DecoderFree(IlbcDecoderInstance* iLBC_decinst);
 
-  int16_t WebRtcIlbcfix_EncoderFree(IlbcEncoderInstance *iLBC_encinst);
-  int16_t WebRtcIlbcfix_DecoderFree(IlbcDecoderInstance *iLBC_decinst);
+/****************************************************************************
+ * WebRtcIlbcfix_EncoderInit(...)
+ *
+ * This function initializes a iLBC instance
+ *
+ * Input:
+ *      - iLBCenc_inst      : iLBC instance, i.e. the user that should receive
+ *                            be initialized
+ *      - frameLen          : The frame length of the codec 20/30 (ms)
+ *
+ * Return value             :  0 - Ok
+ *                            -1 - Error
+ */
 
+int16_t WebRtcIlbcfix_EncoderInit(IlbcEncoderInstance* iLBCenc_inst,
+                                  int16_t frameLen);
 
-  /****************************************************************************
-   * WebRtcIlbcfix_EncoderInit(...)
-   *
-   * This function initializes a iLBC instance
-   *
-   * Input:
-   *      - iLBCenc_inst      : iLBC instance, i.e. the user that should receive
-   *                            be initialized
-   *      - frameLen          : The frame length of the codec 20/30 (ms)
-   *
-   * Return value             :  0 - Ok
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_Encode(...)
+ *
+ * This function encodes one iLBC frame. Input speech length has be a
+ * multiple of the frame length.
+ *
+ * Input:
+ *      - iLBCenc_inst      : iLBC instance, i.e. the user that should encode
+ *                            a package
+ *      - speechIn          : Input speech vector
+ *      - len               : Samples in speechIn (160, 240, 320 or 480)
+ *
+ * Output:
+ *  - encoded               : The encoded data vector
+ *
+ * Return value             : >0 - Length (in bytes) of coded data
+ *                            -1 - Error
+ */
 
-  int16_t WebRtcIlbcfix_EncoderInit(IlbcEncoderInstance *iLBCenc_inst,
-                                    int16_t frameLen);
+int WebRtcIlbcfix_Encode(IlbcEncoderInstance* iLBCenc_inst,
+                         const int16_t* speechIn,
+                         size_t len,
+                         uint8_t* encoded);
 
-  /****************************************************************************
-   * WebRtcIlbcfix_Encode(...)
-   *
-   * This function encodes one iLBC frame. Input speech length has be a
-   * multiple of the frame length.
-   *
-   * Input:
-   *      - iLBCenc_inst      : iLBC instance, i.e. the user that should encode
-   *                            a package
-   *      - speechIn          : Input speech vector
-   *      - len               : Samples in speechIn (160, 240, 320 or 480)
-   *
-   * Output:
-   *  - encoded               : The encoded data vector
-   *
-   * Return value             : >0 - Length (in bytes) of coded data
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_DecoderInit(...)
+ *
+ * This function initializes a iLBC instance with either 20 or 30 ms frames
+ * Alternatively the WebRtcIlbcfix_DecoderInit_XXms can be used. Then it's
+ * not needed to specify the frame length with a variable.
+ *
+ * Input:
+ *      - IlbcDecoderInstance : iLBC decoder instance
+ *      - frameLen            : The frame length of the codec 20/30 (ms)
+ *
+ * Return value               :  0 - Ok
+ *                              -1 - Error
+ */
 
-  int WebRtcIlbcfix_Encode(IlbcEncoderInstance *iLBCenc_inst,
-                           const int16_t *speechIn,
-                           size_t len,
-                           uint8_t* encoded);
+int16_t WebRtcIlbcfix_DecoderInit(IlbcDecoderInstance* iLBCdec_inst,
+                                  int16_t frameLen);
+void WebRtcIlbcfix_DecoderInit20Ms(IlbcDecoderInstance* iLBCdec_inst);
+void WebRtcIlbcfix_Decoderinit30Ms(IlbcDecoderInstance* iLBCdec_inst);
 
-  /****************************************************************************
-   * WebRtcIlbcfix_DecoderInit(...)
-   *
-   * This function initializes a iLBC instance with either 20 or 30 ms frames
-   * Alternatively the WebRtcIlbcfix_DecoderInit_XXms can be used. Then it's
-   * not needed to specify the frame length with a variable.
-   *
-   * Input:
-   *      - IlbcDecoderInstance : iLBC decoder instance
-   *      - frameLen            : The frame length of the codec 20/30 (ms)
-   *
-   * Return value               :  0 - Ok
-   *                              -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_Decode(...)
+ *
+ * This function decodes a packet with iLBC frame(s). Output speech length
+ * will be a multiple of 160 or 240 samples ((160 or 240)*frames/packet).
+ *
+ * Input:
+ *      - iLBCdec_inst      : iLBC instance, i.e. the user that should decode
+ *                            a packet
+ *      - encoded           : Encoded iLBC frame(s)
+ *      - len               : Bytes in encoded vector
+ *
+ * Output:
+ *      - decoded           : The decoded vector
+ *      - speechType        : 1 normal, 2 CNG
+ *
+ * Return value             : >0 - Samples in decoded vector
+ *                            -1 - Error
+ */
 
-  int16_t WebRtcIlbcfix_DecoderInit(IlbcDecoderInstance *iLBCdec_inst,
-                                    int16_t frameLen);
-  void WebRtcIlbcfix_DecoderInit20Ms(IlbcDecoderInstance* iLBCdec_inst);
-  void WebRtcIlbcfix_Decoderinit30Ms(IlbcDecoderInstance* iLBCdec_inst);
+int WebRtcIlbcfix_Decode(IlbcDecoderInstance* iLBCdec_inst,
+                         const uint8_t* encoded,
+                         size_t len,
+                         int16_t* decoded,
+                         int16_t* speechType);
+int WebRtcIlbcfix_Decode20Ms(IlbcDecoderInstance* iLBCdec_inst,
+                             const uint8_t* encoded,
+                             size_t len,
+                             int16_t* decoded,
+                             int16_t* speechType);
+int WebRtcIlbcfix_Decode30Ms(IlbcDecoderInstance* iLBCdec_inst,
+                             const uint8_t* encoded,
+                             size_t len,
+                             int16_t* decoded,
+                             int16_t* speechType);
 
-  /****************************************************************************
-   * WebRtcIlbcfix_Decode(...)
-   *
-   * This function decodes a packet with iLBC frame(s). Output speech length
-   * will be a multiple of 160 or 240 samples ((160 or 240)*frames/packet).
-   *
-   * Input:
-   *      - iLBCdec_inst      : iLBC instance, i.e. the user that should decode
-   *                            a packet
-   *      - encoded           : Encoded iLBC frame(s)
-   *      - len               : Bytes in encoded vector
-   *
-   * Output:
-   *      - decoded           : The decoded vector
-   *      - speechType        : 1 normal, 2 CNG
-   *
-   * Return value             : >0 - Samples in decoded vector
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_DecodePlc(...)
+ *
+ * This function conducts PLC for iLBC frame(s). Output speech length
+ * will be a multiple of 160 or 240 samples.
+ *
+ * Input:
+ *      - iLBCdec_inst      : iLBC instance, i.e. the user that should perform
+ *                            a PLC
+ *      - noOfLostFrames    : Number of PLC frames to produce
+ *
+ * Output:
+ *      - decoded           : The "decoded" vector
+ *
+ * Return value             : Samples in decoded PLC vector
+ */
 
-  int WebRtcIlbcfix_Decode(IlbcDecoderInstance* iLBCdec_inst,
-                           const uint8_t* encoded,
-                           size_t len,
-                           int16_t* decoded,
-                           int16_t* speechType);
-  int WebRtcIlbcfix_Decode20Ms(IlbcDecoderInstance* iLBCdec_inst,
-                               const uint8_t* encoded,
-                               size_t len,
+size_t WebRtcIlbcfix_DecodePlc(IlbcDecoderInstance* iLBCdec_inst,
                                int16_t* decoded,
-                               int16_t* speechType);
-  int WebRtcIlbcfix_Decode30Ms(IlbcDecoderInstance* iLBCdec_inst,
-                               const uint8_t* encoded,
-                               size_t len,
-                               int16_t* decoded,
-                               int16_t* speechType);
+                               size_t noOfLostFrames);
 
-  /****************************************************************************
-   * WebRtcIlbcfix_DecodePlc(...)
-   *
-   * This function conducts PLC for iLBC frame(s). Output speech length
-   * will be a multiple of 160 or 240 samples.
-   *
-   * Input:
-   *      - iLBCdec_inst      : iLBC instance, i.e. the user that should perform
-   *                            a PLC
-   *      - noOfLostFrames    : Number of PLC frames to produce
-   *
-   * Output:
-   *      - decoded           : The "decoded" vector
-   *
-   * Return value             : Samples in decoded PLC vector
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_NetEqPlc(...)
+ *
+ * This function updates the decoder when a packet loss has occured, but it
+ * does not produce any PLC data. Function can be used if another PLC method
+ * is used (i.e NetEq).
+ *
+ * Input:
+ *      - iLBCdec_inst      : iLBC instance that should be updated
+ *      - noOfLostFrames    : Number of lost frames
+ *
+ * Output:
+ *      - decoded           : The "decoded" vector (nothing in this case)
+ *
+ * Return value             : Samples in decoded PLC vector
+ */
 
-  size_t WebRtcIlbcfix_DecodePlc(IlbcDecoderInstance *iLBCdec_inst,
-                                 int16_t *decoded,
-                                 size_t noOfLostFrames);
+size_t WebRtcIlbcfix_NetEqPlc(IlbcDecoderInstance* iLBCdec_inst,
+                              int16_t* decoded,
+                              size_t noOfLostFrames);
 
-  /****************************************************************************
-   * WebRtcIlbcfix_NetEqPlc(...)
-   *
-   * This function updates the decoder when a packet loss has occured, but it
-   * does not produce any PLC data. Function can be used if another PLC method
-   * is used (i.e NetEq).
-   *
-   * Input:
-   *      - iLBCdec_inst      : iLBC instance that should be updated
-   *      - noOfLostFrames    : Number of lost frames
-   *
-   * Output:
-   *      - decoded           : The "decoded" vector (nothing in this case)
-   *
-   * Return value             : Samples in decoded PLC vector
-   */
+/****************************************************************************
+ * WebRtcIlbcfix_version(...)
+ *
+ * This function returns the version number of iLBC
+ *
+ * Output:
+ *      - version           : Version number of iLBC (maximum 20 char)
+ */
 
-  size_t WebRtcIlbcfix_NetEqPlc(IlbcDecoderInstance *iLBCdec_inst,
-                                int16_t *decoded,
-                                size_t noOfLostFrames);
-
-  /****************************************************************************
-   * WebRtcIlbcfix_version(...)
-   *
-   * This function returns the version number of iLBC
-   *
-   * Output:
-   *      - version           : Version number of iLBC (maximum 20 char)
-   */
-
-  void WebRtcIlbcfix_version(char *version);
+void WebRtcIlbcfix_version(char* version);
 
 #ifdef __cplusplus
 }
diff --git a/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc b/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
index b8d3c7c..5ec1219 100644
--- a/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
+++ b/modules/audio_coding/codecs/ilbc/ilbc_unittest.cc
@@ -71,7 +71,7 @@
 TEST_P(SplitIlbcTest, NumFrames) {
   AudioDecoderIlbcImpl decoder;
   const size_t frame_length_samples = frame_length_ms_ * 8;
-  const auto generate_payload = [] (size_t payload_length_bytes) {
+  const auto generate_payload = [](size_t payload_length_bytes) {
     rtc::Buffer payload(payload_length_bytes);
     // Fill payload with increasing integers {0, 1, 2, ...}.
     for (size_t i = 0; i < payload.size(); ++i) {
@@ -104,7 +104,8 @@
 // The maximum is defined by the largest payload length that can be uniquely
 // resolved to a frame size of either 38 bytes (20 ms) or 50 bytes (30 ms).
 INSTANTIATE_TEST_CASE_P(
-    IlbcTest, SplitIlbcTest,
+    IlbcTest,
+    SplitIlbcTest,
     ::testing::Values(std::pair<int, int>(1, 20),  // 1 frame, 20 ms.
                       std::pair<int, int>(2, 20),  // 2 frames, 20 ms.
                       std::pair<int, int>(3, 20),  // And so on.
diff --git a/modules/audio_coding/codecs/ilbc/index_conv_dec.h b/modules/audio_coding/codecs/ilbc/index_conv_dec.h
index 03a721b..4f08ce0 100644
--- a/modules/audio_coding/codecs/ilbc/index_conv_dec.h
+++ b/modules/audio_coding/codecs/ilbc/index_conv_dec.h
@@ -21,8 +21,7 @@
 
 #include "modules/audio_coding/codecs/ilbc/defines.h"
 
-void WebRtcIlbcfix_IndexConvDec(
-    int16_t *index   /* (i/o) Codebook indexes */
+void WebRtcIlbcfix_IndexConvDec(int16_t* index /* (i/o) Codebook indexes */
                                 );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/index_conv_enc.h b/modules/audio_coding/codecs/ilbc/index_conv_enc.h
index 9938448..f899499 100644
--- a/modules/audio_coding/codecs/ilbc/index_conv_enc.h
+++ b/modules/audio_coding/codecs/ilbc/index_conv_enc.h
@@ -25,8 +25,7 @@
  *  Convert the codebook indexes to make the search easier
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_IndexConvEnc(
-    int16_t *index   /* (i/o) Codebook indexes */
+void WebRtcIlbcfix_IndexConvEnc(int16_t* index /* (i/o) Codebook indexes */
                                 );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/init_decode.h b/modules/audio_coding/codecs/ilbc/init_decode.h
index 49bd61c..fdcf9f0 100644
--- a/modules/audio_coding/codecs/ilbc/init_decode.h
+++ b/modules/audio_coding/codecs/ilbc/init_decode.h
@@ -25,11 +25,12 @@
  *  Initiation of decoder instance.
  *---------------------------------------------------------------*/
 
-int WebRtcIlbcfix_InitDecode(  /* (o) Number of decoded samples */
-    IlbcDecoder *iLBCdec_inst, /* (i/o) Decoder instance */
-    int16_t mode,     /* (i) frame size mode */
-    int use_enhancer           /* (i) 1 to use enhancer
-                                  0 to run without enhancer */
-                                         );
+int WebRtcIlbcfix_InitDecode(/* (o) Number of decoded samples */
+                             IlbcDecoder*
+                                 iLBCdec_inst, /* (i/o) Decoder instance */
+                             int16_t mode,     /* (i) frame size mode */
+                             int use_enhancer  /* (i) 1 to use enhancer
+                                                  0 to run without enhancer */
+                             );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/init_encode.h b/modules/audio_coding/codecs/ilbc/init_encode.h
index d9b2971..f91a9b0 100644
--- a/modules/audio_coding/codecs/ilbc/init_encode.h
+++ b/modules/audio_coding/codecs/ilbc/init_encode.h
@@ -25,9 +25,10 @@
  *  Initiation of encoder instance.
  *---------------------------------------------------------------*/
 
-int WebRtcIlbcfix_InitEncode(  /* (o) Number of bytes encoded */
-    IlbcEncoder *iLBCenc_inst, /* (i/o) Encoder instance */
-    int16_t mode     /* (i) frame size mode */
-                                         );
+int WebRtcIlbcfix_InitEncode(/* (o) Number of bytes encoded */
+                             IlbcEncoder*
+                                 iLBCenc_inst, /* (i/o) Encoder instance */
+                             int16_t mode      /* (i) frame size mode */
+                             );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/interpolate.h b/modules/audio_coding/codecs/ilbc/interpolate.h
index fc360b4..9f03236 100644
--- a/modules/audio_coding/codecs/ilbc/interpolate.h
+++ b/modules/audio_coding/codecs/ilbc/interpolate.h
@@ -26,10 +26,10 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Interpolate(
-    int16_t *out, /* (o) output vector */
-    int16_t *in1, /* (i) first input vector */
-    int16_t *in2, /* (i) second input vector */
-    int16_t coef, /* (i) weight coefficient in Q14 */
+    int16_t* out,    /* (o) output vector */
+    int16_t* in1,    /* (i) first input vector */
+    int16_t* in2,    /* (i) second input vector */
+    int16_t coef,    /* (i) weight coefficient in Q14 */
     int16_t length); /* (i) number of sample is vectors */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/interpolate_samples.h b/modules/audio_coding/codecs/ilbc/interpolate_samples.h
index f522f93..264a101 100644
--- a/modules/audio_coding/codecs/ilbc/interpolate_samples.h
+++ b/modules/audio_coding/codecs/ilbc/interpolate_samples.h
@@ -26,9 +26,9 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_InterpolateSamples(
-    int16_t *interpSamples, /* (o) The interpolated samples */
-    int16_t *CBmem,   /* (i) The CB memory */
-    size_t lMem    /* (i) Length of the CB memory */
-                                      );
+    int16_t* interpSamples, /* (o) The interpolated samples */
+    int16_t* CBmem,         /* (i) The CB memory */
+    size_t lMem             /* (i) Length of the CB memory */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lpc_encode.h b/modules/audio_coding/codecs/ilbc/lpc_encode.h
index 7255705..256fa49 100644
--- a/modules/audio_coding/codecs/ilbc/lpc_encode.h
+++ b/modules/audio_coding/codecs/ilbc/lpc_encode.h
@@ -26,14 +26,14 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_LpcEncode(
-    int16_t *syntdenum,  /* (i/o) synthesis filter coefficients
-                                  before/after encoding */
-    int16_t *weightdenum, /* (i/o) weighting denumerator coefficients
+    int16_t* syntdenum,   /* (i/o) synthesis filter coefficients
                                    before/after encoding */
-    int16_t *lsf_index,  /* (o) lsf quantization index */
-    int16_t *data,   /* (i) Speech to do LPC analysis on */
-    IlbcEncoder *iLBCenc_inst
+    int16_t* weightdenum, /* (i/o) weighting denumerator coefficients
+                                   before/after encoding */
+    int16_t* lsf_index,   /* (o) lsf quantization index */
+    int16_t* data,        /* (i) Speech to do LPC analysis on */
+    IlbcEncoder* iLBCenc_inst
     /* (i/o) the encoder state structure */
-                             );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lsf_check.h b/modules/audio_coding/codecs/ilbc/lsf_check.h
index f92e0cc..d367c1d 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_check.h
+++ b/modules/audio_coding/codecs/ilbc/lsf_check.h
@@ -25,9 +25,8 @@
  *  check for stability of lsf coefficients
  *---------------------------------------------------------------*/
 
-int WebRtcIlbcfix_LsfCheck(
-    int16_t *lsf, /* LSF parameters */
-    int dim, /* dimension of LSF */
-    int NoAn); /* No of analysis per frame */
+int WebRtcIlbcfix_LsfCheck(int16_t* lsf, /* LSF parameters */
+                           int dim,      /* dimension of LSF */
+                           int NoAn);    /* No of analysis per frame */
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_dec.h b/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_dec.h
index 4a6c0d5..016897a 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_dec.h
+++ b/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_dec.h
@@ -26,12 +26,12 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_LspInterpolate2PolyDec(
-    int16_t *a,   /* (o) lpc coefficients Q12 */
-    int16_t *lsf1,  /* (i) first set of lsf coefficients Q13 */
-    int16_t *lsf2,  /* (i) second set of lsf coefficients Q13 */
+    int16_t* a,    /* (o) lpc coefficients Q12 */
+    int16_t* lsf1, /* (i) first set of lsf coefficients Q13 */
+    int16_t* lsf2, /* (i) second set of lsf coefficients Q13 */
     int16_t coef,  /* (i) weighting coefficient to use between
                                    lsf1 and lsf2 Q14 */
-    int16_t length  /* (i) length of coefficient vectors */
-                                          );
+    int16_t length /* (i) length of coefficient vectors */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_enc.h b/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_enc.h
index 74863c6..9cb0dd9 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_enc.h
+++ b/modules/audio_coding/codecs/ilbc/lsf_interpolate_to_poly_enc.h
@@ -27,12 +27,12 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_LsfInterpolate2PloyEnc(
-    int16_t *a,  /* (o) lpc coefficients Q12 */
-    int16_t *lsf1, /* (i) first set of lsf coefficients Q13 */
-    int16_t *lsf2, /* (i) second set of lsf coefficients Q13 */
-    int16_t coef, /* (i) weighting coefficient to use between
-                           lsf1 and lsf2 Q14 */
+    int16_t* a,    /* (o) lpc coefficients Q12 */
+    int16_t* lsf1, /* (i) first set of lsf coefficients Q13 */
+    int16_t* lsf2, /* (i) second set of lsf coefficients Q13 */
+    int16_t coef,  /* (i) weighting coefficient to use between
+                            lsf1 and lsf2 Q14 */
     int16_t length /* (i) length of coefficient vectors */
-                                          );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lsf_to_lsp.h b/modules/audio_coding/codecs/ilbc/lsf_to_lsp.h
index 80c0798..921101a 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_to_lsp.h
+++ b/modules/audio_coding/codecs/ilbc/lsf_to_lsp.h
@@ -26,9 +26,9 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Lsf2Lsp(
-    int16_t *lsf, /* (i) lsf in Q13 values between 0 and pi */
-    int16_t *lsp, /* (o) lsp in Q15 values between -1 and 1 */
+    int16_t* lsf, /* (i) lsf in Q13 values between 0 and pi */
+    int16_t* lsp, /* (o) lsp in Q15 values between -1 and 1 */
     int16_t m     /* (i) number of coefficients */
-                           );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lsf_to_poly.h b/modules/audio_coding/codecs/ilbc/lsf_to_poly.h
index 68c4dd0..e551836 100644
--- a/modules/audio_coding/codecs/ilbc/lsf_to_poly.h
+++ b/modules/audio_coding/codecs/ilbc/lsf_to_poly.h
@@ -26,8 +26,8 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Lsf2Poly(
-    int16_t *a,     /* (o) predictor coefficients (order = 10) in Q12 */
-    int16_t *lsf    /* (i) line spectral frequencies in Q13 */
-                            );
+    int16_t* a,  /* (o) predictor coefficients (order = 10) in Q12 */
+    int16_t* lsf /* (i) line spectral frequencies in Q13 */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/lsp_to_lsf.h b/modules/audio_coding/codecs/ilbc/lsp_to_lsf.h
index 666a99a..358786e 100644
--- a/modules/audio_coding/codecs/ilbc/lsp_to_lsf.h
+++ b/modules/audio_coding/codecs/ilbc/lsp_to_lsf.h
@@ -26,10 +26,10 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Lsp2Lsf(
-    int16_t *lsp, /* (i) lsp vector -1...+1 in Q15 */
-    int16_t *lsf, /* (o) Lsf vector 0...Pi in Q13
+    int16_t* lsp, /* (i) lsp vector -1...+1 in Q15 */
+    int16_t* lsf, /* (o) Lsf vector 0...Pi in Q13
                            (ordered, so that lsf[i]<lsf[i+1]) */
-    int16_t m  /* (i) Number of coefficients */
-                           );
+    int16_t m     /* (i) Number of coefficients */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/my_corr.h b/modules/audio_coding/codecs/ilbc/my_corr.h
index 7c6eb19..21deea5 100644
--- a/modules/audio_coding/codecs/ilbc/my_corr.h
+++ b/modules/audio_coding/codecs/ilbc/my_corr.h
@@ -25,12 +25,11 @@
  * compute cross correlation between sequences
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_MyCorr(
-    int32_t* corr,  /* (o) correlation of seq1 and seq2 */
-    const int16_t* seq1,  /* (i) first sequence */
-    size_t dim1,  /* (i) dimension first seq1 */
-    const int16_t* seq2, /* (i) second sequence */
-    size_t dim2   /* (i) dimension seq2 */
+void WebRtcIlbcfix_MyCorr(int32_t* corr, /* (o) correlation of seq1 and seq2 */
+                          const int16_t* seq1, /* (i) first sequence */
+                          size_t dim1,         /* (i) dimension first seq1 */
+                          const int16_t* seq2, /* (i) second sequence */
+                          size_t dim2          /* (i) dimension seq2 */
                           );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/nearest_neighbor.h b/modules/audio_coding/codecs/ilbc/nearest_neighbor.h
index d541fb7..68b5c59 100644
--- a/modules/audio_coding/codecs/ilbc/nearest_neighbor.h
+++ b/modules/audio_coding/codecs/ilbc/nearest_neighbor.h
@@ -27,10 +27,10 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_NearestNeighbor(
-    size_t* index, /* (o) index of array element closest to value */
+    size_t* index,       /* (o) index of array element closest to value */
     const size_t* array, /* (i) data array (Q2) */
-    size_t value, /* (i) value (Q2) */
-    size_t arlength /* (i) dimension of data array (==ENH_NBLOCKS_TOT) */
-                                   );
+    size_t value,        /* (i) value (Q2) */
+    size_t arlength      /* (i) dimension of data array (==ENH_NBLOCKS_TOT) */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/pack_bits.h b/modules/audio_coding/codecs/ilbc/pack_bits.h
index 8ae3013..8dcf41c 100644
--- a/modules/audio_coding/codecs/ilbc/pack_bits.h
+++ b/modules/audio_coding/codecs/ilbc/pack_bits.h
@@ -25,10 +25,10 @@
  *  unpacking of bits from bitstream, i.e., vector of bytes
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_PackBits( 
-    uint16_t *bitstream,   /* (o) The packetized bitstream */
-    iLBC_bits *enc_bits,  /* (i) Encoded bits */
-    int16_t mode     /* (i) Codec mode (20 or 30) */
-                             );
+void WebRtcIlbcfix_PackBits(
+    uint16_t* bitstream, /* (o) The packetized bitstream */
+    iLBC_bits* enc_bits, /* (i) Encoded bits */
+    int16_t mode         /* (i) Codec mode (20 or 30) */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/poly_to_lsf.h b/modules/audio_coding/codecs/ilbc/poly_to_lsf.h
index f930c45..8a68d07 100644
--- a/modules/audio_coding/codecs/ilbc/poly_to_lsf.h
+++ b/modules/audio_coding/codecs/ilbc/poly_to_lsf.h
@@ -25,9 +25,8 @@
  *  conversion from lpc coefficients to lsf coefficients
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_Poly2Lsf(
-    int16_t *lsf,   /* (o) lsf coefficients (Q13) */
-    int16_t *a    /* (i) A coefficients (Q12) */
+void WebRtcIlbcfix_Poly2Lsf(int16_t* lsf, /* (o) lsf coefficients (Q13) */
+                            int16_t* a    /* (i) A coefficients (Q12) */
                             );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/poly_to_lsp.h b/modules/audio_coding/codecs/ilbc/poly_to_lsp.h
index e53aa20..76378f2 100644
--- a/modules/audio_coding/codecs/ilbc/poly_to_lsp.h
+++ b/modules/audio_coding/codecs/ilbc/poly_to_lsp.h
@@ -27,10 +27,10 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Poly2Lsp(
-    int16_t *a,  /* (o) A coefficients in Q12 */
-    int16_t *lsp, /* (i) LSP coefficients in Q15 */
-    int16_t *old_lsp /* (i) old LSP coefficients that are used if the new
+    int16_t* a,      /* (o) A coefficients in Q12 */
+    int16_t* lsp,    /* (i) LSP coefficients in Q15 */
+    int16_t* old_lsp /* (i) old LSP coefficients that are used if the new
                               coefficients turn out to be unstable */
-                            );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/refiner.h b/modules/audio_coding/codecs/ilbc/refiner.h
index 707be7f..87d0de7 100644
--- a/modules/audio_coding/codecs/ilbc/refiner.h
+++ b/modules/audio_coding/codecs/ilbc/refiner.h
@@ -30,14 +30,14 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Refiner(
-    size_t *updStartPos, /* (o) updated start point (Q-2) */
-    int16_t *idata,   /* (i) original data buffer */
-    size_t idatal,   /* (i) dimension of idata */
+    size_t* updStartPos,   /* (o) updated start point (Q-2) */
+    int16_t* idata,        /* (i) original data buffer */
+    size_t idatal,         /* (i) dimension of idata */
     size_t centerStartPos, /* (i) beginning center segment */
-    size_t estSegPos,  /* (i) estimated beginning other segment (Q-2) */
-    int16_t *surround,  /* (i/o) The contribution from this sequence
-                                 summed with earlier contributions */
-    int16_t gain    /* (i) Gain to use for this sequence */
-                           );
+    size_t estSegPos,      /* (i) estimated beginning other segment (Q-2) */
+    int16_t* surround,     /* (i/o) The contribution from this sequence
+                                    summed with earlier contributions */
+    int16_t gain           /* (i) Gain to use for this sequence */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/simple_interpolate_lsf.h b/modules/audio_coding/codecs/ilbc/simple_interpolate_lsf.h
index 61a5625..317f613 100644
--- a/modules/audio_coding/codecs/ilbc/simple_interpolate_lsf.h
+++ b/modules/audio_coding/codecs/ilbc/simple_interpolate_lsf.h
@@ -26,21 +26,21 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SimpleInterpolateLsf(
-    int16_t *syntdenum, /* (o) the synthesis filter denominator
-                                   resulting from the quantized
-                                   interpolated lsf Q12 */
-    int16_t *weightdenum, /* (o) the weighting filter denominator
+    int16_t* syntdenum,   /* (o) the synthesis filter denominator
+                                     resulting from the quantized
+                                     interpolated lsf Q12 */
+    int16_t* weightdenum, /* (o) the weighting filter denominator
                                    resulting from the unquantized
                                    interpolated lsf Q12 */
-    int16_t *lsf,  /* (i) the unquantized lsf coefficients Q13 */
-    int16_t *lsfdeq,  /* (i) the dequantized lsf coefficients Q13 */
-    int16_t *lsfold,  /* (i) the unquantized lsf coefficients of
-                                           the previous signal frame Q13 */
-    int16_t *lsfdeqold, /* (i) the dequantized lsf coefficients of the
-                                   previous signal frame Q13 */
-    int16_t length,  /* (i) should equate FILTERORDER */
-    IlbcEncoder *iLBCenc_inst
+    int16_t* lsf,         /* (i) the unquantized lsf coefficients Q13 */
+    int16_t* lsfdeq,      /* (i) the dequantized lsf coefficients Q13 */
+    int16_t* lsfold,      /* (i) the unquantized lsf coefficients of
+                                               the previous signal frame Q13 */
+    int16_t* lsfdeqold,   /* (i) the dequantized lsf coefficients of the
+                                     previous signal frame Q13 */
+    int16_t length,       /* (i) should equate FILTERORDER */
+    IlbcEncoder* iLBCenc_inst
     /* (i/o) the encoder state structure */
-                                        );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/simple_lpc_analysis.h b/modules/audio_coding/codecs/ilbc/simple_lpc_analysis.h
index 5eaa3d7..3b0548d 100644
--- a/modules/audio_coding/codecs/ilbc/simple_lpc_analysis.h
+++ b/modules/audio_coding/codecs/ilbc/simple_lpc_analysis.h
@@ -26,10 +26,10 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SimpleLpcAnalysis(
-    int16_t *lsf,   /* (o) lsf coefficients */
-    int16_t *data,   /* (i) new block of speech */
-    IlbcEncoder *iLBCenc_inst
+    int16_t* lsf,  /* (o) lsf coefficients */
+    int16_t* data, /* (i) new block of speech */
+    IlbcEncoder* iLBCenc_inst
     /* (i/o) the encoder state structure */
-                                     );
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/simple_lsf_dequant.h b/modules/audio_coding/codecs/ilbc/simple_lsf_dequant.h
index d78d714..ee18486 100644
--- a/modules/audio_coding/codecs/ilbc/simple_lsf_dequant.h
+++ b/modules/audio_coding/codecs/ilbc/simple_lsf_dequant.h
@@ -26,9 +26,9 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SimpleLsfDeQ(
-    int16_t *lsfdeq,  /* (o) dequantized lsf coefficients */
-    int16_t *index,  /* (i) quantization index */
-    int16_t lpc_n  /* (i) number of LPCs */
-                                );
+    int16_t* lsfdeq, /* (o) dequantized lsf coefficients */
+    int16_t* index,  /* (i) quantization index */
+    int16_t lpc_n    /* (i) number of LPCs */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/simple_lsf_quant.h b/modules/audio_coding/codecs/ilbc/simple_lsf_quant.h
index 5e4e6f1..74fb0be 100644
--- a/modules/audio_coding/codecs/ilbc/simple_lsf_quant.h
+++ b/modules/audio_coding/codecs/ilbc/simple_lsf_quant.h
@@ -26,12 +26,12 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SimpleLsfQ(
-    int16_t *lsfdeq, /* (o) dequantized lsf coefficients
+    int16_t* lsfdeq, /* (o) dequantized lsf coefficients
                                    (dimension FILTERORDER) Q13 */
-    int16_t *index, /* (o) quantization index */
-    int16_t *lsf, /* (i) the lsf coefficient vector to be
-                           quantized (dimension FILTERORDER) Q13 */
-    int16_t lpc_n /* (i) number of lsf sets to quantize */
-                              );
+    int16_t* index,  /* (o) quantization index */
+    int16_t* lsf,    /* (i) the lsf coefficient vector to be
+                              quantized (dimension FILTERORDER) Q13 */
+    int16_t lpc_n    /* (i) number of lsf sets to quantize */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/smooth.h b/modules/audio_coding/codecs/ilbc/smooth.h
index a8d1706..52e7ff9 100644
--- a/modules/audio_coding/codecs/ilbc/smooth.h
+++ b/modules/audio_coding/codecs/ilbc/smooth.h
@@ -25,12 +25,11 @@
  * find the smoothed output data
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_Smooth(
-    int16_t *odata,   /* (o) smoothed output */
-    int16_t *current,  /* (i) the un enhanced residual for
-                                this block */
-    int16_t *surround  /* (i) The approximation from the
-                                surrounding sequences */
+void WebRtcIlbcfix_Smooth(int16_t* odata,   /* (o) smoothed output */
+                          int16_t* current, /* (i) the un enhanced residual for
+                                                     this block */
+                          int16_t* surround /* (i) The approximation from the
+                                                     surrounding sequences */
                           );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/smooth_out_data.c b/modules/audio_coding/codecs/ilbc/smooth_out_data.c
index 1aa1e0a..72b3a47 100644
--- a/modules/audio_coding/codecs/ilbc/smooth_out_data.c
+++ b/modules/audio_coding/codecs/ilbc/smooth_out_data.c
@@ -18,6 +18,16 @@
 
 #include "modules/audio_coding/codecs/ilbc/defines.h"
 #include "modules/audio_coding/codecs/ilbc/constants.h"
+#include "rtc_base/sanitizer.h"
+
+// An s32 + s32 -> s32 addition that's allowed to overflow. (It's still
+// undefined behavior, so not a good idea; this just makes UBSan ignore the
+// violation, so that our old code can continue to do what it's always been
+// doing.)
+static inline int32_t RTC_NO_SANITIZE("signed-integer-overflow")
+    OverflowingAdd_S32_S32_To_S32(int32_t a, int32_t b) {
+  return a + b;
+}
 
 int32_t WebRtcIlbcfix_Smooth_odata(
     int16_t *odata,
@@ -37,7 +47,7 @@
   errs=0;
   for(i=0;i<80;i++) {
     err = (psseq[i] - odata[i]) >> 3;
-    errs += err * err;  /* errs in Q-6 */
+    errs = OverflowingAdd_S32_S32_To_S32(errs, err * err);  // errs in Q-6
   }
 
   return errs;
diff --git a/modules/audio_coding/codecs/ilbc/smooth_out_data.h b/modules/audio_coding/codecs/ilbc/smooth_out_data.h
index 6370d10..df946e3 100644
--- a/modules/audio_coding/codecs/ilbc/smooth_out_data.h
+++ b/modules/audio_coding/codecs/ilbc/smooth_out_data.h
@@ -25,11 +25,9 @@
  * help function to WebRtcIlbcfix_Smooth()
  *---------------------------------------------------------------*/
 
-int32_t WebRtcIlbcfix_Smooth_odata(
-    int16_t *odata,
-    int16_t *psseq,
-    int16_t *surround,
-    int16_t C);
-
+int32_t WebRtcIlbcfix_Smooth_odata(int16_t* odata,
+                                   int16_t* psseq,
+                                   int16_t* surround,
+                                   int16_t C);
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/sort_sq.h b/modules/audio_coding/codecs/ilbc/sort_sq.h
index f3c01ef..1fe7fbf 100644
--- a/modules/audio_coding/codecs/ilbc/sort_sq.h
+++ b/modules/audio_coding/codecs/ilbc/sort_sq.h
@@ -26,11 +26,11 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SortSq(
-    int16_t *xq,   /* (o) the quantized value */
-    int16_t *index,  /* (o) the quantization index */
-    int16_t x,   /* (i) the value to quantize */
-    const int16_t *cb, /* (i) the quantization codebook */
-    int16_t cb_size  /* (i) the size of the quantization codebook */
-                           );
+    int16_t* xq,       /* (o) the quantized value */
+    int16_t* index,    /* (o) the quantization index */
+    int16_t x,         /* (i) the value to quantize */
+    const int16_t* cb, /* (i) the quantization codebook */
+    int16_t cb_size    /* (i) the size of the quantization codebook */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/split_vq.h b/modules/audio_coding/codecs/ilbc/split_vq.h
index a758159..6bc2db6 100644
--- a/modules/audio_coding/codecs/ilbc/split_vq.h
+++ b/modules/audio_coding/codecs/ilbc/split_vq.h
@@ -26,13 +26,13 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SplitVq(
-    int16_t *qX,  /* (o) the quantized vector in Q13 */
-    int16_t *index, /* (o) a vector of indexes for all vector
+    int16_t* qX,    /* (o) the quantized vector in Q13 */
+    int16_t* index, /* (o) a vector of indexes for all vector
                                    codebooks in the split */
-    int16_t *X,  /* (i) the vector to quantize */
-    int16_t *CB,  /* (i) the quantizer codebook in Q13 */
-    int16_t *dim, /* (i) the dimension of X and qX */
-    int16_t *cbsize /* (i) the number of vectors in the codebook */
-                           );
+    int16_t* X,     /* (i) the vector to quantize */
+    int16_t* CB,    /* (i) the quantizer codebook in Q13 */
+    int16_t* dim,   /* (i) the dimension of X and qX */
+    int16_t* cbsize /* (i) the number of vectors in the codebook */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/state_construct.h b/modules/audio_coding/codecs/ilbc/state_construct.h
index 9339f65..0dadf48 100644
--- a/modules/audio_coding/codecs/ilbc/state_construct.h
+++ b/modules/audio_coding/codecs/ilbc/state_construct.h
@@ -26,10 +26,10 @@
 void WebRtcIlbcfix_StateConstruct(
     size_t idxForMax,   /* (i) 6-bit index for the quantization of
                                            max amplitude */
-    int16_t *idxVec,   /* (i) vector of quantization indexes */
-    int16_t *syntDenum,  /* (i) synthesis filter denumerator */
-    int16_t *Out_fix,  /* (o) the decoded state vector */
-    size_t len    /* (i) length of a state vector */
-                                  );
+    int16_t* idxVec,    /* (i) vector of quantization indexes */
+    int16_t* syntDenum, /* (i) synthesis filter denumerator */
+    int16_t* Out_fix,   /* (o) the decoded state vector */
+    size_t len          /* (i) length of a state vector */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/state_search.h b/modules/audio_coding/codecs/ilbc/state_search.h
index 976edca..1ad27ce 100644
--- a/modules/audio_coding/codecs/ilbc/state_search.h
+++ b/modules/audio_coding/codecs/ilbc/state_search.h
@@ -26,13 +26,13 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_StateSearch(
-    IlbcEncoder *iLBCenc_inst,
+    IlbcEncoder* iLBCenc_inst,
     /* (i) Encoder instance */
-    iLBC_bits *iLBC_encbits,/* (i/o) Encoded bits (output idxForMax
-                               and idxVec, input state_first) */
-    int16_t *residual,   /* (i) target residual vector */
-    int16_t *syntDenum,  /* (i) lpc synthesis filter */
-    int16_t *weightDenum  /* (i) weighting filter denuminator */
-                               );
+    iLBC_bits* iLBC_encbits, /* (i/o) Encoded bits (output idxForMax
+                                and idxVec, input state_first) */
+    int16_t* residual,       /* (i) target residual vector */
+    int16_t* syntDenum,      /* (i) lpc synthesis filter */
+    int16_t* weightDenum     /* (i) weighting filter denuminator */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/swap_bytes.h b/modules/audio_coding/codecs/ilbc/swap_bytes.h
index 63930d4..381b73a 100644
--- a/modules/audio_coding/codecs/ilbc/swap_bytes.h
+++ b/modules/audio_coding/codecs/ilbc/swap_bytes.h
@@ -26,9 +26,9 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_SwapBytes(
-    const uint16_t* input,   /* (i) the sequence to swap */
-    size_t wordLength,      /* (i) number or uint16_t to swap */
-    uint16_t* output         /* (o) the swapped sequence */
-                              );
+    const uint16_t* input, /* (i) the sequence to swap */
+    size_t wordLength,     /* (i) number or uint16_t to swap */
+    uint16_t* output       /* (o) the swapped sequence */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/unpack_bits.h b/modules/audio_coding/codecs/ilbc/unpack_bits.h
index b2e622f..4fd0a80 100644
--- a/modules/audio_coding/codecs/ilbc/unpack_bits.h
+++ b/modules/audio_coding/codecs/ilbc/unpack_bits.h
@@ -25,10 +25,13 @@
  *  unpacking of bits from bitstream, i.e., vector of bytes
  *---------------------------------------------------------------*/
 
-int16_t WebRtcIlbcfix_UnpackBits( /* (o) "Empty" frame indicator */
-    const uint16_t *bitstream,    /* (i) The packatized bitstream */
-    iLBC_bits *enc_bits,  /* (o) Paramerers from bitstream */
-    int16_t mode     /* (i) Codec mode (20 or 30) */
-                                        );
+int16_t
+WebRtcIlbcfix_UnpackBits(/* (o) "Empty" frame indicator */
+                         const uint16_t*
+                             bitstream, /* (i) The packatized bitstream */
+                         iLBC_bits*
+                             enc_bits, /* (o) Paramerers from bitstream */
+                         int16_t mode  /* (i) Codec mode (20 or 30) */
+                         );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/vq3.h b/modules/audio_coding/codecs/ilbc/vq3.h
index 6d3dc3a..ceaff8d 100644
--- a/modules/audio_coding/codecs/ilbc/vq3.h
+++ b/modules/audio_coding/codecs/ilbc/vq3.h
@@ -26,11 +26,11 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Vq3(
-    int16_t *Xq,  /* (o) the quantized vector (Q13) */
-    int16_t *index, /* (o) the quantization index */
-    int16_t *CB,  /* (i) the vector quantization codebook (Q13) */
-    int16_t *X,  /* (i) the vector to quantize (Q13) */
-    int16_t n_cb  /* (i) the number of vectors in the codebook */
-                       );
+    int16_t* Xq,    /* (o) the quantized vector (Q13) */
+    int16_t* index, /* (o) the quantization index */
+    int16_t* CB,    /* (i) the vector quantization codebook (Q13) */
+    int16_t* X,     /* (i) the vector to quantize (Q13) */
+    int16_t n_cb    /* (i) the number of vectors in the codebook */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/vq4.h b/modules/audio_coding/codecs/ilbc/vq4.h
index c7f5271..8dbedc9 100644
--- a/modules/audio_coding/codecs/ilbc/vq4.h
+++ b/modules/audio_coding/codecs/ilbc/vq4.h
@@ -26,11 +26,11 @@
  *---------------------------------------------------------------*/
 
 void WebRtcIlbcfix_Vq4(
-    int16_t *Xq,  /* (o) the quantized vector (Q13) */
-    int16_t *index, /* (o) the quantization index */
-    int16_t *CB,  /* (i) the vector quantization codebook (Q13) */
-    int16_t *X,  /* (i) the vector to quantize (Q13) */
-    int16_t n_cb  /* (i) the number of vectors in the codebook */
-                       );
+    int16_t* Xq,    /* (o) the quantized vector (Q13) */
+    int16_t* index, /* (o) the quantization index */
+    int16_t* CB,    /* (i) the vector quantization codebook (Q13) */
+    int16_t* X,     /* (i) the vector to quantize (Q13) */
+    int16_t n_cb    /* (i) the number of vectors in the codebook */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/window32_w32.h b/modules/audio_coding/codecs/ilbc/window32_w32.h
index c348d1d..0cef084 100644
--- a/modules/audio_coding/codecs/ilbc/window32_w32.h
+++ b/modules/audio_coding/codecs/ilbc/window32_w32.h
@@ -25,11 +25,10 @@
  *  window multiplication
  *---------------------------------------------------------------*/
 
-void WebRtcIlbcfix_Window32W32(
-    int32_t *z,    /* Output */
-    int32_t *x,    /* Input (same domain as Output)*/
-    const int32_t  *y,  /* Q31 Window */
-    size_t N     /* length to process */
+void WebRtcIlbcfix_Window32W32(int32_t* z, /* Output */
+                               int32_t* x, /* Input (same domain as Output)*/
+                               const int32_t* y, /* Q31 Window */
+                               size_t N          /* length to process */
                                );
 
 #endif
diff --git a/modules/audio_coding/codecs/ilbc/xcorr_coef.h b/modules/audio_coding/codecs/ilbc/xcorr_coef.h
index cd58b60..e6c3d3f 100644
--- a/modules/audio_coding/codecs/ilbc/xcorr_coef.h
+++ b/modules/audio_coding/codecs/ilbc/xcorr_coef.h
@@ -27,12 +27,12 @@
  *---------------------------------------------------------------*/
 
 size_t WebRtcIlbcfix_XcorrCoef(
-    int16_t *target,  /* (i) first array */
-    int16_t *regressor, /* (i) second array */
-    size_t subl,  /* (i) dimension arrays */
-    size_t searchLen, /* (i) the search lenght */
-    size_t offset,  /* (i) samples offset between arrays */
-    int16_t step   /* (i) +1 or -1 */
-                            );
+    int16_t* target,    /* (i) first array */
+    int16_t* regressor, /* (i) second array */
+    size_t subl,        /* (i) dimension arrays */
+    size_t searchLen,   /* (i) the search lenght */
+    size_t offset,      /* (i) samples offset between arrays */
+    int16_t step        /* (i) +1 or -1 */
+    );
 
 #endif
diff --git a/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h b/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
index eda1cfa..f840ffa 100644
--- a/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
+++ b/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
@@ -13,8 +13,8 @@
 
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio_codecs/audio_decoder.h"
-#include "api/optional.h"
 #include "modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/scoped_ref_ptr.h"
diff --git a/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
index 696b799..cbf15fc 100644
--- a/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
+++ b/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -90,9 +90,8 @@
 template <typename T>
 size_t AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
   const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
-  return static_cast<size_t>(
-      rtc::CheckedDivExact(samples_in_next_packet,
-                           rtc::CheckedDivExact(SampleRateHz(), 100)));
+  return static_cast<size_t>(rtc::CheckedDivExact(
+      samples_in_next_packet, rtc::CheckedDivExact(SampleRateHz(), 100)));
 }
 
 template <typename T>
@@ -123,8 +122,7 @@
   }
 
   size_t encoded_bytes = encoded->AppendData(
-      kSufficientEncodeBufferSizeBytes,
-      [&] (rtc::ArrayView<uint8_t> encoded) {
+      kSufficientEncodeBufferSizeBytes, [&](rtc::ArrayView<uint8_t> encoded) {
         int r = T::Encode(isac_state_, audio.data(), encoded.data());
 
         RTC_CHECK_GE(r, 0) << "Encode failed (error code "
diff --git a/modules/audio_coding/codecs/isac/fix/include/isacfix.h b/modules/audio_coding/codecs/isac/fix/include/isacfix.h
index ef194ca..626b3c7 100644
--- a/modules/audio_coding/codecs/isac/fix/include/isacfix.h
+++ b/modules/audio_coding/codecs/isac/fix/include/isacfix.h
@@ -16,622 +16,591 @@
 #include "modules/audio_coding/codecs/isac/bandwidth_info.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
-typedef struct {
-  void *dummy;
-} ISACFIX_MainStruct;
-
+typedef struct { void* dummy; } ISACFIX_MainStruct;
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
+/**************************************************************************
+ * WebRtcIsacfix_AssignSize(...)
+ *
+ *  Functions used when malloc is not allowed
+ *  Output the number of bytes needed to allocate for iSAC struct.
+ *
+ */
 
-  /**************************************************************************
-   * WebRtcIsacfix_AssignSize(...)
-   *
-   *  Functions used when malloc is not allowed
-   *  Output the number of bytes needed to allocate for iSAC struct.
-   *
-   */
+int16_t WebRtcIsacfix_AssignSize(int* sizeinbytes);
 
-  int16_t WebRtcIsacfix_AssignSize(int *sizeinbytes);
+/**************************************************************************
+ * WebRtcIsacfix_Assign(...)
+ *
+ * Functions used when malloc is not allowed, it
+ * places a struct at the given address.
+ *
+ * Input:
+ *      - *ISAC_main_inst   : a pointer to the coder instance.
+ *      - ISACFIX_inst_Addr : address of the memory where a space is
+ *                            for iSAC structure.
+ *
+ * Return value             : 0 - Ok
+ *                           -1 - Error
+ */
 
-  /**************************************************************************
-   * WebRtcIsacfix_Assign(...)
-   *
-   * Functions used when malloc is not allowed, it
-   * places a struct at the given address.
-   *
-   * Input:
-   *      - *ISAC_main_inst   : a pointer to the coder instance.
-   *      - ISACFIX_inst_Addr : address of the memory where a space is
-   *                            for iSAC structure.
-   *
-   * Return value             : 0 - Ok
-   *                           -1 - Error
-   */
+int16_t WebRtcIsacfix_Assign(ISACFIX_MainStruct** inst,
+                             void* ISACFIX_inst_Addr);
 
-  int16_t WebRtcIsacfix_Assign(ISACFIX_MainStruct **inst,
-                                     void *ISACFIX_inst_Addr);
+/****************************************************************************
+ * WebRtcIsacfix_Create(...)
+ *
+ * This function creates an ISAC instance, which will contain the state
+ * information for one coding/decoding channel.
+ *
+ * Input:
+ *      - *ISAC_main_inst   : a pointer to the coder instance.
+ *
+ * Return value             : 0 - Ok
+ *                           -1 - Error
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_Create(...)
-   *
-   * This function creates an ISAC instance, which will contain the state
-   * information for one coding/decoding channel.
-   *
-   * Input:
-   *      - *ISAC_main_inst   : a pointer to the coder instance.
-   *
-   * Return value             : 0 - Ok
-   *                           -1 - Error
-   */
+int16_t WebRtcIsacfix_Create(ISACFIX_MainStruct** ISAC_main_inst);
 
-  int16_t WebRtcIsacfix_Create(ISACFIX_MainStruct **ISAC_main_inst);
+/****************************************************************************
+ * WebRtcIsacfix_Free(...)
+ *
+ * This function frees the ISAC instance created at the beginning.
+ *
+ * Input:
+ *      - ISAC_main_inst    : a ISAC instance.
+ *
+ * Return value             :  0 - Ok
+ *                            -1 - Error
+ */
 
+int16_t WebRtcIsacfix_Free(ISACFIX_MainStruct* ISAC_main_inst);
 
-  /****************************************************************************
-   * WebRtcIsacfix_Free(...)
-   *
-   * This function frees the ISAC instance created at the beginning.
-   *
-   * Input:
-   *      - ISAC_main_inst    : a ISAC instance.
-   *
-   * Return value             :  0 - Ok
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIsacfix_EncoderInit(...)
+ *
+ * This function initializes an ISAC instance prior to the encoder calls.
+ *
+ * Input:
+ *     - ISAC_main_inst     : ISAC instance.
+ *     - CodingMode         : 0 - Bit rate and frame length are automatically
+ *                                adjusted to available bandwidth on
+ *                                transmission channel.
+ *                            1 - User sets a frame length and a target bit
+ *                                rate which is taken as the maximum short-term
+ *                                average bit rate.
+ *
+ * Return value             :  0 - Ok
+ *                            -1 - Error
+ */
 
-  int16_t WebRtcIsacfix_Free(ISACFIX_MainStruct *ISAC_main_inst);
+int16_t WebRtcIsacfix_EncoderInit(ISACFIX_MainStruct* ISAC_main_inst,
+                                  int16_t CodingMode);
 
+/****************************************************************************
+ * WebRtcIsacfix_Encode(...)
+ *
+ * This function encodes 10ms frame(s) and inserts it into a package.
+ * Input speech length has to be 160 samples (10ms). The encoder buffers those
+ * 10ms frames until it reaches the chosen Framesize (480 or 960 samples
+ * corresponding to 30 or 60 ms frames), and then proceeds to the encoding.
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - speechIn          : input speech vector.
+ *
+ * Output:
+ *      - encoded           : the encoded data vector
+ *
+ * Return value             : >0 - Length (in bytes) of coded data
+ *                             0 - The buffer didn't reach the chosen framesize
+ *                                 so it keeps buffering speech samples.
+ *                            -1 - Error
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_EncoderInit(...)
-   *
-   * This function initializes an ISAC instance prior to the encoder calls.
-   *
-   * Input:
-   *     - ISAC_main_inst     : ISAC instance.
-   *     - CodingMode         : 0 - Bit rate and frame length are automatically
-   *                                adjusted to available bandwidth on
-   *                                transmission channel.
-   *                            1 - User sets a frame length and a target bit
-   *                                rate which is taken as the maximum short-term
-   *                                average bit rate.
-   *
-   * Return value             :  0 - Ok
-   *                            -1 - Error
-   */
+int WebRtcIsacfix_Encode(ISACFIX_MainStruct* ISAC_main_inst,
+                         const int16_t* speechIn,
+                         uint8_t* encoded);
 
-  int16_t WebRtcIsacfix_EncoderInit(ISACFIX_MainStruct *ISAC_main_inst,
-                                    int16_t  CodingMode);
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_Encode(...)
-   *
-   * This function encodes 10ms frame(s) and inserts it into a package.
-   * Input speech length has to be 160 samples (10ms). The encoder buffers those
-   * 10ms frames until it reaches the chosen Framesize (480 or 960 samples
-   * corresponding to 30 or 60 ms frames), and then proceeds to the encoding.
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - speechIn          : input speech vector.
-   *
-   * Output:
-   *      - encoded           : the encoded data vector
-   *
-   * Return value             : >0 - Length (in bytes) of coded data
-   *                             0 - The buffer didn't reach the chosen framesize
-   *                                 so it keeps buffering speech samples.
-   *                            -1 - Error
-   */
-
-  int WebRtcIsacfix_Encode(ISACFIX_MainStruct *ISAC_main_inst,
-                           const int16_t *speechIn,
-                           uint8_t* encoded);
-
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_EncodeNb(...)
-   *
-   * This function encodes 10ms narrow band (8 kHz sampling) frame(s) and inserts
-   * it into a package. Input speech length has to be 80 samples (10ms). The encoder
-   * interpolates into wide-band (16 kHz sampling) buffers those
-   * 10ms frames until it reaches the chosen Framesize (480 or 960 wide-band samples
-   * corresponding to 30 or 60 ms frames), and then proceeds to the encoding.
-   *
-   * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - speechIn          : input speech vector.
-   *
-   * Output:
-   *      - encoded           : the encoded data vector
-   *
-   * Return value             : >0 - Length (in bytes) of coded data
-   *                             0 - The buffer didn't reach the chosen framesize
-   *                                 so it keeps buffering speech samples.
-   *                            -1 - Error
-   */
-
+/****************************************************************************
+ * WebRtcIsacfix_EncodeNb(...)
+ *
+ * This function encodes 10ms narrow band (8 kHz sampling) frame(s) and inserts
+ * it into a package. Input speech length has to be 80 samples (10ms). The
+ * encoder interpolates into wide-band (16 kHz sampling) buffers those 10ms
+ * frames until it reaches the chosen Framesize (480 or 960 wide-band samples
+ * corresponding to 30 or 60 ms frames), and then proceeds to the encoding.
+ *
+ * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - speechIn          : input speech vector.
+ *
+ * Output:
+ *      - encoded           : the encoded data vector
+ *
+ * Return value             : >0 - Length (in bytes) of coded data
+ *                             0 - The buffer didn't reach the chosen framesize
+ *                                 so it keeps buffering speech samples.
+ *                            -1 - Error
+ */
 
 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
-  int16_t WebRtcIsacfix_EncodeNb(ISACFIX_MainStruct *ISAC_main_inst,
-                                 const int16_t *speechIn,
-                                 int16_t *encoded);
-#endif //  WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
+int16_t WebRtcIsacfix_EncodeNb(ISACFIX_MainStruct* ISAC_main_inst,
+                               const int16_t* speechIn,
+                               int16_t* encoded);
+#endif  //  WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
 
+/****************************************************************************
+ * WebRtcIsacfix_DecoderInit(...)
+ *
+ * This function initializes an ISAC instance prior to the decoder calls.
+ *
+ * Input:
+ *  - ISAC_main_inst : ISAC instance.
+ */
 
+void WebRtcIsacfix_DecoderInit(ISACFIX_MainStruct* ISAC_main_inst);
 
-  /****************************************************************************
-   * WebRtcIsacfix_DecoderInit(...)
-   *
-   * This function initializes an ISAC instance prior to the decoder calls.
-   *
-   * Input:
-   *  - ISAC_main_inst : ISAC instance.
-   */
+/****************************************************************************
+ * WebRtcIsacfix_UpdateBwEstimate1(...)
+ *
+ * This function updates the estimate of the bandwidth.
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - encoded           : encoded ISAC frame(s).
+ *      - packet_size       : size of the packet in bytes.
+ *      - rtp_seq_number    : the RTP number of the packet.
+ *      - arr_ts            : the arrival time of the packet (from NetEq)
+ *                            in samples.
+ *
+ * Return value             : 0 - Ok
+ *                           -1 - Error
+ */
 
-  void WebRtcIsacfix_DecoderInit(ISACFIX_MainStruct* ISAC_main_inst);
+int16_t WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_MainStruct* ISAC_main_inst,
+                                        const uint8_t* encoded,
+                                        size_t packet_size,
+                                        uint16_t rtp_seq_number,
+                                        uint32_t arr_ts);
 
-  /****************************************************************************
-   * WebRtcIsacfix_UpdateBwEstimate1(...)
-   *
-   * This function updates the estimate of the bandwidth.
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - encoded           : encoded ISAC frame(s).
-   *      - packet_size       : size of the packet in bytes.
-   *      - rtp_seq_number    : the RTP number of the packet.
-   *      - arr_ts            : the arrival time of the packet (from NetEq)
-   *                            in samples.
-   *
-   * Return value             : 0 - Ok
-   *                           -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIsacfix_UpdateBwEstimate(...)
+ *
+ * This function updates the estimate of the bandwidth.
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - encoded           : encoded ISAC frame(s).
+ *      - packet_size       : size of the packet in bytes.
+ *      - rtp_seq_number    : the RTP number of the packet.
+ *      - send_ts           : the send time of the packet from RTP header,
+ *                            in samples.
+ *      - arr_ts            : the arrival time of the packet (from NetEq)
+ *                            in samples.
+ *
+ * Return value             :  0 - Ok
+ *                            -1 - Error
+ */
 
-  int16_t WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_MainStruct *ISAC_main_inst,
-                                          const uint8_t* encoded,
-                                          size_t packet_size,
-                                          uint16_t rtp_seq_number,
-                                          uint32_t arr_ts);
+int16_t WebRtcIsacfix_UpdateBwEstimate(ISACFIX_MainStruct* ISAC_main_inst,
+                                       const uint8_t* encoded,
+                                       size_t packet_size,
+                                       uint16_t rtp_seq_number,
+                                       uint32_t send_ts,
+                                       uint32_t arr_ts);
 
-  /****************************************************************************
-   * WebRtcIsacfix_UpdateBwEstimate(...)
-   *
-   * This function updates the estimate of the bandwidth.
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - encoded           : encoded ISAC frame(s).
-   *      - packet_size       : size of the packet in bytes.
-   *      - rtp_seq_number    : the RTP number of the packet.
-   *      - send_ts           : the send time of the packet from RTP header,
-   *                            in samples.
-   *      - arr_ts            : the arrival time of the packet (from NetEq)
-   *                            in samples.
-   *
-   * Return value             :  0 - Ok
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIsacfix_Decode(...)
+ *
+ * This function decodes an ISAC frame. Output speech length
+ * will be a multiple of 480 samples: 480 or 960 samples,
+ * depending on the framesize (30 or 60 ms).
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - encoded           : encoded ISAC frame(s)
+ *      - len               : bytes in encoded vector
+ *
+ * Output:
+ *      - decoded           : The decoded vector
+ *
+ * Return value             : >0 - number of samples in decoded vector
+ *                            -1 - Error
+ */
 
-  int16_t WebRtcIsacfix_UpdateBwEstimate(ISACFIX_MainStruct *ISAC_main_inst,
-                                         const uint8_t* encoded,
-                                         size_t packet_size,
-                                         uint16_t rtp_seq_number,
-                                         uint32_t send_ts,
-                                         uint32_t arr_ts);
+int WebRtcIsacfix_Decode(ISACFIX_MainStruct* ISAC_main_inst,
+                         const uint8_t* encoded,
+                         size_t len,
+                         int16_t* decoded,
+                         int16_t* speechType);
 
-  /****************************************************************************
-   * WebRtcIsacfix_Decode(...)
-   *
-   * This function decodes an ISAC frame. Output speech length
-   * will be a multiple of 480 samples: 480 or 960 samples,
-   * depending on the framesize (30 or 60 ms).
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - encoded           : encoded ISAC frame(s)
-   *      - len               : bytes in encoded vector
-   *
-   * Output:
-   *      - decoded           : The decoded vector
-   *
-   * Return value             : >0 - number of samples in decoded vector
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIsacfix_DecodeNb(...)
+ *
+ * This function decodes a ISAC frame in narrow-band (8 kHz sampling).
+ * Output speech length will be a multiple of 240 samples: 240 or 480 samples,
+ * depending on the framesize (30 or 60 ms).
+ *
+ * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - encoded           : encoded ISAC frame(s)
+ *      - len               : bytes in encoded vector
+ *
+ * Output:
+ *      - decoded           : The decoded vector
+ *
+ * Return value             : >0 - number of samples in decoded vector
+ *                            -1 - Error
+ */
 
-  int WebRtcIsacfix_Decode(ISACFIX_MainStruct *ISAC_main_inst,
-                           const uint8_t* encoded,
+#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
+int WebRtcIsacfix_DecodeNb(ISACFIX_MainStruct* ISAC_main_inst,
+                           const uint16_t* encoded,
                            size_t len,
-                           int16_t *decoded,
-                           int16_t *speechType);
+                           int16_t* decoded,
+                           int16_t* speechType);
+#endif  //  WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
 
-
-  /****************************************************************************
-   * WebRtcIsacfix_DecodeNb(...)
-   *
-   * This function decodes a ISAC frame in narrow-band (8 kHz sampling).
-   * Output speech length will be a multiple of 240 samples: 240 or 480 samples,
-   * depending on the framesize (30 or 60 ms).
-   *
-   * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - encoded           : encoded ISAC frame(s)
-   *      - len               : bytes in encoded vector
-   *
-   * Output:
-   *      - decoded           : The decoded vector
-   *
-   * Return value             : >0 - number of samples in decoded vector
-   *                            -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIsacfix_DecodePlcNb(...)
+ *
+ * This function conducts PLC for ISAC frame(s) in narrow-band (8kHz sampling).
+ * Output speech length  will be "240*noOfLostFrames" samples
+ * that equevalent of "30*noOfLostFrames" millisecond.
+ *
+ * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - noOfLostFrames    : Number of PLC frames (240 sample=30ms) to produce
+ *                            NOTE! Maximum number is 2 (480 samples = 60ms)
+ *
+ * Output:
+ *      - decoded           : The decoded vector
+ *
+ * Return value             : Number of samples in decoded PLC vector
+ */
 
 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
-  int WebRtcIsacfix_DecodeNb(ISACFIX_MainStruct *ISAC_main_inst,
-                             const uint16_t *encoded,
-                             size_t len,
-                             int16_t *decoded,
-                             int16_t *speechType);
-#endif //  WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
+size_t WebRtcIsacfix_DecodePlcNb(ISACFIX_MainStruct* ISAC_main_inst,
+                                 int16_t* decoded,
+                                 size_t noOfLostFrames);
+#endif  // WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
 
+/****************************************************************************
+ * WebRtcIsacfix_DecodePlc(...)
+ *
+ * This function conducts PLC for ISAC frame(s) in wide-band (16kHz sampling).
+ * Output speech length  will be "480*noOfLostFrames" samples
+ * that is equevalent of "30*noOfLostFrames" millisecond.
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - noOfLostFrames    : Number of PLC frames (480sample = 30ms)
+ *                            to produce
+ *                            NOTE! Maximum number is 2 (960 samples = 60ms)
+ *
+ * Output:
+ *      - decoded           : The decoded vector
+ *
+ * Return value             : Number of samples in decoded PLC vector
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_DecodePlcNb(...)
-   *
-   * This function conducts PLC for ISAC frame(s) in narrow-band (8kHz sampling).
-   * Output speech length  will be "240*noOfLostFrames" samples
-   * that equevalent of "30*noOfLostFrames" millisecond.
-   *
-   * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - noOfLostFrames    : Number of PLC frames (240 sample=30ms) to produce
-   *                            NOTE! Maximum number is 2 (480 samples = 60ms)
-   *
-   * Output:
-   *      - decoded           : The decoded vector
-   *
-   * Return value             : Number of samples in decoded PLC vector
-   */
+size_t WebRtcIsacfix_DecodePlc(ISACFIX_MainStruct* ISAC_main_inst,
+                               int16_t* decoded,
+                               size_t noOfLostFrames);
 
-#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
-  size_t WebRtcIsacfix_DecodePlcNb(ISACFIX_MainStruct *ISAC_main_inst,
-                                   int16_t *decoded,
-                                   size_t noOfLostFrames);
-#endif // WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
+/****************************************************************************
+ * WebRtcIsacfix_ReadFrameLen(...)
+ *
+ * This function returns the length of the frame represented in the packet.
+ *
+ * Input:
+ *      - encoded           : Encoded bitstream
+ *      - encoded_len_bytes : Length of the bitstream in bytes.
+ *
+ * Output:
+ *      - frameLength       : Length of frame in packet (in samples)
+ *
+ */
 
+int16_t WebRtcIsacfix_ReadFrameLen(const uint8_t* encoded,
+                                   size_t encoded_len_bytes,
+                                   size_t* frameLength);
 
+/****************************************************************************
+ * WebRtcIsacfix_Control(...)
+ *
+ * This function sets the limit on the short-term average bit rate and the
+ * frame length. Should be used only in Instantaneous mode.
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - rate              : limit on the short-term average bit rate,
+ *                            in bits/second (between 10000 and 32000)
+ *      - framesize         : number of milliseconds per frame (30 or 60)
+ *
+ * Return value             : 0  - ok
+ *                           -1 - Error
+ */
 
+int16_t WebRtcIsacfix_Control(ISACFIX_MainStruct* ISAC_main_inst,
+                              int16_t rate,
+                              int framesize);
 
-  /****************************************************************************
-   * WebRtcIsacfix_DecodePlc(...)
-   *
-   * This function conducts PLC for ISAC frame(s) in wide-band (16kHz sampling).
-   * Output speech length  will be "480*noOfLostFrames" samples
-   * that is equevalent of "30*noOfLostFrames" millisecond.
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - noOfLostFrames    : Number of PLC frames (480sample = 30ms)
-   *                            to produce
-   *                            NOTE! Maximum number is 2 (960 samples = 60ms)
-   *
-   * Output:
-   *      - decoded           : The decoded vector
-   *
-   * Return value             : Number of samples in decoded PLC vector
-   */
+void WebRtcIsacfix_SetInitialBweBottleneck(ISACFIX_MainStruct* ISAC_main_inst,
+                                           int bottleneck_bits_per_second);
 
-  size_t WebRtcIsacfix_DecodePlc(ISACFIX_MainStruct *ISAC_main_inst,
-                                 int16_t *decoded,
-                                 size_t noOfLostFrames );
+/****************************************************************************
+ * WebRtcIsacfix_ControlBwe(...)
+ *
+ * This function sets the initial values of bottleneck and frame-size if
+ * iSAC is used in channel-adaptive mode. Through this API, users can
+ * enforce a frame-size for all values of bottleneck. Then iSAC will not
+ * automatically change the frame-size.
+ *
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - rateBPS           : initial value of bottleneck in bits/second
+ *                            10000 <= rateBPS <= 32000 is accepted
+ *      - frameSizeMs       : number of milliseconds per frame (30 or 60)
+ *      - enforceFrameSize  : 1 to enforce the given frame-size through out
+ *                            the adaptation process, 0 to let iSAC change
+ *                            the frame-size if required.
+ *
+ * Return value             : 0  - ok
+ *                           -1 - Error
+ */
 
+int16_t WebRtcIsacfix_ControlBwe(ISACFIX_MainStruct* ISAC_main_inst,
+                                 int16_t rateBPS,
+                                 int frameSizeMs,
+                                 int16_t enforceFrameSize);
 
-  /****************************************************************************
-   * WebRtcIsacfix_ReadFrameLen(...)
-   *
-   * This function returns the length of the frame represented in the packet.
-   *
-   * Input:
-   *      - encoded           : Encoded bitstream
-   *      - encoded_len_bytes : Length of the bitstream in bytes.
-   *
-   * Output:
-   *      - frameLength       : Length of frame in packet (in samples)
-   *
-   */
+/****************************************************************************
+ * WebRtcIsacfix_version(...)
+ *
+ * This function returns the version number.
+ *
+ * Output:
+ *      - version      : Pointer to character string
+ *
+ */
 
-  int16_t WebRtcIsacfix_ReadFrameLen(const uint8_t* encoded,
-                                     size_t encoded_len_bytes,
-                                     size_t* frameLength);
+void WebRtcIsacfix_version(char* version);
 
-  /****************************************************************************
-   * WebRtcIsacfix_Control(...)
-   *
-   * This function sets the limit on the short-term average bit rate and the
-   * frame length. Should be used only in Instantaneous mode.
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - rate              : limit on the short-term average bit rate,
-   *                            in bits/second (between 10000 and 32000)
-   *      - framesize         : number of milliseconds per frame (30 or 60)
-   *
-   * Return value             : 0  - ok
-   *                           -1 - Error
-   */
+/****************************************************************************
+ * WebRtcIsacfix_GetErrorCode(...)
+ *
+ * This function can be used to check the error code of an iSAC instance. When
+ * a function returns -1 a error code will be set for that instance. The
+ * function below extract the code of the last error that occured in the
+ * specified instance.
+ *
+ * Input:
+ *  - ISAC_main_inst        : ISAC instance
+ *
+ * Return value             : Error code
+ */
 
-  int16_t WebRtcIsacfix_Control(ISACFIX_MainStruct *ISAC_main_inst,
-                                int16_t rate,
-                                int framesize);
+int16_t WebRtcIsacfix_GetErrorCode(ISACFIX_MainStruct* ISAC_main_inst);
 
-  void WebRtcIsacfix_SetInitialBweBottleneck(ISACFIX_MainStruct* ISAC_main_inst,
-                                             int bottleneck_bits_per_second);
+/****************************************************************************
+ * WebRtcIsacfix_GetUplinkBw(...)
+ *
+ * This function return iSAC send bitrate
+ *
+ * Input:
+ *      - ISAC_main_inst    : iSAC instance
+ *
+ * Return value             : <0 Error code
+ *                            else bitrate
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_ControlBwe(...)
-   *
-   * This function sets the initial values of bottleneck and frame-size if
-   * iSAC is used in channel-adaptive mode. Through this API, users can
-   * enforce a frame-size for all values of bottleneck. Then iSAC will not
-   * automatically change the frame-size.
-   *
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - rateBPS           : initial value of bottleneck in bits/second
-   *                            10000 <= rateBPS <= 32000 is accepted
-   *      - frameSizeMs       : number of milliseconds per frame (30 or 60)
-   *      - enforceFrameSize  : 1 to enforce the given frame-size through out
-   *                            the adaptation process, 0 to let iSAC change
-   *                            the frame-size if required.
-   *
-   * Return value             : 0  - ok
-   *                           -1 - Error
-   */
+int32_t WebRtcIsacfix_GetUplinkBw(ISACFIX_MainStruct* ISAC_main_inst);
 
-  int16_t WebRtcIsacfix_ControlBwe(ISACFIX_MainStruct *ISAC_main_inst,
-                                   int16_t rateBPS,
-                                   int frameSizeMs,
-                                   int16_t enforceFrameSize);
+/****************************************************************************
+ * WebRtcIsacfix_SetMaxPayloadSize(...)
+ *
+ * This function sets a limit for the maximum payload size of iSAC. The same
+ * value is used both for 30 and 60 msec packets.
+ * The absolute max will be valid until next time the function is called.
+ * NOTE! This function may override the function WebRtcIsacfix_SetMaxRate()
+ *
+ * Input:
+ *      - ISAC_main_inst    : iSAC instance
+ *      - maxPayloadBytes   : maximum size of the payload in bytes
+ *                            valid values are between 100 and 400 bytes
+ *
+ *
+ * Return value             : 0 if sucessful
+ *                           -1 if error happens
+ */
 
+int16_t WebRtcIsacfix_SetMaxPayloadSize(ISACFIX_MainStruct* ISAC_main_inst,
+                                        int16_t maxPayloadBytes);
 
+/****************************************************************************
+ * WebRtcIsacfix_SetMaxRate(...)
+ *
+ * This function sets the maximum rate which the codec may not exceed for a
+ * singel packet. The maximum rate is set in bits per second.
+ * The codec has an absolute maximum rate of 53400 bits per second (200 bytes
+ * per 30 msec).
+ * It is possible to set a maximum rate between 32000 and 53400 bits per second.
+ *
+ * The rate limit is valid until next time the function is called.
+ *
+ * NOTE! Packet size will never go above the value set if calling
+ * WebRtcIsacfix_SetMaxPayloadSize() (default max packet size is 400 bytes).
+ *
+ * Input:
+ *      - ISAC_main_inst    : iSAC instance
+ *      - maxRateInBytes    : maximum rate in bits per second,
+ *                            valid values are 32000 to 53400 bits
+ *
+ * Return value             : 0 if sucessful
+ *                           -1 if error happens
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_version(...)
-   *
-   * This function returns the version number.
-   *
-   * Output:
-   *      - version      : Pointer to character string
-   *
-   */
+int16_t WebRtcIsacfix_SetMaxRate(ISACFIX_MainStruct* ISAC_main_inst,
+                                 int32_t maxRate);
 
-  void WebRtcIsacfix_version(char *version);
+/****************************************************************************
+ * WebRtcIsacfix_CreateInternal(...)
+ *
+ * This function creates the memory that is used to store data in the encoder
+ *
+ * Input:
+ *      - *ISAC_main_inst   : a pointer to the coder instance.
+ *
+ * Return value             : 0 - Ok
+ *                           -1 - Error
+ */
 
+int16_t WebRtcIsacfix_CreateInternal(ISACFIX_MainStruct* ISAC_main_inst);
 
-  /****************************************************************************
-   * WebRtcIsacfix_GetErrorCode(...)
-   *
-   * This function can be used to check the error code of an iSAC instance. When
-   * a function returns -1 a error code will be set for that instance. The
-   * function below extract the code of the last error that occured in the
-   * specified instance.
-   *
-   * Input:
-   *  - ISAC_main_inst        : ISAC instance
-   *
-   * Return value             : Error code
-   */
+/****************************************************************************
+ * WebRtcIsacfix_FreeInternal(...)
+ *
+ * This function frees the internal memory for storing encoder data.
+ *
+ * Input:
+ *      - ISAC_main_inst        : an ISAC instance.
+ *
+ * Return value                 :  0 - Ok
+ *                                -1 - Error
+ */
 
-  int16_t WebRtcIsacfix_GetErrorCode(ISACFIX_MainStruct *ISAC_main_inst);
+int16_t WebRtcIsacfix_FreeInternal(ISACFIX_MainStruct* ISAC_main_inst);
 
+/****************************************************************************
+ * WebRtcIsacfix_GetNewBitStream(...)
+ *
+ * This function returns encoded data, with the recieved bwe-index in the
+ * stream. It should always return a complete packet, i.e. only called once
+ * even for 60 msec frames
+ *
+ * Input:
+ *      - ISAC_main_inst    : ISAC instance.
+ *      - bweIndex          : index of bandwidth estimate to put in new
+ * bitstream - scale             : factor for rate change (0.4 ~=> half the
+ * rate, 1 no change).
+ *
+ * Output:
+ *      - encoded           : the encoded data vector
+ *
+ * Return value             : >0 - Length (in bytes) of coded data
+ *                            -1 - Error
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_GetUplinkBw(...)
-   *
-   * This function return iSAC send bitrate
-   *
-   * Input:
-   *      - ISAC_main_inst    : iSAC instance
-   *
-   * Return value             : <0 Error code
-   *                            else bitrate
-   */
+int16_t WebRtcIsacfix_GetNewBitStream(ISACFIX_MainStruct* ISAC_main_inst,
+                                      int16_t bweIndex,
+                                      float scale,
+                                      uint8_t* encoded);
 
-  int32_t WebRtcIsacfix_GetUplinkBw(ISACFIX_MainStruct *ISAC_main_inst);
+/****************************************************************************
+ * WebRtcIsacfix_GetDownLinkBwIndex(...)
+ *
+ * This function returns index representing the Bandwidth estimate from
+ * other side to this side.
+ *
+ * Input:
+ *      - ISAC_main_inst    : iSAC struct
+ *
+ * Output:
+ *      - rateIndex         : Bandwidth estimate to transmit to other side.
+ *
+ */
 
+int16_t WebRtcIsacfix_GetDownLinkBwIndex(ISACFIX_MainStruct* ISAC_main_inst,
+                                         int16_t* rateIndex);
 
-  /****************************************************************************
-   * WebRtcIsacfix_SetMaxPayloadSize(...)
-   *
-   * This function sets a limit for the maximum payload size of iSAC. The same
-   * value is used both for 30 and 60 msec packets.
-   * The absolute max will be valid until next time the function is called.
-   * NOTE! This function may override the function WebRtcIsacfix_SetMaxRate()
-   *
-   * Input:
-   *      - ISAC_main_inst    : iSAC instance
-   *      - maxPayloadBytes   : maximum size of the payload in bytes
-   *                            valid values are between 100 and 400 bytes
-   *
-   *
-   * Return value             : 0 if sucessful
-   *                           -1 if error happens
-   */
+/****************************************************************************
+ * WebRtcIsacfix_UpdateUplinkBw(...)
+ *
+ * This function takes an index representing the Bandwidth estimate from
+ * this side to other side and updates BWE.
+ *
+ * Input:
+ *      - ISAC_main_inst    : iSAC struct
+ *      - rateIndex         : Bandwidth estimate from other side.
+ *
+ */
 
-  int16_t WebRtcIsacfix_SetMaxPayloadSize(ISACFIX_MainStruct *ISAC_main_inst,
-                                          int16_t maxPayloadBytes);
+int16_t WebRtcIsacfix_UpdateUplinkBw(ISACFIX_MainStruct* ISAC_main_inst,
+                                     int16_t rateIndex);
 
+/****************************************************************************
+ * WebRtcIsacfix_ReadBwIndex(...)
+ *
+ * This function returns the index of the Bandwidth estimate from the bitstream.
+ *
+ * Input:
+ *      - encoded           : Encoded bitstream
+ *      - encoded_len_bytes : Length of the bitstream in bytes.
+ *
+ * Output:
+ *      - rateIndex         : Bandwidth estimate in bitstream
+ *
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_SetMaxRate(...)
-   *
-   * This function sets the maximum rate which the codec may not exceed for a
-   * singel packet. The maximum rate is set in bits per second.
-   * The codec has an absolute maximum rate of 53400 bits per second (200 bytes
-   * per 30 msec).
-   * It is possible to set a maximum rate between 32000 and 53400 bits per second.
-   *
-   * The rate limit is valid until next time the function is called.
-   *
-   * NOTE! Packet size will never go above the value set if calling
-   * WebRtcIsacfix_SetMaxPayloadSize() (default max packet size is 400 bytes).
-   *
-   * Input:
-   *      - ISAC_main_inst    : iSAC instance
-   *      - maxRateInBytes    : maximum rate in bits per second,
-   *                            valid values are 32000 to 53400 bits
-   *
-   * Return value             : 0 if sucessful
-   *                           -1 if error happens
-   */
+int16_t WebRtcIsacfix_ReadBwIndex(const uint8_t* encoded,
+                                  size_t encoded_len_bytes,
+                                  int16_t* rateIndex);
 
-  int16_t WebRtcIsacfix_SetMaxRate(ISACFIX_MainStruct *ISAC_main_inst,
-                                   int32_t maxRate);
+/****************************************************************************
+ * WebRtcIsacfix_GetNewFrameLen(...)
+ *
+ * This function return the next frame length (in samples) of iSAC.
+ *
+ * Input:
+ *      -ISAC_main_inst     : iSAC instance
+ *
+ * Return value             : frame lenght in samples
+ */
 
-  /****************************************************************************
-   * WebRtcIsacfix_CreateInternal(...)
-   *
-   * This function creates the memory that is used to store data in the encoder
-   *
-   * Input:
-   *      - *ISAC_main_inst   : a pointer to the coder instance.
-   *
-   * Return value             : 0 - Ok
-   *                           -1 - Error
-   */
+int16_t WebRtcIsacfix_GetNewFrameLen(ISACFIX_MainStruct* ISAC_main_inst);
 
-  int16_t WebRtcIsacfix_CreateInternal(ISACFIX_MainStruct *ISAC_main_inst);
+/* Fills in an IsacBandwidthInfo struct. */
+void WebRtcIsacfix_GetBandwidthInfo(ISACFIX_MainStruct* ISAC_main_inst,
+                                    IsacBandwidthInfo* bwinfo);
 
-
-  /****************************************************************************
-   * WebRtcIsacfix_FreeInternal(...)
-   *
-   * This function frees the internal memory for storing encoder data.
-   *
-   * Input:
-   *      - ISAC_main_inst        : an ISAC instance.
-   *
-   * Return value                 :  0 - Ok
-   *                                -1 - Error
-   */
-
-  int16_t WebRtcIsacfix_FreeInternal(ISACFIX_MainStruct *ISAC_main_inst);
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_GetNewBitStream(...)
-   *
-   * This function returns encoded data, with the recieved bwe-index in the
-   * stream. It should always return a complete packet, i.e. only called once
-   * even for 60 msec frames
-   *
-   * Input:
-   *      - ISAC_main_inst    : ISAC instance.
-   *      - bweIndex          : index of bandwidth estimate to put in new bitstream
-   *      - scale             : factor for rate change (0.4 ~=> half the rate, 1 no change).
-   *
-   * Output:
-   *      - encoded           : the encoded data vector
-   *
-   * Return value             : >0 - Length (in bytes) of coded data
-   *                            -1 - Error
-   */
-
-  int16_t WebRtcIsacfix_GetNewBitStream(ISACFIX_MainStruct *ISAC_main_inst,
-                                        int16_t          bweIndex,
-                                        float              scale,
-                                        uint8_t* encoded);
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_GetDownLinkBwIndex(...)
-   *
-   * This function returns index representing the Bandwidth estimate from
-   * other side to this side.
-   *
-   * Input:
-   *      - ISAC_main_inst    : iSAC struct
-   *
-   * Output:
-   *      - rateIndex         : Bandwidth estimate to transmit to other side.
-   *
-   */
-
-  int16_t WebRtcIsacfix_GetDownLinkBwIndex(ISACFIX_MainStruct* ISAC_main_inst,
-                                           int16_t*     rateIndex);
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_UpdateUplinkBw(...)
-   *
-   * This function takes an index representing the Bandwidth estimate from
-   * this side to other side and updates BWE.
-   *
-   * Input:
-   *      - ISAC_main_inst    : iSAC struct
-   *      - rateIndex         : Bandwidth estimate from other side.
-   *
-   */
-
-  int16_t WebRtcIsacfix_UpdateUplinkBw(ISACFIX_MainStruct* ISAC_main_inst,
-                                       int16_t     rateIndex);
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_ReadBwIndex(...)
-   *
-   * This function returns the index of the Bandwidth estimate from the bitstream.
-   *
-   * Input:
-   *      - encoded           : Encoded bitstream
-   *      - encoded_len_bytes : Length of the bitstream in bytes.
-   *
-   * Output:
-   *      - rateIndex         : Bandwidth estimate in bitstream
-   *
-   */
-
-  int16_t WebRtcIsacfix_ReadBwIndex(const uint8_t* encoded,
-                                    size_t encoded_len_bytes,
-                                    int16_t* rateIndex);
-
-
-  /****************************************************************************
-   * WebRtcIsacfix_GetNewFrameLen(...)
-   *
-   * This function return the next frame length (in samples) of iSAC.
-   *
-   * Input:
-   *      -ISAC_main_inst     : iSAC instance
-   *
-   * Return value             : frame lenght in samples
-   */
-
-  int16_t WebRtcIsacfix_GetNewFrameLen(ISACFIX_MainStruct *ISAC_main_inst);
-
-  /* Fills in an IsacBandwidthInfo struct. */
-  void WebRtcIsacfix_GetBandwidthInfo(ISACFIX_MainStruct* ISAC_main_inst,
-                                      IsacBandwidthInfo* bwinfo);
-
-  /* Uses the values from an IsacBandwidthInfo struct. */
-  void WebRtcIsacfix_SetBandwidthInfo(ISACFIX_MainStruct* ISAC_main_inst,
-                                      const IsacBandwidthInfo* bwinfo);
+/* Uses the values from an IsacBandwidthInfo struct. */
+void WebRtcIsacfix_SetBandwidthInfo(ISACFIX_MainStruct* ISAC_main_inst,
+                                    const IsacBandwidthInfo* bwinfo);
 
 #if defined(__cplusplus)
 }
 #endif
 
-
-
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INCLUDE_ISACFIX_H_ */
diff --git a/modules/audio_coding/codecs/isac/fix/source/arith_routins.h b/modules/audio_coding/codecs/isac/fix/source/arith_routins.h
index 25eeecf..cc4ed55 100644
--- a/modules/audio_coding/codecs/isac/fix/source/arith_routins.h
+++ b/modules/audio_coding/codecs/isac/fix/source/arith_routins.h
@@ -35,12 +35,10 @@
  * Return value             :  0 if ok,
  *                             <0 otherwise.
  */
-int WebRtcIsacfix_EncLogisticMulti2(
-    Bitstr_enc *streamData,
-    int16_t *dataQ7,
-    const uint16_t *env,
-    const int16_t lenData);
-
+int WebRtcIsacfix_EncLogisticMulti2(Bitstr_enc* streamData,
+                                    int16_t* dataQ7,
+                                    const uint16_t* env,
+                                    const int16_t lenData);
 
 /****************************************************************************
  * WebRtcIsacfix_EncTerminate(...)
@@ -53,8 +51,7 @@
  *
  * Return value             : number of bytes in the stream
  */
-int16_t WebRtcIsacfix_EncTerminate(Bitstr_enc *streamData);
-
+int16_t WebRtcIsacfix_EncTerminate(Bitstr_enc* streamData);
 
 /****************************************************************************
  * WebRtcIsacfix_DecLogisticMulti2(...)
@@ -73,12 +70,10 @@
  * Return value             : number of bytes in the stream so far
  *                            <0 if error detected
  */
-int WebRtcIsacfix_DecLogisticMulti2(
-    int16_t *data,
-    Bitstr_dec *streamData,
-    const int32_t *env,
-    const int16_t lenData);
-
+int WebRtcIsacfix_DecLogisticMulti2(int16_t* data,
+                                    Bitstr_dec* streamData,
+                                    const int32_t* env,
+                                    const int16_t lenData);
 
 /****************************************************************************
  * WebRtcIsacfix_EncHistMulti(...)
@@ -94,12 +89,10 @@
  * Return value             : 0 if ok
  *                            <0 if error detected
  */
-int WebRtcIsacfix_EncHistMulti(
-    Bitstr_enc *streamData,
-    const int16_t *data,
-    const uint16_t *const *cdf,
-    const int16_t lenData);
-
+int WebRtcIsacfix_EncHistMulti(Bitstr_enc* streamData,
+                               const int16_t* data,
+                               const uint16_t* const* cdf,
+                               const int16_t lenData);
 
 /****************************************************************************
  * WebRtcIsacfix_DecHistBisectMulti(...)
@@ -121,13 +114,11 @@
  * Return value             : number of bytes in the stream
  *                            <0 if error detected
  */
-int16_t WebRtcIsacfix_DecHistBisectMulti(
-    int16_t *data,
-    Bitstr_dec *streamData,
-    const uint16_t *const *cdf,
-    const uint16_t *cdfSize,
-    const int16_t lenData);
-
+int16_t WebRtcIsacfix_DecHistBisectMulti(int16_t* data,
+                                         Bitstr_dec* streamData,
+                                         const uint16_t* const* cdf,
+                                         const uint16_t* cdfSize,
+                                         const int16_t lenData);
 
 /****************************************************************************
  * WebRtcIsacfix_DecHistOneStepMulti(...)
@@ -149,11 +140,10 @@
  * Return value             : number of bytes in original stream
  *                            <0 if error detected
  */
-int16_t WebRtcIsacfix_DecHistOneStepMulti(
-    int16_t *data,
-    Bitstr_dec *streamData,
-    const uint16_t *const *cdf,
-    const uint16_t *initIndex,
-    const int16_t lenData);
+int16_t WebRtcIsacfix_DecHistOneStepMulti(int16_t* data,
+                                          Bitstr_dec* streamData,
+                                          const uint16_t* const* cdf,
+                                          const uint16_t* initIndex,
+                                          const int16_t lenData);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ARITH_ROUTINS_H_ */
diff --git a/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h b/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h
index 67f8d07..f8ac1ef 100644
--- a/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h
+++ b/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h
@@ -32,8 +32,7 @@
  * Return value            : 0
  */
 
-int32_t WebRtcIsacfix_InitBandwidthEstimator(BwEstimatorstr *bwest_str);
-
+int32_t WebRtcIsacfix_InitBandwidthEstimator(BwEstimatorstr* bwest_str);
 
 /****************************************************************************
  * WebRtcIsacfix_UpdateUplinkBwImpl(...)
@@ -56,16 +55,17 @@
  *                           -1 otherwise
  */
 
-int32_t WebRtcIsacfix_UpdateUplinkBwImpl(BwEstimatorstr       *bwest_str,
-                                         const uint16_t        rtp_number,
-                                         const int16_t         frameSize,
-                                         const uint32_t        send_ts,
-                                         const uint32_t        arr_ts,
-                                         const size_t          pksize,
-                                         const uint16_t        Index);
+int32_t WebRtcIsacfix_UpdateUplinkBwImpl(BwEstimatorstr* bwest_str,
+                                         const uint16_t rtp_number,
+                                         const int16_t frameSize,
+                                         const uint32_t send_ts,
+                                         const uint32_t arr_ts,
+                                         const size_t pksize,
+                                         const uint16_t Index);
 
-/* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */
-int16_t WebRtcIsacfix_UpdateUplinkBwRec(BwEstimatorstr *bwest_str,
+/* Update receiving estimates. Used when we only receive BWE index, no iSAC data
+ * packet. */
+int16_t WebRtcIsacfix_UpdateUplinkBwRec(BwEstimatorstr* bwest_str,
                                         const int16_t Index);
 
 /****************************************************************************
@@ -80,19 +80,19 @@
  * Return:
  *      bandwith and jitter index (0..23)
  */
-uint16_t WebRtcIsacfix_GetDownlinkBwIndexImpl(BwEstimatorstr *bwest_str);
+uint16_t WebRtcIsacfix_GetDownlinkBwIndexImpl(BwEstimatorstr* bwest_str);
 
 /* Returns the bandwidth estimation (in bps) */
-uint16_t WebRtcIsacfix_GetDownlinkBandwidth(const BwEstimatorstr *bwest_str);
+uint16_t WebRtcIsacfix_GetDownlinkBandwidth(const BwEstimatorstr* bwest_str);
 
 /* Returns the bandwidth that iSAC should send with in bps */
-int16_t WebRtcIsacfix_GetUplinkBandwidth(const BwEstimatorstr *bwest_str);
+int16_t WebRtcIsacfix_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
 
 /* Returns the max delay (in ms) */
-int16_t WebRtcIsacfix_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str);
+int16_t WebRtcIsacfix_GetDownlinkMaxDelay(const BwEstimatorstr* bwest_str);
 
 /* Returns the max delay value from the other side in ms */
-int16_t WebRtcIsacfix_GetUplinkMaxDelay(const BwEstimatorstr *bwest_str);
+int16_t WebRtcIsacfix_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str);
 
 /* Fills in an IsacExternalBandwidthInfo struct. */
 void WebRtcIsacfixBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
@@ -106,29 +106,31 @@
  * update amount of data in bottle neck buffer and burst handling
  * returns minimum payload size (bytes)
  */
-uint16_t WebRtcIsacfix_GetMinBytes(RateModel *State,
-                                   int16_t StreamSize,     /* bytes in bitstream */
-                                   const int16_t FrameLen,    /* ms per frame */
-                                   const int16_t BottleNeck,        /* bottle neck rate; excl headers (bps) */
-                                   const int16_t DelayBuildUp);     /* max delay from bottle neck buffering (ms) */
+uint16_t WebRtcIsacfix_GetMinBytes(
+    RateModel* State,
+    int16_t StreamSize,          /* bytes in bitstream */
+    const int16_t FrameLen,      /* ms per frame */
+    const int16_t BottleNeck,    /* bottle neck rate; excl headers (bps) */
+    const int16_t DelayBuildUp); /* max delay from bottle neck buffering (ms) */
 
 /*
  * update long-term average bitrate and amount of data in buffer
  */
-void WebRtcIsacfix_UpdateRateModel(RateModel *State,
-                                   int16_t StreamSize,    /* bytes in bitstream */
-                                   const int16_t FrameSamples,  /* samples per frame */
-                                   const int16_t BottleNeck);       /* bottle neck rate; excl headers (bps) */
+void WebRtcIsacfix_UpdateRateModel(
+    RateModel* State,
+    int16_t StreamSize,         /* bytes in bitstream */
+    const int16_t FrameSamples, /* samples per frame */
+    const int16_t BottleNeck);  /* bottle neck rate; excl headers (bps) */
 
-
-void WebRtcIsacfix_InitRateModel(RateModel *State);
+void WebRtcIsacfix_InitRateModel(RateModel* State);
 
 /* Returns the new framelength value (input argument: bottle_neck) */
-int16_t WebRtcIsacfix_GetNewFrameLength(int16_t bottle_neck, int16_t current_framelength);
+int16_t WebRtcIsacfix_GetNewFrameLength(int16_t bottle_neck,
+                                        int16_t current_framelength);
 
 /* Returns the new SNR value (input argument: bottle_neck) */
-//returns snr in Q10
+// returns snr in Q10
 int16_t WebRtcIsacfix_GetSnr(int16_t bottle_neck, int16_t framesamples);
 
-
-#endif /*  MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_BANDWIDTH_ESTIMATOR_H_ */
+#endif /*  MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_BANDWIDTH_ESTIMATOR_H_ \
+        */
diff --git a/modules/audio_coding/codecs/isac/fix/source/codec.h b/modules/audio_coding/codecs/isac/fix/source/codec.h
index 9876bd6..c95b53f 100644
--- a/modules/audio_coding/codecs/isac/fix/source/codec.h
+++ b/modules/audio_coding/codecs/isac/fix/source/codec.h
@@ -38,7 +38,7 @@
 
 void WebRtcIsacfix_DecodePlcImpl(int16_t* decoded,
                                  IsacFixDecoderInstance* ISACdec_obj,
-                                 size_t* current_framesample );
+                                 size_t* current_framesample);
 
 int WebRtcIsacfix_EncodeImpl(int16_t* in,
                              IsacFixEncoderInstance* ISACenc_obj,
@@ -64,7 +64,6 @@
 
 void WebRtcIsacfix_InitPlc(PLCstr* State);
 
-
 /* transform functions */
 
 void WebRtcIsacfix_InitTransform(void);
diff --git a/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h b/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h
index ba7bcde..b4251ce 100644
--- a/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h
+++ b/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h
@@ -22,91 +22,79 @@
 #include "modules/audio_coding/codecs/isac/fix/source/structs.h"
 
 /* decode complex spectrum (return number of bytes in stream) */
-int WebRtcIsacfix_DecodeSpec(Bitstr_dec  *streamdata,
-                             int16_t *frQ7,
-                             int16_t *fiQ7,
+int WebRtcIsacfix_DecodeSpec(Bitstr_dec* streamdata,
+                             int16_t* frQ7,
+                             int16_t* fiQ7,
                              int16_t AvgPitchGain_Q12);
 
 /* encode complex spectrum */
-int WebRtcIsacfix_EncodeSpec(const int16_t *fr,
-                             const int16_t *fi,
-                             Bitstr_enc *streamdata,
+int WebRtcIsacfix_EncodeSpec(const int16_t* fr,
+                             const int16_t* fi,
+                             Bitstr_enc* streamdata,
                              int16_t AvgPitchGain_Q12);
 
-
 /* decode & dequantize LPC Coef */
-int WebRtcIsacfix_DecodeLpcCoef(Bitstr_dec  *streamdata,
-                                int32_t *LPCCoefQ17,
-                                int32_t *gain_lo_hiQ17,
-                                int16_t *outmodel);
+int WebRtcIsacfix_DecodeLpcCoef(Bitstr_dec* streamdata,
+                                int32_t* LPCCoefQ17,
+                                int32_t* gain_lo_hiQ17,
+                                int16_t* outmodel);
 
-int WebRtcIsacfix_DecodeLpc(int32_t *gain_lo_hiQ17,
-                            int16_t *LPCCoef_loQ15,
-                            int16_t *LPCCoef_hiQ15,
-                            Bitstr_dec  *streamdata,
-                            int16_t *outmodel);
+int WebRtcIsacfix_DecodeLpc(int32_t* gain_lo_hiQ17,
+                            int16_t* LPCCoef_loQ15,
+                            int16_t* LPCCoef_hiQ15,
+                            Bitstr_dec* streamdata,
+                            int16_t* outmodel);
 
 /* quantize & code LPC Coef */
-int WebRtcIsacfix_EncodeLpc(int32_t *gain_lo_hiQ17,
-                            int16_t *LPCCoef_loQ15,
-                            int16_t *LPCCoef_hiQ15,
-                            int16_t *model,
-                            int32_t *sizeQ11,
-                            Bitstr_enc *streamdata,
+int WebRtcIsacfix_EncodeLpc(int32_t* gain_lo_hiQ17,
+                            int16_t* LPCCoef_loQ15,
+                            int16_t* LPCCoef_hiQ15,
+                            int16_t* model,
+                            int32_t* sizeQ11,
+                            Bitstr_enc* streamdata,
                             IsacSaveEncoderData* encData,
-                            transcode_obj *transcodeParam);
+                            transcode_obj* transcodeParam);
 
-int WebRtcIsacfix_EstCodeLpcGain(int32_t *gain_lo_hiQ17,
-                                 Bitstr_enc *streamdata,
+int WebRtcIsacfix_EstCodeLpcGain(int32_t* gain_lo_hiQ17,
+                                 Bitstr_enc* streamdata,
                                  IsacSaveEncoderData* encData);
 /* decode & dequantize RC */
-int WebRtcIsacfix_DecodeRcCoef(Bitstr_dec *streamdata,
-                               int16_t *RCQ15);
+int WebRtcIsacfix_DecodeRcCoef(Bitstr_dec* streamdata, int16_t* RCQ15);
 
 /* quantize & code RC */
-int WebRtcIsacfix_EncodeRcCoef(int16_t *RCQ15,
-                               Bitstr_enc *streamdata);
+int WebRtcIsacfix_EncodeRcCoef(int16_t* RCQ15, Bitstr_enc* streamdata);
 
 /* decode & dequantize squared Gain */
-int WebRtcIsacfix_DecodeGain2(Bitstr_dec *streamdata,
-                              int32_t *Gain2);
+int WebRtcIsacfix_DecodeGain2(Bitstr_dec* streamdata, int32_t* Gain2);
 
 /* quantize & code squared Gain (input is squared gain) */
-int WebRtcIsacfix_EncodeGain2(int32_t *gain2,
-                              Bitstr_enc *streamdata);
+int WebRtcIsacfix_EncodeGain2(int32_t* gain2, Bitstr_enc* streamdata);
 
-int WebRtcIsacfix_EncodePitchGain(int16_t *PitchGains_Q12,
-                                  Bitstr_enc *streamdata,
+int WebRtcIsacfix_EncodePitchGain(int16_t* PitchGains_Q12,
+                                  Bitstr_enc* streamdata,
                                   IsacSaveEncoderData* encData);
 
-int WebRtcIsacfix_EncodePitchLag(int16_t *PitchLagQ7,
-                                 int16_t *PitchGain_Q12,
-                                 Bitstr_enc *streamdata,
+int WebRtcIsacfix_EncodePitchLag(int16_t* PitchLagQ7,
+                                 int16_t* PitchGain_Q12,
+                                 Bitstr_enc* streamdata,
                                  IsacSaveEncoderData* encData);
 
-int WebRtcIsacfix_DecodePitchGain(Bitstr_dec *streamdata,
-                                  int16_t *PitchGain_Q12);
+int WebRtcIsacfix_DecodePitchGain(Bitstr_dec* streamdata,
+                                  int16_t* PitchGain_Q12);
 
-int WebRtcIsacfix_DecodePitchLag(Bitstr_dec *streamdata,
-                                 int16_t *PitchGain_Q12,
-                                 int16_t *PitchLagQ7);
+int WebRtcIsacfix_DecodePitchLag(Bitstr_dec* streamdata,
+                                 int16_t* PitchGain_Q12,
+                                 int16_t* PitchLagQ7);
 
-int WebRtcIsacfix_DecodeFrameLen(Bitstr_dec *streamdata,
-                                 size_t *framelength);
+int WebRtcIsacfix_DecodeFrameLen(Bitstr_dec* streamdata, size_t* framelength);
 
+int WebRtcIsacfix_EncodeFrameLen(int16_t framelength, Bitstr_enc* streamdata);
 
-int WebRtcIsacfix_EncodeFrameLen(int16_t framelength,
-                                 Bitstr_enc *streamdata);
+int WebRtcIsacfix_DecodeSendBandwidth(Bitstr_dec* streamdata, int16_t* BWno);
 
-int WebRtcIsacfix_DecodeSendBandwidth(Bitstr_dec *streamdata,
-                                      int16_t *BWno);
+int WebRtcIsacfix_EncodeReceiveBandwidth(int16_t* BWno, Bitstr_enc* streamdata);
 
-
-int WebRtcIsacfix_EncodeReceiveBandwidth(int16_t *BWno,
-                                         Bitstr_enc *streamdata);
-
-void WebRtcIsacfix_TranscodeLpcCoef(int32_t *tmpcoeffs_gQ6,
-                                    int16_t *index_gQQ);
+void WebRtcIsacfix_TranscodeLpcCoef(int32_t* tmpcoeffs_gQ6, int16_t* index_gQQ);
 
 // Pointer functions for LPC transforms.
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/fft.h b/modules/audio_coding/codecs/isac/fix/source/fft.h
index 61ec515..4fe9b96 100644
--- a/modules/audio_coding/codecs/isac/fix/source/fft.h
+++ b/modules/audio_coding/codecs/isac/fix/source/fft.h
@@ -32,8 +32,8 @@
 
 #include "modules/audio_coding/codecs/isac/fix/source/structs.h"
 
-int16_t WebRtcIsacfix_FftRadix16Fastest(int16_t RexQx[], int16_t ImxQx[], int16_t iSign);
-
-
+int16_t WebRtcIsacfix_FftRadix16Fastest(int16_t RexQx[],
+                                        int16_t ImxQx[],
+                                        int16_t iSign);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FFT_H_ */
diff --git a/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h b/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h
index 1c34969..8d97347 100644
--- a/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h
+++ b/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h
@@ -42,44 +42,41 @@
 #endif
 
 typedef void (*AllpassFilter2FixDec16)(
-    int16_t *data_ch1,           // Input and output in channel 1, in Q0
-    int16_t *data_ch2,           // Input and output in channel 2, in Q0
-    const int16_t *factor_ch1,   // Scaling factor for channel 1, in Q15
-    const int16_t *factor_ch2,   // Scaling factor for channel 2, in Q15
+    int16_t* data_ch1,           // Input and output in channel 1, in Q0
+    int16_t* data_ch2,           // Input and output in channel 2, in Q0
+    const int16_t* factor_ch1,   // Scaling factor for channel 1, in Q15
+    const int16_t* factor_ch2,   // Scaling factor for channel 2, in Q15
     const int length,            // Length of the data buffers
-    int32_t *filter_state_ch1,   // Filter state for channel 1, in Q16
-    int32_t *filter_state_ch2);  // Filter state for channel 2, in Q16
+    int32_t* filter_state_ch1,   // Filter state for channel 1, in Q16
+    int32_t* filter_state_ch2);  // Filter state for channel 2, in Q16
 extern AllpassFilter2FixDec16 WebRtcIsacfix_AllpassFilter2FixDec16;
 
-void WebRtcIsacfix_AllpassFilter2FixDec16C(
-   int16_t *data_ch1,
-   int16_t *data_ch2,
-   const int16_t *factor_ch1,
-   const int16_t *factor_ch2,
-   const int length,
-   int32_t *filter_state_ch1,
-   int32_t *filter_state_ch2);
+void WebRtcIsacfix_AllpassFilter2FixDec16C(int16_t* data_ch1,
+                                           int16_t* data_ch2,
+                                           const int16_t* factor_ch1,
+                                           const int16_t* factor_ch2,
+                                           const int length,
+                                           int32_t* filter_state_ch1,
+                                           int32_t* filter_state_ch2);
 
 #if defined(WEBRTC_HAS_NEON)
-void WebRtcIsacfix_AllpassFilter2FixDec16Neon(
-   int16_t *data_ch1,
-   int16_t *data_ch2,
-   const int16_t *factor_ch1,
-   const int16_t *factor_ch2,
-   const int length,
-   int32_t *filter_state_ch1,
-   int32_t *filter_state_ch2);
+void WebRtcIsacfix_AllpassFilter2FixDec16Neon(int16_t* data_ch1,
+                                              int16_t* data_ch2,
+                                              const int16_t* factor_ch1,
+                                              const int16_t* factor_ch2,
+                                              const int length,
+                                              int32_t* filter_state_ch1,
+                                              int32_t* filter_state_ch2);
 #endif
 
 #if defined(MIPS_DSP_R1_LE)
-void WebRtcIsacfix_AllpassFilter2FixDec16MIPS(
-   int16_t *data_ch1,
-   int16_t *data_ch2,
-   const int16_t *factor_ch1,
-   const int16_t *factor_ch2,
-   const int length,
-   int32_t *filter_state_ch1,
-   int32_t *filter_state_ch2);
+void WebRtcIsacfix_AllpassFilter2FixDec16MIPS(int16_t* data_ch1,
+                                              int16_t* data_ch2,
+                                              const int16_t* factor_ch1,
+                                              const int16_t* factor_ch2,
+                                              const int length,
+                                              int32_t* filter_state_ch1,
+                                              int32_t* filter_state_ch2);
 #endif
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/modules/audio_coding/codecs/isac/fix/source/filterbanks_unittest.cc b/modules/audio_coding/codecs/isac/fix/source/filterbanks_unittest.cc
index d17f4a5..0727d58 100644
--- a/modules/audio_coding/codecs/isac/fix/source/filterbanks_unittest.cc
+++ b/modules/audio_coding/codecs/isac/fix/source/filterbanks_unittest.cc
@@ -21,8 +21,8 @@
  protected:
   // Pass a function pointer to the Tester function.
   void RTC_NO_SANITIZE("signed-integer-overflow")  // bugs.webrtc.org/5513
-  CalculateResidualEnergyTester(AllpassFilter2FixDec16
-                                AllpassFilter2FixDec16Function) {
+      CalculateResidualEnergyTester(
+          AllpassFilter2FixDec16 AllpassFilter2FixDec16Function) {
     const int kSamples = QLOOKAHEAD;
     const int kState = 2;
     int16_t data_ch1[kSamples] = {0};
@@ -31,12 +31,14 @@
     int32_t state_ch2[kState] = {0};
     const int32_t out_state_ch1[kState] = {-809122714, 1645972152};
     const int32_t out_state_ch2[kState] = {428019288, 1057309936};
-    const int32_t out_data_ch1[kSamples] = {0, 0, 347, 10618, 16718, -7089,
-        32767, 16913, 27042, 8377, -22973, -28372, -27603, -14804, 398, -25332,
-        -11200, 18044, 25223, -6839, 1116, -23984, 32717, 7364};
-    const int32_t out_data_ch2[kSamples] = {0, 0, 3010, 22351, 21106, 16969,
-        -2095, -664, 3513, -30980, 32767, -23839, 13335, 20289, -6831, 339,
-        -17207, 32767, 4959, 6177, 32767, 16599, -4747, 20504};
+    const int32_t out_data_ch1[kSamples] = {
+        0,      0,     347,    10618,  16718,  -7089,  32767, 16913,
+        27042,  8377,  -22973, -28372, -27603, -14804, 398,   -25332,
+        -11200, 18044, 25223,  -6839,  1116,   -23984, 32717, 7364};
+    const int32_t out_data_ch2[kSamples] = {
+        0,      0,      3010,  22351,  21106, 16969, -2095, -664,
+        3513,   -30980, 32767, -23839, 13335, 20289, -6831, 339,
+        -17207, 32767,  4959,  6177,   32767, 16599, -4747, 20504};
     int sign = 1;
 
     for (int i = 0; i < kSamples; i++) {
@@ -46,13 +48,9 @@
       // UBSan: -1 * -2147483648 cannot be represented in type 'int'
     };
 
-    AllpassFilter2FixDec16Function(data_ch1,
-                                   data_ch2,
-                                   WebRtcIsacfix_kUpperApFactorsQ15,
-                                   WebRtcIsacfix_kLowerApFactorsQ15,
-                                   kSamples,
-                                   state_ch1,
-                                   state_ch2);
+    AllpassFilter2FixDec16Function(
+        data_ch1, data_ch2, WebRtcIsacfix_kUpperApFactorsQ15,
+        WebRtcIsacfix_kLowerApFactorsQ15, kSamples, state_ch1, state_ch2);
 
     for (int i = 0; i < kSamples; i++) {
       EXPECT_EQ(out_data_ch1[i], data_ch1[i]);
@@ -77,13 +75,13 @@
   int16_t in[kSamples];
   int32_t state[2] = {12345, 987654};
 #ifdef WEBRTC_ARCH_ARM_V7
-  int32_t out[kSamples] = {-1040, -1035, -22875, -1397, -27604, 20018, 7917,
-    -1279, -8552, -14494, -7558, -23537, -27258, -30554, -32768, -3432, -32768,
-    25215, -27536, 22436};
+  int32_t out[kSamples] = {-1040,  -1035, -22875, -1397, -27604, 20018,  7917,
+                           -1279,  -8552, -14494, -7558, -23537, -27258, -30554,
+                           -32768, -3432, -32768, 25215, -27536, 22436};
 #else
-  int32_t out[kSamples] = {-1040, -1035, -22875, -1397, -27604, 20017, 7915,
-    -1280, -8554, -14496, -7561, -23541, -27263, -30560, -32768, -3441, -32768,
-    25203, -27550, 22419};
+  int32_t out[kSamples] = {-1040,  -1035, -22875, -1397, -27604, 20017,  7915,
+                           -1280,  -8554, -14496, -7561, -23541, -27263, -30560,
+                           -32768, -3441, -32768, 25203, -27550, 22419};
 #endif
   HighpassFilterFixDec32 WebRtcIsacfix_HighpassFilterFixDec32;
 #if defined(MIPS_DSP_R1_LE)
@@ -98,7 +96,7 @@
   }
 
   WebRtcIsacfix_HighpassFilterFixDec32(in, kSamples,
-      WebRtcIsacfix_kHPStCoeffOut1Q30, state);
+                                       WebRtcIsacfix_kHPStCoeffOut1Q30, state);
 
   for (int i = 0; i < kSamples; i++) {
     EXPECT_EQ(out[i], in[i]);
diff --git a/modules/audio_coding/codecs/isac/fix/source/filters_unittest.cc b/modules/audio_coding/codecs/isac/fix/source/filters_unittest.cc
index fa52986..2ab8d6a 100644
--- a/modules/audio_coding/codecs/isac/fix/source/filters_unittest.cc
+++ b/modules/audio_coding/codecs/isac/fix/source/filters_unittest.cc
@@ -23,34 +23,37 @@
     int32_t r_buffer[kOrder + 2] = {0};
 
     // Test an overflow case.
-    const int16_t x_buffer_0[kBuffer] = {0, 0, 3010, 22351, 21106, 16969, -2095,
-        -664, 3513, -30980, 32767, -23839, 13335, 20289, -6831, 339, -17207,
-        32767, 4959, 6177, 32767, 16599, -4747, 20504, 3513, -30980, 32767,
-        -23839, 13335, 20289, 0, -16969, -2095, -664, 3513, 31981, 32767,
-        -13839, 23336, 30281};
-    const int32_t r_expected_0[kOrder + 2] = {1872498461, -224288754, 203789985,
-        483400487, -208272635, 2436500, 137785322, 266600814, -208486262,
-        329510080, 137949184, -161738972, -26894267, 237630192};
+    const int16_t x_buffer_0[kBuffer] = {
+        0,      0,      3010,  22351,  21106, 16969,  -2095, -664,
+        3513,   -30980, 32767, -23839, 13335, 20289,  -6831, 339,
+        -17207, 32767,  4959,  6177,   32767, 16599,  -4747, 20504,
+        3513,   -30980, 32767, -23839, 13335, 20289,  0,     -16969,
+        -2095,  -664,   3513,  31981,  32767, -13839, 23336, 30281};
+    const int32_t r_expected_0[kOrder + 2] = {
+        1872498461, -224288754, 203789985, 483400487,  -208272635,
+        2436500,    137785322,  266600814, -208486262, 329510080,
+        137949184,  -161738972, -26894267, 237630192};
 
-    WebRtcIsacfix_AutocorrFixFunction(r_buffer, x_buffer_0,
-                                      kBuffer, kOrder + 1, &scale);
+    WebRtcIsacfix_AutocorrFixFunction(r_buffer, x_buffer_0, kBuffer, kOrder + 1,
+                                      &scale);
     for (int i = 0; i < kOrder + 2; i++) {
       EXPECT_EQ(r_expected_0[i], r_buffer[i]);
     }
     EXPECT_EQ(3, scale);
 
     // Test a no-overflow case.
-    const int16_t x_buffer_1[kBuffer] = {0, 0, 300, 21, 206, 169, -295,
-        -664, 3513, -300, 327, -29, 15, 289, -6831, 339, -107,
-        37, 59, 6177, 327, 169, -4747, 204, 313, -980, 767,
-        -9, 135, 289, 0, -6969, -2095, -664, 0, 1, 7,
-        -39, 236, 281};
-    const int32_t r_expected_1[kOrder + 2] = {176253864, 8126617, 1983287,
-        -26196788, -3487363, -42839676, -24644043, 3469813, 30559879, 31905045,
-        5101567, 29328896, -55787438, -13163978};
+    const int16_t x_buffer_1[kBuffer] = {
+        0,   0,     300,   21,   206,   169,  -295, -664, 3513, -300,
+        327, -29,   15,    289,  -6831, 339,  -107, 37,   59,   6177,
+        327, 169,   -4747, 204,  313,   -980, 767,  -9,   135,  289,
+        0,   -6969, -2095, -664, 0,     1,    7,    -39,  236,  281};
+    const int32_t r_expected_1[kOrder + 2] = {
+        176253864, 8126617,   1983287,   -26196788, -3487363,
+        -42839676, -24644043, 3469813,   30559879,  31905045,
+        5101567,   29328896,  -55787438, -13163978};
 
-    WebRtcIsacfix_AutocorrFixFunction(r_buffer, x_buffer_1,
-                                      kBuffer, kOrder + 1, &scale);
+    WebRtcIsacfix_AutocorrFixFunction(r_buffer, x_buffer_1, kBuffer, kOrder + 1,
+                                      &scale);
     for (int i = 0; i < kOrder + 2; i++) {
       EXPECT_EQ(r_expected_1[i], r_buffer[i]);
     }
diff --git a/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h b/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h
index d6d1e8f..40a99e8 100644
--- a/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h
+++ b/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h
@@ -24,19 +24,19 @@
 
 #include "modules/audio_coding/codecs/isac/fix/source/structs.h"
 
-void WebRtcIsacfix_GetVars(const int16_t *input,
-                           const int16_t *pitchGains_Q12,
-                           uint32_t *oldEnergy,
-                           int16_t *varscale);
+void WebRtcIsacfix_GetVars(const int16_t* input,
+                           const int16_t* pitchGains_Q12,
+                           uint32_t* oldEnergy,
+                           int16_t* varscale);
 
-void WebRtcIsacfix_GetLpcCoef(int16_t *inLoQ0,
-                              int16_t *inHiQ0,
-                              MaskFiltstr_enc *maskdata,
+void WebRtcIsacfix_GetLpcCoef(int16_t* inLoQ0,
+                              int16_t* inHiQ0,
+                              MaskFiltstr_enc* maskdata,
                               int16_t snrQ10,
-                              const int16_t *pitchGains_Q12,
-                              int32_t *gain_lo_hiQ17,
-                              int16_t *lo_coeffQ15,
-                              int16_t *hi_coeffQ15);
+                              const int16_t* pitchGains_Q12,
+                              int32_t* gain_lo_hiQ17,
+                              int16_t* lo_coeffQ15,
+                              int16_t* hi_coeffQ15);
 
 typedef int32_t (*CalculateResidualEnergy)(int lpc_order,
                                            int32_t q_val_corr,
diff --git a/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_unittest.cc b/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_unittest.cc
index 1604cc4..dbcf420 100644
--- a/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_unittest.cc
+++ b/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_unittest.cc
@@ -16,21 +16,21 @@
 class LpcMaskingModelTest : public testing::Test {
  protected:
   // Pass a function pointer to the Tester function.
-  void CalculateResidualEnergyTester(CalculateResidualEnergy
-                                     CalculateResidualEnergyFunction) {
+  void CalculateResidualEnergyTester(
+      CalculateResidualEnergy CalculateResidualEnergyFunction) {
     const int kIntOrder = 10;
     const int32_t kInt32QDomain = 5;
     const int kIntShift = 11;
-    int16_t a[kIntOrder + 1] = {32760, 122, 7, 0, -32760, -3958,
-        -48, 18745, 498, 9, 23456};
-    int32_t corr[kIntOrder + 1] = {11443647, -27495, 0,
-        98745, -11443600, 1, 1, 498, 9, 888, 23456};
+    int16_t a[kIntOrder + 1] = {32760, 122,   7,   0, -32760, -3958,
+                                -48,   18745, 498, 9, 23456};
+    int32_t corr[kIntOrder + 1] = {11443647, -27495, 0, 98745, -11443600, 1,
+                                   1,        498,    9, 888,   23456};
     int q_shift_residual = 0;
     int32_t residual_energy = 0;
 
     // Test the code path where (residual_energy >= 0x10000).
-    residual_energy = CalculateResidualEnergyFunction(kIntOrder,
-        kInt32QDomain, kIntShift, a, corr, &q_shift_residual);
+    residual_energy = CalculateResidualEnergyFunction(
+        kIntOrder, kInt32QDomain, kIntShift, a, corr, &q_shift_residual);
     EXPECT_EQ(1789023310, residual_energy);
     EXPECT_EQ(2, q_shift_residual);
 
@@ -40,8 +40,8 @@
       a[i] = 24575 >> i;
       corr[i] = i;
     }
-    residual_energy = CalculateResidualEnergyFunction(kIntOrder,
-        kInt32QDomain, kIntShift, a, corr, &q_shift_residual);
+    residual_energy = CalculateResidualEnergyFunction(
+        kIntOrder, kInt32QDomain, kIntShift, a, corr, &q_shift_residual);
     EXPECT_EQ(1595279092, residual_energy);
     EXPECT_EQ(26, q_shift_residual);
 
@@ -49,8 +49,8 @@
     for (int i = 0; i < kIntOrder + 1; i++) {
       a[i] = 2457 >> i;
     }
-    residual_energy = CalculateResidualEnergyFunction(kIntOrder,
-        kInt32QDomain, kIntShift, a, corr, &q_shift_residual);
+    residual_energy = CalculateResidualEnergyFunction(
+        kIntOrder, kInt32QDomain, kIntShift, a, corr, &q_shift_residual);
     EXPECT_EQ(2029266944, residual_energy);
     EXPECT_EQ(33, q_shift_residual);
   }
diff --git a/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h b/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h
index 05c53dd..c51f2ca 100644
--- a/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h
+++ b/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h
@@ -26,10 +26,10 @@
 extern const uint16_t WebRtcIsacfix_kSelIndShape[108];
 
 /* cdf array for model indicator */
-extern const uint16_t WebRtcIsacfix_kModelCdf[KLT_NUM_MODELS+1];
+extern const uint16_t WebRtcIsacfix_kModelCdf[KLT_NUM_MODELS + 1];
 
 /* pointer to cdf array for model indicator */
-extern const uint16_t *WebRtcIsacfix_kModelCdfPtr[1];
+extern const uint16_t* WebRtcIsacfix_kModelCdfPtr[1];
 
 /* initial cdf index for decoder of model indicator */
 extern const uint16_t WebRtcIsacfix_kModelInitIndex[1];
@@ -70,9 +70,9 @@
 extern const uint16_t WebRtcIsacfix_kCdfShape[2059];
 
 /* pointers to cdf tables for quantizer indices */
-extern const uint16_t *WebRtcIsacfix_kCdfGainPtr[KLT_NUM_MODELS][12];
+extern const uint16_t* WebRtcIsacfix_kCdfGainPtr[KLT_NUM_MODELS][12];
 
-extern const uint16_t *WebRtcIsacfix_kCdfShapePtr[KLT_NUM_MODELS][108];
+extern const uint16_t* WebRtcIsacfix_kCdfShapePtr[KLT_NUM_MODELS][108];
 
 /* code length for all coefficients using different models */
 extern const int16_t WebRtcIsacfix_kCodeLenGainQ11[392];
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h
index 994cce7..4303c82 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h
@@ -20,21 +20,22 @@
 
 #include "modules/audio_coding/codecs/isac/fix/source/structs.h"
 
-void WebRtcIsacfix_PitchAnalysis(const int16_t *in,               /* PITCH_FRAME_LEN samples */
-                                 int16_t *outQ0,                  /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
-                                 PitchAnalysisStruct *State,
-                                 int16_t *lagsQ7,
-                                 int16_t *PitchGains_Q12);
+void WebRtcIsacfix_PitchAnalysis(
+    const int16_t* in, /* PITCH_FRAME_LEN samples */
+    int16_t* outQ0,    /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
+    PitchAnalysisStruct* State,
+    int16_t* lagsQ7,
+    int16_t* PitchGains_Q12);
 
-void WebRtcIsacfix_InitialPitch(const int16_t *in,
-                                PitchAnalysisStruct *State,
-                                int16_t *qlags);
+void WebRtcIsacfix_InitialPitch(const int16_t* in,
+                                PitchAnalysisStruct* State,
+                                int16_t* qlags);
 
-void WebRtcIsacfix_PitchFilter(int16_t *indatFix,
-                               int16_t *outdatQQ,
-                               PitchFiltstr *pfp,
-                               int16_t *lagsQ7,
-                               int16_t *gainsQ12,
+void WebRtcIsacfix_PitchFilter(int16_t* indatFix,
+                               int16_t* outdatQQ,
+                               PitchFiltstr* pfp,
+                               int16_t* lagsQ7,
+                               int16_t* gainsQ12,
                                int16_t type);
 
 void WebRtcIsacfix_PitchFilterCore(int loopNumber,
@@ -48,17 +49,18 @@
                                    int16_t* outputBuf,
                                    int* index2);
 
-void WebRtcIsacfix_PitchFilterGains(const int16_t *indatQ0,
-                                    PitchFiltstr *pfp,
-                                    int16_t *lagsQ7,
-                                    int16_t *gainsQ12);
+void WebRtcIsacfix_PitchFilterGains(const int16_t* indatQ0,
+                                    PitchFiltstr* pfp,
+                                    int16_t* lagsQ7,
+                                    int16_t* gainsQ12);
 
-void WebRtcIsacfix_DecimateAllpass32(const int16_t *in,
-                                     int32_t *state_in,        /* array of size: 2*ALLPASSSECTIONS+1 */
-                                     int16_t N,                   /* number of input samples */
-                                     int16_t *out);             /* array of size N/2 */
+void WebRtcIsacfix_DecimateAllpass32(
+    const int16_t* in,
+    int32_t* state_in, /* array of size: 2*ALLPASSSECTIONS+1 */
+    int16_t N,         /* number of input samples */
+    int16_t* out);     /* array of size N/2 */
 
-int32_t WebRtcIsacfix_Log2Q8( uint32_t x );
+int32_t WebRtcIsacfix_Log2Q8(uint32_t x);
 
 void WebRtcIsacfix_PCorr2Q32(const int16_t* in, int32_t* logcorQ8);
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.h b/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.h
index fe4d288..2b5f54e 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.h
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.h
@@ -11,7 +11,8 @@
 /*
  * pitch_gain_tables.h
  *
- * This file contains tables for the pitch filter side-info in the entropy coder.
+ * This file contains tables for the pitch filter side-info in the entropy
+ * coder.
  *
  */
 
@@ -20,7 +21,8 @@
 
 #include "typedefs.h"  // NOLINT(build/include)
 
-/********************* Pitch Filter Gain Coefficient Tables ************************/
+/********************* Pitch Filter Gain Coefficient Tables
+ * ************************/
 /* cdf for quantized pitch filter gains */
 extern const uint16_t WebRtcIsacfix_kPitchGainCdf[255];
 
diff --git a/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h b/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h
index a8c0c3a..f834eab 100644
--- a/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h
+++ b/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h
@@ -11,7 +11,8 @@
 /*
  * pitch_lag_tables.h
  *
- * This file contains tables for the pitch filter side-info in the entropy coder.
+ * This file contains tables for the pitch filter side-info in the entropy
+ * coder.
  *
  */
 
@@ -20,7 +21,8 @@
 
 #include "typedefs.h"  // NOLINT(build/include)
 
-/********************* Pitch Filter Lag Coefficient Tables ************************/
+/********************* Pitch Filter Lag Coefficient Tables
+ * ************************/
 
 /* tables for use with small pitch gain */
 
@@ -30,7 +32,7 @@
 extern const uint16_t WebRtcIsacfix_kPitchLagCdf3Lo[2];
 extern const uint16_t WebRtcIsacfix_kPitchLagCdf4Lo[10];
 
-extern const uint16_t *WebRtcIsacfix_kPitchLagPtrLo[4];
+extern const uint16_t* WebRtcIsacfix_kPitchLagPtrLo[4];
 
 /* size of first cdf table */
 extern const uint16_t WebRtcIsacfix_kPitchLagSizeLo[1];
@@ -46,8 +48,6 @@
 extern const int16_t WebRtcIsacfix_kMeanLag2Lo[19];
 extern const int16_t WebRtcIsacfix_kMeanLag4Lo[9];
 
-
-
 /* tables for use with medium pitch gain */
 
 /* cdfs for quantized pitch lags */
@@ -56,7 +56,7 @@
 extern const uint16_t WebRtcIsacfix_kPitchLagCdf3Mid[2];
 extern const uint16_t WebRtcIsacfix_kPitchLagCdf4Mid[20];
 
-extern const uint16_t *WebRtcIsacfix_kPitchLagPtrMid[4];
+extern const uint16_t* WebRtcIsacfix_kPitchLagPtrMid[4];
 
 /* size of first cdf table */
 extern const uint16_t WebRtcIsacfix_kPitchLagSizeMid[1];
@@ -72,7 +72,6 @@
 extern const int16_t WebRtcIsacfix_kMeanLag2Mid[35];
 extern const int16_t WebRtcIsacfix_kMeanLag4Mid[19];
 
-
 /* tables for use with large pitch gain */
 
 /* cdfs for quantized pitch lags */
@@ -81,7 +80,7 @@
 extern const uint16_t WebRtcIsacfix_kPitchLagCdf3Hi[2];
 extern const uint16_t WebRtcIsacfix_kPitchLagCdf4Hi[35];
 
-extern const uint16_t *WebRtcIsacfix_kPitchLagPtrHi[4];
+extern const uint16_t* WebRtcIsacfix_kPitchLagPtrHi[4];
 
 /* size of first cdf table */
 extern const uint16_t WebRtcIsacfix_kPitchLagSizeHi[1];
@@ -97,5 +96,4 @@
 extern const int16_t WebRtcIsacfix_kMeanLag2Hi[67];
 extern const int16_t WebRtcIsacfix_kMeanLag4Hi[34];
 
-
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_LAG_TABLES_H_ */
diff --git a/modules/audio_coding/codecs/isac/fix/source/settings.h b/modules/audio_coding/codecs/isac/fix/source/settings.h
index 34c0efe..03a2d05 100644
--- a/modules/audio_coding/codecs/isac/fix/source/settings.h
+++ b/modules/audio_coding/codecs/isac/fix/source/settings.h
@@ -18,84 +18,82 @@
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SETTINGS_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SETTINGS_H_
 
-
 /* sampling frequency (Hz) */
-#define FS                                      16000
+#define FS 16000
 /* 1.5 times Sampling frequency */
-#define FS_1_HALF        (uint32_t) 24000
+#define FS_1_HALF (uint32_t)24000
 /* Three times Sampling frequency */
-#define FS3          (uint32_t) 48000
+#define FS3 (uint32_t)48000
 /* Eight times Sampling frequency */
-#define FS8          (uint32_t) 128000
+#define FS8 (uint32_t)128000
 
 /* number of samples per frame (either 480 (30ms) or 960 (60ms)) */
-#define INITIAL_FRAMESAMPLES     960
+#define INITIAL_FRAMESAMPLES 960
 
 /* miliseconds */
-#define FRAMESIZE                               30
+#define FRAMESIZE 30
 /* number of samples per frame processed in the encoder (30ms) */
-#define FRAMESAMPLES                            480     /* ((FRAMESIZE*FS)/1000) */
-#define FRAMESAMPLES_HALF       240
+#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */
+#define FRAMESAMPLES_HALF 240
 /* max number of samples per frame (= 60 ms frame) */
-#define MAX_FRAMESAMPLES      960
+#define MAX_FRAMESAMPLES 960
 /* number of samples per 10ms frame */
-#define FRAMESAMPLES_10ms                       160      /* ((10*FS)/1000) */
+#define FRAMESAMPLES_10ms 160 /* ((10*FS)/1000) */
 /* Number of samples per 1 ms */
-#define SAMPLES_PER_MSEC      16
+#define SAMPLES_PER_MSEC 16
 /* number of subframes */
-#define SUBFRAMES                               6
+#define SUBFRAMES 6
 /* length of a subframe */
-#define UPDATE                                  80
+#define UPDATE 80
 /* length of half a subframe (low/high band) */
-#define HALF_SUBFRAMELEN                        40    /* (UPDATE/2) */
-/* samples of look ahead (in a half-band, so actually half the samples of look ahead @ FS) */
-#define QLOOKAHEAD                              24    /* 3 ms */
+#define HALF_SUBFRAMELEN 40 /* (UPDATE/2) */
+/* samples of look ahead (in a half-band, so actually half the samples of look
+ * ahead @ FS) */
+#define QLOOKAHEAD 24 /* 3 ms */
 
 /* order of AR model in spectral entropy coder */
-#define AR_ORDER                                6
-#define MAX_ORDER                               13
-#define LEVINSON_MAX_ORDER                  12
+#define AR_ORDER 6
+#define MAX_ORDER 13
+#define LEVINSON_MAX_ORDER 12
 
 /* window length (masking analysis) */
-#define WINLEN                                  256
+#define WINLEN 256
 /* order of low-band pole filter used to approximate masking curve */
-#define ORDERLO                                 12
+#define ORDERLO 12
 /* order of hi-band pole filter used to approximate masking curve */
-#define ORDERHI                                 6
+#define ORDERHI 6
 
-#define KLT_NUM_AVG_GAIN                        0
-#define KLT_NUM_AVG_SHAPE                       0
-#define KLT_NUM_MODELS                          3
-#define LPC_SHAPE_ORDER                         18    /* (ORDERLO + ORDERHI) */
+#define KLT_NUM_AVG_GAIN 0
+#define KLT_NUM_AVG_SHAPE 0
+#define KLT_NUM_MODELS 3
+#define LPC_SHAPE_ORDER 18 /* (ORDERLO + ORDERHI) */
 
-#define KLT_ORDER_GAIN                          12    /* (2 * SUBFRAMES) */
-#define KLT_ORDER_SHAPE                         108   /*  (LPC_SHAPE_ORDER * SUBFRAMES) */
-
-
+#define KLT_ORDER_GAIN 12   /* (2 * SUBFRAMES) */
+#define KLT_ORDER_SHAPE 108 /*  (LPC_SHAPE_ORDER * SUBFRAMES) */
 
 /* order for post_filter_bank */
-#define POSTQORDER                              3
+#define POSTQORDER 3
 /* order for pre-filterbank */
-#define QORDER                                  3
+#define QORDER 3
 /* for decimator */
-#define ALLPASSSECTIONS                         2
+#define ALLPASSSECTIONS 2
 /* The number of composite all-pass filter factors */
-#define NUMBEROFCOMPOSITEAPSECTIONS             4
+#define NUMBEROFCOMPOSITEAPSECTIONS 4
 
 /* The number of all-pass filter factors in an upper or lower channel*/
-#define NUMBEROFCHANNELAPSECTIONS               2
+#define NUMBEROFCHANNELAPSECTIONS 2
 
-
-
-#define DPMIN_Q10                            -10240   /* -10.00 in Q10 */
-#define DPMAX_Q10                             10240   /* 10.00 in Q10 */
-#define MINBITS_Q10                           10240   /* 10.0 in Q10 */
-
+#define DPMIN_Q10 -10240  /* -10.00 in Q10 */
+#define DPMAX_Q10 10240   /* 10.00 in Q10 */
+#define MINBITS_Q10 10240 /* 10.0 in Q10 */
 
 /* array size for byte stream in number of Word16. */
-#define STREAM_MAXW16       300 /* The old maximum size still needed for the decoding */
-#define STREAM_MAXW16_30MS  100 /* 100 Word16 = 200 bytes = 53.4 kbit/s @ 30 ms.framelength */
-#define STREAM_MAXW16_60MS  200 /* 200 Word16 = 400 bytes = 53.4 kbit/s @ 60 ms.framelength */
+#define STREAM_MAXW16 \
+  300 /* The old maximum size still needed for the decoding */
+#define STREAM_MAXW16_30MS \
+  100 /* 100 Word16 = 200 bytes = 53.4 kbit/s @ 30 ms.framelength */
+#define STREAM_MAXW16_60MS \
+  200 /* 200 Word16 = 400 bytes = 53.4 kbit/s @ 60 ms.framelength */
 /* This is used only at the decoder bit-stream struct.
  * - The encoder and decoder bitstream containers are of different size because
  *   old iSAC limited the encoded bitstream to 600 bytes. But newer versions
@@ -110,106 +108,104 @@
 /* storage size for bit counts */
 //#define BIT_COUNTER_SIZE                        30
 /* maximum order of any AR model or filter */
-#define MAX_AR_MODEL_ORDER                      12
+#define MAX_AR_MODEL_ORDER 12
 
 /* Maximum number of iterations allowed to limit payload size */
-#define MAX_PAYLOAD_LIMIT_ITERATION           1
+#define MAX_PAYLOAD_LIMIT_ITERATION 1
 
 /* Bandwidth estimator */
 
-#define MIN_ISAC_BW                           10000     /* Minimum bandwidth in bits per sec */
-#define MAX_ISAC_BW                           32000     /* Maxmum bandwidth in bits per sec */
-#define MIN_ISAC_MD                           5         /* Minimum Max Delay in ?? */
-#define MAX_ISAC_MD                           25        /* Maxmum Max Delay in ?? */
-#define DELAY_CORRECTION_MAX      717
-#define DELAY_CORRECTION_MED      819
-#define Thld_30_60         18000
-#define Thld_60_30         27000
+#define MIN_ISAC_BW 10000 /* Minimum bandwidth in bits per sec */
+#define MAX_ISAC_BW 32000 /* Maxmum bandwidth in bits per sec */
+#define MIN_ISAC_MD 5     /* Minimum Max Delay in ?? */
+#define MAX_ISAC_MD 25    /* Maxmum Max Delay in ?? */
+#define DELAY_CORRECTION_MAX 717
+#define DELAY_CORRECTION_MED 819
+#define Thld_30_60 18000
+#define Thld_60_30 27000
 
-/* assumed header size; we don't know the exact number (header compression may be used) */
-#define HEADER_SIZE                           35       /* bytes */
-#define INIT_FRAME_LEN                        60
-#define INIT_BN_EST                           20000
-#define INIT_BN_EST_Q7                        2560000  /* 20 kbps in Q7 */
-#define INIT_REC_BN_EST_Q5                    789312   /* INIT_BN_EST + INIT_HDR_RATE in Q5 */
+/* assumed header size; we don't know the exact number (header compression may
+ * be used) */
+#define HEADER_SIZE 35 /* bytes */
+#define INIT_FRAME_LEN 60
+#define INIT_BN_EST 20000
+#define INIT_BN_EST_Q7 2560000    /* 20 kbps in Q7 */
+#define INIT_REC_BN_EST_Q5 789312 /* INIT_BN_EST + INIT_HDR_RATE in Q5 */
 
 /* 8738 in Q18 is ~ 1/30 */
-/* #define INIT_HDR_RATE (((HEADER_SIZE * 8 * 1000) * 8738) >> NUM_BITS_TO_SHIFT (INIT_FRAME_LEN)) */
-#define INIT_HDR_RATE                    4666
+/* #define INIT_HDR_RATE (((HEADER_SIZE * 8 * 1000) * 8738) >> NUM_BITS_TO_SHIFT
+ * (INIT_FRAME_LEN)) */
+#define INIT_HDR_RATE 4666
 /* number of packets in a row for a high rate burst */
-#define BURST_LEN                             3
+#define BURST_LEN 3
 /* ms, max time between two full bursts */
-#define BURST_INTERVAL                        800
+#define BURST_INTERVAL 800
 /* number of packets in a row for initial high rate burst */
-#define INIT_BURST_LEN                        5
+#define INIT_BURST_LEN 5
 /* bits/s, rate for the first BURST_LEN packets */
-#define INIT_RATE                             10240000 /* INIT_BN_EST in Q9 */
-
+#define INIT_RATE 10240000 /* INIT_BN_EST in Q9 */
 
 /* For pitch analysis */
-#define PITCH_FRAME_LEN                         240  /* (FRAMESAMPLES/2) 30 ms  */
-#define PITCH_MAX_LAG                           140       /* 57 Hz  */
-#define PITCH_MIN_LAG                           20                /* 400 Hz */
-#define PITCH_MIN_LAG_Q8                        5120 /* 256 * PITCH_MIN_LAG */
-#define OFFSET_Q8                               768  /* 256 * 3 */
+#define PITCH_FRAME_LEN 240   /* (FRAMESAMPLES/2) 30 ms  */
+#define PITCH_MAX_LAG 140     /* 57 Hz  */
+#define PITCH_MIN_LAG 20      /* 400 Hz */
+#define PITCH_MIN_LAG_Q8 5120 /* 256 * PITCH_MIN_LAG */
+#define OFFSET_Q8 768         /* 256 * 3 */
 
-#define PITCH_MAX_GAIN_Q12      1843                  /* 0.45 */
-#define PITCH_LAG_SPAN2                         65   /* (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5) */
-#define PITCH_CORR_LEN2                         60     /* 15 ms  */
-#define PITCH_CORR_STEP2                        60   /* (PITCH_FRAME_LEN/4) */
-#define PITCH_SUBFRAMES                         4
-#define PITCH_SUBFRAME_LEN                      60   /* (PITCH_FRAME_LEN/PITCH_SUBFRAMES) */
+#define PITCH_MAX_GAIN_Q12 1843 /* 0.45 */
+#define PITCH_LAG_SPAN2 65      /* (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5) */
+#define PITCH_CORR_LEN2 60      /* 15 ms  */
+#define PITCH_CORR_STEP2 60     /* (PITCH_FRAME_LEN/4) */
+#define PITCH_SUBFRAMES 4
+#define PITCH_SUBFRAME_LEN 60 /* (PITCH_FRAME_LEN/PITCH_SUBFRAMES) */
 
 /* For pitch filter */
-#define PITCH_BUFFSIZE                   190  /* (PITCH_MAX_LAG + 50) Extra 50 for fraction and LP filters */
-#define PITCH_INTBUFFSIZE               430  /* (PITCH_FRAME_LEN+PITCH_BUFFSIZE) */
-#define PITCH_FRACS                             8
-#define PITCH_FRACORDER                         9
-#define PITCH_DAMPORDER                         5
-
+#define PITCH_BUFFSIZE \
+  190 /* (PITCH_MAX_LAG + 50) Extra 50 for fraction and LP filters */
+#define PITCH_INTBUFFSIZE 430 /* (PITCH_FRAME_LEN+PITCH_BUFFSIZE) */
+#define PITCH_FRACS 8
+#define PITCH_FRACORDER 9
+#define PITCH_DAMPORDER 5
 
 /* Order of high pass filter */
-#define HPORDER                                 2
-
+#define HPORDER 2
 
 /* PLC */
-#define DECAY_RATE               10               /* Q15, 20% of decay every lost frame apllied linearly sample by sample*/
-#define PLC_WAS_USED              1
-#define PLC_NOT_USED              3
-#define RECOVERY_OVERLAP         80
-#define RESAMP_RES              256
-#define RESAMP_RES_BIT            8
-
-
+#define DECAY_RATE \
+  10 /* Q15, 20% of decay every lost frame apllied linearly sample by sample*/
+#define PLC_WAS_USED 1
+#define PLC_NOT_USED 3
+#define RECOVERY_OVERLAP 80
+#define RESAMP_RES 256
+#define RESAMP_RES_BIT 8
 
 /* Define Error codes */
 /* 6000 General */
-#define ISAC_MEMORY_ALLOCATION_FAILED    6010
-#define ISAC_MODE_MISMATCH       6020
-#define ISAC_DISALLOWED_BOTTLENECK     6030
-#define ISAC_DISALLOWED_FRAME_LENGTH    6040
+#define ISAC_MEMORY_ALLOCATION_FAILED 6010
+#define ISAC_MODE_MISMATCH 6020
+#define ISAC_DISALLOWED_BOTTLENECK 6030
+#define ISAC_DISALLOWED_FRAME_LENGTH 6040
 /* 6200 Bandwidth estimator */
-#define ISAC_RANGE_ERROR_BW_ESTIMATOR    6240
+#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240
 /* 6400 Encoder */
-#define ISAC_ENCODER_NOT_INITIATED     6410
-#define ISAC_DISALLOWED_CODING_MODE     6420
-#define ISAC_DISALLOWED_FRAME_MODE_ENCODER   6430
-#define ISAC_DISALLOWED_BITSTREAM_LENGTH            6440
-#define ISAC_PAYLOAD_LARGER_THAN_LIMIT              6450
+#define ISAC_ENCODER_NOT_INITIATED 6410
+#define ISAC_DISALLOWED_CODING_MODE 6420
+#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430
+#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440
+#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450
 /* 6600 Decoder */
-#define ISAC_DECODER_NOT_INITIATED     6610
-#define ISAC_EMPTY_PACKET       6620
+#define ISAC_DECODER_NOT_INITIATED 6610
+#define ISAC_EMPTY_PACKET 6620
 #define ISAC_PACKET_TOO_SHORT 6625
-#define ISAC_DISALLOWED_FRAME_MODE_DECODER   6630
-#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH  6640
-#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH   6650
-#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN   6660
-#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG   6670
-#define ISAC_RANGE_ERROR_DECODE_LPC     6680
-#define ISAC_RANGE_ERROR_DECODE_SPECTRUM   6690
-#define ISAC_LENGTH_MISMATCH      6730
+#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630
+#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640
+#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650
+#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660
+#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670
+#define ISAC_RANGE_ERROR_DECODE_LPC 6680
+#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690
+#define ISAC_LENGTH_MISMATCH 6730
 /* 6800 Call setup formats */
-#define ISAC_INCOMPATIBLE_FORMATS     6810
-
+#define ISAC_INCOMPATIBLE_FORMATS 6810
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SETTINGS_H_ */
diff --git a/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.h b/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.h
index 04fddf5..4ac5c0b 100644
--- a/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.h
+++ b/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.h
@@ -62,15 +62,15 @@
 /* quantization boundary levels for reflection coefficients */
 extern const int16_t WebRtcIsacfix_kRcBound[12];
 
-/* initial indices for AR reflection coefficient quantizer and cdf table search */
+/* initial indices for AR reflection coefficient quantizer and cdf table search
+ */
 extern const uint16_t WebRtcIsacfix_kRcInitInd[AR_ORDER];
 
 /* pointers to AR cdf tables */
-extern const uint16_t *WebRtcIsacfix_kRcCdfPtr[AR_ORDER];
+extern const uint16_t* WebRtcIsacfix_kRcCdfPtr[AR_ORDER];
 
 /* pointers to AR representation levels tables */
-extern const int16_t *WebRtcIsacfix_kRcLevPtr[AR_ORDER];
-
+extern const int16_t* WebRtcIsacfix_kRcLevPtr[AR_ORDER];
 
 /******************** GAIN Coefficient Tables ***********************/
 /* cdf for Gain coefficient */
@@ -83,7 +83,7 @@
 extern const int32_t WebRtcIsacfix_kGain2Bound[19];
 
 /* pointer to Gain cdf table */
-extern const uint16_t *WebRtcIsacfix_kGainPtr[1];
+extern const uint16_t* WebRtcIsacfix_kGainPtr[1];
 
 /* Gain initial index for gain quantizer and cdf table search */
 extern const uint16_t WebRtcIsacfix_kGainInitInd[1];
@@ -92,4 +92,5 @@
 /* Cosine table */
 extern const int16_t WebRtcIsacfix_kCos[6][60];
 
-#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ \
+        */
diff --git a/modules/audio_coding/codecs/isac/fix/source/structs.h b/modules/audio_coding/codecs/isac/fix/source/structs.h
index 7a14e5c..352eef0 100644
--- a/modules/audio_coding/codecs/isac/fix/source/structs.h
+++ b/modules/audio_coding/codecs/isac/fix/source/structs.h
@@ -18,7 +18,6 @@
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_
 
-
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "modules/audio_coding/codecs/isac/bandwidth_info.h"
 #include "modules/audio_coding/codecs/isac/fix/source/settings.h"
@@ -26,72 +25,58 @@
 
 /* Bitstream struct for decoder */
 typedef struct Bitstreamstruct_dec {
-
-  uint16_t  stream[INTERNAL_STREAM_SIZE_W16];  /* Array bytestream to decode */
-  uint32_t  W_upper;          /* Upper boundary of interval W */
-  uint32_t  streamval;
-  uint16_t  stream_index;     /* Index to the current position in bytestream */
-  int16_t   full;             /* 0 - first byte in memory filled, second empty*/
+  uint16_t stream[INTERNAL_STREAM_SIZE_W16]; /* Array bytestream to decode */
+  uint32_t W_upper;                          /* Upper boundary of interval W */
+  uint32_t streamval;
+  uint16_t stream_index; /* Index to the current position in bytestream */
+  int16_t full;          /* 0 - first byte in memory filled, second empty*/
   /* 1 - both bytes are empty (we just filled the previous memory */
 
-  size_t stream_size;  /* The size of stream in bytes. */
+  size_t stream_size; /* The size of stream in bytes. */
 } Bitstr_dec;
 
 /* Bitstream struct for encoder */
 typedef struct Bitstreamstruct_enc {
-
-  uint16_t  stream[STREAM_MAXW16_60MS];   /* Vector for adding encoded bytestream */
-  uint32_t  W_upper;          /* Upper boundary of interval W */
-  uint32_t  streamval;
-  uint16_t  stream_index;     /* Index to the current position in bytestream */
-  int16_t   full;             /* 0 - first byte in memory filled, second empty*/
+  uint16_t
+      stream[STREAM_MAXW16_60MS]; /* Vector for adding encoded bytestream */
+  uint32_t W_upper;               /* Upper boundary of interval W */
+  uint32_t streamval;
+  uint16_t stream_index; /* Index to the current position in bytestream */
+  int16_t full;          /* 0 - first byte in memory filled, second empty*/
   /* 1 - both bytes are empty (we just filled the previous memory */
 
 } Bitstr_enc;
 
-
 typedef struct {
-
   int16_t DataBufferLoQ0[WINLEN];
   int16_t DataBufferHiQ0[WINLEN];
 
-  int32_t CorrBufLoQQ[ORDERLO+1];
-  int32_t CorrBufHiQQ[ORDERHI+1];
+  int32_t CorrBufLoQQ[ORDERLO + 1];
+  int32_t CorrBufHiQQ[ORDERHI + 1];
 
-  int16_t CorrBufLoQdom[ORDERLO+1];
-  int16_t CorrBufHiQdom[ORDERHI+1];
+  int16_t CorrBufLoQdom[ORDERLO + 1];
+  int16_t CorrBufHiQdom[ORDERHI + 1];
 
-  int32_t PreStateLoGQ15[ORDERLO+1];
-  int32_t PreStateHiGQ15[ORDERHI+1];
+  int32_t PreStateLoGQ15[ORDERLO + 1];
+  int32_t PreStateHiGQ15[ORDERHI + 1];
 
   uint32_t OldEnergy;
 
 } MaskFiltstr_enc;
 
-
-
 typedef struct {
-
-  int16_t PostStateLoGQ0[ORDERLO+1];
-  int16_t PostStateHiGQ0[ORDERHI+1];
+  int16_t PostStateLoGQ0[ORDERLO + 1];
+  int16_t PostStateHiGQ0[ORDERHI + 1];
 
   uint32_t OldEnergy;
 
 } MaskFiltstr_dec;
 
-
-
-
-
-
-
-
 typedef struct {
+  // state vectors for each of the two analysis filters
 
-  //state vectors for each of the two analysis filters
-
-  int32_t INSTAT1_fix[2*(QORDER-1)];
-  int32_t INSTAT2_fix[2*(QORDER-1)];
+  int32_t INSTAT1_fix[2 * (QORDER - 1)];
+  int32_t INSTAT2_fix[2 * (QORDER - 1)];
   int16_t INLABUF1_fix[QLOOKAHEAD];
   int16_t INLABUF2_fix[QLOOKAHEAD];
 
@@ -100,12 +85,10 @@
 
 } PreFiltBankstr;
 
-
 typedef struct {
-
-  //state vectors for each of the two analysis filters
-  int32_t STATE_0_LOWER_fix[2*POSTQORDER];
-  int32_t STATE_0_UPPER_fix[2*POSTQORDER];
+  // state vectors for each of the two analysis filters
+  int32_t STATE_0_LOWER_fix[2 * POSTQORDER];
+  int32_t STATE_0_UPPER_fix[2 * POSTQORDER];
 
   /* High pass filter */
 
@@ -115,8 +98,6 @@
 } PostFiltBankstr;
 
 typedef struct {
-
-
   /* data buffer for pitch filter */
   int16_t ubufQQ[PITCH_BUFFSIZE];
 
@@ -129,42 +110,35 @@
 
 } PitchFiltstr;
 
-
-
 typedef struct {
+  // for inital estimator
+  int16_t dec_buffer16[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 -
+                       PITCH_FRAME_LEN / 2 + 2];
+  int32_t decimator_state32[2 * ALLPASSSECTIONS + 1];
+  int16_t inbuf[QLOOKAHEAD];
 
-  //for inital estimator
-  int16_t   dec_buffer16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2];
-  int32_t   decimator_state32[2*ALLPASSSECTIONS+1];
-  int16_t   inbuf[QLOOKAHEAD];
-
-  PitchFiltstr  PFstr_wght;
-  PitchFiltstr  PFstr;
-
+  PitchFiltstr PFstr_wght;
+  PitchFiltstr PFstr;
 
 } PitchAnalysisStruct;
 
-
 typedef struct {
   /* Parameters used in PLC to avoid re-computation       */
 
   /* --- residual signals --- */
-  int16_t prevPitchInvIn[FRAMESAMPLES/2];
-  int16_t prevPitchInvOut[PITCH_MAX_LAG + 10];            // [FRAMESAMPLES/2]; save 90
-  int32_t prevHP[PITCH_MAX_LAG + 10];                     // [FRAMESAMPLES/2]; save 90
-
+  int16_t prevPitchInvIn[FRAMESAMPLES / 2];
+  int16_t prevPitchInvOut[PITCH_MAX_LAG + 10];  // [FRAMESAMPLES/2]; save 90
+  int32_t prevHP[PITCH_MAX_LAG + 10];           // [FRAMESAMPLES/2]; save 90
 
   int16_t decayCoeffPriodic; /* how much to supress a sample */
   int16_t decayCoeffNoise;
-  int16_t used;       /* if PLC is used */
+  int16_t used; /* if PLC is used */
 
-
-  int16_t *lastPitchLP;                                  // [FRAMESAMPLES/2]; saved 240;
-
+  int16_t* lastPitchLP;  // [FRAMESAMPLES/2]; saved 240;
 
   /* --- LPC side info --- */
-  int16_t lofilt_coefQ15[ ORDERLO ];
-  int16_t hifilt_coefQ15[ ORDERHI ];
+  int16_t lofilt_coefQ15[ORDERLO];
+  int16_t hifilt_coefQ15[ORDERHI];
   int32_t gain_lo_hiQ17[2];
 
   /* --- LTP side info --- */
@@ -173,95 +147,101 @@
   int16_t lastPitchLag_Q7;
 
   /* --- Add-overlap in recovery packet --- */
-  int16_t overlapLP[ RECOVERY_OVERLAP ];                 // [FRAMESAMPLES/2]; saved 160
+  int16_t overlapLP[RECOVERY_OVERLAP];  // [FRAMESAMPLES/2]; saved 160
 
   int16_t pitchCycles;
   int16_t A;
   int16_t B;
   size_t pitchIndex;
   size_t stretchLag;
-  int16_t *prevPitchLP;                                  // [ FRAMESAMPLES/2 ]; saved 240
+  int16_t* prevPitchLP;  // [ FRAMESAMPLES/2 ]; saved 240
   int16_t seed;
 
   int16_t std;
 } PLCstr;
 
-
-
 /* Have instance of struct together with other iSAC structs */
 typedef struct {
-
-  int16_t   prevFrameSizeMs;      /* Previous frame size (in ms) */
-  uint16_t  prevRtpNumber;      /* Previous RTP timestamp from received packet */
+  int16_t prevFrameSizeMs; /* Previous frame size (in ms) */
+  uint16_t prevRtpNumber;  /* Previous RTP timestamp from received packet */
   /* (in samples relative beginning)  */
-  uint32_t  prevSendTime;   /* Send time for previous packet, from RTP header */
-  uint32_t  prevArrivalTime;      /* Arrival time for previous packet (in ms using timeGetTime()) */
-  uint16_t  prevRtpRate;          /* rate of previous packet, derived from RTP timestamps (in bits/s) */
-  uint32_t  lastUpdate;           /* Time since the last update of the Bottle Neck estimate (in samples) */
-  uint32_t  lastReduction;        /* Time sinse the last reduction (in samples) */
-  int32_t   countUpdates;         /* How many times the estimate was update in the beginning */
+  uint32_t prevSendTime;    /* Send time for previous packet, from RTP header */
+  uint32_t prevArrivalTime; /* Arrival time for previous packet (in ms using
+                               timeGetTime()) */
+  uint16_t
+      prevRtpRate; /* rate of previous packet, derived from RTP timestamps (in
+                      bits/s) */
+  uint32_t
+      lastUpdate;         /* Time since the last update of the Bottle Neck estimate (in
+                             samples) */
+  uint32_t lastReduction; /* Time sinse the last reduction (in samples) */
+  int32_t countUpdates;   /* How many times the estimate was update in the
+                             beginning */
 
-  /* The estimated bottle neck rate from there to here (in bits/s)                */
-  uint32_t  recBw;
-  uint32_t  recBwInv;
-  uint32_t  recBwAvg;
-  uint32_t  recBwAvgQ;
+  /* The estimated bottle neck rate from there to here (in bits/s) */
+  uint32_t recBw;
+  uint32_t recBwInv;
+  uint32_t recBwAvg;
+  uint32_t recBwAvgQ;
 
-  uint32_t  minBwInv;
-  uint32_t  maxBwInv;
+  uint32_t minBwInv;
+  uint32_t maxBwInv;
 
-  /* The estimated mean absolute jitter value, as seen on this side (in ms)       */
-  int32_t   recJitter;
-  int32_t   recJitterShortTerm;
-  int32_t   recJitterShortTermAbs;
-  int32_t   recMaxDelay;
-  int32_t   recMaxDelayAvgQ;
+  /* The estimated mean absolute jitter value, as seen on this side (in ms) */
+  int32_t recJitter;
+  int32_t recJitterShortTerm;
+  int32_t recJitterShortTermAbs;
+  int32_t recMaxDelay;
+  int32_t recMaxDelayAvgQ;
 
+  int16_t recHeaderRate; /* (assumed) bitrate for headers (bps) */
 
-  int16_t   recHeaderRate;         /* (assumed) bitrate for headers (bps) */
+  uint32_t sendBwAvg; /* The estimated bottle neck rate from here to there (in
+                         bits/s) */
+  int32_t
+      sendMaxDelayAvg; /* The estimated mean absolute jitter value, as seen on
+                          the other siee (in ms)  */
 
-  uint32_t  sendBwAvg;           /* The estimated bottle neck rate from here to there (in bits/s) */
-  int32_t   sendMaxDelayAvg;    /* The estimated mean absolute jitter value, as seen on the other siee (in ms)  */
-
-
-  int16_t   countRecPkts;          /* number of packets received since last update */
-  int16_t   highSpeedRec;        /* flag for marking that a high speed network has been detected downstream */
+  int16_t countRecPkts; /* number of packets received since last update */
+  int16_t highSpeedRec; /* flag for marking that a high speed network has been
+                           detected downstream */
 
   /* number of consecutive pkts sent during which the bwe estimate has
-     remained at a value greater than the downstream threshold for determining highspeed network */
-  int16_t   countHighSpeedRec;
+     remained at a value greater than the downstream threshold for determining
+     highspeed network */
+  int16_t countHighSpeedRec;
 
-  /* flag indicating bwe should not adjust down immediately for very late pckts */
-  int16_t   inWaitPeriod;
+  /* flag indicating bwe should not adjust down immediately for very late pckts
+   */
+  int16_t inWaitPeriod;
 
   /* variable holding the time of the start of a window of time when
      bwe should not adjust down immediately for very late pckts */
-  uint32_t  startWaitPeriod;
+  uint32_t startWaitPeriod;
 
   /* number of consecutive pkts sent during which the bwe estimate has
-     remained at a value greater than the upstream threshold for determining highspeed network */
-  int16_t   countHighSpeedSent;
+     remained at a value greater than the upstream threshold for determining
+     highspeed network */
+  int16_t countHighSpeedSent;
 
-  /* flag indicated the desired number of packets over threshold rate have been sent and
-     bwe will assume the connection is over broadband network */
-  int16_t   highSpeedSend;
+  /* flag indicated the desired number of packets over threshold rate have been
+     sent and bwe will assume the connection is over broadband network */
+  int16_t highSpeedSend;
 
   IsacBandwidthInfo external_bw_info;
 } BwEstimatorstr;
 
-
 typedef struct {
-
   /* boolean, flags if previous packet exceeded B.N. */
-  int16_t    PrevExceed;
+  int16_t PrevExceed;
   /* ms */
-  int16_t    ExceedAgo;
+  int16_t ExceedAgo;
   /* packets left to send in current burst */
-  int16_t    BurstCounter;
+  int16_t BurstCounter;
   /* packets */
-  int16_t    InitCounter;
+  int16_t InitCounter;
   /* ms remaining in buffer when next packet will be sent */
-  int16_t    StillBuffered;
+  int16_t StillBuffered;
 
 } RateModel;
 
@@ -271,112 +251,107 @@
    handle 60 ms of data.
 */
 typedef struct {
-
   /* Used to keep track of if it is first or second part of 60 msec packet */
-  int     startIdx;
+  int startIdx;
 
   /* Frame length in samples */
-  int16_t         framelength;
+  int16_t framelength;
 
   /* Pitch Gain */
-  int16_t   pitchGain_index[2];
+  int16_t pitchGain_index[2];
 
   /* Pitch Lag */
-  int32_t   meanGain[2];
-  int16_t   pitchIndex[PITCH_SUBFRAMES*2];
+  int32_t meanGain[2];
+  int16_t pitchIndex[PITCH_SUBFRAMES * 2];
 
   /* LPC */
-  int32_t         LPCcoeffs_g[12*2]; /* KLT_ORDER_GAIN = 12 */
-  int16_t   LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */
-  int16_t   LPCindex_g[12*2];  /* KLT_ORDER_GAIN = 12 */
+  int32_t LPCcoeffs_g[12 * 2]; /* KLT_ORDER_GAIN = 12 */
+  int16_t LPCindex_s[108 * 2]; /* KLT_ORDER_SHAPE = 108 */
+  int16_t LPCindex_g[12 * 2];  /* KLT_ORDER_GAIN = 12 */
 
   /* Encode Spec */
-  int16_t   fre[FRAMESAMPLES];
-  int16_t   fim[FRAMESAMPLES];
-  int16_t   AvgPitchGain[2];
+  int16_t fre[FRAMESAMPLES];
+  int16_t fim[FRAMESAMPLES];
+  int16_t AvgPitchGain[2];
 
   /* Used in adaptive mode only */
-  int     minBytes;
+  int minBytes;
 
 } IsacSaveEncoderData;
 
 typedef struct {
-
-  Bitstr_enc          bitstr_obj;
-  MaskFiltstr_enc     maskfiltstr_obj;
-  PreFiltBankstr      prefiltbankstr_obj;
-  PitchFiltstr        pitchfiltstr_obj;
+  Bitstr_enc bitstr_obj;
+  MaskFiltstr_enc maskfiltstr_obj;
+  PreFiltBankstr prefiltbankstr_obj;
+  PitchFiltstr pitchfiltstr_obj;
   PitchAnalysisStruct pitchanalysisstr_obj;
-  RateModel           rate_data_obj;
+  RateModel rate_data_obj;
 
-  int16_t         buffer_index;
-  int16_t         current_framesamples;
+  int16_t buffer_index;
+  int16_t current_framesamples;
 
-  int16_t      data_buffer_fix[FRAMESAMPLES]; // the size was MAX_FRAMESAMPLES
+  int16_t data_buffer_fix[FRAMESAMPLES];  // the size was MAX_FRAMESAMPLES
 
-  int16_t         frame_nb;
-  int16_t         BottleNeck;
-  int16_t         MaxDelay;
-  int16_t         new_framelength;
-  int16_t         s2nr;
-  uint16_t        MaxBits;
+  int16_t frame_nb;
+  int16_t BottleNeck;
+  int16_t MaxDelay;
+  int16_t new_framelength;
+  int16_t s2nr;
+  uint16_t MaxBits;
 
-  int16_t         bitstr_seed;
+  int16_t bitstr_seed;
 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
-  PostFiltBankstr     interpolatorstr_obj;
+  PostFiltBankstr interpolatorstr_obj;
 #endif
 
-  IsacSaveEncoderData *SaveEnc_ptr;
-  int16_t         payloadLimitBytes30; /* Maximum allowed number of bits for a 30 msec packet */
-  int16_t         payloadLimitBytes60; /* Maximum allowed number of bits for a 30 msec packet */
-  int16_t         maxPayloadBytes;     /* Maximum allowed number of bits for both 30 and 60 msec packet */
-  int16_t         maxRateInBytes;      /* Maximum allowed rate in bytes per 30 msec packet */
-  int16_t         enforceFrameSize;    /* If set iSAC will never change packet size */
+  IsacSaveEncoderData* SaveEnc_ptr;
+  int16_t payloadLimitBytes30; /* Maximum allowed number of bits for a 30 msec
+                                  packet */
+  int16_t payloadLimitBytes60; /* Maximum allowed number of bits for a 30 msec
+                                  packet */
+  int16_t maxPayloadBytes;     /* Maximum allowed number of bits for both 30 and 60
+                                  msec packet */
+  int16_t maxRateInBytes; /* Maximum allowed rate in bytes per 30 msec packet */
+  int16_t enforceFrameSize; /* If set iSAC will never change packet size */
 
 } IsacFixEncoderInstance;
 
-
 typedef struct {
-
-  Bitstr_dec          bitstr_obj;
-  MaskFiltstr_dec     maskfiltstr_obj;
-  PostFiltBankstr     postfiltbankstr_obj;
-  PitchFiltstr        pitchfiltstr_obj;
-  PLCstr              plcstr_obj;               /* TS; for packet loss concealment */
+  Bitstr_dec bitstr_obj;
+  MaskFiltstr_dec maskfiltstr_obj;
+  PostFiltBankstr postfiltbankstr_obj;
+  PitchFiltstr pitchfiltstr_obj;
+  PLCstr plcstr_obj; /* TS; for packet loss concealment */
 
 #ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED
-  PreFiltBankstr      decimatorstr_obj;
+  PreFiltBankstr decimatorstr_obj;
 #endif
 
 } IsacFixDecoderInstance;
 
-
-
 typedef struct {
-
   IsacFixEncoderInstance ISACenc_obj;
   IsacFixDecoderInstance ISACdec_obj;
-  BwEstimatorstr     bwestimator_obj;
-  int16_t         CodingMode;       /* 0 = adaptive; 1 = instantaneous */
-  int16_t   errorcode;
-  int16_t   initflag;  /* 0 = nothing initiated; 1 = encoder or decoder */
+  BwEstimatorstr bwestimator_obj;
+  int16_t CodingMode; /* 0 = adaptive; 1 = instantaneous */
+  int16_t errorcode;
+  int16_t initflag; /* 0 = nothing initiated; 1 = encoder or decoder */
   /* not initiated; 2 = all initiated */
 } ISACFIX_SubStruct;
 
-
 typedef struct {
-  int32_t   lpcGains[12];     /* 6 lower-band & 6 upper-band we may need to double it for 60*/
+  int32_t lpcGains
+      [12]; /* 6 lower-band & 6 upper-band we may need to double it for 60*/
   /* */
-  uint32_t  W_upper;          /* Upper boundary of interval W */
-  uint32_t  streamval;
-  uint16_t  stream_index;     /* Index to the current position in bytestream */
-  int16_t   full;             /* 0 - first byte in memory filled, second empty*/
+  uint32_t W_upper; /* Upper boundary of interval W */
+  uint32_t streamval;
+  uint16_t stream_index; /* Index to the current position in bytestream */
+  int16_t full;          /* 0 - first byte in memory filled, second empty*/
   /* 1 - both bytes are empty (we just filled the previous memory */
-  uint16_t  beforeLastWord;
-  uint16_t  lastWord;
+  uint16_t beforeLastWord;
+  uint16_t lastWord;
 } transcode_obj;
 
+// Bitstr_enc myBitStr;
 
-//Bitstr_enc myBitStr;
-
-#endif  /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_ */
diff --git a/modules/audio_coding/codecs/isac/fix/source/transform_unittest.cc b/modules/audio_coding/codecs/isac/fix/source/transform_unittest.cc
index 347b049..a058530 100644
--- a/modules/audio_coding/codecs/isac/fix/source/transform_unittest.cc
+++ b/modules/audio_coding/codecs/isac/fix/source/transform_unittest.cc
@@ -12,147 +12,156 @@
 #include "system_wrappers/include/cpu_features_wrapper.h"
 #include "test/gtest.h"
 
-static const int kSamples = FRAMESAMPLES/2;
+static const int kSamples = FRAMESAMPLES / 2;
 static const int32_t spec2time_out_expected_1[kSamples] = {
-  -3366470, -2285227,
-  -3415765, -2310215, -3118030, -2222470, -3030254, -2192091, -3423170,
-  -2216041, -3305541, -2171936, -3195767, -2095779, -3153304, -2157560,
-  -3071167, -2032108, -3101190, -1972016, -3103824, -2089118, -3139811,
-  -1898337, -3102801, -2055082, -3029665, -1854140, -2962586, -1966454,
-  -3071167, -1894588, -2851743, -1917315, -2848087, -1594932, -2799242,
-  -1462184, -2845887, -1437599, -2691776, -1329637, -2770659, -1268491,
-  -2625161, -1578991, -2460299, -1186385, -2365613, -1039354, -2322608,
-  -958518, -2271749, -789860, -2254538, -850308, -2384436, -850959, -2133734,
-  -587678, -2093316, -495115, -1973364, -475177, -1801282, -173507,
-  -1848516, -158015, -1792018, -62648, -1643313, 214746, -1500758, 267077,
-  -1450193, 560521, -1521579, 675283, -1345408, 857559, -1300822, 1116332,
-  -1294533, 1241117, -1070027, 1263503, -983816, 1529821, -1019586,
-  1910421, -955420, 2073688, -836459, 2401105, -653905, 2690474, -731425,
-  2930131, -935234, 3299500, -875978, 3523432, -878906, 3924822, -1081630,
-  4561267, -1203023, 5105274, -1510983, 6052762, -2294646, 7021597,
-  -3108053, 8826736, -4935222, 11678789, -8442713, 18725700, -21526692,
-  25420577, 19589811, -28108666, 12634054, -14483066, 6263217, -9979706,
-  3665661, -7909736, 2531530, -6434896, 1700772, -5525393, 1479473,
-  -4894262, 1231760, -4353044, 1032940, -3786590, 941152, -3331614,
-  665090, -2851619, 830696, -2762201, 958007, -2483118, 788233, -2184965,
-  804825, -1967306, 1007255, -1862474, 920889, -1457506, 755406, -1405841,
-  890230, -1302124, 1161599, -701867, 1154163, -1083366, 1204743, -513581,
-  1547264, -650636, 1493384, -285543, 1771863, -277906, 1841343, -9078,
-  1751863, 230222, 1819578, 207170, 1978972, 398137, 2106468, 552155,
-  1997624, 685213, 2129520, 601078, 2238736, 944591, 2441879, 1194178,
-  2355280, 986124, 2393328, 1049005, 2417944, 1208368, 2489516, 1352023,
-  2572118, 1445283, 2856081, 1532997, 2742279, 1615877, 2915274, 1808036,
-  2856871, 1806936, 3241747, 1622461, 2978558, 1841297, 3010378, 1923666,
-  3271367, 2126700, 3070935, 1956958, 3107588, 2128405, 3288872, 2114911,
-  3315952, 2406651, 3344038, 2370199, 3368980, 2144361, 3305030, 2183803,
-  3401450, 2523102, 3405463, 2452475, 3463355, 2421678, 3551968, 2431949,
-  3477251, 2148125, 3244489, 2174090};
+    -3366470, -2285227, -3415765,  -2310215, -3118030,  -2222470, -3030254,
+    -2192091, -3423170, -2216041,  -3305541, -2171936,  -3195767, -2095779,
+    -3153304, -2157560, -3071167,  -2032108, -3101190,  -1972016, -3103824,
+    -2089118, -3139811, -1898337,  -3102801, -2055082,  -3029665, -1854140,
+    -2962586, -1966454, -3071167,  -1894588, -2851743,  -1917315, -2848087,
+    -1594932, -2799242, -1462184,  -2845887, -1437599,  -2691776, -1329637,
+    -2770659, -1268491, -2625161,  -1578991, -2460299,  -1186385, -2365613,
+    -1039354, -2322608, -958518,   -2271749, -789860,   -2254538, -850308,
+    -2384436, -850959,  -2133734,  -587678,  -2093316,  -495115,  -1973364,
+    -475177,  -1801282, -173507,   -1848516, -158015,   -1792018, -62648,
+    -1643313, 214746,   -1500758,  267077,   -1450193,  560521,   -1521579,
+    675283,   -1345408, 857559,    -1300822, 1116332,   -1294533, 1241117,
+    -1070027, 1263503,  -983816,   1529821,  -1019586,  1910421,  -955420,
+    2073688,  -836459,  2401105,   -653905,  2690474,   -731425,  2930131,
+    -935234,  3299500,  -875978,   3523432,  -878906,   3924822,  -1081630,
+    4561267,  -1203023, 5105274,   -1510983, 6052762,   -2294646, 7021597,
+    -3108053, 8826736,  -4935222,  11678789, -8442713,  18725700, -21526692,
+    25420577, 19589811, -28108666, 12634054, -14483066, 6263217,  -9979706,
+    3665661,  -7909736, 2531530,   -6434896, 1700772,   -5525393, 1479473,
+    -4894262, 1231760,  -4353044,  1032940,  -3786590,  941152,   -3331614,
+    665090,   -2851619, 830696,    -2762201, 958007,    -2483118, 788233,
+    -2184965, 804825,   -1967306,  1007255,  -1862474,  920889,   -1457506,
+    755406,   -1405841, 890230,    -1302124, 1161599,   -701867,  1154163,
+    -1083366, 1204743,  -513581,   1547264,  -650636,   1493384,  -285543,
+    1771863,  -277906,  1841343,   -9078,    1751863,   230222,   1819578,
+    207170,   1978972,  398137,    2106468,  552155,    1997624,  685213,
+    2129520,  601078,   2238736,   944591,   2441879,   1194178,  2355280,
+    986124,   2393328,  1049005,   2417944,  1208368,   2489516,  1352023,
+    2572118,  1445283,  2856081,   1532997,  2742279,   1615877,  2915274,
+    1808036,  2856871,  1806936,   3241747,  1622461,   2978558,  1841297,
+    3010378,  1923666,  3271367,   2126700,  3070935,   1956958,  3107588,
+    2128405,  3288872,  2114911,   3315952,  2406651,   3344038,  2370199,
+    3368980,  2144361,  3305030,   2183803,  3401450,   2523102,  3405463,
+    2452475,  3463355,  2421678,   3551968,  2431949,   3477251,  2148125,
+    3244489,  2174090};
 static const int32_t spec2time_out_expected_2[kSamples] = {
-  1691694, -2499988, -2035547,
-  1060469, 988634, -2044502, -306271, 2041000, 201454, -2289456, 93694,
-  2129427, -369152, -1887834, 860796, 2089102, -929424, -1673956, 1395291,
-  1785651, -1619673, -1380109, 1963449, 1093311, -2111007, -840456,
-  2372786, 578119, -2242702, 89774, 2463304, -132717, -2121480, 643634,
-  2277636, -1125999, -1995858, 1543748, 2227861, -1483779, -1495491,
-  2102642, 1833876, -1920568, -958378, 2485101, 772261, -2454257, -24942,
-  2918714, 136838, -2500453, 816118, 3039735, -746560, -2365815, 1586396,
-  2714951, -1511696, -1942334, 2571792, 2182827, -2325335, -1311543,
-  3055970, 1367220, -2737182, -110626, 3889222, 631008, -3280879, 853066,
-  4122279, -706638, -3334449, 2148311, 3993512, -1846301, -3004894,
-  3426779, 3329522, -3165264, -2242423, 4756866, 2557711, -4131280,
-  -805259, 5702711, 1120592, -4852821, 743664, 6476444, -621186, -5465828,
-  2815787, 6768835, -3017442, -5338409, 5658126, 6838454, -5492288,
-  -4682382, 8874947, 6153814, -8832561, -2649251, 12817398, 4237692,
-  -13000247, 1190661, 18986363, -115738, -19693978, 9908367, 30660381,
-  -10632635, -37962068, 47022884, 89744622, -42087632, 40279224,
-  -88869341, -47542383, 38572364, 10441576, -30339718, -9926740, 19896578,
-  28009, -18886612, -1124047, 13232498, -4150304, -12770551, 2637074,
-  9051831, -6162211, -8713972, 4557937, 5489716, -6862312, -5532349,
-  5415449, 2791310, -6999367, -2790102, 5375806, 546222, -6486452,
-  -821261, 4994973, -1278840, -5645501, 1060484, 3996285, -2503954,
-  -4653629, 2220549, 3036977, -3282133, -3318585, 2780636, 1789880,
-  -4004589, -2041031, 3105373, 574819, -3992722, -971004, 3001703,
-  -676739, -3841508, 417284, 2897970, -1427018, -3058480, 1189948,
-  2210960, -2268992, -2603272, 1949785, 1576172, -2720404, -1891738,
-  2309456, 769178, -2975646, -707150, 2424652, -88039, -2966660, -65452,
-  2320780, -957557, -2798978, 744640, 1879794, -1672081, -2365319,
-  1253309, 1366383, -2204082, -1544367, 1801452, 613828, -2531994,
-  -983847, 2064842, 118326, -2613790, -203220, 2219635, -730341, -2641861,
-  563557, 1765434, -1329916, -2272927, 1037138, 1266725, -1939220,
-  -1588643, 1754528, 816552, -2376303, -1099167, 1864999, 122477,
-  -2422762, -400027, 1889228, -579916, -2490353, 287139, 2011318,
-  -1176657, -2502978, 812896, 1116502, -1940211};
+    1691694,   -2499988, -2035547,  1060469,   988634,    -2044502, -306271,
+    2041000,   201454,   -2289456,  93694,     2129427,   -369152,  -1887834,
+    860796,    2089102,  -929424,   -1673956,  1395291,   1785651,  -1619673,
+    -1380109,  1963449,  1093311,   -2111007,  -840456,   2372786,  578119,
+    -2242702,  89774,    2463304,   -132717,   -2121480,  643634,   2277636,
+    -1125999,  -1995858, 1543748,   2227861,   -1483779,  -1495491, 2102642,
+    1833876,   -1920568, -958378,   2485101,   772261,    -2454257, -24942,
+    2918714,   136838,   -2500453,  816118,    3039735,   -746560,  -2365815,
+    1586396,   2714951,  -1511696,  -1942334,  2571792,   2182827,  -2325335,
+    -1311543,  3055970,  1367220,   -2737182,  -110626,   3889222,  631008,
+    -3280879,  853066,   4122279,   -706638,   -3334449,  2148311,  3993512,
+    -1846301,  -3004894, 3426779,   3329522,   -3165264,  -2242423, 4756866,
+    2557711,   -4131280, -805259,   5702711,   1120592,   -4852821, 743664,
+    6476444,   -621186,  -5465828,  2815787,   6768835,   -3017442, -5338409,
+    5658126,   6838454,  -5492288,  -4682382,  8874947,   6153814,  -8832561,
+    -2649251,  12817398, 4237692,   -13000247, 1190661,   18986363, -115738,
+    -19693978, 9908367,  30660381,  -10632635, -37962068, 47022884, 89744622,
+    -42087632, 40279224, -88869341, -47542383, 38572364,  10441576, -30339718,
+    -9926740,  19896578, 28009,     -18886612, -1124047,  13232498, -4150304,
+    -12770551, 2637074,  9051831,   -6162211,  -8713972,  4557937,  5489716,
+    -6862312,  -5532349, 5415449,   2791310,   -6999367,  -2790102, 5375806,
+    546222,    -6486452, -821261,   4994973,   -1278840,  -5645501, 1060484,
+    3996285,   -2503954, -4653629,  2220549,   3036977,   -3282133, -3318585,
+    2780636,   1789880,  -4004589,  -2041031,  3105373,   574819,   -3992722,
+    -971004,   3001703,  -676739,   -3841508,  417284,    2897970,  -1427018,
+    -3058480,  1189948,  2210960,   -2268992,  -2603272,  1949785,  1576172,
+    -2720404,  -1891738, 2309456,   769178,    -2975646,  -707150,  2424652,
+    -88039,    -2966660, -65452,    2320780,   -957557,   -2798978, 744640,
+    1879794,   -1672081, -2365319,  1253309,   1366383,   -2204082, -1544367,
+    1801452,   613828,   -2531994,  -983847,   2064842,   118326,   -2613790,
+    -203220,   2219635,  -730341,   -2641861,  563557,    1765434,  -1329916,
+    -2272927,  1037138,  1266725,   -1939220,  -1588643,  1754528,  816552,
+    -2376303,  -1099167, 1864999,   122477,    -2422762,  -400027,  1889228,
+    -579916,   -2490353, 287139,    2011318,   -1176657,  -2502978, 812896,
+    1116502,   -1940211};
 static const int16_t time2spec_out_expected_1[kSamples] = {
-  20342, 23889, -10063, -9419,
-  3242, 7280, -2012, -5029, 332, 4478, -97, -3244, -891, 3117, 773, -2204,
-  -1335, 2009, 1236, -1469, -1562, 1277, 1366, -815, -1619, 599, 1449, -177,
-  -1507, 116, 1294, 263, -1338, -244, 1059, 553, -1045, -549, 829, 826,
-  -731, -755, 516, 909, -427, -853, 189, 1004, -184, -828, -108, 888, 72,
-  -700, -280, 717, 342, -611, -534, 601, 534, -374, -646, 399, 567, -171,
-  -720, 234, 645, -11, -712, -26, 593, 215, -643, -172, 536, 361, -527,
-  -403, 388, 550, -361, -480, 208, 623, -206, -585, 41, 578, 12, -504,
-  -182, 583, 218, -437, -339, 499, 263, -354, -450, 347, 456, -193, -524,
-  212, 475, -74, -566, 94, 511, 112, -577, -201, 408, 217, -546, -295, 338,
-  387, -13, 4, -46, 2, -76, 103, -83, 108, -55, 100, -150, 131, -156, 141,
-  -171, 179, -190, 128, -227, 172, -214, 215, -189, 265, -244, 322, -335,
-  337, -352, 358, -368, 362, -355, 366, -381, 403, -395, 411, -392, 446,
-  -458, 504, -449, 507, -464, 452, -491, 481, -534, 486, -516, 560, -535,
-  525, -537, 559, -554, 570, -616, 591, -585, 627, -509, 588, -584, 547,
-  -610, 580, -614, 635, -620, 655, -554, 546, -591, 642, -590, 660, -656,
-  629, -604, 620, -580, 617, -645, 648, -573, 612, -604, 584, -571, 597,
-  -562, 627, -550, 560, -606, 529, -584, 568, -503, 532, -463, 512, -440,
-  399, -457, 437, -349, 278, -317, 257, -220, 163, -8, -61, 18, -161, 367,
-  -1306};
+    20342, 23889, -10063, -9419, 3242,  7280,  -2012, -5029, 332,   4478,
+    -97,   -3244, -891,   3117,  773,   -2204, -1335, 2009,  1236,  -1469,
+    -1562, 1277,  1366,   -815,  -1619, 599,   1449,  -177,  -1507, 116,
+    1294,  263,   -1338,  -244,  1059,  553,   -1045, -549,  829,   826,
+    -731,  -755,  516,    909,   -427,  -853,  189,   1004,  -184,  -828,
+    -108,  888,   72,     -700,  -280,  717,   342,   -611,  -534,  601,
+    534,   -374,  -646,   399,   567,   -171,  -720,  234,   645,   -11,
+    -712,  -26,   593,    215,   -643,  -172,  536,   361,   -527,  -403,
+    388,   550,   -361,   -480,  208,   623,   -206,  -585,  41,    578,
+    12,    -504,  -182,   583,   218,   -437,  -339,  499,   263,   -354,
+    -450,  347,   456,    -193,  -524,  212,   475,   -74,   -566,  94,
+    511,   112,   -577,   -201,  408,   217,   -546,  -295,  338,   387,
+    -13,   4,     -46,    2,     -76,   103,   -83,   108,   -55,   100,
+    -150,  131,   -156,   141,   -171,  179,   -190,  128,   -227,  172,
+    -214,  215,   -189,   265,   -244,  322,   -335,  337,   -352,  358,
+    -368,  362,   -355,   366,   -381,  403,   -395,  411,   -392,  446,
+    -458,  504,   -449,   507,   -464,  452,   -491,  481,   -534,  486,
+    -516,  560,   -535,   525,   -537,  559,   -554,  570,   -616,  591,
+    -585,  627,   -509,   588,   -584,  547,   -610,  580,   -614,  635,
+    -620,  655,   -554,   546,   -591,  642,   -590,  660,   -656,  629,
+    -604,  620,   -580,   617,   -645,  648,   -573,  612,   -604,  584,
+    -571,  597,   -562,   627,   -550,  560,   -606,  529,   -584,  568,
+    -503,  532,   -463,   512,   -440,  399,   -457,  437,   -349,  278,
+    -317,  257,   -220,   163,   -8,    -61,   18,    -161,  367,   -1306};
 static const int16_t time2spec_out_expected_2[kSamples] = {
-  14283, -11552, -15335, 6626,
-  7554, -2150, -6309, 1307, 4523, -4, -3908, -314, 3001, 914, -2715, -1042,
-  2094, 1272, -1715, -1399, 1263, 1508, -1021, -1534, 735, 1595, -439, -1447,
-  155, 1433, 22, -1325, -268, 1205, 424, -1030, -608, 950, 643, -733, -787,
-  661, 861, -502, -888, 331, 852, -144, -849, 19, 833, 99, -826, -154,
-  771, 368, -735, -459, 645, 513, -491, -604, 431, 630, -314, -598, 183,
-  622, -78, -612, -48, 641, 154, -645, -257, 610, 281, -529, -444, 450,
-  441, -327, -506, 274, 476, -232, -570, 117, 554, -86, -531, -21, 572,
-  151, -606, -221, 496, 322, -407, -388, 407, 394, -268, -428, 280, 505,
-  -115, -588, 19, 513, -29, -539, -109, 468, 173, -501, -242, 442, 278,
-  -478, -680, 656, -659, 656, -669, 602, -688, 612, -667, 612, -642, 627,
-  -648, 653, -676, 596, -680, 655, -649, 678, -672, 587, -608, 637, -645,
-  637, -620, 556, -580, 553, -635, 518, -599, 583, -501, 536, -544, 473,
-  -552, 583, -511, 541, -532, 563, -486, 461, -453, 486, -388, 424, -416,
-  432, -374, 399, -462, 364, -346, 293, -329, 331, -313, 281, -247, 309,
-  -337, 241, -190, 207, -194, 179, -163, 155, -156, 117, -135, 107, -126,
-  29, -22, 81, -8, 17, -61, -10, 8, -37, 80, -44, 72, -88, 65, -89, 130,
-  -114, 181, -215, 189, -245, 260, -288, 294, -339, 344, -396, 407, -429,
-  438, -439, 485, -556, 629, -612, 637, -645, 661, -737, 829, -830, 831,
-  -1041};
+    14283, -11552, -15335, 6626,  7554,  -2150, -6309, 1307,  4523,  -4,
+    -3908, -314,   3001,   914,   -2715, -1042, 2094,  1272,  -1715, -1399,
+    1263,  1508,   -1021,  -1534, 735,   1595,  -439,  -1447, 155,   1433,
+    22,    -1325,  -268,   1205,  424,   -1030, -608,  950,   643,   -733,
+    -787,  661,    861,    -502,  -888,  331,   852,   -144,  -849,  19,
+    833,   99,     -826,   -154,  771,   368,   -735,  -459,  645,   513,
+    -491,  -604,   431,    630,   -314,  -598,  183,   622,   -78,   -612,
+    -48,   641,    154,    -645,  -257,  610,   281,   -529,  -444,  450,
+    441,   -327,   -506,   274,   476,   -232,  -570,  117,   554,   -86,
+    -531,  -21,    572,    151,   -606,  -221,  496,   322,   -407,  -388,
+    407,   394,    -268,   -428,  280,   505,   -115,  -588,  19,    513,
+    -29,   -539,   -109,   468,   173,   -501,  -242,  442,   278,   -478,
+    -680,  656,    -659,   656,   -669,  602,   -688,  612,   -667,  612,
+    -642,  627,    -648,   653,   -676,  596,   -680,  655,   -649,  678,
+    -672,  587,    -608,   637,   -645,  637,   -620,  556,   -580,  553,
+    -635,  518,    -599,   583,   -501,  536,   -544,  473,   -552,  583,
+    -511,  541,    -532,   563,   -486,  461,   -453,  486,   -388,  424,
+    -416,  432,    -374,   399,   -462,  364,   -346,  293,   -329,  331,
+    -313,  281,    -247,   309,   -337,  241,   -190,  207,   -194,  179,
+    -163,  155,    -156,   117,   -135,  107,   -126,  29,    -22,   81,
+    -8,    17,     -61,    -10,   8,     -37,   80,    -44,   72,    -88,
+    65,    -89,    130,    -114,  181,   -215,  189,   -245,  260,   -288,
+    294,   -339,   344,    -396,  407,   -429,  438,   -439,  485,   -556,
+    629,   -612,   637,    -645,  661,   -737,  829,   -830,  831,   -1041};
 
 class TransformTest : public testing::Test {
  protected:
-   TransformTest() {
-     WebRtcSpl_Init();
-   }
+  TransformTest() { WebRtcSpl_Init(); }
 
-   // Pass a function pointer to the Tester function.
-   void Time2SpecTester(Time2Spec Time2SpecFunction) {
-     // WebRtcIsacfix_Time2Spec functions hard coded the buffer lengths. It's a
-     // large buffer but we have to test it here.
-     int16_t data_in_1[kSamples] = {0};
-     int16_t data_in_2[kSamples] = {0};
-     int16_t data_out_1[kSamples] = {0};
-     int16_t data_out_2[kSamples] = {0};
+  // Pass a function pointer to the Tester function.
+  void Time2SpecTester(Time2Spec Time2SpecFunction) {
+    // WebRtcIsacfix_Time2Spec functions hard coded the buffer lengths. It's a
+    // large buffer but we have to test it here.
+    int16_t data_in_1[kSamples] = {0};
+    int16_t data_in_2[kSamples] = {0};
+    int16_t data_out_1[kSamples] = {0};
+    int16_t data_out_2[kSamples] = {0};
 
-     for(int i = 0; i < kSamples; i++) {
-       data_in_1[i] = i * i + 1777;
-       data_in_2[i] = WEBRTC_SPL_WORD16_MAX / (i + 1) + 17;
-     }
+    for (int i = 0; i < kSamples; i++) {
+      data_in_1[i] = i * i + 1777;
+      data_in_2[i] = WEBRTC_SPL_WORD16_MAX / (i + 1) + 17;
+    }
 
-     Time2SpecFunction(data_in_1, data_in_2, data_out_1, data_out_2);
+    Time2SpecFunction(data_in_1, data_in_2, data_out_1, data_out_2);
 
-     for (int i = 0; i < kSamples; i++) {
-       // We don't require bit-exact for ARM assembly code.
-       EXPECT_LE(abs(time2spec_out_expected_1[i] - data_out_1[i]), 1);
-       EXPECT_LE(abs(time2spec_out_expected_2[i] - data_out_2[i]), 1);
-     }
-   }
+    for (int i = 0; i < kSamples; i++) {
+      // We don't require bit-exact for ARM assembly code.
+      EXPECT_LE(abs(time2spec_out_expected_1[i] - data_out_1[i]), 1);
+      EXPECT_LE(abs(time2spec_out_expected_2[i] - data_out_2[i]), 1);
+    }
+  }
 
   // Pass a function pointer to the Tester function.
   void Spec2TimeTester(Spec2Time Spec2TimeFunction) {
@@ -162,7 +171,7 @@
     int16_t data_in_2[kSamples] = {0};
     int32_t data_out_1[kSamples] = {0};
     int32_t data_out_2[kSamples] = {0};
-    for(int i = 0; i < kSamples; i++) {
+    for (int i = 0; i < kSamples; i++) {
       data_in_1[i] = i * i + 1777;
       data_in_2[i] = WEBRTC_SPL_WORD16_MAX / (i + 1) + 17;
     }
@@ -175,7 +184,6 @@
       EXPECT_LE(abs(spec2time_out_expected_2[i] - data_out_2[i]), 16);
     }
   }
-
 };
 
 TEST_F(TransformTest, Time2SpecTest) {
diff --git a/modules/audio_coding/codecs/isac/main/include/isac.h b/modules/audio_coding/codecs/isac/main/include/isac.h
index e1ee818..1d7e075 100644
--- a/modules/audio_coding/codecs/isac/main/include/isac.h
+++ b/modules/audio_coding/codecs/isac/main/include/isac.h
@@ -16,709 +16,647 @@
 #include "modules/audio_coding/codecs/isac/bandwidth_info.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
-typedef struct WebRtcISACStruct    ISACStruct;
+typedef struct WebRtcISACStruct ISACStruct;
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
-  /******************************************************************************
-   * WebRtcIsac_AssignSize(...)
-   *
-   * This function returns the size of the ISAC instance, so that the instance
-   * can be created outside iSAC.
-   *
-   * Input:
-   *        - samplingRate      : sampling rate of the input/output audio.
-   *
-   * Output:
-   *        - sizeinbytes       : number of bytes needed to allocate for the
-   *                              instance.
-   *
-   * Return value               : 0 - Ok
-   *                             -1 - Error
-   */
+/******************************************************************************
+ * WebRtcIsac_AssignSize(...)
+ *
+ * This function returns the size of the ISAC instance, so that the instance
+ * can be created outside iSAC.
+ *
+ * Input:
+ *        - samplingRate      : sampling rate of the input/output audio.
+ *
+ * Output:
+ *        - sizeinbytes       : number of bytes needed to allocate for the
+ *                              instance.
+ *
+ * Return value               : 0 - Ok
+ *                             -1 - Error
+ */
 
-  int16_t WebRtcIsac_AssignSize(
-      int* sizeinbytes);
+int16_t WebRtcIsac_AssignSize(int* sizeinbytes);
 
+/******************************************************************************
+ * WebRtcIsac_Assign(...)
+ *
+ * This function assignes the memory already created to the ISAC instance.
+ *
+ * Input:
+ *        - *ISAC_main_inst   : a pointer to the coder instance.
+ *        - samplingRate      : sampling rate of the input/output audio.
+ *        - ISAC_inst_Addr    : the already allocated memory, where we put the
+ *                              iSAC structure.
+ *
+ * Return value               : 0 - Ok
+ *                             -1 - Error
+ */
 
-  /******************************************************************************
-   * WebRtcIsac_Assign(...)
-   *
-   * This function assignes the memory already created to the ISAC instance.
-   *
-   * Input:
-   *        - *ISAC_main_inst   : a pointer to the coder instance.
-   *        - samplingRate      : sampling rate of the input/output audio.
-   *        - ISAC_inst_Addr    : the already allocated memory, where we put the
-   *                              iSAC structure.
-   *
-   * Return value               : 0 - Ok
-   *                             -1 - Error
-   */
+int16_t WebRtcIsac_Assign(ISACStruct** ISAC_main_inst, void* ISAC_inst_Addr);
 
-  int16_t WebRtcIsac_Assign(
-      ISACStruct** ISAC_main_inst,
-      void*        ISAC_inst_Addr);
+/******************************************************************************
+ * WebRtcIsac_Create(...)
+ *
+ * This function creates an ISAC instance, which will contain the state
+ * information for one coding/decoding channel.
+ *
+ * Input:
+ *        - *ISAC_main_inst   : a pointer to the coder instance.
+ *
+ * Return value               : 0 - Ok
+ *                             -1 - Error
+ */
 
+int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst);
 
-  /******************************************************************************
-   * WebRtcIsac_Create(...)
-   *
-   * This function creates an ISAC instance, which will contain the state
-   * information for one coding/decoding channel.
-   *
-   * Input:
-   *        - *ISAC_main_inst   : a pointer to the coder instance.
-   *
-   * Return value               : 0 - Ok
-   *                             -1 - Error
-   */
+/******************************************************************************
+ * WebRtcIsac_Free(...)
+ *
+ * This function frees the ISAC instance created at the beginning.
+ *
+ * Input:
+ *        - ISAC_main_inst    : an ISAC instance.
+ *
+ * Return value               : 0 - Ok
+ *                             -1 - Error
+ */
 
-  int16_t WebRtcIsac_Create(
-      ISACStruct** ISAC_main_inst);
+int16_t WebRtcIsac_Free(ISACStruct* ISAC_main_inst);
 
+/******************************************************************************
+ * WebRtcIsac_EncoderInit(...)
+ *
+ * This function initializes an ISAC instance prior to the encoder calls.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - CodingMode        : 0 -> Bit rate and frame length are
+ *                                automatically adjusted to available bandwidth
+ *                                on transmission channel, just valid if codec
+ *                                is created to work in wideband mode.
+ *                              1 -> User sets a frame length and a target bit
+ *                                rate which is taken as the maximum
+ *                                short-term average bit rate.
+ *
+ * Return value               : 0 - Ok
+ *                             -1 - Error
+ */
 
-  /******************************************************************************
-   * WebRtcIsac_Free(...)
-   *
-   * This function frees the ISAC instance created at the beginning.
-   *
-   * Input:
-   *        - ISAC_main_inst    : an ISAC instance.
-   *
-   * Return value               : 0 - Ok
-   *                             -1 - Error
-   */
+int16_t WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst, int16_t CodingMode);
 
-  int16_t WebRtcIsac_Free(
-      ISACStruct* ISAC_main_inst);
+/******************************************************************************
+ * WebRtcIsac_Encode(...)
+ *
+ * This function encodes 10ms audio blocks and inserts it into a package.
+ * Input speech length has 160 samples if operating at 16 kHz sampling
+ * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the
+ * input audio until the whole frame is buffered then proceeds with encoding.
+ *
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - speechIn          : input speech vector.
+ *
+ * Output:
+ *        - encoded           : the encoded data vector
+ *
+ * Return value:
+ *                            : >0 - Length (in bytes) of coded data
+ *                            :  0 - The buffer didn't reach the chosen
+ *                               frame-size so it keeps buffering speech
+ *                               samples.
+ *                            : -1 - Error
+ */
 
+int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst,
+                      const int16_t* speechIn,
+                      uint8_t* encoded);
 
-  /******************************************************************************
-   * WebRtcIsac_EncoderInit(...)
-   *
-   * This function initializes an ISAC instance prior to the encoder calls.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - CodingMode        : 0 -> Bit rate and frame length are
-   *                                automatically adjusted to available bandwidth
-   *                                on transmission channel, just valid if codec
-   *                                is created to work in wideband mode.
-   *                              1 -> User sets a frame length and a target bit
-   *                                rate which is taken as the maximum
-   *                                short-term average bit rate.
-   *
-   * Return value               : 0 - Ok
-   *                             -1 - Error
-   */
+/******************************************************************************
+ * WebRtcIsac_DecoderInit(...)
+ *
+ * This function initializes an ISAC instance prior to the decoder calls.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ */
 
-  int16_t WebRtcIsac_EncoderInit(
-      ISACStruct* ISAC_main_inst,
-      int16_t CodingMode);
+void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst);
 
+/******************************************************************************
+ * WebRtcIsac_UpdateBwEstimate(...)
+ *
+ * This function updates the estimate of the bandwidth.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - encoded           : encoded ISAC frame(s).
+ *        - packet_size       : size of the packet.
+ *        - rtp_seq_number    : the RTP number of the packet.
+ *        - send_ts           : the RTP send timestamp, given in samples
+ *        - arr_ts            : the arrival time of the packet (from NetEq)
+ *                              in samples.
+ *
+ * Return value               : 0 - Ok
+ *                             -1 - Error
+ */
 
-  /******************************************************************************
-   * WebRtcIsac_Encode(...)
-   *
-   * This function encodes 10ms audio blocks and inserts it into a package.
-   * Input speech length has 160 samples if operating at 16 kHz sampling
-   * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the
-   * input audio until the whole frame is buffered then proceeds with encoding.
-   *
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - speechIn          : input speech vector.
-   *
-   * Output:
-   *        - encoded           : the encoded data vector
-   *
-   * Return value:
-   *                            : >0 - Length (in bytes) of coded data
-   *                            :  0 - The buffer didn't reach the chosen
-   *                               frame-size so it keeps buffering speech
-   *                               samples.
-   *                            : -1 - Error
-   */
+int16_t WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst,
+                                    const uint8_t* encoded,
+                                    size_t packet_size,
+                                    uint16_t rtp_seq_number,
+                                    uint32_t send_ts,
+                                    uint32_t arr_ts);
 
-  int WebRtcIsac_Encode(
-      ISACStruct*        ISAC_main_inst,
-      const int16_t* speechIn,
-      uint8_t* encoded);
+/******************************************************************************
+ * WebRtcIsac_Decode(...)
+ *
+ * This function decodes an ISAC frame. At 16 kHz sampling rate, the length
+ * of the output audio could be either 480 or 960 samples, equivalent to
+ * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the
+ * output audio is 960 samples, which is 30 ms.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - encoded           : encoded ISAC frame(s).
+ *        - len               : bytes in encoded vector.
+ *
+ * Output:
+ *        - decoded           : The decoded vector.
+ *
+ * Return value               : >0 - number of samples in decoded vector.
+ *                              -1 - Error.
+ */
 
+int WebRtcIsac_Decode(ISACStruct* ISAC_main_inst,
+                      const uint8_t* encoded,
+                      size_t len,
+                      int16_t* decoded,
+                      int16_t* speechType);
 
-  /******************************************************************************
-   * WebRtcIsac_DecoderInit(...)
-   *
-   * This function initializes an ISAC instance prior to the decoder calls.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   */
+/******************************************************************************
+ * WebRtcIsac_DecodePlc(...)
+ *
+ * This function conducts PLC for ISAC frame(s). Output speech length
+ * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore,
+ * the output is multiple of 480 samples if operating at 16 kHz and multiple
+ * of 960 if operating at 32 kHz.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - noOfLostFrames    : Number of PLC frames to produce.
+ *
+ * Output:
+ *        - decoded           : The decoded vector.
+ *
+ * Return value               : Number of samples in decoded PLC vector
+ */
 
-  void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst);
+size_t WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst,
+                            int16_t* decoded,
+                            size_t noOfLostFrames);
 
-  /******************************************************************************
-   * WebRtcIsac_UpdateBwEstimate(...)
-   *
-   * This function updates the estimate of the bandwidth.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - encoded           : encoded ISAC frame(s).
-   *        - packet_size       : size of the packet.
-   *        - rtp_seq_number    : the RTP number of the packet.
-   *        - send_ts           : the RTP send timestamp, given in samples
-   *        - arr_ts            : the arrival time of the packet (from NetEq)
-   *                              in samples.
-   *
-   * Return value               : 0 - Ok
-   *                             -1 - Error
-   */
+/******************************************************************************
+ * WebRtcIsac_Control(...)
+ *
+ * This function sets the limit on the short-term average bit-rate and the
+ * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling
+ * rate, an average bit-rate between 10000 to 32000 bps is valid and a
+ * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate
+ * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - rate              : limit on the short-term average bit rate,
+ *                              in bits/second.
+ *        - framesize         : frame-size in millisecond.
+ *
+ * Return value               : 0  - ok
+ *                             -1 - Error
+ */
 
-  int16_t WebRtcIsac_UpdateBwEstimate(
-      ISACStruct*         ISAC_main_inst,
-      const uint8_t* encoded,
-      size_t         packet_size,
-      uint16_t        rtp_seq_number,
-      uint32_t        send_ts,
-      uint32_t        arr_ts);
+int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst,
+                           int32_t rate,
+                           int framesize);
 
+void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
+                                        int bottleneck_bits_per_second);
 
-  /******************************************************************************
-   * WebRtcIsac_Decode(...)
-   *
-   * This function decodes an ISAC frame. At 16 kHz sampling rate, the length
-   * of the output audio could be either 480 or 960 samples, equivalent to
-   * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the
-   * output audio is 960 samples, which is 30 ms.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - encoded           : encoded ISAC frame(s).
-   *        - len               : bytes in encoded vector.
-   *
-   * Output:
-   *        - decoded           : The decoded vector.
-   *
-   * Return value               : >0 - number of samples in decoded vector.
-   *                              -1 - Error.
-   */
+/******************************************************************************
+ * WebRtcIsac_ControlBwe(...)
+ *
+ * This function sets the initial values of bottleneck and frame-size if
+ * iSAC is used in channel-adaptive mode. Therefore, this API is not
+ * applicable if the codec is created to operate in super-wideband mode.
+ *
+ * Through this API, users can enforce a frame-size for all values of
+ * bottleneck. Then iSAC will not automatically change the frame-size.
+ *
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - rateBPS           : initial value of bottleneck in bits/second
+ *                              10000 <= rateBPS <= 56000 is accepted
+ *                              For default bottleneck set rateBPS = 0
+ *        - frameSizeMs       : number of milliseconds per frame (30 or 60)
+ *        - enforceFrameSize  : 1 to enforce the given frame-size through
+ *                              out the adaptation process, 0 to let iSAC
+ *                              change the frame-size if required.
+ *
+ * Return value               : 0  - ok
+ *                             -1 - Error
+ */
 
-  int WebRtcIsac_Decode(
-      ISACStruct*           ISAC_main_inst,
-      const uint8_t* encoded,
-      size_t         len,
-      int16_t*        decoded,
-      int16_t*        speechType);
+int16_t WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst,
+                              int32_t rateBPS,
+                              int frameSizeMs,
+                              int16_t enforceFrameSize);
 
+/******************************************************************************
+ * WebRtcIsac_ReadFrameLen(...)
+ *
+ * This function returns the length of the frame represented in the packet.
+ *
+ * Input:
+ *        - encoded           : Encoded bit-stream
+ *
+ * Output:
+ *        - frameLength       : Length of frame in packet (in samples)
+ *
+ */
 
-  /******************************************************************************
-   * WebRtcIsac_DecodePlc(...)
-   *
-   * This function conducts PLC for ISAC frame(s). Output speech length
-   * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore,
-   * the output is multiple of 480 samples if operating at 16 kHz and multiple
-   * of 960 if operating at 32 kHz.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - noOfLostFrames    : Number of PLC frames to produce.
-   *
-   * Output:
-   *        - decoded           : The decoded vector.
-   *
-   * Return value               : Number of samples in decoded PLC vector
-   */
+int16_t WebRtcIsac_ReadFrameLen(ISACStruct* ISAC_main_inst,
+                                const uint8_t* encoded,
+                                int16_t* frameLength);
 
-  size_t WebRtcIsac_DecodePlc(
-      ISACStruct*  ISAC_main_inst,
-      int16_t* decoded,
-      size_t  noOfLostFrames);
+/******************************************************************************
+ * WebRtcIsac_version(...)
+ *
+ * This function returns the version number.
+ *
+ * Output:
+ *        - version      : Pointer to character string
+ *
+ */
 
+void WebRtcIsac_version(char* version);
 
-  /******************************************************************************
-   * WebRtcIsac_Control(...)
-   *
-   * This function sets the limit on the short-term average bit-rate and the
-   * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling
-   * rate, an average bit-rate between 10000 to 32000 bps is valid and a
-   * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate
-   * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - rate              : limit on the short-term average bit rate,
-   *                              in bits/second.
-   *        - framesize         : frame-size in millisecond.
-   *
-   * Return value               : 0  - ok
-   *                             -1 - Error
-   */
+/******************************************************************************
+ * WebRtcIsac_GetErrorCode(...)
+ *
+ * This function can be used to check the error code of an iSAC instance. When
+ * a function returns -1 a error code will be set for that instance. The
+ * function below extract the code of the last error that occurred in the
+ * specified instance.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance
+ *
+ * Return value               : Error code
+ */
 
-  int16_t WebRtcIsac_Control(
-      ISACStruct*   ISAC_main_inst,
-      int32_t rate,
-      int framesize);
+int16_t WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst);
 
-  void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
-                                          int bottleneck_bits_per_second);
+/****************************************************************************
+ * WebRtcIsac_GetUplinkBw(...)
+ *
+ * This function outputs the target bottleneck of the codec. In
+ * channel-adaptive mode, the target bottleneck is specified through in-band
+ * signalling retreived by bandwidth estimator.
+ * In channel-independent, also called instantaneous mode, the target
+ * bottleneck is provided to the encoder by calling xxx_control(...). If
+ * xxx_control is never called the default values is returned. The default
+ * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec,
+ * and it is 56000 bits/sec for 32 kHz sampling rate.
+ * Note that the output is the iSAC internal operating bottleneck which might
+ * differ slightly from the one provided through xxx_control().
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *
+ * Output:
+ *        - *bottleneck       : bottleneck in bits/sec
+ *
+ * Return value               : -1 if error happens
+ *                               0 bit-rates computed correctly.
+ */
 
-  /******************************************************************************
-   * WebRtcIsac_ControlBwe(...)
-   *
-   * This function sets the initial values of bottleneck and frame-size if
-   * iSAC is used in channel-adaptive mode. Therefore, this API is not
-   * applicable if the codec is created to operate in super-wideband mode.
-   *
-   * Through this API, users can enforce a frame-size for all values of
-   * bottleneck. Then iSAC will not automatically change the frame-size.
-   *
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - rateBPS           : initial value of bottleneck in bits/second
-   *                              10000 <= rateBPS <= 56000 is accepted
-   *                              For default bottleneck set rateBPS = 0
-   *        - frameSizeMs       : number of milliseconds per frame (30 or 60)
-   *        - enforceFrameSize  : 1 to enforce the given frame-size through
-   *                              out the adaptation process, 0 to let iSAC
-   *                              change the frame-size if required.
-   *
-   * Return value               : 0  - ok
-   *                             -1 - Error
-   */
+int16_t WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst, int32_t* bottleneck);
 
-  int16_t WebRtcIsac_ControlBwe(
-      ISACStruct* ISAC_main_inst,
-      int32_t rateBPS,
-      int frameSizeMs,
-      int16_t enforceFrameSize);
+/******************************************************************************
+ * WebRtcIsac_SetMaxPayloadSize(...)
+ *
+ * This function sets a limit for the maximum payload size of iSAC. The same
+ * value is used both for 30 and 60 ms packets. If the encoder sampling rate
+ * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
+ * encoder sampling rate is 32 kHz the maximum payload size is between 120
+ * and 600 bytes.
+ *
+ * If an out of range limit is used, the function returns -1, but the closest
+ * valid value will be applied.
+ *
+ * ---------------
+ * IMPORTANT NOTES
+ * ---------------
+ * The size of a packet is limited to the minimum of 'max-payload-size' and
+ * 'max-rate.' For instance, let's assume the max-payload-size is set to
+ * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
+ * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
+ * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
+ * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
+ * 170 bytes, i.e. min(170, 300).
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *        - maxPayloadBytes   : maximum size of the payload in bytes
+ *                              valid values are between 120 and 400 bytes
+ *                              if encoder sampling rate is 16 kHz. For
+ *                              32 kHz encoder sampling rate valid values
+ *                              are between 120 and 600 bytes.
+ *
+ * Return value               : 0 if successful
+ *                             -1 if error happens
+ */
 
+int16_t WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst,
+                                     int16_t maxPayloadBytes);
 
-  /******************************************************************************
-   * WebRtcIsac_ReadFrameLen(...)
-   *
-   * This function returns the length of the frame represented in the packet.
-   *
-   * Input:
-   *        - encoded           : Encoded bit-stream
-   *
-   * Output:
-   *        - frameLength       : Length of frame in packet (in samples)
-   *
-   */
-
-  int16_t WebRtcIsac_ReadFrameLen(
-      ISACStruct*          ISAC_main_inst,
-      const uint8_t* encoded,
-      int16_t*       frameLength);
-
-
-  /******************************************************************************
-   * WebRtcIsac_version(...)
-   *
-   * This function returns the version number.
-   *
-   * Output:
-   *        - version      : Pointer to character string
-   *
-   */
-
-  void WebRtcIsac_version(
-      char *version);
-
-
-  /******************************************************************************
-   * WebRtcIsac_GetErrorCode(...)
-   *
-   * This function can be used to check the error code of an iSAC instance. When
-   * a function returns -1 a error code will be set for that instance. The
-   * function below extract the code of the last error that occurred in the
-   * specified instance.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance
-   *
-   * Return value               : Error code
-   */
-
-  int16_t WebRtcIsac_GetErrorCode(
-      ISACStruct* ISAC_main_inst);
-
-
-  /****************************************************************************
-   * WebRtcIsac_GetUplinkBw(...)
-   *
-   * This function outputs the target bottleneck of the codec. In
-   * channel-adaptive mode, the target bottleneck is specified through in-band
-   * signalling retreived by bandwidth estimator.
-   * In channel-independent, also called instantaneous mode, the target
-   * bottleneck is provided to the encoder by calling xxx_control(...). If
-   * xxx_control is never called the default values is returned. The default
-   * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec,
-   * and it is 56000 bits/sec for 32 kHz sampling rate.
-   * Note that the output is the iSAC internal operating bottleneck which might
-   * differ slightly from the one provided through xxx_control().
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *
-   * Output:
-   *        - *bottleneck       : bottleneck in bits/sec
-   *
-   * Return value               : -1 if error happens
-   *                               0 bit-rates computed correctly.
-   */
-
-  int16_t WebRtcIsac_GetUplinkBw(
-      ISACStruct*    ISAC_main_inst,
-      int32_t* bottleneck);
-
-
-  /******************************************************************************
-   * WebRtcIsac_SetMaxPayloadSize(...)
-   *
-   * This function sets a limit for the maximum payload size of iSAC. The same
-   * value is used both for 30 and 60 ms packets. If the encoder sampling rate
-   * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
-   * encoder sampling rate is 32 kHz the maximum payload size is between 120
-   * and 600 bytes.
-   *
-   * If an out of range limit is used, the function returns -1, but the closest
-   * valid value will be applied.
-   *
-   * ---------------
-   * IMPORTANT NOTES
-   * ---------------
-   * The size of a packet is limited to the minimum of 'max-payload-size' and
-   * 'max-rate.' For instance, let's assume the max-payload-size is set to
-   * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
-   * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
-   * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
-   * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
-   * 170 bytes, i.e. min(170, 300).
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *        - maxPayloadBytes   : maximum size of the payload in bytes
-   *                              valid values are between 120 and 400 bytes
-   *                              if encoder sampling rate is 16 kHz. For
-   *                              32 kHz encoder sampling rate valid values
-   *                              are between 120 and 600 bytes.
-   *
-   * Return value               : 0 if successful
-   *                             -1 if error happens
-   */
-
-  int16_t WebRtcIsac_SetMaxPayloadSize(
-      ISACStruct* ISAC_main_inst,
-      int16_t maxPayloadBytes);
-
-
-  /******************************************************************************
-   * WebRtcIsac_SetMaxRate(...)
-   *
-   * This function sets the maximum rate which the codec may not exceed for
-   * any signal packet. The maximum rate is defined and payload-size per
-   * frame-size in bits per second.
-   *
-   * The codec has a maximum rate of 53400 bits per second (200 bytes per 30
-   * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
-   * if the encoder sampling rate is 32 kHz.
-   *
-   * It is possible to set a maximum rate between 32000 and 53400 bits/sec
-   * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
-   *
-   * If an out of range limit is used, the function returns -1, but the closest
-   * valid value will be applied.
-   *
-   * ---------------
-   * IMPORTANT NOTES
-   * ---------------
-   * The size of a packet is limited to the minimum of 'max-payload-size' and
-   * 'max-rate.' For instance, let's assume the max-payload-size is set to
-   * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
-   * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
-   * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
-   * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
-   * 170 bytes, min(170, 300).
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *        - maxRate           : maximum rate in bits per second,
-   *                              valid values are 32000 to 53400 bits/sec in
-   *                              wideband mode, and 32000 to 160000 bits/sec in
-   *                              super-wideband mode.
-   *
-   * Return value               : 0 if successful
-   *                             -1 if error happens
-   */
-
-  int16_t WebRtcIsac_SetMaxRate(
-      ISACStruct* ISAC_main_inst,
-      int32_t maxRate);
-
-
-  /******************************************************************************
-   * WebRtcIsac_DecSampRate()
-   * Return the sampling rate of the decoded audio.
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *
-   * Return value               : sampling frequency in Hertz.
-   *
-   */
-
-  uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst);
-
-
-  /******************************************************************************
-   * WebRtcIsac_EncSampRate()
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *
-   * Return value               : sampling rate in Hertz.
-   *
-   */
-
-  uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst);
-
-
-  /******************************************************************************
-   * WebRtcIsac_SetDecSampRate()
-   * Set the sampling rate of the decoder.  Initialization of the decoder WILL
-   * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
-   * which is set when the instance is created.
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *        - sampRate          : sampling rate in Hertz.
-   *
-   * Return value               : 0 if successful
-   *                             -1 if failed.
-   */
-
-  int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
-                                          uint16_t samp_rate_hz);
-
-
-  /******************************************************************************
-   * WebRtcIsac_SetEncSampRate()
-   * Set the sampling rate of the encoder. Initialization of the encoder WILL
-   * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
-   * which is set when the instance is created. The encoding-mode and the
-   * bottleneck remain unchanged by this call, however, the maximum rate and
-   * maximum payload-size will reset to their default value.
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC instance
-   *        - sampRate          : sampling rate in Hertz.
-   *
-   * Return value               : 0 if successful
-   *                             -1 if failed.
-   */
-
-  int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
-                                          uint16_t sample_rate_hz);
-
+/******************************************************************************
+ * WebRtcIsac_SetMaxRate(...)
+ *
+ * This function sets the maximum rate which the codec may not exceed for
+ * any signal packet. The maximum rate is defined and payload-size per
+ * frame-size in bits per second.
+ *
+ * The codec has a maximum rate of 53400 bits per second (200 bytes per 30
+ * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
+ * if the encoder sampling rate is 32 kHz.
+ *
+ * It is possible to set a maximum rate between 32000 and 53400 bits/sec
+ * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
+ *
+ * If an out of range limit is used, the function returns -1, but the closest
+ * valid value will be applied.
+ *
+ * ---------------
+ * IMPORTANT NOTES
+ * ---------------
+ * The size of a packet is limited to the minimum of 'max-payload-size' and
+ * 'max-rate.' For instance, let's assume the max-payload-size is set to
+ * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
+ * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
+ * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
+ * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
+ * 170 bytes, min(170, 300).
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *        - maxRate           : maximum rate in bits per second,
+ *                              valid values are 32000 to 53400 bits/sec in
+ *                              wideband mode, and 32000 to 160000 bits/sec in
+ *                              super-wideband mode.
+ *
+ * Return value               : 0 if successful
+ *                             -1 if error happens
+ */
 
+int16_t WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst, int32_t maxRate);
 
-  /******************************************************************************
-   * WebRtcIsac_GetNewBitStream(...)
-   *
-   * This function returns encoded data, with the recieved bwe-index in the
-   * stream. If the rate is set to a value less than bottleneck of codec
-   * the new bistream will be re-encoded with the given target rate.
-   * It should always return a complete packet, i.e. only called once
-   * even for 60 msec frames.
-   *
-   * NOTE 1! This function does not write in the ISACStruct, it is not allowed.
-   * NOTE 2! Currently not implemented for SWB mode.
-   * NOTE 3! Rates larger than the bottleneck of the codec will be limited
-   *         to the current bottleneck.
-   *
-   * Input:
-   *        - ISAC_main_inst    : ISAC instance.
-   *        - bweIndex          : Index of bandwidth estimate to put in new
-   *                              bitstream
-   *        - rate              : target rate of the transcoder is bits/sec.
-   *                              Valid values are the accepted rate in iSAC,
-   *                              i.e. 10000 to 56000.
-   *        - isRCU                       : if the new bit-stream is an RCU stream.
-   *                              Note that the rate parameter always indicates
-   *                              the target rate of the main payload, regardless
-   *                              of 'isRCU' value.
-   *
-   * Output:
-   *        - encoded           : The encoded data vector
-   *
-   * Return value               : >0 - Length (in bytes) of coded data
-   *                              -1 - Error  or called in SWB mode
-   *                                 NOTE! No error code is written to
-   *                                 the struct since it is only allowed to read
-   *                                 the struct.
-   */
-  int16_t WebRtcIsac_GetNewBitStream(
-      ISACStruct*    ISAC_main_inst,
-      int16_t  bweIndex,
-      int16_t  jitterInfo,
-      int32_t  rate,
-      uint8_t* encoded,
-      int16_t  isRCU);
+/******************************************************************************
+ * WebRtcIsac_DecSampRate()
+ * Return the sampling rate of the decoded audio.
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *
+ * Return value               : sampling frequency in Hertz.
+ *
+ */
 
+uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst);
 
+/******************************************************************************
+ * WebRtcIsac_EncSampRate()
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *
+ * Return value               : sampling rate in Hertz.
+ *
+ */
 
-  /****************************************************************************
-   * WebRtcIsac_GetDownLinkBwIndex(...)
-   *
-   * This function returns index representing the Bandwidth estimate from
-   * other side to this side.
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC struct
-   *
-   * Output:
-   *        - bweIndex          : Bandwidth estimate to transmit to other side.
-   *
-   */
+uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst);
 
-  int16_t WebRtcIsac_GetDownLinkBwIndex(
-      ISACStruct*  ISAC_main_inst,
-      int16_t* bweIndex,
-      int16_t* jitterInfo);
+/******************************************************************************
+ * WebRtcIsac_SetDecSampRate()
+ * Set the sampling rate of the decoder.  Initialization of the decoder WILL
+ * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
+ * which is set when the instance is created.
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *        - sampRate          : sampling rate in Hertz.
+ *
+ * Return value               : 0 if successful
+ *                             -1 if failed.
+ */
 
+int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
+                                  uint16_t samp_rate_hz);
 
-  /****************************************************************************
-   * WebRtcIsac_UpdateUplinkBw(...)
-   *
-   * This function takes an index representing the Bandwidth estimate from
-   * this side to other side and updates BWE.
-   *
-   * Input:
-   *        - ISAC_main_inst    : iSAC struct
-   *        - bweIndex          : Bandwidth estimate from other side.
-   *
-   */
+/******************************************************************************
+ * WebRtcIsac_SetEncSampRate()
+ * Set the sampling rate of the encoder. Initialization of the encoder WILL
+ * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
+ * which is set when the instance is created. The encoding-mode and the
+ * bottleneck remain unchanged by this call, however, the maximum rate and
+ * maximum payload-size will reset to their default value.
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC instance
+ *        - sampRate          : sampling rate in Hertz.
+ *
+ * Return value               : 0 if successful
+ *                             -1 if failed.
+ */
 
-  int16_t WebRtcIsac_UpdateUplinkBw(
-      ISACStruct* ISAC_main_inst,
-      int16_t bweIndex);
+int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
+                                  uint16_t sample_rate_hz);
 
+/******************************************************************************
+ * WebRtcIsac_GetNewBitStream(...)
+ *
+ * This function returns encoded data, with the recieved bwe-index in the
+ * stream. If the rate is set to a value less than bottleneck of codec
+ * the new bistream will be re-encoded with the given target rate.
+ * It should always return a complete packet, i.e. only called once
+ * even for 60 msec frames.
+ *
+ * NOTE 1! This function does not write in the ISACStruct, it is not allowed.
+ * NOTE 2! Currently not implemented for SWB mode.
+ * NOTE 3! Rates larger than the bottleneck of the codec will be limited
+ *         to the current bottleneck.
+ *
+ * Input:
+ *        - ISAC_main_inst    : ISAC instance.
+ *        - bweIndex          : Index of bandwidth estimate to put in new
+ *                              bitstream
+ *        - rate              : target rate of the transcoder is bits/sec.
+ *                              Valid values are the accepted rate in iSAC,
+ *                              i.e. 10000 to 56000.
+ *        - isRCU                       : if the new bit-stream is an RCU
+ * stream. Note that the rate parameter always indicates the target rate of the
+ * main payload, regardless of 'isRCU' value.
+ *
+ * Output:
+ *        - encoded           : The encoded data vector
+ *
+ * Return value               : >0 - Length (in bytes) of coded data
+ *                              -1 - Error  or called in SWB mode
+ *                                 NOTE! No error code is written to
+ *                                 the struct since it is only allowed to read
+ *                                 the struct.
+ */
+int16_t WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst,
+                                   int16_t bweIndex,
+                                   int16_t jitterInfo,
+                                   int32_t rate,
+                                   uint8_t* encoded,
+                                   int16_t isRCU);
 
-  /****************************************************************************
-   * WebRtcIsac_ReadBwIndex(...)
-   *
-   * This function returns the index of the Bandwidth estimate from the bitstream.
-   *
-   * Input:
-   *        - encoded           : Encoded bitstream
-   *
-   * Output:
-   *        - frameLength       : Length of frame in packet (in samples)
-   *        - bweIndex         : Bandwidth estimate in bitstream
-   *
-   */
+/****************************************************************************
+ * WebRtcIsac_GetDownLinkBwIndex(...)
+ *
+ * This function returns index representing the Bandwidth estimate from
+ * other side to this side.
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC struct
+ *
+ * Output:
+ *        - bweIndex          : Bandwidth estimate to transmit to other side.
+ *
+ */
 
-  int16_t WebRtcIsac_ReadBwIndex(
-      const uint8_t* encoded,
-      int16_t*       bweIndex);
+int16_t WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst,
+                                      int16_t* bweIndex,
+                                      int16_t* jitterInfo);
 
+/****************************************************************************
+ * WebRtcIsac_UpdateUplinkBw(...)
+ *
+ * This function takes an index representing the Bandwidth estimate from
+ * this side to other side and updates BWE.
+ *
+ * Input:
+ *        - ISAC_main_inst    : iSAC struct
+ *        - bweIndex          : Bandwidth estimate from other side.
+ *
+ */
 
+int16_t WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst, int16_t bweIndex);
 
-  /*******************************************************************************
-   * WebRtcIsac_GetNewFrameLen(...)
-   *
-   * returns the frame lenght (in samples) of the next packet. In the case of channel-adaptive
-   * mode, iSAC decides on its frame lenght based on the estimated bottleneck
-   * this allows a user to prepare for the next packet (at the encoder)
-   *
-   * The primary usage is in CE to make the iSAC works in channel-adaptive mode
-   *
-   * Input:
-   *        - ISAC_main_inst     : iSAC struct
-   *
-   * Return Value                : frame lenght in samples
-   *
-   */
+/****************************************************************************
+ * WebRtcIsac_ReadBwIndex(...)
+ *
+ * This function returns the index of the Bandwidth estimate from the bitstream.
+ *
+ * Input:
+ *        - encoded           : Encoded bitstream
+ *
+ * Output:
+ *        - frameLength       : Length of frame in packet (in samples)
+ *        - bweIndex         : Bandwidth estimate in bitstream
+ *
+ */
 
-  int16_t WebRtcIsac_GetNewFrameLen(
-      ISACStruct* ISAC_main_inst);
+int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded, int16_t* bweIndex);
 
+/*******************************************************************************
+ * WebRtcIsac_GetNewFrameLen(...)
+ *
+ * returns the frame lenght (in samples) of the next packet. In the case of
+ * channel-adaptive mode, iSAC decides on its frame lenght based on the
+ * estimated bottleneck this allows a user to prepare for the next packet (at
+ * the encoder)
+ *
+ * The primary usage is in CE to make the iSAC works in channel-adaptive mode
+ *
+ * Input:
+ *        - ISAC_main_inst     : iSAC struct
+ *
+ * Return Value                : frame lenght in samples
+ *
+ */
 
-  /****************************************************************************
-   *  WebRtcIsac_GetRedPayload(...)
-   *
-   *  Populates "encoded" with the redundant payload of the recently encoded
-   *  frame. This function has to be called once that WebRtcIsac_Encode(...)
-   *  returns a positive value. Regardless of the frame-size this function will
-   *  be called only once after encoding is completed.
-   *
-   * Input:
-   *      - ISAC_main_inst    : iSAC struct
-   *
-   * Output:
-   *        - encoded            : the encoded data vector
-   *
-   *
-   * Return value:
-   *                              : >0 - Length (in bytes) of coded data
-   *                              : -1 - Error
-   *
-   *
-   */
-  int16_t WebRtcIsac_GetRedPayload(
-      ISACStruct*    ISAC_main_inst,
-      uint8_t* encoded);
+int16_t WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst);
 
+/****************************************************************************
+ *  WebRtcIsac_GetRedPayload(...)
+ *
+ *  Populates "encoded" with the redundant payload of the recently encoded
+ *  frame. This function has to be called once that WebRtcIsac_Encode(...)
+ *  returns a positive value. Regardless of the frame-size this function will
+ *  be called only once after encoding is completed.
+ *
+ * Input:
+ *      - ISAC_main_inst    : iSAC struct
+ *
+ * Output:
+ *        - encoded            : the encoded data vector
+ *
+ *
+ * Return value:
+ *                              : >0 - Length (in bytes) of coded data
+ *                              : -1 - Error
+ *
+ *
+ */
+int16_t WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst, uint8_t* encoded);
 
-  /****************************************************************************
-   * WebRtcIsac_DecodeRcu(...)
-   *
-   * This function decodes a redundant (RCU) iSAC frame. Function is called in
-   * NetEq with a stored RCU payload i case of packet loss. Output speech length
-   * will be a multiple of 480 samples: 480 or 960 samples,
-   * depending on the framesize (30 or 60 ms).
-   *
-   * Input:
-   *      - ISAC_main_inst     : ISAC instance.
-   *      - encoded            : encoded ISAC RCU frame(s)
-   *      - len                : bytes in encoded vector
-   *
-   * Output:
-   *      - decoded            : The decoded vector
-   *
-   * Return value              : >0 - number of samples in decoded vector
-   *                             -1 - Error
-   */
-  int WebRtcIsac_DecodeRcu(
-      ISACStruct*           ISAC_main_inst,
-      const uint8_t* encoded,
-      size_t         len,
-      int16_t*        decoded,
-      int16_t*        speechType);
+/****************************************************************************
+ * WebRtcIsac_DecodeRcu(...)
+ *
+ * This function decodes a redundant (RCU) iSAC frame. Function is called in
+ * NetEq with a stored RCU payload i case of packet loss. Output speech length
+ * will be a multiple of 480 samples: 480 or 960 samples,
+ * depending on the framesize (30 or 60 ms).
+ *
+ * Input:
+ *      - ISAC_main_inst     : ISAC instance.
+ *      - encoded            : encoded ISAC RCU frame(s)
+ *      - len                : bytes in encoded vector
+ *
+ * Output:
+ *      - decoded            : The decoded vector
+ *
+ * Return value              : >0 - number of samples in decoded vector
+ *                             -1 - Error
+ */
+int WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst,
+                         const uint8_t* encoded,
+                         size_t len,
+                         int16_t* decoded,
+                         int16_t* speechType);
 
-  /* Fills in an IsacBandwidthInfo struct. |inst| should be a decoder. */
-  void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst, IsacBandwidthInfo* bwinfo);
+/* Fills in an IsacBandwidthInfo struct. |inst| should be a decoder. */
+void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst, IsacBandwidthInfo* bwinfo);
 
-  /* Uses the values from an IsacBandwidthInfo struct. |inst| should be an
-     encoder. */
-  void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
-                                   const IsacBandwidthInfo* bwinfo);
+/* Uses the values from an IsacBandwidthInfo struct. |inst| should be an
+   encoder. */
+void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
+                                 const IsacBandwidthInfo* bwinfo);
 
-  /* If |inst| is a decoder but not an encoder: tell it what sample rate the
-     encoder is using, for bandwidth estimation purposes. */
-  void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz);
+/* If |inst| is a decoder but not an encoder: tell it what sample rate the
+   encoder is using, for bandwidth estimation purposes. */
+void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz);
 
 #if defined(__cplusplus)
 }
 #endif
 
-
-
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/arith_routines.h b/modules/audio_coding/codecs/isac/main/source/arith_routines.h
index d001c68..6e7ea1d 100644
--- a/modules/audio_coding/codecs/isac/main/source/arith_routines.h
+++ b/modules/audio_coding/codecs/isac/main/source/arith_routines.h
@@ -21,42 +21,47 @@
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 
 int WebRtcIsac_EncLogisticMulti2(
-    Bitstr *streamdata,              /* in-/output struct containing bitstream */
-    int16_t *dataQ7,           /* input: data vector */
-    const uint16_t *env,       /* input: side info vector defining the width of the pdf */
-    const int N,                     /* input: data vector length */
+    Bitstr* streamdata, /* in-/output struct containing bitstream */
+    int16_t* dataQ7,    /* input: data vector */
+    const uint16_t*
+        env,     /* input: side info vector defining the width of the pdf */
+    const int N, /* input: data vector length */
     const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
 
 /* returns the number of bytes in the stream */
-int WebRtcIsac_EncTerminate(Bitstr *streamdata); /* in-/output struct containing bitstream */
+int WebRtcIsac_EncTerminate(
+    Bitstr* streamdata); /* in-/output struct containing bitstream */
 
 /* returns the number of bytes in the stream so far */
 int WebRtcIsac_DecLogisticMulti2(
-    int16_t *data,             /* output: data vector */
-    Bitstr *streamdata,              /* in-/output struct containing bitstream */
-    const uint16_t *env,       /* input: side info vector defining the width of the pdf */
-    const int16_t *dither,     /* input: dither vector */
-    const int N,                     /* input: data vector length */
+    int16_t* data,      /* output: data vector */
+    Bitstr* streamdata, /* in-/output struct containing bitstream */
+    const uint16_t*
+        env, /* input: side info vector defining the width of the pdf */
+    const int16_t* dither,     /* input: dither vector */
+    const int N,               /* input: data vector length */
     const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
 
 void WebRtcIsac_EncHistMulti(
-    Bitstr *streamdata,         /* in-/output struct containing bitstream */
-    const int *data,            /* input: data vector */
-    const uint16_t *const *cdf, /* input: array of cdf arrays */
+    Bitstr* streamdata,         /* in-/output struct containing bitstream */
+    const int* data,            /* input: data vector */
+    const uint16_t* const* cdf, /* input: array of cdf arrays */
     const int N);               /* input: data vector length */
 
 int WebRtcIsac_DecHistBisectMulti(
-    int *data,                      /* output: data vector */
-    Bitstr *streamdata,             /* in-/output struct containing bitstream */
-    const uint16_t *const *cdf,     /* input: array of cdf arrays */
-    const uint16_t *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
-    const int N);                   /* input: data vector length */
+    int* data,                  /* output: data vector */
+    Bitstr* streamdata,         /* in-/output struct containing bitstream */
+    const uint16_t* const* cdf, /* input: array of cdf arrays */
+    const uint16_t*
+        cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
+    const int N); /* input: data vector length */
 
 int WebRtcIsac_DecHistOneStepMulti(
-    int *data,                       /* output: data vector */
-    Bitstr *streamdata,              /* in-/output struct containing bitstream */
-    const uint16_t *const *cdf,      /* input: array of cdf arrays */
-    const uint16_t *init_index,/* input: vector of initial cdf table search entries */
-    const int N);                    /* input: data vector length */
+    int* data,                  /* output: data vector */
+    Bitstr* streamdata,         /* in-/output struct containing bitstream */
+    const uint16_t* const* cdf, /* input: array of cdf arrays */
+    const uint16_t*
+        init_index, /* input: vector of initial cdf table search entries */
+    const int N);   /* input: data vector length */
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc b/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc
index 333ab52..87ae0e0 100644
--- a/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc
+++ b/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_unittest.cc
@@ -29,7 +29,11 @@
 // Wrap subroutine calls that test things in this, so that the error messages
 // will be accompanied by stack traces that make it possible to tell which
 // subroutine invocation caused the failure.
-#define S(x) do { SCOPED_TRACE(#x); x; } while (0)
+#define S(x)          \
+  do {                \
+    SCOPED_TRACE(#x); \
+    x;                \
+  } while (0)
 
 }  // namespace
 
diff --git a/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h b/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
index e0ecf55..d80ff73 100644
--- a/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
+++ b/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
@@ -19,165 +19,156 @@
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
 
+#include <stddef.h>
+
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 
-#define MIN_ISAC_BW     10000
-#define MIN_ISAC_BW_LB  10000
-#define MIN_ISAC_BW_UB  25000
+#define MIN_ISAC_BW 10000
+#define MIN_ISAC_BW_LB 10000
+#define MIN_ISAC_BW_UB 25000
 
-#define MAX_ISAC_BW     56000
-#define MAX_ISAC_BW_UB  32000
-#define MAX_ISAC_BW_LB  32000
+#define MAX_ISAC_BW 56000
+#define MAX_ISAC_BW_UB 32000
+#define MAX_ISAC_BW_LB 32000
 
-#define MIN_ISAC_MD     5
-#define MAX_ISAC_MD     25
+#define MIN_ISAC_MD 5
+#define MAX_ISAC_MD 25
 
 // assumed header size, in bytes; we don't know the exact number
 // (header compression may be used)
-#define HEADER_SIZE        35
+#define HEADER_SIZE 35
 
 // Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode
-#define INIT_FRAME_LEN_WB  60
+#define INIT_FRAME_LEN_WB 60
 #define INIT_FRAME_LEN_SWB 30
 
 // Initial Bottleneck Estimate, in bits/sec, for
 // Wideband & Super-wideband mode
-#define INIT_BN_EST_WB     20e3f
-#define INIT_BN_EST_SWB    56e3f
+#define INIT_BN_EST_WB 20e3f
+#define INIT_BN_EST_SWB 56e3f
 
 // Initial Header rate (header rate depends on frame-size),
 // in bits/sec, for Wideband & Super-Wideband mode.
-#define INIT_HDR_RATE_WB                                                \
+#define INIT_HDR_RATE_WB \
   ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB)
-#define INIT_HDR_RATE_SWB                                               \
+#define INIT_HDR_RATE_SWB \
   ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB)
 
 // number of packets in a row for a high rate burst
-#define BURST_LEN       3
+#define BURST_LEN 3
 
 // ms, max time between two full bursts
-#define BURST_INTERVAL  500
+#define BURST_INTERVAL 500
 
 // number of packets in a row for initial high rate burst
-#define INIT_BURST_LEN  5
+#define INIT_BURST_LEN 5
 
 // bits/s, rate for the first BURST_LEN packets
-#define INIT_RATE_WB       INIT_BN_EST_WB
-#define INIT_RATE_SWB      INIT_BN_EST_SWB
-
+#define INIT_RATE_WB INIT_BN_EST_WB
+#define INIT_RATE_SWB INIT_BN_EST_SWB
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
-  /* This function initializes the struct                    */
-  /* to be called before using the struct for anything else  */
-  /* returns 0 if everything went fine, -1 otherwise         */
-  int32_t WebRtcIsac_InitBandwidthEstimator(
-      BwEstimatorstr*           bwest_str,
-      enum IsacSamplingRate encoderSampRate,
-      enum IsacSamplingRate decoderSampRate);
+/* This function initializes the struct                    */
+/* to be called before using the struct for anything else  */
+/* returns 0 if everything went fine, -1 otherwise         */
+int32_t WebRtcIsac_InitBandwidthEstimator(
+    BwEstimatorstr* bwest_str,
+    enum IsacSamplingRate encoderSampRate,
+    enum IsacSamplingRate decoderSampRate);
 
-  /* This function updates the receiving estimate                                                      */
-  /* Parameters:                                                                                       */
-  /* rtp_number    - value from RTP packet, from NetEq                                                 */
-  /* frame length  - length of signal frame in ms, from iSAC decoder                                   */
-  /* send_ts       - value in RTP header giving send time in samples                                   */
-  /* arr_ts        - value given by timeGetTime() time of arrival in samples of packet from NetEq      */
-  /* pksize        - size of packet in bytes, from NetEq                                               */
-  /* Index         - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
-  /* returns 0 if everything went fine, -1 otherwise                                                   */
-  int16_t WebRtcIsac_UpdateBandwidthEstimator(
-      BwEstimatorstr* bwest_str,
-      const uint16_t rtp_number,
-      const int32_t frame_length,
-      const uint32_t send_ts,
-      const uint32_t arr_ts,
-      const size_t pksize);
+/* This function updates the receiving estimate */
+/* Parameters: */
+/* rtp_number    - value from RTP packet, from NetEq */
+/* frame length  - length of signal frame in ms, from iSAC decoder */
+/* send_ts       - value in RTP header giving send time in samples */
+/* arr_ts        - value given by timeGetTime() time of arrival in samples of
+ * packet from NetEq      */
+/* pksize        - size of packet in bytes, from NetEq */
+/* Index         - integer (range 0...23) indicating bottle neck & jitter as
+ * estimated by other side */
+/* returns 0 if everything went fine, -1 otherwise */
+int16_t WebRtcIsac_UpdateBandwidthEstimator(BwEstimatorstr* bwest_str,
+                                            const uint16_t rtp_number,
+                                            const int32_t frame_length,
+                                            const uint32_t send_ts,
+                                            const uint32_t arr_ts,
+                                            const size_t pksize);
 
-  /* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */
-  int16_t WebRtcIsac_UpdateUplinkBwImpl(
-      BwEstimatorstr*           bwest_str,
-      int16_t               Index,
-      enum IsacSamplingRate encoderSamplingFreq);
+/* Update receiving estimates. Used when we only receive BWE index, no iSAC data
+ * packet. */
+int16_t WebRtcIsac_UpdateUplinkBwImpl(
+    BwEstimatorstr* bwest_str,
+    int16_t Index,
+    enum IsacSamplingRate encoderSamplingFreq);
 
-  /* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */
-  void WebRtcIsac_GetDownlinkBwJitIndexImpl(
-      BwEstimatorstr* bwest_str,
-      int16_t* bottleneckIndex,
-      int16_t* jitterInfo,
-      enum IsacSamplingRate decoderSamplingFreq);
+/* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the
+ * sending iSAC payload */
+void WebRtcIsac_GetDownlinkBwJitIndexImpl(
+    BwEstimatorstr* bwest_str,
+    int16_t* bottleneckIndex,
+    int16_t* jitterInfo,
+    enum IsacSamplingRate decoderSamplingFreq);
 
-  /* Returns the bandwidth estimation (in bps) */
-  int32_t WebRtcIsac_GetDownlinkBandwidth(
-      const BwEstimatorstr *bwest_str);
+/* Returns the bandwidth estimation (in bps) */
+int32_t WebRtcIsac_GetDownlinkBandwidth(const BwEstimatorstr* bwest_str);
 
-  /* Returns the max delay (in ms) */
-  int32_t WebRtcIsac_GetDownlinkMaxDelay(
-      const BwEstimatorstr *bwest_str);
+/* Returns the max delay (in ms) */
+int32_t WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr* bwest_str);
 
-  /* Returns the bandwidth that iSAC should send with in bps */
-  int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
+/* Returns the bandwidth that iSAC should send with in bps */
+int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
 
-  /* Returns the max delay value from the other side in ms */
-  int32_t WebRtcIsac_GetUplinkMaxDelay(
-      const BwEstimatorstr *bwest_str);
+/* Returns the max delay value from the other side in ms */
+int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str);
 
-  /* Fills in an IsacExternalBandwidthInfo struct. */
-  void WebRtcIsacBw_GetBandwidthInfo(
-      BwEstimatorstr* bwest_str,
-      enum IsacSamplingRate decoder_sample_rate_hz,
-      IsacBandwidthInfo* bwinfo);
+/* Fills in an IsacExternalBandwidthInfo struct. */
+void WebRtcIsacBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
+                                   enum IsacSamplingRate decoder_sample_rate_hz,
+                                   IsacBandwidthInfo* bwinfo);
 
-  /* Uses the values from an IsacExternalBandwidthInfo struct. */
-  void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
-                                     const IsacBandwidthInfo* bwinfo);
+/* Uses the values from an IsacExternalBandwidthInfo struct. */
+void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
+                                   const IsacBandwidthInfo* bwinfo);
 
-  /*
-   * update amount of data in bottle neck buffer and burst handling
-   * returns minimum payload size (bytes)
-   */
-  int WebRtcIsac_GetMinBytes(
-      RateModel*         State,
-      int                StreamSize,    /* bytes in bitstream */
-      const int          FrameLen,      /* ms per frame */
-      const double       BottleNeck,    /* bottle neck rate; excl headers (bps) */
-      const double       DelayBuildUp,  /* max delay from bottleneck buffering (ms) */
-      enum ISACBandwidth bandwidth
-      /*,int16_t        frequentLargePackets*/);
+/*
+ * update amount of data in bottle neck buffer and burst handling
+ * returns minimum payload size (bytes)
+ */
+int WebRtcIsac_GetMinBytes(
+    RateModel* State,
+    int StreamSize,            /* bytes in bitstream */
+    const int FrameLen,        /* ms per frame */
+    const double BottleNeck,   /* bottle neck rate; excl headers (bps) */
+    const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
+    enum ISACBandwidth bandwidth
+    /*,int16_t        frequentLargePackets*/);
 
-  /*
-   * update long-term average bitrate and amount of data in buffer
-   */
-  void WebRtcIsac_UpdateRateModel(
-      RateModel*   State,
-      int          StreamSize,                /* bytes in bitstream */
-      const int    FrameSamples,        /* samples per frame */
-      const double BottleNeck);       /* bottle neck rate; excl headers (bps) */
+/*
+ * update long-term average bitrate and amount of data in buffer
+ */
+void WebRtcIsac_UpdateRateModel(
+    RateModel* State,
+    int StreamSize,           /* bytes in bitstream */
+    const int FrameSamples,   /* samples per frame */
+    const double BottleNeck); /* bottle neck rate; excl headers (bps) */
 
+void WebRtcIsac_InitRateModel(RateModel* State);
 
-  void WebRtcIsac_InitRateModel(
-      RateModel *State);
+/* Returns the new framelength value (input argument: bottle_neck) */
+int WebRtcIsac_GetNewFrameLength(double bottle_neck, int current_framelength);
 
-  /* Returns the new framelength value (input argument: bottle_neck) */
-  int WebRtcIsac_GetNewFrameLength(
-      double bottle_neck,
-      int    current_framelength);
+/* Returns the new SNR value (input argument: bottle_neck) */
+double WebRtcIsac_GetSnr(double bottle_neck, int new_framelength);
 
-  /* Returns the new SNR value (input argument: bottle_neck) */
-  double WebRtcIsac_GetSnr(
-      double bottle_neck,
-      int    new_framelength);
-
-
-  int16_t WebRtcIsac_UpdateUplinkJitter(
-      BwEstimatorstr*              bwest_str,
-      int32_t                  index);
+int16_t WebRtcIsac_UpdateUplinkJitter(BwEstimatorstr* bwest_str, int32_t index);
 
 #if defined(__cplusplus)
 }
 #endif
 
-
-#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ \
+        */
diff --git a/modules/audio_coding/codecs/isac/main/source/codec.h b/modules/audio_coding/codecs/isac/main/source/codec.h
index af7efc0..c386704 100644
--- a/modules/audio_coding/codecs/isac/main/source/codec.h
+++ b/modules/audio_coding/codecs/isac/main/source/codec.h
@@ -19,14 +19,18 @@
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
 
+#include <stddef.h>
+
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 
 void WebRtcIsac_ResetBitstream(Bitstr* bit_stream);
 
-int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata,
+int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str,
+                                 Bitstr* streamdata,
                                  size_t packet_size,
                                  uint16_t rtp_seq_number,
-                                 uint32_t send_ts, uint32_t arr_ts,
+                                 uint32_t send_ts,
+                                 uint32_t arr_ts,
                                  enum IsacSamplingRate encoderSampRate,
                                  enum IsacSamplingRate decoderSampRate);
 
@@ -36,7 +40,8 @@
                         int16_t* current_framesamples,
                         int16_t isRCUPayload);
 
-int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj,
+int WebRtcIsac_DecodeRcuLb(float* signal_out,
+                           ISACLBDecStruct* ISACdec_obj,
                            int16_t* current_framesamples);
 
 int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
@@ -46,15 +51,20 @@
                         int16_t bottleneckIndex);
 
 int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
-                                  Bitstr* ISACBitStr_obj, int BWnumber,
+                                  Bitstr* ISACBitStr_obj,
+                                  int BWnumber,
                                   float scale);
 
 int WebRtcIsac_EncodeStoredDataUb(
-    const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream,
-    int32_t jitterInfo, float scale, enum ISACBandwidth bandwidth);
+    const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
+    Bitstr* bitStream,
+    int32_t jitterInfo,
+    float scale,
+    enum ISACBandwidth bandwidth);
 
 int16_t WebRtcIsac_GetRedPayloadUb(
-    const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj,
+    const ISACUBSaveEncDataStruct* ISACSavedEncObj,
+    Bitstr* bitStreamObj,
     enum ISACBandwidth bandwidth);
 
 /******************************************************************************
@@ -80,7 +90,6 @@
                                   double* rateUBBitPerSec,
                                   enum ISACBandwidth* bandwidthKHz);
 
-
 /******************************************************************************
  * WebRtcIsac_DecodeUb16()
  *
@@ -165,15 +174,8 @@
 
 void WebRtcIsac_InitMasking(MaskFiltstr* maskdata);
 
-void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata);
-
 void WebRtcIsac_InitPostFilterbank(PostFiltBankstr* postfiltdata);
 
-void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata);
-
-void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State);
-
-
 /**************************** transform functions ****************************/
 
 void WebRtcIsac_InitTransform(TransformTables* tables);
@@ -192,41 +194,29 @@
                           double* outre2,
                           FFTstr* fftstr_obj);
 
-/******************************* filter functions ****************************/
-
-void WebRtcIsac_AllPoleFilter(double* InOut, double* Coef, size_t lengthInOut,
-                              int orderCoef);
-
-void WebRtcIsac_AllZeroFilter(double* In, double* Coef, size_t lengthInOut,
-                              int orderCoef, double* Out);
-
-void WebRtcIsac_ZeroPoleFilter(double* In, double* ZeroCoef, double* PoleCoef,
-                               size_t lengthInOut, int orderCoef, double* Out);
-
-
 /***************************** filterbank functions **************************/
 
-void WebRtcIsac_SplitAndFilterFloat(float* in, float* LP, float* HP,
-                                    double* LP_la, double* HP_la,
-                                    PreFiltBankstr* prefiltdata);
-
-
-void WebRtcIsac_FilterAndCombineFloat(float* InLP, float* InHP, float* Out,
+void WebRtcIsac_FilterAndCombineFloat(float* InLP,
+                                      float* InHP,
+                                      float* Out,
                                       PostFiltBankstr* postfiltdata);
 
-
 /************************* normalized lattice filters ************************/
 
-void WebRtcIsac_NormLatticeFilterMa(int orderCoef, float* stateF, float* stateG,
-                                    float* lat_in, double* filtcoeflo,
+void WebRtcIsac_NormLatticeFilterMa(int orderCoef,
+                                    float* stateF,
+                                    float* stateG,
+                                    float* lat_in,
+                                    double* filtcoeflo,
                                     double* lat_out);
 
-void WebRtcIsac_NormLatticeFilterAr(int orderCoef, float* stateF, float* stateG,
-                                    double* lat_in, double* lo_filt_coef,
+void WebRtcIsac_NormLatticeFilterAr(int orderCoef,
+                                    float* stateF,
+                                    float* stateG,
+                                    double* lat_in,
+                                    double* lo_filt_coef,
                                     float* lat_out);
 
 void WebRtcIsac_Dir2Lat(double* a, int orderCoef, float* sth, float* cth);
 
-void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order);
-
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/crc.h b/modules/audio_coding/codecs/isac/main/source/crc.h
index b3197a1..19adbda 100644
--- a/modules/audio_coding/codecs/isac/main/source/crc.h
+++ b/modules/audio_coding/codecs/isac/main/source/crc.h
@@ -36,11 +36,6 @@
  *                   -1 - Error
  */
 
-int WebRtcIsac_GetCrc(
-    const int16_t* encoded,
-    int no_of_word8s,
-    uint32_t* crc);
-
-
+int WebRtcIsac_GetCrc(const int16_t* encoded, int no_of_word8s, uint32_t* crc);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/decode.c b/modules/audio_coding/codecs/isac/main/source/decode.c
index e13bc55..6e114e4 100644
--- a/modules/audio_coding/codecs/isac/main/source/decode.c
+++ b/modules/audio_coding/codecs/isac/main/source/decode.c
@@ -28,6 +28,7 @@
 #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
 
 /*
  * function to decode the bitstream
diff --git a/modules/audio_coding/codecs/isac/main/source/encode.c b/modules/audio_coding/codecs/isac/main/source/encode.c
index 7963820..bf92d02 100644
--- a/modules/audio_coding/codecs/isac/main/source/encode.c
+++ b/modules/audio_coding/codecs/isac/main/source/encode.c
@@ -35,6 +35,8 @@
 #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
 #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
 #include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
 
 
 #define UB_LOOKAHEAD 24
diff --git a/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h b/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h
index 2fa1c71..b8d918b 100644
--- a/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h
+++ b/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h
@@ -39,9 +39,7 @@
  *
  *
  */
-int16_t WebRtcIsac_RemoveLarMean(
-    double*     lar,
-    int16_t bandwidth);
+int16_t WebRtcIsac_RemoveLarMean(double* lar, int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_DecorrelateIntraVec()
@@ -59,11 +57,9 @@
  * Output:
  *      -out                : decorrelated LAR vectors.
  */
-int16_t WebRtcIsac_DecorrelateIntraVec(
-    const double* inLAR,
-    double*       out,
-    int16_t   bandwidth);
-
+int16_t WebRtcIsac_DecorrelateIntraVec(const double* inLAR,
+                                       double* out,
+                                       int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_DecorrelateInterVec()
@@ -82,11 +78,9 @@
  * Output:
  *      -out                : decorrelated LAR vectors.
  */
-int16_t WebRtcIsac_DecorrelateInterVec(
-    const double* data,
-    double*       out,
-    int16_t   bandwidth);
-
+int16_t WebRtcIsac_DecorrelateInterVec(const double* data,
+                                       double* out,
+                                       int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_QuantizeUncorrLar()
@@ -102,11 +96,7 @@
  *      -data               : quantized version of the input.
  *      -idx                : pointer to quantization indices.
  */
-double WebRtcIsac_QuantizeUncorrLar(
-    double*     data,
-    int*        idx,
-    int16_t bandwidth);
-
+double WebRtcIsac_QuantizeUncorrLar(double* data, int* idx, int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_CorrelateIntraVec()
@@ -121,11 +111,9 @@
  * Output:
  *      -out                : correlated parametrs.
  */
-int16_t WebRtcIsac_CorrelateIntraVec(
-    const double* data,
-    double*       out,
-    int16_t   bandwidth);
-
+int16_t WebRtcIsac_CorrelateIntraVec(const double* data,
+                                     double* out,
+                                     int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_CorrelateInterVec()
@@ -140,17 +128,15 @@
  * Output:
  *      -out                : correlated parametrs.
  */
-int16_t WebRtcIsac_CorrelateInterVec(
-    const double* data,
-    double*       out,
-    int16_t   bandwidth);
-
+int16_t WebRtcIsac_CorrelateInterVec(const double* data,
+                                     double* out,
+                                     int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_AddLarMean()
  *
  * This is the inverse of WebRtcIsac_RemoveLarMean()
- * 
+ *
  * Input:
  *      -data               : pointer to mean-removed LAR:s.
  *      -bandwidth          : indicates if the given LAR vectors belong
@@ -159,10 +145,7 @@
  * Output:
  *      -data               : pointer to LARs.
  */
-int16_t WebRtcIsac_AddLarMean(
-    double*     data,
-    int16_t bandwidth);
-
+int16_t WebRtcIsac_AddLarMean(double* data, int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_DequantizeLpcParam()
@@ -177,11 +160,9 @@
  * Output:
  *      -out                : pointer to quantized values.
  */
-int16_t WebRtcIsac_DequantizeLpcParam(
-    const int*  idx,
-    double*     out,
-    int16_t bandwidth);
-
+int16_t WebRtcIsac_DequantizeLpcParam(const int* idx,
+                                      double* out,
+                                      int16_t bandwidth);
 
 /******************************************************************************
  * WebRtcIsac_ToLogDomainRemoveMean()
@@ -194,9 +175,7 @@
  * Output:
  *      -lpcGain            : mean-removed in log domain.
  */
-int16_t WebRtcIsac_ToLogDomainRemoveMean(
-    double* lpGains);
-
+int16_t WebRtcIsac_ToLogDomainRemoveMean(double* lpGains);
 
 /******************************************************************************
  * WebRtcIsac_DecorrelateLPGain()
@@ -210,16 +189,13 @@
  * Output:
  *      -out                : decorrelated parameters.
  */
-int16_t WebRtcIsac_DecorrelateLPGain(
-    const double* data,
-    double*       out);
-
+int16_t WebRtcIsac_DecorrelateLPGain(const double* data, double* out);
 
 /******************************************************************************
  * WebRtcIsac_QuantizeLpcGain()
  *
  * Quantize the decorrelated log-domain gains.
- * 
+ *
  * Input:
  *      -lpcGain            : uncorrelated LPC gains.
  *
@@ -227,10 +203,7 @@
  *      -idx                : quantization indices
  *      -lpcGain            : quantized value of the inpt.
  */
-double WebRtcIsac_QuantizeLpcGain(
-    double* lpGains,
-    int*    idx);
-
+double WebRtcIsac_QuantizeLpcGain(double* lpGains, int* idx);
 
 /******************************************************************************
  * WebRtcIsac_DequantizeLpcGain()
@@ -243,10 +216,7 @@
  * Output:
  *      -lpcGains           : quantized values of the given parametes.
  */
-int16_t WebRtcIsac_DequantizeLpcGain(
-    const int* idx,
-    double*    lpGains);
-
+int16_t WebRtcIsac_DequantizeLpcGain(const int* idx, double* lpGains);
 
 /******************************************************************************
  * WebRtcIsac_CorrelateLpcGain()
@@ -259,10 +229,7 @@
  * Output:
  *      -out                : correlated parameters.
  */
-int16_t WebRtcIsac_CorrelateLpcGain(
-    const double* data,
-    double*       out);
-
+int16_t WebRtcIsac_CorrelateLpcGain(const double* data, double* out);
 
 /******************************************************************************
  * WebRtcIsac_AddMeanToLinearDomain()
@@ -275,8 +242,6 @@
  * Output:
  *      -lpcGain            : LPC gain in normal domain.
  */
-int16_t WebRtcIsac_AddMeanToLinearDomain(
-    double* lpcGains);
-
+int16_t WebRtcIsac_AddMeanToLinearDomain(double* lpcGains);
 
 #endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/entropy_coding.h b/modules/audio_coding/codecs/isac/main/source/entropy_coding.h
index 7224ad0..6c2b8d3 100644
--- a/modules/audio_coding/codecs/isac/main/source/entropy_coding.h
+++ b/modules/audio_coding/codecs/isac/main/source/entropy_coding.h
@@ -46,8 +46,11 @@
  * Return value             : < 0 if an error occures
  *                              0 if succeeded.
  */
-int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12,
-                          enum ISACBand band, double* fr, double* fi);
+int WebRtcIsac_DecodeSpec(Bitstr* streamdata,
+                          int16_t AvgPitchGain_Q12,
+                          enum ISACBand band,
+                          double* fr,
+                          double* fi);
 
 /******************************************************************************
  * WebRtcIsac_EncodeSpec()
@@ -72,24 +75,31 @@
  * Return value             : < 0 if an error occures
  *                              0 if succeeded.
  */
-int WebRtcIsac_EncodeSpec(const int16_t* fr, const int16_t* fi,
-                          int16_t AvgPitchGain_Q12, enum ISACBand band,
+int WebRtcIsac_EncodeSpec(const int16_t* fr,
+                          const int16_t* fi,
+                          int16_t AvgPitchGain_Q12,
+                          enum ISACBand band,
                           Bitstr* streamdata);
 
 /* decode & dequantize LPC Coef */
 int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef);
-int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs,
+int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata,
+                               double* lpcVecs,
                                double* percepFilterGains,
                                int16_t bandwidth);
 
-int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo,
+int WebRtcIsac_DecodeLpc(Bitstr* streamdata,
+                         double* LPCCoef_lo,
                          double* LPCCoef_hi);
 
 /* quantize & code LPC Coef */
-void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi,
-                            Bitstr* streamdata, IsacSaveEncoderData* encData);
+void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo,
+                            double* LPCCoef_hi,
+                            Bitstr* streamdata,
+                            IsacSaveEncoderData* encData);
 
-void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
+void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo,
+                                double* LPCCoef_hi,
                                 Bitstr* streamdata,
                                 IsacSaveEncoderData* encData);
 
@@ -126,7 +136,8 @@
  * Return value             : 0 if encoding is successful,
  *                           <0 if failed to encode.
  */
-int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff, Bitstr* streamdata,
+int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff,
+                               Bitstr* streamdata,
                                double* interpolLPCCoeff,
                                int16_t bandwidth,
                                ISACUBSaveEncDataStruct* encData);
@@ -184,9 +195,9 @@
                                Bitstr* streamdata,
                                IsacSaveEncoderData* encData);
 
-int WebRtcIsac_DecodePitchGain(Bitstr* streamdata,
-                               int16_t* PitchGain_Q12);
-int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12,
+int WebRtcIsac_DecodePitchGain(Bitstr* streamdata, int16_t* PitchGain_Q12);
+int WebRtcIsac_DecodePitchLag(Bitstr* streamdata,
+                              int16_t* PitchGain_Q12,
                               double* PitchLag);
 
 int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, int16_t* framelength);
@@ -200,10 +211,10 @@
 /* Step-up */
 void WebRtcIsac_Rc2Poly(double* RC, int N, double* a);
 
-void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi,
+void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo,
+                                 double* LPCCoef_hi,
                                  int* index_g);
 
-
 /******************************************************************************
  * WebRtcIsac_EncodeLpcGainUb()
  * Encode LPC gains of sub-Frames.
@@ -220,10 +231,10 @@
  *  - lpcGainIndex          : quantization indices for lpc gains, these will
  *                            be stored to be used  for FEC.
  */
-void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
+void WebRtcIsac_EncodeLpcGainUb(double* lpGains,
+                                Bitstr* streamdata,
                                 int* lpcGainIndex);
 
-
 /******************************************************************************
  * WebRtcIsac_EncodeLpcGainUb()
  * Store LPC gains of sub-Frames in 'streamdata'.
@@ -239,7 +250,6 @@
  */
 void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata);
 
-
 /******************************************************************************
  * WebRtcIsac_DecodeLpcGainUb()
  * Decode the LPC gain of sub-frames.
@@ -257,7 +267,6 @@
  */
 int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata);
 
-
 /******************************************************************************
  * WebRtcIsac_EncodeBandwidth()
  * Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz.
@@ -277,7 +286,6 @@
 int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth,
                                    Bitstr* streamData);
 
-
 /******************************************************************************
  * WebRtcIsac_DecodeBandwidth()
  * Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz
@@ -298,7 +306,6 @@
 int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
                                    enum ISACBandwidth* bandwidth);
 
-
 /******************************************************************************
  * WebRtcIsac_EncodeJitterInfo()
  * Decode the jitter information.
@@ -316,9 +323,7 @@
  * Return value             : 0 if succeeded.
  *                           <0 if failed.
  */
-int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
-                                    Bitstr* streamData);
-
+int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex, Bitstr* streamData);
 
 /******************************************************************************
  * WebRtcIsac_DecodeJitterInfo()
@@ -337,7 +342,6 @@
  * Return value             : 0 if succeeded.
  *                           <0 if failed.
  */
-int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData,
-                                    int32_t* jitterInfo);
+int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, int32_t* jitterInfo);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/fft.h b/modules/audio_coding/codecs/isac/main/source/fft.h
index 9750153..34e5f94 100644
--- a/modules/audio_coding/codecs/isac/main/source/fft.h
+++ b/modules/audio_coding/codecs/isac/main/source/fft.h
@@ -34,10 +34,12 @@
 
 /* double precision routine */
 
-
-int WebRtcIsac_Fftns (unsigned int ndim, const int dims[], double Re[], double Im[],
-                     int isign, double scaling, FFTstr *fftstate);
-
-
+int WebRtcIsac_Fftns(unsigned int ndim,
+                     const int dims[],
+                     double Re[],
+                     double Im[],
+                     int isign,
+                     double scaling,
+                     FFTstr* fftstate);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/filter_functions.c b/modules/audio_coding/codecs/isac/main/source/filter_functions.c
index 7bd5a79..a4f297c 100644
--- a/modules/audio_coding/codecs/isac/main/source/filter_functions.c
+++ b/modules/audio_coding/codecs/isac/main/source/filter_functions.c
@@ -13,16 +13,14 @@
 #ifdef WEBRTC_ANDROID
 #include <stdlib.h>
 #endif
+
 #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
-#include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
-#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
 
-
-
-void WebRtcIsac_AllPoleFilter(double* InOut,
-                              double* Coef,
-                              size_t lengthInOut,
-                              int orderCoef) {
+static void WebRtcIsac_AllPoleFilter(double* InOut,
+                                     double* Coef,
+                                     size_t lengthInOut,
+                                     int orderCoef) {
   /* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */
   double scal;
   double sum;
@@ -55,12 +53,11 @@
   }
 }
 
-
-void WebRtcIsac_AllZeroFilter(double* In,
-                              double* Coef,
-                              size_t lengthInOut,
-                              int orderCoef,
-                              double* Out) {
+static void WebRtcIsac_AllZeroFilter(double* In,
+                                     double* Coef,
+                                     size_t lengthInOut,
+                                     int orderCoef,
+                                     double* Out) {
   /* the state of filter is assumed to be in In[-1] to In[-orderCoef] */
 
   size_t n;
@@ -80,13 +77,12 @@
   }
 }
 
-
-void WebRtcIsac_ZeroPoleFilter(double* In,
-                               double* ZeroCoef,
-                               double* PoleCoef,
-                               size_t lengthInOut,
-                               int orderCoef,
-                               double* Out) {
+static void WebRtcIsac_ZeroPoleFilter(double* In,
+                                      double* ZeroCoef,
+                                      double* PoleCoef,
+                                      size_t lengthInOut,
+                                      int orderCoef,
+                                      double* Out) {
   /* the state of the zero section is assumed to be in In[-1] to In[-orderCoef] */
   /* the state of the pole section is assumed to be in Out[-1] to Out[-orderCoef] */
 
@@ -115,8 +111,10 @@
 
 }
 
-
-void WebRtcIsac_BwExpand(double* out, double* in, double coef, size_t length) {
+static void WebRtcIsac_BwExpand(double* out,
+                                double* in,
+                                double coef,
+                                size_t length) {
   size_t i;
   double  chirp;
 
@@ -195,69 +193,3 @@
   memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
   memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
 }
-
-
-static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
-static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
-
-
-void WebRtcIsac_AllpassFilterForDec(double* InOut,
-                                    const double* APSectionFactors,
-                                    size_t lengthInOut,
-                                    double* FilterState) {
-  //This performs all-pass filtering--a series of first order all-pass sections are used
-  //to filter the input in a cascade manner.
-  size_t n,j;
-  double temp;
-  for (j=0; j<ALLPASSSECTIONS; j++){
-    for (n=0;n<lengthInOut;n+=2){
-      temp = InOut[n]; //store input
-      InOut[n] = FilterState[j] + APSectionFactors[j]*temp;
-      FilterState[j] = -APSectionFactors[j]*InOut[n] + temp;
-    }
-  }
-}
-
-void WebRtcIsac_DecimateAllpass(const double* in,
-                                double* state_in,
-                                size_t N,
-                                double* out) {
-  size_t n;
-  double data_vec[PITCH_FRAME_LEN];
-
-  /* copy input */
-  memcpy(data_vec+1, in, sizeof(double) * (N-1));
-
-  data_vec[0] = state_in[2*ALLPASSSECTIONS];   //the z^(-1) state
-  state_in[2*ALLPASSSECTIONS] = in[N-1];
-
-  WebRtcIsac_AllpassFilterForDec(data_vec+1, APupper, N, state_in);
-  WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N, state_in+ALLPASSSECTIONS);
-
-  for (n=0;n<N/2;n++)
-    out[n] = data_vec[2*n] + data_vec[2*n+1];
-
-}
-
-
-/* create high-pass filter ocefficients
- * z = 0.998 * exp(j*2*pi*35/8000);
- * p = 0.94 * exp(j*2*pi*140/8000);
- * HP_b = [1, -2*real(z), abs(z)^2];
- * HP_a = [1, -2*real(p), abs(p)^2]; */
-static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
-static const double b_coef[2] = {-1.99524591718270,  0.99600400000000};
-
-/* second order high-pass filter */
-void WebRtcIsac_Highpass(const double* in,
-                         double* out,
-                         double* state,
-                         size_t N) {
-  size_t k;
-
-  for (k=0; k<N; k++) {
-    *out = *in + state[1];
-    state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
-    state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
-  }
-}
diff --git a/modules/audio_coding/codecs/isac/main/source/filter_functions.h b/modules/audio_coding/codecs/isac/main/source/filter_functions.h
new file mode 100644
index 0000000..48a9b74
--- /dev/null
+++ b/modules/audio_coding/codecs/isac/main/source/filter_functions.h
@@ -0,0 +1,23 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
+
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order);
+
+void WebRtcIsac_WeightingFilter(const double* in,
+                                double* weiout,
+                                double* whiout,
+                                WeightFiltstr* wfdata);
+
+#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c b/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c
deleted file mode 100644
index 12caee0..0000000
--- a/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Copyright (c) 2011 The WebRTC 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.
- */
-
-/* filterbank_tables.c*/
-/* This file contains variables that are used in filterbanks.c*/
-
-#include "modules/audio_coding/codecs/isac/main/source/filterbank_tables.h"
-#include "modules/audio_coding/codecs/isac/main/source/settings.h"
-
-/* The composite all-pass filter factors */
-const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
- 0.03470000000000f,  0.15440000000000f,  0.38260000000000f,  0.74400000000000f};
-
-/* The upper channel all-pass filter factors */
-const float WebRtcIsac_kUpperApFactorsFloat[2] = {
- 0.03470000000000f,  0.38260000000000f};
-
-/* The lower channel all-pass filter factors */
-const float WebRtcIsac_kLowerApFactorsFloat[2] = {
- 0.15440000000000f,  0.74400000000000f};
-
-/* The matrix for transforming the backward composite state to upper channel state */
-const float WebRtcIsac_kTransform1Float[8] = {
-  -0.00158678506084f,  0.00127157815343f, -0.00104805672709f,  0.00084837248079f,
-  0.00134467983258f, -0.00107756549387f,  0.00088814793277f, -0.00071893072525f};
-
-/* The matrix for transforming the backward composite state to lower channel state */
-const float WebRtcIsac_kTransform2Float[8] = {
- -0.00170686041697f,  0.00136780109829f, -0.00112736532350f,  0.00091257055385f,
-  0.00103094281812f, -0.00082615076557f,  0.00068092756088f, -0.00055119165484f};
diff --git a/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h b/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h
deleted file mode 100644
index 2edb0f0..0000000
--- a/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  Copyright (c) 2011 The WebRTC 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.
- */
-
-/*
- * filterbank_tables.h
- *
- * Header file for variables that are defined in
- * filterbank_tables.c.
- *
- */
-
-#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_
-#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_
-
-#include "modules/audio_coding/codecs/isac/main/source/structs.h"
-
-/********************* Coefficient Tables ************************/
-/* The number of composite all-pass filter factors */
-#define NUMBEROFCOMPOSITEAPSECTIONS 4
-
-/* The number of all-pass filter factors in an upper or lower channel*/
-#define NUMBEROFCHANNELAPSECTIONS 2
-
-/* The composite all-pass filter factors */
-extern const float WebRtcIsac_kCompositeApFactorsFloat[4];
-
-/* The upper channel all-pass filter factors */
-extern const float WebRtcIsac_kUpperApFactorsFloat[2];
-
-/* The lower channel all-pass filter factors */
-extern const float WebRtcIsac_kLowerApFactorsFloat[2];
-
-/* The matrix for transforming the backward composite state to upper channel state */
-extern const float WebRtcIsac_kTransform1Float[8];
-
-/* The matrix for transforming the backward composite state to lower channel state */
-extern const float WebRtcIsac_kTransform2Float[8];
-
-#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/filterbanks.c b/modules/audio_coding/codecs/isac/main/source/filterbanks.c
index 6f1e4db..d57b550 100644
--- a/modules/audio_coding/codecs/isac/main/source/filterbanks.c
+++ b/modules/audio_coding/codecs/isac/main/source/filterbanks.c
@@ -19,240 +19,8 @@
  */
 
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
-#include "modules/audio_coding/codecs/isac/main/source/filterbank_tables.h"
 #include "modules/audio_coding/codecs/isac/main/source/codec.h"
-
-/* This function performs all-pass filtering--a series of first order all-pass
- * sections are used to filter the input in a cascade manner.
- * The input is overwritten!!
- */
-static void WebRtcIsac_AllPassFilter2Float(float *InOut, const float *APSectionFactors,
-                                           int lengthInOut, int NumberOfSections,
-                                           float *FilterState)
-{
-  int n, j;
-  float temp;
-  for (j=0; j<NumberOfSections; j++){
-    for (n=0;n<lengthInOut;n++){
-      temp = FilterState[j] + APSectionFactors[j] * InOut[n];
-      FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
-      InOut[n] = temp;
-    }
-  }
-}
-
-/* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
-static const float kHpStCoefInFloat[4] =
-{-1.94895953203325f, 0.94984516000000f, -0.05101826139794f, 0.05015484000000f};
-
-/* Function WebRtcIsac_SplitAndFilter
- * This function creates low-pass and high-pass decimated versions of part of
- the input signal, and part of the signal in the input 'lookahead buffer'.
-
- INPUTS:
- in: a length FRAMESAMPLES array of input samples
- prefiltdata: input data structure containing the filterbank states
- and lookahead samples from the previous encoding
- iteration.
- OUTPUTS:
- LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
- have been phase equalized.  The first QLOOKAHEAD samples are
- based on the samples in the two prefiltdata->INLABUFx arrays
- each of length QLOOKAHEAD.
- The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
- on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
- array in[].
- HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
- have been phase equalized.  The first QLOOKAHEAD samples are
- based on the samples in the two prefiltdata->INLABUFx arrays
- each of length QLOOKAHEAD.
- The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
- on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
- array in[].
-
- LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
- These samples are not phase equalized. They are computed
- from the samples in the in[] array.
- HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
- that are not phase equalized. They are computed from
- the in[] vector.
- prefiltdata: this input data structure's filterbank state and
- lookahead sample buffers are updated for the next
- encoding iteration.
-*/
-void WebRtcIsac_SplitAndFilterFloat(float *pin, float *LP, float *HP,
-                                    double *LP_la, double *HP_la,
-                                    PreFiltBankstr *prefiltdata)
-{
-  int k,n;
-  float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
-  float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
-  float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
-  float tempinoutvec[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
-  float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
-  float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
-  float in[FRAMESAMPLES];
-  float ftmp;
-
-
-  /* High pass filter */
-
-  for (k=0;k<FRAMESAMPLES;k++) {
-    in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
-        kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
-    ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
-        kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
-    prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
-    prefiltdata->HPstates_float[0] = ftmp;
-  }
-
-  /*
-    % backwards all-pass filtering to obtain zero-phase
-    [tmp1(N2+LA:-1:LA+1, 1), state1] = filter(Q.coef, Q.coef(end:-1:1), in(N:-2:2));
-    tmp1(LA:-1:1) = filter(Q.coef, Q.coef(end:-1:1), Q.LookAheadBuf1, state1);
-    Q.LookAheadBuf1 = in(N:-2:N-2*LA+2);
-  */
-  /*Backwards all-pass filter the odd samples of the input (upper channel)
-    to eventually obtain zero phase.  The composite all-pass filter (comprised of both
-    the upper and lower channel all-pass filsters in series) is used for the
-    filtering. */
-
-  /* First Channel */
-
-  /*initial state of composite filter is zero */
-  for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
-    CompositeAPFilterState[k] = 0.0;
-  }
-  /* put every other sample of input into a temporary vector in reverse (backward) order*/
-  for (k=0;k<FRAMESAMPLES_HALF;k++) {
-    tempinoutvec[k] = in[FRAMESAMPLES-1-2*k];
-  }
-
-  /* now all-pass filter the backwards vector.  Output values overwrite the input vector. */
-  WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
-                                 FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
-
-  /* save the backwards filtered output for later forward filtering,
-     but write it in forward order*/
-  for (k=0;k<FRAMESAMPLES_HALF;k++) {
-    tempin_ch1[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
-  }
-
-  /* save the backwards filter state  becaue it will be transformed
-     later into a forward state */
-  for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
-    ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
-  }
-
-  /* now backwards filter the samples in the lookahead buffer. The samples were
-     placed there in the encoding of the previous frame.  The output samples
-     overwrite the input samples */
-  WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF1_float,
-                                 WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,
-                                 NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
-
-  /* save the output, but write it in forward order */
-  /* write the lookahead samples for the next encoding iteration. Every other
-     sample at the end of the input frame is written in reverse order for the
-     lookahead length. Exported in the prefiltdata structure. */
-  for (k=0;k<QLOOKAHEAD;k++) {
-    tempin_ch1[QLOOKAHEAD-1-k]=prefiltdata->INLABUF1_float[k];
-    prefiltdata->INLABUF1_float[k]=in[FRAMESAMPLES-1-2*k];
-  }
-
-  /* Second Channel.  This is exactly like the first channel, except that the
-     even samples are now filtered instead (lower channel). */
-  for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
-    CompositeAPFilterState[k] = 0.0;
-  }
-
-  for (k=0;k<FRAMESAMPLES_HALF;k++) {
-    tempinoutvec[k] = in[FRAMESAMPLES-2-2*k];
-  }
-
-  WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
-                                 FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
-
-  for (k=0;k<FRAMESAMPLES_HALF;k++) {
-    tempin_ch2[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
-  }
-
-  for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
-    ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
-  }
-
-
-  WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF2_float,
-                                 WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,NUMBEROFCOMPOSITEAPSECTIONS,
-                                 CompositeAPFilterState);
-
-  for (k=0;k<QLOOKAHEAD;k++) {
-    tempin_ch2[QLOOKAHEAD-1-k]=prefiltdata->INLABUF2_float[k];
-    prefiltdata->INLABUF2_float[k]=in[FRAMESAMPLES-2-2*k];
-  }
-
-  /* Transform filter states from backward to forward */
-  /*At this point, each of the states of the backwards composite filters for the
-    two channels are transformed into forward filtering states for the corresponding
-    forward channel filters.  Each channel's forward filtering state from the previous
-    encoding iteration is added to the transformed state to get a proper forward state */
-
-  /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a
-     NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the
-     new state that is added to the previous 2x1 input state */
-
-  for (k=0;k<NUMBEROFCHANNELAPSECTIONS;k++){ /* k is row variable */
-    for (n=0; n<NUMBEROFCOMPOSITEAPSECTIONS;n++){/* n is column variable */
-      prefiltdata->INSTAT1_float[k] += ForTransform_CompositeAPFilterState[n]*
-          WebRtcIsac_kTransform1Float[k*NUMBEROFCHANNELAPSECTIONS+n];
-      prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n]*
-          WebRtcIsac_kTransform2Float[k*NUMBEROFCHANNELAPSECTIONS+n];
-    }
-  }
-
-  /*obtain polyphase components by forward all-pass filtering through each channel */
-  /* the backward filtered samples are now forward filtered with the corresponding channel filters */
-  /* The all pass filtering automatically updates the filter states which are exported in the
-     prefiltdata structure */
-  WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
-                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float);
-  WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
-                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float);
-
-  /* Now Construct low-pass and high-pass signals as combinations of polyphase components */
-  for (k=0; k<FRAMESAMPLES_HALF; k++) {
-    LP[k] = 0.5f*(tempin_ch1[k] + tempin_ch2[k]);/* low pass signal*/
-    HP[k] = 0.5f*(tempin_ch1[k] - tempin_ch2[k]);/* high pass signal*/
-  }
-
-  /* Lookahead LP and HP signals */
-  /* now create low pass and high pass signals of the input vector.  However, no
-     backwards filtering is performed, and hence no phase equalization is involved.
-     Also, the input contains some samples that are lookahead samples.  The high pass
-     and low pass signals that are created are used outside this function for analysis
-     (not encoding) purposes */
-
-  /* set up input */
-  for (k=0; k<FRAMESAMPLES_HALF; k++) {
-    tempin_ch1[k]=in[2*k+1];
-    tempin_ch2[k]=in[2*k];
-  }
-
-  /* the input filter states are passed in and updated by the all-pass filtering routine and
-     exported in the prefiltdata structure*/
-  WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
-                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA1_float);
-  WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
-                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float);
-
-  for (k=0; k<FRAMESAMPLES_HALF; k++) {
-    LP_la[k] = (float)(0.5f*(tempin_ch1[k] + tempin_ch2[k])); /*low pass */
-    HP_la[k] = (double)(0.5f*(tempin_ch1[k] - tempin_ch2[k])); /* high pass */
-  }
-
-
-}/*end of WebRtcIsac_SplitAndFilter */
-
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
 
 /* Combining */
 
diff --git a/modules/audio_coding/codecs/isac/main/source/intialize.c b/modules/audio_coding/codecs/isac/main/source/intialize.c
index 57025c6..5c951f6 100644
--- a/modules/audio_coding/codecs/isac/main/source/intialize.c
+++ b/modules/audio_coding/codecs/isac/main/source/intialize.c
@@ -43,39 +43,6 @@
   return;
 }
 
-void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata)
-{
-  int k;
-
-  for (k = 0; k < QLOOKAHEAD; k++) {
-    prefiltdata->INLABUF1[k] = 0;
-    prefiltdata->INLABUF2[k] = 0;
-
-    prefiltdata->INLABUF1_float[k] = 0;
-    prefiltdata->INLABUF2_float[k] = 0;
-  }
-  for (k = 0; k < 2*(QORDER-1); k++) {
-    prefiltdata->INSTAT1[k] = 0;
-    prefiltdata->INSTAT2[k] = 0;
-    prefiltdata->INSTATLA1[k] = 0;
-    prefiltdata->INSTATLA2[k] = 0;
-
-    prefiltdata->INSTAT1_float[k] = 0;
-    prefiltdata->INSTAT2_float[k] = 0;
-    prefiltdata->INSTATLA1_float[k] = 0;
-    prefiltdata->INSTATLA2_float[k] = 0;
-  }
-
-  /* High pass filter states */
-  prefiltdata->HPstates[0] = 0.0;
-  prefiltdata->HPstates[1] = 0.0;
-
-  prefiltdata->HPstates_float[0] = 0.0f;
-  prefiltdata->HPstates_float[1] = 0.0f;
-
-  return;
-}
-
 void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata)
 {
   int k;
@@ -103,69 +70,3 @@
 
   return;
 }
-
-
-void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata)
-{
-  int k;
-
-  for (k = 0; k < PITCH_BUFFSIZE; k++) {
-    pitchfiltdata->ubuf[k] = 0.0;
-  }
-  pitchfiltdata->ystate[0] = 0.0;
-  for (k = 1; k < (PITCH_DAMPORDER); k++) {
-    pitchfiltdata->ystate[k] = 0.0;
-  }
-  pitchfiltdata->oldlagp[0] = 50.0;
-  pitchfiltdata->oldgainp[0] = 0.0;
-}
-
-void WebRtcIsac_InitWeightingFilter(WeightFiltstr *wfdata)
-{
-  int k;
-  double t, dtmp, dtmp2, denum, denum2;
-
-  for (k=0;k<PITCH_WLPCBUFLEN;k++)
-    wfdata->buffer[k]=0.0;
-
-  for (k=0;k<PITCH_WLPCORDER;k++) {
-    wfdata->istate[k]=0.0;
-    wfdata->weostate[k]=0.0;
-    wfdata->whostate[k]=0.0;
-  }
-
-  /* next part should be in Matlab, writing to a global table */
-  t = 0.5;
-  denum = 1.0 / ((double) PITCH_WLPCWINLEN);
-  denum2 = denum * denum;
-  for (k=0;k<PITCH_WLPCWINLEN;k++) {
-    dtmp = PITCH_WLPCASYM * t * denum + (1-PITCH_WLPCASYM) * t * t * denum2;
-    dtmp *= 3.14159265;
-    dtmp2 = sin(dtmp);
-    wfdata->window[k] = dtmp2 * dtmp2;
-    t++;
-  }
-}
-
-/* clear all buffers */
-void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State)
-{
-  int k;
-
-  for (k = 0; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k++)
-    State->dec_buffer[k] = 0.0;
-  for (k = 0; k < 2*ALLPASSSECTIONS+1; k++)
-    State->decimator_state[k] = 0.0;
-  for (k = 0; k < 2; k++)
-    State->hp_state[k] = 0.0;
-  for (k = 0; k < QLOOKAHEAD; k++)
-    State->whitened_buf[k] = 0.0;
-  for (k = 0; k < QLOOKAHEAD; k++)
-    State->inbuf[k] = 0.0;
-
-  WebRtcIsac_InitPitchFilter(&(State->PFstr_wght));
-
-  WebRtcIsac_InitPitchFilter(&(State->PFstr));
-
-  WebRtcIsac_InitWeightingFilter(&(State->Wghtstr));
-}
diff --git a/modules/audio_coding/codecs/isac/main/source/isac.c b/modules/audio_coding/codecs/isac/main/source/isac.c
index 525e0f3..45eb598 100644
--- a/modules/audio_coding/codecs/isac/main/source/isac.c
+++ b/modules/audio_coding/codecs/isac/main/source/isac.c
@@ -31,6 +31,7 @@
 #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
 #include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
 
 #define BIT_MASK_DEC_INIT 0x0001
 #define BIT_MASK_ENC_INIT 0x0002
diff --git a/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc b/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
index 727f0f6..3ec28cc 100644
--- a/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
+++ b/modules/audio_coding/codecs/isac/main/source/isac_unittest.cc
@@ -35,15 +35,13 @@
   uint8_t bitstream_small_[7];  // Simulate sync packets.
 };
 
-IsacTest::IsacTest()
-    : isac_codec_(NULL) {
-}
+IsacTest::IsacTest() : isac_codec_(NULL) {}
 
 void IsacTest::SetUp() {
   // Read some samples from a speech file, to be used in the encode test.
   FILE* input_file;
   const std::string file_name =
-        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+      webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
   input_file = fopen(file_name.c_str(), "rb");
   ASSERT_TRUE(input_file != NULL);
   ASSERT_EQ(kIsacNumberOfSamples,
@@ -69,7 +67,8 @@
 TEST_F(IsacTest, IsacCreateFree) {
   EXPECT_EQ(0, WebRtcIsac_Create(&isac_codec_));
   EXPECT_TRUE(isac_codec_ != NULL);
-  EXPECT_EQ(0, WebRtcIsac_Free(isac_codec_));}
+  EXPECT_EQ(0, WebRtcIsac_Free(isac_codec_));
+}
 
 TEST_F(IsacTest, IsacUpdateBWE) {
   // Create encoder memory.
@@ -86,17 +85,17 @@
                                             12345, 56789));
 
   // Encode 60 ms of data (needed to create a first packet).
-  encoded_bytes =  WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
+  encoded_bytes = WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
   EXPECT_EQ(0, encoded_bytes);
-  encoded_bytes =  WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
+  encoded_bytes = WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
   EXPECT_EQ(0, encoded_bytes);
-  encoded_bytes =  WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
+  encoded_bytes = WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
   EXPECT_EQ(0, encoded_bytes);
-  encoded_bytes =  WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
+  encoded_bytes = WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
   EXPECT_EQ(0, encoded_bytes);
-  encoded_bytes =  WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
+  encoded_bytes = WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
   EXPECT_EQ(0, encoded_bytes);
-  encoded_bytes =  WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
+  encoded_bytes = WebRtcIsac_Encode(isac_codec_, speech_data_, bitstream_);
   EXPECT_GT(encoded_bytes, 0);
 
   // Call to update bandwidth estimator with real data.
diff --git a/modules/audio_coding/codecs/isac/main/source/isac_vad.c b/modules/audio_coding/codecs/isac/main/source/isac_vad.c
new file mode 100644
index 0000000..57cf0c3
--- /dev/null
+++ b/modules/audio_coding/codecs/isac/main/source/isac_vad.c
@@ -0,0 +1,409 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
+
+#include <math.h>
+
+void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata) {
+  int k;
+
+  for (k = 0; k < PITCH_BUFFSIZE; k++) {
+    pitchfiltdata->ubuf[k] = 0.0;
+  }
+  pitchfiltdata->ystate[0] = 0.0;
+  for (k = 1; k < (PITCH_DAMPORDER); k++) {
+    pitchfiltdata->ystate[k] = 0.0;
+  }
+  pitchfiltdata->oldlagp[0] = 50.0;
+  pitchfiltdata->oldgainp[0] = 0.0;
+}
+
+static void WebRtcIsac_InitWeightingFilter(WeightFiltstr* wfdata) {
+  int k;
+  double t, dtmp, dtmp2, denum, denum2;
+
+  for (k = 0; k < PITCH_WLPCBUFLEN; k++)
+    wfdata->buffer[k] = 0.0;
+
+  for (k = 0; k < PITCH_WLPCORDER; k++) {
+    wfdata->istate[k] = 0.0;
+    wfdata->weostate[k] = 0.0;
+    wfdata->whostate[k] = 0.0;
+  }
+
+  /* next part should be in Matlab, writing to a global table */
+  t = 0.5;
+  denum = 1.0 / ((double)PITCH_WLPCWINLEN);
+  denum2 = denum * denum;
+  for (k = 0; k < PITCH_WLPCWINLEN; k++) {
+    dtmp = PITCH_WLPCASYM * t * denum + (1 - PITCH_WLPCASYM) * t * t * denum2;
+    dtmp *= 3.14159265;
+    dtmp2 = sin(dtmp);
+    wfdata->window[k] = dtmp2 * dtmp2;
+    t++;
+  }
+}
+
+void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State) {
+  int k;
+
+  for (k = 0; k < PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 -
+                      PITCH_FRAME_LEN / 2 + 2;
+       k++)
+    State->dec_buffer[k] = 0.0;
+  for (k = 0; k < 2 * ALLPASSSECTIONS + 1; k++)
+    State->decimator_state[k] = 0.0;
+  for (k = 0; k < 2; k++)
+    State->hp_state[k] = 0.0;
+  for (k = 0; k < QLOOKAHEAD; k++)
+    State->whitened_buf[k] = 0.0;
+  for (k = 0; k < QLOOKAHEAD; k++)
+    State->inbuf[k] = 0.0;
+
+  WebRtcIsac_InitPitchFilter(&(State->PFstr_wght));
+
+  WebRtcIsac_InitPitchFilter(&(State->PFstr));
+
+  WebRtcIsac_InitWeightingFilter(&(State->Wghtstr));
+}
+
+void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata) {
+  int k;
+
+  for (k = 0; k < QLOOKAHEAD; k++) {
+    prefiltdata->INLABUF1[k] = 0;
+    prefiltdata->INLABUF2[k] = 0;
+
+    prefiltdata->INLABUF1_float[k] = 0;
+    prefiltdata->INLABUF2_float[k] = 0;
+  }
+  for (k = 0; k < 2 * (QORDER - 1); k++) {
+    prefiltdata->INSTAT1[k] = 0;
+    prefiltdata->INSTAT2[k] = 0;
+    prefiltdata->INSTATLA1[k] = 0;
+    prefiltdata->INSTATLA2[k] = 0;
+
+    prefiltdata->INSTAT1_float[k] = 0;
+    prefiltdata->INSTAT2_float[k] = 0;
+    prefiltdata->INSTATLA1_float[k] = 0;
+    prefiltdata->INSTATLA2_float[k] = 0;
+  }
+
+  /* High pass filter states */
+  prefiltdata->HPstates[0] = 0.0;
+  prefiltdata->HPstates[1] = 0.0;
+
+  prefiltdata->HPstates_float[0] = 0.0f;
+  prefiltdata->HPstates_float[1] = 0.0f;
+
+  return;
+}
+
+double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order) {
+  const double LEVINSON_EPS = 1.0e-10;
+
+  double sum, alpha;
+  size_t m, m_h, i;
+  alpha = 0;  // warning -DH
+  a[0] = 1.0;
+  if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */
+    for (i = 0; i < order; i++) {
+      k[i] = 0;
+      a[i + 1] = 0;
+    }
+  } else {
+    a[1] = k[0] = -r[1] / r[0];
+    alpha = r[0] + r[1] * k[0];
+    for (m = 1; m < order; m++) {
+      sum = r[m + 1];
+      for (i = 0; i < m; i++) {
+        sum += a[i + 1] * r[m - i];
+      }
+      k[m] = -sum / alpha;
+      alpha += k[m] * sum;
+      m_h = (m + 1) >> 1;
+      for (i = 0; i < m_h; i++) {
+        sum = a[i + 1] + k[m] * a[m - i];
+        a[m - i] += k[m] * a[i + 1];
+        a[i + 1] = sum;
+      }
+      a[m + 1] = k[m];
+    }
+  }
+  return alpha;
+}
+
+/* The upper channel all-pass filter factors */
+const float WebRtcIsac_kUpperApFactorsFloat[2] = {0.03470000000000f,
+                                                  0.38260000000000f};
+
+/* The lower channel all-pass filter factors */
+const float WebRtcIsac_kLowerApFactorsFloat[2] = {0.15440000000000f,
+                                                  0.74400000000000f};
+
+/* This function performs all-pass filtering--a series of first order all-pass
+ * sections are used to filter the input in a cascade manner.
+ * The input is overwritten!!
+ */
+void WebRtcIsac_AllPassFilter2Float(float* InOut,
+                                    const float* APSectionFactors,
+                                    int lengthInOut,
+                                    int NumberOfSections,
+                                    float* FilterState) {
+  int n, j;
+  float temp;
+  for (j = 0; j < NumberOfSections; j++) {
+    for (n = 0; n < lengthInOut; n++) {
+      temp = FilterState[j] + APSectionFactors[j] * InOut[n];
+      FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
+      InOut[n] = temp;
+    }
+  }
+}
+
+/* The number of composite all-pass filter factors */
+#define NUMBEROFCOMPOSITEAPSECTIONS 4
+
+/* Function WebRtcIsac_SplitAndFilter
+ * This function creates low-pass and high-pass decimated versions of part of
+ the input signal, and part of the signal in the input 'lookahead buffer'.
+
+ INPUTS:
+ in: a length FRAMESAMPLES array of input samples
+ prefiltdata: input data structure containing the filterbank states
+ and lookahead samples from the previous encoding
+ iteration.
+ OUTPUTS:
+ LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
+ have been phase equalized.  The first QLOOKAHEAD samples are
+ based on the samples in the two prefiltdata->INLABUFx arrays
+ each of length QLOOKAHEAD.
+ The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
+ on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
+ array in[].
+ HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
+ have been phase equalized.  The first QLOOKAHEAD samples are
+ based on the samples in the two prefiltdata->INLABUFx arrays
+ each of length QLOOKAHEAD.
+ The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
+ on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
+ array in[].
+
+ LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
+ These samples are not phase equalized. They are computed
+ from the samples in the in[] array.
+ HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
+ that are not phase equalized. They are computed from
+ the in[] vector.
+ prefiltdata: this input data structure's filterbank state and
+ lookahead sample buffers are updated for the next
+ encoding iteration.
+*/
+void WebRtcIsac_SplitAndFilterFloat(float* pin,
+                                    float* LP,
+                                    float* HP,
+                                    double* LP_la,
+                                    double* HP_la,
+                                    PreFiltBankstr* prefiltdata) {
+  int k, n;
+  float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
+  float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
+  float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
+  float tempinoutvec[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
+  float tempin_ch1[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
+  float tempin_ch2[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
+  float in[FRAMESAMPLES];
+  float ftmp;
+
+  /* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
+  static const float kHpStCoefInFloat[4] = {
+      -1.94895953203325f, 0.94984516000000f, -0.05101826139794f,
+      0.05015484000000f};
+
+  /* The composite all-pass filter factors */
+  static const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
+      0.03470000000000f, 0.15440000000000f, 0.38260000000000f,
+      0.74400000000000f};
+
+  // The matrix for transforming the backward composite state to upper channel
+  // state.
+  static const float WebRtcIsac_kTransform1Float[8] = {
+      -0.00158678506084f, 0.00127157815343f, -0.00104805672709f,
+      0.00084837248079f,  0.00134467983258f, -0.00107756549387f,
+      0.00088814793277f,  -0.00071893072525f};
+
+  // The matrix for transforming the backward composite state to lower channel
+  // state.
+  static const float WebRtcIsac_kTransform2Float[8] = {
+      -0.00170686041697f, 0.00136780109829f, -0.00112736532350f,
+      0.00091257055385f,  0.00103094281812f, -0.00082615076557f,
+      0.00068092756088f,  -0.00055119165484f};
+
+  /* High pass filter */
+
+  for (k = 0; k < FRAMESAMPLES; k++) {
+    in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
+            kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
+    ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
+           kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
+    prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
+    prefiltdata->HPstates_float[0] = ftmp;
+  }
+
+  /* First Channel */
+
+  /*initial state of composite filter is zero */
+  for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+    CompositeAPFilterState[k] = 0.0;
+  }
+  /* put every other sample of input into a temporary vector in reverse
+   * (backward) order*/
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    tempinoutvec[k] = in[FRAMESAMPLES - 1 - 2 * k];
+  }
+
+  /* now all-pass filter the backwards vector.  Output values overwrite the
+   * input vector. */
+  WebRtcIsac_AllPassFilter2Float(
+      tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF,
+      NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+  /* save the backwards filtered output for later forward filtering,
+     but write it in forward order*/
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    tempin_ch1[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k];
+  }
+
+  /* save the backwards filter state  becaue it will be transformed
+     later into a forward state */
+  for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+    ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
+  }
+
+  /* now backwards filter the samples in the lookahead buffer. The samples were
+     placed there in the encoding of the previous frame.  The output samples
+     overwrite the input samples */
+  WebRtcIsac_AllPassFilter2Float(
+      prefiltdata->INLABUF1_float, WebRtcIsac_kCompositeApFactorsFloat,
+      QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+  /* save the output, but write it in forward order */
+  /* write the lookahead samples for the next encoding iteration. Every other
+     sample at the end of the input frame is written in reverse order for the
+     lookahead length. Exported in the prefiltdata structure. */
+  for (k = 0; k < QLOOKAHEAD; k++) {
+    tempin_ch1[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF1_float[k];
+    prefiltdata->INLABUF1_float[k] = in[FRAMESAMPLES - 1 - 2 * k];
+  }
+
+  /* Second Channel.  This is exactly like the first channel, except that the
+     even samples are now filtered instead (lower channel). */
+  for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+    CompositeAPFilterState[k] = 0.0;
+  }
+
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    tempinoutvec[k] = in[FRAMESAMPLES - 2 - 2 * k];
+  }
+
+  WebRtcIsac_AllPassFilter2Float(
+      tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF,
+      NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    tempin_ch2[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k];
+  }
+
+  for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+    ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
+  }
+
+  WebRtcIsac_AllPassFilter2Float(
+      prefiltdata->INLABUF2_float, WebRtcIsac_kCompositeApFactorsFloat,
+      QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+  for (k = 0; k < QLOOKAHEAD; k++) {
+    tempin_ch2[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF2_float[k];
+    prefiltdata->INLABUF2_float[k] = in[FRAMESAMPLES - 2 - 2 * k];
+  }
+
+  /* Transform filter states from backward to forward */
+  /*At this point, each of the states of the backwards composite filters for the
+    two channels are transformed into forward filtering states for the
+    corresponding forward channel filters.  Each channel's forward filtering
+    state from the previous
+    encoding iteration is added to the transformed state to get a proper forward
+    state */
+
+  /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is
+     multiplied by a NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4)
+     transform matrix to get the new state that is added to the previous 2x1
+     input state */
+
+  for (k = 0; k < NUMBEROFCHANNELAPSECTIONS; k++) { /* k is row variable */
+    for (n = 0; n < NUMBEROFCOMPOSITEAPSECTIONS;
+         n++) { /* n is column variable */
+      prefiltdata->INSTAT1_float[k] +=
+          ForTransform_CompositeAPFilterState[n] *
+          WebRtcIsac_kTransform1Float[k * NUMBEROFCHANNELAPSECTIONS + n];
+      prefiltdata->INSTAT2_float[k] +=
+          ForTransform_CompositeAPFilterState2[n] *
+          WebRtcIsac_kTransform2Float[k * NUMBEROFCHANNELAPSECTIONS + n];
+    }
+  }
+
+  /*obtain polyphase components by forward all-pass filtering through each
+   * channel */
+  /* the backward filtered samples are now forward filtered with the
+   * corresponding channel filters */
+  /* The all pass filtering automatically updates the filter states which are
+     exported in the prefiltdata structure */
+  WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat,
+                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+                                 prefiltdata->INSTAT1_float);
+  WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat,
+                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+                                 prefiltdata->INSTAT2_float);
+
+  /* Now Construct low-pass and high-pass signals as combinations of polyphase
+   * components */
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    LP[k] = 0.5f * (tempin_ch1[k] + tempin_ch2[k]); /* low pass signal*/
+    HP[k] = 0.5f * (tempin_ch1[k] - tempin_ch2[k]); /* high pass signal*/
+  }
+
+  /* Lookahead LP and HP signals */
+  /* now create low pass and high pass signals of the input vector.  However, no
+     backwards filtering is performed, and hence no phase equalization is
+     involved. Also, the input contains some samples that are lookahead samples.
+     The high pass and low pass signals that are created are used outside this
+     function for analysis (not encoding) purposes */
+
+  /* set up input */
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    tempin_ch1[k] = in[2 * k + 1];
+    tempin_ch2[k] = in[2 * k];
+  }
+
+  /* the input filter states are passed in and updated by the all-pass filtering
+     routine and exported in the prefiltdata structure*/
+  WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat,
+                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+                                 prefiltdata->INSTATLA1_float);
+  WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat,
+                                 FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+                                 prefiltdata->INSTATLA2_float);
+
+  for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+    LP_la[k] = (float)(0.5f * (tempin_ch1[k] + tempin_ch2[k]));  /*low pass */
+    HP_la[k] = (double)(0.5f * (tempin_ch1[k] - tempin_ch2[k])); /* high pass */
+  }
+}
diff --git a/modules/audio_coding/codecs/isac/main/source/isac_vad.h b/modules/audio_coding/codecs/isac/main/source/isac_vad.h
new file mode 100644
index 0000000..1aecfc4
--- /dev/null
+++ b/modules/audio_coding/codecs/isac/main/source/isac_vad.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
+
+#include <stddef.h>
+
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata);
+void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* state);
+void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata);
+
+double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order);
+
+/* The number of all-pass filter factors in an upper or lower channel*/
+#define NUMBEROFCHANNELAPSECTIONS 2
+
+/* The upper channel all-pass filter factors */
+extern const float WebRtcIsac_kUpperApFactorsFloat[2];
+
+/* The lower channel all-pass filter factors */
+extern const float WebRtcIsac_kLowerApFactorsFloat[2];
+
+void WebRtcIsac_AllPassFilter2Float(float* InOut,
+                                    const float* APSectionFactors,
+                                    int lengthInOut,
+                                    int NumberOfSections,
+                                    float* FilterState);
+void WebRtcIsac_SplitAndFilterFloat(float* in,
+                                    float* LP,
+                                    float* HP,
+                                    double* LP_la,
+                                    double* HP_la,
+                                    PreFiltBankstr* prefiltdata);
+
+#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c b/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c
index dbf33fc..0fda73b 100644
--- a/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c
+++ b/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c
@@ -15,9 +15,8 @@
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
 #include "modules/audio_coding/codecs/isac/main/source/codec.h"
 #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
-
-#define LEVINSON_EPS    1.0e-10
-
+#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
 
 /* window */
 /* Matlab generation code:
@@ -75,45 +74,10 @@
   0.00155690, 0.00124918, 0.00094895, 0.00066112, 0.00039320, 0.00015881
 };
 
-double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order)
-{
-
-  double sum, alpha;
-  size_t m, m_h, i;
-  alpha = 0; //warning -DH
-  a[0] = 1.0;
-  if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */
-    for (i = 0; i < order; i++) {
-      k[i] = 0;
-      a[i+1] = 0;
-    }
-  } else {
-    a[1] = k[0] = -r[1]/r[0];
-    alpha = r[0] + r[1] * k[0];
-    for (m = 1; m < order; m++){
-      sum = r[m + 1];
-      for (i = 0; i < m; i++){
-        sum += a[i+1] * r[m - i];
-      }
-      k[m] = -sum / alpha;
-      alpha += k[m] * sum;
-      m_h = (m + 1) >> 1;
-      for (i = 0; i < m_h; i++){
-        sum = a[i+1] + k[m] * a[m - i];
-        a[m - i] += k[m] * a[i+1];
-        a[i+1] = sum;
-      }
-      a[m+1] = k[m];
-    }
-  }
-  return alpha;
-}
-
-
-//was static before, but didn't work with MEX file
-void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
-                       double *oldEnergy, double *varscale)
-{
+static void WebRtcIsac_GetVars(const double* input,
+                               const int16_t* pitchGains_Q12,
+                               double* oldEnergy,
+                               double* varscale) {
   double nrg[4], chng, pg;
   int k;
 
@@ -162,12 +126,9 @@
   *oldEnergy = nrg[3];
 }
 
-void
-WebRtcIsac_GetVarsUB(
-    const double* input,
-    double*       oldEnergy,
-    double*       varscale)
-{
+static void WebRtcIsac_GetVarsUB(const double* input,
+                                 double* oldEnergy,
+                                 double* varscale) {
   double nrg[4], chng;
   int k;
 
diff --git a/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h b/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h
index c0848ab..5503e2d 100644
--- a/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h
+++ b/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h
@@ -21,30 +21,26 @@
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 
-double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order);
+void WebRtcIsac_GetLpcCoefLb(double* inLo,
+                             double* inHi,
+                             MaskFiltstr* maskdata,
+                             double signal_noise_ratio,
+                             const int16_t* pitchGains_Q12,
+                             double* lo_coeff,
+                             double* hi_coeff);
 
-void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
-                       double *oldEnergy, double *varscale);
+void WebRtcIsac_GetLpcGain(double signal_noise_ratio,
+                           const double* filtCoeffVecs,
+                           int numVecs,
+                           double* gain,
+                           double corrLo[][UB_LPC_ORDER + 1],
+                           const double* varscale);
 
-void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata,
-                             double signal_noise_ratio, const int16_t *pitchGains_Q12,
-                             double *lo_coeff, double *hi_coeff);
-
-
-void WebRtcIsac_GetLpcGain(
-    double         signal_noise_ratio,
-    const double*  filtCoeffVecs,
-    int            numVecs,
-    double*        gain,
-    double         corrLo[][UB_LPC_ORDER + 1],
-    const double*  varscale);
-
-void WebRtcIsac_GetLpcCoefUb(
-    double*      inSignal,
-    MaskFiltstr* maskdata,
-    double*      lpCoeff,
-    double       corr[][UB_LPC_ORDER + 1],
-    double*      varscale,
-    int16_t  bandwidth);
+void WebRtcIsac_GetLpcCoefUb(double* inSignal,
+                             MaskFiltstr* maskdata,
+                             double* lpCoeff,
+                             double corr[][UB_LPC_ORDER + 1],
+                             double* varscale,
+                             int16_t bandwidth);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h b/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h
index 7a5abfd..84913dd 100644
--- a/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h
@@ -46,4 +46,4 @@
 
 extern const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES];
 
-#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
+#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h b/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h
index 7bae096..e21e15a 100644
--- a/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h
@@ -26,22 +26,22 @@
 
 extern const double WebRtcIsac_kMeanLpcGain;
 
-extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER];
+extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER]
+                                                     [UB_LPC_ORDER];
 
-extern const double WebRtcIsac_kInterVecDecorrMatUb12
-[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME];
+extern const double WebRtcIsac_kInterVecDecorrMatUb12[UB_LPC_VEC_PER_FRAME]
+                                                     [UB_LPC_VEC_PER_FRAME];
 
 extern const double WebRtcIsac_kLpcShapeQStepSizeUb12;
 
-extern const double WebRtcIsac_kLpcShapeLeftRecPointUb12
-[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME];
+extern const double
+    WebRtcIsac_kLpcShapeLeftRecPointUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
 
+extern const int16_t
+    WebRtcIsac_kLpcShapeNumRecPointUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
 
-extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb12
-[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
-
-extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb12
-[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
+extern const uint16_t
+    WebRtcIsac_kLpcShapeEntropySearchUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
 
 extern const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14];
 
@@ -59,7 +59,7 @@
 
 extern const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub12[49];
 
-extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb12
-[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
+extern const uint16_t*
+    WebRtcIsac_kLpcShapeCdfMatUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
 
-#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
+#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h b/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h
index d828b83..4d5403d 100644
--- a/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h
@@ -24,10 +24,11 @@
 
 extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER];
 
-extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER];
+extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER]
+                                                      [UB_LPC_ORDER];
 
-extern const double WebRtcIsac_kInterVecDecorrMatUb16
-[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME];
+extern const double WebRtcIsac_kInterVecDecorrMatUb16[UB16_LPC_VEC_PER_FRAME]
+                                                     [UB16_LPC_VEC_PER_FRAME];
 
 extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14];
 
@@ -61,18 +62,19 @@
 
 extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub166[71];
 
-extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const uint16_t*
+    WebRtcIsac_kLpcShapeCdfMatUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
 
-extern const double WebRtcIsac_kLpcShapeLeftRecPointUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const double
+    WebRtcIsac_kLpcShapeLeftRecPointUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
 
-extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const int16_t
+    WebRtcIsac_kLpcShapeNumRecPointUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
 
-extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const uint16_t
+    WebRtcIsac_kLpcShapeEntropySearchUb16[UB_LPC_ORDER *
+                                          UB16_LPC_VEC_PER_FRAME];
 
 extern const double WebRtcIsac_kLpcShapeQStepSizeUb16;
 
-#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
+#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/lpc_tables.h b/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
index 2b02557..2d92dfa 100644
--- a/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
@@ -22,27 +22,27 @@
 
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
 
-#define KLT_STEPSIZE         1.00000000
-#define KLT_NUM_AVG_GAIN     0
-#define KLT_NUM_AVG_SHAPE    0
-#define KLT_NUM_MODELS  3
-#define LPC_GAIN_SCALE     4.000f
-#define LPC_LOBAND_SCALE   2.100f
-#define LPC_LOBAND_ORDER   ORDERLO
-#define LPC_HIBAND_SCALE   0.450f
-#define LPC_HIBAND_ORDER   ORDERHI
-#define LPC_GAIN_ORDER     2
+#define KLT_STEPSIZE 1.00000000
+#define KLT_NUM_AVG_GAIN 0
+#define KLT_NUM_AVG_SHAPE 0
+#define KLT_NUM_MODELS 3
+#define LPC_GAIN_SCALE 4.000f
+#define LPC_LOBAND_SCALE 2.100f
+#define LPC_LOBAND_ORDER ORDERLO
+#define LPC_HIBAND_SCALE 0.450f
+#define LPC_HIBAND_ORDER ORDERHI
+#define LPC_GAIN_ORDER 2
 
-#define LPC_SHAPE_ORDER    (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER)
+#define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER)
 
-#define KLT_ORDER_GAIN     (LPC_GAIN_ORDER * SUBFRAMES)
-#define KLT_ORDER_SHAPE    (LPC_SHAPE_ORDER * SUBFRAMES)
+#define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES)
+#define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES)
 
 /* cdf array for model indicator */
-extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS+1];
+extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS + 1];
 
 /* pointer to cdf array for model indicator */
-extern const uint16_t *WebRtcIsac_kQKltModelCdfPtr[1];
+extern const uint16_t* WebRtcIsac_kQKltModelCdfPtr[1];
 
 /* initial cdf index for decoder of model indicator */
 extern const uint16_t WebRtcIsac_kQKltModelInitIndex[1];
@@ -78,9 +78,9 @@
 extern const uint16_t WebRtcIsac_kQKltCdfShape[686];
 
 /* pointers to cdf tables for quantizer indices */
-extern const uint16_t *WebRtcIsac_kQKltCdfPtrGain[12];
+extern const uint16_t* WebRtcIsac_kQKltCdfPtrGain[12];
 
-extern const uint16_t *WebRtcIsac_kQKltCdfPtrShape[108];
+extern const uint16_t* WebRtcIsac_kQKltCdfPtrShape[108];
 
 /* left KLT transforms */
 extern const double WebRtcIsac_kKltT1Gain[4];
diff --git a/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h b/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h
index 597dc21..f72236d 100644
--- a/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h
+++ b/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
 
@@ -24,11 +23,12 @@
   __asm {
     fld x_dbl
     fistp x_int
-  };
+  }
+  ;
 
   return x_int;
 }
-#else // Do a slow but correct implementation of lrint
+#else  // Do a slow but correct implementation of lrint
 
 static __inline long int WebRtcIsac_lrint(double x_dbl) {
   long int x_int;
diff --git a/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c b/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c
index 4c0a558..8a19ac1 100644
--- a/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c
+++ b/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c
@@ -8,6 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+
 #include <math.h>
 #include <memory.h>
 #include <string.h>
@@ -15,7 +17,9 @@
 #include <stdlib.h>
 #endif
 
-#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
+#include "rtc_base/system/ignore_warnings.h"
 
 static const double kInterpolWin[8] = {-0.00067556028640,  0.02184247643159, -0.12203175715679,  0.60086484101160,
                                        0.60086484101160, -0.12203175715679,  0.02184247643159, -0.00067556028640};
@@ -122,13 +126,56 @@
   }
 }
 
+static void WebRtcIsac_AllpassFilterForDec(double* InOut,
+                                           const double* APSectionFactors,
+                                           size_t lengthInOut,
+                                           double* FilterState) {
+  // This performs all-pass filtering--a series of first order all-pass
+  // sections are used to filter the input in a cascade manner.
+  size_t n, j;
+  double temp;
+  for (j = 0; j < ALLPASSSECTIONS; j++) {
+    for (n = 0; n < lengthInOut; n += 2) {
+      temp = InOut[n];  // store input
+      InOut[n] = FilterState[j] + APSectionFactors[j] * temp;
+      FilterState[j] = -APSectionFactors[j] * InOut[n] + temp;
+    }
+  }
+}
 
-void WebRtcIsac_InitializePitch(const double *in,
-                                const double old_lag,
-                                const double old_gain,
-                                PitchAnalysisStruct *State,
-                                double *lags)
-{
+static void WebRtcIsac_DecimateAllpass(
+    const double* in,
+    double* state_in,  // array of size: 2*ALLPASSSECTIONS+1
+    size_t N,          // number of input samples
+    double* out) {     // array of size N/2
+
+  static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
+  static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
+
+  size_t n;
+  double data_vec[PITCH_FRAME_LEN];
+
+  /* copy input */
+  memcpy(data_vec + 1, in, sizeof(double) * (N - 1));
+
+  data_vec[0] = state_in[2 * ALLPASSSECTIONS];  // the z^(-1) state
+  state_in[2 * ALLPASSSECTIONS] = in[N - 1];
+
+  WebRtcIsac_AllpassFilterForDec(data_vec + 1, APupper, N, state_in);
+  WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N,
+                                 state_in + ALLPASSSECTIONS);
+
+  for (n = 0; n < N / 2; n++)
+    out[n] = data_vec[2 * n] + data_vec[2 * n + 1];
+}
+
+RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
+
+static void WebRtcIsac_InitializePitch(const double* in,
+                                       const double old_lag,
+                                       const double old_gain,
+                                       PitchAnalysisStruct* State,
+                                       double* lags) {
   double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2];
   double ratio, log_lag, gain_bias;
   double bias;
@@ -449,7 +496,7 @@
   }
 }
 
-
+RTC_POP_IGNORING_WFRAME_LARGER_THAN()
 
 /* create weighting matrix by orthogonalizing a basis of polynomials of increasing order
  * t = (0:4)';
@@ -464,6 +511,29 @@
   { 0.01714285714286,   0.05142857142857,  -0.05714285714286,  -0.30857142857143,  0.29714285714286}
 };
 
+/* second order high-pass filter */
+static void WebRtcIsac_Highpass(const double* in,
+                         double* out,
+                         double* state,
+                         size_t N) {
+  /* create high-pass filter ocefficients
+   * z = 0.998 * exp(j*2*pi*35/8000);
+   * p = 0.94 * exp(j*2*pi*140/8000);
+   * HP_b = [1, -2*real(z), abs(z)^2];
+   * HP_a = [1, -2*real(p), abs(p)^2]; */
+  static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
+  static const double b_coef[2] = {-1.99524591718270,  0.99600400000000};
+
+  size_t k;
+
+  for (k=0; k<N; k++) {
+    *out = *in + state[1];
+    state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
+    state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
+  }
+}
+
+RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
 
 void WebRtcIsac_PitchAnalysis(const double *in,               /* PITCH_FRAME_LEN samples */
                               double *out,                    /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
@@ -621,3 +691,5 @@
   for (k = 0; k < QLOOKAHEAD; k++)
     State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN];
 }
+
+RTC_POP_IGNORING_WFRAME_LARGER_THAN()
diff --git a/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h b/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h
index 47dab0e..4ab78c2 100644
--- a/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h
+++ b/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h
@@ -18,56 +18,15 @@
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
 
+#include <stddef.h>
+
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 
-void WebRtcIsac_PitchAnalysis(const double *in,               /* PITCH_FRAME_LEN samples */
-                              double *out,                    /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
-                              PitchAnalysisStruct *State,
-                              double *lags,
-                              double *gains);
-
-void WebRtcIsac_InitializePitch(const double *in,
-                                const double old_lag,
-                                const double old_gain,
-                                PitchAnalysisStruct *State,
-                                double *lags);
-
-void WebRtcIsac_PitchfilterPre(double *indat,
-                               double *outdat,
-                               PitchFiltstr *pfp,
-                               double *lags,
-                               double *gains);
-
-void WebRtcIsac_PitchfilterPost(double *indat,
-                                double *outdat,
-                                PitchFiltstr *pfp,
-                                double *lags,
-                                double *gains);
-
-void WebRtcIsac_PitchfilterPre_la(double *indat,
-                                  double *outdat,
-                                  PitchFiltstr *pfp,
-                                  double *lags,
-                                  double *gains);
-
-void WebRtcIsac_PitchfilterPre_gains(double *indat,
-                                     double *outdat,
-                                     double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD],
-                                     PitchFiltstr *pfp,
-                                     double *lags,
-                                     double *gains);
-
-void WebRtcIsac_WeightingFilter(const double *in, double *weiout, double *whiout, WeightFiltstr *wfdata);
-
-void WebRtcIsac_Highpass(const double *in,
-                         double *out,
-                         double *state,
-                         size_t N);
-
-void WebRtcIsac_DecimateAllpass(const double *in,
-                                double *state_in,  /* array of size:
-                                                    *     2*ALLPASSSECTIONS+1 */
-                                size_t N,          /* number of input samples */
-                                double *out);      /* array of size N/2 */
+void WebRtcIsac_PitchAnalysis(
+    const double* in, /* PITCH_FRAME_LEN samples */
+    double* out,      /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
+    PitchAnalysisStruct* State,
+    double* lags,
+    double* gains);
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/pitch_filter.h b/modules/audio_coding/codecs/isac/main/source/pitch_filter.h
new file mode 100644
index 0000000..9a232de
--- /dev/null
+++ b/modules/audio_coding/codecs/isac/main/source/pitch_filter.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
+
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_PitchfilterPre(double* indat,
+                               double* outdat,
+                               PitchFiltstr* pfp,
+                               double* lags,
+                               double* gains);
+
+void WebRtcIsac_PitchfilterPost(double* indat,
+                                double* outdat,
+                                PitchFiltstr* pfp,
+                                double* lags,
+                                double* gains);
+
+void WebRtcIsac_PitchfilterPre_la(double* indat,
+                                  double* outdat,
+                                  PitchFiltstr* pfp,
+                                  double* lags,
+                                  double* gains);
+
+void WebRtcIsac_PitchfilterPre_gains(
+    double* indat,
+    double* outdat,
+    double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD],
+    PitchFiltstr* pfp,
+    double* lags,
+    double* gains);
+
+#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
diff --git a/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h b/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h
index fe506ee..891bcef 100644
--- a/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h
@@ -11,7 +11,8 @@
 /*
  * pitch_gain_tables.h
  *
- * This file contains tables for the pitch filter side-info in the entropy coder.
+ * This file contains tables for the pitch filter side-info in the entropy
+ * coder.
  *
  */
 
@@ -20,8 +21,10 @@
 
 #include "typedefs.h"  // NOLINT(build/include)
 
-/* header file for coding tables for the pitch filter side-info in the entropy coder */
-/********************* Pitch Filter Gain Coefficient Tables ************************/
+/* header file for coding tables for the pitch filter side-info in the entropy
+ * coder */
+/********************* Pitch Filter Gain Coefficient Tables
+ * ************************/
 /* cdf for quantized pitch filter gains */
 extern const uint16_t WebRtcIsac_kQPitchGainCdf[255];
 
diff --git a/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h b/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h
index 6a57c87..b662ab5 100644
--- a/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h
@@ -11,7 +11,8 @@
 /*
  * pitch_lag_tables.h
  *
- * This file contains tables for the pitch filter side-info in the entropy coder.
+ * This file contains tables for the pitch filter side-info in the entropy
+ * coder.
  *
  */
 
@@ -19,8 +20,10 @@
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
 
 #include "typedefs.h"  // NOLINT(build/include)
-/* header file for coding tables for the pitch filter side-info in the entropy coder */
-/********************* Pitch Filter Lag Coefficient Tables ************************/
+/* header file for coding tables for the pitch filter side-info in the entropy
+ * coder */
+/********************* Pitch Filter Lag Coefficient Tables
+ * ************************/
 
 /* tables for use with small pitch gain */
 
@@ -30,7 +33,7 @@
 extern const uint16_t WebRtcIsac_kQPitchLagCdf3Lo[2];
 extern const uint16_t WebRtcIsac_kQPitchLagCdf4Lo[10];
 
-extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrLo[4];
+extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrLo[4];
 
 /* size of first cdf table */
 extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1];
@@ -49,7 +52,6 @@
 
 extern const double WebRtcIsac_kQPitchLagStepsizeLo;
 
-
 /* tables for use with medium pitch gain */
 
 /* cdfs for quantized pitch lags */
@@ -58,7 +60,7 @@
 extern const uint16_t WebRtcIsac_kQPitchLagCdf3Mid[2];
 extern const uint16_t WebRtcIsac_kQPitchLagCdf4Mid[20];
 
-extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrMid[4];
+extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrMid[4];
 
 /* size of first cdf table */
 extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1];
@@ -77,7 +79,6 @@
 
 extern const double WebRtcIsac_kQPitchLagStepsizeMid;
 
-
 /* tables for use with large pitch gain */
 
 /* cdfs for quantized pitch lags */
@@ -86,7 +87,7 @@
 extern const uint16_t WebRtcIsac_kQPitchLagCdf3Hi[2];
 extern const uint16_t WebRtcIsac_kQPitchLagCdf4Hi[35];
 
-extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrHi[4];
+extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrHi[4];
 
 /* size of first cdf table */
 extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1];
diff --git a/modules/audio_coding/codecs/isac/main/source/settings.h b/modules/audio_coding/codecs/isac/main/source/settings.h
index c08d72f..14a5be8 100644
--- a/modules/audio_coding/codecs/isac/main/source/settings.h
+++ b/modules/audio_coding/codecs/isac/main/source/settings.h
@@ -19,187 +19,181 @@
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
 
 /* sampling frequency (Hz) */
-#define FS                                      16000
+#define FS 16000
 
 /* number of samples per frame (either 320 (20ms), 480 (30ms) or 960 (60ms)) */
-#define INITIAL_FRAMESAMPLES     960
-
+#define INITIAL_FRAMESAMPLES 960
 
 #define MAXFFTSIZE 2048
 #define NFACTOR 11
 
-
-
 /* do not modify the following; this will have to be modified if we
  * have a 20ms framesize option */
 /**********************************************************************/
 /* miliseconds */
-#define FRAMESIZE                               30
+#define FRAMESIZE 30
 /* number of samples per frame processed in the encoder, 480 */
-#define FRAMESAMPLES                            480 /* ((FRAMESIZE*FS)/1000) */
-#define FRAMESAMPLES_HALF      240
-#define FRAMESAMPLES_QUARTER                    120
+#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */
+#define FRAMESAMPLES_HALF 240
+#define FRAMESAMPLES_QUARTER 120
 /**********************************************************************/
 
-
-
 /* max number of samples per frame (= 60 ms frame) */
-#define MAX_FRAMESAMPLES      960
-#define MAX_SWBFRAMESAMPLES                     (MAX_FRAMESAMPLES * 2)
+#define MAX_FRAMESAMPLES 960
+#define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2)
 /* number of samples per 10ms frame */
-#define FRAMESAMPLES_10ms                       ((10*FS)/1000)
-#define SWBFRAMESAMPLES_10ms                    (FRAMESAMPLES_10ms * 2)
+#define FRAMESAMPLES_10ms ((10 * FS) / 1000)
+#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2)
 /* number of samples in 30 ms frame */
-#define FRAMESAMPLES_30ms            480
+#define FRAMESAMPLES_30ms 480
 /* number of subframes */
-#define SUBFRAMES                               6
+#define SUBFRAMES 6
 /* length of a subframe */
-#define UPDATE                                  80
+#define UPDATE 80
 /* length of half a subframe (low/high band) */
-#define HALF_SUBFRAMELEN                        (UPDATE/2)
+#define HALF_SUBFRAMELEN (UPDATE / 2)
 /* samples of look ahead (in a half-band, so actually
  * half the samples of look ahead @ FS) */
-#define QLOOKAHEAD                              24    /* 3 ms */
+#define QLOOKAHEAD 24 /* 3 ms */
 /* order of AR model in spectral entropy coder */
-#define AR_ORDER                                6
+#define AR_ORDER 6
 /* order of LP model in spectral entropy coder */
-#define LP_ORDER                                0
+#define LP_ORDER 0
 
 /* window length (masking analysis) */
-#define WINLEN                                  256
+#define WINLEN 256
 /* order of low-band pole filter used to approximate masking curve */
-#define ORDERLO                                 12
+#define ORDERLO 12
 /* order of hi-band pole filter used to approximate masking curve */
-#define ORDERHI                                 6
+#define ORDERHI 6
 
-#define UB_LPC_ORDER                            4
-#define UB_LPC_VEC_PER_FRAME                    2
-#define UB16_LPC_VEC_PER_FRAME                  4
-#define UB_ACTIVE_SUBFRAMES                     2
-#define UB_MAX_LPC_ORDER                        6
-#define UB_INTERPOL_SEGMENTS                    1
-#define UB16_INTERPOL_SEGMENTS                  3
-#define LB_TOTAL_DELAY_SAMPLES                 48
-enum ISACBandwidth {isac8kHz = 8, isac12kHz = 12, isac16kHz = 16};
-enum ISACBand {kIsacLowerBand = 0, kIsacUpperBand12 = 1, kIsacUpperBand16 = 2};
-enum IsacSamplingRate {kIsacWideband = 16,  kIsacSuperWideband = 32};
-#define UB_LPC_GAIN_DIM                 SUBFRAMES
-#define FB_STATE_SIZE_WORD32                    6
-
+#define UB_LPC_ORDER 4
+#define UB_LPC_VEC_PER_FRAME 2
+#define UB16_LPC_VEC_PER_FRAME 4
+#define UB_ACTIVE_SUBFRAMES 2
+#define UB_MAX_LPC_ORDER 6
+#define UB_INTERPOL_SEGMENTS 1
+#define UB16_INTERPOL_SEGMENTS 3
+#define LB_TOTAL_DELAY_SAMPLES 48
+enum ISACBandwidth { isac8kHz = 8, isac12kHz = 12, isac16kHz = 16 };
+enum ISACBand {
+  kIsacLowerBand = 0,
+  kIsacUpperBand12 = 1,
+  kIsacUpperBand16 = 2
+};
+enum IsacSamplingRate { kIsacWideband = 16, kIsacSuperWideband = 32 };
+#define UB_LPC_GAIN_DIM SUBFRAMES
+#define FB_STATE_SIZE_WORD32 6
 
 /* order for post_filter_bank */
-#define POSTQORDER                              3
+#define POSTQORDER 3
 /* order for pre-filterbank */
-#define QORDER                                  3
+#define QORDER 3
 /* another order */
-#define QORDER_ALL                              (POSTQORDER+QORDER-1)
+#define QORDER_ALL (POSTQORDER + QORDER - 1)
 /* for decimator */
-#define ALLPASSSECTIONS                         2
-
+#define ALLPASSSECTIONS 2
 
 /* array size for byte stream in number of bytes. */
 /* The old maximum size still needed for the decoding */
-#define STREAM_SIZE_MAX     600
-#define STREAM_SIZE_MAX_30  200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */
-#define STREAM_SIZE_MAX_60  400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */
+#define STREAM_SIZE_MAX 600
+#define STREAM_SIZE_MAX_30 200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */
+#define STREAM_SIZE_MAX_60 400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */
 
 /* storage size for bit counts */
-#define BIT_COUNTER_SIZE                        30
+#define BIT_COUNTER_SIZE 30
 /* maximum order of any AR model or filter */
-#define MAX_AR_MODEL_ORDER                      12//50
-
+#define MAX_AR_MODEL_ORDER 12  // 50
 
 /* For pitch analysis */
-#define PITCH_FRAME_LEN                         (FRAMESAMPLES_HALF) /* 30 ms  */
-#define PITCH_MAX_LAG                           140     /* 57 Hz  */
-#define PITCH_MIN_LAG                           20              /* 400 Hz */
-#define PITCH_MAX_GAIN                          0.45
-#define PITCH_MAX_GAIN_06                       0.27  /* PITCH_MAX_GAIN*0.6 */
-#define PITCH_MAX_GAIN_Q12      1843
-#define PITCH_LAG_SPAN2                     (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5)
-#define PITCH_CORR_LEN2                         60     /* 15 ms  */
-#define PITCH_CORR_STEP2                        (PITCH_FRAME_LEN/4)
-#define PITCH_BW        11     /* half the band width of correlation surface */
-#define PITCH_SUBFRAMES                         4
-#define PITCH_GRAN_PER_SUBFRAME                 5
-#define PITCH_SUBFRAME_LEN        (PITCH_FRAME_LEN/PITCH_SUBFRAMES)
-#define PITCH_UPDATE              (PITCH_SUBFRAME_LEN/PITCH_GRAN_PER_SUBFRAME)
+#define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms  */
+#define PITCH_MAX_LAG 140                   /* 57 Hz  */
+#define PITCH_MIN_LAG 20                    /* 400 Hz */
+#define PITCH_MAX_GAIN 0.45
+#define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */
+#define PITCH_MAX_GAIN_Q12 1843
+#define PITCH_LAG_SPAN2 (PITCH_MAX_LAG / 2 - PITCH_MIN_LAG / 2 + 5)
+#define PITCH_CORR_LEN2 60 /* 15 ms  */
+#define PITCH_CORR_STEP2 (PITCH_FRAME_LEN / 4)
+#define PITCH_BW 11 /* half the band width of correlation surface */
+#define PITCH_SUBFRAMES 4
+#define PITCH_GRAN_PER_SUBFRAME 5
+#define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN / PITCH_SUBFRAMES)
+#define PITCH_UPDATE (PITCH_SUBFRAME_LEN / PITCH_GRAN_PER_SUBFRAME)
 /* maximum number of peaks to be examined in correlation surface */
-#define PITCH_MAX_NUM_PEAKS                  10
-#define PITCH_PEAK_DECAY               0.85
+#define PITCH_MAX_NUM_PEAKS 10
+#define PITCH_PEAK_DECAY 0.85
 /* For weighting filter */
-#define PITCH_WLPCORDER                   6
-#define PITCH_WLPCWINLEN               PITCH_FRAME_LEN
-#define PITCH_WLPCASYM                   0.3         /* asymmetry parameter */
-#define PITCH_WLPCBUFLEN               PITCH_WLPCWINLEN
+#define PITCH_WLPCORDER 6
+#define PITCH_WLPCWINLEN PITCH_FRAME_LEN
+#define PITCH_WLPCASYM 0.3 /* asymmetry parameter */
+#define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN
 /* For pitch filter */
 /* Extra 50 for fraction and LP filters */
-#define PITCH_BUFFSIZE                   (PITCH_MAX_LAG + 50)
-#define PITCH_INTBUFFSIZE               (PITCH_FRAME_LEN+PITCH_BUFFSIZE)
+#define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50)
+#define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN + PITCH_BUFFSIZE)
 /* Max rel. step for interpolation */
-#define PITCH_UPSTEP                1.5
+#define PITCH_UPSTEP 1.5
 /* Max rel. step for interpolation */
-#define PITCH_DOWNSTEP                   0.67
-#define PITCH_FRACS                             8
-#define PITCH_FRACORDER                         9
-#define PITCH_DAMPORDER                         5
-#define PITCH_FILTDELAY                         1.5f
+#define PITCH_DOWNSTEP 0.67
+#define PITCH_FRACS 8
+#define PITCH_FRACORDER 9
+#define PITCH_DAMPORDER 5
+#define PITCH_FILTDELAY 1.5f
 /* stepsize for quantization of the pitch Gain */
-#define PITCH_GAIN_STEPSIZE                     0.125
-
-
+#define PITCH_GAIN_STEPSIZE 0.125
 
 /* Order of high pass filter */
-#define HPORDER                                 2
+#define HPORDER 2
 
 /* some mathematical constants */
 /* log2(exp) */
-#define LOG2EXP                                 1.44269504088896
-#define PI                                      3.14159265358979
+#define LOG2EXP 1.44269504088896
+#define PI 3.14159265358979
 
 /* Maximum number of iterations allowed to limit payload size */
-#define MAX_PAYLOAD_LIMIT_ITERATION             5
+#define MAX_PAYLOAD_LIMIT_ITERATION 5
 
 /* Redundant Coding */
-#define RCU_BOTTLENECK_BPS                      16000
-#define RCU_TRANSCODING_SCALE                   0.40f
-#define RCU_TRANSCODING_SCALE_INVERSE           2.5f
+#define RCU_BOTTLENECK_BPS 16000
+#define RCU_TRANSCODING_SCALE 0.40f
+#define RCU_TRANSCODING_SCALE_INVERSE 2.5f
 
-#define RCU_TRANSCODING_SCALE_UB                0.50f
-#define RCU_TRANSCODING_SCALE_UB_INVERSE        2.0f
+#define RCU_TRANSCODING_SCALE_UB 0.50f
+#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f
 
 /* Define Error codes */
 /* 6000 General */
-#define ISAC_MEMORY_ALLOCATION_FAILED    6010
-#define ISAC_MODE_MISMATCH       6020
-#define ISAC_DISALLOWED_BOTTLENECK     6030
-#define ISAC_DISALLOWED_FRAME_LENGTH    6040
-#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY         6050
+#define ISAC_MEMORY_ALLOCATION_FAILED 6010
+#define ISAC_MODE_MISMATCH 6020
+#define ISAC_DISALLOWED_BOTTLENECK 6030
+#define ISAC_DISALLOWED_FRAME_LENGTH 6040
+#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050
 
 /* 6200 Bandwidth estimator */
-#define ISAC_RANGE_ERROR_BW_ESTIMATOR    6240
+#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240
 /* 6400 Encoder */
-#define ISAC_ENCODER_NOT_INITIATED     6410
-#define ISAC_DISALLOWED_CODING_MODE     6420
-#define ISAC_DISALLOWED_FRAME_MODE_ENCODER   6430
-#define ISAC_DISALLOWED_BITSTREAM_LENGTH            6440
-#define ISAC_PAYLOAD_LARGER_THAN_LIMIT              6450
-#define ISAC_DISALLOWED_ENCODER_BANDWIDTH           6460
+#define ISAC_ENCODER_NOT_INITIATED 6410
+#define ISAC_DISALLOWED_CODING_MODE 6420
+#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430
+#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440
+#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450
+#define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460
 /* 6600 Decoder */
-#define ISAC_DECODER_NOT_INITIATED     6610
-#define ISAC_EMPTY_PACKET       6620
-#define ISAC_DISALLOWED_FRAME_MODE_DECODER   6630
-#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH  6640
-#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH   6650
-#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN   6660
-#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG   6670
-#define ISAC_RANGE_ERROR_DECODE_LPC     6680
-#define ISAC_RANGE_ERROR_DECODE_SPECTRUM   6690
-#define ISAC_LENGTH_MISMATCH      6730
-#define ISAC_RANGE_ERROR_DECODE_BANDWITH            6740
-#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER      6750
-#define ISAC_DISALLOWED_LPC_MODEL                   6760
+#define ISAC_DECODER_NOT_INITIATED 6610
+#define ISAC_EMPTY_PACKET 6620
+#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630
+#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640
+#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650
+#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660
+#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670
+#define ISAC_RANGE_ERROR_DECODE_LPC 6680
+#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690
+#define ISAC_LENGTH_MISMATCH 6730
+#define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740
+#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750
+#define ISAC_DISALLOWED_LPC_MODEL 6760
 /* 6800 Call setup formats */
-#define ISAC_INCOMPATIBLE_FORMATS     6810
+#define ISAC_INCOMPATIBLE_FORMATS 6810
 
 #endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h b/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h
index 1e656eb..d272be0 100644
--- a/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h
+++ b/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h
@@ -11,7 +11,7 @@
 /*
  * spectrum_ar_model_tables.h
  *
- * This file contains definitions of tables with AR coefficients, 
+ * This file contains definitions of tables with AR coefficients,
  * Gain coefficients and cosine tables.
  *
  */
@@ -45,15 +45,15 @@
 /* quantization boundary levels for reflection coefficients */
 extern const int16_t WebRtcIsac_kQArBoundaryLevels[NUM_AR_RC_QUANT_BAUNDARY];
 
-/* initial indices for AR reflection coefficient quantizer and cdf table search */
+/* initial indices for AR reflection coefficient quantizer and cdf table search
+ */
 extern const uint16_t WebRtcIsac_kQArRcInitIndex[AR_ORDER];
 
 /* pointers to AR cdf tables */
-extern const uint16_t *WebRtcIsac_kQArRcCdfPtr[AR_ORDER];
+extern const uint16_t* WebRtcIsac_kQArRcCdfPtr[AR_ORDER];
 
 /* pointers to AR representation levels tables */
-extern const int16_t *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
-
+extern const int16_t* WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
 
 /******************** GAIN Coefficient Tables ***********************/
 /* cdf for Gain coefficient */
@@ -66,7 +66,7 @@
 extern const int32_t WebRtcIsac_kQGain2BoundaryLevels[19];
 
 /* pointer to Gain cdf table */
-extern const uint16_t *WebRtcIsac_kQGainCdf_ptr[1];
+extern const uint16_t* WebRtcIsac_kQGainCdf_ptr[1];
 
 /* Gain initial index for gain quantizer and cdf table search */
 extern const uint16_t WebRtcIsac_kQGainInitIndex[1];
@@ -75,4 +75,5 @@
 /* Cosine table */
 extern const int16_t WebRtcIsac_kCos[6][60];
 
-#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ \
+        */
diff --git a/modules/audio_coding/codecs/isac/main/source/structs.h b/modules/audio_coding/codecs/isac/main/source/structs.h
index ef4282b..f8ac9c7 100644
--- a/modules/audio_coding/codecs/isac/main/source/structs.h
+++ b/modules/audio_coding/codecs/isac/main/source/structs.h
@@ -19,183 +19,170 @@
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
 
 #include "modules/audio_coding/codecs/isac/bandwidth_info.h"
-#include "modules/audio_coding/codecs/isac/main/include/isac.h"
 #include "modules/audio_coding/codecs/isac/main/source/settings.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 typedef struct Bitstreamstruct {
-
-  uint8_t   stream[STREAM_SIZE_MAX];
-  uint32_t  W_upper;
-  uint32_t  streamval;
-  uint32_t  stream_index;
+  uint8_t stream[STREAM_SIZE_MAX];
+  uint32_t W_upper;
+  uint32_t streamval;
+  uint32_t stream_index;
 
 } Bitstr;
 
 typedef struct {
+  double DataBufferLo[WINLEN];
+  double DataBufferHi[WINLEN];
 
-  double    DataBufferLo[WINLEN];
-  double    DataBufferHi[WINLEN];
+  double CorrBufLo[ORDERLO + 1];
+  double CorrBufHi[ORDERHI + 1];
 
-  double    CorrBufLo[ORDERLO+1];
-  double    CorrBufHi[ORDERHI+1];
+  float PreStateLoF[ORDERLO + 1];
+  float PreStateLoG[ORDERLO + 1];
+  float PreStateHiF[ORDERHI + 1];
+  float PreStateHiG[ORDERHI + 1];
+  float PostStateLoF[ORDERLO + 1];
+  float PostStateLoG[ORDERLO + 1];
+  float PostStateHiF[ORDERHI + 1];
+  float PostStateHiG[ORDERHI + 1];
 
-  float    PreStateLoF[ORDERLO+1];
-  float    PreStateLoG[ORDERLO+1];
-  float    PreStateHiF[ORDERHI+1];
-  float    PreStateHiG[ORDERHI+1];
-  float    PostStateLoF[ORDERLO+1];
-  float    PostStateLoG[ORDERLO+1];
-  float    PostStateHiF[ORDERHI+1];
-  float    PostStateHiG[ORDERHI+1];
-
-  double    OldEnergy;
+  double OldEnergy;
 
 } MaskFiltstr;
 
-
 typedef struct {
+  // state vectors for each of the two analysis filters
+  double INSTAT1[2 * (QORDER - 1)];
+  double INSTAT2[2 * (QORDER - 1)];
+  double INSTATLA1[2 * (QORDER - 1)];
+  double INSTATLA2[2 * (QORDER - 1)];
+  double INLABUF1[QLOOKAHEAD];
+  double INLABUF2[QLOOKAHEAD];
 
-  //state vectors for each of the two analysis filters
-  double    INSTAT1[2*(QORDER-1)];
-  double    INSTAT2[2*(QORDER-1)];
-  double    INSTATLA1[2*(QORDER-1)];
-  double    INSTATLA2[2*(QORDER-1)];
-  double    INLABUF1[QLOOKAHEAD];
-  double    INLABUF2[QLOOKAHEAD];
-
-  float    INSTAT1_float[2*(QORDER-1)];
-  float    INSTAT2_float[2*(QORDER-1)];
-  float    INSTATLA1_float[2*(QORDER-1)];
-  float    INSTATLA2_float[2*(QORDER-1)];
-  float    INLABUF1_float[QLOOKAHEAD];
-  float    INLABUF2_float[QLOOKAHEAD];
+  float INSTAT1_float[2 * (QORDER - 1)];
+  float INSTAT2_float[2 * (QORDER - 1)];
+  float INSTATLA1_float[2 * (QORDER - 1)];
+  float INSTATLA2_float[2 * (QORDER - 1)];
+  float INLABUF1_float[QLOOKAHEAD];
+  float INLABUF2_float[QLOOKAHEAD];
 
   /* High pass filter */
-  double    HPstates[HPORDER];
-  float    HPstates_float[HPORDER];
+  double HPstates[HPORDER];
+  float HPstates_float[HPORDER];
 
 } PreFiltBankstr;
 
-
 typedef struct {
-
-  //state vectors for each of the two analysis filters
-  double    STATE_0_LOWER[2*POSTQORDER];
-  double    STATE_0_UPPER[2*POSTQORDER];
+  // state vectors for each of the two analysis filters
+  double STATE_0_LOWER[2 * POSTQORDER];
+  double STATE_0_UPPER[2 * POSTQORDER];
 
   /* High pass filter */
-  double    HPstates1[HPORDER];
-  double    HPstates2[HPORDER];
+  double HPstates1[HPORDER];
+  double HPstates2[HPORDER];
 
-  float    STATE_0_LOWER_float[2*POSTQORDER];
-  float    STATE_0_UPPER_float[2*POSTQORDER];
+  float STATE_0_LOWER_float[2 * POSTQORDER];
+  float STATE_0_UPPER_float[2 * POSTQORDER];
 
-  float    HPstates1_float[HPORDER];
-  float    HPstates2_float[HPORDER];
+  float HPstates1_float[HPORDER];
+  float HPstates2_float[HPORDER];
 
 } PostFiltBankstr;
 
 typedef struct {
+  // data buffer for pitch filter
+  double ubuf[PITCH_BUFFSIZE];
 
-  //data buffer for pitch filter
-  double    ubuf[PITCH_BUFFSIZE];
+  // low pass state vector
+  double ystate[PITCH_DAMPORDER];
 
-  //low pass state vector
-  double    ystate[PITCH_DAMPORDER];
-
-  //old lag and gain
-  double    oldlagp[1];
-  double    oldgainp[1];
+  // old lag and gain
+  double oldlagp[1];
+  double oldgainp[1];
 
 } PitchFiltstr;
 
 typedef struct {
+  // data buffer
+  double buffer[PITCH_WLPCBUFLEN];
 
-  //data buffer
-  double    buffer[PITCH_WLPCBUFLEN];
+  // state vectors
+  double istate[PITCH_WLPCORDER];
+  double weostate[PITCH_WLPCORDER];
+  double whostate[PITCH_WLPCORDER];
 
-  //state vectors
-  double    istate[PITCH_WLPCORDER];
-  double    weostate[PITCH_WLPCORDER];
-  double    whostate[PITCH_WLPCORDER];
-
-  //LPC window   -> should be a global array because constant
-  double    window[PITCH_WLPCWINLEN];
+  // LPC window   -> should be a global array because constant
+  double window[PITCH_WLPCWINLEN];
 
 } WeightFiltstr;
 
 typedef struct {
+  // for inital estimator
+  double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 -
+                    PITCH_FRAME_LEN / 2 + 2];
+  double decimator_state[2 * ALLPASSSECTIONS + 1];
+  double hp_state[2];
 
-  //for inital estimator
-  double         dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 +
-                            PITCH_MAX_LAG/2 - PITCH_FRAME_LEN/2+2];
-  double        decimator_state[2*ALLPASSSECTIONS+1];
-  double        hp_state[2];
+  double whitened_buf[QLOOKAHEAD];
 
-  double        whitened_buf[QLOOKAHEAD];
+  double inbuf[QLOOKAHEAD];
 
-  double        inbuf[QLOOKAHEAD];
-
-  PitchFiltstr  PFstr_wght;
-  PitchFiltstr  PFstr;
+  PitchFiltstr PFstr_wght;
+  PitchFiltstr PFstr;
   WeightFiltstr Wghtstr;
 
 } PitchAnalysisStruct;
 
-
-
 /* Have instance of struct together with other iSAC structs */
 typedef struct {
-
   /* Previous frame length (in ms)                                    */
-  int32_t    prev_frame_length;
+  int32_t prev_frame_length;
 
   /* Previous RTP timestamp from received
      packet (in samples relative beginning)                           */
-  int32_t    prev_rec_rtp_number;
+  int32_t prev_rec_rtp_number;
 
   /* Send timestamp for previous packet (in ms using timeGetTime())   */
-  uint32_t    prev_rec_send_ts;
+  uint32_t prev_rec_send_ts;
 
   /* Arrival time for previous packet (in ms using timeGetTime())     */
-  uint32_t    prev_rec_arr_ts;
+  uint32_t prev_rec_arr_ts;
 
   /* rate of previous packet, derived from RTP timestamps (in bits/s) */
-  float   prev_rec_rtp_rate;
+  float prev_rec_rtp_rate;
 
   /* Time sinse the last update of the BN estimate (in ms)            */
-  uint32_t    last_update_ts;
+  uint32_t last_update_ts;
 
   /* Time sinse the last reduction (in ms)                            */
-  uint32_t    last_reduction_ts;
+  uint32_t last_reduction_ts;
 
   /* How many times the estimate was update in the beginning          */
-  int32_t    count_tot_updates_rec;
+  int32_t count_tot_updates_rec;
 
   /* The estimated bottle neck rate from there to here (in bits/s)    */
-  int32_t  rec_bw;
-  float   rec_bw_inv;
-  float   rec_bw_avg;
-  float   rec_bw_avg_Q;
+  int32_t rec_bw;
+  float rec_bw_inv;
+  float rec_bw_avg;
+  float rec_bw_avg_Q;
 
   /* The estimated mean absolute jitter value,
      as seen on this side (in ms)                                     */
-  float   rec_jitter;
-  float   rec_jitter_short_term;
-  float   rec_jitter_short_term_abs;
-  float   rec_max_delay;
-  float   rec_max_delay_avg_Q;
+  float rec_jitter;
+  float rec_jitter_short_term;
+  float rec_jitter_short_term_abs;
+  float rec_max_delay;
+  float rec_max_delay_avg_Q;
 
   /* (assumed) bitrate for headers (bps)                              */
-  float   rec_header_rate;
+  float rec_header_rate;
 
   /* The estimated bottle neck rate from here to there (in bits/s)    */
-  float    send_bw_avg;
+  float send_bw_avg;
 
   /* The estimated mean absolute jitter value, as seen on
      the other siee (in ms)                                           */
-  float   send_max_delay_avg;
+  float send_max_delay_avg;
 
   // number of packets received since last update
   int num_pkts_rec;
@@ -218,35 +205,31 @@
 
   int change_to_WB;
 
-  uint32_t                 senderTimestamp;
-  uint32_t                 receiverTimestamp;
-  //enum IsacSamplingRate incomingStreamSampFreq;
-  uint16_t                 numConsecLatePkts;
-  float                        consecLatency;
-  int16_t                  inWaitLatePkts;
+  uint32_t senderTimestamp;
+  uint32_t receiverTimestamp;
+  // enum IsacSamplingRate incomingStreamSampFreq;
+  uint16_t numConsecLatePkts;
+  float consecLatency;
+  int16_t inWaitLatePkts;
 
   IsacBandwidthInfo external_bw_info;
 } BwEstimatorstr;
 
-
 typedef struct {
-
   /* boolean, flags if previous packet exceeded B.N. */
-  int    PrevExceed;
+  int PrevExceed;
   /* ms */
-  int    ExceedAgo;
+  int ExceedAgo;
   /* packets left to send in current burst */
-  int    BurstCounter;
+  int BurstCounter;
   /* packets */
-  int    InitCounter;
+  int InitCounter;
   /* ms remaining in buffer when next packet will be sent */
   double StillBuffered;
 
 } RateModel;
 
-
 typedef struct {
-
   unsigned int SpaceAlloced;
   unsigned int MaxPermAlloced;
   double Tmp0[MAXFFTSIZE];
@@ -254,36 +237,34 @@
   double Tmp2[MAXFFTSIZE];
   double Tmp3[MAXFFTSIZE];
   int Perm[MAXFFTSIZE];
-  int factor [NFACTOR];
+  int factor[NFACTOR];
 
 } FFTstr;
 
-
 /* The following strutc is used to store data from encoding, to make it
    fast and easy to construct a new bitstream with a different Bandwidth
    estimate. All values (except framelength and minBytes) is double size to
    handle 60 ms of data.
 */
 typedef struct {
-
   /* Used to keep track of if it is first or second part of 60 msec packet */
-  int         startIdx;
+  int startIdx;
 
   /* Frame length in samples */
   int16_t framelength;
 
   /* Pitch Gain */
-  int         pitchGain_index[2];
+  int pitchGain_index[2];
 
   /* Pitch Lag */
-  double      meanGain[2];
-  int         pitchIndex[PITCH_SUBFRAMES*2];
+  double meanGain[2];
+  int pitchIndex[PITCH_SUBFRAMES * 2];
 
   /* LPC */
-  int         LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */
-  int         LPCindex_g[12*2];  /* KLT_ORDER_GAIN = 12 */
-  double      LPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2];
-  double      LPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2];
+  int LPCindex_s[108 * 2]; /* KLT_ORDER_SHAPE = 108 */
+  int LPCindex_g[12 * 2];  /* KLT_ORDER_GAIN = 12 */
+  double LPCcoeffs_lo[(ORDERLO + 1) * SUBFRAMES * 2];
+  double LPCcoeffs_hi[(ORDERHI + 1) * SUBFRAMES * 2];
 
   /* Encode Spec */
   int16_t fre[FRAMESAMPLES];
@@ -291,59 +272,54 @@
   int16_t AvgPitchGain[2];
 
   /* Used in adaptive mode only */
-  int         minBytes;
+  int minBytes;
 
 } IsacSaveEncoderData;
 
-
 typedef struct {
+  int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+  double lpcGain[SUBFRAMES << 1];
+  int lpcGainIndex[SUBFRAMES << 1];
 
-  int         indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
-  double      lpcGain[SUBFRAMES<<1];
-  int         lpcGainIndex[SUBFRAMES<<1];
-
-  Bitstr      bitStreamObj;
+  Bitstr bitStreamObj;
 
   int16_t realFFT[FRAMESAMPLES_HALF];
   int16_t imagFFT[FRAMESAMPLES_HALF];
 } ISACUBSaveEncDataStruct;
 
-
-
 typedef struct {
-
-  Bitstr              bitstr_obj;
-  MaskFiltstr         maskfiltstr_obj;
-  PreFiltBankstr      prefiltbankstr_obj;
-  PitchFiltstr        pitchfiltstr_obj;
+  Bitstr bitstr_obj;
+  MaskFiltstr maskfiltstr_obj;
+  PreFiltBankstr prefiltbankstr_obj;
+  PitchFiltstr pitchfiltstr_obj;
   PitchAnalysisStruct pitchanalysisstr_obj;
-  FFTstr              fftstr_obj;
+  FFTstr fftstr_obj;
   IsacSaveEncoderData SaveEnc_obj;
 
-  int                 buffer_index;
-  int16_t         current_framesamples;
+  int buffer_index;
+  int16_t current_framesamples;
 
-  float               data_buffer_float[FRAMESAMPLES_30ms];
+  float data_buffer_float[FRAMESAMPLES_30ms];
 
-  int                 frame_nb;
-  double              bottleneck;
-  int16_t         new_framelength;
-  double              s2nr;
+  int frame_nb;
+  double bottleneck;
+  int16_t new_framelength;
+  double s2nr;
 
   /* Maximum allowed number of bits for a 30 msec packet */
-  int16_t         payloadLimitBytes30;
+  int16_t payloadLimitBytes30;
   /* Maximum allowed number of bits for a 30 msec packet */
-  int16_t         payloadLimitBytes60;
+  int16_t payloadLimitBytes60;
   /* Maximum allowed number of bits for both 30 and 60 msec packet */
-  int16_t         maxPayloadBytes;
+  int16_t maxPayloadBytes;
   /* Maximum allowed rate in bytes per 30 msec packet */
-  int16_t         maxRateInBytes;
+  int16_t maxRateInBytes;
 
   /*---
     If set to 1 iSAC will not addapt the frame-size, if used in
     channel-adaptive mode. The initial value will be used for all rates.
     ---*/
-  int16_t         enforceFrameSize;
+  int16_t enforceFrameSize;
 
   /*-----
     This records the BWE index the encoder injected into the bit-stream.
@@ -352,64 +328,53 @@
     a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be
     called only once per each encode.
     -----*/
-  int16_t         lastBWIdx;
+  int16_t lastBWIdx;
 } ISACLBEncStruct;
 
 typedef struct {
-
-  Bitstr                  bitstr_obj;
-  MaskFiltstr             maskfiltstr_obj;
-  PreFiltBankstr          prefiltbankstr_obj;
-  FFTstr                  fftstr_obj;
+  Bitstr bitstr_obj;
+  MaskFiltstr maskfiltstr_obj;
+  PreFiltBankstr prefiltbankstr_obj;
+  FFTstr fftstr_obj;
   ISACUBSaveEncDataStruct SaveEnc_obj;
 
-  int                     buffer_index;
-  float                   data_buffer_float[MAX_FRAMESAMPLES +
-                                            LB_TOTAL_DELAY_SAMPLES];
-  double                  bottleneck;
+  int buffer_index;
+  float data_buffer_float[MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES];
+  double bottleneck;
   /* Maximum allowed number of bits for a 30 msec packet */
-  //int16_t        payloadLimitBytes30;
+  // int16_t        payloadLimitBytes30;
   /* Maximum allowed number of bits for both 30 and 60 msec packet */
-  //int16_t        maxPayloadBytes;
-  int16_t             maxPayloadSizeBytes;
+  // int16_t        maxPayloadBytes;
+  int16_t maxPayloadSizeBytes;
 
-  double                  lastLPCVec[UB_LPC_ORDER];
-  int16_t             numBytesUsed;
-  int16_t             lastJitterInfo;
+  double lastLPCVec[UB_LPC_ORDER];
+  int16_t numBytesUsed;
+  int16_t lastJitterInfo;
 } ISACUBEncStruct;
 
-
-
 typedef struct {
-
-  Bitstr          bitstr_obj;
-  MaskFiltstr     maskfiltstr_obj;
+  Bitstr bitstr_obj;
+  MaskFiltstr maskfiltstr_obj;
   PostFiltBankstr postfiltbankstr_obj;
-  PitchFiltstr    pitchfiltstr_obj;
-  FFTstr          fftstr_obj;
+  PitchFiltstr pitchfiltstr_obj;
+  FFTstr fftstr_obj;
 
 } ISACLBDecStruct;
 
 typedef struct {
-
-  Bitstr          bitstr_obj;
-  MaskFiltstr     maskfiltstr_obj;
+  Bitstr bitstr_obj;
+  MaskFiltstr maskfiltstr_obj;
   PostFiltBankstr postfiltbankstr_obj;
-  FFTstr          fftstr_obj;
+  FFTstr fftstr_obj;
 
 } ISACUBDecStruct;
 
-
-
 typedef struct {
-
   ISACLBEncStruct ISACencLB_obj;
   ISACLBDecStruct ISACdecLB_obj;
 } ISACLBStruct;
 
-
 typedef struct {
-
   ISACUBEncStruct ISACencUB_obj;
   ISACUBDecStruct ISACdecUB_obj;
 } ISACUBStruct;
@@ -421,14 +386,14 @@
 */
 typedef struct {
   /* 6 lower-band & 6 upper-band */
-  double       loFiltGain[SUBFRAMES];
-  double       hiFiltGain[SUBFRAMES];
+  double loFiltGain[SUBFRAMES];
+  double hiFiltGain[SUBFRAMES];
   /* Upper boundary of interval W */
   uint32_t W_upper;
   uint32_t streamval;
   /* Index to the current position in bytestream */
   uint32_t stream_index;
-  uint8_t  stream[3];
+  uint8_t stream[3];
 } transcode_obj;
 
 typedef struct {
@@ -444,46 +409,46 @@
 
 typedef struct {
   // lower-band codec instance
-  ISACLBStruct              instLB;
+  ISACLBStruct instLB;
   // upper-band codec instance
-  ISACUBStruct              instUB;
+  ISACUBStruct instUB;
 
   // Bandwidth Estimator and model for the rate.
-  BwEstimatorstr            bwestimator_obj;
-  RateModel                 rate_data_obj;
-  double                    MaxDelay;
+  BwEstimatorstr bwestimator_obj;
+  RateModel rate_data_obj;
+  double MaxDelay;
 
   /* 0 = adaptive; 1 = instantaneous */
-  int16_t               codingMode;
+  int16_t codingMode;
 
   // overall bottleneck of the codec
-  int32_t               bottleneck;
+  int32_t bottleneck;
 
   // QMF Filter state
-  int32_t               analysisFBState1[FB_STATE_SIZE_WORD32];
-  int32_t               analysisFBState2[FB_STATE_SIZE_WORD32];
-  int32_t               synthesisFBState1[FB_STATE_SIZE_WORD32];
-  int32_t               synthesisFBState2[FB_STATE_SIZE_WORD32];
+  int32_t analysisFBState1[FB_STATE_SIZE_WORD32];
+  int32_t analysisFBState2[FB_STATE_SIZE_WORD32];
+  int32_t synthesisFBState1[FB_STATE_SIZE_WORD32];
+  int32_t synthesisFBState2[FB_STATE_SIZE_WORD32];
 
   // Error Code
-  int16_t               errorCode;
+  int16_t errorCode;
 
   // bandwidth of the encoded audio 8, 12 or 16 kHz
-  enum ISACBandwidth        bandwidthKHz;
+  enum ISACBandwidth bandwidthKHz;
   // Sampling rate of audio, encoder and decode,  8 or 16 kHz
   enum IsacSamplingRate encoderSamplingRateKHz;
   enum IsacSamplingRate decoderSamplingRateKHz;
   // Flag to keep track of initializations, lower & upper-band
   // encoder and decoder.
-  int16_t               initFlag;
+  int16_t initFlag;
 
   // Flag to to indicate signal bandwidth switch
-  int16_t               resetFlag_8kHz;
+  int16_t resetFlag_8kHz;
 
   // Maximum allowed rate, measured in Bytes per 30 ms.
-  int16_t               maxRateBytesPer30Ms;
+  int16_t maxRateBytesPer30Ms;
   // Maximum allowed payload-size, measured in Bytes.
-  int16_t               maxPayloadSizeBytes;
+  int16_t maxPayloadSizeBytes;
   /* The expected sampling rate of the input signal. Valid values are 16000
    * and 32000. This is not the operation sampling rate of the codec. */
   uint16_t in_sample_rate_hz;
diff --git a/modules/audio_coding/codecs/isac/main/util/utility.h b/modules/audio_coding/codecs/isac/main/util/utility.h
index b5882a5..1acc542 100644
--- a/modules/audio_coding/codecs/isac/main/util/utility.h
+++ b/modules/audio_coding/codecs/isac/main/util/utility.h
@@ -11,134 +11,98 @@
 #ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_UTIL_UTILITY_H_
 #define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_UTIL_UTILITY_H_
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
-#define OPEN_FILE_WB(filePtr, fullPath)                         \
-  do                                                            \
-  {                                                             \
-    if(fullPath != NULL)                                        \
-    {                                                           \
-      filePtr = fopen(fullPath, "wb");                          \
-      if(filePtr == NULL)                                       \
-      {                                                         \
-        printf("could not open %s to write to.", fullPath);     \
-        return -1;                                              \
-      }                                                         \
-    }                                                           \
-    else                                                        \
-    {                                                           \
-      filePtr = NULL;                                           \
-    }                                                           \
-  }while(0)
+#define OPEN_FILE_WB(filePtr, fullPath)                     \
+  do {                                                      \
+    if (fullPath != NULL) {                                 \
+      filePtr = fopen(fullPath, "wb");                      \
+      if (filePtr == NULL) {                                \
+        printf("could not open %s to write to.", fullPath); \
+        return -1;                                          \
+      }                                                     \
+    } else {                                                \
+      filePtr = NULL;                                       \
+    }                                                       \
+  } while (0)
 
-#define OPEN_FILE_AB(filePtr, fullPath)                         \
-  do                                                            \
-  {                                                             \
-    if(fullPath != NULL)                                        \
-    {                                                           \
-      filePtr = fopen(fullPath, "ab");                          \
-      if(filePtr == NULL)                                       \
-      {                                                         \
-        printf("could not open %s to write to.", fullPath);     \
-        return -1;                                              \
-      }                                                         \
-    }                                                           \
-    else                                                        \
-    {                                                           \
-      filePtr = NULL;                                           \
-    }                                                           \
-  }while(0)
+#define OPEN_FILE_AB(filePtr, fullPath)                     \
+  do {                                                      \
+    if (fullPath != NULL) {                                 \
+      filePtr = fopen(fullPath, "ab");                      \
+      if (filePtr == NULL) {                                \
+        printf("could not open %s to write to.", fullPath); \
+        return -1;                                          \
+      }                                                     \
+    } else {                                                \
+      filePtr = NULL;                                       \
+    }                                                       \
+  } while (0)
 
-#define OPEN_FILE_RB(filePtr, fullPath)                         \
-  do                                                            \
-  {                                                             \
-    if(fullPath != NULL)                                        \
-    {                                                           \
-      filePtr = fopen(fullPath, "rb");                          \
-      if(filePtr == NULL)                                       \
-      {                                                         \
-        printf("could not open %s to read from.", fullPath);    \
-        return -1;                                              \
-      }                                                         \
-    }                                                           \
-    else                                                        \
-    {                                                           \
-      filePtr = NULL;                                           \
-    }                                                           \
-  }while(0)
+#define OPEN_FILE_RB(filePtr, fullPath)                      \
+  do {                                                       \
+    if (fullPath != NULL) {                                  \
+      filePtr = fopen(fullPath, "rb");                       \
+      if (filePtr == NULL) {                                 \
+        printf("could not open %s to read from.", fullPath); \
+        return -1;                                           \
+      }                                                      \
+    } else {                                                 \
+      filePtr = NULL;                                        \
+    }                                                        \
+  } while (0)
 
-#define WRITE_FILE_D(bufferPtr, len, filePtr)           \
-  do                                                    \
-  {                                                     \
-    if(filePtr != NULL)                                 \
-    {                                                   \
-      double dummy[1000];                               \
-      int cntr;                                         \
-      for(cntr = 0; cntr < (len); cntr++)               \
-      {                                                 \
-        dummy[cntr] = (double)bufferPtr[cntr];          \
-      }                                                 \
-      fwrite(dummy, sizeof(double), len, filePtr);      \
-      fflush(filePtr);                                  \
-    }                                                   \
-  } while(0)
+#define WRITE_FILE_D(bufferPtr, len, filePtr)      \
+  do {                                             \
+    if (filePtr != NULL) {                         \
+      double dummy[1000];                          \
+      int cntr;                                    \
+      for (cntr = 0; cntr < (len); cntr++) {       \
+        dummy[cntr] = (double)bufferPtr[cntr];     \
+      }                                            \
+      fwrite(dummy, sizeof(double), len, filePtr); \
+      fflush(filePtr);                             \
+    }                                              \
+  } while (0)
 
-  typedef struct {
-    unsigned int whenPackGeneratedMs;
-    unsigned int whenPrevPackLeftMs;
-    unsigned int sendTimeMs ;          /* milisecond */
-    unsigned int arrival_time;         /* samples */
-    unsigned int sample_count;         /* samples, also used as "send time stamp" */
-    unsigned int rtp_number;
-  } BottleNeckModel;
+typedef struct {
+  unsigned int whenPackGeneratedMs;
+  unsigned int whenPrevPackLeftMs;
+  unsigned int sendTimeMs;   /* milisecond */
+  unsigned int arrival_time; /* samples */
+  unsigned int sample_count; /* samples, also used as "send time stamp" */
+  unsigned int rtp_number;
+} BottleNeckModel;
 
-  void get_arrival_time(
-      int              current_framesamples,   /* samples */
-      size_t           packet_size,            /* bytes */
-      int              bottleneck,             /* excluding headers; bits/s */
-      BottleNeckModel* BN_data,
-      short            senderSampFreqHz,
-      short            receiverSampFreqHz);
+void get_arrival_time(int current_framesamples, /* samples */
+                      size_t packet_size,       /* bytes */
+                      int bottleneck,           /* excluding headers; bits/s */
+                      BottleNeckModel* BN_data,
+                      short senderSampFreqHz,
+                      short receiverSampFreqHz);
 
-  /* function for reading audio data from PCM file */
-  int readframe(
-      short* data,
-      FILE*  inp,
-      int    length);
+/* function for reading audio data from PCM file */
+int readframe(short* data, FILE* inp, int length);
 
-  short readSwitch(
-      int   argc,
-      char* argv[],
-      char* strID);
+short readSwitch(int argc, char* argv[], char* strID);
 
-  double readParamDouble(
-      int    argc,
-      char*  argv[],
-      char*  strID,
-      double defaultVal);
+double readParamDouble(int argc, char* argv[], char* strID, double defaultVal);
 
-  int readParamInt(
-      int   argc,
-      char* argv[],
-      char* strID,
-      int   defaultVal);
+int readParamInt(int argc, char* argv[], char* strID, int defaultVal);
 
-  int readParamString(
-      int   argc,
-      char* argv[],
-      char* strID,
-      char* stringParam,
-      int   maxSize);
+int readParamString(int argc,
+                    char* argv[],
+                    char* strID,
+                    char* stringParam,
+                    int maxSize);
 
 #if defined(__cplusplus)
 }
 #endif
 
-
-
 #endif
diff --git a/modules/audio_coding/codecs/legacy_encoded_audio_frame.cc b/modules/audio_coding/codecs/legacy_encoded_audio_frame.cc
index 341336e..0bf3b19 100644
--- a/modules/audio_coding/codecs/legacy_encoded_audio_frame.cc
+++ b/modules/audio_coding/codecs/legacy_encoded_audio_frame.cc
@@ -27,7 +27,7 @@
   return (ret < 0) ? 0 : static_cast<size_t>(ret);
 }
 
-rtc::Optional<AudioDecoder::EncodedAudioFrame::DecodeResult>
+absl::optional<AudioDecoder::EncodedAudioFrame::DecodeResult>
 LegacyEncodedAudioFrame::Decode(rtc::ArrayView<int16_t> decoded) const {
   AudioDecoder::SpeechType speech_type = AudioDecoder::kSpeech;
   const int ret = decoder_->Decode(
@@ -35,7 +35,7 @@
       decoded.size() * sizeof(int16_t), decoded.data(), &speech_type);
 
   if (ret < 0)
-    return rtc::nullopt;
+    return absl::nullopt;
 
   return DecodeResult{static_cast<size_t>(ret), speech_type};
 }
@@ -68,10 +68,9 @@
         split_size_bytes * timestamps_per_ms / bytes_per_ms);
     size_t byte_offset;
     uint32_t timestamp_offset;
-    for (byte_offset = 0, timestamp_offset = 0;
-         byte_offset < payload.size();
+    for (byte_offset = 0, timestamp_offset = 0; byte_offset < payload.size();
          byte_offset += split_size_bytes,
-             timestamp_offset += timestamps_per_chunk) {
+        timestamp_offset += timestamps_per_chunk) {
       split_size_bytes =
           std::min(split_size_bytes, payload.size() - byte_offset);
       rtc::Buffer new_payload(payload.data() + byte_offset, split_size_bytes);
diff --git a/modules/audio_coding/codecs/legacy_encoded_audio_frame.h b/modules/audio_coding/codecs/legacy_encoded_audio_frame.h
index 275576e..05d4fe4 100644
--- a/modules/audio_coding/codecs/legacy_encoded_audio_frame.h
+++ b/modules/audio_coding/codecs/legacy_encoded_audio_frame.h
@@ -32,7 +32,7 @@
 
   size_t Duration() const override;
 
-  rtc::Optional<DecodeResult> Decode(
+  absl::optional<DecodeResult> Decode(
       rtc::ArrayView<int16_t> decoded) const override;
 
   // For testing:
diff --git a/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc b/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
index e2dd445..9079bcd 100644
--- a/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
+++ b/modules/audio_coding/codecs/legacy_encoded_audio_frame_unittest.cc
@@ -97,20 +97,15 @@
   // 40 ms -> 20 + 20 ms
   // 50 ms -> 25 + 25 ms
   // 60 ms -> 30 + 30 ms
-  ExpectedSplit expected_splits[] = {
-    {10, 1, {10}},
-    {20, 1, {20}},
-    {30, 1, {30}},
-    {40, 2, {20, 20}},
-    {50, 2, {25, 25}},
-    {60, 2, {30, 30}}
-  };
+  ExpectedSplit expected_splits[] = {{10, 1, {10}},     {20, 1, {20}},
+                                     {30, 1, {30}},     {40, 2, {20, 20}},
+                                     {50, 2, {25, 25}}, {60, 2, {30, 30}}};
 
   for (const auto& expected_split : expected_splits) {
     // The payload values are set to steadily increase (modulo 256), so that the
     // resulting frames can be checked and we can be reasonably certain no
     // sample was missed or repeated.
-    const auto generate_payload = [] (size_t num_bytes) {
+    const auto generate_payload = [](size_t num_bytes) {
       rtc::Buffer payload(num_bytes);
       uint8_t value = 0;
       // Allow wrap-around of value in counter below.
diff --git a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
index 3d10b6f..302b714 100644
--- a/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
+++ b/modules/audio_coding/codecs/opus/audio_decoder_opus.cc
@@ -36,7 +36,9 @@
     return (ret < 0) ? 0 : static_cast<size_t>(ret);
   }
 
-  rtc::Optional<DecodeResult> Decode(
+  bool IsDtxPacket() const override { return payload_.size() <= 2; }
+
+  absl::optional<DecodeResult> Decode(
       rtc::ArrayView<int16_t> decoded) const override {
     AudioDecoder::SpeechType speech_type = AudioDecoder::kSpeech;
     int ret;
@@ -51,7 +53,7 @@
     }
 
     if (ret < 0)
-      return rtc::nullopt;
+      return absl::nullopt;
 
     return DecodeResult{static_cast<size_t>(ret), speech_type};
   }
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index caac4ae..e6240e6 100644
--- a/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -14,6 +14,7 @@
 #include <iterator>
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h"
 #include "modules/audio_coding/audio_network_adaptor/controller_manager.h"
@@ -25,7 +26,6 @@
 #include "rtc_base/numerics/safe_conversions.h"
 #include "rtc_base/numerics/safe_minmax.h"
 #include "rtc_base/protobuf_utils.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/string_to_number.h"
 #include "rtc_base/timeutils.h"
 #include "system_wrappers/include/field_trial.h"
@@ -105,18 +105,18 @@
   }
 }
 
-rtc::Optional<std::string> GetFormatParameter(const SdpAudioFormat& format,
-                                              const std::string& param) {
+absl::optional<std::string> GetFormatParameter(const SdpAudioFormat& format,
+                                               const std::string& param) {
   auto it = format.parameters.find(param);
   if (it == format.parameters.end())
-    return rtc::nullopt;
+    return absl::nullopt;
 
   return it->second;
 }
 
 template <typename T>
-rtc::Optional<T> GetFormatParameter(const SdpAudioFormat& format,
-                                    const std::string& param) {
+absl::optional<T> GetFormatParameter(const SdpAudioFormat& format,
+                                     const std::string& param) {
   return rtc::StringToNumber<T>(GetFormatParameter(format, param).value_or(""));
 }
 
@@ -139,7 +139,7 @@
 // out how invalid it is and accurately log invalid values.
 int CalculateBitrate(int max_playback_rate_hz,
                      size_t num_channels,
-                     rtc::Optional<std::string> bitrate_param) {
+                     absl::optional<std::string> bitrate_param) {
   const int default_bitrate =
       CalculateDefaultBitrate(max_playback_rate_hz, num_channels);
 
@@ -239,10 +239,10 @@
     const AudioEncoderOpusConfig& config,
     int payload_type) {
   RTC_DCHECK(config.IsOk());
-  return rtc::MakeUnique<AudioEncoderOpusImpl>(config, payload_type);
+  return absl::make_unique<AudioEncoderOpusImpl>(config, payload_type);
 }
 
-rtc::Optional<AudioCodecInfo> AudioEncoderOpusImpl::QueryAudioEncoder(
+absl::optional<AudioCodecInfo> AudioEncoderOpusImpl::QueryAudioEncoder(
     const SdpAudioFormat& format) {
   if (STR_CASE_CMP(format.name.c_str(), GetPayloadName()) == 0 &&
       format.clockrate_hz == 48000 && format.num_channels == 2) {
@@ -258,7 +258,7 @@
 
     return info;
   }
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
 AudioEncoderOpusConfig AudioEncoderOpusImpl::CreateConfig(
@@ -274,11 +274,11 @@
   return config;
 }
 
-rtc::Optional<AudioEncoderOpusConfig> AudioEncoderOpusImpl::SdpToConfig(
+absl::optional<AudioEncoderOpusConfig> AudioEncoderOpusImpl::SdpToConfig(
     const SdpAudioFormat& format) {
   if (STR_CASE_CMP(format.name.c_str(), "opus") != 0 ||
       format.clockrate_hz != 48000 || format.num_channels != 2) {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
 
   AudioEncoderOpusConfig config;
@@ -313,7 +313,7 @@
   return config;
 }
 
-rtc::Optional<int> AudioEncoderOpusImpl::GetNewComplexity(
+absl::optional<int> AudioEncoderOpusImpl::GetNewComplexity(
     const AudioEncoderOpusConfig& config) {
   RTC_DCHECK(config.IsOk());
   const int bitrate_bps = GetBitrateBps(config);
@@ -322,7 +322,7 @@
       bitrate_bps <= config.complexity_threshold_bps +
                          config.complexity_threshold_window_bps) {
     // Within the hysteresis window; make no change.
-    return rtc::nullopt;
+    return absl::nullopt;
   } else {
     return bitrate_bps <= config.complexity_threshold_bps
                ? config.low_rate_complexity
@@ -330,7 +330,7 @@
   }
 }
 
-rtc::Optional<int> AudioEncoderOpusImpl::GetNewBandwidth(
+absl::optional<int> AudioEncoderOpusImpl::GetNewBandwidth(
     const AudioEncoderOpusConfig& config,
     OpusEncInst* inst) {
   constexpr int kMinWidebandBitrate = 8000;
@@ -339,17 +339,17 @@
   RTC_DCHECK(config.IsOk());
   const int bitrate = GetBitrateBps(config);
   if (bitrate > kAutomaticThreshold) {
-    return rtc::Optional<int>(OPUS_AUTO);
+    return absl::optional<int>(OPUS_AUTO);
   }
   const int bandwidth = WebRtcOpus_GetBandwidth(inst);
   RTC_DCHECK_GE(bandwidth, 0);
   if (bitrate > kMaxNarrowbandBitrate && bandwidth < OPUS_BANDWIDTH_WIDEBAND) {
-    return rtc::Optional<int>(OPUS_BANDWIDTH_WIDEBAND);
+    return absl::optional<int>(OPUS_BANDWIDTH_WIDEBAND);
   } else if (bitrate < kMinWidebandBitrate &&
              bandwidth > OPUS_BANDWIDTH_NARROWBAND) {
-    return rtc::Optional<int>(OPUS_BANDWIDTH_NARROWBAND);
+    return absl::optional<int>(OPUS_BANDWIDTH_NARROWBAND);
   }
-  return rtc::Optional<int>();
+  return absl::optional<int>();
 }
 
 class AudioEncoderOpusImpl::PacketLossFractionSmoother {
@@ -388,7 +388,7 @@
             return DefaultAudioNetworkAdaptorCreator(config_string, event_log);
           },
           // We choose 5sec as initial time constant due to empirical data.
-          rtc::MakeUnique<SmoothingFilterImpl>(5000)) {}
+          absl::make_unique<SmoothingFilterImpl>(5000)) {}
 
 AudioEncoderOpusImpl::AudioEncoderOpusImpl(
     const AudioEncoderOpusConfig& config,
@@ -529,7 +529,7 @@
 
 void AudioEncoderOpusImpl::OnReceivedUplinkBandwidth(
     int target_audio_bitrate_bps,
-    rtc::Optional<int64_t> bwe_period_ms) {
+    absl::optional<int64_t> bwe_period_ms) {
   if (audio_network_adaptor_) {
     audio_network_adaptor_->SetTargetAudioBitrate(target_audio_bitrate_bps);
     // We give smoothed bitrate allocation to audio network adaptor as
@@ -613,20 +613,17 @@
 
   const size_t max_encoded_bytes = SufficientOutputBufferSize();
   EncodedInfo info;
-  info.encoded_bytes =
-      encoded->AppendData(
-          max_encoded_bytes, [&] (rtc::ArrayView<uint8_t> encoded) {
-            int status = WebRtcOpus_Encode(
-                inst_, &input_buffer_[0],
-                rtc::CheckedDivExact(input_buffer_.size(),
-                                     config_.num_channels),
-                rtc::saturated_cast<int16_t>(max_encoded_bytes),
-                encoded.data());
+  info.encoded_bytes = encoded->AppendData(
+      max_encoded_bytes, [&](rtc::ArrayView<uint8_t> encoded) {
+        int status = WebRtcOpus_Encode(
+            inst_, &input_buffer_[0],
+            rtc::CheckedDivExact(input_buffer_.size(), config_.num_channels),
+            rtc::saturated_cast<int16_t>(max_encoded_bytes), encoded.data());
 
-            RTC_CHECK_GE(status, 0);  // Fails only if fed invalid data.
+        RTC_CHECK_GE(status, 0);  // Fails only if fed invalid data.
 
-            return static_cast<size_t>(status);
-          });
+        return static_cast<size_t>(status);
+      });
   input_buffer_.clear();
 
   bool dtx_frame = (info.encoded_bytes <= 2);
@@ -801,7 +798,7 @@
     if (!bitrate_smoother_last_update_time_ ||
         now_ms - *bitrate_smoother_last_update_time_ >=
             config_.uplink_bandwidth_update_interval_ms) {
-      rtc::Optional<float> smoothed_bitrate = bitrate_smoother_->GetAverage();
+      absl::optional<float> smoothed_bitrate = bitrate_smoother_->GetAverage();
       if (smoothed_bitrate)
         audio_network_adaptor_->SetUplinkBandwidth(*smoothed_bitrate);
       bitrate_smoother_last_update_time_ = now_ms;
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus.h b/modules/audio_coding/codecs/opus/audio_encoder_opus.h
index 49c5207..ea4b265 100644
--- a/modules/audio_coding/codecs/opus/audio_encoder_opus.h
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus.h
@@ -16,10 +16,10 @@
 #include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio_codecs/audio_encoder.h"
 #include "api/audio_codecs/audio_format.h"
 #include "api/audio_codecs/opus/audio_encoder_opus_config.h"
-#include "api/optional.h"
 #include "common_audio/smoothing_filter.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
 #include "modules/audio_coding/codecs/opus/opus_interface.h"
@@ -40,13 +40,13 @@
   // defined by complexity_threshold_bps +/- complexity_threshold_window_bps.
   // Otherwise, returns the current complexity depending on whether the
   // current bitrate is above or below complexity_threshold_bps.
-  static rtc::Optional<int> GetNewComplexity(
+  static absl::optional<int> GetNewComplexity(
       const AudioEncoderOpusConfig& config);
 
   // Returns OPUS_AUTO if the the current bitrate is above wideband threshold.
   // Returns empty if it is below, but bandwidth coincides with the desired one.
   // Otherwise returns the desired bandwidth.
-  static rtc::Optional<int> GetNewBandwidth(
+  static absl::optional<int> GetNewBandwidth(
       const AudioEncoderOpusConfig& config,
       OpusEncInst* inst);
 
@@ -69,7 +69,7 @@
 
   // Static interface for use by BuiltinAudioEncoderFactory.
   static constexpr const char* GetPayloadName() { return "opus"; }
-  static rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
+  static absl::optional<AudioCodecInfo> QueryAudioEncoder(
       const SdpAudioFormat& format);
 
   int SampleRateHz() const override;
@@ -98,7 +98,7 @@
       float uplink_recoverable_packet_loss_fraction) override;
   void OnReceivedUplinkBandwidth(
       int target_audio_bitrate_bps,
-      rtc::Optional<int64_t> bwe_period_ms) override;
+      absl::optional<int64_t> bwe_period_ms) override;
   void OnReceivedRtt(int rtt_ms) override;
   void OnReceivedOverhead(size_t overhead_bytes_per_packet) override;
   void SetReceiverFrameLengthRange(int min_frame_length_ms,
@@ -125,7 +125,7 @@
  private:
   class PacketLossFractionSmoother;
 
-  static rtc::Optional<AudioEncoderOpusConfig> SdpToConfig(
+  static absl::optional<AudioEncoderOpusConfig> SdpToConfig(
       const SdpAudioFormat& format);
   static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs);
   static AudioCodecInfo QueryAudioEncoder(const AudioEncoderOpusConfig& config);
@@ -167,9 +167,9 @@
   std::unique_ptr<PacketLossFractionSmoother> packet_loss_fraction_smoother_;
   const AudioNetworkAdaptorCreator audio_network_adaptor_creator_;
   std::unique_ptr<AudioNetworkAdaptor> audio_network_adaptor_;
-  rtc::Optional<size_t> overhead_bytes_per_packet_;
+  absl::optional<size_t> overhead_bytes_per_packet_;
   const std::unique_ptr<SmoothingFilter> bitrate_smoother_;
-  rtc::Optional<int64_t> bitrate_smoother_last_update_time_;
+  absl::optional<int64_t> bitrate_smoother_last_update_time_;
   int consecutive_dtx_frames_;
 
   friend struct AudioEncoderOpus;
diff --git a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
index bd34118..7a6d5fd 100644
--- a/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
+++ b/modules/audio_coding/codecs/opus/audio_encoder_opus_unittest.cc
@@ -12,6 +12,7 @@
 #include <memory>
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "api/audio_codecs/opus/audio_encoder_opus.h"
 #include "common_audio/mocks/mock_smoothing_filter.h"
 #include "common_types.h"  // NOLINT(build/include)
@@ -21,7 +22,6 @@
 #include "modules/audio_coding/neteq/tools/audio_loop.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/fakeclock.h"
-#include "rtc_base/ptr_util.h"
 #include "test/field_trial.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
@@ -64,7 +64,7 @@
 
 std::unique_ptr<AudioEncoderOpusStates> CreateCodec(size_t num_channels) {
   std::unique_ptr<AudioEncoderOpusStates> states =
-      rtc::MakeUnique<AudioEncoderOpusStates>();
+      absl::make_unique<AudioEncoderOpusStates>();
   states->mock_audio_network_adaptor = nullptr;
   states->fake_clock.reset(new rtc::ScopedFakeClock());
   states->fake_clock->SetTimeMicros(kInitialTimeUs);
@@ -198,20 +198,20 @@
   const int kMinBitrateBps = 6000;
   const int kMaxBitrateBps = 510000;
   // Set a too low bitrate.
-  states->encoder->OnReceivedUplinkBandwidth(kMinBitrateBps - 1, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(kMinBitrateBps - 1, absl::nullopt);
   EXPECT_EQ(kMinBitrateBps, states->encoder->GetTargetBitrate());
   // Set a too high bitrate.
-  states->encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps + 1, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps + 1, absl::nullopt);
   EXPECT_EQ(kMaxBitrateBps, states->encoder->GetTargetBitrate());
   // Set the minimum rate.
-  states->encoder->OnReceivedUplinkBandwidth(kMinBitrateBps, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(kMinBitrateBps, absl::nullopt);
   EXPECT_EQ(kMinBitrateBps, states->encoder->GetTargetBitrate());
   // Set the maximum rate.
-  states->encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps, absl::nullopt);
   EXPECT_EQ(kMaxBitrateBps, states->encoder->GetTargetBitrate());
   // Set rates from kMaxBitrateBps up to 32000 bps.
   for (int rate = kMinBitrateBps; rate <= 32000; rate += 1000) {
-    states->encoder->OnReceivedUplinkBandwidth(rate, rtc::nullopt);
+    states->encoder->OnReceivedUplinkBandwidth(rate, absl::nullopt);
     EXPECT_EQ(rate, states->encoder->GetTargetBitrate());
   }
 }
@@ -243,8 +243,7 @@
   constexpr int64_t kSampleIntervalMs = 184198;
   for (float loss : losses) {
     states->encoder->OnReceivedUplinkPacketLossFraction(loss);
-    states->fake_clock->AdvanceTime(
-        rtc::TimeDelta::FromMilliseconds(kSampleIntervalMs));
+    states->fake_clock->AdvanceTime(TimeDelta::ms(kSampleIntervalMs));
     EXPECT_FLOAT_EQ(expected_return, states->encoder->packet_loss_rate());
   }
 }
@@ -376,8 +375,7 @@
   states->encoder->OnReceivedUplinkPacketLossFraction(kPacketLossFraction_1);
   EXPECT_FLOAT_EQ(0.01f, states->encoder->packet_loss_rate());
 
-  states->fake_clock->AdvanceTime(
-      rtc::TimeDelta::FromMilliseconds(kSecondSampleTimeMs));
+  states->fake_clock->AdvanceTime(TimeDelta::ms(kSecondSampleTimeMs));
   states->encoder->OnReceivedUplinkPacketLossFraction(kPacketLossFraction_2);
 
   // Now the output of packet loss fraction smoother should be
@@ -394,7 +392,7 @@
   auto states = CreateCodec(2);
 
   states->encoder->OnReceivedUplinkBandwidth(kDefaultOpusSettings.rate * 2,
-                                             rtc::nullopt);
+                                             absl::nullopt);
 
   // Since |OnReceivedOverhead| has not been called, the codec bitrate should
   // not change.
@@ -411,7 +409,7 @@
   states->encoder->OnReceivedOverhead(kOverheadBytesPerPacket);
 
   constexpr int kTargetBitrateBps = 40000;
-  states->encoder->OnReceivedUplinkBandwidth(kTargetBitrateBps, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(kTargetBitrateBps, absl::nullopt);
 
   int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize);
   EXPECT_EQ(kTargetBitrateBps -
@@ -437,14 +435,14 @@
   // subtracted. The eventual codec rate should be bounded by |kMinBitrateBps|.
   int target_bitrate =
       kOverheadBytesPerPacket * 8 * packet_rate + kMinBitrateBps - 1;
-  states->encoder->OnReceivedUplinkBandwidth(target_bitrate, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(target_bitrate, absl::nullopt);
   EXPECT_EQ(kMinBitrateBps, states->encoder->GetTargetBitrate());
 
   // Set a target rate that is greater than |kMaxBitrateBps| when overhead is
   // subtracted. The eventual codec rate should be bounded by |kMaxBitrateBps|.
   target_bitrate =
       kOverheadBytesPerPacket * 8 * packet_rate + kMaxBitrateBps + 1;
-  states->encoder->OnReceivedUplinkBandwidth(target_bitrate, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(target_bitrate, absl::nullopt);
   EXPECT_EQ(kMaxBitrateBps, states->encoder->GetTargetBitrate());
 }
 
@@ -456,7 +454,7 @@
 
   // Bitrate within hysteresis window. Expect empty output.
   config.bitrate_bps = 12500;
-  EXPECT_EQ(rtc::nullopt, AudioEncoderOpusImpl::GetNewComplexity(config));
+  EXPECT_EQ(absl::nullopt, AudioEncoderOpusImpl::GetNewComplexity(config));
 
   // Bitrate below hysteresis window. Expect higher complexity.
   config.bitrate_bps = 10999;
@@ -464,7 +462,7 @@
 
   // Bitrate within hysteresis window. Expect empty output.
   config.bitrate_bps = 12500;
-  EXPECT_EQ(rtc::nullopt, AudioEncoderOpusImpl::GetNewComplexity(config));
+  EXPECT_EQ(absl::nullopt, AudioEncoderOpusImpl::GetNewComplexity(config));
 
   // Bitrate above hysteresis window. Expect lower complexity.
   config.bitrate_bps = 14001;
@@ -490,9 +488,9 @@
                        : 1));
 
   // Bitrate below minmum wideband. Expect narrowband.
-  config.bitrate_bps = rtc::Optional<int>(7999);
+  config.bitrate_bps = absl::optional<int>(7999);
   auto bandwidth = AudioEncoderOpusImpl::GetNewBandwidth(config, inst);
-  EXPECT_EQ(rtc::Optional<int>(OPUS_BANDWIDTH_NARROWBAND), bandwidth);
+  EXPECT_EQ(absl::optional<int>(OPUS_BANDWIDTH_NARROWBAND), bandwidth);
   WebRtcOpus_SetBandwidth(inst, *bandwidth);
   // It is necessary to encode here because Opus has some logic in the encoder
   // that goes from the user-set bandwidth to the used and returned one.
@@ -501,14 +499,14 @@
                     kMaxBytes, bitstream);
 
   // Bitrate not yet above maximum narrowband. Expect empty.
-  config.bitrate_bps = rtc::Optional<int>(9000);
+  config.bitrate_bps = absl::optional<int>(9000);
   bandwidth = AudioEncoderOpusImpl::GetNewBandwidth(config, inst);
-  EXPECT_EQ(rtc::Optional<int>(), bandwidth);
+  EXPECT_EQ(absl::optional<int>(), bandwidth);
 
   // Bitrate above maximum narrowband. Expect wideband.
-  config.bitrate_bps = rtc::Optional<int>(9001);
+  config.bitrate_bps = absl::optional<int>(9001);
   bandwidth = AudioEncoderOpusImpl::GetNewBandwidth(config, inst);
-  EXPECT_EQ(rtc::Optional<int>(OPUS_BANDWIDTH_WIDEBAND), bandwidth);
+  EXPECT_EQ(absl::optional<int>(OPUS_BANDWIDTH_WIDEBAND), bandwidth);
   WebRtcOpus_SetBandwidth(inst, *bandwidth);
   // It is necessary to encode here because Opus has some logic in the encoder
   // that goes from the user-set bandwidth to the used and returned one.
@@ -517,14 +515,14 @@
                     kMaxBytes, bitstream);
 
   // Bitrate not yet below minimum wideband. Expect empty.
-  config.bitrate_bps = rtc::Optional<int>(8000);
+  config.bitrate_bps = absl::optional<int>(8000);
   bandwidth = AudioEncoderOpusImpl::GetNewBandwidth(config, inst);
-  EXPECT_EQ(rtc::Optional<int>(), bandwidth);
+  EXPECT_EQ(absl::optional<int>(), bandwidth);
 
   // Bitrate above automatic threshold. Expect automatic.
-  config.bitrate_bps = rtc::Optional<int>(12001);
+  config.bitrate_bps = absl::optional<int>(12001);
   bandwidth = AudioEncoderOpusImpl::GetNewBandwidth(config, inst);
-  EXPECT_EQ(rtc::Optional<int>(OPUS_AUTO), bandwidth);
+  EXPECT_EQ(absl::optional<int>(OPUS_AUTO), bandwidth);
 
   EXPECT_EQ(0, WebRtcOpus_EncoderFree(inst));
 }
@@ -564,8 +562,8 @@
   // Repeat update uplink bandwidth tests.
   for (int i = 0; i < 5; i++) {
     // Don't update till it is time to update again.
-    states->fake_clock->AdvanceTime(rtc::TimeDelta::FromMilliseconds(
-        states->config.uplink_bandwidth_update_interval_ms - 1));
+    states->fake_clock->AdvanceTime(
+        TimeDelta::ms(states->config.uplink_bandwidth_update_interval_ms - 1));
     states->encoder->Encode(
         0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded);
 
@@ -573,7 +571,7 @@
     EXPECT_CALL(*states->mock_bitrate_smoother, GetAverage())
         .WillOnce(Return(40000));
     EXPECT_CALL(*states->mock_audio_network_adaptor, SetUplinkBandwidth(40000));
-    states->fake_clock->AdvanceTime(rtc::TimeDelta::FromMilliseconds(1));
+    states->fake_clock->AdvanceTime(TimeDelta::ms(1));
     states->encoder->Encode(
         0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded);
   }
@@ -588,7 +586,7 @@
   rtc::Buffer encoded;
   uint32_t rtp_timestamp = 12345;  // Just a number not important to this test.
 
-  states->encoder->OnReceivedUplinkBandwidth(0, rtc::nullopt);
+  states->encoder->OnReceivedUplinkBandwidth(0, absl::nullopt);
   for (int packet_index = 0; packet_index < kNumPacketsToEncode;
        packet_index++) {
     // Make sure we are not encoding before we have enough data for
@@ -755,8 +753,8 @@
   EXPECT_EQ(8000, config.max_playback_rate_hz);
   EXPECT_EQ(12000, config.bitrate_bps);
 
-  config = CreateConfigWithParameters({{"maxplaybackrate", "8000"},
-                                       {"stereo", "1"}});
+  config = CreateConfigWithParameters(
+      {{"maxplaybackrate", "8000"}, {"stereo", "1"}});
   EXPECT_EQ(8000, config.max_playback_rate_hz);
   EXPECT_EQ(24000, config.bitrate_bps);
 }
@@ -767,8 +765,8 @@
   EXPECT_EQ(8001, config.max_playback_rate_hz);
   EXPECT_EQ(20000, config.bitrate_bps);
 
-  config = CreateConfigWithParameters({{"maxplaybackrate", "8001"},
-                                       {"stereo", "1"}});
+  config = CreateConfigWithParameters(
+      {{"maxplaybackrate", "8001"}, {"stereo", "1"}});
   EXPECT_EQ(8001, config.max_playback_rate_hz);
   EXPECT_EQ(40000, config.bitrate_bps);
 }
@@ -779,8 +777,8 @@
   EXPECT_EQ(12001, config.max_playback_rate_hz);
   EXPECT_EQ(20000, config.bitrate_bps);
 
-  config = CreateConfigWithParameters({{"maxplaybackrate", "12001"},
-                                       {"stereo", "1"}});
+  config = CreateConfigWithParameters(
+      {{"maxplaybackrate", "12001"}, {"stereo", "1"}});
   EXPECT_EQ(12001, config.max_playback_rate_hz);
   EXPECT_EQ(40000, config.bitrate_bps);
 }
@@ -791,8 +789,8 @@
   EXPECT_EQ(16001, config.max_playback_rate_hz);
   EXPECT_EQ(32000, config.bitrate_bps);
 
-  config = CreateConfigWithParameters({{"maxplaybackrate", "16001"},
-                                       {"stereo", "1"}});
+  config = CreateConfigWithParameters(
+      {{"maxplaybackrate", "16001"}, {"stereo", "1"}});
   EXPECT_EQ(16001, config.max_playback_rate_hz);
   EXPECT_EQ(64000, config.bitrate_bps);
 }
@@ -803,8 +801,8 @@
   EXPECT_EQ(24001, config.max_playback_rate_hz);
   EXPECT_EQ(32000, config.bitrate_bps);
 
-  config = CreateConfigWithParameters({{"maxplaybackrate", "24001"},
-                                       {"stereo", "1"}});
+  config = CreateConfigWithParameters(
+      {{"maxplaybackrate", "24001"}, {"stereo", "1"}});
   EXPECT_EQ(24001, config.max_playback_rate_hz);
   EXPECT_EQ(64000, config.bitrate_bps);
 }
diff --git a/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc b/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
index 4394949..7f09c2a 100644
--- a/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_bandwidth_unittest.cc
@@ -105,12 +105,12 @@
   test::ScopedFieldTrials override_field_trials(
       "WebRTC-AdjustOpusBandwidth/Enabled/");
 
-  constexpr float kMaxNarrowbandRatio = 0.003f;
+  constexpr float kMaxNarrowbandRatio = 0.0035f;
   constexpr float kMinWidebandRatio = 0.03f;
 
   // Create encoder.
   AudioEncoderOpusConfig enc_config;
-  enc_config.bitrate_bps = rtc::Optional<int>(7999);
+  enc_config.bitrate_bps = absl::optional<int>(7999);
   enc_config.num_channels = kNumChannels;
   constexpr int payload_type = 17;
   auto encoder = AudioEncoderOpus::MakeAudioEncoder(enc_config, payload_type);
diff --git a/modules/audio_coding/codecs/opus/opus_fec_test.cc b/modules/audio_coding/codecs/opus/opus_fec_test.cc
index 4e0a17e..f1983ae 100644
--- a/modules/audio_coding/codecs/opus/opus_fec_test.cc
+++ b/modules/audio_coding/codecs/opus/opus_fec_test.cc
@@ -83,8 +83,8 @@
   rewind(fp);
 
   // Allocate memory to contain the whole file.
-  in_data_.reset(new int16_t[loop_length_samples_ +
-      block_length_sample_ * channels_]);
+  in_data_.reset(
+      new int16_t[loop_length_samples_ + block_length_sample_ * channels_]);
 
   // Copy the file into the buffer.
   ASSERT_EQ(fread(&in_data_[0], sizeof(int16_t), loop_length_samples_, fp),
@@ -130,14 +130,12 @@
       max_bytes_(0),
       encoded_bytes_(0),
       opus_encoder_(NULL),
-      opus_decoder_(NULL) {
-}
+      opus_decoder_(NULL) {}
 
 void OpusFecTest::EncodeABlock() {
-  int value = WebRtcOpus_Encode(opus_encoder_,
-                                &in_data_[data_pointer_],
-                                block_length_sample_,
-                                max_bytes_, &bit_stream_[0]);
+  int value =
+      WebRtcOpus_Encode(opus_encoder_, &in_data_[data_pointer_],
+                        block_length_sample_, max_bytes_, &bit_stream_[0]);
   EXPECT_GT(value, 0);
 
   encoded_bytes_ = static_cast<size_t>(value);
@@ -151,9 +149,9 @@
     // Decode previous frame.
     if (!lost_current &&
         WebRtcOpus_PacketHasFec(&bit_stream_[0], encoded_bytes_) == 1) {
-      value_1 = WebRtcOpus_DecodeFec(opus_decoder_, &bit_stream_[0],
-                                     encoded_bytes_, &out_data_[0],
-                                     &audio_type);
+      value_1 =
+          WebRtcOpus_DecodeFec(opus_decoder_, &bit_stream_[0], encoded_bytes_,
+                               &out_data_[0], &audio_type);
     } else {
       value_1 = WebRtcOpus_DecodePlc(opus_decoder_, &out_data_[0], 1);
     }
@@ -173,16 +171,14 @@
   int time_now_ms, fec_frames;
   int actual_packet_loss_rate;
   bool lost_current, lost_previous;
-  mode mode_set[3] = {{true, 0},
-                      {false, 0},
-                      {true, 50}};
+  mode mode_set[3] = {{true, 0}, {false, 0}, {true, 50}};
 
   lost_current = false;
   for (int i = 0; i < 3; i++) {
     if (mode_set[i].fec) {
       EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
-      EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_,
-          mode_set[i].target_packet_loss_rate));
+      EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(
+                       opus_encoder_, mode_set[i].target_packet_loss_rate));
       printf("FEC is ON, target at packet loss rate %d percent.\n",
              mode_set[i].target_packet_loss_rate);
     } else {
@@ -218,7 +214,7 @@
       // |data_pointer_| is incremented and wrapped across
       // |loop_length_samples_|.
       data_pointer_ = (data_pointer_ + block_length_sample_ * channels_) %
-        loop_length_samples_;
+                      loop_length_samples_;
     }
     if (mode_set[i].fec) {
       printf("%.2f percent frames has FEC.\n",
@@ -242,7 +238,6 @@
                     string("pcm"))};
 
 // 64 kbps, stereo
-INSTANTIATE_TEST_CASE_P(AllTest, OpusFecTest,
-                        ::testing::ValuesIn(param_set));
+INSTANTIATE_TEST_CASE_P(AllTest, OpusFecTest, ::testing::ValuesIn(param_set));
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/opus_inst.h b/modules/audio_coding/codecs/opus/opus_inst.h
index 066fa22..2473a5c 100644
--- a/modules/audio_coding/codecs/opus/opus_inst.h
+++ b/modules/audio_coding/codecs/opus/opus_inst.h
@@ -32,5 +32,4 @@
   int in_dtx_mode;
 };
 
-
 #endif  // MODULES_AUDIO_CODING_CODECS_OPUS_OPUS_INST_H_
diff --git a/modules/audio_coding/codecs/opus/opus_interface.h b/modules/audio_coding/codecs/opus/opus_interface.h
index 4b8e892..0b1c64d 100644
--- a/modules/audio_coding/codecs/opus/opus_interface.h
+++ b/modules/audio_coding/codecs/opus/opus_interface.h
@@ -318,8 +318,10 @@
  * Return value              : >0 - Samples per channel in decoded vector
  *                             -1 - Error
  */
-int WebRtcOpus_Decode(OpusDecInst* inst, const uint8_t* encoded,
-                      size_t encoded_bytes, int16_t* decoded,
+int WebRtcOpus_Decode(OpusDecInst* inst,
+                      const uint8_t* encoded,
+                      size_t encoded_bytes,
+                      int16_t* decoded,
                       int16_t* audio_type);
 
 /****************************************************************************
@@ -336,7 +338,8 @@
  * Return value                   : >0 - number of samples in decoded PLC vector
  *                                  -1 - Error
  */
-int WebRtcOpus_DecodePlc(OpusDecInst* inst, int16_t* decoded,
+int WebRtcOpus_DecodePlc(OpusDecInst* inst,
+                         int16_t* decoded,
                          int number_of_lost_frames);
 
 /****************************************************************************
@@ -357,8 +360,10 @@
  *                              0 - No FEC data in the packet
  *                             -1 - Error
  */
-int WebRtcOpus_DecodeFec(OpusDecInst* inst, const uint8_t* encoded,
-                         size_t encoded_bytes, int16_t* decoded,
+int WebRtcOpus_DecodeFec(OpusDecInst* inst,
+                         const uint8_t* encoded,
+                         size_t encoded_bytes,
+                         int16_t* decoded,
                          int16_t* audio_type);
 
 /****************************************************************************
diff --git a/modules/audio_coding/codecs/opus/opus_speed_test.cc b/modules/audio_coding/codecs/opus/opus_speed_test.cc
index ca46aa1..03b59ed 100644
--- a/modules/audio_coding/codecs/opus/opus_speed_test.cc
+++ b/modules/audio_coding/codecs/opus/opus_speed_test.cc
@@ -23,9 +23,12 @@
   OpusSpeedTest();
   void SetUp() override;
   void TearDown() override;
-  float EncodeABlock(int16_t* in_data, uint8_t* bit_stream,
-                     size_t max_bytes, size_t* encoded_bytes) override;
-  float DecodeABlock(const uint8_t* bit_stream, size_t encoded_bytes,
+  float EncodeABlock(int16_t* in_data,
+                     uint8_t* bit_stream,
+                     size_t max_bytes,
+                     size_t* encoded_bytes) override;
+  float DecodeABlock(const uint8_t* bit_stream,
+                     size_t encoded_bytes,
                      int16_t* out_data) override;
   WebRtcOpusEncInst* opus_encoder_;
   WebRtcOpusDecInst* opus_decoder_;
@@ -36,8 +39,7 @@
                           kOpusSamplingKhz,
                           kOpusSamplingKhz),
       opus_encoder_(NULL),
-      opus_decoder_(NULL) {
-}
+      opus_decoder_(NULL) {}
 
 void OpusSpeedTest::SetUp() {
   AudioCodecSpeedTest::SetUp();
@@ -57,12 +59,13 @@
   EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
 }
 
-float OpusSpeedTest::EncodeABlock(int16_t* in_data, uint8_t* bit_stream,
-                                  size_t max_bytes, size_t* encoded_bytes) {
+float OpusSpeedTest::EncodeABlock(int16_t* in_data,
+                                  uint8_t* bit_stream,
+                                  size_t max_bytes,
+                                  size_t* encoded_bytes) {
   clock_t clocks = clock();
-  int value = WebRtcOpus_Encode(opus_encoder_, in_data,
-                                input_length_sample_, max_bytes,
-                                bit_stream);
+  int value = WebRtcOpus_Encode(opus_encoder_, in_data, input_length_sample_,
+                                max_bytes, bit_stream);
   clocks = clock() - clocks;
   EXPECT_GT(value, 0);
   *encoded_bytes = static_cast<size_t>(value);
@@ -70,7 +73,8 @@
 }
 
 float OpusSpeedTest::DecodeABlock(const uint8_t* bit_stream,
-                                  size_t encoded_bytes, int16_t* out_data) {
+                                  size_t encoded_bytes,
+                                  int16_t* out_data) {
   int value;
   int16_t audio_type;
   clock_t clocks = clock();
@@ -84,13 +88,13 @@
 /* Test audio length in second. */
 constexpr size_t kDurationSec = 400;
 
-#define ADD_TEST(complexity) \
-TEST_P(OpusSpeedTest, OpusSetComplexityTest##complexity) { \
-  /* Set complexity. */ \
-  printf("Setting complexity to %d ...\n", complexity); \
-  EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, complexity)); \
-  EncodeDecode(kDurationSec); \
-}
+#define ADD_TEST(complexity)                                           \
+  TEST_P(OpusSpeedTest, OpusSetComplexityTest##complexity) {           \
+    /* Set complexity. */                                              \
+    printf("Setting complexity to %d ...\n", complexity);              \
+    EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, complexity)); \
+    EncodeDecode(kDurationSec);                                        \
+  }
 
 ADD_TEST(10);
 ADD_TEST(9);
@@ -136,7 +140,6 @@
                     string("pcm"),
                     true)};
 
-INSTANTIATE_TEST_CASE_P(AllTest, OpusSpeedTest,
-                        ::testing::ValuesIn(param_set));
+INSTANTIATE_TEST_CASE_P(AllTest, OpusSpeedTest, ::testing::ValuesIn(param_set));
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/codecs/opus/opus_unittest.cc b/modules/audio_coding/codecs/opus/opus_unittest.cc
index 12a1585..034f8cd 100644
--- a/modules/audio_coding/codecs/opus/opus_unittest.cc
+++ b/modules/audio_coding/codecs/opus/opus_unittest.cc
@@ -58,9 +58,12 @@
                    int16_t* audio_type);
 
   void SetMaxPlaybackRate(WebRtcOpusEncInst* encoder,
-                          opus_int32 expect, int32_t set);
+                          opus_int32 expect,
+                          int32_t set);
 
-  void CheckAudioBounded(const int16_t* audio, size_t samples, size_t channels,
+  void CheckAudioBounded(const int16_t* audio,
+                         size_t samples,
+                         size_t channels,
                          uint16_t bound) const;
 
   WebRtcOpusEncInst* opus_encoder_;
@@ -78,15 +81,15 @@
       opus_decoder_(NULL),
       encoded_bytes_(0),
       channels_(static_cast<size_t>(::testing::get<0>(GetParam()))),
-      application_(::testing::get<1>(GetParam())) {
-}
+      application_(::testing::get<1>(GetParam())) {}
 
-void OpusTest::PrepareSpeechData(size_t channel, int block_length_ms,
+void OpusTest::PrepareSpeechData(size_t channel,
+                                 int block_length_ms,
                                  int loop_length_ms) {
-  const std::string file_name =
-        webrtc::test::ResourcePath((channel == 1) ?
-            "audio_coding/testfile32kHz" :
-            "audio_coding/teststereo32kHz", "pcm");
+  const std::string file_name = webrtc::test::ResourcePath(
+      (channel == 1) ? "audio_coding/testfile32kHz"
+                     : "audio_coding/teststereo32kHz",
+      "pcm");
   if (loop_length_ms < block_length_ms) {
     loop_length_ms = block_length_ms;
   }
@@ -100,13 +103,14 @@
                                   int32_t set) {
   opus_int32 bandwidth;
   EXPECT_EQ(0, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, set));
-  opus_encoder_ctl(opus_encoder_->encoder,
-                   OPUS_GET_MAX_BANDWIDTH(&bandwidth));
+  opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_MAX_BANDWIDTH(&bandwidth));
   EXPECT_EQ(expect, bandwidth);
 }
 
-void OpusTest::CheckAudioBounded(const int16_t* audio, size_t samples,
-                                 size_t channels, uint16_t bound) const {
+void OpusTest::CheckAudioBounded(const int16_t* audio,
+                                 size_t samples,
+                                 size_t channels,
+                                 uint16_t bound) const {
   for (size_t i = 0; i < samples; ++i) {
     for (size_t c = 0; c < channels; ++c) {
       ASSERT_GE(audio[i * channels + c], -bound);
@@ -120,16 +124,15 @@
                            WebRtcOpusDecInst* decoder,
                            int16_t* output_audio,
                            int16_t* audio_type) {
-  int encoded_bytes_int = WebRtcOpus_Encode(
-      encoder, input_audio.data(),
-      rtc::CheckedDivExact(input_audio.size(), channels_),
-      kMaxBytes, bitstream_);
+  int encoded_bytes_int =
+      WebRtcOpus_Encode(encoder, input_audio.data(),
+                        rtc::CheckedDivExact(input_audio.size(), channels_),
+                        kMaxBytes, bitstream_);
   EXPECT_GE(encoded_bytes_int, 0);
   encoded_bytes_ = static_cast<size_t>(encoded_bytes_int);
   int est_len = WebRtcOpus_DurationEst(decoder, bitstream_, encoded_bytes_);
-  int act_len = WebRtcOpus_Decode(decoder, bitstream_,
-                                  encoded_bytes_, output_audio,
-                                  audio_type);
+  int act_len = WebRtcOpus_Decode(decoder, bitstream_, encoded_bytes_,
+                                  output_audio, audio_type);
   EXPECT_EQ(est_len, act_len);
   return act_len;
 }
@@ -141,30 +144,28 @@
   const size_t samples = kOpusRateKhz * block_length_ms;
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
   EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
 
   // Set bitrate.
-  EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_,
-                                     channels_ == 1 ? 32000 : 64000));
+  EXPECT_EQ(
+      0, WebRtcOpus_SetBitRate(opus_encoder_, channels_ == 1 ? 32000 : 64000));
 
   // Set input audio as silence.
   std::vector<int16_t> silence(samples * channels_, 0);
 
   // Setting DTX.
-  EXPECT_EQ(0, dtx ? WebRtcOpus_EnableDtx(opus_encoder_) :
-      WebRtcOpus_DisableDtx(opus_encoder_));
+  EXPECT_EQ(0, dtx ? WebRtcOpus_EnableDtx(opus_encoder_)
+                   : WebRtcOpus_DisableDtx(opus_encoder_));
 
   int16_t audio_type;
   int16_t* output_data_decode = new int16_t[samples * channels_];
 
   for (int i = 0; i < 100; ++i) {
-    EXPECT_EQ(samples,
-              static_cast<size_t>(EncodeDecode(
-                  opus_encoder_, speech_data_.GetNextBlock(), opus_decoder_,
-                  output_data_decode, &audio_type)));
+    EXPECT_EQ(samples, static_cast<size_t>(EncodeDecode(
+                           opus_encoder_, speech_data_.GetNextBlock(),
+                           opus_decoder_, output_data_decode, &audio_type)));
     // If not DTX, it should never enter DTX mode. If DTX, we do not care since
     // whether it enters DTX depends on the signal type.
     if (!dtx) {
@@ -178,10 +179,9 @@
   // We input some silent segments. In DTX mode, the encoder will stop sending.
   // However, DTX may happen after a while.
   for (int i = 0; i < 30; ++i) {
-    EXPECT_EQ(samples,
-              static_cast<size_t>(EncodeDecode(
-                  opus_encoder_, silence, opus_decoder_, output_data_decode,
-                  &audio_type)));
+    EXPECT_EQ(samples, static_cast<size_t>(
+                           EncodeDecode(opus_encoder_, silence, opus_decoder_,
+                                        output_data_decode, &audio_type)));
     if (!dtx) {
       EXPECT_GT(encoded_bytes_, 1U);
       EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
@@ -227,10 +227,9 @@
     int i = 0;
     for (; i < max_dtx_frames; ++i) {
       time += block_length_ms;
-      EXPECT_EQ(samples,
-                static_cast<size_t>(EncodeDecode(
-                    opus_encoder_, silence, opus_decoder_, output_data_decode,
-                    &audio_type)));
+      EXPECT_EQ(samples, static_cast<size_t>(
+                             EncodeDecode(opus_encoder_, silence, opus_decoder_,
+                                          output_data_decode, &audio_type)));
       if (dtx) {
         if (encoded_bytes_ > 1)
           break;
@@ -263,10 +262,9 @@
 
     // Enters DTX again immediately.
     time += block_length_ms;
-    EXPECT_EQ(samples,
-              static_cast<size_t>(EncodeDecode(
-                  opus_encoder_, silence, opus_decoder_, output_data_decode,
-                  &audio_type)));
+    EXPECT_EQ(samples, static_cast<size_t>(
+                           EncodeDecode(opus_encoder_, silence, opus_decoder_,
+                                        output_data_decode, &audio_type)));
     if (dtx) {
       EXPECT_EQ(1U, encoded_bytes_);  // Send 1 byte.
       EXPECT_EQ(1, opus_encoder_->in_dtx_mode);
@@ -287,10 +285,9 @@
   silence[0] = 10000;
   if (dtx) {
     // Verify that encoder/decoder can jump out from DTX mode.
-    EXPECT_EQ(samples,
-              static_cast<size_t>(EncodeDecode(
-                  opus_encoder_, silence, opus_decoder_, output_data_decode,
-                  &audio_type)));
+    EXPECT_EQ(samples, static_cast<size_t>(
+                           EncodeDecode(opus_encoder_, silence, opus_decoder_,
+                                        output_data_decode, &audio_type)));
     EXPECT_GT(encoded_bytes_, 1U);
     EXPECT_EQ(0, opus_encoder_->in_dtx_mode);
     EXPECT_EQ(0, opus_decoder_->in_dtx_mode);
@@ -375,9 +372,8 @@
 
 // Test normal Create and Free.
 TEST_P(OpusTest, OpusCreateFree) {
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
   EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
   EXPECT_TRUE(opus_encoder_ != NULL);
   EXPECT_TRUE(opus_decoder_ != NULL);
@@ -390,23 +386,20 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
-  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_,
-                                        channels_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
 
   // Set bitrate.
-  EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_,
-                                     channels_ == 1 ? 32000 : 64000));
+  EXPECT_EQ(
+      0, WebRtcOpus_SetBitRate(opus_encoder_, channels_ == 1 ? 32000 : 64000));
 
   // Check number of channels for decoder.
   EXPECT_EQ(channels_, WebRtcOpus_DecoderChannels(opus_decoder_));
 
   // Check application mode.
   opus_int32 app;
-  opus_encoder_ctl(opus_encoder_->encoder,
-                   OPUS_GET_APPLICATION(&app));
+  opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_APPLICATION(&app));
   EXPECT_EQ(application_ == 0 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO,
             app);
 
@@ -429,9 +422,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
 
   // Create encoder memory, try with different bitrates.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 30000));
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 60000));
   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, 300000));
@@ -446,9 +438,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetComplexity(opus_encoder_, 9));
 
   // Create encoder memory, try with different complexities.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
 
   EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 0));
   EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_encoder_, 10));
@@ -524,9 +515,8 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
   EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
 
   // Encode & decode.
@@ -540,9 +530,9 @@
   WebRtcOpus_DecoderInit(opus_decoder_);
 
   EXPECT_EQ(kOpus20msFrameSamples,
-            static_cast<size_t>(WebRtcOpus_Decode(
-                opus_decoder_, bitstream_, encoded_bytes_, output_data_decode,
-                &audio_type)));
+            static_cast<size_t>(
+                WebRtcOpus_Decode(opus_decoder_, bitstream_, encoded_bytes_,
+                                  output_data_decode, &audio_type)));
 
   // Free memory.
   delete[] output_data_decode;
@@ -556,9 +546,8 @@
   EXPECT_EQ(-1, WebRtcOpus_DisableFec(opus_encoder_));
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
 
   EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
   EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_));
@@ -573,30 +562,25 @@
   EXPECT_EQ(-1, WebRtcOpus_DisableDtx(opus_encoder_));
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
 
   opus_int32 dtx;
 
   // DTX is off by default.
-  opus_encoder_ctl(opus_encoder_->encoder,
-                   OPUS_GET_DTX(&dtx));
+  opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx));
   EXPECT_EQ(0, dtx);
 
   // Test to enable DTX.
   EXPECT_EQ(0, WebRtcOpus_EnableDtx(opus_encoder_));
-  opus_encoder_ctl(opus_encoder_->encoder,
-                   OPUS_GET_DTX(&dtx));
+  opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx));
   EXPECT_EQ(1, dtx);
 
   // Test to disable DTX.
   EXPECT_EQ(0, WebRtcOpus_DisableDtx(opus_encoder_));
-  opus_encoder_ctl(opus_encoder_->encoder,
-                   OPUS_GET_DTX(&dtx));
+  opus_encoder_ctl(opus_encoder_->encoder, OPUS_GET_DTX(&dtx));
   EXPECT_EQ(0, dtx);
 
-
   // Free memory.
   EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
 }
@@ -630,9 +614,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
 
   EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_, 50));
   EXPECT_EQ(-1, WebRtcOpus_SetPacketLossRate(opus_encoder_, -1));
@@ -647,9 +630,8 @@
   EXPECT_EQ(-1, WebRtcOpus_SetMaxPlaybackRate(opus_encoder_, 20000));
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
 
   SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 48000);
   SetMaxPlaybackRate(opus_encoder_, OPUS_BANDWIDTH_FULLBAND, 24001);
@@ -671,14 +653,13 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create encoder memory.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
   EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
 
   // Set bitrate.
-  EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_,
-                                     channels_== 1 ? 32000 : 64000));
+  EXPECT_EQ(
+      0, WebRtcOpus_SetBitRate(opus_encoder_, channels_ == 1 ? 32000 : 64000));
 
   // Check number of channels for decoder.
   EXPECT_EQ(channels_, WebRtcOpus_DecoderChannels(opus_decoder_));
@@ -693,9 +674,8 @@
 
   // Call decoder PLC.
   int16_t* plc_buffer = new int16_t[kOpus20msFrameSamples * channels_];
-  EXPECT_EQ(kOpus20msFrameSamples,
-            static_cast<size_t>(WebRtcOpus_DecodePlc(
-                opus_decoder_, plc_buffer, 1)));
+  EXPECT_EQ(kOpus20msFrameSamples, static_cast<size_t>(WebRtcOpus_DecodePlc(
+                                       opus_decoder_, plc_buffer, 1)));
 
   // Free memory.
   delete[] plc_buffer;
@@ -709,34 +689,33 @@
   PrepareSpeechData(channels_, 20, 20);
 
   // Create.
-  EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
+  EXPECT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
   EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
 
   // 10 ms. We use only first 10 ms of a 20 ms block.
   auto speech_block = speech_data_.GetNextBlock();
   int encoded_bytes_int = WebRtcOpus_Encode(
       opus_encoder_, speech_block.data(),
-      rtc::CheckedDivExact(speech_block.size(), 2 * channels_),
-      kMaxBytes, bitstream_);
+      rtc::CheckedDivExact(speech_block.size(), 2 * channels_), kMaxBytes,
+      bitstream_);
   EXPECT_GE(encoded_bytes_int, 0);
-  EXPECT_EQ(kOpus10msFrameSamples,
-            static_cast<size_t>(WebRtcOpus_DurationEst(
-                opus_decoder_, bitstream_,
-                static_cast<size_t>(encoded_bytes_int))));
+  EXPECT_EQ(
+      kOpus10msFrameSamples,
+      static_cast<size_t>(WebRtcOpus_DurationEst(
+          opus_decoder_, bitstream_, static_cast<size_t>(encoded_bytes_int))));
 
   // 20 ms
   speech_block = speech_data_.GetNextBlock();
-  encoded_bytes_int = WebRtcOpus_Encode(
-      opus_encoder_, speech_block.data(),
-      rtc::CheckedDivExact(speech_block.size(), channels_),
-      kMaxBytes, bitstream_);
+  encoded_bytes_int =
+      WebRtcOpus_Encode(opus_encoder_, speech_block.data(),
+                        rtc::CheckedDivExact(speech_block.size(), channels_),
+                        kMaxBytes, bitstream_);
   EXPECT_GE(encoded_bytes_int, 0);
-  EXPECT_EQ(kOpus20msFrameSamples,
-            static_cast<size_t>(WebRtcOpus_DurationEst(
-                opus_decoder_, bitstream_,
-                static_cast<size_t>(encoded_bytes_int))));
+  EXPECT_EQ(
+      kOpus20msFrameSamples,
+      static_cast<size_t>(WebRtcOpus_DurationEst(
+          opus_decoder_, bitstream_, static_cast<size_t>(encoded_bytes_int))));
 
   // Free memory.
   EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
@@ -749,15 +728,13 @@
   PrepareSpeechData(channels_, 20, 20 * kPackets);
 
   // Create encoder memory.
-  ASSERT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_,
-                                        channels_,
-                                        application_));
-  ASSERT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_,
-                                        channels_));
+  ASSERT_EQ(0,
+            WebRtcOpus_EncoderCreate(&opus_encoder_, channels_, application_));
+  ASSERT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
 
   // Set bitrate.
-  EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_,
-                                     channels_ == 1 ? 32000 : 64000));
+  EXPECT_EQ(
+      0, WebRtcOpus_SetBitRate(opus_encoder_, channels_ == 1 ? 32000 : 64000));
 
   // Check number of channels for decoder.
   EXPECT_EQ(channels_, WebRtcOpus_DecoderChannels(opus_decoder_));
@@ -776,9 +753,9 @@
         WebRtcOpus_Encode(opus_encoder_, speech_block.data(),
                           rtc::CheckedDivExact(speech_block.size(), channels_),
                           kMaxBytes, bitstream_);
-    if (opus_repacketizer_cat(
-            rp, bitstream_,
-            rtc::checked_cast<opus_int32>(encoded_bytes_)) == OPUS_OK) {
+    if (opus_repacketizer_cat(rp, bitstream_,
+                              rtc::checked_cast<opus_int32>(encoded_bytes_)) ==
+        OPUS_OK) {
       ++num_packets;
       if (num_packets == kPackets) {
         break;
@@ -798,9 +775,9 @@
                 opus_decoder_, bitstream_, encoded_bytes_)));
 
   EXPECT_EQ(kOpus20msFrameSamples * kPackets,
-            static_cast<size_t>(WebRtcOpus_Decode(
-                opus_decoder_, bitstream_, encoded_bytes_,
-                output_data_decode.get(), &audio_type)));
+            static_cast<size_t>(
+                WebRtcOpus_Decode(opus_decoder_, bitstream_, encoded_bytes_,
+                                  output_data_decode.get(), &audio_type)));
 
   // Free memory.
   opus_repacketizer_destroy(rp);
@@ -812,5 +789,4 @@
                         OpusTest,
                         Combine(Values(1, 2), Values(0, 1)));
 
-
 }  // namespace webrtc
diff --git a/modules/audio_coding/codecs/pcm16b/pcm16b.h b/modules/audio_coding/codecs/pcm16b/pcm16b.h
index 041701a..9a3bfe9 100644
--- a/modules/audio_coding/codecs/pcm16b/pcm16b.h
+++ b/modules/audio_coding/codecs/pcm16b/pcm16b.h
@@ -38,9 +38,7 @@
  *                                Always equal to twice the len input parameter.
  */
 
-size_t WebRtcPcm16b_Encode(const int16_t* speech,
-                           size_t len,
-                           uint8_t* encoded);
+size_t WebRtcPcm16b_Encode(const int16_t* speech, size_t len, uint8_t* encoded);
 
 /****************************************************************************
  * WebRtcPcm16b_Decode(...)
@@ -57,9 +55,7 @@
  * Returned value               : Samples in speech
  */
 
-size_t WebRtcPcm16b_Decode(const uint8_t* encoded,
-                           size_t len,
-                           int16_t* speech);
+size_t WebRtcPcm16b_Decode(const uint8_t* encoded, size_t len, int16_t* speech);
 
 #ifdef __cplusplus
 }
diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc b/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
index 4b9df6e..2601f26 100644
--- a/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
+++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
@@ -58,10 +58,8 @@
     uint32_t rtp_timestamp,
     rtc::ArrayView<const int16_t> audio,
     rtc::Buffer* encoded) {
-
   const size_t primary_offset = encoded->size();
-  EncodedInfo info =
-      speech_encoder_->Encode(rtp_timestamp, audio, encoded);
+  EncodedInfo info = speech_encoder_->Encode(rtp_timestamp, audio, encoded);
 
   RTC_CHECK(info.redundant.empty()) << "Cannot use nested redundant encoders.";
   RTC_DCHECK_EQ(encoded->size() - primary_offset, info.encoded_bytes);
@@ -134,7 +132,7 @@
 
 void AudioEncoderCopyRed::OnReceivedUplinkBandwidth(
     int target_audio_bitrate_bps,
-    rtc::Optional<int64_t> bwe_period_ms) {
+    absl::optional<int64_t> bwe_period_ms) {
   speech_encoder_->OnReceivedUplinkBandwidth(target_audio_bitrate_bps,
                                              bwe_period_ms);
 }
diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
index e625c50..492ee3a 100644
--- a/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
+++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
@@ -57,7 +57,7 @@
       float uplink_recoverable_packet_loss_fraction) override;
   void OnReceivedUplinkBandwidth(
       int target_audio_bitrate_bps,
-      rtc::Optional<int64_t> bwe_period_ms) override;
+      absl::optional<int64_t> bwe_period_ms) override;
 
  protected:
   EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
diff --git a/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc b/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
index 64bafd2..0f5a811 100644
--- a/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
+++ b/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
@@ -48,9 +48,7 @@
         .WillRepeatedly(Return(sample_rate_hz_));
   }
 
-  void TearDown() override {
-    red_.reset();
-  }
+  void TearDown() override { red_.reset(); }
 
   void Encode() {
     ASSERT_TRUE(red_.get() != NULL);
@@ -73,8 +71,7 @@
   const int red_payload_type_;
 };
 
-TEST_F(AudioEncoderCopyRedTest, CreateAndDestroy) {
-}
+TEST_F(AudioEncoderCopyRedTest, CreateAndDestroy) {}
 
 TEST_F(AudioEncoderCopyRedTest, CheckSampleRatePropagation) {
   EXPECT_CALL(*mock_encoder_, SampleRateHz()).WillOnce(Return(17));
@@ -99,8 +96,8 @@
 
 TEST_F(AudioEncoderCopyRedTest, CheckTargetAudioBitratePropagation) {
   EXPECT_CALL(*mock_encoder_,
-              OnReceivedUplinkBandwidth(4711, rtc::Optional<int64_t>()));
-  red_->OnReceivedUplinkBandwidth(4711, rtc::nullopt);
+              OnReceivedUplinkBandwidth(4711, absl::optional<int64_t>()));
+  red_->OnReceivedUplinkBandwidth(4711, absl::nullopt);
 }
 
 TEST_F(AudioEncoderCopyRedTest, CheckPacketLossFractionPropagation) {
diff --git a/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc b/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
index d3749c1..c539152 100644
--- a/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
+++ b/modules/audio_coding/codecs/tools/audio_codec_speed_test.cc
@@ -34,8 +34,7 @@
       encoded_bytes_(0),
       encoding_time_ms_(0.0),
       decoding_time_ms_(0.0),
-      out_file_(NULL) {
-}
+      out_file_(NULL) {}
 
 void AudioCodecSpeedTest::SetUp() {
   channels_ = get<0>(GetParam());
@@ -52,8 +51,8 @@
   rewind(fp);
 
   // Allocate memory to contain the whole file.
-  in_data_.reset(new int16_t[loop_length_samples_ +
-      input_length_sample_ * channels_]);
+  in_data_.reset(
+      new int16_t[loop_length_samples_ + input_length_sample_ * channels_]);
 
   data_pointer_ = 0;
 
@@ -111,11 +110,11 @@
     time_ms = DecodeABlock(&bit_stream_[0], encoded_bytes_, &out_data_[0]);
     decoding_time_ms_ += time_ms;
     if (save_out_data_) {
-      fwrite(&out_data_[0], sizeof(int16_t),
-             output_length_sample_ * channels_, out_file_);
+      fwrite(&out_data_[0], sizeof(int16_t), output_length_sample_ * channels_,
+             out_file_);
     }
     data_pointer_ = (data_pointer_ + input_length_sample_ * channels_) %
-        loop_length_samples_;
+                    loop_length_samples_;
     time_now_ms += block_duration_ms_;
   }
 
diff --git a/modules/audio_coding/codecs/tools/audio_codec_speed_test.h b/modules/audio_coding/codecs/tools/audio_codec_speed_test.h
index 9e616e7..0214a7d 100644
--- a/modules/audio_coding/codecs/tools/audio_codec_speed_test.h
+++ b/modules/audio_coding/codecs/tools/audio_codec_speed_test.h
@@ -36,15 +36,18 @@
   // 2. save the bit stream to |bit_stream| of |max_bytes| bytes in size,
   // 3. assign |encoded_bytes| with the length of the bit stream (in bytes),
   // 4. return the cost of time (in millisecond) spent on actual encoding.
-  virtual float EncodeABlock(int16_t* in_data, uint8_t* bit_stream,
-                             size_t max_bytes, size_t* encoded_bytes) = 0;
+  virtual float EncodeABlock(int16_t* in_data,
+                             uint8_t* bit_stream,
+                             size_t max_bytes,
+                             size_t* encoded_bytes) = 0;
 
   // DecodeABlock(...) does the following:
   // 1. decodes the bit stream in |bit_stream| with a length of |encoded_bytes|
   // (in bytes),
   // 2. save the decoded audio in |out_data|,
   // 3. return the cost of time (in millisecond) spent on actual decoding.
-  virtual float DecodeABlock(const uint8_t* bit_stream, size_t encoded_bytes,
+  virtual float DecodeABlock(const uint8_t* bit_stream,
+                             size_t encoded_bytes,
                              int16_t* out_data) = 0;
 
   // Encoding and decode an audio of |audio_duration| (in seconds) and
diff --git a/modules/audio_coding/include/audio_coding_module.h b/modules/audio_coding/include/audio_coding_module.h
index 3c193a4..a5ad4ff 100644
--- a/modules/audio_coding/include/audio_coding_module.h
+++ b/modules/audio_coding/include/audio_coding_module.h
@@ -15,9 +15,9 @@
 #include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio_codecs/audio_decoder_factory.h"
 #include "api/audio_codecs/audio_encoder.h"
-#include "api/optional.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/include/audio_coding_module_typedefs.h"
 #include "modules/audio_coding/neteq/include/neteq.h"
@@ -127,8 +127,10 @@
   //   -1 if no codec matches the given parameters.
   //    0 if succeeded.
   //
-  static int Codec(const char* payload_name, CodecInst* codec,
-                   int sampling_freq_hz, size_t channels);
+  static int Codec(const char* payload_name,
+                   CodecInst* codec,
+                   int sampling_freq_hz,
+                   size_t channels);
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t Codec()
@@ -146,7 +148,8 @@
   //   if the codec is found, the index of the codec in the list,
   //   -1 if the codec is not found.
   //
-  static int Codec(const char* payload_name, int sampling_freq_hz,
+  static int Codec(const char* payload_name,
+                   int sampling_freq_hz,
                    size_t channels);
 
   ///////////////////////////////////////////////////////////////////////////
@@ -228,7 +231,7 @@
   // Return value:
   //   The send codec, or nothing if we don't have one
   //
-  virtual rtc::Optional<CodecInst> SendCodec() const = 0;
+  virtual absl::optional<CodecInst> SendCodec() const = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t SendFrequency()
@@ -398,8 +401,8 @@
   //    0 if succeeded.
   //
   virtual int32_t SetVAD(const bool enable_dtx = true,
-                               const bool enable_vad = false,
-                               const ACMVADMode vad_mode = VADNormal) = 0;
+                         const bool enable_vad = false,
+                         const ACMVADMode vad_mode = VADNormal) = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t VAD()
@@ -416,8 +419,9 @@
   //   -1 if fails to retrieve the setting of DTX/VAD,
   //    0 if succeeded.
   //
-  virtual int32_t VAD(bool* dtx_enabled, bool* vad_enabled,
-                            ACMVADMode* vad_mode) const = 0;
+  virtual int32_t VAD(bool* dtx_enabled,
+                      bool* vad_enabled,
+                      ACMVADMode* vad_mode) const = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t RegisterVADCallback()
@@ -527,8 +531,7 @@
   //   -1 if fails to unregister.
   //    0 if the given codec is successfully unregistered.
   //
-  virtual int UnregisterReceiveCodec(
-      uint8_t payload_type) = 0;
+  virtual int UnregisterReceiveCodec(uint8_t payload_type) = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t ReceiveCodec()
@@ -546,7 +549,7 @@
   virtual int32_t ReceiveCodec(CodecInst* curr_receive_codec) const = 0;
 
   ///////////////////////////////////////////////////////////////////////////
-  // rtc::Optional<SdpAudioFormat> ReceiveFormat()
+  // absl::optional<SdpAudioFormat> ReceiveFormat()
   // Get the format associated with last received payload.
   //
   // Return value:
@@ -554,7 +557,7 @@
   //    received payload.
   //    An empty Optional if no payload has yet been received.
   //
-  virtual rtc::Optional<SdpAudioFormat> ReceiveFormat() const = 0;
+  virtual absl::optional<SdpAudioFormat> ReceiveFormat() const = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int32_t IncomingPacket()
@@ -631,7 +634,7 @@
   // the latest audio obtained by calling PlayoutData10ms(), or empty if no
   // valid timestamp is available.
   //
-  virtual rtc::Optional<uint32_t> PlayoutTimestamp() = 0;
+  virtual absl::optional<uint32_t> PlayoutTimestamp() = 0;
 
   ///////////////////////////////////////////////////////////////////////////
   // int FilteredCurrentDelayMs()
diff --git a/modules/audio_coding/include/audio_coding_module_typedefs.h b/modules/audio_coding/include/audio_coding_module_typedefs.h
index 85a6bf9..e8f80dc 100644
--- a/modules/audio_coding/include/audio_coding_module_typedefs.h
+++ b/modules/audio_coding/include/audio_coding_module_typedefs.h
@@ -41,8 +41,8 @@
 // kAudio             : optimized for non-voice signals like music.
 //
 enum OpusApplicationMode {
- kVoip = 0,
- kAudio = 1,
+  kVoip = 0,
+  kAudio = 1,
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/module.mk b/modules/audio_coding/module.mk
index 800cc56..b49e8aa 100644
--- a/modules/audio_coding/module.mk
+++ b/modules/audio_coding/module.mk
@@ -4,6 +4,12 @@
 
 include common.mk
 
+isac_vad_c_OBJECTS = \
+	modules/audio_coding/codecs/isac/main/source/filter_functions.o \
+	modules/audio_coding/codecs/isac/main/source/isac_vad.o \
+	modules/audio_coding/codecs/isac/main/source/pitch_estimator.o \
+	modules/audio_coding/codecs/isac/main/source/pitch_filter.o
+
 # From isac_c.ninja
 isac_c_C_OBJECTS = \
 	modules/audio_coding/codecs/isac/main/source/arith_routines.o \
@@ -17,8 +23,6 @@
 	modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.o \
 	modules/audio_coding/codecs/isac/main/source/entropy_coding.o \
 	modules/audio_coding/codecs/isac/main/source/fft.o \
-	modules/audio_coding/codecs/isac/main/source/filter_functions.o \
-	modules/audio_coding/codecs/isac/main/source/filterbank_tables.o \
 	modules/audio_coding/codecs/isac/main/source/filterbanks.o \
 	modules/audio_coding/codecs/isac/main/source/intialize.o \
 	modules/audio_coding/codecs/isac/main/source/isac.o \
@@ -28,15 +32,13 @@
 	modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.o \
 	modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.o \
 	modules/audio_coding/codecs/isac/main/source/lpc_tables.o \
-	modules/audio_coding/codecs/isac/main/source/pitch_estimator.o \
-	modules/audio_coding/codecs/isac/main/source/pitch_filter.o \
 	modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.o \
 	modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.o \
 	modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.o \
 	modules/audio_coding/codecs/isac/main/source/transform.o
 
 CC_STATIC_LIBRARY(modules/audio_coding/libaudio_coding.pic.a): \
-	$(isac_c_C_OBJECTS)
+	$(isac_c_C_OBJECTS) $(isac_vad_c_OBJECTS)
 
 modules/audio_coding/libaudio_coding: \
 	CC_STATIC_LIBRARY(modules/audio_coding/libaudio_coding.pic.a)
diff --git a/modules/audio_coding/neteq/accelerate.h b/modules/audio_coding/neteq/accelerate.h
index bf4f0f7..6d5b115 100644
--- a/modules/audio_coding/neteq/accelerate.h
+++ b/modules/audio_coding/neteq/accelerate.h
@@ -29,10 +29,10 @@
 // Accelerate are implemented.
 class Accelerate : public TimeStretch {
  public:
-  Accelerate(int sample_rate_hz, size_t num_channels,
+  Accelerate(int sample_rate_hz,
+             size_t num_channels,
              const BackgroundNoise& background_noise)
-      : TimeStretch(sample_rate_hz, num_channels, background_noise) {
-  }
+      : TimeStretch(sample_rate_hz, num_channels, background_noise) {}
 
   // This method performs the actual Accelerate operation. The samples are
   // read from |input|, of length |input_length| elements, and are written to
diff --git a/modules/audio_coding/neteq/audio_decoder_unittest.cc b/modules/audio_coding/neteq/audio_decoder_unittest.cc
index 3181d6f..54ede6f 100644
--- a/modules/audio_coding/neteq/audio_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/audio_decoder_unittest.cc
@@ -114,7 +114,7 @@
     decoder_ = NULL;
   }
 
-  virtual void InitEncoder() { }
+  virtual void InitEncoder() {}
 
   // TODO(henrik.lundin) Change return type to size_t once most/all overriding
   // implementations are gone.
@@ -136,12 +136,13 @@
                                                  samples_per_10ms, channels_,
                                                  interleaved_input.get());
 
-      encoded_info = audio_encoder_->Encode(
-          0, rtc::ArrayView<const int16_t>(interleaved_input.get(),
-                                           audio_encoder_->NumChannels() *
-                                               audio_encoder_->SampleRateHz() /
-                                               100),
-          output);
+      encoded_info =
+          audio_encoder_->Encode(0,
+                                 rtc::ArrayView<const int16_t>(
+                                     interleaved_input.get(),
+                                     audio_encoder_->NumChannels() *
+                                         audio_encoder_->SampleRateHz() / 100),
+                                 output);
     }
     EXPECT_EQ(payload_type_, encoded_info.payload_type);
     return static_cast<int>(encoded_info.encoded_bytes);
@@ -152,11 +153,14 @@
   // with |mse|. The encoded stream should contain |expected_bytes|. For stereo
   // audio, the absolute difference between the two channels is compared vs
   // |channel_diff_tolerance|.
-  void EncodeDecodeTest(size_t expected_bytes, int tolerance, double mse,
-                        int delay = 0, int channel_diff_tolerance = 0) {
+  void EncodeDecodeTest(size_t expected_bytes,
+                        int tolerance,
+                        double mse,
+                        int delay = 0,
+                        int channel_diff_tolerance = 0) {
     ASSERT_GE(tolerance, 0) << "Test must define a tolerance >= 0";
-    ASSERT_GE(channel_diff_tolerance, 0) <<
-        "Test must define a channel_diff_tolerance >= 0";
+    ASSERT_GE(channel_diff_tolerance, 0)
+        << "Test must define a channel_diff_tolerance >= 0";
     size_t processed_samples = 0u;
     rtc::Buffer encoded;
     size_t encoded_bytes = 0u;
@@ -168,10 +172,10 @@
       input.resize(input.size() + frame_size_, 0);
       // Read from input file.
       ASSERT_GE(input.size() - processed_samples, frame_size_);
-      ASSERT_TRUE(input_audio_.Read(
-          frame_size_, codec_input_rate_hz_, &input[processed_samples]));
-      size_t enc_len = EncodeFrame(
-          &input[processed_samples], frame_size_, &encoded);
+      ASSERT_TRUE(input_audio_.Read(frame_size_, codec_input_rate_hz_,
+                                    &input[processed_samples]));
+      size_t enc_len =
+          EncodeFrame(&input[processed_samples], frame_size_, &encoded);
       // Make sure that frame_size_ * channels_ samples are allocated and free.
       decoded.resize((processed_samples + frame_size_) * channels_, 0);
       AudioDecoder::SpeechType speech_type;
@@ -189,11 +193,11 @@
     if (expected_bytes) {
       EXPECT_EQ(expected_bytes, encoded_bytes);
     }
-    CompareInputOutput(
-        input, decoded, processed_samples, channels_, tolerance, delay);
+    CompareInputOutput(input, decoded, processed_samples, channels_, tolerance,
+                       delay);
     if (channels_ == 2)
-      CompareTwoChannels(
-          decoded, processed_samples, channels_, channel_diff_tolerance);
+      CompareTwoChannels(decoded, processed_samples, channels_,
+                         channel_diff_tolerance);
     EXPECT_LE(
         MseInputOutput(input, decoded, processed_samples, channels_, delay),
         mse);
@@ -242,10 +246,9 @@
     AudioDecoder::SpeechType speech_type;
     decoder_->Reset();
     std::unique_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]);
-    size_t dec_len = decoder_->Decode(encoded.data(), enc_len,
-                                      codec_input_rate_hz_,
-                                      frame_size_ * channels_ * sizeof(int16_t),
-                                      output.get(), &speech_type);
+    size_t dec_len = decoder_->Decode(
+        encoded.data(), enc_len, codec_input_rate_hz_,
+        frame_size_ * channels_ * sizeof(int16_t), output.get(), &speech_type);
     EXPECT_EQ(frame_size_ * channels_, dec_len);
     // Call DecodePlc and verify that we get one frame of data.
     // (Overwrite the output from the above Decode call, but that does not
@@ -332,10 +335,9 @@
     AudioDecoder::SpeechType speech_type;
     decoder_->Reset();
     std::unique_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]);
-    size_t dec_len = decoder_->Decode(encoded.data(), enc_len,
-                                      codec_input_rate_hz_,
-                                      frame_size_ * channels_ * sizeof(int16_t),
-                                      output.get(), &speech_type);
+    size_t dec_len = decoder_->Decode(
+        encoded.data(), enc_len, codec_input_rate_hz_,
+        frame_size_ * channels_ * sizeof(int16_t), output.get(), &speech_type);
     EXPECT_EQ(frame_size_, dec_len);
     // Simply call DecodePlc and verify that we get 0 as return value.
     EXPECT_EQ(0U, decoder_->DecodePlc(1, output.get()));
@@ -462,7 +464,7 @@
 
 namespace {
 int SetAndGetTargetBitrate(AudioEncoder* audio_encoder, int rate) {
-  audio_encoder->OnReceivedUplinkBandwidth(rate, rtc::nullopt);
+  audio_encoder->OnReceivedUplinkBandwidth(rate, absl::nullopt);
   return audio_encoder->GetTargetBitrate();
 }
 void TestSetAndGetTargetBitratesWithFixedCodec(AudioEncoder* audio_encoder,
diff --git a/modules/audio_coding/neteq/audio_multi_vector.cc b/modules/audio_coding/neteq/audio_multi_vector.cc
index c3e623f..fee37cb 100644
--- a/modules/audio_coding/neteq/audio_multi_vector.cc
+++ b/modules/audio_coding/neteq/audio_multi_vector.cc
@@ -21,7 +21,8 @@
 
 AudioMultiVector::AudioMultiVector(size_t N) {
   assert(N > 0);
-  if (N < 1) N = 1;
+  if (N < 1)
+    N = 1;
   for (size_t n = 0; n < N; ++n) {
     channels_.push_back(new AudioVector);
   }
@@ -30,7 +31,8 @@
 
 AudioMultiVector::AudioMultiVector(size_t N, size_t initial_size) {
   assert(N > 0);
-  if (N < 1) N = 1;
+  if (N < 1)
+    N = 1;
   for (size_t n = 0; n < N; ++n) {
     channels_.push_back(new AudioVector(initial_size));
   }
@@ -86,7 +88,7 @@
     }
     channels_[channel]->PushBack(temp_array, length_per_channel);
   }
-  delete [] temp_array;
+  delete[] temp_array;
 }
 
 void AudioMultiVector::PushBack(const AudioMultiVector& append_this) {
diff --git a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
index f05aee0..7272dc2 100644
--- a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
+++ b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc
@@ -37,9 +37,7 @@
     array_interleaved_ = new int16_t[num_channels_ * array_length()];
   }
 
-  ~AudioMultiVectorTest() {
-    delete [] array_interleaved_;
-  }
+  ~AudioMultiVectorTest() { delete[] array_interleaved_; }
 
   virtual void SetUp() {
     // Populate test arrays.
@@ -58,9 +56,7 @@
     }
   }
 
-  size_t array_length() const {
-    return sizeof(array_) / sizeof(array_[0]);
-  }
+  size_t array_length() const { return sizeof(array_) / sizeof(array_[0]); }
 
   const size_t num_channels_;
   size_t interleaved_length_;
@@ -168,8 +164,9 @@
   ASSERT_EQ(2u, vec2.Size());
   for (size_t channel = 0; channel < num_channels_; ++channel) {
     for (size_t i = 0; i < 2; ++i) {
-      EXPECT_EQ(array_interleaved_[channel + num_channels_ *
-                  (array_length() - 2 + i)], vec2[channel][i]);
+      EXPECT_EQ(array_interleaved_[channel +
+                                   num_channels_ * (array_length() - 2 + i)],
+                vec2[channel][i]);
     }
   }
 }
@@ -206,7 +203,7 @@
   EXPECT_EQ(0,
             memcmp(array_interleaved_, output, read_samples * sizeof(int16_t)));
 
-  delete [] output;
+  delete[] output;
 }
 
 // Test the PopFront method.
diff --git a/modules/audio_coding/neteq/audio_vector.cc b/modules/audio_coding/neteq/audio_vector.cc
index 93cd1fb..0486416 100644
--- a/modules/audio_coding/neteq/audio_vector.cc
+++ b/modules/audio_coding/neteq/audio_vector.cc
@@ -20,8 +20,7 @@
 
 namespace webrtc {
 
-AudioVector::AudioVector()
-    : AudioVector(kDefaultInitialSize) {
+AudioVector::AudioVector() : AudioVector(kDefaultInitialSize) {
   Clear();
 }
 
@@ -47,16 +46,15 @@
   copy_to->end_index_ = Size();
 }
 
-void AudioVector::CopyTo(
-    size_t length, size_t position, int16_t* copy_to) const {
+void AudioVector::CopyTo(size_t length,
+                         size_t position,
+                         int16_t* copy_to) const {
   if (length == 0)
     return;
   length = std::min(length, Size() - position);
   const size_t copy_index = (begin_index_ + position) % capacity_;
-  const size_t first_chunk_length =
-      std::min(length, capacity_ - copy_index);
-  memcpy(copy_to, &array_[copy_index],
-         first_chunk_length * sizeof(int16_t));
+  const size_t first_chunk_length = std::min(length, capacity_ - copy_index);
+  memcpy(copy_to, &array_[copy_index], first_chunk_length * sizeof(int16_t));
   const size_t remaining_length = length - first_chunk_length;
   if (remaining_length > 0) {
     memcpy(&copy_to[first_chunk_length], array_.get(),
@@ -102,8 +100,9 @@
   PushBack(append_this, append_this.Size(), 0);
 }
 
-void AudioVector::PushBack(
-    const AudioVector& append_this, size_t length, size_t position) {
+void AudioVector::PushBack(const AudioVector& append_this,
+                           size_t length,
+                           size_t position) {
   RTC_DCHECK_LE(position, append_this.Size());
   RTC_DCHECK_LE(length, append_this.Size() - position);
 
@@ -116,8 +115,8 @@
 
   const size_t start_index =
       (append_this.begin_index_ + position) % append_this.capacity_;
-  const size_t first_chunk_length = std::min(
-      length, append_this.capacity_ - start_index);
+  const size_t first_chunk_length =
+      std::min(length, append_this.capacity_ - start_index);
   PushBack(&append_this.array_[start_index], first_chunk_length);
 
   const size_t remaining_length = length - first_chunk_length;
@@ -179,8 +178,7 @@
   }
 }
 
-void AudioVector::InsertZerosAt(size_t length,
-                                size_t position) {
+void AudioVector::InsertZerosAt(size_t length, size_t position) {
   if (length == 0)
     return;
   // Cap the insert position at the current array length.
@@ -265,7 +263,8 @@
     alpha -= alpha_step;
     array_[(position + i) % capacity_] =
         (alpha * array_[(position + i) % capacity_] +
-            (16384 - alpha) * append_this[i] + 8192) >> 14;
+         (16384 - alpha) * append_this[i] + 8192) >>
+        14;
   }
   assert(alpha >= 0);  // Verify that the slope was correct.
   // Append what is left of |append_this|.
@@ -319,8 +318,8 @@
 }
 
 void AudioVector::InsertByPushFront(const int16_t* insert_this,
-                                   size_t length,
-                                   size_t position) {
+                                    size_t length,
+                                    size_t position) {
   std::unique_ptr<int16_t[]> temp_array(nullptr);
   if (position > 0) {
     // TODO(minyue): see if it is possible to avoid copying to a buffer.
@@ -335,8 +334,7 @@
     PushFront(temp_array.get(), position);
 }
 
-void AudioVector::InsertZerosByPushBack(size_t length,
-                                        size_t position) {
+void AudioVector::InsertZerosByPushBack(size_t length, size_t position) {
   const size_t move_chunk_length = Size() - position;
   std::unique_ptr<int16_t[]> temp_array(nullptr);
   if (move_chunk_length > 0) {
@@ -359,8 +357,7 @@
     PushBack(temp_array.get(), move_chunk_length);
 }
 
-void AudioVector::InsertZerosByPushFront(size_t length,
-                                         size_t position) {
+void AudioVector::InsertZerosByPushFront(size_t length, size_t position) {
   std::unique_ptr<int16_t[]> temp_array(nullptr);
   if (position > 0) {
     temp_array.reset(new int16_t[position]);
diff --git a/modules/audio_coding/neteq/audio_vector.h b/modules/audio_coding/neteq/audio_vector.h
index 754a9fd..65939ce 100644
--- a/modules/audio_coding/neteq/audio_vector.h
+++ b/modules/audio_coding/neteq/audio_vector.h
@@ -75,7 +75,8 @@
   // them at |position|. The length of the AudioVector is increased by |length|.
   // |position| = 0 means that the new values are prepended to the vector.
   // |position| = Size() means that the new values are appended to the vector.
-  virtual void InsertAt(const int16_t* insert_this, size_t length,
+  virtual void InsertAt(const int16_t* insert_this,
+                        size_t length,
                         size_t position);
 
   // Like InsertAt, but inserts |length| zero elements at |position|.
@@ -140,10 +141,12 @@
 
   void Reserve(size_t n);
 
-  void InsertByPushBack(const int16_t* insert_this, size_t length,
+  void InsertByPushBack(const int16_t* insert_this,
+                        size_t length,
                         size_t position);
 
-  void InsertByPushFront(const int16_t* insert_this, size_t length,
+  void InsertByPushFront(const int16_t* insert_this,
+                         size_t length,
                          size_t position);
 
   void InsertZerosByPushBack(size_t length, size_t position);
diff --git a/modules/audio_coding/neteq/audio_vector_unittest.cc b/modules/audio_coding/neteq/audio_vector_unittest.cc
index 1b54abc..e70178c 100644
--- a/modules/audio_coding/neteq/audio_vector_unittest.cc
+++ b/modules/audio_coding/neteq/audio_vector_unittest.cc
@@ -30,9 +30,7 @@
     }
   }
 
-  size_t array_length() const {
-    return sizeof(array_) / sizeof(array_[0]);
-  }
+  size_t array_length() const { return sizeof(array_) / sizeof(array_[0]); }
 
   int16_t array_[10];
 };
@@ -283,8 +281,8 @@
   for (int i = 0; i < kNewLength; ++i) {
     new_array[i] = 100 + i;
   }
-  int insert_position = rtc::checked_cast<int>(
-      array_length() + 10); // Too large.
+  int insert_position =
+      rtc::checked_cast<int>(array_length() + 10);  // Too large.
   vec.InsertAt(new_array, kNewLength, insert_position);
   // Verify that the vector looks as follows:
   // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }.
@@ -375,7 +373,7 @@
     EXPECT_EQ(0, vec1[i]);
   }
   // Check mixing zone.
-  for (size_t i = 0 ; i < kFadeLength; ++i) {
+  for (size_t i = 0; i < kFadeLength; ++i) {
     EXPECT_NEAR((i + 1) * 100 / (kFadeLength + 1),
                 vec1[kLength - kFadeLength + i], 1);
   }
diff --git a/modules/audio_coding/neteq/background_noise.cc b/modules/audio_coding/neteq/background_noise.cc
index 50ffa86..08c278e 100644
--- a/modules/audio_coding/neteq/background_noise.cc
+++ b/modules/audio_coding/neteq/background_noise.cc
@@ -58,11 +58,11 @@
     int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
     int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
     input[channel_ix].CopyTo(kVecLen, input.Size() - kVecLen, temp_signal);
-    int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen,
-                                                     auto_correlation);
+    int32_t sample_energy =
+        CalculateAutoCorrelation(temp_signal, kVecLen, auto_correlation);
 
     if ((!vad.running() &&
-        sample_energy < parameters.energy_update_threshold) ||
+         sample_energy < parameters.energy_update_threshold) ||
         (vad.running() && !vad.active_speech())) {
       // Generate LPC coefficients.
       if (auto_correlation[0] > 0) {
@@ -91,10 +91,8 @@
       WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
                                 fiter_output, lpc_coefficients,
                                 kMaxLpcOrder + 1, kResidualLength);
-      int32_t residual_energy = WebRtcSpl_DotProductWithScale(fiter_output,
-                                                              fiter_output,
-                                                              kResidualLength,
-                                                              0);
+      int32_t residual_energy = WebRtcSpl_DotProductWithScale(
+          fiter_output, fiter_output, kResidualLength, 0);
 
       // Check spectral flatness.
       // Comparing the residual variance with the input signal variance tells
@@ -146,7 +144,8 @@
   return channel_parameters_[channel].filter_state;
 }
 
-void BackgroundNoise::SetFilterState(size_t channel, const int16_t* input,
+void BackgroundNoise::SetFilterState(size_t channel,
+                                     const int16_t* input,
                                      size_t length) {
   assert(channel < num_channels_);
   length = std::min(length, kMaxLpcOrder);
@@ -164,7 +163,9 @@
 }
 
 int32_t BackgroundNoise::CalculateAutoCorrelation(
-    const int16_t* signal, size_t length, int32_t* auto_correlation) const {
+    const int16_t* signal,
+    size_t length,
+    int32_t* auto_correlation) const {
   static const int kCorrelationStep = -1;
   const int correlation_scale =
       CrossCorrelationWithAutoShift(signal, signal, length, kMaxLpcOrder + 1,
@@ -185,15 +186,16 @@
   assert(channel < num_channels_);
   ChannelParameters& parameters = channel_parameters_[channel];
   int32_t temp_energy =
-    (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
-  temp_energy += kThresholdIncrement *
-      (parameters.energy_update_threshold & 0xFF);
-  temp_energy += (kThresholdIncrement *
-      ((parameters.energy_update_threshold>>8) & 0xFF)) << 8;
+      (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
+  temp_energy +=
+      kThresholdIncrement * (parameters.energy_update_threshold & 0xFF);
+  temp_energy +=
+      (kThresholdIncrement * ((parameters.energy_update_threshold >> 8) & 0xFF))
+      << 8;
   parameters.low_energy_update_threshold += temp_energy;
 
-  parameters.energy_update_threshold += kThresholdIncrement *
-      (parameters.energy_update_threshold>>16);
+  parameters.energy_update_threshold +=
+      kThresholdIncrement * (parameters.energy_update_threshold >> 16);
   parameters.energy_update_threshold +=
       parameters.low_energy_update_threshold >> 16;
   parameters.low_energy_update_threshold =
@@ -201,8 +203,7 @@
 
   // Update maximum energy.
   // Decrease by a factor 1/1024 each time.
-  parameters.max_energy = parameters.max_energy -
-      (parameters.max_energy >> 10);
+  parameters.max_energy = parameters.max_energy - (parameters.max_energy >> 10);
   if (sample_energy > parameters.max_energy) {
     parameters.max_energy = sample_energy;
   }
@@ -223,9 +224,8 @@
   assert(channel < num_channels_);
   ChannelParameters& parameters = channel_parameters_[channel];
   memcpy(parameters.filter, lpc_coefficients,
-         (kMaxLpcOrder+1) * sizeof(int16_t));
-  memcpy(parameters.filter_state, filter_state,
-         kMaxLpcOrder * sizeof(int16_t));
+         (kMaxLpcOrder + 1) * sizeof(int16_t));
+  memcpy(parameters.filter_state, filter_state, kMaxLpcOrder * sizeof(int16_t));
   // Save energy level and update energy threshold levels.
   // Never get under 1.0 in average sample energy.
   parameters.energy = std::max(sample_energy, 1);
diff --git a/modules/audio_coding/neteq/background_noise.h b/modules/audio_coding/neteq/background_noise.h
index a6f1395..26d42b5 100644
--- a/modules/audio_coding/neteq/background_noise.h
+++ b/modules/audio_coding/neteq/background_noise.h
@@ -38,8 +38,7 @@
 
   // Updates the parameter estimates based on the signal currently in the
   // |sync_buffer|, and on the latest decision in |vad| if it is running.
-  void Update(const AudioMultiVector& sync_buffer,
-              const PostDecodeVad& vad);
+  void Update(const AudioMultiVector& sync_buffer, const PostDecodeVad& vad);
 
   // Returns |energy_| for |channel|.
   int32_t Energy(size_t channel) const;
@@ -78,9 +77,7 @@
 
   struct ChannelParameters {
     // Constructor.
-    ChannelParameters() {
-      Reset();
-    }
+    ChannelParameters() { Reset(); }
 
     void Reset() {
       energy = 2500;
diff --git a/modules/audio_coding/neteq/buffer_level_filter.cc b/modules/audio_coding/neteq/buffer_level_filter.cc
index 6005de6..4d015b6 100644
--- a/modules/audio_coding/neteq/buffer_level_filter.cc
+++ b/modules/audio_coding/neteq/buffer_level_filter.cc
@@ -31,7 +31,8 @@
   //                            (1 - |level_factor_|) * |buffer_size_packets|
   // |level_factor_| and |filtered_current_level_| are in Q8.
   // |buffer_size_packets| is in Q0.
-  filtered_current_level_ = ((level_factor_ * filtered_current_level_) >> 8) +
+  filtered_current_level_ =
+      ((level_factor_ * filtered_current_level_) >> 8) +
       ((256 - level_factor_) * static_cast<int>(buffer_size_packets));
 
   // Account for time-scale operations (accelerate and pre-emptive expand).
diff --git a/modules/audio_coding/neteq/buffer_level_filter.h b/modules/audio_coding/neteq/buffer_level_filter.h
index 7a48c72..c8d27dc 100644
--- a/modules/audio_coding/neteq/buffer_level_filter.h
+++ b/modules/audio_coding/neteq/buffer_level_filter.h
@@ -28,7 +28,8 @@
   // corresponding number of packets, and is subtracted from the filtered
   // value (thus bypassing the filter operation). |packet_len_samples| is the
   // number of audio samples carried in each incoming packet.
-  virtual void Update(size_t buffer_size_packets, int time_stretched_samples,
+  virtual void Update(size_t buffer_size_packets,
+                      int time_stretched_samples,
                       size_t packet_len_samples);
 
   // Set the current target buffer level (obtained from
diff --git a/modules/audio_coding/neteq/buffer_level_filter_unittest.cc b/modules/audio_coding/neteq/buffer_level_filter_unittest.cc
index 72c8727..b6dcd2a 100644
--- a/modules/audio_coding/neteq/buffer_level_filter_unittest.cc
+++ b/modules/audio_coding/neteq/buffer_level_filter_unittest.cc
@@ -39,8 +39,7 @@
       }
       // Expect the filtered value to be (theoretically)
       // (1 - (251/256) ^ |times|) * |value|.
-      double expected_value_double =
-          (1 - pow(251.0 / 256.0, times)) * value;
+      double expected_value_double = (1 - pow(251.0 / 256.0, times)) * value;
       int expected_value = static_cast<int>(expected_value_double);
       // filtered_current_level() returns the value in Q8.
       // The actual value may differ slightly from the expected value due to
@@ -94,7 +93,6 @@
   EXPECT_EQ(expected_value, filter.filtered_current_level() >> 8);
 }
 
-
 TEST(BufferLevelFilter, TimeStretchedSamples) {
   BufferLevelFilter filter;
   filter.SetTargetBufferLevel(1);  // Makes filter coefficient 251/256.
diff --git a/modules/audio_coding/neteq/comfort_noise.cc b/modules/audio_coding/neteq/comfort_noise.cc
index 5e0a875..b341acd 100644
--- a/modules/audio_coding/neteq/comfort_noise.cc
+++ b/modules/audio_coding/neteq/comfort_noise.cc
@@ -35,10 +35,9 @@
   return kOK;
 }
 
-int ComfortNoise::Generate(size_t requested_length,
-                           AudioMultiVector* output) {
+int ComfortNoise::Generate(size_t requested_length, AudioMultiVector* output) {
   // TODO(hlundin): Change to an enumerator and skip assert.
-  assert(fs_hz_ == 8000 || fs_hz_ == 16000 || fs_hz_ ==  32000 ||
+  assert(fs_hz_ == 8000 || fs_hz_ == 16000 || fs_hz_ == 32000 ||
          fs_hz_ == 48000);
   // Not adapted for multi-channel yet.
   if (output->Channels() != 1) {
@@ -63,8 +62,7 @@
 
   std::unique_ptr<int16_t[]> temp(new int16_t[number_of_samples]);
   if (!cng_decoder->Generate(
-          rtc::ArrayView<int16_t>(temp.get(), number_of_samples),
-          new_period)) {
+          rtc::ArrayView<int16_t>(temp.get(), number_of_samples), new_period)) {
     // Error returned.
     output->Zeros(requested_length);
     RTC_LOG(LS_ERROR)
@@ -75,9 +73,9 @@
 
   if (first_call_) {
     // Set tapering window parameters. Values are in Q15.
-    int16_t muting_window;  // Mixing factor for overlap data.
-    int16_t muting_window_increment;  // Mixing factor increment (negative).
-    int16_t unmuting_window;  // Mixing factor for comfort noise.
+    int16_t muting_window;              // Mixing factor for overlap data.
+    int16_t muting_window_increment;    // Mixing factor increment (negative).
+    int16_t unmuting_window;            // Mixing factor for comfort noise.
     int16_t unmuting_window_increment;  // Mixing factor increment.
     if (fs_hz_ == 8000) {
       muting_window = DspHelper::kMuteFactorStart8kHz;
@@ -109,7 +107,8 @@
       // channel.
       (*sync_buffer_)[0][start_ix + i] =
           (((*sync_buffer_)[0][start_ix + i] * muting_window) +
-              ((*output)[0][i] * unmuting_window) + 16384) >> 15;
+           ((*output)[0][i] * unmuting_window) + 16384) >>
+          15;
       muting_window += muting_window_increment;
       unmuting_window += unmuting_window_increment;
     }
diff --git a/modules/audio_coding/neteq/comfort_noise.h b/modules/audio_coding/neteq/comfort_noise.h
index 18800ad..c8cc64a 100644
--- a/modules/audio_coding/neteq/comfort_noise.h
+++ b/modules/audio_coding/neteq/comfort_noise.h
@@ -32,14 +32,14 @@
     kMultiChannelNotSupported
   };
 
-  ComfortNoise(int fs_hz, DecoderDatabase* decoder_database,
+  ComfortNoise(int fs_hz,
+               DecoderDatabase* decoder_database,
                SyncBuffer* sync_buffer)
       : fs_hz_(fs_hz),
         first_call_(true),
         overlap_length_(5 * fs_hz_ / 8000),
         decoder_database_(decoder_database),
-        sync_buffer_(sync_buffer) {
-  }
+        sync_buffer_(sync_buffer) {}
 
   // Resets the state. Should be called before each new comfort noise period.
   void Reset();
diff --git a/modules/audio_coding/neteq/cross_correlation.cc b/modules/audio_coding/neteq/cross_correlation.cc
index da9c913..2a03d4a 100644
--- a/modules/audio_coding/neteq/cross_correlation.cc
+++ b/modules/audio_coding/neteq/cross_correlation.cc
@@ -48,8 +48,9 @@
   // There are some corner cases that 2) is not satisfied, e.g.,
   // max_1 = 17, max_2 = 30848, sequence_1_length = 4095, in such case,
   // optimal scaling is 0, while the following calculation results in 1.
-  const int32_t factor = (max_1 * max_2) / (std::numeric_limits<int32_t>::max()
-      / static_cast<int32_t>(sequence_1_length));
+  const int32_t factor =
+      (max_1 * max_2) / (std::numeric_limits<int32_t>::max() /
+                         static_cast<int32_t>(sequence_1_length));
   const int scaling = factor == 0 ? 0 : 31 - WebRtcSpl_NormW32(factor);
 
   WebRtcSpl_CrossCorrelation(cross_correlation, sequence_1, sequence_2,
diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc
index 6ab2716..e24ca62 100644
--- a/modules/audio_coding/neteq/decision_logic.cc
+++ b/modules/audio_coding/neteq/decision_logic.cc
@@ -10,47 +10,37 @@
 
 #include "modules/audio_coding/neteq/decision_logic.h"
 
+#include <assert.h>
 #include <algorithm>
+#include <limits>
 
 #include "modules/audio_coding/neteq/buffer_level_filter.h"
-#include "modules/audio_coding/neteq/decision_logic_fax.h"
-#include "modules/audio_coding/neteq/decision_logic_normal.h"
+#include "modules/audio_coding/neteq/decoder_database.h"
 #include "modules/audio_coding/neteq/delay_manager.h"
 #include "modules/audio_coding/neteq/expand.h"
 #include "modules/audio_coding/neteq/packet_buffer.h"
 #include "modules/audio_coding/neteq/sync_buffer.h"
 #include "modules/include/module_common_types.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
 DecisionLogic* DecisionLogic::Create(int fs_hz,
                                      size_t output_size_samples,
-                                     NetEqPlayoutMode playout_mode,
+                                     bool disallow_time_stretching,
                                      DecoderDatabase* decoder_database,
                                      const PacketBuffer& packet_buffer,
                                      DelayManager* delay_manager,
                                      BufferLevelFilter* buffer_level_filter,
                                      const TickTimer* tick_timer) {
-  switch (playout_mode) {
-    case kPlayoutOn:
-    case kPlayoutStreaming:
-      return new DecisionLogicNormal(
-          fs_hz, output_size_samples, playout_mode, decoder_database,
-          packet_buffer, delay_manager, buffer_level_filter, tick_timer);
-    case kPlayoutFax:
-    case kPlayoutOff:
-      return new DecisionLogicFax(
-          fs_hz, output_size_samples, playout_mode, decoder_database,
-          packet_buffer, delay_manager, buffer_level_filter, tick_timer);
-  }
-  // This line cannot be reached, but must be here to avoid compiler errors.
-  assert(false);
-  return NULL;
+  return new DecisionLogic(fs_hz, output_size_samples, disallow_time_stretching,
+                           decoder_database, packet_buffer, delay_manager,
+                           buffer_level_filter, tick_timer);
 }
 
 DecisionLogic::DecisionLogic(int fs_hz,
                              size_t output_size_samples,
-                             NetEqPlayoutMode playout_mode,
+                             bool disallow_time_stretching,
                              DecoderDatabase* decoder_database,
                              const PacketBuffer& packet_buffer,
                              DelayManager* delay_manager,
@@ -65,11 +55,13 @@
       packet_length_samples_(0),
       sample_memory_(0),
       prev_time_scale_(false),
+      disallow_time_stretching_(disallow_time_stretching),
       timescale_countdown_(
           tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)),
       num_consecutive_expands_(0),
-      playout_mode_(playout_mode) {
-  delay_manager_->set_streaming_mode(playout_mode_ == kPlayoutStreaming);
+      postpone_decoding_after_expand_(field_trial::IsEnabled(
+          "WebRTC-Audio-NetEqPostponeDecodingAfterExpand")) {
+  delay_manager_->set_streaming_mode(false);
   SetSampleRate(fs_hz, output_size_samples);
 }
 
@@ -95,7 +87,7 @@
 
 void DecisionLogic::SetSampleRate(int fs_hz, size_t output_size_samples) {
   // TODO(hlundin): Change to an enumerator and skip assert.
-  assert(fs_hz == 8000 || fs_hz == 16000 || fs_hz ==  32000 || fs_hz == 48000);
+  assert(fs_hz == 8000 || fs_hz == 16000 || fs_hz == 32000 || fs_hz == 48000);
   fs_mult_ = fs_hz / 8000;
   output_size_samples_ = output_size_samples;
 }
@@ -122,17 +114,79 @@
   const size_t cur_size_samples =
       samples_left + packet_buffer_.NumSamplesInBuffer(decoder_frame_length);
 
-  prev_time_scale_ = prev_time_scale_ &&
-      (prev_mode == kModeAccelerateSuccess ||
-          prev_mode == kModeAccelerateLowEnergy ||
-          prev_mode == kModePreemptiveExpandSuccess ||
-          prev_mode == kModePreemptiveExpandLowEnergy);
+  prev_time_scale_ =
+      prev_time_scale_ && (prev_mode == kModeAccelerateSuccess ||
+                           prev_mode == kModeAccelerateLowEnergy ||
+                           prev_mode == kModePreemptiveExpandSuccess ||
+                           prev_mode == kModePreemptiveExpandLowEnergy);
 
   FilterBufferLevel(cur_size_samples, prev_mode);
 
-  return GetDecisionSpecialized(sync_buffer, expand, decoder_frame_length,
-                                next_packet, prev_mode, play_dtmf,
-                                reset_decoder, generated_noise_samples);
+  // Guard for errors, to avoid getting stuck in error mode.
+  if (prev_mode == kModeError) {
+    if (!next_packet) {
+      return kExpand;
+    } else {
+      return kUndefined;  // Use kUndefined to flag for a reset.
+    }
+  }
+
+  uint32_t target_timestamp = sync_buffer.end_timestamp();
+  uint32_t available_timestamp = 0;
+  bool is_cng_packet = false;
+  if (next_packet) {
+    available_timestamp = next_packet->timestamp;
+    is_cng_packet =
+        decoder_database_->IsComfortNoise(next_packet->payload_type);
+  }
+
+  if (is_cng_packet) {
+    return CngOperation(prev_mode, target_timestamp, available_timestamp,
+                        generated_noise_samples);
+  }
+
+  // Handle the case with no packet at all available (except maybe DTMF).
+  if (!next_packet) {
+    return NoPacket(play_dtmf);
+  }
+
+  // If the expand period was very long, reset NetEQ since it is likely that the
+  // sender was restarted.
+  if (num_consecutive_expands_ > kReinitAfterExpands) {
+    *reset_decoder = true;
+    return kNormal;
+  }
+
+  // Make sure we don't restart audio too soon after an expansion to avoid
+  // running out of data right away again. We should only wait if there are no
+  // DTX or CNG packets in the buffer (otherwise we should just play out what we
+  // have, since we cannot know the exact duration of DTX or CNG packets), and
+  // if the mute factor is low enough (otherwise the expansion was short enough
+  // to not be noticable).
+  // Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1.
+  if (postpone_decoding_after_expand_ && prev_mode == kModeExpand &&
+      !packet_buffer_.ContainsDtxOrCngPacket(decoder_database_) &&
+      cur_size_samples<static_cast<size_t>(delay_manager_->TargetLevel() *
+                                           packet_length_samples_)>> 8 &&
+      expand.MuteFactor(0) < 16384 / 2) {
+    return kExpand;
+  }
+
+  const uint32_t five_seconds_samples =
+      static_cast<uint32_t>(5 * 8000 * fs_mult_);
+  // Check if the required packet is available.
+  if (target_timestamp == available_timestamp) {
+    return ExpectedPacketAvailable(prev_mode, play_dtmf);
+  } else if (!PacketBuffer::IsObsoleteTimestamp(
+                 available_timestamp, target_timestamp, five_seconds_samples)) {
+    return FuturePacketAvailable(
+        sync_buffer, expand, decoder_frame_length, prev_mode, target_timestamp,
+        available_timestamp, play_dtmf, generated_noise_samples);
+  } else {
+    // This implies that available_timestamp < target_timestamp, which can
+    // happen when a new stream or codec is received. Signal for a reset.
+    return kUndefined;
+  }
 }
 
 void DecisionLogic::ExpandDecision(Operations operation) {
@@ -168,4 +222,152 @@
   }
 }
 
+Operations DecisionLogic::CngOperation(Modes prev_mode,
+                                       uint32_t target_timestamp,
+                                       uint32_t available_timestamp,
+                                       size_t generated_noise_samples) {
+  // Signed difference between target and available timestamp.
+  int32_t timestamp_diff = static_cast<int32_t>(
+      static_cast<uint32_t>(generated_noise_samples + target_timestamp) -
+      available_timestamp);
+  int32_t optimal_level_samp = static_cast<int32_t>(
+      (delay_manager_->TargetLevel() * packet_length_samples_) >> 8);
+  const int64_t excess_waiting_time_samp =
+      -static_cast<int64_t>(timestamp_diff) - optimal_level_samp;
+
+  if (excess_waiting_time_samp > optimal_level_samp / 2) {
+    // The waiting time for this packet will be longer than 1.5
+    // times the wanted buffer delay. Apply fast-forward to cut the
+    // waiting time down to the optimal.
+    noise_fast_forward_ = rtc::dchecked_cast<size_t>(noise_fast_forward_ +
+                                                     excess_waiting_time_samp);
+    timestamp_diff =
+        rtc::saturated_cast<int32_t>(timestamp_diff + excess_waiting_time_samp);
+  }
+
+  if (timestamp_diff < 0 && prev_mode == kModeRfc3389Cng) {
+    // Not time to play this packet yet. Wait another round before using this
+    // packet. Keep on playing CNG from previous CNG parameters.
+    return kRfc3389CngNoPacket;
+  } else {
+    // Otherwise, go for the CNG packet now.
+    noise_fast_forward_ = 0;
+    return kRfc3389Cng;
+  }
+}
+
+Operations DecisionLogic::NoPacket(bool play_dtmf) {
+  if (cng_state_ == kCngRfc3389On) {
+    // Keep on playing comfort noise.
+    return kRfc3389CngNoPacket;
+  } else if (cng_state_ == kCngInternalOn) {
+    // Keep on playing codec internal comfort noise.
+    return kCodecInternalCng;
+  } else if (play_dtmf) {
+    return kDtmf;
+  } else {
+    // Nothing to play, do expand.
+    return kExpand;
+  }
+}
+
+Operations DecisionLogic::ExpectedPacketAvailable(Modes prev_mode,
+                                                  bool play_dtmf) {
+  if (!disallow_time_stretching_ && prev_mode != kModeExpand && !play_dtmf) {
+    // Check criterion for time-stretching.
+    int low_limit, high_limit;
+    delay_manager_->BufferLimits(&low_limit, &high_limit);
+    if (buffer_level_filter_->filtered_current_level() >= high_limit << 2)
+      return kFastAccelerate;
+    if (TimescaleAllowed()) {
+      if (buffer_level_filter_->filtered_current_level() >= high_limit)
+        return kAccelerate;
+      if (buffer_level_filter_->filtered_current_level() < low_limit)
+        return kPreemptiveExpand;
+    }
+  }
+  return kNormal;
+}
+
+Operations DecisionLogic::FuturePacketAvailable(
+    const SyncBuffer& sync_buffer,
+    const Expand& expand,
+    size_t decoder_frame_length,
+    Modes prev_mode,
+    uint32_t target_timestamp,
+    uint32_t available_timestamp,
+    bool play_dtmf,
+    size_t generated_noise_samples) {
+  // Required packet is not available, but a future packet is.
+  // Check if we should continue with an ongoing expand because the new packet
+  // is too far into the future.
+  uint32_t timestamp_leap = available_timestamp - target_timestamp;
+  if ((prev_mode == kModeExpand) && !ReinitAfterExpands(timestamp_leap) &&
+      !MaxWaitForPacket() && PacketTooEarly(timestamp_leap) &&
+      UnderTargetLevel()) {
+    if (play_dtmf) {
+      // Still have DTMF to play, so do not do expand.
+      return kDtmf;
+    } else {
+      // Nothing to play.
+      return kExpand;
+    }
+  }
+
+  const size_t samples_left =
+      sync_buffer.FutureLength() - expand.overlap_length();
+  const size_t cur_size_samples =
+      samples_left + packet_buffer_.NumPacketsInBuffer() * decoder_frame_length;
+
+  // If previous was comfort noise, then no merge is needed.
+  if (prev_mode == kModeRfc3389Cng || prev_mode == kModeCodecInternalCng) {
+    // Keep the same delay as before the CNG, but make sure that the number of
+    // samples in buffer is no higher than 4 times the optimal level. (Note that
+    // TargetLevel() is in Q8.)
+    if (static_cast<uint32_t>(generated_noise_samples + target_timestamp) >=
+            available_timestamp ||
+        cur_size_samples >
+            ((delay_manager_->TargetLevel() * packet_length_samples_) >> 8) *
+                4) {
+      // Time to play this new packet.
+      return kNormal;
+    } else {
+      // Too early to play this new packet; keep on playing comfort noise.
+      if (prev_mode == kModeRfc3389Cng) {
+        return kRfc3389CngNoPacket;
+      } else {  // prevPlayMode == kModeCodecInternalCng.
+        return kCodecInternalCng;
+      }
+    }
+  }
+  // Do not merge unless we have done an expand before.
+  if (prev_mode == kModeExpand) {
+    return kMerge;
+  } else if (play_dtmf) {
+    // Play DTMF instead of expand.
+    return kDtmf;
+  } else {
+    return kExpand;
+  }
+}
+
+bool DecisionLogic::UnderTargetLevel() const {
+  return buffer_level_filter_->filtered_current_level() <=
+         delay_manager_->TargetLevel();
+}
+
+bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const {
+  return timestamp_leap >=
+         static_cast<uint32_t>(output_size_samples_ * kReinitAfterExpands);
+}
+
+bool DecisionLogic::PacketTooEarly(uint32_t timestamp_leap) const {
+  return timestamp_leap >
+         static_cast<uint32_t>(output_size_samples_ * num_consecutive_expands_);
+}
+
+bool DecisionLogic::MaxWaitForPacket() const {
+  return num_consecutive_expands_ >= kMaxWaitForPacket;
+}
+
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h
index 5b67196..20ba8af 100644
--- a/modules/audio_coding/neteq/decision_logic.h
+++ b/modules/audio_coding/neteq/decision_logic.h
@@ -28,32 +28,34 @@
 class SyncBuffer;
 struct Packet;
 
-// This is the base class for the decision tree implementations. Derived classes
-// must implement the method GetDecisionSpecialized().
-class DecisionLogic {
+// This is the class for the decision tree implementation.
+class DecisionLogic final {
  public:
   // Static factory function which creates different types of objects depending
   // on the |playout_mode|.
   static DecisionLogic* Create(int fs_hz,
                                size_t output_size_samples,
-                               NetEqPlayoutMode playout_mode,
+                               bool disallow_time_stretching,
                                DecoderDatabase* decoder_database,
                                const PacketBuffer& packet_buffer,
                                DelayManager* delay_manager,
                                BufferLevelFilter* buffer_level_filter,
                                const TickTimer* tick_timer);
 
+  static const int kReinitAfterExpands = 100;
+  static const int kMaxWaitForPacket = 10;
+
   // Constructor.
   DecisionLogic(int fs_hz,
                 size_t output_size_samples,
-                NetEqPlayoutMode playout_mode,
+                bool disallow_time_stretching,
                 DecoderDatabase* decoder_database,
                 const PacketBuffer& packet_buffer,
                 DelayManager* delay_manager,
                 BufferLevelFilter* buffer_level_filter,
                 const TickTimer* tick_timer);
 
-  virtual ~DecisionLogic();
+  ~DecisionLogic();
 
   // Resets object to a clean state.
   void Reset();
@@ -94,12 +96,10 @@
   // not. Note that this is necessary, since an expand decision can be changed
   // to kNormal in NetEqImpl::GetDecision if there is still enough data in the
   // sync buffer.
-  virtual void ExpandDecision(Operations operation);
+  void ExpandDecision(Operations operation);
 
   // Adds |value| to |sample_memory_|.
-  void AddSampleMemory(int32_t value) {
-    sample_memory_ += value;
-  }
+  void AddSampleMemory(int32_t value) { sample_memory_ += value; }
 
   // Accessors and mutators.
   void set_sample_memory(int32_t value) { sample_memory_ = value; }
@@ -109,40 +109,63 @@
     packet_length_samples_ = value;
   }
   void set_prev_time_scale(bool value) { prev_time_scale_ = value; }
-  NetEqPlayoutMode playout_mode() const { return playout_mode_; }
 
- protected:
+ private:
   // The value 5 sets maximum time-stretch rate to about 100 ms/s.
   static const int kMinTimescaleInterval = 5;
 
-  enum CngState {
-    kCngOff,
-    kCngRfc3389On,
-    kCngInternalOn
-  };
-
-  // Returns the operation that should be done next. |sync_buffer| and |expand|
-  // are provided for reference. |decoder_frame_length| is the number of samples
-  // obtained from the last decoded frame. If there is a packet available, it
-  // should be supplied in |next_packet|; otherwise it should be NULL. The mode
-  // resulting from the last call to NetEqImpl::GetAudio is supplied in
-  // |prev_mode|. If there is a DTMF event to play, |play_dtmf| should be set to
-  // true. The output variable |reset_decoder| will be set to true if a reset is
-  // required; otherwise it is left unchanged (i.e., it can remain true if it
-  // was true before the call).  Should be implemented by derived classes.
-  virtual Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
-                                            const Expand& expand,
-                                            size_t decoder_frame_length,
-                                            const Packet* next_packet,
-                                            Modes prev_mode,
-                                            bool play_dtmf,
-                                            bool* reset_decoder,
-                                            size_t generated_noise_samples) = 0;
+  enum CngState { kCngOff, kCngRfc3389On, kCngInternalOn };
 
   // Updates the |buffer_level_filter_| with the current buffer level
   // |buffer_size_packets|.
   void FilterBufferLevel(size_t buffer_size_packets, Modes prev_mode);
 
+  // Returns the operation given that the next available packet is a comfort
+  // noise payload (RFC 3389 only, not codec-internal).
+  Operations CngOperation(Modes prev_mode,
+                          uint32_t target_timestamp,
+                          uint32_t available_timestamp,
+                          size_t generated_noise_samples);
+
+  // Returns the operation given that no packets are available (except maybe
+  // a DTMF event, flagged by setting |play_dtmf| true).
+  Operations NoPacket(bool play_dtmf);
+
+  // Returns the operation to do given that the expected packet is available.
+  Operations ExpectedPacketAvailable(Modes prev_mode, bool play_dtmf);
+
+  // Returns the operation to do given that the expected packet is not
+  // available, but a packet further into the future is at hand.
+  Operations FuturePacketAvailable(const SyncBuffer& sync_buffer,
+                                   const Expand& expand,
+                                   size_t decoder_frame_length,
+                                   Modes prev_mode,
+                                   uint32_t target_timestamp,
+                                   uint32_t available_timestamp,
+                                   bool play_dtmf,
+                                   size_t generated_noise_samples);
+
+  // Checks if enough time has elapsed since the last successful timescale
+  // operation was done (i.e., accelerate or preemptive expand).
+  bool TimescaleAllowed() const {
+    return !timescale_countdown_ || timescale_countdown_->Finished();
+  }
+
+  // Checks if the current (filtered) buffer level is under the target level.
+  bool UnderTargetLevel() const;
+
+  // Checks if |timestamp_leap| is so long into the future that a reset due
+  // to exceeding kReinitAfterExpands will be done.
+  bool ReinitAfterExpands(uint32_t timestamp_leap) const;
+
+  // Checks if we still have not done enough expands to cover the distance from
+  // the last decoded packet to the next available packet, the distance beeing
+  // conveyed in |timestamp_leap|.
+  bool PacketTooEarly(uint32_t timestamp_leap) const;
+
+  // Checks if num_consecutive_expands_ >= kMaxWaitForPacket.
+  bool MaxWaitForPacket() const;
+
   DecoderDatabase* decoder_database_;
   const PacketBuffer& packet_buffer_;
   DelayManager* delay_manager_;
@@ -156,11 +179,11 @@
   size_t packet_length_samples_;
   int sample_memory_;
   bool prev_time_scale_;
+  bool disallow_time_stretching_;
   std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
   int num_consecutive_expands_;
-  const NetEqPlayoutMode playout_mode_;
+  const bool postpone_decoding_after_expand_;
 
- private:
   RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogic);
 };
 
diff --git a/modules/audio_coding/neteq/decision_logic_fax.cc b/modules/audio_coding/neteq/decision_logic_fax.cc
deleted file mode 100644
index cc21ee9..0000000
--- a/modules/audio_coding/neteq/decision_logic_fax.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *  Copyright (c) 2013 The WebRTC 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.
- */
-
-#include "modules/audio_coding/neteq/decision_logic_fax.h"
-
-#include <assert.h>
-
-#include <algorithm>
-
-#include "modules/audio_coding/neteq/decoder_database.h"
-#include "modules/audio_coding/neteq/sync_buffer.h"
-
-namespace webrtc {
-
-Operations DecisionLogicFax::GetDecisionSpecialized(
-    const SyncBuffer& sync_buffer,
-    const Expand& expand,
-    size_t decoder_frame_length,
-    const Packet* next_packet,
-    Modes prev_mode,
-    bool play_dtmf,
-    bool* reset_decoder,
-    size_t generated_noise_samples) {
-  assert(playout_mode_ == kPlayoutFax || playout_mode_ == kPlayoutOff);
-  uint32_t target_timestamp = sync_buffer.end_timestamp();
-  uint32_t available_timestamp = 0;
-  int is_cng_packet = 0;
-  if (next_packet) {
-    available_timestamp = next_packet->timestamp;
-    is_cng_packet =
-        decoder_database_->IsComfortNoise(next_packet->payload_type);
-  }
-  if (is_cng_packet) {
-    if (static_cast<int32_t>((generated_noise_samples + target_timestamp)
-        - available_timestamp) >= 0) {
-      // Time to play this packet now.
-      return kRfc3389Cng;
-    } else {
-      // Wait before playing this packet.
-      return kRfc3389CngNoPacket;
-    }
-  }
-  if (!next_packet) {
-    // No packet. If in CNG mode, play as usual. Otherwise, use other method to
-    // generate data.
-    if (cng_state_ == kCngRfc3389On) {
-      // Continue playing comfort noise.
-      return kRfc3389CngNoPacket;
-    } else if (cng_state_ == kCngInternalOn) {
-      // Continue playing codec-internal comfort noise.
-      return kCodecInternalCng;
-    } else {
-      // Nothing to play. Generate some data to play out.
-      switch (playout_mode_) {
-        case kPlayoutOff:
-          return kAlternativePlc;
-        case kPlayoutFax:
-          return kAudioRepetition;
-        default:
-          assert(false);
-          return kUndefined;
-      }
-    }
-  } else if (target_timestamp == available_timestamp) {
-    return kNormal;
-  } else {
-    if (static_cast<int32_t>((generated_noise_samples + target_timestamp)
-        - available_timestamp) >= 0) {
-      return kNormal;
-    } else {
-      // If currently playing comfort noise, continue with that. Do not
-      // increase the timestamp counter since generated_noise_stopwatch_ in
-      // NetEqImpl will take care of the time-keeping.
-      if (cng_state_ == kCngRfc3389On) {
-        return kRfc3389CngNoPacket;
-      } else if (cng_state_ == kCngInternalOn) {
-        return kCodecInternalCng;
-      } else {
-        // Otherwise, do packet-loss concealment and increase the
-        // timestamp while waiting for the time to play this packet.
-        switch (playout_mode_) {
-          case kPlayoutOff:
-            return kAlternativePlcIncreaseTimestamp;
-          case kPlayoutFax:
-            return kAudioRepetitionIncreaseTimestamp;
-          default:
-            assert(0);
-            return kUndefined;
-        }
-      }
-    }
-  }
-}
-
-
-}  // namespace webrtc
diff --git a/modules/audio_coding/neteq/decision_logic_fax.h b/modules/audio_coding/neteq/decision_logic_fax.h
deleted file mode 100644
index cefd8e4..0000000
--- a/modules/audio_coding/neteq/decision_logic_fax.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  Copyright (c) 2013 The WebRTC 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 MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_FAX_H_
-#define MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_FAX_H_
-
-#include "modules/audio_coding/neteq/decision_logic.h"
-#include "rtc_base/constructormagic.h"
-#include "typedefs.h"  // NOLINT(build/include)
-
-namespace webrtc {
-
-// Implementation of the DecisionLogic class for playout modes kPlayoutFax and
-// kPlayoutOff.
-class DecisionLogicFax : public DecisionLogic {
- public:
-  // Constructor.
-  DecisionLogicFax(int fs_hz,
-                   size_t output_size_samples,
-                   NetEqPlayoutMode playout_mode,
-                   DecoderDatabase* decoder_database,
-                   const PacketBuffer& packet_buffer,
-                   DelayManager* delay_manager,
-                   BufferLevelFilter* buffer_level_filter,
-                   const TickTimer* tick_timer)
-      : DecisionLogic(fs_hz,
-                      output_size_samples,
-                      playout_mode,
-                      decoder_database,
-                      packet_buffer,
-                      delay_manager,
-                      buffer_level_filter,
-                      tick_timer) {}
-
- protected:
-  Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
-                                    const Expand& expand,
-                                    size_t decoder_frame_length,
-                                    const Packet* next_packet,
-                                    Modes prev_mode,
-                                    bool play_dtmf,
-                                    bool* reset_decoder,
-                                    size_t generated_noise_samples) override;
-
- private:
-  RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogicFax);
-};
-
-}  // namespace webrtc
-#endif  // MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_FAX_H_
diff --git a/modules/audio_coding/neteq/decision_logic_normal.cc b/modules/audio_coding/neteq/decision_logic_normal.cc
deleted file mode 100644
index 1429bb7..0000000
--- a/modules/audio_coding/neteq/decision_logic_normal.cc
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- *  Copyright (c) 2013 The WebRTC 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.
- */
-
-#include "modules/audio_coding/neteq/decision_logic_normal.h"
-
-#include <assert.h>
-
-#include <algorithm>
-
-#include "modules/audio_coding/neteq/buffer_level_filter.h"
-#include "modules/audio_coding/neteq/decoder_database.h"
-#include "modules/audio_coding/neteq/delay_manager.h"
-#include "modules/audio_coding/neteq/expand.h"
-#include "modules/audio_coding/neteq/packet_buffer.h"
-#include "modules/audio_coding/neteq/sync_buffer.h"
-
-namespace webrtc {
-
-Operations DecisionLogicNormal::GetDecisionSpecialized(
-    const SyncBuffer& sync_buffer,
-    const Expand& expand,
-    size_t decoder_frame_length,
-    const Packet* next_packet,
-    Modes prev_mode,
-    bool play_dtmf,
-    bool* reset_decoder,
-    size_t generated_noise_samples) {
-  assert(playout_mode_ == kPlayoutOn || playout_mode_ == kPlayoutStreaming);
-  // Guard for errors, to avoid getting stuck in error mode.
-  if (prev_mode == kModeError) {
-    if (!next_packet) {
-      return kExpand;
-    } else {
-      return kUndefined;  // Use kUndefined to flag for a reset.
-    }
-  }
-
-  uint32_t target_timestamp = sync_buffer.end_timestamp();
-  uint32_t available_timestamp = 0;
-  bool is_cng_packet = false;
-  if (next_packet) {
-    available_timestamp = next_packet->timestamp;
-    is_cng_packet =
-        decoder_database_->IsComfortNoise(next_packet->payload_type);
-  }
-
-  if (is_cng_packet) {
-    return CngOperation(prev_mode, target_timestamp, available_timestamp,
-                        generated_noise_samples);
-  }
-
-  // Handle the case with no packet at all available (except maybe DTMF).
-  if (!next_packet) {
-    return NoPacket(play_dtmf);
-  }
-
-  // If the expand period was very long, reset NetEQ since it is likely that the
-  // sender was restarted.
-  if (num_consecutive_expands_ > kReinitAfterExpands) {
-    *reset_decoder = true;
-    return kNormal;
-  }
-
-  const uint32_t five_seconds_samples =
-      static_cast<uint32_t>(5 * 8000 * fs_mult_);
-  // Check if the required packet is available.
-  if (target_timestamp == available_timestamp) {
-    return ExpectedPacketAvailable(prev_mode, play_dtmf);
-  } else if (!PacketBuffer::IsObsoleteTimestamp(
-                 available_timestamp, target_timestamp, five_seconds_samples)) {
-    return FuturePacketAvailable(sync_buffer, expand, decoder_frame_length,
-                                 prev_mode, target_timestamp,
-                                 available_timestamp, play_dtmf,
-                                 generated_noise_samples);
-  } else {
-    // This implies that available_timestamp < target_timestamp, which can
-    // happen when a new stream or codec is received. Signal for a reset.
-    return kUndefined;
-  }
-}
-
-Operations DecisionLogicNormal::CngOperation(Modes prev_mode,
-                                             uint32_t target_timestamp,
-                                             uint32_t available_timestamp,
-                                             size_t generated_noise_samples) {
-  // Signed difference between target and available timestamp.
-  int32_t timestamp_diff = static_cast<int32_t>(
-      static_cast<uint32_t>(generated_noise_samples + target_timestamp) -
-      available_timestamp);
-  int32_t optimal_level_samp = static_cast<int32_t>(
-      (delay_manager_->TargetLevel() * packet_length_samples_) >> 8);
-  const int64_t excess_waiting_time_samp =
-      -static_cast<int64_t>(timestamp_diff) - optimal_level_samp;
-
-  if (excess_waiting_time_samp > optimal_level_samp / 2) {
-    // The waiting time for this packet will be longer than 1.5
-    // times the wanted buffer delay. Apply fast-forward to cut the
-    // waiting time down to the optimal.
-    noise_fast_forward_ = rtc::dchecked_cast<size_t>(noise_fast_forward_ +
-                                                     excess_waiting_time_samp);
-    timestamp_diff =
-        rtc::saturated_cast<int32_t>(timestamp_diff + excess_waiting_time_samp);
-  }
-
-  if (timestamp_diff < 0 && prev_mode == kModeRfc3389Cng) {
-    // Not time to play this packet yet. Wait another round before using this
-    // packet. Keep on playing CNG from previous CNG parameters.
-    return kRfc3389CngNoPacket;
-  } else {
-    // Otherwise, go for the CNG packet now.
-    noise_fast_forward_ = 0;
-    return kRfc3389Cng;
-  }
-}
-
-Operations DecisionLogicNormal::NoPacket(bool play_dtmf) {
-  if (cng_state_ == kCngRfc3389On) {
-    // Keep on playing comfort noise.
-    return kRfc3389CngNoPacket;
-  } else if (cng_state_ == kCngInternalOn) {
-    // Keep on playing codec internal comfort noise.
-    return kCodecInternalCng;
-  } else if (play_dtmf) {
-    return kDtmf;
-  } else {
-    // Nothing to play, do expand.
-    return kExpand;
-  }
-}
-
-Operations DecisionLogicNormal::ExpectedPacketAvailable(Modes prev_mode,
-                                                        bool play_dtmf) {
-  if (prev_mode != kModeExpand && !play_dtmf) {
-    // Check criterion for time-stretching.
-    int low_limit, high_limit;
-    delay_manager_->BufferLimits(&low_limit, &high_limit);
-    if (buffer_level_filter_->filtered_current_level() >= high_limit << 2)
-      return kFastAccelerate;
-    if (TimescaleAllowed()) {
-      if (buffer_level_filter_->filtered_current_level() >= high_limit)
-        return kAccelerate;
-      if (buffer_level_filter_->filtered_current_level() < low_limit)
-        return kPreemptiveExpand;
-    }
-  }
-  return kNormal;
-}
-
-Operations DecisionLogicNormal::FuturePacketAvailable(
-    const SyncBuffer& sync_buffer,
-    const Expand& expand,
-    size_t decoder_frame_length,
-    Modes prev_mode,
-    uint32_t target_timestamp,
-    uint32_t available_timestamp,
-    bool play_dtmf,
-    size_t generated_noise_samples) {
-  // Required packet is not available, but a future packet is.
-  // Check if we should continue with an ongoing expand because the new packet
-  // is too far into the future.
-  uint32_t timestamp_leap = available_timestamp - target_timestamp;
-  if ((prev_mode == kModeExpand) &&
-      !ReinitAfterExpands(timestamp_leap) &&
-      !MaxWaitForPacket() &&
-      PacketTooEarly(timestamp_leap) &&
-      UnderTargetLevel()) {
-    if (play_dtmf) {
-      // Still have DTMF to play, so do not do expand.
-      return kDtmf;
-    } else {
-      // Nothing to play.
-      return kExpand;
-    }
-  }
-
-  const size_t samples_left =
-      sync_buffer.FutureLength() - expand.overlap_length();
-  const size_t cur_size_samples = samples_left +
-      packet_buffer_.NumPacketsInBuffer() * decoder_frame_length;
-
-  // If previous was comfort noise, then no merge is needed.
-  if (prev_mode == kModeRfc3389Cng ||
-      prev_mode == kModeCodecInternalCng) {
-    // Keep the same delay as before the CNG, but make sure that the number of
-    // samples in buffer is no higher than 4 times the optimal level. (Note that
-    // TargetLevel() is in Q8.)
-    if (static_cast<uint32_t>(generated_noise_samples + target_timestamp) >=
-            available_timestamp ||
-        cur_size_samples >
-            ((delay_manager_->TargetLevel() * packet_length_samples_) >> 8) *
-            4) {
-      // Time to play this new packet.
-      return kNormal;
-    } else {
-      // Too early to play this new packet; keep on playing comfort noise.
-      if (prev_mode == kModeRfc3389Cng) {
-        return kRfc3389CngNoPacket;
-      } else {  // prevPlayMode == kModeCodecInternalCng.
-        return kCodecInternalCng;
-      }
-    }
-  }
-  // Do not merge unless we have done an expand before.
-  if (prev_mode == kModeExpand) {
-    return kMerge;
-  } else if (play_dtmf) {
-    // Play DTMF instead of expand.
-    return kDtmf;
-  } else {
-    return kExpand;
-  }
-}
-
-bool DecisionLogicNormal::UnderTargetLevel() const {
-  return buffer_level_filter_->filtered_current_level() <=
-      delay_manager_->TargetLevel();
-}
-
-bool DecisionLogicNormal::ReinitAfterExpands(uint32_t timestamp_leap) const {
-  return timestamp_leap >=
-      static_cast<uint32_t>(output_size_samples_ * kReinitAfterExpands);
-}
-
-bool DecisionLogicNormal::PacketTooEarly(uint32_t timestamp_leap) const {
-  return timestamp_leap >
-      static_cast<uint32_t>(output_size_samples_ * num_consecutive_expands_);
-}
-
-bool DecisionLogicNormal::MaxWaitForPacket() const {
-  return num_consecutive_expands_ >= kMaxWaitForPacket;
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_coding/neteq/decision_logic_normal.h b/modules/audio_coding/neteq/decision_logic_normal.h
deleted file mode 100644
index 366d103..0000000
--- a/modules/audio_coding/neteq/decision_logic_normal.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *  Copyright (c) 2013 The WebRTC 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 MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_NORMAL_H_
-#define MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_NORMAL_H_
-
-#include "modules/audio_coding/neteq/decision_logic.h"
-#include "rtc_base/constructormagic.h"
-#include "typedefs.h"  // NOLINT(build/include)
-
-namespace webrtc {
-
-// Implementation of the DecisionLogic class for playout modes kPlayoutOn and
-// kPlayoutStreaming.
-class DecisionLogicNormal : public DecisionLogic {
- public:
-  // Constructor.
-  DecisionLogicNormal(int fs_hz,
-                      size_t output_size_samples,
-                      NetEqPlayoutMode playout_mode,
-                      DecoderDatabase* decoder_database,
-                      const PacketBuffer& packet_buffer,
-                      DelayManager* delay_manager,
-                      BufferLevelFilter* buffer_level_filter,
-                      const TickTimer* tick_timer)
-      : DecisionLogic(fs_hz,
-                      output_size_samples,
-                      playout_mode,
-                      decoder_database,
-                      packet_buffer,
-                      delay_manager,
-                      buffer_level_filter,
-                      tick_timer) {}
-
- protected:
-  static const int kReinitAfterExpands = 100;
-  static const int kMaxWaitForPacket = 10;
-
-  Operations GetDecisionSpecialized(const SyncBuffer& sync_buffer,
-                                    const Expand& expand,
-                                    size_t decoder_frame_length,
-                                    const Packet* next_packet,
-                                    Modes prev_mode,
-                                    bool play_dtmf,
-                                    bool* reset_decoder,
-                                    size_t generated_noise_samples) override;
-
-  // Returns the operation to do given that the expected packet is not
-  // available, but a packet further into the future is at hand.
-  virtual Operations FuturePacketAvailable(
-      const SyncBuffer& sync_buffer,
-      const Expand& expand,
-      size_t decoder_frame_length,
-      Modes prev_mode,
-      uint32_t target_timestamp,
-      uint32_t available_timestamp,
-      bool play_dtmf,
-      size_t generated_noise_samples);
-
-  // Returns the operation to do given that the expected packet is available.
-  virtual Operations ExpectedPacketAvailable(Modes prev_mode, bool play_dtmf);
-
-  // Returns the operation given that no packets are available (except maybe
-  // a DTMF event, flagged by setting |play_dtmf| true).
-  virtual Operations NoPacket(bool play_dtmf);
-
- private:
-  // Returns the operation given that the next available packet is a comfort
-  // noise payload (RFC 3389 only, not codec-internal).
-  Operations CngOperation(Modes prev_mode,
-                          uint32_t target_timestamp,
-                          uint32_t available_timestamp,
-                          size_t generated_noise_samples);
-
-  // Checks if enough time has elapsed since the last successful timescale
-  // operation was done (i.e., accelerate or preemptive expand).
-  bool TimescaleAllowed() const {
-    return !timescale_countdown_ || timescale_countdown_->Finished();
-  }
-
-  // Checks if the current (filtered) buffer level is under the target level.
-  bool UnderTargetLevel() const;
-
-  // Checks if |timestamp_leap| is so long into the future that a reset due
-  // to exceeding kReinitAfterExpands will be done.
-  bool ReinitAfterExpands(uint32_t timestamp_leap) const;
-
-  // Checks if we still have not done enough expands to cover the distance from
-  // the last decoded packet to the next available packet, the distance beeing
-  // conveyed in |timestamp_leap|.
-  bool PacketTooEarly(uint32_t timestamp_leap) const;
-
-  // Checks if num_consecutive_expands_ >= kMaxWaitForPacket.
-  bool MaxWaitForPacket() const;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(DecisionLogicNormal);
-};
-
-}  // namespace webrtc
-#endif  // MODULES_AUDIO_CODING_NETEQ_DECISION_LOGIC_NORMAL_H_
diff --git a/modules/audio_coding/neteq/decision_logic_unittest.cc b/modules/audio_coding/neteq/decision_logic_unittest.cc
index be1b854..6929daa 100644
--- a/modules/audio_coding/neteq/decision_logic_unittest.cc
+++ b/modules/audio_coding/neteq/decision_logic_unittest.cc
@@ -26,26 +26,14 @@
   int fs_hz = 8000;
   int output_size_samples = fs_hz / 100;  // Samples per 10 ms.
   DecoderDatabase decoder_database(
-      new rtc::RefCountedObject<MockAudioDecoderFactory>, rtc::nullopt);
+      new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
   TickTimer tick_timer;
   PacketBuffer packet_buffer(10, &tick_timer);
   DelayPeakDetector delay_peak_detector(&tick_timer);
   DelayManager delay_manager(240, &delay_peak_detector, &tick_timer);
   BufferLevelFilter buffer_level_filter;
   DecisionLogic* logic = DecisionLogic::Create(
-      fs_hz, output_size_samples, kPlayoutOn, &decoder_database, packet_buffer,
-      &delay_manager, &buffer_level_filter, &tick_timer);
-  delete logic;
-  logic = DecisionLogic::Create(
-      fs_hz, output_size_samples, kPlayoutStreaming, &decoder_database,
-      packet_buffer, &delay_manager, &buffer_level_filter, &tick_timer);
-  delete logic;
-  logic = DecisionLogic::Create(
-      fs_hz, output_size_samples, kPlayoutFax, &decoder_database, packet_buffer,
-      &delay_manager, &buffer_level_filter, &tick_timer);
-  delete logic;
-  logic = DecisionLogic::Create(
-      fs_hz, output_size_samples, kPlayoutOff, &decoder_database, packet_buffer,
+      fs_hz, output_size_samples, false, &decoder_database, packet_buffer,
       &delay_manager, &buffer_level_filter, &tick_timer);
   delete logic;
 }
diff --git a/modules/audio_coding/neteq/decoder_database.cc b/modules/audio_coding/neteq/decoder_database.cc
index 5b940ae..1fd8c03 100644
--- a/modules/audio_coding/neteq/decoder_database.cc
+++ b/modules/audio_coding/neteq/decoder_database.cc
@@ -21,7 +21,7 @@
 
 DecoderDatabase::DecoderDatabase(
     const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory,
-    rtc::Optional<AudioCodecPairId> codec_pair_id)
+    absl::optional<AudioCodecPairId> codec_pair_id)
     : active_decoder_type_(-1),
       active_cng_decoder_type_(-1),
       decoder_factory_(decoder_factory),
@@ -31,7 +31,7 @@
 
 DecoderDatabase::DecoderInfo::DecoderInfo(
     const SdpAudioFormat& audio_format,
-    rtc::Optional<AudioCodecPairId> codec_pair_id,
+    absl::optional<AudioCodecPairId> codec_pair_id,
     AudioDecoderFactory* factory,
     const std::string& codec_name)
     : name_(codec_name),
@@ -44,13 +44,13 @@
 
 DecoderDatabase::DecoderInfo::DecoderInfo(
     const SdpAudioFormat& audio_format,
-    rtc::Optional<AudioCodecPairId> codec_pair_id,
+    absl::optional<AudioCodecPairId> codec_pair_id,
     AudioDecoderFactory* factory)
     : DecoderInfo(audio_format, codec_pair_id, factory, audio_format.name) {}
 
 DecoderDatabase::DecoderInfo::DecoderInfo(
     NetEqDecoder ct,
-    rtc::Optional<AudioCodecPairId> codec_pair_id,
+    absl::optional<AudioCodecPairId> codec_pair_id,
     AudioDecoderFactory* factory)
     : DecoderInfo(*NetEqDecoderToSdpAudioFormat(ct), codec_pair_id, factory) {}
 
@@ -59,7 +59,7 @@
                                           const std::string& codec_name)
     : name_(codec_name),
       audio_format_(audio_format),
-      codec_pair_id_(rtc::nullopt),
+      codec_pair_id_(absl::nullopt),
       factory_(nullptr),
       external_decoder_(ext_dec),
       subtype_(Subtype::kNormal) {
@@ -108,7 +108,7 @@
   return IsType(name.c_str());
 }
 
-rtc::Optional<DecoderDatabase::DecoderInfo::CngDecoder>
+absl::optional<DecoderDatabase::DecoderInfo::CngDecoder>
 DecoderDatabase::DecoderInfo::CngDecoder::Create(const SdpAudioFormat& format) {
   if (STR_CASE_CMP(format.name.c_str(), "CN") == 0) {
     // CN has a 1:1 RTP clock rate to sample rate ratio.
@@ -117,7 +117,7 @@
                sample_rate_hz == 32000 || sample_rate_hz == 48000);
     return DecoderDatabase::DecoderInfo::CngDecoder{sample_rate_hz};
   } else {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
 }
 
@@ -134,9 +134,13 @@
   return Subtype::kNormal;
 }
 
-bool DecoderDatabase::Empty() const { return decoders_.empty(); }
+bool DecoderDatabase::Empty() const {
+  return decoders_.empty();
+}
 
-int DecoderDatabase::Size() const { return static_cast<int>(decoders_.size()); }
+int DecoderDatabase::Size() const {
+  return static_cast<int>(decoders_.size());
+}
 
 void DecoderDatabase::Reset() {
   decoders_.clear();
@@ -276,7 +280,7 @@
 int DecoderDatabase::SetActiveDecoder(uint8_t rtp_payload_type,
                                       bool* new_decoder) {
   // Check that |rtp_payload_type| exists in the database.
-  const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
+  const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
   if (!info) {
     // Decoder not found.
     return kDecoderNotFound;
@@ -289,7 +293,7 @@
     *new_decoder = true;
   } else if (active_decoder_type_ != rtp_payload_type) {
     // Moving from one active decoder to another. Delete the first one.
-    const DecoderInfo *old_info = GetDecoderInfo(active_decoder_type_);
+    const DecoderInfo* old_info = GetDecoderInfo(active_decoder_type_);
     RTC_DCHECK(old_info);
     old_info->DropDecoder();
     *new_decoder = true;
@@ -308,7 +312,7 @@
 
 int DecoderDatabase::SetActiveCngDecoder(uint8_t rtp_payload_type) {
   // Check that |rtp_payload_type| exists in the database.
-  const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
+  const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
   if (!info) {
     // Decoder not found.
     return kDecoderNotFound;
@@ -335,7 +339,7 @@
 }
 
 AudioDecoder* DecoderDatabase::GetDecoder(uint8_t rtp_payload_type) const {
-  const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
+  const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
   return info ? info->GetDecoder() : nullptr;
 }
 
@@ -350,17 +354,17 @@
 }
 
 bool DecoderDatabase::IsComfortNoise(uint8_t rtp_payload_type) const {
-  const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
+  const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
   return info && info->IsComfortNoise();
 }
 
 bool DecoderDatabase::IsDtmf(uint8_t rtp_payload_type) const {
-  const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
+  const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
   return info && info->IsDtmf();
 }
 
 bool DecoderDatabase::IsRed(uint8_t rtp_payload_type) const {
-  const DecoderInfo *info = GetDecoderInfo(rtp_payload_type);
+  const DecoderInfo* info = GetDecoderInfo(rtp_payload_type);
   return info && info->IsRed();
 }
 
diff --git a/modules/audio_coding/neteq/decoder_database.h b/modules/audio_coding/neteq/decoder_database.h
index f769e39..107d2f3 100644
--- a/modules/audio_coding/neteq/decoder_database.h
+++ b/modules/audio_coding/neteq/decoder_database.h
@@ -43,14 +43,14 @@
   class DecoderInfo {
    public:
     DecoderInfo(const SdpAudioFormat& audio_format,
-                rtc::Optional<AudioCodecPairId> codec_pair_id,
+                absl::optional<AudioCodecPairId> codec_pair_id,
                 AudioDecoderFactory* factory,
                 const std::string& codec_name);
     explicit DecoderInfo(const SdpAudioFormat& audio_format,
-                         rtc::Optional<AudioCodecPairId> codec_pair_id,
+                         absl::optional<AudioCodecPairId> codec_pair_id,
                          AudioDecoderFactory* factory = nullptr);
     explicit DecoderInfo(NetEqDecoder ct,
-                         rtc::Optional<AudioCodecPairId> codec_pair_id,
+                         absl::optional<AudioCodecPairId> codec_pair_id,
                          AudioDecoderFactory* factory = nullptr);
     DecoderInfo(const SdpAudioFormat& audio_format,
                 AudioDecoder* ext_dec,
@@ -88,14 +88,10 @@
     }
 
     // Returns true if the decoder's format is DTMF.
-    bool IsDtmf() const {
-      return subtype_ == Subtype::kDtmf;
-    }
+    bool IsDtmf() const { return subtype_ == Subtype::kDtmf; }
 
     // Returns true if the decoder's format is RED.
-    bool IsRed() const {
-      return subtype_ == Subtype::kRed;
-    }
+    bool IsRed() const { return subtype_ == Subtype::kRed; }
 
     // Returns true if the decoder's format is named |name|.
     bool IsType(const char* name) const;
@@ -111,7 +107,7 @@
     const std::string name_;
 
     const SdpAudioFormat audio_format_;
-    const rtc::Optional<AudioCodecPairId> codec_pair_id_;
+    const absl::optional<AudioCodecPairId> codec_pair_id_;
     AudioDecoderFactory* const factory_;
     mutable std::unique_ptr<AudioDecoder> decoder_;
 
@@ -120,17 +116,12 @@
 
     // Set iff this is a comfort noise decoder.
     struct CngDecoder {
-      static rtc::Optional<CngDecoder> Create(const SdpAudioFormat& format);
+      static absl::optional<CngDecoder> Create(const SdpAudioFormat& format);
       int sample_rate_hz;
     };
-    const rtc::Optional<CngDecoder> cng_decoder_;
+    const absl::optional<CngDecoder> cng_decoder_;
 
-    enum class Subtype : int8_t {
-      kNormal,
-      kComfortNoise,
-      kDtmf,
-      kRed
-    };
+    enum class Subtype : int8_t { kNormal, kComfortNoise, kDtmf, kRed };
 
     static Subtype SubtypeFromFormat(const SdpAudioFormat& format);
 
@@ -143,7 +134,7 @@
 
   DecoderDatabase(
       const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory,
-      rtc::Optional<AudioCodecPairId> codec_pair_id);
+      absl::optional<AudioCodecPairId> codec_pair_id);
 
   virtual ~DecoderDatabase();
 
@@ -247,7 +238,7 @@
   int active_cng_decoder_type_;
   mutable std::unique_ptr<ComfortNoiseDecoder> active_cng_decoder_;
   rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
-  const rtc::Optional<AudioCodecPairId> codec_pair_id_;
+  const absl::optional<AudioCodecPairId> codec_pair_id_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(DecoderDatabase);
 };
diff --git a/modules/audio_coding/neteq/decoder_database_unittest.cc b/modules/audio_coding/neteq/decoder_database_unittest.cc
index a6b9689..10043e0 100644
--- a/modules/audio_coding/neteq/decoder_database_unittest.cc
+++ b/modules/audio_coding/neteq/decoder_database_unittest.cc
@@ -29,7 +29,7 @@
 
 TEST(DecoderDatabase, CreateAndDestroy) {
   DecoderDatabase db(new rtc::RefCountedObject<MockAudioDecoderFactory>,
-                     rtc::nullopt);
+                     absl::nullopt);
   EXPECT_EQ(0, db.Size());
   EXPECT_TRUE(db.Empty());
 }
@@ -42,7 +42,7 @@
         EXPECT_EQ("pcmu", format.name);
         return true;
       }));
-  DecoderDatabase db(factory, rtc::nullopt);
+  DecoderDatabase db(factory, absl::nullopt);
   const uint8_t kPayloadType = 0;
   const std::string kCodecName = "Robert\'); DROP TABLE Students;";
   EXPECT_EQ(
@@ -67,7 +67,7 @@
         EXPECT_EQ("pcma", format.name);
         return true;
       }));
-  DecoderDatabase db(factory, rtc::nullopt);
+  DecoderDatabase db(factory, absl::nullopt);
   const std::string kCodecName1 = "Robert\'); DROP TABLE Students;";
   const std::string kCodecName2 = "https://xkcd.com/327/";
   EXPECT_EQ(DecoderDatabase::kOK,
@@ -92,12 +92,12 @@
   auto* decoder = new MockAudioDecoder;
   EXPECT_CALL(*factory, MakeAudioDecoderMock(_, _, _))
       .WillOnce(Invoke([decoder](const SdpAudioFormat& format,
-                                 rtc::Optional<AudioCodecPairId> codec_pair_id,
+                                 absl::optional<AudioCodecPairId> codec_pair_id,
                                  std::unique_ptr<AudioDecoder>* dec) {
         EXPECT_EQ("pcmu", format.name);
         dec->reset(decoder);
       }));
-  DecoderDatabase db(factory, rtc::nullopt);
+  DecoderDatabase db(factory, absl::nullopt);
   const uint8_t kPayloadType = 0;
   const std::string kCodecName = "Robert\'); DROP TABLE Students;";
   EXPECT_EQ(
@@ -110,11 +110,11 @@
   EXPECT_EQ(kCodecName, info->get_name());
   EXPECT_EQ(decoder, db.GetDecoder(kPayloadType));
   info = db.GetDecoderInfo(kPayloadType + 1);  // Other payload type.
-  EXPECT_TRUE(info == NULL);  // Should not be found.
+  EXPECT_TRUE(info == NULL);                   // Should not be found.
 }
 
 TEST(DecoderDatabase, GetDecoder) {
-  DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), rtc::nullopt);
+  DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), absl::nullopt);
   const uint8_t kPayloadType = 0;
   const std::string kCodecName = "Robert\'); DROP TABLE Students;";
   EXPECT_EQ(DecoderDatabase::kOK,
@@ -132,7 +132,7 @@
         EXPECT_EQ("pcmu", format.name);
         return true;
       }));
-  DecoderDatabase db(factory, rtc::nullopt);
+  DecoderDatabase db(factory, absl::nullopt);
   const uint8_t kPayloadTypePcmU = 0;
   const uint8_t kPayloadTypeCng = 13;
   const uint8_t kPayloadTypeDtmf = 100;
@@ -168,7 +168,7 @@
 
 TEST(DecoderDatabase, ExternalDecoder) {
   DecoderDatabase db(new rtc::RefCountedObject<MockAudioDecoderFactory>,
-                     rtc::nullopt);
+                     absl::nullopt);
   const uint8_t kPayloadType = 0;
   const std::string kCodecName = "Robert\'); DROP TABLE Students;";
   MockAudioDecoder decoder;
@@ -205,7 +205,7 @@
         EXPECT_EQ("pcmu", format.name);
         return true;
       }));
-  DecoderDatabase db(factory, rtc::nullopt);
+  DecoderDatabase db(factory, absl::nullopt);
   // Load a number of payloads into the database. Payload types are 0, 1, ...,
   // while the decoder type is the same for all payload types (this does not
   // matter for the test).
@@ -245,7 +245,7 @@
 
 // Test the methods for setting and getting active speech and CNG decoders.
 TEST(DecoderDatabase, IF_ISAC(ActiveDecoders)) {
-  DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), rtc::nullopt);
+  DecoderDatabase db(CreateBuiltinAudioDecoderFactory(), absl::nullopt);
   // Load payload types.
   ASSERT_EQ(DecoderDatabase::kOK,
             db.RegisterPayload(0, NetEqDecoder::kDecoderPCMu, "pcmu"));
@@ -292,7 +292,6 @@
   // Try to set non-existing codecs as active.
   EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
             db.SetActiveDecoder(17, &changed));
-  EXPECT_EQ(DecoderDatabase::kDecoderNotFound,
-            db.SetActiveCngDecoder(17));
+  EXPECT_EQ(DecoderDatabase::kDecoderNotFound, db.SetActiveCngDecoder(17));
 }
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/defines.h b/modules/audio_coding/neteq/defines.h
index 496a36d..768f0b9 100644
--- a/modules/audio_coding/neteq/defines.h
+++ b/modules/audio_coding/neteq/defines.h
@@ -24,10 +24,6 @@
   kRfc3389CngNoPacket,
   kCodecInternalCng,
   kDtmf,
-  kAlternativePlc,
-  kAlternativePlcIncreaseTimestamp,
-  kAudioRepetition,
-  kAudioRepetitionIncreaseTimestamp,
   kUndefined = -1
 };
 
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc
index b70131d..a945cdc 100644
--- a/modules/audio_coding/neteq/delay_manager.cc
+++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -155,8 +155,9 @@
       (packet_iat_stopwatch_->ElapsedMs() << 8) / packet_len_ms;
   // Calculate cumulative sum IAT with sequence number compensation. The sum
   // is zero if there is no clock-drift.
-  iat_cumulative_sum_ += (iat_packets_q8 -
-      (static_cast<int>(sequence_number - last_seq_no_) << 8));
+  iat_cumulative_sum_ +=
+      (iat_packets_q8 -
+       (static_cast<int>(sequence_number - last_seq_no_) << 8));
   // Subtract drift term.
   iat_cumulative_sum_ -= kCumulativeSumDrift;
   // Ensure not negative.
@@ -189,8 +190,8 @@
   assert(iat_packets < iat_vector_.size());
   int vector_sum = 0;  // Sum up the vector elements as they are processed.
   // Multiply each element in |iat_vector_| with |iat_factor_|.
-  for (IATVector::iterator it = iat_vector_.begin();
-      it != iat_vector_.end(); ++it) {
+  for (IATVector::iterator it = iat_vector_.begin(); it != iat_vector_.end();
+       ++it) {
     *it = (static_cast<int64_t>(*it) * iat_factor_) >> 15;
     vector_sum += *it;
   }
@@ -236,7 +237,7 @@
   least_required_delay_ms_ = (target_level_ * packet_len_ms_) >> 8;
 
   if (packet_len_ms_ > 0 && minimum_delay_ms_ > 0) {
-    int minimum_delay_packet_q8 =  (minimum_delay_ms_ << 8) / packet_len_ms_;
+    int minimum_delay_packet_q8 = (minimum_delay_ms_ << 8) / packet_len_ms_;
     target_level_ = std::max(target_level_, minimum_delay_packet_q8);
   }
 
@@ -269,8 +270,8 @@
   // (in Q30) by definition, and since the solution is often a low value for
   // |iat_index|, it is more efficient to start with |sum| = 1 and subtract
   // elements from the start of the histogram.
-  size_t index = 0;  // Start from the beginning of |iat_vector_|.
-  int sum = 1 << 30;  // Assign to 1 in Q30.
+  size_t index = 0;           // Start from the beginning of |iat_vector_|.
+  int sum = 1 << 30;          // Assign to 1 in Q30.
   sum -= iat_vector_[index];  // Ensure that target level is >= 1.
 
   do {
@@ -313,13 +314,12 @@
   return 0;
 }
 
-
 void DelayManager::Reset() {
   packet_len_ms_ = 0;  // Packet size unknown.
   streaming_mode_ = false;
   peak_detector_.Reset();
   ResetHistogram();  // Resets target levels too.
-  iat_factor_ = 0;  // Adapt the histogram faster for the first few packets.
+  iat_factor_ = 0;   // Adapt the histogram faster for the first few packets.
   packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
   max_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
   iat_cumulative_sum_ = 0;
@@ -471,8 +471,12 @@
   return least_required_delay_ms_;
 }
 
-int DelayManager::base_target_level() const { return base_target_level_; }
-void DelayManager::set_streaming_mode(bool value) { streaming_mode_ = value; }
+int DelayManager::base_target_level() const {
+  return base_target_level_;
+}
+void DelayManager::set_streaming_mode(bool value) {
+  streaming_mode_ = value;
+}
 int DelayManager::last_pack_cng_or_dtmf() const {
   return last_pack_cng_or_dtmf_;
 }
diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h
index 0d082c8..08004ea 100644
--- a/modules/audio_coding/neteq/delay_manager.h
+++ b/modules/audio_coding/neteq/delay_manager.h
@@ -117,9 +117,9 @@
   virtual void set_last_pack_cng_or_dtmf(int value);
 
  private:
-  static const int kLimitProbability = 53687091;  // 1/20 in Q30.
+  static const int kLimitProbability = 53687091;         // 1/20 in Q30.
   static const int kLimitProbabilityStreaming = 536871;  // 1/2000 in Q30.
-  static const int kMaxStreamingPeakPeriodMs = 600000;  // 10 minutes in ms.
+  static const int kMaxStreamingPeakPeriodMs = 600000;   // 10 minutes in ms.
   static const int kCumulativeSumDrift = 2;  // Drift term for cumulative sum
                                              // |iat_cumulative_sum_|.
   // Steady-state forgetting factor for |iat_vector_|, 0.9993 in Q15.
@@ -146,28 +146,29 @@
 
   bool first_packet_received_;
   const size_t max_packets_in_buffer_;  // Capacity of the packet buffer.
-  IATVector iat_vector_;  // Histogram of inter-arrival times.
+  IATVector iat_vector_;                // Histogram of inter-arrival times.
   int iat_factor_;  // Forgetting factor for updating the IAT histogram (Q15).
   const TickTimer* tick_timer_;
   // Time elapsed since last packet.
   std::unique_ptr<TickTimer::Stopwatch> packet_iat_stopwatch_;
-  int base_target_level_;   // Currently preferred buffer level before peak
-                            // detection and streaming mode (Q0).
+  int base_target_level_;  // Currently preferred buffer level before peak
+                           // detection and streaming mode (Q0).
   // TODO(turajs) change the comment according to the implementation of
   // minimum-delay.
-  int target_level_;  // Currently preferred buffer level in (fractions)
-                      // of packets (Q8), before adding any extra delay.
+  int target_level_;   // Currently preferred buffer level in (fractions)
+                       // of packets (Q8), before adding any extra delay.
   int packet_len_ms_;  // Length of audio in each incoming packet [ms].
   bool streaming_mode_;
-  uint16_t last_seq_no_;  // Sequence number for last received packet.
-  uint32_t last_timestamp_;  // Timestamp for the last received packet.
-  int minimum_delay_ms_;  // Externally set minimum delay.
+  uint16_t last_seq_no_;         // Sequence number for last received packet.
+  uint32_t last_timestamp_;      // Timestamp for the last received packet.
+  int minimum_delay_ms_;         // Externally set minimum delay.
   int least_required_delay_ms_;  // Smallest preferred buffer level (same unit
-                              // as |target_level_|), before applying
-                              // |minimum_delay_ms_| and/or |maximum_delay_ms_|.
-  int maximum_delay_ms_;  // Externally set maximum allowed delay.
-  int iat_cumulative_sum_;  // Cumulative sum of delta inter-arrival times.
-  int max_iat_cumulative_sum_;  // Max of |iat_cumulative_sum_|.
+                                 // as |target_level_|), before applying
+                                 // |minimum_delay_ms_| and/or
+                                 // |maximum_delay_ms_|.
+  int maximum_delay_ms_;         // Externally set maximum allowed delay.
+  int iat_cumulative_sum_;       // Cumulative sum of delta inter-arrival times.
+  int max_iat_cumulative_sum_;   // Max of |iat_cumulative_sum_|.
   // Time elapsed since maximum was observed.
   std::unique_ptr<TickTimer::Stopwatch> max_iat_stopwatch_;
   DelayPeakDetector& peak_detector_;
diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc
index 953bc6b..f9c5680 100644
--- a/modules/audio_coding/neteq/delay_manager_unittest.cc
+++ b/modules/audio_coding/neteq/delay_manager_unittest.cc
@@ -49,8 +49,7 @@
     : dm_(NULL), detector_(&tick_timer_), seq_no_(0x1234), ts_(0x12345678) {}
 
 void DelayManagerTest::SetUp() {
-  EXPECT_CALL(detector_, Reset())
-            .Times(1);
+  EXPECT_CALL(detector_, Reset()).Times(1);
   dm_ = new DelayManager(kMaxNumberOfPackets, &detector_, &tick_timer_);
 }
 
@@ -94,8 +93,7 @@
 TEST_F(DelayManagerTest, SetPacketAudioLength) {
   const int kLengthMs = 30;
   // Expect DelayManager to pass on the new length to the detector object.
-  EXPECT_CALL(detector_, SetPacketAudioLength(kLengthMs))
-      .Times(1);
+  EXPECT_CALL(detector_, SetPacketAudioLength(kLengthMs)).Times(1);
   EXPECT_EQ(0, dm_->SetPacketAudioLength(kLengthMs));
   EXPECT_EQ(-1, dm_->SetPacketAudioLength(-1));  // Illegal parameter value.
 }
@@ -121,8 +119,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(1, 1))
-      .WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
   InsertNextPacket();
   EXPECT_EQ(1 << 8, dm_->TargetLevel());  // In Q8.
   EXPECT_EQ(1, dm_->base_target_level());
@@ -145,8 +142,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(2, 2))
-      .WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(2, 2)).WillOnce(Return(false));
   InsertNextPacket();
   EXPECT_EQ(2 << 8, dm_->TargetLevel());  // In Q8.
   EXPECT_EQ(2, dm_->base_target_level());
@@ -169,10 +165,8 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return true to indicate that peaks are found. Let the peak height be 5.
-  EXPECT_CALL(detector_, Update(1, 1))
-      .WillOnce(Return(true));
-  EXPECT_CALL(detector_, MaxPeakHeight())
-      .WillOnce(Return(5));
+  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(true));
+  EXPECT_CALL(detector_, MaxPeakHeight()).WillOnce(Return(5));
   InsertNextPacket();
   EXPECT_EQ(5 << 8, dm_->TargetLevel());
   EXPECT_EQ(1, dm_->base_target_level());  // Base target level is w/o peaks.
@@ -193,8 +187,7 @@
   // Expect detector update method to be called once with inter-arrival time
   // equal to 1 packet, and (base) target level equal to 1 as well.
   // Return false to indicate no peaks found.
-  EXPECT_CALL(detector_, Update(1, 1))
-      .WillOnce(Return(false));
+  EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
   InsertNextPacket();
   const int kExpectedTarget = 1;
   EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel());  // In Q8.
diff --git a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
index 058ba66..fd4dded 100644
--- a/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
+++ b/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
@@ -65,8 +65,8 @@
   int next = 1;  // Start with the second packet to get a proper IAT.
   while (next < kNumPackets) {
     while (next < kNumPackets && arrival_times_ms[next] <= time) {
-      int iat_packets = (arrival_times_ms[next] - arrival_times_ms[next - 1]) /
-          kPacketSizeMs;
+      int iat_packets =
+          (arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
       const int kTargetBufferLevel = 1;  // Define peaks to be iat > 2.
       if (time < peak_mode_start_ms || time > peak_mode_end_ms) {
         EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
@@ -112,8 +112,8 @@
   int next = 1;  // Start with the second packet to get a proper IAT.
   while (next < kNumPackets) {
     while (next < kNumPackets && arrival_times_ms[next] <= time) {
-      int iat_packets = (arrival_times_ms[next] - arrival_times_ms[next - 1]) /
-          kPacketSizeMs;
+      int iat_packets =
+          (arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
       const int kTargetBufferLevel = 2;  // Define peaks to be iat > 4.
       EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
       ++next;
diff --git a/modules/audio_coding/neteq/dsp_helper.cc b/modules/audio_coding/neteq/dsp_helper.cc
index 2a1d81b..05b0f70 100644
--- a/modules/audio_coding/neteq/dsp_helper.cc
+++ b/modules/audio_coding/neteq/dsp_helper.cc
@@ -21,41 +21,29 @@
 
 // Table of constants used in method DspHelper::ParabolicFit().
 const int16_t DspHelper::kParabolaCoefficients[17][3] = {
-    { 120, 32, 64 },
-    { 140, 44, 75 },
-    { 150, 50, 80 },
-    { 160, 57, 85 },
-    { 180, 72, 96 },
-    { 200, 89, 107 },
-    { 210, 98, 112 },
-    { 220, 108, 117 },
-    { 240, 128, 128 },
-    { 260, 150, 139 },
-    { 270, 162, 144 },
-    { 280, 174, 149 },
-    { 300, 200, 160 },
-    { 320, 228, 171 },
-    { 330, 242, 176 },
-    { 340, 257, 181 },
-    { 360, 288, 192 } };
+    {120, 32, 64},   {140, 44, 75},   {150, 50, 80},   {160, 57, 85},
+    {180, 72, 96},   {200, 89, 107},  {210, 98, 112},  {220, 108, 117},
+    {240, 128, 128}, {260, 150, 139}, {270, 162, 144}, {280, 174, 149},
+    {300, 200, 160}, {320, 228, 171}, {330, 242, 176}, {340, 257, 181},
+    {360, 288, 192}};
 
 // Filter coefficients used when downsampling from the indicated sample rates
 // (8, 16, 32, 48 kHz) to 4 kHz. Coefficients are in Q12. The corresponding Q0
 // values are provided in the comments before each array.
 
 // Q0 values: {0.3, 0.4, 0.3}.
-const int16_t DspHelper::kDownsample8kHzTbl[3] = { 1229, 1638, 1229 };
+const int16_t DspHelper::kDownsample8kHzTbl[3] = {1229, 1638, 1229};
 
 // Q0 values: {0.15, 0.2, 0.3, 0.2, 0.15}.
-const int16_t DspHelper::kDownsample16kHzTbl[5] = { 614, 819, 1229, 819, 614 };
+const int16_t DspHelper::kDownsample16kHzTbl[5] = {614, 819, 1229, 819, 614};
 
 // Q0 values: {0.1425, 0.1251, 0.1525, 0.1628, 0.1525, 0.1251, 0.1425}.
-const int16_t DspHelper::kDownsample32kHzTbl[7] = {
-    584, 512, 625, 667, 625, 512, 584 };
+const int16_t DspHelper::kDownsample32kHzTbl[7] = {584, 512, 625, 667,
+                                                   625, 512, 584};
 
 // Q0 values: {0.2487, 0.0952, 0.1042, 0.1074, 0.1042, 0.0952, 0.2487}.
-const int16_t DspHelper::kDownsample48kHzTbl[7] = {
-    1019, 390, 427, 440, 427, 390, 1019 };
+const int16_t DspHelper::kDownsample48kHzTbl[7] = {1019, 390, 427, 440,
+                                                   427,  390, 1019};
 
 int DspHelper::RampSignal(const int16_t* input,
                           size_t length,
@@ -115,9 +103,12 @@
   return end_factor;
 }
 
-void DspHelper::PeakDetection(int16_t* data, size_t data_length,
-                              size_t num_peaks, int fs_mult,
-                              size_t* peak_index, int16_t* peak_value) {
+void DspHelper::PeakDetection(int16_t* data,
+                              size_t data_length,
+                              size_t num_peaks,
+                              int fs_mult,
+                              size_t* peak_index,
+                              int16_t* peak_value) {
   size_t min_index = 0;
   size_t max_index = 0;
 
@@ -163,8 +154,10 @@
   }
 }
 
-void DspHelper::ParabolicFit(int16_t* signal_points, int fs_mult,
-                             size_t* peak_index, int16_t* peak_value) {
+void DspHelper::ParabolicFit(int16_t* signal_points,
+                             int fs_mult,
+                             size_t* peak_index,
+                             int16_t* peak_value) {
   uint16_t fit_index[13];
   if (fs_mult == 1) {
     fit_index[0] = 0;
@@ -204,23 +197,26 @@
 
   //  num = -3 * signal_points[0] + 4 * signal_points[1] - signal_points[2];
   //  den =      signal_points[0] - 2 * signal_points[1] + signal_points[2];
-  int32_t num = (signal_points[0] * -3) + (signal_points[1] * 4)
-      - signal_points[2];
+  int32_t num =
+      (signal_points[0] * -3) + (signal_points[1] * 4) - signal_points[2];
   int32_t den = signal_points[0] + (signal_points[1] * -2) + signal_points[2];
   int32_t temp = num * 120;
   int flag = 1;
-  int16_t stp = kParabolaCoefficients[fit_index[fs_mult]][0]
-      - kParabolaCoefficients[fit_index[fs_mult - 1]][0];
-  int16_t strt = (kParabolaCoefficients[fit_index[fs_mult]][0]
-      + kParabolaCoefficients[fit_index[fs_mult - 1]][0]) / 2;
+  int16_t stp = kParabolaCoefficients[fit_index[fs_mult]][0] -
+                kParabolaCoefficients[fit_index[fs_mult - 1]][0];
+  int16_t strt = (kParabolaCoefficients[fit_index[fs_mult]][0] +
+                  kParabolaCoefficients[fit_index[fs_mult - 1]][0]) /
+                 2;
   int16_t lmt;
   if (temp < -den * strt) {
     lmt = strt - stp;
     while (flag) {
       if ((flag == fs_mult) || (temp > -den * lmt)) {
-        *peak_value = (den * kParabolaCoefficients[fit_index[fs_mult - flag]][1]
-            + num * kParabolaCoefficients[fit_index[fs_mult - flag]][2]
-            + signal_points[0] * 256) / 256;
+        *peak_value =
+            (den * kParabolaCoefficients[fit_index[fs_mult - flag]][1] +
+             num * kParabolaCoefficients[fit_index[fs_mult - flag]][2] +
+             signal_points[0] * 256) /
+            256;
         *peak_index = *peak_index * 2 * fs_mult - flag;
         flag = 0;
       } else {
@@ -233,9 +229,9 @@
     while (flag) {
       if ((flag == fs_mult) || (temp < -den * lmt)) {
         int32_t temp_term_1 =
-            den * kParabolaCoefficients[fit_index[fs_mult+flag]][1];
+            den * kParabolaCoefficients[fit_index[fs_mult + flag]][1];
         int32_t temp_term_2 =
-            num * kParabolaCoefficients[fit_index[fs_mult+flag]][2];
+            num * kParabolaCoefficients[fit_index[fs_mult + flag]][2];
         int32_t temp_term_3 = signal_points[0] * 256;
         *peak_value = (temp_term_1 + temp_term_2 + temp_term_3) / 256;
         *peak_index = *peak_index * 2 * fs_mult + flag;
@@ -251,8 +247,10 @@
   }
 }
 
-size_t DspHelper::MinDistortion(const int16_t* signal, size_t min_lag,
-                                size_t max_lag, size_t length,
+size_t DspHelper::MinDistortion(const int16_t* signal,
+                                size_t min_lag,
+                                size_t max_lag,
+                                size_t length,
                                 int32_t* distortion_value) {
   size_t best_index = 0;
   int32_t min_distortion = WEBRTC_SPL_WORD32_MAX;
@@ -273,9 +271,12 @@
   return best_index;
 }
 
-void DspHelper::CrossFade(const int16_t* input1, const int16_t* input2,
-                          size_t length, int16_t* mix_factor,
-                          int16_t factor_decrement, int16_t* output) {
+void DspHelper::CrossFade(const int16_t* input1,
+                          const int16_t* input2,
+                          size_t length,
+                          int16_t* mix_factor,
+                          int16_t factor_decrement,
+                          int16_t* output) {
   int16_t factor = *mix_factor;
   int16_t complement_factor = 16384 - factor;
   for (size_t i = 0; i < length; i++) {
@@ -287,8 +288,10 @@
   *mix_factor = factor;
 }
 
-void DspHelper::UnmuteSignal(const int16_t* input, size_t length,
-                             int16_t* factor, int increment,
+void DspHelper::UnmuteSignal(const int16_t* input,
+                             size_t length,
+                             int16_t* factor,
+                             int increment,
                              int16_t* output) {
   uint16_t factor_16b = *factor;
   int32_t factor_32b = (static_cast<int32_t>(factor_16b) << 6) + 32;
@@ -308,17 +311,20 @@
   }
 }
 
-int DspHelper::DownsampleTo4kHz(const int16_t* input, size_t input_length,
-                                size_t output_length, int input_rate_hz,
-                                bool compensate_delay, int16_t* output) {
+int DspHelper::DownsampleTo4kHz(const int16_t* input,
+                                size_t input_length,
+                                size_t output_length,
+                                int input_rate_hz,
+                                bool compensate_delay,
+                                int16_t* output) {
   // Set filter parameters depending on input frequency.
   // NOTE: The phase delay values are wrong compared to the true phase delay
   // of the filters. However, the error is preserved (through the +1 term) for
   // consistency.
   const int16_t* filter_coefficients;  // Filter coefficients.
-  size_t filter_length;  // Number of coefficients.
-  size_t filter_delay;  // Phase delay in samples.
-  int16_t factor;  // Conversion rate (inFsHz / 8000).
+  size_t filter_length;                // Number of coefficients.
+  size_t filter_delay;                 // Phase delay in samples.
+  int16_t factor;                      // Conversion rate (inFsHz / 8000).
   switch (input_rate_hz) {
     case 8000: {
       filter_length = 3;
diff --git a/modules/audio_coding/neteq/dsp_helper.h b/modules/audio_coding/neteq/dsp_helper.h
index 7ceb66f..8940acd 100644
--- a/modules/audio_coding/neteq/dsp_helper.h
+++ b/modules/audio_coding/neteq/dsp_helper.h
@@ -85,9 +85,12 @@
   // locations and values are written to the arrays |peak_index| and
   // |peak_value|, respectively. Both arrays must hold at least |num_peaks|
   // elements.
-  static void PeakDetection(int16_t* data, size_t data_length,
-                            size_t num_peaks, int fs_mult,
-                            size_t* peak_index, int16_t* peak_value);
+  static void PeakDetection(int16_t* data,
+                            size_t data_length,
+                            size_t num_peaks,
+                            int fs_mult,
+                            size_t* peak_index,
+                            int16_t* peak_value);
 
   // Estimates the height and location of a maximum. The three values in the
   // array |signal_points| are used as basis for a parabolic fit, which is then
@@ -95,30 +98,40 @@
   // assumed to be from a 4 kHz signal, while the maximum, written to
   // |peak_index| and |peak_value| is given in the full sample rate, as
   // indicated by the sample rate multiplier |fs_mult|.
-  static void ParabolicFit(int16_t* signal_points, int fs_mult,
-                           size_t* peak_index, int16_t* peak_value);
+  static void ParabolicFit(int16_t* signal_points,
+                           int fs_mult,
+                           size_t* peak_index,
+                           int16_t* peak_value);
 
   // Calculates the sum-abs-diff for |signal| when compared to a displaced
   // version of itself. Returns the displacement lag that results in the minimum
   // distortion. The resulting distortion is written to |distortion_value|.
   // The values of |min_lag| and |max_lag| are boundaries for the search.
-  static size_t MinDistortion(const int16_t* signal, size_t min_lag,
-                           size_t max_lag, size_t length,
-                           int32_t* distortion_value);
+  static size_t MinDistortion(const int16_t* signal,
+                              size_t min_lag,
+                              size_t max_lag,
+                              size_t length,
+                              int32_t* distortion_value);
 
   // Mixes |length| samples from |input1| and |input2| together and writes the
   // result to |output|. The gain for |input1| starts at |mix_factor| (Q14) and
   // is decreased by |factor_decrement| (Q14) for each sample. The gain for
   // |input2| is the complement 16384 - mix_factor.
-  static void CrossFade(const int16_t* input1, const int16_t* input2,
-                        size_t length, int16_t* mix_factor,
-                        int16_t factor_decrement, int16_t* output);
+  static void CrossFade(const int16_t* input1,
+                        const int16_t* input2,
+                        size_t length,
+                        int16_t* mix_factor,
+                        int16_t factor_decrement,
+                        int16_t* output);
 
   // Scales |input| with an increasing gain. Applies |factor| (Q14) to the first
   // sample and increases the gain by |increment| (Q20) for each sample. The
   // result is written to |output|. |length| samples are processed.
-  static void UnmuteSignal(const int16_t* input, size_t length, int16_t* factor,
-                           int increment, int16_t* output);
+  static void UnmuteSignal(const int16_t* input,
+                           size_t length,
+                           int16_t* factor,
+                           int increment,
+                           int16_t* output);
 
   // Starts at unity gain and gradually fades out |signal|. For each sample,
   // the gain is reduced by |mute_slope| (Q14). |length| samples are processed.
@@ -129,9 +142,12 @@
   // samples to |output|. Compensates for the phase delay of the downsampling
   // filters if |compensate_delay| is true. Returns -1 if the input is too short
   // to produce |output_length| samples, otherwise 0.
-  static int DownsampleTo4kHz(const int16_t* input, size_t input_length,
-                              size_t output_length, int input_rate_hz,
-                              bool compensate_delay, int16_t* output);
+  static int DownsampleTo4kHz(const int16_t* input,
+                              size_t input_length,
+                              size_t output_length,
+                              int input_rate_hz,
+                              bool compensate_delay,
+                              int16_t* output);
 
  private:
   // Table of constants used in method DspHelper::ParabolicFit().
diff --git a/modules/audio_coding/neteq/dsp_helper_unittest.cc b/modules/audio_coding/neteq/dsp_helper_unittest.cc
index 98ae2a2..9d5da5d 100644
--- a/modules/audio_coding/neteq/dsp_helper_unittest.cc
+++ b/modules/audio_coding/neteq/dsp_helper_unittest.cc
@@ -30,8 +30,8 @@
   int increment = (16384 << 6) / kLen;
 
   // Test first method.
-  int stop_factor = DspHelper::RampSignal(input, kLen, start_factor, increment,
-                                          output);
+  int stop_factor =
+      DspHelper::RampSignal(input, kLen, start_factor, increment, output);
   EXPECT_EQ(16383, stop_factor);  // Almost reach 1 in Q14.
   for (int i = 0; i < kLen; ++i) {
     EXPECT_EQ(1000 * i / kLen, output[i]);
@@ -63,8 +63,8 @@
   // Q20, while the factor is in Q14, hence the shift by 6.
   int increment = (16384 << 6) / kLen;
 
-  int stop_factor = DspHelper::RampSignal(&input, start_index, kLen,
-                                          start_factor, increment);
+  int stop_factor =
+      DspHelper::RampSignal(&input, start_index, kLen, start_factor, increment);
   EXPECT_EQ(16383, stop_factor);  // Almost reach 1 in Q14.
   // Verify that the first |kLen| samples are left untouched.
   int i;
diff --git a/modules/audio_coding/neteq/dtmf_buffer.cc b/modules/audio_coding/neteq/dtmf_buffer.cc
index 370de42..656cff9 100644
--- a/modules/audio_coding/neteq/dtmf_buffer.cc
+++ b/modules/audio_coding/neteq/dtmf_buffer.cc
@@ -98,9 +98,8 @@
 // already in the buffer. If so, the new event is simply merged with the
 // existing one.
 int DtmfBuffer::InsertEvent(const DtmfEvent& event) {
-  if (event.event_no < 0 || event.event_no > 15 ||
-      event.volume < 0 || event.volume > 63 ||
-      event.duration <= 0 || event.duration > 65535) {
+  if (event.event_no < 0 || event.event_no > 15 || event.volume < 0 ||
+      event.volume > 63 || event.duration <= 0 || event.duration > 65535) {
     RTC_LOG(LS_WARNING) << "InsertEvent invalid parameters";
     return kInvalidEventParameters;
   }
@@ -142,8 +141,8 @@
 #endif
       }
     }
-    if (current_timestamp >= it->timestamp
-        && current_timestamp <= event_end) {  // TODO(hlundin): Change to <.
+    if (current_timestamp >= it->timestamp &&
+        current_timestamp <= event_end) {  // TODO(hlundin): Change to <.
       // Found a matching event.
       if (event) {
         event->event_no = it->event_no;
@@ -153,16 +152,15 @@
         event->timestamp = it->timestamp;
       }
 #ifdef LEGACY_BITEXACT
-      if (it->end_bit &&
-          current_timestamp + frame_len_samples_ >= event_end) {
+      if (it->end_bit && current_timestamp + frame_len_samples_ >= event_end) {
         // We are done playing this. Erase the event.
         buffer_.erase(it);
       }
 #endif
       return true;
     } else if (current_timestamp > event_end) {  // TODO(hlundin): Change to >=.
-      // Erase old event. Operation returns a valid pointer to the next element
-      // in the list.
+// Erase old event. Operation returns a valid pointer to the next element
+// in the list.
 #ifdef LEGACY_BITEXACT
       if (!next_available) {
         if (event) {
@@ -196,10 +194,7 @@
 }
 
 int DtmfBuffer::SetSampleRate(int fs_hz) {
-  if (fs_hz != 8000 &&
-      fs_hz != 16000 &&
-      fs_hz != 32000 &&
-      fs_hz != 48000) {
+  if (fs_hz != 8000 && fs_hz != 16000 && fs_hz != 32000 && fs_hz != 48000) {
     return kInvalidSampleRate;
   }
   max_extrapolation_samples_ = 7 * fs_hz / 100;
diff --git a/modules/audio_coding/neteq/dtmf_buffer.h b/modules/audio_coding/neteq/dtmf_buffer.h
index 87a5655..1035e87 100644
--- a/modules/audio_coding/neteq/dtmf_buffer.h
+++ b/modules/audio_coding/neteq/dtmf_buffer.h
@@ -28,19 +28,9 @@
 
   // Constructors
   DtmfEvent()
-      : timestamp(0),
-        event_no(0),
-        volume(0),
-        duration(0),
-        end_bit(false) {
-  }
+      : timestamp(0), event_no(0), volume(0), duration(0), end_bit(false) {}
   DtmfEvent(uint32_t ts, int ev, int vol, int dur, bool end)
-      : timestamp(ts),
-        event_no(ev),
-        volume(vol),
-        duration(dur),
-        end_bit(end) {
-  }
+      : timestamp(ts), event_no(ev), volume(vol), duration(dur), end_bit(end) {}
 };
 
 // This is the buffer holding DTMF events while waiting for them to be played.
diff --git a/modules/audio_coding/neteq/dtmf_buffer_unittest.cc b/modules/audio_coding/neteq/dtmf_buffer_unittest.cc
index 7bcf1e0..607a5ec 100644
--- a/modules/audio_coding/neteq/dtmf_buffer_unittest.cc
+++ b/modules/audio_coding/neteq/dtmf_buffer_unittest.cc
@@ -31,11 +31,11 @@
 
 static uint32_t MakeDtmfPayload(int event, bool end, int volume, int duration) {
   uint32_t payload = 0;
-//  0                   1                   2                   3
-//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |     event     |E|R| volume    |          duration             |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //  0                   1                   2                   3
+  //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // |     event     |E|R| volume    |          duration             |
+  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   payload |= (event & 0x00FF) << 24;
   payload |= (end ? 0x00800000 : 0x00000000);
   payload |= (volume & 0x003F) << 16;
@@ -44,13 +44,10 @@
   return payload;
 }
 
-static bool EqualEvents(const DtmfEvent& a,
-                        const DtmfEvent& b) {
-  return (a.duration == b.duration
-      && a.end_bit == b.end_bit
-      && a.event_no == b.event_no
-      && a.timestamp == b.timestamp
-      && a.volume == b.volume);
+static bool EqualEvents(const DtmfEvent& a, const DtmfEvent& b) {
+  return (a.duration == b.duration && a.end_bit == b.end_bit &&
+          a.event_no == b.event_no && a.timestamp == b.timestamp &&
+          a.volume == b.volume);
 }
 
 TEST(DtmfBuffer, CreateAndDestroy) {
@@ -68,9 +65,8 @@
   uint32_t payload = MakeDtmfPayload(event_no, end_bit, volume, duration);
   uint8_t* payload_ptr = reinterpret_cast<uint8_t*>(&payload);
   DtmfEvent event;
-  EXPECT_EQ(DtmfBuffer::kOK,
-            DtmfBuffer::ParseEvent(timestamp, payload_ptr, sizeof(payload),
-                                   &event));
+  EXPECT_EQ(DtmfBuffer::kOK, DtmfBuffer::ParseEvent(timestamp, payload_ptr,
+                                                    sizeof(payload), &event));
   EXPECT_EQ(duration, event.duration);
   EXPECT_EQ(end_bit, event.end_bit);
   EXPECT_EQ(event_no, event.event_no);
@@ -107,7 +103,7 @@
   EXPECT_TRUE(EqualEvents(event, out_event));
   EXPECT_EQ(1u, buffer.Length());
   EXPECT_FALSE(buffer.Empty());
-  // Give a "current" timestamp after the event has ended.
+// Give a "current" timestamp after the event has ended.
 #ifdef LEGACY_BITEXACT
   EXPECT_TRUE(buffer.GetEvent(timestamp + duration + 10, &out_event));
 #endif
@@ -171,17 +167,17 @@
   // Expect to get the long event.
   EXPECT_TRUE(buffer.GetEvent(timestamp, &out_event));
   EXPECT_TRUE(EqualEvents(long_event, out_event));
-  // Expect no more events.
+// Expect no more events.
 #ifdef LEGACY_BITEXACT
-  EXPECT_TRUE(buffer.GetEvent(timestamp + long_event.duration + 10,
-                              &out_event));
+  EXPECT_TRUE(
+      buffer.GetEvent(timestamp + long_event.duration + 10, &out_event));
   EXPECT_TRUE(EqualEvents(long_event, out_event));
-  EXPECT_TRUE(buffer.GetEvent(timestamp + long_event.duration + 10,
-                              &out_event));
+  EXPECT_TRUE(
+      buffer.GetEvent(timestamp + long_event.duration + 10, &out_event));
   EXPECT_TRUE(EqualEvents(short_event, out_event));
 #else
-  EXPECT_FALSE(buffer.GetEvent(timestamp + long_event.duration + 10,
-                               &out_event));
+  EXPECT_FALSE(
+      buffer.GetEvent(timestamp + long_event.duration + 10, &out_event));
 #endif
   EXPECT_TRUE(buffer.Empty());
 }
diff --git a/modules/audio_coding/neteq/dtmf_tone_generator.cc b/modules/audio_coding/neteq/dtmf_tone_generator.cc
index b848c60..6fdb95a 100644
--- a/modules/audio_coding/neteq/dtmf_tone_generator.cc
+++ b/modules/audio_coding/neteq/dtmf_tone_generator.cc
@@ -39,72 +39,69 @@
 // sample rates fs = {8000, 16000, 32000, 48000} Hz, and events 0 through 15.
 // Values are in Q14.
 const int DtmfToneGenerator::kCoeff1[4][16] = {
-    { 24219, 27980, 27980, 27980, 26956, 26956, 26956, 25701, 25701, 25701,
-      24219, 24219, 27980, 26956, 25701, 24219 },
-    { 30556, 31548, 31548, 31548, 31281, 31281, 31281, 30951, 30951, 30951,
-      30556, 30556, 31548, 31281, 30951, 30556 },
-    { 32210, 32462, 32462, 32462, 32394, 32394, 32394, 32311, 32311, 32311,
-      32210, 32210, 32462, 32394, 32311, 32210 },
-    { 32520, 32632, 32632, 32632, 32602, 32602, 32602, 32564, 32564, 32564,
-      32520, 32520, 32632, 32602, 32564, 32520 } };
+    {24219, 27980, 27980, 27980, 26956, 26956, 26956, 25701, 25701, 25701,
+     24219, 24219, 27980, 26956, 25701, 24219},
+    {30556, 31548, 31548, 31548, 31281, 31281, 31281, 30951, 30951, 30951,
+     30556, 30556, 31548, 31281, 30951, 30556},
+    {32210, 32462, 32462, 32462, 32394, 32394, 32394, 32311, 32311, 32311,
+     32210, 32210, 32462, 32394, 32311, 32210},
+    {32520, 32632, 32632, 32632, 32602, 32602, 32602, 32564, 32564, 32564,
+     32520, 32520, 32632, 32602, 32564, 32520}};
 
 // The filter coefficient a = 2*cos(2*pi*f/fs) for the high frequency tone, for
 // sample rates fs = {8000, 16000, 32000, 48000} Hz, and events 0 through 15.
 // Values are in Q14.
 const int DtmfToneGenerator::kCoeff2[4][16] = {
-    { 16325, 19073, 16325, 13085, 19073, 16325, 13085, 19073, 16325, 13085,
-      19073, 13085, 9315, 9315, 9315, 9315},
-    { 28361, 29144, 28361, 27409, 29144, 28361, 27409, 29144, 28361, 27409,
-      29144, 27409, 26258, 26258, 26258, 26258},
-    { 31647, 31849, 31647, 31400, 31849, 31647, 31400, 31849, 31647, 31400,
-      31849, 31400, 31098, 31098, 31098, 31098},
-    { 32268, 32359, 32268, 32157, 32359, 32268, 32157, 32359, 32268, 32157,
-      32359, 32157, 32022, 32022, 32022, 32022} };
+    {16325, 19073, 16325, 13085, 19073, 16325, 13085, 19073, 16325, 13085,
+     19073, 13085, 9315, 9315, 9315, 9315},
+    {28361, 29144, 28361, 27409, 29144, 28361, 27409, 29144, 28361, 27409,
+     29144, 27409, 26258, 26258, 26258, 26258},
+    {31647, 31849, 31647, 31400, 31849, 31647, 31400, 31849, 31647, 31400,
+     31849, 31400, 31098, 31098, 31098, 31098},
+    {32268, 32359, 32268, 32157, 32359, 32268, 32157, 32359, 32268, 32157,
+     32359, 32157, 32022, 32022, 32022, 32022}};
 
 // The initialization value x[-2] = sin(2*pi*f/fs) for the low frequency tone,
 // for sample rates fs = {8000, 16000, 32000, 48000} Hz, and events 0-15.
 // Values are in Q14.
 const int DtmfToneGenerator::kInitValue1[4][16] = {
-    { 11036, 8528, 8528, 8528, 9315, 9315, 9315, 10163, 10163, 10163, 11036,
-      11036, 8528, 9315, 10163, 11036},
-    { 5918, 4429, 4429, 4429, 4879, 4879, 4879, 5380, 5380, 5380, 5918, 5918,
-      4429, 4879, 5380, 5918},
-    { 3010, 2235, 2235, 2235, 2468, 2468, 2468, 2728, 2728, 2728, 3010, 3010,
-      2235, 2468, 2728, 3010},
-    { 2013, 1493, 1493, 1493, 1649, 1649, 1649, 1823, 1823, 1823, 2013, 2013,
-      1493, 1649, 1823, 2013 } };
+    {11036, 8528, 8528, 8528, 9315, 9315, 9315, 10163, 10163, 10163, 11036,
+     11036, 8528, 9315, 10163, 11036},
+    {5918, 4429, 4429, 4429, 4879, 4879, 4879, 5380, 5380, 5380, 5918, 5918,
+     4429, 4879, 5380, 5918},
+    {3010, 2235, 2235, 2235, 2468, 2468, 2468, 2728, 2728, 2728, 3010, 3010,
+     2235, 2468, 2728, 3010},
+    {2013, 1493, 1493, 1493, 1649, 1649, 1649, 1823, 1823, 1823, 2013, 2013,
+     1493, 1649, 1823, 2013}};
 
 // The initialization value x[-2] = sin(2*pi*f/fs) for the high frequency tone,
 // for sample rates fs = {8000, 16000, 32000, 48000} Hz, and events 0-15.
 // Values are in Q14.
 const int DtmfToneGenerator::kInitValue2[4][16] = {
-    { 14206, 13323, 14206, 15021, 13323, 14206, 15021, 13323, 14206, 15021,
-      13323, 15021, 15708, 15708, 15708, 15708},
-    { 8207, 7490, 8207, 8979, 7490, 8207, 8979, 7490, 8207, 8979, 7490, 8979,
-      9801, 9801, 9801, 9801},
-    { 4249, 3853, 4249, 4685, 3853, 4249, 4685, 3853, 4249, 4685, 3853, 4685,
-      5164, 5164, 5164, 5164},
-    { 2851, 2582, 2851, 3148, 2582, 2851, 3148, 2582, 2851, 3148, 2582, 3148,
-      3476, 3476, 3476, 3476} };
+    {14206, 13323, 14206, 15021, 13323, 14206, 15021, 13323, 14206, 15021,
+     13323, 15021, 15708, 15708, 15708, 15708},
+    {8207, 7490, 8207, 8979, 7490, 8207, 8979, 7490, 8207, 8979, 7490, 8979,
+     9801, 9801, 9801, 9801},
+    {4249, 3853, 4249, 4685, 3853, 4249, 4685, 3853, 4249, 4685, 3853, 4685,
+     5164, 5164, 5164, 5164},
+    {2851, 2582, 2851, 3148, 2582, 2851, 3148, 2582, 2851, 3148, 2582, 3148,
+     3476, 3476, 3476, 3476}};
 
 // Amplitude multipliers for volume values 0 through 63, corresponding to
 // 0 dBm0 through -63 dBm0. Values are in Q14.
 // for a in range(0, 64):
 //   print round(16141.0 * 10**(-float(a)/20))
 const int DtmfToneGenerator::kAmplitude[64] = {
-    16141, 14386, 12821, 11427, 10184, 9077, 8090, 7210, 6426, 5727, 5104, 4549,
-    4054, 3614, 3221, 2870, 2558, 2280, 2032, 1811, 1614, 1439, 1282, 1143,
-    1018, 908, 809, 721, 643, 573, 510, 455, 405, 361, 322, 287, 256, 228, 203,
-    181, 161, 144, 128, 114, 102, 91, 81, 72, 64, 57, 51, 45, 41, 36, 32, 29,
-    26, 23, 20, 18, 16, 14, 13, 11 };
+    16141, 14386, 12821, 11427, 10184, 9077, 8090, 7210, 6426, 5727, 5104,
+    4549,  4054,  3614,  3221,  2870,  2558, 2280, 2032, 1811, 1614, 1439,
+    1282,  1143,  1018,  908,   809,   721,  643,  573,  510,  455,  405,
+    361,   322,   287,   256,   228,   203,  181,  161,  144,  128,  114,
+    102,   91,    81,    72,    64,    57,   51,   45,   41,   36,   32,
+    29,    26,    23,    20,    18,    16,   14,   13,   11};
 
 // Constructor.
 DtmfToneGenerator::DtmfToneGenerator()
-    : initialized_(false),
-      coeff1_(0),
-      coeff2_(0),
-      amplitude_(0) {
-}
+    : initialized_(false), coeff1_(0), coeff2_(0), amplitude_(0) {}
 
 // Initialize the DTMF generator with sample rate fs Hz (8000, 16000, 32000,
 // 48000), event (0-15) and attenuation (0-36 dB).
@@ -170,8 +167,7 @@
 }
 
 // Generate num_samples of DTMF signal and write to |output|.
-int DtmfToneGenerator::Generate(size_t num_samples,
-                                AudioMultiVector* output) {
+int DtmfToneGenerator::Generate(size_t num_samples, AudioMultiVector* output) {
   if (!initialized_) {
     return kNotInitialized;
   }
@@ -183,10 +179,10 @@
   output->AssertSize(num_samples);
   for (size_t i = 0; i < num_samples; ++i) {
     // Use recursion formula y[n] = a * y[n - 1] - y[n - 2].
-    int16_t temp_val_low = ((coeff1_ * sample_history1_[1] + 8192) >> 14)
-        - sample_history1_[0];
-    int16_t temp_val_high = ((coeff2_ * sample_history2_[1] + 8192) >> 14)
-        - sample_history2_[0];
+    int16_t temp_val_low =
+        ((coeff1_ * sample_history1_[1] + 8192) >> 14) - sample_history1_[0];
+    int16_t temp_val_high =
+        ((coeff2_ * sample_history2_[1] + 8192) >> 14) - sample_history2_[0];
 
     // Update recursion memory.
     sample_history1_[0] = sample_history1_[1];
diff --git a/modules/audio_coding/neteq/dtmf_tone_generator.h b/modules/audio_coding/neteq/dtmf_tone_generator.h
index faad6a2..b91d221 100644
--- a/modules/audio_coding/neteq/dtmf_tone_generator.h
+++ b/modules/audio_coding/neteq/dtmf_tone_generator.h
@@ -37,7 +37,7 @@
   static const int kCoeff2[4][16];  // 2nd oscillator model coefficient table.
   static const int kInitValue1[4][16];  // Initialization for 1st oscillator.
   static const int kInitValue2[4][16];  // Initialization for 2nd oscillator.
-  static const int kAmplitude[64];  // Amplitude for 0 through -63 dBm0.
+  static const int kAmplitude[64];      // Amplitude for 0 through -63 dBm0.
   static const int16_t kAmpMultiplier = 23171;  // 3 dB attenuation (in Q15).
 
   bool initialized_;            // True if generator is initialized properly.
diff --git a/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc b/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc
index 8c22fe5..11a0ac6 100644
--- a/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc
+++ b/modules/audio_coding/neteq/dtmf_tone_generator_unittest.cc
@@ -84,8 +84,7 @@
           // Verify that the attenuation is correct.
           for (int channel = 0; channel < channels; ++channel) {
             EXPECT_NEAR(attenuation_factor * ref_signal[channel][n],
-                        signal[channel][n],
-                        2);
+                        signal[channel][n], 2);
           }
         }
 
diff --git a/modules/audio_coding/neteq/expand.cc b/modules/audio_coding/neteq/expand.cc
index 03bcc77..5f671ad 100644
--- a/modules/audio_coding/neteq/expand.cc
+++ b/modules/audio_coding/neteq/expand.cc
@@ -14,7 +14,7 @@
 #include <string.h>  // memset
 
 #include <algorithm>  // min, max
-#include <limits>  // numeric_limits<T>
+#include <limits>     // numeric_limits<T>
 
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "modules/audio_coding/neteq/background_noise.h"
@@ -94,7 +94,6 @@
     GenerateRandomVector(2, rand_length, random_vector);
   }
 
-
   // Generate signal.
   UpdateLagIndex();
 
@@ -103,8 +102,8 @@
   size_t expansion_vector_length = max_lag_ + overlap_length_;
   size_t current_lag = expand_lags_[current_lag_index_];
   // Copy lag+overlap data.
-  size_t expansion_vector_position = expansion_vector_length - current_lag -
-      overlap_length_;
+  size_t expansion_vector_position =
+      expansion_vector_length - current_lag - overlap_length_;
   size_t temp_length = current_lag + overlap_length_;
   for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
     ChannelParameters& parameters = channel_parameters_[channel_ix];
@@ -175,8 +174,10 @@
         // Do overlap add between new vector and overlap.
         (*sync_buffer_)[channel_ix][start_ix + i] =
             (((*sync_buffer_)[channel_ix][start_ix + i] * muting_window) +
-                (((parameters.mute_factor * voiced_vector_storage[i]) >> 14) *
-                    unmuting_window) + 16384) >> 15;
+             (((parameters.mute_factor * voiced_vector_storage[i]) >> 14) *
+              unmuting_window) +
+             16384) >>
+            15;
         muting_window += muting_window_increment;
         unmuting_window += unmuting_window_increment;
       }
@@ -188,10 +189,10 @@
       // parameters.expand_vector0 and parameters.expand_vector1 no longer
       // match with expand_lags_, causing invalid reads and writes. Is it a good
       // idea to enable this again, and solve the vector size problem?
-//      max_lag_ = fs_mult * 120;
-//      expand_lags_[0] = fs_mult * 120;
-//      expand_lags_[1] = fs_mult * 120;
-//      expand_lags_[2] = fs_mult * 120;
+      //      max_lag_ = fs_mult * 120;
+      //      expand_lags_[0] = fs_mult * 120;
+      //      expand_lags_[1] = fs_mult * 120;
+      //      expand_lags_[2] = fs_mult * 120;
     }
 
     // Unvoiced part.
@@ -204,8 +205,7 @@
     }
     WebRtcSpl_AffineTransformVector(scaled_random_vector, random_vector,
                                     parameters.ar_gain, add_constant,
-                                    parameters.ar_gain_scale,
-                                    current_lag);
+                                    parameters.ar_gain_scale, current_lag);
     WebRtcSpl_FilterARFastQ12(scaled_random_vector, unvoiced_vector,
                               parameters.ar_filter, kUnvoicedLpcOrder + 1,
                               current_lag);
@@ -230,8 +230,9 @@
 
     // Create combined signal by shifting in more and more of unvoiced part.
     temp_shift = 8 - temp_shift;  // = getbits(mix_factor_increment).
-    size_t temp_length = (parameters.current_voice_mix_factor -
-        parameters.voice_mix_factor) >> temp_shift;
+    size_t temp_length =
+        (parameters.current_voice_mix_factor - parameters.voice_mix_factor) >>
+        temp_shift;
     temp_length = std::min(temp_length, current_lag);
     DspHelper::CrossFade(voiced_vector, unvoiced_vector, temp_length,
                          &parameters.current_voice_mix_factor,
@@ -266,9 +267,8 @@
     // Mute segment according to slope value.
     if ((consecutive_expands_ != 0) || !parameters.onset) {
       // Mute to the previous level, then continue with the muting.
-      WebRtcSpl_AffineTransformVector(temp_data, temp_data,
-                                      parameters.mute_factor, 8192,
-                                      14, current_lag);
+      WebRtcSpl_AffineTransformVector(
+          temp_data, temp_data, parameters.mute_factor, 8192, 14, current_lag);
 
       if (!stop_muting_) {
         DspHelper::MuteSignal(temp_data, parameters.mute_slope, current_lag);
@@ -276,8 +276,8 @@
         // Shift by 6 to go from Q20 to Q14.
         // TODO(hlundin): Adding 8192 before shifting 6 steps seems wrong.
         // Legacy.
-        int16_t gain = static_cast<int16_t>(16384 -
-            (((current_lag * parameters.mute_slope) + 8192) >> 6));
+        int16_t gain = static_cast<int16_t>(
+            16384 - (((current_lag * parameters.mute_slope) + 8192) >> 6));
         gain = ((gain * parameters.mute_factor) + 8192) >> 14;
 
         // Guard against getting stuck with very small (but sometimes audible)
@@ -291,12 +291,9 @@
     }
 
     // Background noise part.
-    GenerateBackgroundNoise(random_vector,
-                            channel_ix,
-                            channel_parameters_[channel_ix].mute_slope,
-                            TooManyExpands(),
-                            current_lag,
-                            unvoiced_array_memory);
+    GenerateBackgroundNoise(
+        random_vector, channel_ix, channel_parameters_[channel_ix].mute_slope,
+        TooManyExpands(), current_lag, unvoiced_array_memory);
 
     // Add background noise to the combined voiced-unvoiced signal.
     for (size_t i = 0; i < current_lag; i++) {
@@ -311,8 +308,9 @@
   }
 
   // Increase call number and cap it.
-  consecutive_expands_ = consecutive_expands_ >= kMaxConsecutiveExpands ?
-      kMaxConsecutiveExpands : consecutive_expands_ + 1;
+  consecutive_expands_ = consecutive_expands_ >= kMaxConsecutiveExpands
+                             ? kMaxConsecutiveExpands
+                             : consecutive_expands_ + 1;
   expand_duration_samples_ += output->Size();
   // Clamp the duration counter at 2 seconds.
   expand_duration_samples_ = std::min(expand_duration_samples_,
@@ -329,7 +327,7 @@
 }
 
 void Expand::SetParametersForMergeAfterExpand() {
-  current_lag_index_ = -1; /* out of the 3 possible ones */
+  current_lag_index_ = -1;  /* out of the 3 possible ones */
   lag_index_direction_ = 1; /* make sure we get the "optimal" lag */
   stop_muting_ = true;
 }
@@ -357,7 +355,7 @@
   consecutive_expands_ = 0;
   for (size_t ix = 0; ix < num_channels_; ++ix) {
     channel_parameters_[ix].current_voice_mix_factor = 16384;  // 1.0 in Q14.
-    channel_parameters_[ix].mute_factor = 16384;  // 1.0 in Q14.
+    channel_parameters_[ix].mute_factor = 16384;               // 1.0 in Q14.
     // Start with 0 gain for background noise.
     background_noise_->SetMuteFactor(ix, 0);
   }
@@ -420,10 +418,10 @@
   // Calculate distortion around the |kNumCorrelationCandidates| best lags.
   int distortion_scale = 0;
   for (size_t i = 0; i < kNumCorrelationCandidates; i++) {
-    size_t min_index = std::max(fs_mult_20,
-                                best_correlation_index[i] - fs_mult_4);
-    size_t max_index = std::min(fs_mult_120 - 1,
-                                best_correlation_index[i] + fs_mult_4);
+    size_t min_index =
+        std::max(fs_mult_20, best_correlation_index[i] - fs_mult_4);
+    size_t max_index =
+        std::min(fs_mult_120 - 1, best_correlation_index[i] + fs_mult_4);
     best_distortion_index[i] = DspHelper::MinDistortion(
         &(audio_history[signal_length - fs_mult_dist_len]), min_index,
         max_index, fs_mult_dist_len, &best_distortion_w32[i]);
@@ -459,23 +457,23 @@
 
   // Calculate the exact best correlation in the range between
   // |correlation_lag| and |distortion_lag|.
-  correlation_length =
-      std::max(std::min(distortion_lag + 10, fs_mult_120),
-               static_cast<size_t>(60 * fs_mult));
+  correlation_length = std::max(std::min(distortion_lag + 10, fs_mult_120),
+                                static_cast<size_t>(60 * fs_mult));
 
   size_t start_index = std::min(distortion_lag, correlation_lag);
   size_t correlation_lags = static_cast<size_t>(
-      WEBRTC_SPL_ABS_W16((distortion_lag-correlation_lag)) + 1);
+      WEBRTC_SPL_ABS_W16((distortion_lag - correlation_lag)) + 1);
   assert(correlation_lags <= static_cast<size_t>(99 * fs_mult + 1));
 
   for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
     ChannelParameters& parameters = channel_parameters_[channel_ix];
     // Calculate suitable scaling.
     int16_t signal_max = WebRtcSpl_MaxAbsValueW16(
-        &audio_history[signal_length - correlation_length - start_index
-                       - correlation_lags],
-                       correlation_length + start_index + correlation_lags - 1);
-    int correlation_scale = (31 - WebRtcSpl_NormW32(signal_max * signal_max)) +
+        &audio_history[signal_length - correlation_length - start_index -
+                       correlation_lags],
+        correlation_length + start_index + correlation_lags - 1);
+    int correlation_scale =
+        (31 - WebRtcSpl_NormW32(signal_max * signal_max)) +
         (31 - WebRtcSpl_NormW32(static_cast<int32_t>(correlation_length))) - 31;
     correlation_scale = std::max(0, correlation_scale);
 
@@ -520,8 +518,8 @@
       // Calculate max_correlation / sqrt(energy1 * energy2) in Q14.
       int cc_shift = 14 - (energy1_scale + energy2_scale) / 2;
       max_correlation = WEBRTC_SPL_SHIFT_W32(max_correlation, cc_shift);
-      corr_coefficient = WebRtcSpl_DivW32W16(max_correlation,
-                                             sqrt_energy_product);
+      corr_coefficient =
+          WebRtcSpl_DivW32W16(max_correlation, sqrt_energy_product);
       // Cap at 1.0 in Q14.
       corr_coefficient = std::min(16384, corr_coefficient);
     } else {
@@ -547,9 +545,9 @@
       int32_t scaled_energy2 = std::max(16 - WebRtcSpl_NormW32(energy2), 0);
       int32_t scaled_energy1 = scaled_energy2 - 13;
       // Calculate scaled_energy1 / scaled_energy2 in Q13.
-      int32_t energy_ratio = WebRtcSpl_DivW32W16(
-          WEBRTC_SPL_SHIFT_W32(energy1, -scaled_energy1),
-          static_cast<int16_t>(energy2 >> scaled_energy2));
+      int32_t energy_ratio =
+          WebRtcSpl_DivW32W16(WEBRTC_SPL_SHIFT_W32(energy1, -scaled_energy1),
+                              static_cast<int16_t>(energy2 >> scaled_energy2));
       // Calculate sqrt ratio in Q13 (sqrt of en1/en2 in Q26).
       amplitude_ratio =
           static_cast<int16_t>(WebRtcSpl_SqrtFloor(energy_ratio << 13));
@@ -558,16 +556,13 @@
       parameters.expand_vector0.PushBack(vector1, expansion_length);
       parameters.expand_vector1.Clear();
       if (parameters.expand_vector1.Size() < expansion_length) {
-        parameters.expand_vector1.Extend(
-            expansion_length - parameters.expand_vector1.Size());
+        parameters.expand_vector1.Extend(expansion_length -
+                                         parameters.expand_vector1.Size());
       }
       std::unique_ptr<int16_t[]> temp_1(new int16_t[expansion_length]);
-      WebRtcSpl_AffineTransformVector(temp_1.get(),
-                                      const_cast<int16_t*>(vector2),
-                                      amplitude_ratio,
-                                      4096,
-                                      13,
-                                      expansion_length);
+      WebRtcSpl_AffineTransformVector(
+          temp_1.get(), const_cast<int16_t*>(vector2), amplitude_ratio, 4096,
+          13, expansion_length);
       parameters.expand_vector1.OverwriteAt(temp_1.get(), expansion_length, 0);
     } else {
       // Energy change constraint not fulfilled. Only use last vector.
@@ -606,11 +601,11 @@
     // Calculate the LPC and the gain of the filters.
 
     // Calculate kUnvoicedLpcOrder + 1 lags of the auto-correlation function.
-    size_t temp_index = signal_length - fs_mult_lpc_analysis_len -
-        kUnvoicedLpcOrder;
+    size_t temp_index =
+        signal_length - fs_mult_lpc_analysis_len - kUnvoicedLpcOrder;
     // Copy signal to temporary vector to be able to pad with leading zeros.
-    int16_t* temp_signal = new int16_t[fs_mult_lpc_analysis_len
-                                       + kUnvoicedLpcOrder];
+    int16_t* temp_signal =
+        new int16_t[fs_mult_lpc_analysis_len + kUnvoicedLpcOrder];
     memset(temp_signal, 0,
            sizeof(int16_t) * (fs_mult_lpc_analysis_len + kUnvoicedLpcOrder));
     memcpy(&temp_signal[kUnvoicedLpcOrder],
@@ -619,16 +614,15 @@
     CrossCorrelationWithAutoShift(
         &temp_signal[kUnvoicedLpcOrder], &temp_signal[kUnvoicedLpcOrder],
         fs_mult_lpc_analysis_len, kUnvoicedLpcOrder + 1, -1, auto_correlation);
-    delete [] temp_signal;
+    delete[] temp_signal;
 
     // Verify that variance is positive.
     if (auto_correlation[0] > 0) {
       // Estimate AR filter parameters using Levinson-Durbin algorithm;
       // kUnvoicedLpcOrder + 1 filter coefficients.
-      int16_t stability = WebRtcSpl_LevinsonDurbin(auto_correlation,
-                                                   parameters.ar_filter,
-                                                   reflection_coeff,
-                                                   kUnvoicedLpcOrder);
+      int16_t stability =
+          WebRtcSpl_LevinsonDurbin(auto_correlation, parameters.ar_filter,
+                                   reflection_coeff, kUnvoicedLpcOrder);
 
       // Keep filter parameters only if filter is stable.
       if (stability != 1) {
@@ -671,10 +665,8 @@
            &(audio_history[signal_length - 128 - kUnvoicedLpcOrder]),
            sizeof(int16_t) * kUnvoicedLpcOrder);
     WebRtcSpl_FilterMAFastQ12(&audio_history[signal_length - 128],
-                              unvoiced_vector,
-                              parameters.ar_filter,
-                              kUnvoicedLpcOrder + 1,
-                              128);
+                              unvoiced_vector, parameters.ar_filter,
+                              kUnvoicedLpcOrder + 1, 128);
     const int unvoiced_max_abs = [&] {
       const int16_t max_abs = WebRtcSpl_MaxAbsValueW16(unvoiced_vector, 128);
       // Since WebRtcSpl_MaxAbsValueW16 returns 2^15 - 1 when the input contains
@@ -689,10 +681,8 @@
     int unvoiced_prescale =
         std::max(0, 2 * WebRtcSpl_GetSizeInBits(unvoiced_max_abs) - 24);
 
-    int32_t unvoiced_energy = WebRtcSpl_DotProductWithScale(unvoiced_vector,
-                                                            unvoiced_vector,
-                                                            128,
-                                                            unvoiced_prescale);
+    int32_t unvoiced_energy = WebRtcSpl_DotProductWithScale(
+        unvoiced_vector, unvoiced_vector, 128, unvoiced_prescale);
 
     // Normalize |unvoiced_energy| to 28 or 29 bits to preserve sqrt() accuracy.
     int16_t unvoiced_scale = WebRtcSpl_NormW32(unvoiced_energy) - 3;
@@ -703,8 +693,8 @@
     unvoiced_energy = WEBRTC_SPL_SHIFT_W32(unvoiced_energy, unvoiced_scale);
     int16_t unvoiced_gain =
         static_cast<int16_t>(WebRtcSpl_SqrtFloor(unvoiced_energy));
-    parameters.ar_gain_scale = 13
-        + (unvoiced_scale + 7 - unvoiced_prescale) / 2;
+    parameters.ar_gain_scale =
+        13 + (unvoiced_scale + 7 - unvoiced_prescale) / 2;
     parameters.ar_gain = unvoiced_gain;
 
     // Calculate voice_mix_factor from corr_coefficient.
@@ -717,17 +707,17 @@
       int16_t x1, x2, x3;
       // |corr_coefficient| is in Q14.
       x1 = static_cast<int16_t>(corr_coefficient);
-      x2 = (x1 * x1) >> 14;   // Shift 14 to keep result in Q14.
+      x2 = (x1 * x1) >> 14;  // Shift 14 to keep result in Q14.
       x3 = (x1 * x2) >> 14;
-      static const int kCoefficients[4] = { -5179, 19931, -16422, 5776 };
+      static const int kCoefficients[4] = {-5179, 19931, -16422, 5776};
       int32_t temp_sum = kCoefficients[0] * 16384;
       temp_sum += kCoefficients[1] * x1;
       temp_sum += kCoefficients[2] * x2;
       temp_sum += kCoefficients[3] * x3;
       parameters.voice_mix_factor =
           static_cast<int16_t>(std::min(temp_sum / 4096, 16384));
-      parameters.voice_mix_factor = std::max(parameters.voice_mix_factor,
-                                             static_cast<int16_t>(0));
+      parameters.voice_mix_factor =
+          std::max(parameters.voice_mix_factor, static_cast<int16_t>(0));
     } else {
       parameters.voice_mix_factor = 0;
     }
@@ -743,9 +733,9 @@
       // the division.
       // Shift the denominator from Q13 to Q5 before the division. The result of
       // the division will then be in Q20.
-      int temp_ratio = WebRtcSpl_DivW32W16(
-          (slope - 8192) << 12,
-          static_cast<int16_t>((distortion_lag * slope) >> 8));
+      int16_t denom =
+          rtc::saturated_cast<int16_t>((distortion_lag * slope) >> 8);
+      int temp_ratio = WebRtcSpl_DivW32W16((slope - 8192) << 12, denom);
       if (slope > 14746) {
         // slope > 1.8.
         // Divide by 2, with proper rounding.
@@ -816,8 +806,8 @@
   static const size_t kNumCorrelationLags = 54;
   static const size_t kCorrelationLength = 60;
   // Downsample to 4 kHz sample rate.
-  static const size_t kDownsampledLength = kCorrelationStartLag
-      + kNumCorrelationLags + kCorrelationLength;
+  static const size_t kDownsampledLength =
+      kCorrelationStartLag + kNumCorrelationLags + kCorrelationLength;
   int16_t downsampled_input[kDownsampledLength];
   static const size_t kFilterDelay = 0;
   WebRtcSpl_DownsampleFast(
@@ -827,8 +817,8 @@
       downsampling_factor, kFilterDelay);
 
   // Normalize |downsampled_input| to using all 16 bits.
-  int16_t max_value = WebRtcSpl_MaxAbsValueW16(downsampled_input,
-                                               kDownsampledLength);
+  int16_t max_value =
+      WebRtcSpl_MaxAbsValueW16(downsampled_input, kDownsampledLength);
   int16_t norm_shift = 16 - WebRtcSpl_NormW32(max_value);
   WebRtcSpl_VectorBitShiftW16(downsampled_input, kDownsampledLength,
                               downsampled_input, norm_shift);
@@ -836,13 +826,13 @@
   int32_t correlation[kNumCorrelationLags];
   CrossCorrelationWithAutoShift(
       &downsampled_input[kDownsampledLength - kCorrelationLength],
-      &downsampled_input[kDownsampledLength - kCorrelationLength
-          - kCorrelationStartLag],
+      &downsampled_input[kDownsampledLength - kCorrelationLength -
+                         kCorrelationStartLag],
       kCorrelationLength, kNumCorrelationLags, -1, correlation);
 
   // Normalize and move data from 32-bit to 16-bit vector.
-  int32_t max_correlation = WebRtcSpl_MaxAbsValueW32(correlation,
-                                                     kNumCorrelationLags);
+  int32_t max_correlation =
+      WebRtcSpl_MaxAbsValueW32(correlation, kNumCorrelationLags);
   int16_t norm_shift2 = static_cast<int16_t>(
       std::max(18 - WebRtcSpl_NormW32(max_correlation), 0));
   WebRtcSpl_VectorBitShiftW32ToW16(output, kNumCorrelationLags, correlation,
@@ -894,19 +884,15 @@
 
     // Scale random vector to correct energy level.
     WebRtcSpl_AffineTransformVector(
-        scaled_random_vector, random_vector,
-        background_noise_->Scale(channel), dc_offset,
-        background_noise_->ScaleShift(channel),
-        num_noise_samples);
+        scaled_random_vector, random_vector, background_noise_->Scale(channel),
+        dc_offset, background_noise_->ScaleShift(channel), num_noise_samples);
 
     WebRtcSpl_FilterARFastQ12(scaled_random_vector, noise_samples,
                               background_noise_->Filter(channel),
-                              kNoiseLpcOrder + 1,
-                              num_noise_samples);
+                              kNoiseLpcOrder + 1, num_noise_samples);
 
     background_noise_->SetFilterState(
-        channel,
-        &(noise_samples[num_noise_samples - kNoiseLpcOrder]),
+        channel, &(noise_samples[num_noise_samples - kNoiseLpcOrder]),
         kNoiseLpcOrder);
 
     // Unmute the background noise.
diff --git a/modules/audio_coding/neteq/expand.h b/modules/audio_coding/neteq/expand.h
index 39249f1..2fd4fae 100644
--- a/modules/audio_coding/neteq/expand.h
+++ b/modules/audio_coding/neteq/expand.h
@@ -57,7 +57,7 @@
   virtual void SetParametersForMergeAfterExpand();
 
   // Returns the mute factor for |channel|.
-  int16_t MuteFactor(size_t channel) {
+  int16_t MuteFactor(size_t channel) const {
     assert(channel < num_channels_);
     return channel_parameters_[channel].mute_factor;
   }
@@ -114,7 +114,7 @@
     int16_t ar_filter_state[kUnvoicedLpcOrder];
     int16_t ar_gain;
     int16_t ar_gain_scale;
-    int16_t voice_mix_factor; /* Q14 */
+    int16_t voice_mix_factor;         /* Q14 */
     int16_t current_voice_mix_factor; /* Q14 */
     AudioVector expand_vector0;
     AudioVector expand_vector1;
diff --git a/modules/audio_coding/neteq/expand_uma_logger.cc b/modules/audio_coding/neteq/expand_uma_logger.cc
index c656eed..01c2dab 100644
--- a/modules/audio_coding/neteq/expand_uma_logger.cc
+++ b/modules/audio_coding/neteq/expand_uma_logger.cc
@@ -45,7 +45,7 @@
   last_value_ = samples;
   sample_rate_hz_ = sample_rate_hz;
   if (!last_logged_value_) {
-    last_logged_value_ = rtc::Optional<uint64_t>(samples);
+    last_logged_value_ = absl::optional<uint64_t>(samples);
   }
 
   if (!timer_->Finished()) {
@@ -56,7 +56,7 @@
   RTC_DCHECK(last_logged_value_);
   RTC_DCHECK_GE(last_value_, *last_logged_value_);
   const uint64_t diff = last_value_ - *last_logged_value_;
-  last_logged_value_ = rtc::Optional<uint64_t>(last_value_);
+  last_logged_value_ = absl::optional<uint64_t>(last_value_);
   // Calculate rate in percent.
   RTC_DCHECK_GT(sample_rate_hz, 0);
   const int rate = (100 * diff) / (sample_rate_hz * logging_period_s_);
diff --git a/modules/audio_coding/neteq/expand_uma_logger.h b/modules/audio_coding/neteq/expand_uma_logger.h
index 70af39b..00907d4 100644
--- a/modules/audio_coding/neteq/expand_uma_logger.h
+++ b/modules/audio_coding/neteq/expand_uma_logger.h
@@ -13,7 +13,7 @@
 #include <memory>
 #include <string>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_coding/neteq/tick_timer.h"
 #include "rtc_base/constructormagic.h"
 
@@ -43,7 +43,7 @@
   const int logging_period_s_;
   const TickTimer& tick_timer_;
   std::unique_ptr<TickTimer::Countdown> timer_;
-  rtc::Optional<uint64_t> last_logged_value_;
+  absl::optional<uint64_t> last_logged_value_;
   uint64_t last_value_ = 0;
   int sample_rate_hz_ = 0;
 
diff --git a/modules/audio_coding/neteq/include/neteq.h b/modules/audio_coding/neteq/include/neteq.h
index 310a227..ce1448a 100644
--- a/modules/audio_coding/neteq/include/neteq.h
+++ b/modules/audio_coding/neteq/include/neteq.h
@@ -16,9 +16,9 @@
 #include <string>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio_codecs/audio_codec_pair_id.h"
 #include "api/audio_codecs/audio_decoder.h"
-#include "api/optional.h"
 #include "api/rtp_headers.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/neteq/neteq_decoder_enum.h"
@@ -33,25 +33,25 @@
 class AudioDecoderFactory;
 
 struct NetEqNetworkStatistics {
-  uint16_t current_buffer_size_ms;  // Current jitter buffer size in ms.
+  uint16_t current_buffer_size_ms;    // Current jitter buffer size in ms.
   uint16_t preferred_buffer_size_ms;  // Target buffer size in ms.
-  uint16_t jitter_peaks_found;  // 1 if adding extra delay due to peaky
-                                // jitter; 0 otherwise.
-  uint16_t packet_loss_rate;  // Loss rate (network + late) in Q14.
-  uint16_t expand_rate;  // Fraction (of original stream) of synthesized
-                         // audio inserted through expansion (in Q14).
+  uint16_t jitter_peaks_found;        // 1 if adding extra delay due to peaky
+                                      // jitter; 0 otherwise.
+  uint16_t packet_loss_rate;          // Loss rate (network + late) in Q14.
+  uint16_t expand_rate;         // Fraction (of original stream) of synthesized
+                                // audio inserted through expansion (in Q14).
   uint16_t speech_expand_rate;  // Fraction (of original stream) of synthesized
                                 // speech inserted through expansion (in Q14).
-  uint16_t preemptive_rate;  // Fraction of data inserted through pre-emptive
-                             // expansion (in Q14).
-  uint16_t accelerate_rate;  // Fraction of data removed through acceleration
-                             // (in Q14).
-  uint16_t secondary_decoded_rate;  // Fraction of data coming from FEC/RED
-                                    // decoding (in Q14).
+  uint16_t preemptive_rate;     // Fraction of data inserted through pre-emptive
+                                // expansion (in Q14).
+  uint16_t accelerate_rate;     // Fraction of data removed through acceleration
+                                // (in Q14).
+  uint16_t secondary_decoded_rate;    // Fraction of data coming from FEC/RED
+                                      // decoding (in Q14).
   uint16_t secondary_discarded_rate;  // Fraction of discarded FEC/RED data (in
                                       // Q14).
-  int32_t clockdrift_ppm;  // Average clock-drift in parts-per-million
-                           // (positive or negative).
+  int32_t clockdrift_ppm;     // Average clock-drift in parts-per-million
+                              // (positive or negative).
   size_t added_zero_samples;  // Number of zero samples added in "off" mode.
   // Statistics for packet waiting times, i.e., the time between a packet
   // arrives until it is decoded.
@@ -74,13 +74,6 @@
   uint64_t voice_concealed_samples = 0;
 };
 
-enum NetEqPlayoutMode {
-  kPlayoutOn,
-  kPlayoutOff,
-  kPlayoutFax,
-  kPlayoutStreaming
-};
-
 // This is the interface class for NetEq.
 class NetEq {
  public:
@@ -98,17 +91,13 @@
     bool enable_post_decode_vad = false;
     size_t max_packets_in_buffer = 50;
     int max_delay_ms = 2000;
-    NetEqPlayoutMode playout_mode = kPlayoutOn;
     bool enable_fast_accelerate = false;
     bool enable_muted_state = false;
-    rtc::Optional<AudioCodecPairId> codec_pair_id;
+    absl::optional<AudioCodecPairId> codec_pair_id;
+    bool for_test_no_time_stretching = false;  // Use only for testing.
   };
 
-  enum ReturnCodes {
-    kOK = 0,
-    kFail = -1,
-    kNotImplemented = -2
-  };
+  enum ReturnCodes { kOK = 0, kFail = -1, kNotImplemented = -2 };
 
   // Creates a new NetEq object, with parameters set in |config|. The |config|
   // object will only have to be valid for the duration of the call to this
@@ -213,16 +202,6 @@
   // The packet buffer part of the delay is not updated during DTX/CNG periods.
   virtual int FilteredCurrentDelayMs() const = 0;
 
-  // Sets the playout mode to |mode|.
-  // Deprecated. Set the mode in the Config struct passed to the constructor.
-  // TODO(henrik.lundin) Delete.
-  virtual void SetPlayoutMode(NetEqPlayoutMode mode) = 0;
-
-  // Returns the current playout mode.
-  // Deprecated.
-  // TODO(henrik.lundin) Delete.
-  virtual NetEqPlayoutMode PlayoutMode() const = 0;
-
   // Writes the current network statistics to |stats|. The statistics are reset
   // after the call.
   virtual int NetworkStatistics(NetEqNetworkStatistics* stats) = 0;
@@ -247,7 +226,7 @@
 
   // Returns the RTP timestamp for the last sample delivered by GetAudio().
   // The return value will be empty if no valid timestamp is available.
-  virtual rtc::Optional<uint32_t> GetPlayoutTimestamp() const = 0;
+  virtual absl::optional<uint32_t> GetPlayoutTimestamp() const = 0;
 
   // Returns the sample rate in Hz of the audio produced in the last GetAudio
   // call. If GetAudio has not been called yet, the configured sample rate
@@ -256,11 +235,11 @@
 
   // Returns info about the decoder for the given payload type, or an empty
   // value if we have no decoder for that payload type.
-  virtual rtc::Optional<CodecInst> GetDecoder(int payload_type) const = 0;
+  virtual absl::optional<CodecInst> GetDecoder(int payload_type) const = 0;
 
   // Returns the decoder format for the given payload type. Returns empty if no
   // such payload type was registered.
-  virtual rtc::Optional<SdpAudioFormat> GetDecoderFormat(
+  virtual absl::optional<SdpAudioFormat> GetDecoderFormat(
       int payload_type) const = 0;
 
   // Not implemented.
diff --git a/modules/audio_coding/neteq/merge.cc b/modules/audio_coding/neteq/merge.cc
index b568ff0..3c9ad19 100644
--- a/modules/audio_coding/neteq/merge.cc
+++ b/modules/audio_coding/neteq/merge.cc
@@ -43,11 +43,11 @@
 
 Merge::~Merge() = default;
 
-size_t Merge::Process(int16_t* input, size_t input_length,
-                      int16_t* external_mute_factor_array,
+size_t Merge::Process(int16_t* input,
+                      size_t input_length,
                       AudioMultiVector* output) {
   // TODO(hlundin): Change to an enumerator and skip assert.
-  assert(fs_hz_ == 8000 || fs_hz_ == 16000 || fs_hz_ ==  32000 ||
+  assert(fs_hz_ == 8000 || fs_hz_ == 16000 || fs_hz_ == 32000 ||
          fs_hz_ == 48000);
   assert(fs_hz_ <= kMaxSampleRate);  // Should not be possible.
 
@@ -69,24 +69,13 @@
       new int16_t[input_length_per_channel]);
   std::unique_ptr<int16_t[]> expanded_channel(new int16_t[expanded_length]);
   for (size_t channel = 0; channel < num_channels_; ++channel) {
-    input_vector[channel].CopyTo(
-        input_length_per_channel, 0, input_channel.get());
+    input_vector[channel].CopyTo(input_length_per_channel, 0,
+                                 input_channel.get());
     expanded_[channel].CopyTo(expanded_length, 0, expanded_channel.get());
 
-    int16_t new_mute_factor = SignalScaling(
-        input_channel.get(), input_length_per_channel, expanded_channel.get());
-
-    // Adjust muting factor (product of "main" muting factor and expand muting
-    // factor).
-    int16_t* external_mute_factor = &external_mute_factor_array[channel];
-    *external_mute_factor =
-        (*external_mute_factor * expand_->MuteFactor(channel)) >> 14;
-
-    // Update |external_mute_factor| if it is lower than |new_mute_factor|.
-    if (new_mute_factor > *external_mute_factor) {
-      *external_mute_factor = std::min(new_mute_factor,
-                                       static_cast<int16_t>(16384));
-    }
+    const int16_t new_mute_factor = std::min<int16_t>(
+        16384, SignalScaling(input_channel.get(), input_length_per_channel,
+                             expanded_channel.get()));
 
     if (channel == 0) {
       // Downsample, correlate, and find strongest correlation period for the
@@ -105,23 +94,29 @@
 
     // Mute the new decoded data if needed (and unmute it linearly).
     // This is the overlapping part of expanded_signal.
-    size_t interpolation_length = std::min(
-        kMaxCorrelationLength * fs_mult_,
-        expanded_length - best_correlation_index);
-    interpolation_length = std::min(interpolation_length,
-                                    input_length_per_channel);
-    if (*external_mute_factor < 16384) {
+    size_t interpolation_length =
+        std::min(kMaxCorrelationLength * fs_mult_,
+                 expanded_length - best_correlation_index);
+    interpolation_length =
+        std::min(interpolation_length, input_length_per_channel);
+
+    RTC_DCHECK_LE(new_mute_factor, 16384);
+    int16_t mute_factor =
+        std::max(expand_->MuteFactor(channel), new_mute_factor);
+    RTC_DCHECK_GE(mute_factor, 0);
+
+    if (mute_factor < 16384) {
       // Set a suitable muting slope (Q20). 0.004 for NB, 0.002 for WB,
-      // and so on.
-      int increment = 4194 / fs_mult_;
-      *external_mute_factor =
-          static_cast<int16_t>(DspHelper::RampSignal(input_channel.get(),
-                                                     interpolation_length,
-                                                     *external_mute_factor,
-                                                     increment));
+      // and so on, or as fast as it takes to come back to full gain within the
+      // frame length.
+      const int back_to_fullscale_inc = static_cast<int>(
+          ((16384 - mute_factor) << 6) / input_length_per_channel);
+      const int increment = std::max(4194 / fs_mult_, back_to_fullscale_inc);
+      mute_factor = static_cast<int16_t>(DspHelper::RampSignal(
+          input_channel.get(), interpolation_length, mute_factor, increment));
       DspHelper::UnmuteSignal(&input_channel[interpolation_length],
                               input_length_per_channel - interpolation_length,
-                              external_mute_factor, increment,
+                              &mute_factor, increment,
                               &decoded_output[interpolation_length]);
     } else {
       // No muting needed.
@@ -134,12 +129,12 @@
     // Do overlap and mix linearly.
     int16_t increment =
         static_cast<int16_t>(16384 / (interpolation_length + 1));  // In Q14.
-    int16_t mute_factor = 16384 - increment;
+    int16_t local_mute_factor = 16384 - increment;
     memmove(temp_data_.data(), expanded_channel.get(),
             sizeof(int16_t) * best_correlation_index);
     DspHelper::CrossFade(&expanded_channel[best_correlation_index],
                          input_channel.get(), interpolation_length,
-                         &mute_factor, increment, decoded_output);
+                         &local_mute_factor, increment, decoded_output);
 
     output_length = best_correlation_index + input_length_per_channel;
     if (channel == 0) {
@@ -209,30 +204,28 @@
   return required_length;
 }
 
-int16_t Merge::SignalScaling(const int16_t* input, size_t input_length,
+int16_t Merge::SignalScaling(const int16_t* input,
+                             size_t input_length,
                              const int16_t* expanded_signal) const {
   // Adjust muting factor if new vector is more or less of the BGN energy.
   const auto mod_input_length = rtc::SafeMin<size_t>(
       64 * rtc::dchecked_cast<size_t>(fs_mult_), input_length);
   const int16_t expanded_max =
       WebRtcSpl_MaxAbsValueW16(expanded_signal, mod_input_length);
-  int32_t factor = (expanded_max * expanded_max) /
-      (std::numeric_limits<int32_t>::max() /
-          static_cast<int32_t>(mod_input_length));
+  int32_t factor =
+      (expanded_max * expanded_max) / (std::numeric_limits<int32_t>::max() /
+                                       static_cast<int32_t>(mod_input_length));
   const int expanded_shift = factor == 0 ? 0 : 31 - WebRtcSpl_NormW32(factor);
-  int32_t energy_expanded = WebRtcSpl_DotProductWithScale(expanded_signal,
-                                                          expanded_signal,
-                                                          mod_input_length,
-                                                          expanded_shift);
+  int32_t energy_expanded = WebRtcSpl_DotProductWithScale(
+      expanded_signal, expanded_signal, mod_input_length, expanded_shift);
 
   // Calculate energy of input signal.
   const int16_t input_max = WebRtcSpl_MaxAbsValueW16(input, mod_input_length);
   factor = (input_max * input_max) / (std::numeric_limits<int32_t>::max() /
-      static_cast<int32_t>(mod_input_length));
+                                      static_cast<int32_t>(mod_input_length));
   const int input_shift = factor == 0 ? 0 : 31 - WebRtcSpl_NormW32(factor);
-  int32_t energy_input = WebRtcSpl_DotProductWithScale(input, input,
-                                                       mod_input_length,
-                                                       input_shift);
+  int32_t energy_input = WebRtcSpl_DotProductWithScale(
+      input, input, mod_input_length, input_shift);
 
   // Align to the same Q-domain.
   if (input_shift > expanded_shift) {
@@ -263,8 +256,10 @@
 
 // TODO(hlundin): There are some parameter values in this method that seem
 // strange. Compare with Expand::Correlation.
-void Merge::Downsample(const int16_t* input, size_t input_length,
-                       const int16_t* expanded_signal, size_t expanded_length) {
+void Merge::Downsample(const int16_t* input,
+                       size_t input_length,
+                       const int16_t* expanded_signal,
+                       size_t expanded_length) {
   const int16_t* filter_coefficients;
   size_t num_coefficients;
   int decimation_factor = fs_hz_ / 4000;
@@ -284,11 +279,10 @@
     num_coefficients = 7;
   }
   size_t signal_offset = num_coefficients - 1;
-  WebRtcSpl_DownsampleFast(&expanded_signal[signal_offset],
-                           expanded_length - signal_offset,
-                           expanded_downsampled_, kExpandDownsampLength,
-                           filter_coefficients, num_coefficients,
-                           decimation_factor, kCompensateDelay);
+  WebRtcSpl_DownsampleFast(
+      &expanded_signal[signal_offset], expanded_length - signal_offset,
+      expanded_downsampled_, kExpandDownsampLength, filter_coefficients,
+      num_coefficients, decimation_factor, kCompensateDelay);
   if (input_length <= length_limit) {
     // Not quite long enough, so we have to cheat a bit.
     // If the input is really short, we'll just use the input length as is, and
@@ -307,15 +301,15 @@
     memset(&input_downsampled_[downsamp_temp_len], 0,
            sizeof(int16_t) * (kInputDownsampLength - downsamp_temp_len));
   } else {
-    WebRtcSpl_DownsampleFast(&input[signal_offset],
-                             input_length - signal_offset, input_downsampled_,
-                             kInputDownsampLength, filter_coefficients,
-                             num_coefficients, decimation_factor,
-                             kCompensateDelay);
+    WebRtcSpl_DownsampleFast(
+        &input[signal_offset], input_length - signal_offset, input_downsampled_,
+        kInputDownsampLength, filter_coefficients, num_coefficients,
+        decimation_factor, kCompensateDelay);
   }
 }
 
-size_t Merge::CorrelateAndPeakSearch(size_t start_position, size_t input_length,
+size_t Merge::CorrelateAndPeakSearch(size_t start_position,
+                                     size_t input_length,
                                      size_t expand_period) const {
   // Calculate correlation without any normalization.
   const size_t max_corr_length = kMaxCorrelationLength;
@@ -334,8 +328,8 @@
       new int16_t[correlation_buffer_size]);
   memset(correlation16.get(), 0, correlation_buffer_size * sizeof(int16_t));
   int16_t* correlation_ptr = &correlation16[pad_length];
-  int32_t max_correlation = WebRtcSpl_MaxAbsValueW32(correlation,
-                                                     stop_position_downsamp);
+  int32_t max_correlation =
+      WebRtcSpl_MaxAbsValueW32(correlation, stop_position_downsamp);
   int norm_shift = std::max(0, 17 - WebRtcSpl_NormW32(max_correlation));
   WebRtcSpl_VectorBitShiftW32ToW16(correlation_ptr, stop_position_downsamp,
                                    correlation, norm_shift);
@@ -372,7 +366,7 @@
   while (((best_correlation_index + input_length) <
           (timestamps_per_call_ + expand_->overlap_length())) ||
          ((best_correlation_index + input_length) < start_position)) {
-    assert(false);  // Should never happen.
+    assert(false);                            // Should never happen.
     best_correlation_index += expand_period;  // Jump one lag ahead.
   }
   return best_correlation_index;
@@ -382,5 +376,4 @@
   return fs_hz_ / 100 * num_channels_;  // 10 ms.
 }
 
-
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/merge.h b/modules/audio_coding/neteq/merge.h
index e027cd7..017e824 100644
--- a/modules/audio_coding/neteq/merge.h
+++ b/modules/audio_coding/neteq/merge.h
@@ -43,11 +43,9 @@
   // |input|, having |input_length| samples in total for all channels
   // (interleaved). The result is written to |output|. The number of channels
   // allocated in |output| defines the number of channels that will be used when
-  // de-interleaving |input|. The values in |external_mute_factor_array| (Q14)
-  // will be used to scale the audio, and is updated in the process. The array
-  // must have |num_channels_| elements.
-  virtual size_t Process(int16_t* input, size_t input_length,
-                         int16_t* external_mute_factor_array,
+  // de-interleaving |input|.
+  virtual size_t Process(int16_t* input,
+                         size_t input_length,
                          AudioMultiVector* output);
 
   virtual size_t RequiredFutureSamples();
@@ -71,19 +69,23 @@
 
   // Analyzes |input| and |expanded_signal| and returns muting factor (Q14) to
   // be used on the new data.
-  int16_t SignalScaling(const int16_t* input, size_t input_length,
+  int16_t SignalScaling(const int16_t* input,
+                        size_t input_length,
                         const int16_t* expanded_signal) const;
 
   // Downsamples |input| (|input_length| samples) and |expanded_signal| to
   // 4 kHz sample rate. The downsampled signals are written to
   // |input_downsampled_| and |expanded_downsampled_|, respectively.
-  void Downsample(const int16_t* input, size_t input_length,
-                  const int16_t* expanded_signal, size_t expanded_length);
+  void Downsample(const int16_t* input,
+                  size_t input_length,
+                  const int16_t* expanded_signal,
+                  size_t expanded_length);
 
   // Calculates cross-correlation between |input_downsampled_| and
   // |expanded_downsampled_|, and finds the correlation maximum. The maximizing
   // lag is returned.
-  size_t CorrelateAndPeakSearch(size_t start_position, size_t input_length,
+  size_t CorrelateAndPeakSearch(size_t start_position,
+                                size_t input_length,
                                 size_t expand_period) const;
 
   const int fs_mult_;  // fs_hz_ / 8000.
diff --git a/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h b/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h
index f662fb6..bf9fd59 100644
--- a/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h
+++ b/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h
@@ -20,17 +20,14 @@
 class MockBufferLevelFilter : public BufferLevelFilter {
  public:
   virtual ~MockBufferLevelFilter() { Die(); }
-  MOCK_METHOD0(Die,
-      void());
-  MOCK_METHOD0(Reset,
-      void());
+  MOCK_METHOD0(Die, void());
+  MOCK_METHOD0(Reset, void());
   MOCK_METHOD3(Update,
-      void(size_t buffer_size_packets, int time_stretched_samples,
-           size_t packet_len_samples));
-  MOCK_METHOD1(SetTargetBufferLevel,
-      void(int target_buffer_level));
-  MOCK_CONST_METHOD0(filtered_current_level,
-      int());
+               void(size_t buffer_size_packets,
+                    int time_stretched_samples,
+                    size_t packet_len_samples));
+  MOCK_METHOD1(SetTargetBufferLevel, void(int target_buffer_level));
+  MOCK_CONST_METHOD0(filtered_current_level, int());
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_decoder_database.h b/modules/audio_coding/neteq/mock/mock_decoder_database.h
index a4240ce..b1d8151 100644
--- a/modules/audio_coding/neteq/mock/mock_decoder_database.h
+++ b/modules/audio_coding/neteq/mock/mock_decoder_database.h
@@ -23,18 +23,16 @@
  public:
   explicit MockDecoderDatabase(
       rtc::scoped_refptr<AudioDecoderFactory> factory = nullptr)
-      : DecoderDatabase(factory, rtc::nullopt) {}
+      : DecoderDatabase(factory, absl::nullopt) {}
   virtual ~MockDecoderDatabase() { Die(); }
   MOCK_METHOD0(Die, void());
-  MOCK_CONST_METHOD0(Empty,
-      bool());
-  MOCK_CONST_METHOD0(Size,
-      int());
-  MOCK_METHOD0(Reset,
-      void());
+  MOCK_CONST_METHOD0(Empty, bool());
+  MOCK_CONST_METHOD0(Size, int());
+  MOCK_METHOD0(Reset, void());
   MOCK_METHOD3(RegisterPayload,
-      int(uint8_t rtp_payload_type, NetEqDecoder codec_type,
-          const std::string& name));
+               int(uint8_t rtp_payload_type,
+                   NetEqDecoder codec_type,
+                   const std::string& name));
   MOCK_METHOD2(RegisterPayload,
                int(int rtp_payload_type, const SdpAudioFormat& audio_format));
   MOCK_METHOD4(InsertExternal,
@@ -42,19 +40,15 @@
                    NetEqDecoder codec_type,
                    const std::string& codec_name,
                    AudioDecoder* decoder));
-  MOCK_METHOD1(Remove,
-      int(uint8_t rtp_payload_type));
+  MOCK_METHOD1(Remove, int(uint8_t rtp_payload_type));
   MOCK_METHOD0(RemoveAll, void());
   MOCK_CONST_METHOD1(GetDecoderInfo,
-      const DecoderInfo*(uint8_t rtp_payload_type));
+                     const DecoderInfo*(uint8_t rtp_payload_type));
   MOCK_METHOD2(SetActiveDecoder,
-      int(uint8_t rtp_payload_type, bool* new_decoder));
-  MOCK_CONST_METHOD0(GetActiveDecoder,
-      AudioDecoder*());
-  MOCK_METHOD1(SetActiveCngDecoder,
-      int(uint8_t rtp_payload_type));
-  MOCK_CONST_METHOD0(GetActiveCngDecoder,
-      ComfortNoiseDecoder*());
+               int(uint8_t rtp_payload_type, bool* new_decoder));
+  MOCK_CONST_METHOD0(GetActiveDecoder, AudioDecoder*());
+  MOCK_METHOD1(SetActiveCngDecoder, int(uint8_t rtp_payload_type));
+  MOCK_CONST_METHOD0(GetActiveCngDecoder, ComfortNoiseDecoder*());
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_delay_manager.h b/modules/audio_coding/neteq/mock/mock_delay_manager.h
index 61f209d..9b2ed49 100644
--- a/modules/audio_coding/neteq/mock/mock_delay_manager.h
+++ b/modules/audio_coding/neteq/mock/mock_delay_manager.h
@@ -25,37 +25,25 @@
       : DelayManager(max_packets_in_buffer, peak_detector, tick_timer) {}
   virtual ~MockDelayManager() { Die(); }
   MOCK_METHOD0(Die, void());
-  MOCK_CONST_METHOD0(iat_vector,
-      const IATVector&());
+  MOCK_CONST_METHOD0(iat_vector, const IATVector&());
   MOCK_METHOD3(Update,
-      int(uint16_t sequence_number, uint32_t timestamp, int sample_rate_hz));
-  MOCK_METHOD1(CalculateTargetLevel,
-      int(int iat_packets));
-  MOCK_METHOD1(SetPacketAudioLength,
-      int(int length_ms));
-  MOCK_METHOD0(Reset,
-      void());
-  MOCK_CONST_METHOD0(PeakFound,
-      bool());
-  MOCK_METHOD1(UpdateCounters,
-      void(int elapsed_time_ms));
-  MOCK_METHOD0(ResetPacketIatCount,
-      void());
-  MOCK_CONST_METHOD2(BufferLimits,
-      void(int* lower_limit, int* higher_limit));
-  MOCK_CONST_METHOD0(TargetLevel,
-      int());
+               int(uint16_t sequence_number,
+                   uint32_t timestamp,
+                   int sample_rate_hz));
+  MOCK_METHOD1(CalculateTargetLevel, int(int iat_packets));
+  MOCK_METHOD1(SetPacketAudioLength, int(int length_ms));
+  MOCK_METHOD0(Reset, void());
+  MOCK_CONST_METHOD0(PeakFound, bool());
+  MOCK_METHOD1(UpdateCounters, void(int elapsed_time_ms));
+  MOCK_METHOD0(ResetPacketIatCount, void());
+  MOCK_CONST_METHOD2(BufferLimits, void(int* lower_limit, int* higher_limit));
+  MOCK_CONST_METHOD0(TargetLevel, int());
   MOCK_METHOD0(RegisterEmptyPacket, void());
-  MOCK_METHOD1(set_extra_delay_ms,
-      void(int16_t delay));
-  MOCK_CONST_METHOD0(base_target_level,
-      int());
-  MOCK_METHOD1(set_streaming_mode,
-      void(bool value));
-  MOCK_CONST_METHOD0(last_pack_cng_or_dtmf,
-      int());
-  MOCK_METHOD1(set_last_pack_cng_or_dtmf,
-      void(int value));
+  MOCK_METHOD1(set_extra_delay_ms, void(int16_t delay));
+  MOCK_CONST_METHOD0(base_target_level, int());
+  MOCK_METHOD1(set_streaming_mode, void(bool value));
+  MOCK_CONST_METHOD0(last_pack_cng_or_dtmf, int());
+  MOCK_METHOD1(set_last_pack_cng_or_dtmf, void(int value));
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_dtmf_buffer.h b/modules/audio_coding/neteq/mock/mock_dtmf_buffer.h
index 153a4d7..11b571f 100644
--- a/modules/audio_coding/neteq/mock/mock_dtmf_buffer.h
+++ b/modules/audio_coding/neteq/mock/mock_dtmf_buffer.h
@@ -22,16 +22,11 @@
   MockDtmfBuffer(int fs) : DtmfBuffer(fs) {}
   virtual ~MockDtmfBuffer() { Die(); }
   MOCK_METHOD0(Die, void());
-  MOCK_METHOD0(Flush,
-      void());
-  MOCK_METHOD1(InsertEvent,
-      int(const DtmfEvent& event));
-  MOCK_METHOD2(GetEvent,
-      bool(uint32_t current_timestamp, DtmfEvent* event));
-  MOCK_CONST_METHOD0(Length,
-      size_t());
-  MOCK_CONST_METHOD0(Empty,
-      bool());
+  MOCK_METHOD0(Flush, void());
+  MOCK_METHOD1(InsertEvent, int(const DtmfEvent& event));
+  MOCK_METHOD2(GetEvent, bool(uint32_t current_timestamp, DtmfEvent* event));
+  MOCK_CONST_METHOD0(Length, size_t());
+  MOCK_CONST_METHOD0(Empty, bool());
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_dtmf_tone_generator.h b/modules/audio_coding/neteq/mock/mock_dtmf_tone_generator.h
index 2cb5980..be4b7b5 100644
--- a/modules/audio_coding/neteq/mock/mock_dtmf_tone_generator.h
+++ b/modules/audio_coding/neteq/mock/mock_dtmf_tone_generator.h
@@ -21,14 +21,10 @@
  public:
   virtual ~MockDtmfToneGenerator() { Die(); }
   MOCK_METHOD0(Die, void());
-  MOCK_METHOD3(Init,
-      int(int fs, int event, int attenuation));
-  MOCK_METHOD0(Reset,
-      void());
-  MOCK_METHOD2(Generate,
-      int(size_t num_samples, AudioMultiVector* output));
-  MOCK_CONST_METHOD0(initialized,
-      bool());
+  MOCK_METHOD3(Init, int(int fs, int event, int attenuation));
+  MOCK_METHOD0(Reset, void());
+  MOCK_METHOD2(Generate, int(size_t num_samples, AudioMultiVector* output));
+  MOCK_CONST_METHOD0(initialized, bool());
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_expand.h b/modules/audio_coding/neteq/mock/mock_expand.h
index 05fdaec..aed0164 100644
--- a/modules/audio_coding/neteq/mock/mock_expand.h
+++ b/modules/audio_coding/neteq/mock/mock_expand.h
@@ -33,16 +33,11 @@
                num_channels) {}
   virtual ~MockExpand() { Die(); }
   MOCK_METHOD0(Die, void());
-  MOCK_METHOD0(Reset,
-      void());
-  MOCK_METHOD1(Process,
-      int(AudioMultiVector* output));
-  MOCK_METHOD0(SetParametersForNormalAfterExpand,
-      void());
-  MOCK_METHOD0(SetParametersForMergeAfterExpand,
-      void());
-  MOCK_CONST_METHOD0(overlap_length,
-      size_t());
+  MOCK_METHOD0(Reset, void());
+  MOCK_METHOD1(Process, int(AudioMultiVector* output));
+  MOCK_METHOD0(SetParametersForNormalAfterExpand, void());
+  MOCK_METHOD0(SetParametersForMergeAfterExpand, void());
+  MOCK_CONST_METHOD0(overlap_length, size_t());
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
index b315240..5aed6a9 100644
--- a/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
+++ b/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.h
@@ -75,17 +75,16 @@
                    int sample_rate_hz,
                    int16_t* decoded,
                    SpeechType* speech_type));
-  MOCK_CONST_METHOD0(HasDecodePlc,
-      bool());
-  MOCK_METHOD2(DecodePlc,
-      size_t(size_t num_frames, int16_t* decoded));
+  MOCK_CONST_METHOD0(HasDecodePlc, bool());
+  MOCK_METHOD2(DecodePlc, size_t(size_t num_frames, int16_t* decoded));
   MOCK_METHOD0(Reset, void());
   MOCK_METHOD5(IncomingPacket,
-      int(const uint8_t* payload, size_t payload_len,
-          uint16_t rtp_sequence_number, uint32_t rtp_timestamp,
-          uint32_t arrival_timestamp));
-  MOCK_METHOD0(ErrorCode,
-      int());
+               int(const uint8_t* payload,
+                   size_t payload_len,
+                   uint16_t rtp_sequence_number,
+                   uint32_t rtp_timestamp,
+                   uint32_t arrival_timestamp));
+  MOCK_METHOD0(ErrorCode, int());
 
   int SampleRateHz() const /* override */ { return real_.SampleRateHz(); }
   size_t Channels() const /* override */ { return real_.Channels(); }
diff --git a/modules/audio_coding/neteq/mock/mock_packet_buffer.h b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
index ac7d9b7..b477b1a 100644
--- a/modules/audio_coding/neteq/mock/mock_packet_buffer.h
+++ b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
@@ -38,8 +38,8 @@
   MOCK_METHOD5(InsertPacketList,
                int(PacketList* packet_list,
                    const DecoderDatabase& decoder_database,
-                   rtc::Optional<uint8_t>* current_rtp_payload_type,
-                   rtc::Optional<uint8_t>* current_cng_rtp_payload_type,
+                   absl::optional<uint8_t>* current_rtp_payload_type,
+                   absl::optional<uint8_t>* current_cng_rtp_payload_type,
                    StatisticsCalculator* stats));
   MOCK_CONST_METHOD1(NextTimestamp,
       int(uint32_t* next_timestamp));
@@ -47,8 +47,7 @@
       int(uint32_t timestamp, uint32_t* next_timestamp));
   MOCK_CONST_METHOD0(PeekNextPacket,
       const Packet*());
-  MOCK_METHOD0(GetNextPacket,
-      rtc::Optional<Packet>());
+  MOCK_METHOD0(GetNextPacket, absl::optional<Packet>());
   MOCK_METHOD1(DiscardNextPacket, int(StatisticsCalculator* stats));
   MOCK_METHOD3(DiscardOldPackets,
                void(uint32_t timestamp_limit,
diff --git a/modules/audio_coding/neteq/mock/mock_red_payload_splitter.h b/modules/audio_coding/neteq/mock/mock_red_payload_splitter.h
index 27a2276..426c467 100644
--- a/modules/audio_coding/neteq/mock/mock_red_payload_splitter.h
+++ b/modules/audio_coding/neteq/mock/mock_red_payload_splitter.h
@@ -21,8 +21,8 @@
  public:
   MOCK_METHOD1(SplitRed, bool(PacketList* packet_list));
   MOCK_METHOD2(CheckRedPayloads,
-               int(PacketList* packet_list,
-                   const DecoderDatabase& decoder_database));
+               void(PacketList* packet_list,
+                    const DecoderDatabase& decoder_database));
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/nack_tracker.h b/modules/audio_coding/neteq/nack_tracker.h
index 66383ce..1936a94 100644
--- a/modules/audio_coding/neteq/nack_tracker.h
+++ b/modules/audio_coding/neteq/nack_tracker.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
 #define MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
 
-#include <vector>
 #include <map>
+#include <vector>
 
 #include "modules/audio_coding/include/audio_coding_module_typedefs.h"
 #include "modules/include/module_common_types.h"
diff --git a/modules/audio_coding/neteq/neteq.cc b/modules/audio_coding/neteq/neteq.cc
index db12589..cf1c6aa 100644
--- a/modules/audio_coding/neteq/neteq.cc
+++ b/modules/audio_coding/neteq/neteq.cc
@@ -27,14 +27,12 @@
 std::string NetEq::Config::ToString() const {
   char buf[1024];
   rtc::SimpleStringBuilder ss(buf);
-  ss << "sample_rate_hz=" << sample_rate_hz
-     << ", enable_post_decode_vad="
+  ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad="
      << (enable_post_decode_vad ? "true" : "false")
      << ", max_packets_in_buffer=" << max_packets_in_buffer
-     << ", playout_mode=" << playout_mode
      << ", enable_fast_accelerate="
-     << (enable_fast_accelerate ? " true": "false")
-     << ", enable_muted_state=" << (enable_muted_state ? " true": "false");
+     << (enable_fast_accelerate ? " true" : "false")
+     << ", enable_muted_state=" << (enable_muted_state ? " true" : "false");
   return ss.str();
 }
 
diff --git a/modules/audio_coding/neteq/neteq_decoder_enum.cc b/modules/audio_coding/neteq/neteq_decoder_enum.cc
index 8d66c2a..e3b633e 100644
--- a/modules/audio_coding/neteq/neteq_decoder_enum.cc
+++ b/modules/audio_coding/neteq/neteq_decoder_enum.cc
@@ -15,7 +15,7 @@
 
 namespace webrtc {
 
-rtc::Optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd) {
+absl::optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd) {
   switch (nd) {
     case NetEqDecoder::kDecoderPCMu:
       return SdpAudioFormat("pcmu", 8000, 1);
@@ -78,7 +78,7 @@
     case NetEqDecoder::kDecoderCNGswb48kHz:
       return SdpAudioFormat("cn", 48000, 1);
     default:
-      return rtc::nullopt;
+      return absl::nullopt;
   }
 }
 
diff --git a/modules/audio_coding/neteq/neteq_decoder_enum.h b/modules/audio_coding/neteq/neteq_decoder_enum.h
index 024f03c..00629bc 100644
--- a/modules/audio_coding/neteq/neteq_decoder_enum.h
+++ b/modules/audio_coding/neteq/neteq_decoder_enum.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_
 #define MODULES_AUDIO_CODING_NETEQ_NETEQ_DECODER_ENUM_H_
 
+#include "absl/types/optional.h"
 #include "api/audio_codecs/audio_format.h"
-#include "api/optional.h"
 
 namespace webrtc {
 
@@ -49,7 +49,7 @@
   kDecoderOpus_2ch,
 };
 
-rtc::Optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd);
+absl::optional<SdpAudioFormat> NetEqDecoderToSdpAudioFormat(NetEqDecoder nd);
 
 }  // namespace webrtc
 
diff --git a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
index 03f5aa3..5c350bb 100644
--- a/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_external_decoder_unittest.cc
@@ -55,8 +55,8 @@
   }
 
   virtual ~NetEqExternalDecoderUnitTest() {
-    delete [] input_;
-    delete [] encoded_;
+    delete[] input_;
+    delete[] encoded_;
     // ~NetEqExternalDecoderTest() will delete |external_decoder_|, so expecting
     // Die() to be called.
     EXPECT_CALL(*external_decoder_, Die()).Times(1);
@@ -75,8 +75,8 @@
     if (!input_file_->Read(frame_size_samples_, input_)) {
       return -1;
     }
-    payload_size_bytes_ = WebRtcPcm16b_Encode(input_, frame_size_samples_,
-                                              encoded_);
+    payload_size_bytes_ =
+        WebRtcPcm16b_Encode(input_, frame_size_samples_, encoded_);
 
     int next_send_time = rtp_generator_->GetRtpHeader(
         kPayloadType, frame_size_samples_, &rtp_header_);
@@ -111,9 +111,10 @@
     uint32_t time_now = 0;
     for (int k = 0; k < num_loops; ++k) {
       while (time_now >= next_arrival_time) {
-        InsertPacket(rtp_header_, rtc::ArrayView<const uint8_t>(
-                                      encoded_, payload_size_bytes_),
-                     next_arrival_time);
+        InsertPacket(
+            rtp_header_,
+            rtc::ArrayView<const uint8_t>(encoded_, payload_size_bytes_),
+            next_arrival_time);
         // Get next input packet.
         do {
           next_send_time = GetNewPacket();
@@ -148,6 +149,7 @@
   }
 
   int samples_per_ms() const { return samples_per_ms_; }
+
  private:
   std::unique_ptr<MockExternalPcm16B> external_decoder_;
   int samples_per_ms_;
@@ -337,11 +339,9 @@
       static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) > 0x7FFFFFFF,
       "jump should be larger than half range");
   // Replace the default RTP generator with one that jumps in timestamp.
-  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(samples_per_ms(),
-                                                        kStartSeqeunceNumber,
-                                                        kStartTimestamp,
-                                                        kJumpFromTimestamp,
-                                                        kJumpToTimestamp));
+  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(
+      samples_per_ms(), kStartSeqeunceNumber, kStartTimestamp,
+      kJumpFromTimestamp, kJumpToTimestamp));
 
   RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
   EXPECT_EQ(kRecovered, test_state_);
@@ -361,11 +361,9 @@
       static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) > 0x7FFFFFFF,
       "jump should be larger than half range");
   // Replace the default RTP generator with one that jumps in timestamp.
-  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(samples_per_ms(),
-                                                        kStartSeqeunceNumber,
-                                                        kStartTimestamp,
-                                                        kJumpFromTimestamp,
-                                                        kJumpToTimestamp));
+  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(
+      samples_per_ms(), kStartSeqeunceNumber, kStartTimestamp,
+      kJumpFromTimestamp, kJumpToTimestamp));
 
   RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
   EXPECT_EQ(kRecovered, test_state_);
@@ -420,11 +418,9 @@
       static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) < 0x7FFFFFFF,
       "jump should be smaller than half range");
   // Replace the default RTP generator with one that jumps in timestamp.
-  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(samples_per_ms(),
-                                                        kStartSeqeunceNumber,
-                                                        kStartTimestamp,
-                                                        kJumpFromTimestamp,
-                                                        kJumpToTimestamp));
+  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(
+      samples_per_ms(), kStartSeqeunceNumber, kStartTimestamp,
+      kJumpFromTimestamp, kJumpToTimestamp));
 
   RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
   EXPECT_EQ(kRecovered, test_state_);
@@ -444,11 +440,9 @@
       static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) < 0x7FFFFFFF,
       "jump should be smaller than half range");
   // Replace the default RTP generator with one that jumps in timestamp.
-  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(samples_per_ms(),
-                                                        kStartSeqeunceNumber,
-                                                        kStartTimestamp,
-                                                        kJumpFromTimestamp,
-                                                        kJumpToTimestamp));
+  ResetRtpGenerator(new test::TimestampJumpRtpGenerator(
+      samples_per_ms(), kStartSeqeunceNumber, kStartTimestamp,
+      kJumpFromTimestamp, kJumpToTimestamp));
 
   RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
   EXPECT_EQ(kRecovered, test_state_);
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index 80bfdaf..0ef3263 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -101,7 +101,6 @@
       reset_decoder_(false),
       ssrc_(0),
       first_packet_(true),
-      playout_mode_(config.playout_mode),
       enable_fast_accelerate_(config.enable_fast_accelerate),
       nack_enabled_(false),
       enable_muted_state_(config.enable_muted_state),
@@ -110,7 +109,8 @@
                          tick_timer_.get()),
       speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
                                 10,  // Report once every 10 s.
-                                tick_timer_.get()) {
+                                tick_timer_.get()),
+      no_time_stretching_(config.for_test_no_time_stretching) {
   RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString();
   int fs = config.sample_rate_hz;
   if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
@@ -358,23 +358,6 @@
   return static_cast<int>(delay_samples) / rtc::CheckedDivExact(fs_hz_, 1000);
 }
 
-// Deprecated.
-// TODO(henrik.lundin) Delete.
-void NetEqImpl::SetPlayoutMode(NetEqPlayoutMode mode) {
-  rtc::CritScope lock(&crit_sect_);
-  if (mode != playout_mode_) {
-    playout_mode_ = mode;
-    CreateDecisionLogic();
-  }
-}
-
-// Deprecated.
-// TODO(henrik.lundin) Delete.
-NetEqPlayoutMode NetEqImpl::PlayoutMode() const {
-  rtc::CritScope lock(&crit_sect_);
-  return playout_mode_;
-}
-
 int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
   rtc::CritScope lock(&crit_sect_);
   assert(decoder_database_.get());
@@ -422,14 +405,14 @@
   vad_->Disable();
 }
 
-rtc::Optional<uint32_t> NetEqImpl::GetPlayoutTimestamp() const {
+absl::optional<uint32_t> NetEqImpl::GetPlayoutTimestamp() const {
   rtc::CritScope lock(&crit_sect_);
   if (first_packet_ || last_mode_ == kModeRfc3389Cng ||
       last_mode_ == kModeCodecInternalCng) {
     // We don't have a valid RTP timestamp until we have decoded our first
     // RTP packet. Also, the RTP timestamp is not accurate while playing CNG,
     // which is indicated by returning an empty value.
-    return rtc::nullopt;
+    return absl::nullopt;
   }
   return timestamp_scaler_->ToExternal(playout_timestamp_);
 }
@@ -439,12 +422,12 @@
   return last_output_sample_rate_hz_;
 }
 
-rtc::Optional<CodecInst> NetEqImpl::GetDecoder(int payload_type) const {
+absl::optional<CodecInst> NetEqImpl::GetDecoder(int payload_type) const {
   rtc::CritScope lock(&crit_sect_);
   const DecoderDatabase::DecoderInfo* di =
       decoder_database_->GetDecoderInfo(payload_type);
   if (!di) {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
 
   // Create a CodecInst with some fields set. The remaining fields are zeroed,
@@ -460,13 +443,13 @@
   return ci;
 }
 
-rtc::Optional<SdpAudioFormat> NetEqImpl::GetDecoderFormat(
+absl::optional<SdpAudioFormat> NetEqImpl::GetDecoderFormat(
     int payload_type) const {
   rtc::CritScope lock(&crit_sect_);
   const DecoderDatabase::DecoderInfo* const di =
       decoder_database_->GetDecoderInfo(payload_type);
   if (!di) {
-    return rtc::nullopt;  // Payload type not registered.
+    return absl::nullopt;  // Payload type not registered.
   }
   return di->GetFormat();
 }
@@ -629,6 +612,9 @@
     // Only accept a few RED payloads of the same type as the main data,
     // DTMF events and CNG.
     red_payload_splitter_->CheckRedPayloads(&packet_list, *decoder_database_);
+    if (packet_list.empty()) {
+      return kRedundancySplitError;
+    }
   }
 
   // Check payload types.
@@ -681,8 +667,7 @@
     decoder->IncomingPacket(packet_list.front().payload.data(),
                             packet_list.front().payload.size(),
                             packet_list.front().sequence_number,
-                            packet_list.front().timestamp,
-                            receive_timestamp);
+                            packet_list.front().timestamp, receive_timestamp);
   }
 
   PacketList parsed_packet_list;
@@ -703,7 +688,7 @@
       const auto sequence_number = packet.sequence_number;
       const auto payload_type = packet.payload_type;
       const Packet::Priority original_priority = packet.priority;
-      auto packet_from_result = [&] (AudioDecoder::ParseResult& result) {
+      auto packet_from_result = [&](AudioDecoder::ParseResult& result) {
         Packet new_packet;
         new_packet.sequence_number = sequence_number;
         new_packet.payload_type = payload_type;
@@ -788,8 +773,7 @@
     assert(decoder_info);
     if (decoder_info->SampleRateHz() != fs_hz_ ||
         channels != algorithm_buffer_->Channels()) {
-      SetSampleRateAndChannels(decoder_info->SampleRateHz(),
-                               channels);
+      SetSampleRateAndChannels(decoder_info->SampleRateHz(), channels);
     }
     if (nack_enabled_) {
       RTC_DCHECK(nack_);
@@ -866,8 +850,8 @@
     return 0;
   }
 
-  int return_value = GetDecision(&operation, &packet_list, &dtmf_event,
-                                 &play_dtmf);
+  int return_value =
+      GetDecision(&operation, &packet_list, &dtmf_event, &play_dtmf);
   if (return_value != 0) {
     last_mode_ = kModeError;
     return return_value;
@@ -876,12 +860,11 @@
   AudioDecoder::SpeechType speech_type;
   int length = 0;
   const size_t start_num_packets = packet_list.size();
-  int decode_return_value = Decode(&packet_list, &operation,
-                                   &length, &speech_type);
+  int decode_return_value =
+      Decode(&packet_list, &operation, &length, &speech_type);
 
   assert(vad_.get());
-  bool sid_frame_available =
-      (operation == kRfc3389Cng && !packet_list.empty());
+  bool sid_frame_available = (operation == kRfc3389Cng && !packet_list.empty());
   vad_->Update(decoded_buffer_.get(), static_cast<size_t>(length), speech_type,
                sid_frame_available, fs_hz_);
 
@@ -940,33 +923,6 @@
       return_value = DoDtmf(dtmf_event, &play_dtmf);
       break;
     }
-    case kAlternativePlc: {
-      // TODO(hlundin): Write test for this.
-      DoAlternativePlc(false);
-      break;
-    }
-    case kAlternativePlcIncreaseTimestamp: {
-      // TODO(hlundin): Write test for this.
-      DoAlternativePlc(true);
-      break;
-    }
-    case kAudioRepetitionIncreaseTimestamp: {
-      // TODO(hlundin): Write test for this.
-      sync_buffer_->IncreaseEndTimestamp(
-          static_cast<uint32_t>(output_size_samples_));
-      // Skipping break on purpose. Execution should move on into the
-      // next case.
-      RTC_FALLTHROUGH();
-    }
-    case kAudioRepetition: {
-      // TODO(hlundin): Write test for this.
-      // Copy last |output_size_samples_| from |sync_buffer_| to
-      // |algorithm_buffer|.
-      algorithm_buffer_->PushBackFromIndex(
-          *sync_buffer_, sync_buffer_->Size() - output_size_samples_);
-      expand_->Reset();
-      break;
-    }
     case kUndefined: {
       RTC_LOG(LS_ERROR) << "Invalid operation kUndefined.";
       assert(false);  // This should not happen.
@@ -1033,8 +989,7 @@
   // Update the background noise parameters if last operation wrote data
   // straight from the decoder to the |sync_buffer_|. That is, none of the
   // operations that modify the signal can be followed by a parameter update.
-  if ((last_mode_ == kModeNormal) ||
-      (last_mode_ == kModeAccelerateFail) ||
+  if ((last_mode_ == kModeNormal) || (last_mode_ == kModeAccelerateFail) ||
       (last_mode_ == kModePreemptiveExpandFail) ||
       (last_mode_ == kModeRfc3389Cng) ||
       (last_mode_ == kModeCodecInternalCng)) {
@@ -1051,7 +1006,8 @@
     // If last operation was not expand, calculate the |playout_timestamp_| from
     // the |sync_buffer_|. However, do not update the |playout_timestamp_| if it
     // would be moved "backwards".
-    uint32_t temp_timestamp = sync_buffer_->end_timestamp() -
+    uint32_t temp_timestamp =
+        sync_buffer_->end_timestamp() -
         static_cast<uint32_t>(sync_buffer_->FutureLength());
     if (static_cast<int32_t>(temp_timestamp - playout_timestamp_) > 0) {
       playout_timestamp_ = temp_timestamp;
@@ -1070,13 +1026,13 @@
           : timestamp_scaler_->ToExternal(playout_timestamp_) -
                 static_cast<uint32_t>(audio_frame->samples_per_channel_);
 
-  if (!(last_mode_ == kModeRfc3389Cng ||
-      last_mode_ == kModeCodecInternalCng ||
-      last_mode_ == kModeExpand)) {
+  if (!(last_mode_ == kModeRfc3389Cng || last_mode_ == kModeCodecInternalCng ||
+        last_mode_ == kModeExpand)) {
     generated_noise_stopwatch_.reset();
   }
 
-  if (decode_return_value) return decode_return_value;
+  if (decode_return_value)
+    return decode_return_value;
   return return_value;
 }
 
@@ -1100,11 +1056,10 @@
   RTC_DCHECK(!generated_noise_stopwatch_ ||
              generated_noise_stopwatch_->ElapsedTicks() >= 1);
   uint64_t generated_noise_samples =
-      generated_noise_stopwatch_
-          ? (generated_noise_stopwatch_->ElapsedTicks() - 1) *
-                    output_size_samples_ +
-                decision_logic_->noise_fast_forward()
-          : 0;
+      generated_noise_stopwatch_ ? (generated_noise_stopwatch_->ElapsedTicks() -
+                                    1) * output_size_samples_ +
+                                       decision_logic_->noise_fast_forward()
+                                 : 0;
 
   if (decision_logic_->CngRfc3389On() || last_mode_ == kModeRfc3389Cng) {
     // Because of timestamp peculiarities, we have to "manually" disallow using
@@ -1127,7 +1082,7 @@
 
   assert(expand_.get());
   const int samples_left = static_cast<int>(sync_buffer_->FutureLength() -
-      expand_->overlap_length());
+                                            expand_->overlap_length());
   if (last_mode_ == kModeAccelerateSuccess ||
       last_mode_ == kModeAccelerateLowEnergy ||
       last_mode_ == kModePreemptiveExpandSuccess ||
@@ -1139,9 +1094,8 @@
 
   // Check if it is time to play a DTMF event.
   if (dtmf_buffer_->GetEvent(
-      static_cast<uint32_t>(
-          end_timestamp + generated_noise_samples),
-      dtmf_event)) {
+          static_cast<uint32_t>(end_timestamp + generated_noise_samples),
+          dtmf_event)) {
     *play_dtmf = true;
   }
 
@@ -1243,12 +1197,12 @@
         decision_logic_->set_prev_time_scale(true);
         return 0;
       } else if (samples_left >= static_cast<int>(samples_10_ms) &&
-          decoder_frame_length_ >= samples_30_ms) {
+                 decoder_frame_length_ >= samples_30_ms) {
         // Avoid decoding more data as it might overflow the playout buffer.
         *operation = kNormal;
         return 0;
       } else if (samples_left < static_cast<int>(samples_20_ms) &&
-          decoder_frame_length_ < samples_30_ms) {
+                 decoder_frame_length_ < samples_30_ms) {
         // Build up decoded data by decoding at least 20 ms of audio data. Do
         // not perform accelerate yet, but wait until we only need to do one
         // decoding.
@@ -1267,7 +1221,7 @@
       // audio data.
       if ((samples_left >= static_cast<int>(samples_30_ms)) ||
           (samples_left >= static_cast<int>(samples_10_ms) &&
-              decoder_frame_length_ >= samples_30_ms)) {
+           decoder_frame_length_ >= samples_30_ms)) {
         // Already have enough data, so we do not need to extract any more.
         // Or, avoid decoding more data as it might overflow the playout buffer.
         // Still try preemptive expand, though.
@@ -1296,10 +1250,7 @@
 
   // Get packets from buffer.
   int extracted_samples = 0;
-  if (packet && *operation != kAlternativePlc &&
-      *operation != kAlternativePlcIncreaseTimestamp &&
-      *operation != kAudioRepetition &&
-      *operation != kAudioRepetitionIncreaseTimestamp) {
+  if (packet) {
     sync_buffer_->IncreaseEndTimestamp(packet->timestamp - end_timestamp);
     if (decision_logic_->CngOff()) {
       // Adjustment of timestamp only corresponds to an actual packet loss
@@ -1339,7 +1290,8 @@
   return 0;
 }
 
-int NetEqImpl::Decode(PacketList* packet_list, Operations* operation,
+int NetEqImpl::Decode(PacketList* packet_list,
+                      Operations* operation,
                       int* decoded_length,
                       AudioDecoder::SpeechType* speech_type) {
   *speech_type = AudioDecoder::kSpeech;
@@ -1364,8 +1316,8 @@
       decoder_database_->SetActiveDecoder(payload_type, &decoder_changed);
       if (decoder_changed) {
         // We have a new decoder. Re-init some values.
-        const DecoderDatabase::DecoderInfo* decoder_info = decoder_database_
-            ->GetDecoderInfo(payload_type);
+        const DecoderDatabase::DecoderInfo* decoder_info =
+            decoder_database_->GetDecoderInfo(payload_type);
         assert(decoder_info);
         if (!decoder_info) {
           RTC_LOG(LS_WARNING)
@@ -1411,8 +1363,8 @@
     RTC_DCHECK(packet_list->empty());
     return_value = DecodeCng(decoder, decoded_length, speech_type);
   } else {
-    return_value = DecodeLoop(packet_list, *operation, decoder,
-                              decoded_length, speech_type);
+    return_value = DecodeLoop(packet_list, *operation, decoder, decoded_length,
+                              speech_type);
   }
 
   if (*decoded_length < 0) {
@@ -1446,7 +1398,8 @@
   return return_value;
 }
 
-int NetEqImpl::DecodeCng(AudioDecoder* decoder, int* decoded_length,
+int NetEqImpl::DecodeCng(AudioDecoder* decoder,
+                         int* decoded_length,
                          AudioDecoder::SpeechType* speech_type) {
   if (!decoder) {
     // This happens when active decoder is not defined.
@@ -1456,9 +1409,9 @@
 
   while (*decoded_length < rtc::dchecked_cast<int>(output_size_samples_)) {
     const int length = decoder->Decode(
-            nullptr, 0, fs_hz_,
-            (decoded_buffer_length_ - *decoded_length) * sizeof(int16_t),
-            &decoded_buffer_[*decoded_length], speech_type);
+        nullptr, 0, fs_hz_,
+        (decoded_buffer_length_ - *decoded_length) * sizeof(int16_t),
+        &decoded_buffer_[*decoded_length], speech_type);
     if (length > 0) {
       *decoded_length += length;
     } else {
@@ -1476,15 +1429,16 @@
   return 0;
 }
 
-int NetEqImpl::DecodeLoop(PacketList* packet_list, const Operations& operation,
-                          AudioDecoder* decoder, int* decoded_length,
+int NetEqImpl::DecodeLoop(PacketList* packet_list,
+                          const Operations& operation,
+                          AudioDecoder* decoder,
+                          int* decoded_length,
                           AudioDecoder::SpeechType* speech_type) {
   RTC_DCHECK(last_decoded_timestamps_.empty());
 
   // Do decoding.
-  while (
-      !packet_list->empty() &&
-      !decoder_database_->IsComfortNoise(packet_list->front().payload_type)) {
+  while (!packet_list->empty() && !decoder_database_->IsComfortNoise(
+                                      packet_list->front().payload_type)) {
     assert(decoder);  // At this point, we must have a decoder object.
     // The number of channels in the |sync_buffer_| should be the same as the
     // number decoder channels.
@@ -1526,27 +1480,26 @@
 
   // If the list is not empty at this point, either a decoding error terminated
   // the while-loop, or list must hold exactly one CNG packet.
-  assert(
-      packet_list->empty() || *decoded_length < 0 ||
-      (packet_list->size() == 1 &&
-       decoder_database_->IsComfortNoise(packet_list->front().payload_type)));
+  assert(packet_list->empty() || *decoded_length < 0 ||
+         (packet_list->size() == 1 && decoder_database_->IsComfortNoise(
+                                          packet_list->front().payload_type)));
   return 0;
 }
 
-void NetEqImpl::DoNormal(const int16_t* decoded_buffer, size_t decoded_length,
-                         AudioDecoder::SpeechType speech_type, bool play_dtmf) {
+void NetEqImpl::DoNormal(const int16_t* decoded_buffer,
+                         size_t decoded_length,
+                         AudioDecoder::SpeechType speech_type,
+                         bool play_dtmf) {
   assert(normal_.get());
-  assert(mute_factor_array_.get());
   normal_->Process(decoded_buffer, decoded_length, last_mode_,
-                   mute_factor_array_.get(), algorithm_buffer_.get());
+                   algorithm_buffer_.get());
   if (decoded_length != 0) {
     last_mode_ = kModeNormal;
   }
 
   // If last packet was decoded as an inband CNG, set mode to CNG instead.
-  if ((speech_type == AudioDecoder::kComfortNoise)
-      || ((last_mode_ == kModeCodecInternalCng)
-          && (decoded_length == 0))) {
+  if ((speech_type == AudioDecoder::kComfortNoise) ||
+      ((last_mode_ == kModeCodecInternalCng) && (decoded_length == 0))) {
     // TODO(hlundin): Remove second part of || statement above.
     last_mode_ = kModeCodecInternalCng;
   }
@@ -1556,13 +1509,13 @@
   }
 }
 
-void NetEqImpl::DoMerge(int16_t* decoded_buffer, size_t decoded_length,
-                        AudioDecoder::SpeechType speech_type, bool play_dtmf) {
-  assert(mute_factor_array_.get());
+void NetEqImpl::DoMerge(int16_t* decoded_buffer,
+                        size_t decoded_length,
+                        AudioDecoder::SpeechType speech_type,
+                        bool play_dtmf) {
   assert(merge_.get());
-  size_t new_length = merge_->Process(decoded_buffer, decoded_length,
-                                      mute_factor_array_.get(),
-                                      algorithm_buffer_.get());
+  size_t new_length =
+      merge_->Process(decoded_buffer, decoded_length, algorithm_buffer_.get());
   // Correction can be negative.
   int expand_length_correction =
       rtc::dchecked_cast<int>(new_length) -
@@ -1590,7 +1543,7 @@
 
 int NetEqImpl::DoExpand(bool play_dtmf) {
   while ((sync_buffer_->FutureLength() - expand_->overlap_length()) <
-      output_size_samples_) {
+         output_size_samples_) {
     algorithm_buffer_->Clear();
     int return_value = expand_->Process(algorithm_buffer_.get());
     size_t length = algorithm_buffer_->Size();
@@ -1638,11 +1591,10 @@
   size_t decoded_length_per_channel = decoded_length / num_channels;
   if (decoded_length_per_channel < required_samples) {
     // Must move data from the |sync_buffer_| in order to get 30 ms.
-    borrowed_samples_per_channel = static_cast<int>(required_samples -
-        decoded_length_per_channel);
+    borrowed_samples_per_channel =
+        static_cast<int>(required_samples - decoded_length_per_channel);
     memmove(&decoded_buffer[borrowed_samples_per_channel * num_channels],
-            decoded_buffer,
-            sizeof(int16_t) * decoded_length);
+            decoded_buffer, sizeof(int16_t) * decoded_length);
     sync_buffer_->ReadInterleavedFromEnd(borrowed_samples_per_channel,
                                          decoded_buffer);
     decoded_length = required_samples * num_channels;
@@ -1675,17 +1627,16 @@
     if (length < borrowed_samples_per_channel) {
       // This destroys the beginning of the buffer, but will not cause any
       // problems.
-      sync_buffer_->ReplaceAtIndex(*algorithm_buffer_,
-                                   sync_buffer_->Size() -
-                                   borrowed_samples_per_channel);
+      sync_buffer_->ReplaceAtIndex(
+          *algorithm_buffer_,
+          sync_buffer_->Size() - borrowed_samples_per_channel);
       sync_buffer_->PushFrontZeros(borrowed_samples_per_channel - length);
       algorithm_buffer_->PopFront(length);
       assert(algorithm_buffer_->Empty());
     } else {
-      sync_buffer_->ReplaceAtIndex(*algorithm_buffer_,
-                                   borrowed_samples_per_channel,
-                                   sync_buffer_->Size() -
-                                   borrowed_samples_per_channel);
+      sync_buffer_->ReplaceAtIndex(
+          *algorithm_buffer_, borrowed_samples_per_channel,
+          sync_buffer_->Size() - borrowed_samples_per_channel);
       algorithm_buffer_->PopFront(borrowed_samples_per_channel);
     }
   }
@@ -1717,11 +1668,11 @@
         required_samples - decoded_length_per_channel;
     // Calculate how many of these were already played out.
     old_borrowed_samples_per_channel =
-        (borrowed_samples_per_channel > sync_buffer_->FutureLength()) ?
-        (borrowed_samples_per_channel - sync_buffer_->FutureLength()) : 0;
+        (borrowed_samples_per_channel > sync_buffer_->FutureLength())
+            ? (borrowed_samples_per_channel - sync_buffer_->FutureLength())
+            : 0;
     memmove(&decoded_buffer[borrowed_samples_per_channel * num_channels],
-            decoded_buffer,
-            sizeof(int16_t) * decoded_length);
+            decoded_buffer, sizeof(int16_t) * decoded_length);
     sync_buffer_->ReadInterleavedFromEnd(borrowed_samples_per_channel,
                                          decoded_buffer);
     decoded_length = required_samples * num_channels;
@@ -1729,8 +1680,7 @@
 
   size_t samples_added;
   PreemptiveExpand::ReturnCodes return_code = preemptive_expand_->Process(
-      decoded_buffer, decoded_length,
-      old_borrowed_samples_per_channel,
+      decoded_buffer, decoded_length, old_borrowed_samples_per_channel,
       algorithm_buffer_.get(), &samples_added);
   stats_.PreemptiveExpandedSamples(samples_added);
   switch (return_code) {
@@ -1783,8 +1733,8 @@
       return -comfort_noise_->internal_error_code();
     }
   }
-  int cn_return = comfort_noise_->Generate(output_size_samples_,
-                                           algorithm_buffer_.get());
+  int cn_return =
+      comfort_noise_->Generate(output_size_samples_, algorithm_buffer_.get());
   expand_->Reset();
   last_mode_ = kModeRfc3389Cng;
   if (!play_dtmf) {
@@ -1803,9 +1753,8 @@
 void NetEqImpl::DoCodecInternalCng(const int16_t* decoded_buffer,
                                    size_t decoded_length) {
   RTC_DCHECK(normal_.get());
-  RTC_DCHECK(mute_factor_array_.get());
   normal_->Process(decoded_buffer, decoded_length, last_mode_,
-                   mute_factor_array_.get(), algorithm_buffer_.get());
+                   algorithm_buffer_.get());
   last_mode_ = kModeCodecInternalCng;
   expand_->Reset();
 }
@@ -1890,39 +1839,17 @@
   return 0;
 }
 
-void NetEqImpl::DoAlternativePlc(bool increase_timestamp) {
-  AudioDecoder* decoder = decoder_database_->GetActiveDecoder();
-  size_t length;
-  if (decoder && decoder->HasDecodePlc()) {
-    // Use the decoder's packet-loss concealment.
-    // TODO(hlundin): Will probably need a longer buffer for multi-channel.
-    int16_t decoded_buffer[kMaxFrameSize];
-    length = decoder->DecodePlc(1, decoded_buffer);
-    if (length > 0)
-      algorithm_buffer_->PushBackInterleaved(decoded_buffer, length);
-  } else {
-    // Do simple zero-stuffing.
-    length = output_size_samples_;
-    algorithm_buffer_->Zeros(length);
-    // By not advancing the timestamp, NetEq inserts samples.
-    stats_.AddZeros(length);
-  }
-  if (increase_timestamp) {
-    sync_buffer_->IncreaseEndTimestamp(static_cast<uint32_t>(length));
-  }
-  expand_->Reset();
-}
-
-int NetEqImpl::DtmfOverdub(const DtmfEvent& dtmf_event, size_t num_channels,
+int NetEqImpl::DtmfOverdub(const DtmfEvent& dtmf_event,
+                           size_t num_channels,
                            int16_t* output) const {
   size_t out_index = 0;
   size_t overdub_length = output_size_samples_;  // Default value.
 
   if (sync_buffer_->dtmf_index() > sync_buffer_->next_index()) {
     // Special operation for transition from "DTMF only" to "DTMF overdub".
-    out_index = std::min(
-        sync_buffer_->dtmf_index() - sync_buffer_->next_index(),
-        output_size_samples_);
+    out_index =
+        std::min(sync_buffer_->dtmf_index() - sync_buffer_->next_index(),
+                 output_size_samples_);
     overdub_length = output_size_samples_ - out_index;
   }
 
@@ -1933,8 +1860,8 @@
                                                    dtmf_event.volume);
   }
   if (dtmf_return_value == 0) {
-    dtmf_return_value = dtmf_tone_generator_->Generate(overdub_length,
-                                                       &dtmf_output);
+    dtmf_return_value =
+        dtmf_tone_generator_->Generate(overdub_length, &dtmf_output);
     assert(overdub_length == dtmf_output.Size());
   }
   dtmf_output.ReadInterleaved(overdub_length, &output[out_index]);
@@ -1961,7 +1888,7 @@
   // Packet extraction loop.
   do {
     timestamp_ = next_packet->timestamp;
-    rtc::Optional<Packet> packet = packet_buffer_->GetNextPacket();
+    absl::optional<Packet> packet = packet_buffer_->GetNextPacket();
     // |next_packet| may be invalid after the |packet_buffer_| operation.
     next_packet = nullptr;
     if (!packet) {
@@ -2013,7 +1940,7 @@
     stats_.JitterBufferDelay(extracted_samples, waiting_time_ms);
 
     packet_list->push_back(std::move(*packet));  // Store packet in list.
-    packet = rtc::nullopt;  // Ensure it's never used after the move.
+    packet = absl::nullopt;  // Ensure it's never used after the move.
 
     // Check what packet is available next.
     next_packet = packet_buffer_->PeekNextPacket();
@@ -2055,7 +1982,7 @@
   RTC_LOG(LS_VERBOSE) << "SetSampleRateAndChannels " << fs_hz << " "
                       << channels;
   // TODO(hlundin): Change to an enumerator and skip assert.
-  assert(fs_hz == 8000 || fs_hz == 16000 || fs_hz ==  32000 || fs_hz == 48000);
+  assert(fs_hz == 8000 || fs_hz == 16000 || fs_hz == 32000 || fs_hz == 48000);
   assert(channels > 0);
 
   fs_hz_ = fs_hz;
@@ -2065,12 +1992,6 @@
 
   last_mode_ = kModeNormal;
 
-  // Create a new array of mute factors and set all to 1.
-  mute_factor_array_.reset(new int16_t[channels]);
-  for (size_t i = 0; i < channels; ++i) {
-    mute_factor_array_[i] = 16384;  // 1.0 in Q14.
-  }
-
   ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder();
   if (cng_decoder)
     cng_decoder->Reset();
@@ -2095,7 +2016,7 @@
 
   // Move index so that we create a small set of future samples (all 0).
   sync_buffer_->set_next_index(sync_buffer_->next_index() -
-      expand_->overlap_length());
+                               expand_->overlap_length());
 
   normal_.reset(new Normal(fs_hz, decoder_database_.get(), *background_noise_,
                            expand_.get()));
@@ -2105,8 +2026,8 @@
       fs_hz, channels, *background_noise_, expand_->overlap_length()));
 
   // Delete ComfortNoise object and create a new one.
-  comfort_noise_.reset(new ComfortNoise(fs_hz, decoder_database_.get(),
-                                        sync_buffer_.get()));
+  comfort_noise_.reset(
+      new ComfortNoise(fs_hz, decoder_database_.get(), sync_buffer_.get()));
 
   // Verify that |decoded_buffer_| is long enough.
   if (decoded_buffer_length_ < kMaxFrameSize * channels) {
@@ -2142,8 +2063,8 @@
 
 void NetEqImpl::CreateDecisionLogic() {
   decision_logic_.reset(DecisionLogic::Create(
-      fs_hz_, output_size_samples_, playout_mode_, decoder_database_.get(),
-      *packet_buffer_.get(), delay_manager_.get(), buffer_level_filter_.get(),
-      tick_timer_.get()));
+      fs_hz_, output_size_samples_, no_time_stretching_,
+      decoder_database_.get(), *packet_buffer_.get(), delay_manager_.get(),
+      buffer_level_filter_.get(), tick_timer_.get()));
 }
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h
index ce75ce0..6b8764d 100644
--- a/modules/audio_coding/neteq/neteq_impl.h
+++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -14,7 +14,7 @@
 #include <memory>
 #include <string>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "api/audio/audio_frame.h"
 #include "modules/audio_coding/neteq/audio_multi_vector.h"
 #include "modules/audio_coding/neteq/defines.h"
@@ -168,16 +168,6 @@
 
   int FilteredCurrentDelayMs() const override;
 
-  // Sets the playout mode to |mode|.
-  // Deprecated.
-  // TODO(henrik.lundin) Delete.
-  void SetPlayoutMode(NetEqPlayoutMode mode) override;
-
-  // Returns the current playout mode.
-  // Deprecated.
-  // TODO(henrik.lundin) Delete.
-  NetEqPlayoutMode PlayoutMode() const override;
-
   // Writes the current network statistics to |stats|. The statistics are reset
   // after the call.
   int NetworkStatistics(NetEqNetworkStatistics* stats) override;
@@ -198,13 +188,13 @@
   // Disables post-decode VAD.
   void DisableVad() override;
 
-  rtc::Optional<uint32_t> GetPlayoutTimestamp() const override;
+  absl::optional<uint32_t> GetPlayoutTimestamp() const override;
 
   int last_output_sample_rate_hz() const override;
 
-  rtc::Optional<CodecInst> GetDecoder(int payload_type) const override;
+  absl::optional<CodecInst> GetDecoder(int payload_type) const override;
 
-  rtc::Optional<SdpAudioFormat> GetDecoderFormat(
+  absl::optional<SdpAudioFormat> GetDecoderFormat(
       int payload_type) const override;
 
   int SetTargetNumberOfChannels() override;
@@ -336,12 +326,6 @@
   int DoDtmf(const DtmfEvent& dtmf_event, bool* play_dtmf)
       RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
 
-  // Produces packet-loss concealment using alternative methods. If the codec
-  // has an internal PLC, it is called to generate samples. Otherwise, the
-  // method performs zero-stuffing.
-  void DoAlternativePlc(bool increase_timestamp)
-      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
-
   // Overdub DTMF on top of |output|.
   int DtmfOverdub(const DtmfEvent& dtmf_event,
                   size_t num_channels,
@@ -418,19 +402,17 @@
   size_t decoder_frame_length_ RTC_GUARDED_BY(crit_sect_);
   Modes last_mode_ RTC_GUARDED_BY(crit_sect_);
   Operations last_operation_ RTC_GUARDED_BY(crit_sect_);
-  std::unique_ptr<int16_t[]> mute_factor_array_ RTC_GUARDED_BY(crit_sect_);
   size_t decoded_buffer_length_ RTC_GUARDED_BY(crit_sect_);
   std::unique_ptr<int16_t[]> decoded_buffer_ RTC_GUARDED_BY(crit_sect_);
   uint32_t playout_timestamp_ RTC_GUARDED_BY(crit_sect_);
   bool new_codec_ RTC_GUARDED_BY(crit_sect_);
   uint32_t timestamp_ RTC_GUARDED_BY(crit_sect_);
   bool reset_decoder_ RTC_GUARDED_BY(crit_sect_);
-  rtc::Optional<uint8_t> current_rtp_payload_type_ RTC_GUARDED_BY(crit_sect_);
-  rtc::Optional<uint8_t> current_cng_rtp_payload_type_
+  absl::optional<uint8_t> current_rtp_payload_type_ RTC_GUARDED_BY(crit_sect_);
+  absl::optional<uint8_t> current_cng_rtp_payload_type_
       RTC_GUARDED_BY(crit_sect_);
   uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_);
   bool first_packet_ RTC_GUARDED_BY(crit_sect_);
-  NetEqPlayoutMode playout_mode_ RTC_GUARDED_BY(crit_sect_);
   bool enable_fast_accelerate_ RTC_GUARDED_BY(crit_sect_);
   std::unique_ptr<NackTracker> nack_ RTC_GUARDED_BY(crit_sect_);
   bool nack_enabled_ RTC_GUARDED_BY(crit_sect_);
@@ -442,6 +424,7 @@
   std::vector<uint32_t> last_decoded_timestamps_ RTC_GUARDED_BY(crit_sect_);
   ExpandUmaLogger expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
   ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
+  bool no_time_stretching_ RTC_GUARDED_BY(crit_sect_);  // Only used for test.
 
  private:
   RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc
index de24cda..b772dfa 100644
--- a/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -314,7 +314,7 @@
       new rtc::RefCountedObject<MockAudioDecoderFactory>);
   EXPECT_CALL(*mock_decoder_factory, MakeAudioDecoderMock(_, _, _))
       .WillOnce(Invoke([&](const SdpAudioFormat& format,
-                           rtc::Optional<AudioCodecPairId> codec_pair_id,
+                           absl::optional<AudioCodecPairId> codec_pair_id,
                            std::unique_ptr<AudioDecoder>* dec) {
         EXPECT_EQ("pcmu", format.name);
 
@@ -334,7 +334,7 @@
 
         *dec = std::move(mock_decoder);
       }));
-  DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, rtc::nullopt,
+  DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu, absl::nullopt,
                                     mock_decoder_factory);
 
   // Expectations for decoder database.
@@ -518,10 +518,10 @@
   // The value of the last of the output samples is the same as the number of
   // samples played from the decoded packet. Thus, this number + the RTP
   // timestamp should match the playout timestamp.
-  // Wrap the expected value in an rtc::Optional to compare them as such.
+  // Wrap the expected value in an absl::optional to compare them as such.
   EXPECT_EQ(
-      rtc::Optional<uint32_t>(rtp_header.timestamp +
-                              output.data()[output.samples_per_channel_ - 1]),
+      absl::optional<uint32_t>(rtp_header.timestamp +
+                               output.data()[output.samples_per_channel_ - 1]),
       neteq_->GetPlayoutTimestamp());
 
   // Check the timestamp for the last value in the sync buffer. This should
@@ -783,12 +783,12 @@
 
   bool muted;
   EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
-  rtc::Optional<uint32_t> last_timestamp = neteq_->GetPlayoutTimestamp();
+  absl::optional<uint32_t> last_timestamp = neteq_->GetPlayoutTimestamp();
   ASSERT_TRUE(last_timestamp);
 
   // Lambda for verifying the timestamps.
   auto verify_timestamp = [&last_timestamp, &expected_timestamp_increment](
-      rtc::Optional<uint32_t> ts, size_t i) {
+                              absl::optional<uint32_t> ts, size_t i) {
     if (expected_timestamp_increment[i] == -1) {
       // Expect to get an empty timestamp value during CNG and PLC.
       EXPECT_FALSE(ts) << "i = " << i;
@@ -1377,32 +1377,6 @@
   uint16_t sequence_number_ = 1;
 };
 
-TEST_F(NetEqImplTest120ms, AudioRepetition) {
-  config_.playout_mode = kPlayoutFax;
-  CreateInstanceNoMocks();
-  Register120msCodec(AudioDecoder::kSpeech);
-
-  InsertPacket(first_timestamp());
-  GetFirstPacket();
-
-  bool muted;
-  EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
-  EXPECT_EQ(kAudioRepetition, neteq_->last_operation_for_test());
-}
-
-TEST_F(NetEqImplTest120ms, AlternativePlc) {
-  config_.playout_mode = kPlayoutOff;
-  CreateInstanceNoMocks();
-  Register120msCodec(AudioDecoder::kSpeech);
-
-  InsertPacket(first_timestamp());
-  GetFirstPacket();
-
-  bool muted;
-  EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output_, &muted));
-  EXPECT_EQ(kAlternativePlc, neteq_->last_operation_for_test());
-}
-
 TEST_F(NetEqImplTest120ms, CodecInternalCng) {
   CreateInstanceNoMocks();
   Register120msCodec(AudioDecoder::kComfortNoise);
diff --git a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
index b317099..57fc682 100644
--- a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc
@@ -46,7 +46,7 @@
 
     size_t Duration() const override { return kPacketDuration; }
 
-    rtc::Optional<DecodeResult> Decode(
+    absl::optional<DecodeResult> Decode(
         rtc::ArrayView<int16_t> decoded) const override {
       const size_t output_size =
           sizeof(int16_t) * kPacketDuration * num_channels_;
@@ -57,7 +57,7 @@
       } else {
         ADD_FAILURE() << "Expected decoded.size() to be >= output_size ("
                       << decoded.size() << " vs. " << output_size << ")";
-        return rtc::nullopt;
+        return absl::nullopt;
       }
     }
 
@@ -86,8 +86,8 @@
     return kPacketDuration;
   }
 
-  bool PacketHasFec(
-      const uint8_t* encoded, size_t encoded_len) const /* override */ {
+  bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const
+  /* override */ {
     ADD_FAILURE() << "Since going through ParsePayload, PacketHasFec should "
                      "never get called.";
     return fec_enabled_;
@@ -123,40 +123,40 @@
   static const int kPayloadSizeByte = 30;
   static const int kFrameSizeMs = 20;
 
-enum logic {
-  kIgnore,
-  kEqual,
-  kSmallerThan,
-  kLargerThan,
-};
+  enum logic {
+    kIgnore,
+    kEqual,
+    kSmallerThan,
+    kLargerThan,
+  };
 
-struct NetEqNetworkStatsCheck {
-  logic current_buffer_size_ms;
-  logic preferred_buffer_size_ms;
-  logic jitter_peaks_found;
-  logic packet_loss_rate;
-  logic expand_rate;
-  logic speech_expand_rate;
-  logic preemptive_rate;
-  logic accelerate_rate;
-  logic secondary_decoded_rate;
-  logic secondary_discarded_rate;
-  logic clockdrift_ppm;
-  logic added_zero_samples;
-  NetEqNetworkStatistics stats_ref;
-};
+  struct NetEqNetworkStatsCheck {
+    logic current_buffer_size_ms;
+    logic preferred_buffer_size_ms;
+    logic jitter_peaks_found;
+    logic packet_loss_rate;
+    logic expand_rate;
+    logic speech_expand_rate;
+    logic preemptive_rate;
+    logic accelerate_rate;
+    logic secondary_decoded_rate;
+    logic secondary_discarded_rate;
+    logic clockdrift_ppm;
+    logic added_zero_samples;
+    NetEqNetworkStatistics stats_ref;
+  };
 
-NetEqNetworkStatsTest(NetEqDecoder codec,
-                      int sample_rate_hz,
-                      MockAudioDecoder* decoder)
-    : NetEqExternalDecoderTest(codec, sample_rate_hz, decoder),
-      external_decoder_(decoder),
-      samples_per_ms_(sample_rate_hz / 1000),
-      frame_size_samples_(kFrameSizeMs * samples_per_ms_),
-      rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
-      last_lost_time_(0),
-      packet_loss_interval_(0xffffffff) {
-  Init();
+  NetEqNetworkStatsTest(NetEqDecoder codec,
+                        int sample_rate_hz,
+                        MockAudioDecoder* decoder)
+      : NetEqExternalDecoderTest(codec, sample_rate_hz, decoder),
+        external_decoder_(decoder),
+        samples_per_ms_(sample_rate_hz / 1000),
+        frame_size_samples_(kFrameSizeMs * samples_per_ms_),
+        rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
+        last_lost_time_(0),
+        packet_loss_interval_(0xffffffff) {
+    Init();
   }
 
   bool Lost(uint32_t send_time) {
@@ -168,8 +168,9 @@
   }
 
   void SetPacketLossRate(double loss_rate) {
-      packet_loss_interval_ = (loss_rate >= 1e-3 ?
-          static_cast<double>(kFrameSizeMs) / loss_rate : 0xffffffff);
+    packet_loss_interval_ =
+        (loss_rate >= 1e-3 ? static_cast<double>(kFrameSizeMs) / loss_rate
+                           : 0xffffffff);
   }
 
   // |stats_ref|
@@ -181,19 +182,19 @@
     NetEqNetworkStatistics stats;
     neteq()->NetworkStatistics(&stats);
 
-#define CHECK_NETEQ_NETWORK_STATS(x)\
-  switch (expects.x) {\
-    case kEqual:\
-      EXPECT_EQ(stats.x, expects.stats_ref.x);\
-      break;\
-    case kSmallerThan:\
-      EXPECT_LT(stats.x, expects.stats_ref.x);\
-      break;\
-    case kLargerThan:\
-      EXPECT_GT(stats.x, expects.stats_ref.x);\
-      break;\
-    default:\
-      break;\
+#define CHECK_NETEQ_NETWORK_STATS(x)           \
+  switch (expects.x) {                         \
+    case kEqual:                               \
+      EXPECT_EQ(stats.x, expects.stats_ref.x); \
+      break;                                   \
+    case kSmallerThan:                         \
+      EXPECT_LT(stats.x, expects.stats_ref.x); \
+      break;                                   \
+    case kLargerThan:                          \
+      EXPECT_GT(stats.x, expects.stats_ref.x); \
+      break;                                   \
+    default:                                   \
+      break;                                   \
   }
 
     CHECK_NETEQ_NETWORK_STATS(current_buffer_size_ms);
@@ -220,15 +221,13 @@
     uint32_t next_send_time;
 
     // Initiate |last_lost_time_|.
-    time_now = next_send_time = last_lost_time_ =
-        rtp_generator_->GetRtpHeader(kPayloadType, frame_size_samples_,
-                                     &rtp_header_);
+    time_now = next_send_time = last_lost_time_ = rtp_generator_->GetRtpHeader(
+        kPayloadType, frame_size_samples_, &rtp_header_);
     for (int k = 0; k < num_loops; ++k) {
       // Delay by one frame such that the FEC can come in.
       while (time_now + kFrameSizeMs >= next_send_time) {
-        next_send_time = rtp_generator_->GetRtpHeader(kPayloadType,
-                                                      frame_size_samples_,
-                                                      &rtp_header_);
+        next_send_time = rtp_generator_->GetRtpHeader(
+            kPayloadType, frame_size_samples_, &rtp_header_);
         if (!Lost(next_send_time)) {
           static const uint8_t payload[kPayloadSizeByte] = {0};
           InsertPacket(rtp_header_, payload, next_send_time);
@@ -243,21 +242,19 @@
 
   void DecodeFecTest() {
     external_decoder_->set_fec_enabled(false);
-    NetEqNetworkStatsCheck expects = {
-      kIgnore,  // current_buffer_size_ms
-      kIgnore,  // preferred_buffer_size_ms
-      kIgnore,  // jitter_peaks_found
-      kEqual,  // packet_loss_rate
-      kEqual,  // expand_rate
-      kEqual,  // voice_expand_rate
-      kIgnore,  // preemptive_rate
-      kEqual,  // accelerate_rate
-      kEqual,  // decoded_fec_rate
-      kEqual,  // discarded_fec_rate
-      kIgnore,  // clockdrift_ppm
-      kEqual,  // added_zero_samples
-      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-    };
+    NetEqNetworkStatsCheck expects = {kIgnore,  // current_buffer_size_ms
+                                      kIgnore,  // preferred_buffer_size_ms
+                                      kIgnore,  // jitter_peaks_found
+                                      kEqual,   // packet_loss_rate
+                                      kEqual,   // expand_rate
+                                      kEqual,   // voice_expand_rate
+                                      kIgnore,  // preemptive_rate
+                                      kEqual,   // accelerate_rate
+                                      kEqual,   // decoded_fec_rate
+                                      kEqual,   // discarded_fec_rate
+                                      kIgnore,  // clockdrift_ppm
+                                      kEqual,   // added_zero_samples
+                                      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
     RunTest(50, expects);
 
     // Next we introduce packet losses.
@@ -277,21 +274,19 @@
   }
 
   void NoiseExpansionTest() {
-    NetEqNetworkStatsCheck expects = {
-      kIgnore,  // current_buffer_size_ms
-      kIgnore,  // preferred_buffer_size_ms
-      kIgnore,  // jitter_peaks_found
-      kEqual,  // packet_loss_rate
-      kEqual,  // expand_rate
-      kEqual,  // speech_expand_rate
-      kIgnore,  // preemptive_rate
-      kEqual,  // accelerate_rate
-      kEqual,  // decoded_fec_rate
-      kEqual,  // discard_fec_rate
-      kIgnore,  // clockdrift_ppm
-      kEqual,  // added_zero_samples
-      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-    };
+    NetEqNetworkStatsCheck expects = {kIgnore,  // current_buffer_size_ms
+                                      kIgnore,  // preferred_buffer_size_ms
+                                      kIgnore,  // jitter_peaks_found
+                                      kEqual,   // packet_loss_rate
+                                      kEqual,   // expand_rate
+                                      kEqual,   // speech_expand_rate
+                                      kIgnore,  // preemptive_rate
+                                      kEqual,   // accelerate_rate
+                                      kEqual,   // decoded_fec_rate
+                                      kEqual,   // discard_fec_rate
+                                      kIgnore,  // clockdrift_ppm
+                                      kEqual,   // added_zero_samples
+                                      {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
     RunTest(50, expects);
 
     SetPacketLossRate(1);
diff --git a/modules/audio_coding/neteq/neteq_stereo_unittest.cc b/modules/audio_coding/neteq/neteq_stereo_unittest.cc
index 49facdd..ef4c235 100644
--- a/modules/audio_coding/neteq/neteq_stereo_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_stereo_unittest.cc
@@ -11,9 +11,9 @@
 // Test to verify correct stereo and multi-channel operation.
 
 #include <algorithm>
+#include <list>
 #include <memory>
 #include <string>
-#include <list>
 
 #include "api/audio/audio_frame.h"
 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
@@ -72,17 +72,17 @@
     input_ = new int16_t[frame_size_samples_];
     encoded_ = new uint8_t[2 * frame_size_samples_];
     input_multi_channel_ = new int16_t[frame_size_samples_ * num_channels_];
-    encoded_multi_channel_ = new uint8_t[frame_size_samples_ * 2 *
-                                         num_channels_];
+    encoded_multi_channel_ =
+        new uint8_t[frame_size_samples_ * 2 * num_channels_];
   }
 
   ~NetEqStereoTest() {
     delete neteq_mono_;
     delete neteq_;
-    delete [] input_;
-    delete [] encoded_;
-    delete [] input_multi_channel_;
-    delete [] encoded_multi_channel_;
+    delete[] input_;
+    delete[] encoded_;
+    delete[] input_multi_channel_;
+    delete[] encoded_multi_channel_;
   }
 
   virtual void SetUp() {
@@ -142,17 +142,15 @@
     if (!input_file_->Read(frame_size_samples_, input_)) {
       return -1;
     }
-    payload_size_bytes_ = WebRtcPcm16b_Encode(input_, frame_size_samples_,
-                                             encoded_);
+    payload_size_bytes_ =
+        WebRtcPcm16b_Encode(input_, frame_size_samples_, encoded_);
     if (frame_size_samples_ * 2 != payload_size_bytes_) {
       return -1;
     }
-    int next_send_time = rtp_generator_mono_.GetRtpHeader(kPayloadTypeMono,
-                                                          frame_size_samples_,
-                                                          &rtp_header_mono_);
-    test::InputAudioFile::DuplicateInterleaved(input_, frame_size_samples_,
-                                               num_channels_,
-                                               input_multi_channel_);
+    int next_send_time = rtp_generator_mono_.GetRtpHeader(
+        kPayloadTypeMono, frame_size_samples_, &rtp_header_mono_);
+    test::InputAudioFile::DuplicateInterleaved(
+        input_, frame_size_samples_, num_channels_, input_multi_channel_);
     multi_payload_size_bytes_ = WebRtcPcm16b_Encode(
         input_multi_channel_, frame_size_samples_ * num_channels_,
         encoded_multi_channel_);
@@ -267,8 +265,7 @@
 
 class NetEqStereoTestNoJitter : public NetEqStereoTest {
  protected:
-  NetEqStereoTestNoJitter()
-      : NetEqStereoTest() {
+  NetEqStereoTestNoJitter() : NetEqStereoTest() {
     // Start the sender 100 ms before the receiver to pre-fill the buffer.
     // This is to avoid doing preemptive expand early in the test.
     // TODO(hlundin): Mock the decision making instead to control the modes.
@@ -282,17 +279,15 @@
 
 class NetEqStereoTestPositiveDrift : public NetEqStereoTest {
  protected:
-  NetEqStereoTestPositiveDrift()
-      : NetEqStereoTest(),
-        drift_factor(0.9) {
+  NetEqStereoTestPositiveDrift() : NetEqStereoTest(), drift_factor(0.9) {
     // Start the sender 100 ms before the receiver to pre-fill the buffer.
     // This is to avoid doing preemptive expand early in the test.
     // TODO(hlundin): Mock the decision making instead to control the modes.
     last_arrival_time_ = -100;
   }
   virtual int GetArrivalTime(int send_time) {
-    int arrival_time = last_arrival_time_ +
-        drift_factor * (send_time - last_send_time_);
+    int arrival_time =
+        last_arrival_time_ + drift_factor * (send_time - last_send_time_);
     last_send_time_ = send_time;
     last_arrival_time_ = arrival_time;
     return arrival_time;
@@ -307,8 +302,7 @@
 
 class NetEqStereoTestNegativeDrift : public NetEqStereoTestPositiveDrift {
  protected:
-  NetEqStereoTestNegativeDrift()
-      : NetEqStereoTestPositiveDrift() {
+  NetEqStereoTestNegativeDrift() : NetEqStereoTestPositiveDrift() {
     drift_factor = 1.1;
     last_arrival_time_ = 0;
   }
@@ -322,10 +316,7 @@
  protected:
   static const int kDelayInterval = 10;
   static const int kDelay = 1000;
-  NetEqStereoTestDelays()
-      : NetEqStereoTest(),
-        frame_index_(0) {
-  }
+  NetEqStereoTestDelays() : NetEqStereoTest(), frame_index_(0) {}
 
   virtual int GetArrivalTime(int send_time) {
     // Deliver immediately, unless we have a back-log.
@@ -349,22 +340,16 @@
 class NetEqStereoTestLosses : public NetEqStereoTest {
  protected:
   static const int kLossInterval = 10;
-  NetEqStereoTestLosses()
-      : NetEqStereoTest(),
-        frame_index_(0) {
-  }
+  NetEqStereoTestLosses() : NetEqStereoTest(), frame_index_(0) {}
 
-  virtual bool Lost() {
-    return (++frame_index_) % kLossInterval == 0;
-  }
+  virtual bool Lost() { return (++frame_index_) % kLossInterval == 0; }
 
   // TODO(hlundin): NetEq is not giving bitexact results for these cases.
   virtual void VerifyOutput(size_t num_samples) {
     for (size_t i = 0; i < num_samples; ++i) {
       const int16_t* output_data = output_.data();
       const int16_t* output_multi_channel_data = output_multi_channel_.data();
-      auto first_channel_sample =
-          output_multi_channel_data[i * num_channels_];
+      auto first_channel_sample = output_multi_channel_data[i * num_channels_];
       for (size_t j = 0; j < num_channels_; ++j) {
         const int kErrorMargin = 200;
         EXPECT_NEAR(output_data[i],
@@ -384,7 +369,6 @@
   RunTest(100);
 }
 
-
 // Creates a list of parameter sets.
 std::list<TestParameters> GetTestParameters() {
   std::list<TestParameters> l;
@@ -412,9 +396,9 @@
 
 // Pretty-printing the test parameters in case of an error.
 void PrintTo(const TestParameters& p, ::std::ostream* os) {
-  *os << "{frame_size = " << p.frame_size <<
-      ", num_channels = " << p.num_channels <<
-      ", sample_rate = " << p.sample_rate << "}";
+  *os << "{frame_size = " << p.frame_size
+      << ", num_channels = " << p.num_channels
+      << ", sample_rate = " << p.sample_rate << "}";
 }
 
 // Instantiate the tests. Each test is instantiated using the function above,
diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc
index 4cd3014..5d43fdb 100644
--- a/modules/audio_coding/neteq/neteq_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_unittest.cc
@@ -25,6 +25,8 @@
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
 #include "modules/audio_coding/neteq/tools/audio_loop.h"
+#include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h"
+#include "modules/audio_coding/neteq/tools/neteq_test.h"
 #include "modules/audio_coding/neteq/tools/rtp_file_source.h"
 #include "rtc_base/ignore_wundef.h"
 #include "rtc_base/messagedigest.h"
@@ -61,17 +63,17 @@
                                     const std::string& checksum_win_32,
                                     const std::string& checksum_win_64) {
 #if defined(WEBRTC_ANDROID)
-  #ifdef WEBRTC_ARCH_64_BITS
-    return checksum_android_64;
-  #else
-    return checksum_android_32;
-  #endif  // WEBRTC_ARCH_64_BITS
+#ifdef WEBRTC_ARCH_64_BITS
+  return checksum_android_64;
+#else
+  return checksum_android_32;
+#endif  // WEBRTC_ARCH_64_BITS
 #elif defined(WEBRTC_WIN)
-  #ifdef WEBRTC_ARCH_64_BITS
-    return checksum_win_64;
-  #else
-    return checksum_win_32;
-  #endif  // WEBRTC_ARCH_64_BITS
+#ifdef WEBRTC_ARCH_64_BITS
+  return checksum_win_64;
+#else
+  return checksum_win_32;
+#endif  // WEBRTC_ARCH_64_BITS
 #else
   return checksum_general;
 #endif  // WEBRTC_WIN
@@ -107,7 +109,8 @@
   stats->set_jitter(stats_raw.jitter);
 }
 
-void AddMessage(FILE* file, rtc::MessageDigest* digest,
+void AddMessage(FILE* file,
+                rtc::MessageDigest* digest,
                 const std::string& message) {
   int32_t size = message.length();
   if (file)
@@ -164,7 +167,8 @@
   explicit ResultSink(const std::string& output_file);
   ~ResultSink();
 
-  template<typename T> void AddResult(const T* test_results, size_t length);
+  template <typename T>
+  void AddResult(const T* test_results, size_t length);
 
   void AddResult(const NetEqNetworkStatistics& stats);
   void AddResult(const RtcpStatistics& stats);
@@ -190,7 +194,7 @@
     fclose(output_fp_);
 }
 
-template<typename T>
+template <typename T>
 void ResultSink::AddResult(const T* test_results, size_t length) {
   if (output_fp_) {
     ASSERT_EQ(length, fwrite(test_results, sizeof(T), length, output_fp_));
@@ -247,7 +251,7 @@
   virtual void SetUp();
   virtual void TearDown();
   void SelectDecoders(NetEqDecoder* used_codec);
-  void OpenInputFile(const std::string &rtp_file);
+  void OpenInputFile(const std::string& rtp_file);
   void Process();
 
   void DecodeAndCompare(const std::string& rtp_file,
@@ -265,9 +269,11 @@
                           uint8_t* payload,
                           size_t* payload_len);
 
-  void WrapTest(uint16_t start_seq_no, uint32_t start_timestamp,
+  void WrapTest(uint16_t start_seq_no,
+                uint32_t start_timestamp,
                 const std::set<uint16_t>& drop_seq_numbers,
-                bool expect_seq_no_wrap, bool expect_timestamp_wrap);
+                bool expect_seq_no_wrap,
+                bool expect_timestamp_wrap);
 
   void LongCngWithClockDrift(double drift_factor,
                              double network_freeze_ms,
@@ -316,7 +322,7 @@
   delete neteq_;
 }
 
-void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
+void NetEqDecodingTest::OpenInputFile(const std::string& rtp_file) {
   rtp_source_.reset(test::RtpFileSource::Create(rtp_file));
 }
 
@@ -384,8 +390,8 @@
     ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
     SCOPED_TRACE(ss.str());  // Print out the parameter values on failure.
     ASSERT_NO_FATAL_FAILURE(Process());
-    ASSERT_NO_FATAL_FAILURE(output.AddResult(
-        out_frame_.data(), out_frame_.samples_per_channel_));
+    ASSERT_NO_FATAL_FAILURE(
+        output.AddResult(out_frame_.data(), out_frame_.samples_per_channel_));
 
     // Query the network statistics API once per second
     if (sim_clock_ % 1000 == 0) {
@@ -447,7 +453,7 @@
   rtp_info->ssrc = 0x1234;     // Just an arbitrary SSRC.
   rtp_info->payloadType = 98;  // WB CNG.
   rtp_info->markerBit = 0;
-  payload[0] = 64;  // Noise level -64 dBov, quite arbitrarily chosen.
+  payload[0] = 64;   // Noise level -64 dBov, quite arbitrarily chosen.
   *payload_len = 1;  // Only noise level, no spectral parameters.
 }
 
@@ -462,36 +468,29 @@
   const std::string input_rtp_file =
       webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
 
-  const std::string output_checksum = PlatformChecksum(
-      "09fa7646e2ad032a0b156177b95f09012430f81f",
-      "1c64eb8b55ce8878676c6a1e6ddd78f48de0668b",
-      "not used",
-      "09fa7646e2ad032a0b156177b95f09012430f81f",
-      "759fef89a5de52bd17e733dc255c671ce86be909");
+  const std::string output_checksum =
+      PlatformChecksum("0c6dc227f781c81a229970f8fceda1a012498cba",
+                       "15c4a2202877a414515e218bdb7992f0ad53e5af", "not used",
+                       "0c6dc227f781c81a229970f8fceda1a012498cba",
+                       "25fc4c863caa499aa447a5b8d059f5452cbcc500");
 
   const std::string network_stats_checksum =
-      PlatformChecksum("5b4262ca328e5f066af5d34f3380521583dd20de",
-                       "80235b6d727281203acb63b98f9a9e85d95f7ec0",
-                       "not used",
-                       "5b4262ca328e5f066af5d34f3380521583dd20de",
-                       "5b4262ca328e5f066af5d34f3380521583dd20de");
+      PlatformChecksum("4b2370f5c794741d2a46be5c7935c66ef3fb53e9",
+                       "e339cb2adf5ab3dfc21cb7205d670a34751e8336", "not used",
+                       "4b2370f5c794741d2a46be5c7935c66ef3fb53e9",
+                       "4b2370f5c794741d2a46be5c7935c66ef3fb53e9");
 
-  const std::string rtcp_stats_checksum = PlatformChecksum(
-      "b8880bf9fed2487efbddcb8d94b9937a29ae521d",
-      "f3f7b3d3e71d7e635240b5373b57df6a7e4ce9d4",
-      "not used",
-      "b8880bf9fed2487efbddcb8d94b9937a29ae521d",
-      "b8880bf9fed2487efbddcb8d94b9937a29ae521d");
+  const std::string rtcp_stats_checksum =
+      PlatformChecksum("b8880bf9fed2487efbddcb8d94b9937a29ae521d",
+                       "f3f7b3d3e71d7e635240b5373b57df6a7e4ce9d4", "not used",
+                       "b8880bf9fed2487efbddcb8d94b9937a29ae521d",
+                       "b8880bf9fed2487efbddcb8d94b9937a29ae521d");
 
-  DecodeAndCompare(input_rtp_file,
-                   output_checksum,
-                   network_stats_checksum,
-                   rtcp_stats_checksum,
-                   FLAG_gen_ref);
+  DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
+                   rtcp_stats_checksum, FLAG_gen_ref);
 }
 
-#if !defined(WEBRTC_IOS) &&                                         \
-    defined(WEBRTC_NETEQ_UNITTEST_BITEXACT) &&                      \
+#if !defined(WEBRTC_IOS) && defined(WEBRTC_NETEQ_UNITTEST_BITEXACT) && \
     defined(WEBRTC_CODEC_OPUS)
 #define MAYBE_TestOpusBitExactness TestOpusBitExactness
 #else
@@ -501,36 +500,32 @@
   const std::string input_rtp_file =
       webrtc::test::ResourcePath("audio_coding/neteq_opus", "rtp");
 
-  const std::string output_checksum = PlatformChecksum(
-      "7ea28d7edf9395f4ac8e8d8dd3a9e5c620b1bf48",
-      "5b1e691ab1c4465c742d6d944bc71e3b1c0e4c0e",
-      "b096114dd8c233eaf2b0ce9802ac95af13933772",
-      "7ea28d7edf9395f4ac8e8d8dd3a9e5c620b1bf48",
-      "7ea28d7edf9395f4ac8e8d8dd3a9e5c620b1bf48");
+  const std::string output_checksum =
+      PlatformChecksum("14a63b3c7b925c82296be4bafc71bec85f2915c2",
+                       "b7b7ed802b0e18ee416973bf3b9ae98599b0181d",
+                       "5876e52dda90d5ca433c3726555b907b97c86374",
+                       "14a63b3c7b925c82296be4bafc71bec85f2915c2",
+                       "14a63b3c7b925c82296be4bafc71bec85f2915c2");
 
   const std::string network_stats_checksum =
-      PlatformChecksum("9e72233c78baf685e500dd6c94212b30a4c5f27d",
-                       "9a37270e4242fbd31e80bb47dc5e7ab82cf2d557",
-                       "4f1e9734bc80a290faaf9d611efcb8d7802dbc4f",
-                       "9e72233c78baf685e500dd6c94212b30a4c5f27d",
-                       "9e72233c78baf685e500dd6c94212b30a4c5f27d");
+      PlatformChecksum("adb3272498e436d1c019cbfd71610e9510c54497",
+                       "fa935a91abc7291db47428a2d7c5361b98713a92",
+                       "42106aa5267300f709f63737707ef07afd9dac61",
+                       "adb3272498e436d1c019cbfd71610e9510c54497",
+                       "adb3272498e436d1c019cbfd71610e9510c54497");
 
-  const std::string rtcp_stats_checksum = PlatformChecksum(
-      "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
-      "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
-      "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
-      "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
-      "e37c797e3de6a64dda88c9ade7a013d022a2e1e0");
+  const std::string rtcp_stats_checksum =
+      PlatformChecksum("e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
+                       "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
+                       "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
+                       "e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
+                       "e37c797e3de6a64dda88c9ade7a013d022a2e1e0");
 
-  DecodeAndCompare(input_rtp_file,
-                   output_checksum,
-                   network_stats_checksum,
-                   rtcp_stats_checksum,
-                   FLAG_gen_ref);
+  DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
+                   rtcp_stats_checksum, FLAG_gen_ref);
 }
 
-#if !defined(WEBRTC_IOS) &&                                         \
-    defined(WEBRTC_NETEQ_UNITTEST_BITEXACT) &&                      \
+#if !defined(WEBRTC_IOS) && defined(WEBRTC_NETEQ_UNITTEST_BITEXACT) && \
     defined(WEBRTC_CODEC_OPUS)
 #define MAYBE_TestOpusDtxBitExactness TestOpusDtxBitExactness
 #else
@@ -562,7 +557,7 @@
 class NetEqDecodingTestFaxMode : public NetEqDecodingTest {
  protected:
   NetEqDecodingTestFaxMode() : NetEqDecodingTest() {
-    config_.playout_mode = kPlayoutFax;
+    config_.for_test_no_time_stretching = true;
   }
   void TestJitterBufferDelay(bool apply_packet_loss);
 };
@@ -698,7 +693,7 @@
   }
 
   EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
-  rtc::Optional<uint32_t> playout_timestamp = neteq_->GetPlayoutTimestamp();
+  absl::optional<uint32_t> playout_timestamp = neteq_->GetPlayoutTimestamp();
   ASSERT_TRUE(playout_timestamp);
   int32_t delay_before = timestamp - *playout_timestamp;
 
@@ -805,10 +800,8 @@
   const bool kGetAudioDuringFreezeRecovery = false;
   const int kDelayToleranceMs = 20;
   const int kMaxTimeToSpeechMs = 100;
-  LongCngWithClockDrift(kDriftFactor,
-                        kNetworkFreezeTimeMs,
-                        kGetAudioDuringFreezeRecovery,
-                        kDelayToleranceMs,
+  LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs,
+                        kGetAudioDuringFreezeRecovery, kDelayToleranceMs,
                         kMaxTimeToSpeechMs);
 }
 
@@ -819,10 +812,8 @@
   const bool kGetAudioDuringFreezeRecovery = false;
   const int kDelayToleranceMs = 20;
   const int kMaxTimeToSpeechMs = 100;
-  LongCngWithClockDrift(kDriftFactor,
-                        kNetworkFreezeTimeMs,
-                        kGetAudioDuringFreezeRecovery,
-                        kDelayToleranceMs,
+  LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs,
+                        kGetAudioDuringFreezeRecovery, kDelayToleranceMs,
                         kMaxTimeToSpeechMs);
 }
 
@@ -833,10 +824,8 @@
   const bool kGetAudioDuringFreezeRecovery = false;
   const int kDelayToleranceMs = 50;
   const int kMaxTimeToSpeechMs = 200;
-  LongCngWithClockDrift(kDriftFactor,
-                        kNetworkFreezeTimeMs,
-                        kGetAudioDuringFreezeRecovery,
-                        kDelayToleranceMs,
+  LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs,
+                        kGetAudioDuringFreezeRecovery, kDelayToleranceMs,
                         kMaxTimeToSpeechMs);
 }
 
@@ -847,10 +836,8 @@
   const bool kGetAudioDuringFreezeRecovery = false;
   const int kDelayToleranceMs = 20;
   const int kMaxTimeToSpeechMs = 100;
-  LongCngWithClockDrift(kDriftFactor,
-                        kNetworkFreezeTimeMs,
-                        kGetAudioDuringFreezeRecovery,
-                        kDelayToleranceMs,
+  LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs,
+                        kGetAudioDuringFreezeRecovery, kDelayToleranceMs,
                         kMaxTimeToSpeechMs);
 }
 
@@ -861,10 +848,8 @@
   const bool kGetAudioDuringFreezeRecovery = true;
   const int kDelayToleranceMs = 20;
   const int kMaxTimeToSpeechMs = 100;
-  LongCngWithClockDrift(kDriftFactor,
-                        kNetworkFreezeTimeMs,
-                        kGetAudioDuringFreezeRecovery,
-                        kDelayToleranceMs,
+  LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs,
+                        kGetAudioDuringFreezeRecovery, kDelayToleranceMs,
                         kMaxTimeToSpeechMs);
 }
 
@@ -874,10 +859,8 @@
   const bool kGetAudioDuringFreezeRecovery = false;
   const int kDelayToleranceMs = 10;
   const int kMaxTimeToSpeechMs = 50;
-  LongCngWithClockDrift(kDriftFactor,
-                        kNetworkFreezeTimeMs,
-                        kGetAudioDuringFreezeRecovery,
-                        kDelayToleranceMs,
+  LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs,
+                        kGetAudioDuringFreezeRecovery, kDelayToleranceMs,
                         kMaxTimeToSpeechMs);
 }
 
@@ -1002,11 +985,11 @@
       ASSERT_EQ(AudioFrame::kNormalSpeech, output.speech_type_);
 
       // Next packet.
-      rtp_info.timestamp += rtc::checked_cast<uint32_t>(
-          expected_samples_per_channel);
+      rtp_info.timestamp +=
+          rtc::checked_cast<uint32_t>(expected_samples_per_channel);
       rtp_info.sequenceNumber++;
-      receive_timestamp += rtc::checked_cast<uint32_t>(
-          expected_samples_per_channel);
+      receive_timestamp +=
+          rtc::checked_cast<uint32_t>(expected_samples_per_channel);
     }
 
     output.Reset();
@@ -1099,8 +1082,8 @@
       if (packets_inserted > 4) {
         // Expect preferred and actual buffer size to be no more than 2 frames.
         EXPECT_LE(network_stats.preferred_buffer_size_ms, kFrameSizeMs * 2);
-        EXPECT_LE(network_stats.current_buffer_size_ms, kFrameSizeMs * 2 +
-                  algorithmic_delay_ms_);
+        EXPECT_LE(network_stats.current_buffer_size_ms,
+                  kFrameSizeMs * 2 + algorithmic_delay_ms_);
       }
       last_seq_no = seq_no;
       last_timestamp = timestamp;
@@ -1121,7 +1104,7 @@
     ASSERT_EQ(1u, output.num_channels_);
 
     // Expect delay (in samples) to be less than 2 packets.
-    rtc::Optional<uint32_t> playout_timestamp = neteq_->GetPlayoutTimestamp();
+    absl::optional<uint32_t> playout_timestamp = neteq_->GetPlayoutTimestamp();
     ASSERT_TRUE(playout_timestamp);
     EXPECT_LE(timestamp - *playout_timestamp,
               static_cast<uint32_t>(kSamples * 2));
@@ -1166,8 +1149,8 @@
   const int kSamples = kFrameSizeMs * kSampleRateKhz;
   const size_t kPayloadBytes = kSamples * 2;
 
-  const int algorithmic_delay_samples = std::max(
-      algorithmic_delay_ms_ * kSampleRateKhz, 5 * kSampleRateKhz / 8);
+  const int algorithmic_delay_samples =
+      std::max(algorithmic_delay_ms_ * kSampleRateKhz, 5 * kSampleRateKhz / 8);
   // Insert three speech packets. Three are needed to get the frame length
   // correct.
   uint8_t payload[kPayloadBytes] = {0};
@@ -1233,13 +1216,15 @@
   ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted));
   ASSERT_EQ(kBlockSize16kHz, out_frame_.samples_per_channel_);
   EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
-  rtc::Optional<uint32_t> playout_timestamp = neteq_->GetPlayoutTimestamp();
+  absl::optional<uint32_t> playout_timestamp = neteq_->GetPlayoutTimestamp();
   ASSERT_TRUE(playout_timestamp);
   EXPECT_EQ(timestamp + kSamples - algorithmic_delay_samples,
             *playout_timestamp);
 }
 
-TEST_F(NetEqDecodingTest, DiscardDuplicateCng) { DuplicateCng(); }
+TEST_F(NetEqDecodingTest, DiscardDuplicateCng) {
+  DuplicateCng();
+}
 
 TEST_F(NetEqDecodingTest, CngFirst) {
   uint16_t seq_no = 0;
@@ -1493,25 +1478,25 @@
     return ::testing::AssertionFailure() << "timestamp_ diff (" << a.timestamp_
                                          << " != " << b.timestamp_ << ")";
   if (a.sample_rate_hz_ != b.sample_rate_hz_)
-    return ::testing::AssertionFailure() << "sample_rate_hz_ diff ("
-                                         << a.sample_rate_hz_
-                                         << " != " << b.sample_rate_hz_ << ")";
+    return ::testing::AssertionFailure()
+           << "sample_rate_hz_ diff (" << a.sample_rate_hz_
+           << " != " << b.sample_rate_hz_ << ")";
   if (a.samples_per_channel_ != b.samples_per_channel_)
     return ::testing::AssertionFailure()
            << "samples_per_channel_ diff (" << a.samples_per_channel_
            << " != " << b.samples_per_channel_ << ")";
   if (a.num_channels_ != b.num_channels_)
-    return ::testing::AssertionFailure() << "num_channels_ diff ("
-                                         << a.num_channels_
-                                         << " != " << b.num_channels_ << ")";
+    return ::testing::AssertionFailure()
+           << "num_channels_ diff (" << a.num_channels_
+           << " != " << b.num_channels_ << ")";
   if (a.speech_type_ != b.speech_type_)
-    return ::testing::AssertionFailure() << "speech_type_ diff ("
-                                         << a.speech_type_
-                                         << " != " << b.speech_type_ << ")";
+    return ::testing::AssertionFailure()
+           << "speech_type_ diff (" << a.speech_type_
+           << " != " << b.speech_type_ << ")";
   if (a.vad_activity_ != b.vad_activity_)
-    return ::testing::AssertionFailure() << "vad_activity_ diff ("
-                                         << a.vad_activity_
-                                         << " != " << b.vad_activity_ << ")";
+    return ::testing::AssertionFailure()
+           << "vad_activity_ diff (" << a.vad_activity_
+           << " != " << b.vad_activity_ << ")";
   return ::testing::AssertionSuccess();
 }
 
@@ -1520,9 +1505,9 @@
   ::testing::AssertionResult res = AudioFramesEqualExceptData(a, b);
   if (!res)
     return res;
-  if (memcmp(
-      a.data(), b.data(),
-      a.samples_per_channel_ * a.num_channels_ * sizeof(*a.data())) != 0) {
+  if (memcmp(a.data(), b.data(),
+             a.samples_per_channel_ * a.num_channels_ * sizeof(*a.data())) !=
+      0) {
     return ::testing::AssertionFailure() << "data_ diff";
   }
   return ::testing::AssertionSuccess();
@@ -1740,4 +1725,32 @@
   TestJitterBufferDelay(true);
 }
 
+namespace test {
+TEST(NetEqNoTimeStretchingMode, RunTest) {
+  NetEq::Config config;
+  config.for_test_no_time_stretching = true;
+  auto codecs = NetEqTest::StandardDecoderMap();
+  NetEqTest::ExtDecoderMap ext_codecs;
+  NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
+      {1, kRtpExtensionAudioLevel},
+      {3, kRtpExtensionAbsoluteSendTime},
+      {5, kRtpExtensionTransportSequenceNumber},
+      {7, kRtpExtensionVideoContentType},
+      {8, kRtpExtensionVideoTiming}};
+  std::unique_ptr<NetEqInput> input(new NetEqRtpDumpInput(
+      webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"),
+      rtp_ext_map));
+  std::unique_ptr<TimeLimitedNetEqInput> input_time_limit(
+      new TimeLimitedNetEqInput(std::move(input), 20000));
+  std::unique_ptr<AudioSink> output(new VoidAudioSink);
+  NetEqTest::Callbacks callbacks;
+  NetEqTest test(config, codecs, ext_codecs, std::move(input_time_limit),
+                 std::move(output), callbacks);
+  test.Run();
+  const auto stats = test.SimulationStats();
+  EXPECT_EQ(0, stats.accelerate_rate);
+  EXPECT_EQ(0, stats.preemptive_rate);
+}
+
+}  // namespace test
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/normal.cc b/modules/audio_coding/neteq/normal.cc
index 48d723a..83f7616 100644
--- a/modules/audio_coding/neteq/normal.cc
+++ b/modules/audio_coding/neteq/normal.cc
@@ -27,7 +27,6 @@
 int Normal::Process(const int16_t* input,
                     size_t length,
                     Modes last_mode,
-                    int16_t* external_mute_factor_array,
                     AudioMultiVector* output) {
   if (length == 0) {
     // Nothing to process.
@@ -66,10 +65,8 @@
     size_t length_per_channel = length / output->Channels();
     std::unique_ptr<int16_t[]> signal(new int16_t[length_per_channel]);
     for (size_t channel_ix = 0; channel_ix < output->Channels(); ++channel_ix) {
-      // Adjust muting factor (main muting factor times expand muting factor).
-      external_mute_factor_array[channel_ix] = static_cast<int16_t>(
-          (external_mute_factor_array[channel_ix] *
-          expand_->MuteFactor(channel_ix)) >> 14);
+      // Set muting factor to the same as expand muting factor.
+      int16_t mute_factor = expand_->MuteFactor(channel_ix);
 
       (*output)[channel_ix].CopyTo(length_per_channel, 0, signal.get());
 
@@ -79,8 +76,7 @@
       // Adjust muting factor if needed (to BGN level).
       size_t energy_length =
           std::min(static_cast<size_t>(fs_mult * 64), length_per_channel);
-      int scaling = 6 + fs_shift
-          - WebRtcSpl_NormW32(decoded_max * decoded_max);
+      int scaling = 6 + fs_shift - WebRtcSpl_NormW32(decoded_max * decoded_max);
       scaling = std::max(scaling, 0);  // |scaling| should always be >= 0.
       int32_t energy = WebRtcSpl_DotProductWithScale(signal.get(), signal.get(),
                                                      energy_length, scaling);
@@ -92,9 +88,8 @@
         energy = 0;
       }
 
-      int mute_factor;
-      if ((energy != 0) &&
-          (energy > background_noise_.Energy(channel_ix))) {
+      int local_mute_factor = 16384;  // 1.0 in Q14.
+      if ((energy != 0) && (energy > background_noise_.Energy(channel_ix))) {
         // Normalize new frame energy to 15 bits.
         scaling = WebRtcSpl_NormW32(energy) - 16;
         // We want background_noise_.energy() / energy in Q14.
@@ -103,29 +98,30 @@
         int16_t energy_scaled =
             static_cast<int16_t>(WEBRTC_SPL_SHIFT_W32(energy, scaling));
         int32_t ratio = WebRtcSpl_DivW32W16(bgn_energy, energy_scaled);
-        mute_factor = WebRtcSpl_SqrtFloor(ratio << 14);
-      } else {
-        mute_factor = 16384;  // 1.0 in Q14.
+        local_mute_factor =
+            std::min(local_mute_factor, WebRtcSpl_SqrtFloor(ratio << 14));
       }
-      if (mute_factor > external_mute_factor_array[channel_ix]) {
-        external_mute_factor_array[channel_ix] =
-            static_cast<int16_t>(std::min(mute_factor, 16384));
-      }
+      mute_factor = std::max<int16_t>(mute_factor, local_mute_factor);
+      RTC_DCHECK_LE(mute_factor, 16384);
+      RTC_DCHECK_GE(mute_factor, 0);
 
-      // If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14).
-      int increment = 64 / fs_mult;
+      // If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14),
+      // or as fast as it takes to come back to full gain within the frame
+      // length.
+      const int back_to_fullscale_inc =
+          static_cast<int>((16384 - mute_factor) / length_per_channel);
+      const int increment = std::max(64 / fs_mult, back_to_fullscale_inc);
       for (size_t i = 0; i < length_per_channel; i++) {
         // Scale with mute factor.
         RTC_DCHECK_LT(channel_ix, output->Channels());
         RTC_DCHECK_LT(i, output->Size());
-        int32_t scaled_signal = (*output)[channel_ix][i] *
-            external_mute_factor_array[channel_ix];
+        int32_t scaled_signal = (*output)[channel_ix][i] * mute_factor;
         // Shift 14 with proper rounding.
         (*output)[channel_ix][i] =
             static_cast<int16_t>((scaled_signal + 8192) >> 14);
         // Increase mute_factor towards 16384.
-        external_mute_factor_array[channel_ix] = static_cast<int16_t>(std::min(
-            external_mute_factor_array[channel_ix] + increment, 16384));
+        mute_factor =
+            static_cast<int16_t>(std::min(mute_factor + increment, 16384));
       }
 
       // Interpolate the expanded data into the new vector.
@@ -153,8 +149,6 @@
     static const size_t kCngLength = 48;
     RTC_DCHECK_LE(8 * fs_mult, kCngLength);
     int16_t cng_output[kCngLength];
-    // Reset mute factor and start up fresh.
-    external_mute_factor_array[0] = 16384;
     ComfortNoiseDecoder* cng_decoder = decoder_database_->GetActiveCngDecoder();
 
     if (cng_decoder) {
@@ -186,28 +180,6 @@
     }
     RTC_DCHECK_GT(win_up_Q14,
                   (1 << 14) - 32);  // Worst case rouding is a length of 34
-  } else if (external_mute_factor_array[0] < 16384) {
-    // Previous was neither of Expand, FadeToBGN or RFC3389_CNG, but we are
-    // still ramping up from previous muting.
-    // If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14).
-    int increment = 64 / fs_mult;
-    size_t length_per_channel = length / output->Channels();
-    for (size_t i = 0; i < length_per_channel; i++) {
-      for (size_t channel_ix = 0; channel_ix < output->Channels();
-          ++channel_ix) {
-        // Scale with mute factor.
-        RTC_DCHECK_LT(channel_ix, output->Channels());
-        RTC_DCHECK_LT(i, output->Size());
-        int32_t scaled_signal = (*output)[channel_ix][i] *
-            external_mute_factor_array[channel_ix];
-        // Shift 14 with proper rounding.
-        (*output)[channel_ix][i] =
-            static_cast<int16_t>((scaled_signal + 8192) >> 14);
-        // Increase mute_factor towards 16384.
-        external_mute_factor_array[channel_ix] = static_cast<int16_t>(std::min(
-            16384, external_mute_factor_array[channel_ix] + increment));
-      }
-    }
   }
 
   return static_cast<int>(length);
diff --git a/modules/audio_coding/neteq/normal.h b/modules/audio_coding/neteq/normal.h
index ab02217..41bd30a 100644
--- a/modules/audio_coding/neteq/normal.h
+++ b/modules/audio_coding/neteq/normal.h
@@ -53,11 +53,10 @@
   // result is written to |output|. The number of channels allocated in
   // |output| defines the number of channels that will be used when
   // de-interleaving |input|. |last_mode| contains the mode used in the previous
-  // GetAudio call (i.e., not the current one), and |external_mute_factor| is
-  // a pointer to the mute factor in the NetEqImpl class.
-  int Process(const int16_t* input, size_t length,
+  // GetAudio call (i.e., not the current one).
+  int Process(const int16_t* input,
+              size_t length,
               Modes last_mode,
-              int16_t* external_mute_factor_array,
               AudioMultiVector* output);
 
  private:
diff --git a/modules/audio_coding/neteq/normal_unittest.cc b/modules/audio_coding/neteq/normal_unittest.cc
index b0655d9..106762a 100644
--- a/modules/audio_coding/neteq/normal_unittest.cc
+++ b/modules/audio_coding/neteq/normal_unittest.cc
@@ -39,7 +39,7 @@
   return 0;
 }
 
-} // namespace
+}  // namespace
 
 TEST(Normal, CreateAndDestroy) {
   MockDecoderDatabase db;
@@ -68,16 +68,10 @@
   Normal normal(fs, &db, bgn, &expand);
 
   int16_t input[1000] = {0};
-  std::unique_ptr<int16_t[]> mute_factor_array(new int16_t[channels]);
-  for (size_t i = 0; i < channels; ++i) {
-    mute_factor_array[i] = 16384;
-  }
   AudioMultiVector output(channels);
 
   // Zero input length.
-  EXPECT_EQ(
-      0,
-      normal.Process(input, 0, kModeExpand, mute_factor_array.get(), &output));
+  EXPECT_EQ(0, normal.Process(input, 0, kModeExpand, &output));
   EXPECT_EQ(0u, output.Size());
 
   // Try to make energy_length >> scaling = 0;
@@ -90,11 +84,7 @@
   // and using this as a denominator would lead to problems.
   int input_size_samples = 63;
   EXPECT_EQ(input_size_samples,
-            normal.Process(input,
-                           input_size_samples,
-                           kModeExpand,
-                           mute_factor_array.get(),
-                           &output));
+            normal.Process(input, input_size_samples, kModeExpand, &output));
 
   EXPECT_CALL(db, Die());      // Called when |db| goes out of scope.
   EXPECT_CALL(expand, Die());  // Called when |expand| goes out of scope.
@@ -114,18 +104,11 @@
   Normal normal(fs, &db, bgn, &expand);
 
   int16_t input[1000] = {0};
-  std::unique_ptr<int16_t[]> mute_factor_array(new int16_t[channels]);
-  for (size_t i = 0; i < channels; ++i) {
-    mute_factor_array[i] = 16384;
-  }
   AudioMultiVector output(channels);
 
   // Let the number of samples be one sample less than 80 samples per channel.
   size_t input_len = 80 * channels - 1;
-  EXPECT_EQ(
-      0,
-      normal.Process(
-          input, input_len, kModeExpand, mute_factor_array.get(), &output));
+  EXPECT_EQ(0, normal.Process(input, input_len, kModeExpand, &output));
   EXPECT_EQ(0u, output.Size());
 
   EXPECT_CALL(db, Die());      // Called when |db| goes out of scope.
@@ -147,23 +130,13 @@
   Normal normal(kFs, &db, bgn, &expand);
 
   int16_t input[kPacketsizeBytes] = {0};
-
-  std::unique_ptr<int16_t[]> mute_factor_array(new int16_t[kChannels]);
-  for (size_t i = 0; i < kChannels; ++i) {
-    mute_factor_array[i] = 16384;
-  }
-
   AudioMultiVector output(kChannels);
 
   EXPECT_CALL(expand, SetParametersForNormalAfterExpand());
   EXPECT_CALL(expand, Process(_)).WillOnce(Invoke(ExpandProcess120ms));
   EXPECT_CALL(expand, Reset());
   EXPECT_EQ(static_cast<int>(kPacketsizeBytes),
-            normal.Process(input,
-                           kPacketsizeBytes,
-                           kModeExpand,
-                           mute_factor_array.get(),
-                           &output));
+            normal.Process(input, kPacketsizeBytes, kModeExpand, &output));
 
   EXPECT_EQ(kPacketsizeBytes, output.Size());
 
diff --git a/modules/audio_coding/neteq/packet_buffer.cc b/modules/audio_coding/neteq/packet_buffer.cc
index dfffebd..c04534e 100644
--- a/modules/audio_coding/neteq/packet_buffer.cc
+++ b/modules/audio_coding/neteq/packet_buffer.cc
@@ -29,11 +29,8 @@
 class NewTimestampIsLarger {
  public:
   explicit NewTimestampIsLarger(const Packet& new_packet)
-      : new_packet_(new_packet) {
-  }
-  bool operator()(const Packet& packet) {
-    return (new_packet_ >= packet);
-  }
+      : new_packet_(new_packet) {}
+  bool operator()(const Packet& packet) { return (new_packet_ >= packet); }
 
  private:
   const Packet& new_packet_;
@@ -102,8 +99,7 @@
   // should be inserted. The list is searched from the back, since the most
   // likely case is that the new packet should be near the end of the list.
   PacketList::reverse_iterator rit = std::find_if(
-      buffer_.rbegin(), buffer_.rend(),
-      NewTimestampIsLarger(packet));
+      buffer_.rbegin(), buffer_.rend(), NewTimestampIsLarger(packet));
 
   // The new packet is to be inserted to the right of |rit|. If it has the same
   // timestamp as |rit|, which has a higher priority, do not insert the new
@@ -118,7 +114,7 @@
   // packet.
   PacketList::iterator it = rit.base();
   if (it != buffer_.end() && packet.timestamp == it->timestamp) {
-    LogPacketDiscarded(packet.priority.codec_level, stats);
+    LogPacketDiscarded(it->priority.codec_level, stats);
     it = buffer_.erase(it);
   }
   buffer_.insert(it, std::move(packet));  // Insert the packet at that position.
@@ -129,8 +125,8 @@
 int PacketBuffer::InsertPacketList(
     PacketList* packet_list,
     const DecoderDatabase& decoder_database,
-    rtc::Optional<uint8_t>* current_rtp_payload_type,
-    rtc::Optional<uint8_t>* current_cng_rtp_payload_type,
+    absl::optional<uint8_t>* current_rtp_payload_type,
+    absl::optional<uint8_t>* current_cng_rtp_payload_type,
     StatisticsCalculator* stats) {
   RTC_DCHECK(stats);
   bool flushed = false;
@@ -139,7 +135,7 @@
       if (*current_cng_rtp_payload_type &&
           **current_cng_rtp_payload_type != packet.payload_type) {
         // New CNG payload type implies new codec type.
-        *current_rtp_payload_type = rtc::nullopt;
+        *current_rtp_payload_type = absl::nullopt;
         Flush();
         flushed = true;
       }
@@ -152,7 +148,7 @@
            !EqualSampleRates(packet.payload_type,
                              **current_cng_rtp_payload_type,
                              decoder_database))) {
-        *current_cng_rtp_payload_type = rtc::nullopt;
+        *current_cng_rtp_payload_type = absl::nullopt;
         Flush();
         flushed = true;
       }
@@ -206,13 +202,13 @@
   return buffer_.empty() ? nullptr : &buffer_.front();
 }
 
-rtc::Optional<Packet> PacketBuffer::GetNextPacket() {
+absl::optional<Packet> PacketBuffer::GetNextPacket() {
   if (Empty()) {
     // Buffer is empty.
-    return rtc::nullopt;
+    return absl::nullopt;
   }
 
-  rtc::Optional<Packet> packet(std::move(buffer_.front()));
+  absl::optional<Packet> packet(std::move(buffer_.front()));
   // Assert that the packet sanity checks in InsertPacket method works.
   RTC_DCHECK(!packet->empty());
   buffer_.pop_front();
@@ -285,6 +281,18 @@
   return num_samples;
 }
 
+bool PacketBuffer::ContainsDtxOrCngPacket(
+    const DecoderDatabase* decoder_database) const {
+  RTC_DCHECK(decoder_database);
+  for (const Packet& packet : buffer_) {
+    if ((packet.frame && packet.frame->IsDtxPacket()) ||
+        decoder_database->IsComfortNoise(packet.payload_type)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void PacketBuffer::BufferStat(int* num_packets, int* max_num_packets) const {
   *num_packets = static_cast<int>(buffer_.size());
   *max_num_packets = static_cast<int>(max_number_of_packets_);
diff --git a/modules/audio_coding/neteq/packet_buffer.h b/modules/audio_coding/neteq/packet_buffer.h
index c83bf89..74f36a5 100644
--- a/modules/audio_coding/neteq/packet_buffer.h
+++ b/modules/audio_coding/neteq/packet_buffer.h
@@ -11,7 +11,8 @@
 #ifndef MODULES_AUDIO_CODING_NETEQ_PACKET_BUFFER_H_
 #define MODULES_AUDIO_CODING_NETEQ_PACKET_BUFFER_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
+#include "modules/audio_coding/neteq/decoder_database.h"
 #include "modules/audio_coding/neteq/packet.h"
 #include "modules/include/module_common_types.h"
 #include "rtc_base/constructormagic.h"
@@ -65,8 +66,8 @@
   virtual int InsertPacketList(
       PacketList* packet_list,
       const DecoderDatabase& decoder_database,
-      rtc::Optional<uint8_t>* current_rtp_payload_type,
-      rtc::Optional<uint8_t>* current_cng_rtp_payload_type,
+      absl::optional<uint8_t>* current_rtp_payload_type,
+      absl::optional<uint8_t>* current_cng_rtp_payload_type,
       StatisticsCalculator* stats);
 
   // Gets the timestamp for the first packet in the buffer and writes it to the
@@ -89,7 +90,7 @@
 
   // Extracts the first packet in the buffer and returns it.
   // Returns an empty optional if the buffer is empty.
-  virtual rtc::Optional<Packet> GetNextPacket();
+  virtual absl::optional<Packet> GetNextPacket();
 
   // Discards the first packet in the buffer. The packet is deleted.
   // Returns PacketBuffer::kBufferEmpty if the buffer is empty,
@@ -121,6 +122,10 @@
   // duplicate and redundant packets.
   virtual size_t NumSamplesInBuffer(size_t last_decoded_length) const;
 
+  // Returns true if the packet buffer contains any DTX or CNG packets.
+  virtual bool ContainsDtxOrCngPacket(
+      const DecoderDatabase* decoder_database) const;
+
   virtual void BufferStat(int* num_packets, int* max_num_packets) const;
 
   // Static method returning true if |timestamp| is older than |timestamp_limit|
diff --git a/modules/audio_coding/neteq/packet_buffer_unittest.cc b/modules/audio_coding/neteq/packet_buffer_unittest.cc
index 1aaed8b..cb40d7d 100644
--- a/modules/audio_coding/neteq/packet_buffer_unittest.cc
+++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc
@@ -176,21 +176,21 @@
   MockDecoderDatabase decoder_database;
   auto factory = CreateBuiltinAudioDecoderFactory();
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(0))
       .WillRepeatedly(Return(&info));
 
   StrictMock<MockStatisticsCalculator> mock_stats;
 
-  rtc::Optional<uint8_t> current_pt;
-  rtc::Optional<uint8_t> current_cng_pt;
+  absl::optional<uint8_t> current_pt;
+  absl::optional<uint8_t> current_cng_pt;
   EXPECT_EQ(PacketBuffer::kOK,
             buffer.InsertPacketList(&list, decoder_database, &current_pt,
                                     &current_cng_pt, &mock_stats));
   EXPECT_TRUE(list.empty());  // The PacketBuffer should have depleted the list.
   EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
   EXPECT_EQ(0, current_pt);      // Current payload type changed to 0.
-  EXPECT_EQ(rtc::nullopt, current_cng_pt);  // CNG payload type not changed.
+  EXPECT_EQ(absl::nullopt, current_cng_pt);  // CNG payload type not changed.
 
   buffer.Flush();  // Clean up.
 
@@ -221,25 +221,25 @@
   MockDecoderDatabase decoder_database;
   auto factory = CreateBuiltinAudioDecoderFactory();
   const DecoderDatabase::DecoderInfo info0(NetEqDecoder::kDecoderPCMu,
-                                           rtc::nullopt, factory);
+                                           absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(0))
       .WillRepeatedly(Return(&info0));
   const DecoderDatabase::DecoderInfo info1(NetEqDecoder::kDecoderPCMa,
-                                           rtc::nullopt, factory);
+                                           absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(1))
       .WillRepeatedly(Return(&info1));
 
   StrictMock<MockStatisticsCalculator> mock_stats;
 
-  rtc::Optional<uint8_t> current_pt;
-  rtc::Optional<uint8_t> current_cng_pt;
+  absl::optional<uint8_t> current_pt;
+  absl::optional<uint8_t> current_cng_pt;
   EXPECT_EQ(PacketBuffer::kFlushed,
             buffer.InsertPacketList(&list, decoder_database, &current_pt,
                                     &current_cng_pt, &mock_stats));
   EXPECT_TRUE(list.empty());  // The PacketBuffer should have depleted the list.
   EXPECT_EQ(1u, buffer.NumPacketsInBuffer());  // Only the last packet.
   EXPECT_EQ(1, current_pt);      // Current payload type changed to 1.
-  EXPECT_EQ(rtc::nullopt, current_cng_pt);  // CNG payload type not changed.
+  EXPECT_EQ(absl::nullopt, current_cng_pt);  // CNG payload type not changed.
 
   buffer.Flush();  // Clean up.
 
@@ -313,7 +313,7 @@
   EXPECT_EQ(kExpectPacketsInBuffer, buffer.NumPacketsInBuffer());
 
   for (size_t i = 0; i < kExpectPacketsInBuffer; ++i) {
-    const rtc::Optional<Packet> packet = buffer.GetNextPacket();
+    const absl::optional<Packet> packet = buffer.GetNextPacket();
     EXPECT_EQ(packet, expect_order[i]);  // Compare contents.
   }
   EXPECT_TRUE(buffer.Empty());
@@ -408,11 +408,11 @@
   MockDecoderDatabase decoder_database;
   auto factory = CreateBuiltinAudioDecoderFactory();
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(0))
       .WillRepeatedly(Return(&info));
-  rtc::Optional<uint8_t> current_pt;
-  rtc::Optional<uint8_t> current_cng_pt;
+  absl::optional<uint8_t> current_pt;
+  absl::optional<uint8_t> current_cng_pt;
 
   StrictMock<MockStatisticsCalculator> mock_stats;
 
@@ -424,7 +424,7 @@
   // Extract them and make sure that come out in the right order.
   uint32_t current_ts = start_ts;
   for (int i = 0; i < 10; ++i) {
-    const rtc::Optional<Packet> packet = buffer.GetNextPacket();
+    const absl::optional<Packet> packet = buffer.GetNextPacket();
     ASSERT_TRUE(packet);
     EXPECT_EQ(current_ts, packet->timestamp);
     current_ts += ts_increment;
@@ -448,11 +448,11 @@
   MockDecoderDatabase decoder_database;
   auto factory = CreateBuiltinAudioDecoderFactory();
   const DecoderDatabase::DecoderInfo info_cng(NetEqDecoder::kDecoderCNGnb,
-                                              rtc::nullopt, factory);
+                                              absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(kCngPt))
       .WillRepeatedly(Return(&info_cng));
   const DecoderDatabase::DecoderInfo info_speech(NetEqDecoder::kDecoderPCM16Bwb,
-                                                 rtc::nullopt, factory);
+                                                 absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(kSpeechPt))
       .WillRepeatedly(Return(&info_speech));
 
@@ -460,8 +460,8 @@
   PacketGenerator gen(0, 0, kCngPt, 10);
   PacketList list;
   list.push_back(gen.NextPacket(kPayloadLen));
-  rtc::Optional<uint8_t> current_pt;
-  rtc::Optional<uint8_t> current_cng_pt;
+  absl::optional<uint8_t> current_pt;
+  absl::optional<uint8_t> current_cng_pt;
 
   StrictMock<MockStatisticsCalculator> mock_stats;
 
@@ -472,7 +472,7 @@
   EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
   ASSERT_TRUE(buffer.PeekNextPacket());
   EXPECT_EQ(kCngPt, buffer.PeekNextPacket()->payload_type);
-  EXPECT_EQ(current_pt, rtc::nullopt);  // Current payload type not set.
+  EXPECT_EQ(current_pt, absl::nullopt);  // Current payload type not set.
   EXPECT_EQ(kCngPt, current_cng_pt);  // CNG payload type set.
 
   // Insert second packet, which is wide-band speech.
@@ -492,7 +492,7 @@
   EXPECT_EQ(kSpeechPt, buffer.PeekNextPacket()->payload_type);
 
   EXPECT_EQ(kSpeechPt, current_pt);  // Current payload type set.
-  EXPECT_EQ(rtc::nullopt, current_cng_pt);  // CNG payload type reset.
+  EXPECT_EQ(absl::nullopt, current_cng_pt);  // CNG payload type reset.
 
   buffer.Flush();                        // Clean up.
   EXPECT_CALL(decoder_database, Die());  // Called when object is deleted.
@@ -550,11 +550,11 @@
   MockDecoderDatabase decoder_database;
   auto factory = CreateBuiltinAudioDecoderFactory();
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   EXPECT_CALL(decoder_database, GetDecoderInfo(0))
       .WillRepeatedly(Return(&info));
-  rtc::Optional<uint8_t> current_pt;
-  rtc::Optional<uint8_t> current_cng_pt;
+  absl::optional<uint8_t> current_pt;
+  absl::optional<uint8_t> current_cng_pt;
   EXPECT_EQ(PacketBuffer::kInvalidPacket,
             buffer->InsertPacketList(&list, decoder_database, &current_pt,
                                      &current_cng_pt, &mock_stats));
diff --git a/modules/audio_coding/neteq/post_decode_vad.cc b/modules/audio_coding/neteq/post_decode_vad.cc
index a09d18f..9999d67 100644
--- a/modules/audio_coding/neteq/post_decode_vad.cc
+++ b/modules/audio_coding/neteq/post_decode_vad.cc
@@ -45,7 +45,8 @@
   }
 }
 
-void PostDecodeVad::Update(int16_t* signal, size_t length,
+void PostDecodeVad::Update(int16_t* signal,
+                           size_t length,
                            AudioDecoder::SpeechType speech_type,
                            bool sid_frame,
                            int fs_hz) {
@@ -72,13 +73,13 @@
     active_speech_ = false;
     // Loop through frame sizes 30, 20, and 10 ms.
     for (int vad_frame_size_ms = 30; vad_frame_size_ms >= 10;
-        vad_frame_size_ms -= 10) {
+         vad_frame_size_ms -= 10) {
       size_t vad_frame_size_samples =
           static_cast<size_t>(vad_frame_size_ms * fs_hz / 1000);
       while (length - vad_sample_index >= vad_frame_size_samples) {
-        int vad_return = WebRtcVad_Process(
-            vad_instance_, fs_hz, &signal[vad_sample_index],
-            vad_frame_size_samples);
+        int vad_return =
+            WebRtcVad_Process(vad_instance_, fs_hz, &signal[vad_sample_index],
+                              vad_frame_size_samples);
         active_speech_ |= (vad_return == 1);
         vad_sample_index += vad_frame_size_samples;
       }
diff --git a/modules/audio_coding/neteq/post_decode_vad.h b/modules/audio_coding/neteq/post_decode_vad.h
index 7b67bbe..dac95f0 100644
--- a/modules/audio_coding/neteq/post_decode_vad.h
+++ b/modules/audio_coding/neteq/post_decode_vad.h
@@ -30,8 +30,7 @@
         running_(false),
         active_speech_(true),
         sid_interval_counter_(0),
-        vad_instance_(NULL) {
-  }
+        vad_instance_(NULL) {}
 
   virtual ~PostDecodeVad();
 
@@ -46,8 +45,11 @@
 
   // Updates post-decode VAD with the audio data in |signal| having |length|
   // samples. The data is of type |speech_type|, at the sample rate |fs_hz|.
-  void Update(int16_t* signal, size_t length,
-              AudioDecoder::SpeechType speech_type, bool sid_frame, int fs_hz);
+  void Update(int16_t* signal,
+              size_t length,
+              AudioDecoder::SpeechType speech_type,
+              bool sid_frame,
+              int fs_hz);
 
   // Accessors.
   bool enabled() const { return enabled_; }
diff --git a/modules/audio_coding/neteq/preemptive_expand.cc b/modules/audio_coding/neteq/preemptive_expand.cc
index bc75389..4702078 100644
--- a/modules/audio_coding/neteq/preemptive_expand.cc
+++ b/modules/audio_coding/neteq/preemptive_expand.cc
@@ -50,8 +50,7 @@
   // but we must ensure that best_correlation is not larger than the length of
   // the new data.
   // but we must ensure that best_correlation is not larger than the new data.
-  *peak_index = std::min(*peak_index,
-                         len - old_data_length_per_channel_);
+  *peak_index = std::min(*peak_index, len - old_data_length_per_channel_);
 }
 
 PreemptiveExpand::ReturnCodes PreemptiveExpand::CheckCriteriaAndStretch(
@@ -68,13 +67,13 @@
   // Check for strong correlation (>0.9 in Q14) and at least 15 ms new data,
   // or passive speech.
   if (((best_correlation > kCorrelationThreshold) &&
-      (old_data_length_per_channel_ <= fs_mult_120)) ||
+       (old_data_length_per_channel_ <= fs_mult_120)) ||
       !active_speech) {
     // Do accelerate operation by overlap add.
 
     // Set length of the first part, not to be modified.
-    size_t unmodified_length = std::max(old_data_length_per_channel_,
-                                        fs_mult_120);
+    size_t unmodified_length =
+        std::max(old_data_length_per_channel_, fs_mult_120);
     // Copy first part, including cross-fade region.
     output->PushBackInterleaved(
         input, (unmodified_length + peak_index) * num_channels_);
@@ -107,8 +106,8 @@
     size_t num_channels,
     const BackgroundNoise& background_noise,
     size_t overlap_samples) const {
-  return new PreemptiveExpand(
-      sample_rate_hz, num_channels, background_noise, overlap_samples);
+  return new PreemptiveExpand(sample_rate_hz, num_channels, background_noise,
+                              overlap_samples);
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/preemptive_expand.h b/modules/audio_coding/neteq/preemptive_expand.h
index 303501d..197d3f1 100644
--- a/modules/audio_coding/neteq/preemptive_expand.h
+++ b/modules/audio_coding/neteq/preemptive_expand.h
@@ -35,15 +35,14 @@
                    size_t overlap_samples)
       : TimeStretch(sample_rate_hz, num_channels, background_noise),
         old_data_length_per_channel_(0),
-        overlap_samples_(overlap_samples) {
-  }
+        overlap_samples_(overlap_samples) {}
 
   // This method performs the actual PreemptiveExpand operation. The samples are
   // read from |input|, of length |input_length| elements, and are written to
   // |output|. The number of samples added through time-stretching is
   // is provided in the output |length_change_samples|. The method returns
   // the outcome of the operation as an enumerator value.
-  ReturnCodes Process(const int16_t *pw16_decoded,
+  ReturnCodes Process(const int16_t* pw16_decoded,
                       size_t len,
                       size_t old_data_len,
                       AudioMultiVector* output,
@@ -77,11 +76,10 @@
   PreemptiveExpandFactory() {}
   virtual ~PreemptiveExpandFactory() {}
 
-  virtual PreemptiveExpand* Create(
-      int sample_rate_hz,
-      size_t num_channels,
-      const BackgroundNoise& background_noise,
-      size_t overlap_samples) const;
+  virtual PreemptiveExpand* Create(int sample_rate_hz,
+                                   size_t num_channels,
+                                   const BackgroundNoise& background_noise,
+                                   size_t overlap_samples) const;
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/random_vector.cc b/modules/audio_coding/neteq/random_vector.cc
index c2df8cf..ada1758 100644
--- a/modules/audio_coding/neteq/random_vector.cc
+++ b/modules/audio_coding/neteq/random_vector.cc
@@ -13,29 +13,35 @@
 namespace webrtc {
 
 const int16_t RandomVector::kRandomTable[RandomVector::kRandomTableSize] = {
-    2680, 5532, 441, 5520, 16170, -5146, -1024, -8733, 3115, 9598, -10380,
-    -4959, -1280, -21716, 7133, -1522, 13458, -3902, 2789, -675, 3441, 5016,
-    -13599, -4003, -2739, 3922, -7209, 13352, -11617, -7241, 12905, -2314, 5426,
-    10121, -9702, 11207, -13542, 1373, 816, -5934, -12504, 4798, 1811, 4112,
-    -613, 201, -10367, -2960, -2419, 3442, 4299, -6116, -6092, 1552, -1650,
-    -480, -1237, 18720, -11858, -8303, -8212, 865, -2890, -16968, 12052, -5845,
-    -5912, 9777, -5665, -6294, 5426, -4737, -6335, 1652, 761, 3832, 641, -8552,
-    -9084, -5753, 8146, 12156, -4915, 15086, -1231, -1869, 11749, -9319, -6403,
-    11407, 6232, -1683, 24340, -11166, 4017, -10448, 3153, -2936, 6212, 2891,
-    -866, -404, -4807, -2324, -1917, -2388, -6470, -3895, -10300, 5323, -5403,
-    2205, 4640, 7022, -21186, -6244, -882, -10031, -3395, -12885, 7155, -5339,
-    5079, -2645, -9515, 6622, 14651, 15852, 359, 122, 8246, -3502, -6696, -3679,
-    -13535, -1409, -704, -7403, -4007, 1798, 279, -420, -12796, -14219, 1141,
-    3359, 11434, 7049, -6684, -7473, 14283, -4115, -9123, -8969, 4152, 4117,
-    13792, 5742, 16168, 8661, -1609, -6095, 1881, 14380, -5588, 6758, -6425,
-    -22969, -7269, 7031, 1119, -1611, -5850, -11281, 3559, -8952, -10146, -4667,
-    -16251, -1538, 2062, -1012, -13073, 227, -3142, -5265, 20, 5770, -7559,
-    4740, -4819, 992, -8208, -7130, -4652, 6725, 7369, -1036, 13144, -1588,
-    -5304, -2344, -449, -5705, -8894, 5205, -17904, -11188, -1022, 4852, 10101,
-    -5255, -4200, -752, 7941, -1543, 5959, 14719, 13346, 17045, -15605, -1678,
-    -1600, -9230, 68, 23348, 1172, 7750, 11212, -18227, 9956, 4161, 883, 3947,
-    4341, 1014, -4889, -2603, 1246, -5630, -3596, -870, -1298, 2784, -3317,
-    -6612, -20541, 4166, 4181, -8625, 3562, 12890, 4761, 3205, -12259, -8579 };
+    2680,   5532,   441,    5520,   16170,  -5146,  -1024,  -8733,  3115,
+    9598,   -10380, -4959,  -1280,  -21716, 7133,   -1522,  13458,  -3902,
+    2789,   -675,   3441,   5016,   -13599, -4003,  -2739,  3922,   -7209,
+    13352,  -11617, -7241,  12905,  -2314,  5426,   10121,  -9702,  11207,
+    -13542, 1373,   816,    -5934,  -12504, 4798,   1811,   4112,   -613,
+    201,    -10367, -2960,  -2419,  3442,   4299,   -6116,  -6092,  1552,
+    -1650,  -480,   -1237,  18720,  -11858, -8303,  -8212,  865,    -2890,
+    -16968, 12052,  -5845,  -5912,  9777,   -5665,  -6294,  5426,   -4737,
+    -6335,  1652,   761,    3832,   641,    -8552,  -9084,  -5753,  8146,
+    12156,  -4915,  15086,  -1231,  -1869,  11749,  -9319,  -6403,  11407,
+    6232,   -1683,  24340,  -11166, 4017,   -10448, 3153,   -2936,  6212,
+    2891,   -866,   -404,   -4807,  -2324,  -1917,  -2388,  -6470,  -3895,
+    -10300, 5323,   -5403,  2205,   4640,   7022,   -21186, -6244,  -882,
+    -10031, -3395,  -12885, 7155,   -5339,  5079,   -2645,  -9515,  6622,
+    14651,  15852,  359,    122,    8246,   -3502,  -6696,  -3679,  -13535,
+    -1409,  -704,   -7403,  -4007,  1798,   279,    -420,   -12796, -14219,
+    1141,   3359,   11434,  7049,   -6684,  -7473,  14283,  -4115,  -9123,
+    -8969,  4152,   4117,   13792,  5742,   16168,  8661,   -1609,  -6095,
+    1881,   14380,  -5588,  6758,   -6425,  -22969, -7269,  7031,   1119,
+    -1611,  -5850,  -11281, 3559,   -8952,  -10146, -4667,  -16251, -1538,
+    2062,   -1012,  -13073, 227,    -3142,  -5265,  20,     5770,   -7559,
+    4740,   -4819,  992,    -8208,  -7130,  -4652,  6725,   7369,   -1036,
+    13144,  -1588,  -5304,  -2344,  -449,   -5705,  -8894,  5205,   -17904,
+    -11188, -1022,  4852,   10101,  -5255,  -4200,  -752,   7941,   -1543,
+    5959,   14719,  13346,  17045,  -15605, -1678,  -1600,  -9230,  68,
+    23348,  1172,   7750,   11212,  -18227, 9956,   4161,   883,    3947,
+    4341,   1014,   -4889,  -2603,  1246,   -5630,  -3596,  -870,   -1298,
+    2784,   -3317,  -6612,  -20541, 4166,   4181,   -8625,  3562,   12890,
+    4761,   3205,   -12259, -8579};
 
 void RandomVector::Reset() {
   seed_ = 777;
@@ -51,7 +57,7 @@
 }
 
 void RandomVector::IncreaseSeedIncrement(int16_t increase_by) {
-  seed_increment_+= increase_by;
+  seed_increment_ += increase_by;
   seed_increment_ &= kRandomTableSize - 1;
 }
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/random_vector.h b/modules/audio_coding/neteq/random_vector.h
index 18adbe0..2c6e06c 100644
--- a/modules/audio_coding/neteq/random_vector.h
+++ b/modules/audio_coding/neteq/random_vector.h
@@ -24,10 +24,7 @@
   static const size_t kRandomTableSize = 256;
   static const int16_t kRandomTable[kRandomTableSize];
 
-  RandomVector()
-      : seed_(777),
-        seed_increment_(1) {
-  }
+  RandomVector() : seed_(777), seed_increment_(1) {}
 
   void Reset();
 
diff --git a/modules/audio_coding/neteq/red_payload_splitter.cc b/modules/audio_coding/neteq/red_payload_splitter.cc
index 85e399c..f5435e8 100644
--- a/modules/audio_coding/neteq/red_payload_splitter.cc
+++ b/modules/audio_coding/neteq/red_payload_splitter.cc
@@ -130,13 +130,16 @@
   return ret;
 }
 
-int RedPayloadSplitter::CheckRedPayloads(
+void RedPayloadSplitter::CheckRedPayloads(
     PacketList* packet_list,
     const DecoderDatabase& decoder_database) {
   int main_payload_type = -1;
-  int num_deleted_packets = 0;
   for (auto it = packet_list->begin(); it != packet_list->end(); /* */) {
     uint8_t this_payload_type = it->payload_type;
+    if (decoder_database.IsRed(this_payload_type)) {
+      it = packet_list->erase(it);
+      continue;
+    }
     if (!decoder_database.IsDtmf(this_payload_type) &&
         !decoder_database.IsComfortNoise(this_payload_type)) {
       if (main_payload_type == -1) {
@@ -149,14 +152,12 @@
           // moves the iterator |it| to the next packet in the list. Thus, we
           // do not have to increment it manually.
           it = packet_list->erase(it);
-          ++num_deleted_packets;
           continue;
         }
       }
     }
     ++it;
   }
-  return num_deleted_packets;
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/red_payload_splitter.h b/modules/audio_coding/neteq/red_payload_splitter.h
index 1475b1b..5e239dd 100644
--- a/modules/audio_coding/neteq/red_payload_splitter.h
+++ b/modules/audio_coding/neteq/red_payload_splitter.h
@@ -38,10 +38,9 @@
 
   // Checks all packets in |packet_list|. Packets that are DTMF events or
   // comfort noise payloads are kept. Except that, only one single payload type
-  // is accepted. Any packet with another payload type is discarded.  Returns
-  // the number of discarded packets.
-  virtual int CheckRedPayloads(PacketList* packet_list,
-                               const DecoderDatabase& decoder_database);
+  // is accepted. Any packet with another payload type is discarded.
+  virtual void CheckRedPayloads(PacketList* packet_list,
+                                const DecoderDatabase& decoder_database);
 
  private:
   RTC_DISALLOW_COPY_AND_ASSIGN(RedPayloadSplitter);
diff --git a/modules/audio_coding/neteq/red_payload_splitter_unittest.cc b/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
index 077c8ea..52fc1ba 100644
--- a/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
+++ b/modules/audio_coding/neteq/red_payload_splitter_unittest.cc
@@ -100,8 +100,8 @@
     // Not the last block; set F = 1.
     *payload_ptr |= 0x80;
     ++payload_ptr;
-    int this_offset = rtc::checked_cast<int>(
-        (num_payloads - i - 1) * timestamp_offset);
+    int this_offset =
+        rtc::checked_cast<int>((num_payloads - i - 1) * timestamp_offset);
     *payload_ptr = this_offset >> 6;
     ++payload_ptr;
     assert(kPayloadLength <= 1023);  // Max length described by 10 bits.
@@ -299,7 +299,7 @@
   // easier to just register the payload types and let the actual implementation
   // do its job.
   DecoderDatabase decoder_database(
-      new rtc::RefCountedObject<MockAudioDecoderFactory>, rtc::nullopt);
+      new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
   decoder_database.RegisterPayload(0, NetEqDecoder::kDecoderCNGnb, "cng-nb");
   decoder_database.RegisterPayload(1, NetEqDecoder::kDecoderPCMu, "pcmu");
   decoder_database.RegisterPayload(2, NetEqDecoder::kDecoderAVT, "avt");
@@ -319,6 +319,30 @@
   EXPECT_TRUE(packet_list.empty());
 }
 
+// This test creates a RED packet where the payloads also have the payload type
+// for RED. That is, some kind of weird nested RED packet. This is not supported
+// and the splitter should discard all packets.
+TEST(RedPayloadSplitter, CheckRedPayloadsRecursiveRed) {
+  PacketList packet_list;
+  for (uint8_t i = 0; i <= 3; ++i) {
+    // Create packet with RED payload type, payload length 10 bytes, all 0.
+    packet_list.push_back(CreatePacket(kRedPayloadType, 10, 0));
+  }
+
+  // Use a real DecoderDatabase object here instead of a mock, since it is
+  // easier to just register the payload types and let the actual implementation
+  // do its job.
+  DecoderDatabase decoder_database(
+      new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
+  decoder_database.RegisterPayload(kRedPayloadType, NetEqDecoder::kDecoderRED,
+                                   "red");
+
+  RedPayloadSplitter splitter;
+  splitter.CheckRedPayloads(&packet_list, decoder_database);
+
+  EXPECT_TRUE(packet_list.empty());  // Should have dropped all packets.
+}
+
 // Packet A is split into A1, A2 and A3. But the length parameter is off, so
 // the last payloads should be discarded.
 TEST(RedPayloadSplitter, WrongPayloadLength) {
diff --git a/modules/audio_coding/neteq/rtcp.h b/modules/audio_coding/neteq/rtcp.h
index ce2035b..45bb058 100644
--- a/modules/audio_coding/neteq/rtcp.h
+++ b/modules/audio_coding/neteq/rtcp.h
@@ -22,9 +22,7 @@
 
 class Rtcp {
  public:
-  Rtcp() {
-    Init(0);
-  }
+  Rtcp() { Init(0); }
 
   ~Rtcp() {}
 
@@ -39,17 +37,17 @@
   void GetStatistics(bool no_reset, RtcpStatistics* stats);
 
  private:
-  uint16_t cycles_;  // The number of wrap-arounds for the sequence number.
-  uint16_t max_seq_no_;  // The maximum sequence number received. Starts over
-                         // from 0 after wrap-around.
+  uint16_t cycles_;       // The number of wrap-arounds for the sequence number.
+  uint16_t max_seq_no_;   // The maximum sequence number received. Starts over
+                          // from 0 after wrap-around.
   uint16_t base_seq_no_;  // The sequence number of the first received packet.
   uint32_t received_packets_;  // The number of packets that have been received.
   uint32_t received_packets_prior_;  // Number of packets received when last
                                      // report was generated.
   uint32_t expected_prior_;  // Expected number of packets, at the time of the
                              // last report.
-  int64_t jitter_;  // Current jitter value in Q4.
-  int32_t transit_;  // Clock difference for previous packet.
+  int64_t jitter_;           // Current jitter value in Q4.
+  int32_t transit_;          // Clock difference for previous packet.
 
   RTC_DISALLOW_COPY_AND_ASSIGN(Rtcp);
 };
diff --git a/modules/audio_coding/neteq/statistics_calculator.cc b/modules/audio_coding/neteq/statistics_calculator.cc
index c698790..3d5744c 100644
--- a/modules/audio_coding/neteq/statistics_calculator.cc
+++ b/modules/audio_coding/neteq/statistics_calculator.cc
@@ -42,8 +42,7 @@
     : uma_name_(uma_name),
       report_interval_ms_(report_interval_ms),
       max_value_(max_value),
-      timer_(0) {
-}
+      timer_(0) {}
 
 StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;
 
@@ -66,8 +65,7 @@
     const std::string& uma_name,
     int report_interval_ms,
     int max_value)
-    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {
-}
+    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
 
 StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
   // Log the count for the current (incomplete) interval.
@@ -90,8 +88,7 @@
     const std::string& uma_name,
     int report_interval_ms,
     int max_value)
-    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {
-}
+    : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
 
 StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
   // Log the average for the current (incomplete) interval.
@@ -266,11 +263,10 @@
   waiting_times_.push_back(waiting_time_ms);
 }
 
-void StatisticsCalculator::GetNetworkStatistics(
-    int fs_hz,
-    size_t num_samples_in_buffers,
-    size_t samples_per_packet,
-    NetEqNetworkStatistics *stats) {
+void StatisticsCalculator::GetNetworkStatistics(int fs_hz,
+                                                size_t num_samples_in_buffers,
+                                                size_t samples_per_packet,
+                                                NetEqNetworkStatistics* stats) {
   RTC_DCHECK_GT(fs_hz, 0);
   RTC_DCHECK(stats);
 
@@ -291,20 +287,18 @@
       CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
                         timestamps_since_last_report_);
 
-  stats->speech_expand_rate =
-      CalculateQ14Ratio(expanded_speech_samples_,
-                        timestamps_since_last_report_);
+  stats->speech_expand_rate = CalculateQ14Ratio(expanded_speech_samples_,
+                                                timestamps_since_last_report_);
 
-  stats->secondary_decoded_rate =
-      CalculateQ14Ratio(secondary_decoded_samples_,
-                        timestamps_since_last_report_);
+  stats->secondary_decoded_rate = CalculateQ14Ratio(
+      secondary_decoded_samples_, timestamps_since_last_report_);
 
   const size_t discarded_secondary_samples =
       discarded_secondary_packets_ * samples_per_packet;
-  stats->secondary_discarded_rate = CalculateQ14Ratio(
-      discarded_secondary_samples,
-      static_cast<uint32_t>(discarded_secondary_samples +
-        secondary_decoded_samples_));
+  stats->secondary_discarded_rate =
+      CalculateQ14Ratio(discarded_secondary_samples,
+                        static_cast<uint32_t>(discarded_secondary_samples +
+                                              secondary_decoded_samples_));
 
   if (waiting_times_.size() == 0) {
     stats->mean_waiting_time_ms = -1;
diff --git a/modules/audio_coding/neteq/statistics_calculator.h b/modules/audio_coding/neteq/statistics_calculator.h
index a06ddfb..42fd4c9 100644
--- a/modules/audio_coding/neteq/statistics_calculator.h
+++ b/modules/audio_coding/neteq/statistics_calculator.h
@@ -98,7 +98,7 @@
   void GetNetworkStatistics(int fs_hz,
                             size_t num_samples_in_buffers,
                             size_t samples_per_packet,
-                            NetEqNetworkStatistics *stats);
+                            NetEqNetworkStatistics* stats);
 
   // Populates |preferred_buffer_size_ms|, |jitter_peaks_found| and
   // |clockdrift_ppm| in |stats|. This is a convenience method, and does not
diff --git a/modules/audio_coding/neteq/sync_buffer.cc b/modules/audio_coding/neteq/sync_buffer.cc
index 28d7649..82ca16f 100644
--- a/modules/audio_coding/neteq/sync_buffer.cc
+++ b/modules/audio_coding/neteq/sync_buffer.cc
@@ -27,7 +27,7 @@
     next_index_ -= samples_added;
   } else {
     // This means that we are pushing out future data that was never used.
-//    assert(false);
+    //    assert(false);
     // TODO(hlundin): This assert must be disabled to support 60 ms frames.
     // This should not happen even for 60 ms frames, but it does. Investigate
     // why.
@@ -75,9 +75,8 @@
   RTC_DCHECK(output);
   const size_t samples_to_read = std::min(FutureLength(), requested_len);
   output->ResetWithoutMuting();
-  const size_t tot_samples_read =
-      ReadInterleavedFromIndex(next_index_, samples_to_read,
-                               output->mutable_data());
+  const size_t tot_samples_read = ReadInterleavedFromIndex(
+      next_index_, samples_to_read, output->mutable_data());
   const size_t samples_read_per_channel = tot_samples_read / Channels();
   next_index_ += samples_read_per_channel;
   output->num_channels_ = Channels();
diff --git a/modules/audio_coding/neteq/sync_buffer.h b/modules/audio_coding/neteq/sync_buffer.h
index d880356..8a35326 100644
--- a/modules/audio_coding/neteq/sync_buffer.h
+++ b/modules/audio_coding/neteq/sync_buffer.h
@@ -92,7 +92,7 @@
  private:
   size_t next_index_;
   uint32_t end_timestamp_;  // The timestamp of the last sample in the buffer.
-  size_t dtmf_index_;  // Index to the first non-DTMF sample in the buffer.
+  size_t dtmf_index_;       // Index to the first non-DTMF sample in the buffer.
 
   RTC_DISALLOW_COPY_AND_ASSIGN(SyncBuffer);
 };
diff --git a/modules/audio_coding/neteq/time_stretch.cc b/modules/audio_coding/neteq/time_stretch.cc
index 8a1bfa2..560d9be 100644
--- a/modules/audio_coding/neteq/time_stretch.cc
+++ b/modules/audio_coding/neteq/time_stretch.cc
@@ -80,7 +80,7 @@
   // Calculate scaling to ensure that |peak_index| samples can be square-summed
   // without overflowing.
   int scaling = 31 - WebRtcSpl_NormW32(max_input_value_ * max_input_value_) -
-      WebRtcSpl_NormW32(static_cast<int32_t>(peak_index));
+                WebRtcSpl_NormW32(static_cast<int32_t>(peak_index));
   scaling = std::max(0, scaling);
 
   // |vec1| starts at 15 ms minus one pitch period.
@@ -99,8 +99,8 @@
       WebRtcSpl_DotProductWithScale(vec1, vec2, peak_index, scaling);
 
   // Check if the signal seems to be active speech or not (simple VAD).
-  bool active_speech = SpeechDetection(vec1_energy, vec2_energy, peak_index,
-                                       scaling);
+  bool active_speech =
+      SpeechDetection(vec1_energy, vec2_energy, peak_index, scaling);
 
   int16_t best_correlation;
   if (!active_speech) {
@@ -126,8 +126,8 @@
         static_cast<int16_t>(vec2_energy >> energy2_scale);
 
     // Calculate square-root of energy product.
-    int16_t sqrt_energy_prod = WebRtcSpl_SqrtFloor(vec1_energy_int16 *
-                                                   vec2_energy_int16);
+    int16_t sqrt_energy_prod =
+        WebRtcSpl_SqrtFloor(vec1_energy_int16 * vec2_energy_int16);
 
     // Calculate cross_corr / sqrt(en1*en2) in Q14.
     int temp_scale = 14 - (energy1_scale + energy2_scale) / 2;
@@ -138,7 +138,6 @@
     best_correlation = std::min(static_cast<int16_t>(16384), best_correlation);
   }
 
-
   // Check accelerate criteria and stretch the signal.
   ReturnCodes return_value =
       CheckCriteriaAndStretch(input, input_len, peak_index, best_correlation,
@@ -172,8 +171,10 @@
                                    auto_corr, scaling);
 }
 
-bool TimeStretch::SpeechDetection(int32_t vec1_energy, int32_t vec2_energy,
-                                  size_t peak_index, int scaling) const {
+bool TimeStretch::SpeechDetection(int32_t vec1_energy,
+                                  int32_t vec2_energy,
+                                  size_t peak_index,
+                                  int scaling) const {
   // Check if the signal seems to be active speech or not (simple VAD).
   // If (vec1_energy + vec2_energy) / (2 * peak_index) <=
   // 8 * background_noise_energy, then we say that the signal contains no
diff --git a/modules/audio_coding/neteq/time_stretch.h b/modules/audio_coding/neteq/time_stretch.h
index ace10cd..606d1d0 100644
--- a/modules/audio_coding/neteq/time_stretch.h
+++ b/modules/audio_coding/neteq/time_stretch.h
@@ -35,7 +35,8 @@
     kError = -1
   };
 
-  TimeStretch(int sample_rate_hz, size_t num_channels,
+  TimeStretch(int sample_rate_hz,
+              size_t num_channels,
               const BackgroundNoise& background_noise)
       : sample_rate_hz_(sample_rate_hz),
         fs_mult_(sample_rate_hz / 8000),
@@ -43,10 +44,8 @@
         master_channel_(0),  // First channel is master.
         background_noise_(background_noise),
         max_input_value_(0) {
-    assert(sample_rate_hz_ == 8000 ||
-           sample_rate_hz_ == 16000 ||
-           sample_rate_hz_ == 32000 ||
-           sample_rate_hz_ == 48000);
+    assert(sample_rate_hz_ == 8000 || sample_rate_hz_ == 16000 ||
+           sample_rate_hz_ == 32000 || sample_rate_hz_ == 48000);
     assert(num_channels_ > 0);
     assert(master_channel_ < num_channels_);
     memset(auto_correlation_, 0, sizeof(auto_correlation_));
@@ -106,8 +105,10 @@
   void AutoCorrelation();
 
   // Performs a simple voice-activity detection based on the input parameters.
-  bool SpeechDetection(int32_t vec1_energy, int32_t vec2_energy,
-                       size_t peak_index, int scaling) const;
+  bool SpeechDetection(int32_t vec1_energy,
+                       int32_t vec2_energy,
+                       size_t peak_index,
+                       int scaling) const;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(TimeStretch);
 };
diff --git a/modules/audio_coding/neteq/time_stretch_unittest.cc b/modules/audio_coding/neteq/time_stretch_unittest.cc
index 8d0f4d4..c96c7d4 100644
--- a/modules/audio_coding/neteq/time_stretch_unittest.cc
+++ b/modules/audio_coding/neteq/time_stretch_unittest.cc
@@ -34,8 +34,8 @@
   const int kOverlapSamples = 5 * kSampleRate / 8000;
   BackgroundNoise bgn(kNumChannels);
   Accelerate accelerate(kSampleRate, kNumChannels, bgn);
-  PreemptiveExpand preemptive_expand(
-      kSampleRate, kNumChannels, bgn, kOverlapSamples);
+  PreemptiveExpand preemptive_expand(kSampleRate, kNumChannels, bgn,
+                                     kOverlapSamples);
 }
 
 TEST(TimeStretch, CreateUsingFactory) {
diff --git a/modules/audio_coding/neteq/timestamp_scaler.cc b/modules/audio_coding/neteq/timestamp_scaler.cc
index d7aa9fe..07d945e 100644
--- a/modules/audio_coding/neteq/timestamp_scaler.cc
+++ b/modules/audio_coding/neteq/timestamp_scaler.cc
@@ -70,7 +70,6 @@
   }
 }
 
-
 uint32_t TimestampScaler::ToExternal(uint32_t internal_timestamp) const {
   if (!first_packet_received_ || (numerator_ == denominator_)) {
     // Not initialized, or scale factor is 1.
diff --git a/modules/audio_coding/neteq/timestamp_scaler_unittest.cc b/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
index 1a7b71a..1f1445a 100644
--- a/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
+++ b/modules/audio_coding/neteq/timestamp_scaler_unittest.cc
@@ -8,10 +8,10 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "modules/audio_coding/neteq/timestamp_scaler.h"
 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
 #include "modules/audio_coding/neteq/mock/mock_decoder_database.h"
 #include "modules/audio_coding/neteq/packet.h"
-#include "modules/audio_coding/neteq/timestamp_scaler.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 
@@ -26,7 +26,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use PCMu, because it doesn't use scaled timestamps.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 0;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -48,7 +48,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use PCMu, because it doesn't use scaled timestamps.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderPCMu,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 0;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -60,7 +60,7 @@
   // |external_timestamp| will be a large positive value.
   start_timestamp = start_timestamp - 5 * kStep;
   for (uint32_t timestamp = start_timestamp; timestamp != 5 * kStep;
-      timestamp += kStep) {
+       timestamp += kStep) {
     // Scale to internal timestamp.
     EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
     // Scale back.
@@ -75,7 +75,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use G722, which has a factor 2 scaling.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 17;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -101,7 +101,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use G722, which has a factor 2 scaling.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 17;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -131,9 +131,9 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use G722, which has a factor 2 scaling.
   const DecoderDatabase::DecoderInfo info_g722(NetEqDecoder::kDecoderG722,
-                                               rtc::nullopt, factory);
+                                               absl::nullopt, factory);
   const DecoderDatabase::DecoderInfo info_cng(NetEqDecoder::kDecoderCNGwb,
-                                              rtc::nullopt, factory);
+                                              absl::nullopt, factory);
   static const uint8_t kRtpPayloadTypeG722 = 17;
   static const uint8_t kRtpPayloadTypeCng = 13;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadTypeG722))
@@ -175,7 +175,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use G722, which has a factor 2 scaling.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 17;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -205,7 +205,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use G722, which has a factor 2 scaling.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 17;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -239,7 +239,7 @@
   auto factory = CreateBuiltinAudioDecoderFactory();
   // Use G722, which has a factor 2 scaling.
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderG722,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 17;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
@@ -280,7 +280,7 @@
   MockDecoderDatabase db;
   auto factory = CreateBuiltinAudioDecoderFactory();
   const DecoderDatabase::DecoderInfo info(NetEqDecoder::kDecoderOpus,
-                                          rtc::nullopt, factory);
+                                          absl::nullopt, factory);
   static const uint8_t kRtpPayloadType = 17;
   EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
       .WillRepeatedly(Return(&info));
diff --git a/modules/audio_coding/neteq/tools/audio_loop.cc b/modules/audio_coding/neteq/tools/audio_loop.cc
index b5ad881..972921b 100644
--- a/modules/audio_coding/neteq/tools/audio_loop.cc
+++ b/modules/audio_coding/neteq/tools/audio_loop.cc
@@ -21,16 +21,18 @@
                      size_t max_loop_length_samples,
                      size_t block_length_samples) {
   FILE* fp = fopen(file_name.c_str(), "rb");
-  if (!fp) return false;
+  if (!fp)
+    return false;
 
-  audio_array_.reset(new int16_t[max_loop_length_samples +
-                                 block_length_samples]);
-  size_t samples_read = fread(audio_array_.get(), sizeof(int16_t),
-                              max_loop_length_samples, fp);
+  audio_array_.reset(
+      new int16_t[max_loop_length_samples + block_length_samples]);
+  size_t samples_read =
+      fread(audio_array_.get(), sizeof(int16_t), max_loop_length_samples, fp);
   fclose(fp);
 
   // Block length must be shorter than the loop length.
-  if (block_length_samples > samples_read) return false;
+  if (block_length_samples > samples_read)
+    return false;
 
   // Add an extra block length of samples to the end of the array, starting
   // over again from the beginning of the array. This is done to simplify
@@ -54,6 +56,5 @@
   return rtc::ArrayView<const int16_t>(output_ptr, block_length_samples_);
 }
 
-
 }  // namespace test
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/audio_loop.h b/modules/audio_coding/neteq/tools/audio_loop.h
index abb1a36..876c2d7 100644
--- a/modules/audio_coding/neteq/tools/audio_loop.h
+++ b/modules/audio_coding/neteq/tools/audio_loop.h
@@ -26,10 +26,7 @@
 class AudioLoop {
  public:
   AudioLoop()
-      : next_index_(0),
-        loop_length_samples_(0),
-        block_length_samples_(0) {
-  }
+      : next_index_(0), loop_length_samples_(0), block_length_samples_(0) {}
 
   virtual ~AudioLoop() {}
 
@@ -38,7 +35,8 @@
   // greater. Otherwise, the loop length is the same as the file length.
   // The audio will be delivered in blocks of |block_length_samples|.
   // Returns false if the initialization failed, otherwise true.
-  bool Init(const std::string file_name, size_t max_loop_length_samples,
+  bool Init(const std::string file_name,
+            size_t max_loop_length_samples,
             size_t block_length_samples);
 
   // Returns a (pointer,size) pair for the next block of audio. The size is
diff --git a/modules/audio_coding/neteq/tools/audio_sink.h b/modules/audio_coding/neteq/tools/audio_sink.h
index 18ac6fc..05e6fe8 100644
--- a/modules/audio_coding/neteq/tools/audio_sink.h
+++ b/modules/audio_coding/neteq/tools/audio_sink.h
@@ -32,9 +32,8 @@
   // Writes |audio_frame| to the AudioSink. Returns true if successful,
   // otherwise false.
   bool WriteAudioFrame(const AudioFrame& audio_frame) {
-    return WriteArray(
-        audio_frame.data(),
-        audio_frame.samples_per_channel_ * audio_frame.num_channels_);
+    return WriteArray(audio_frame.data(), audio_frame.samples_per_channel_ *
+                                              audio_frame.num_channels_);
   }
 
  private:
diff --git a/modules/audio_coding/neteq/tools/encode_neteq_input.cc b/modules/audio_coding/neteq/tools/encode_neteq_input.cc
index a8d1bdf..f0d5b6f 100644
--- a/modules/audio_coding/neteq/tools/encode_neteq_input.cc
+++ b/modules/audio_coding/neteq/tools/encode_neteq_input.cc
@@ -27,12 +27,12 @@
   CreatePacket();
 }
 
-rtc::Optional<int64_t> EncodeNetEqInput::NextPacketTime() const {
+absl::optional<int64_t> EncodeNetEqInput::NextPacketTime() const {
   RTC_DCHECK(packet_data_);
   return static_cast<int64_t>(packet_data_->time_ms);
 }
 
-rtc::Optional<int64_t> EncodeNetEqInput::NextOutputEventTime() const {
+absl::optional<int64_t> EncodeNetEqInput::NextOutputEventTime() const {
   return next_output_event_ms_;
 }
 
@@ -50,7 +50,7 @@
   next_output_event_ms_ += kOutputPeriodMs;
 }
 
-rtc::Optional<RTPHeader> EncodeNetEqInput::NextHeader() const {
+absl::optional<RTPHeader> EncodeNetEqInput::NextHeader() const {
   RTC_DCHECK(packet_data_);
   return packet_data_->header;
 }
diff --git a/modules/audio_coding/neteq/tools/encode_neteq_input.h b/modules/audio_coding/neteq/tools/encode_neteq_input.h
index 13b39b3..a75262b 100644
--- a/modules/audio_coding/neteq/tools/encode_neteq_input.h
+++ b/modules/audio_coding/neteq/tools/encode_neteq_input.h
@@ -36,9 +36,9 @@
                    std::unique_ptr<AudioEncoder> encoder,
                    int64_t input_duration_ms);
 
-  rtc::Optional<int64_t> NextPacketTime() const override;
+  absl::optional<int64_t> NextPacketTime() const override;
 
-  rtc::Optional<int64_t> NextOutputEventTime() const override;
+  absl::optional<int64_t> NextOutputEventTime() const override;
 
   std::unique_ptr<PacketData> PopPacket() override;
 
@@ -48,7 +48,7 @@
     return next_output_event_ms_ <= input_duration_ms_;
   }
 
-  rtc::Optional<RTPHeader> NextHeader() const override;
+  absl::optional<RTPHeader> NextHeader() const override;
 
  private:
   static constexpr int64_t kOutputPeriodMs = 10;
diff --git a/modules/audio_coding/neteq/tools/fake_decode_from_file.cc b/modules/audio_coding/neteq/tools/fake_decode_from_file.cc
index f437608..a51dac3 100644
--- a/modules/audio_coding/neteq/tools/fake_decode_from_file.cc
+++ b/modules/audio_coding/neteq/tools/fake_decode_from_file.cc
@@ -22,34 +22,24 @@
                                        int sample_rate_hz,
                                        int16_t* decoded,
                                        SpeechType* speech_type) {
+  RTC_DCHECK_EQ(sample_rate_hz, SampleRateHz());
+
+  const int samples_to_decode = PacketDuration(encoded, encoded_len);
+  const int total_samples_to_decode = samples_to_decode * (stereo_ ? 2 : 1);
+
   if (encoded_len == 0) {
     // Decoder is asked to produce codec-internal comfort noise.
     RTC_DCHECK(!encoded);  // NetEq always sends nullptr in this case.
     RTC_DCHECK(cng_mode_);
-    RTC_DCHECK_GT(last_decoded_length_, 0);
-    std::fill_n(decoded, last_decoded_length_, 0);
+    RTC_DCHECK_GT(total_samples_to_decode, 0);
+    std::fill_n(decoded, total_samples_to_decode, 0);
     *speech_type = kComfortNoise;
-    return rtc::dchecked_cast<int>(last_decoded_length_);
+    return rtc::dchecked_cast<int>(total_samples_to_decode);
   }
 
   RTC_CHECK_GE(encoded_len, 12);
   uint32_t timestamp_to_decode =
       ByteReader<uint32_t>::ReadLittleEndian(encoded);
-  uint32_t samples_to_decode =
-      ByteReader<uint32_t>::ReadLittleEndian(&encoded[4]);
-  if (samples_to_decode == 0) {
-    // Number of samples in packet is unknown.
-    if (last_decoded_length_ > 0) {
-      // Use length of last decoded packet, but since this is the total for all
-      // channels, we have to divide by 2 in the stereo case.
-      samples_to_decode = rtc::dchecked_cast<int>(rtc::CheckedDivExact(
-          last_decoded_length_, static_cast<size_t>(stereo_ ? 2uL : 1uL)));
-    } else {
-      // This is the first packet to decode, and we do not know the length of
-      // it. Set it to 10 ms.
-      samples_to_decode = rtc::CheckedDivExact(sample_rate_hz, 100);
-    }
-  }
 
   if (next_timestamp_from_input_ &&
       timestamp_to_decode != *next_timestamp_from_input_) {
@@ -65,11 +55,11 @@
       ByteReader<uint32_t>::ReadLittleEndian(&encoded[8]);
   if (original_payload_size_bytes == 1) {
     // This is a comfort noise payload.
-    RTC_DCHECK_GT(last_decoded_length_, 0);
-    std::fill_n(decoded, last_decoded_length_, 0);
+    RTC_DCHECK_GT(total_samples_to_decode, 0);
+    std::fill_n(decoded, total_samples_to_decode, 0);
     *speech_type = kComfortNoise;
     cng_mode_ = true;
-    return rtc::dchecked_cast<int>(last_decoded_length_);
+    return rtc::dchecked_cast<int>(total_samples_to_decode);
   }
 
   cng_mode_ = false;
@@ -78,12 +68,39 @@
   if (stereo_) {
     InputAudioFile::DuplicateInterleaved(decoded, samples_to_decode, 2,
                                          decoded);
-    samples_to_decode *= 2;
   }
 
   *speech_type = kSpeech;
   last_decoded_length_ = samples_to_decode;
-  return rtc::dchecked_cast<int>(last_decoded_length_);
+  return rtc::dchecked_cast<int>(total_samples_to_decode);
+}
+
+int FakeDecodeFromFile::PacketDuration(const uint8_t* encoded,
+                                       size_t encoded_len) const {
+  const uint32_t original_payload_size_bytes =
+      encoded_len < 8 + sizeof(uint32_t)
+          ? 0
+          : ByteReader<uint32_t>::ReadLittleEndian(&encoded[8]);
+  const uint32_t samples_to_decode =
+      encoded_len < 4 + sizeof(uint32_t)
+          ? 0
+          : ByteReader<uint32_t>::ReadLittleEndian(&encoded[4]);
+  if (  // Decoder is asked to produce codec-internal comfort noise
+      encoded_len == 0 ||
+      // Comfort noise payload
+      original_payload_size_bytes == 1 || samples_to_decode == 0 ||
+      // Erroneous duration since it is not a multiple of 10ms
+      samples_to_decode % rtc::CheckedDivExact(SampleRateHz(), 100) != 0) {
+    if (last_decoded_length_ > 0) {
+      // Use length of last decoded packet.
+      return rtc::dchecked_cast<int>(last_decoded_length_);
+    } else {
+      // This is the first packet to decode, and we do not know the length of
+      // it. Set it to 10 ms.
+      return rtc::CheckedDivExact(SampleRateHz(), 100);
+    }
+  }
+  return samples_to_decode;
 }
 
 void FakeDecodeFromFile::PrepareEncoded(uint32_t timestamp,
diff --git a/modules/audio_coding/neteq/tools/fake_decode_from_file.h b/modules/audio_coding/neteq/tools/fake_decode_from_file.h
index 7aa8e6e..c266d38 100644
--- a/modules/audio_coding/neteq/tools/fake_decode_from_file.h
+++ b/modules/audio_coding/neteq/tools/fake_decode_from_file.h
@@ -13,9 +13,9 @@
 
 #include <memory>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/audio_codecs/audio_decoder.h"
-#include "api/optional.h"
 #include "modules/audio_coding/neteq/tools/input_audio_file.h"
 
 namespace webrtc {
@@ -50,6 +50,8 @@
                      int16_t* decoded,
                      SpeechType* speech_type) override;
 
+  int PacketDuration(const uint8_t* encoded, size_t encoded_len) const override;
+
   // Helper method. Writes |timestamp|, |samples| and
   // |original_payload_size_bytes| to |encoded| in a format that the
   // FakeDecodeFromFile decoder will understand. |encoded| must be at least 12
@@ -61,7 +63,7 @@
 
  private:
   std::unique_ptr<InputAudioFile> input_;
-  rtc::Optional<uint32_t> next_timestamp_from_input_;
+  absl::optional<uint32_t> next_timestamp_from_input_;
   const int sample_rate_hz_;
   const bool stereo_;
   size_t last_decoded_length_ = 0;
diff --git a/modules/audio_coding/neteq/tools/input_audio_file.cc b/modules/audio_coding/neteq/tools/input_audio_file.cc
index 330a874..6d11064 100644
--- a/modules/audio_coding/neteq/tools/input_audio_file.cc
+++ b/modules/audio_coding/neteq/tools/input_audio_file.cc
@@ -20,7 +20,9 @@
   fp_ = fopen(file_name.c_str(), "rb");
 }
 
-InputAudioFile::~InputAudioFile() { fclose(fp_); }
+InputAudioFile::~InputAudioFile() {
+  fclose(fp_);
+}
 
 bool InputAudioFile::Read(size_t samples, int16_t* destination) {
   if (!fp_) {
@@ -73,7 +75,8 @@
   return true;
 }
 
-void InputAudioFile::DuplicateInterleaved(const int16_t* source, size_t samples,
+void InputAudioFile::DuplicateInterleaved(const int16_t* source,
+                                          size_t samples,
                                           size_t channels,
                                           int16_t* destination) {
   // Start from the end of |source| and |destination|, and work towards the
diff --git a/modules/audio_coding/neteq/tools/input_audio_file.h b/modules/audio_coding/neteq/tools/input_audio_file.h
index 6bfa369..db5a944 100644
--- a/modules/audio_coding/neteq/tools/input_audio_file.h
+++ b/modules/audio_coding/neteq/tools/input_audio_file.h
@@ -45,8 +45,10 @@
   // channels are identical. The output |destination| must have the capacity to
   // hold samples * channels elements. Note that |source| and |destination| can
   // be the same array (i.e., point to the same address).
-  static void DuplicateInterleaved(const int16_t* source, size_t samples,
-                                   size_t channels, int16_t* destination);
+  static void DuplicateInterleaved(const int16_t* source,
+                                   size_t samples,
+                                   size_t channels,
+                                   int16_t* destination);
 
  private:
   FILE* fp_;
diff --git a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc
index ba0b217..e5bd765 100644
--- a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc
+++ b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.cc
@@ -23,6 +23,13 @@
 namespace webrtc {
 namespace test {
 namespace {
+std::string kArrivalDelayX = "arrival_delay_x";
+std::string kArrivalDelayY = "arrival_delay_y";
+std::string kTargetDelayX = "target_delay_x";
+std::string kTargetDelayY = "target_delay_y";
+std::string kPlayoutDelayX = "playout_delay_x";
+std::string kPlayoutDelayY = "playout_delay_y";
+
 // Helper function for NetEqDelayAnalyzer::CreateGraphs. Returns the
 // interpolated value of a function at the point x. Vector x_vec contains the
 // sample points, and y_vec contains the function values at these points. The
@@ -54,6 +61,26 @@
   }
   return y;
 }
+
+void PrintDelays(const NetEqDelayAnalyzer::Delays& delays,
+                 int64_t ref_time_ms,
+                 const std::string& var_name_x,
+                 const std::string& var_name_y,
+                 std::ofstream& output,
+                 const std::string& terminator = "") {
+  output << var_name_x << " = [ ";
+  for (const std::pair<int64_t, float>& delay : delays) {
+    output << (delay.first - ref_time_ms) / 1000.f << ", ";
+  }
+  output << "]" << terminator << std::endl;
+
+  output << var_name_y << " = [ ";
+  for (const std::pair<int64_t, float>& delay : delays) {
+    output << delay.second << ", ";
+  }
+  output << "]" << terminator << std::endl;
+}
+
 }  // namespace
 
 void NetEqDelayAnalyzer::AfterInsertPacket(
@@ -97,12 +124,10 @@
   ++get_audio_count_;
 }
 
-void NetEqDelayAnalyzer::CreateGraphs(
-    std::vector<float>* send_time_s,
-    std::vector<float>* arrival_delay_ms,
-    std::vector<float>* corrected_arrival_delay_ms,
-    std::vector<rtc::Optional<float>>* playout_delay_ms,
-    std::vector<rtc::Optional<float>>* target_delay_ms) const {
+void NetEqDelayAnalyzer::CreateGraphs(Delays* arrival_delay_ms,
+                                      Delays* corrected_arrival_delay_ms,
+                                      Delays* playout_delay_ms,
+                                      Delays* target_delay_ms) const {
   if (get_audio_time_ms_.empty()) {
     return;
   }
@@ -123,111 +148,76 @@
   // calculates the base offset.
   for (auto& d : data_) {
     rtp_timestamps_ms.push_back(
-        unwrapper.Unwrap(d.first) /
+        static_cast<double>(unwrapper.Unwrap(d.first)) /
         rtc::CheckedDivExact(last_sample_rate_hz_, 1000));
     offset =
         std::min(offset, d.second.arrival_time_ms - rtp_timestamps_ms.back());
   }
 
-  // Calculate send times in seconds for each packet. This is the (unwrapped)
-  // RTP timestamp in ms divided by 1000.
-  send_time_s->resize(rtp_timestamps_ms.size());
-  std::transform(rtp_timestamps_ms.begin(), rtp_timestamps_ms.end(),
-                 send_time_s->begin(), [rtp_timestamps_ms](double x) {
-                   return (x - rtp_timestamps_ms[0]) / 1000.f;
-                 });
-  RTC_DCHECK_EQ(send_time_s->size(), rtp_timestamps_ms.size());
-
   // This loop traverses the data again and populates the graph vectors. The
   // reason to have two loops and traverse twice is that the offset cannot be
   // known until the first traversal is done. Meanwhile, the final offset must
   // be known already at the start of this second loop.
-  auto data_it = data_.cbegin();
-  for (size_t i = 0; i < send_time_s->size(); ++i, ++data_it) {
-    RTC_DCHECK(data_it != data_.end());
-    const double offset_send_time_ms = rtp_timestamps_ms[i] + offset;
-    const auto& timing = data_it->second;
-    corrected_arrival_delay_ms->push_back(
+  size_t i = 0;
+  for (const auto& data : data_) {
+    const double offset_send_time_ms = rtp_timestamps_ms[i++] + offset;
+    const auto& timing = data.second;
+    corrected_arrival_delay_ms->push_back(std::make_pair(
+        timing.arrival_time_ms,
         LinearInterpolate(timing.arrival_time_ms, get_audio_time_ms_,
                           nominal_get_audio_time_ms) -
-        offset_send_time_ms);
-    arrival_delay_ms->push_back(timing.arrival_time_ms - offset_send_time_ms);
+            offset_send_time_ms));
+    arrival_delay_ms->push_back(std::make_pair(
+        timing.arrival_time_ms, timing.arrival_time_ms - offset_send_time_ms));
 
     if (timing.decode_get_audio_count) {
       // This packet was decoded.
       RTC_DCHECK(timing.sync_delay_ms);
-      const float playout_ms = *timing.decode_get_audio_count * 10 +
-                               get_audio_time_ms_[0] + *timing.sync_delay_ms -
-                               offset_send_time_ms;
-      playout_delay_ms->push_back(playout_ms);
+      const int64_t get_audio_time =
+          *timing.decode_get_audio_count * 10 + get_audio_time_ms_[0];
+      const float playout_ms =
+          get_audio_time + *timing.sync_delay_ms - offset_send_time_ms;
+      playout_delay_ms->push_back(std::make_pair(get_audio_time, playout_ms));
       RTC_DCHECK(timing.target_delay_ms);
       RTC_DCHECK(timing.current_delay_ms);
       const float target =
           playout_ms - *timing.current_delay_ms + *timing.target_delay_ms;
-      target_delay_ms->push_back(target);
-    } else {
-      // This packet was never decoded. Mark target and playout delays as empty.
-      playout_delay_ms->push_back(rtc::nullopt);
-      target_delay_ms->push_back(rtc::nullopt);
+      target_delay_ms->push_back(std::make_pair(get_audio_time, target));
     }
   }
-  RTC_DCHECK(data_it == data_.end());
-  RTC_DCHECK_EQ(send_time_s->size(), corrected_arrival_delay_ms->size());
-  RTC_DCHECK_EQ(send_time_s->size(), playout_delay_ms->size());
-  RTC_DCHECK_EQ(send_time_s->size(), target_delay_ms->size());
 }
 
 void NetEqDelayAnalyzer::CreateMatlabScript(
     const std::string& script_name) const {
-  std::vector<float> send_time_s;
-  std::vector<float> arrival_delay_ms;
-  std::vector<float> corrected_arrival_delay_ms;
-  std::vector<rtc::Optional<float>> playout_delay_ms;
-  std::vector<rtc::Optional<float>> target_delay_ms;
-  CreateGraphs(&send_time_s, &arrival_delay_ms, &corrected_arrival_delay_ms,
+  Delays arrival_delay_ms;
+  Delays corrected_arrival_delay_ms;
+  Delays playout_delay_ms;
+  Delays target_delay_ms;
+  CreateGraphs(&arrival_delay_ms, &corrected_arrival_delay_ms,
                &playout_delay_ms, &target_delay_ms);
 
+  // Maybe better to find the actually smallest timestamp, to surely avoid
+  // x-axis starting from negative.
+  const int64_t ref_time_ms = arrival_delay_ms.front().first;
+
   // Create an output file stream to Matlab script file.
   std::ofstream output(script_name);
-  // The iterator is used to batch-output comma-separated values from vectors.
-  std::ostream_iterator<float> output_iterator(output, ",");
 
-  output << "send_time_s = [ ";
-  std::copy(send_time_s.begin(), send_time_s.end(), output_iterator);
-  output << "];" << std::endl;
+  PrintDelays(corrected_arrival_delay_ms, ref_time_ms, kArrivalDelayX,
+              kArrivalDelayY, output, ";");
 
-  output << "arrival_delay_ms = [ ";
-  std::copy(arrival_delay_ms.begin(), arrival_delay_ms.end(), output_iterator);
-  output << "];" << std::endl;
+  // PrintDelays(corrected_arrival_delay_x, kCorrectedArrivalDelayX,
+  // kCorrectedArrivalDelayY, output);
 
-  output << "corrected_arrival_delay_ms = [ ";
-  std::copy(corrected_arrival_delay_ms.begin(),
-            corrected_arrival_delay_ms.end(), output_iterator);
-  output << "];" << std::endl;
+  PrintDelays(playout_delay_ms, ref_time_ms, kPlayoutDelayX, kPlayoutDelayY,
+              output, ";");
 
-  output << "playout_delay_ms = [ ";
-  for (const auto& v : playout_delay_ms) {
-    if (!v) {
-      output << "nan, ";
-    } else {
-      output << *v << ", ";
-    }
-  }
-  output << "];" << std::endl;
+  PrintDelays(target_delay_ms, ref_time_ms, kTargetDelayX, kTargetDelayY,
+              output, ";");
 
-  output << "target_delay_ms = [ ";
-  for (const auto& v : target_delay_ms) {
-    if (!v) {
-      output << "nan, ";
-    } else {
-      output << *v << ", ";
-    }
-  }
-  output << "];" << std::endl;
-
-  output << "h=plot(send_time_s, arrival_delay_ms, "
-         << "send_time_s, target_delay_ms, 'g.', "
-         << "send_time_s, playout_delay_ms);" << std::endl;
+  output << "h=plot(" << kArrivalDelayX << ", " << kArrivalDelayY << ", "
+         << kTargetDelayX << ", " << kTargetDelayY << ", 'g.', "
+         << kPlayoutDelayX << ", " << kPlayoutDelayY << ");" << std::endl;
   output << "set(h(1),'color',0.75*[1 1 1]);" << std::endl;
   output << "set(h(2),'markersize',6);" << std::endl;
   output << "set(h(3),'linew',1.5);" << std::endl;
@@ -235,7 +225,7 @@
   output << "axis tight" << std::endl;
   output << "ax2=axis;" << std::endl;
   output << "axis([ax2(1:3) ax1(4)])" << std::endl;
-  output << "xlabel('send time [s]');" << std::endl;
+  output << "xlabel('time [s]');" << std::endl;
   output << "ylabel('relative delay [ms]');" << std::endl;
   if (!ssrcs_.empty()) {
     auto ssrc_it = ssrcs_.cbegin();
@@ -255,65 +245,45 @@
 
 void NetEqDelayAnalyzer::CreatePythonScript(
     const std::string& script_name) const {
-  std::vector<float> send_time_s;
-  std::vector<float> arrival_delay_ms;
-  std::vector<float> corrected_arrival_delay_ms;
-  std::vector<rtc::Optional<float>> playout_delay_ms;
-  std::vector<rtc::Optional<float>> target_delay_ms;
-  CreateGraphs(&send_time_s, &arrival_delay_ms, &corrected_arrival_delay_ms,
+  Delays arrival_delay_ms;
+  Delays corrected_arrival_delay_ms;
+  Delays playout_delay_ms;
+  Delays target_delay_ms;
+  CreateGraphs(&arrival_delay_ms, &corrected_arrival_delay_ms,
                &playout_delay_ms, &target_delay_ms);
 
+  // Maybe better to find the actually smallest timestamp, to surely avoid
+  // x-axis starting from negative.
+  const int64_t ref_time_ms = arrival_delay_ms.front().first;
+
   // Create an output file stream to the python script file.
   std::ofstream output(script_name);
-  // The iterator is used to batch-output comma-separated values from vectors.
-  std::ostream_iterator<float> output_iterator(output, ",");
 
   // Necessary includes
   output << "import numpy as np" << std::endl;
   output << "import matplotlib.pyplot as plt" << std::endl;
 
-  output << "send_time_s = [";
-  std::copy(send_time_s.begin(), send_time_s.end(), output_iterator);
-  output << "]" << std::endl;
+  PrintDelays(corrected_arrival_delay_ms, ref_time_ms, kArrivalDelayX,
+              kArrivalDelayY, output);
 
-  output << "arrival_delay_ms = [";
-  std::copy(arrival_delay_ms.begin(), arrival_delay_ms.end(), output_iterator);
-  output << "]" << std::endl;
+  // PrintDelays(corrected_arrival_delay_x, kCorrectedArrivalDelayX,
+  // kCorrectedArrivalDelayY, output);
 
-  output << "corrected_arrival_delay_ms = [";
-  std::copy(corrected_arrival_delay_ms.begin(),
-            corrected_arrival_delay_ms.end(), output_iterator);
-  output << "]" << std::endl;
+  PrintDelays(playout_delay_ms, ref_time_ms, kPlayoutDelayX, kPlayoutDelayY,
+              output);
 
-  output << "playout_delay_ms = [";
-  for (const auto& v : playout_delay_ms) {
-    if (!v) {
-      output << "float('nan'), ";
-    } else {
-      output << *v << ", ";
-    }
-  }
-  output << "]" << std::endl;
-
-  output << "target_delay_ms = [";
-  for (const auto& v : target_delay_ms) {
-    if (!v) {
-      output << "float('nan'), ";
-    } else {
-      output << *v << ", ";
-    }
-  }
-  output << "]" << std::endl;
+  PrintDelays(target_delay_ms, ref_time_ms, kTargetDelayX, kTargetDelayY,
+              output);
 
   output << "if __name__ == '__main__':" << std::endl;
-  output << "  h=plt.plot(send_time_s, arrival_delay_ms, "
-         << "send_time_s, target_delay_ms, 'g.', "
-         << "send_time_s, playout_delay_ms)" << std::endl;
+  output << "  h=plt.plot(" << kArrivalDelayX << ", " << kArrivalDelayY << ", "
+         << kTargetDelayX << ", " << kTargetDelayY << ", 'g.', "
+         << kPlayoutDelayX << ", " << kPlayoutDelayY << ")" << std::endl;
   output << "  plt.setp(h[0],'color',[.75, .75, .75])" << std::endl;
   output << "  plt.setp(h[1],'markersize',6)" << std::endl;
   output << "  plt.setp(h[2],'linewidth',1.5)" << std::endl;
   output << "  plt.axis('tight')" << std::endl;
-  output << "  plt.xlabel('send time [s]')" << std::endl;
+  output << "  plt.xlabel('time [s]')" << std::endl;
   output << "  plt.ylabel('relative delay [ms]')" << std::endl;
   if (!ssrcs_.empty()) {
     auto ssrc_it = ssrcs_.cbegin();
diff --git a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h
index e6d6913..5099e03 100644
--- a/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h
+++ b/modules/audio_coding/neteq/tools/neteq_delay_analyzer.h
@@ -16,7 +16,7 @@
 #include <string>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_coding/neteq/tools/neteq_input.h"
 #include "modules/audio_coding/neteq/tools/neteq_test.h"
 #include "typedefs.h"  // NOLINT(build/include)
@@ -37,11 +37,11 @@
                      bool muted,
                      NetEq* neteq) override;
 
-  void CreateGraphs(std::vector<float>* send_times_s,
-                    std::vector<float>* arrival_delay_ms,
-                    std::vector<float>* corrected_arrival_delay_ms,
-                    std::vector<rtc::Optional<float>>* playout_delay_ms,
-                    std::vector<rtc::Optional<float>>* target_delay_ms) const;
+  using Delays = std::vector<std::pair<int64_t, float>>;
+  void CreateGraphs(Delays* arrival_delay_ms,
+                    Delays* corrected_arrival_delay_ms,
+                    Delays* playout_delay_ms,
+                    Delays* target_delay_ms) const;
 
   // Creates a matlab script with file name script_name. When executed in
   // Matlab, the script will generate graphs with the same timing information
@@ -55,12 +55,12 @@
 
  private:
   struct TimingData {
-    explicit TimingData(double at) : arrival_time_ms(at) {}
-    double arrival_time_ms;
-    rtc::Optional<int64_t> decode_get_audio_count;
-    rtc::Optional<int64_t> sync_delay_ms;
-    rtc::Optional<int> target_delay_ms;
-    rtc::Optional<int> current_delay_ms;
+    explicit TimingData(int64_t at) : arrival_time_ms(at) {}
+    int64_t arrival_time_ms;
+    absl::optional<int64_t> decode_get_audio_count;
+    absl::optional<int64_t> sync_delay_ms;
+    absl::optional<int> target_delay_ms;
+    absl::optional<int> current_delay_ms;
   };
   std::map<uint32_t, TimingData> data_;
   std::vector<int64_t> get_audio_time_ms_;
diff --git a/modules/audio_coding/neteq/tools/neteq_event_log_input.cc b/modules/audio_coding/neteq/tools/neteq_event_log_input.cc
new file mode 100644
index 0000000..21c5f9e
--- /dev/null
+++ b/modules/audio_coding/neteq/tools/neteq_event_log_input.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_coding/neteq/tools/neteq_event_log_input.h"
+
+#include <limits>
+
+#include "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+
+NetEqEventLogInput::NetEqEventLogInput(const std::string& file_name,
+                                       const RtpHeaderExtensionMap& hdr_ext_map)
+    : source_(RtcEventLogSource::Create(file_name)) {
+  for (const auto& ext_pair : hdr_ext_map) {
+    source_->RegisterRtpHeaderExtension(ext_pair.second, ext_pair.first);
+  }
+  LoadNextPacket();
+  AdvanceOutputEvent();
+}
+
+absl::optional<int64_t> NetEqEventLogInput::NextOutputEventTime() const {
+  return next_output_event_ms_;
+}
+
+void NetEqEventLogInput::AdvanceOutputEvent() {
+  next_output_event_ms_ = source_->NextAudioOutputEventMs();
+  if (*next_output_event_ms_ == std::numeric_limits<int64_t>::max()) {
+    next_output_event_ms_ = absl::nullopt;
+  }
+}
+
+PacketSource* NetEqEventLogInput::source() {
+  return source_.get();
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_event_log_input.h b/modules/audio_coding/neteq/tools/neteq_event_log_input.h
new file mode 100644
index 0000000..86cf9f2
--- /dev/null
+++ b/modules/audio_coding/neteq/tools/neteq_event_log_input.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EVENT_LOG_INPUT_H_
+#define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EVENT_LOG_INPUT_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+namespace test {
+
+class RtcEventLogSource;
+
+// Implementation of NetEqPacketSourceInput to be used with an
+// RtcEventLogSource.
+class NetEqEventLogInput final : public NetEqPacketSourceInput {
+ public:
+  NetEqEventLogInput(const std::string& file_name,
+                     const RtpHeaderExtensionMap& hdr_ext_map);
+
+  absl::optional<int64_t> NextOutputEventTime() const override;
+  void AdvanceOutputEvent() override;
+
+ protected:
+  PacketSource* source() override;
+
+ private:
+  std::unique_ptr<RtcEventLogSource> source_;
+};
+
+}  // namespace test
+}  // namespace webrtc
+#endif  // MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EVENT_LOG_INPUT_H_
diff --git a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
index 2c23e5c..3bd218b 100644
--- a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 #include "modules/audio_coding/neteq/tools/neteq_external_decoder_test.h"
 
 #include "api/audio/audio_frame.h"
@@ -32,9 +31,8 @@
 }
 
 void NetEqExternalDecoderTest::Init() {
-  ASSERT_EQ(NetEq::kOK,
-            neteq_->RegisterExternalDecoder(decoder_, codec_, name_,
-                                            kPayloadType));
+  ASSERT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(decoder_, codec_, name_,
+                                                        kPayloadType));
 }
 
 void NetEqExternalDecoderTest::InsertPacket(
diff --git a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h
index b8670a3..78f0085 100644
--- a/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h
+++ b/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h
@@ -31,7 +31,7 @@
                            int sample_rate_hz,
                            AudioDecoder* decoder);
 
-  virtual ~NetEqExternalDecoderTest() { }
+  virtual ~NetEqExternalDecoderTest() {}
 
   // In Init(), we register the external decoder.
   void Init();
diff --git a/modules/audio_coding/neteq/tools/neteq_input.cc b/modules/audio_coding/neteq/tools/neteq_input.cc
index 44513ab..fed3ecc 100644
--- a/modules/audio_coding/neteq/tools/neteq_input.cc
+++ b/modules/audio_coding/neteq/tools/neteq_input.cc
@@ -28,5 +28,50 @@
   return ss.str();
 }
 
+TimeLimitedNetEqInput::TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input,
+                                             int64_t duration_ms)
+    : input_(std::move(input)),
+      start_time_ms_(input_->NextEventTime()),
+      duration_ms_(duration_ms) {}
+
+absl::optional<int64_t> TimeLimitedNetEqInput::NextPacketTime() const {
+  return ended_ ? absl::nullopt : input_->NextPacketTime();
+}
+
+absl::optional<int64_t> TimeLimitedNetEqInput::NextOutputEventTime() const {
+  return ended_ ? absl::nullopt : input_->NextOutputEventTime();
+}
+
+std::unique_ptr<NetEqInput::PacketData> TimeLimitedNetEqInput::PopPacket() {
+  if (ended_) {
+    return std::unique_ptr<PacketData>();
+  }
+  auto packet = input_->PopPacket();
+  MaybeSetEnded();
+  return packet;
+}
+
+void TimeLimitedNetEqInput::AdvanceOutputEvent() {
+  if (!ended_) {
+    input_->AdvanceOutputEvent();
+    MaybeSetEnded();
+  }
+}
+
+bool TimeLimitedNetEqInput::ended() const {
+  return ended_ || input_->ended();
+}
+
+absl::optional<RTPHeader> TimeLimitedNetEqInput::NextHeader() const {
+  return ended_ ? absl::nullopt : input_->NextHeader();
+}
+
+void TimeLimitedNetEqInput::MaybeSetEnded() {
+  if (NextEventTime() && start_time_ms_ &&
+      *NextEventTime() - *start_time_ms_ > duration_ms_) {
+    ended_ = true;
+  }
+}
+
 }  // namespace test
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_input.h b/modules/audio_coding/neteq/tools/neteq_input.h
index 88d9eb9..1691585 100644
--- a/modules/audio_coding/neteq/tools/neteq_input.h
+++ b/modules/audio_coding/neteq/tools/neteq_input.h
@@ -15,7 +15,7 @@
 #include <memory>
 #include <string>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/audio_coding/neteq/tools/packet.h"
 #include "modules/audio_coding/neteq/tools/packet_source.h"
@@ -32,29 +32,29 @@
 
     RTPHeader header;
     rtc::Buffer payload;
-    double time_ms;
+    int64_t time_ms;
   };
 
   virtual ~NetEqInput() = default;
 
   // Returns at what time (in ms) NetEq::InsertPacket should be called next, or
   // empty if the source is out of packets.
-  virtual rtc::Optional<int64_t> NextPacketTime() const = 0;
+  virtual absl::optional<int64_t> NextPacketTime() const = 0;
 
   // Returns at what time (in ms) NetEq::GetAudio should be called next, or
   // empty if no more output events are available.
-  virtual rtc::Optional<int64_t> NextOutputEventTime() const = 0;
+  virtual absl::optional<int64_t> NextOutputEventTime() const = 0;
 
   // Returns the time (in ms) for the next event from either NextPacketTime()
   // or NextOutputEventTime(), or empty if both are out of events.
-  rtc::Optional<int64_t> NextEventTime() const {
+  absl::optional<int64_t> NextEventTime() const {
     const auto a = NextPacketTime();
     const auto b = NextOutputEventTime();
     // Return the minimum of non-empty |a| and |b|, or empty if both are empty.
     if (a) {
       return b ? std::min(*a, *b) : a;
     }
-    return b ? b : rtc::nullopt;
+    return b ? b : absl::nullopt;
   }
 
   // Returns the next packet to be inserted into NetEq. The packet following the
@@ -75,7 +75,29 @@
 
   // Returns the RTP header for the next packet, i.e., the packet that will be
   // delivered next by PopPacket().
-  virtual rtc::Optional<RTPHeader> NextHeader() const = 0;
+  virtual absl::optional<RTPHeader> NextHeader() const = 0;
+};
+
+// Wrapper class to impose a time limit on a NetEqInput object, typically
+// another time limit than what the object itself provides. For example, an
+// input taken from a file can be cut shorter by wrapping it in this class.
+class TimeLimitedNetEqInput : public NetEqInput {
+ public:
+  TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input, int64_t duration_ms);
+  absl::optional<int64_t> NextPacketTime() const override;
+  absl::optional<int64_t> NextOutputEventTime() const override;
+  std::unique_ptr<PacketData> PopPacket() override;
+  void AdvanceOutputEvent() override;
+  bool ended() const override;
+  absl::optional<RTPHeader> NextHeader() const override;
+
+ private:
+  void MaybeSetEnded();
+
+  std::unique_ptr<NetEqInput> input_;
+  const absl::optional<int64_t> start_time_ms_;
+  const int64_t duration_ms_;
+  bool ended_ = false;
 };
 
 }  // namespace test
diff --git a/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc b/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc
index 0741d7c..a86cf6a 100644
--- a/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc
+++ b/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc
@@ -13,7 +13,6 @@
 #include <algorithm>
 #include <limits>
 
-#include "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
 #include "modules/audio_coding/neteq/tools/rtp_file_source.h"
 #include "rtc_base/checks.h"
 
@@ -22,15 +21,14 @@
 
 NetEqPacketSourceInput::NetEqPacketSourceInput() : next_output_event_ms_(0) {}
 
-rtc::Optional<int64_t> NetEqPacketSourceInput::NextPacketTime() const {
+absl::optional<int64_t> NetEqPacketSourceInput::NextPacketTime() const {
   return packet_
-             ? rtc::Optional<int64_t>(static_cast<int64_t>(packet_->time_ms()))
-             : rtc::nullopt;
+             ? absl::optional<int64_t>(static_cast<int64_t>(packet_->time_ms()))
+             : absl::nullopt;
 }
 
-rtc::Optional<RTPHeader> NetEqPacketSourceInput::NextHeader() const {
-  return packet_ ? rtc::Optional<RTPHeader>(packet_->header())
-                 : rtc::nullopt;
+absl::optional<RTPHeader> NetEqPacketSourceInput::NextHeader() const {
+  return packet_ ? absl::optional<RTPHeader>(packet_->header()) : absl::nullopt;
 }
 
 void NetEqPacketSourceInput::LoadNextPacket() {
@@ -60,6 +58,12 @@
   return packet_data;
 }
 
+void NetEqPacketSourceInput::SelectSsrc(uint32_t ssrc) {
+  source()->SelectSsrc(ssrc);
+  if (packet_ && packet_->header().ssrc != ssrc)
+    LoadNextPacket();
+}
+
 NetEqRtpDumpInput::NetEqRtpDumpInput(const std::string& file_name,
                                      const RtpHeaderExtensionMap& hdr_ext_map)
     : source_(RtpFileSource::Create(file_name)) {
@@ -69,7 +73,7 @@
   LoadNextPacket();
 }
 
-rtc::Optional<int64_t> NetEqRtpDumpInput::NextOutputEventTime() const {
+absl::optional<int64_t> NetEqRtpDumpInput::NextOutputEventTime() const {
   return next_output_event_ms_;
 }
 
@@ -78,7 +82,7 @@
     *next_output_event_ms_ += kOutputPeriodMs;
   }
   if (!NextPacketTime()) {
-    next_output_event_ms_ = rtc::nullopt;
+    next_output_event_ms_ = absl::nullopt;
   }
 }
 
@@ -86,30 +90,5 @@
   return source_.get();
 }
 
-NetEqEventLogInput::NetEqEventLogInput(const std::string& file_name,
-                                       const RtpHeaderExtensionMap& hdr_ext_map)
-    : source_(RtcEventLogSource::Create(file_name)) {
-  for (const auto& ext_pair : hdr_ext_map) {
-    source_->RegisterRtpHeaderExtension(ext_pair.second, ext_pair.first);
-  }
-  LoadNextPacket();
-  AdvanceOutputEvent();
-}
-
-rtc::Optional<int64_t> NetEqEventLogInput::NextOutputEventTime() const {
-  return next_output_event_ms_;
-}
-
-void NetEqEventLogInput::AdvanceOutputEvent() {
-  next_output_event_ms_ = source_->NextAudioOutputEventMs();
-  if (*next_output_event_ms_ == std::numeric_limits<int64_t>::max()) {
-    next_output_event_ms_ = rtc::nullopt;
-  }
-}
-
-PacketSource* NetEqEventLogInput::source() {
-  return source_.get();
-}
-
 }  // namespace test
 }  // namespace webrtc
diff --git a/modules/audio_coding/neteq/tools/neteq_packet_source_input.h b/modules/audio_coding/neteq/tools/neteq_packet_source_input.h
index b482556..b32c534 100644
--- a/modules/audio_coding/neteq/tools/neteq_packet_source_input.h
+++ b/modules/audio_coding/neteq/tools/neteq_packet_source_input.h
@@ -21,7 +21,6 @@
 namespace test {
 
 class RtpFileSource;
-class RtcEventLogSource;
 
 // An adapter class to dress up a PacketSource object as a NetEqInput.
 class NetEqPacketSourceInput : public NetEqInput {
@@ -29,16 +28,17 @@
   using RtpHeaderExtensionMap = std::map<int, webrtc::RTPExtensionType>;
 
   NetEqPacketSourceInput();
-  rtc::Optional<int64_t> NextPacketTime() const override;
+  absl::optional<int64_t> NextPacketTime() const override;
   std::unique_ptr<PacketData> PopPacket() override;
-  rtc::Optional<RTPHeader> NextHeader() const override;
+  absl::optional<RTPHeader> NextHeader() const override;
   bool ended() const override { return !next_output_event_ms_; }
+  void SelectSsrc(uint32_t);
 
  protected:
   virtual PacketSource* source() = 0;
   void LoadNextPacket();
 
-  rtc::Optional<int64_t> next_output_event_ms_;
+  absl::optional<int64_t> next_output_event_ms_;
 
  private:
   std::unique_ptr<Packet> packet_;
@@ -50,7 +50,7 @@
   NetEqRtpDumpInput(const std::string& file_name,
                     const RtpHeaderExtensionMap& hdr_ext_map);
 
-  rtc::Optional<int64_t> NextOutputEventTime() const override;
+  absl::optional<int64_t> NextOutputEventTime() const override;
   void AdvanceOutputEvent() override;
 
  protected:
@@ -62,23 +62,6 @@
   std::unique_ptr<RtpFileSource> source_;
 };
 
-// Implementation of NetEqPacketSourceInput to be used with an
-// RtcEventLogSource.
-class NetEqEventLogInput final : public NetEqPacketSourceInput {
- public:
-  NetEqEventLogInput(const std::string& file_name,
-                     const RtpHeaderExtensionMap& hdr_ext_map);
-
-  rtc::Optional<int64_t> NextOutputEventTime() const override;
-  void AdvanceOutputEvent() override;
-
- protected:
-  PacketSource* source() override;
-
- private:
-  std::unique_ptr<RtcEventLogSource> source_;
-};
-
 }  // namespace test
 }  // namespace webrtc
 #endif  // MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_PACKET_SOURCE_INPUT_H_
diff --git a/modules/audio_coding/neteq/tools/neteq_performance_test.cc b/modules/audio_coding/neteq/tools/neteq_performance_test.cc
index 80aa809..e0dfebf 100644
--- a/modules/audio_coding/neteq/tools/neteq_performance_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_performance_test.cc
@@ -95,9 +95,8 @@
       }
 
       // Get next packet.
-      packet_input_time_ms = rtp_gen.GetRtpHeader(kPayloadType,
-                                                  kInputBlockSizeSamples,
-                                                  &rtp_header);
+      packet_input_time_ms = rtp_gen.GetRtpHeader(
+          kPayloadType, kInputBlockSizeSamples, &rtp_header);
       input_samples = audio_loop.GetNextBlock();
       if (input_samples.empty())
         return -1;
diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.cc b/modules/audio_coding/neteq/tools/neteq_quality_test.cc
index 82fa90e..faca895 100644
--- a/modules/audio_coding/neteq/tools/neteq_quality_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_quality_test.cc
@@ -47,7 +47,9 @@
   return true;
 }
 
-DEFINE_string(in_filename, DefaultInFilename().c_str(),
+DEFINE_string(
+    in_filename,
+    DefaultInFilename().c_str(),
     "Filename for input audio (specify sample rate with --input_sample_rate, "
     "and channels with --channels).");
 
@@ -55,8 +57,9 @@
 
 DEFINE_int(channels, 1, "Number of channels in input audio.");
 
-DEFINE_string(out_filename, DefaultOutFilename().c_str(),
-    "Name of output audio file.");
+DEFINE_string(out_filename,
+              DefaultOutFilename().c_str(),
+              "Name of output audio file.");
 
 DEFINE_int(runtime_ms, 10000, "Simulated runtime (milliseconds).");
 
@@ -67,8 +70,9 @@
            "Random loss mode: 0--no loss, 1--uniform loss, 2--Gilbert Elliot "
            "loss, 3--fixed loss.");
 
-DEFINE_int(burst_length, 30,
-    "Burst length in milliseconds, only valid for Gilbert Elliot loss.");
+DEFINE_int(burst_length,
+           30,
+           "Burst length in milliseconds, only valid for Gilbert Elliot loss.");
 
 DEFINE_float(drift_factor, 0.0, "Time drift factor.");
 
@@ -85,21 +89,22 @@
 // to achieve the target packet loss rate |loss_rate|, when a packet is not
 // lost only if all |units| drawings within the duration of the packet result in
 // no-loss.
-static double ProbTrans00Solver(int units, double loss_rate,
+static double ProbTrans00Solver(int units,
+                                double loss_rate,
                                 double prob_trans_10) {
   if (units == 1)
     return prob_trans_10 / (1.0f - loss_rate) - prob_trans_10;
-// 0 == prob_trans_00 ^ (units - 1) + (1 - loss_rate) / prob_trans_10 *
-//     prob_trans_00 - (1 - loss_rate) * (1 + 1 / prob_trans_10).
-// There is a unique solution between 0.0 and 1.0, due to the monotonicity and
-// an opposite sign at 0.0 and 1.0.
-// For simplicity, we reformulate the equation as
-//     f(x) = x ^ (units - 1) + a x + b.
-// Its derivative is
-//     f'(x) = (units - 1) x ^ (units - 2) + a.
-// The derivative is strictly greater than 0 when x is between 0 and 1.
-// We use Newton's method to solve the equation, iteration is
-//     x(k+1) = x(k) - f(x) / f'(x);
+  // 0 == prob_trans_00 ^ (units - 1) + (1 - loss_rate) / prob_trans_10 *
+  //     prob_trans_00 - (1 - loss_rate) * (1 + 1 / prob_trans_10).
+  // There is a unique solution between 0.0 and 1.0, due to the monotonicity and
+  // an opposite sign at 0.0 and 1.0.
+  // For simplicity, we reformulate the equation as
+  //     f(x) = x ^ (units - 1) + a x + b.
+  // Its derivative is
+  //     f'(x) = (units - 1) x ^ (units - 2) + a.
+  // The derivative is strictly greater than 0 when x is between 0 and 1.
+  // We use Newton's method to solve the equation, iteration is
+  //     x(k+1) = x(k) - f(x) / f'(x);
   const double kPrecision = 0.001f;
   const int kIterations = 100;
   const double a = (1.0f - loss_rate) / prob_trans_10;
@@ -117,7 +122,7 @@
       x = 0.0f;
     }
     f = pow(x, units - 1) + a * x + b;
-    iter ++;
+    iter++;
   }
   return x;
 }
@@ -210,9 +215,7 @@
   return false;
 }
 
-UniformLoss::UniformLoss(double loss_rate)
-    : loss_rate_(loss_rate) {
-}
+UniformLoss::UniformLoss(double loss_rate) : loss_rate_(loss_rate) {}
 
 bool UniformLoss::Lost(int now_ms) {
   int drop_this = rand();
@@ -223,8 +226,7 @@
     : prob_trans_11_(prob_trans_11),
       prob_trans_01_(prob_trans_01),
       lost_last_(false),
-      uniform_loss_model_(new UniformLoss(0)) {
-}
+      uniform_loss_model_(new UniformLoss(0)) {}
 
 GilbertElliotLoss::~GilbertElliotLoss() {}
 
@@ -277,8 +279,8 @@
       // a full packet duration is drawn with a loss, |unit_loss_rate| fulfills
       // (1 - unit_loss_rate) ^ (block_duration_ms_ / kPacketLossTimeUnitMs) ==
       // 1 - packet_loss_rate.
-      double unit_loss_rate = (1.0f - pow(1.0f - 0.01f * packet_loss_rate_,
-          1.0f / units));
+      double unit_loss_rate =
+          (1.0f - pow(1.0f - 0.01f * packet_loss_rate_, 1.0f / units));
       loss_model_.reset(new UniformLoss(unit_loss_rate));
       break;
     }
@@ -304,8 +306,8 @@
       double loss_rate = 0.01f * packet_loss_rate_;
       double prob_trans_10 = 1.0f * kPacketLossTimeUnitMs / FLAG_burst_length;
       double prob_trans_00 = ProbTrans00Solver(units, loss_rate, prob_trans_10);
-      loss_model_.reset(new GilbertElliotLoss(1.0f - prob_trans_10,
-                                              1.0f - prob_trans_00));
+      loss_model_.reset(
+          new GilbertElliotLoss(1.0f - prob_trans_10, 1.0f - prob_trans_00));
       break;
     }
     case kFixedLoss: {
@@ -347,7 +349,7 @@
   // The loop is to make sure that codecs with different block lengths share the
   // same packet loss profile.
   bool lost = false;
-  for (int idx = 0; idx < cycles; idx ++) {
+  for (int idx = 0; idx < cycles; idx++) {
     if (loss_model_->Lost(decoded_time_ms_)) {
       // The packet will be lost if any of the drawings indicates a loss, but
       // the loop has to go on to make sure that codecs with different block
@@ -359,14 +361,10 @@
 }
 
 int NetEqQualityTest::Transmit() {
-  int packet_input_time_ms =
-      rtp_generator_->GetRtpHeader(kPayloadType, in_size_samples_,
-                                   &rtp_header_);
-  Log() << "Packet of size "
-        << payload_size_bytes_
-        << " bytes, for frame at "
-        << packet_input_time_ms
-        << " ms ";
+  int packet_input_time_ms = rtp_generator_->GetRtpHeader(
+      kPayloadType, in_size_samples_, &rtp_header_);
+  Log() << "Packet of size " << payload_size_bytes_ << " bytes, for frame at "
+        << packet_input_time_ms << " ms ";
   if (payload_size_bytes_ > 0) {
     if (!PacketLost()) {
       int ret = neteq_->InsertPacket(
@@ -411,9 +409,8 @@
            decoded_time_ms_) {
       ASSERT_TRUE(in_file_->Read(in_size_samples_ * channels_, &in_data_[0]));
       payload_.Clear();
-      payload_size_bytes_ = EncodeBlock(&in_data_[0],
-                                        in_size_samples_, &payload_,
-                                        max_payload_bytes_);
+      payload_size_bytes_ = EncodeBlock(&in_data_[0], in_size_samples_,
+                                        &payload_, max_payload_bytes_);
       total_payload_size_bytes_ += payload_size_bytes_;
       decodable_time_ms_ = Transmit() + block_duration_ms_;
     }
@@ -423,8 +420,7 @@
     }
   }
   Log() << "Average bit rate was "
-        << 8.0f * total_payload_size_bytes_ / FLAG_runtime_ms
-        << " kbps"
+        << 8.0f * total_payload_size_bytes_ / FLAG_runtime_ms << " kbps"
         << std::endl;
 }
 
diff --git a/modules/audio_coding/neteq/tools/neteq_quality_test.h b/modules/audio_coding/neteq/tools/neteq_quality_test.h
index 2b82b0a..b19460c 100644
--- a/modules/audio_coding/neteq/tools/neteq_quality_test.h
+++ b/modules/audio_coding/neteq/tools/neteq_quality_test.h
@@ -36,7 +36,7 @@
 
 class LossModel {
  public:
-  virtual ~LossModel() {};
+  virtual ~LossModel(){};
   virtual bool Lost(int now_ms) = 0;
 };
 
@@ -110,8 +110,10 @@
   // |block_size_samples| (samples per channel),
   // 2. save the bit stream to |payload| of |max_bytes| bytes in size,
   // 3. returns the length of the payload (in bytes),
-  virtual int EncodeBlock(int16_t* in_data, size_t block_size_samples,
-                          rtc::Buffer* payload, size_t max_bytes) = 0;
+  virtual int EncodeBlock(int16_t* in_data,
+                          size_t block_size_samples,
+                          rtc::Buffer* payload,
+                          size_t max_bytes) = 0;
 
   // PacketLost(...) determines weather a packet sent at an indicated time gets
   // lost or not.
diff --git a/modules/audio_coding/neteq/tools/neteq_replacement_input.cc b/modules/audio_coding/neteq/tools/neteq_replacement_input.cc
index 6c846c0..6aa7581 100644
--- a/modules/audio_coding/neteq/tools/neteq_replacement_input.cc
+++ b/modules/audio_coding/neteq/tools/neteq_replacement_input.cc
@@ -31,13 +31,13 @@
   RTC_CHECK(packet_);
 }
 
-rtc::Optional<int64_t> NetEqReplacementInput::NextPacketTime() const {
+absl::optional<int64_t> NetEqReplacementInput::NextPacketTime() const {
   return packet_
-             ? rtc::Optional<int64_t>(static_cast<int64_t>(packet_->time_ms))
-             : rtc::nullopt;
+             ? absl::optional<int64_t>(static_cast<int64_t>(packet_->time_ms))
+             : absl::nullopt;
 }
 
-rtc::Optional<int64_t> NetEqReplacementInput::NextOutputEventTime() const {
+absl::optional<int64_t> NetEqReplacementInput::NextOutputEventTime() const {
   return source_->NextOutputEventTime();
 }
 
@@ -56,7 +56,7 @@
   return source_->ended();
 }
 
-rtc::Optional<RTPHeader> NetEqReplacementInput::NextHeader() const {
+absl::optional<RTPHeader> NetEqReplacementInput::NextHeader() const {
   return source_->NextHeader();
 }
 
@@ -82,7 +82,7 @@
     return;
   }
 
-  rtc::Optional<RTPHeader> next_hdr = source_->NextHeader();
+  absl::optional<RTPHeader> next_hdr = source_->NextHeader();
   RTC_DCHECK(next_hdr);
   uint8_t payload[12];
   RTC_DCHECK_LE(last_frame_size_timestamps_, 120 * 48);
diff --git a/modules/audio_coding/neteq/tools/neteq_replacement_input.h b/modules/audio_coding/neteq/tools/neteq_replacement_input.h
index 3a89399..9ce9b9d 100644
--- a/modules/audio_coding/neteq/tools/neteq_replacement_input.h
+++ b/modules/audio_coding/neteq/tools/neteq_replacement_input.h
@@ -28,12 +28,12 @@
                         const std::set<uint8_t>& comfort_noise_types,
                         const std::set<uint8_t>& forbidden_types);
 
-  rtc::Optional<int64_t> NextPacketTime() const override;
-  rtc::Optional<int64_t> NextOutputEventTime() const override;
+  absl::optional<int64_t> NextPacketTime() const override;
+  absl::optional<int64_t> NextOutputEventTime() const override;
   std::unique_ptr<PacketData> PopPacket() override;
   void AdvanceOutputEvent() override;
   bool ended() const override;
-  rtc::Optional<RTPHeader> NextHeader() const override;
+  absl::optional<RTPHeader> NextHeader() const override;
 
  private:
   void ReplacePacket();
@@ -42,7 +42,7 @@
   const uint8_t replacement_payload_type_;
   const std::set<uint8_t> comfort_noise_types_;
   const std::set<uint8_t> forbidden_types_;
-  std::unique_ptr<PacketData> packet_;  // The next packet to deliver.
+  std::unique_ptr<PacketData> packet_;         // The next packet to deliver.
   uint32_t last_frame_size_timestamps_ = 960;  // Initial guess: 20 ms @ 48 kHz.
 };
 
diff --git a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
index 7c071db..7f1263c 100644
--- a/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
+++ b/modules/audio_coding/neteq/tools/neteq_rtpplay.cc
@@ -10,20 +10,21 @@
 
 #include <errno.h>
 #include <inttypes.h>
-#include <iostream>
 #include <limits.h>  // For ULONG_MAX returned by strtoul.
-#include <memory>
 #include <stdio.h>
 #include <stdlib.h>  // For strtoul.
+#include <iostream>
+#include <memory>
 #include <string>
 
 #include "modules/audio_coding/neteq/include/neteq.h"
 #include "modules/audio_coding/neteq/tools/fake_decode_from_file.h"
 #include "modules/audio_coding/neteq/tools/input_audio_file.h"
 #include "modules/audio_coding/neteq/tools/neteq_delay_analyzer.h"
-#include "modules/audio_coding/neteq/tools/neteq_stats_getter.h"
+#include "modules/audio_coding/neteq/tools/neteq_event_log_input.h"
 #include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h"
 #include "modules/audio_coding/neteq/tools/neteq_replacement_input.h"
+#include "modules/audio_coding/neteq/tools/neteq_stats_getter.h"
 #include "modules/audio_coding/neteq/tools/neteq_test.h"
 #include "modules/audio_coding/neteq/tools/output_audio_file.h"
 #include "modules/audio_coding/neteq/tools/output_wav_file.h"
@@ -71,7 +72,7 @@
 
 bool ValidateSsrcValue(const std::string& str) {
   uint32_t dummy_ssrc;
-  if (ParseSsrc(str, &dummy_ssrc)) // Value is ok.
+  if (ParseSsrc(str, &dummy_ssrc))  // Value is ok.
     return true;
   printf("Invalid SSRC: %s\n", str.c_str());
   return false;
@@ -106,10 +107,15 @@
 DEFINE_int(cn_wb, 98, "RTP payload type for comfort noise (16 kHz)");
 DEFINE_int(cn_swb32, 99, "RTP payload type for comfort noise (32 kHz)");
 DEFINE_int(cn_swb48, 100, "RTP payload type for comfort noise (48 kHz)");
-DEFINE_bool(codec_map, false, "Prints the mapping between RTP payload type and "
-    "codec");
-DEFINE_string(replacement_audio_file, "",
-              "A PCM file that will be used to populate ""dummy"" RTP packets");
+DEFINE_bool(codec_map,
+            false,
+            "Prints the mapping between RTP payload type and "
+            "codec");
+DEFINE_string(replacement_audio_file,
+              "",
+              "A PCM file that will be used to populate "
+              "dummy"
+              " RTP packets");
 DEFINE_string(ssrc,
               "",
               "Only use packets with this SSRC (decimal or hex, the latter "
@@ -117,6 +123,8 @@
 DEFINE_int(audio_level, 1, "Extension ID for audio level (RFC 6464)");
 DEFINE_int(abs_send_time, 3, "Extension ID for absolute sender time");
 DEFINE_int(transport_seq_no, 5, "Extension ID for transport sequence number");
+DEFINE_int(video_content_type, 7, "Extension ID for video content type");
+DEFINE_int(video_timing, 8, "Extension ID for video timing");
 DEFINE_bool(matlabplot,
             false,
             "Generates a matlab script for plotting the delay profile");
@@ -204,7 +212,7 @@
   PrintCodecMappingEntry(NetEqDecoder::kDecoderCNGswb48kHz, FLAG_cn_swb48);
 }
 
-rtc::Optional<int> CodecSampleRate(uint8_t payload_type) {
+absl::optional<int> CodecSampleRate(uint8_t payload_type) {
   if (payload_type == FLAG_pcmu || payload_type == FLAG_pcma ||
       payload_type == FLAG_ilbc || payload_type == FLAG_pcm16b ||
       payload_type == FLAG_cn_nb || payload_type == FLAG_avt)
@@ -221,59 +229,9 @@
     return 48000;
   if (payload_type == FLAG_red)
     return 0;
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
-// Class to let through only the packets with a given SSRC. Should be used as an
-// outer layer on another NetEqInput object.
-class FilterSsrcInput : public NetEqInput {
- public:
-  FilterSsrcInput(std::unique_ptr<NetEqInput> source, uint32_t ssrc)
-      : source_(std::move(source)), ssrc_(ssrc) {
-    FindNextWithCorrectSsrc();
-    RTC_CHECK(source_->NextHeader()) << "Found no packet with SSRC = 0x"
-                                     << std::hex << ssrc_;
-  }
-
-  // All methods but PopPacket() simply relay to the |source_| object.
-  rtc::Optional<int64_t> NextPacketTime() const override {
-    return source_->NextPacketTime();
-  }
-  rtc::Optional<int64_t> NextOutputEventTime() const override {
-    return source_->NextOutputEventTime();
-  }
-
-  // Returns the next packet, and throws away upcoming packets that do not match
-  // the desired SSRC.
-  std::unique_ptr<PacketData> PopPacket() override {
-    std::unique_ptr<PacketData> packet_to_return = source_->PopPacket();
-    RTC_DCHECK(!packet_to_return || packet_to_return->header.ssrc == ssrc_);
-    // Pre-fetch the next packet with correct SSRC. Hence, |source_| will always
-    // be have a valid packet (or empty if no more packets are available) when
-    // this method returns.
-    FindNextWithCorrectSsrc();
-    return packet_to_return;
-  }
-
-  void AdvanceOutputEvent() override { source_->AdvanceOutputEvent(); }
-
-  bool ended() const override { return source_->ended(); }
-
-  rtc::Optional<RTPHeader> NextHeader() const override {
-    return source_->NextHeader();
-  }
-
- private:
-  void FindNextWithCorrectSsrc() {
-    while (source_->NextHeader() && source_->NextHeader()->ssrc != ssrc_) {
-      source_->PopPacket();
-    }
-  }
-
-  std::unique_ptr<NetEqInput> source_;
-  uint32_t ssrc_;
-};
-
 // A callback class which prints whenver the inserted packet stream changes
 // the SSRC.
 class SsrcSwitchDetector : public NetEqPostInsertPacket {
@@ -288,8 +246,8 @@
                          NetEq* neteq) override {
     if (last_ssrc_ && packet.header.ssrc != *last_ssrc_) {
       std::cout << "Changing streams from 0x" << std::hex << *last_ssrc_
-                << " to 0x" << std::hex << packet.header.ssrc
-                << std::dec << " (payload type "
+                << " to 0x" << std::hex << packet.header.ssrc << std::dec
+                << " (payload type "
                 << static_cast<int>(packet.header.payloadType) << ")"
                 << std::endl;
     }
@@ -301,15 +259,18 @@
 
  private:
   NetEqPostInsertPacket* other_callback_;
-  rtc::Optional<uint32_t> last_ssrc_;
+  absl::optional<uint32_t> last_ssrc_;
 };
 
 int RunTest(int argc, char* argv[]) {
   std::string program_name = argv[0];
-  std::string usage = "Tool for decoding an RTP dump file using NetEq.\n"
-      "Run " + program_name + " --help for usage.\n"
-      "Example usage:\n" + program_name +
-      " input.rtp output.{pcm, wav}\n";
+  std::string usage =
+      "Tool for decoding an RTP dump file using NetEq.\n"
+      "Run " +
+      program_name +
+      " --help for usage.\n"
+      "Example usage:\n" +
+      program_name + " input.rtp output.{pcm, wav}\n";
   if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true)) {
     return 1;
   }
@@ -356,12 +317,16 @@
   RTC_CHECK(ValidateExtensionId(FLAG_audio_level));
   RTC_CHECK(ValidateExtensionId(FLAG_abs_send_time));
   RTC_CHECK(ValidateExtensionId(FLAG_transport_seq_no));
+  RTC_CHECK(ValidateExtensionId(FLAG_video_content_type));
+  RTC_CHECK(ValidateExtensionId(FLAG_video_timing));
 
   // Gather RTP header extensions in a map.
   NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
       {FLAG_audio_level, kRtpExtensionAudioLevel},
       {FLAG_abs_send_time, kRtpExtensionAbsoluteSendTime},
-      {FLAG_transport_seq_no, kRtpExtensionTransportSequenceNumber}};
+      {FLAG_transport_seq_no, kRtpExtensionTransportSequenceNumber},
+      {FLAG_video_content_type, kRtpExtensionVideoContentType},
+      {FLAG_video_timing, kRtpExtensionVideoTiming}};
 
   const std::string input_file_name = argv[1];
   std::unique_ptr<NetEqInput> input;
@@ -380,14 +345,13 @@
   if (strlen(FLAG_ssrc) > 0) {
     uint32_t ssrc;
     RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed.";
-    input.reset(new FilterSsrcInput(std::move(input), ssrc));
+    static_cast<NetEqPacketSourceInput*>(input.get())->SelectSsrc(ssrc);
   }
 
   // Check the sample rate.
-  rtc::Optional<int> sample_rate_hz;
+  absl::optional<int> sample_rate_hz;
   std::set<std::pair<int, uint32_t>> discarded_pt_and_ssrc;
-  while (input->NextHeader()) {
-    rtc::Optional<RTPHeader> first_rtp_header = input->NextHeader();
+  while (absl::optional<RTPHeader> first_rtp_header = input->NextHeader()) {
     RTC_DCHECK(first_rtp_header);
     sample_rate_hz = CodecSampleRate(first_rtp_header->payloadType);
     if (sample_rate_hz) {
@@ -451,10 +415,8 @@
       {FLAG_g722, std::make_pair(NetEqDecoder::kDecoderG722, "g722")},
       {FLAG_avt, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")},
       {FLAG_avt_16, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")},
-      {FLAG_avt_32,
-       std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
-      {FLAG_avt_48,
-       std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
+      {FLAG_avt_32, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
+      {FLAG_avt_48, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
       {FLAG_red, std::make_pair(NetEqDecoder::kDecoderRED, "red")},
       {FLAG_cn_nb, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")},
       {FLAG_cn_wb, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")},
@@ -485,9 +447,8 @@
 
     std::set<uint8_t> cn_types = std_set_int32_to_uint8(
         {FLAG_cn_nb, FLAG_cn_wb, FLAG_cn_swb32, FLAG_cn_swb48});
-    std::set<uint8_t> forbidden_types =
-        std_set_int32_to_uint8({FLAG_g722, FLAG_red, FLAG_avt,
-                                FLAG_avt_16, FLAG_avt_32, FLAG_avt_48});
+    std::set<uint8_t> forbidden_types = std_set_int32_to_uint8(
+        {FLAG_g722, FLAG_red, FLAG_avt, FLAG_avt_16, FLAG_avt_32, FLAG_avt_48});
     input.reset(new NetEqReplacementInput(std::move(input), replacement_pt,
                                           cn_types, forbidden_types));
 
@@ -524,7 +485,8 @@
                  '_');
     std::cout << "Creating Matlab plot script " << matlab_script_name + ".m"
               << std::endl;
-    delay_analyzer->CreateMatlabScript(matlab_script_name + ".m");
+    stats_getter.delay_analyzer()->CreateMatlabScript(matlab_script_name +
+                                                      ".m");
   }
   if (FLAG_pythonplot) {
     auto python_script_name = output_file_name;
@@ -532,7 +494,8 @@
                  '_');
     std::cout << "Creating Python plot script " << python_script_name + ".py"
               << std::endl;
-    delay_analyzer->CreatePythonScript(python_script_name + ".py");
+    stats_getter.delay_analyzer()->CreatePythonScript(python_script_name +
+                                                      ".py");
   }
 
   printf("Simulation statistics:\n");
diff --git a/modules/audio_coding/neteq/tools/neteq_stats_getter.cc b/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
index 6474e21..1a52176 100644
--- a/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
+++ b/modules/audio_coding/neteq/tools/neteq_stats_getter.cc
@@ -26,8 +26,7 @@
   rtc::SimpleStringBuilder ss(ss_buf);
   ss << "ConcealmentEvent duration_ms:" << duration_ms
      << " event_number:" << concealment_event_number
-     << " time_from_previous_event_end_ms:"
-     << time_from_previous_event_end_ms;
+     << " time_from_previous_event_end_ms:" << time_from_previous_event_end_ms;
   return ss.str();
 }
 
@@ -47,15 +46,17 @@
                                      NetEq* neteq) {
   // TODO(minyue): Get stats should better not be called as a call back after
   // get audio. It is called independently from get audio in practice.
+  const auto lifetime_stat = neteq->GetLifetimeStatistics();
   if (last_stats_query_time_ms_ == 0 ||
       rtc::TimeDiff(time_now_ms, last_stats_query_time_ms_) >=
           stats_query_interval_ms_) {
     NetEqNetworkStatistics stats;
     RTC_CHECK_EQ(neteq->NetworkStatistics(&stats), 0);
     stats_.push_back(std::make_pair(time_now_ms, stats));
+    lifetime_stats_.push_back(std::make_pair(time_now_ms, lifetime_stat));
     last_stats_query_time_ms_ = time_now_ms;
   }
-  const auto lifetime_stat = neteq->GetLifetimeStatistics();
+
   if (current_concealment_event_ != lifetime_stat.concealment_events &&
       voice_concealed_samples_until_last_event_ <
           lifetime_stat.voice_concealed_samples) {
@@ -115,12 +116,10 @@
         a.added_zero_samples += b.added_zero_samples;
         a.mean_waiting_time_ms += b.mean_waiting_time_ms;
         a.median_waiting_time_ms += b.median_waiting_time_ms;
-        a.min_waiting_time_ms =
-            std::min(a.min_waiting_time_ms,
-                     static_cast<double>(b.min_waiting_time_ms));
-        a.max_waiting_time_ms =
-            std::max(a.max_waiting_time_ms,
-                     static_cast<double>(b.max_waiting_time_ms));
+        a.min_waiting_time_ms = std::min(
+            a.min_waiting_time_ms, static_cast<double>(b.min_waiting_time_ms));
+        a.max_waiting_time_ms = std::max(
+            a.max_waiting_time_ms, static_cast<double>(b.max_waiting_time_ms));
         return a;
       });
 
diff --git a/modules/audio_coding/neteq/tools/neteq_stats_getter.h b/modules/audio_coding/neteq/tools/neteq_stats_getter.h
index dbb396a..b1b12bb 100644
--- a/modules/audio_coding/neteq/tools/neteq_stats_getter.h
+++ b/modules/audio_coding/neteq/tools/neteq_stats_getter.h
@@ -69,9 +69,7 @@
 
   double AverageSpeechExpandRate() const;
 
-  NetEqDelayAnalyzer* delay_analyzer() const {
-    return delay_analyzer_.get();
-  }
+  NetEqDelayAnalyzer* delay_analyzer() const { return delay_analyzer_.get(); }
 
   const std::vector<ConcealmentEvent>& concealment_events() const {
     // Do not account for the last concealment event to avoid potential end
@@ -79,8 +77,13 @@
     return concealment_events_;
   }
 
-  const std::vector<std::pair<int64_t, NetEqNetworkStatistics>>& stats() const {
-    return stats_;
+  const std::vector<std::pair<int64_t, NetEqNetworkStatistics>>* stats() const {
+    return &stats_;
+  }
+
+  const std::vector<std::pair<int64_t, NetEqLifetimeStatistics>>*
+  lifetime_stats() const {
+    return &lifetime_stats_;
   }
 
   Stats AverageStats() const;
@@ -90,6 +93,7 @@
   int64_t stats_query_interval_ms_ = 1000;
   int64_t last_stats_query_time_ms_ = 0;
   std::vector<std::pair<int64_t, NetEqNetworkStatistics>> stats_;
+  std::vector<std::pair<int64_t, NetEqLifetimeStatistics>> lifetime_stats_;
   size_t current_concealment_event_ = 1;
   uint64_t voice_concealed_samples_until_last_event_ = 0;
   std::vector<ConcealmentEvent> concealment_events_;
diff --git a/modules/audio_coding/neteq/tools/neteq_test.cc b/modules/audio_coding/neteq/tools/neteq_test.cc
index e6dd114..e2bed56 100644
--- a/modules/audio_coding/neteq/tools/neteq_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_test.cc
@@ -115,6 +115,38 @@
   return neteq_->GetLifetimeStatistics();
 }
 
+NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() {
+  DecoderMap codecs = {
+    {0, std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu")},
+    {8, std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma")},
+#ifdef WEBRTC_CODEC_ILBC
+    {102, std::make_pair(NetEqDecoder::kDecoderILBC, "ilbc")},
+#endif
+    {103, std::make_pair(NetEqDecoder::kDecoderISAC, "isac")},
+#if !defined(WEBRTC_ANDROID)
+    {104, std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb")},
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+    {111, std::make_pair(NetEqDecoder::kDecoderOpus, "opus")},
+#endif
+    {93, std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb")},
+    {94, std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb")},
+    {95, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32")},
+    {96, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48")},
+    {9, std::make_pair(NetEqDecoder::kDecoderG722, "g722")},
+    {106, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")},
+    {114, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")},
+    {115, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
+    {116, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
+    {117, std::make_pair(NetEqDecoder::kDecoderRED, "red")},
+    {13, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")},
+    {98, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")},
+    {99, std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32")},
+    {100, std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48")}
+  };
+  return codecs;
+}
+
 void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
   for (const auto& c : codecs) {
     RTC_CHECK_EQ(
diff --git a/modules/audio_coding/neteq/tools/neteq_test.h b/modules/audio_coding/neteq/tools/neteq_test.h
index e645e42..9c05fc4 100644
--- a/modules/audio_coding/neteq/tools/neteq_test.h
+++ b/modules/audio_coding/neteq/tools/neteq_test.h
@@ -91,6 +91,8 @@
   NetEqNetworkStatistics SimulationStats();
   NetEqLifetimeStatistics LifetimeStats() const;
 
+  static DecoderMap StandardDecoderMap();
+
  private:
   void RegisterDecoders(const DecoderMap& codecs);
   void RegisterExternalDecoders(const ExtDecoderMap& codecs);
diff --git a/modules/audio_coding/neteq/tools/packet.cc b/modules/audio_coding/neteq/tools/packet.cc
index 9505a29..b1a9b64 100644
--- a/modules/audio_coding/neteq/tools/packet.cc
+++ b/modules/audio_coding/neteq/tools/packet.cc
@@ -158,11 +158,10 @@
   destination->paddingLength = header_.paddingLength;
   destination->headerLength = header_.headerLength;
   destination->payload_type_frequency = header_.payload_type_frequency;
-  memcpy(&destination->arrOfCSRCs,
-         &header_.arrOfCSRCs,
+  memcpy(&destination->arrOfCSRCs, &header_.arrOfCSRCs,
          sizeof(header_.arrOfCSRCs));
-  memcpy(
-      &destination->extension, &header_.extension, sizeof(header_.extension));
+  memcpy(&destination->extension, &header_.extension,
+         sizeof(header_.extension));
 }
 
 }  // namespace test
diff --git a/modules/audio_coding/neteq/tools/packet.h b/modules/audio_coding/neteq/tools/packet.h
index 94d45c5..2c9a26f 100644
--- a/modules/audio_coding/neteq/tools/packet.h
+++ b/modules/audio_coding/neteq/tools/packet.h
@@ -15,7 +15,7 @@
 #include <memory>
 
 #include "api/rtp_headers.h"  // NOLINT(build/include)
-#include "common_types.h"  // NOLINT(build/include)
+#include "common_types.h"     // NOLINT(build/include)
 #include "rtc_base/constructormagic.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
diff --git a/modules/audio_coding/neteq/tools/packet_unittest.cc b/modules/audio_coding/neteq/tools/packet_unittest.cc
index ce6a3b9..7f3d663 100644
--- a/modules/audio_coding/neteq/tools/packet_unittest.cc
+++ b/modules/audio_coding/neteq/tools/packet_unittest.cc
@@ -28,7 +28,7 @@
   rtp_data[0] = 0x80;
   rtp_data[1] = static_cast<uint8_t>(payload_type);
   rtp_data[2] = (seq_number >> 8) & 0xFF;
-  rtp_data[3] = (seq_number) & 0xFF;
+  rtp_data[3] = (seq_number)&0xFF;
   rtp_data[4] = timestamp >> 24;
   rtp_data[5] = (timestamp >> 16) & 0xFF;
   rtp_data[6] = (timestamp >> 8) & 0xFF;
@@ -47,8 +47,8 @@
   const uint16_t kSequenceNumber = 4711;
   const uint32_t kTimestamp = 47114711;
   const uint32_t kSsrc = 0x12345678;
-  MakeRtpHeader(
-      kPayloadType, kSequenceNumber, kTimestamp, kSsrc, packet_memory);
+  MakeRtpHeader(kPayloadType, kSequenceNumber, kTimestamp, kSsrc,
+                packet_memory);
   const double kPacketTime = 1.0;
   // Hand over ownership of |packet_memory| to |packet|.
   Packet packet(packet_memory, kPacketLengthBytes, kPacketTime);
@@ -75,13 +75,11 @@
   const uint16_t kSequenceNumber = 4711;
   const uint32_t kTimestamp = 47114711;
   const uint32_t kSsrc = 0x12345678;
-  MakeRtpHeader(
-      kPayloadType, kSequenceNumber, kTimestamp, kSsrc, packet_memory);
+  MakeRtpHeader(kPayloadType, kSequenceNumber, kTimestamp, kSsrc,
+                packet_memory);
   const double kPacketTime = 1.0;
   // Hand over ownership of |packet_memory| to |packet|.
-  Packet packet(packet_memory,
-                kPacketLengthBytes,
-                kVirtualPacketLengthBytes,
+  Packet packet(packet_memory, kPacketLengthBytes, kVirtualPacketLengthBytes,
                 kPacketTime);
   ASSERT_TRUE(packet.valid_header());
   EXPECT_EQ(kPayloadType, packet.header().payloadType);
@@ -140,8 +138,8 @@
   const uint16_t kSequenceNumber = 4711;
   const uint32_t kTimestamp = 47114711;
   const uint32_t kSsrc = 0x12345678;
-  MakeRtpHeader(
-      kRedPayloadType, kSequenceNumber, kTimestamp, kSsrc, packet_memory);
+  MakeRtpHeader(kRedPayloadType, kSequenceNumber, kTimestamp, kSsrc,
+                packet_memory);
   // Create four RED headers.
   // Payload types are just the same as the block index the offset is 100 times
   // the block index.
@@ -154,8 +152,8 @@
     uint32_t timestamp_offset = 100 * i;
     int block_length = 10 * i;
     bool last_block = (i == kRedBlocks - 1) ? true : false;
-    payload_ptr += MakeRedHeader(
-        payload_type, timestamp_offset, block_length, last_block, payload_ptr);
+    payload_ptr += MakeRedHeader(payload_type, timestamp_offset, block_length,
+                                 last_block, payload_ptr);
   }
   const double kPacketTime = 1.0;
   // Hand over ownership of |packet_memory| to |packet|.
@@ -178,8 +176,7 @@
   EXPECT_EQ(kRedBlocks, static_cast<int>(red_headers.size()));
   int block_index = 0;
   for (std::list<RTPHeader*>::reverse_iterator it = red_headers.rbegin();
-       it != red_headers.rend();
-       ++it) {
+       it != red_headers.rend(); ++it) {
     // Reading list from the back, since the extraction puts the main payload
     // (which is the last one on wire) first.
     RTPHeader* red_block = *it;
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
index b853248..7c97824 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
@@ -40,7 +40,7 @@
   for (; rtp_packet_index_ < parsed_stream_.GetNumberOfEvents();
        rtp_packet_index_++) {
     if (parsed_stream_.GetEventType(rtp_packet_index_) ==
-        ParsedRtcEventLogNew::RTP_EVENT) {
+        ParsedRtcEventLogNew::EventType::RTP_EVENT) {
       PacketDirection direction;
       size_t header_length;
       size_t packet_length;
@@ -84,11 +84,13 @@
 int64_t RtcEventLogSource::NextAudioOutputEventMs() {
   while (audio_output_index_ < parsed_stream_.GetNumberOfEvents()) {
     if (parsed_stream_.GetEventType(audio_output_index_) ==
-        ParsedRtcEventLogNew::AUDIO_PLAYOUT_EVENT) {
+        ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT) {
       LoggedAudioPlayoutEvent playout_event =
           parsed_stream_.GetAudioPlayout(audio_output_index_);
-      audio_output_index_++;
-      return playout_event.timestamp_us / 1000;
+      if (!(use_ssrc_filter_ && playout_event.ssrc != ssrc_)) {
+        audio_output_index_++;
+        return playout_event.timestamp_us / 1000;
+      }
     }
     audio_output_index_++;
   }
diff --git a/modules/audio_coding/neteq/tools/rtp_analyze.cc b/modules/audio_coding/neteq/tools/rtp_analyze.cc
index 12721cc..f939038 100644
--- a/modules/audio_coding/neteq/tools/rtp_analyze.cc
+++ b/modules/audio_coding/neteq/tools/rtp_analyze.cc
@@ -20,10 +20,14 @@
 
 // Define command line flags.
 DEFINE_int(red, 117, "RTP payload type for RED");
-DEFINE_int(audio_level, -1, "Extension ID for audio level (RFC 6464); "
-                            "-1 not to print audio level");
-DEFINE_int(abs_send_time, -1, "Extension ID for absolute sender time; "
-                             "-1 not to print absolute send time");
+DEFINE_int(audio_level,
+           -1,
+           "Extension ID for audio level (RFC 6464); "
+           "-1 not to print audio level");
+DEFINE_int(abs_send_time,
+           -1,
+           "Extension ID for absolute sender time; "
+           "-1 not to print absolute send time");
 DEFINE_bool(help, false, "Print this message");
 
 int main(int argc, char* argv[]) {
@@ -37,8 +41,8 @@
       program_name + " input.rtp output.txt\n\n" +
       "Output is sent to stdout if no output file is given. " +
       "Note that this tool can read files with or without payloads.\n";
-  if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) ||
-      FLAG_help || (argc != 2 && argc != 3)) {
+  if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || FLAG_help ||
+      (argc != 2 && argc != 3)) {
     printf("%s", usage.c_str());
     if (FLAG_help) {
       rtc::FlagList::Print(nullptr, false);
@@ -47,10 +51,11 @@
     return 1;
   }
 
-  RTC_CHECK(FLAG_red >= 0 && FLAG_red <= 127);  // Payload type
-  RTC_CHECK(FLAG_audio_level == -1 ||  // Default
-      (FLAG_audio_level > 0 && FLAG_audio_level <= 255));  // Extension ID
-  RTC_CHECK(FLAG_abs_send_time == -1 ||  // Default
+  RTC_CHECK(FLAG_red >= 0 && FLAG_red <= 127);                   // Payload type
+  RTC_CHECK(FLAG_audio_level == -1 ||                            // Default
+            (FLAG_audio_level > 0 && FLAG_audio_level <= 255));  // Extension ID
+  RTC_CHECK(
+      FLAG_abs_send_time == -1 ||                              // Default
       (FLAG_abs_send_time > 0 && FLAG_abs_send_time <= 255));  // Extension ID
 
   printf("Input file: %s\n", argv[1]);
@@ -104,19 +109,14 @@
     }
     // Write packet data to file. Use virtual_packet_length_bytes so that the
     // correct packet sizes are printed also for RTP header-only dumps.
-    fprintf(out_file,
-            "%5u %10u %10u %5i %5i %2i %#08X",
-            packet->header().sequenceNumber,
-            packet->header().timestamp,
+    fprintf(out_file, "%5u %10u %10u %5i %5i %2i %#08X",
+            packet->header().sequenceNumber, packet->header().timestamp,
             static_cast<unsigned int>(packet->time_ms()),
             static_cast<int>(packet->virtual_packet_length_bytes()),
-            packet->header().payloadType,
-            packet->header().markerBit,
+            packet->header().payloadType, packet->header().markerBit,
             packet->header().ssrc);
     if (print_audio_level && packet->header().extension.hasAudioLevel) {
-      fprintf(out_file,
-              " %5u (%1i)",
-              packet->header().extension.audioLevel,
+      fprintf(out_file, " %5u (%1i)", packet->header().extension.audioLevel,
               packet->header().extension.voiceActivity);
     }
     if (print_abs_send_time && packet->header().extension.hasAbsoluteSendTime) {
@@ -156,11 +156,8 @@
       while (!red_headers.empty()) {
         webrtc::RTPHeader* red = red_headers.front();
         assert(red);
-        fprintf(out_file,
-                "* %5u %10u %10u %5i\n",
-                red->sequenceNumber,
-                red->timestamp,
-                static_cast<unsigned int>(packet->time_ms()),
+        fprintf(out_file, "* %5u %10u %10u %5i\n", red->sequenceNumber,
+                red->timestamp, static_cast<unsigned int>(packet->time_ms()),
                 red->payloadType);
         red_headers.pop_front();
         delete red;
diff --git a/modules/audio_coding/neteq/tools/rtp_encode.cc b/modules/audio_coding/neteq/tools/rtp_encode.cc
index 66e7a28..abbb621 100644
--- a/modules/audio_coding/neteq/tools/rtp_encode.cc
+++ b/modules/audio_coding/neteq/tools/rtp_encode.cc
@@ -21,6 +21,7 @@
 #include <map>
 #include <string>
 
+#include "absl/memory/memory.h"
 #include "api/audio/audio_frame.h"
 #include "api/audio_codecs/L16/audio_encoder_L16.h"
 #include "api/audio_codecs/g711/audio_encoder_g711.h"
@@ -33,7 +34,6 @@
 #include "modules/audio_coding/neteq/tools/input_audio_file.h"
 #include "rtc_base/flags.h"
 #include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/ptr_util.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
@@ -247,11 +247,16 @@
   AudioEncoderCng::Config cng_config;
   const auto default_payload_type = [&] {
     switch (sample_rate_hz) {
-      case 8000: return 13;
-      case 16000: return 98;
-      case 32000: return 99;
-      case 48000: return 100;
-      default: RTC_NOTREACHED();
+      case 8000:
+        return 13;
+      case 16000:
+        return 98;
+      case 32000:
+        return 99;
+      case 48000:
+        return 100;
+      default:
+        RTC_NOTREACHED();
     }
     return 0;
   };
@@ -308,7 +313,7 @@
     AudioEncoderCng::Config cng_config = GetCngConfig(codec->SampleRateHz());
     RTC_DCHECK(codec);
     cng_config.speech_encoder = std::move(codec);
-    codec = rtc::MakeUnique<AudioEncoderCng>(std::move(cng_config));
+    codec = absl::make_unique<AudioEncoderCng>(std::move(cng_config));
   }
   RTC_DCHECK(codec);
 
diff --git a/modules/audio_coding/neteq/tools/rtp_file_source.cc b/modules/audio_coding/neteq/tools/rtp_file_source.cc
index 0945667..806bba7 100644
--- a/modules/audio_coding/neteq/tools/rtp_file_source.cc
+++ b/modules/audio_coding/neteq/tools/rtp_file_source.cc
@@ -44,8 +44,7 @@
   return !!temp_file;
 }
 
-RtpFileSource::~RtpFileSource() {
-}
+RtpFileSource::~RtpFileSource() {}
 
 bool RtpFileSource::RegisterRtpHeaderExtension(RTPExtensionType type,
                                                uint8_t id) {
@@ -82,8 +81,7 @@
 }
 
 RtpFileSource::RtpFileSource()
-    : PacketSource(),
-      parser_(RtpHeaderParser::Create()) {}
+    : PacketSource(), parser_(RtpHeaderParser::Create()) {}
 
 bool RtpFileSource::OpenFile(const std::string& file_name) {
   rtp_reader_.reset(RtpFileReader::Create(RtpFileReader::kRtpDump, file_name));
diff --git a/modules/audio_coding/neteq/tools/rtp_generator.cc b/modules/audio_coding/neteq/tools/rtp_generator.cc
index cedd7ae..ab7acdc 100644
--- a/modules/audio_coding/neteq/tools/rtp_generator.cc
+++ b/modules/audio_coding/neteq/tools/rtp_generator.cc
@@ -32,8 +32,8 @@
 
   uint32_t this_send_time = next_send_time_ms_;
   assert(samples_per_ms_ > 0);
-  next_send_time_ms_ += ((1.0 + drift_factor_) * payload_length_samples) /
-      samples_per_ms_;
+  next_send_time_ms_ +=
+      ((1.0 + drift_factor_) * payload_length_samples) / samples_per_ms_;
   return this_send_time;
 }
 
@@ -46,8 +46,8 @@
 uint32_t TimestampJumpRtpGenerator::GetRtpHeader(uint8_t payload_type,
                                                  size_t payload_length_samples,
                                                  RTPHeader* rtp_header) {
-  uint32_t ret = RtpGenerator::GetRtpHeader(
-      payload_type, payload_length_samples, rtp_header);
+  uint32_t ret = RtpGenerator::GetRtpHeader(payload_type,
+                                            payload_length_samples, rtp_header);
   if (timestamp_ - static_cast<uint32_t>(payload_length_samples) <=
           jump_from_timestamp_ &&
       timestamp_ > jump_from_timestamp_) {
diff --git a/modules/audio_coding/neteq/tools/rtp_generator.h b/modules/audio_coding/neteq/tools/rtp_generator.h
index 3b3cca9..04fdbdd 100644
--- a/modules/audio_coding/neteq/tools/rtp_generator.h
+++ b/modules/audio_coding/neteq/tools/rtp_generator.h
@@ -32,8 +32,7 @@
         next_send_time_ms_(start_send_time_ms),
         ssrc_(ssrc),
         samples_per_ms_(samples_per_ms),
-        drift_factor_(0.0) {
-  }
+        drift_factor_(0.0) {}
 
   virtual ~RtpGenerator() {}
 
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index a64fc6f..4be7d8f 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -6,7 +6,6 @@
 # in the file PATENTS.  All contributing project authors may
 # be found in the AUTHORS file in the root of the source tree.
 
-import("//build/config/arm.gni")
 import("../../webrtc.gni")
 if (!build_with_mozilla) {
   import("//third_party/protobuf/proto_library.gni")
@@ -29,34 +28,12 @@
 
 rtc_static_library("audio_processing") {
   visibility = [ "*" ]
-  allow_poison = [ "audio_codecs" ]  # TODO(bugs.webrtc.org/8396): Remove.
   configs += [ ":apm_debug_dump" ]
   sources = [
-    "aec/aec_resampler.cc",
-    "aec/aec_resampler.h",
-    "aec/echo_cancellation.cc",
-    "aec/echo_cancellation.h",
-    "agc/agc.cc",
-    "agc/agc.h",
-    "agc/agc_manager_direct.cc",
-    "agc/agc_manager_direct.h",
-    "agc/gain_map_internal.h",
-    "agc/loudness_histogram.cc",
-    "agc/loudness_histogram.h",
-    "agc/utility.cc",
-    "agc/utility.h",
     "audio_buffer.cc",
     "audio_buffer.h",
     "audio_processing_impl.cc",
     "audio_processing_impl.h",
-    "beamformer/array_util.cc",
-    "beamformer/array_util.h",
-    "beamformer/complex_matrix.h",
-    "beamformer/covariance_matrix_generator.cc",
-    "beamformer/covariance_matrix_generator.h",
-    "beamformer/matrix.h",
-    "beamformer/nonlinear_beamformer.cc",
-    "beamformer/nonlinear_beamformer.h",
     "common.h",
     "echo_cancellation_impl.cc",
     "echo_cancellation_impl.h",
@@ -76,6 +53,8 @@
     "gain_control_impl.h",
     "gain_controller2.cc",
     "gain_controller2.h",
+    "include/aec_dump.cc",
+    "include/aec_dump.h",
     "include/audio_processing.cc",
     "include/audio_processing.h",
     "include/config.cc",
@@ -116,22 +95,21 @@
 
   defines = []
   deps = [
-    ":aec_core",
-    ":aec_dump_interface",
     ":apm_logging",
     ":audio_frame_view",
     ":audio_generator_interface",
     ":audio_processing_c",
     ":audio_processing_statistics",
+    ":gain_control_interface",
     "../..:typedefs",
     "../..:webrtc_common",
     "../../api:array_view",
-    "../../api:optional",
     "../../api/audio:aec3_config",
     "../../api/audio:audio_frame_api",
     "../../api/audio:echo_control",
     "../../audio/utility:audio_frame_operations",
     "../../common_audio:common_audio_c",
+    "../../common_audio:fft4g",
     "../../rtc_base:checks",
     "../../rtc_base:deprecation",
     "../../rtc_base:gtest_prod",
@@ -140,10 +118,16 @@
     "../../system_wrappers:cpu_features_api",
     "../../system_wrappers:field_trial_api",
     "../../system_wrappers:metrics_api",
+    "aec:aec",
+    "aec:aec_core",
+    "aecm:aecm_core",
+    "agc",
+    "agc:agc_legacy_c",
     "agc2:adaptive_digital",
     "agc2:fixed_digital",
     "agc2:gain_applier",
     "vad",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 
   if (aec_untrusted_delay_for_testing) {
@@ -168,9 +152,6 @@
     defines += [ "WEBRTC_NS_FLOAT" ]
   }
 
-  # TODO(jschuh): Bug 1348: fix this warning.
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
   deps += [
     "../../common_audio",
     "../../common_audio:fir_filter",
@@ -180,6 +161,12 @@
   ]
 }
 
+rtc_source_set("gain_control_interface") {
+  sources = [
+    "include/gain_control.h",
+  ]
+}
+
 rtc_source_set("audio_processing_statistics") {
   visibility = [ "*" ]
   sources = [
@@ -187,7 +174,7 @@
     "include/audio_processing_statistics.h",
   ]
   deps = [
-    "../../api:optional",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -200,20 +187,6 @@
   ]
 }
 
-rtc_source_set("aec_dump_interface") {
-  sources = [
-    "include/aec_dump.cc",
-    "include/aec_dump.h",
-  ]
-
-  deps = [
-    ":audio_frame_view",
-    "../../api:array_view",
-    "../../api/audio:audio_frame_api",
-    "../../rtc_base:rtc_base_approved",
-  ]
-}
-
 rtc_source_set("audio_generator_interface") {
   visibility = [ "*" ]
   sources = [
@@ -238,6 +211,7 @@
     "../../common_audio:common_audio",
     "../../rtc_base:rtc_base_approved",
     "../../system_wrappers:system_wrappers",
+    "//third_party/abseil-cpp/absl/memory",
   ]
 }
 
@@ -256,13 +230,7 @@
 
 rtc_source_set("audio_processing_c") {
   visibility = [ ":*" ]  # Only targets in this file can depend on this.
-  sources = [
-    "agc/legacy/analog_agc.c",
-    "agc/legacy/analog_agc.h",
-    "agc/legacy/digital_agc.c",
-    "agc/legacy/digital_agc.h",
-    "agc/legacy/gain_control.h",
-  ]
+  sources = []
 
   if (rtc_prefer_fixed_point) {
     sources += [
@@ -293,9 +261,11 @@
     "../..:webrtc_common",
     "../../common_audio",
     "../../common_audio:common_audio_c",
+    "../../common_audio:fft4g",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
     "../../system_wrappers:cpu_features_api",
+    "agc:agc_legacy_c",
   ]
 
   if (rtc_build_with_neon) {
@@ -345,100 +315,6 @@
   defines = []
 }
 
-rtc_source_set("aec_core") {
-  configs += [ ":apm_debug_dump" ]
-  sources = [
-    "aec/aec_common.h",
-    "aec/aec_core.cc",
-    "aec/aec_core.h",
-    "aec/aec_core_optimized_methods.h",
-    "aecm/aecm_core.cc",
-    "aecm/aecm_core.h",
-    "aecm/aecm_defines.h",
-    "aecm/echo_control_mobile.cc",
-    "aecm/echo_control_mobile.h",
-    "utility/block_mean_calculator.cc",
-    "utility/block_mean_calculator.h",
-    "utility/delay_estimator.cc",
-    "utility/delay_estimator.h",
-    "utility/delay_estimator_internal.h",
-    "utility/delay_estimator_wrapper.cc",
-    "utility/delay_estimator_wrapper.h",
-    "utility/ooura_fft.cc",
-    "utility/ooura_fft.h",
-    "utility/ooura_fft_tables_common.h",
-  ]
-  deps = [
-    ":apm_logging",
-    ":audio_processing_statistics",
-    "../..:typedefs",
-    "../..:webrtc_common",
-    "../../common_audio:common_audio",
-    "../../common_audio:common_audio_c",
-    "../../rtc_base:checks",
-    "../../rtc_base:rtc_base_approved",
-    "../../rtc_base:sanitizer",
-    "../../system_wrappers:cpu_features_api",
-    "../../system_wrappers:metrics_api",
-  ]
-  cflags = []
-  defines = []
-
-  if (current_cpu == "x86" || current_cpu == "x64") {
-    sources += [
-      "aec/aec_core_sse2.cc",
-      "utility/ooura_fft_sse2.cc",
-      "utility/ooura_fft_tables_neon_sse2.h",
-    ]
-    if (is_posix || is_fuchsia) {
-      cflags += [ "-msse2" ]
-    }
-  }
-
-  if (rtc_build_with_neon) {
-    sources += [
-      "aec/aec_core_neon.cc",
-      "aecm/aecm_core_neon.cc",
-      "utility/ooura_fft_neon.cc",
-      "utility/ooura_fft_tables_neon_sse2.h",
-    ]
-
-    if (current_cpu != "arm64") {
-      # Enable compilation for the NEON instruction set. This is needed
-      # since //build/config/arm.gni only enables NEON for iOS, not Android.
-      # This provides the same functionality as webrtc/build/arm_neon.gypi.
-      suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
-      cflags += [ "-mfpu=neon" ]
-    }
-
-    # Disable LTO on NEON targets due to compiler bug.
-    # TODO(fdegans): Enable this. See crbug.com/408997.
-    if (rtc_use_lto) {
-      cflags -= [
-        "-flto",
-        "-ffat-lto-objects",
-      ]
-    }
-
-    deps += [ "../../common_audio" ]
-  }
-
-  if (current_cpu == "mipsel") {
-    sources += [ "aecm/aecm_core_mips.cc" ]
-    if (mips_float_abi == "hard") {
-      sources += [
-        "aec/aec_core_mips.cc",
-        "utility/ooura_fft_mips.cc",
-      ]
-    }
-  } else {
-    sources += [ "aecm/aecm_core_c.cc" ]
-  }
-
-  # TODO(jschuh): Bug 1348: fix this warning.
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-}
-
 if (rtc_include_tests) {
   rtc_source_set("mocks") {
     testonly = true
@@ -446,7 +322,6 @@
       "include/mock_audio_processing.h",
     ]
     deps = [
-      ":aec_dump_interface",
       ":audio_processing",
       ":audio_processing_statistics",
       "../../test:test_support",
@@ -458,7 +333,6 @@
     deps = [
       ":audioproc_test_utils",
       ":click_annotate",
-      ":nonlinear_beamformer_test",
       ":transient_suppression_test",
     ]
 
@@ -482,19 +356,8 @@
 
     configs += [ ":apm_debug_dump" ]
     sources = [
-      "aec/echo_cancellation_unittest.cc",
-      "aec/system_delay_unittest.cc",
-      "agc/agc_manager_direct_unittest.cc",
-      "agc/loudness_histogram_unittest.cc",
-      "agc/mock_agc.h",
       "audio_buffer_unittest.cc",
       "audio_frame_view_unittest.cc",
-      "beamformer/array_util_unittest.cc",
-      "beamformer/complex_matrix_unittest.cc",
-      "beamformer/covariance_matrix_generator_unittest.cc",
-      "beamformer/matrix_test_helpers.h",
-      "beamformer/matrix_unittest.cc",
-      "beamformer/mock_nonlinear_beamformer.h",
       "config_unittest.cc",
       "echo_cancellation_impl_unittest.cc",
       "gain_controller2_unittest.cc",
@@ -509,12 +372,9 @@
       "transient/transient_suppressor_unittest.cc",
       "transient/wpd_node_unittest.cc",
       "transient/wpd_tree_unittest.cc",
-      "utility/block_mean_calculator_unittest.cc",
-      "utility/delay_estimator_unittest.cc",
     ]
 
     deps = [
-      ":aec_core",
       ":analog_mic_simulation",
       ":apm_logging",
       ":audio_frame_view",
@@ -525,7 +385,6 @@
       "../..:typedefs",
       "../..:webrtc_common",
       "../../api:array_view",
-      "../../api:optional",
       "../../api/audio:aec3_config",
       "../../api/audio:aec3_factory",
       "../../common_audio:common_audio",
@@ -542,14 +401,22 @@
       "../../test:fileutils",
       "../../test:test_support",
       "../audio_coding:neteq_input_audio_tools",
+      "aec:aec_core",
+      "aec:aec_unittests",
       "aec_dump:mock_aec_dump_unittests",
+      "agc:agc_unittests",
       "agc2:adaptive_digital_unittests",
+      "agc2:biquad_filter_unittests",
       "agc2:fixed_digital_unittests",
       "agc2:noise_estimator_unittests",
       "agc2/rnn_vad:unittests",
       "test/conversational_speech:unittest",
+      "utility:block_mean_calculator_unittest",
+      "utility:legacy_delay_estimator_unittest",
       "vad:vad_unittests",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
 
     defines = []
@@ -586,7 +453,6 @@
         "audio_processing_impl_locking_unittest.cc",
         "audio_processing_impl_unittest.cc",
         "audio_processing_unittest.cc",
-        "beamformer/nonlinear_beamformer_unittest.cc",
         "echo_cancellation_bit_exact_unittest.cc",
         "echo_control_mobile_unittest.cc",
         "echo_detector/circular_buffer_unittest.cc",
@@ -664,11 +530,14 @@
     ]
     deps = [
       "../../api:array_view",
-      "../../api:optional",
       "../../api/audio:audio_frame_api",
       "../../common_audio:common_audio",
       "../../rtc_base:checks",
       "../../rtc_base:rtc_base_approved",
+      "../../rtc_base:safe_minmax",
+      "agc:gain_map",
+      "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
   }
 
@@ -692,7 +561,6 @@
         ":audioproc_debug_proto",
         ":audioproc_protobuf_utils",
         ":audioproc_test_utils",
-        "../../api:optional",
         "../../api/audio:aec3_factory",
         "../../common_audio:common_audio",
         "../../rtc_base:checks",
@@ -707,6 +575,8 @@
         "aec_dump",
         "aec_dump:aec_dump_impl",
         "//testing/gtest",
+        "//third_party/abseil-cpp/absl/memory",
+        "//third_party/abseil-cpp/absl/types:optional",
       ]
     }  # audioproc_f_impl
     rtc_executable("audioproc_f") {
@@ -718,6 +588,7 @@
         ":audio_processing",
         "../../api:audioproc_f_api",
         "../../rtc_base:rtc_base_approved",
+        "//third_party/abseil-cpp/absl/memory",
       ]
     }  # audioproc_f
   }
@@ -741,7 +612,6 @@
     deps = [
       ":audio_processing",
       "../../api:array_view",
-      "../../api:optional",
       "../../api/audio:audio_frame_api",
       "../../common_audio",
       "../../rtc_base:checks",
@@ -751,6 +621,7 @@
       "../../test:test_support",
       "../audio_coding:neteq_input_audio_tools",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
   }
 
@@ -772,6 +643,7 @@
       "../../system_wrappers:metrics_default",
       "../../test:fileutils",
       "../../test:test_support",
+      "agc:level_estimation",
       "//testing/gtest",
     ]
   }
@@ -793,21 +665,6 @@
     ]
   }
 
-  rtc_executable("nonlinear_beamformer_test") {
-    testonly = true
-    sources = [
-      "beamformer/nonlinear_beamformer_test.cc",
-    ]
-    deps = [
-      ":audio_processing",
-      ":audioproc_test_utils",
-      "../../common_audio:common_audio",
-      "../../rtc_base:checks",
-      "../../rtc_base:rtc_base_approved",
-      "../../system_wrappers:metrics_default",
-    ]
-  }
-
   if (rtc_enable_intelligibility_enhancer) {
     rtc_executable("intelligibility_proc") {
       testonly = true
diff --git a/modules/audio_processing/OWNERS b/modules/audio_processing/OWNERS
index 910d566..9a82da6 100644
--- a/modules/audio_processing/OWNERS
+++ b/modules/audio_processing/OWNERS
@@ -1,8 +1,12 @@
 aleloi@webrtc.org
+alessiob@webrtc.org
 aluebs@webrtc.org
 gustaf@webrtc.org
 henrik.lundin@webrtc.org
+ivoc@webrtc.org
+minyue@webrtc.org
 peah@webrtc.org
+saza@webrtc.org
 
 # These are for the common case of adding or renaming files. If you're doing
 # structural changes, please get a review from a reviewer in this file.
diff --git a/modules/audio_processing/aec/BUILD.gn b/modules/audio_processing/aec/BUILD.gn
new file mode 100644
index 0000000..5a858f5
--- /dev/null
+++ b/modules/audio_processing/aec/BUILD.gn
@@ -0,0 +1,104 @@
+# Copyright (c) 2018 The WebRTC 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.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("aec") {
+  configs += [ "..:apm_debug_dump" ]
+  sources = [
+    "aec_resampler.cc",
+    "aec_resampler.h",
+    "echo_cancellation.cc",
+    "echo_cancellation.h",
+  ]
+  deps = [
+    ":aec_core",
+    "..:apm_logging",
+    "../../..:typedefs",
+    "../../../common_audio:common_audio_c",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+  ]
+}
+
+rtc_source_set("aec_core") {
+  configs += [ "..:apm_debug_dump" ]
+  sources = [
+    "aec_common.h",
+    "aec_core.cc",
+    "aec_core.h",
+    "aec_core_optimized_methods.h",
+  ]
+  deps = [
+    "..:apm_logging",
+    "../../..:typedefs",
+    "../../../common_audio:common_audio_c",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../system_wrappers:cpu_features_api",
+    "../../../system_wrappers:metrics_api",
+    "../utility:block_mean_calculator",
+    "../utility:legacy_delay_estimator",
+    "../utility:ooura_fft",
+  ]
+  cflags = []
+
+  if (current_cpu == "x86" || current_cpu == "x64") {
+    sources += [ "aec_core_sse2.cc" ]
+    if (is_posix || is_fuchsia) {
+      cflags += [ "-msse2" ]
+    }
+  }
+
+  if (rtc_build_with_neon) {
+    sources += [ "aec_core_neon.cc" ]
+
+    if (current_cpu != "arm64") {
+      # Enable compilation for the NEON instruction set. This is needed
+      # since //build/config/arm.gni only enables NEON for iOS, not Android.
+      # This provides the same functionality as webrtc/build/arm_neon.gypi.
+      suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+      cflags += [ "-mfpu=neon" ]
+    }
+
+    # Disable LTO on NEON targets due to compiler bug.
+    # TODO(fdegans): Enable this. See crbug.com/408997.
+    if (rtc_use_lto) {
+      cflags -= [
+        "-flto",
+        "-ffat-lto-objects",
+      ]
+    }
+
+    deps += [ "../../../common_audio" ]
+  }
+
+  if (current_cpu == "mipsel" && mips_float_abi == "hard") {
+    sources += [ "aec_core_mips.cc" ]
+  }
+}
+
+if (rtc_include_tests) {
+  rtc_source_set("aec_unittests") {
+    testonly = true
+
+    sources = [
+      "echo_cancellation_unittest.cc",
+      "system_delay_unittest.cc",
+    ]
+    deps = [
+      ":aec",
+      ":aec_core",
+      "../../..:typedefs",
+      "../../../rtc_base:checks",
+      "../../../rtc_base:rtc_base_approved",
+      "../../../test:test_support",
+      "//testing/gtest",
+    ]
+  }
+}
diff --git a/modules/audio_processing/aec/aec_core.cc b/modules/audio_processing/aec/aec_core.cc
index 4394929..95ed595 100644
--- a/modules/audio_processing/aec/aec_core.cc
+++ b/modules/audio_processing/aec/aec_core.cc
@@ -14,11 +14,11 @@
 
 #include "modules/audio_processing/aec/aec_core.h"
 
-#include <algorithm>
 #include <math.h>
 #include <stddef.h>  // size_t
 #include <stdlib.h>
 #include <string.h>
+#include <algorithm>
 
 #include "rtc_base/checks.h"
 extern "C" {
@@ -178,9 +178,7 @@
 // window, of which the length is 1 unit longer than indicated. Remove "+1" when
 // the code is refactored.
 PowerLevel::PowerLevel()
-    : framelevel(kSubCountLen + 1),
-      averagelevel(kCountLen + 1) {
-}
+    : framelevel(kSubCountLen + 1), averagelevel(kCountLen + 1) {}
 
 BlockBuffer::BlockBuffer() {
   buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN);
@@ -238,10 +236,7 @@
 }
 
 DivergentFilterFraction::DivergentFilterFraction()
-    : count_(0),
-      occurrence_(0),
-      fraction_(-1.0) {
-}
+    : count_(0), occurrence_(0), fraction_(-1.0) {}
 
 void DivergentFilterFraction::Reset() {
   Clear();
@@ -254,19 +249,18 @@
   const float near_level = nearlevel.framelevel.GetLatestMean();
   const float level_increase =
       linoutlevel.framelevel.GetLatestMean() - near_level;
-  const bool output_signal_active = nlpoutlevel.framelevel.GetLatestMean() >
-          40.0 * nlpoutlevel.minlevel;
+  const bool output_signal_active =
+      nlpoutlevel.framelevel.GetLatestMean() > 40.0 * nlpoutlevel.minlevel;
   // Level increase should be, in principle, negative, when the filter
   // does not diverge. Here we allow some margin (0.01 * near end level) and
   // numerical error (1.0). We count divergence only when the AEC output
   // signal is active.
-  if (output_signal_active &&
-      level_increase > std::max(0.01 * near_level, 1.0))
+  if (output_signal_active && level_increase > std::max(0.01 * near_level, 1.0))
     occurrence_++;
   ++count_;
   if (count_ == kDivergentFilterFractionAggregationWindowSize) {
     fraction_ = static_cast<float>(occurrence_) /
-        kDivergentFilterFractionAggregationWindowSize;
+                kDivergentFilterFractionAggregationWindowSize;
     Clear();
   }
 }
@@ -416,9 +410,9 @@
   }
 }
 
-static int PartitionDelay(int num_partitions,
-                          float h_fft_buf[2]
-                                         [kExtendedNumPartitions * PART_LEN1]) {
+static int PartitionDelay(
+    int num_partitions,
+    float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1]) {
   // Measures the energy in each filter partition and returns the partition with
   // highest energy.
   // TODO(bjornv): Spread computational cost by computing one partition per
@@ -445,7 +439,8 @@
 }
 
 // Update metric with 10 * log10(numerator / denominator).
-static void UpdateLogRatioMetric(Stats* metric, float numerator,
+static void UpdateLogRatioMetric(Stats* metric,
+                                 float numerator,
                                  float denominator) {
   RTC_DCHECK(metric);
   RTC_CHECK(numerator >= 0);
@@ -736,9 +731,8 @@
   }
 
   if (aec->linoutlevel.framelevel.EndOfBlock()) {
-    aec->divergent_filter_fraction.AddObservation(aec->nearlevel,
-                                                  aec->linoutlevel,
-                                                  aec->nlpoutlevel);
+    aec->divergent_filter_fraction.AddObservation(
+        aec->nearlevel, aec->linoutlevel, aec->nlpoutlevel);
   }
 
   if (aec->farlevel.averagelevel.EndOfBlock()) {
@@ -755,7 +749,6 @@
     if ((aec->stateCounter > (0.5f * kCountLen * kSubCountLen)) &&
         (aec->farlevel.framelevel.EndOfBlock()) &&
         (far_average_level > (actThreshold * aec->farlevel.minlevel))) {
-
       // ERL: error return loss.
       const float near_average_level =
           aec->nearlevel.averagelevel.GetLatestMean();
@@ -815,9 +808,9 @@
   for (i = 0; i < kHistorySizeBlocks; i++) {
     l1_norm += abs(i - median) * self->delay_histogram[i];
   }
-  self->delay_std =
-      static_cast<int>((l1_norm + self->num_delay_values / 2) /
-                       self->num_delay_values) * kMsPerBlock;
+  self->delay_std = static_cast<int>((l1_norm + self->num_delay_values / 2) /
+                                     self->num_delay_values) *
+                    kMsPerBlock;
 
   // Determine fraction of delays that are out of bounds, that is, either
   // negative (anti-causal system) or larger than the AEC filter length.
@@ -949,11 +942,11 @@
   return delay_correction;
 }
 
-static void RegressorPower(int num_partitions,
-                           int latest_added_partition,
-                           float x_fft_buf[2]
-                                          [kExtendedNumPartitions * PART_LEN1],
-                           float x_pow[PART_LEN1]) {
+static void RegressorPower(
+    int num_partitions,
+    int latest_added_partition,
+    float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float x_pow[PART_LEN1]) {
   RTC_DCHECK_LT(latest_added_partition, num_partitions);
   memset(x_pow, 0, PART_LEN1 * sizeof(x_pow[0]));
 
@@ -976,21 +969,20 @@
   }
 }
 
-static void EchoSubtraction(const OouraFft& ooura_fft,
-                            int num_partitions,
-                            int extended_filter_enabled,
-                            int* extreme_filter_divergence,
-                            float filter_step_size,
-                            float error_threshold,
-                            float* x_fft,
-                            int* x_fft_buf_block_pos,
-                            float x_fft_buf[2]
-                                           [kExtendedNumPartitions * PART_LEN1],
-                            float* const y,
-                            float x_pow[PART_LEN1],
-                            float h_fft_buf[2]
-                                           [kExtendedNumPartitions * PART_LEN1],
-                            float echo_subtractor_output[PART_LEN]) {
+static void EchoSubtraction(
+    const OouraFft& ooura_fft,
+    int num_partitions,
+    int extended_filter_enabled,
+    int* extreme_filter_divergence,
+    float filter_step_size,
+    float error_threshold,
+    float* x_fft,
+    int* x_fft_buf_block_pos,
+    float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float* const y,
+    float x_pow[PART_LEN1],
+    float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float echo_subtractor_output[PART_LEN]) {
   float s_fft[2][PART_LEN1];
   float e_extended[PART_LEN2];
   float s_extended[PART_LEN2];
@@ -1118,10 +1110,10 @@
       // preferred.
       memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize);
       qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat);
-      hNlFb = hNlPref[static_cast<int>(floor(prefBandQuant *
-                                             (prefBandSize - 1)))];
-      hNlFbLow = hNlPref[static_cast<int>(floor(prefBandQuantLow *
-                                                (prefBandSize - 1)))];
+      hNlFb =
+          hNlPref[static_cast<int>(floor(prefBandQuant * (prefBandSize - 1)))];
+      hNlFbLow = hNlPref[static_cast<int>(
+          floor(prefBandQuantLow * (prefBandSize - 1)))];
     }
   }
 
@@ -1142,10 +1134,10 @@
   if (aec->hNlMinCtr == 2) {
     aec->hNlNewMin = 0;
     aec->hNlMinCtr = 0;
-    aec->overDrive =
-        WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] /
-                       static_cast<float>(log(aec->hNlFbMin + 1e-10f) + 1e-10f),
-                       min_overdrive[aec->nlp_mode]);
+    aec->overDrive = WEBRTC_SPL_MAX(
+        kTargetSupp[aec->nlp_mode] /
+            static_cast<float>(log(aec->hNlFbMin + 1e-10f) + 1e-10f),
+        min_overdrive[aec->nlp_mode]);
   }
 
   // Smooth the overdrive.
@@ -1773,20 +1765,18 @@
     float nearend_buffer[NUM_HIGH_BANDS_MAX + 1]
                         [PART_LEN - (FRAME_LEN - PART_LEN)]) {
   for (size_t i = 0; i < num_bands; ++i) {
-    memcpy(
-        &nearend_buffer[i][0],
-        &nearend_frame[i]
-                      [nearend_start_index + FRAME_LEN - num_samples_to_buffer],
-        num_samples_to_buffer * sizeof(float));
+    memcpy(&nearend_buffer[i][0],
+           &nearend_frame[i][nearend_start_index + FRAME_LEN -
+                             num_samples_to_buffer],
+           num_samples_to_buffer * sizeof(float));
   }
 }
 
-void BufferOutputBlock(size_t num_bands,
-                       const float output_block[NUM_HIGH_BANDS_MAX + 1]
-                                               [PART_LEN],
-                       size_t* output_buffer_size,
-                       float output_buffer[NUM_HIGH_BANDS_MAX + 1]
-                                          [2 * PART_LEN]) {
+void BufferOutputBlock(
+    size_t num_bands,
+    const float output_block[NUM_HIGH_BANDS_MAX + 1][PART_LEN],
+    size_t* output_buffer_size,
+    float output_buffer[NUM_HIGH_BANDS_MAX + 1][2 * PART_LEN]) {
   for (size_t i = 0; i < num_bands; ++i) {
     memcpy(&output_buffer[i][*output_buffer_size], &output_block[i][0],
            PART_LEN * sizeof(float));
diff --git a/modules/audio_processing/aec/aec_core_mips.cc b/modules/audio_processing/aec/aec_core_mips.cc
index ebe6349..bf89cfa 100644
--- a/modules/audio_processing/aec/aec_core_mips.cc
+++ b/modules/audio_processing/aec/aec_core_mips.cc
@@ -51,95 +51,94 @@
     int len = PART_LEN1 >> 1;
 
     __asm __volatile(
-      ".set       push                                                \n\t"
-      ".set       noreorder                                           \n\t"
-      "1:                                                             \n\t"
-      "lwc1       %[f0],      0(%[aRe])                               \n\t"
-      "lwc1       %[f1],      0(%[bRe])                               \n\t"
-      "lwc1       %[f2],      0(%[bIm])                               \n\t"
-      "lwc1       %[f3],      0(%[aIm])                               \n\t"
-      "lwc1       %[f4],      4(%[aRe])                               \n\t"
-      "lwc1       %[f5],      4(%[bRe])                               \n\t"
-      "lwc1       %[f6],      4(%[bIm])                               \n\t"
-      "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
-      "mul.s      %[f0],      %[f0],          %[f2]                   \n\t"
-      "mul.s      %[f9],      %[f4],          %[f5]                   \n\t"
-      "mul.s      %[f4],      %[f4],          %[f6]                   \n\t"
-      "lwc1       %[f7],      4(%[aIm])                               \n\t"
+        ".set       push                                                \n\t"
+        ".set       noreorder                                           \n\t"
+        "1:                                                             \n\t"
+        "lwc1       %[f0],      0(%[aRe])                               \n\t"
+        "lwc1       %[f1],      0(%[bRe])                               \n\t"
+        "lwc1       %[f2],      0(%[bIm])                               \n\t"
+        "lwc1       %[f3],      0(%[aIm])                               \n\t"
+        "lwc1       %[f4],      4(%[aRe])                               \n\t"
+        "lwc1       %[f5],      4(%[bRe])                               \n\t"
+        "lwc1       %[f6],      4(%[bIm])                               \n\t"
+        "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
+        "mul.s      %[f0],      %[f0],          %[f2]                   \n\t"
+        "mul.s      %[f9],      %[f4],          %[f5]                   \n\t"
+        "mul.s      %[f4],      %[f4],          %[f6]                   \n\t"
+        "lwc1       %[f7],      4(%[aIm])                               \n\t"
 #if !defined(MIPS32_R2_LE)
-      "mul.s      %[f12],     %[f2],          %[f3]                   \n\t"
-      "mul.s      %[f1],      %[f3],          %[f1]                   \n\t"
-      "mul.s      %[f11],     %[f6],          %[f7]                   \n\t"
-      "addiu      %[aRe],     %[aRe],         8                       \n\t"
-      "addiu      %[aIm],     %[aIm],         8                       \n\t"
-      "addiu      %[len],     %[len],         -1                      \n\t"
-      "sub.s      %[f8],      %[f8],          %[f12]                  \n\t"
-      "mul.s      %[f12],     %[f7],          %[f5]                   \n\t"
-      "lwc1       %[f2],      0(%[yf0])                               \n\t"
-      "add.s      %[f1],      %[f0],          %[f1]                   \n\t"
-      "lwc1       %[f3],      0(%[yf1])                               \n\t"
-      "sub.s      %[f9],      %[f9],          %[f11]                  \n\t"
-      "lwc1       %[f6],      4(%[yf0])                               \n\t"
-      "add.s      %[f4],      %[f4],          %[f12]                  \n\t"
-#else  // #if !defined(MIPS32_R2_LE)
-      "addiu      %[aRe],     %[aRe],         8                       \n\t"
-      "addiu      %[aIm],     %[aIm],         8                       \n\t"
-      "addiu      %[len],     %[len],         -1                      \n\t"
-      "nmsub.s    %[f8],      %[f8],          %[f2],      %[f3]       \n\t"
-      "lwc1       %[f2],      0(%[yf0])                               \n\t"
-      "madd.s     %[f1],      %[f0],          %[f3],      %[f1]       \n\t"
-      "lwc1       %[f3],      0(%[yf1])                               \n\t"
-      "nmsub.s    %[f9],      %[f9],          %[f6],      %[f7]       \n\t"
-      "lwc1       %[f6],      4(%[yf0])                               \n\t"
-      "madd.s     %[f4],      %[f4],          %[f7],      %[f5]       \n\t"
+        "mul.s      %[f12],     %[f2],          %[f3]                   \n\t"
+        "mul.s      %[f1],      %[f3],          %[f1]                   \n\t"
+        "mul.s      %[f11],     %[f6],          %[f7]                   \n\t"
+        "addiu      %[aRe],     %[aRe],         8                       \n\t"
+        "addiu      %[aIm],     %[aIm],         8                       \n\t"
+        "addiu      %[len],     %[len],         -1                      \n\t"
+        "sub.s      %[f8],      %[f8],          %[f12]                  \n\t"
+        "mul.s      %[f12],     %[f7],          %[f5]                   \n\t"
+        "lwc1       %[f2],      0(%[yf0])                               \n\t"
+        "add.s      %[f1],      %[f0],          %[f1]                   \n\t"
+        "lwc1       %[f3],      0(%[yf1])                               \n\t"
+        "sub.s      %[f9],      %[f9],          %[f11]                  \n\t"
+        "lwc1       %[f6],      4(%[yf0])                               \n\t"
+        "add.s      %[f4],      %[f4],          %[f12]                  \n\t"
+#else   // #if !defined(MIPS32_R2_LE)
+        "addiu      %[aRe],     %[aRe],         8                       \n\t"
+        "addiu      %[aIm],     %[aIm],         8                       \n\t"
+        "addiu      %[len],     %[len],         -1                      \n\t"
+        "nmsub.s    %[f8],      %[f8],          %[f2],      %[f3]       \n\t"
+        "lwc1       %[f2],      0(%[yf0])                               \n\t"
+        "madd.s     %[f1],      %[f0],          %[f3],      %[f1]       \n\t"
+        "lwc1       %[f3],      0(%[yf1])                               \n\t"
+        "nmsub.s    %[f9],      %[f9],          %[f6],      %[f7]       \n\t"
+        "lwc1       %[f6],      4(%[yf0])                               \n\t"
+        "madd.s     %[f4],      %[f4],          %[f7],      %[f5]       \n\t"
 #endif  // #if !defined(MIPS32_R2_LE)
-      "lwc1       %[f5],      4(%[yf1])                               \n\t"
-      "add.s      %[f2],      %[f2],          %[f8]                   \n\t"
-      "addiu      %[bRe],     %[bRe],         8                       \n\t"
-      "addiu      %[bIm],     %[bIm],         8                       \n\t"
-      "add.s      %[f3],      %[f3],          %[f1]                   \n\t"
-      "add.s      %[f6],      %[f6],          %[f9]                   \n\t"
-      "add.s      %[f5],      %[f5],          %[f4]                   \n\t"
-      "swc1       %[f2],      0(%[yf0])                               \n\t"
-      "swc1       %[f3],      0(%[yf1])                               \n\t"
-      "swc1       %[f6],      4(%[yf0])                               \n\t"
-      "swc1       %[f5],      4(%[yf1])                               \n\t"
-      "addiu      %[yf0],     %[yf0],         8                       \n\t"
-      "bgtz       %[len],     1b                                      \n\t"
-      " addiu     %[yf1],     %[yf1],         8                       \n\t"
-      "lwc1       %[f0],      0(%[aRe])                               \n\t"
-      "lwc1       %[f1],      0(%[bRe])                               \n\t"
-      "lwc1       %[f2],      0(%[bIm])                               \n\t"
-      "lwc1       %[f3],      0(%[aIm])                               \n\t"
-      "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
-      "mul.s      %[f0],      %[f0],          %[f2]                   \n\t"
+        "lwc1       %[f5],      4(%[yf1])                               \n\t"
+        "add.s      %[f2],      %[f2],          %[f8]                   \n\t"
+        "addiu      %[bRe],     %[bRe],         8                       \n\t"
+        "addiu      %[bIm],     %[bIm],         8                       \n\t"
+        "add.s      %[f3],      %[f3],          %[f1]                   \n\t"
+        "add.s      %[f6],      %[f6],          %[f9]                   \n\t"
+        "add.s      %[f5],      %[f5],          %[f4]                   \n\t"
+        "swc1       %[f2],      0(%[yf0])                               \n\t"
+        "swc1       %[f3],      0(%[yf1])                               \n\t"
+        "swc1       %[f6],      4(%[yf0])                               \n\t"
+        "swc1       %[f5],      4(%[yf1])                               \n\t"
+        "addiu      %[yf0],     %[yf0],         8                       \n\t"
+        "bgtz       %[len],     1b                                      \n\t"
+        " addiu     %[yf1],     %[yf1],         8                       \n\t"
+        "lwc1       %[f0],      0(%[aRe])                               \n\t"
+        "lwc1       %[f1],      0(%[bRe])                               \n\t"
+        "lwc1       %[f2],      0(%[bIm])                               \n\t"
+        "lwc1       %[f3],      0(%[aIm])                               \n\t"
+        "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
+        "mul.s      %[f0],      %[f0],          %[f2]                   \n\t"
 #if !defined(MIPS32_R2_LE)
-      "mul.s      %[f12],     %[f2],          %[f3]                   \n\t"
-      "mul.s      %[f1],      %[f3],          %[f1]                   \n\t"
-      "sub.s      %[f8],      %[f8],          %[f12]                  \n\t"
-      "lwc1       %[f2],      0(%[yf0])                               \n\t"
-      "add.s      %[f1],      %[f0],          %[f1]                   \n\t"
-      "lwc1       %[f3],      0(%[yf1])                               \n\t"
-#else  // #if !defined(MIPS32_R2_LE)
-      "nmsub.s    %[f8],      %[f8],          %[f2],      %[f3]       \n\t"
-      "lwc1       %[f2],      0(%[yf0])                               \n\t"
-      "madd.s     %[f1],      %[f0],          %[f3],      %[f1]       \n\t"
-      "lwc1       %[f3],      0(%[yf1])                               \n\t"
+        "mul.s      %[f12],     %[f2],          %[f3]                   \n\t"
+        "mul.s      %[f1],      %[f3],          %[f1]                   \n\t"
+        "sub.s      %[f8],      %[f8],          %[f12]                  \n\t"
+        "lwc1       %[f2],      0(%[yf0])                               \n\t"
+        "add.s      %[f1],      %[f0],          %[f1]                   \n\t"
+        "lwc1       %[f3],      0(%[yf1])                               \n\t"
+#else   // #if !defined(MIPS32_R2_LE)
+        "nmsub.s    %[f8],      %[f8],          %[f2],      %[f3]       \n\t"
+        "lwc1       %[f2],      0(%[yf0])                               \n\t"
+        "madd.s     %[f1],      %[f0],          %[f3],      %[f1]       \n\t"
+        "lwc1       %[f3],      0(%[yf1])                               \n\t"
 #endif  // #if !defined(MIPS32_R2_LE)
-      "add.s      %[f2],      %[f2],          %[f8]                   \n\t"
-      "add.s      %[f3],      %[f3],          %[f1]                   \n\t"
-      "swc1       %[f2],      0(%[yf0])                               \n\t"
-      "swc1       %[f3],      0(%[yf1])                               \n\t"
-      ".set       pop                                                 \n\t"
-      : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
-        [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
-        [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
-        [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
-        [f12] "=&f" (f12), [f13] "=&f" (f13), [aRe] "+r" (aRe),
-        [aIm] "+r" (aIm), [bRe] "+r" (bRe), [bIm] "+r" (bIm),
-        [yf0] "+r" (yf0), [yf1] "+r" (yf1), [len] "+r" (len)
-      :
-      : "memory");
+        "add.s      %[f2],      %[f2],          %[f8]                   \n\t"
+        "add.s      %[f3],      %[f3],          %[f1]                   \n\t"
+        "swc1       %[f2],      0(%[yf0])                               \n\t"
+        "swc1       %[f3],      0(%[yf1])                               \n\t"
+        ".set       pop                                                 \n\t"
+        : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+          [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+          [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11),
+          [f12] "=&f"(f12), [f13] "=&f"(f13), [aRe] "+r"(aRe), [aIm] "+r"(aIm),
+          [bRe] "+r"(bRe), [bIm] "+r"(bIm), [yf0] "+r"(yf0), [yf1] "+r"(yf1),
+          [len] "+r"(len)
+        :
+        : "memory");
   }
 }
 
@@ -171,73 +170,71 @@
     int len = PART_LEN >> 1;
 
     __asm __volatile(
-      ".set       push                                                \n\t"
-      ".set       noreorder                                           \n\t"
-      "addiu      %[fft_tmp], %[fft],         0                       \n\t"
-      "1:                                                             \n\t"
-      "lwc1       %[f0],      0(%[aRe])                               \n\t"
-      "lwc1       %[f1],      0(%[bRe])                               \n\t"
-      "lwc1       %[f2],      0(%[bIm])                               \n\t"
-      "lwc1       %[f4],      4(%[aRe])                               \n\t"
-      "lwc1       %[f5],      4(%[bRe])                               \n\t"
-      "lwc1       %[f6],      4(%[bIm])                               \n\t"
-      "addiu      %[aRe],     %[aRe],         8                       \n\t"
-      "addiu      %[bRe],     %[bRe],         8                       \n\t"
-      "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
-      "mul.s      %[f0],      %[f0],          %[f2]                   \n\t"
-      "lwc1       %[f3],      0(%[aIm])                               \n\t"
-      "mul.s      %[f9],      %[f4],          %[f5]                   \n\t"
-      "lwc1       %[f7],      4(%[aIm])                               \n\t"
-      "mul.s      %[f4],      %[f4],          %[f6]                   \n\t"
+        ".set       push                                                \n\t"
+        ".set       noreorder                                           \n\t"
+        "addiu      %[fft_tmp], %[fft],         0                       \n\t"
+        "1:                                                             \n\t"
+        "lwc1       %[f0],      0(%[aRe])                               \n\t"
+        "lwc1       %[f1],      0(%[bRe])                               \n\t"
+        "lwc1       %[f2],      0(%[bIm])                               \n\t"
+        "lwc1       %[f4],      4(%[aRe])                               \n\t"
+        "lwc1       %[f5],      4(%[bRe])                               \n\t"
+        "lwc1       %[f6],      4(%[bIm])                               \n\t"
+        "addiu      %[aRe],     %[aRe],         8                       \n\t"
+        "addiu      %[bRe],     %[bRe],         8                       \n\t"
+        "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
+        "mul.s      %[f0],      %[f0],          %[f2]                   \n\t"
+        "lwc1       %[f3],      0(%[aIm])                               \n\t"
+        "mul.s      %[f9],      %[f4],          %[f5]                   \n\t"
+        "lwc1       %[f7],      4(%[aIm])                               \n\t"
+        "mul.s      %[f4],      %[f4],          %[f6]                   \n\t"
 #if !defined(MIPS32_R2_LE)
-      "mul.s      %[f10],     %[f3],          %[f2]                   \n\t"
-      "mul.s      %[f1],      %[f3],          %[f1]                   \n\t"
-      "mul.s      %[f11],     %[f7],          %[f6]                   \n\t"
-      "mul.s      %[f5],      %[f7],          %[f5]                   \n\t"
-      "addiu      %[aIm],     %[aIm],         8                       \n\t"
-      "addiu      %[bIm],     %[bIm],         8                       \n\t"
-      "addiu      %[len],     %[len],         -1                      \n\t"
-      "add.s      %[f8],      %[f8],          %[f10]                  \n\t"
-      "sub.s      %[f1],      %[f0],          %[f1]                   \n\t"
-      "add.s      %[f9],      %[f9],          %[f11]                  \n\t"
-      "sub.s      %[f5],      %[f4],          %[f5]                   \n\t"
-#else  // #if !defined(MIPS32_R2_LE)
-      "addiu      %[aIm],     %[aIm],         8                       \n\t"
-      "addiu      %[bIm],     %[bIm],         8                       \n\t"
-      "addiu      %[len],     %[len],         -1                      \n\t"
-      "madd.s     %[f8],      %[f8],          %[f3],      %[f2]       \n\t"
-      "nmsub.s    %[f1],      %[f0],          %[f3],      %[f1]       \n\t"
-      "madd.s     %[f9],      %[f9],          %[f7],      %[f6]       \n\t"
-      "nmsub.s    %[f5],      %[f4],          %[f7],      %[f5]       \n\t"
+        "mul.s      %[f10],     %[f3],          %[f2]                   \n\t"
+        "mul.s      %[f1],      %[f3],          %[f1]                   \n\t"
+        "mul.s      %[f11],     %[f7],          %[f6]                   \n\t"
+        "mul.s      %[f5],      %[f7],          %[f5]                   \n\t"
+        "addiu      %[aIm],     %[aIm],         8                       \n\t"
+        "addiu      %[bIm],     %[bIm],         8                       \n\t"
+        "addiu      %[len],     %[len],         -1                      \n\t"
+        "add.s      %[f8],      %[f8],          %[f10]                  \n\t"
+        "sub.s      %[f1],      %[f0],          %[f1]                   \n\t"
+        "add.s      %[f9],      %[f9],          %[f11]                  \n\t"
+        "sub.s      %[f5],      %[f4],          %[f5]                   \n\t"
+#else   // #if !defined(MIPS32_R2_LE)
+        "addiu      %[aIm],     %[aIm],         8                       \n\t"
+        "addiu      %[bIm],     %[bIm],         8                       \n\t"
+        "addiu      %[len],     %[len],         -1                      \n\t"
+        "madd.s     %[f8],      %[f8],          %[f3],      %[f2]       \n\t"
+        "nmsub.s    %[f1],      %[f0],          %[f3],      %[f1]       \n\t"
+        "madd.s     %[f9],      %[f9],          %[f7],      %[f6]       \n\t"
+        "nmsub.s    %[f5],      %[f4],          %[f7],      %[f5]       \n\t"
 #endif  // #if !defined(MIPS32_R2_LE)
-      "swc1       %[f8],      0(%[fft_tmp])                           \n\t"
-      "swc1       %[f1],      4(%[fft_tmp])                           \n\t"
-      "swc1       %[f9],      8(%[fft_tmp])                           \n\t"
-      "swc1       %[f5],      12(%[fft_tmp])                          \n\t"
-      "bgtz       %[len],     1b                                      \n\t"
-      " addiu     %[fft_tmp], %[fft_tmp],     16                      \n\t"
-      "lwc1       %[f0],      0(%[aRe])                               \n\t"
-      "lwc1       %[f1],      0(%[bRe])                               \n\t"
-      "lwc1       %[f2],      0(%[bIm])                               \n\t"
-      "lwc1       %[f3],      0(%[aIm])                               \n\t"
-      "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
+        "swc1       %[f8],      0(%[fft_tmp])                           \n\t"
+        "swc1       %[f1],      4(%[fft_tmp])                           \n\t"
+        "swc1       %[f9],      8(%[fft_tmp])                           \n\t"
+        "swc1       %[f5],      12(%[fft_tmp])                          \n\t"
+        "bgtz       %[len],     1b                                      \n\t"
+        " addiu     %[fft_tmp], %[fft_tmp],     16                      \n\t"
+        "lwc1       %[f0],      0(%[aRe])                               \n\t"
+        "lwc1       %[f1],      0(%[bRe])                               \n\t"
+        "lwc1       %[f2],      0(%[bIm])                               \n\t"
+        "lwc1       %[f3],      0(%[aIm])                               \n\t"
+        "mul.s      %[f8],      %[f0],          %[f1]                   \n\t"
 #if !defined(MIPS32_R2_LE)
-      "mul.s      %[f10],     %[f3],          %[f2]                   \n\t"
-      "add.s      %[f8],      %[f8],          %[f10]                  \n\t"
-#else  // #if !defined(MIPS32_R2_LE)
-      "madd.s     %[f8],      %[f8],          %[f3],      %[f2]       \n\t"
+        "mul.s      %[f10],     %[f3],          %[f2]                   \n\t"
+        "add.s      %[f8],      %[f8],          %[f10]                  \n\t"
+#else   // #if !defined(MIPS32_R2_LE)
+        "madd.s     %[f8],      %[f8],          %[f3],      %[f2]       \n\t"
 #endif  // #if !defined(MIPS32_R2_LE)
-      "swc1       %[f8],      4(%[fft])                               \n\t"
-      ".set       pop                                                 \n\t"
-      : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
-        [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
-        [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
-        [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
-        [f12] "=&f" (f12), [aRe] "+r" (aRe), [aIm] "+r" (aIm),
-        [bRe] "+r" (bRe), [bIm] "+r" (bIm), [fft_tmp] "=&r" (fft_tmp),
-        [len] "+r" (len)
-      : [fft] "r" (fft)
-      : "memory");
+        "swc1       %[f8],      4(%[fft])                               \n\t"
+        ".set       pop                                                 \n\t"
+        : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+          [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+          [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11),
+          [f12] "=&f"(f12), [aRe] "+r"(aRe), [aIm] "+r"(aIm), [bRe] "+r"(bRe),
+          [bIm] "+r"(bIm), [fft_tmp] "=&r"(fft_tmp), [len] "+r"(len)
+        : [fft] "r"(fft)
+        : "memory");
 
     ooura_fft.InverseFft(fft);
     memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
@@ -246,102 +243,101 @@
     {
       float scale = 2.0f / PART_LEN2;
       __asm __volatile(
-        ".set     push                                    \n\t"
-        ".set     noreorder                               \n\t"
-        "addiu    %[fft_tmp], %[fft],        0            \n\t"
-        "addiu    %[len],     $zero,         8            \n\t"
-        "1:                                               \n\t"
-        "addiu    %[len],     %[len],        -1           \n\t"
-        "lwc1     %[f0],      0(%[fft_tmp])               \n\t"
-        "lwc1     %[f1],      4(%[fft_tmp])               \n\t"
-        "lwc1     %[f2],      8(%[fft_tmp])               \n\t"
-        "lwc1     %[f3],      12(%[fft_tmp])              \n\t"
-        "mul.s    %[f0],      %[f0],         %[scale]     \n\t"
-        "mul.s    %[f1],      %[f1],         %[scale]     \n\t"
-        "mul.s    %[f2],      %[f2],         %[scale]     \n\t"
-        "mul.s    %[f3],      %[f3],         %[scale]     \n\t"
-        "lwc1     %[f4],      16(%[fft_tmp])              \n\t"
-        "lwc1     %[f5],      20(%[fft_tmp])              \n\t"
-        "lwc1     %[f6],      24(%[fft_tmp])              \n\t"
-        "lwc1     %[f7],      28(%[fft_tmp])              \n\t"
-        "mul.s    %[f4],      %[f4],         %[scale]     \n\t"
-        "mul.s    %[f5],      %[f5],         %[scale]     \n\t"
-        "mul.s    %[f6],      %[f6],         %[scale]     \n\t"
-        "mul.s    %[f7],      %[f7],         %[scale]     \n\t"
-        "swc1     %[f0],      0(%[fft_tmp])               \n\t"
-        "swc1     %[f1],      4(%[fft_tmp])               \n\t"
-        "swc1     %[f2],      8(%[fft_tmp])               \n\t"
-        "swc1     %[f3],      12(%[fft_tmp])              \n\t"
-        "swc1     %[f4],      16(%[fft_tmp])              \n\t"
-        "swc1     %[f5],      20(%[fft_tmp])              \n\t"
-        "swc1     %[f6],      24(%[fft_tmp])              \n\t"
-        "swc1     %[f7],      28(%[fft_tmp])              \n\t"
-        "bgtz     %[len],     1b                          \n\t"
-        " addiu   %[fft_tmp], %[fft_tmp],    32           \n\t"
-        ".set     pop                                     \n\t"
-        : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
-          [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
-          [f6] "=&f" (f6), [f7] "=&f" (f7), [len] "=&r" (len),
-          [fft_tmp] "=&r" (fft_tmp)
-        : [scale] "f" (scale), [fft] "r" (fft)
-        : "memory");
+          ".set     push                                    \n\t"
+          ".set     noreorder                               \n\t"
+          "addiu    %[fft_tmp], %[fft],        0            \n\t"
+          "addiu    %[len],     $zero,         8            \n\t"
+          "1:                                               \n\t"
+          "addiu    %[len],     %[len],        -1           \n\t"
+          "lwc1     %[f0],      0(%[fft_tmp])               \n\t"
+          "lwc1     %[f1],      4(%[fft_tmp])               \n\t"
+          "lwc1     %[f2],      8(%[fft_tmp])               \n\t"
+          "lwc1     %[f3],      12(%[fft_tmp])              \n\t"
+          "mul.s    %[f0],      %[f0],         %[scale]     \n\t"
+          "mul.s    %[f1],      %[f1],         %[scale]     \n\t"
+          "mul.s    %[f2],      %[f2],         %[scale]     \n\t"
+          "mul.s    %[f3],      %[f3],         %[scale]     \n\t"
+          "lwc1     %[f4],      16(%[fft_tmp])              \n\t"
+          "lwc1     %[f5],      20(%[fft_tmp])              \n\t"
+          "lwc1     %[f6],      24(%[fft_tmp])              \n\t"
+          "lwc1     %[f7],      28(%[fft_tmp])              \n\t"
+          "mul.s    %[f4],      %[f4],         %[scale]     \n\t"
+          "mul.s    %[f5],      %[f5],         %[scale]     \n\t"
+          "mul.s    %[f6],      %[f6],         %[scale]     \n\t"
+          "mul.s    %[f7],      %[f7],         %[scale]     \n\t"
+          "swc1     %[f0],      0(%[fft_tmp])               \n\t"
+          "swc1     %[f1],      4(%[fft_tmp])               \n\t"
+          "swc1     %[f2],      8(%[fft_tmp])               \n\t"
+          "swc1     %[f3],      12(%[fft_tmp])              \n\t"
+          "swc1     %[f4],      16(%[fft_tmp])              \n\t"
+          "swc1     %[f5],      20(%[fft_tmp])              \n\t"
+          "swc1     %[f6],      24(%[fft_tmp])              \n\t"
+          "swc1     %[f7],      28(%[fft_tmp])              \n\t"
+          "bgtz     %[len],     1b                          \n\t"
+          " addiu   %[fft_tmp], %[fft_tmp],    32           \n\t"
+          ".set     pop                                     \n\t"
+          : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+            [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+            [len] "=&r"(len), [fft_tmp] "=&r"(fft_tmp)
+          : [scale] "f"(scale), [fft] "r"(fft)
+          : "memory");
     }
     ooura_fft.Fft(fft);
     aRe = h_fft_buf[0] + pos;
     aIm = h_fft_buf[1] + pos;
     __asm __volatile(
-      ".set     push                                    \n\t"
-      ".set     noreorder                               \n\t"
-      "addiu    %[fft_tmp], %[fft],        0            \n\t"
-      "addiu    %[len],     $zero,         31           \n\t"
-      "lwc1     %[f0],      0(%[aRe])                   \n\t"
-      "lwc1     %[f1],      0(%[fft_tmp])               \n\t"
-      "lwc1     %[f2],      256(%[aRe])                 \n\t"
-      "lwc1     %[f3],      4(%[fft_tmp])               \n\t"
-      "lwc1     %[f4],      4(%[aRe])                   \n\t"
-      "lwc1     %[f5],      8(%[fft_tmp])               \n\t"
-      "lwc1     %[f6],      4(%[aIm])                   \n\t"
-      "lwc1     %[f7],      12(%[fft_tmp])              \n\t"
-      "add.s    %[f0],      %[f0],         %[f1]        \n\t"
-      "add.s    %[f2],      %[f2],         %[f3]        \n\t"
-      "add.s    %[f4],      %[f4],         %[f5]        \n\t"
-      "add.s    %[f6],      %[f6],         %[f7]        \n\t"
-      "addiu    %[fft_tmp], %[fft_tmp],    16           \n\t"
-      "swc1     %[f0],      0(%[aRe])                   \n\t"
-      "swc1     %[f2],      256(%[aRe])                 \n\t"
-      "swc1     %[f4],      4(%[aRe])                   \n\t"
-      "addiu    %[aRe],     %[aRe],        8            \n\t"
-      "swc1     %[f6],      4(%[aIm])                   \n\t"
-      "addiu    %[aIm],     %[aIm],        8            \n\t"
-      "1:                                               \n\t"
-      "lwc1     %[f0],      0(%[aRe])                   \n\t"
-      "lwc1     %[f1],      0(%[fft_tmp])               \n\t"
-      "lwc1     %[f2],      0(%[aIm])                   \n\t"
-      "lwc1     %[f3],      4(%[fft_tmp])               \n\t"
-      "lwc1     %[f4],      4(%[aRe])                   \n\t"
-      "lwc1     %[f5],      8(%[fft_tmp])               \n\t"
-      "lwc1     %[f6],      4(%[aIm])                   \n\t"
-      "lwc1     %[f7],      12(%[fft_tmp])              \n\t"
-      "add.s    %[f0],      %[f0],         %[f1]        \n\t"
-      "add.s    %[f2],      %[f2],         %[f3]        \n\t"
-      "add.s    %[f4],      %[f4],         %[f5]        \n\t"
-      "add.s    %[f6],      %[f6],         %[f7]        \n\t"
-      "addiu    %[len],     %[len],        -1           \n\t"
-      "addiu    %[fft_tmp], %[fft_tmp],    16           \n\t"
-      "swc1     %[f0],      0(%[aRe])                   \n\t"
-      "swc1     %[f2],      0(%[aIm])                   \n\t"
-      "swc1     %[f4],      4(%[aRe])                   \n\t"
-      "addiu    %[aRe],     %[aRe],        8            \n\t"
-      "swc1     %[f6],      4(%[aIm])                   \n\t"
-      "bgtz     %[len],     1b                          \n\t"
-      " addiu   %[aIm],     %[aIm],        8            \n\t"
-      ".set     pop                                     \n\t"
-      : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
-        [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
-        [f6] "=&f" (f6), [f7] "=&f" (f7), [len] "=&r" (len),
-        [fft_tmp] "=&r" (fft_tmp), [aRe] "+r" (aRe), [aIm] "+r" (aIm)
-      : [fft] "r" (fft)
-      : "memory");
+        ".set     push                                    \n\t"
+        ".set     noreorder                               \n\t"
+        "addiu    %[fft_tmp], %[fft],        0            \n\t"
+        "addiu    %[len],     $zero,         31           \n\t"
+        "lwc1     %[f0],      0(%[aRe])                   \n\t"
+        "lwc1     %[f1],      0(%[fft_tmp])               \n\t"
+        "lwc1     %[f2],      256(%[aRe])                 \n\t"
+        "lwc1     %[f3],      4(%[fft_tmp])               \n\t"
+        "lwc1     %[f4],      4(%[aRe])                   \n\t"
+        "lwc1     %[f5],      8(%[fft_tmp])               \n\t"
+        "lwc1     %[f6],      4(%[aIm])                   \n\t"
+        "lwc1     %[f7],      12(%[fft_tmp])              \n\t"
+        "add.s    %[f0],      %[f0],         %[f1]        \n\t"
+        "add.s    %[f2],      %[f2],         %[f3]        \n\t"
+        "add.s    %[f4],      %[f4],         %[f5]        \n\t"
+        "add.s    %[f6],      %[f6],         %[f7]        \n\t"
+        "addiu    %[fft_tmp], %[fft_tmp],    16           \n\t"
+        "swc1     %[f0],      0(%[aRe])                   \n\t"
+        "swc1     %[f2],      256(%[aRe])                 \n\t"
+        "swc1     %[f4],      4(%[aRe])                   \n\t"
+        "addiu    %[aRe],     %[aRe],        8            \n\t"
+        "swc1     %[f6],      4(%[aIm])                   \n\t"
+        "addiu    %[aIm],     %[aIm],        8            \n\t"
+        "1:                                               \n\t"
+        "lwc1     %[f0],      0(%[aRe])                   \n\t"
+        "lwc1     %[f1],      0(%[fft_tmp])               \n\t"
+        "lwc1     %[f2],      0(%[aIm])                   \n\t"
+        "lwc1     %[f3],      4(%[fft_tmp])               \n\t"
+        "lwc1     %[f4],      4(%[aRe])                   \n\t"
+        "lwc1     %[f5],      8(%[fft_tmp])               \n\t"
+        "lwc1     %[f6],      4(%[aIm])                   \n\t"
+        "lwc1     %[f7],      12(%[fft_tmp])              \n\t"
+        "add.s    %[f0],      %[f0],         %[f1]        \n\t"
+        "add.s    %[f2],      %[f2],         %[f3]        \n\t"
+        "add.s    %[f4],      %[f4],         %[f5]        \n\t"
+        "add.s    %[f6],      %[f6],         %[f7]        \n\t"
+        "addiu    %[len],     %[len],        -1           \n\t"
+        "addiu    %[fft_tmp], %[fft_tmp],    16           \n\t"
+        "swc1     %[f0],      0(%[aRe])                   \n\t"
+        "swc1     %[f2],      0(%[aIm])                   \n\t"
+        "swc1     %[f4],      4(%[aRe])                   \n\t"
+        "addiu    %[aRe],     %[aRe],        8            \n\t"
+        "swc1     %[f6],      4(%[aIm])                   \n\t"
+        "bgtz     %[len],     1b                          \n\t"
+        " addiu   %[aIm],     %[aIm],        8            \n\t"
+        ".set     pop                                     \n\t"
+        : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+          [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+          [len] "=&r"(len), [fft_tmp] "=&r"(fft_tmp), [aRe] "+r"(aRe),
+          [aIm] "+r"(aIm)
+        : [fft] "r"(fft)
+        : "memory");
   }
 }
 
@@ -359,28 +355,28 @@
   for (int i = 0; i < PART_LEN1; ++i) {
     // Weight subbands
     __asm __volatile(
-      ".set      push                                              \n\t"
-      ".set      noreorder                                         \n\t"
-      "lwc1      %[temp1],    0(%[p_hNl])                          \n\t"
-      "lwc1      %[temp2],    0(%[p_wC])                           \n\t"
-      "c.lt.s    %[hNlFb],    %[temp1]                             \n\t"
-      "bc1f      1f                                                \n\t"
-      " mul.s    %[temp3],    %[temp2],     %[hNlFb]               \n\t"
-      "sub.s     %[temp4],    %[one],       %[temp2]               \n\t"
+        ".set      push                                              \n\t"
+        ".set      noreorder                                         \n\t"
+        "lwc1      %[temp1],    0(%[p_hNl])                          \n\t"
+        "lwc1      %[temp2],    0(%[p_wC])                           \n\t"
+        "c.lt.s    %[hNlFb],    %[temp1]                             \n\t"
+        "bc1f      1f                                                \n\t"
+        " mul.s    %[temp3],    %[temp2],     %[hNlFb]               \n\t"
+        "sub.s     %[temp4],    %[one],       %[temp2]               \n\t"
 #if !defined(MIPS32_R2_LE)
-      "mul.s     %[temp1],    %[temp1],     %[temp4]               \n\t"
-      "add.s     %[temp1],    %[temp3],     %[temp1]               \n\t"
-#else  // #if !defined(MIPS32_R2_LE)
-      "madd.s    %[temp1],    %[temp3],     %[temp1],   %[temp4]   \n\t"
+        "mul.s     %[temp1],    %[temp1],     %[temp4]               \n\t"
+        "add.s     %[temp1],    %[temp3],     %[temp1]               \n\t"
+#else   // #if !defined(MIPS32_R2_LE)
+        "madd.s    %[temp1],    %[temp3],     %[temp1],   %[temp4]   \n\t"
 #endif  // #if !defined(MIPS32_R2_LE)
-      "swc1      %[temp1],    0(%[p_hNl])                          \n\t"
-     "1:                                                           \n\t"
-      "addiu     %[p_wC],     %[p_wC],      4                      \n\t"
-      ".set      pop                                               \n\t"
-      : [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), [temp3] "=&f" (temp3),
-        [temp4] "=&f" (temp4), [p_wC] "+r" (p_WebRtcAec_wC)
-      : [hNlFb] "f" (hNlFb), [one] "f" (one), [p_hNl] "r" (p_hNl)
-      : "memory");
+        "swc1      %[temp1],    0(%[p_hNl])                          \n\t"
+        "1:                                                           \n\t"
+        "addiu     %[p_wC],     %[p_wC],      4                      \n\t"
+        ".set      pop                                               \n\t"
+        : [temp1] "=&f"(temp1), [temp2] "=&f"(temp2), [temp3] "=&f"(temp3),
+          [temp4] "=&f"(temp4), [p_wC] "+r"(p_WebRtcAec_wC)
+        : [hNlFb] "f"(hNlFb), [one] "f"(one), [p_hNl] "r"(p_hNl)
+        : "memory");
 
     hNl[i] = powf(hNl[i], overdrive_scaling * WebRtcAec_overDriveCurve[i]);
   }
@@ -399,22 +395,22 @@
 
   for (int i = 0; i < PART_LEN1; ++i) {
     __asm __volatile(
-      "lwc1      %[temp1],    0(%[p_hNl])              \n\t"
-      "lwc1      %[temp3],    0(%[p_efw1])             \n\t"
-      "lwc1      %[temp2],    0(%[p_efw0])             \n\t"
-      "addiu     %[p_hNl],    %[p_hNl],     4          \n\t"
-      "mul.s     %[temp3],    %[temp3],     %[temp1]   \n\t"
-      "mul.s     %[temp2],    %[temp2],     %[temp1]   \n\t"
-      "addiu     %[p_efw0],   %[p_efw0],    4          \n\t"
-      "addiu     %[p_efw1],   %[p_efw1],    4          \n\t"
-      "neg.s     %[temp4],    %[temp3]                 \n\t"
-      "swc1      %[temp2],    -4(%[p_efw0])            \n\t"
-      "swc1      %[temp4],    -4(%[p_efw1])            \n\t"
-      : [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), [temp3] "=&f" (temp3),
-        [temp4] "=&f" (temp4), [p_efw0] "+r" (p_efw0), [p_efw1] "+r" (p_efw1),
-        [p_hNl] "+r" (p_hNl)
-      :
-      : "memory");
+        "lwc1      %[temp1],    0(%[p_hNl])              \n\t"
+        "lwc1      %[temp3],    0(%[p_efw1])             \n\t"
+        "lwc1      %[temp2],    0(%[p_efw0])             \n\t"
+        "addiu     %[p_hNl],    %[p_hNl],     4          \n\t"
+        "mul.s     %[temp3],    %[temp3],     %[temp1]   \n\t"
+        "mul.s     %[temp2],    %[temp2],     %[temp1]   \n\t"
+        "addiu     %[p_efw0],   %[p_efw0],    4          \n\t"
+        "addiu     %[p_efw1],   %[p_efw1],    4          \n\t"
+        "neg.s     %[temp4],    %[temp3]                 \n\t"
+        "swc1      %[temp2],    -4(%[p_efw0])            \n\t"
+        "swc1      %[temp4],    -4(%[p_efw1])            \n\t"
+        : [temp1] "=&f"(temp1), [temp2] "=&f"(temp2), [temp3] "=&f"(temp3),
+          [temp4] "=&f"(temp4), [p_efw0] "+r"(p_efw0), [p_efw1] "+r"(p_efw1),
+          [p_hNl] "+r"(p_hNl)
+        :
+        : "memory");
   }
 }
 
@@ -433,51 +429,50 @@
 #endif
 
   __asm __volatile(
-    ".set       push                                   \n\t"
-    ".set       noreorder                              \n\t"
-    "1:                                                \n\t"
-    "lwc1       %[f0],     0(%[x_pow])                 \n\t"
-    "lwc1       %[f1],     0(%[ef0])                   \n\t"
-    "lwc1       %[f2],     0(%[ef1])                   \n\t"
-    "add.s      %[f0],     %[f0],       %[fac1]        \n\t"
-    "div.s      %[f1],     %[f1],       %[f0]          \n\t"
-    "div.s      %[f2],     %[f2],       %[f0]          \n\t"
-    "mul.s      %[f0],     %[f1],       %[f1]          \n\t"
+      ".set       push                                   \n\t"
+      ".set       noreorder                              \n\t"
+      "1:                                                \n\t"
+      "lwc1       %[f0],     0(%[x_pow])                 \n\t"
+      "lwc1       %[f1],     0(%[ef0])                   \n\t"
+      "lwc1       %[f2],     0(%[ef1])                   \n\t"
+      "add.s      %[f0],     %[f0],       %[fac1]        \n\t"
+      "div.s      %[f1],     %[f1],       %[f0]          \n\t"
+      "div.s      %[f2],     %[f2],       %[f0]          \n\t"
+      "mul.s      %[f0],     %[f1],       %[f1]          \n\t"
 #if defined(MIPS32_R2_LE)
-    "madd.s     %[f0],     %[f0],       %[f2],   %[f2] \n\t"
+      "madd.s     %[f0],     %[f0],       %[f2],   %[f2] \n\t"
 #else
-    "mul.s      %[f3],     %[f2],       %[f2]          \n\t"
-    "add.s      %[f0],     %[f0],       %[f3]          \n\t"
+      "mul.s      %[f3],     %[f2],       %[f2]          \n\t"
+      "add.s      %[f0],     %[f0],       %[f3]          \n\t"
 #endif
-    "c.le.s     %[f0],     %[err_th2]                  \n\t"
-    "nop                                               \n\t"
-    "bc1t       2f                                     \n\t"
-    " nop                                              \n\t"
-    "sqrt.s     %[f0],     %[f0]                       \n\t"
-    "add.s      %[f0],     %[f0],       %[fac1]        \n\t"
-    "div.s      %[f0],     %[err_th],   %[f0]          \n\t"
-    "mul.s      %[f1],     %[f1],       %[f0]          \n\t"
-    "mul.s      %[f2],     %[f2],       %[f0]          \n\t"
-    "2:                                                \n\t"
-    "mul.s      %[f1],     %[f1],       %[mu]          \n\t"
-    "mul.s      %[f2],     %[f2],       %[mu]          \n\t"
-    "swc1       %[f1],     0(%[ef0])                   \n\t"
-    "swc1       %[f2],     0(%[ef1])                   \n\t"
-    "addiu      %[len],    %[len],      -1             \n\t"
-    "addiu      %[x_pow],  %[x_pow],    4              \n\t"
-    "addiu      %[ef0],    %[ef0],      4              \n\t"
-    "bgtz       %[len],    1b                          \n\t"
-    " addiu     %[ef1],    %[ef1],      4              \n\t"
-    ".set       pop                                    \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
+      "c.le.s     %[f0],     %[err_th2]                  \n\t"
+      "nop                                               \n\t"
+      "bc1t       2f                                     \n\t"
+      " nop                                              \n\t"
+      "sqrt.s     %[f0],     %[f0]                       \n\t"
+      "add.s      %[f0],     %[f0],       %[fac1]        \n\t"
+      "div.s      %[f0],     %[err_th],   %[f0]          \n\t"
+      "mul.s      %[f1],     %[f1],       %[f0]          \n\t"
+      "mul.s      %[f2],     %[f2],       %[f0]          \n\t"
+      "2:                                                \n\t"
+      "mul.s      %[f1],     %[f1],       %[mu]          \n\t"
+      "mul.s      %[f2],     %[f2],       %[mu]          \n\t"
+      "swc1       %[f1],     0(%[ef0])                   \n\t"
+      "swc1       %[f2],     0(%[ef1])                   \n\t"
+      "addiu      %[len],    %[len],      -1             \n\t"
+      "addiu      %[x_pow],  %[x_pow],    4              \n\t"
+      "addiu      %[ef0],    %[ef0],      4              \n\t"
+      "bgtz       %[len],    1b                          \n\t"
+      " addiu     %[ef1],    %[ef1],      4              \n\t"
+      ".set       pop                                    \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2),
 #if !defined(MIPS32_R2_LE)
-      [f3] "=&f" (f3),
+        [f3] "=&f"(f3),
 #endif
-      [x_pow] "+r" (x_pow), [ef0] "+r" (ef0), [ef1] "+r" (ef1),
-      [len] "+r" (len)
-    : [fac1] "f" (fac1), [err_th2] "f" (err_th2), [mu] "f" (mu),
-      [err_th] "f" (error_threshold)
-    : "memory");
+        [x_pow] "+r"(x_pow), [ef0] "+r"(ef0), [ef1] "+r"(ef1), [len] "+r"(len)
+      : [fac1] "f"(fac1), [err_th2] "f"(err_th2), [mu] "f"(mu),
+        [err_th] "f"(error_threshold)
+      : "memory");
 }
 
 void WebRtcAec_InitAec_mips(void) {
diff --git a/modules/audio_processing/aec/aec_core_neon.cc b/modules/audio_processing/aec/aec_core_neon.cc
index 1fbf56b..072bd17 100644
--- a/modules/audio_processing/aec/aec_core_neon.cc
+++ b/modules/audio_processing/aec/aec_core_neon.cc
@@ -38,13 +38,12 @@
   return aRe * bIm + aIm * bRe;
 }
 
-static void FilterFarNEON(int num_partitions,
-                          int x_fft_buf_block_pos,
-                          float x_fft_buf[2]
-                                         [kExtendedNumPartitions * PART_LEN1],
-                          float h_fft_buf[2]
-                                         [kExtendedNumPartitions * PART_LEN1],
-                          float y_fft[2][PART_LEN1]) {
+static void FilterFarNEON(
+    int num_partitions,
+    int x_fft_buf_block_pos,
+    float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float y_fft[2][PART_LEN1]) {
   int i;
   for (i = 0; i < num_partitions; i++) {
     int j;
diff --git a/modules/audio_processing/aec/aec_core_sse2.cc b/modules/audio_processing/aec/aec_core_sse2.cc
index 0532662..ede04dd 100644
--- a/modules/audio_processing/aec/aec_core_sse2.cc
+++ b/modules/audio_processing/aec/aec_core_sse2.cc
@@ -33,13 +33,12 @@
   return aRe * bIm + aIm * bRe;
 }
 
-static void FilterFarSSE2(int num_partitions,
-                          int x_fft_buf_block_pos,
-                          float x_fft_buf[2]
-                                         [kExtendedNumPartitions * PART_LEN1],
-                          float h_fft_buf[2]
-                                         [kExtendedNumPartitions * PART_LEN1],
-                          float y_fft[2][PART_LEN1]) {
+static void FilterFarSSE2(
+    int num_partitions,
+    int x_fft_buf_block_pos,
+    float x_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
+    float y_fft[2][PART_LEN1]) {
   int i;
   for (i = 0; i < num_partitions; i++) {
     int j;
@@ -257,10 +256,10 @@
         _mm_and_ps(a, *(reinterpret_cast<const __m128*>(float_exponent_mask)));
     const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(
         _mm_castps_si128(two_n), shift_exponent_into_top_mantissa));
-    const __m128 n_0 =
-      _mm_or_ps(n_1, *(reinterpret_cast<const __m128*>(eight_biased_exponent)));
-    const __m128 n =
-      _mm_sub_ps(n_0, *(reinterpret_cast<const __m128*>(implicit_leading_one)));
+    const __m128 n_0 = _mm_or_ps(
+        n_1, *(reinterpret_cast<const __m128*>(eight_biased_exponent)));
+    const __m128 n = _mm_sub_ps(
+        n_0, *(reinterpret_cast<const __m128*>(implicit_leading_one)));
 
     // Compute y.
     static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END = {
@@ -269,9 +268,9 @@
         0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000};
     const __m128 mantissa =
         _mm_and_ps(a, *(reinterpret_cast<const __m128*>(mantissa_mask)));
-    const __m128 y =
-        _mm_or_ps(mantissa,
-               *(reinterpret_cast<const __m128*>(zero_biased_exponent_is_one)));
+    const __m128 y = _mm_or_ps(
+        mantissa,
+        *(reinterpret_cast<const __m128*>(zero_biased_exponent_is_one)));
 
     // Approximate log2(y) ~= (y - 1) * pol5(y).
     //    pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
@@ -303,9 +302,8 @@
     const __m128 pol5_y_8 = _mm_mul_ps(pol5_y_7, y);
     const __m128 pol5_y =
         _mm_add_ps(pol5_y_8, *(reinterpret_cast<const __m128*>(C0)));
-    const __m128 y_minus_one =
-        _mm_sub_ps(y,
-               *(reinterpret_cast<const __m128*>(zero_biased_exponent_is_one)));
+    const __m128 y_minus_one = _mm_sub_ps(
+        y, *(reinterpret_cast<const __m128*>(zero_biased_exponent_is_one)));
     const __m128 log2_y = _mm_mul_ps(y_minus_one, pol5_y);
 
     // Combine parts.
diff --git a/modules/audio_processing/aec/echo_cancellation.cc b/modules/audio_processing/aec/echo_cancellation.cc
index 1633068..c8382ec 100644
--- a/modules/audio_processing/aec/echo_cancellation.cc
+++ b/modules/audio_processing/aec/echo_cancellation.cc
@@ -291,7 +291,7 @@
 
   aecpc->farend_started = 1;
   WebRtcAec_SetSystemDelay(aecpc->aec, WebRtcAec_system_delay(aecpc->aec) +
-                           static_cast<int>(newNrOfSamples));
+                                           static_cast<int>(newNrOfSamples));
 
   // Write the time-domain data to |far_pre_buf|.
   WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);
@@ -302,8 +302,8 @@
     {
       float* ptmp = NULL;
       float tmp[PART_LEN2];
-      WebRtc_ReadBuffer(aecpc->far_pre_buf,
-                        reinterpret_cast<void**>(&ptmp), tmp, PART_LEN2);
+      WebRtc_ReadBuffer(aecpc->far_pre_buf, reinterpret_cast<void**>(&ptmp),
+                        tmp, PART_LEN2);
       WebRtcAec_BufferFarendBlock(aecpc->aec, &ptmp[PART_LEN]);
     }
 
@@ -545,9 +545,9 @@
   const float minSkewEst = -0.5f;
   const float maxSkewEst = 1.0f;
 
-  reported_delay_ms =
-      reported_delay_ms > kMaxTrustedDelayMs ? kMaxTrustedDelayMs :
-      reported_delay_ms;
+  reported_delay_ms = reported_delay_ms > kMaxTrustedDelayMs
+                          ? kMaxTrustedDelayMs
+                          : reported_delay_ms;
   // TODO(andrew): we need to investigate if this +10 is really wanted.
   reported_delay_ms += 10;
   aecInst->msInSndCardBuf = reported_delay_ms;
@@ -642,9 +642,8 @@
       // for too long). When the far-end buffer is filled with
       // approximately the same amount of data as reported by the system
       // we end the startup phase.
-      int overhead_elements =
-          WebRtcAec_system_delay(aecInst->aec) / PART_LEN -
-          aecInst->bufSizeStart;
+      int overhead_elements = WebRtcAec_system_delay(aecInst->aec) / PART_LEN -
+                              aecInst->bufSizeStart;
       if (overhead_elements == 0) {
         // Enable the AEC
         aecInst->startup_phase = 0;
@@ -780,10 +779,8 @@
   // We use -1 to signal an initialized state in the "extended" implementation;
   // compensate for that.
   aecInst->filtDelay = aecInst->filtDelay < 0 ? 0 : aecInst->filtDelay;
-  aecInst->filtDelay =
-      WEBRTC_SPL_MAX(0, static_cast<int16_t>(0.8 *
-                                             aecInst->filtDelay +
-                                             0.2 * current_delay));
+  aecInst->filtDelay = WEBRTC_SPL_MAX(
+      0, static_cast<int16_t>(0.8 * aecInst->filtDelay + 0.2 * current_delay));
 
   delay_difference = aecInst->filtDelay - aecInst->knownDelay;
   if (delay_difference > 224) {
@@ -809,8 +806,8 @@
 }
 
 static void EstBufDelayExtended(Aec* aecInst) {
-  int reported_delay = aecInst->msInSndCardBuf * sampMsNb *
-      aecInst->rate_factor;
+  int reported_delay =
+      aecInst->msInSndCardBuf * sampMsNb * aecInst->rate_factor;
   int current_delay = reported_delay - WebRtcAec_system_delay(aecInst->aec);
   int delay_difference = 0;
 
@@ -839,8 +836,8 @@
     aecInst->filtDelay = WEBRTC_SPL_MAX(0, 0.5 * current_delay);
   } else {
     aecInst->filtDelay = WEBRTC_SPL_MAX(
-        0, static_cast<int16_t>(0.95 * aecInst->filtDelay + 0.05 *
-                                current_delay));
+        0,
+        static_cast<int16_t>(0.95 * aecInst->filtDelay + 0.05 * current_delay));
   }
 
   delay_difference = aecInst->filtDelay - aecInst->knownDelay;
diff --git a/modules/audio_processing/aec/system_delay_unittest.cc b/modules/audio_processing/aec/system_delay_unittest.cc
index fc57af8..01119db 100644
--- a/modules/audio_processing/aec/system_delay_unittest.cc
+++ b/modules/audio_processing/aec/system_delay_unittest.cc
@@ -19,8 +19,8 @@
 class SystemDelayTest : public ::testing::Test {
  protected:
   SystemDelayTest();
-  virtual void SetUp();
-  virtual void TearDown();
+  void SetUp() override;
+  void TearDown() override;
 
   // Initialization of AEC handle with respect to |sample_rate_hz|. Since the
   // device sample rate is unimportant we set that value to 48000 Hz.
@@ -104,14 +104,8 @@
 
 void SystemDelayTest::RenderAndCapture(int device_buffer_ms) {
   EXPECT_EQ(0, WebRtcAec_BufferFarend(handle_, far_, samples_per_frame_));
-  EXPECT_EQ(0,
-            WebRtcAec_Process(handle_,
-                              &near_ptr_,
-                              1,
-                              &out_ptr_,
-                              samples_per_frame_,
-                              device_buffer_ms,
-                              0));
+  EXPECT_EQ(0, WebRtcAec_Process(handle_, &near_ptr_, 1, &out_ptr_,
+                                 samples_per_frame_, device_buffer_ms, 0));
 }
 
 size_t SystemDelayTest::BufferFillUp() {
@@ -157,16 +151,15 @@
     EXPECT_GT(kStableConvergenceMs, process_time_ms);
   }
   // Verify that the buffer has been flushed.
-  EXPECT_GE(static_cast<int>(buffer_size),
-            WebRtcAec_system_delay(self_->aec));
+  EXPECT_GE(static_cast<int>(buffer_size), WebRtcAec_system_delay(self_->aec));
 }
 
-  int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms,
-                                              bool extended_filter) {
+int SystemDelayTest::MapBufferSizeToSamples(int size_in_ms,
+                                            bool extended_filter) {
   // If extended_filter is disabled we add an extra 10 ms for the unprocessed
   // frame. That is simply how the algorithm is constructed.
-  return static_cast<int>(
-      (size_in_ms + (extended_filter ? 0 : 10)) * samples_per_frame_ / 10);
+  return static_cast<int>((size_in_ms + (extended_filter ? 0 : 10)) *
+                          samples_per_frame_ / 10);
 }
 
 // The tests should meet basic requirements and not be adjusted to what is
@@ -241,9 +234,9 @@
             static_cast<int>(kDeviceBufMs * samples_per_frame_ / 10);
         EXPECT_GE(average_reported_delay, WebRtcAec_system_delay(self_->aec));
         int lower_bound = WebRtcAec_extended_filter_enabled(self_->aec)
-            ? (average_reported_delay / 2 -
-               rtc::checked_cast<int>(samples_per_frame_))
-            : average_reported_delay * 3 / 4;
+                              ? (average_reported_delay / 2 -
+                                 rtc::checked_cast<int>(samples_per_frame_))
+                              : average_reported_delay * 3 / 4;
         EXPECT_LE(lower_bound, WebRtcAec_system_delay(self_->aec));
       }
     }
@@ -322,14 +315,8 @@
     // can make that assumption since we have a separate stability test.
     int process_time_ms = 0;
     for (; process_time_ms < kStableConvergenceMs; process_time_ms += 10) {
-      EXPECT_EQ(0,
-                WebRtcAec_Process(handle_,
-                                  &near_ptr_,
-                                  1,
-                                  &out_ptr_,
-                                  samples_per_frame_,
-                                  kDeviceBufMs,
-                                  0));
+      EXPECT_EQ(0, WebRtcAec_Process(handle_, &near_ptr_, 1, &out_ptr_,
+                                     samples_per_frame_, kDeviceBufMs, 0));
     }
     // Verify that a buffer size has been established.
     EXPECT_EQ(0, self_->checkBuffSize);
@@ -414,8 +401,8 @@
         for (int j = 0; j < 1000; j++) {
           // Drift = -1 ms per 100 ms of data.
           int device_buf_ms = kDeviceBufMs - (j / 10) + jump;
-          int device_buf = MapBufferSizeToSamples(device_buf_ms,
-                                                  extended_filter == 1);
+          int device_buf =
+              MapBufferSizeToSamples(device_buf_ms, extended_filter == 1);
 
           if (device_buf_ms < 30) {
             // Add 10 ms data, taking affect next frame.
@@ -452,8 +439,8 @@
       for (size_t i = 0; i < kNumSampleRates; i++) {
         Init(kSampleRateHz[i]);
         RunStableStartup();
-        int device_buf = MapBufferSizeToSamples(kDeviceBufMs,
-                                                extended_filter == 1);
+        int device_buf =
+            MapBufferSizeToSamples(kDeviceBufMs, extended_filter == 1);
         // Glitch state.
         for (int j = 0; j < 20; j++) {
           EXPECT_EQ(0,
@@ -513,8 +500,8 @@
     for (size_t i = 0; i < kNumSampleRates; i++) {
       Init(kSampleRateHz[i]);
       RunStableStartup();
-      int device_buf = MapBufferSizeToSamples(kDeviceBufMs,
-                                              extended_filter == 1);
+      int device_buf =
+          MapBufferSizeToSamples(kDeviceBufMs, extended_filter == 1);
 
       // Normal state. We are currently not in a non-causal state.
       bool non_causal = false;
@@ -566,8 +553,8 @@
       for (size_t i = 0; i < kNumSampleRates; i++) {
         Init(kSampleRateHz[i]);
         RunStableStartup();
-        const int device_buf = MapBufferSizeToSamples(kDeviceBufMs,
-                                                      extended_filter == 1);
+        const int device_buf =
+            MapBufferSizeToSamples(kDeviceBufMs, extended_filter == 1);
 
         // Normal state. We are currently not in a non-causal state.
         bool non_causal = false;
diff --git a/modules/audio_processing/aec3/BUILD.gn b/modules/audio_processing/aec3/BUILD.gn
index 9658f6b..f27168d 100644
--- a/modules/audio_processing/aec3/BUILD.gn
+++ b/modules/audio_processing/aec3/BUILD.gn
@@ -6,12 +6,10 @@
 # in the file PATENTS.  All contributing project authors may
 # be found in the AUTHORS file in the root of the source tree.
 
-import("//build/config/arm.gni")
 import("../../../webrtc.gni")
 
 rtc_static_library("aec3") {
   visibility = [ "*" ]
-  allow_poison = [ "audio_codecs" ]  # TODO(bugs.webrtc.org/8396): Remove.
   configs += [ "..:apm_debug_dump" ]
   sources = [
     "adaptive_fir_filter.cc",
@@ -70,6 +68,8 @@
     "matched_filter_lag_aggregator.h",
     "matrix_buffer.cc",
     "matrix_buffer.h",
+    "moving_average.cc",
+    "moving_average.h",
     "render_buffer.cc",
     "render_buffer.h",
     "render_delay_buffer.cc",
@@ -82,6 +82,12 @@
     "render_signal_analyzer.h",
     "residual_echo_estimator.cc",
     "residual_echo_estimator.h",
+    "reverb_model.cc",
+    "reverb_model.h",
+    "reverb_model_estimator.cc",
+    "reverb_model_estimator.h",
+    "reverb_model_fallback.cc",
+    "reverb_model_fallback.h",
     "shadow_filter_update_gain.cc",
     "shadow_filter_update_gain.h",
     "skew_estimator.cc",
@@ -90,7 +96,10 @@
     "stationarity_estimator.h",
     "subtractor.cc",
     "subtractor.h",
+    "subtractor_output.cc",
     "subtractor_output.h",
+    "subtractor_output_analyzer.cc",
+    "subtractor_output_analyzer.h",
     "suppression_filter.cc",
     "suppression_filter.h",
     "suppression_gain.cc",
@@ -104,12 +113,10 @@
 
   defines = []
   deps = [
-    "..:aec_core",
     "..:apm_logging",
     "..:audio_processing",
     "../../..:typedefs",
     "../../../api:array_view",
-    "../../../api:optional",
     "../../../api/audio:aec3_config",
     "../../../api/audio:echo_control",
     "../../../common_audio:common_audio_c",
@@ -117,10 +124,11 @@
     "../../../rtc_base:rtc_base_approved",
     "../../../rtc_base:safe_minmax",
     "../../../system_wrappers:cpu_features_api",
+    "../../../system_wrappers:field_trial_api",
     "../../../system_wrappers:metrics_api",
+    "../utility:ooura_fft",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
-
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
 if (rtc_include_tests) {
@@ -129,9 +137,13 @@
 
     configs += [ "..:apm_debug_dump" ]
     sources = [
+      "mock/mock_block_processor.cc",
       "mock/mock_block_processor.h",
+      "mock/mock_echo_remover.cc",
       "mock/mock_echo_remover.h",
+      "mock/mock_render_delay_buffer.cc",
       "mock/mock_render_delay_buffer.h",
+      "mock/mock_render_delay_controller.cc",
       "mock/mock_render_delay_controller.h",
     ]
 
@@ -142,13 +154,13 @@
       "..:audio_processing_unittests",
       "../../..:typedefs",
       "../../../api:array_view",
-      "../../../api:optional",
       "../../../api/audio:aec3_config",
       "../../../rtc_base:checks",
       "../../../rtc_base:rtc_base_approved",
       "../../../rtc_base:safe_minmax",
       "../../../system_wrappers:cpu_features_api",
       "../../../test:test_support",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
 
     defines = []
@@ -176,12 +188,14 @@
         "main_filter_update_gain_unittest.cc",
         "matched_filter_lag_aggregator_unittest.cc",
         "matched_filter_unittest.cc",
+        "moving_average_unittest.cc",
         "render_buffer_unittest.cc",
         "render_delay_buffer_unittest.cc",
         "render_delay_controller_metrics_unittest.cc",
         "render_delay_controller_unittest.cc",
         "render_signal_analyzer_unittest.cc",
         "residual_echo_estimator_unittest.cc",
+        "reverb_model_estimator_unittest.cc",
         "shadow_filter_update_gain_unittest.cc",
         "skew_estimator_unittest.cc",
         "subtractor_unittest.cc",
@@ -190,12 +204,5 @@
         "vector_math_unittest.cc",
       ]
     }
-
-    if ((!build_with_chromium || is_win) && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-    }
-
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
   }
 }
diff --git a/modules/audio_processing/aec3/adaptive_fir_filter.cc b/modules/audio_processing/aec3/adaptive_fir_filter.cc
index f44fe3d..377436c 100644
--- a/modules/audio_processing/aec3/adaptive_fir_filter.cc
+++ b/modules/audio_processing/aec3/adaptive_fir_filter.cc
@@ -616,4 +616,27 @@
                                 : 0;
 }
 
+void AdaptiveFirFilter::ScaleFilter(float factor) {
+  for (auto& H : H_) {
+    for (auto& re : H.re) {
+      re *= factor;
+    }
+    for (auto& im : H.im) {
+      im *= factor;
+    }
+  }
+  for (auto& h : h_) {
+    h *= factor;
+  }
+}
+
+// Set the filter coefficients.
+void AdaptiveFirFilter::SetFilter(const std::vector<FftData>& H) {
+  const size_t num_partitions = std::min(H_.size(), H.size());
+  for (size_t k = 0; k < num_partitions; ++k) {
+    std::copy(H[k].re.begin(), H[k].re.end(), H_[k].re.begin());
+    std::copy(H[k].im.begin(), H[k].im.end(), H_[k].im.begin());
+  }
+}
+
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/adaptive_fir_filter.h b/modules/audio_processing/aec3/adaptive_fir_filter.h
index 1e128b5..9b6ca90 100644
--- a/modules/audio_processing/aec3/adaptive_fir_filter.h
+++ b/modules/audio_processing/aec3/adaptive_fir_filter.h
@@ -143,6 +143,15 @@
     h_.resize(current_size);
   }
 
+  // Scale the filter impulse response and spectrum by a factor.
+  void ScaleFilter(float factor);
+
+  // Set the filter coefficients.
+  void SetFilter(const std::vector<FftData>& H);
+
+  // Gets the filter coefficients.
+  const std::vector<FftData>& GetFilter() const { return H_; }
+
  private:
   // Constrain the filter partitions in a cyclic manner.
   void Constrain();
diff --git a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
index 9561dff..6c441f3 100644
--- a/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
+++ b/modules/audio_processing/aec3/adaptive_fir_filter_unittest.cc
@@ -73,7 +73,7 @@
     }
     render_delay_buffer->PrepareCaptureProcessing();
   }
-  const auto& render_buffer = render_delay_buffer->GetRenderBuffer();
+  auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
 
   for (size_t j = 0; j < G.re.size(); ++j) {
     G.re[j] = j / 10001.f;
@@ -183,7 +183,7 @@
         render_delay_buffer->Reset();
       }
       render_delay_buffer->PrepareCaptureProcessing();
-      const auto& render_buffer = render_delay_buffer->GetRenderBuffer();
+      auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
 
       ApplyFilter_SSE2(*render_buffer, H_SSE2, &S_SSE2);
       ApplyFilter(*render_buffer, H_C, &S_C);
@@ -325,10 +325,10 @@
   std::vector<float> y(kBlockSize, 0.f);
   AecState aec_state(EchoCanceller3Config{});
   RenderSignalAnalyzer render_signal_analyzer(config);
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   std::vector<float> e(kBlockSize, 0.f);
   std::array<float, kFftLength> s_scratch;
-  std::array<float, kBlockSize> s;
+  SubtractorOutput output;
   FftData S;
   FftData G;
   FftData E;
@@ -342,6 +342,7 @@
   Y2.fill(0.f);
   E2_main.fill(0.f);
   E2_shadow.fill(0.f);
+  output.Reset();
 
   constexpr float kScale = 1.0f / kFftLengthBy2;
 
@@ -357,9 +358,8 @@
 
       RandomizeSampleVector(&random_generator, n);
       static constexpr float kNoiseScaling = 1.f / 100.f;
-      std::transform(
-          y.begin(), y.end(), n.begin(), y.begin(),
-          [](float a, float b) { return a + b * kNoiseScaling; });
+      std::transform(y.begin(), y.end(), n.begin(), y.begin(),
+                     [](float a, float b) { return a + b * kNoiseScaling; });
 
       x_hp_filter.Process(x[0]);
       y_hp_filter.Process(y);
@@ -369,7 +369,7 @@
         render_delay_buffer->Reset();
       }
       render_delay_buffer->PrepareCaptureProcessing();
-      const auto& render_buffer = render_delay_buffer->GetRenderBuffer();
+      auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
 
       render_signal_analyzer.Update(*render_buffer,
                                     aec_state.FilterDelayBlocks());
@@ -383,7 +383,7 @@
                     [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
       fft.ZeroPaddedFft(e, Aec3Fft::Window::kRectangular, &E);
       for (size_t k = 0; k < kBlockSize; ++k) {
-        s[k] = kScale * s_scratch[k + kFftLengthBy2];
+        output.s_main[k] = kScale * s_scratch[k + kFftLengthBy2];
       }
 
       std::array<float, kFftLengthBy2Plus1> render_power;
@@ -395,8 +395,8 @@
           false, EchoPathVariability::DelayAdjustment::kNone, false));
 
       aec_state.Update(delay_estimate, filter.FilterFrequencyResponse(),
-                       filter.FilterImpulseResponse(), true, false,
-                       *render_buffer, E2_main, Y2, s);
+                       filter.FilterImpulseResponse(), *render_buffer, E2_main,
+                       Y2, output, y);
     }
     // Verify that the filter is able to perform well.
     EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
diff --git a/modules/audio_processing/aec3/aec3_common.cc b/modules/audio_processing/aec3/aec3_common.cc
index 7becce4..3e60b46 100644
--- a/modules/audio_processing/aec3/aec3_common.cc
+++ b/modules/audio_processing/aec3/aec3_common.cc
@@ -10,8 +10,10 @@
 
 #include "modules/audio_processing/aec3/aec3_common.h"
 
-#include "typedefs.h"  // NOLINT(build/include)
 #include "system_wrappers/include/cpu_features_wrapper.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+#include "rtc_base/checks.h"
 
 namespace webrtc {
 
@@ -29,4 +31,25 @@
   return Aec3Optimization::kNone;
 }
 
+float FastApproxLog2f(const float in) {
+  RTC_DCHECK_GT(in, .0f);
+  // Read and interpret float as uint32_t and then cast to float.
+  // This is done to extract the exponent (bits 30 - 23).
+  // "Right shift" of the exponent is then performed by multiplying
+  // with the constant (1/2^23). Finally, we subtract a constant to
+  // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
+  union {
+    float dummy;
+    uint32_t a;
+  } x = {in};
+  float out = x.a;
+  out *= 1.1920929e-7f;  // 1/2^23
+  out -= 126.942695f;    // Remove bias.
+  return out;
+}
+
+float Log2TodB(const float in_log2) {
+  return 3.0102999566398121 * in_log2;
+}
+
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/aec3_common.h b/modules/audio_processing/aec3/aec3_common.h
index 47f0784..6422a52 100644
--- a/modules/audio_processing/aec3/aec3_common.h
+++ b/modules/audio_processing/aec3/aec3_common.h
@@ -88,6 +88,12 @@
 // Detects what kind of optimizations to use for the code.
 Aec3Optimization DetectOptimization();
 
+// Computes the log2 of the input in a fast an approximate manner.
+float FastApproxLog2f(const float in);
+
+// Returns dB from a power quantity expressed in log2.
+float Log2TodB(const float in_log2);
+
 static_assert(1 << kBlockSizeLog2 == kBlockSize,
               "Proper number of shifts for blocksize");
 
diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc
index 5f36e65..d470611 100644
--- a/modules/audio_processing/aec3/aec_state.cc
+++ b/modules/audio_processing/aec3/aec_state.cc
@@ -15,14 +15,98 @@
 #include <numeric>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/atomicops.h"
 #include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
 
+bool EnableTransparentMode() {
+  return !field_trial::IsEnabled("WebRTC-Aec3TransparentModeKillSwitch");
+}
+
+bool EnableStationaryRenderImprovements() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3StationaryRenderImprovementsKillSwitch");
+}
+
+bool EnableEnforcingDelayAfterRealignment() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3EnforceDelayAfterRealignmentKillSwitch");
+}
+
+bool EnableLinearModeWithDivergedFilter() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3LinearModeWithDivergedFilterKillSwitch");
+}
+
+bool EnableEarlyFilterUsage() {
+  return !field_trial::IsEnabled("WebRTC-Aec3EarlyLinearFilterUsageKillSwitch");
+}
+
+bool EnableShortInitialState() {
+  return !field_trial::IsEnabled("WebRTC-Aec3ShortInitialStateKillSwitch");
+}
+
+bool EnableNoWaitForAlignment() {
+  return !field_trial::IsEnabled("WebRTC-Aec3NoAlignmentWaitKillSwitch");
+}
+
+bool EnableConvergenceTriggeredLinearMode() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3ConvergenceTriggingLinearKillSwitch");
+}
+
+bool EnableUncertaintyUntilSufficientAdapted() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3ErleUncertaintyUntilSufficientlyAdaptedKillSwitch");
+}
+
+bool TreatTransparentModeAsNonlinear() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3TreatTransparentModeAsNonlinearKillSwitch");
+}
+
+bool LowUncertaintyBeforeConvergence() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3LowUncertaintyBeforeConvergenceKillSwitch");
+}
+
+bool MediumUncertaintyBeforeConvergence() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3MediumUncertaintyBeforeConvergenceKillSwitch");
+}
+
+bool EarlyEntryToConvergedMode() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3EarlyEntryToConvergedModeKillSwitch");
+}
+
+bool ConservativeFilterDivergence() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3ConservativeFilterDivergenceKillSwitch");
+}
+
+bool UseEarlyLimiterDeactivation() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3EarlyLimiterDeactivationKillSwitch");
+}
+
+float UncertaintyBeforeConvergence() {
+  if (LowUncertaintyBeforeConvergence()) {
+    return 1.f;
+  } else if (MediumUncertaintyBeforeConvergence()) {
+    return 4.f;
+  } else {
+    return 10.f;
+  }
+}
+
 float ComputeGainRampupIncrease(const EchoCanceller3Config& config) {
   const auto& c = config.echo_removal_control.gain_rampup;
   return powf(1.f / c.first_non_zero_gain, 1.f / c.non_zero_gain_blocks);
@@ -38,16 +122,35 @@
 AecState::AecState(const EchoCanceller3Config& config)
     : data_dumper_(
           new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
-      erle_estimator_(config.erle.min, config.erle.max_l, config.erle.max_h),
       config_(config),
+      allow_transparent_mode_(EnableTransparentMode()),
+      use_stationary_properties_(
+          EnableStationaryRenderImprovements() &&
+          config_.echo_audibility.use_stationary_properties),
+      enforce_delay_after_realignment_(EnableEnforcingDelayAfterRealignment()),
+      allow_linear_mode_with_diverged_filter_(
+          EnableLinearModeWithDivergedFilter()),
+      early_filter_usage_activated_(EnableEarlyFilterUsage()),
+      use_short_initial_state_(EnableShortInitialState()),
+      convergence_trigger_linear_mode_(EnableConvergenceTriggeredLinearMode()),
+      no_alignment_required_for_linear_mode_(EnableNoWaitForAlignment()),
+      use_uncertainty_until_sufficiently_adapted_(
+          EnableUncertaintyUntilSufficientAdapted()),
+      transparent_mode_enforces_nonlinear_mode_(
+          TreatTransparentModeAsNonlinear()),
+      uncertainty_before_convergence_(UncertaintyBeforeConvergence()),
+      early_entry_to_converged_mode_(EarlyEntryToConvergedMode()),
+      conservative_filter_divergence_(ConservativeFilterDivergence()),
+      early_limiter_deactivation_(UseEarlyLimiterDeactivation()),
+      erle_estimator_(config.erle.min, config.erle.max_l, config.erle.max_h),
       max_render_(config_.filter.main.length_blocks, 0.f),
-      reverb_decay_(fabsf(config_.ep_strength.default_len)),
       gain_rampup_increase_(ComputeGainRampupIncrease(config_)),
       suppression_gain_limiter_(config_),
       filter_analyzer_(config_),
       blocks_since_converged_filter_(kBlocksSinceConvergencedFilterInit),
       active_blocks_since_consistent_filter_estimate_(
-          kBlocksSinceConsistentEstimateInit) {}
+          kBlocksSinceConsistentEstimateInit),
+      reverb_model_estimator_(config) {}
 
 AecState::~AecState() = default;
 
@@ -57,6 +160,7 @@
     filter_analyzer_.Reset();
     blocks_since_last_saturation_ = 0;
     usable_linear_estimate_ = false;
+    diverged_linear_filter_ = false;
     capture_signal_saturation_ = false;
     echo_saturation_ = false;
     std::fill(max_render_.begin(), max_render_.end(), 0.f);
@@ -73,46 +177,51 @@
 
   // TODO(peah): Refine the reset scheme according to the type of gain and
   // delay adjustment.
-  if (echo_path_variability.gain_change) {
+
+  if (echo_path_variability.delay_change !=
+      EchoPathVariability::DelayAdjustment::kNone) {
     full_reset();
   }
 
-  if (echo_path_variability.delay_change !=
-      EchoPathVariability::DelayAdjustment::kBufferReadjustment) {
-    full_reset();
-  } else if (echo_path_variability.delay_change !=
-             EchoPathVariability::DelayAdjustment::kBufferFlush) {
-    full_reset();
-  } else if (echo_path_variability.delay_change !=
-             EchoPathVariability::DelayAdjustment::kDelayReset) {
-    full_reset();
-  } else if (echo_path_variability.delay_change !=
-             EchoPathVariability::DelayAdjustment::kNewDetectedDelay) {
-    full_reset();
-  } else if (echo_path_variability.gain_change) {
-    blocks_since_reset_ = kNumBlocksPerSecond;
-  }
+  subtractor_output_analyzer_.HandleEchoPathChange();
 }
 
 void AecState::Update(
-    const rtc::Optional<DelayEstimate>& external_delay,
+    const absl::optional<DelayEstimate>& external_delay,
     const std::vector<std::array<float, kFftLengthBy2Plus1>>&
         adaptive_filter_frequency_response,
     const std::vector<float>& adaptive_filter_impulse_response,
-    bool converged_filter,
-    bool diverged_filter,
     const RenderBuffer& render_buffer,
     const std::array<float, kFftLengthBy2Plus1>& E2_main,
     const std::array<float, kFftLengthBy2Plus1>& Y2,
-    const std::array<float, kBlockSize>& s) {
+    const SubtractorOutput& subtractor_output,
+    rtc::ArrayView<const float> y) {
+  // Analyze the filter output.
+  subtractor_output_analyzer_.Update(subtractor_output);
+
+  const bool converged_filter = subtractor_output_analyzer_.ConvergedFilter();
+  const bool diverged_filter = subtractor_output_analyzer_.DivergedFilter();
+
   // Analyze the filter and compute the delays.
-  filter_analyzer_.Update(adaptive_filter_impulse_response, render_buffer);
+  filter_analyzer_.Update(adaptive_filter_impulse_response,
+                          adaptive_filter_frequency_response, render_buffer);
   filter_delay_blocks_ = filter_analyzer_.DelayBlocks();
+  if (enforce_delay_after_realignment_) {
+    if (external_delay &&
+        (!external_delay_ || external_delay_->delay != external_delay->delay)) {
+      frames_since_external_delay_change_ = 0;
+      external_delay_ = external_delay;
+    }
+    if (blocks_with_proper_filter_adaptation_ < 2 * kNumBlocksPerSecond &&
+        external_delay_) {
+      filter_delay_blocks_ = config_.delay.delay_headroom_blocks;
+    }
+  }
 
   if (filter_analyzer_.Consistent()) {
     internal_delay_ = filter_analyzer_.DelayBlocks();
   } else {
-    internal_delay_ = rtc::nullopt;
+    internal_delay_ = absl::nullopt;
   }
 
   external_delay_seen_ = external_delay_seen_ || external_delay;
@@ -131,29 +240,42 @@
   // an initial echo burst.
   suppression_gain_limiter_.Update(render_buffer.GetRenderActivity(),
                                    transparent_mode_);
+  if (converged_filter && early_limiter_deactivation_) {
+    suppression_gain_limiter_.Deactivate();
+  }
 
   if (UseStationaryProperties()) {
     // Update the echo audibility evaluator.
-    echo_audibility_.Update(render_buffer, FilterDelayBlocks(),
-                            external_delay_seen_);
+    echo_audibility_.Update(
+        render_buffer, FilterDelayBlocks(), external_delay_seen_,
+        config_.ep_strength.reverb_based_on_render ? ReverbDecay() : 0.f);
   }
 
   // Update the ERL and ERLE measures.
-  if (converged_filter && blocks_since_reset_ >= 2 * kNumBlocksPerSecond) {
+  if (blocks_since_reset_ >= 2 * kNumBlocksPerSecond) {
     const auto& X2 = render_buffer.Spectrum(filter_delay_blocks_);
-    erle_estimator_.Update(X2, Y2, E2_main);
-    erl_estimator_.Update(X2, Y2);
+    erle_estimator_.Update(X2, Y2, E2_main, converged_filter);
+    if (converged_filter) {
+      erl_estimator_.Update(X2, Y2);
+    }
   }
 
   // Detect and flag echo saturation.
-  // TODO(peah): Add the delay in this computation to ensure that the render and
-  // capture signals are properly aligned.
   if (config_.ep_strength.echo_can_saturate) {
     echo_saturation_ = DetectEchoSaturation(x, EchoPathGain());
   }
 
-  bool filter_has_had_time_to_converge =
-      blocks_with_proper_filter_adaptation_ >= 1.5f * kNumBlocksPerSecond;
+  if (early_filter_usage_activated_) {
+    filter_has_had_time_to_converge_ =
+        blocks_with_proper_filter_adaptation_ >= 0.8f * kNumBlocksPerSecond;
+  } else {
+    filter_has_had_time_to_converge_ =
+        blocks_with_proper_filter_adaptation_ >= 1.5f * kNumBlocksPerSecond;
+  }
+
+  if (converged_filter && early_entry_to_converged_mode_) {
+    filter_has_had_time_to_converge_ = true;
+  }
 
   if (!filter_should_have_converged_) {
     filter_should_have_converged_ =
@@ -161,8 +283,13 @@
   }
 
   // Flag whether the initial state is still active.
-  initial_state_ =
-      blocks_with_proper_filter_adaptation_ < 5 * kNumBlocksPerSecond;
+  if (use_short_initial_state_) {
+    initial_state_ =
+        blocks_with_proper_filter_adaptation_ < 2.5f * kNumBlocksPerSecond;
+  } else {
+    initial_state_ =
+        blocks_with_proper_filter_adaptation_ < 5 * kNumBlocksPerSecond;
+  }
 
   // Update counters for the filter divergence and convergence.
   diverged_blocks_ = diverged_filter ? diverged_blocks_ + 1 : 0;
@@ -223,25 +350,55 @@
   transparent_mode_ =
       transparent_mode_ &&
       (consistent_filter_estimate_not_seen || !converged_filter_seen_);
-  transparent_mode_ = transparent_mode_ &&
-                      (filter_should_have_converged_ ||
-                       (!external_delay_seen_ &&
-                        capture_block_counter_ > 10 * kNumBlocksPerSecond));
+  transparent_mode_ = transparent_mode_ && filter_should_have_converged_;
+  transparent_mode_ = transparent_mode_ && allow_transparent_mode_;
 
   usable_linear_estimate_ = !echo_saturation_;
-  usable_linear_estimate_ =
-      usable_linear_estimate_ && filter_has_had_time_to_converge;
-  usable_linear_estimate_ =
-      usable_linear_estimate_ && recently_converged_filter;
-  usable_linear_estimate_ = usable_linear_estimate_ && !diverged_filter;
-  usable_linear_estimate_ = usable_linear_estimate_ && external_delay;
+
+  if (convergence_trigger_linear_mode_) {
+    usable_linear_estimate_ =
+        usable_linear_estimate_ &&
+        ((filter_has_had_time_to_converge_ && external_delay) ||
+         converged_filter_seen_);
+  } else {
+    usable_linear_estimate_ =
+        usable_linear_estimate_ && filter_has_had_time_to_converge_;
+  }
+
+  if (!no_alignment_required_for_linear_mode_) {
+    usable_linear_estimate_ = usable_linear_estimate_ && external_delay;
+  }
+
+  if (!config_.echo_removal_control.linear_and_stable_echo_path) {
+    usable_linear_estimate_ =
+        usable_linear_estimate_ && recently_converged_filter;
+    if (!allow_linear_mode_with_diverged_filter_) {
+      usable_linear_estimate_ = usable_linear_estimate_ && !diverged_filter;
+    }
+  }
+  if (transparent_mode_enforces_nonlinear_mode_) {
+    usable_linear_estimate_ = usable_linear_estimate_ && !TransparentMode();
+  }
 
   use_linear_filter_output_ = usable_linear_estimate_ && !TransparentMode();
 
-  data_dumper_->DumpRaw("aec3_erle", Erle());
-  data_dumper_->DumpRaw("aec3_erle_onset", erle_estimator_.ErleOnsets());
+  if (conservative_filter_divergence_) {
+    diverged_linear_filter_ =
+        subtractor_output_analyzer_.SeverelyDivergedFilter() &&
+        active_render_block;
+  } else {
+    diverged_linear_filter_ = diverged_filter;
+  }
+
+  reverb_model_estimator_.Update(
+      adaptive_filter_impulse_response, adaptive_filter_frequency_response,
+      erle_estimator_.GetInstLinearQualityEstimate(), filter_delay_blocks_,
+      usable_linear_estimate_, config_.ep_strength.default_len,
+      IsBlockStationary());
+
+  erle_estimator_.Dump(data_dumper_);
+  reverb_model_estimator_.Dump(data_dumper_);
   data_dumper_->DumpRaw("aec3_erl", Erl());
-  data_dumper_->DumpRaw("aec3_erle_time_domain", ErleTimeDomain());
   data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
   data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
   data_dumper_->DumpRaw("aec3_transparent_mode", transparent_mode_);
@@ -265,195 +422,13 @@
   data_dumper_->DumpRaw("aec3_filter_should_have_converged",
                         filter_should_have_converged_);
   data_dumper_->DumpRaw("aec3_filter_has_had_time_to_converge",
-                        filter_has_had_time_to_converge);
+                        filter_has_had_time_to_converge_);
   data_dumper_->DumpRaw("aec3_recently_converged_filter",
                         recently_converged_filter);
-}
+  data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
+                        IsSuppressionGainLimitActive());
+  data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est", GetFreqRespTail());
 
-void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
-  // Echo tail estimation enabled if the below variable is set as negative.
-  if (config_.ep_strength.default_len > 0.f) {
-    return;
-  }
-
-  if ((!(filter_delay_blocks_ && usable_linear_estimate_)) ||
-      (filter_delay_blocks_ >
-       static_cast<int>(config_.filter.main.length_blocks) - 4)) {
-    return;
-  }
-
-  constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;
-
-  // Form the data to match against by squaring the impulse response
-  // coefficients.
-  std::array<float, GetTimeDomainLength(kMaxAdaptiveFilterLength)>
-      matching_data_data;
-  RTC_DCHECK_LE(GetTimeDomainLength(config_.filter.main.length_blocks),
-                matching_data_data.size());
-  rtc::ArrayView<float> matching_data(
-      matching_data_data.data(),
-      GetTimeDomainLength(config_.filter.main.length_blocks));
-  std::transform(impulse_response.begin(), impulse_response.end(),
-                 matching_data.begin(), [](float a) { return a * a; });
-
-  if (current_reverb_decay_section_ < config_.filter.main.length_blocks) {
-    // Update accumulated variables for the current filter section.
-
-    const size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;
-
-    RTC_DCHECK_GT(matching_data.size(), start_index);
-    RTC_DCHECK_GE(matching_data.size(), start_index + kFftLengthBy2);
-    float section_energy =
-        std::accumulate(matching_data.begin() + start_index,
-                        matching_data.begin() + start_index + kFftLengthBy2,
-                        0.f) *
-        kOneByFftLengthBy2;
-
-    section_energy = std::max(
-        section_energy, 1e-32f);  // Regularization to avoid division by 0.
-
-    RTC_DCHECK_LT(current_reverb_decay_section_, block_energies_.size());
-    const float energy_ratio =
-        block_energies_[current_reverb_decay_section_] / section_energy;
-
-    main_filter_is_adapting_ = main_filter_is_adapting_ ||
-                               (energy_ratio > 1.1f || energy_ratio < 0.9f);
-
-    // Count consecutive number of "good" filter sections, where "good" means:
-    // 1) energy is above noise floor.
-    // 2) energy of current section has not changed too much from last check.
-    if (!found_end_of_reverb_decay_ && section_energy > tail_energy_ &&
-        !main_filter_is_adapting_) {
-      ++num_reverb_decay_sections_next_;
-    } else {
-      found_end_of_reverb_decay_ = true;
-    }
-
-    block_energies_[current_reverb_decay_section_] = section_energy;
-
-    if (num_reverb_decay_sections_ > 0) {
-      // Linear regression of log squared magnitude of impulse response.
-      for (size_t i = 0; i < kFftLengthBy2; i++) {
-        auto fast_approx_log2f = [](const float in) {
-          RTC_DCHECK_GT(in, .0f);
-          // Read and interpret float as uint32_t and then cast to float.
-          // This is done to extract the exponent (bits 30 - 23).
-          // "Right shift" of the exponent is then performed by multiplying
-          // with the constant (1/2^23). Finally, we subtract a constant to
-          // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
-          union {
-            float dummy;
-            uint32_t a;
-          } x = {in};
-          float out = x.a;
-          out *= 1.1920929e-7f;  // 1/2^23
-          out -= 126.942695f;  // Remove bias.
-          return out;
-        };
-        RTC_DCHECK_GT(matching_data.size(), start_index + i);
-        float z = fast_approx_log2f(matching_data[start_index + i]);
-        accumulated_nz_ += accumulated_count_ * z;
-        ++accumulated_count_;
-      }
-    }
-
-    num_reverb_decay_sections_ =
-        num_reverb_decay_sections_ > 0 ? num_reverb_decay_sections_ - 1 : 0;
-    ++current_reverb_decay_section_;
-
-  } else {
-    constexpr float kMaxDecay = 0.95f;  // ~1 sec min RT60.
-    constexpr float kMinDecay = 0.02f;  // ~15 ms max RT60.
-
-    // Accumulated variables throughout whole filter.
-
-    // Solve for decay rate.
-
-    float decay = reverb_decay_;
-
-    if (accumulated_nn_ != 0.f) {
-      const float exp_candidate = -accumulated_nz_ / accumulated_nn_;
-      decay = powf(2.0f, -exp_candidate * kFftLengthBy2);
-      decay = std::min(decay, kMaxDecay);
-      decay = std::max(decay, kMinDecay);
-    }
-
-    // Filter tail energy (assumed to be noise).
-
-    constexpr size_t kTailLength = kFftLength;
-    constexpr float k1ByTailLength = 1.f / kTailLength;
-    const size_t tail_index =
-        GetTimeDomainLength(config_.filter.main.length_blocks) - kTailLength;
-
-    RTC_DCHECK_GT(matching_data.size(), tail_index);
-    tail_energy_ = std::accumulate(matching_data.begin() + tail_index,
-                                   matching_data.end(), 0.f) *
-                   k1ByTailLength;
-
-    // Update length of decay.
-    num_reverb_decay_sections_ = num_reverb_decay_sections_next_;
-    num_reverb_decay_sections_next_ = 0;
-    // Must have enough data (number of sections) in order
-    // to estimate decay rate.
-    if (num_reverb_decay_sections_ < 5) {
-      num_reverb_decay_sections_ = 0;
-    }
-
-    const float N = num_reverb_decay_sections_ * kFftLengthBy2;
-    accumulated_nz_ = 0.f;
-    const float k1By12 = 1.f / 12.f;
-    // Arithmetic sum $2 \sum_{i=0}^{(N-1)/2}i^2$ calculated directly.
-    accumulated_nn_ = N * (N * N - 1.0f) * k1By12;
-    accumulated_count_ = -N * 0.5f;
-    // Linear regression approach assumes symmetric index around 0.
-    accumulated_count_ += 0.5f;
-
-    // Identify the peak index of the impulse response.
-    const size_t peak_index = std::distance(
-        matching_data.begin(),
-        std::max_element(matching_data.begin(), matching_data.end()));
-
-    current_reverb_decay_section_ = peak_index * kOneByFftLengthBy2 + 3;
-    // Make sure we're not out of bounds.
-    if (current_reverb_decay_section_ + 1 >=
-        config_.filter.main.length_blocks) {
-      current_reverb_decay_section_ = config_.filter.main.length_blocks;
-    }
-    size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;
-    float first_section_energy =
-        std::accumulate(matching_data.begin() + start_index,
-                        matching_data.begin() + start_index + kFftLengthBy2,
-                        0.f) *
-        kOneByFftLengthBy2;
-
-    // To estimate the reverb decay, the energy of the first filter section
-    // must be substantially larger than the last.
-    // Also, the first filter section energy must not deviate too much
-    // from the max peak.
-    bool main_filter_has_reverb = first_section_energy > 4.f * tail_energy_;
-    bool main_filter_is_sane = first_section_energy > 2.f * tail_energy_ &&
-                               matching_data[peak_index] < 100.f;
-
-    // Not detecting any decay, but tail is over noise - assume max decay.
-    if (num_reverb_decay_sections_ == 0 && main_filter_is_sane &&
-        main_filter_has_reverb) {
-      decay = kMaxDecay;
-    }
-
-    if (!main_filter_is_adapting_ && main_filter_is_sane &&
-        num_reverb_decay_sections_ > 0) {
-      decay = std::max(.97f * reverb_decay_, decay);
-      reverb_decay_ -= .1f * (reverb_decay_ - decay);
-    }
-
-    found_end_of_reverb_decay_ =
-        !(main_filter_is_sane && main_filter_has_reverb);
-    main_filter_is_adapting_ = false;
-  }
-
-  data_dumper_->DumpRaw("aec3_reverb_decay", reverb_decay_);
-  data_dumper_->DumpRaw("aec3_reverb_tail_energy", tail_energy_);
-  data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit());
 }
 
 bool AecState::DetectActiveRender(rtc::ArrayView<const float> x) const {
diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h
index ebfa62f..408f9b8 100644
--- a/modules/audio_processing/aec3/aec_state.h
+++ b/modules/audio_processing/aec3/aec_state.h
@@ -17,9 +17,9 @@
 #include <memory>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/delay_estimate.h"
 #include "modules/audio_processing/aec3/echo_audibility.h"
@@ -28,6 +28,9 @@
 #include "modules/audio_processing/aec3/erle_estimator.h"
 #include "modules/audio_processing/aec3/filter_analyzer.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/reverb_model_estimator.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
+#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
 #include "modules/audio_processing/aec3/suppression_gain_limiter.h"
 #include "rtc_base/constructormagic.h"
 
@@ -49,7 +52,7 @@
   bool UseLinearFilterOutput() const { return use_linear_filter_output_; }
 
   // Returns the estimated echo path gain.
-  bool EchoPathGain() const { return filter_analyzer_.Gain(); }
+  float EchoPathGain() const { return filter_analyzer_.Gain(); }
 
   // Returns whether the render signal is currently active.
   bool ActiveRender() const { return blocks_with_active_render_ > 200; }
@@ -62,8 +65,17 @@
 
   // Returns whether the stationary properties of the signals are used in the
   // aec.
-  bool UseStationaryProperties() const {
-    return config_.echo_audibility.use_stationary_properties;
+  bool UseStationaryProperties() const { return use_stationary_properties_; }
+
+  // Returns true if the current render block is estimated as stationary.
+  bool IsBlockStationary() const {
+    if (UseStationaryProperties()) {
+      return echo_audibility_.IsBlockStationary();
+    } else {
+      // Assume that a non stationary block when the use of
+      // stationary properties are not enabled.
+      return false;
+    }
   }
 
   // Returns the ERLE.
@@ -71,8 +83,23 @@
     return erle_estimator_.Erle();
   }
 
-  // Returns the time-domain ERLE.
-  float ErleTimeDomain() const { return erle_estimator_.ErleTimeDomain(); }
+  // Returns any uncertainty in the ERLE estimate.
+  absl::optional<float> ErleUncertainty() const {
+    if (allow_linear_mode_with_diverged_filter_ && diverged_linear_filter_) {
+      return 10.f;
+    }
+
+    if (!filter_has_had_time_to_converge_ &&
+        use_uncertainty_until_sufficiently_adapted_) {
+      return uncertainty_before_convergence_;
+    }
+    return absl::nullopt;
+  }
+
+  // Returns the time-domain ERLE in log2 units.
+  float ErleTimeDomainLog2() const {
+    return erle_estimator_.ErleTimeDomainLog2();
+  }
 
   // Returns the ERL.
   const std::array<float, kFftLengthBy2Plus1>& Erl() const {
@@ -86,7 +113,7 @@
   int FilterDelayBlocks() const { return filter_delay_blocks_; }
 
   // Returns the internal delay estimate based on the linear filter.
-  rtc::Optional<int> InternalDelay() const { return internal_delay_; }
+  absl::optional<int> InternalDelay() const { return internal_delay_; }
 
   // Returns whether the capture signal is saturated.
   bool SaturatedCapture() const { return capture_signal_saturation_; }
@@ -106,13 +133,18 @@
   void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
 
   // Returns the decay factor for the echo reverberation.
-  float ReverbDecay() const { return reverb_decay_; }
+  float ReverbDecay() const { return reverb_model_estimator_.ReverbDecay(); }
 
   // Returns the upper limit for the echo suppression gain.
   float SuppressionGainLimit() const {
     return suppression_gain_limiter_.Limit();
   }
 
+  // Returns whether the suppression gain limiter is active.
+  bool IsSuppressionGainLimitActive() const {
+    return suppression_gain_limiter_.IsActive();
+  }
+
   // Returns whether the linear filter should have been able to properly adapt.
   bool FilterHasHadTimeToConverge() const {
     return filter_has_had_time_to_converge_;
@@ -122,19 +154,27 @@
   bool InitialState() const { return initial_state_; }
 
   // Updates the aec state.
-  void Update(const rtc::Optional<DelayEstimate>& external_delay,
+  void Update(const absl::optional<DelayEstimate>& external_delay,
               const std::vector<std::array<float, kFftLengthBy2Plus1>>&
                   adaptive_filter_frequency_response,
               const std::vector<float>& adaptive_filter_impulse_response,
-              bool converged_filter,
-              bool diverged_filter,
               const RenderBuffer& render_buffer,
               const std::array<float, kFftLengthBy2Plus1>& E2_main,
               const std::array<float, kFftLengthBy2Plus1>& Y2,
-              const std::array<float, kBlockSize>& s);
+              const SubtractorOutput& subtractor_output,
+              rtc::ArrayView<const float> y);
+
+  // Returns the tail freq. response of the linear filter.
+  rtc::ArrayView<const float> GetFreqRespTail() const {
+    return reverb_model_estimator_.GetFreqRespTail();
+  }
+
+  // Returns filter length in blocks.
+  int FilterLengthBlocks() const {
+    return filter_analyzer_.FilterLengthBlocks();
+  }
 
  private:
-  void UpdateReverb(const std::vector<float>& impulse_response);
   bool DetectActiveRender(rtc::ArrayView<const float> x) const;
   void UpdateSuppressorGainLimit(bool render_activity);
   bool DetectEchoSaturation(rtc::ArrayView<const float> x,
@@ -142,6 +182,21 @@
 
   static int instance_count_;
   std::unique_ptr<ApmDataDumper> data_dumper_;
+  const EchoCanceller3Config config_;
+  const bool allow_transparent_mode_;
+  const bool use_stationary_properties_;
+  const bool enforce_delay_after_realignment_;
+  const bool allow_linear_mode_with_diverged_filter_;
+  const bool early_filter_usage_activated_;
+  const bool use_short_initial_state_;
+  const bool convergence_trigger_linear_mode_;
+  const bool no_alignment_required_for_linear_mode_;
+  const bool use_uncertainty_until_sufficiently_adapted_;
+  const bool transparent_mode_enforces_nonlinear_mode_;
+  const float uncertainty_before_convergence_;
+  const bool early_entry_to_converged_mode_;
+  const bool conservative_filter_divergence_;
+  const bool early_limiter_deactivation_;
   ErlEstimator erl_estimator_;
   ErleEstimator erle_estimator_;
   size_t capture_block_counter_ = 0;
@@ -149,32 +204,22 @@
   size_t blocks_with_proper_filter_adaptation_ = 0;
   size_t blocks_with_active_render_ = 0;
   bool usable_linear_estimate_ = false;
+  bool diverged_linear_filter_ = false;
   bool capture_signal_saturation_ = false;
   bool echo_saturation_ = false;
   bool transparent_mode_ = false;
   bool render_received_ = false;
   int filter_delay_blocks_ = 0;
   size_t blocks_since_last_saturation_ = 1000;
-  float tail_energy_ = 0.f;
-  float accumulated_nz_ = 0.f;
-  float accumulated_nn_ = 0.f;
-  float accumulated_count_ = 0.f;
-  size_t current_reverb_decay_section_ = 0;
-  size_t num_reverb_decay_sections_ = 0;
-  size_t num_reverb_decay_sections_next_ = 0;
-  bool found_end_of_reverb_decay_ = false;
-  bool main_filter_is_adapting_ = true;
-  std::array<float, kMaxAdaptiveFilterLength> block_energies_;
-  const EchoCanceller3Config config_;
+
   std::vector<float> max_render_;
-  float reverb_decay_ = fabsf(config_.ep_strength.default_len);
   bool filter_has_had_time_to_converge_ = false;
   bool initial_state_ = true;
   const float gain_rampup_increase_;
   SuppressionGainUpperLimiter suppression_gain_limiter_;
   FilterAnalyzer filter_analyzer_;
   bool use_linear_filter_output_ = false;
-  rtc::Optional<int> internal_delay_;
+  absl::optional<int> internal_delay_;
   size_t diverged_blocks_ = 0;
   bool filter_should_have_converged_ = false;
   size_t blocks_since_converged_filter_;
@@ -182,11 +227,14 @@
   bool converged_filter_seen_ = false;
   bool consistent_filter_seen_ = false;
   bool external_delay_seen_ = false;
+  absl::optional<DelayEstimate> external_delay_;
+  size_t frames_since_external_delay_change_ = 0;
   size_t converged_filter_count_ = 0;
   bool finite_erl_ = false;
   size_t active_blocks_since_converged_filter_ = 0;
   EchoAudibility echo_audibility_;
-
+  ReverbModelEstimator reverb_model_estimator_;
+  SubtractorOutputAnalyzer subtractor_output_analyzer_;
   RTC_DISALLOW_COPY_AND_ASSIGN(AecState);
 };
 
diff --git a/modules/audio_processing/aec3/aec_state_unittest.cc b/modules/audio_processing/aec3/aec_state_unittest.cc
index 83213b5..50b97f4 100644
--- a/modules/audio_processing/aec3/aec_state_unittest.cc
+++ b/modules/audio_processing/aec3/aec_state_unittest.cc
@@ -22,7 +22,7 @@
   ApmDataDumper data_dumper(42);
   EchoCanceller3Config config;
   AecState state(config);
-  rtc::Optional<DelayEstimate> delay_estimate =
+  absl::optional<DelayEstimate> delay_estimate =
       DelayEstimate(DelayEstimate::Quality::kRefined, 10);
   std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
       RenderDelayBuffer::Create(config, 3));
@@ -31,9 +31,13 @@
   std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
   EchoPathVariability echo_path_variability(
       false, EchoPathVariability::DelayAdjustment::kNone, false);
-  std::array<float, kBlockSize> s;
+  SubtractorOutput output;
+  output.Reset();
+  std::array<float, kBlockSize> y;
   Aec3Fft fft;
-  s.fill(100.f);
+  output.s_main.fill(100.f);
+  output.e_main.fill(100.f);
+  y.fill(1000.f);
 
   std::vector<std::array<float, kFftLengthBy2Plus1>>
       converged_filter_frequency_response(10);
@@ -48,46 +52,44 @@
   std::vector<float> impulse_response(
       GetTimeDomainLength(config.filter.main.length_blocks), 0.f);
 
-  // Verify that linear AEC usability is false when the filter is diverged.
-  state.Update(delay_estimate, diverged_filter_frequency_response,
-               impulse_response, true, false,
-               *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
-  EXPECT_FALSE(state.UsableLinearEstimate());
-
   // Verify that linear AEC usability is true when the filter is converged
   std::fill(x[0].begin(), x[0].end(), 101.f);
   for (int k = 0; k < 3000; ++k) {
     render_delay_buffer->Insert(x);
+    output.UpdatePowers(y);
     state.Update(delay_estimate, converged_filter_frequency_response,
-                 impulse_response, true, false,
-                 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+                 impulse_response, *render_delay_buffer->GetRenderBuffer(),
+                 E2_main, Y2, output, y);
   }
   EXPECT_TRUE(state.UsableLinearEstimate());
 
   // Verify that linear AEC usability becomes false after an echo path change is
   // reported
+  output.UpdatePowers(y);
   state.HandleEchoPathChange(EchoPathVariability(
-      true, EchoPathVariability::DelayAdjustment::kNone, false));
+      false, EchoPathVariability::DelayAdjustment::kBufferReadjustment, false));
   state.Update(delay_estimate, converged_filter_frequency_response,
-               impulse_response, true, false,
-               *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+               impulse_response, *render_delay_buffer->GetRenderBuffer(),
+               E2_main, Y2, output, y);
   EXPECT_FALSE(state.UsableLinearEstimate());
 
   // Verify that the active render detection works as intended.
   std::fill(x[0].begin(), x[0].end(), 101.f);
   render_delay_buffer->Insert(x);
+  output.UpdatePowers(y);
   state.HandleEchoPathChange(EchoPathVariability(
       true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay, false));
   state.Update(delay_estimate, converged_filter_frequency_response,
-               impulse_response, true, false,
-               *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+               impulse_response, *render_delay_buffer->GetRenderBuffer(),
+               E2_main, Y2, output, y);
   EXPECT_FALSE(state.ActiveRender());
 
   for (int k = 0; k < 1000; ++k) {
     render_delay_buffer->Insert(x);
+    output.UpdatePowers(y);
     state.Update(delay_estimate, converged_filter_frequency_response,
-                 impulse_response, true, false,
-                 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+                 impulse_response, *render_delay_buffer->GetRenderBuffer(),
+                 E2_main, Y2, output, y);
   }
   EXPECT_TRUE(state.ActiveRender());
 
@@ -108,9 +110,10 @@
 
   Y2.fill(10.f * 10000.f * 10000.f);
   for (size_t k = 0; k < 1000; ++k) {
+    output.UpdatePowers(y);
     state.Update(delay_estimate, converged_filter_frequency_response,
-                 impulse_response, true, false,
-                 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+                 impulse_response, *render_delay_buffer->GetRenderBuffer(),
+                 E2_main, Y2, output, y);
   }
 
   ASSERT_TRUE(state.UsableLinearEstimate());
@@ -125,9 +128,10 @@
   E2_main.fill(1.f * 10000.f * 10000.f);
   Y2.fill(10.f * E2_main[0]);
   for (size_t k = 0; k < 1000; ++k) {
+    output.UpdatePowers(y);
     state.Update(delay_estimate, converged_filter_frequency_response,
-                 impulse_response, true, false,
-                 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+                 impulse_response, *render_delay_buffer->GetRenderBuffer(),
+                 E2_main, Y2, output, y);
   }
   ASSERT_TRUE(state.UsableLinearEstimate());
   {
@@ -146,9 +150,10 @@
   E2_main.fill(1.f * 10000.f * 10000.f);
   Y2.fill(5.f * E2_main[0]);
   for (size_t k = 0; k < 1000; ++k) {
+    output.UpdatePowers(y);
     state.Update(delay_estimate, converged_filter_frequency_response,
-                 impulse_response, true, false,
-                 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+                 impulse_response, *render_delay_buffer->GetRenderBuffer(),
+                 E2_main, Y2, output, y);
   }
 
   ASSERT_TRUE(state.UsableLinearEstimate());
@@ -173,15 +178,18 @@
   AecState state(config);
   std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
       RenderDelayBuffer::Create(config, 3));
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   std::array<float, kFftLengthBy2Plus1> E2_main;
   std::array<float, kFftLengthBy2Plus1> Y2;
   std::array<float, kBlockSize> x;
   EchoPathVariability echo_path_variability(
       false, EchoPathVariability::DelayAdjustment::kNone, false);
-  std::array<float, kBlockSize> s;
-  s.fill(100.f);
+  SubtractorOutput output;
+  output.Reset();
+  std::array<float, kBlockSize> y;
+  output.s_main.fill(100.f);
   x.fill(0.f);
+  y.fill(0.f);
 
   std::vector<std::array<float, kFftLengthBy2Plus1>> frequency_response(
       kFilterLengthBlocks);
@@ -198,9 +206,10 @@
     impulse_response[k * kBlockSize + 1] = 1.f;
 
     state.HandleEchoPathChange(echo_path_variability);
-    state.Update(delay_estimate, frequency_response, impulse_response, true,
-                 false, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
-                 s);
+    output.UpdatePowers(y);
+    state.Update(delay_estimate, frequency_response, impulse_response,
+                 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, output,
+                 y);
   }
 }
 
diff --git a/modules/audio_processing/aec3/block_processor.cc b/modules/audio_processing/aec3/block_processor.cc
index f954be3..1bb6958 100644
--- a/modules/audio_processing/aec3/block_processor.cc
+++ b/modules/audio_processing/aec3/block_processor.cc
@@ -9,7 +9,7 @@
  */
 #include "modules/audio_processing/aec3/block_processor.h"
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/block_processor_metrics.h"
 #include "modules/audio_processing/aec3/echo_path_variability.h"
@@ -58,8 +58,8 @@
   BlockProcessorMetrics metrics_;
   RenderDelayBuffer::BufferingEvent render_event_;
   size_t capture_call_counter_ = 0;
-  rtc::Optional<DelayEstimate> estimated_delay_;
-  rtc::Optional<int> echo_remover_delay_;
+  absl::optional<DelayEstimate> estimated_delay_;
+  absl::optional<int> echo_remover_delay_;
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorImpl);
 };
 
@@ -232,7 +232,7 @@
 void BlockProcessorImpl::GetMetrics(EchoControl::Metrics* metrics) const {
   echo_remover_->GetMetrics(metrics);
   const int block_size_ms = sample_rate_hz_ == 8000 ? 8 : 4;
-  rtc::Optional<size_t> delay = render_buffer_->Delay();
+  absl::optional<size_t> delay = render_buffer_->Delay();
   metrics->delay_ms = delay ? static_cast<int>(*delay) * block_size_ms : 0;
 }
 
diff --git a/modules/audio_processing/aec3/block_processor_metrics_unittest.cc b/modules/audio_processing/aec3/block_processor_metrics_unittest.cc
index 7ce8573..73f7689 100644
--- a/modules/audio_processing/aec3/block_processor_metrics_unittest.cc
+++ b/modules/audio_processing/aec3/block_processor_metrics_unittest.cc
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/block_processor_metrics.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
 
 #include "test/gtest.h"
 
diff --git a/modules/audio_processing/aec3/cascaded_biquad_filter.cc b/modules/audio_processing/aec3/cascaded_biquad_filter.cc
index 9a472f5..333d226 100644
--- a/modules/audio_processing/aec3/cascaded_biquad_filter.cc
+++ b/modules/audio_processing/aec3/cascaded_biquad_filter.cc
@@ -13,37 +13,84 @@
 
 namespace webrtc {
 
+CascadedBiQuadFilter::BiQuadParam::BiQuadParam(std::complex<float> zero,
+                                               std::complex<float> pole,
+                                               float gain,
+                                               bool mirror_zero_along_i_axis)
+    : zero(zero),
+      pole(pole),
+      gain(gain),
+      mirror_zero_along_i_axis(mirror_zero_along_i_axis) {}
+
+CascadedBiQuadFilter::BiQuadParam::BiQuadParam(const BiQuadParam&) = default;
+
+CascadedBiQuadFilter::BiQuad::BiQuad(
+    const CascadedBiQuadFilter::BiQuadParam& param)
+    : x(), y() {
+  float z_r = std::real(param.zero);
+  float z_i = std::imag(param.zero);
+  float p_r = std::real(param.pole);
+  float p_i = std::imag(param.pole);
+  float gain = param.gain;
+
+  if (param.mirror_zero_along_i_axis) {
+    // Assuming zeroes at z_r and -z_r.
+    RTC_DCHECK(z_i == 0.f);
+    coefficients.b[0] = gain * 1.f;
+    coefficients.b[1] = 0.f;
+    coefficients.b[2] = gain * -(z_r * z_r);
+  } else {
+    // Assuming zeros at (z_r + z_i*i) and (z_r - z_i*i).
+    coefficients.b[0] = gain * 1.f;
+    coefficients.b[1] = gain * -2.f * z_r;
+    coefficients.b[2] = gain * (z_r * z_r + z_i * z_i);
+  }
+
+  // Assuming poles at (p_r + p_i*i) and (p_r - p_i*i).
+  coefficients.a[0] = -2.f * p_r;
+  coefficients.a[1] = p_r * p_r + p_i * p_i;
+}
+
 CascadedBiQuadFilter::CascadedBiQuadFilter(
     const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
     size_t num_biquads)
-    : biquad_states_(num_biquads), coefficients_(coefficients) {}
+    : biquads_(num_biquads, coefficients) {}
+
+CascadedBiQuadFilter::CascadedBiQuadFilter(
+    const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params) {
+  for (const auto& param : biquad_params) {
+    biquads_.push_back(BiQuad(param));
+  }
+}
 
 CascadedBiQuadFilter::~CascadedBiQuadFilter() = default;
 
 void CascadedBiQuadFilter::Process(rtc::ArrayView<const float> x,
                                    rtc::ArrayView<float> y) {
-  ApplyBiQuad(x, y, &biquad_states_[0]);
-  for (size_t k = 1; k < biquad_states_.size(); ++k) {
-    ApplyBiQuad(y, y, &biquad_states_[k]);
+  if (biquads_.size() > 0) {
+    ApplyBiQuad(x, y, &biquads_[0]);
+    for (size_t k = 1; k < biquads_.size(); ++k) {
+      ApplyBiQuad(y, y, &biquads_[k]);
+    }
+  } else {
+    std::copy(x.begin(), x.end(), y.begin());
   }
 }
 
 void CascadedBiQuadFilter::Process(rtc::ArrayView<float> y) {
-  for (auto& biquad : biquad_states_) {
+  for (auto& biquad : biquads_) {
     ApplyBiQuad(y, y, &biquad);
   }
 }
 
-void CascadedBiQuadFilter::ApplyBiQuad(
-    rtc::ArrayView<const float> x,
-    rtc::ArrayView<float> y,
-    CascadedBiQuadFilter::BiQuadState* biquad_state) {
+void CascadedBiQuadFilter::ApplyBiQuad(rtc::ArrayView<const float> x,
+                                       rtc::ArrayView<float> y,
+                                       CascadedBiQuadFilter::BiQuad* biquad) {
   RTC_DCHECK_EQ(x.size(), y.size());
-  RTC_DCHECK(biquad_state);
-  const auto* c_b = coefficients_.b;
-  const auto* c_a = coefficients_.a;
-  auto* m_x = biquad_state->x;
-  auto* m_y = biquad_state->y;
+  const auto* c_b = biquad->coefficients.b;
+  const auto* c_a = biquad->coefficients.a;
+  auto* m_x = biquad->x;
+  auto* m_y = biquad->y;
   for (size_t k = 0; k < x.size(); ++k) {
     const float tmp = x[k];
     y[k] = c_b[0] * tmp + c_b[1] * m_x[0] + c_b[2] * m_x[1] - c_a[0] * m_y[0] -
diff --git a/modules/audio_processing/aec3/cascaded_biquad_filter.h b/modules/audio_processing/aec3/cascaded_biquad_filter.h
index aea889a..1e09fa6 100644
--- a/modules/audio_processing/aec3/cascaded_biquad_filter.h
+++ b/modules/audio_processing/aec3/cascaded_biquad_filter.h
@@ -11,6 +11,7 @@
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_CASCADED_BIQUAD_FILTER_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_CASCADED_BIQUAD_FILTER_H_
 
+#include <complex>
 #include <vector>
 
 #include "api/array_view.h"
@@ -18,14 +19,20 @@
 
 namespace webrtc {
 
-// Applies a number of identical biquads in a cascaded manner. The filter
-// implementation is direct form 1.
+// Applies a number of biquads in a cascaded manner. The filter implementation
+// is direct form 1.
 class CascadedBiQuadFilter {
  public:
-  struct BiQuadState {
-    BiQuadState() : x(), y() {}
-    float x[2];
-    float y[2];
+  struct BiQuadParam {
+    BiQuadParam(std::complex<float> zero,
+                std::complex<float> pole,
+                float gain,
+                bool mirror_zero_along_i_axis = false);
+    BiQuadParam(const BiQuadParam&);
+    std::complex<float> zero;
+    std::complex<float> pole;
+    float gain;
+    bool mirror_zero_along_i_axis;
   };
 
   struct BiQuadCoefficients {
@@ -33,9 +40,20 @@
     float a[2];
   };
 
+  struct BiQuad {
+    BiQuad(const BiQuadCoefficients& coefficients)
+        : coefficients(coefficients), x(), y() {}
+    BiQuad(const CascadedBiQuadFilter::BiQuadParam& param);
+    BiQuadCoefficients coefficients;
+    float x[2];
+    float y[2];
+  };
+
   CascadedBiQuadFilter(
       const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
       size_t num_biquads);
+  CascadedBiQuadFilter(
+      const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params);
   ~CascadedBiQuadFilter();
   // Applies the biquads on the values in x in order to form the output in y.
   void Process(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
@@ -45,10 +63,9 @@
  private:
   void ApplyBiQuad(rtc::ArrayView<const float> x,
                    rtc::ArrayView<float> y,
-                   CascadedBiQuadFilter::BiQuadState* biquad_state);
+                   CascadedBiQuadFilter::BiQuad* biquad);
 
-  std::vector<BiQuadState> biquad_states_;
-  const BiQuadCoefficients coefficients_;
+  std::vector<BiQuad> biquads_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(CascadedBiQuadFilter);
 };
diff --git a/modules/audio_processing/aec3/cascaded_biquad_filter_unittest.cc b/modules/audio_processing/aec3/cascaded_biquad_filter_unittest.cc
index fcb77e1..57f4b04 100644
--- a/modules/audio_processing/aec3/cascaded_biquad_filter_unittest.cc
+++ b/modules/audio_processing/aec3/cascaded_biquad_filter_unittest.cc
@@ -95,4 +95,46 @@
 }
 #endif
 
+// Verifies the conversion from zero, pole, gain to filter coefficients for
+// lowpass filter.
+TEST(CascadedBiquadFilter, BiQuadParamLowPass) {
+  CascadedBiQuadFilter::BiQuadParam param(
+      {-1.0f, 0.0f}, {0.23146901f, 0.39514232f}, 0.1866943331163784f);
+  CascadedBiQuadFilter::BiQuad filter(param);
+  const float epsilon = 1e-6f;
+  EXPECT_NEAR(filter.coefficients.b[0], 0.18669433f, epsilon);
+  EXPECT_NEAR(filter.coefficients.b[1], 0.37338867f, epsilon);
+  EXPECT_NEAR(filter.coefficients.b[2], 0.18669433f, epsilon);
+  EXPECT_NEAR(filter.coefficients.a[0], -0.46293803f, epsilon);
+  EXPECT_NEAR(filter.coefficients.a[1], 0.20971536f, epsilon);
+}
+
+// Verifies the conversion from zero, pole, gain to filter coefficients for
+// highpass filter.
+TEST(CascadedBiquadFilter, BiQuadParamHighPass) {
+  CascadedBiQuadFilter::BiQuadParam param(
+      {1.0f, 0.0f}, {0.72712179f, 0.21296904f}, 0.75707637533388494f);
+  CascadedBiQuadFilter::BiQuad filter(param);
+  const float epsilon = 1e-6f;
+  EXPECT_NEAR(filter.coefficients.b[0], 0.75707638f, epsilon);
+  EXPECT_NEAR(filter.coefficients.b[1], -1.51415275f, epsilon);
+  EXPECT_NEAR(filter.coefficients.b[2], 0.75707638f, epsilon);
+  EXPECT_NEAR(filter.coefficients.a[0], -1.45424359f, epsilon);
+  EXPECT_NEAR(filter.coefficients.a[1], 0.57406192f, epsilon);
+}
+
+// Verifies the conversion from zero, pole, gain to filter coefficients for
+// bandpass filter.
+TEST(CascadedBiquadFilter, BiQuadParamBandPass) {
+  CascadedBiQuadFilter::BiQuadParam param(
+      {1.0f, 0.0f}, {1.11022302e-16f, 0.71381051f}, 0.2452372752527856f, true);
+  CascadedBiQuadFilter::BiQuad filter(param);
+  const float epsilon = 1e-6f;
+  EXPECT_NEAR(filter.coefficients.b[0], 0.24523728f, epsilon);
+  EXPECT_NEAR(filter.coefficients.b[1], 0.f, epsilon);
+  EXPECT_NEAR(filter.coefficients.b[2], -0.24523728f, epsilon);
+  EXPECT_NEAR(filter.coefficients.a[0], -2.22044605e-16f, epsilon);
+  EXPECT_NEAR(filter.coefficients.a[1], 5.09525449e-01f, epsilon);
+}
+
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/decimator.cc b/modules/audio_processing/aec3/decimator.cc
index 135a771..d9faa62 100644
--- a/modules/audio_processing/aec3/decimator.cc
+++ b/modules/audio_processing/aec3/decimator.cc
@@ -14,39 +14,53 @@
 namespace webrtc {
 namespace {
 
-// b, a = signal.butter(2, 3400/8000.0, 'lowpass', analog=False) which are the
-// same as b, a = signal.butter(2, 1700/4000.0, 'lowpass', analog=False).
-const CascadedBiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients2 = {
-    {0.22711796f, 0.45423593f, 0.22711796f},
-    {-0.27666461f, 0.18513647f}};
-constexpr int kNumFilters2 = 3;
+// signal.butter(2, 3400/8000.0, 'lowpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetLowPassFilterDS2() {
+  return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+      {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f},
+      {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f},
+      {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f}};
+}
 
-// b, a = signal.butter(2, 1500/8000.0, 'lowpass', analog=False) which are the
-// same as b, a = signal.butter(2, 75/4000.0, 'lowpass', analog=False).
-const CascadedBiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients4 = {
-    {0.0179f, 0.0357f, 0.0179f},
-    {-1.5879f, 0.6594f}};
-constexpr int kNumFilters4 = 3;
+// signal.ellip(6, 1, 40, 1800/8000, btype='lowpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetLowPassFilterDS4() {
+  return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+      {{-0.08873842f, 0.99605496f}, {0.75916227f, 0.23841065f}, 0.26250696827f},
+      {{0.62273832f, 0.78243018f}, {0.74892112f, 0.5410152f}, 0.26250696827f},
+      {{0.71107693f, 0.70311421f}, {0.74895534f, 0.63924616f}, 0.26250696827f}};
+}
 
-// b, a = signal.butter(2, 800/8000.0, 'lowpass', analog=False) which are the
-// same as b, a = signal.butter(2, 400/4000.0, 'lowpass', analog=False).
-const CascadedBiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients8 = {
-    {0.02008337f, 0.04016673f, 0.02008337f},
-    {-1.56101808f, 0.64135154f}};
-constexpr int kNumFilters8 = 4;
+// signal.cheby1(1, 6, [1000/8000, 2000/8000], btype='bandpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetBandPassFilterDS8() {
+  return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+      {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+      {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+      {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+      {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+      {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}};
+}
 
+// signal.butter(2, 1000/8000.0, 'highpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetHighPassFilter() {
+  return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+      {{1.f, 0.f}, {0.72712179f, 0.21296904f}, 0.7570763753338849f}};
+}
+
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetPassThroughFilter() {
+  return std::vector<CascadedBiQuadFilter::BiQuadParam>{};
+}
 }  // namespace
 
 Decimator::Decimator(size_t down_sampling_factor)
     : down_sampling_factor_(down_sampling_factor),
-      low_pass_filter_(
-          down_sampling_factor_ == 4
-              ? kLowPassFilterCoefficients4
-              : (down_sampling_factor_ == 8 ? kLowPassFilterCoefficients8
-                                            : kLowPassFilterCoefficients2),
-          down_sampling_factor_ == 4
-              ? kNumFilters4
-              : (down_sampling_factor_ == 8 ? kNumFilters8 : kNumFilters2)) {
+      anti_aliasing_filter_(down_sampling_factor_ == 4
+                                ? GetLowPassFilterDS4()
+                                : (down_sampling_factor_ == 8
+                                       ? GetBandPassFilterDS8()
+                                       : GetLowPassFilterDS2())),
+      noise_reduction_filter_(down_sampling_factor_ == 8
+                                  ? GetPassThroughFilter()
+                                  : GetHighPassFilter()) {
   RTC_DCHECK(down_sampling_factor_ == 2 || down_sampling_factor_ == 4 ||
              down_sampling_factor_ == 8);
 }
@@ -58,7 +72,10 @@
   std::array<float, kBlockSize> x;
 
   // Limit the frequency content of the signal to avoid aliasing.
-  low_pass_filter_.Process(in, x);
+  anti_aliasing_filter_.Process(in, x);
+
+  // Reduce the impact of near-end noise.
+  noise_reduction_filter_.Process(x);
 
   // Downsample the signal.
   for (size_t j = 0, k = 0; j < out.size(); ++j, k += down_sampling_factor_) {
diff --git a/modules/audio_processing/aec3/decimator.h b/modules/audio_processing/aec3/decimator.h
index 7418a26..2bb60a4 100644
--- a/modules/audio_processing/aec3/decimator.h
+++ b/modules/audio_processing/aec3/decimator.h
@@ -30,7 +30,8 @@
 
  private:
   const size_t down_sampling_factor_;
-  CascadedBiQuadFilter low_pass_filter_;
+  CascadedBiQuadFilter anti_aliasing_filter_;
+  CascadedBiQuadFilter noise_reduction_filter_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(Decimator);
 };
diff --git a/modules/audio_processing/aec3/decimator_unittest.cc b/modules/audio_processing/aec3/decimator_unittest.cc
index e77a990..e9ab21b 100644
--- a/modules/audio_processing/aec3/decimator_unittest.cc
+++ b/modules/audio_processing/aec3/decimator_unittest.cc
@@ -99,21 +99,6 @@
   }
 }
 
-// Verifies that the impact of low-frequency content is small during the
-// downsampling.
-TEST(Decimator, NoImpactOnLowerFrequencies) {
-  float input_power;
-  float output_power;
-  for (auto rate : {8000, 16000, 32000, 48000}) {
-    for (auto down_sampling_factor : kDownSamplingFactors) {
-      ProduceDebugText(rate);
-      ProduceDecimatedSinusoidalOutputPower(rate, down_sampling_factor, 200.f,
-                                            &input_power, &output_power);
-      EXPECT_LT(0.7f * input_power, output_power);
-    }
-  }
-}
-
 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
 // Verifies the check for the input size.
 TEST(Decimator, WrongInputSize) {
diff --git a/modules/audio_processing/aec3/echo_audibility.cc b/modules/audio_processing/aec3/echo_audibility.cc
index 68d2dd1..567873b 100644
--- a/modules/audio_processing/aec3/echo_audibility.cc
+++ b/modules/audio_processing/aec3/echo_audibility.cc
@@ -28,25 +28,27 @@
 
 void EchoAudibility::Update(const RenderBuffer& render_buffer,
                             int delay_blocks,
-                            bool external_delay_seen) {
+                            bool external_delay_seen,
+                            float reverb_decay) {
   UpdateRenderNoiseEstimator(render_buffer.GetSpectrumBuffer(),
                              render_buffer.GetBlockBuffer(),
                              external_delay_seen);
 
   if (external_delay_seen) {
-    UpdateRenderStationarityFlags(render_buffer, delay_blocks);
+    UpdateRenderStationarityFlags(render_buffer, delay_blocks, reverb_decay);
   }
 }
 
 void EchoAudibility::Reset() {
   render_stationarity_.Reset();
   non_zero_render_seen_ = false;
-  render_spectrum_write_prev_ = rtc::nullopt;
+  render_spectrum_write_prev_ = absl::nullopt;
 }
 
 void EchoAudibility::UpdateRenderStationarityFlags(
     const RenderBuffer& render_buffer,
-    int delay_blocks) {
+    int delay_blocks,
+    float reverb_decay) {
   const VectorBuffer& spectrum_buffer = render_buffer.GetSpectrumBuffer();
   int idx_at_delay =
       spectrum_buffer.OffsetIndex(spectrum_buffer.read, delay_blocks);
@@ -55,7 +57,7 @@
   num_lookahead = std::max(0, num_lookahead);
 
   render_stationarity_.UpdateStationarityFlags(spectrum_buffer, idx_at_delay,
-                                               num_lookahead);
+                                               num_lookahead, reverb_decay);
 }
 
 void EchoAudibility::UpdateRenderNoiseEstimator(
diff --git a/modules/audio_processing/aec3/echo_audibility.h b/modules/audio_processing/aec3/echo_audibility.h
index 038951e..4650fa5 100644
--- a/modules/audio_processing/aec3/echo_audibility.h
+++ b/modules/audio_processing/aec3/echo_audibility.h
@@ -17,8 +17,8 @@
 #include <memory>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/matrix_buffer.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
 #include "modules/audio_processing/aec3/stationarity_estimator.h"
@@ -37,7 +37,8 @@
   // Feed new render data to the echo audibility estimator.
   void Update(const RenderBuffer& render_buffer,
               int delay_blocks,
-              bool external_delay_seen);
+              bool external_delay_seen,
+              float reverb_decay);
 
   // Get the residual echo scaling.
   void GetResidualEchoScaling(rtc::ArrayView<float> residual_scaling) const {
@@ -50,13 +51,19 @@
     }
   }
 
+  // Returns true if the current render block is estimated as stationary.
+  bool IsBlockStationary() const {
+    return render_stationarity_.IsBlockStationary();
+  }
+
  private:
   // Reset the EchoAudibility class.
   void Reset();
 
   // Updates the render stationarity flags for the current frame.
   void UpdateRenderStationarityFlags(const RenderBuffer& render_buffer,
-                                     int delay_blocks);
+                                     int delay_blocks,
+                                     float reverb_decay);
 
   // Updates the noise estimator with the new render data since the previous
   // call to this method.
@@ -68,7 +75,7 @@
   // values.
   bool IsRenderTooLow(const MatrixBuffer& block_buffer);
 
-  rtc::Optional<int> render_spectrum_write_prev_;
+  absl::optional<int> render_spectrum_write_prev_;
   int render_block_write_prev_;
   bool non_zero_render_seen_;
   StationarityEstimator render_stationarity_;
diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc
index 765e4de..c02bc14 100644
--- a/modules/audio_processing/aec3/echo_canceller3.cc
+++ b/modules/audio_processing/aec3/echo_canceller3.cc
@@ -12,6 +12,7 @@
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/atomicops.h"
 #include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
@@ -28,9 +29,47 @@
   return false;
 }
 
+bool UseShortDelayEstimatorWindow() {
+  return field_trial::IsEnabled("WebRTC-Aec3UseShortDelayEstimatorWindow");
+}
+
+bool EnableReverbBasedOnRender() {
+  return !field_trial::IsEnabled("WebRTC-Aec3ReverbBasedOnRenderKillSwitch");
+}
+
+bool EnableReverbModelling() {
+  return !field_trial::IsEnabled("WebRTC-Aec3ReverbModellingKillSwitch");
+}
+
+bool EnableSuppressorNearendAveraging() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3SuppressorNearendAveragingKillSwitch");
+}
+
+bool EnableSlowFilterAdaptation() {
+  return !field_trial::IsEnabled("WebRTC-Aec3SlowFilterAdaptationKillSwitch");
+}
+
+bool EnableShadowFilterJumpstart() {
+  return !field_trial::IsEnabled("WebRTC-Aec3ShadowFilterJumpstartKillSwitch");
+}
+
+bool EnableUnityInitialRampupGain() {
+  return field_trial::IsEnabled("WebRTC-Aec3EnableUnityInitialRampupGain");
+}
+
+bool EnableUnityNonZeroRampupGain() {
+  return field_trial::IsEnabled("WebRTC-Aec3EnableUnityNonZeroRampupGain");
+}
+
 // Method for adjusting config parameter dependencies..
 EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
   EchoCanceller3Config adjusted_cfg = config;
+  const EchoCanceller3Config default_cfg;
+
+  if (!EnableReverbModelling()) {
+    adjusted_cfg.ep_strength.default_len = 0.f;
+  }
 
   // Use customized parameters when the system has clock-drift.
   if (config.echo_removal_control.has_clock_drift) {
@@ -62,6 +101,52 @@
       adjusted_cfg.echo_model.nonlinear_release = 0.6f;
     }
   }
+
+  if (UseShortDelayEstimatorWindow()) {
+    adjusted_cfg.delay.num_filters =
+        std::min(adjusted_cfg.delay.num_filters, static_cast<size_t>(5));
+  }
+
+  if (EnableReverbBasedOnRender() == false) {
+    adjusted_cfg.ep_strength.reverb_based_on_render = false;
+  }
+
+  if (!EnableSuppressorNearendAveraging()) {
+    adjusted_cfg.suppressor.nearend_average_blocks = 1;
+  }
+
+  if (!EnableSlowFilterAdaptation()) {
+    if (!EnableShadowFilterJumpstart()) {
+      adjusted_cfg.filter.main.leakage_converged = 0.005f;
+      adjusted_cfg.filter.main.leakage_diverged = 0.1f;
+    }
+    adjusted_cfg.filter.main_initial.leakage_converged = 0.05f;
+    adjusted_cfg.filter.main_initial.leakage_diverged = 5.f;
+  }
+
+  if (!EnableShadowFilterJumpstart()) {
+    if (EnableSlowFilterAdaptation()) {
+      adjusted_cfg.filter.main.leakage_converged = 0.0005f;
+      adjusted_cfg.filter.main.leakage_diverged = 0.01f;
+    } else {
+      adjusted_cfg.filter.main.leakage_converged = 0.005f;
+      adjusted_cfg.filter.main.leakage_diverged = 0.1f;
+    }
+    adjusted_cfg.filter.main.error_floor = 0.001f;
+  }
+
+  if (EnableUnityInitialRampupGain() &&
+      adjusted_cfg.echo_removal_control.gain_rampup.initial_gain ==
+          default_cfg.echo_removal_control.gain_rampup.initial_gain) {
+    adjusted_cfg.echo_removal_control.gain_rampup.initial_gain = 1.f;
+  }
+
+  if (EnableUnityNonZeroRampupGain() &&
+      adjusted_cfg.echo_removal_control.gain_rampup.first_non_zero_gain ==
+          default_cfg.echo_removal_control.gain_rampup.first_non_zero_gain) {
+    adjusted_cfg.echo_removal_control.gain_rampup.first_non_zero_gain = 1.f;
+  }
+
   return adjusted_cfg;
 }
 
diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.cc b/modules/audio_processing/aec3/echo_path_delay_estimator.cc
index 0026522..4cae277 100644
--- a/modules/audio_processing/aec3/echo_path_delay_estimator.cc
+++ b/modules/audio_processing/aec3/echo_path_delay_estimator.cc
@@ -16,25 +16,38 @@
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
+namespace {
+size_t GetDownSamplingFactor(const EchoCanceller3Config& config) {
+  // Do not use down sampling factor 8 if kill switch is triggered.
+  return (config.delay.down_sampling_factor == 8 &&
+          field_trial::IsEnabled("WebRTC-Aec3DownSamplingFactor8KillSwitch"))
+             ? 4
+             : config.delay.down_sampling_factor;
+}
+}  // namespace
 
 EchoPathDelayEstimator::EchoPathDelayEstimator(
     ApmDataDumper* data_dumper,
     const EchoCanceller3Config& config)
     : data_dumper_(data_dumper),
-      down_sampling_factor_(config.delay.down_sampling_factor),
+      down_sampling_factor_(GetDownSamplingFactor(config)),
       sub_block_size_(down_sampling_factor_ != 0
                           ? kBlockSize / down_sampling_factor_
                           : kBlockSize),
       capture_decimator_(down_sampling_factor_),
-      matched_filter_(data_dumper_,
-                      DetectOptimization(),
-                      sub_block_size_,
-                      kMatchedFilterWindowSizeSubBlocks,
-                      config.delay.num_filters,
-                      kMatchedFilterAlignmentShiftSizeSubBlocks,
-                      config.render_levels.poor_excitation_render_limit),
+      matched_filter_(
+          data_dumper_,
+          DetectOptimization(),
+          sub_block_size_,
+          kMatchedFilterWindowSizeSubBlocks,
+          config.delay.num_filters,
+          kMatchedFilterAlignmentShiftSizeSubBlocks,
+          GetDownSamplingFactor(config) == 8
+              ? config.render_levels.poor_excitation_render_limit_ds8
+              : config.render_levels.poor_excitation_render_limit),
       matched_filter_lag_aggregator_(data_dumper_,
                                      matched_filter_.GetMaxFilterLag()) {
   RTC_DCHECK(data_dumper);
@@ -48,11 +61,11 @@
     matched_filter_lag_aggregator_.Reset();
   }
   matched_filter_.Reset();
-  old_aggregated_lag_ = rtc::nullopt;
+  old_aggregated_lag_ = absl::nullopt;
   consistent_estimate_counter_ = 0;
 }
 
-rtc::Optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
+absl::optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
     const DownsampledRenderBuffer& render_buffer,
     rtc::ArrayView<const float> capture) {
   RTC_DCHECK_EQ(kBlockSize, capture.size());
@@ -68,7 +81,7 @@
                         16000 / down_sampling_factor_, 1);
   matched_filter_.Update(render_buffer, downsampled_capture);
 
-  rtc::Optional<DelayEstimate> aggregated_matched_filter_lag =
+  absl::optional<DelayEstimate> aggregated_matched_filter_lag =
       matched_filter_lag_aggregator_.Aggregate(
           matched_filter_.GetLagEstimates());
 
diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.h b/modules/audio_processing/aec3/echo_path_delay_estimator.h
index 6389098..cea9abc 100644
--- a/modules/audio_processing/aec3/echo_path_delay_estimator.h
+++ b/modules/audio_processing/aec3/echo_path_delay_estimator.h
@@ -13,8 +13,8 @@
 
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/decimator.h"
 #include "modules/audio_processing/aec3/delay_estimate.h"
 #include "modules/audio_processing/aec3/downsampled_render_buffer.h"
@@ -38,7 +38,7 @@
   void Reset(bool soft_reset);
 
   // Produce a delay estimate if such is avaliable.
-  rtc::Optional<DelayEstimate> EstimateDelay(
+  absl::optional<DelayEstimate> EstimateDelay(
       const DownsampledRenderBuffer& render_buffer,
       rtc::ArrayView<const float> capture);
 
@@ -55,7 +55,7 @@
   Decimator capture_decimator_;
   MatchedFilter matched_filter_;
   MatchedFilterLagAggregator matched_filter_lag_aggregator_;
-  rtc::Optional<DelayEstimate> old_aggregated_lag_;
+  absl::optional<DelayEstimate> old_aggregated_lag_;
   size_t consistent_estimate_counter_ = 0;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(EchoPathDelayEstimator);
diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc
index 38f31c9..0e237a5 100644
--- a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc
@@ -72,7 +72,7 @@
           delay_samples + 2 * config.delay.api_call_jitter_blocks * 64);
       EchoPathDelayEstimator estimator(&data_dumper, config);
 
-      rtc::Optional<DelayEstimate> estimated_delay_samples;
+      absl::optional<DelayEstimate> estimated_delay_samples;
       for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) {
         RandomizeSampleVector(&random_generator, render[0]);
         signal_delay_buffer.Delay(render[0], capture);
@@ -93,18 +93,20 @@
       }
 
       if (estimated_delay_samples) {
-        // Due to the internal down-sampling done inside the delay estimator
-        // the estimated delay cannot be expected to be exact to the true delay.
-        EXPECT_NEAR(delay_samples,
-                    estimated_delay_samples->delay -
-                        (config.delay.api_call_jitter_blocks + 1) * 64,
-                    config.delay.down_sampling_factor);
+        // Allow estimated delay to be off by one sample in the down-sampled
+        // domain.
+        size_t delay_ds = delay_samples / down_sampling_factor;
+        size_t estimated_delay_ds =
+            (estimated_delay_samples->delay -
+             (config.delay.api_call_jitter_blocks + 1) * 64) /
+            down_sampling_factor;
+        EXPECT_NEAR(delay_ds, estimated_delay_ds, 1);
       } else {
         ADD_FAILURE();
       }
+    }
   }
 }
-}
 
 // Verifies that the delay estimator does not produce delay estimates for render
 // signals of low level.
diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc
index 96887fe..5394eaf 100644
--- a/modules/audio_processing/aec3/echo_remover.cc
+++ b/modules/audio_processing/aec3/echo_remover.cc
@@ -31,11 +31,23 @@
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/atomicops.h"
 #include "rtc_base/constructormagic.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
 namespace {
 
+bool UseShadowFilterOutput() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3UtilizeShadowFilterOutputKillSwitch");
+}
+
+bool UseSmoothSignalTransitions() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3SmoothSignalTransitionsKillSwitch");
+}
+
 void LinearEchoPower(const FftData& E,
                      const FftData& Y,
                      std::array<float, kFftLengthBy2Plus1>* S2) {
@@ -45,6 +57,26 @@
   }
 }
 
+// Fades between two input signals using a fix-sized transition.
+void SignalTransition(rtc::ArrayView<const float> from,
+                      rtc::ArrayView<const float> to,
+                      rtc::ArrayView<float> out) {
+  constexpr size_t kTransitionSize = 30;
+  constexpr float kOneByTransitionSize = 1.f / kTransitionSize;
+
+  RTC_DCHECK_EQ(from.size(), to.size());
+  RTC_DCHECK_EQ(from.size(), out.size());
+  RTC_DCHECK_LE(kTransitionSize, out.size());
+
+  for (size_t k = 0; k < kTransitionSize; ++k) {
+    out[k] = k * kOneByTransitionSize * to[k];
+    out[k] += (kTransitionSize - k) * kOneByTransitionSize * to[k];
+  }
+
+  std::copy(to.begin() + kTransitionSize, to.end(),
+            out.begin() + kTransitionSize);
+}
+
 // Computes a windowed (square root Hanning) padded FFT and updates the related
 // memory.
 void WindowedPaddedFft(const Aec3Fft& fft,
@@ -66,15 +98,16 @@
   // Removes the echo from a block of samples from the capture signal. The
   // supplied render signal is assumed to be pre-aligned with the capture
   // signal.
-  void ProcessCapture(const EchoPathVariability& echo_path_variability,
+  void ProcessCapture(EchoPathVariability echo_path_variability,
                       bool capture_signal_saturation,
-                      const rtc::Optional<DelayEstimate>& external_delay,
+                      const absl::optional<DelayEstimate>& external_delay,
                       RenderBuffer* render_buffer,
                       std::vector<std::vector<float>>* capture) override;
 
   // Returns the internal delay estimate in blocks.
-  rtc::Optional<int> Delay() const override {
-    return aec_state_.InternalDelay();
+  absl::optional<int> Delay() const override {
+    // TODO(peah): Remove or reactivate this functionality.
+    return absl::nullopt;
   }
 
   // Updates the status on whether echo leakage is detected in the output of the
@@ -84,12 +117,21 @@
   }
 
  private:
+  // Selects which of the shadow and main linear filter outputs that is most
+  // appropriate to pass to the suppressor and forms the linear filter output by
+  // smoothly transition between those.
+  void FormLinearFilterOutput(bool smooth_transition,
+                              const SubtractorOutput& subtractor_output,
+                              rtc::ArrayView<float> output);
+
   static int instance_count_;
   const EchoCanceller3Config config_;
   const Aec3Fft fft_;
   std::unique_ptr<ApmDataDumper> data_dumper_;
   const Aec3Optimization optimization_;
   const int sample_rate_hz_;
+  const bool use_shadow_filter_output_;
+  const bool use_smooth_signal_transitions_;
   Subtractor subtractor_;
   SuppressionGain suppression_gain_;
   ComfortNoiseGenerator cng_;
@@ -103,6 +145,10 @@
   std::array<float, kFftLengthBy2> e_old_;
   std::array<float, kFftLengthBy2> x_old_;
   std::array<float, kFftLengthBy2> y_old_;
+  size_t block_counter_ = 0;
+  int gain_change_hangover_ = 0;
+  bool main_filter_output_last_selected_ = true;
+  bool linear_filter_output_last_selected_ = true;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(EchoRemoverImpl);
 };
@@ -117,6 +163,8 @@
           new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
       optimization_(DetectOptimization()),
       sample_rate_hz_(sample_rate_hz),
+      use_shadow_filter_output_(UseShadowFilterOutput()),
+      use_smooth_signal_transitions_(UseSmoothSignalTransitions()),
       subtractor_(config, data_dumper_.get(), optimization_),
       suppression_gain_(config_, optimization_, sample_rate_hz),
       cng_(optimization_),
@@ -136,15 +184,16 @@
   // Echo return loss (ERL) is inverted to go from gain to attenuation.
   metrics->echo_return_loss = -10.0 * log10(aec_state_.ErlTimeDomain());
   metrics->echo_return_loss_enhancement =
-      10.0 * log10(aec_state_.ErleTimeDomain());
+      Log2TodB(aec_state_.ErleTimeDomainLog2());
 }
 
 void EchoRemoverImpl::ProcessCapture(
-    const EchoPathVariability& echo_path_variability,
+    EchoPathVariability echo_path_variability,
     bool capture_signal_saturation,
-    const rtc::Optional<DelayEstimate>& external_delay,
+    const absl::optional<DelayEstimate>& external_delay,
     RenderBuffer* render_buffer,
     std::vector<std::vector<float>>* capture) {
+  ++block_counter_;
   const std::vector<std::vector<float>>& x = render_buffer->Block(0);
   std::vector<std::vector<float>>* y = capture;
   RTC_DCHECK(render_buffer);
@@ -166,10 +215,29 @@
   aec_state_.UpdateCaptureSaturation(capture_signal_saturation);
 
   if (echo_path_variability.AudioPathChanged()) {
+    // Ensure that the gain change is only acted on once per frame.
+    if (echo_path_variability.gain_change) {
+      if (gain_change_hangover_ == 0) {
+        constexpr int kMaxBlocksPerFrame = 3;
+        gain_change_hangover_ = kMaxBlocksPerFrame;
+        RTC_LOG(LS_WARNING)
+            << "Gain change detected at block " << block_counter_;
+      } else {
+        echo_path_variability.gain_change = false;
+      }
+    }
+
     subtractor_.HandleEchoPathChange(echo_path_variability);
     aec_state_.HandleEchoPathChange(echo_path_variability);
-    suppression_gain_.SetInitialState(true);
-    initial_state_ = true;
+
+    if (echo_path_variability.delay_change !=
+        EchoPathVariability::DelayAdjustment::kNone) {
+      suppression_gain_.SetInitialState(true);
+      initial_state_ = true;
+    }
+  }
+  if (gain_change_hangover_ > 0) {
+    --gain_change_hangover_;
   }
 
   std::array<float, kFftLengthBy2Plus1> Y2;
@@ -198,7 +266,8 @@
   // If the delay is known, use the echo subtractor.
   subtractor_.Process(*render_buffer, y0, render_signal_analyzer_, aec_state_,
                       &subtractor_output);
-  const auto& e = subtractor_output.e_main;
+  std::array<float, kBlockSize> e;
+  FormLinearFilterOutput(use_smooth_signal_transitions_, subtractor_output, e);
 
   // Compute spectra.
   WindowedPaddedFft(fft_, y0, y_old_, &Y);
@@ -209,9 +278,8 @@
 
   // Update the AEC state information.
   aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponse(),
-                    subtractor_.FilterImpulseResponse(),
-                    subtractor_.ConvergedFilter(), subtractor_.DivergedFilter(),
-                    *render_buffer, E2, Y2, subtractor_output.s_main);
+                    subtractor_.FilterImpulseResponse(), *render_buffer, E2, Y2,
+                    subtractor_output, y0);
 
   // Compute spectra.
   const bool suppression_gain_uses_ffts =
@@ -228,8 +296,18 @@
   data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0],
                         LowestBandRate(sample_rate_hz_), 1);
   if (aec_state_.UseLinearFilterOutput()) {
-    std::copy(e.begin(), e.end(), y0.begin());
+    if (!linear_filter_output_last_selected_ &&
+        use_smooth_signal_transitions_) {
+      SignalTransition(y0, e, y0);
+    } else {
+      std::copy(e.begin(), e.end(), y0.begin());
+    }
+  } else {
+    if (linear_filter_output_last_selected_ && use_smooth_signal_transitions_) {
+      SignalTransition(e, y0, y0);
+    }
   }
+  linear_filter_output_last_selected_ = aec_state_.UseLinearFilterOutput();
   const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y;
 
   data_dumper_->DumpWav("aec3_output_linear", kBlockSize, &y0[0],
@@ -242,8 +320,6 @@
   // Estimate the comfort noise.
   cng_.Compute(aec_state_, Y2, &comfort_noise, &high_band_comfort_noise);
 
-
-
   // Compute and apply the suppression gain.
   suppression_gain_.GetGain(E2, R2, cng_.NoiseSpectrum(), E, X, Y,
                             render_signal_analyzer_, aec_state_, x,
@@ -275,11 +351,59 @@
   data_dumper_->DumpRaw(
       "aec3_X2", render_buffer->Spectrum(aec_state_.FilterDelayBlocks()));
   data_dumper_->DumpRaw("aec3_R2", R2);
+  data_dumper_->DumpRaw("aec3_R2_reverb",
+                        residual_echo_estimator_.GetReverbPowerSpectrum());
   data_dumper_->DumpRaw("aec3_filter_delay", aec_state_.FilterDelayBlocks());
   data_dumper_->DumpRaw("aec3_capture_saturation",
                         aec_state_.SaturatedCapture() ? 1 : 0);
 }
 
+void EchoRemoverImpl::FormLinearFilterOutput(
+    bool smooth_transition,
+    const SubtractorOutput& subtractor_output,
+    rtc::ArrayView<float> output) {
+  RTC_DCHECK_EQ(subtractor_output.e_main.size(), output.size());
+  RTC_DCHECK_EQ(subtractor_output.e_shadow.size(), output.size());
+  bool use_main_output = true;
+  if (use_shadow_filter_output_) {
+    // As the output of the main adaptive filter generally should be better than
+    // the shadow filter output, add a margin and threshold for when choosing
+    // the shadow filter output.
+    if (subtractor_output.e2_shadow < 0.9f * subtractor_output.e2_main &&
+        subtractor_output.y2 > 30.f * 30.f * kBlockSize &&
+        (subtractor_output.s2_main > 60.f * 60.f * kBlockSize ||
+         subtractor_output.s2_shadow > 60.f * 60.f * kBlockSize)) {
+      use_main_output = false;
+    } else {
+      // If the main filter is diverged, choose the filter output that has the
+      // lowest power.
+      if (subtractor_output.e2_shadow < subtractor_output.e2_main &&
+          subtractor_output.y2 < subtractor_output.e2_main) {
+        use_main_output = false;
+      }
+    }
+  }
+
+  if (use_main_output) {
+    if (!main_filter_output_last_selected_ && smooth_transition) {
+      SignalTransition(subtractor_output.e_shadow, subtractor_output.e_main,
+                       output);
+    } else {
+      std::copy(subtractor_output.e_main.begin(),
+                subtractor_output.e_main.end(), output.begin());
+    }
+  } else {
+    if (main_filter_output_last_selected_ && smooth_transition) {
+      SignalTransition(subtractor_output.e_main, subtractor_output.e_shadow,
+                       output);
+    } else {
+      std::copy(subtractor_output.e_shadow.begin(),
+                subtractor_output.e_shadow.end(), output.begin());
+    }
+  }
+  main_filter_output_last_selected_ = use_main_output;
+}
+
 }  // namespace
 
 EchoRemover* EchoRemover::Create(const EchoCanceller3Config& config,
diff --git a/modules/audio_processing/aec3/echo_remover.h b/modules/audio_processing/aec3/echo_remover.h
index 61d2999..cc8dae9 100644
--- a/modules/audio_processing/aec3/echo_remover.h
+++ b/modules/audio_processing/aec3/echo_remover.h
@@ -13,9 +13,9 @@
 
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio/echo_canceller3_config.h"
 #include "api/audio/echo_control.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/delay_estimate.h"
 #include "modules/audio_processing/aec3/echo_path_variability.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
@@ -36,14 +36,14 @@
   // supplied render signal is assumed to be pre-aligned with the capture
   // signal.
   virtual void ProcessCapture(
-      const EchoPathVariability& echo_path_variability,
+      EchoPathVariability echo_path_variability,
       bool capture_signal_saturation,
-      const rtc::Optional<DelayEstimate>& external_delay,
+      const absl::optional<DelayEstimate>& external_delay,
       RenderBuffer* render_buffer,
       std::vector<std::vector<float>>* capture) = 0;
 
   // Returns the internal delay estimate in blocks.
-  virtual rtc::Optional<int> Delay() const = 0;
+  virtual absl::optional<int> Delay() const = 0;
 
   // Updates the status on whether echo leakage is detected in the output of the
   // echo remover.
diff --git a/modules/audio_processing/aec3/echo_remover_metrics.cc b/modules/audio_processing/aec3/echo_remover_metrics.cc
index c970649..8592a93 100644
--- a/modules/audio_processing/aec3/echo_remover_metrics.cc
+++ b/modules/audio_processing/aec3/echo_remover_metrics.cc
@@ -67,7 +67,7 @@
     aec3::UpdateDbMetric(aec_state.Erl(), &erl_);
     erl_time_domain_.UpdateInstant(aec_state.ErlTimeDomain());
     aec3::UpdateDbMetric(aec_state.Erle(), &erle_);
-    erle_time_domain_.UpdateInstant(aec_state.ErleTimeDomain());
+    erle_time_domain_.UpdateInstant(aec_state.ErleTimeDomainLog2());
     aec3::UpdateDbMetric(comfort_noise_spectrum, &comfort_noise_);
     aec3::UpdateDbMetric(suppressor_gain, &suppressor_gain_);
     active_render_count_ += (aec_state.ActiveRender() ? 1 : 0);
diff --git a/modules/audio_processing/aec3/echo_remover_metrics_unittest.cc b/modules/audio_processing/aec3/echo_remover_metrics_unittest.cc
index fbd30d1..fb9f151 100644
--- a/modules/audio_processing/aec3/echo_remover_metrics_unittest.cc
+++ b/modules/audio_processing/aec3/echo_remover_metrics_unittest.cc
@@ -12,8 +12,8 @@
 
 #include <math.h>
 
-#include "modules/audio_processing/aec3/aec_state.h"
 #include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/aec_state.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -78,23 +78,19 @@
 // Verifies that the TransformDbMetricForReporting method is able to properly
 // limit the output.
 TEST(TransformDbMetricForReporting, Limits) {
-  EXPECT_EQ(
-      0,
-      aec3::TransformDbMetricForReporting(false, 0.f, 10.f, 0.f, 1.f, 0.001f));
-  EXPECT_EQ(
-      10,
-      aec3::TransformDbMetricForReporting(false, 0.f, 10.f, 0.f, 1.f, 100.f));
+  EXPECT_EQ(0, aec3::TransformDbMetricForReporting(false, 0.f, 10.f, 0.f, 1.f,
+                                                   0.001f));
+  EXPECT_EQ(10, aec3::TransformDbMetricForReporting(false, 0.f, 10.f, 0.f, 1.f,
+                                                    100.f));
 }
 
 // Verifies that the TransformDbMetricForReporting method is able to properly
 // negate output.
 TEST(TransformDbMetricForReporting, Negate) {
-  EXPECT_EQ(
-      10,
-      aec3::TransformDbMetricForReporting(true, -20.f, 20.f, 0.f, 1.f, 0.1f));
-  EXPECT_EQ(
-      -10,
-      aec3::TransformDbMetricForReporting(true, -20.f, 20.f, 0.f, 1.f, 10.f));
+  EXPECT_EQ(10, aec3::TransformDbMetricForReporting(true, -20.f, 20.f, 0.f, 1.f,
+                                                    0.1f));
+  EXPECT_EQ(-10, aec3::TransformDbMetricForReporting(true, -20.f, 20.f, 0.f,
+                                                     1.f, 10.f));
 }
 
 // Verify the Update functionality of DbMetric.
diff --git a/modules/audio_processing/aec3/echo_remover_unittest.cc b/modules/audio_processing/aec3/echo_remover_unittest.cc
index 8e131fe..04a2727 100644
--- a/modules/audio_processing/aec3/echo_remover_unittest.cc
+++ b/modules/audio_processing/aec3/echo_remover_unittest.cc
@@ -43,7 +43,7 @@
 
 // Verifies the basic API call sequence
 TEST(EchoRemover, BasicApiCalls) {
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   for (auto rate : {8000, 16000, 32000, 48000}) {
     SCOPED_TRACE(ProduceDebugText(rate));
     std::unique_ptr<EchoRemover> remover(
@@ -84,7 +84,7 @@
 
 // Verifies the check for the capture block size.
 TEST(EchoRemover, WrongCaptureBlockSize) {
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   for (auto rate : {8000, 16000, 32000, 48000}) {
     SCOPED_TRACE(ProduceDebugText(rate));
     std::unique_ptr<EchoRemover> remover(
@@ -106,7 +106,7 @@
 // TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
 // tests on test bots has been fixed.c
 TEST(EchoRemover, DISABLED_WrongCaptureNumBands) {
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   for (auto rate : {16000, 32000, 48000}) {
     SCOPED_TRACE(ProduceDebugText(rate));
     std::unique_ptr<EchoRemover> remover(
@@ -127,7 +127,7 @@
 
 // Verifies the check for non-null capture block.
 TEST(EchoRemover, NullCapture) {
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   std::unique_ptr<EchoRemover> remover(
       EchoRemover::Create(EchoCanceller3Config(), 8000));
   std::unique_ptr<RenderDelayBuffer> render_buffer(
@@ -147,7 +147,7 @@
 TEST(EchoRemover, BasicEchoRemoval) {
   constexpr int kNumBlocksToProcess = 500;
   Random random_generator(42U);
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   for (auto rate : {8000, 16000, 32000, 48000}) {
     std::vector<std::vector<float>> x(NumBandsForRate(rate),
                                       std::vector<float>(kBlockSize, 0.f));
diff --git a/modules/audio_processing/aec3/erle_estimator.cc b/modules/audio_processing/aec3/erle_estimator.cc
index 18763cb..52ef8ed 100644
--- a/modules/audio_processing/aec3/erle_estimator.cc
+++ b/modules/audio_processing/aec3/erle_estimator.cc
@@ -13,29 +13,161 @@
 #include <algorithm>
 #include <numeric>
 
+#include "absl/types/optional.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/numerics/safe_minmax.h"
 
 namespace webrtc {
 
+namespace {
+constexpr int kPointsToAccumulate = 6;
+constexpr float kEpsilon = 1e-3f;
+}  // namespace
+
 ErleEstimator::ErleEstimator(float min_erle,
                              float max_erle_lf,
                              float max_erle_hf)
     : min_erle_(min_erle),
+      min_erle_log2_(FastApproxLog2f(min_erle_ + kEpsilon)),
       max_erle_lf_(max_erle_lf),
-      max_erle_hf_(max_erle_hf) {
+      max_erle_lf_log2(FastApproxLog2f(max_erle_lf_ + kEpsilon)),
+      max_erle_hf_(max_erle_hf),
+      erle_freq_inst_(kPointsToAccumulate),
+      erle_time_inst_(kPointsToAccumulate) {
   erle_.fill(min_erle_);
   erle_onsets_.fill(min_erle_);
   hold_counters_.fill(0);
   coming_onset_.fill(true);
-  erle_time_domain_ = min_erle_;
+  erle_time_domain_log2_ = min_erle_log2_;
   hold_counter_time_domain_ = 0;
 }
 
 ErleEstimator::~ErleEstimator() = default;
 
+ErleEstimator::ErleTimeInstantaneous::ErleTimeInstantaneous(
+    int points_to_accumulate)
+    : points_to_accumulate_(points_to_accumulate) {
+  Reset();
+}
+ErleEstimator::ErleTimeInstantaneous::~ErleTimeInstantaneous() = default;
+
+bool ErleEstimator::ErleTimeInstantaneous::Update(const float Y2_sum,
+                                                  const float E2_sum) {
+  bool ret = false;
+  E2_acum_ += E2_sum;
+  Y2_acum_ += Y2_sum;
+  num_points_++;
+  if (num_points_ == points_to_accumulate_) {
+    if (E2_acum_ > 0.f) {
+      ret = true;
+      erle_log2_ = FastApproxLog2f(Y2_acum_ / E2_acum_ + kEpsilon);
+    }
+    num_points_ = 0;
+    E2_acum_ = 0.f;
+    Y2_acum_ = 0.f;
+  }
+
+  if (ret) {
+    UpdateMaxMin();
+    UpdateQualityEstimate();
+  }
+  return ret;
+}
+
+void ErleEstimator::ErleTimeInstantaneous::Reset() {
+  ResetAccumulators();
+  max_erle_log2_ = -10.f;  // -30 dB.
+  min_erle_log2_ = 33.f;   // 100 dB.
+  inst_quality_estimate_ = 0.f;
+}
+
+void ErleEstimator::ErleTimeInstantaneous::ResetAccumulators() {
+  erle_log2_ = absl::nullopt;
+  inst_quality_estimate_ = 0.f;
+  num_points_ = 0;
+  E2_acum_ = 0.f;
+  Y2_acum_ = 0.f;
+}
+
+void ErleEstimator::ErleTimeInstantaneous::Dump(
+    const std::unique_ptr<ApmDataDumper>& data_dumper) {
+  data_dumper->DumpRaw("aec3_erle_time_inst_log2",
+                       erle_log2_ ? *erle_log2_ : -10.f);
+  data_dumper->DumpRaw(
+      "aec3_erle_time_quality",
+      GetInstQualityEstimate() ? GetInstQualityEstimate().value() : 0.f);
+  data_dumper->DumpRaw("aec3_erle_time_max_log2", max_erle_log2_);
+  data_dumper->DumpRaw("aec3_erle_time_min_log2", min_erle_log2_);
+}
+
+void ErleEstimator::ErleTimeInstantaneous::UpdateMaxMin() {
+  RTC_DCHECK(erle_log2_);
+  if (erle_log2_.value() > max_erle_log2_) {
+    max_erle_log2_ = erle_log2_.value();
+  } else {
+    max_erle_log2_ -= 0.0004;  // Forget factor, approx 1dB every 3 sec.
+  }
+
+  if (erle_log2_.value() < min_erle_log2_) {
+    min_erle_log2_ = erle_log2_.value();
+  } else {
+    min_erle_log2_ += 0.0004;  // Forget factor, approx 1dB every 3 sec.
+  }
+}
+
+void ErleEstimator::ErleTimeInstantaneous::UpdateQualityEstimate() {
+  const float alpha = 0.07f;
+  float quality_estimate = 0.f;
+  RTC_DCHECK(erle_log2_);
+  if (max_erle_log2_ > min_erle_log2_) {
+    quality_estimate = (erle_log2_.value() - min_erle_log2_) /
+                       (max_erle_log2_ - min_erle_log2_);
+  }
+  if (quality_estimate > inst_quality_estimate_) {
+    inst_quality_estimate_ = quality_estimate;
+  } else {
+    inst_quality_estimate_ +=
+        alpha * (quality_estimate - inst_quality_estimate_);
+  }
+}
+
+ErleEstimator::ErleFreqInstantaneous::ErleFreqInstantaneous(
+    int points_to_accumulate)
+    : points_to_accumulate_(points_to_accumulate) {
+  Reset();
+}
+
+ErleEstimator::ErleFreqInstantaneous::~ErleFreqInstantaneous() = default;
+
+absl::optional<float>
+ErleEstimator::ErleFreqInstantaneous::Update(float Y2, float E2, size_t band) {
+  absl::optional<float> ret = absl::nullopt;
+  RTC_DCHECK_LT(band, kFftLengthBy2Plus1);
+  Y2_acum_[band] += Y2;
+  E2_acum_[band] += E2;
+  if (++num_points_[band] == points_to_accumulate_) {
+    if (E2_acum_[band]) {
+      ret = Y2_acum_[band] / E2_acum_[band];
+    }
+    num_points_[band] = 0;
+    Y2_acum_[band] = 0.f;
+    E2_acum_[band] = 0.f;
+  }
+
+  return ret;
+}
+
+void ErleEstimator::ErleFreqInstantaneous::Reset() {
+  Y2_acum_.fill(0.f);
+  E2_acum_.fill(0.f);
+  num_points_.fill(0);
+}
+
 void ErleEstimator::Update(rtc::ArrayView<const float> render_spectrum,
                            rtc::ArrayView<const float> capture_spectrum,
-                           rtc::ArrayView<const float> subtractor_spectrum) {
+                           rtc::ArrayView<const float> subtractor_spectrum,
+                           bool converged_filter) {
   RTC_DCHECK_EQ(kFftLengthBy2Plus1, render_spectrum.size());
   RTC_DCHECK_EQ(kFftLengthBy2Plus1, capture_spectrum.size());
   RTC_DCHECK_EQ(kFftLengthBy2Plus1, subtractor_spectrum.size());
@@ -45,9 +177,9 @@
 
   // Corresponds of WGN of power -46 dBFS.
   constexpr float kX2Min = 44015068.0f;
-  constexpr int kOnsetSizeBlocks = 4;
+
   constexpr int kErleHold = 100;
-  constexpr int kErleOnsetHold = kErleHold + kOnsetSizeBlocks;
+  constexpr int kBlocksForOnsetDetection = kErleHold + 150;
 
   auto erle_band_update = [](float erle_band, float new_erle, float alpha_inc,
                              float alpha_dec, float min_erle, float max_erle) {
@@ -61,36 +193,43 @@
   // Update the estimates in a clamped minimum statistics manner.
   auto erle_update = [&](size_t start, size_t stop, float max_erle) {
     for (size_t k = start; k < stop; ++k) {
-      if (X2[k] > kX2Min && E2[k] > 0.f) {
-        const float new_erle = Y2[k] / E2[k];
-
-        if (coming_onset_[k - 1]) {
-          hold_counters_[k - 1] = kErleOnsetHold;
-          coming_onset_[k - 1] = false;
+      if (X2[k] > kX2Min) {
+        absl::optional<float> new_erle =
+            erle_freq_inst_.Update(Y2[k], E2[k], k);
+        if (new_erle) {
+          if (coming_onset_[k]) {
+            coming_onset_[k] = false;
+            erle_onsets_[k] =
+                erle_band_update(erle_onsets_[k], new_erle.value(), 0.15f, 0.3f,
+                                 min_erle_, max_erle);
+          }
+          hold_counters_[k] = kBlocksForOnsetDetection;
+          erle_[k] = erle_band_update(erle_[k], new_erle.value(), 0.05f, 0.1f,
+                                      min_erle_, max_erle);
         }
-        if (hold_counters_[k - 1] > kErleHold) {
-          erle_onsets_[k] = erle_band_update(erle_onsets_[k], new_erle, 0.05f,
-                                             0.1f, min_erle_, max_erle);
-        } else {
-          hold_counters_[k - 1] = kErleHold;
-        }
-        erle_[k] = erle_band_update(erle_[k], new_erle, 0.01f, 0.02f, min_erle_,
-                                    max_erle);
       }
     }
   };
 
-  constexpr size_t kFftLengthBy4 = kFftLengthBy2 / 2;
-  erle_update(1, kFftLengthBy4, max_erle_lf_);
-  erle_update(kFftLengthBy4, kFftLengthBy2, max_erle_hf_);
+  if (converged_filter) {
+    // Note that the use of the converged_filter flag already imposed
+    // a minimum of the erle that can be estimated as that flag would
+    // be false if the filter is performing poorly.
+    constexpr size_t kFftLengthBy4 = kFftLengthBy2 / 2;
+    erle_update(1, kFftLengthBy4, max_erle_lf_);
+    erle_update(kFftLengthBy4, kFftLengthBy2, max_erle_hf_);
+  }
 
-  for (size_t k = 0; k < hold_counters_.size(); ++k) {
+  for (size_t k = 1; k < kFftLengthBy2; ++k) {
     hold_counters_[k]--;
-    if (hold_counters_[k] <= 0) {
-      coming_onset_[k] = true;
-      if (erle_[k + 1] > erle_onsets_[k + 1]) {
-        erle_[k + 1] = std::max(erle_onsets_[k + 1], 0.97f * erle_[k + 1]);
-        RTC_DCHECK_LE(min_erle_, erle_[k + 1]);
+    if (hold_counters_[k] <= (kBlocksForOnsetDetection - kErleHold)) {
+      if (erle_[k] > erle_onsets_[k]) {
+        erle_[k] = std::max(erle_onsets_[k], 0.97f * erle_[k]);
+        RTC_DCHECK_LE(min_erle_, erle_[k]);
+      }
+      if (hold_counters_[k] <= 0) {
+        coming_onset_[k] = true;
+        hold_counters_[k] = 0;
       }
     }
   }
@@ -98,23 +237,37 @@
   erle_[0] = erle_[1];
   erle_[kFftLengthBy2] = erle_[kFftLengthBy2 - 1];
 
-  // Compute ERLE over all frequency bins.
-  const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f);
-  const float E2_sum = std::accumulate(E2.begin(), E2.end(), 0.0f);
-  if (X2_sum > kX2Min * X2.size() && E2_sum > 0.f) {
-    const float Y2_sum = std::accumulate(Y2.begin(), Y2.end(), 0.0f);
-    const float new_erle = Y2_sum / E2_sum;
-    if (new_erle > erle_time_domain_) {
-      hold_counter_time_domain_ = kErleHold;
-      erle_time_domain_ += 0.1f * (new_erle - erle_time_domain_);
-      erle_time_domain_ =
-          rtc::SafeClamp(erle_time_domain_, min_erle_, max_erle_lf_);
+  if (converged_filter) {
+    // Compute ERLE over all frequency bins.
+    const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f);
+    if (X2_sum > kX2Min * X2.size()) {
+      const float Y2_sum = std::accumulate(Y2.begin(), Y2.end(), 0.0f);
+      const float E2_sum = std::accumulate(E2.begin(), E2.end(), 0.0f);
+      if (erle_time_inst_.Update(Y2_sum, E2_sum)) {
+        hold_counter_time_domain_ = kErleHold;
+        erle_time_domain_log2_ +=
+            0.1f * ((erle_time_inst_.GetInstErle_log2().value()) -
+                    erle_time_domain_log2_);
+        erle_time_domain_log2_ = rtc::SafeClamp(
+            erle_time_domain_log2_, min_erle_log2_, max_erle_lf_log2);
+      }
     }
   }
   --hold_counter_time_domain_;
-  erle_time_domain_ = (hold_counter_time_domain_ > 0)
-                        ? erle_time_domain_
-                        : std::max(min_erle_, 0.97f * erle_time_domain_);
+  if (hold_counter_time_domain_ <= 0) {
+    erle_time_domain_log2_ =
+        std::max(min_erle_log2_, erle_time_domain_log2_ - 0.044f);
+  }
+  if (hold_counter_time_domain_ == 0) {
+    erle_time_inst_.ResetAccumulators();
+  }
+}
+
+void ErleEstimator::Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) {
+  data_dumper->DumpRaw("aec3_erle", Erle());
+  data_dumper->DumpRaw("aec3_erle_onset", ErleOnsets());
+  data_dumper->DumpRaw("aec3_erle_time_domain_log2", ErleTimeDomainLog2());
+  erle_time_inst_.Dump(data_dumper);
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/erle_estimator.h b/modules/audio_processing/aec3/erle_estimator.h
index 809466c..19bc7b4 100644
--- a/modules/audio_processing/aec3/erle_estimator.h
+++ b/modules/audio_processing/aec3/erle_estimator.h
@@ -13,8 +13,10 @@
 
 #include <array>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
@@ -28,7 +30,8 @@
   // Updates the ERLE estimate.
   void Update(rtc::ArrayView<const float> render_spectrum,
               rtc::ArrayView<const float> capture_spectrum,
-              rtc::ArrayView<const float> subtractor_spectrum);
+              rtc::ArrayView<const float> subtractor_spectrum,
+              bool converged_filter);
 
   // Returns the most recent ERLE estimate.
   const std::array<float, kFftLengthBy2Plus1>& Erle() const { return erle_; }
@@ -36,19 +39,80 @@
   const std::array<float, kFftLengthBy2Plus1>& ErleOnsets() const {
     return erle_onsets_;
   }
-  float ErleTimeDomain() const { return erle_time_domain_; }
+  float ErleTimeDomainLog2() const { return erle_time_domain_log2_; }
+
+  absl::optional<float> GetInstLinearQualityEstimate() const {
+    return erle_time_inst_.GetInstQualityEstimate();
+  }
+
+  void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper);
+
+  class ErleTimeInstantaneous {
+   public:
+    ErleTimeInstantaneous(int points_to_accumulate);
+    ~ErleTimeInstantaneous();
+    // Update the estimator with a new point, returns true
+    // if the instantaneous erle was updated due to having enough
+    // points for performing the estimate.
+    bool Update(const float Y2_sum, const float E2_sum);
+    // Reset all the members of the class.
+    void Reset();
+    // Reset the members realated with an instantaneous estimate.
+    void ResetAccumulators();
+    // Returns the instantaneous ERLE in log2 units.
+    absl::optional<float> GetInstErle_log2() const { return erle_log2_; }
+    // Get an indication between 0 and 1 of the performance of the linear filter
+    // for the current time instant.
+    absl::optional<float> GetInstQualityEstimate() const {
+      return erle_log2_ ? absl::optional<float>(inst_quality_estimate_)
+                        : absl::nullopt;
+    }
+    void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper);
+
+   private:
+    void UpdateMaxMin();
+    void UpdateQualityEstimate();
+    absl::optional<float> erle_log2_;
+    float inst_quality_estimate_;
+    float max_erle_log2_;
+    float min_erle_log2_;
+    float Y2_acum_;
+    float E2_acum_;
+    int num_points_;
+    const int points_to_accumulate_;
+  };
+
+  class ErleFreqInstantaneous {
+   public:
+    ErleFreqInstantaneous(int points_to_accumulate);
+    ~ErleFreqInstantaneous();
+    // Updates the ERLE for a band with a new block. Returns absl::nullopt
+    // if not enough points were accuulated for doing the estimation.
+    absl::optional<float> Update(float Y2, float E2, size_t band);
+    // Reset all the member of the class.
+    void Reset();
+
+   private:
+    std::array<float, kFftLengthBy2Plus1> Y2_acum_;
+    std::array<float, kFftLengthBy2Plus1> E2_acum_;
+    std::array<int, kFftLengthBy2Plus1> num_points_;
+    const int points_to_accumulate_;
+  };
 
  private:
   std::array<float, kFftLengthBy2Plus1> erle_;
   std::array<float, kFftLengthBy2Plus1> erle_onsets_;
-  std::array<bool, kFftLengthBy2Minus1> coming_onset_;
-  std::array<int, kFftLengthBy2Minus1> hold_counters_;
-  float erle_time_domain_;
+  std::array<bool, kFftLengthBy2Plus1> coming_onset_;
+  std::array<int, kFftLengthBy2Plus1> hold_counters_;
   int hold_counter_time_domain_;
+  float erle_time_domain_log2_;
   const float min_erle_;
+  const float min_erle_log2_;
   const float max_erle_lf_;
+  const float max_erle_lf_log2;
   const float max_erle_hf_;
-
+  ErleFreqInstantaneous erle_freq_inst_;
+  ErleTimeInstantaneous erle_time_inst_;
   RTC_DISALLOW_COPY_AND_ASSIGN(ErleEstimator);
 };
 
diff --git a/modules/audio_processing/aec3/erle_estimator_unittest.cc b/modules/audio_processing/aec3/erle_estimator_unittest.cc
index 9ccdb20..86ac5df 100644
--- a/modules/audio_processing/aec3/erle_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/erle_estimator_unittest.cc
@@ -8,7 +8,10 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include <cmath>
+
 #include "modules/audio_processing/aec3/erle_estimator.h"
+#include "api/array_view.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -22,7 +25,7 @@
 constexpr float kTrueErle = 10.f;
 constexpr float kTrueErleOnsets = 1.0f;
 
-void VerifyErleBands(const std::array<float, kFftLengthBy2Plus1>& erle,
+void VerifyErleBands(rtc::ArrayView<const float> erle,
                      float reference_lf,
                      float reference_hf) {
   std::for_each(
@@ -33,12 +36,12 @@
       [reference_hf](float a) { EXPECT_NEAR(reference_hf, a, 0.001); });
 }
 
-void VerifyErle(const std::array<float, kFftLengthBy2Plus1>& erle,
+void VerifyErle(rtc::ArrayView<const float> erle,
                 float erle_time_domain,
                 float reference_lf,
                 float reference_hf) {
   VerifyErleBands(erle, reference_lf, reference_hf);
-  EXPECT_NEAR(reference_lf, erle_time_domain, 0.001);
+  EXPECT_NEAR(reference_lf, erle_time_domain, 0.5);
 }
 
 void FormFarendFrame(std::array<float, kFftLengthBy2Plus1>* X2,
@@ -71,17 +74,19 @@
   FormFarendFrame(&X2, &E2, &Y2, kTrueErle);
 
   for (size_t k = 0; k < 200; ++k) {
-    estimator.Update(X2, Y2, E2);
+    estimator.Update(X2, Y2, E2, true);
   }
-  VerifyErle(estimator.Erle(), estimator.ErleTimeDomain(), 8.f, 1.5f);
+  VerifyErle(estimator.Erle(), std::pow(2.f, estimator.ErleTimeDomainLog2()),
+             kMaxErleLf, kMaxErleHf);
 
   FormNearendFrame(&X2, &E2, &Y2);
   // Verifies that the ERLE is not immediately decreased during nearend
   // activity.
-  for (size_t k = 0; k < 98; ++k) {
-    estimator.Update(X2, Y2, E2);
+  for (size_t k = 0; k < 50; ++k) {
+    estimator.Update(X2, Y2, E2, true);
   }
-  VerifyErle(estimator.Erle(), estimator.ErleTimeDomain(), 8.f, 1.5f);
+  VerifyErle(estimator.Erle(), std::pow(2.f, estimator.ErleTimeDomainLog2()),
+             kMaxErleLf, kMaxErleHf);
 }
 
 TEST(ErleEstimator, VerifyErleTrackingOnOnsets) {
@@ -94,24 +99,25 @@
   for (size_t burst = 0; burst < 20; ++burst) {
     FormFarendFrame(&X2, &E2, &Y2, kTrueErleOnsets);
     for (size_t k = 0; k < 10; ++k) {
-      estimator.Update(X2, Y2, E2);
+      estimator.Update(X2, Y2, E2, true);
     }
     FormFarendFrame(&X2, &E2, &Y2, kTrueErle);
     for (size_t k = 0; k < 200; ++k) {
-      estimator.Update(X2, Y2, E2);
+      estimator.Update(X2, Y2, E2, true);
     }
     FormNearendFrame(&X2, &E2, &Y2);
-    for (size_t k = 0; k < 100; ++k) {
-      estimator.Update(X2, Y2, E2);
+    for (size_t k = 0; k < 300; ++k) {
+      estimator.Update(X2, Y2, E2, true);
     }
   }
   VerifyErleBands(estimator.ErleOnsets(), kMinErle, kMinErle);
   FormNearendFrame(&X2, &E2, &Y2);
   for (size_t k = 0; k < 1000; k++) {
-    estimator.Update(X2, Y2, E2);
+    estimator.Update(X2, Y2, E2, true);
   }
   // Verifies that during ne activity, Erle converges to the Erle for onsets.
-  VerifyErle(estimator.Erle(), estimator.ErleTimeDomain(), kMinErle, kMinErle);
+  VerifyErle(estimator.Erle(), std::pow(2.f, estimator.ErleTimeDomainLog2()),
+             kMinErle, kMinErle);
 }
 
 TEST(ErleEstimator, VerifyNoErleUpdateDuringLowActivity) {
@@ -125,9 +131,10 @@
   X2.fill(1000.f * 1000.f);
   Y2.fill(10 * E2[0]);
   for (size_t k = 0; k < 200; ++k) {
-    estimator.Update(X2, Y2, E2);
+    estimator.Update(X2, Y2, E2, true);
   }
-  VerifyErle(estimator.Erle(), estimator.ErleTimeDomain(), kMinErle, kMinErle);
+  VerifyErle(estimator.Erle(), std::pow(2.f, estimator.ErleTimeDomainLog2()),
+             kMinErle, kMinErle);
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/filter_analyzer.cc b/modules/audio_processing/aec3/filter_analyzer.cc
index 363373c..ab2c4f2 100644
--- a/modules/audio_processing/aec3/filter_analyzer.cc
+++ b/modules/audio_processing/aec3/filter_analyzer.cc
@@ -15,7 +15,11 @@
 #include <array>
 #include <numeric>
 
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomicops.h"
 #include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
@@ -34,17 +38,44 @@
   return peak_index;
 }
 
+bool EnableFilterPreprocessing() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch");
+}
+
 }  // namespace
 
+int FilterAnalyzer::instance_count_ = 0;
+
 FilterAnalyzer::FilterAnalyzer(const EchoCanceller3Config& config)
-    : bounded_erl_(config.ep_strength.bounded_erl),
+    : data_dumper_(
+          new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+      use_preprocessed_filter_(EnableFilterPreprocessing()),
+      bounded_erl_(config.ep_strength.bounded_erl),
       default_gain_(config.ep_strength.lf),
       active_render_threshold_(config.render_levels.active_render_limit *
                                config.render_levels.active_render_limit *
-                               kFftLengthBy2) {
+                               kFftLengthBy2),
+      h_highpass_(GetTimeDomainLength(config.filter.main.length_blocks), 0.f),
+      filter_length_blocks_(config.filter.main_initial.length_blocks) {
   Reset();
 }
 
+void FilterAnalyzer::PreProcessFilter(
+    rtc::ArrayView<const float> filter_time_domain) {
+  RTC_DCHECK_GE(h_highpass_.capacity(), filter_time_domain.size());
+  h_highpass_.resize(filter_time_domain.size());
+  // Minimum phase high-pass filter with cutoff frequency at about 600 Hz.
+  constexpr std::array<float, 3> h = {{0.7929742f, -0.36072128f, -0.47047766f}};
+
+  std::fill(h_highpass_.begin(), h_highpass_.end(), 0.f);
+  for (size_t k = h.size() - 1; k < filter_time_domain.size(); ++k) {
+    for (size_t j = 0; j < h.size(); ++j) {
+      h_highpass_[k] += filter_time_domain[k - j] * h[j];
+    }
+  }
+}
+
 FilterAnalyzer::~FilterAnalyzer() = default;
 
 void FilterAnalyzer::Reset() {
@@ -57,33 +88,45 @@
   gain_ = default_gain_;
 }
 
-void FilterAnalyzer::Update(rtc::ArrayView<const float> filter_time_domain,
-                            const RenderBuffer& render_buffer) {
-  size_t peak_index = FindPeakIndex(filter_time_domain);
-  delay_blocks_ = peak_index / kBlockSize;
+void FilterAnalyzer::Update(
+    rtc::ArrayView<const float> filter_time_domain,
+    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+        filter_freq_response,
+    const RenderBuffer& render_buffer) {
+  // Preprocess the filter to avoid issues with low-frequency components in the
+  // filter.
+  if (use_preprocessed_filter_) {
+    PreProcessFilter(filter_time_domain);
+    data_dumper_->DumpRaw("aec3_linear_filter_processed_td", h_highpass_);
+  }
+  const auto& filter_to_analyze =
+      use_preprocessed_filter_ ? h_highpass_ : filter_time_domain;
+  RTC_DCHECK_EQ(filter_to_analyze.size(), filter_time_domain.size());
 
-  UpdateFilterGain(filter_time_domain, peak_index);
+  size_t peak_index = FindPeakIndex(filter_to_analyze);
+  delay_blocks_ = peak_index >> kBlockSizeLog2;
+  UpdateFilterGain(filter_to_analyze, peak_index);
 
   float filter_floor = 0;
   float filter_secondary_peak = 0;
   size_t limit1 = peak_index < 64 ? 0 : peak_index - 64;
   size_t limit2 =
-      peak_index > filter_time_domain.size() - 129 ? 0 : peak_index + 128;
+      peak_index > filter_to_analyze.size() - 129 ? 0 : peak_index + 128;
 
   for (size_t k = 0; k < limit1; ++k) {
-    float abs_h = fabsf(filter_time_domain[k]);
+    float abs_h = fabsf(filter_to_analyze[k]);
     filter_floor += abs_h;
     filter_secondary_peak = std::max(filter_secondary_peak, abs_h);
   }
-  for (size_t k = limit2; k < filter_time_domain.size(); ++k) {
-    float abs_h = fabsf(filter_time_domain[k]);
+  for (size_t k = limit2; k < filter_to_analyze.size(); ++k) {
+    float abs_h = fabsf(filter_to_analyze[k]);
     filter_floor += abs_h;
     filter_secondary_peak = std::max(filter_secondary_peak, abs_h);
   }
 
-  filter_floor /= (limit1 + filter_time_domain.size() - limit2);
+  filter_floor /= (limit1 + filter_to_analyze.size() - limit2);
 
-  float abs_peak = fabsf(filter_time_domain[peak_index]);
+  float abs_peak = fabsf(filter_to_analyze[peak_index]);
   bool significant_peak_index =
       abs_peak > 10.f * filter_floor && abs_peak > 2.f * filter_secondary_peak;
 
@@ -103,6 +146,8 @@
 
   consistent_estimate_ =
       consistent_estimate_counter_ > 1.5f * kNumBlocksPerSecond;
+
+  filter_length_blocks_ = filter_time_domain.size() * (1.f / kBlockSize);
 }
 
 void FilterAnalyzer::UpdateFilterGain(
diff --git a/modules/audio_processing/aec3/filter_analyzer.h b/modules/audio_processing/aec3/filter_analyzer.h
index f02a210..627341d 100644
--- a/modules/audio_processing/aec3/filter_analyzer.h
+++ b/modules/audio_processing/aec3/filter_analyzer.h
@@ -11,17 +11,21 @@
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_
 
+#include <array>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/cascaded_biquad_filter.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
 
+class ApmDataDumper;
+
 // Class for analyzing the properties of an adaptive filter.
 class FilterAnalyzer {
  public:
@@ -33,6 +37,8 @@
 
   // Updates the estimates with new input data.
   void Update(rtc::ArrayView<const float> filter_time_domain,
+              const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+                  filter_freq_response,
               const RenderBuffer& render_buffer);
 
   // Returns the delay of the filter in terms of blocks.
@@ -45,21 +51,33 @@
   // Returns the estimated filter gain.
   float Gain() const { return gain_; }
 
+  // Returns the number of blocks for the current used filter.
+  float FilterLengthBlocks() const { return filter_length_blocks_; }
+
  private:
   void UpdateFilterGain(rtc::ArrayView<const float> filter_time_domain,
                         size_t max_index);
+  void PreProcessFilter(rtc::ArrayView<const float> filter_time_domain);
 
+  // Updates the estimation of the frequency response at the filter tails.
+  void UpdateFreqRespTail(
+      const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+          filter_freq_response);
+
+  static int instance_count_;
+  std::unique_ptr<ApmDataDumper> data_dumper_;
+  const bool use_preprocessed_filter_;
   const bool bounded_erl_;
   const float default_gain_;
   const float active_render_threshold_;
-
+  std::vector<float> h_highpass_;
   int delay_blocks_ = 0;
   size_t blocks_since_reset_ = 0;
   bool consistent_estimate_ = false;
   size_t consistent_estimate_counter_ = 0;
   int consistent_delay_reference_ = -10;
   float gain_;
-
+  int filter_length_blocks_;
   RTC_DISALLOW_COPY_AND_ASSIGN(FilterAnalyzer);
 };
 
diff --git a/modules/audio_processing/aec3/main_filter_update_gain.cc b/modules/audio_processing/aec3/main_filter_update_gain.cc
index 6aa5780..6d31ed0 100644
--- a/modules/audio_processing/aec3/main_filter_update_gain.cc
+++ b/modules/audio_processing/aec3/main_filter_update_gain.cc
@@ -22,6 +22,7 @@
 namespace {
 
 constexpr float kHErrorInitial = 10000.f;
+constexpr float kHErrorGainChange = 10000.f;
 constexpr int kPoorExcitationCounterInitial = 1000;
 
 }  // namespace
@@ -46,10 +47,19 @@
 
 void MainFilterUpdateGain::HandleEchoPathChange(
     const EchoPathVariability& echo_path_variability) {
-  // TODO(peah): Add even-specific behavior.
-  H_error_.fill(kHErrorInitial);
-  poor_excitation_counter_ = kPoorExcitationCounterInitial;
-  call_counter_ = 0;
+  if (echo_path_variability.gain_change) {
+    H_error_.fill(kHErrorGainChange);
+  }
+
+  if (echo_path_variability.delay_change !=
+      EchoPathVariability::DelayAdjustment::kNone) {
+    H_error_.fill(kHErrorInitial);
+  }
+
+  if (!echo_path_variability.gain_change) {
+    poor_excitation_counter_ = kPoorExcitationCounterInitial;
+    call_counter_ = 0;
+  }
 }
 
 void MainFilterUpdateGain::Compute(
diff --git a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
index 3d0a8c3..bed148a 100644
--- a/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
+++ b/modules/audio_processing/aec3/main_filter_update_gain_unittest.cc
@@ -68,7 +68,7 @@
       RenderDelayBuffer::Create(config, 3));
   AecState aec_state(config);
   RenderSignalAnalyzer render_signal_analyzer(config);
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   std::array<float, kFftLength> s_scratch;
   std::array<float, kBlockSize> s;
   FftData S;
@@ -162,8 +162,9 @@
     aec_state.HandleEchoPathChange(EchoPathVariability(
         false, EchoPathVariability::DelayAdjustment::kNone, false));
     aec_state.Update(delay_estimate, main_filter.FilterFrequencyResponse(),
-                     main_filter.FilterImpulseResponse(), true, false,
-                     *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+                     main_filter.FilterImpulseResponse(),
+                     *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
+                     output, y);
   }
 
   std::copy(e_main.begin(), e_main.end(), e_last_block->begin());
@@ -221,7 +222,7 @@
       std::array<float, kBlockSize> y;
       FftData G;
 
-      RunFilterUpdateTest(500, delay_samples, filter_length_blocks,
+      RunFilterUpdateTest(600, delay_samples, filter_length_blocks,
                           blocks_with_echo_path_changes, blocks_with_saturation,
                           false, &e, &y, &G);
 
@@ -241,34 +242,34 @@
 // Verifies that the magnitude of the gain on average decreases for a
 // persistently exciting signal.
 TEST(MainFilterUpdateGain, DecreasingGain) {
-    std::vector<int> blocks_with_echo_path_changes;
-    std::vector<int> blocks_with_saturation;
+  std::vector<int> blocks_with_echo_path_changes;
+  std::vector<int> blocks_with_saturation;
 
-    std::array<float, kBlockSize> e;
-    std::array<float, kBlockSize> y;
-    FftData G_a;
-    FftData G_b;
-    FftData G_c;
-    std::array<float, kFftLengthBy2Plus1> G_a_power;
-    std::array<float, kFftLengthBy2Plus1> G_b_power;
-    std::array<float, kFftLengthBy2Plus1> G_c_power;
+  std::array<float, kBlockSize> e;
+  std::array<float, kBlockSize> y;
+  FftData G_a;
+  FftData G_b;
+  FftData G_c;
+  std::array<float, kFftLengthBy2Plus1> G_a_power;
+  std::array<float, kFftLengthBy2Plus1> G_b_power;
+  std::array<float, kFftLengthBy2Plus1> G_c_power;
 
-    RunFilterUpdateTest(100, 65, 12, blocks_with_echo_path_changes,
-                        blocks_with_saturation, false, &e, &y, &G_a);
-    RunFilterUpdateTest(300, 65, 12, blocks_with_echo_path_changes,
-                        blocks_with_saturation, false, &e, &y, &G_b);
-    RunFilterUpdateTest(600, 65, 12, blocks_with_echo_path_changes,
-                        blocks_with_saturation, false, &e, &y, &G_c);
+  RunFilterUpdateTest(250, 65, 12, blocks_with_echo_path_changes,
+                      blocks_with_saturation, false, &e, &y, &G_a);
+  RunFilterUpdateTest(500, 65, 12, blocks_with_echo_path_changes,
+                      blocks_with_saturation, false, &e, &y, &G_b);
+  RunFilterUpdateTest(750, 65, 12, blocks_with_echo_path_changes,
+                      blocks_with_saturation, false, &e, &y, &G_c);
 
-    G_a.Spectrum(Aec3Optimization::kNone, G_a_power);
-    G_b.Spectrum(Aec3Optimization::kNone, G_b_power);
-    G_c.Spectrum(Aec3Optimization::kNone, G_c_power);
+  G_a.Spectrum(Aec3Optimization::kNone, G_a_power);
+  G_b.Spectrum(Aec3Optimization::kNone, G_b_power);
+  G_c.Spectrum(Aec3Optimization::kNone, G_c_power);
 
-    EXPECT_GT(std::accumulate(G_a_power.begin(), G_a_power.end(), 0.),
-              std::accumulate(G_b_power.begin(), G_b_power.end(), 0.));
+  EXPECT_GT(std::accumulate(G_a_power.begin(), G_a_power.end(), 0.),
+            std::accumulate(G_b_power.begin(), G_b_power.end(), 0.));
 
-    EXPECT_GT(std::accumulate(G_b_power.begin(), G_b_power.end(), 0.),
-              std::accumulate(G_c_power.begin(), G_c_power.end(), 0.));
+  EXPECT_GT(std::accumulate(G_b_power.begin(), G_b_power.end(), 0.),
+            std::accumulate(G_c_power.begin(), G_c_power.end(), 0.));
 }
 
 // Verifies that the gain is zero when there is saturation and that the internal
diff --git a/modules/audio_processing/aec3/matched_filter.h b/modules/audio_processing/aec3/matched_filter.h
index 36c9cad..8add6fe 100644
--- a/modules/audio_processing/aec3/matched_filter.h
+++ b/modules/audio_processing/aec3/matched_filter.h
@@ -15,8 +15,8 @@
 #include <memory>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/downsampled_render_buffer.h"
 #include "rtc_base/constructormagic.h"
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
index 23cd71a..9cd2eb3 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
@@ -30,7 +30,7 @@
   significant_candidate_found_ = false;
 }
 
-rtc::Optional<DelayEstimate> MatchedFilterLagAggregator::Aggregate(
+absl::optional<DelayEstimate> MatchedFilterLagAggregator::Aggregate(
     rtc::ArrayView<const MatchedFilter::LagEstimate> lag_estimates) {
   // Choose the strongest lag estimate as the best one.
   float best_accuracy = 0.f;
@@ -72,7 +72,7 @@
       return DelayEstimate(DelayEstimate::Quality::kRefined, candidate);
     }
   }
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
index 86968bd..fddcfbf 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
@@ -13,7 +13,7 @@
 
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_processing/aec3/delay_estimate.h"
 #include "modules/audio_processing/aec3/matched_filter.h"
 #include "rtc_base/constructormagic.h"
@@ -33,7 +33,7 @@
   void Reset();
 
   // Aggregates the provided lag estimates.
-  rtc::Optional<DelayEstimate> Aggregate(
+  absl::optional<DelayEstimate> Aggregate(
       rtc::ArrayView<const MatchedFilter::LagEstimate> lag_estimates);
 
  private:
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc
index 18b8829..cea5f13 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc
@@ -6,7 +6,7 @@
  *  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.
-  */
+ */
 
 #include "modules/audio_processing/aec3/matched_filter_lag_aggregator.h"
 
@@ -40,7 +40,7 @@
     aggregator.Aggregate(lag_estimates);
   }
 
-  rtc::Optional<DelayEstimate> aggregated_lag =
+  absl::optional<DelayEstimate> aggregated_lag =
       aggregator.Aggregate(lag_estimates);
   EXPECT_TRUE(aggregated_lag);
   EXPECT_EQ(kLag1, aggregated_lag->delay);
@@ -68,7 +68,7 @@
   std::vector<MatchedFilter::LagEstimate> lag_estimates(1);
   MatchedFilterLagAggregator aggregator(&data_dumper, 100);
 
-  rtc::Optional<DelayEstimate> aggregated_lag;
+  absl::optional<DelayEstimate> aggregated_lag;
   for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) {
     lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, 10, true);
     aggregated_lag = aggregator.Aggregate(lag_estimates);
@@ -98,7 +98,7 @@
   MatchedFilterLagAggregator aggregator(&data_dumper, kLag);
   for (size_t k = 0; k < kNumLagsBeforeDetection * 10; ++k) {
     lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag, false);
-    rtc::Optional<DelayEstimate> aggregated_lag =
+    absl::optional<DelayEstimate> aggregated_lag =
         aggregator.Aggregate(lag_estimates);
     EXPECT_FALSE(aggregated_lag);
     EXPECT_EQ(kLag, aggregated_lag->delay);
@@ -114,7 +114,7 @@
   ApmDataDumper data_dumper(0);
   std::vector<MatchedFilter::LagEstimate> lag_estimates(1);
   MatchedFilterLagAggregator aggregator(&data_dumper, std::max(kLag1, kLag2));
-  rtc::Optional<DelayEstimate> aggregated_lag;
+  absl::optional<DelayEstimate> aggregated_lag;
   for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) {
     lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag1, true);
     aggregated_lag = aggregator.Aggregate(lag_estimates);
diff --git a/modules/audio_processing/aec3/matched_filter_unittest.cc b/modules/audio_processing/aec3/matched_filter_unittest.cc
index e30c78c..fd878ff 100644
--- a/modules/audio_processing/aec3/matched_filter_unittest.cc
+++ b/modules/audio_processing/aec3/matched_filter_unittest.cc
@@ -6,7 +6,7 @@
  *  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.
-  */
+ */
 
 #include "modules/audio_processing/aec3/matched_filter.h"
 
@@ -183,7 +183,7 @@
       auto lag_estimates = filter.GetLagEstimates();
 
       // Find which lag estimate should be the most accurate.
-      rtc::Optional<size_t> expected_most_accurate_lag_estimate;
+      absl::optional<size_t> expected_most_accurate_lag_estimate;
       size_t alignment_shift_sub_blocks = 0;
       for (size_t k = 0; k < config.delay.num_filters; ++k) {
         if ((alignment_shift_sub_blocks + 3 * kWindowSizeSubBlocks / 4) *
diff --git a/modules/audio_processing/aec3/mock/mock_block_processor.cc b/modules/audio_processing/aec3/mock/mock_block_processor.cc
new file mode 100644
index 0000000..c5c33db
--- /dev/null
+++ b/modules/audio_processing/aec3/mock/mock_block_processor.cc
@@ -0,0 +1,20 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/mock/mock_block_processor.h"
+
+namespace webrtc {
+namespace test {
+
+MockBlockProcessor::MockBlockProcessor() = default;
+MockBlockProcessor::~MockBlockProcessor() = default;
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/mock/mock_block_processor.h b/modules/audio_processing/aec3/mock/mock_block_processor.h
index 803bf78..85b88f7 100644
--- a/modules/audio_processing/aec3/mock/mock_block_processor.h
+++ b/modules/audio_processing/aec3/mock/mock_block_processor.h
@@ -21,7 +21,8 @@
 
 class MockBlockProcessor : public BlockProcessor {
  public:
-  virtual ~MockBlockProcessor() {}
+  MockBlockProcessor();
+  virtual ~MockBlockProcessor();
 
   MOCK_METHOD3(ProcessCapture,
                void(bool level_change,
diff --git a/modules/audio_processing/aec3/mock/mock_echo_remover.cc b/modules/audio_processing/aec3/mock/mock_echo_remover.cc
new file mode 100644
index 0000000..b903bf0
--- /dev/null
+++ b/modules/audio_processing/aec3/mock/mock_echo_remover.cc
@@ -0,0 +1,20 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/mock/mock_echo_remover.h"
+
+namespace webrtc {
+namespace test {
+
+MockEchoRemover::MockEchoRemover() = default;
+MockEchoRemover::~MockEchoRemover() = default;
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/mock/mock_echo_remover.h b/modules/audio_processing/aec3/mock/mock_echo_remover.h
index 0acf139..5faea26 100644
--- a/modules/audio_processing/aec3/mock/mock_echo_remover.h
+++ b/modules/audio_processing/aec3/mock/mock_echo_remover.h
@@ -13,7 +13,7 @@
 
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_processing/aec3/echo_path_variability.h"
 #include "modules/audio_processing/aec3/echo_remover.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
@@ -24,15 +24,16 @@
 
 class MockEchoRemover : public EchoRemover {
  public:
-  virtual ~MockEchoRemover() = default;
+  MockEchoRemover();
+  virtual ~MockEchoRemover();
 
   MOCK_METHOD5(ProcessCapture,
-               void(const EchoPathVariability& echo_path_variability,
+               void(EchoPathVariability echo_path_variability,
                     bool capture_signal_saturation,
-                    const rtc::Optional<DelayEstimate>& delay_estimate,
+                    const absl::optional<DelayEstimate>& delay_estimate,
                     RenderBuffer* render_buffer,
                     std::vector<std::vector<float>>* capture));
-  MOCK_CONST_METHOD0(Delay, rtc::Optional<int>());
+  MOCK_CONST_METHOD0(Delay, absl::optional<int>());
   MOCK_METHOD1(UpdateEchoLeakageStatus, void(bool leakage_detected));
   MOCK_CONST_METHOD1(GetMetrics, void(EchoControl::Metrics* metrics));
 };
diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc
new file mode 100644
index 0000000..20214cb
--- /dev/null
+++ b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.cc
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/mock/mock_render_delay_buffer.h"
+
+namespace webrtc {
+namespace test {
+
+MockRenderDelayBuffer::MockRenderDelayBuffer(int sample_rate_hz)
+    : block_buffer_(GetRenderDelayBufferSize(4, 4, 12),
+                    NumBandsForRate(sample_rate_hz),
+                    kBlockSize),
+      spectrum_buffer_(block_buffer_.buffer.size(), kFftLengthBy2Plus1),
+      fft_buffer_(block_buffer_.buffer.size()),
+      render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_),
+      downsampled_render_buffer_(GetDownSampledBufferSize(4, 4)) {
+  ON_CALL(*this, GetRenderBuffer())
+      .WillByDefault(
+          testing::Invoke(this, &MockRenderDelayBuffer::FakeGetRenderBuffer));
+  ON_CALL(*this, GetDownsampledRenderBuffer())
+      .WillByDefault(testing::Invoke(
+          this, &MockRenderDelayBuffer::FakeGetDownsampledRenderBuffer));
+}
+
+MockRenderDelayBuffer::~MockRenderDelayBuffer() = default;
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h
index 00c13f4..ba5e98c 100644
--- a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h
+++ b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h
@@ -24,22 +24,8 @@
 
 class MockRenderDelayBuffer : public RenderDelayBuffer {
  public:
-  explicit MockRenderDelayBuffer(int sample_rate_hz)
-      : block_buffer_(GetRenderDelayBufferSize(4, 4, 12),
-                      NumBandsForRate(sample_rate_hz),
-                      kBlockSize),
-        spectrum_buffer_(block_buffer_.buffer.size(), kFftLengthBy2Plus1),
-        fft_buffer_(block_buffer_.buffer.size()),
-        render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_),
-        downsampled_render_buffer_(GetDownSampledBufferSize(4, 4)) {
-    ON_CALL(*this, GetRenderBuffer())
-        .WillByDefault(
-            testing::Invoke(this, &MockRenderDelayBuffer::FakeGetRenderBuffer));
-    ON_CALL(*this, GetDownsampledRenderBuffer())
-        .WillByDefault(testing::Invoke(
-            this, &MockRenderDelayBuffer::FakeGetDownsampledRenderBuffer));
-  }
-  virtual ~MockRenderDelayBuffer() = default;
+  explicit MockRenderDelayBuffer(int sample_rate_hz);
+  virtual ~MockRenderDelayBuffer();
 
   MOCK_METHOD0(Reset, void());
   MOCK_METHOD1(Insert,
diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_controller.cc b/modules/audio_processing/aec3/mock/mock_render_delay_controller.cc
new file mode 100644
index 0000000..4ae2af9
--- /dev/null
+++ b/modules/audio_processing/aec3/mock/mock_render_delay_controller.cc
@@ -0,0 +1,20 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/mock/mock_render_delay_controller.h"
+
+namespace webrtc {
+namespace test {
+
+MockRenderDelayController::MockRenderDelayController() = default;
+MockRenderDelayController::~MockRenderDelayController() = default;
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_controller.h b/modules/audio_processing/aec3/mock/mock_render_delay_controller.h
index fab2b65..ed5971c 100644
--- a/modules/audio_processing/aec3/mock/mock_render_delay_controller.h
+++ b/modules/audio_processing/aec3/mock/mock_render_delay_controller.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_MOCK_MOCK_RENDER_DELAY_CONTROLLER_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_MOCK_MOCK_RENDER_DELAY_CONTROLLER_H_
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/downsampled_render_buffer.h"
 #include "modules/audio_processing/aec3/render_delay_controller.h"
 #include "test/gmock.h"
@@ -22,16 +22,17 @@
 
 class MockRenderDelayController : public RenderDelayController {
  public:
-  virtual ~MockRenderDelayController() = default;
+  MockRenderDelayController();
+  virtual ~MockRenderDelayController();
 
   MOCK_METHOD0(Reset, void());
   MOCK_METHOD0(LogRenderCall, void());
-  MOCK_METHOD4(
-      GetDelay,
-      rtc::Optional<DelayEstimate>(const DownsampledRenderBuffer& render_buffer,
-                                   size_t render_delay_buffer_delay,
-                                   const rtc::Optional<int>& echo_remover_delay,
-                                   rtc::ArrayView<const float> capture));
+  MOCK_METHOD4(GetDelay,
+               absl::optional<DelayEstimate>(
+                   const DownsampledRenderBuffer& render_buffer,
+                   size_t render_delay_buffer_delay,
+                   const absl::optional<int>& echo_remover_delay,
+                   rtc::ArrayView<const float> capture));
 };
 
 }  // namespace test
diff --git a/modules/audio_processing/aec3/moving_average.cc b/modules/audio_processing/aec3/moving_average.cc
new file mode 100644
index 0000000..e9d64e6
--- /dev/null
+++ b/modules/audio_processing/aec3/moving_average.cc
@@ -0,0 +1,58 @@
+
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/moving_average.h"
+
+#include <algorithm>
+#include <functional>
+
+namespace webrtc {
+namespace aec3 {
+
+MovingAverage::MovingAverage(size_t num_elem, size_t mem_len)
+    : num_elem_(num_elem),
+      mem_len_(mem_len - 1),
+      scaling_(1.0f / static_cast<float>(mem_len)),
+      memory_(num_elem * mem_len_, 0.f),
+      mem_index_(0) {
+  RTC_DCHECK(num_elem_ > 0);
+  RTC_DCHECK(mem_len > 0);
+}
+
+MovingAverage::~MovingAverage() = default;
+
+void MovingAverage::Average(rtc::ArrayView<const float> input,
+                            rtc::ArrayView<float> output) {
+  RTC_DCHECK(input.size() == num_elem_);
+  RTC_DCHECK(output.size() == num_elem_);
+
+  // Sum all contributions.
+  std::copy(input.begin(), input.end(), output.begin());
+  for (auto i = memory_.begin(); i < memory_.end(); i += num_elem_) {
+    std::transform(i, i + num_elem_, output.begin(), output.begin(),
+                   std::plus<float>());
+  }
+
+  // Divide by mem_len_.
+  for (float& o : output) {
+    o *= scaling_;
+  }
+
+  // Update memory.
+  if (mem_len_ > 0) {
+    std::copy(input.begin(), input.end(),
+              memory_.begin() + mem_index_ * num_elem_);
+    mem_index_ = (mem_index_ + 1) % mem_len_;
+  }
+}
+
+}  // namespace aec3
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/moving_average.h b/modules/audio_processing/aec3/moving_average.h
new file mode 100644
index 0000000..94497d7
--- /dev/null
+++ b/modules/audio_processing/aec3/moving_average.h
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+namespace aec3 {
+
+class MovingAverage {
+ public:
+  // Creates an instance of MovingAverage that accepts inputs of length num_elem
+  // and averages over mem_len inputs.
+  MovingAverage(size_t num_elem, size_t mem_len);
+  ~MovingAverage();
+
+  // Computes the average of input and mem_len-1 previous inputs and stores the
+  // result in output.
+  void Average(rtc::ArrayView<const float> input, rtc::ArrayView<float> output);
+
+ private:
+  const size_t num_elem_;
+  const size_t mem_len_;
+  const float scaling_;
+  std::vector<float> memory_;
+  size_t mem_index_;
+};
+
+}  // namespace aec3
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_
diff --git a/modules/audio_processing/aec3/moving_average_unittest.cc b/modules/audio_processing/aec3/moving_average_unittest.cc
new file mode 100644
index 0000000..05542d1
--- /dev/null
+++ b/modules/audio_processing/aec3/moving_average_unittest.cc
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/moving_average.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(MovingAverage, Average) {
+  constexpr size_t num_elem = 4;
+  constexpr size_t mem_len = 3;
+  constexpr float e = 1e-6f;
+  aec3::MovingAverage ma(num_elem, mem_len);
+  std::array<float, num_elem> data1 = {1, 2, 3, 4};
+  std::array<float, num_elem> data2 = {5, 1, 9, 7};
+  std::array<float, num_elem> data3 = {3, 3, 5, 6};
+  std::array<float, num_elem> data4 = {8, 4, 2, 1};
+  std::array<float, num_elem> output;
+
+  ma.Average(data1, output);
+  EXPECT_NEAR(output[0], data1[0] / 3.0f, e);
+  EXPECT_NEAR(output[1], data1[1] / 3.0f, e);
+  EXPECT_NEAR(output[2], data1[2] / 3.0f, e);
+  EXPECT_NEAR(output[3], data1[3] / 3.0f, e);
+
+  ma.Average(data2, output);
+  EXPECT_NEAR(output[0], (data1[0] + data2[0]) / 3.0f, e);
+  EXPECT_NEAR(output[1], (data1[1] + data2[1]) / 3.0f, e);
+  EXPECT_NEAR(output[2], (data1[2] + data2[2]) / 3.0f, e);
+  EXPECT_NEAR(output[3], (data1[3] + data2[3]) / 3.0f, e);
+
+  ma.Average(data3, output);
+  EXPECT_NEAR(output[0], (data1[0] + data2[0] + data3[0]) / 3.0f, e);
+  EXPECT_NEAR(output[1], (data1[1] + data2[1] + data3[1]) / 3.0f, e);
+  EXPECT_NEAR(output[2], (data1[2] + data2[2] + data3[2]) / 3.0f, e);
+  EXPECT_NEAR(output[3], (data1[3] + data2[3] + data3[3]) / 3.0f, e);
+
+  ma.Average(data4, output);
+  EXPECT_NEAR(output[0], (data2[0] + data3[0] + data4[0]) / 3.0f, e);
+  EXPECT_NEAR(output[1], (data2[1] + data3[1] + data4[1]) / 3.0f, e);
+  EXPECT_NEAR(output[2], (data2[2] + data3[2] + data4[2]) / 3.0f, e);
+  EXPECT_NEAR(output[3], (data2[3] + data3[3] + data4[3]) / 3.0f, e);
+}
+
+TEST(MovingAverage, PassThrough) {
+  constexpr size_t num_elem = 4;
+  constexpr size_t mem_len = 1;
+  constexpr float e = 1e-6f;
+  aec3::MovingAverage ma(num_elem, mem_len);
+  std::array<float, num_elem> data1 = {1, 2, 3, 4};
+  std::array<float, num_elem> data2 = {5, 1, 9, 7};
+  std::array<float, num_elem> data3 = {3, 3, 5, 6};
+  std::array<float, num_elem> data4 = {8, 4, 2, 1};
+  std::array<float, num_elem> output;
+
+  ma.Average(data1, output);
+  EXPECT_NEAR(output[0], data1[0], e);
+  EXPECT_NEAR(output[1], data1[1], e);
+  EXPECT_NEAR(output[2], data1[2], e);
+  EXPECT_NEAR(output[3], data1[3], e);
+
+  ma.Average(data2, output);
+  EXPECT_NEAR(output[0], data2[0], e);
+  EXPECT_NEAR(output[1], data2[1], e);
+  EXPECT_NEAR(output[2], data2[2], e);
+  EXPECT_NEAR(output[3], data2[3], e);
+
+  ma.Average(data3, output);
+  EXPECT_NEAR(output[0], data3[0], e);
+  EXPECT_NEAR(output[1], data3[1], e);
+  EXPECT_NEAR(output[2], data3[2], e);
+  EXPECT_NEAR(output[3], data3[3], e);
+
+  ma.Average(data4, output);
+  EXPECT_NEAR(output[0], data4[0], e);
+  EXPECT_NEAR(output[1], data4[1], e);
+  EXPECT_NEAR(output[2], data4[2], e);
+  EXPECT_NEAR(output[3], data4[3], e);
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/render_buffer.h b/modules/audio_processing/aec3/render_buffer.h
index 9419b30..34e7edf 100644
--- a/modules/audio_processing/aec3/render_buffer.h
+++ b/modules/audio_processing/aec3/render_buffer.h
@@ -82,7 +82,6 @@
     return headroom;
   }
 
-
   // Returns a reference to the spectrum buffer.
   const VectorBuffer& GetSpectrumBuffer() const { return *spectrum_buffer_; }
 
diff --git a/modules/audio_processing/aec3/render_delay_buffer.cc b/modules/audio_processing/aec3/render_delay_buffer.cc
index 5aa432d..37a2378 100644
--- a/modules/audio_processing/aec3/render_delay_buffer.cc
+++ b/modules/audio_processing/aec3/render_delay_buffer.cc
@@ -25,10 +25,24 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
 
+bool EnableZeroExternalDelayHeadroom() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch");
+}
+
+size_t GetDownSamplingFactor(const EchoCanceller3Config& config) {
+  // Do not use down sampling factor 8 if kill switch is triggered.
+  return (config.delay.down_sampling_factor == 8 &&
+          field_trial::IsEnabled("WebRTC-Aec3DownSamplingFactor8KillSwitch"))
+             ? 4
+             : config.delay.down_sampling_factor;
+}
+
 class RenderDelayBufferImpl final : public RenderDelayBuffer {
  public:
   RenderDelayBufferImpl(const EchoCanceller3Config& config, size_t num_bands);
@@ -57,12 +71,14 @@
   std::unique_ptr<ApmDataDumper> data_dumper_;
   const Aec3Optimization optimization_;
   const EchoCanceller3Config config_;
+  size_t down_sampling_factor_;
+  const bool use_zero_external_delay_headroom_;
   const int sub_block_size_;
   MatrixBuffer blocks_;
   VectorBuffer spectra_;
   FftBuffer ffts_;
-  rtc::Optional<size_t> delay_;
-  rtc::Optional<int> internal_delay_;
+  absl::optional<size_t> delay_;
+  absl::optional<int> internal_delay_;
   RenderBuffer echo_remover_buffer_;
   DownsampledRenderBuffer low_rate_;
   Decimator render_decimator_;
@@ -77,7 +93,7 @@
   size_t render_call_counter_ = 0;
   bool render_activity_ = false;
   size_t render_activity_counter_ = 0;
-  rtc::Optional<size_t> external_audio_buffer_delay_ms_;
+  absl::optional<size_t> external_audio_buffer_delay_;
   bool external_delay_verified_after_reset_ = false;
 
   int LowRateBufferOffset() const { return DelayEstimatorOffset(config_) >> 1; }
@@ -104,7 +120,7 @@
 }
 
 // Increases the read indices for the render buffers.
-void IncreaseReadIndices(const rtc::Optional<int>& delay,
+void IncreaseReadIndices(const absl::optional<int>& delay,
                          int sub_block_size,
                          MatrixBuffer* blocks,
                          VectorBuffer* spectra,
@@ -131,7 +147,7 @@
 // Checks for a render buffer underrun. If the delay is not specified, only the
 // low rate buffer underrun is counted as the delay offset for the other buffers
 // is unknown.
-bool RenderUnderrun(const rtc::Optional<int>& delay,
+bool RenderUnderrun(const absl::optional<int>& delay,
                     const MatrixBuffer& b,
                     const DownsampledRenderBuffer& l) {
   return l.read == l.write || (delay && b.read == b.write);
@@ -161,11 +177,12 @@
           new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
       optimization_(DetectOptimization()),
       config_(config),
-      sub_block_size_(
-          static_cast<int>(config.delay.down_sampling_factor > 0
-                               ? kBlockSize / config.delay.down_sampling_factor
-                               : kBlockSize)),
-      blocks_(GetRenderDelayBufferSize(config.delay.down_sampling_factor,
+      down_sampling_factor_(GetDownSamplingFactor(config)),
+      use_zero_external_delay_headroom_(EnableZeroExternalDelayHeadroom()),
+      sub_block_size_(static_cast<int>(down_sampling_factor_ > 0
+                                           ? kBlockSize / down_sampling_factor_
+                                           : kBlockSize)),
+      blocks_(GetRenderDelayBufferSize(down_sampling_factor_,
                                        config.delay.num_filters,
                                        config.filter.main.length_blocks),
               num_bands,
@@ -174,9 +191,9 @@
       ffts_(blocks_.buffer.size()),
       delay_(config_.delay.default_delay),
       echo_remover_buffer_(&blocks_, &spectra_, &ffts_),
-      low_rate_(GetDownSampledBufferSize(config.delay.down_sampling_factor,
+      low_rate_(GetDownSampledBufferSize(down_sampling_factor_,
                                          config.delay.num_filters)),
-      render_decimator_(config.delay.down_sampling_factor),
+      render_decimator_(down_sampling_factor_),
       zero_block_(num_bands, std::vector<float>(kBlockSize, 0.f)),
       fft_(),
       render_ds_(sub_block_size_, 0.f),
@@ -202,22 +219,23 @@
       low_rate_.write, LowRateBufferOffset() * sub_block_size_);
 
   // Check for any external audio buffer delay and whether it is feasible.
-  if (external_audio_buffer_delay_ms_) {
-    constexpr size_t kHeadroom = 5;
+  if (external_audio_buffer_delay_) {
+    const size_t headroom = use_zero_external_delay_headroom_ ? 0 : 2;
     size_t external_delay_to_set = 0;
-    if (*external_audio_buffer_delay_ms_ < kHeadroom) {
+    if (*external_audio_buffer_delay_ < headroom) {
       external_delay_to_set = 0;
     } else {
-      external_delay_to_set = *external_audio_buffer_delay_ms_ - kHeadroom;
+      external_delay_to_set = *external_audio_buffer_delay_ - headroom;
     }
 
-    constexpr size_t kMaxExternalDelay = 170;
-    external_delay_to_set = std::min(external_delay_to_set, kMaxExternalDelay);
+    external_delay_to_set = std::min(external_delay_to_set, MaxDelay());
 
     // When an external delay estimate is available, use that delay as the
-    // initial render buffer delay. Avoid verifying the set delay.
-    external_delay_verified_after_reset_ = true;
-    SetDelay(external_delay_to_set);
+    // initial render buffer delay.
+    internal_delay_ = external_delay_to_set;
+    ApplyDelay(*internal_delay_);
+    delay_ = MapInternalDelayToExternalDelay();
+
     external_delay_verified_after_reset_ = false;
   } else {
     // If an external delay estimate is not available, use that delay as the
@@ -225,8 +243,8 @@
     ApplyDelay(config_.delay.default_delay);
 
     // Unset the delays which are set by SetDelay.
-    delay_ = rtc::nullopt;
-    internal_delay_ = rtc::nullopt;
+    delay_ = absl::nullopt;
+    internal_delay_ = absl::nullopt;
   }
 }
 
@@ -330,13 +348,12 @@
 
 // Sets the delay and returns a bool indicating whether the delay was changed.
 bool RenderDelayBufferImpl::SetDelay(size_t delay) {
-  if (!external_delay_verified_after_reset_ &&
-      external_audio_buffer_delay_ms_) {
-    int delay_difference = static_cast<int>(*external_audio_buffer_delay_ms_) -
-                           static_cast<int>(delay);
-    RTC_LOG(LS_WARNING) << "Difference between the externally reported delay "
-                           "and the first delay estimate: "
-                        << delay_difference << " ms.";
+  if (!external_delay_verified_after_reset_ && external_audio_buffer_delay_ &&
+      delay_) {
+    int difference = static_cast<int>(delay) - static_cast<int>(*delay_);
+    RTC_LOG(LS_WARNING) << "Mismatch between first estimated delay after reset "
+                           "and external delay: "
+                        << difference << " blocks";
     external_delay_verified_after_reset_ = true;
   }
   if (delay_ && *delay_ == delay) {
@@ -366,12 +383,14 @@
 }
 
 void RenderDelayBufferImpl::SetAudioBufferDelay(size_t delay_ms) {
-  if (!external_audio_buffer_delay_ms_) {
+  if (!external_audio_buffer_delay_) {
     RTC_LOG(LS_WARNING)
         << "Receiving a first reported externally buffer delay of " << delay_ms
         << " ms.";
   }
-  external_audio_buffer_delay_ms_ = delay_ms;
+
+  // Convert delay from milliseconds to blocks (rounded down).
+  external_audio_buffer_delay_ = delay_ms / 4;
 }
 
 // Maps the externally computed delay to the delay used internally.
@@ -419,7 +438,11 @@
     std::copy(block[k].begin(), block[k].end(), b.buffer[b.write][k].begin());
   }
 
+  data_dumper_->DumpWav("aec3_render_decimator_input", block[0].size(),
+                        block[0].data(), 16000, 1);
   render_decimator_.Decimate(block[0], ds);
+  data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(),
+                        16000 / down_sampling_factor_, 1);
   std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write);
   fft_.PaddedFft(block[0], b.buffer[previous_write][0], &f.buffer[f.write]);
   f.buffer[f.write].Spectrum(optimization_, s.buffer[s.write]);
diff --git a/modules/audio_processing/aec3/render_delay_buffer.h b/modules/audio_processing/aec3/render_delay_buffer.h
index e361628..a6d6874 100644
--- a/modules/audio_processing/aec3/render_delay_buffer.h
+++ b/modules/audio_processing/aec3/render_delay_buffer.h
@@ -15,9 +15,9 @@
 #include <array>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/downsampled_render_buffer.h"
 #include "modules/audio_processing/aec3/fft_data.h"
diff --git a/modules/audio_processing/aec3/render_delay_controller.cc b/modules/audio_processing/aec3/render_delay_controller.cc
index fc91108..8adf5f5 100644
--- a/modules/audio_processing/aec3/render_delay_controller.cc
+++ b/modules/audio_processing/aec3/render_delay_controller.cc
@@ -23,11 +23,23 @@
 #include "rtc_base/atomicops.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
 namespace {
 
+int GetSkewHysteresis(const EchoCanceller3Config& config) {
+  if (field_trial::IsEnabled("WebRTC-Aec3EnforceSkewHysteresis1")) {
+    return 1;
+  }
+  if (field_trial::IsEnabled("WebRTC-Aec3EnforceSkewHysteresis2")) {
+    return 2;
+  }
+
+  return static_cast<int>(config.delay.skew_hysteresis_blocks);
+}
+
 constexpr int kSkewHistorySizeLog2 = 8;
 
 class RenderDelayControllerImpl final : public RenderDelayController {
@@ -38,10 +50,10 @@
   ~RenderDelayControllerImpl() override;
   void Reset() override;
   void LogRenderCall() override;
-  rtc::Optional<DelayEstimate> GetDelay(
+  absl::optional<DelayEstimate> GetDelay(
       const DownsampledRenderBuffer& render_buffer,
       size_t render_delay_buffer_delay,
-      const rtc::Optional<int>& echo_remover_delay,
+      const absl::optional<int>& echo_remover_delay,
       rtc::ArrayView<const float> capture) override;
 
  private:
@@ -51,14 +63,14 @@
   const int hysteresis_limit_1_blocks_;
   const int hysteresis_limit_2_blocks_;
   const int skew_hysteresis_blocks_;
-  rtc::Optional<DelayEstimate> delay_;
+  absl::optional<DelayEstimate> delay_;
   EchoPathDelayEstimator delay_estimator_;
   std::vector<float> delay_buf_;
   int delay_buf_index_ = 0;
   RenderDelayControllerMetrics metrics_;
   SkewEstimator skew_estimator_;
-  rtc::Optional<DelayEstimate> delay_samples_;
-  rtc::Optional<int> skew_;
+  absl::optional<DelayEstimate> delay_samples_;
+  absl::optional<int> skew_;
   int previous_offset_blocks_ = 0;
   int skew_shift_reporting_counter_ = 0;
   size_t capture_call_counter_ = 0;
@@ -68,7 +80,7 @@
 };
 
 DelayEstimate ComputeBufferDelay(
-    const rtc::Optional<DelayEstimate>& current_delay,
+    const absl::optional<DelayEstimate>& current_delay,
     int delay_headroom_blocks,
     int hysteresis_limit_1_blocks,
     int hysteresis_limit_2_blocks,
@@ -118,8 +130,7 @@
           static_cast<int>(config.delay.hysteresis_limit_1_blocks)),
       hysteresis_limit_2_blocks_(
           static_cast<int>(config.delay.hysteresis_limit_2_blocks)),
-      skew_hysteresis_blocks_(
-          static_cast<int>(config.delay.skew_hysteresis_blocks)),
+      skew_hysteresis_blocks_(GetSkewHysteresis(config)),
       delay_estimator_(data_dumper_.get(), config),
       delay_buf_(kBlockSize * non_causal_offset, 0.f),
       skew_estimator_(kSkewHistorySizeLog2) {
@@ -131,9 +142,9 @@
 RenderDelayControllerImpl::~RenderDelayControllerImpl() = default;
 
 void RenderDelayControllerImpl::Reset() {
-  delay_ = rtc::nullopt;
-  delay_samples_ = rtc::nullopt;
-  skew_ = rtc::nullopt;
+  delay_ = absl::nullopt;
+  delay_samples_ = absl::nullopt;
+  skew_ = absl::nullopt;
   previous_offset_blocks_ = 0;
   std::fill(delay_buf_.begin(), delay_buf_.end(), 0.f);
   delay_estimator_.Reset(false);
@@ -146,10 +157,10 @@
   skew_estimator_.LogRenderCall();
 }
 
-rtc::Optional<DelayEstimate> RenderDelayControllerImpl::GetDelay(
+absl::optional<DelayEstimate> RenderDelayControllerImpl::GetDelay(
     const DownsampledRenderBuffer& render_buffer,
     size_t render_delay_buffer_delay,
-    const rtc::Optional<int>& echo_remover_delay,
+    const absl::optional<int>& echo_remover_delay,
     rtc::ArrayView<const float> capture) {
   RTC_DCHECK_EQ(kBlockSize, capture.size());
   ++capture_call_counter_;
@@ -174,7 +185,7 @@
   delay_buf_index_ = (delay_buf_index_ + kBlockSize) % delay_buf_.size();
 
   // Compute the latest skew update.
-  rtc::Optional<int> skew = skew_estimator_.GetSkewFromCapture();
+  absl::optional<int> skew = skew_estimator_.GetSkewFromCapture();
 
   if (delay_samples) {
     // TODO(peah): Refactor the rest of the code to assume a kRefined estimate
@@ -230,11 +241,11 @@
   // Log any changes in the skew.
   skew_shift_reporting_counter_ =
       std::max(0, skew_shift_reporting_counter_ - 1);
-  rtc::Optional<int> skew_shift =
+  absl::optional<int> skew_shift =
       skew_shift_reporting_counter_ == 0 &&
               previous_offset_blocks_ != offset_blocks
-          ? rtc::Optional<int>(offset_blocks - previous_offset_blocks_)
-          : rtc::nullopt;
+          ? absl::optional<int>(offset_blocks - previous_offset_blocks_)
+          : absl::nullopt;
   previous_offset_blocks_ = offset_blocks;
   if (skew_shift) {
     RTC_LOG(LS_WARNING) << "API call skew shift of " << *skew_shift
@@ -250,8 +261,8 @@
         hysteresis_limit_2_blocks_, offset_blocks, *delay_samples_);
   }
 
-  metrics_.Update(delay_samples_ ? rtc::Optional<size_t>(delay_samples_->delay)
-                                 : rtc::nullopt,
+  metrics_.Update(delay_samples_ ? absl::optional<size_t>(delay_samples_->delay)
+                                 : absl::nullopt,
                   delay_ ? delay_->delay : 0, skew_shift);
 
   data_dumper_->DumpRaw("aec3_render_delay_controller_delay",
diff --git a/modules/audio_processing/aec3/render_delay_controller.h b/modules/audio_processing/aec3/render_delay_controller.h
index 1e1df0d..ddd9548 100644
--- a/modules/audio_processing/aec3/render_delay_controller.h
+++ b/modules/audio_processing/aec3/render_delay_controller.h
@@ -11,9 +11,9 @@
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/delay_estimate.h"
 #include "modules/audio_processing/aec3/downsampled_render_buffer.h"
 #include "modules/audio_processing/aec3/render_delay_buffer.h"
@@ -36,10 +36,10 @@
   virtual void LogRenderCall() = 0;
 
   // Aligns the render buffer content with the capture signal.
-  virtual rtc::Optional<DelayEstimate> GetDelay(
+  virtual absl::optional<DelayEstimate> GetDelay(
       const DownsampledRenderBuffer& render_buffer,
       size_t render_delay_buffer_delay,
-      const rtc::Optional<int>& echo_remover_delay,
+      const absl::optional<int>& echo_remover_delay,
       rtc::ArrayView<const float> capture) = 0;
 };
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/render_delay_controller_metrics.cc b/modules/audio_processing/aec3/render_delay_controller_metrics.cc
index e5668da..09db339 100644
--- a/modules/audio_processing/aec3/render_delay_controller_metrics.cc
+++ b/modules/audio_processing/aec3/render_delay_controller_metrics.cc
@@ -43,20 +43,23 @@
 RenderDelayControllerMetrics::RenderDelayControllerMetrics() = default;
 
 void RenderDelayControllerMetrics::Update(
-    rtc::Optional<size_t> delay_samples,
+    absl::optional<size_t> delay_samples,
     size_t buffer_delay_blocks,
-    rtc::Optional<int> skew_shift_blocks) {
+    absl::optional<int> skew_shift_blocks) {
   ++call_counter_;
 
   if (!initial_update) {
+    size_t delay_blocks;
     if (delay_samples) {
       ++reliable_delay_estimate_counter_;
-      size_t delay_blocks = (*delay_samples) / kBlockSize;
+      delay_blocks = (*delay_samples) / kBlockSize + 2;
+    } else {
+      delay_blocks = 0;
+    }
 
-      if (delay_blocks != delay_blocks_) {
-        ++delay_change_counter_;
-        delay_blocks_ = delay_blocks;
-      }
+    if (delay_blocks != delay_blocks_) {
+      ++delay_change_counter_;
+      delay_blocks_ = delay_blocks;
     }
 
     if (skew_shift_blocks) {
@@ -68,12 +71,12 @@
 
   if (call_counter_ == kMetricsReportingIntervalBlocks) {
     int value_to_report = static_cast<int>(delay_blocks_);
-    value_to_report = std::min(124, value_to_report);
+    value_to_report = std::min(124, value_to_report >> 1);
     RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.EchoPathDelay",
                                 value_to_report, 0, 124, 125);
 
-    value_to_report = static_cast<int>(buffer_delay_blocks);
-    value_to_report = std::min(124, value_to_report);
+    value_to_report = static_cast<int>(buffer_delay_blocks + 2);
+    value_to_report = std::min(124, value_to_report >> 1);
     RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.BufferDelay",
                                 value_to_report, 0, 124, 125);
 
diff --git a/modules/audio_processing/aec3/render_delay_controller_metrics.h b/modules/audio_processing/aec3/render_delay_controller_metrics.h
index 8c8845e..1cfe899 100644
--- a/modules/audio_processing/aec3/render_delay_controller_metrics.h
+++ b/modules/audio_processing/aec3/render_delay_controller_metrics.h
@@ -11,7 +11,7 @@
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
@@ -22,9 +22,9 @@
   RenderDelayControllerMetrics();
 
   // Updates the metric with new data.
-  void Update(rtc::Optional<size_t> delay_samples,
+  void Update(absl::optional<size_t> delay_samples,
               size_t buffer_delay_blocks,
-              rtc::Optional<int> skew_shift_blocks);
+              absl::optional<int> skew_shift_blocks);
 
   // Returns true if the metrics have just been reported, otherwise false.
   bool MetricsReported() { return metrics_reported_; }
diff --git a/modules/audio_processing/aec3/render_delay_controller_metrics_unittest.cc b/modules/audio_processing/aec3/render_delay_controller_metrics_unittest.cc
index 1129f49..e867de4 100644
--- a/modules/audio_processing/aec3/render_delay_controller_metrics_unittest.cc
+++ b/modules/audio_processing/aec3/render_delay_controller_metrics_unittest.cc
@@ -9,7 +9,7 @@
  */
 
 #include "modules/audio_processing/aec3/render_delay_controller_metrics.h"
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 
 #include "test/gtest.h"
@@ -22,10 +22,10 @@
 
   for (int j = 0; j < 3; ++j) {
     for (int k = 0; k < kMetricsReportingIntervalBlocks - 1; ++k) {
-      metrics.Update(rtc::nullopt, 0, rtc::nullopt);
+      metrics.Update(absl::nullopt, 0, absl::nullopt);
       EXPECT_FALSE(metrics.MetricsReported());
     }
-    metrics.Update(rtc::nullopt, 0, rtc::nullopt);
+    metrics.Update(absl::nullopt, 0, absl::nullopt);
     EXPECT_TRUE(metrics.MetricsReported());
   }
 }
diff --git a/modules/audio_processing/aec3/render_delay_controller_unittest.cc b/modules/audio_processing/aec3/render_delay_controller_unittest.cc
index 2c9bbef..98d5b25 100644
--- a/modules/audio_processing/aec3/render_delay_controller_unittest.cc
+++ b/modules/audio_processing/aec3/render_delay_controller_unittest.cc
@@ -48,7 +48,7 @@
 TEST(RenderDelayController, NoRenderSignal) {
   std::vector<float> block(kBlockSize, 0.f);
   EchoCanceller3Config config;
-  rtc::Optional<int> echo_remover_delay_;
+  absl::optional<int> echo_remover_delay_;
   for (size_t num_matched_filters = 4; num_matched_filters == 10;
        num_matched_filters++) {
     for (auto down_sampling_factor : kDownSamplingFactors) {
@@ -75,8 +75,8 @@
 // Verifies the basic API call sequence.
 TEST(RenderDelayController, BasicApiCalls) {
   std::vector<float> capture_block(kBlockSize, 0.f);
-  rtc::Optional<DelayEstimate> delay_blocks;
-  rtc::Optional<int> echo_remover_delay;
+  absl::optional<DelayEstimate> delay_blocks;
+  absl::optional<int> echo_remover_delay;
   for (size_t num_matched_filters = 4; num_matched_filters == 10;
        num_matched_filters++) {
     for (auto down_sampling_factor : kDownSamplingFactors) {
@@ -111,7 +111,7 @@
 // simple timeshifts between the signals.
 TEST(RenderDelayController, Alignment) {
   Random random_generator(42U);
-  rtc::Optional<int> echo_remover_delay;
+  absl::optional<int> echo_remover_delay;
   std::vector<float> capture_block(kBlockSize, 0.f);
   for (size_t num_matched_filters = 4; num_matched_filters == 10;
        num_matched_filters++) {
@@ -125,7 +125,7 @@
             NumBandsForRate(rate), std::vector<float>(kBlockSize, 0.f));
 
         for (size_t delay_samples : {15, 50, 150, 200, 800, 4000}) {
-          rtc::Optional<DelayEstimate> delay_blocks;
+          absl::optional<DelayEstimate> delay_blocks;
           SCOPED_TRACE(ProduceDebugText(rate, delay_samples));
           std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
               RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
@@ -162,7 +162,7 @@
 // delays.
 TEST(RenderDelayController, NonCausalAlignment) {
   Random random_generator(42U);
-  rtc::Optional<int> echo_remover_delay;
+  absl::optional<int> echo_remover_delay;
   for (size_t num_matched_filters = 4; num_matched_filters == 10;
        num_matched_filters++) {
     for (auto down_sampling_factor : kDownSamplingFactors) {
@@ -176,7 +176,7 @@
             NumBandsForRate(rate), std::vector<float>(kBlockSize, 0.f));
 
         for (int delay_samples : {-15, -50, -150, -200}) {
-          rtc::Optional<DelayEstimate> delay_blocks;
+          absl::optional<DelayEstimate> delay_blocks;
           SCOPED_TRACE(ProduceDebugText(rate, -delay_samples));
           std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
               RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
@@ -208,7 +208,7 @@
 // simple timeshifts between the signals when there is jitter in the API calls.
 TEST(RenderDelayController, AlignmentWithJitter) {
   Random random_generator(42U);
-  rtc::Optional<int> echo_remover_delay;
+  absl::optional<int> echo_remover_delay;
   std::vector<float> capture_block(kBlockSize, 0.f);
   for (size_t num_matched_filters = 4; num_matched_filters == 10;
        num_matched_filters++) {
@@ -220,7 +220,7 @@
         std::vector<std::vector<float>> render_block(
             NumBandsForRate(rate), std::vector<float>(kBlockSize, 0.f));
         for (size_t delay_samples : {15, 50, 300, 800}) {
-          rtc::Optional<DelayEstimate> delay_blocks;
+          absl::optional<DelayEstimate> delay_blocks;
           SCOPED_TRACE(ProduceDebugText(rate, delay_samples));
           std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
               RenderDelayBuffer::Create(config, NumBandsForRate(rate)));
@@ -296,7 +296,7 @@
 TEST(RenderDelayController, WrongCaptureSize) {
   std::vector<float> block(kBlockSize - 1, 0.f);
   EchoCanceller3Config config;
-  rtc::Optional<int> echo_remover_delay;
+  absl::optional<int> echo_remover_delay;
   for (auto rate : {8000, 16000, 32000, 48000}) {
     SCOPED_TRACE(ProduceDebugText(rate));
     std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
diff --git a/modules/audio_processing/aec3/render_signal_analyzer.cc b/modules/audio_processing/aec3/render_signal_analyzer.cc
index 10b68b0..50c34ce 100644
--- a/modules/audio_processing/aec3/render_signal_analyzer.cc
+++ b/modules/audio_processing/aec3/render_signal_analyzer.cc
@@ -23,7 +23,7 @@
 // Identifies local bands with narrow characteristics.
 void IdentifySmallNarrowBandRegions(
     const RenderBuffer& render_buffer,
-    const rtc::Optional<size_t>& delay_partitions,
+    const absl::optional<size_t>& delay_partitions,
     std::array<size_t, kFftLengthBy2 - 1>* narrow_band_counters) {
   if (!delay_partitions) {
     narrow_band_counters->fill(0);
@@ -43,7 +43,7 @@
 // Identifies whether the signal has a single strong narrow-band component.
 void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer,
                                        int strong_peak_freeze_duration,
-                                       rtc::Optional<int>* narrow_peak_band,
+                                       absl::optional<int>* narrow_peak_band,
                                        size_t* narrow_peak_counter) {
   const auto X2_latest = render_buffer.Spectrum(0);
 
@@ -83,7 +83,7 @@
     if (*narrow_peak_band &&
         ++(*narrow_peak_counter) >
             static_cast<size_t>(strong_peak_freeze_duration)) {
-      *narrow_peak_band = rtc::nullopt;
+      *narrow_peak_band = absl::nullopt;
     }
   }
 }
@@ -98,7 +98,7 @@
 
 void RenderSignalAnalyzer::Update(
     const RenderBuffer& render_buffer,
-    const rtc::Optional<size_t>& delay_partitions) {
+    const absl::optional<size_t>& delay_partitions) {
   // Identify bands of narrow nature.
   IdentifySmallNarrowBandRegions(render_buffer, delay_partitions,
                                  &narrow_band_counters_);
diff --git a/modules/audio_processing/aec3/render_signal_analyzer.h b/modules/audio_processing/aec3/render_signal_analyzer.h
index 8cd2172..c603c92 100644
--- a/modules/audio_processing/aec3/render_signal_analyzer.h
+++ b/modules/audio_processing/aec3/render_signal_analyzer.h
@@ -14,8 +14,8 @@
 #include <array>
 #include <memory>
 
+#include "absl/types/optional.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/optional.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
 #include "rtc_base/constructormagic.h"
@@ -30,7 +30,7 @@
 
   // Updates the render signal analysis with the most recent render signal.
   void Update(const RenderBuffer& render_buffer,
-              const rtc::Optional<size_t>& delay_partitions);
+              const absl::optional<size_t>& delay_partitions);
 
   // Returns true if the render signal is poorly exciting.
   bool PoorSignalExcitation() const {
@@ -44,12 +44,12 @@
   void MaskRegionsAroundNarrowBands(
       std::array<float, kFftLengthBy2Plus1>* v) const;
 
-  rtc::Optional<int> NarrowPeakBand() const { return narrow_peak_band_; }
+  absl::optional<int> NarrowPeakBand() const { return narrow_peak_band_; }
 
  private:
   const int strong_peak_freeze_duration_;
   std::array<size_t, kFftLengthBy2 - 1> narrow_band_counters_;
-  rtc::Optional<int> narrow_peak_band_;
+  absl::optional<int> narrow_peak_band_;
   size_t narrow_peak_counter_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(RenderSignalAnalyzer);
diff --git a/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc b/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc
index 5191874..f9b1955 100644
--- a/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc
+++ b/modules/audio_processing/aec3/render_signal_analyzer_unittest.cc
@@ -73,7 +73,7 @@
     render_delay_buffer->PrepareCaptureProcessing();
 
     analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
-                    rtc::Optional<size_t>(0));
+                    absl::optional<size_t>(0));
   }
 
   mask.fill(1.f);
@@ -112,7 +112,7 @@
       render_delay_buffer->PrepareCaptureProcessing();
 
       analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
-                      known_delay ? rtc::Optional<size_t>(0) : rtc::nullopt);
+                      known_delay ? absl::optional<size_t>(0) : absl::nullopt);
     }
   };
 
diff --git a/modules/audio_processing/aec3/residual_echo_estimator.cc b/modules/audio_processing/aec3/residual_echo_estimator.cc
index 4b6c959..43002e3 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.cc
+++ b/modules/audio_processing/aec3/residual_echo_estimator.cc
@@ -14,12 +14,79 @@
 #include <numeric>
 #include <vector>
 
+#include "modules/audio_processing/aec3/reverb_model.h"
+#include "modules/audio_processing/aec3/reverb_model_fallback.h"
 #include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
+namespace {
+
+bool EnableSoftTransparentMode() {
+  return !field_trial::IsEnabled("WebRTC-Aec3SoftTransparentModeKillSwitch");
+}
+
+bool OverrideEstimatedEchoPathGain() {
+  return !field_trial::IsEnabled("WebRTC-Aec3OverrideEchoPathGainKillSwitch");
+}
+
+bool UseFixedNonLinearReverbModel() {
+  return field_trial::IsEnabled(
+      "WebRTC-Aec3StandardNonlinearReverbModelKillSwitch");
+}
+
+// Computes the indexes that will be used for computing spectral power over
+// the blocks surrounding the delay.
+void GetRenderIndexesToAnalyze(
+    const VectorBuffer& spectrum_buffer,
+    const EchoCanceller3Config::EchoModel& echo_model,
+    int filter_delay_blocks,
+    bool gain_limiter_running,
+    int headroom,
+    int* idx_start,
+    int* idx_stop) {
+  RTC_DCHECK(idx_start);
+  RTC_DCHECK(idx_stop);
+  if (gain_limiter_running) {
+    if (static_cast<size_t>(headroom) >
+        echo_model.render_post_window_size_init) {
+      *idx_start = spectrum_buffer.OffsetIndex(
+          spectrum_buffer.read,
+          -static_cast<int>(echo_model.render_post_window_size_init));
+    } else {
+      *idx_start = spectrum_buffer.IncIndex(spectrum_buffer.write);
+    }
+
+    *idx_stop = spectrum_buffer.OffsetIndex(
+        spectrum_buffer.read, echo_model.render_pre_window_size_init);
+  } else {
+    size_t window_start;
+    size_t window_end;
+    window_start =
+        std::max(0, filter_delay_blocks -
+                        static_cast<int>(echo_model.render_pre_window_size));
+    window_end = filter_delay_blocks +
+                 static_cast<int>(echo_model.render_post_window_size);
+    *idx_start =
+        spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
+    *idx_stop =
+        spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
+  }
+}
+
+}  // namespace
 
 ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config)
-    : config_(config), S2_old_(config_.filter.main.length_blocks) {
+    : config_(config),
+      soft_transparent_mode_(EnableSoftTransparentMode()),
+      override_estimated_echo_path_gain_(OverrideEstimatedEchoPathGain()),
+      use_fixed_nonlinear_reverb_model_(UseFixedNonLinearReverbModel()) {
+  if (config_.ep_strength.reverb_based_on_render) {
+    echo_reverb_.reset(new ReverbModel());
+  } else {
+    echo_reverb_fallback.reset(
+        new ReverbModelFallback(config_.filter.main.length_blocks));
+  }
   Reset();
 }
 
@@ -39,24 +106,31 @@
   // Estimate the residual echo power.
   if (aec_state.UsableLinearEstimate()) {
     RTC_DCHECK(!aec_state.SaturatedEcho());
-    LinearEstimate(S2_linear, aec_state.Erle(), R2);
-    AddEchoReverb(S2_linear, aec_state.FilterDelayBlocks(),
-                  aec_state.ReverbDecay(), R2);
+    LinearEstimate(S2_linear, aec_state.Erle(), aec_state.ErleUncertainty(),
+                   R2);
+    // Adds the estimated unmodelled echo power to the residual echo power
+    // estimate.
+    if (echo_reverb_) {
+      echo_reverb_->AddReverb(
+          render_buffer.Spectrum(aec_state.FilterLengthBlocks() + 1),
+          aec_state.GetFreqRespTail(), aec_state.ReverbDecay(), *R2);
+
+    } else {
+      RTC_DCHECK(echo_reverb_fallback);
+      echo_reverb_fallback->AddEchoReverb(S2_linear,
+                                          aec_state.FilterDelayBlocks(),
+                                          aec_state.ReverbDecay(), R2);
+    }
+
   } else {
     // Estimate the echo generating signal power.
     std::array<float, kFftLengthBy2Plus1> X2;
 
-    // Computes the spectral power over the blocks surrounding the delay.
-    size_t window_start = std::max(
-        0, aec_state.FilterDelayBlocks() -
-               static_cast<int>(config_.echo_model.render_pre_window_size));
-    size_t window_end =
-        aec_state.FilterDelayBlocks() +
-        static_cast<int>(config_.echo_model.render_post_window_size);
-    EchoGeneratingPower(render_buffer, window_start, window_end, &X2);
+    EchoGeneratingPower(render_buffer.GetSpectrumBuffer(), config_.echo_model,
+                        render_buffer.Headroom(), aec_state.FilterDelayBlocks(),
+                        aec_state.IsSuppressionGainLimitActive(),
+                        !aec_state.UseStationaryProperties(), &X2);
 
-    // TODO(devicentepena): look if this is competing/completing
-    // with the stationarity estimator
     // Subtract the stationary noise power to avoid stationary noise causing
     // excessive echo suppression.
     std::transform(X2.begin(), X2.end(), X2_noise_floor_.begin(), X2.begin(),
@@ -65,7 +139,17 @@
                          0.f, a - config_.echo_model.stationary_gate_slope * b);
                    });
 
-    NonLinearEstimate(aec_state.EchoPathGain(), X2, Y2, R2);
+    float echo_path_gain;
+    if (override_estimated_echo_path_gain_) {
+      echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
+                           ? 0.01f
+                           : config_.ep_strength.lf;
+    } else {
+      echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
+                           ? 0.01f
+                           : aec_state.EchoPathGain();
+    }
+    NonLinearEstimate(echo_path_gain, X2, Y2, R2);
 
     // If the echo is saturated, estimate the echo power as the maximum echo
     // power with a leakage factor.
@@ -73,8 +157,18 @@
       R2->fill((*std::max_element(R2->begin(), R2->end())) * 100.f);
     }
 
-    AddEchoReverb(*R2, config_.filter.main.length_blocks,
-                  aec_state.ReverbDecay(), R2);
+    if (!(aec_state.TransparentMode() && soft_transparent_mode_)) {
+      if (echo_reverb_) {
+        echo_reverb_->AddReverbNoFreqShaping(
+            render_buffer.Spectrum(aec_state.FilterDelayBlocks() + 1),
+            echo_path_gain * echo_path_gain, aec_state.ReverbDecay(), *R2);
+      } else {
+        RTC_DCHECK(echo_reverb_fallback);
+        echo_reverb_fallback->AddEchoReverb(*R2,
+                                            config_.filter.main.length_blocks,
+                                            aec_state.ReverbDecay(), R2);
+      }
+    }
   }
 
   if (aec_state.UseStationaryProperties()) {
@@ -88,38 +182,48 @@
       }
     }
   }
-
-  // If the echo is deemed inaudible, set the residual echo to zero.
-  if (aec_state.TransparentMode()) {
-    R2->fill(0.f);
-    R2_old_.fill(0.f);
-    R2_hold_counter_.fill(0.f);
+  if (!soft_transparent_mode_) {
+    // If the echo is deemed inaudible, set the residual echo to zero.
+    if (aec_state.TransparentMode()) {
+      R2->fill(0.f);
+      R2_old_.fill(0.f);
+      R2_hold_counter_.fill(0.f);
+    }
   }
 
   std::copy(R2->begin(), R2->end(), R2_old_.begin());
 }
 
 void ResidualEchoEstimator::Reset() {
+  if (echo_reverb_) {
+    echo_reverb_->Reset();
+  } else {
+    RTC_DCHECK(echo_reverb_fallback);
+    echo_reverb_fallback->Reset();
+  }
   X2_noise_floor_counter_.fill(config_.echo_model.noise_floor_hold);
   X2_noise_floor_.fill(config_.echo_model.min_noise_floor_power);
-  R2_reverb_.fill(0.f);
   R2_old_.fill(0.f);
   R2_hold_counter_.fill(0.f);
-  for (auto& S2_k : S2_old_) {
-    S2_k.fill(0.f);
-  }
 }
 
 void ResidualEchoEstimator::LinearEstimate(
     const std::array<float, kFftLengthBy2Plus1>& S2_linear,
     const std::array<float, kFftLengthBy2Plus1>& erle,
+    absl::optional<float> erle_uncertainty,
     std::array<float, kFftLengthBy2Plus1>* R2) {
   std::fill(R2_hold_counter_.begin(), R2_hold_counter_.end(), 10.f);
-  std::transform(erle.begin(), erle.end(), S2_linear.begin(), R2->begin(),
-                 [](float a, float b) {
-                   RTC_DCHECK_LT(0.f, a);
-                   return b / a;
-                 });
+  if (erle_uncertainty) {
+    for (size_t k = 0; k < R2->size(); ++k) {
+      (*R2)[k] = S2_linear[k] * *erle_uncertainty;
+    }
+  } else {
+    std::transform(erle.begin(), erle.end(), S2_linear.begin(), R2->begin(),
+                   [](float a, float b) {
+                     RTC_DCHECK_LT(0.f, a);
+                     return b / a;
+                   });
+  }
 }
 
 void ResidualEchoEstimator::NonLinearEstimate(
@@ -127,81 +231,59 @@
     const std::array<float, kFftLengthBy2Plus1>& X2,
     const std::array<float, kFftLengthBy2Plus1>& Y2,
     std::array<float, kFftLengthBy2Plus1>* R2) {
-
   // Compute preliminary residual echo.
   std::transform(X2.begin(), X2.end(), R2->begin(), [echo_path_gain](float a) {
     return a * echo_path_gain * echo_path_gain;
   });
 
-  for (size_t k = 0; k < R2->size(); ++k) {
-    // Update hold counter.
-    R2_hold_counter_[k] = R2_old_[k] < (*R2)[k] ? 0 : R2_hold_counter_[k] + 1;
+  if (use_fixed_nonlinear_reverb_model_) {
+    for (size_t k = 0; k < R2->size(); ++k) {
+      // Update hold counter.
+      R2_hold_counter_[k] = R2_old_[k] < (*R2)[k] ? 0 : R2_hold_counter_[k] + 1;
 
-    // Compute the residual echo by holding a maximum echo powers and an echo
-    // fading corresponding to a room with an RT60 value of about 50 ms.
-    (*R2)[k] =
-        R2_hold_counter_[k] < config_.echo_model.nonlinear_hold
-            ? std::max((*R2)[k], R2_old_[k])
-            : std::min(
-                  (*R2)[k] + R2_old_[k] * config_.echo_model.nonlinear_release,
-                  Y2[k]);
+      // Compute the residual echo by holding a maximum echo powers and an echo
+      // fading corresponding to a room with an RT60 value of about 50 ms.
+      (*R2)[k] =
+          R2_hold_counter_[k] < config_.echo_model.nonlinear_hold
+              ? std::max((*R2)[k], R2_old_[k])
+              : std::min((*R2)[k] +
+                             R2_old_[k] * config_.echo_model.nonlinear_release,
+                         Y2[k]);
+    }
   }
 }
 
-void ResidualEchoEstimator::AddEchoReverb(
-    const std::array<float, kFftLengthBy2Plus1>& S2,
-    size_t delay,
-    float reverb_decay_factor,
-    std::array<float, kFftLengthBy2Plus1>* R2) {
-  // Compute the decay factor for how much the echo has decayed before leaving
-  // the region covered by the linear model.
-  auto integer_power = [](float base, int exp) {
-    float result = 1.f;
-    for (int k = 0; k < exp; ++k) {
-      result *= base;
-    }
-    return result;
-  };
-  RTC_DCHECK_LE(delay, S2_old_.size());
-  const float reverb_decay_for_delay =
-      integer_power(reverb_decay_factor, S2_old_.size() - delay);
-
-  // Update the estimate of the reverberant residual echo power.
-  S2_old_index_ = S2_old_index_ > 0 ? S2_old_index_ - 1 : S2_old_.size() - 1;
-  const auto& S2_end = S2_old_[S2_old_index_];
-  std::transform(
-      S2_end.begin(), S2_end.end(), R2_reverb_.begin(), R2_reverb_.begin(),
-      [reverb_decay_for_delay, reverb_decay_factor](float a, float b) {
-        return (b + a * reverb_decay_for_delay) * reverb_decay_factor;
-      });
-
-  // Update the buffer of old echo powers.
-  std::copy(S2.begin(), S2.end(), S2_old_[S2_old_index_].begin());
-
-  // Add the power of the echo reverb to the residual echo power.
-  std::transform(R2->begin(), R2->end(), R2_reverb_.begin(), R2->begin(),
-                 std::plus<float>());
-}
-
 void ResidualEchoEstimator::EchoGeneratingPower(
-    const RenderBuffer& render_buffer,
-    size_t min_delay,
-    size_t max_delay,
+    const VectorBuffer& spectrum_buffer,
+    const EchoCanceller3Config::EchoModel& echo_model,
+    int headroom_spectrum_buffer,
+    int filter_delay_blocks,
+    bool gain_limiter_running,
+    bool apply_noise_gating,
     std::array<float, kFftLengthBy2Plus1>* X2) const {
+  int idx_stop, idx_start;
+
+  RTC_DCHECK(X2);
+  GetRenderIndexesToAnalyze(spectrum_buffer, config_.echo_model,
+                            filter_delay_blocks, gain_limiter_running,
+                            headroom_spectrum_buffer, &idx_start, &idx_stop);
+
   X2->fill(0.f);
-  for (size_t k = min_delay; k <= max_delay; ++k) {
-    std::transform(X2->begin(), X2->end(), render_buffer.Spectrum(k).begin(),
+  for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
+    std::transform(X2->begin(), X2->end(), spectrum_buffer.buffer[k].begin(),
                    X2->begin(),
                    [](float a, float b) { return std::max(a, b); });
   }
 
-  // Apply soft noise gate.
-  std::for_each(X2->begin(), X2->end(), [&](float& a) {
-    if (config_.echo_model.noise_gate_power > a) {
-      a = std::max(0.f, a - config_.echo_model.noise_gate_slope *
-                                (config_.echo_model.noise_gate_power - a));
-    }
-  });
+  if (apply_noise_gating) {
+    // Apply soft noise gate.
+    std::for_each(X2->begin(), X2->end(), [&](float& a) {
+      if (config_.echo_model.noise_gate_power > a) {
+        a = std::max(0.f, a - config_.echo_model.noise_gate_slope *
+                                  (config_.echo_model.noise_gate_power - a));
+      }
+    });
+  }
 }
 
 void ResidualEchoEstimator::RenderNoisePower(
diff --git a/modules/audio_processing/aec3/residual_echo_estimator.h b/modules/audio_processing/aec3/residual_echo_estimator.h
index 7b8a9b1..6dcf24f 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.h
+++ b/modules/audio_processing/aec3/residual_echo_estimator.h
@@ -13,6 +13,7 @@
 
 #include <algorithm>
 #include <array>
+#include <memory>
 #include <vector>
 
 #include "api/array_view.h"
@@ -20,6 +21,8 @@
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/aec_state.h"
 #include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/reverb_model.h"
+#include "modules/audio_processing/aec3/reverb_model_fallback.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
@@ -35,6 +38,16 @@
                 const std::array<float, kFftLengthBy2Plus1>& Y2,
                 std::array<float, kFftLengthBy2Plus1>* R2);
 
+  // Returns the reverberant power spectrum contributions to the echo residual.
+  const std::array<float, kFftLengthBy2Plus1>& GetReverbPowerSpectrum() const {
+    if (echo_reverb_) {
+      return echo_reverb_->GetPowerSpectrum();
+    } else {
+      RTC_DCHECK(echo_reverb_fallback);
+      return echo_reverb_fallback->GetPowerSpectrum();
+    }
+  }
+
  private:
   // Resets the state.
   void Reset();
@@ -43,6 +56,7 @@
   // (ERLE) and the linear power estimate.
   void LinearEstimate(const std::array<float, kFftLengthBy2Plus1>& S2_linear,
                       const std::array<float, kFftLengthBy2Plus1>& erle,
+                      absl::optional<float> erle_uncertainty,
                       std::array<float, kFftLengthBy2Plus1>* R2);
 
   // Estimates the residual echo power based on the estimate of the echo path
@@ -52,18 +66,15 @@
                          const std::array<float, kFftLengthBy2Plus1>& Y2,
                          std::array<float, kFftLengthBy2Plus1>* R2);
 
-  // Adds the estimated unmodelled echo power to the residual echo power
-  // estimate.
-  void AddEchoReverb(const std::array<float, kFftLengthBy2Plus1>& S2,
-                     size_t delay,
-                     float reverb_decay_factor,
-                     std::array<float, kFftLengthBy2Plus1>* R2);
 
   // Estimates the echo generating signal power as gated maximal power over a
   // time window.
-  void EchoGeneratingPower(const RenderBuffer& render_buffer,
-                           size_t min_delay,
-                           size_t max_delay,
+  void EchoGeneratingPower(const VectorBuffer& spectrum_buffer,
+                           const EchoCanceller3Config::EchoModel& echo_model,
+                           int headroom_spectrum_buffer,
+                           int filter_delay_blocks,
+                           bool gain_limiter_running,
+                           bool apply_noise_gating,
                            std::array<float, kFftLengthBy2Plus1>* X2) const;
 
   // Updates estimate for the power of the stationary noise component in the
@@ -76,12 +87,13 @@
   const EchoCanceller3Config config_;
   std::array<float, kFftLengthBy2Plus1> R2_old_;
   std::array<int, kFftLengthBy2Plus1> R2_hold_counter_;
-  std::array<float, kFftLengthBy2Plus1> R2_reverb_;
-  int S2_old_index_ = 0;
-  std::vector<std::array<float, kFftLengthBy2Plus1>> S2_old_;
   std::array<float, kFftLengthBy2Plus1> X2_noise_floor_;
   std::array<int, kFftLengthBy2Plus1> X2_noise_floor_counter_;
-
+  const bool soft_transparent_mode_;
+  const bool override_estimated_echo_path_gain_;
+  const bool use_fixed_nonlinear_reverb_model_;
+  std::unique_ptr<ReverbModel> echo_reverb_;
+  std::unique_ptr<ReverbModelFallback> echo_reverb_fallback;
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ResidualEchoEstimator);
 };
 
diff --git a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc
index 7f9ad8d..832d8ca 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/residual_echo_estimator_unittest.cc
@@ -61,9 +61,10 @@
   std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
   std::vector<std::array<float, kFftLengthBy2Plus1>> H2(10);
   Random random_generator(42U);
-  std::array<float, kBlockSize> s;
+  SubtractorOutput output;
+  std::array<float, kBlockSize> y;
   Aec3Fft fft;
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
 
   for (auto& H2_k : H2) {
     H2_k.fill(0.01f);
@@ -74,7 +75,9 @@
   std::vector<float> h(GetTimeDomainLength(config.filter.main.length_blocks),
                        0.f);
 
-  s.fill(100.f);
+  output.Reset();
+  output.s_main.fill(100.f);
+  y.fill(0.f);
 
   constexpr float kLevel = 10.f;
   E2_shadow.fill(kLevel);
@@ -93,8 +96,9 @@
     render_delay_buffer->PrepareCaptureProcessing();
 
     aec_state.HandleEchoPathChange(echo_path_variability);
-    aec_state.Update(delay_estimate, H2, h, true, false,
-                     *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, s);
+    aec_state.Update(delay_estimate, H2, h,
+                     *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
+                     output, y);
 
     estimator.Estimate(aec_state, *render_delay_buffer->GetRenderBuffer(),
                        S2_linear, Y2, &R2);
diff --git a/modules/audio_processing/aec3/reverb_model.cc b/modules/audio_processing/aec3/reverb_model.cc
new file mode 100644
index 0000000..0ca248f
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model.cc
@@ -0,0 +1,87 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/reverb_model.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <functional>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+ReverbModel::ReverbModel() {
+  Reset();
+}
+
+ReverbModel::~ReverbModel() = default;
+
+void ReverbModel::Reset() {
+  reverb_.fill(0.);
+}
+
+void ReverbModel::AddReverbNoFreqShaping(
+    rtc::ArrayView<const float> power_spectrum,
+    float power_spectrum_scaling,
+    float reverb_decay,
+    rtc::ArrayView<float> reverb_power_spectrum) {
+  UpdateReverbContributionsNoFreqShaping(power_spectrum, power_spectrum_scaling,
+                                         reverb_decay);
+
+  // Add the power of the echo reverb to the residual echo power.
+  std::transform(reverb_power_spectrum.begin(), reverb_power_spectrum.end(),
+                 reverb_.begin(), reverb_power_spectrum.begin(),
+                 std::plus<float>());
+}
+
+void ReverbModel::AddReverb(rtc::ArrayView<const float> power_spectrum,
+                            rtc::ArrayView<const float> power_spectrum_scaling,
+                            float reverb_decay,
+                            rtc::ArrayView<float> reverb_power_spectrum) {
+  UpdateReverbContributions(power_spectrum, power_spectrum_scaling,
+                            reverb_decay);
+
+  // Add the power of the echo reverb to the residual echo power.
+  std::transform(reverb_power_spectrum.begin(), reverb_power_spectrum.end(),
+                 reverb_.begin(), reverb_power_spectrum.begin(),
+                 std::plus<float>());
+}
+
+void ReverbModel::UpdateReverbContributionsNoFreqShaping(
+    rtc::ArrayView<const float> power_spectrum,
+    float power_spectrum_scaling,
+    float reverb_decay) {
+  if (reverb_decay > 0) {
+    // Update the estimate of the reverberant power.
+    for (size_t k = 0; k < power_spectrum.size(); ++k) {
+      reverb_[k] = (reverb_[k] + power_spectrum[k] * power_spectrum_scaling) *
+                   reverb_decay;
+    }
+  }
+}
+
+void ReverbModel::UpdateReverbContributions(
+    rtc::ArrayView<const float>& power_spectrum,
+    rtc::ArrayView<const float>& power_spectrum_scaling,
+    float reverb_decay) {
+  if (reverb_decay > 0) {
+    // Update the estimate of the reverberant power.
+    for (size_t k = 0; k < power_spectrum.size(); ++k) {
+      reverb_[k] =
+          (reverb_[k] + power_spectrum[k] * power_spectrum_scaling[k]) *
+          reverb_decay;
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/reverb_model.h b/modules/audio_processing/aec3/reverb_model.h
new file mode 100644
index 0000000..d3087a7
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model.h
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// The ReverbModel class describes an exponential reverberant model
+// that can be applied over power spectrums.
+class ReverbModel {
+ public:
+  ReverbModel();
+  ~ReverbModel();
+
+  // Resets the state.
+  void Reset();
+
+  // The methods AddReverbNoFreqShaping and AddReverb add the reverberation
+  // contribution to an input/output power spectrum
+  // Before applying the exponential reverberant model, the input power spectrum
+  // is pre-scaled. Use the method AddReverb when a different scaling should be
+  // applied per frequency and AddReverb_no_freq_shape if the same scaling
+  // should be used for all the frequencies.
+  void AddReverbNoFreqShaping(rtc::ArrayView<const float> power_spectrum,
+                              float power_spectrum_scaling,
+                              float reverb_decay,
+                              rtc::ArrayView<float> reverb_power_spectrum);
+
+  void AddReverb(rtc::ArrayView<const float> power_spectrum,
+                 rtc::ArrayView<const float> freq_response_tail,
+                 float reverb_decay,
+                 rtc::ArrayView<float> reverb_power_spectrum);
+
+  // Updates the reverberation contributions without applying any shaping of the
+  // spectrum.
+  void UpdateReverbContributionsNoFreqShaping(
+      rtc::ArrayView<const float> power_spectrum,
+      float power_spectrum_scaling,
+      float reverb_decay);
+
+  // Returns the current power spectrum reverberation contributions.
+  const std::array<float, kFftLengthBy2Plus1>& GetPowerSpectrum() const {
+    return reverb_;
+  }
+
+ private:
+  // Updates the reverberation contributions.
+  void UpdateReverbContributions(rtc::ArrayView<const float>& power_spectrum,
+                                 rtc::ArrayView<const float>& freq_resp_tail,
+                                 float reverb_decay);
+
+  std::array<float, kFftLengthBy2Plus1> reverb_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_
diff --git a/modules/audio_processing/aec3/reverb_model_estimator.cc b/modules/audio_processing/aec3/reverb_model_estimator.cc
new file mode 100644
index 0000000..84e8e48
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model_estimator.cc
@@ -0,0 +1,322 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/reverb_model_estimator.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <memory>
+#include <numeric>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+
+namespace {
+
+bool EnableSmoothUpdatesTailFreqResp() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch");
+}
+
+// Computes the ratio of the energies between the direct path and the tail. The
+// energy is computed in the power spectrum domain discarding the DC
+// contributions.
+float ComputeRatioEnergies(
+    const rtc::ArrayView<const float>& freq_resp_direct_path,
+    const rtc::ArrayView<const float>& freq_resp_tail) {
+  // Skipping the DC for the ratio computation
+  constexpr size_t n_skip_bins = 1;
+  RTC_CHECK_EQ(freq_resp_direct_path.size(), freq_resp_tail.size());
+
+  float direct_path_energy =
+      std::accumulate(freq_resp_direct_path.begin() + n_skip_bins,
+                      freq_resp_direct_path.end(), 0.f);
+
+  float tail_energy = std::accumulate(freq_resp_tail.begin() + n_skip_bins,
+                                      freq_resp_tail.end(), 0.f);
+
+  if (direct_path_energy > 0) {
+    return tail_energy / direct_path_energy;
+  } else {
+    return 0.f;
+  }
+}
+
+}  // namespace
+
+ReverbModelEstimator::ReverbModelEstimator(const EchoCanceller3Config& config)
+    : filter_main_length_blocks_(config.filter.main.length_blocks),
+      reverb_decay_(std::fabs(config.ep_strength.default_len)),
+      enable_smooth_freq_resp_tail_updates_(EnableSmoothUpdatesTailFreqResp()) {
+  block_energies_.fill(0.f);
+  freq_resp_tail_.fill(0.f);
+}
+
+ReverbModelEstimator::~ReverbModelEstimator() = default;
+
+bool ReverbModelEstimator::IsAGoodFilterForDecayEstimation(
+    int filter_delay_blocks,
+    bool usable_linear_estimate,
+    size_t length_filter) {
+  if ((filter_delay_blocks && usable_linear_estimate) &&
+      (filter_delay_blocks <=
+       static_cast<int>(filter_main_length_blocks_) - 4) &&
+      (length_filter >=
+       static_cast<size_t>(GetTimeDomainLength(filter_main_length_blocks_)))) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void ReverbModelEstimator::Update(
+    const std::vector<float>& impulse_response,
+    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+        filter_freq_response,
+    const absl::optional<float>& quality_linear,
+    int filter_delay_blocks,
+    bool usable_linear_estimate,
+    float default_decay,
+    bool stationary_block) {
+  if (enable_smooth_freq_resp_tail_updates_) {
+    if (!stationary_block) {
+      float alpha = 0;
+      if (quality_linear) {
+        alpha = 0.2f * quality_linear.value();
+        UpdateFreqRespTail(filter_freq_response, filter_delay_blocks, alpha);
+      }
+      if (IsAGoodFilterForDecayEstimation(filter_delay_blocks,
+                                          usable_linear_estimate,
+                                          impulse_response.size())) {
+        alpha_ = std::max(alpha, alpha_);
+        if ((alpha_ > 0.f) && (default_decay < 0.f)) {
+          // Echo tail decay estimation if default_decay is negative.
+          UpdateReverbDecay(impulse_response);
+        }
+      } else {
+        ResetDecayEstimation();
+      }
+    }
+  } else {
+    UpdateFreqRespTail(filter_freq_response, filter_delay_blocks, 0.1f);
+  }
+}
+
+void ReverbModelEstimator::ResetDecayEstimation() {
+  accumulated_nz_ = 0.f;
+  accumulated_nn_ = 0.f;
+  accumulated_count_ = 0.f;
+  current_reverb_decay_section_ = 0;
+  num_reverb_decay_sections_ = 0;
+  num_reverb_decay_sections_next_ = 0;
+  found_end_of_reverb_decay_ = false;
+  alpha_ = 0.f;
+}
+
+void ReverbModelEstimator::UpdateReverbDecay(
+    const std::vector<float>& impulse_response) {
+  constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;
+
+  // Form the data to match against by squaring the impulse response
+  // coefficients.
+  std::array<float, GetTimeDomainLength(kMaxAdaptiveFilterLength)>
+      matching_data_data;
+  RTC_DCHECK_LE(GetTimeDomainLength(filter_main_length_blocks_),
+                matching_data_data.size());
+  rtc::ArrayView<float> matching_data(
+      matching_data_data.data(),
+      GetTimeDomainLength(filter_main_length_blocks_));
+  std::transform(
+      impulse_response.begin(), impulse_response.end(), matching_data.begin(),
+      [](float a) { return a * a; });  // TODO(devicentepena) check if focusing
+                                       // on one block would be enough.
+
+  if (current_reverb_decay_section_ < filter_main_length_blocks_) {
+    // Update accumulated variables for the current filter section.
+
+    const size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;
+
+    RTC_DCHECK_GT(matching_data.size(), start_index);
+    RTC_DCHECK_GE(matching_data.size(), start_index + kFftLengthBy2);
+    float section_energy =
+        std::accumulate(matching_data.begin() + start_index,
+                        matching_data.begin() + start_index + kFftLengthBy2,
+                        0.f) *
+        kOneByFftLengthBy2;
+
+    section_energy = std::max(
+        section_energy, 1e-32f);  // Regularization to avoid division by 0.
+
+    RTC_DCHECK_LT(current_reverb_decay_section_, block_energies_.size());
+    const float energy_ratio =
+        block_energies_[current_reverb_decay_section_] / section_energy;
+
+    found_end_of_reverb_decay_ = found_end_of_reverb_decay_ ||
+                                 (energy_ratio > 1.1f || energy_ratio < 0.9f);
+
+    // Count consecutive number of "good" filter sections, where "good" means:
+    // 1) energy is above noise floor.
+    // 2) energy of current section has not changed too much from last check.
+    if (!found_end_of_reverb_decay_ && section_energy > tail_energy_) {
+      ++num_reverb_decay_sections_next_;
+    } else {
+      found_end_of_reverb_decay_ = true;
+    }
+
+    block_energies_[current_reverb_decay_section_] = section_energy;
+
+    if (num_reverb_decay_sections_ > 0) {
+      // Linear regression of log squared magnitude of impulse response.
+      for (size_t i = 0; i < kFftLengthBy2; i++) {
+        RTC_DCHECK_GT(matching_data.size(), start_index + i);
+        float z = FastApproxLog2f(matching_data[start_index + i] + 1e-10);
+        accumulated_nz_ += accumulated_count_ * z;
+        ++accumulated_count_;
+      }
+    }
+
+    num_reverb_decay_sections_ =
+        num_reverb_decay_sections_ > 0 ? num_reverb_decay_sections_ - 1 : 0;
+    ++current_reverb_decay_section_;
+
+  } else {
+    constexpr float kMaxDecay = 0.95f;  // ~1 sec min RT60.
+    constexpr float kMinDecay = 0.02f;  // ~15 ms max RT60.
+
+    // Accumulated variables throughout whole filter.
+
+    // Solve for decay rate.
+
+    float decay = reverb_decay_;
+
+    if (accumulated_nn_ != 0.f) {
+      const float exp_candidate = -accumulated_nz_ / accumulated_nn_;
+      decay = std::pow(2.0f, -exp_candidate * kFftLengthBy2);
+      decay = std::min(decay, kMaxDecay);
+      decay = std::max(decay, kMinDecay);
+    }
+
+    // Filter tail energy (assumed to be noise).
+    constexpr size_t kTailLength = kFftLengthBy2;
+
+    constexpr float k1ByTailLength = 1.f / kTailLength;
+    const size_t tail_index =
+        GetTimeDomainLength(filter_main_length_blocks_) - kTailLength;
+
+    RTC_DCHECK_GT(matching_data.size(), tail_index);
+
+    tail_energy_ = std::accumulate(matching_data.begin() + tail_index,
+                                   matching_data.end(), 0.f) *
+                   k1ByTailLength;
+
+    // Update length of decay.
+    num_reverb_decay_sections_ = num_reverb_decay_sections_next_;
+    num_reverb_decay_sections_next_ = 0;
+    // Must have enough data (number of sections) in order
+    // to estimate decay rate.
+    if (num_reverb_decay_sections_ < 5) {
+      num_reverb_decay_sections_ = 0;
+    }
+
+    const float N = num_reverb_decay_sections_ * kFftLengthBy2;
+    accumulated_nz_ = 0.f;
+    const float k1By12 = 1.f / 12.f;
+    // Arithmetic sum $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
+    accumulated_nn_ = N * (N * N - 1.0f) * k1By12;
+    accumulated_count_ = -N * 0.5f;
+    // Linear regression approach assumes symmetric index around 0.
+    accumulated_count_ += 0.5f;
+
+    // Identify the peak index of the impulse response.
+    const size_t peak_index = std::distance(
+        matching_data.begin(),
+        std::max_element(matching_data.begin(), matching_data.end()));
+
+    current_reverb_decay_section_ = peak_index * kOneByFftLengthBy2 + 3;
+    // Make sure we're not out of bounds.
+    if (current_reverb_decay_section_ + 1 >= filter_main_length_blocks_) {
+      current_reverb_decay_section_ = filter_main_length_blocks_;
+    }
+    size_t start_index = current_reverb_decay_section_ * kFftLengthBy2;
+    float first_section_energy =
+        std::accumulate(matching_data.begin() + start_index,
+                        matching_data.begin() + start_index + kFftLengthBy2,
+                        0.f) *
+        kOneByFftLengthBy2;
+
+    // To estimate the reverb decay, the energy of the first filter section
+    // must be substantially larger than the last.
+    // Also, the first filter section energy must not deviate too much
+    // from the max peak.
+    bool main_filter_has_reverb = first_section_energy > 4.f * tail_energy_;
+    bool main_filter_is_sane = first_section_energy > 2.f * tail_energy_ &&
+                               matching_data[peak_index] < 100.f;
+
+    // Not detecting any decay, but tail is over noise - assume max decay.
+    if (num_reverb_decay_sections_ == 0 && main_filter_is_sane &&
+        main_filter_has_reverb) {
+      decay = kMaxDecay;
+    }
+
+    if (main_filter_is_sane && num_reverb_decay_sections_ > 0) {
+      decay = std::max(.97f * reverb_decay_, decay);
+      reverb_decay_ -= alpha_ * (reverb_decay_ - decay);
+    }
+
+    found_end_of_reverb_decay_ =
+        !(main_filter_is_sane && main_filter_has_reverb);
+    alpha_ = 0.f;  // Stop estimation of the decay until another good filter is
+                   // received
+  }
+}
+
+// Updates the estimation of the frequency response at the filter tail.
+void ReverbModelEstimator::UpdateFreqRespTail(
+    const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+        filter_freq_response,
+    int filter_delay_blocks,
+    float alpha) {
+  size_t num_blocks = filter_freq_response.size();
+  rtc::ArrayView<const float> freq_resp_tail(
+      filter_freq_response[num_blocks - 1]);
+  rtc::ArrayView<const float> freq_resp_direct_path(
+      filter_freq_response[filter_delay_blocks]);
+  float ratio_energies =
+      ComputeRatioEnergies(freq_resp_direct_path, freq_resp_tail);
+  ratio_tail_to_direct_path_ +=
+      alpha * (ratio_energies - ratio_tail_to_direct_path_);
+
+  for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+    freq_resp_tail_[k] = freq_resp_direct_path[k] * ratio_tail_to_direct_path_;
+  }
+
+  for (size_t k = 1; k < kFftLengthBy2; ++k) {
+    float avg_neighbour =
+        0.5f * (freq_resp_tail_[k - 1] + freq_resp_tail_[k + 1]);
+    freq_resp_tail_[k] = std::max(freq_resp_tail_[k], avg_neighbour);
+  }
+}
+
+void ReverbModelEstimator::Dump(
+    const std::unique_ptr<ApmDataDumper>& data_dumper) {
+  data_dumper->DumpRaw("aec3_reverb_decay", reverb_decay_);
+  data_dumper->DumpRaw("aec3_reverb_tail_energy", tail_energy_);
+  data_dumper->DumpRaw("aec3_reverb_alpha", alpha_);
+  data_dumper->DumpRaw("aec3_num_reverb_decay_sections",
+                       static_cast<int>(num_reverb_decay_sections_));
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/reverb_model_estimator.h b/modules/audio_processing/aec3/reverb_model_estimator.h
new file mode 100644
index 0000000..d2015aa
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model_estimator.h
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+
+namespace webrtc {
+
+// The ReverbModelEstimator class describes an estimator of the parameters
+// that are used for the reverberant model.
+class ReverbModelEstimator {
+ public:
+  explicit ReverbModelEstimator(const EchoCanceller3Config& config);
+  ~ReverbModelEstimator();
+  // Updates the model.
+  void Update(const std::vector<float>& impulse_response,
+              const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+                  filter_freq_response,
+              const absl::optional<float>& quality_linear,
+              int filter_delay_blocks,
+              bool usable_linear_estimate,
+              float default_decay,
+              bool stationary_block);
+  // Returns the decay for the exponential model.
+  float ReverbDecay() const { return reverb_decay_; }
+
+  void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper);
+
+  // Return the estimated freq. response of the tail of the filter.
+  rtc::ArrayView<const float> GetFreqRespTail() const {
+    return freq_resp_tail_;
+  }
+
+ private:
+  bool IsAGoodFilterForDecayEstimation(int filter_delay_blocks,
+                                       bool usable_linear_estimate,
+                                       size_t length_filter);
+  void UpdateReverbDecay(const std::vector<float>& impulse_response);
+
+  void UpdateFreqRespTail(
+      const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+          filter_freq_response,
+      int filter_delay_blocks,
+      float alpha);
+
+  void ResetDecayEstimation();
+
+  const size_t filter_main_length_blocks_;
+
+  float accumulated_nz_ = 0.f;
+  float accumulated_nn_ = 0.f;
+  float accumulated_count_ = 0.f;
+  size_t current_reverb_decay_section_ = 0;
+  size_t num_reverb_decay_sections_ = 0;
+  size_t num_reverb_decay_sections_next_ = 0;
+  bool found_end_of_reverb_decay_ = false;
+  std::array<float, kMaxAdaptiveFilterLength> block_energies_;
+  float reverb_decay_;
+  float tail_energy_ = 0.f;
+  float alpha_ = 0.f;
+  std::array<float, kFftLengthBy2Plus1> freq_resp_tail_;
+  float ratio_tail_to_direct_path_ = 0.f;
+  bool enable_smooth_freq_resp_tail_updates_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_
diff --git a/modules/audio_processing/aec3/reverb_model_estimator_unittest.cc b/modules/audio_processing/aec3/reverb_model_estimator_unittest.cc
new file mode 100644
index 0000000..9667f4f
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model_estimator_unittest.cc
@@ -0,0 +1,123 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/reverb_model_estimator.h"
+
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "rtc_base/checks.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+class ReverbModelEstimatorTest {
+ public:
+  explicit ReverbModelEstimatorTest(float default_decay)
+      : default_decay_(default_decay),
+        estimated_decay_(default_decay),
+        h_(aec3_config_.filter.main.length_blocks * kBlockSize, 0.f),
+        H2_(aec3_config_.filter.main.length_blocks) {
+    aec3_config_.ep_strength.default_len = default_decay_;
+    CreateImpulseResponseWithDecay();
+  }
+  void RunEstimator();
+  float GetDecay() { return estimated_decay_; }
+  float GetTrueDecay() { return true_power_decay_; }
+  float GetPowerTailDb() { return 10.f * log10(estimated_power_tail_); }
+  float GetTruePowerTailDb() { return 10.f * log10(true_power_tail_); }
+
+ private:
+  void CreateImpulseResponseWithDecay();
+
+  absl::optional<float> quality_linear_ = 1.0f;
+  static constexpr int filter_delay_blocks_ = 2;
+  static constexpr bool usable_linear_estimate_ = true;
+  static constexpr bool stationary_block_ = false;
+  static constexpr float true_power_decay_ = 0.5f;
+  EchoCanceller3Config aec3_config_;
+  float default_decay_;
+  float estimated_decay_;
+  float estimated_power_tail_ = 0.f;
+  float true_power_tail_ = 0.f;
+  std::vector<float> h_;
+  std::vector<std::array<float, kFftLengthBy2Plus1>> H2_;
+};
+
+void ReverbModelEstimatorTest::CreateImpulseResponseWithDecay() {
+  const Aec3Fft fft;
+  RTC_DCHECK_EQ(h_.size(), aec3_config_.filter.main.length_blocks * kBlockSize);
+  RTC_DCHECK_EQ(H2_.size(), aec3_config_.filter.main.length_blocks);
+  RTC_DCHECK_EQ(filter_delay_blocks_, 2);
+  const float peak = 1.0f;
+  float decay_power_sample = std::sqrt(true_power_decay_);
+  for (size_t k = 1; k < kBlockSizeLog2; k++) {
+    decay_power_sample = std::sqrt(decay_power_sample);
+  }
+  h_[filter_delay_blocks_ * kBlockSize] = peak;
+  for (size_t k = filter_delay_blocks_ * kBlockSize + 1; k < h_.size(); ++k) {
+    h_[k] = h_[k - 1] * std::sqrt(decay_power_sample);
+  }
+
+  for (size_t block = 0; block < H2_.size(); ++block) {
+    std::array<float, kFftLength> h_block;
+    h_block.fill(0.f);
+    FftData H_block;
+    rtc::ArrayView<float> H2_block(H2_[block]);
+    std::copy(h_.begin() + block * kBlockSize,
+              h_.begin() + block * (kBlockSize + 1), h_block.begin());
+
+    fft.Fft(&h_block, &H_block);
+    for (size_t k = 0; k < H2_block.size(); ++k) {
+      H2_block[k] =
+          H_block.re[k] * H_block.re[k] + H_block.im[k] * H_block.im[k];
+    }
+  }
+  rtc::ArrayView<float> H2_tail(H2_[H2_.size() - 1]);
+  true_power_tail_ = std::accumulate(H2_tail.begin(), H2_tail.end(), 0.f);
+}
+void ReverbModelEstimatorTest::RunEstimator() {
+  ReverbModelEstimator estimator(aec3_config_);
+  for (size_t k = 0; k < 1000; ++k) {
+    estimator.Update(h_, H2_, quality_linear_, filter_delay_blocks_,
+                     usable_linear_estimate_, default_decay_,
+                     stationary_block_);
+  }
+  estimated_decay_ = estimator.ReverbDecay();
+  rtc::ArrayView<const float> freq_resp_tail = estimator.GetFreqRespTail();
+  estimated_power_tail_ =
+      std::accumulate(freq_resp_tail.begin(), freq_resp_tail.end(), 0.f);
+}
+
+TEST(ReverbModelEstimatorTests, NotChangingDecay) {
+  constexpr float default_decay = 0.9f;
+  ReverbModelEstimatorTest test(default_decay);
+  test.RunEstimator();
+  EXPECT_EQ(test.GetDecay(), default_decay);
+  EXPECT_NEAR(test.GetPowerTailDb(), test.GetTruePowerTailDb(), 5.f);
+}
+
+TEST(ReverbModelEstimatorTests, ChangingDecay) {
+  constexpr float default_decay = -0.9f;
+  ReverbModelEstimatorTest test(default_decay);
+  test.RunEstimator();
+  EXPECT_NEAR(test.GetDecay(), test.GetTrueDecay(), 0.1);
+  EXPECT_NEAR(test.GetPowerTailDb(), test.GetTruePowerTailDb(), 5.f);
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/reverb_model_fallback.cc b/modules/audio_processing/aec3/reverb_model_fallback.cc
new file mode 100644
index 0000000..67df37b
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model_fallback.cc
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/reverb_model_fallback.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+ReverbModelFallback::ReverbModelFallback(size_t length_blocks)
+    : S2_old_(length_blocks) {
+  Reset();
+}
+
+ReverbModelFallback::~ReverbModelFallback() = default;
+
+void ReverbModelFallback::Reset() {
+  R2_reverb_.fill(0.f);
+  for (auto& S2_k : S2_old_) {
+    S2_k.fill(0.f);
+  }
+}
+
+void ReverbModelFallback::AddEchoReverb(
+    const std::array<float, kFftLengthBy2Plus1>& S2,
+    size_t delay,
+    float reverb_decay_factor,
+    std::array<float, kFftLengthBy2Plus1>* R2) {
+  // Compute the decay factor for how much the echo has decayed before leaving
+  // the region covered by the linear model.
+  auto integer_power = [](float base, int exp) {
+    float result = 1.f;
+    for (int k = 0; k < exp; ++k) {
+      result *= base;
+    }
+    return result;
+  };
+  RTC_DCHECK_LE(delay, S2_old_.size());
+  const float reverb_decay_for_delay =
+      integer_power(reverb_decay_factor, S2_old_.size() - delay);
+
+  // Update the estimate of the reverberant residual echo power.
+  S2_old_index_ = S2_old_index_ > 0 ? S2_old_index_ - 1 : S2_old_.size() - 1;
+  const auto& S2_end = S2_old_[S2_old_index_];
+  std::transform(
+      S2_end.begin(), S2_end.end(), R2_reverb_.begin(), R2_reverb_.begin(),
+      [reverb_decay_for_delay, reverb_decay_factor](float a, float b) {
+        return (b + a * reverb_decay_for_delay) * reverb_decay_factor;
+      });
+
+  // Update the buffer of old echo powers.
+  std::copy(S2.begin(), S2.end(), S2_old_[S2_old_index_].begin());
+
+  // Add the power of the echo reverb to the residual echo power.
+  std::transform(R2->begin(), R2->end(), R2_reverb_.begin(), R2->begin(),
+                 std::plus<float>());
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/reverb_model_fallback.h b/modules/audio_processing/aec3/reverb_model_fallback.h
new file mode 100644
index 0000000..1b2a953
--- /dev/null
+++ b/modules/audio_processing/aec3/reverb_model_fallback.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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 MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_FALLBACK_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_FALLBACK_H_
+
+#include <array>
+#include <vector>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// The ReverbModelFallback class describes an exponential reverberant model.
+// This model is expected to be applied over the echo power spectrum that
+// is estimated by the linear filter.
+
+class ReverbModelFallback {
+ public:
+  explicit ReverbModelFallback(size_t length_blocks);
+  ~ReverbModelFallback();
+
+  // Resets the state
+  void Reset();
+
+  // Adds the estimated unmodelled echo power to the residual echo power
+  // estimate.
+  void AddEchoReverb(const std::array<float, kFftLengthBy2Plus1>& S2,
+                     size_t delay,
+                     float reverb_decay_factor,
+                     std::array<float, kFftLengthBy2Plus1>* R2);
+
+  // Returns the current power spectrum reverberation contributions.
+  const std::array<float, kFftLengthBy2Plus1>& GetPowerSpectrum() const {
+    return R2_reverb_;
+  }
+
+ private:
+  std::array<float, kFftLengthBy2Plus1> R2_reverb_;
+  int S2_old_index_ = 0;
+  std::vector<std::array<float, kFftLengthBy2Plus1>> S2_old_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_FALLBACK_H_
diff --git a/modules/audio_processing/aec3/skew_estimator.cc b/modules/audio_processing/aec3/skew_estimator.cc
index 608a707..310e4e9 100644
--- a/modules/audio_processing/aec3/skew_estimator.cc
+++ b/modules/audio_processing/aec3/skew_estimator.cc
@@ -28,7 +28,7 @@
   std::fill(skew_history_.begin(), skew_history_.end(), 0);
 }
 
-rtc::Optional<int> SkewEstimator::GetSkewFromCapture() {
+absl::optional<int> SkewEstimator::GetSkewFromCapture() {
   --skew_;
 
   skew_sum_ += skew_ - skew_history_[next_index_];
@@ -38,9 +38,9 @@
     sufficient_skew_stored_ = true;
   }
 
-  return sufficient_skew_stored_
-             ? rtc::Optional<int>(skew_sum_ >> skew_history_size_log2_)
-             : rtc::nullopt;
+  const int bias = static_cast<int>(skew_history_.size()) >> 1;
+  const int average = (skew_sum_ + bias) >> skew_history_size_log2_;
+  return sufficient_skew_stored_ ? absl::optional<int>(average) : absl::nullopt;
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/skew_estimator.h b/modules/audio_processing/aec3/skew_estimator.h
index 2afcd76..ff25260 100644
--- a/modules/audio_processing/aec3/skew_estimator.h
+++ b/modules/audio_processing/aec3/skew_estimator.h
@@ -13,7 +13,7 @@
 
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
@@ -32,7 +32,7 @@
 
   // Updates and computes the skew at a capture call. Returns an optional which
   // is non-null if a reliable skew has been found.
-  rtc::Optional<int> GetSkewFromCapture();
+  absl::optional<int> GetSkewFromCapture();
 
  private:
   const int skew_history_size_log2_;
diff --git a/modules/audio_processing/aec3/skew_estimator_unittest.cc b/modules/audio_processing/aec3/skew_estimator_unittest.cc
index a1a679f..3e8c13e 100644
--- a/modules/audio_processing/aec3/skew_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/skew_estimator_unittest.cc
@@ -30,7 +30,7 @@
 
   estimator.LogRenderCall();
 
-  rtc::Optional<int> skew;
+  absl::optional<int> skew;
   for (int k = 0; k < kNumSkews; ++k) {
     estimator.LogRenderCall();
     skew = estimator.GetSkewFromCapture();
@@ -63,7 +63,7 @@
 
   estimator.LogRenderCall();
 
-  rtc::Optional<int> skew;
+  absl::optional<int> skew;
   for (int k = 0; k < kNumSkews; ++k) {
     estimator.LogRenderCall();
     skew = estimator.GetSkewFromCapture();
@@ -85,7 +85,7 @@
     EXPECT_FALSE(skew);
   }
 
-  rtc::Optional<int> skew;
+  absl::optional<int> skew;
   skew = estimator.GetSkewFromCapture();
 
   for (int k = 0; k < kNumSkews; ++k) {
@@ -120,5 +120,38 @@
     EXPECT_FALSE(skew);
   }
 }
+
+// Tests that the skew estimator properly rounds the average skew.
+TEST(SkewEstimator, SkewRounding) {
+  constexpr int kNumSkewsLog2 = 4;
+  constexpr int kNumSkews = 1 << kNumSkewsLog2;
+
+  SkewEstimator estimator(kNumSkewsLog2);
+
+  absl::optional<int> skew;
+  for (int k = 0; k < kNumSkews; ++k) {
+    if (k == kNumSkews - 1) {
+      // Reverse call order once.
+      skew = estimator.GetSkewFromCapture();
+      estimator.LogRenderCall();
+    } else {
+      // Normal call order.
+      estimator.LogRenderCall();
+      skew = estimator.GetSkewFromCapture();
+    }
+  }
+  EXPECT_EQ(*skew, 0);
+
+  estimator.Reset();
+  for (int k = 0; k < kNumSkews; ++k) {
+    estimator.LogRenderCall();
+    estimator.LogRenderCall();
+    estimator.LogRenderCall();
+    estimator.GetSkewFromCapture();
+    estimator.GetSkewFromCapture();
+    skew = estimator.GetSkewFromCapture();
+  }
+  EXPECT_EQ(*skew, 1);
+}
 }  // namespace aec3
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/stationarity_estimator.cc b/modules/audio_processing/aec3/stationarity_estimator.cc
index 8e065d2..efeabf1 100644
--- a/modules/audio_processing/aec3/stationarity_estimator.cc
+++ b/modules/audio_processing/aec3/stationarity_estimator.cc
@@ -40,6 +40,7 @@
   noise_.Reset();
   hangovers_.fill(0);
   stationarity_flags_.fill(false);
+  render_reverb_.Reset();
 }
 
 // Update just the noise estimator. Usefull until the delay is known
@@ -47,12 +48,15 @@
     rtc::ArrayView<const float> spectrum) {
   noise_.Update(spectrum);
   data_dumper_->DumpRaw("aec3_stationarity_noise_spectrum", noise_.Spectrum());
+  data_dumper_->DumpRaw("aec3_stationarity_is_block_stationary",
+                        IsBlockStationary());
 }
 
 void StationarityEstimator::UpdateStationarityFlags(
     const VectorBuffer& spectrum_buffer,
     int idx_current,
-    int num_lookahead) {
+    int num_lookahead,
+    float reverb_decay) {
   std::array<int, kWindowLength> indexes;
   int num_lookahead_bounded = std::min(num_lookahead, kWindowLength - 1);
   int idx = idx_current;
@@ -75,17 +79,30 @@
       spectrum_buffer.DecIndex(indexes[kWindowLength - 1]),
       spectrum_buffer.OffsetIndex(idx_current, -(num_lookahead_bounded + 1)));
 
+  int idx_past = spectrum_buffer.IncIndex(idx_current);
+  render_reverb_.UpdateReverbContributionsNoFreqShaping(
+      spectrum_buffer.buffer[idx_past], 1.0f, reverb_decay);
   for (size_t k = 0; k < stationarity_flags_.size(); ++k) {
-    stationarity_flags_[k] =
-        EstimateBandStationarity(spectrum_buffer, indexes, k);
+    stationarity_flags_[k] = EstimateBandStationarity(
+        spectrum_buffer, render_reverb_.GetPowerSpectrum(), indexes, k);
   }
   UpdateHangover();
   SmoothStationaryPerFreq();
+}
 
+bool StationarityEstimator::IsBlockStationary() const {
+  float acum_stationarity = 0.f;
+  RTC_DCHECK_EQ(stationarity_flags_.size(), kFftLengthBy2Plus1);
+  for (size_t band = 0; band < stationarity_flags_.size(); ++band) {
+    bool st = IsBandStationary(band);
+    acum_stationarity += static_cast<float>(st);
+  }
+  return ((acum_stationarity * (1.f / kFftLengthBy2Plus1)) > 0.75f);
 }
 
 bool StationarityEstimator::EstimateBandStationarity(
     const VectorBuffer& spectrum_buffer,
+    const std::array<float, kFftLengthBy2Plus1>& reverb,
     const std::array<int, kWindowLength>& indexes,
     size_t band) const {
   constexpr float kThrStationarity = 10.f;
@@ -93,6 +110,7 @@
   for (auto idx : indexes) {
     acum_power += spectrum_buffer.buffer[idx][band];
   }
+  acum_power += reverb[band];
   float noise = kWindowLength * GetStationarityPowerBand(band);
   RTC_CHECK_LT(0.f, noise);
   bool stationary = acum_power < kThrStationarity * noise;
diff --git a/modules/audio_processing/aec3/stationarity_estimator.h b/modules/audio_processing/aec3/stationarity_estimator.h
index 8f01790..e2c5a62 100644
--- a/modules/audio_processing/aec3/stationarity_estimator.h
+++ b/modules/audio_processing/aec3/stationarity_estimator.h
@@ -17,6 +17,7 @@
 
 #include "api/array_view.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/reverb_model.h"
 #include "modules/audio_processing/aec3/vector_buffer.h"
 
 namespace webrtc {
@@ -38,13 +39,17 @@
   // getting a more robust estimation, it looks at future and/or past frames.
   void UpdateStationarityFlags(const VectorBuffer& spectrum_buffer,
                                int idx_current,
-                               int num_lookahead);
+                               int num_lookahead,
+                               float reverb_decay);
 
   // Returns true if the current band is stationary.
   bool IsBandStationary(size_t band) const {
     return stationarity_flags_[band] && (hangovers_[band] == 0);
   }
 
+  // Returns true if the current block is estimated as stationary.
+  bool IsBlockStationary() const;
+
  private:
   static constexpr int kWindowLength = 13;
   // Returns the power of the stationary noise spectrum at a band.
@@ -52,9 +57,11 @@
 
   // Get an estimation of the stationarity for the current band by looking
   // at the past/present/future available data.
-  bool EstimateBandStationarity(const VectorBuffer& spectrum_buffer,
-                                const std::array<int, kWindowLength>& indexes,
-                                size_t band) const;
+  bool EstimateBandStationarity(
+      const VectorBuffer& spectrum_buffer,
+      const std::array<float, kFftLengthBy2Plus1>& reverb,
+      const std::array<int, kWindowLength>& indexes,
+      size_t band) const;
 
   // True if all bands at the current point are stationary.
   bool AreAllBandsStationary();
@@ -104,6 +111,7 @@
   NoiseSpectrum noise_;
   std::array<int, kFftLengthBy2Plus1> hangovers_;
   std::array<bool, kFftLengthBy2Plus1> stationarity_flags_;
+  ReverbModel render_reverb_;
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/subtractor.cc b/modules/audio_processing/aec3/subtractor.cc
index a72a667..614034b 100644
--- a/modules/audio_processing/aec3/subtractor.cc
+++ b/modules/audio_processing/aec3/subtractor.cc
@@ -16,17 +16,46 @@
 #include "api/array_view.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_minmax.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
 namespace {
 
+bool EnableAgcGainChangeResponse() {
+  return !field_trial::IsEnabled("WebRTC-Aec3AgcGainChangeResponseKillSwitch");
+}
+
+bool EnableAdaptationDuringSaturation() {
+  return !field_trial::IsEnabled("WebRTC-Aec3RapidAgcGainRecoveryKillSwitch");
+}
+
+bool EnableMisadjustmentEstimator() {
+  return !field_trial::IsEnabled("WebRTC-Aec3MisadjustmentEstimatorKillSwitch");
+}
+
+bool EnableShadowFilterJumpstart() {
+  return !field_trial::IsEnabled("WebRTC-Aec3ShadowFilterJumpstartKillSwitch");
+}
+
+bool EnableShadowFilterBoostedJumpstart() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3ShadowFilterBoostedJumpstartKillSwitch");
+}
+
+bool EnableEarlyShadowFilterJumpstart() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3EarlyShadowFilterJumpstartKillSwitch");
+}
+
 void PredictionError(const Aec3Fft& fft,
                      const FftData& S,
                      rtc::ArrayView<const float> y,
                      std::array<float, kBlockSize>* e,
                      std::array<float, kBlockSize>* s,
+                     bool adaptation_during_saturation,
                      bool* saturation) {
   std::array<float, kFftLength> tmp;
   fft.Ifft(S, &tmp);
@@ -48,8 +77,24 @@
     *saturation = *result.first <= -32768 || *result.first >= 32767;
   }
 
-  std::for_each(e->begin(), e->end(),
-                [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
+  if (!adaptation_during_saturation) {
+    std::for_each(e->begin(), e->end(),
+                  [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
+  } else {
+    *saturation = false;
+  }
+}
+
+void ScaleFilterOutput(rtc::ArrayView<const float> y,
+                       float factor,
+                       rtc::ArrayView<float> e,
+                       rtc::ArrayView<float> s) {
+  RTC_DCHECK_EQ(y.size(), e.size());
+  RTC_DCHECK_EQ(y.size(), s.size());
+  for (size_t k = 0; k < y.size(); ++k) {
+    s[k] *= factor;
+    e[k] = y[k] - s[k];
+  }
 }
 
 }  // namespace
@@ -61,6 +106,13 @@
       data_dumper_(data_dumper),
       optimization_(optimization),
       config_(config),
+      adaptation_during_saturation_(EnableAdaptationDuringSaturation()),
+      enable_misadjustment_estimator_(EnableMisadjustmentEstimator()),
+      enable_agc_gain_change_response_(EnableAgcGainChangeResponse()),
+      enable_shadow_filter_jumpstart_(EnableShadowFilterJumpstart()),
+      enable_shadow_filter_boosted_jumpstart_(
+          EnableShadowFilterBoostedJumpstart()),
+      enable_early_shadow_filter_jumpstart_(EnableEarlyShadowFilterJumpstart()),
       main_filter_(config_.filter.main.length_blocks,
                    config_.filter.main_initial.length_blocks,
                    config.filter.config_change_duration_blocks,
@@ -95,27 +147,21 @@
     G_shadow_.HandleEchoPathChange();
     G_main_.SetConfig(config_.filter.main_initial, true);
     G_shadow_.SetConfig(config_.filter.shadow_initial, true);
-    main_filter_converged_ = false;
-    shadow_filter_converged_ = false;
     main_filter_.SetSizePartitions(config_.filter.main_initial.length_blocks,
                                    true);
-    main_filter_once_converged_ = false;
     shadow_filter_.SetSizePartitions(
         config_.filter.shadow_initial.length_blocks, true);
   };
 
-  // TODO(peah): Add delay-change specific reset behavior.
-  if ((echo_path_variability.delay_change ==
-       EchoPathVariability::DelayAdjustment::kBufferFlush) ||
-      (echo_path_variability.delay_change ==
-       EchoPathVariability::DelayAdjustment::kDelayReset)) {
+  if (echo_path_variability.delay_change !=
+      EchoPathVariability::DelayAdjustment::kNone) {
     full_reset();
-  } else if (echo_path_variability.delay_change ==
-             EchoPathVariability::DelayAdjustment::kNewDetectedDelay) {
-    full_reset();
-  } else if (echo_path_variability.delay_change ==
-             EchoPathVariability::DelayAdjustment::kBufferReadjustment) {
-    full_reset();
+  }
+
+  if (echo_path_variability.gain_change && enable_agc_gain_change_response_) {
+    RTC_LOG(LS_WARNING) << "Resetting main filter adaptation speed due to "
+                           "microphone gain change";
+    G_main_.HandleEchoPathChange(echo_path_variability);
   }
 }
 
@@ -141,34 +187,37 @@
   FftData S;
   FftData& G = S;
 
-  // Form the output of the main filter.
+  // Form the outputs of the main and shadow filters.
   main_filter_.Filter(render_buffer, &S);
   bool main_saturation = false;
-  PredictionError(fft_, S, y, &e_main, &output->s_main, &main_saturation);
-  fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main);
+  PredictionError(fft_, S, y, &e_main, &output->s_main,
+                  adaptation_during_saturation_, &main_saturation);
 
-  // Form the output of the shadow filter.
   shadow_filter_.Filter(render_buffer, &S);
   bool shadow_saturation = false;
-  PredictionError(fft_, S, y, &e_shadow, nullptr, &shadow_saturation);
+  PredictionError(fft_, S, y, &e_shadow, &output->s_shadow,
+                  adaptation_during_saturation_, &shadow_saturation);
+
+  // Compute the signal powers in the subtractor output.
+  output->UpdatePowers(y);
+
+  // Adjust the filter if needed.
+  bool main_filter_adjusted = false;
+  if (enable_misadjustment_estimator_) {
+    filter_misadjustment_estimator_.Update(*output);
+    if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) {
+      float scale = filter_misadjustment_estimator_.GetMisadjustment();
+      main_filter_.ScaleFilter(scale);
+      ScaleFilterOutput(y, scale, e_main, output->s_main);
+      filter_misadjustment_estimator_.Reset();
+      main_filter_adjusted = true;
+    }
+  }
+
+  // Compute the FFts of the main and shadow filter outputs.
+  fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main);
   fft_.ZeroPaddedFft(e_shadow, Aec3Fft::Window::kHanning, &E_shadow);
 
-  // Check for filter convergence.
-  const auto sum_of_squares = [](float a, float b) { return a + b * b; };
-  const float y2 = std::accumulate(y.begin(), y.end(), 0.f, sum_of_squares);
-  const float e2_main =
-      std::accumulate(e_main.begin(), e_main.end(), 0.f, sum_of_squares);
-  const float e2_shadow =
-      std::accumulate(e_shadow.begin(), e_shadow.end(), 0.f, sum_of_squares);
-
-  constexpr float kConvergenceThreshold = 50 * 50 * kBlockSize;
-  main_filter_converged_ = e2_main < 0.2 * y2 && y2 > kConvergenceThreshold;
-  shadow_filter_converged_ =
-      e2_shadow < 0.05 * y2 && y2 > kConvergenceThreshold;
-  main_filter_once_converged_ =
-      main_filter_once_converged_ || main_filter_converged_;
-  main_filter_diverged_ = e2_main > 1.5f * y2 && y2 > 30.f * 30.f * kBlockSize;
-
   // Compute spectra for future use.
   E_shadow.Spectrum(optimization_, output->E2_shadow);
   E_main.Spectrum(optimization_, output->E2_main);
@@ -176,25 +225,95 @@
   // Update the main filter.
   std::array<float, kFftLengthBy2Plus1> X2;
   render_buffer.SpectralSum(main_filter_.SizePartitions(), &X2);
-  G_main_.Compute(X2, render_signal_analyzer, *output, main_filter_,
-                  aec_state.SaturatedCapture() || main_saturation, &G);
+  if (!main_filter_adjusted) {
+    G_main_.Compute(X2, render_signal_analyzer, *output, main_filter_,
+                    aec_state.SaturatedCapture() || main_saturation, &G);
+  } else {
+    G.re.fill(0.f);
+    G.im.fill(0.f);
+  }
   main_filter_.Adapt(render_buffer, G);
   data_dumper_->DumpRaw("aec3_subtractor_G_main", G.re);
   data_dumper_->DumpRaw("aec3_subtractor_G_main", G.im);
 
   // Update the shadow filter.
-  if (shadow_filter_.SizePartitions() != main_filter_.SizePartitions()) {
-    render_buffer.SpectralSum(shadow_filter_.SizePartitions(), &X2);
+  poor_shadow_filter_counter_ =
+      output->e2_main < output->e2_shadow ? poor_shadow_filter_counter_ + 1 : 0;
+  if (((poor_shadow_filter_counter_ < 5 &&
+        enable_early_shadow_filter_jumpstart_) ||
+       (poor_shadow_filter_counter_ < 10 &&
+        !enable_early_shadow_filter_jumpstart_)) ||
+      !enable_shadow_filter_jumpstart_) {
+    if (shadow_filter_.SizePartitions() != main_filter_.SizePartitions()) {
+      render_buffer.SpectralSum(shadow_filter_.SizePartitions(), &X2);
+    }
+    G_shadow_.Compute(X2, render_signal_analyzer, E_shadow,
+                      shadow_filter_.SizePartitions(),
+                      aec_state.SaturatedCapture() || shadow_saturation, &G);
+    shadow_filter_.Adapt(render_buffer, G);
+  } else {
+    poor_shadow_filter_counter_ = 0;
+
+    if (enable_shadow_filter_boosted_jumpstart_) {
+      shadow_filter_.SetFilter(main_filter_.GetFilter());
+      G_shadow_.Compute(X2, render_signal_analyzer, E_main,
+                        shadow_filter_.SizePartitions(),
+                        aec_state.SaturatedCapture() || main_saturation, &G);
+      shadow_filter_.Adapt(render_buffer, G);
+    } else {
+      G.re.fill(0.f);
+      G.im.fill(0.f);
+      shadow_filter_.Adapt(render_buffer, G);
+      shadow_filter_.SetFilter(main_filter_.GetFilter());
+    }
   }
-  G_shadow_.Compute(X2, render_signal_analyzer, E_shadow,
-                    shadow_filter_.SizePartitions(),
-                    aec_state.SaturatedCapture() || shadow_saturation, &G);
-  shadow_filter_.Adapt(render_buffer, G);
 
   data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re);
   data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im);
-
+  filter_misadjustment_estimator_.Dump(data_dumper_);
   DumpFilters();
+
+  if (adaptation_during_saturation_) {
+    std::for_each(e_main.begin(), e_main.end(),
+                  [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
+  }
+}
+
+void Subtractor::FilterMisadjustmentEstimator::Update(
+    const SubtractorOutput& output) {
+  e2_acum_ += output.e2_main;
+  y2_acum_ += output.y2;
+  if (++n_blocks_acum_ == n_blocks_) {
+    if (y2_acum_ > n_blocks_ * 200.f * 200.f * kBlockSize) {
+      float update = (e2_acum_ / y2_acum_);
+      if (e2_acum_ > n_blocks_ * 7500.f * 7500.f * kBlockSize) {
+        // Duration equal to blockSizeMs * n_blocks_ * 4.
+        overhang_ = 4;
+      } else {
+        overhang_ = std::max(overhang_ - 1, 0);
+      }
+
+      if ((update < inv_misadjustment_) || (overhang_ > 0)) {
+        inv_misadjustment_ += 0.1f * (update - inv_misadjustment_);
+      }
+    }
+    e2_acum_ = 0.f;
+    y2_acum_ = 0.f;
+    n_blocks_acum_ = 0;
+  }
+}
+
+void Subtractor::FilterMisadjustmentEstimator::Reset() {
+  e2_acum_ = 0.f;
+  y2_acum_ = 0.f;
+  n_blocks_acum_ = 0;
+  inv_misadjustment_ = 0.f;
+  overhang_ = 0.f;
+}
+
+void Subtractor::FilterMisadjustmentEstimator::Dump(
+    ApmDataDumper* data_dumper) const {
+  data_dumper->DumpRaw("aec3_inv_misadjustment_factor", inv_misadjustment_);
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/subtractor.h b/modules/audio_processing/aec3/subtractor.h
index 38fc3c6..c92a971 100644
--- a/modules/audio_processing/aec3/subtractor.h
+++ b/modules/audio_processing/aec3/subtractor.h
@@ -11,9 +11,10 @@
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_
 
-#include <array>
 #include <algorithm>
+#include <array>
 #include <vector>
+#include "math.h"
 
 #include "modules/audio_processing/aec3/adaptive_fir_filter.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
@@ -53,24 +54,14 @@
   // Returns the block-wise frequency response for the main adaptive filter.
   const std::vector<std::array<float, kFftLengthBy2Plus1>>&
   FilterFrequencyResponse() const {
-    return main_filter_once_converged_ || (!shadow_filter_converged_)
-               ? main_filter_.FilterFrequencyResponse()
-               : shadow_filter_.FilterFrequencyResponse();
+    return main_filter_.FilterFrequencyResponse();
   }
 
   // Returns the estimate of the impulse response for the main adaptive filter.
   const std::vector<float>& FilterImpulseResponse() const {
-    return main_filter_once_converged_ || (!shadow_filter_converged_)
-               ? main_filter_.FilterImpulseResponse()
-               : shadow_filter_.FilterImpulseResponse();
+    return main_filter_.FilterImpulseResponse();
   }
 
-  bool ConvergedFilter() const {
-    return main_filter_converged_ || shadow_filter_converged_;
-  }
-
-  bool DivergedFilter() const { return main_filter_diverged_; }
-
   void DumpFilters() {
     main_filter_.DumpFilter("aec3_subtractor_H_main", "aec3_subtractor_h_main");
     shadow_filter_.DumpFilter("aec3_subtractor_H_shadow",
@@ -78,18 +69,54 @@
   }
 
  private:
+  class FilterMisadjustmentEstimator {
+   public:
+    FilterMisadjustmentEstimator() = default;
+    ~FilterMisadjustmentEstimator() = default;
+    // Update the misadjustment estimator.
+    void Update(const SubtractorOutput& output);
+    // GetMisadjustment() Returns a recommended scale for the filter so the
+    // prediction error energy gets closer to the energy that is seen at the
+    // microphone input.
+    float GetMisadjustment() const {
+      RTC_DCHECK_GT(inv_misadjustment_, 0.0f);
+      // It is not aiming to adjust all the estimated mismatch. Instead,
+      // it adjusts half of that estimated mismatch.
+      return 2.f / sqrtf(inv_misadjustment_);
+    }
+    // Returns true if the prediciton error energy is significantly larger
+    // than the microphone signal energy and, therefore, an adjustment is
+    // recommended.
+    bool IsAdjustmentNeeded() const { return inv_misadjustment_ > 10.f; }
+    void Reset();
+    void Dump(ApmDataDumper* data_dumper) const;
+
+   private:
+    const int n_blocks_ = 4;
+    int n_blocks_acum_ = 0;
+    float e2_acum_ = 0.f;
+    float y2_acum_ = 0.f;
+    float inv_misadjustment_ = 0.f;
+    int overhang_ = 0.f;
+  };
+
   const Aec3Fft fft_;
   ApmDataDumper* data_dumper_;
   const Aec3Optimization optimization_;
   const EchoCanceller3Config config_;
+  const bool adaptation_during_saturation_;
+  const bool enable_misadjustment_estimator_;
+  const bool enable_agc_gain_change_response_;
+  const bool enable_shadow_filter_jumpstart_;
+  const bool enable_shadow_filter_boosted_jumpstart_;
+  const bool enable_early_shadow_filter_jumpstart_;
+
   AdaptiveFirFilter main_filter_;
   AdaptiveFirFilter shadow_filter_;
   MainFilterUpdateGain G_main_;
   ShadowFilterUpdateGain G_shadow_;
-  bool main_filter_converged_ = false;
-  bool main_filter_once_converged_ = false;
-  bool shadow_filter_converged_ = false;
-  bool main_filter_diverged_ = false;
+  FilterMisadjustmentEstimator filter_misadjustment_estimator_;
+  size_t poor_shadow_filter_counter_ = 0;
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Subtractor);
 };
 
diff --git a/modules/audio_processing/aec3/subtractor_output.cc b/modules/audio_processing/aec3/subtractor_output.cc
new file mode 100644
index 0000000..affa4a3
--- /dev/null
+++ b/modules/audio_processing/aec3/subtractor_output.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/subtractor_output.h"
+
+#include <numeric>
+
+namespace webrtc {
+
+SubtractorOutput::SubtractorOutput() = default;
+SubtractorOutput::~SubtractorOutput() = default;
+
+void SubtractorOutput::Reset() {
+  s_main.fill(0.f);
+  s_shadow.fill(0.f);
+  e_main.fill(0.f);
+  e_shadow.fill(0.f);
+  E_main.re.fill(0.f);
+  E_main.im.fill(0.f);
+  E2_main.fill(0.f);
+  E2_shadow.fill(0.f);
+  e2_main = 0.f;
+  e2_shadow = 0.f;
+  s2_main = 0.f;
+  s2_shadow = 0.f;
+  y2 = 0.f;
+}
+
+void SubtractorOutput::UpdatePowers(rtc::ArrayView<const float> y) {
+  const auto sum_of_squares = [](float a, float b) { return a + b * b; };
+  y2 = std::accumulate(y.begin(), y.end(), 0.f, sum_of_squares);
+  e2_main = std::accumulate(e_main.begin(), e_main.end(), 0.f, sum_of_squares);
+  e2_shadow =
+      std::accumulate(e_shadow.begin(), e_shadow.end(), 0.f, sum_of_squares);
+  s2_main = std::accumulate(s_main.begin(), s_main.end(), 0.f, sum_of_squares);
+  s2_shadow =
+      std::accumulate(s_shadow.begin(), s_shadow.end(), 0.f, sum_of_squares);
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/subtractor_output.h b/modules/audio_processing/aec3/subtractor_output.h
index 8655665..89727e9 100644
--- a/modules/audio_processing/aec3/subtractor_output.h
+++ b/modules/audio_processing/aec3/subtractor_output.h
@@ -13,6 +13,7 @@
 
 #include <array>
 
+#include "api/array_view.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/fft_data.h"
 
@@ -20,22 +21,27 @@
 
 // Stores the values being returned from the echo subtractor.
 struct SubtractorOutput {
+  SubtractorOutput();
+  ~SubtractorOutput();
+
   std::array<float, kBlockSize> s_main;
+  std::array<float, kBlockSize> s_shadow;
   std::array<float, kBlockSize> e_main;
   std::array<float, kBlockSize> e_shadow;
   FftData E_main;
   std::array<float, kFftLengthBy2Plus1> E2_main;
   std::array<float, kFftLengthBy2Plus1> E2_shadow;
+  float s2_main = 0.f;
+  float s2_shadow = 0.f;
+  float e2_main = 0.f;
+  float e2_shadow = 0.f;
+  float y2 = 0.f;
 
-  void Reset() {
-    s_main.fill(0.f);
-    e_main.fill(0.f);
-    e_shadow.fill(0.f);
-    E_main.re.fill(0.f);
-    E_main.im.fill(0.f);
-    E2_main.fill(0.f);
-    E2_shadow.fill(0.f);
-  }
+  // Reset the struct content.
+  void Reset();
+
+  // Updates the powers of the signals.
+  void UpdatePowers(rtc::ArrayView<const float> y);
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/subtractor_output_analyzer.cc b/modules/audio_processing/aec3/subtractor_output_analyzer.cc
new file mode 100644
index 0000000..93675f5
--- /dev/null
+++ b/modules/audio_processing/aec3/subtractor_output_analyzer.cc
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
+
+#include <array>
+#include <numeric>
+
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+
+bool EnableStrictDivergenceCheck() {
+  return !field_trial::IsEnabled("WebRTC-Aec3StrictDivergenceCheckKillSwitch");
+}
+
+}  // namespace
+
+SubtractorOutputAnalyzer::SubtractorOutputAnalyzer()
+    : strict_divergence_check_(EnableStrictDivergenceCheck()) {}
+
+void SubtractorOutputAnalyzer::Update(
+    const SubtractorOutput& subtractor_output) {
+  const float y2 = subtractor_output.y2;
+  const float e2_main = subtractor_output.e2_main;
+  const float e2_shadow = subtractor_output.e2_shadow;
+
+  constexpr float kConvergenceThreshold = 50 * 50 * kBlockSize;
+  main_filter_converged_ = e2_main < 0.5f * y2 && y2 > kConvergenceThreshold;
+  shadow_filter_converged_ =
+      e2_shadow < 0.05 * y2 && y2 > kConvergenceThreshold;
+  float min_e2 =
+      strict_divergence_check_ ? std::min(e2_main, e2_shadow) : e2_main;
+  filter_diverged_ = min_e2 > 1.5f * y2 && y2 > 30.f * 30.f * kBlockSize;
+  filter_severely_diverged_ =
+      min_e2 > 1.5f * y2 && y2 > 200.f * 200.f * kBlockSize;
+}
+
+void SubtractorOutputAnalyzer::HandleEchoPathChange() {
+  shadow_filter_converged_ = false;
+  main_filter_converged_ = false;
+  filter_diverged_ = false;
+  filter_severely_diverged_ = false;
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec3/subtractor_output_analyzer.h b/modules/audio_processing/aec3/subtractor_output_analyzer.h
new file mode 100644
index 0000000..b9a2445
--- /dev/null
+++ b/modules/audio_processing/aec3/subtractor_output_analyzer.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
+
+namespace webrtc {
+
+// Class for analyzing the properties subtractor output
+class SubtractorOutputAnalyzer {
+ public:
+  SubtractorOutputAnalyzer();
+  ~SubtractorOutputAnalyzer() = default;
+
+  // Analyses the subtractor output.
+  void Update(const SubtractorOutput& subtractor_output);
+
+  bool ConvergedFilter() const {
+    return main_filter_converged_ || shadow_filter_converged_;
+  }
+
+  bool DivergedFilter() const { return filter_diverged_; }
+  bool SeverelyDivergedFilter() const { return filter_severely_diverged_; }
+
+  // Handle echo path change.
+  void HandleEchoPathChange();
+
+ private:
+  const bool strict_divergence_check_;
+  bool shadow_filter_converged_ = false;
+  bool main_filter_converged_ = false;
+  bool filter_diverged_ = false;
+  bool filter_severely_diverged_ = false;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_
diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc
index 097d7e8..35abf1c 100644
--- a/modules/audio_processing/aec3/subtractor_unittest.cc
+++ b/modules/audio_processing/aec3/subtractor_unittest.cc
@@ -33,7 +33,7 @@
   config.filter.main.length_blocks = config.filter.shadow.length_blocks =
       filter_length_blocks;
   Subtractor subtractor(config, &data_dumper, DetectOptimization());
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
   std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
   std::vector<float> y(kBlockSize, 0.f);
   std::array<float, kBlockSize> x_old;
@@ -85,9 +85,8 @@
         false, EchoPathVariability::DelayAdjustment::kNone, false));
     aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
                      subtractor.FilterImpulseResponse(),
-                     subtractor.ConvergedFilter(), subtractor.DivergedFilter(),
                      *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
-                     output.s_main);
+                     output, y);
   }
 
   const float output_power = std::inner_product(
diff --git a/modules/audio_processing/aec3/suppression_gain.cc b/modules/audio_processing/aec3/suppression_gain.cc
index 9591c67..846836d 100644
--- a/modules/audio_processing/aec3/suppression_gain.cc
+++ b/modules/audio_processing/aec3/suppression_gain.cc
@@ -20,14 +20,25 @@
 #include <functional>
 #include <numeric>
 
+#include "modules/audio_processing/aec3/moving_average.h"
 #include "modules/audio_processing/aec3/vector_math.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/atomicops.h"
 #include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
 
+bool EnableTransparencyImprovements() {
+  return !field_trial::IsEnabled(
+      "WebRTC-Aec3TransparencyImprovementsKillSwitch");
+}
+
+bool EnableNewSuppression() {
+  return !field_trial::IsEnabled("WebRTC-Aec3NewSuppressionKillSwitch");
+}
+
 // Adjust the gains according to the presence of known external filters.
 void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) {
   // Limit the low frequency gains to avoid the impact of the high-pass filter
@@ -48,7 +59,7 @@
 
 // Computes the gain to apply for the bands beyond the first band.
 float UpperBandsGain(
-    const rtc::Optional<int>& narrow_peak_band,
+    const absl::optional<int>& narrow_peak_band,
     bool saturated_echo,
     const std::vector<std::vector<float>>& render,
     const std::array<float, kFftLengthBy2Plus1>& low_band_gain) {
@@ -143,11 +154,12 @@
 }
 
 // Computes the gain to reduce the echo to a non audible level.
-void GainToNoAudibleEcho(
+void GainToNoAudibleEchoFallback(
     const EchoCanceller3Config& config,
     bool low_noise_render,
     bool saturated_echo,
     bool linear_echo_estimate,
+    bool enable_transparency_improvements,
     const std::array<float, kFftLengthBy2Plus1>& nearend,
     const std::array<float, kFftLengthBy2Plus1>& weighted_echo,
     const std::array<float, kFftLengthBy2Plus1>& masker,
@@ -169,9 +181,14 @@
   RTC_DCHECK_GT(1.f, nearend_masking_margin);
 
   const float masker_margin =
-      linear_echo_estimate ? config.gain_mask.m1 : config.gain_mask.m8;
+      linear_echo_estimate
+          ? (enable_transparency_improvements ? config.gain_mask.m0
+                                              : config.gain_mask.m1)
+          : config.gain_mask.m8;
 
   for (size_t k = 0; k < gain->size(); ++k) {
+    // TODO(devicentepena): Experiment by removing the reverberation estimation
+    // from the nearend signal before computing the gains.
     const float unity_gain_masker = std::max(nearend[k], masker[k]);
     RTC_DCHECK_LE(0.f, nearend_masking_margin * unity_gain_masker);
     if (weighted_echo[k] <= nearend_masking_margin * unity_gain_masker ||
@@ -196,11 +213,17 @@
 
 // Computes the signal output power that masks the echo signal.
 void MaskingPower(const EchoCanceller3Config& config,
+                  bool enable_transparency_improvements,
                   const std::array<float, kFftLengthBy2Plus1>& nearend,
                   const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
                   const std::array<float, kFftLengthBy2Plus1>& last_masker,
                   const std::array<float, kFftLengthBy2Plus1>& gain,
                   std::array<float, kFftLengthBy2Plus1>* masker) {
+  if (enable_transparency_improvements) {
+    std::copy(comfort_noise.begin(), comfort_noise.end(), masker->begin());
+    return;
+  }
+
   // Apply masking over time.
   float masking_factor = config.gain_mask.temporal_masking_lf;
   auto limit = config.gain_mask.temporal_masking_lf_bands;
@@ -257,6 +280,26 @@
 
 int SuppressionGain::instance_count_ = 0;
 
+// Computes the gain to reduce the echo to a non audible level.
+void SuppressionGain::GainToNoAudibleEcho(
+    const std::array<float, kFftLengthBy2Plus1>& nearend,
+    const std::array<float, kFftLengthBy2Plus1>& echo,
+    const std::array<float, kFftLengthBy2Plus1>& masker,
+    const std::array<float, kFftLengthBy2Plus1>& min_gain,
+    const std::array<float, kFftLengthBy2Plus1>& max_gain,
+    std::array<float, kFftLengthBy2Plus1>* gain) const {
+  for (size_t k = 0; k < gain->size(); ++k) {
+    float enr = echo[k] / (nearend[k] + 1.f);  // Echo-to-nearend ratio.
+    float emr = echo[k] / (masker[k] + 1.f);   // Echo-to-masker (noise) ratio.
+    float g = 1.0f;
+    if (enr > enr_transparent_[k] && emr > emr_transparent_[k]) {
+      g = (enr_suppress_[k] - enr) / (enr_suppress_[k] - enr_transparent_[k]);
+      g = std::max(g, emr_transparent_[k] / emr);
+    }
+    (*gain)[k] = std::max(std::min(g, max_gain[k]), min_gain[k]);
+  }
+}
+
 // TODO(peah): Add further optimizations, in particular for the divisions.
 void SuppressionGain::LowerBandGain(
     bool low_noise_render,
@@ -286,6 +329,18 @@
       min_gain[k] = denom > 0.f ? min_echo_power / denom : 1.f;
       min_gain[k] = std::min(min_gain[k], 1.f);
     }
+    if (enable_transparency_improvements_) {
+      for (size_t k = 0; k < 6; ++k) {
+        // Make sure the gains of the low frequencies do not decrease too
+        // quickly after strong nearend.
+        if (last_nearend_[k] > last_echo_[k]) {
+          min_gain[k] =
+              std::max(min_gain[k],
+                       last_gain_[k] * config_.gain_updates.max_dec_factor_lf);
+          min_gain[k] = std::min(min_gain[k], 1.f);
+        }
+      }
+    }
   } else {
     min_gain.fill(0.f);
   }
@@ -293,22 +348,40 @@
   // Compute the maximum gain by limiting the gain increase from the previous
   // gain.
   std::array<float, kFftLengthBy2Plus1> max_gain;
-  for (size_t k = 0; k < gain->size(); ++k) {
-    max_gain[k] = std::min(std::max(last_gain_[k] * gain_increase_[k],
-                                    config_.gain_updates.floor_first_increase),
-                           1.f);
+  if (enable_transparency_improvements_) {
+    for (size_t k = 0; k < gain->size(); ++k) {
+      max_gain[k] =
+          std::min(std::max(last_gain_[k] * config_.gain_updates.max_inc_factor,
+                            config_.gain_updates.floor_first_increase),
+                   1.f);
+    }
+  } else {
+    for (size_t k = 0; k < gain->size(); ++k) {
+      max_gain[k] =
+          std::min(std::max(last_gain_[k] * gain_increase_[k],
+                            config_.gain_updates.floor_first_increase),
+                   1.f);
+    }
   }
 
   // Iteratively compute the gain required to attenuate the echo to a non
   // noticeable level.
-  gain->fill(0.f);
   std::array<float, kFftLengthBy2Plus1> masker;
-  for (int k = 0; k < 2; ++k) {
-    MaskingPower(config_, nearend, comfort_noise, last_masker_, *gain, &masker);
-    GainToNoAudibleEcho(config_, low_noise_render, saturated_echo,
-                        linear_echo_estimate, nearend, weighted_echo, masker,
-                        min_gain, max_gain, one_by_weighted_echo, gain);
+  if (enable_new_suppression_) {
+    GainToNoAudibleEcho(nearend, weighted_echo, comfort_noise, min_gain,
+                        max_gain, gain);
     AdjustForExternalFilters(gain);
+  } else {
+    gain->fill(0.f);
+    for (int k = 0; k < 2; ++k) {
+      MaskingPower(config_, enable_transparency_improvements_, nearend,
+                   comfort_noise, last_masker_, *gain, &masker);
+      GainToNoAudibleEchoFallback(
+          config_, low_noise_render, saturated_echo, linear_echo_estimate,
+          enable_transparency_improvements_, nearend, weighted_echo, masker,
+          min_gain, max_gain, one_by_weighted_echo, gain);
+      AdjustForExternalFilters(gain);
+    }
   }
 
   // Adjust the gain for frequencies which have not yet converged.
@@ -319,10 +392,11 @@
                      weighted_echo, *gain);
 
   // Store data required for the gain computation of the next block.
+  std::copy(nearend.begin(), nearend.end(), last_nearend_.begin());
   std::copy(weighted_echo.begin(), weighted_echo.end(), last_echo_.begin());
   std::copy(gain->begin(), gain->end(), last_gain_.begin());
-  MaskingPower(config_, nearend, comfort_noise, last_masker_, *gain,
-               &last_masker_);
+  MaskingPower(config_, enable_transparency_improvements_, nearend,
+               comfort_noise, last_masker_, *gain, &last_masker_);
   aec3::VectorMath(optimization_).Sqrt(*gain);
 
   // Debug outputs for the purpose of development and analysis.
@@ -342,13 +416,40 @@
       state_change_duration_blocks_(
           static_cast<int>(config_.filter.config_change_duration_blocks)),
       coherence_gain_(sample_rate_hz,
-                      config_.suppressor.bands_with_reliable_coherence) {
+                      config_.suppressor.bands_with_reliable_coherence),
+      enable_transparency_improvements_(EnableTransparencyImprovements()),
+      enable_new_suppression_(EnableNewSuppression()),
+      moving_average_(kFftLengthBy2Plus1,
+                      config.suppressor.nearend_average_blocks) {
   RTC_DCHECK_LT(0, state_change_duration_blocks_);
   one_by_state_change_duration_blocks_ = 1.f / state_change_duration_blocks_;
   last_gain_.fill(1.f);
   last_masker_.fill(0.f);
   gain_increase_.fill(1.f);
+  last_nearend_.fill(0.f);
   last_echo_.fill(0.f);
+
+  // Compute per-band masking thresholds.
+  constexpr size_t kLastLfBand = 5;
+  constexpr size_t kFirstHfBand = 8;
+  RTC_DCHECK_LT(kLastLfBand, kFirstHfBand);
+  auto& lf = config.suppressor.mask_lf;
+  auto& hf = config.suppressor.mask_hf;
+  RTC_DCHECK_LT(lf.enr_transparent, lf.enr_suppress);
+  RTC_DCHECK_LT(hf.enr_transparent, hf.enr_suppress);
+  for (size_t k = 0; k < kFftLengthBy2Plus1; k++) {
+    float a;
+    if (k <= kLastLfBand) {
+      a = 0.f;
+    } else if (k < kFirstHfBand) {
+      a = (k - kLastLfBand) / static_cast<float>(kFirstHfBand - kLastLfBand);
+    } else {
+      a = 1.f;
+    }
+    enr_transparent_[k] = (1 - a) * lf.enr_transparent + a * hf.enr_transparent;
+    enr_suppress_[k] = (1 - a) * lf.enr_suppress + a * hf.enr_suppress;
+    emr_transparent_[k] = (1 - a) * lf.emr_transparent + a * hf.emr_transparent;
+  }
 }
 
 SuppressionGain::~SuppressionGain() = default;
@@ -368,15 +469,19 @@
   RTC_DCHECK(high_bands_gain);
   RTC_DCHECK(low_band_gain);
 
+  std::array<float, kFftLengthBy2Plus1> nearend_average;
+  moving_average_.Average(nearend_spectrum, nearend_average);
+
   // Compute gain for the lower band.
   bool low_noise_render = low_render_detector_.Detect(render);
-  const rtc::Optional<int> narrow_peak_band =
+  const absl::optional<int> narrow_peak_band =
       render_signal_analyzer.NarrowPeakBand();
-  LowerBandGain(low_noise_render, aec_state, nearend_spectrum, echo_spectrum,
+  LowerBandGain(low_noise_render, aec_state, nearend_average, echo_spectrum,
                 comfort_noise_spectrum, low_band_gain);
 
   // Adjust the gain for bands where the coherence indicates not echo.
-  if (config_.suppressor.bands_with_reliable_coherence > 0) {
+  if (config_.suppressor.bands_with_reliable_coherence > 0 &&
+      !enable_transparency_improvements_) {
     std::array<float, kFftLengthBy2Plus1> G_coherence;
     coherence_gain_.ComputeGain(linear_aec_fft, render_fft, capture_fft,
                                 G_coherence);
diff --git a/modules/audio_processing/aec3/suppression_gain.h b/modules/audio_processing/aec3/suppression_gain.h
index 7b34d0a..4c0c85d 100644
--- a/modules/audio_processing/aec3/suppression_gain.h
+++ b/modules/audio_processing/aec3/suppression_gain.h
@@ -18,6 +18,7 @@
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/aec3/aec_state.h"
 #include "modules/audio_processing/aec3/coherence_gain.h"
+#include "modules/audio_processing/aec3/moving_average.h"
 #include "modules/audio_processing/aec3/render_signal_analyzer.h"
 #include "rtc_base/constructormagic.h"
 
@@ -46,6 +47,14 @@
   void SetInitialState(bool state);
 
  private:
+  void GainToNoAudibleEcho(
+      const std::array<float, kFftLengthBy2Plus1>& nearend,
+      const std::array<float, kFftLengthBy2Plus1>& echo,
+      const std::array<float, kFftLengthBy2Plus1>& masker,
+      const std::array<float, kFftLengthBy2Plus1>& min_gain,
+      const std::array<float, kFftLengthBy2Plus1>& max_gain,
+      std::array<float, kFftLengthBy2Plus1>* gain) const;
+
   void LowerBandGain(bool stationary_with_low_power,
                      const AecState& aec_state,
                      const std::array<float, kFftLengthBy2Plus1>& nearend,
@@ -78,11 +87,18 @@
   std::array<float, kFftLengthBy2Plus1> last_gain_;
   std::array<float, kFftLengthBy2Plus1> last_masker_;
   std::array<float, kFftLengthBy2Plus1> gain_increase_;
+  std::array<float, kFftLengthBy2Plus1> last_nearend_;
   std::array<float, kFftLengthBy2Plus1> last_echo_;
+  std::array<float, kFftLengthBy2Plus1> enr_transparent_;
+  std::array<float, kFftLengthBy2Plus1> enr_suppress_;
+  std::array<float, kFftLengthBy2Plus1> emr_transparent_;
   LowNoiseRenderDetector low_render_detector_;
   bool initial_state_ = true;
   int initial_state_change_counter_ = 0;
   CoherenceGain coherence_gain_;
+  const bool enable_transparency_improvements_;
+  const bool enable_new_suppression_;
+  aec3::MovingAverage moving_average_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionGain);
 };
diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.cc b/modules/audio_processing/aec3/suppression_gain_limiter.cc
index 52218eb..e3d7a66 100644
--- a/modules/audio_processing/aec3/suppression_gain_limiter.cc
+++ b/modules/audio_processing/aec3/suppression_gain_limiter.cc
@@ -64,7 +64,7 @@
   recent_reset_ = false;
 
   // Do not enforce any gain limit on the suppressor.
-  if (realignment_counter_ <= 0) {
+  if (!IsActive()) {
     suppressor_gain_limit_ = 1.f;
     return;
   }
@@ -72,7 +72,7 @@
   // Enforce full suppression.
   if (realignment_counter_ > rampup_config_.non_zero_gain_blocks ||
       (!call_startup_phase_ && realignment_counter_ > 0)) {
-    suppressor_gain_limit_ = 0.f;
+    suppressor_gain_limit_ = rampup_config_.initial_gain;
     return;
   }
 
diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.h b/modules/audio_processing/aec3/suppression_gain_limiter.h
index e02f491..eade949 100644
--- a/modules/audio_processing/aec3/suppression_gain_limiter.h
+++ b/modules/audio_processing/aec3/suppression_gain_limiter.h
@@ -32,6 +32,15 @@
   // Returns the current suppressor gain limit.
   float Limit() const { return suppressor_gain_limit_; }
 
+  // Return whether the suppressor gain limit is active.
+  bool IsActive() const { return (realignment_counter_ > 0); }
+
+  // Inactivate limiter.
+  void Deactivate() {
+    realignment_counter_ = 0;
+    suppressor_gain_limit_ = 1.f;
+  }
+
  private:
   const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_;
   const float gain_rampup_increase_;
diff --git a/modules/audio_processing/aec3/suppression_gain_unittest.cc b/modules/audio_processing/aec3/suppression_gain_unittest.cc
index 128c61e..2eeb68b 100644
--- a/modules/audio_processing/aec3/suppression_gain_unittest.cc
+++ b/modules/audio_processing/aec3/suppression_gain_unittest.cc
@@ -13,6 +13,7 @@
 #include "modules/audio_processing/aec3/aec_state.h"
 #include "modules/audio_processing/aec3/render_delay_buffer.h"
 #include "modules/audio_processing/aec3/subtractor.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/checks.h"
 #include "system_wrappers/include/cpu_features_wrapper.h"
@@ -67,7 +68,8 @@
   std::array<float, kFftLengthBy2Plus1> R2;
   std::array<float, kFftLengthBy2Plus1> N2;
   std::array<float, kFftLengthBy2Plus1> g;
-  std::array<float, kBlockSize> s;
+  SubtractorOutput output;
+  std::array<float, kBlockSize> y;
   FftData E;
   FftData X;
   FftData Y;
@@ -78,14 +80,15 @@
   Subtractor subtractor(config, &data_dumper, DetectOptimization());
   std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
       RenderDelayBuffer::Create(config, 3));
-  rtc::Optional<DelayEstimate> delay_estimate;
+  absl::optional<DelayEstimate> delay_estimate;
 
   // Ensure that a strong noise is detected to mask any echoes.
   E2.fill(10.f);
   Y2.fill(10.f);
   R2.fill(0.1f);
   N2.fill(100.f);
-  s.fill(10.f);
+  output.Reset();
+  y.fill(0.f);
   E.re.fill(sqrtf(E2[0]));
   E.im.fill(0.f);
   X.re.fill(sqrtf(R2[0]));
@@ -97,15 +100,15 @@
   for (int k = 0; k <= kNumBlocksPerSecond / 5 + 1; ++k) {
     aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
                      subtractor.FilterImpulseResponse(),
-                     subtractor.ConvergedFilter(), subtractor.DivergedFilter(),
-                     *render_delay_buffer->GetRenderBuffer(), E2, Y2, s);
+                     *render_delay_buffer->GetRenderBuffer(), E2, Y2, output,
+                     y);
   }
 
   for (int k = 0; k < 100; ++k) {
     aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
                      subtractor.FilterImpulseResponse(),
-                     subtractor.ConvergedFilter(), subtractor.DivergedFilter(),
-                     *render_delay_buffer->GetRenderBuffer(), E2, Y2, s);
+                     *render_delay_buffer->GetRenderBuffer(), E2, Y2, output,
+                     y);
     suppression_gain.GetGain(E2, R2, N2, E, X, Y, analyzer, aec_state, x,
                              &high_bands_gain, &g);
   }
@@ -124,8 +127,8 @@
   for (int k = 0; k < 100; ++k) {
     aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
                      subtractor.FilterImpulseResponse(),
-                     subtractor.ConvergedFilter(), subtractor.DivergedFilter(),
-                     *render_delay_buffer->GetRenderBuffer(), E2, Y2, s);
+                     *render_delay_buffer->GetRenderBuffer(), E2, Y2, output,
+                     y);
     suppression_gain.GetGain(E2, R2, N2, E, X, Y, analyzer, aec_state, x,
                              &high_bands_gain, &g);
   }
@@ -144,7 +147,6 @@
   }
   std::for_each(g.begin(), g.end(),
                 [](float a) { EXPECT_NEAR(0.f, a, 0.001); });
-
 }
 
 }  // namespace aec3
diff --git a/modules/audio_processing/aec3/vector_buffer.h b/modules/audio_processing/aec3/vector_buffer.h
index a7f9932..c7d4f68 100644
--- a/modules/audio_processing/aec3/vector_buffer.h
+++ b/modules/audio_processing/aec3/vector_buffer.h
@@ -36,6 +36,7 @@
   int OffsetIndex(int index, int offset) const {
     RTC_DCHECK_GE(size, offset);
     RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+    RTC_DCHECK_GE(size + index + offset, 0);
     return (size + index + offset) % size;
   }
 
diff --git a/modules/audio_processing/aec_dump/BUILD.gn b/modules/audio_processing/aec_dump/BUILD.gn
index 152c290..e5fee3e 100644
--- a/modules/audio_processing/aec_dump/BUILD.gn
+++ b/modules/audio_processing/aec_dump/BUILD.gn
@@ -15,7 +15,7 @@
   ]
 
   deps = [
-    "..:aec_dump_interface",
+    "../",
     "../../../rtc_base:rtc_base_approved",
   ]
 }
@@ -28,7 +28,7 @@
   ]
 
   deps = [
-    "..:aec_dump_interface",
+    "../",
     "../../../test:test_support",
   ]
 }
@@ -42,9 +42,10 @@
 
   deps = [
     ":mock_aec_dump",
-    "..:audio_processing",
+    "../",
     "../../../rtc_base:rtc_base_approved",
     "//testing/gtest",
+    "//third_party/abseil-cpp/absl/memory",
   ]
 }
 
@@ -61,7 +62,7 @@
 
     deps = [
       ":aec_dump",
-      "..:aec_dump_interface",
+      "../",
       "../../../api/audio:audio_frame_api",
       "../../../rtc_base:checks",
       "../../../rtc_base:protobuf_utils",
@@ -69,6 +70,7 @@
       "../../../rtc_base:rtc_task_queue",
       "../../../rtc_base/system:file_wrapper",
       "../../../system_wrappers",
+      "//third_party/abseil-cpp/absl/memory",
     ]
 
     deps += [ "../:audioproc_debug_proto" ]
@@ -80,8 +82,8 @@
     deps = [
       ":aec_dump",
       ":aec_dump_impl",
-      "..:aec_dump_interface",
       "..:audioproc_debug_proto",
+      "../",
       "../../../rtc_base:rtc_task_queue",
       "../../../test:fileutils",
       "../../../test:test_support",
@@ -101,6 +103,6 @@
 
   deps = [
     ":aec_dump",
-    "..:aec_dump_interface",
+    "../",
   ]
 }
diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.cc b/modules/audio_processing/aec_dump/aec_dump_impl.cc
index ec35f0a..1b8df40 100644
--- a/modules/audio_processing/aec_dump/aec_dump_impl.cc
+++ b/modules/audio_processing/aec_dump/aec_dump_impl.cc
@@ -12,10 +12,10 @@
 
 #include "modules/audio_processing/aec_dump/aec_dump_impl.h"
 
+#include "absl/memory/memory.h"
 #include "modules/audio_processing/aec_dump/aec_dump_factory.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/event.h"
-#include "rtc_base/ptr_util.h"
 
 namespace webrtc {
 
@@ -74,26 +74,27 @@
   thread_sync_event.Wait(rtc::Event::kForever);
 }
 
-void AecDumpImpl::WriteInitMessage(
-    const InternalAPMStreamsConfig& streams_config) {
+void AecDumpImpl::WriteInitMessage(const ProcessingConfig& api_format) {
   auto task = CreateWriteToFileTask();
   auto* event = task->GetEvent();
   event->set_type(audioproc::Event::INIT);
   audioproc::Init* msg = event->mutable_init();
 
-  msg->set_sample_rate(streams_config.input_sample_rate);
-  msg->set_output_sample_rate(streams_config.output_sample_rate);
-  msg->set_reverse_sample_rate(streams_config.render_input_sample_rate);
-  msg->set_reverse_output_sample_rate(streams_config.render_output_sample_rate);
+  msg->set_sample_rate(api_format.input_stream().sample_rate_hz());
+  msg->set_output_sample_rate(api_format.output_stream().sample_rate_hz());
+  msg->set_reverse_sample_rate(
+      api_format.reverse_input_stream().sample_rate_hz());
+  msg->set_reverse_output_sample_rate(
+      api_format.reverse_output_stream().sample_rate_hz());
 
   msg->set_num_input_channels(
-      static_cast<int32_t>(streams_config.input_num_channels));
+      static_cast<int32_t>(api_format.input_stream().num_channels()));
   msg->set_num_output_channels(
-      static_cast<int32_t>(streams_config.output_num_channels));
+      static_cast<int32_t>(api_format.output_stream().num_channels()));
   msg->set_num_reverse_channels(
-      static_cast<int32_t>(streams_config.render_input_num_channels));
+      static_cast<int32_t>(api_format.reverse_input_stream().num_channels()));
   msg->set_num_reverse_output_channels(
-      streams_config.render_output_num_channels);
+      api_format.reverse_output_stream().num_channels());
 
   worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(std::move(task)));
 }
@@ -167,8 +168,8 @@
 }
 
 std::unique_ptr<WriteToFileTask> AecDumpImpl::CreateWriteToFileTask() {
-  return rtc::MakeUnique<WriteToFileTask>(debug_file_.get(),
-                                          &num_bytes_left_for_log_);
+  return absl::make_unique<WriteToFileTask>(debug_file_.get(),
+                                            &num_bytes_left_for_log_);
 }
 
 std::unique_ptr<AecDump> AecDumpFactory::Create(rtc::PlatformFile file,
@@ -183,8 +184,8 @@
   if (!debug_file->OpenFromFileHandle(handle)) {
     return nullptr;
   }
-  return rtc::MakeUnique<AecDumpImpl>(std::move(debug_file), max_log_size_bytes,
-                                      worker_queue);
+  return absl::make_unique<AecDumpImpl>(std::move(debug_file),
+                                        max_log_size_bytes, worker_queue);
 }
 
 std::unique_ptr<AecDump> AecDumpFactory::Create(std::string file_name,
@@ -195,8 +196,8 @@
   if (!debug_file->OpenFile(file_name.c_str(), false)) {
     return nullptr;
   }
-  return rtc::MakeUnique<AecDumpImpl>(std::move(debug_file), max_log_size_bytes,
-                                      worker_queue);
+  return absl::make_unique<AecDumpImpl>(std::move(debug_file),
+                                        max_log_size_bytes, worker_queue);
 }
 
 std::unique_ptr<AecDump> AecDumpFactory::Create(FILE* handle,
@@ -208,7 +209,7 @@
   if (!debug_file->OpenFromFileHandle(handle)) {
     return nullptr;
   }
-  return rtc::MakeUnique<AecDumpImpl>(std::move(debug_file), max_log_size_bytes,
-                                      worker_queue);
+  return absl::make_unique<AecDumpImpl>(std::move(debug_file),
+                                        max_log_size_bytes, worker_queue);
 }
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.h b/modules/audio_processing/aec_dump/aec_dump_impl.h
index 0d88a7e..1ad4fc8 100644
--- a/modules/audio_processing/aec_dump/aec_dump_impl.h
+++ b/modules/audio_processing/aec_dump/aec_dump_impl.h
@@ -52,7 +52,7 @@
 
   ~AecDumpImpl() override;
 
-  void WriteInitMessage(const InternalAPMStreamsConfig& api_format) override;
+  void WriteInitMessage(const ProcessingConfig& api_format) override;
 
   void AddCaptureStreamInput(const AudioFrameView<const float>& src) override;
   void AddCaptureStreamOutput(const AudioFrameView<const float>& src) override;
diff --git a/modules/audio_processing/aec_dump/aec_dump_integration_test.cc b/modules/audio_processing/aec_dump/aec_dump_integration_test.cc
index a7d53b5..53e731a 100644
--- a/modules/audio_processing/aec_dump/aec_dump_integration_test.cc
+++ b/modules/audio_processing/aec_dump/aec_dump_integration_test.cc
@@ -10,9 +10,9 @@
 
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "modules/audio_processing/aec_dump/mock_aec_dump.h"
 #include "modules/audio_processing/include/audio_processing.h"
-#include "rtc_base/ptr_util.h"
 
 using testing::_;
 using testing::AtLeast;
@@ -31,14 +31,14 @@
 
 std::unique_ptr<webrtc::test::MockAecDump> CreateMockAecDump() {
   auto mock_aec_dump =
-      rtc::MakeUnique<testing::StrictMock<webrtc::test::MockAecDump>>();
+      absl::make_unique<testing::StrictMock<webrtc::test::MockAecDump>>();
   EXPECT_CALL(*mock_aec_dump.get(), WriteConfig(_)).Times(AtLeast(1));
   EXPECT_CALL(*mock_aec_dump.get(), WriteInitMessage(_)).Times(AtLeast(1));
   return std::unique_ptr<webrtc::test::MockAecDump>(std::move(mock_aec_dump));
 }
 
 std::unique_ptr<webrtc::AudioFrame> CreateFakeFrame() {
-  auto fake_frame = rtc::MakeUnique<webrtc::AudioFrame>();
+  auto fake_frame = absl::make_unique<webrtc::AudioFrame>();
   fake_frame->num_channels_ = 1;
   fake_frame->sample_rate_hz_ = 48000;
   fake_frame->samples_per_channel_ = 480;
diff --git a/modules/audio_processing/aec_dump/aec_dump_unittest.cc b/modules/audio_processing/aec_dump/aec_dump_unittest.cc
index 98640b9..dea149d 100644
--- a/modules/audio_processing/aec_dump/aec_dump_unittest.cc
+++ b/modules/audio_processing/aec_dump/aec_dump_unittest.cc
@@ -39,8 +39,8 @@
     webrtc::InternalAPMConfig apm_config;
     aec_dump->WriteConfig(apm_config);
 
-    webrtc::InternalAPMStreamsConfig streams_config;
-    aec_dump->WriteInitMessage(streams_config);
+    webrtc::ProcessingConfig api_format;
+    aec_dump->WriteInitMessage(api_format);
   }
   // Remove file after the AecDump d-tor has finished.
   ASSERT_EQ(0, remove(filename.c_str()));
diff --git a/modules/audio_processing/aec_dump/mock_aec_dump.cc b/modules/audio_processing/aec_dump/mock_aec_dump.cc
index aa89e45..fe35d81 100644
--- a/modules/audio_processing/aec_dump/mock_aec_dump.cc
+++ b/modules/audio_processing/aec_dump/mock_aec_dump.cc
@@ -15,5 +15,5 @@
 
 MockAecDump::MockAecDump() = default;
 MockAecDump::~MockAecDump() = default;
-}
-}
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_processing/aec_dump/mock_aec_dump.h b/modules/audio_processing/aec_dump/mock_aec_dump.h
index c2088c0..95f912f 100644
--- a/modules/audio_processing/aec_dump/mock_aec_dump.h
+++ b/modules/audio_processing/aec_dump/mock_aec_dump.h
@@ -25,8 +25,7 @@
   MockAecDump();
   virtual ~MockAecDump();
 
-  MOCK_METHOD1(WriteInitMessage,
-               void(const InternalAPMStreamsConfig& streams_config));
+  MOCK_METHOD1(WriteInitMessage, void(const ProcessingConfig& api_format));
 
   MOCK_METHOD1(AddCaptureStreamInput,
                void(const AudioFrameView<const float>& src));
diff --git a/modules/audio_processing/aecm/BUILD.gn b/modules/audio_processing/aecm/BUILD.gn
new file mode 100644
index 0000000..54d839e
--- /dev/null
+++ b/modules/audio_processing/aecm/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright (c) 2018 The WebRTC 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.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("aecm_core") {
+  sources = [
+    "aecm_core.cc",
+    "aecm_core.h",
+    "aecm_defines.h",
+    "echo_control_mobile.cc",
+    "echo_control_mobile.h",
+  ]
+  deps = [
+    "../../..:typedefs",
+    "../../../common_audio:common_audio_c",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../rtc_base:sanitizer",
+    "../../../system_wrappers:cpu_features_api",
+    "../utility:legacy_delay_estimator",
+  ]
+  cflags = []
+
+  if (rtc_build_with_neon) {
+    sources += [ "aecm_core_neon.cc" ]
+
+    if (current_cpu != "arm64") {
+      # Enable compilation for the NEON instruction set. This is needed
+      # since //build/config/arm.gni only enables NEON for iOS, not Android.
+      # This provides the same functionality as webrtc/build/arm_neon.gypi.
+      suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+      cflags += [ "-mfpu=neon" ]
+    }
+
+    # Disable LTO on NEON targets due to compiler bug.
+    # TODO(fdegans): Enable this. See crbug.com/408997.
+    if (rtc_use_lto) {
+      cflags -= [
+        "-flto",
+        "-ffat-lto-objects",
+      ]
+    }
+  }
+
+  if (current_cpu == "mipsel") {
+    sources += [ "aecm_core_mips.cc" ]
+  } else {
+    sources += [ "aecm_core_c.cc" ]
+  }
+}
diff --git a/modules/audio_processing/aecm/aecm_core.cc b/modules/audio_processing/aecm/aecm_core.cc
index 3d9faca..21a2ba1 100644
--- a/modules/audio_processing/aecm/aecm_core.cc
+++ b/modules/audio_processing/aecm/aecm_core.cc
@@ -28,126 +28,97 @@
 #include "typedefs.h"  // NOLINT(build/include)
 
 #ifdef AEC_DEBUG
-FILE *dfile;
-FILE *testfile;
+FILE* dfile;
+FILE* testfile;
 #endif
 
 const int16_t WebRtcAecm_kCosTable[] = {
-    8192,  8190,  8187,  8180,  8172,  8160,  8147,  8130,  8112,
-    8091,  8067,  8041,  8012,  7982,  7948,  7912,  7874,  7834,
-    7791,  7745,  7697,  7647,  7595,  7540,  7483,  7424,  7362,
-    7299,  7233,  7164,  7094,  7021,  6947,  6870,  6791,  6710,
-    6627,  6542,  6455,  6366,  6275,  6182,  6087,  5991,  5892,
-    5792,  5690,  5586,  5481,  5374,  5265,  5155,  5043,  4930,
-    4815,  4698,  4580,  4461,  4341,  4219,  4096,  3971,  3845,
-    3719,  3591,  3462,  3331,  3200,  3068,  2935,  2801,  2667,
-    2531,  2395,  2258,  2120,  1981,  1842,  1703,  1563,  1422,
-    1281,  1140,   998,   856,   713,   571,   428,   285,   142,
-       0,  -142,  -285,  -428,  -571,  -713,  -856,  -998, -1140,
-   -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
-   -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
-   -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
-   -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
-   -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
-   -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
-   -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
-   -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
-   -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
-   -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
-   -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
-   -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
-   -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
-   -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
-   -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
-   -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
-   -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
-   -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
-   -1281, -1140,  -998,  -856,  -713,  -571,  -428,  -285,  -142,
-       0,   142,   285,   428,   571,   713,   856,   998,  1140,
-    1281,  1422,  1563,  1703,  1842,  1981,  2120,  2258,  2395,
-    2531,  2667,  2801,  2935,  3068,  3200,  3331,  3462,  3591,
-    3719,  3845,  3971,  4095,  4219,  4341,  4461,  4580,  4698,
-    4815,  4930,  5043,  5155,  5265,  5374,  5481,  5586,  5690,
-    5792,  5892,  5991,  6087,  6182,  6275,  6366,  6455,  6542,
-    6627,  6710,  6791,  6870,  6947,  7021,  7094,  7164,  7233,
-    7299,  7362,  7424,  7483,  7540,  7595,  7647,  7697,  7745,
-    7791,  7834,  7874,  7912,  7948,  7982,  8012,  8041,  8067,
-    8091,  8112,  8130,  8147,  8160,  8172,  8180,  8187,  8190
-};
+    8192,  8190,  8187,  8180,  8172,  8160,  8147,  8130,  8112,  8091,  8067,
+    8041,  8012,  7982,  7948,  7912,  7874,  7834,  7791,  7745,  7697,  7647,
+    7595,  7540,  7483,  7424,  7362,  7299,  7233,  7164,  7094,  7021,  6947,
+    6870,  6791,  6710,  6627,  6542,  6455,  6366,  6275,  6182,  6087,  5991,
+    5892,  5792,  5690,  5586,  5481,  5374,  5265,  5155,  5043,  4930,  4815,
+    4698,  4580,  4461,  4341,  4219,  4096,  3971,  3845,  3719,  3591,  3462,
+    3331,  3200,  3068,  2935,  2801,  2667,  2531,  2395,  2258,  2120,  1981,
+    1842,  1703,  1563,  1422,  1281,  1140,  998,   856,   713,   571,   428,
+    285,   142,   0,     -142,  -285,  -428,  -571,  -713,  -856,  -998,  -1140,
+    -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667,
+    -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095,
+    -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374,
+    -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455,
+    -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299,
+    -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874,
+    -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160,
+    -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147,
+    -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
+    -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233,
+    -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366,
+    -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265,
+    -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971,
+    -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531,
+    -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998,
+    -856,  -713,  -571,  -428,  -285,  -142,  0,     142,   285,   428,   571,
+    713,   856,   998,   1140,  1281,  1422,  1563,  1703,  1842,  1981,  2120,
+    2258,  2395,  2531,  2667,  2801,  2935,  3068,  3200,  3331,  3462,  3591,
+    3719,  3845,  3971,  4095,  4219,  4341,  4461,  4580,  4698,  4815,  4930,
+    5043,  5155,  5265,  5374,  5481,  5586,  5690,  5792,  5892,  5991,  6087,
+    6182,  6275,  6366,  6455,  6542,  6627,  6710,  6791,  6870,  6947,  7021,
+    7094,  7164,  7233,  7299,  7362,  7424,  7483,  7540,  7595,  7647,  7697,
+    7745,  7791,  7834,  7874,  7912,  7948,  7982,  8012,  8041,  8067,  8091,
+    8112,  8130,  8147,  8160,  8172,  8180,  8187,  8190};
 
 const int16_t WebRtcAecm_kSinTable[] = {
-       0,    142,    285,    428,    571,    713,    856,    998,
-    1140,   1281,   1422,   1563,   1703,   1842,   1981,   2120,
-    2258,   2395,   2531,   2667,   2801,   2935,   3068,   3200,
-    3331,   3462,   3591,   3719,   3845,   3971,   4095,   4219,
-    4341,   4461,   4580,   4698,   4815,   4930,   5043,   5155,
-    5265,   5374,   5481,   5586,   5690,   5792,   5892,   5991,
-    6087,   6182,   6275,   6366,   6455,   6542,   6627,   6710,
-    6791,   6870,   6947,   7021,   7094,   7164,   7233,   7299,
-    7362,   7424,   7483,   7540,   7595,   7647,   7697,   7745,
-    7791,   7834,   7874,   7912,   7948,   7982,   8012,   8041,
-    8067,   8091,   8112,   8130,   8147,   8160,   8172,   8180,
-    8187,   8190,   8191,   8190,   8187,   8180,   8172,   8160,
-    8147,   8130,   8112,   8091,   8067,   8041,   8012,   7982,
-    7948,   7912,   7874,   7834,   7791,   7745,   7697,   7647,
-    7595,   7540,   7483,   7424,   7362,   7299,   7233,   7164,
-    7094,   7021,   6947,   6870,   6791,   6710,   6627,   6542,
-    6455,   6366,   6275,   6182,   6087,   5991,   5892,   5792,
-    5690,   5586,   5481,   5374,   5265,   5155,   5043,   4930,
-    4815,   4698,   4580,   4461,   4341,   4219,   4096,   3971,
-    3845,   3719,   3591,   3462,   3331,   3200,   3068,   2935,
-    2801,   2667,   2531,   2395,   2258,   2120,   1981,   1842,
-    1703,   1563,   1422,   1281,   1140,    998,    856,    713,
-     571,    428,    285,    142,      0,   -142,   -285,   -428,
-    -571,   -713,   -856,   -998,  -1140,  -1281,  -1422,  -1563,
-   -1703,  -1842,  -1981,  -2120,  -2258,  -2395,  -2531,  -2667,
-   -2801,  -2935,  -3068,  -3200,  -3331,  -3462,  -3591,  -3719,
-   -3845,  -3971,  -4095,  -4219,  -4341,  -4461,  -4580,  -4698,
-   -4815,  -4930,  -5043,  -5155,  -5265,  -5374,  -5481,  -5586,
-   -5690,  -5792,  -5892,  -5991,  -6087,  -6182,  -6275,  -6366,
-   -6455,  -6542,  -6627,  -6710,  -6791,  -6870,  -6947,  -7021,
-   -7094,  -7164,  -7233,  -7299,  -7362,  -7424,  -7483,  -7540,
-   -7595,  -7647,  -7697,  -7745,  -7791,  -7834,  -7874,  -7912,
-   -7948,  -7982,  -8012,  -8041,  -8067,  -8091,  -8112,  -8130,
-   -8147,  -8160,  -8172,  -8180,  -8187,  -8190,  -8191,  -8190,
-   -8187,  -8180,  -8172,  -8160,  -8147,  -8130,  -8112,  -8091,
-   -8067,  -8041,  -8012,  -7982,  -7948,  -7912,  -7874,  -7834,
-   -7791,  -7745,  -7697,  -7647,  -7595,  -7540,  -7483,  -7424,
-   -7362,  -7299,  -7233,  -7164,  -7094,  -7021,  -6947,  -6870,
-   -6791,  -6710,  -6627,  -6542,  -6455,  -6366,  -6275,  -6182,
-   -6087,  -5991,  -5892,  -5792,  -5690,  -5586,  -5481,  -5374,
-   -5265,  -5155,  -5043,  -4930,  -4815,  -4698,  -4580,  -4461,
-   -4341,  -4219,  -4096,  -3971,  -3845,  -3719,  -3591,  -3462,
-   -3331,  -3200,  -3068,  -2935,  -2801,  -2667,  -2531,  -2395,
-   -2258,  -2120,  -1981,  -1842,  -1703,  -1563,  -1422,  -1281,
-   -1140,   -998,   -856,   -713,   -571,   -428,   -285,   -142
-};
+    0,     142,   285,   428,   571,   713,   856,   998,   1140,  1281,  1422,
+    1563,  1703,  1842,  1981,  2120,  2258,  2395,  2531,  2667,  2801,  2935,
+    3068,  3200,  3331,  3462,  3591,  3719,  3845,  3971,  4095,  4219,  4341,
+    4461,  4580,  4698,  4815,  4930,  5043,  5155,  5265,  5374,  5481,  5586,
+    5690,  5792,  5892,  5991,  6087,  6182,  6275,  6366,  6455,  6542,  6627,
+    6710,  6791,  6870,  6947,  7021,  7094,  7164,  7233,  7299,  7362,  7424,
+    7483,  7540,  7595,  7647,  7697,  7745,  7791,  7834,  7874,  7912,  7948,
+    7982,  8012,  8041,  8067,  8091,  8112,  8130,  8147,  8160,  8172,  8180,
+    8187,  8190,  8191,  8190,  8187,  8180,  8172,  8160,  8147,  8130,  8112,
+    8091,  8067,  8041,  8012,  7982,  7948,  7912,  7874,  7834,  7791,  7745,
+    7697,  7647,  7595,  7540,  7483,  7424,  7362,  7299,  7233,  7164,  7094,
+    7021,  6947,  6870,  6791,  6710,  6627,  6542,  6455,  6366,  6275,  6182,
+    6087,  5991,  5892,  5792,  5690,  5586,  5481,  5374,  5265,  5155,  5043,
+    4930,  4815,  4698,  4580,  4461,  4341,  4219,  4096,  3971,  3845,  3719,
+    3591,  3462,  3331,  3200,  3068,  2935,  2801,  2667,  2531,  2395,  2258,
+    2120,  1981,  1842,  1703,  1563,  1422,  1281,  1140,  998,   856,   713,
+    571,   428,   285,   142,   0,     -142,  -285,  -428,  -571,  -713,  -856,
+    -998,  -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
+    -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845,
+    -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155,
+    -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275,
+    -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164,
+    -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791,
+    -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130,
+    -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172,
+    -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912,
+    -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
+    -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542,
+    -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481,
+    -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219,
+    -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801,
+    -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281,
+    -1140, -998,  -856,  -713,  -571,  -428,  -285,  -142};
 
 // Initialization table for echo channel in 8 kHz
 static const int16_t kChannelStored8kHz[PART_LEN1] = {
-    2040,   1815,   1590,   1498,   1405,   1395,   1385,   1418,
-    1451,   1506,   1562,   1644,   1726,   1804,   1882,   1918,
-    1953,   1982,   2010,   2025,   2040,   2034,   2027,   2021,
-    2014,   1997,   1980,   1925,   1869,   1800,   1732,   1683,
-    1635,   1604,   1572,   1545,   1517,   1481,   1444,   1405,
-    1367,   1331,   1294,   1270,   1245,   1239,   1233,   1247,
-    1260,   1282,   1303,   1338,   1373,   1407,   1441,   1470,
-    1499,   1524,   1549,   1565,   1582,   1601,   1621,   1649,
-    1676
-};
+    2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, 1451, 1506, 1562,
+    1644, 1726, 1804, 1882, 1918, 1953, 1982, 2010, 2025, 2040, 2034,
+    2027, 2021, 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, 1635,
+    1604, 1572, 1545, 1517, 1481, 1444, 1405, 1367, 1331, 1294, 1270,
+    1245, 1239, 1233, 1247, 1260, 1282, 1303, 1338, 1373, 1407, 1441,
+    1470, 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, 1676};
 
 // Initialization table for echo channel in 16 kHz
 static const int16_t kChannelStored16kHz[PART_LEN1] = {
-    2040,   1590,   1405,   1385,   1451,   1562,   1726,   1882,
-    1953,   2010,   2040,   2027,   2014,   1980,   1869,   1732,
-    1635,   1572,   1517,   1444,   1367,   1294,   1245,   1233,
-    1260,   1303,   1373,   1441,   1499,   1549,   1582,   1621,
-    1676,   1741,   1802,   1861,   1921,   1983,   2040,   2102,
-    2170,   2265,   2375,   2515,   2651,   2781,   2922,   3075,
-    3253,   3471,   3738,   3976,   4151,   4258,   4308,   4288,
-    4270,   4253,   4237,   4179,   4086,   3947,   3757,   3484,
-    3153
-};
+    2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, 1953, 2010, 2040,
+    2027, 2014, 1980, 1869, 1732, 1635, 1572, 1517, 1444, 1367, 1294,
+    1245, 1233, 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, 1676,
+    1741, 1802, 1861, 1921, 1983, 2040, 2102, 2170, 2265, 2375, 2515,
+    2651, 2781, 2922, 3075, 3253, 3471, 3738, 3976, 4151, 4258, 4308,
+    4288, 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, 3153};
 
 // Moves the pointer to the next entry and inserts |far_spectrum| and
 // corresponding Q-domain in its buffer.
@@ -168,8 +139,7 @@
   // Update Q-domain buffer
   self->far_q_domains[self->far_history_pos] = far_q;
   // Update far end spectrum buffer
-  memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
-         far_spectrum,
+  memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), far_spectrum,
          sizeof(uint16_t) * PART_LEN1);
 }
 
@@ -213,95 +183,90 @@
 ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
 
 AecmCore* WebRtcAecm_CreateCore() {
-    AecmCore* aecm = static_cast<AecmCore*>(malloc(sizeof(AecmCore)));
+  AecmCore* aecm = static_cast<AecmCore*>(malloc(sizeof(AecmCore)));
 
-    aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
-                                            sizeof(int16_t));
-    if (!aecm->farFrameBuf)
-    {
-        WebRtcAecm_FreeCore(aecm);
-        return NULL;
-    }
+  aecm->farFrameBuf =
+      WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+  if (!aecm->farFrameBuf) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
 
-    aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
-                                                  sizeof(int16_t));
-    if (!aecm->nearNoisyFrameBuf)
-    {
-        WebRtcAecm_FreeCore(aecm);
-        return NULL;
-    }
+  aecm->nearNoisyFrameBuf =
+      WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+  if (!aecm->nearNoisyFrameBuf) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
 
-    aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
-                                                  sizeof(int16_t));
-    if (!aecm->nearCleanFrameBuf)
-    {
-        WebRtcAecm_FreeCore(aecm);
-        return NULL;
-    }
+  aecm->nearCleanFrameBuf =
+      WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+  if (!aecm->nearCleanFrameBuf) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
 
-    aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
-                                            sizeof(int16_t));
-    if (!aecm->outFrameBuf)
-    {
-        WebRtcAecm_FreeCore(aecm);
-        return NULL;
-    }
+  aecm->outFrameBuf =
+      WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+  if (!aecm->outFrameBuf) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
 
-    aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
-                                                                     MAX_DELAY);
-    if (aecm->delay_estimator_farend == NULL) {
-      WebRtcAecm_FreeCore(aecm);
-      return NULL;
-    }
-    aecm->delay_estimator =
-        WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
-    if (aecm->delay_estimator == NULL) {
-      WebRtcAecm_FreeCore(aecm);
-      return NULL;
-    }
-    // TODO(bjornv): Explicitly disable robust delay validation until no
-    // performance regression has been established.  Then remove the line.
-    WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
+  aecm->delay_estimator_farend =
+      WebRtc_CreateDelayEstimatorFarend(PART_LEN1, MAX_DELAY);
+  if (aecm->delay_estimator_farend == NULL) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
+  aecm->delay_estimator =
+      WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
+  if (aecm->delay_estimator == NULL) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
+  // TODO(bjornv): Explicitly disable robust delay validation until no
+  // performance regression has been established.  Then remove the line.
+  WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
 
-    aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
-    if (aecm->real_fft == NULL) {
-      WebRtcAecm_FreeCore(aecm);
-      return NULL;
-    }
+  aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
+  if (aecm->real_fft == NULL) {
+    WebRtcAecm_FreeCore(aecm);
+    return NULL;
+  }
 
-    // Init some aecm pointers. 16 and 32 byte alignment is only necessary
-    // for Neon code currently.
-    aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
-    aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
-    aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
-    aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
-    aecm->channelStored = (int16_t*) (((uintptr_t)
-                                             aecm->channelStored_buf + 15) & ~ 15);
-    aecm->channelAdapt16 = (int16_t*) (((uintptr_t)
-                                              aecm->channelAdapt16_buf + 15) & ~ 15);
-    aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
-                                              aecm->channelAdapt32_buf + 31) & ~ 31);
+  // Init some aecm pointers. 16 and 32 byte alignment is only necessary
+  // for Neon code currently.
+  aecm->xBuf = (int16_t*)(((uintptr_t)aecm->xBuf_buf + 31) & ~31);
+  aecm->dBufClean = (int16_t*)(((uintptr_t)aecm->dBufClean_buf + 31) & ~31);
+  aecm->dBufNoisy = (int16_t*)(((uintptr_t)aecm->dBufNoisy_buf + 31) & ~31);
+  aecm->outBuf = (int16_t*)(((uintptr_t)aecm->outBuf_buf + 15) & ~15);
+  aecm->channelStored =
+      (int16_t*)(((uintptr_t)aecm->channelStored_buf + 15) & ~15);
+  aecm->channelAdapt16 =
+      (int16_t*)(((uintptr_t)aecm->channelAdapt16_buf + 15) & ~15);
+  aecm->channelAdapt32 =
+      (int32_t*)(((uintptr_t)aecm->channelAdapt32_buf + 31) & ~31);
 
-    return aecm;
+  return aecm;
 }
 
 void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
-    int i = 0;
+  int i = 0;
 
-    // Reset the stored channel
-    memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
-    // Reset the adapted channels
-    memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
-    for (i = 0; i < PART_LEN1; i++)
-    {
-        aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
-    }
+  // Reset the stored channel
+  memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
+  // Reset the adapted channels
+  memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
+  for (i = 0; i < PART_LEN1; i++) {
+    aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
+  }
 
-    // Reset channel storing variables
-    aecm->mseAdaptOld = 1000;
-    aecm->mseStoredOld = 1000;
-    aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
-    aecm->mseChannelCount = 0;
+  // Reset channel storing variables
+  aecm->mseAdaptOld = 1000;
+  aecm->mseStoredOld = 1000;
+  aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
+  aecm->mseChannelCount = 0;
 }
 
 static void CalcLinearEnergiesC(AecmCore* aecm,
@@ -310,65 +275,61 @@
                                 uint32_t* far_energy,
                                 uint32_t* echo_energy_adapt,
                                 uint32_t* echo_energy_stored) {
-    int i;
+  int i;
 
-    // Get energy for the delayed far end signal and estimated
-    // echo using both stored and adapted channels.
-    for (i = 0; i < PART_LEN1; i++)
-    {
-        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
-                                           far_spectrum[i]);
-        (*far_energy) += (uint32_t)(far_spectrum[i]);
-        *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
-        (*echo_energy_stored) += (uint32_t)echo_est[i];
-    }
+  // Get energy for the delayed far end signal and estimated
+  // echo using both stored and adapted channels.
+  for (i = 0; i < PART_LEN1; i++) {
+    echo_est[i] =
+        WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+    (*far_energy) += (uint32_t)(far_spectrum[i]);
+    *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
+    (*echo_energy_stored) += (uint32_t)echo_est[i];
+  }
 }
 
 static void StoreAdaptiveChannelC(AecmCore* aecm,
                                   const uint16_t* far_spectrum,
                                   int32_t* echo_est) {
-    int i;
+  int i;
 
-    // During startup we store the channel every block.
-    memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1);
-    // Recalculate echo estimate
-    for (i = 0; i < PART_LEN; i += 4)
-    {
-        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
-                                           far_spectrum[i]);
-        echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
-                                           far_spectrum[i + 1]);
-        echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
-                                           far_spectrum[i + 2]);
-        echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
-                                           far_spectrum[i + 3]);
-    }
-    echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
-                                       far_spectrum[i]);
+  // During startup we store the channel every block.
+  memcpy(aecm->channelStored, aecm->channelAdapt16,
+         sizeof(int16_t) * PART_LEN1);
+  // Recalculate echo estimate
+  for (i = 0; i < PART_LEN; i += 4) {
+    echo_est[i] =
+        WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+    echo_est[i + 1] =
+        WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], far_spectrum[i + 1]);
+    echo_est[i + 2] =
+        WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], far_spectrum[i + 2]);
+    echo_est[i + 3] =
+        WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], far_spectrum[i + 3]);
+  }
+  echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
 }
 
 static void ResetAdaptiveChannelC(AecmCore* aecm) {
-    int i;
+  int i;
 
-    // The stored channel has a significantly lower MSE than the adaptive one for
-    // two consecutive calculations. Reset the adaptive channel.
-    memcpy(aecm->channelAdapt16, aecm->channelStored,
-           sizeof(int16_t) * PART_LEN1);
-    // Restore the W32 channel
-    for (i = 0; i < PART_LEN; i += 4)
-    {
-        aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
-        aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
-        aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
-        aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
-    }
+  // The stored channel has a significantly lower MSE than the adaptive one for
+  // two consecutive calculations. Reset the adaptive channel.
+  memcpy(aecm->channelAdapt16, aecm->channelStored,
+         sizeof(int16_t) * PART_LEN1);
+  // Restore the W32 channel
+  for (i = 0; i < PART_LEN; i += 4) {
     aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
+    aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
+    aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
+    aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
+  }
+  aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
 }
 
 // Initialize function pointers for ARM Neon platform.
 #if defined(WEBRTC_HAS_NEON)
-static void WebRtcAecm_InitNeon(void)
-{
+static void WebRtcAecm_InitNeon(void) {
   WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
   WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
   WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
@@ -377,8 +338,7 @@
 
 // Initialize function pointers for MIPS platform.
 #if defined(MIPS32_LE)
-static void WebRtcAecm_InitMips(void)
-{
+static void WebRtcAecm_InitMips(void) {
 #if defined(MIPS_DSP_R1_LE)
   WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
   WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
@@ -389,8 +349,8 @@
 
 // WebRtcAecm_InitCore(...)
 //
-// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
-// Input:
+// This function initializes the AECM instant created with
+// WebRtcAecm_CreateCore(...) Input:
 //      - aecm            : Pointer to the Echo Suppression instance
 //      - samplingFreq   : Sampling Frequency
 //
@@ -401,152 +361,147 @@
 //                        -1 - Error
 //
 int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) {
-    int i = 0;
-    int32_t tmp32 = PART_LEN1 * PART_LEN1;
-    int16_t tmp16 = PART_LEN1;
+  int i = 0;
+  int32_t tmp32 = PART_LEN1 * PART_LEN1;
+  int16_t tmp16 = PART_LEN1;
 
-    if (samplingFreq != 8000 && samplingFreq != 16000)
-    {
-        samplingFreq = 8000;
-        return -1;
-    }
-    // sanity check of sampling frequency
-    aecm->mult = (int16_t)samplingFreq / 8000;
+  if (samplingFreq != 8000 && samplingFreq != 16000) {
+    samplingFreq = 8000;
+    return -1;
+  }
+  // sanity check of sampling frequency
+  aecm->mult = (int16_t)samplingFreq / 8000;
 
-    aecm->farBufWritePos = 0;
-    aecm->farBufReadPos = 0;
-    aecm->knownDelay = 0;
-    aecm->lastKnownDelay = 0;
+  aecm->farBufWritePos = 0;
+  aecm->farBufReadPos = 0;
+  aecm->knownDelay = 0;
+  aecm->lastKnownDelay = 0;
 
-    WebRtc_InitBuffer(aecm->farFrameBuf);
-    WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
-    WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
-    WebRtc_InitBuffer(aecm->outFrameBuf);
+  WebRtc_InitBuffer(aecm->farFrameBuf);
+  WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
+  WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
+  WebRtc_InitBuffer(aecm->outFrameBuf);
 
-    memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
-    memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
-    memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
-    memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
+  memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
+  memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
+  memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
+  memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
 
-    aecm->seed = 666;
-    aecm->totCount = 0;
+  aecm->seed = 666;
+  aecm->totCount = 0;
 
-    if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
-      return -1;
-    }
-    if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
-      return -1;
-    }
-    // Set far end histories to zero
-    memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
-    memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
-    aecm->far_history_pos = MAX_DELAY;
+  if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
+    return -1;
+  }
+  if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
+    return -1;
+  }
+  // Set far end histories to zero
+  memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
+  memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
+  aecm->far_history_pos = MAX_DELAY;
 
-    aecm->nlpFlag = 1;
-    aecm->fixedDelay = -1;
+  aecm->nlpFlag = 1;
+  aecm->fixedDelay = -1;
 
-    aecm->dfaCleanQDomain = 0;
-    aecm->dfaCleanQDomainOld = 0;
-    aecm->dfaNoisyQDomain = 0;
-    aecm->dfaNoisyQDomainOld = 0;
+  aecm->dfaCleanQDomain = 0;
+  aecm->dfaCleanQDomainOld = 0;
+  aecm->dfaNoisyQDomain = 0;
+  aecm->dfaNoisyQDomainOld = 0;
 
-    memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
-    aecm->farLogEnergy = 0;
-    memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
-    memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
+  memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
+  aecm->farLogEnergy = 0;
+  memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
+  memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
 
-    // Initialize the echo channels with a stored shape.
-    if (samplingFreq == 8000)
-    {
-        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
-    }
-    else
-    {
-        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
-    }
+  // Initialize the echo channels with a stored shape.
+  if (samplingFreq == 8000) {
+    WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
+  } else {
+    WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
+  }
 
-    memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
-    memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
-    aecm->noiseEstCtr = 0;
+  memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
+  memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
+  aecm->noiseEstCtr = 0;
 
-    aecm->cngMode = AecmTrue;
+  aecm->cngMode = AecmTrue;
 
-    memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
-    memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
-    // Shape the initial noise level to an approximate pink noise.
-    for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
-    {
-        aecm->noiseEst[i] = (tmp32 << 8);
-        tmp16--;
-        tmp32 -= (int32_t)((tmp16 << 1) + 1);
-    }
-    for (; i < PART_LEN1; i++)
-    {
-        aecm->noiseEst[i] = (tmp32 << 8);
-    }
+  memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
+  memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
+  // Shape the initial noise level to an approximate pink noise.
+  for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) {
+    aecm->noiseEst[i] = (tmp32 << 8);
+    tmp16--;
+    tmp32 -= (int32_t)((tmp16 << 1) + 1);
+  }
+  for (; i < PART_LEN1; i++) {
+    aecm->noiseEst[i] = (tmp32 << 8);
+  }
 
-    aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
-    aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
-    aecm->farEnergyMaxMin = 0;
-    aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
-                                         // beginning.
-    aecm->farEnergyMSE = 0;
-    aecm->currentVADValue = 0;
-    aecm->vadUpdateCount = 0;
-    aecm->firstVAD = 1;
+  aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
+  aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
+  aecm->farEnergyMaxMin = 0;
+  aecm->farEnergyVAD =
+      FAR_ENERGY_MIN;  // This prevents false speech detection at the
+                       // beginning.
+  aecm->farEnergyMSE = 0;
+  aecm->currentVADValue = 0;
+  aecm->vadUpdateCount = 0;
+  aecm->firstVAD = 1;
 
-    aecm->startupState = 0;
-    aecm->supGain = SUPGAIN_DEFAULT;
-    aecm->supGainOld = SUPGAIN_DEFAULT;
+  aecm->startupState = 0;
+  aecm->supGain = SUPGAIN_DEFAULT;
+  aecm->supGainOld = SUPGAIN_DEFAULT;
 
-    aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
-    aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
-    aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
-    aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
+  aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
+  aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
+  aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
+  aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
 
-    // Assert a preprocessor definition at compile-time. It's an assumption
-    // used in assembly code, so check the assembly files before any change.
-    static_assert(PART_LEN % 16 == 0, "PART_LEN is not a multiple of 16");
+  // Assert a preprocessor definition at compile-time. It's an assumption
+  // used in assembly code, so check the assembly files before any change.
+  static_assert(PART_LEN % 16 == 0, "PART_LEN is not a multiple of 16");
 
-    // Initialize function pointers.
-    WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
-    WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
-    WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
+  // Initialize function pointers.
+  WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
+  WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
+  WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
 
 #if defined(WEBRTC_HAS_NEON)
-    WebRtcAecm_InitNeon();
+  WebRtcAecm_InitNeon();
 #endif
 
 #if defined(MIPS32_LE)
-    WebRtcAecm_InitMips();
+  WebRtcAecm_InitMips();
 #endif
-    return 0;
+  return 0;
 }
 
 // TODO(bjornv): This function is currently not used. Add support for these
 // parameters from a higher level
 int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
-    aecm->nlpFlag = nlpFlag;
-    aecm->fixedDelay = delay;
+  aecm->nlpFlag = nlpFlag;
+  aecm->fixedDelay = delay;
 
-    return 0;
+  return 0;
 }
 
 void WebRtcAecm_FreeCore(AecmCore* aecm) {
-    if (aecm == NULL) {
-      return;
-    }
+  if (aecm == NULL) {
+    return;
+  }
 
-    WebRtc_FreeBuffer(aecm->farFrameBuf);
-    WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
-    WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
-    WebRtc_FreeBuffer(aecm->outFrameBuf);
+  WebRtc_FreeBuffer(aecm->farFrameBuf);
+  WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
+  WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
+  WebRtc_FreeBuffer(aecm->outFrameBuf);
 
-    WebRtc_FreeDelayEstimator(aecm->delay_estimator);
-    WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
-    WebRtcSpl_FreeRealFFT(aecm->real_fft);
+  WebRtc_FreeDelayEstimator(aecm->delay_estimator);
+  WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
+  WebRtcSpl_FreeRealFFT(aecm->real_fft);
 
-    free(aecm);
+  free(aecm);
 }
 
 int WebRtcAecm_ProcessFrame(AecmCore* aecm,
@@ -554,89 +509,72 @@
                             const int16_t* nearendNoisy,
                             const int16_t* nearendClean,
                             int16_t* out) {
-    int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
-    int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
+  int16_t outBlock_buf[PART_LEN + 8];  // Align buffer to 8-byte boundary.
+  int16_t* outBlock = (int16_t*)(((uintptr_t)outBlock_buf + 15) & ~15);
 
-    int16_t farFrame[FRAME_LEN];
-    const int16_t* out_ptr = NULL;
-    int size = 0;
+  int16_t farFrame[FRAME_LEN];
+  const int16_t* out_ptr = NULL;
+  int size = 0;
 
-    // Buffer the current frame.
-    // Fetch an older one corresponding to the delay.
-    WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
-    WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
+  // Buffer the current frame.
+  // Fetch an older one corresponding to the delay.
+  WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
+  WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
 
-    // Buffer the synchronized far and near frames,
-    // to pass the smaller blocks individually.
-    WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
-    WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
-    if (nearendClean != NULL)
-    {
-        WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
+  // Buffer the synchronized far and near frames,
+  // to pass the smaller blocks individually.
+  WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
+  WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
+  if (nearendClean != NULL) {
+    WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
+  }
+
+  // Process as many blocks as possible.
+  while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) {
+    int16_t far_block[PART_LEN];
+    const int16_t* far_block_ptr = NULL;
+    int16_t near_noisy_block[PART_LEN];
+    const int16_t* near_noisy_block_ptr = NULL;
+
+    WebRtc_ReadBuffer(aecm->farFrameBuf, (void**)&far_block_ptr, far_block,
+                      PART_LEN);
+    WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, (void**)&near_noisy_block_ptr,
+                      near_noisy_block, PART_LEN);
+    if (nearendClean != NULL) {
+      int16_t near_clean_block[PART_LEN];
+      const int16_t* near_clean_block_ptr = NULL;
+
+      WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, (void**)&near_clean_block_ptr,
+                        near_clean_block, PART_LEN);
+      if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr,
+                                  near_clean_block_ptr, outBlock) == -1) {
+        return -1;
+      }
+    } else {
+      if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr,
+                                  NULL, outBlock) == -1) {
+        return -1;
+      }
     }
 
-    // Process as many blocks as possible.
-    while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
-    {
-        int16_t far_block[PART_LEN];
-        const int16_t* far_block_ptr = NULL;
-        int16_t near_noisy_block[PART_LEN];
-        const int16_t* near_noisy_block_ptr = NULL;
+    WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
+  }
 
-        WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
-                          PART_LEN);
-        WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
-                          (void**) &near_noisy_block_ptr,
-                          near_noisy_block,
-                          PART_LEN);
-        if (nearendClean != NULL)
-        {
-            int16_t near_clean_block[PART_LEN];
-            const int16_t* near_clean_block_ptr = NULL;
+  // Stuff the out buffer if we have less than a frame to output.
+  // This should only happen for the first frame.
+  size = (int)WebRtc_available_read(aecm->outFrameBuf);
+  if (size < FRAME_LEN) {
+    WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
+  }
 
-            WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
-                              (void**) &near_clean_block_ptr,
-                              near_clean_block,
-                              PART_LEN);
-            if (WebRtcAecm_ProcessBlock(aecm,
-                                        far_block_ptr,
-                                        near_noisy_block_ptr,
-                                        near_clean_block_ptr,
-                                        outBlock) == -1)
-            {
-                return -1;
-            }
-        } else
-        {
-            if (WebRtcAecm_ProcessBlock(aecm,
-                                        far_block_ptr,
-                                        near_noisy_block_ptr,
-                                        NULL,
-                                        outBlock) == -1)
-            {
-                return -1;
-            }
-        }
+  // Obtain an output frame.
+  WebRtc_ReadBuffer(aecm->outFrameBuf, (void**)&out_ptr, out, FRAME_LEN);
+  if (out_ptr != out) {
+    // ReadBuffer() hasn't copied to |out| in this case.
+    memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
+  }
 
-        WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
-    }
-
-    // Stuff the out buffer if we have less than a frame to output.
-    // This should only happen for the first frame.
-    size = (int) WebRtc_available_read(aecm->outFrameBuf);
-    if (size < FRAME_LEN)
-    {
-        WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
-    }
-
-    // Obtain an output frame.
-    WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
-    if (out_ptr != out) {
-      // ReadBuffer() hasn't copied to |out| in this case.
-      memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
-    }
-
-    return 0;
+  return 0;
 }
 
 // WebRtcAecm_AsymFilt(...)
@@ -653,26 +591,23 @@
 //
 // Return: - Filtered value.
 //
-int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal,
+int16_t WebRtcAecm_AsymFilt(const int16_t filtOld,
+                            const int16_t inVal,
                             const int16_t stepSizePos,
-                            const int16_t stepSizeNeg)
-{
-    int16_t retVal;
+                            const int16_t stepSizeNeg) {
+  int16_t retVal;
 
-    if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
-    {
-        return inVal;
-    }
-    retVal = filtOld;
-    if (filtOld > inVal)
-    {
-        retVal -= (filtOld - inVal) >> stepSizeNeg;
-    } else
-    {
-        retVal += (inVal - filtOld) >> stepSizePos;
-    }
+  if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) {
+    return inVal;
+  }
+  retVal = filtOld;
+  if (filtOld > inVal) {
+    retVal -= (filtOld - inVal) >> stepSizeNeg;
+  } else {
+    retVal += (inVal - filtOld) >> stepSizePos;
+  }
 
-    return retVal;
+  return retVal;
 }
 
 // ExtractFractionPart(a, zeros)
@@ -700,8 +635,9 @@
 
 // WebRtcAecm_CalcEnergies(...)
 //
-// This function calculates the log of energies for nearend, farend and estimated
-// echoes. There is also an update of energy decision levels, i.e. internal VAD.
+// This function calculates the log of energies for nearend, farend and
+// estimated echoes. There is also an update of energy decision levels, i.e.
+// internal VAD.
 //
 //
 // @param  aecm         [i/o]   Handle of the AECM instance.
@@ -716,123 +652,112 @@
                              const int16_t far_q,
                              const uint32_t nearEner,
                              int32_t* echoEst) {
-    // Local variables
-    uint32_t tmpAdapt = 0;
-    uint32_t tmpStored = 0;
-    uint32_t tmpFar = 0;
+  // Local variables
+  uint32_t tmpAdapt = 0;
+  uint32_t tmpStored = 0;
+  uint32_t tmpFar = 0;
 
-    int i;
+  int i;
 
-    int16_t tmp16;
-    int16_t increase_max_shifts = 4;
-    int16_t decrease_max_shifts = 11;
-    int16_t increase_min_shifts = 11;
-    int16_t decrease_min_shifts = 3;
+  int16_t tmp16;
+  int16_t increase_max_shifts = 4;
+  int16_t decrease_max_shifts = 11;
+  int16_t increase_min_shifts = 11;
+  int16_t decrease_min_shifts = 3;
 
-    // Get log of near end energy and store in buffer
+  // Get log of near end energy and store in buffer
 
-    // Shift buffer
-    memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
-            sizeof(int16_t) * (MAX_BUF_LEN - 1));
+  // Shift buffer
+  memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
+          sizeof(int16_t) * (MAX_BUF_LEN - 1));
 
-    // Logarithm of integrated magnitude spectrum (nearEner)
-    aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
+  // Logarithm of integrated magnitude spectrum (nearEner)
+  aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
 
-    WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
+  WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt,
+                                &tmpStored);
 
-    // Shift buffers
-    memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
-            sizeof(int16_t) * (MAX_BUF_LEN - 1));
-    memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
-            sizeof(int16_t) * (MAX_BUF_LEN - 1));
+  // Shift buffers
+  memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
+          sizeof(int16_t) * (MAX_BUF_LEN - 1));
+  memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
+          sizeof(int16_t) * (MAX_BUF_LEN - 1));
 
-    // Logarithm of delayed far end energy
-    aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
+  // Logarithm of delayed far end energy
+  aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
 
-    // Logarithm of estimated echo energy through adapted channel
-    aecm->echoAdaptLogEnergy[0] = LogOfEnergyInQ8(tmpAdapt,
-                                                  RESOLUTION_CHANNEL16 + far_q);
+  // Logarithm of estimated echo energy through adapted channel
+  aecm->echoAdaptLogEnergy[0] =
+      LogOfEnergyInQ8(tmpAdapt, RESOLUTION_CHANNEL16 + far_q);
 
-    // Logarithm of estimated echo energy through stored channel
-    aecm->echoStoredLogEnergy[0] =
-        LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
+  // Logarithm of estimated echo energy through stored channel
+  aecm->echoStoredLogEnergy[0] =
+      LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
 
-    // Update farend energy levels (min, max, vad, mse)
-    if (aecm->farLogEnergy > FAR_ENERGY_MIN)
-    {
-        if (aecm->startupState == 0)
-        {
-            increase_max_shifts = 2;
-            decrease_min_shifts = 2;
-            increase_min_shifts = 8;
-        }
-
-        aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
-                                                 increase_min_shifts, decrease_min_shifts);
-        aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
-                                                 increase_max_shifts, decrease_max_shifts);
-        aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
-
-        // Dynamic VAD region size
-        tmp16 = 2560 - aecm->farEnergyMin;
-        if (tmp16 > 0)
-        {
-          tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
-        } else
-        {
-            tmp16 = 0;
-        }
-        tmp16 += FAR_ENERGY_VAD_REGION;
-
-        if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
-        {
-            // In startup phase or VAD update halted
-            aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
-        } else
-        {
-            if (aecm->farEnergyVAD > aecm->farLogEnergy)
-            {
-                aecm->farEnergyVAD +=
-                    (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
-                aecm->vadUpdateCount = 0;
-            } else
-            {
-                aecm->vadUpdateCount++;
-            }
-        }
-        // Put MSE threshold higher than VAD
-        aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
+  // Update farend energy levels (min, max, vad, mse)
+  if (aecm->farLogEnergy > FAR_ENERGY_MIN) {
+    if (aecm->startupState == 0) {
+      increase_max_shifts = 2;
+      decrease_min_shifts = 2;
+      increase_min_shifts = 8;
     }
 
-    // Update VAD variables
-    if (aecm->farLogEnergy > aecm->farEnergyVAD)
-    {
-        if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
-        {
-            // We are in startup or have significant dynamics in input speech level
-            aecm->currentVADValue = 1;
-        }
-    } else
-    {
-        aecm->currentVADValue = 0;
+    aecm->farEnergyMin =
+        WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
+                            increase_min_shifts, decrease_min_shifts);
+    aecm->farEnergyMax =
+        WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
+                            increase_max_shifts, decrease_max_shifts);
+    aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
+
+    // Dynamic VAD region size
+    tmp16 = 2560 - aecm->farEnergyMin;
+    if (tmp16 > 0) {
+      tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
+    } else {
+      tmp16 = 0;
     }
-    if ((aecm->currentVADValue) && (aecm->firstVAD))
-    {
-        aecm->firstVAD = 0;
-        if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
-        {
-            // The estimated echo has higher energy than the near end signal.
-            // This means that the initialization was too aggressive. Scale
-            // down by a factor 8
-            for (i = 0; i < PART_LEN1; i++)
-            {
-                aecm->channelAdapt16[i] >>= 3;
-            }
-            // Compensate the adapted echo energy level accordingly.
-            aecm->echoAdaptLogEnergy[0] -= (3 << 8);
-            aecm->firstVAD = 1;
-        }
+    tmp16 += FAR_ENERGY_VAD_REGION;
+
+    if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) {
+      // In startup phase or VAD update halted
+      aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
+    } else {
+      if (aecm->farEnergyVAD > aecm->farLogEnergy) {
+        aecm->farEnergyVAD +=
+            (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
+        aecm->vadUpdateCount = 0;
+      } else {
+        aecm->vadUpdateCount++;
+      }
     }
+    // Put MSE threshold higher than VAD
+    aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
+  }
+
+  // Update VAD variables
+  if (aecm->farLogEnergy > aecm->farEnergyVAD) {
+    if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF)) {
+      // We are in startup or have significant dynamics in input speech level
+      aecm->currentVADValue = 1;
+    }
+  } else {
+    aecm->currentVADValue = 0;
+  }
+  if ((aecm->currentVADValue) && (aecm->firstVAD)) {
+    aecm->firstVAD = 0;
+    if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) {
+      // The estimated echo has higher energy than the near end signal.
+      // This means that the initialization was too aggressive. Scale
+      // down by a factor 8
+      for (i = 0; i < PART_LEN1; i++) {
+        aecm->channelAdapt16[i] >>= 3;
+      }
+      // Compensate the adapted echo energy level accordingly.
+      aecm->echoAdaptLogEnergy[0] -= (3 << 8);
+      aecm->firstVAD = 1;
+    }
+  }
 }
 
 // WebRtcAecm_CalcStepSize(...)
@@ -841,52 +766,50 @@
 //
 //
 // @param  aecm  [in]    Handle of the AECM instance.
-// @param  mu    [out]   (Return value) Stepsize in log2(), i.e. number of shifts.
+// @param  mu    [out]   (Return value) Stepsize in log2(), i.e. number of
+// shifts.
 //
 //
 int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) {
-    int32_t tmp32;
-    int16_t tmp16;
-    int16_t mu = MU_MAX;
+  int32_t tmp32;
+  int16_t tmp16;
+  int16_t mu = MU_MAX;
 
-    // Here we calculate the step size mu used in the
-    // following NLMS based Channel estimation algorithm
-    if (!aecm->currentVADValue)
-    {
-        // Far end energy level too low, no channel update
-        mu = 0;
-    } else if (aecm->startupState > 0)
-    {
-        if (aecm->farEnergyMin >= aecm->farEnergyMax)
-        {
-            mu = MU_MIN;
-        } else
-        {
-            tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
-            tmp32 = tmp16 * MU_DIFF;
-            tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
-            mu = MU_MIN - 1 - (int16_t)(tmp32);
-            // The -1 is an alternative to rounding. This way we get a larger
-            // stepsize, so we in some sense compensate for truncation in NLMS
-        }
-        if (mu < MU_MAX)
-        {
-            mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
-        }
+  // Here we calculate the step size mu used in the
+  // following NLMS based Channel estimation algorithm
+  if (!aecm->currentVADValue) {
+    // Far end energy level too low, no channel update
+    mu = 0;
+  } else if (aecm->startupState > 0) {
+    if (aecm->farEnergyMin >= aecm->farEnergyMax) {
+      mu = MU_MIN;
+    } else {
+      tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
+      tmp32 = tmp16 * MU_DIFF;
+      tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
+      mu = MU_MIN - 1 - (int16_t)(tmp32);
+      // The -1 is an alternative to rounding. This way we get a larger
+      // stepsize, so we in some sense compensate for truncation in NLMS
     }
+    if (mu < MU_MAX) {
+      mu = MU_MAX;  // Equivalent with maximum step size of 2^-MU_MAX
+    }
+  }
 
-    return mu;
+  return mu;
 }
 
 // WebRtcAecm_UpdateChannel(...)
 //
-// This function performs channel estimation. NLMS and decision on channel storage.
+// This function performs channel estimation. NLMS and decision on channel
+// storage.
 //
 //
 // @param  aecm         [i/o]   Handle of the AECM instance.
 // @param  far_spectrum [in]    Absolute value of the farend signal in Q(far_q)
 // @param  far_q        [in]    Q-domain of the farend signal
-// @param  dfa          [in]    Absolute value of the nearend signal (Q[aecm->dfaQDomain])
+// @param  dfa          [in]    Absolute value of the nearend signal
+// (Q[aecm->dfaQDomain])
 // @param  mu           [in]    NLMS step size.
 // @param  echoEst      [i/o]   Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
 //
@@ -896,343 +819,301 @@
                               const uint16_t* const dfa,
                               const int16_t mu,
                               int32_t* echoEst) {
-    uint32_t tmpU32no1, tmpU32no2;
-    int32_t tmp32no1, tmp32no2;
-    int32_t mseStored;
-    int32_t mseAdapt;
+  uint32_t tmpU32no1, tmpU32no2;
+  int32_t tmp32no1, tmp32no2;
+  int32_t mseStored;
+  int32_t mseAdapt;
 
-    int i;
+  int i;
 
-    int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
-    int16_t shiftChFar, shiftNum, shift2ResChan;
-    int16_t tmp16no1;
-    int16_t xfaQ, dfaQ;
+  int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
+  int16_t shiftChFar, shiftNum, shift2ResChan;
+  int16_t tmp16no1;
+  int16_t xfaQ, dfaQ;
 
-    // This is the channel estimation algorithm. It is base on NLMS but has a variable step
-    // length, which was calculated above.
-    if (mu)
-    {
-        for (i = 0; i < PART_LEN1; i++)
-        {
-            // Determine norm of channel and farend to make sure we don't get overflow in
-            // multiplication
-            zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
-            zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
-            if (zerosCh + zerosFar > 31)
-            {
-                // Multiplication is safe
-                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
-                        far_spectrum[i]);
-                shiftChFar = 0;
-            } else
-            {
-                // We need to shift down before multiplication
-                shiftChFar = 32 - zerosCh - zerosFar;
-                // If zerosCh == zerosFar == 0, shiftChFar is 32. A
-                // right shift of 32 is undefined. To avoid that, we
-                // do this check.
-                tmpU32no1 = rtc::dchecked_cast<uint32_t>(
-                                shiftChFar >= 32
-                                    ? 0
-                                    : aecm->channelAdapt32[i] >> shiftChFar) *
-                            far_spectrum[i];
-            }
-            // Determine Q-domain of numerator
-            zerosNum = WebRtcSpl_NormU32(tmpU32no1);
-            if (dfa[i])
-            {
-                zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
-            } else
-            {
-                zerosDfa = 32;
-            }
-            tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
-                RESOLUTION_CHANNEL32 - far_q + shiftChFar;
-            if (zerosNum > tmp16no1 + 1)
-            {
-                xfaQ = tmp16no1;
-                dfaQ = zerosDfa - 2;
-            } else
-            {
-                xfaQ = zerosNum - 2;
-                dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
-                    shiftChFar + xfaQ;
-            }
-            // Add in the same Q-domain
-            tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
-            tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
-            tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
-            zerosNum = WebRtcSpl_NormW32(tmp32no1);
-            if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
-            {
-                //
-                // Update is needed
-                //
-                // This is what we would like to compute
-                //
-                // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
-                // tmp32norm = (i + 1)
-                // aecm->channelAdapt[i] += (2^mu) * tmp32no1
-                //                        / (tmp32norm * far_spectrum[i])
-                //
+  // This is the channel estimation algorithm. It is base on NLMS but has a
+  // variable step length, which was calculated above.
+  if (mu) {
+    for (i = 0; i < PART_LEN1; i++) {
+      // Determine norm of channel and farend to make sure we don't get overflow
+      // in multiplication
+      zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
+      zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
+      if (zerosCh + zerosFar > 31) {
+        // Multiplication is safe
+        tmpU32no1 =
+            WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], far_spectrum[i]);
+        shiftChFar = 0;
+      } else {
+        // We need to shift down before multiplication
+        shiftChFar = 32 - zerosCh - zerosFar;
+        // If zerosCh == zerosFar == 0, shiftChFar is 32. A
+        // right shift of 32 is undefined. To avoid that, we
+        // do this check.
+        tmpU32no1 =
+            rtc::dchecked_cast<uint32_t>(
+                shiftChFar >= 32 ? 0 : aecm->channelAdapt32[i] >> shiftChFar) *
+            far_spectrum[i];
+      }
+      // Determine Q-domain of numerator
+      zerosNum = WebRtcSpl_NormU32(tmpU32no1);
+      if (dfa[i]) {
+        zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
+      } else {
+        zerosDfa = 32;
+      }
+      tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - RESOLUTION_CHANNEL32 -
+                 far_q + shiftChFar;
+      if (zerosNum > tmp16no1 + 1) {
+        xfaQ = tmp16no1;
+        dfaQ = zerosDfa - 2;
+      } else {
+        xfaQ = zerosNum - 2;
+        dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
+               shiftChFar + xfaQ;
+      }
+      // Add in the same Q-domain
+      tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
+      tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
+      tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
+      zerosNum = WebRtcSpl_NormW32(tmp32no1);
+      if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) {
+        //
+        // Update is needed
+        //
+        // This is what we would like to compute
+        //
+        // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
+        // tmp32norm = (i + 1)
+        // aecm->channelAdapt[i] += (2^mu) * tmp32no1
+        //                        / (tmp32norm * far_spectrum[i])
+        //
 
-                // Make sure we don't get overflow in multiplication.
-                if (zerosNum + zerosFar > 31)
-                {
-                    if (tmp32no1 > 0)
-                    {
-                        tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1,
-                                                                        far_spectrum[i]);
-                    } else
-                    {
-                        tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
-                                                                         far_spectrum[i]);
-                    }
-                    shiftNum = 0;
-                } else
-                {
-                    shiftNum = 32 - (zerosNum + zerosFar);
-                    if (tmp32no1 > 0)
-                    {
-                        tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
-                    } else
-                    {
-                        tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
-                    }
-                }
-                // Normalize with respect to frequency bin
-                tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
-                // Make sure we are in the right Q-domain
-                shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
-                if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
-                {
-                    tmp32no2 = WEBRTC_SPL_WORD32_MAX;
-                } else
-                {
-                    tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
-                }
-                aecm->channelAdapt32[i] =
-                    WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
-                if (aecm->channelAdapt32[i] < 0)
-                {
-                    // We can never have negative channel gain
-                    aecm->channelAdapt32[i] = 0;
-                }
-                aecm->channelAdapt16[i] =
-                    (int16_t)(aecm->channelAdapt32[i] >> 16);
-            }
+        // Make sure we don't get overflow in multiplication.
+        if (zerosNum + zerosFar > 31) {
+          if (tmp32no1 > 0) {
+            tmp32no2 =
+                (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1, far_spectrum[i]);
+          } else {
+            tmp32no2 =
+                -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1, far_spectrum[i]);
+          }
+          shiftNum = 0;
+        } else {
+          shiftNum = 32 - (zerosNum + zerosFar);
+          if (tmp32no1 > 0) {
+            tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
+          } else {
+            tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
+          }
         }
+        // Normalize with respect to frequency bin
+        tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
+        // Make sure we are in the right Q-domain
+        shift2ResChan =
+            shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
+        if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) {
+          tmp32no2 = WEBRTC_SPL_WORD32_MAX;
+        } else {
+          tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
+        }
+        aecm->channelAdapt32[i] =
+            WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
+        if (aecm->channelAdapt32[i] < 0) {
+          // We can never have negative channel gain
+          aecm->channelAdapt32[i] = 0;
+        }
+        aecm->channelAdapt16[i] = (int16_t)(aecm->channelAdapt32[i] >> 16);
+      }
     }
-    // END: Adaptive channel update
+  }
+  // END: Adaptive channel update
 
-    // Determine if we should store or restore the channel
-    if ((aecm->startupState == 0) & (aecm->currentVADValue))
-    {
-        // During startup we store the channel every block,
-        // and we recalculate echo estimate
+  // Determine if we should store or restore the channel
+  if ((aecm->startupState == 0) & (aecm->currentVADValue)) {
+    // During startup we store the channel every block,
+    // and we recalculate echo estimate
+    WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
+  } else {
+    if (aecm->farLogEnergy < aecm->farEnergyMSE) {
+      aecm->mseChannelCount = 0;
+    } else {
+      aecm->mseChannelCount++;
+    }
+    // Enough data for validation. Store channel if we can.
+    if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10)) {
+      // We have enough data.
+      // Calculate MSE of "Adapt" and "Stored" versions.
+      // It is actually not MSE, but average absolute error.
+      mseStored = 0;
+      mseAdapt = 0;
+      for (i = 0; i < MIN_MSE_COUNT; i++) {
+        tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i] -
+                    (int32_t)aecm->nearLogEnergy[i]);
+        tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
+        mseStored += tmp32no2;
+
+        tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i] -
+                    (int32_t)aecm->nearLogEnergy[i]);
+        tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
+        mseAdapt += tmp32no2;
+      }
+      if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt)) &
+          ((aecm->mseStoredOld << MSE_RESOLUTION) <
+           (MIN_MSE_DIFF * aecm->mseAdaptOld))) {
+        // The stored channel has a significantly lower MSE than the adaptive
+        // one for two consecutive calculations. Reset the adaptive channel.
+        WebRtcAecm_ResetAdaptiveChannel(aecm);
+      } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) &
+                 (mseAdapt < aecm->mseThreshold) &
+                 (aecm->mseAdaptOld < aecm->mseThreshold)) {
+        // The adaptive channel has a significantly lower MSE than the stored
+        // one. The MSE for the adaptive channel has also been low for two
+        // consecutive calculations. Store the adaptive channel.
         WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
-    } else
-    {
-        if (aecm->farLogEnergy < aecm->farEnergyMSE)
-        {
-            aecm->mseChannelCount = 0;
-        } else
-        {
-            aecm->mseChannelCount++;
+
+        // Update threshold
+        if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) {
+          aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
+        } else {
+          int scaled_threshold = aecm->mseThreshold * 5 / 8;
+          aecm->mseThreshold += ((mseAdapt - scaled_threshold) * 205) >> 8;
         }
-        // Enough data for validation. Store channel if we can.
-        if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
-        {
-            // We have enough data.
-            // Calculate MSE of "Adapt" and "Stored" versions.
-            // It is actually not MSE, but average absolute error.
-            mseStored = 0;
-            mseAdapt = 0;
-            for (i = 0; i < MIN_MSE_COUNT; i++)
-            {
-                tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i]
-                        - (int32_t)aecm->nearLogEnergy[i]);
-                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
-                mseStored += tmp32no2;
+      }
 
-                tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i]
-                        - (int32_t)aecm->nearLogEnergy[i]);
-                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
-                mseAdapt += tmp32no2;
-            }
-            if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
-                    & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
-                            * aecm->mseAdaptOld)))
-            {
-                // The stored channel has a significantly lower MSE than the adaptive one for
-                // two consecutive calculations. Reset the adaptive channel.
-                WebRtcAecm_ResetAdaptiveChannel(aecm);
-            } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
-                    < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
-            {
-                // The adaptive channel has a significantly lower MSE than the stored one.
-                // The MSE for the adaptive channel has also been low for two consecutive
-                // calculations. Store the adaptive channel.
-                WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
+      // Reset counter
+      aecm->mseChannelCount = 0;
 
-                // Update threshold
-                if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
-                {
-                    aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
-                } else
-                {
-                  int scaled_threshold = aecm->mseThreshold * 5 / 8;
-                  aecm->mseThreshold +=
-                      ((mseAdapt - scaled_threshold) * 205) >> 8;
-                }
-
-            }
-
-            // Reset counter
-            aecm->mseChannelCount = 0;
-
-            // Store the MSE values.
-            aecm->mseStoredOld = mseStored;
-            aecm->mseAdaptOld = mseAdapt;
-        }
+      // Store the MSE values.
+      aecm->mseStoredOld = mseStored;
+      aecm->mseAdaptOld = mseAdapt;
     }
-    // END: Determine if we should store or reset channel estimate.
+  }
+  // END: Determine if we should store or reset channel estimate.
 }
 
 // CalcSuppressionGain(...)
 //
-// This function calculates the suppression gain that is used in the Wiener filter.
+// This function calculates the suppression gain that is used in the Wiener
+// filter.
 //
 //
 // @param  aecm     [i/n]   Handle of the AECM instance.
-// @param  supGain  [out]   (Return value) Suppression gain with which to scale the noise
+// @param  supGain  [out]   (Return value) Suppression gain with which to scale
+// the noise
 //                          level (Q14).
 //
 //
 int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) {
-    int32_t tmp32no1;
+  int32_t tmp32no1;
 
-    int16_t supGain = SUPGAIN_DEFAULT;
-    int16_t tmp16no1;
-    int16_t dE = 0;
+  int16_t supGain = SUPGAIN_DEFAULT;
+  int16_t tmp16no1;
+  int16_t dE = 0;
 
-    // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
-    // end energy and echo estimation error.
-    // Adjust for the far end signal level. A low signal level indicates no far end signal,
-    // hence we set the suppression gain to 0
-    if (!aecm->currentVADValue)
-    {
-        supGain = 0;
-    } else
-    {
-        // Adjust for possible double talk. If we have large variations in estimation error we
-        // likely have double talk (or poor channel).
-        tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
-        dE = WEBRTC_SPL_ABS_W16(tmp16no1);
+  // Determine suppression gain used in the Wiener filter. The gain is based on
+  // a mix of far end energy and echo estimation error. Adjust for the far end
+  // signal level. A low signal level indicates no far end signal, hence we set
+  // the suppression gain to 0
+  if (!aecm->currentVADValue) {
+    supGain = 0;
+  } else {
+    // Adjust for possible double talk. If we have large variations in
+    // estimation error we likely have double talk (or poor channel).
+    tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] -
+                ENERGY_DEV_OFFSET);
+    dE = WEBRTC_SPL_ABS_W16(tmp16no1);
 
-        if (dE < ENERGY_DEV_TOL)
-        {
-            // Likely no double talk. The better estimation, the more we can suppress signal.
-            // Update counters
-            if (dE < SUPGAIN_EPC_DT)
-            {
-                tmp32no1 = aecm->supGainErrParamDiffAB * dE;
-                tmp32no1 += (SUPGAIN_EPC_DT >> 1);
-                tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
-                supGain = aecm->supGainErrParamA - tmp16no1;
-            } else
-            {
-                tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
-                tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
-                tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
-                        - SUPGAIN_EPC_DT));
-                supGain = aecm->supGainErrParamD + tmp16no1;
-            }
-        } else
-        {
-            // Likely in double talk. Use default value
-            supGain = aecm->supGainErrParamD;
-        }
+    if (dE < ENERGY_DEV_TOL) {
+      // Likely no double talk. The better estimation, the more we can suppress
+      // signal. Update counters
+      if (dE < SUPGAIN_EPC_DT) {
+        tmp32no1 = aecm->supGainErrParamDiffAB * dE;
+        tmp32no1 += (SUPGAIN_EPC_DT >> 1);
+        tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
+        supGain = aecm->supGainErrParamA - tmp16no1;
+      } else {
+        tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
+        tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
+        tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(
+            tmp32no1, (ENERGY_DEV_TOL - SUPGAIN_EPC_DT));
+        supGain = aecm->supGainErrParamD + tmp16no1;
+      }
+    } else {
+      // Likely in double talk. Use default value
+      supGain = aecm->supGainErrParamD;
     }
+  }
 
-    if (supGain > aecm->supGainOld)
-    {
-        tmp16no1 = supGain;
-    } else
-    {
-        tmp16no1 = aecm->supGainOld;
-    }
-    aecm->supGainOld = supGain;
-    if (tmp16no1 < aecm->supGain)
-    {
-        aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
-    } else
-    {
-        aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
-    }
+  if (supGain > aecm->supGainOld) {
+    tmp16no1 = supGain;
+  } else {
+    tmp16no1 = aecm->supGainOld;
+  }
+  aecm->supGainOld = supGain;
+  if (tmp16no1 < aecm->supGain) {
+    aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
+  } else {
+    aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
+  }
 
-    // END: Update suppression gain
+  // END: Update suppression gain
 
-    return aecm->supGain;
+  return aecm->supGain;
 }
 
 void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
                                const int16_t* const farend,
                                const int farLen) {
-    int writeLen = farLen, writePos = 0;
+  int writeLen = farLen, writePos = 0;
 
-    // Check if the write position must be wrapped
-    while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
-    {
-        // Write to remaining buffer space before wrapping
-        writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
-        memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
-               sizeof(int16_t) * writeLen);
-        aecm->farBufWritePos = 0;
-        writePos = writeLen;
-        writeLen = farLen - writeLen;
-    }
-
+  // Check if the write position must be wrapped
+  while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN) {
+    // Write to remaining buffer space before wrapping
+    writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
     memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
            sizeof(int16_t) * writeLen);
-    aecm->farBufWritePos += writeLen;
+    aecm->farBufWritePos = 0;
+    writePos = writeLen;
+    writeLen = farLen - writeLen;
+  }
+
+  memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
+         sizeof(int16_t) * writeLen);
+  aecm->farBufWritePos += writeLen;
 }
 
 void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
                               int16_t* const farend,
                               const int farLen,
                               const int knownDelay) {
-    int readLen = farLen;
-    int readPos = 0;
-    int delayChange = knownDelay - aecm->lastKnownDelay;
+  int readLen = farLen;
+  int readPos = 0;
+  int delayChange = knownDelay - aecm->lastKnownDelay;
 
-    aecm->farBufReadPos -= delayChange;
+  aecm->farBufReadPos -= delayChange;
 
-    // Check if delay forces a read position wrap
-    while (aecm->farBufReadPos < 0)
-    {
-        aecm->farBufReadPos += FAR_BUF_LEN;
-    }
-    while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
-    {
-        aecm->farBufReadPos -= FAR_BUF_LEN;
-    }
+  // Check if delay forces a read position wrap
+  while (aecm->farBufReadPos < 0) {
+    aecm->farBufReadPos += FAR_BUF_LEN;
+  }
+  while (aecm->farBufReadPos > FAR_BUF_LEN - 1) {
+    aecm->farBufReadPos -= FAR_BUF_LEN;
+  }
 
-    aecm->lastKnownDelay = knownDelay;
+  aecm->lastKnownDelay = knownDelay;
 
-    // Check if read position must be wrapped
-    while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
-    {
-
-        // Read from remaining buffer space before wrapping
-        readLen = FAR_BUF_LEN - aecm->farBufReadPos;
-        memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
-               sizeof(int16_t) * readLen);
-        aecm->farBufReadPos = 0;
-        readPos = readLen;
-        readLen = farLen - readLen;
-    }
+  // Check if read position must be wrapped
+  while (aecm->farBufReadPos + readLen > FAR_BUF_LEN) {
+    // Read from remaining buffer space before wrapping
+    readLen = FAR_BUF_LEN - aecm->farBufReadPos;
     memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
            sizeof(int16_t) * readLen);
-    aecm->farBufReadPos += readLen;
+    aecm->farBufReadPos = 0;
+    readPos = readLen;
+    readLen = farLen - readLen;
+  }
+  memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
+         sizeof(int16_t) * readLen);
+  aecm->farBufReadPos += readLen;
 }
diff --git a/modules/audio_processing/aecm/aecm_core.h b/modules/audio_processing/aecm/aecm_core.h
index feb997e..3da3bca 100644
--- a/modules/audio_processing/aecm/aecm_core.h
+++ b/modules/audio_processing/aecm/aecm_core.h
@@ -29,109 +29,109 @@
 #endif
 
 typedef struct {
-    int16_t real;
-    int16_t imag;
+  int16_t real;
+  int16_t imag;
 } ComplexInt16;
 
 typedef struct {
-    int farBufWritePos;
-    int farBufReadPos;
-    int knownDelay;
-    int lastKnownDelay;
-    int firstVAD;  // Parameter to control poorly initialized channels
+  int farBufWritePos;
+  int farBufReadPos;
+  int knownDelay;
+  int lastKnownDelay;
+  int firstVAD;  // Parameter to control poorly initialized channels
 
-    RingBuffer* farFrameBuf;
-    RingBuffer* nearNoisyFrameBuf;
-    RingBuffer* nearCleanFrameBuf;
-    RingBuffer* outFrameBuf;
+  RingBuffer* farFrameBuf;
+  RingBuffer* nearNoisyFrameBuf;
+  RingBuffer* nearCleanFrameBuf;
+  RingBuffer* outFrameBuf;
 
-    int16_t farBuf[FAR_BUF_LEN];
+  int16_t farBuf[FAR_BUF_LEN];
 
-    int16_t mult;
-    uint32_t seed;
+  int16_t mult;
+  uint32_t seed;
 
-    // Delay estimation variables
-    void* delay_estimator_farend;
-    void* delay_estimator;
-    uint16_t currentDelay;
-    // Far end history variables
-    // TODO(bjornv): Replace |far_history| with ring_buffer.
-    uint16_t far_history[PART_LEN1 * MAX_DELAY];
-    int far_history_pos;
-    int far_q_domains[MAX_DELAY];
+  // Delay estimation variables
+  void* delay_estimator_farend;
+  void* delay_estimator;
+  uint16_t currentDelay;
+  // Far end history variables
+  // TODO(bjornv): Replace |far_history| with ring_buffer.
+  uint16_t far_history[PART_LEN1 * MAX_DELAY];
+  int far_history_pos;
+  int far_q_domains[MAX_DELAY];
 
-    int16_t nlpFlag;
-    int16_t fixedDelay;
+  int16_t nlpFlag;
+  int16_t fixedDelay;
 
-    uint32_t totCount;
+  uint32_t totCount;
 
-    int16_t dfaCleanQDomain;
-    int16_t dfaCleanQDomainOld;
-    int16_t dfaNoisyQDomain;
-    int16_t dfaNoisyQDomainOld;
+  int16_t dfaCleanQDomain;
+  int16_t dfaCleanQDomainOld;
+  int16_t dfaNoisyQDomain;
+  int16_t dfaNoisyQDomainOld;
 
-    int16_t nearLogEnergy[MAX_BUF_LEN];
-    int16_t farLogEnergy;
-    int16_t echoAdaptLogEnergy[MAX_BUF_LEN];
-    int16_t echoStoredLogEnergy[MAX_BUF_LEN];
+  int16_t nearLogEnergy[MAX_BUF_LEN];
+  int16_t farLogEnergy;
+  int16_t echoAdaptLogEnergy[MAX_BUF_LEN];
+  int16_t echoStoredLogEnergy[MAX_BUF_LEN];
 
-    // The extra 16 or 32 bytes in the following buffers are for alignment based
-    // Neon code.
-    // It's designed this way since the current GCC compiler can't align a
-    // buffer in 16 or 32 byte boundaries properly.
-    int16_t channelStored_buf[PART_LEN1 + 8];
-    int16_t channelAdapt16_buf[PART_LEN1 + 8];
-    int32_t channelAdapt32_buf[PART_LEN1 + 8];
-    int16_t xBuf_buf[PART_LEN2 + 16];  // farend
-    int16_t dBufClean_buf[PART_LEN2 + 16];  // nearend
-    int16_t dBufNoisy_buf[PART_LEN2 + 16];  // nearend
-    int16_t outBuf_buf[PART_LEN + 8];
+  // The extra 16 or 32 bytes in the following buffers are for alignment based
+  // Neon code.
+  // It's designed this way since the current GCC compiler can't align a
+  // buffer in 16 or 32 byte boundaries properly.
+  int16_t channelStored_buf[PART_LEN1 + 8];
+  int16_t channelAdapt16_buf[PART_LEN1 + 8];
+  int32_t channelAdapt32_buf[PART_LEN1 + 8];
+  int16_t xBuf_buf[PART_LEN2 + 16];       // farend
+  int16_t dBufClean_buf[PART_LEN2 + 16];  // nearend
+  int16_t dBufNoisy_buf[PART_LEN2 + 16];  // nearend
+  int16_t outBuf_buf[PART_LEN + 8];
 
-    // Pointers to the above buffers
-    int16_t *channelStored;
-    int16_t *channelAdapt16;
-    int32_t *channelAdapt32;
-    int16_t *xBuf;
-    int16_t *dBufClean;
-    int16_t *dBufNoisy;
-    int16_t *outBuf;
+  // Pointers to the above buffers
+  int16_t* channelStored;
+  int16_t* channelAdapt16;
+  int32_t* channelAdapt32;
+  int16_t* xBuf;
+  int16_t* dBufClean;
+  int16_t* dBufNoisy;
+  int16_t* outBuf;
 
-    int32_t echoFilt[PART_LEN1];
-    int16_t nearFilt[PART_LEN1];
-    int32_t noiseEst[PART_LEN1];
-    int           noiseEstTooLowCtr[PART_LEN1];
-    int           noiseEstTooHighCtr[PART_LEN1];
-    int16_t noiseEstCtr;
-    int16_t cngMode;
+  int32_t echoFilt[PART_LEN1];
+  int16_t nearFilt[PART_LEN1];
+  int32_t noiseEst[PART_LEN1];
+  int noiseEstTooLowCtr[PART_LEN1];
+  int noiseEstTooHighCtr[PART_LEN1];
+  int16_t noiseEstCtr;
+  int16_t cngMode;
 
-    int32_t mseAdaptOld;
-    int32_t mseStoredOld;
-    int32_t mseThreshold;
+  int32_t mseAdaptOld;
+  int32_t mseStoredOld;
+  int32_t mseThreshold;
 
-    int16_t farEnergyMin;
-    int16_t farEnergyMax;
-    int16_t farEnergyMaxMin;
-    int16_t farEnergyVAD;
-    int16_t farEnergyMSE;
-    int currentVADValue;
-    int16_t vadUpdateCount;
+  int16_t farEnergyMin;
+  int16_t farEnergyMax;
+  int16_t farEnergyMaxMin;
+  int16_t farEnergyVAD;
+  int16_t farEnergyMSE;
+  int currentVADValue;
+  int16_t vadUpdateCount;
 
-    int16_t startupState;
-    int16_t mseChannelCount;
-    int16_t supGain;
-    int16_t supGainOld;
+  int16_t startupState;
+  int16_t mseChannelCount;
+  int16_t supGain;
+  int16_t supGainOld;
 
-    int16_t supGainErrParamA;
-    int16_t supGainErrParamD;
-    int16_t supGainErrParamDiffAB;
-    int16_t supGainErrParamDiffBD;
+  int16_t supGainErrParamA;
+  int16_t supGainErrParamD;
+  int16_t supGainErrParamDiffAB;
+  int16_t supGainErrParamDiffBD;
 
-    struct RealFFT* real_fft;
+  struct RealFFT* real_fft;
 
 #ifdef AEC_DEBUG
-    FILE *farFile;
-    FILE *nearFile;
-    FILE *outFile;
+  FILE* farFile;
+  FILE* nearFile;
+  FILE* outFile;
 #endif
 } AecmCore;
 
diff --git a/modules/audio_processing/aecm/aecm_core_c.cc b/modules/audio_processing/aecm/aecm_core_c.cc
index effe048..b640f1a 100644
--- a/modules/audio_processing/aecm/aecm_core_c.cc
+++ b/modules/audio_processing/aecm/aecm_core_c.cc
@@ -30,28 +30,25 @@
 
 // Square root of Hanning window in Q14.
 static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
-  0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
-  3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
-  6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
-  9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
-  11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
-  13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
-  15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
-  16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
-};
+    0,     399,   798,   1196,  1594,  1990,  2386,  2780,  3172,  3562,  3951,
+    4337,  4720,  5101,  5478,  5853,  6224,  6591,  6954,  7313,  7668,  8019,
+    8364,  8705,  9040,  9370,  9695,  10013, 10326, 10633, 10933, 11227, 11514,
+    11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189,
+    14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851,
+    15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384};
 
 #ifdef AECM_WITH_ABS_APPROX
-//Q15 alpha = 0.99439986968132  const Factor for magnitude approximation
+// Q15 alpha = 0.99439986968132  const Factor for magnitude approximation
 static const uint16_t kAlpha1 = 32584;
-//Q15 beta = 0.12967166976970   const Factor for magnitude approximation
+// Q15 beta = 0.12967166976970   const Factor for magnitude approximation
 static const uint16_t kBeta1 = 4249;
-//Q15 alpha = 0.94234827210087  const Factor for magnitude approximation
+// Q15 alpha = 0.94234827210087  const Factor for magnitude approximation
 static const uint16_t kAlpha2 = 30879;
-//Q15 beta = 0.33787806009150   const Factor for magnitude approximation
+// Q15 beta = 0.33787806009150   const Factor for magnitude approximation
 static const uint16_t kBeta2 = 11072;
-//Q15 alpha = 0.82247698684306  const Factor for magnitude approximation
+// Q15 alpha = 0.82247698684306  const Factor for magnitude approximation
 static const uint16_t kAlpha3 = 26951;
-//Q15 beta = 0.57762063060713   const Factor for magnitude approximation
+// Q15 beta = 0.57762063060713   const Factor for magnitude approximation
 static const uint16_t kBeta3 = 18927;
 #endif
 
@@ -77,8 +74,8 @@
     int16_t scaled_time_signal = time_signal[i] * (1 << time_signal_scaling);
     fft[i] = (int16_t)((scaled_time_signal * WebRtcAecm_kSqrtHanning[i]) >> 14);
     scaled_time_signal = time_signal[i + PART_LEN] * (1 << time_signal_scaling);
-    fft[PART_LEN + i] = (int16_t)((
-        scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14);
+    fft[PART_LEN + i] = (int16_t)(
+        (scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14);
   }
 
   // Do forward FFT, then take only the first PART_LEN complex samples,
@@ -115,32 +112,27 @@
   outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out);
   for (i = 0; i < PART_LEN; i++) {
     ifft_out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-                    ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14);
+        ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14);
     tmp32no1 = WEBRTC_SPL_SHIFT_W32((int32_t)ifft_out[i],
-                                     outCFFT - aecm->dfaCleanQDomain);
+                                    outCFFT - aecm->dfaCleanQDomain);
     output[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
                                         tmp32no1 + aecm->outBuf[i],
                                         WEBRTC_SPL_WORD16_MIN);
 
-    tmp32no1 = (ifft_out[PART_LEN + i] *
-        WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14;
-    tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
-                                    outCFFT - aecm->dfaCleanQDomain);
-    aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
-                                                tmp32no1,
-                                                WEBRTC_SPL_WORD16_MIN);
+    tmp32no1 =
+        (ifft_out[PART_LEN + i] * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14;
+    tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain);
+    aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1,
+                                              WEBRTC_SPL_WORD16_MIN);
   }
 
   // Copy the current block to the old position
   // (aecm->outBuf is shifted elsewhere)
   memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
-  memcpy(aecm->dBufNoisy,
-         aecm->dBufNoisy + PART_LEN,
+  memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN,
          sizeof(int16_t) * PART_LEN);
-  if (nearendClean != NULL)
-  {
-    memcpy(aecm->dBufClean,
-           aecm->dBufClean + PART_LEN,
+  if (nearendClean != NULL) {
+    memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN,
            sizeof(int16_t) * PART_LEN);
   }
 }
@@ -171,7 +163,7 @@
 
   // In fft_buf, +16 for 32-byte alignment.
   int16_t fft_buf[PART_LEN4 + 16];
-  int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31);
+  int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
 
   int16_t tmp16no1;
 #ifndef WEBRTC_ARCH_ARM_V7
@@ -196,54 +188,43 @@
   freq_signal[0].imag = 0;
   freq_signal[PART_LEN].imag = 0;
   freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
-  freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(
-                                freq_signal[PART_LEN].real);
-  (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) +
-                           (uint32_t)(freq_signal_abs[PART_LEN]);
+  freq_signal_abs[PART_LEN] =
+      (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real);
+  (*freq_signal_sum_abs) =
+      (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]);
 
-  for (i = 1; i < PART_LEN; i++)
-  {
-    if (freq_signal[i].real == 0)
-    {
+  for (i = 1; i < PART_LEN; i++) {
+    if (freq_signal[i].real == 0) {
       freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
-    }
-    else if (freq_signal[i].imag == 0)
-    {
+    } else if (freq_signal[i].imag == 0) {
       freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real);
-    }
-    else
-    {
-      // Approximation for magnitude of complex fft output
-      // magn = sqrt(real^2 + imag^2)
-      // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
-      //
-      // The parameters alpha and beta are stored in Q15
+    } else {
+// Approximation for magnitude of complex fft output
+// magn = sqrt(real^2 + imag^2)
+// magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
+//
+// The parameters alpha and beta are stored in Q15
 
 #ifdef AECM_WITH_ABS_APPROX
       tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
       tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
 
-      if(tmp16no1 > tmp16no2)
-      {
+      if (tmp16no1 > tmp16no2) {
         max_value = tmp16no1;
         min_value = tmp16no2;
-      } else
-      {
+      } else {
         max_value = tmp16no2;
         min_value = tmp16no1;
       }
 
       // Magnitude in Q(-6)
-      if ((max_value >> 2) > min_value)
-      {
+      if ((max_value >> 2) > min_value) {
         alpha = kAlpha1;
         beta = kBeta1;
-      } else if ((max_value >> 1) > min_value)
-      {
+      } else if ((max_value >> 1) > min_value) {
         alpha = kAlpha2;
         beta = kBeta2;
-      } else
-      {
+      } else {
         alpha = kAlpha3;
         beta = kBeta3;
       }
@@ -253,24 +234,21 @@
 #else
 #ifdef WEBRTC_ARCH_ARM_V7
       __asm __volatile(
-        "smulbb %[tmp32no1], %[real], %[real]\n\t"
-        "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t"
-        :[tmp32no1]"+&r"(tmp32no1),
-         [tmp32no2]"=r"(tmp32no2)
-        :[real]"r"(freq_signal[i].real),
-         [imag]"r"(freq_signal[i].imag)
-      );
+          "smulbb %[tmp32no1], %[real], %[real]\n\t"
+          "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t"
+          : [tmp32no1] "+&r"(tmp32no1), [tmp32no2] "=r"(tmp32no2)
+          : [real] "r"(freq_signal[i].real), [imag] "r"(freq_signal[i].imag));
 #else
       tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
       tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
       tmp32no1 = tmp16no1 * tmp16no1;
       tmp32no2 = tmp16no2 * tmp16no2;
       tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2);
-#endif // WEBRTC_ARCH_ARM_V7
+#endif  // WEBRTC_ARCH_ARM_V7
       tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
 
       freq_signal_abs[i] = (uint16_t)tmp32no1;
-#endif // AECM_WITH_ABS_APPROX
+#endif  // AECM_WITH_ABS_APPROX
     }
     (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
   }
@@ -279,11 +257,11 @@
 }
 
 int RTC_NO_SANITIZE("signed-integer-overflow")  // bugs.webrtc.org/8200
-WebRtcAecm_ProcessBlock(AecmCore* aecm,
-                        const int16_t* farend,
-                        const int16_t* nearendNoisy,
-                        const int16_t* nearendClean,
-                        int16_t* output) {
+    WebRtcAecm_ProcessBlock(AecmCore* aecm,
+                            const int16_t* farend,
+                            const int16_t* nearendNoisy,
+                            const int16_t* nearendClean,
+                            int16_t* output) {
   int i;
 
   uint32_t xfaSum;
@@ -302,13 +280,13 @@
 
   // 32 byte aligned buffers (with +8 or +16).
   // TODO(kma): define fft with ComplexInt16.
-  int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
+  int16_t fft_buf[PART_LEN4 + 2 + 16];  // +2 to make a loop safe.
   int32_t echoEst32_buf[PART_LEN1 + 8];
   int32_t dfw_buf[PART_LEN2 + 8];
   int32_t efw_buf[PART_LEN2 + 8];
 
-  int16_t* fft = (int16_t*) (((uintptr_t) fft_buf + 31) & ~ 31);
-  int32_t* echoEst32 = (int32_t*) (((uintptr_t) echoEst32_buf + 31) & ~ 31);
+  int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
+  int32_t* echoEst32 = (int32_t*)(((uintptr_t)echoEst32_buf + 31) & ~31);
   ComplexInt16* dfw = (ComplexInt16*)(((uintptr_t)dfw_buf + 31) & ~31);
   ComplexInt16* efw = (ComplexInt16*)(((uintptr_t)efw_buf + 31) & ~31);
 
@@ -334,53 +312,37 @@
   // (1) another CONV_LEN blocks
   // (2) the rest
 
-  if (aecm->startupState < 2)
-  {
-    aecm->startupState = (aecm->totCount >= CONV_LEN) +
-                         (aecm->totCount >= CONV_LEN2);
+  if (aecm->startupState < 2) {
+    aecm->startupState =
+        (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
   }
   // END: Determine startup state
 
   // Buffer near and far end signals
   memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
   memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN);
-  if (nearendClean != NULL)
-  {
-    memcpy(aecm->dBufClean + PART_LEN,
-           nearendClean,
+  if (nearendClean != NULL) {
+    memcpy(aecm->dBufClean + PART_LEN, nearendClean,
            sizeof(int16_t) * PART_LEN);
   }
 
   // Transform far end signal from time domain to frequency domain.
-  far_q = TimeToFrequencyDomain(aecm,
-                                aecm->xBuf,
-                                dfw,
-                                xfa,
-                                &xfaSum);
+  far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum);
 
   // Transform noisy near end signal from time domain to frequency domain.
-  zerosDBufNoisy = TimeToFrequencyDomain(aecm,
-                                         aecm->dBufNoisy,
-                                         dfw,
-                                         dfaNoisy,
-                                         &dfaNoisySum);
+  zerosDBufNoisy =
+      TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum);
   aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
   aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
 
-
-  if (nearendClean == NULL)
-  {
+  if (nearendClean == NULL) {
     ptrDfaClean = dfaNoisy;
     aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
     aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
     dfaCleanSum = dfaNoisySum;
-  } else
-  {
+  } else {
     // Transform clean near end signal from time domain to frequency domain.
-    zerosDBufClean = TimeToFrequencyDomain(aecm,
-                                           aecm->dBufClean,
-                                           dfw,
-                                           dfaClean,
+    zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean,
                                            &dfaCleanSum);
     aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
     aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
@@ -389,46 +351,34 @@
   // Get the delay
   // Save far-end history and estimate delay
   WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q);
-  if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend,
-                               xfa,
-                               PART_LEN1,
+  if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1,
                                far_q) == -1) {
     return -1;
   }
-  delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
-                                          dfaNoisy,
-                                          PART_LEN1,
-                                          zerosDBufNoisy);
-  if (delay == -1)
-  {
+  delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy,
+                                          PART_LEN1, zerosDBufNoisy);
+  if (delay == -1) {
     return -1;
-  }
-  else if (delay == -2)
-  {
+  } else if (delay == -2) {
     // If the delay is unknown, we assume zero.
     // NOTE: this will have to be adjusted if we ever add lookahead.
     delay = 0;
   }
 
-  if (aecm->fixedDelay >= 0)
-  {
+  if (aecm->fixedDelay >= 0) {
     // Use fixed delay
     delay = aecm->fixedDelay;
   }
 
   // Get aligned far end spectrum
   far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
-  zerosXBuf = (int16_t) far_q;
-  if (far_spectrum_ptr == NULL)
-  {
+  zerosXBuf = (int16_t)far_q;
+  if (far_spectrum_ptr == NULL) {
     return -1;
   }
 
   // Calculate log(energy) and update energy threshold levels
-  WebRtcAecm_CalcEnergies(aecm,
-                          far_spectrum_ptr,
-                          zerosXBuf,
-                          dfaNoisySum,
+  WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum,
                           echoEst32);
 
   // Calculate stepsize
@@ -440,18 +390,12 @@
   // This is the channel estimation algorithm.
   // It is base on NLMS but has a variable step length,
   // which was calculated above.
-  WebRtcAecm_UpdateChannel(aecm,
-                           far_spectrum_ptr,
-                           zerosXBuf,
-                           dfaNoisy,
-                           mu,
+  WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu,
                            echoEst32);
   supGain = WebRtcAecm_CalcSuppressionGain(aecm);
 
-
   // Calculate Wiener filter hnl[]
-  for (i = 0; i < PART_LEN1; i++)
-  {
+  for (i = 0; i < PART_LEN1; i++) {
     // Far end signal through channel estimate in Q8
     // How much can we shift right to preserve resolution
     tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
@@ -460,28 +404,24 @@
 
     zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
     zeros16 = WebRtcSpl_NormW16(supGain) + 1;
-    if (zeros32 + zeros16 > 16)
-    {
+    if (zeros32 + zeros16 > 16) {
       // Multiplication is safe
       // Result in
       // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+
       //   aecm->xfaQDomainBuf[diff])
-      echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
-                                              (uint16_t)supGain);
+      echoEst32Gained =
+          WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], (uint16_t)supGain);
       resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
       resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
-    } else
-    {
+    } else {
       tmp16no1 = 17 - zeros32 - zeros16;
-      resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 -
-                       RESOLUTION_SUPGAIN;
+      resolutionDiff =
+          14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
       resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
-      if (zeros32 > tmp16no1)
-      {
+      if (zeros32 > tmp16no1) {
         echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
                                                 supGain >> tmp16no1);
-      } else
-      {
+      } else {
         // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
         echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
       }
@@ -513,125 +453,100 @@
     }
 
     // Wiener filter coefficients, resulting hnl in Q14
-    if (echoEst32Gained == 0)
-    {
+    if (echoEst32Gained == 0) {
       hnl[i] = ONE_Q14;
-    } else if (aecm->nearFilt[i] == 0)
-    {
+    } else if (aecm->nearFilt[i] == 0) {
       hnl[i] = 0;
-    } else
-    {
+    } else {
       // Multiply the suppression gain
       // Rounding
       echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
-      tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained,
-                                   (uint16_t)aecm->nearFilt[i]);
+      tmpU32 =
+          WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]);
 
       // Current resolution is
       // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN- max(0,17-zeros16- zeros32))
       // Make sure we are in Q14
       tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
-      if (tmp32no1 > ONE_Q14)
-      {
+      if (tmp32no1 > ONE_Q14) {
         hnl[i] = 0;
-      } else if (tmp32no1 < 0)
-      {
+      } else if (tmp32no1 < 0) {
         hnl[i] = ONE_Q14;
-      } else
-      {
+      } else {
         // 1-echoEst/dfa
         hnl[i] = ONE_Q14 - (int16_t)tmp32no1;
-        if (hnl[i] < 0)
-        {
+        if (hnl[i] < 0) {
           hnl[i] = 0;
         }
       }
     }
-    if (hnl[i])
-    {
+    if (hnl[i]) {
       numPosCoef++;
     }
   }
   // Only in wideband. Prevent the gain in upper band from being larger than
   // in lower band.
-  if (aecm->mult == 2)
-  {
+  if (aecm->mult == 2) {
     // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
     //               speech distortion in double-talk.
-    for (i = 0; i < PART_LEN1; i++)
-    {
+    for (i = 0; i < PART_LEN1; i++) {
       hnl[i] = (int16_t)((hnl[i] * hnl[i]) >> 14);
     }
 
-    for (i = kMinPrefBand; i <= kMaxPrefBand; i++)
-    {
+    for (i = kMinPrefBand; i <= kMaxPrefBand; i++) {
       avgHnl32 += (int32_t)hnl[i];
     }
     RTC_DCHECK_GT(kMaxPrefBand - kMinPrefBand + 1, 0);
     avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
 
-    for (i = kMaxPrefBand; i < PART_LEN1; i++)
-    {
-      if (hnl[i] > (int16_t)avgHnl32)
-      {
+    for (i = kMaxPrefBand; i < PART_LEN1; i++) {
+      if (hnl[i] > (int16_t)avgHnl32) {
         hnl[i] = (int16_t)avgHnl32;
       }
     }
   }
 
   // Calculate NLP gain, result is in Q14
-  if (aecm->nlpFlag)
-  {
-    for (i = 0; i < PART_LEN1; i++)
-    {
+  if (aecm->nlpFlag) {
+    for (i = 0; i < PART_LEN1; i++) {
       // Truncate values close to zero and one.
-      if (hnl[i] > NLP_COMP_HIGH)
-      {
+      if (hnl[i] > NLP_COMP_HIGH) {
         hnl[i] = ONE_Q14;
-      } else if (hnl[i] < NLP_COMP_LOW)
-      {
+      } else if (hnl[i] < NLP_COMP_LOW) {
         hnl[i] = 0;
       }
 
       // Remove outliers
-      if (numPosCoef < 3)
-      {
+      if (numPosCoef < 3) {
         nlpGain = 0;
-      } else
-      {
+      } else {
         nlpGain = ONE_Q14;
       }
 
       // NLP
-      if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
-      {
+      if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14)) {
         hnl[i] = ONE_Q14;
-      } else
-      {
+      } else {
         hnl[i] = (int16_t)((hnl[i] * nlpGain) >> 14);
       }
 
       // multiply with Wiener coefficients
-      efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
-                                                                   hnl[i], 14));
-      efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
-                                                                   hnl[i], 14));
+      efw[i].real = (int16_t)(
+          WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14));
+      efw[i].imag = (int16_t)(
+          WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14));
     }
-  }
-  else
-  {
+  } else {
     // multiply with Wiener coefficients
-    for (i = 0; i < PART_LEN1; i++)
-    {
-      efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
-                                                                   hnl[i], 14));
-      efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
-                                                                   hnl[i], 14));
+    for (i = 0; i < PART_LEN1; i++) {
+      efw[i].real = (int16_t)(
+          WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14));
+      efw[i].imag = (int16_t)(
+          WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14));
     }
   }
 
-  if (aecm->cngMode == AecmTrue)
-  {
+  if (aecm->cngMode == AecmTrue) {
     ComfortNoise(aecm, ptrDfaClean, efw, hnl);
   }
 
@@ -660,83 +575,66 @@
   RTC_DCHECK_GE(shiftFromNearToNoise, 0);
   RTC_DCHECK_LT(shiftFromNearToNoise, 16);
 
-  if (aecm->noiseEstCtr < 100)
-  {
+  if (aecm->noiseEstCtr < 100) {
     // Track the minimum more quickly initially.
     aecm->noiseEstCtr++;
     minTrackShift = 6;
-  } else
-  {
+  } else {
     minTrackShift = 9;
   }
 
   // Estimate noise power.
-  for (i = 0; i < PART_LEN1; i++)
-  {
+  for (i = 0; i < PART_LEN1; i++) {
     // Shift to the noise domain.
     tmp32 = (int32_t)dfa[i];
     outLShift32 = tmp32 << shiftFromNearToNoise;
 
-    if (outLShift32 < aecm->noiseEst[i])
-    {
+    if (outLShift32 < aecm->noiseEst[i]) {
       // Reset "too low" counter
       aecm->noiseEstTooLowCtr[i] = 0;
       // Track the minimum.
-      if (aecm->noiseEst[i] < (1 << minTrackShift))
-      {
+      if (aecm->noiseEst[i] < (1 << minTrackShift)) {
         // For small values, decrease noiseEst[i] every
         // |kNoiseEstIncCount| block. The regular approach below can not
         // go further down due to truncation.
         aecm->noiseEstTooHighCtr[i]++;
-        if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
-        {
+        if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) {
           aecm->noiseEst[i]--;
-          aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
+          aecm->noiseEstTooHighCtr[i] = 0;  // Reset the counter
         }
+      } else {
+        aecm->noiseEst[i] -=
+            ((aecm->noiseEst[i] - outLShift32) >> minTrackShift);
       }
-      else
-      {
-        aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32)
-                              >> minTrackShift);
-      }
-    } else
-    {
+    } else {
       // Reset "too high" counter
       aecm->noiseEstTooHighCtr[i] = 0;
       // Ramp slowly upwards until we hit the minimum again.
-      if ((aecm->noiseEst[i] >> 19) > 0)
-      {
+      if ((aecm->noiseEst[i] >> 19) > 0) {
         // Avoid overflow.
         // Multiplication with 2049 will cause wrap around. Scale
         // down first and then multiply
         aecm->noiseEst[i] >>= 11;
         aecm->noiseEst[i] *= 2049;
-      }
-      else if ((aecm->noiseEst[i] >> 11) > 0)
-      {
+      } else if ((aecm->noiseEst[i] >> 11) > 0) {
         // Large enough for relative increase
         aecm->noiseEst[i] *= 2049;
         aecm->noiseEst[i] >>= 11;
-      }
-      else
-      {
+      } else {
         // Make incremental increases based on size every
         // |kNoiseEstIncCount| block
         aecm->noiseEstTooLowCtr[i]++;
-        if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
-        {
+        if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) {
           aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
-          aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
+          aecm->noiseEstTooLowCtr[i] = 0;  // Reset counter
         }
       }
     }
   }
 
-  for (i = 0; i < PART_LEN1; i++)
-  {
+  for (i = 0; i < PART_LEN1; i++) {
     tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise;
-    if (tmp32 > 32767)
-    {
+    if (tmp32 > 32767) {
       tmp32 = 32767;
       aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
     }
@@ -750,23 +648,21 @@
   WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
 
   // Generate noise according to estimated energy.
-  uReal[0] = 0; // Reject LF noise.
+  uReal[0] = 0;  // Reject LF noise.
   uImag[0] = 0;
-  for (i = 1; i < PART_LEN1; i++)
-  {
+  for (i = 1; i < PART_LEN1; i++) {
     // Get a random index for the cos and sin tables over [0 359].
     tmp16 = (int16_t)((359 * randW16[i - 1]) >> 15);
 
     // Tables are in Q13.
-    uReal[i] = (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >>
-        13);
-    uImag[i] = (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >>
-        13);
+    uReal[i] =
+        (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >> 13);
+    uImag[i] =
+        (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >> 13);
   }
   uImag[PART_LEN] = 0;
 
-  for (i = 0; i < PART_LEN1; i++)
-  {
+  for (i = 0; i < PART_LEN1; i++) {
     out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]);
     out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]);
   }
diff --git a/modules/audio_processing/aecm/aecm_core_mips.cc b/modules/audio_processing/aecm/aecm_core_mips.cc
index 58e5ec5..11e4095 100644
--- a/modules/audio_processing/aecm/aecm_core_mips.cc
+++ b/modules/audio_processing/aecm/aecm_core_mips.cc
@@ -16,56 +16,37 @@
 #include "rtc_base/numerics/safe_conversions.h"
 
 static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
-  0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
-  3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
-  6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
-  9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
-  11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
-  13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
-  15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
-  16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
-};
+    0,     399,   798,   1196,  1594,  1990,  2386,  2780,  3172,  3562,  3951,
+    4337,  4720,  5101,  5478,  5853,  6224,  6591,  6954,  7313,  7668,  8019,
+    8364,  8705,  9040,  9370,  9695,  10013, 10326, 10633, 10933, 11227, 11514,
+    11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189,
+    14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851,
+    15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384};
 
 static const int16_t kNoiseEstQDomain = 15;
 static const int16_t kNoiseEstIncCount = 5;
 
 static int16_t coefTable[] = {
-   0,   4, 256, 260, 128, 132, 384, 388,
-  64,  68, 320, 324, 192, 196, 448, 452,
-  32,  36, 288, 292, 160, 164, 416, 420,
-  96, 100, 352, 356, 224, 228, 480, 484,
-  16,  20, 272, 276, 144, 148, 400, 404,
-  80,  84, 336, 340, 208, 212, 464, 468,
-  48,  52, 304, 308, 176, 180, 432, 436,
- 112, 116, 368, 372, 240, 244, 496, 500,
-   8,  12, 264, 268, 136, 140, 392, 396,
-  72,  76, 328, 332, 200, 204, 456, 460,
-  40,  44, 296, 300, 168, 172, 424, 428,
- 104, 108, 360, 364, 232, 236, 488, 492,
-  24,  28, 280, 284, 152, 156, 408, 412,
-  88,  92, 344, 348, 216, 220, 472, 476,
-  56,  60, 312, 316, 184, 188, 440, 444,
- 120, 124, 376, 380, 248, 252, 504, 508
-};
+    0,   4,   256, 260, 128, 132, 384, 388, 64,  68,  320, 324, 192, 196, 448,
+    452, 32,  36,  288, 292, 160, 164, 416, 420, 96,  100, 352, 356, 224, 228,
+    480, 484, 16,  20,  272, 276, 144, 148, 400, 404, 80,  84,  336, 340, 208,
+    212, 464, 468, 48,  52,  304, 308, 176, 180, 432, 436, 112, 116, 368, 372,
+    240, 244, 496, 500, 8,   12,  264, 268, 136, 140, 392, 396, 72,  76,  328,
+    332, 200, 204, 456, 460, 40,  44,  296, 300, 168, 172, 424, 428, 104, 108,
+    360, 364, 232, 236, 488, 492, 24,  28,  280, 284, 152, 156, 408, 412, 88,
+    92,  344, 348, 216, 220, 472, 476, 56,  60,  312, 316, 184, 188, 440, 444,
+    120, 124, 376, 380, 248, 252, 504, 508};
 
 static int16_t coefTable_ifft[] = {
-    0, 512, 256, 508, 128, 252, 384, 380,
-   64, 124, 320, 444, 192, 188, 448, 316,
-   32,  60, 288, 476, 160, 220, 416, 348,
-   96,  92, 352, 412, 224, 156, 480, 284,
-   16,  28, 272, 492, 144, 236, 400, 364,
-   80, 108, 336, 428, 208, 172, 464, 300,
-   48,  44, 304, 460, 176, 204, 432, 332,
-  112,  76, 368, 396, 240, 140, 496, 268,
-    8,  12, 264, 500, 136, 244, 392, 372,
-   72, 116, 328, 436, 200, 180, 456, 308,
-   40,  52, 296, 468, 168, 212, 424, 340,
-  104,  84, 360, 404, 232, 148, 488, 276,
-   24,  20, 280, 484, 152, 228, 408, 356,
-   88, 100, 344, 420, 216, 164, 472, 292,
-   56,  36, 312, 452, 184, 196, 440, 324,
-  120,  68, 376, 388, 248, 132, 504, 260
-};
+    0,   512, 256, 508, 128, 252, 384, 380, 64,  124, 320, 444, 192, 188, 448,
+    316, 32,  60,  288, 476, 160, 220, 416, 348, 96,  92,  352, 412, 224, 156,
+    480, 284, 16,  28,  272, 492, 144, 236, 400, 364, 80,  108, 336, 428, 208,
+    172, 464, 300, 48,  44,  304, 460, 176, 204, 432, 332, 112, 76,  368, 396,
+    240, 140, 496, 268, 8,   12,  264, 500, 136, 244, 392, 372, 72,  116, 328,
+    436, 200, 180, 456, 308, 40,  52,  296, 468, 168, 212, 424, 340, 104, 84,
+    360, 404, 232, 148, 488, 276, 24,  20,  280, 484, 152, 228, 408, 356, 88,
+    100, 344, 420, 216, 164, 472, 292, 56,  36,  312, 452, 184, 196, 440, 324,
+    120, 68,  376, 388, 248, 132, 504, 260};
 
 static void ComfortNoise(AecmCore* aecm,
                          const uint16_t* dfa,
@@ -81,122 +62,152 @@
   int32_t tmp1, tmp2, tmp3, tmp4;
   int16_t* pfrfi;
   ComplexInt16* pfreq_signal;
-  int16_t  f_coef, s_coef;
+  int16_t f_coef, s_coef;
   int32_t load_ptr, store_ptr1, store_ptr2, shift, shift1;
   int32_t hann, hann1, coefs;
 
   memset(fft, 0, sizeof(int16_t) * PART_LEN4);
 
   // FFT of signal
-  __asm __volatile (
-    ".set        push                                                    \n\t"
-    ".set        noreorder                                               \n\t"
-    "addiu       %[shift],          %[time_signal_scaling], -14          \n\t"
-    "addiu       %[i],              $zero,                  64           \n\t"
-    "addiu       %[load_ptr],       %[time_signal],         0            \n\t"
-    "addiu       %[hann],           %[hanning],             0            \n\t"
-    "addiu       %[hann1],          %[hanning],             128          \n\t"
-    "addiu       %[coefs],          %[coefTable],           0            \n\t"
-    "bltz        %[shift],          2f                                   \n\t"
-    " negu       %[shift1],         %[shift]                             \n\t"
-   "1:                                                                   \n\t"
-    "lh          %[tmp1],           0(%[load_ptr])                       \n\t"
-    "lh          %[tmp2],           0(%[hann])                           \n\t"
-    "lh          %[tmp3],           128(%[load_ptr])                     \n\t"
-    "lh          %[tmp4],           0(%[hann1])                          \n\t"
-    "addiu       %[i],              %[i],                   -1           \n\t"
-    "mul         %[tmp1],           %[tmp1],                %[tmp2]      \n\t"
-    "mul         %[tmp3],           %[tmp3],                %[tmp4]      \n\t"
-    "lh          %[f_coef],         0(%[coefs])                          \n\t"
-    "lh          %[s_coef],         2(%[coefs])                          \n\t"
-    "addiu       %[load_ptr],       %[load_ptr],            2            \n\t"
-    "addiu       %[hann],           %[hann],                2            \n\t"
-    "addiu       %[hann1],          %[hann1],               -2           \n\t"
-    "addu        %[store_ptr1],     %[fft],                 %[f_coef]    \n\t"
-    "addu        %[store_ptr2],     %[fft],                 %[s_coef]    \n\t"
-    "sllv        %[tmp1],           %[tmp1],                %[shift]     \n\t"
-    "sllv        %[tmp3],           %[tmp3],                %[shift]     \n\t"
-    "sh          %[tmp1],           0(%[store_ptr1])                     \n\t"
-    "sh          %[tmp3],           0(%[store_ptr2])                     \n\t"
-    "bgtz        %[i],              1b                                   \n\t"
-    " addiu      %[coefs],          %[coefs],               4            \n\t"
-    "b           3f                                                      \n\t"
-    " nop                                                                \n\t"
-   "2:                                                                   \n\t"
-    "lh          %[tmp1],           0(%[load_ptr])                       \n\t"
-    "lh          %[tmp2],           0(%[hann])                           \n\t"
-    "lh          %[tmp3],           128(%[load_ptr])                     \n\t"
-    "lh          %[tmp4],           0(%[hann1])                          \n\t"
-    "addiu       %[i],              %[i],                   -1           \n\t"
-    "mul         %[tmp1],           %[tmp1],                %[tmp2]      \n\t"
-    "mul         %[tmp3],           %[tmp3],                %[tmp4]      \n\t"
-    "lh          %[f_coef],         0(%[coefs])                          \n\t"
-    "lh          %[s_coef],         2(%[coefs])                          \n\t"
-    "addiu       %[load_ptr],       %[load_ptr],            2            \n\t"
-    "addiu       %[hann],           %[hann],                2            \n\t"
-    "addiu       %[hann1],          %[hann1],               -2           \n\t"
-    "addu        %[store_ptr1],     %[fft],                 %[f_coef]    \n\t"
-    "addu        %[store_ptr2],     %[fft],                 %[s_coef]    \n\t"
-    "srav        %[tmp1],           %[tmp1],                %[shift1]    \n\t"
-    "srav        %[tmp3],           %[tmp3],                %[shift1]    \n\t"
-    "sh          %[tmp1],           0(%[store_ptr1])                     \n\t"
-    "sh          %[tmp3],           0(%[store_ptr2])                     \n\t"
-    "bgtz        %[i],              2b                                   \n\t"
-    " addiu      %[coefs],          %[coefs],               4            \n\t"
-   "3:                                                                   \n\t"
-    ".set        pop                                                     \n\t"
-    : [load_ptr] "=&r" (load_ptr), [shift] "=&r" (shift), [hann] "=&r" (hann),
-      [hann1] "=&r" (hann1), [shift1] "=&r" (shift1), [coefs] "=&r" (coefs),
-      [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
-      [tmp4] "=&r" (tmp4), [i] "=&r" (i), [f_coef] "=&r" (f_coef),
-      [s_coef] "=&r" (s_coef), [store_ptr1] "=&r" (store_ptr1),
-      [store_ptr2] "=&r" (store_ptr2)
-    : [time_signal] "r" (time_signal), [coefTable] "r" (coefTable),
-      [time_signal_scaling] "r" (time_signal_scaling),
-      [hanning] "r" (WebRtcAecm_kSqrtHanning), [fft] "r" (fft)
-    : "memory", "hi", "lo"
-  );
+  __asm __volatile(
+      ".set        push                                                    \n\t"
+      ".set        noreorder                                               \n\t"
+      "addiu       %[shift],          %[time_signal_scaling], -14          \n\t"
+      "addiu       %[i],              $zero,                  64           \n\t"
+      "addiu       %[load_ptr],       %[time_signal],         0            \n\t"
+      "addiu       %[hann],           %[hanning],             0            \n\t"
+      "addiu       %[hann1],          %[hanning],             128          \n\t"
+      "addiu       %[coefs],          %[coefTable],           0            \n\t"
+      "bltz        %[shift],          2f                                   \n\t"
+      " negu       %[shift1],         %[shift]                             \n\t"
+      "1:                                                                   "
+      "\n\t"
+      "lh          %[tmp1],           0(%[load_ptr])                       \n\t"
+      "lh          %[tmp2],           0(%[hann])                           \n\t"
+      "lh          %[tmp3],           128(%[load_ptr])                     \n\t"
+      "lh          %[tmp4],           0(%[hann1])                          \n\t"
+      "addiu       %[i],              %[i],                   -1           \n\t"
+      "mul         %[tmp1],           %[tmp1],                %[tmp2]      \n\t"
+      "mul         %[tmp3],           %[tmp3],                %[tmp4]      \n\t"
+      "lh          %[f_coef],         0(%[coefs])                          \n\t"
+      "lh          %[s_coef],         2(%[coefs])                          \n\t"
+      "addiu       %[load_ptr],       %[load_ptr],            2            \n\t"
+      "addiu       %[hann],           %[hann],                2            \n\t"
+      "addiu       %[hann1],          %[hann1],               -2           \n\t"
+      "addu        %[store_ptr1],     %[fft],                 %[f_coef]    \n\t"
+      "addu        %[store_ptr2],     %[fft],                 %[s_coef]    \n\t"
+      "sllv        %[tmp1],           %[tmp1],                %[shift]     \n\t"
+      "sllv        %[tmp3],           %[tmp3],                %[shift]     \n\t"
+      "sh          %[tmp1],           0(%[store_ptr1])                     \n\t"
+      "sh          %[tmp3],           0(%[store_ptr2])                     \n\t"
+      "bgtz        %[i],              1b                                   \n\t"
+      " addiu      %[coefs],          %[coefs],               4            \n\t"
+      "b           3f                                                      \n\t"
+      " nop                                                                \n\t"
+      "2:                                                                   "
+      "\n\t"
+      "lh          %[tmp1],           0(%[load_ptr])                       \n\t"
+      "lh          %[tmp2],           0(%[hann])                           \n\t"
+      "lh          %[tmp3],           128(%[load_ptr])                     \n\t"
+      "lh          %[tmp4],           0(%[hann1])                          \n\t"
+      "addiu       %[i],              %[i],                   -1           \n\t"
+      "mul         %[tmp1],           %[tmp1],                %[tmp2]      \n\t"
+      "mul         %[tmp3],           %[tmp3],                %[tmp4]      \n\t"
+      "lh          %[f_coef],         0(%[coefs])                          \n\t"
+      "lh          %[s_coef],         2(%[coefs])                          \n\t"
+      "addiu       %[load_ptr],       %[load_ptr],            2            \n\t"
+      "addiu       %[hann],           %[hann],                2            \n\t"
+      "addiu       %[hann1],          %[hann1],               -2           \n\t"
+      "addu        %[store_ptr1],     %[fft],                 %[f_coef]    \n\t"
+      "addu        %[store_ptr2],     %[fft],                 %[s_coef]    \n\t"
+      "srav        %[tmp1],           %[tmp1],                %[shift1]    \n\t"
+      "srav        %[tmp3],           %[tmp3],                %[shift1]    \n\t"
+      "sh          %[tmp1],           0(%[store_ptr1])                     \n\t"
+      "sh          %[tmp3],           0(%[store_ptr2])                     \n\t"
+      "bgtz        %[i],              2b                                   \n\t"
+      " addiu      %[coefs],          %[coefs],               4            \n\t"
+      "3:                                                                   "
+      "\n\t"
+      ".set        pop                                                     \n\t"
+      : [load_ptr] "=&r"(load_ptr), [shift] "=&r"(shift), [hann] "=&r"(hann),
+        [hann1] "=&r"(hann1), [shift1] "=&r"(shift1), [coefs] "=&r"(coefs),
+        [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3),
+        [tmp4] "=&r"(tmp4), [i] "=&r"(i), [f_coef] "=&r"(f_coef),
+        [s_coef] "=&r"(s_coef), [store_ptr1] "=&r"(store_ptr1),
+        [store_ptr2] "=&r"(store_ptr2)
+      : [time_signal] "r"(time_signal), [coefTable] "r"(coefTable),
+        [time_signal_scaling] "r"(time_signal_scaling),
+        [hanning] "r"(WebRtcAecm_kSqrtHanning), [fft] "r"(fft)
+      : "memory", "hi", "lo");
 
   WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
   pfrfi = fft;
   pfreq_signal = freq_signal;
 
-  __asm __volatile (
-    ".set        push                                                     \n\t"
-    ".set        noreorder                                                \n\t"
-    "addiu       %[j],              $zero,                 128            \n\t"
-   "1:                                                                    \n\t"
-    "lh          %[tmp1],           0(%[pfrfi])                           \n\t"
-    "lh          %[tmp2],           2(%[pfrfi])                           \n\t"
-    "lh          %[tmp3],           4(%[pfrfi])                           \n\t"
-    "lh          %[tmp4],           6(%[pfrfi])                           \n\t"
-    "subu        %[tmp2],           $zero,                 %[tmp2]        \n\t"
-    "sh          %[tmp1],           0(%[pfreq_signal])                    \n\t"
-    "sh          %[tmp2],           2(%[pfreq_signal])                    \n\t"
-    "subu        %[tmp4],           $zero,                 %[tmp4]        \n\t"
-    "sh          %[tmp3],           4(%[pfreq_signal])                    \n\t"
-    "sh          %[tmp4],           6(%[pfreq_signal])                    \n\t"
-    "lh          %[tmp1],           8(%[pfrfi])                           \n\t"
-    "lh          %[tmp2],           10(%[pfrfi])                          \n\t"
-    "lh          %[tmp3],           12(%[pfrfi])                          \n\t"
-    "lh          %[tmp4],           14(%[pfrfi])                          \n\t"
-    "addiu       %[j],              %[j],                  -8             \n\t"
-    "subu        %[tmp2],           $zero,                 %[tmp2]        \n\t"
-    "sh          %[tmp1],           8(%[pfreq_signal])                    \n\t"
-    "sh          %[tmp2],           10(%[pfreq_signal])                   \n\t"
-    "subu        %[tmp4],           $zero,                 %[tmp4]        \n\t"
-    "sh          %[tmp3],           12(%[pfreq_signal])                   \n\t"
-    "sh          %[tmp4],           14(%[pfreq_signal])                   \n\t"
-    "addiu       %[pfreq_signal],   %[pfreq_signal],       16             \n\t"
-    "bgtz        %[j],              1b                                    \n\t"
-    " addiu      %[pfrfi],          %[pfrfi],              16             \n\t"
-    ".set        pop                                                      \n\t"
-    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
-      [j] "=&r" (j), [pfrfi] "+r" (pfrfi), [pfreq_signal] "+r" (pfreq_signal),
-      [tmp4] "=&r" (tmp4)
-    :
-    : "memory"
-  );
+  __asm __volatile(
+      ".set        push                                                     "
+      "\n\t"
+      ".set        noreorder                                                "
+      "\n\t"
+      "addiu       %[j],              $zero,                 128            "
+      "\n\t"
+      "1:                                                                    "
+      "\n\t"
+      "lh          %[tmp1],           0(%[pfrfi])                           "
+      "\n\t"
+      "lh          %[tmp2],           2(%[pfrfi])                           "
+      "\n\t"
+      "lh          %[tmp3],           4(%[pfrfi])                           "
+      "\n\t"
+      "lh          %[tmp4],           6(%[pfrfi])                           "
+      "\n\t"
+      "subu        %[tmp2],           $zero,                 %[tmp2]        "
+      "\n\t"
+      "sh          %[tmp1],           0(%[pfreq_signal])                    "
+      "\n\t"
+      "sh          %[tmp2],           2(%[pfreq_signal])                    "
+      "\n\t"
+      "subu        %[tmp4],           $zero,                 %[tmp4]        "
+      "\n\t"
+      "sh          %[tmp3],           4(%[pfreq_signal])                    "
+      "\n\t"
+      "sh          %[tmp4],           6(%[pfreq_signal])                    "
+      "\n\t"
+      "lh          %[tmp1],           8(%[pfrfi])                           "
+      "\n\t"
+      "lh          %[tmp2],           10(%[pfrfi])                          "
+      "\n\t"
+      "lh          %[tmp3],           12(%[pfrfi])                          "
+      "\n\t"
+      "lh          %[tmp4],           14(%[pfrfi])                          "
+      "\n\t"
+      "addiu       %[j],              %[j],                  -8             "
+      "\n\t"
+      "subu        %[tmp2],           $zero,                 %[tmp2]        "
+      "\n\t"
+      "sh          %[tmp1],           8(%[pfreq_signal])                    "
+      "\n\t"
+      "sh          %[tmp2],           10(%[pfreq_signal])                   "
+      "\n\t"
+      "subu        %[tmp4],           $zero,                 %[tmp4]        "
+      "\n\t"
+      "sh          %[tmp3],           12(%[pfreq_signal])                   "
+      "\n\t"
+      "sh          %[tmp4],           14(%[pfreq_signal])                   "
+      "\n\t"
+      "addiu       %[pfreq_signal],   %[pfreq_signal],       16             "
+      "\n\t"
+      "bgtz        %[j],              1b                                    "
+      "\n\t"
+      " addiu      %[pfrfi],          %[pfrfi],              16             "
+      "\n\t"
+      ".set        pop                                                      "
+      "\n\t"
+      : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3),
+        [j] "=&r"(j), [pfrfi] "+r"(pfrfi), [pfreq_signal] "+r"(pfreq_signal),
+        [tmp4] "=&r"(tmp4)
+      :
+      : "memory");
 }
 
 static void InverseFFTAndWindow(AecmCore* aecm,
@@ -216,67 +227,118 @@
   const int16_t* pp_kSqrtHanning = &WebRtcAecm_kSqrtHanning[PART_LEN];
   int16_t* output1 = output;
 
-  __asm __volatile (
-    ".set      push                                                        \n\t"
-    ".set      noreorder                                                   \n\t"
-    "addiu     %[i],                $zero,                   64            \n\t"
-   "1:                                                                     \n\t"
-    "lh        %[tmp1],             0(%[pcoefTable_ifft])                  \n\t"
-    "lh        %[tmp2],             2(%[pcoefTable_ifft])                  \n\t"
-    "lh        %[tmp_re],           0(%[pefw])                             \n\t"
-    "lh        %[tmp_im],           2(%[pefw])                             \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp2]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp1]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "subu      %[tmp_im],           $zero,                   %[tmp_im]     \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "lh        %[tmp1],             4(%[pcoefTable_ifft])                  \n\t"
-    "lh        %[tmp2],             6(%[pcoefTable_ifft])                  \n\t"
-    "lh        %[tmp_re],           4(%[pefw])                             \n\t"
-    "lh        %[tmp_im],           6(%[pefw])                             \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp2]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp1]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "subu      %[tmp_im],           $zero,                   %[tmp_im]     \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "lh        %[tmp1],             8(%[pcoefTable_ifft])                  \n\t"
-    "lh        %[tmp2],             10(%[pcoefTable_ifft])                 \n\t"
-    "lh        %[tmp_re],           8(%[pefw])                             \n\t"
-    "lh        %[tmp_im],           10(%[pefw])                            \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp2]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp1]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "subu      %[tmp_im],           $zero,                   %[tmp_im]     \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "lh        %[tmp1],             12(%[pcoefTable_ifft])                 \n\t"
-    "lh        %[tmp2],             14(%[pcoefTable_ifft])                 \n\t"
-    "lh        %[tmp_re],           12(%[pefw])                            \n\t"
-    "lh        %[tmp_im],           14(%[pefw])                            \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp2]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "addu      %[pfft],             %[fft],                  %[tmp1]       \n\t"
-    "sh        %[tmp_re],           0(%[pfft])                             \n\t"
-    "subu      %[tmp_im],           $zero,                   %[tmp_im]     \n\t"
-    "sh        %[tmp_im],           2(%[pfft])                             \n\t"
-    "addiu     %[pcoefTable_ifft],  %[pcoefTable_ifft],      16            \n\t"
-    "addiu     %[i],                %[i],                    -4            \n\t"
-    "bgtz      %[i],                1b                                     \n\t"
-    " addiu    %[pefw],             %[pefw],                 16            \n\t"
-    ".set      pop                                                         \n\t"
-    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [pfft] "+r" (pfft),
-      [i] "=&r" (i), [tmp_re] "=&r" (tmp_re), [tmp_im] "=&r" (tmp_im),
-      [pefw] "+r" (pefw), [pcoefTable_ifft] "+r" (pcoefTable_ifft),
-      [fft] "+r" (fft)
-    :
-    : "memory"
-  );
+  __asm __volatile(
+      ".set      push                                                        "
+      "\n\t"
+      ".set      noreorder                                                   "
+      "\n\t"
+      "addiu     %[i],                $zero,                   64            "
+      "\n\t"
+      "1:                                                                     "
+      "\n\t"
+      "lh        %[tmp1],             0(%[pcoefTable_ifft])                  "
+      "\n\t"
+      "lh        %[tmp2],             2(%[pcoefTable_ifft])                  "
+      "\n\t"
+      "lh        %[tmp_re],           0(%[pefw])                             "
+      "\n\t"
+      "lh        %[tmp_im],           2(%[pefw])                             "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp2]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp1]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "subu      %[tmp_im],           $zero,                   %[tmp_im]     "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "lh        %[tmp1],             4(%[pcoefTable_ifft])                  "
+      "\n\t"
+      "lh        %[tmp2],             6(%[pcoefTable_ifft])                  "
+      "\n\t"
+      "lh        %[tmp_re],           4(%[pefw])                             "
+      "\n\t"
+      "lh        %[tmp_im],           6(%[pefw])                             "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp2]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp1]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "subu      %[tmp_im],           $zero,                   %[tmp_im]     "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "lh        %[tmp1],             8(%[pcoefTable_ifft])                  "
+      "\n\t"
+      "lh        %[tmp2],             10(%[pcoefTable_ifft])                 "
+      "\n\t"
+      "lh        %[tmp_re],           8(%[pefw])                             "
+      "\n\t"
+      "lh        %[tmp_im],           10(%[pefw])                            "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp2]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp1]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "subu      %[tmp_im],           $zero,                   %[tmp_im]     "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "lh        %[tmp1],             12(%[pcoefTable_ifft])                 "
+      "\n\t"
+      "lh        %[tmp2],             14(%[pcoefTable_ifft])                 "
+      "\n\t"
+      "lh        %[tmp_re],           12(%[pefw])                            "
+      "\n\t"
+      "lh        %[tmp_im],           14(%[pefw])                            "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp2]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "addu      %[pfft],             %[fft],                  %[tmp1]       "
+      "\n\t"
+      "sh        %[tmp_re],           0(%[pfft])                             "
+      "\n\t"
+      "subu      %[tmp_im],           $zero,                   %[tmp_im]     "
+      "\n\t"
+      "sh        %[tmp_im],           2(%[pfft])                             "
+      "\n\t"
+      "addiu     %[pcoefTable_ifft],  %[pcoefTable_ifft],      16            "
+      "\n\t"
+      "addiu     %[i],                %[i],                    -4            "
+      "\n\t"
+      "bgtz      %[i],                1b                                     "
+      "\n\t"
+      " addiu    %[pefw],             %[pefw],                 16            "
+      "\n\t"
+      ".set      pop                                                         "
+      "\n\t"
+      : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [i] "=&r"(i),
+        [tmp_re] "=&r"(tmp_re), [tmp_im] "=&r"(tmp_im), [pefw] "+r"(pefw),
+        [pcoefTable_ifft] "+r"(pcoefTable_ifft), [fft] "+r"(fft)
+      :
+      : "memory");
 
   fft[2] = efw[PART_LEN].real;
   fft[3] = -efw[PART_LEN].imag;
@@ -284,150 +346,235 @@
   outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
   pfft = fft;
 
-  __asm __volatile (
-    ".set       push                                               \n\t"
-    ".set       noreorder                                          \n\t"
-    "addiu      %[i],            $zero,               128          \n\t"
-   "1:                                                             \n\t"
-    "lh         %[tmp1],         0(%[ppfft])                       \n\t"
-    "lh         %[tmp2],         4(%[ppfft])                       \n\t"
-    "lh         %[tmp3],         8(%[ppfft])                       \n\t"
-    "lh         %[tmp4],         12(%[ppfft])                      \n\t"
-    "addiu      %[i],            %[i],                -4           \n\t"
-    "sh         %[tmp1],         0(%[pfft])                        \n\t"
-    "sh         %[tmp2],         2(%[pfft])                        \n\t"
-    "sh         %[tmp3],         4(%[pfft])                        \n\t"
-    "sh         %[tmp4],         6(%[pfft])                        \n\t"
-    "addiu      %[ppfft],        %[ppfft],            16           \n\t"
-    "bgtz       %[i],            1b                                \n\t"
-    " addiu     %[pfft],         %[pfft],             8            \n\t"
-    ".set       pop                                                \n\t"
-    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [pfft] "+r" (pfft),
-      [i] "=&r" (i), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4),
-      [ppfft] "+r" (ppfft)
-    :
-    : "memory"
-  );
+  __asm __volatile(
+      ".set       push                                               \n\t"
+      ".set       noreorder                                          \n\t"
+      "addiu      %[i],            $zero,               128          \n\t"
+      "1:                                                             \n\t"
+      "lh         %[tmp1],         0(%[ppfft])                       \n\t"
+      "lh         %[tmp2],         4(%[ppfft])                       \n\t"
+      "lh         %[tmp3],         8(%[ppfft])                       \n\t"
+      "lh         %[tmp4],         12(%[ppfft])                      \n\t"
+      "addiu      %[i],            %[i],                -4           \n\t"
+      "sh         %[tmp1],         0(%[pfft])                        \n\t"
+      "sh         %[tmp2],         2(%[pfft])                        \n\t"
+      "sh         %[tmp3],         4(%[pfft])                        \n\t"
+      "sh         %[tmp4],         6(%[pfft])                        \n\t"
+      "addiu      %[ppfft],        %[ppfft],            16           \n\t"
+      "bgtz       %[i],            1b                                \n\t"
+      " addiu     %[pfft],         %[pfft],             8            \n\t"
+      ".set       pop                                                \n\t"
+      : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [i] "=&r"(i),
+        [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4), [ppfft] "+r"(ppfft)
+      :
+      : "memory");
 
   pfft = fft;
   out_aecm = (int32_t)(outCFFT - aecm->dfaCleanQDomain);
 
-  __asm __volatile (
-    ".set       push                                                       \n\t"
-    ".set       noreorder                                                  \n\t"
-    "addiu      %[i],                $zero,                  64            \n\t"
-   "11:                                                                    \n\t"
-    "lh         %[tmp1],             0(%[pfft])                            \n\t"
-    "lh         %[tmp2],             0(%[p_kSqrtHanning])                  \n\t"
-    "addiu      %[i],                %[i],                   -2            \n\t"
-    "mul        %[tmp1],             %[tmp1],                %[tmp2]       \n\t"
-    "lh         %[tmp3],             2(%[pfft])                            \n\t"
-    "lh         %[tmp4],             2(%[p_kSqrtHanning])                  \n\t"
-    "mul        %[tmp3],             %[tmp3],                %[tmp4]       \n\t"
-    "addiu      %[tmp1],             %[tmp1],                8192          \n\t"
-    "sra        %[tmp1],             %[tmp1],                14            \n\t"
-    "addiu      %[tmp3],             %[tmp3],                8192          \n\t"
-    "sra        %[tmp3],             %[tmp3],                14            \n\t"
-    "bgez       %[out_aecm],         1f                                    \n\t"
-    " negu      %[tmp2],             %[out_aecm]                           \n\t"
-    "srav       %[tmp1],             %[tmp1],                %[tmp2]       \n\t"
-    "b          2f                                                         \n\t"
-    " srav      %[tmp3],             %[tmp3],                %[tmp2]       \n\t"
-   "1:                                                                     \n\t"
-    "sllv       %[tmp1],             %[tmp1],                %[out_aecm]   \n\t"
-    "sllv       %[tmp3],             %[tmp3],                %[out_aecm]   \n\t"
-   "2:                                                                     \n\t"
-    "lh         %[tmp4],             0(%[paecm_buf])                       \n\t"
-    "lh         %[tmp2],             2(%[paecm_buf])                       \n\t"
-    "addu       %[tmp3],             %[tmp3],                %[tmp2]       \n\t"
-    "addu       %[tmp1],             %[tmp1],                %[tmp4]       \n\t"
+  __asm __volatile(
+      ".set       push                                                       "
+      "\n\t"
+      ".set       noreorder                                                  "
+      "\n\t"
+      "addiu      %[i],                $zero,                  64            "
+      "\n\t"
+      "11:                                                                    "
+      "\n\t"
+      "lh         %[tmp1],             0(%[pfft])                            "
+      "\n\t"
+      "lh         %[tmp2],             0(%[p_kSqrtHanning])                  "
+      "\n\t"
+      "addiu      %[i],                %[i],                   -2            "
+      "\n\t"
+      "mul        %[tmp1],             %[tmp1],                %[tmp2]       "
+      "\n\t"
+      "lh         %[tmp3],             2(%[pfft])                            "
+      "\n\t"
+      "lh         %[tmp4],             2(%[p_kSqrtHanning])                  "
+      "\n\t"
+      "mul        %[tmp3],             %[tmp3],                %[tmp4]       "
+      "\n\t"
+      "addiu      %[tmp1],             %[tmp1],                8192          "
+      "\n\t"
+      "sra        %[tmp1],             %[tmp1],                14            "
+      "\n\t"
+      "addiu      %[tmp3],             %[tmp3],                8192          "
+      "\n\t"
+      "sra        %[tmp3],             %[tmp3],                14            "
+      "\n\t"
+      "bgez       %[out_aecm],         1f                                    "
+      "\n\t"
+      " negu      %[tmp2],             %[out_aecm]                           "
+      "\n\t"
+      "srav       %[tmp1],             %[tmp1],                %[tmp2]       "
+      "\n\t"
+      "b          2f                                                         "
+      "\n\t"
+      " srav      %[tmp3],             %[tmp3],                %[tmp2]       "
+      "\n\t"
+      "1:                                                                     "
+      "\n\t"
+      "sllv       %[tmp1],             %[tmp1],                %[out_aecm]   "
+      "\n\t"
+      "sllv       %[tmp3],             %[tmp3],                %[out_aecm]   "
+      "\n\t"
+      "2:                                                                     "
+      "\n\t"
+      "lh         %[tmp4],             0(%[paecm_buf])                       "
+      "\n\t"
+      "lh         %[tmp2],             2(%[paecm_buf])                       "
+      "\n\t"
+      "addu       %[tmp3],             %[tmp3],                %[tmp2]       "
+      "\n\t"
+      "addu       %[tmp1],             %[tmp1],                %[tmp4]       "
+      "\n\t"
 #if defined(MIPS_DSP_R1_LE)
-    "shll_s.w   %[tmp1],             %[tmp1],                16            \n\t"
-    "sra        %[tmp1],             %[tmp1],                16            \n\t"
-    "shll_s.w   %[tmp3],             %[tmp3],                16            \n\t"
-    "sra        %[tmp3],             %[tmp3],                16            \n\t"
-#else  // #if defined(MIPS_DSP_R1_LE)
-    "sra        %[tmp4],             %[tmp1],                31            \n\t"
-    "sra        %[tmp2],             %[tmp1],                15            \n\t"
-    "beq        %[tmp4],             %[tmp2],                3f            \n\t"
-    " ori       %[tmp2],             $zero,                  0x7fff        \n\t"
-    "xor        %[tmp1],             %[tmp2],                %[tmp4]       \n\t"
-   "3:                                                                     \n\t"
-    "sra        %[tmp2],             %[tmp3],                31            \n\t"
-    "sra        %[tmp4],             %[tmp3],                15            \n\t"
-    "beq        %[tmp2],             %[tmp4],                4f            \n\t"
-    " ori       %[tmp4],             $zero,                  0x7fff        \n\t"
-    "xor        %[tmp3],             %[tmp4],                %[tmp2]       \n\t"
-   "4:                                                                     \n\t"
+      "shll_s.w   %[tmp1],             %[tmp1],                16            "
+      "\n\t"
+      "sra        %[tmp1],             %[tmp1],                16            "
+      "\n\t"
+      "shll_s.w   %[tmp3],             %[tmp3],                16            "
+      "\n\t"
+      "sra        %[tmp3],             %[tmp3],                16            "
+      "\n\t"
+#else   // #if defined(MIPS_DSP_R1_LE)
+      "sra        %[tmp4],             %[tmp1],                31            "
+      "\n\t"
+      "sra        %[tmp2],             %[tmp1],                15            "
+      "\n\t"
+      "beq        %[tmp4],             %[tmp2],                3f            "
+      "\n\t"
+      " ori       %[tmp2],             $zero,                  0x7fff        "
+      "\n\t"
+      "xor        %[tmp1],             %[tmp2],                %[tmp4]       "
+      "\n\t"
+      "3:                                                                     "
+      "\n\t"
+      "sra        %[tmp2],             %[tmp3],                31            "
+      "\n\t"
+      "sra        %[tmp4],             %[tmp3],                15            "
+      "\n\t"
+      "beq        %[tmp2],             %[tmp4],                4f            "
+      "\n\t"
+      " ori       %[tmp4],             $zero,                  0x7fff        "
+      "\n\t"
+      "xor        %[tmp3],             %[tmp4],                %[tmp2]       "
+      "\n\t"
+      "4:                                                                     "
+      "\n\t"
 #endif  // #if defined(MIPS_DSP_R1_LE)
-    "sh         %[tmp1],             0(%[pfft])                            \n\t"
-    "sh         %[tmp1],             0(%[output1])                         \n\t"
-    "sh         %[tmp3],             2(%[pfft])                            \n\t"
-    "sh         %[tmp3],             2(%[output1])                         \n\t"
-    "lh         %[tmp1],             128(%[pfft])                          \n\t"
-    "lh         %[tmp2],             0(%[pp_kSqrtHanning])                 \n\t"
-    "mul        %[tmp1],             %[tmp1],                %[tmp2]       \n\t"
-    "lh         %[tmp3],             130(%[pfft])                          \n\t"
-    "lh         %[tmp4],             -2(%[pp_kSqrtHanning])                \n\t"
-    "mul        %[tmp3],             %[tmp3],                %[tmp4]       \n\t"
-    "sra        %[tmp1],             %[tmp1],                14            \n\t"
-    "sra        %[tmp3],             %[tmp3],                14            \n\t"
-    "bgez       %[out_aecm],         5f                                    \n\t"
-    " negu      %[tmp2],             %[out_aecm]                           \n\t"
-    "srav       %[tmp3],             %[tmp3],                %[tmp2]       \n\t"
-    "b          6f                                                         \n\t"
-    " srav      %[tmp1],             %[tmp1],                %[tmp2]       \n\t"
-   "5:                                                                     \n\t"
-    "sllv       %[tmp1],             %[tmp1],                %[out_aecm]   \n\t"
-    "sllv       %[tmp3],             %[tmp3],                %[out_aecm]   \n\t"
-   "6:                                                                     \n\t"
+      "sh         %[tmp1],             0(%[pfft])                            "
+      "\n\t"
+      "sh         %[tmp1],             0(%[output1])                         "
+      "\n\t"
+      "sh         %[tmp3],             2(%[pfft])                            "
+      "\n\t"
+      "sh         %[tmp3],             2(%[output1])                         "
+      "\n\t"
+      "lh         %[tmp1],             128(%[pfft])                          "
+      "\n\t"
+      "lh         %[tmp2],             0(%[pp_kSqrtHanning])                 "
+      "\n\t"
+      "mul        %[tmp1],             %[tmp1],                %[tmp2]       "
+      "\n\t"
+      "lh         %[tmp3],             130(%[pfft])                          "
+      "\n\t"
+      "lh         %[tmp4],             -2(%[pp_kSqrtHanning])                "
+      "\n\t"
+      "mul        %[tmp3],             %[tmp3],                %[tmp4]       "
+      "\n\t"
+      "sra        %[tmp1],             %[tmp1],                14            "
+      "\n\t"
+      "sra        %[tmp3],             %[tmp3],                14            "
+      "\n\t"
+      "bgez       %[out_aecm],         5f                                    "
+      "\n\t"
+      " negu      %[tmp2],             %[out_aecm]                           "
+      "\n\t"
+      "srav       %[tmp3],             %[tmp3],                %[tmp2]       "
+      "\n\t"
+      "b          6f                                                         "
+      "\n\t"
+      " srav      %[tmp1],             %[tmp1],                %[tmp2]       "
+      "\n\t"
+      "5:                                                                     "
+      "\n\t"
+      "sllv       %[tmp1],             %[tmp1],                %[out_aecm]   "
+      "\n\t"
+      "sllv       %[tmp3],             %[tmp3],                %[out_aecm]   "
+      "\n\t"
+      "6:                                                                     "
+      "\n\t"
 #if defined(MIPS_DSP_R1_LE)
-    "shll_s.w   %[tmp1],             %[tmp1],                16            \n\t"
-    "sra        %[tmp1],             %[tmp1],                16            \n\t"
-    "shll_s.w   %[tmp3],             %[tmp3],                16            \n\t"
-    "sra        %[tmp3],             %[tmp3],                16            \n\t"
-#else  // #if defined(MIPS_DSP_R1_LE)
-    "sra        %[tmp4],             %[tmp1],                31            \n\t"
-    "sra        %[tmp2],             %[tmp1],                15            \n\t"
-    "beq        %[tmp4],             %[tmp2],                7f            \n\t"
-    " ori       %[tmp2],             $zero,                  0x7fff        \n\t"
-    "xor        %[tmp1],             %[tmp2],                %[tmp4]       \n\t"
-   "7:                                                                     \n\t"
-    "sra        %[tmp2],             %[tmp3],                31            \n\t"
-    "sra        %[tmp4],             %[tmp3],                15            \n\t"
-    "beq        %[tmp2],             %[tmp4],                8f            \n\t"
-    " ori       %[tmp4],             $zero,                  0x7fff        \n\t"
-    "xor        %[tmp3],             %[tmp4],                %[tmp2]       \n\t"
-   "8:                                                                     \n\t"
+      "shll_s.w   %[tmp1],             %[tmp1],                16            "
+      "\n\t"
+      "sra        %[tmp1],             %[tmp1],                16            "
+      "\n\t"
+      "shll_s.w   %[tmp3],             %[tmp3],                16            "
+      "\n\t"
+      "sra        %[tmp3],             %[tmp3],                16            "
+      "\n\t"
+#else   // #if defined(MIPS_DSP_R1_LE)
+      "sra        %[tmp4],             %[tmp1],                31            "
+      "\n\t"
+      "sra        %[tmp2],             %[tmp1],                15            "
+      "\n\t"
+      "beq        %[tmp4],             %[tmp2],                7f            "
+      "\n\t"
+      " ori       %[tmp2],             $zero,                  0x7fff        "
+      "\n\t"
+      "xor        %[tmp1],             %[tmp2],                %[tmp4]       "
+      "\n\t"
+      "7:                                                                     "
+      "\n\t"
+      "sra        %[tmp2],             %[tmp3],                31            "
+      "\n\t"
+      "sra        %[tmp4],             %[tmp3],                15            "
+      "\n\t"
+      "beq        %[tmp2],             %[tmp4],                8f            "
+      "\n\t"
+      " ori       %[tmp4],             $zero,                  0x7fff        "
+      "\n\t"
+      "xor        %[tmp3],             %[tmp4],                %[tmp2]       "
+      "\n\t"
+      "8:                                                                     "
+      "\n\t"
 #endif  // #if defined(MIPS_DSP_R1_LE)
-    "sh         %[tmp1],             0(%[paecm_buf])                       \n\t"
-    "sh         %[tmp3],             2(%[paecm_buf])                       \n\t"
-    "addiu      %[output1],          %[output1],             4             \n\t"
-    "addiu      %[paecm_buf],        %[paecm_buf],           4             \n\t"
-    "addiu      %[pfft],             %[pfft],                4             \n\t"
-    "addiu      %[p_kSqrtHanning],   %[p_kSqrtHanning],      4             \n\t"
-    "bgtz       %[i],                11b                                   \n\t"
-    " addiu     %[pp_kSqrtHanning],  %[pp_kSqrtHanning],     -4            \n\t"
-    ".set       pop                                                        \n\t"
-    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [pfft] "+r" (pfft),
-      [output1] "+r" (output1), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4),
-      [paecm_buf] "+r" (paecm_buf), [i] "=&r" (i),
-      [pp_kSqrtHanning] "+r" (pp_kSqrtHanning),
-      [p_kSqrtHanning] "+r" (p_kSqrtHanning)
-    : [out_aecm] "r" (out_aecm),
-      [WebRtcAecm_kSqrtHanning] "r" (WebRtcAecm_kSqrtHanning)
-    : "hi", "lo","memory"
-  );
+      "sh         %[tmp1],             0(%[paecm_buf])                       "
+      "\n\t"
+      "sh         %[tmp3],             2(%[paecm_buf])                       "
+      "\n\t"
+      "addiu      %[output1],          %[output1],             4             "
+      "\n\t"
+      "addiu      %[paecm_buf],        %[paecm_buf],           4             "
+      "\n\t"
+      "addiu      %[pfft],             %[pfft],                4             "
+      "\n\t"
+      "addiu      %[p_kSqrtHanning],   %[p_kSqrtHanning],      4             "
+      "\n\t"
+      "bgtz       %[i],                11b                                   "
+      "\n\t"
+      " addiu     %[pp_kSqrtHanning],  %[pp_kSqrtHanning],     -4            "
+      "\n\t"
+      ".set       pop                                                        "
+      "\n\t"
+      : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft),
+        [output1] "+r"(output1), [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4),
+        [paecm_buf] "+r"(paecm_buf), [i] "=&r"(i),
+        [pp_kSqrtHanning] "+r"(pp_kSqrtHanning),
+        [p_kSqrtHanning] "+r"(p_kSqrtHanning)
+      : [out_aecm] "r"(out_aecm),
+        [WebRtcAecm_kSqrtHanning] "r"(WebRtcAecm_kSqrtHanning)
+      : "hi", "lo", "memory");
 
   // Copy the current block to the old position
   // (aecm->outBuf is shifted elsewhere)
   memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
-  memcpy(aecm->dBufNoisy,
-         aecm->dBufNoisy + PART_LEN,
+  memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN,
          sizeof(int16_t) * PART_LEN);
   if (nearendClean != NULL) {
-    memcpy(aecm->dBufClean,
-           aecm->dBufClean + PART_LEN,
+    memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN,
            sizeof(int16_t) * PART_LEN);
   }
 }
@@ -451,62 +598,61 @@
 
   // Get energy for the delayed far end signal and estimated
   // echo using both stored and adapted channels.
-  for (i = 0; i < PART_LEN; i+= 4) {
-    __asm __volatile (
-      ".set           push                                            \n\t"
-      ".set           noreorder                                       \n\t"
-      "lh             %[stored0],     0(%[ch_stored_p])               \n\t"
-      "lhu            %[adept0],      0(%[ch_adapt_p])                \n\t"
-      "lhu            %[spectrum0],   0(%[spectrum_p])                \n\t"
-      "lh             %[stored1],     2(%[ch_stored_p])               \n\t"
-      "lhu            %[adept1],      2(%[ch_adapt_p])                \n\t"
-      "lhu            %[spectrum1],   2(%[spectrum_p])                \n\t"
-      "mul            %[echo0],       %[stored0],     %[spectrum0]    \n\t"
-      "mul            %[temp0],       %[adept0],      %[spectrum0]    \n\t"
-      "mul            %[echo1],       %[stored1],     %[spectrum1]    \n\t"
-      "mul            %[temp1],       %[adept1],      %[spectrum1]    \n\t"
-      "addu           %[par1],        %[par1],        %[spectrum0]    \n\t"
-      "addu           %[par1],        %[par1],        %[spectrum1]    \n\t"
-      "addiu          %[echo_p],      %[echo_p],      16              \n\t"
-      "addu           %[par3],        %[par3],        %[echo0]        \n\t"
-      "addu           %[par2],        %[par2],        %[temp0]        \n\t"
-      "addu           %[par3],        %[par3],        %[echo1]        \n\t"
-      "addu           %[par2],        %[par2],        %[temp1]        \n\t"
-      "usw            %[echo0],       -16(%[echo_p])                  \n\t"
-      "usw            %[echo1],       -12(%[echo_p])                  \n\t"
-      "lh             %[stored0],     4(%[ch_stored_p])               \n\t"
-      "lhu            %[adept0],      4(%[ch_adapt_p])                \n\t"
-      "lhu            %[spectrum0],   4(%[spectrum_p])                \n\t"
-      "lh             %[stored1],     6(%[ch_stored_p])               \n\t"
-      "lhu            %[adept1],      6(%[ch_adapt_p])                \n\t"
-      "lhu            %[spectrum1],   6(%[spectrum_p])                \n\t"
-      "mul            %[echo0],       %[stored0],     %[spectrum0]    \n\t"
-      "mul            %[temp0],       %[adept0],      %[spectrum0]    \n\t"
-      "mul            %[echo1],       %[stored1],     %[spectrum1]    \n\t"
-      "mul            %[temp1],       %[adept1],      %[spectrum1]    \n\t"
-      "addu           %[par1],        %[par1],        %[spectrum0]    \n\t"
-      "addu           %[par1],        %[par1],        %[spectrum1]    \n\t"
-      "addiu          %[ch_stored_p], %[ch_stored_p], 8               \n\t"
-      "addiu          %[ch_adapt_p],  %[ch_adapt_p],  8               \n\t"
-      "addiu          %[spectrum_p],  %[spectrum_p],  8               \n\t"
-      "addu           %[par3],        %[par3],        %[echo0]        \n\t"
-      "addu           %[par2],        %[par2],        %[temp0]        \n\t"
-      "addu           %[par3],        %[par3],        %[echo1]        \n\t"
-      "addu           %[par2],        %[par2],        %[temp1]        \n\t"
-      "usw            %[echo0],       -8(%[echo_p])                   \n\t"
-      "usw            %[echo1],       -4(%[echo_p])                   \n\t"
-      ".set           pop                                             \n\t"
-      : [temp0] "=&r" (temp0), [stored0] "=&r" (stored0),
-        [adept0] "=&r" (adept0), [spectrum0] "=&r" (spectrum0),
-        [echo0] "=&r" (echo0), [echo_p] "+r" (echo_p), [par3] "+r" (par3),
-        [par1] "+r" (par1), [par2] "+r" (par2), [stored1] "=&r" (stored1),
-        [adept1] "=&r" (adept1), [echo1] "=&r" (echo1),
-        [spectrum1] "=&r" (spectrum1), [temp1] "=&r" (temp1),
-        [ch_stored_p] "+r" (ch_stored_p), [ch_adapt_p] "+r" (ch_adapt_p),
-        [spectrum_p] "+r" (spectrum_p)
-      :
-      : "hi", "lo", "memory"
-    );
+  for (i = 0; i < PART_LEN; i += 4) {
+    __asm __volatile(
+        ".set           push                                            \n\t"
+        ".set           noreorder                                       \n\t"
+        "lh             %[stored0],     0(%[ch_stored_p])               \n\t"
+        "lhu            %[adept0],      0(%[ch_adapt_p])                \n\t"
+        "lhu            %[spectrum0],   0(%[spectrum_p])                \n\t"
+        "lh             %[stored1],     2(%[ch_stored_p])               \n\t"
+        "lhu            %[adept1],      2(%[ch_adapt_p])                \n\t"
+        "lhu            %[spectrum1],   2(%[spectrum_p])                \n\t"
+        "mul            %[echo0],       %[stored0],     %[spectrum0]    \n\t"
+        "mul            %[temp0],       %[adept0],      %[spectrum0]    \n\t"
+        "mul            %[echo1],       %[stored1],     %[spectrum1]    \n\t"
+        "mul            %[temp1],       %[adept1],      %[spectrum1]    \n\t"
+        "addu           %[par1],        %[par1],        %[spectrum0]    \n\t"
+        "addu           %[par1],        %[par1],        %[spectrum1]    \n\t"
+        "addiu          %[echo_p],      %[echo_p],      16              \n\t"
+        "addu           %[par3],        %[par3],        %[echo0]        \n\t"
+        "addu           %[par2],        %[par2],        %[temp0]        \n\t"
+        "addu           %[par3],        %[par3],        %[echo1]        \n\t"
+        "addu           %[par2],        %[par2],        %[temp1]        \n\t"
+        "usw            %[echo0],       -16(%[echo_p])                  \n\t"
+        "usw            %[echo1],       -12(%[echo_p])                  \n\t"
+        "lh             %[stored0],     4(%[ch_stored_p])               \n\t"
+        "lhu            %[adept0],      4(%[ch_adapt_p])                \n\t"
+        "lhu            %[spectrum0],   4(%[spectrum_p])                \n\t"
+        "lh             %[stored1],     6(%[ch_stored_p])               \n\t"
+        "lhu            %[adept1],      6(%[ch_adapt_p])                \n\t"
+        "lhu            %[spectrum1],   6(%[spectrum_p])                \n\t"
+        "mul            %[echo0],       %[stored0],     %[spectrum0]    \n\t"
+        "mul            %[temp0],       %[adept0],      %[spectrum0]    \n\t"
+        "mul            %[echo1],       %[stored1],     %[spectrum1]    \n\t"
+        "mul            %[temp1],       %[adept1],      %[spectrum1]    \n\t"
+        "addu           %[par1],        %[par1],        %[spectrum0]    \n\t"
+        "addu           %[par1],        %[par1],        %[spectrum1]    \n\t"
+        "addiu          %[ch_stored_p], %[ch_stored_p], 8               \n\t"
+        "addiu          %[ch_adapt_p],  %[ch_adapt_p],  8               \n\t"
+        "addiu          %[spectrum_p],  %[spectrum_p],  8               \n\t"
+        "addu           %[par3],        %[par3],        %[echo0]        \n\t"
+        "addu           %[par2],        %[par2],        %[temp0]        \n\t"
+        "addu           %[par3],        %[par3],        %[echo1]        \n\t"
+        "addu           %[par2],        %[par2],        %[temp1]        \n\t"
+        "usw            %[echo0],       -8(%[echo_p])                   \n\t"
+        "usw            %[echo1],       -4(%[echo_p])                   \n\t"
+        ".set           pop                                             \n\t"
+        : [temp0] "=&r"(temp0), [stored0] "=&r"(stored0),
+          [adept0] "=&r"(adept0), [spectrum0] "=&r"(spectrum0),
+          [echo0] "=&r"(echo0), [echo_p] "+r"(echo_p), [par3] "+r"(par3),
+          [par1] "+r"(par1), [par2] "+r"(par2), [stored1] "=&r"(stored1),
+          [adept1] "=&r"(adept1), [echo1] "=&r"(echo1),
+          [spectrum1] "=&r"(spectrum1), [temp1] "=&r"(temp1),
+          [ch_stored_p] "+r"(ch_stored_p), [ch_adapt_p] "+r"(ch_adapt_p),
+          [spectrum_p] "+r"(spectrum_p)
+        :
+        : "hi", "lo", "memory");
   }
 
   echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN],
@@ -537,35 +683,33 @@
          sizeof(int16_t) * PART_LEN1);
   // Recalculate echo estimate
   for (i = 0; i < PART_LEN; i += 4) {
-    __asm __volatile (
-      "ulw            %[temp0],   0(%[temp8])               \n\t"
-      "ulw            %[temp2],   0(%[temp1])               \n\t"
-      "ulw            %[temp4],   4(%[temp8])               \n\t"
-      "ulw            %[temp5],   4(%[temp1])               \n\t"
-      "muleq_s.w.phl  %[temp3],   %[temp2],     %[temp0]    \n\t"
-      "muleq_s.w.phr  %[temp0],   %[temp2],     %[temp0]    \n\t"
-      "muleq_s.w.phl  %[temp6],   %[temp5],     %[temp4]    \n\t"
-      "muleq_s.w.phr  %[temp4],   %[temp5],     %[temp4]    \n\t"
-      "addiu          %[temp7],   %[temp7],     16          \n\t"
-      "addiu          %[temp1],   %[temp1],     8           \n\t"
-      "addiu          %[temp8],   %[temp8],     8           \n\t"
-      "sra            %[temp3],   %[temp3],     1           \n\t"
-      "sra            %[temp0],   %[temp0],     1           \n\t"
-      "sra            %[temp6],   %[temp6],     1           \n\t"
-      "sra            %[temp4],   %[temp4],     1           \n\t"
-      "usw            %[temp3],   -12(%[temp7])             \n\t"
-      "usw            %[temp0],   -16(%[temp7])             \n\t"
-      "usw            %[temp6],   -4(%[temp7])              \n\t"
-      "usw            %[temp4],   -8(%[temp7])              \n\t"
-      : [temp0] "=&r" (temp0), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
-        [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [temp6] "=&r" (temp6),
-        [temp1] "+r" (temp1), [temp8] "+r" (temp8), [temp7] "+r" (temp7)
-      :
-      : "hi", "lo", "memory"
-    );
+    __asm __volatile(
+        "ulw            %[temp0],   0(%[temp8])               \n\t"
+        "ulw            %[temp2],   0(%[temp1])               \n\t"
+        "ulw            %[temp4],   4(%[temp8])               \n\t"
+        "ulw            %[temp5],   4(%[temp1])               \n\t"
+        "muleq_s.w.phl  %[temp3],   %[temp2],     %[temp0]    \n\t"
+        "muleq_s.w.phr  %[temp0],   %[temp2],     %[temp0]    \n\t"
+        "muleq_s.w.phl  %[temp6],   %[temp5],     %[temp4]    \n\t"
+        "muleq_s.w.phr  %[temp4],   %[temp5],     %[temp4]    \n\t"
+        "addiu          %[temp7],   %[temp7],     16          \n\t"
+        "addiu          %[temp1],   %[temp1],     8           \n\t"
+        "addiu          %[temp8],   %[temp8],     8           \n\t"
+        "sra            %[temp3],   %[temp3],     1           \n\t"
+        "sra            %[temp0],   %[temp0],     1           \n\t"
+        "sra            %[temp6],   %[temp6],     1           \n\t"
+        "sra            %[temp4],   %[temp4],     1           \n\t"
+        "usw            %[temp3],   -12(%[temp7])             \n\t"
+        "usw            %[temp0],   -16(%[temp7])             \n\t"
+        "usw            %[temp6],   -4(%[temp7])              \n\t"
+        "usw            %[temp4],   -8(%[temp7])              \n\t"
+        : [temp0] "=&r"(temp0), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+          [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp6] "=&r"(temp6),
+          [temp1] "+r"(temp1), [temp8] "+r"(temp8), [temp7] "+r"(temp7)
+        :
+        : "hi", "lo", "memory");
   }
-  echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
-                                      far_spectrum[i]);
+  echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
 }
 
 void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm) {
@@ -579,31 +723,28 @@
 
   // The stored channel has a significantly lower MSE than the adaptive one for
   // two consecutive calculations. Reset the adaptive channel.
-  memcpy(aecm->channelAdapt16,
-         aecm->channelStored,
+  memcpy(aecm->channelAdapt16, aecm->channelStored,
          sizeof(int16_t) * PART_LEN1);
 
   // Restore the W32 channel
   for (i = 0; i < PART_LEN; i += 4) {
-    __asm __volatile (
-      "ulw            %[temp1], 0(%[temp0])           \n\t"
-      "ulw            %[temp4], 4(%[temp0])           \n\t"
-      "preceq.w.phl   %[temp2], %[temp1]              \n\t"
-      "preceq.w.phr   %[temp1], %[temp1]              \n\t"
-      "preceq.w.phl   %[temp5], %[temp4]              \n\t"
-      "preceq.w.phr   %[temp4], %[temp4]              \n\t"
-      "addiu          %[temp0], %[temp0], 8           \n\t"
-      "usw            %[temp2], 4(%[temp3])           \n\t"
-      "usw            %[temp1], 0(%[temp3])           \n\t"
-      "usw            %[temp5], 12(%[temp3])          \n\t"
-      "usw            %[temp4], 8(%[temp3])           \n\t"
-      "addiu          %[temp3], %[temp3], 16          \n\t"
-      : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2),
-        [temp4] "=&r" (temp4), [temp5] "=&r" (temp5),
-        [temp3] "+r" (temp3), [temp0] "+r" (temp0)
-      :
-      : "memory"
-    );
+    __asm __volatile(
+        "ulw            %[temp1], 0(%[temp0])           \n\t"
+        "ulw            %[temp4], 4(%[temp0])           \n\t"
+        "preceq.w.phl   %[temp2], %[temp1]              \n\t"
+        "preceq.w.phr   %[temp1], %[temp1]              \n\t"
+        "preceq.w.phl   %[temp5], %[temp4]              \n\t"
+        "preceq.w.phr   %[temp4], %[temp4]              \n\t"
+        "addiu          %[temp0], %[temp0], 8           \n\t"
+        "usw            %[temp2], 4(%[temp3])           \n\t"
+        "usw            %[temp1], 0(%[temp3])           \n\t"
+        "usw            %[temp5], 12(%[temp3])          \n\t"
+        "usw            %[temp4], 8(%[temp3])           \n\t"
+        "addiu          %[temp3], %[temp3], 16          \n\t"
+        : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp4] "=&r"(temp4),
+          [temp5] "=&r"(temp5), [temp3] "+r"(temp3), [temp0] "+r"(temp0)
+        :
+        : "memory");
   }
 
   aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
@@ -633,7 +774,7 @@
 
   // In fft_buf, +16 for 32-byte alignment.
   int16_t fft_buf[PART_LEN4 + 16];
-  int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31);
+  int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
 
   int16_t tmp16no1;
 #if !defined(MIPS_DSP_R2_LE)
@@ -662,25 +803,18 @@
   freq_signal[PART_LEN].imag = 0;
   freq_signal[PART_LEN].real = fft[PART_LEN2];
   freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
-  freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(
-    freq_signal[PART_LEN].real);
-  (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) +
-    (uint32_t)(freq_signal_abs[PART_LEN]);
+  freq_signal_abs[PART_LEN] =
+      (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real);
+  (*freq_signal_sum_abs) =
+      (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]);
 
 #if !defined(MIPS_DSP_R2_LE)
   for (i = 1; i < PART_LEN; i++) {
-    if (freq_signal[i].real == 0)
-    {
-      freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(
-        freq_signal[i].imag);
-    }
-    else if (freq_signal[i].imag == 0)
-    {
-      freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(
-        freq_signal[i].real);
-    }
-    else
-    {
+    if (freq_signal[i].real == 0) {
+      freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
+    } else if (freq_signal[i].imag == 0) {
+      freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real);
+    } else {
       // Approximation for magnitude of complex fft output
       // magn = sqrt(real^2 + imag^2)
       // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
@@ -697,32 +831,30 @@
     }
     (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
   }
-#else // #if !defined(MIPS_DSP_R2_LE)
-  freqs = (uint32_t)(freq_signal_abs[0]) +
-          (uint32_t)(freq_signal_abs[PART_LEN]);
+#else  // #if !defined(MIPS_DSP_R2_LE)
+  freqs =
+      (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]);
   freqp = &(freq_signal[1].real);
 
-  __asm __volatile (
-    "lw             %[freqt0],      0(%[freqp])             \n\t"
-    "lw             %[freqt1],      4(%[freqp])             \n\t"
-    "lw             %[freqt2],      8(%[freqp])             \n\t"
-    "mult           $ac0,           $zero,      $zero       \n\t"
-    "mult           $ac1,           $zero,      $zero       \n\t"
-    "mult           $ac2,           $zero,      $zero       \n\t"
-    "dpaq_s.w.ph    $ac0,           %[freqt0],  %[freqt0]   \n\t"
-    "dpaq_s.w.ph    $ac1,           %[freqt1],  %[freqt1]   \n\t"
-    "dpaq_s.w.ph    $ac2,           %[freqt2],  %[freqt2]   \n\t"
-    "addiu          %[freqp],       %[freqp],   12          \n\t"
-    "extr.w         %[tmp32no20],   $ac0,       1           \n\t"
-    "extr.w         %[tmp32no21],   $ac1,       1           \n\t"
-    "extr.w         %[tmp32no22],   $ac2,       1           \n\t"
-    : [freqt0] "=&r" (freqt0), [freqt1] "=&r" (freqt1),
-      [freqt2] "=&r" (freqt2), [freqp] "+r" (freqp),
-      [tmp32no20] "=r" (tmp32no20), [tmp32no21] "=r" (tmp32no21),
-      [tmp32no22] "=r" (tmp32no22)
-    :
-    : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo"
-  );
+  __asm __volatile(
+      "lw             %[freqt0],      0(%[freqp])             \n\t"
+      "lw             %[freqt1],      4(%[freqp])             \n\t"
+      "lw             %[freqt2],      8(%[freqp])             \n\t"
+      "mult           $ac0,           $zero,      $zero       \n\t"
+      "mult           $ac1,           $zero,      $zero       \n\t"
+      "mult           $ac2,           $zero,      $zero       \n\t"
+      "dpaq_s.w.ph    $ac0,           %[freqt0],  %[freqt0]   \n\t"
+      "dpaq_s.w.ph    $ac1,           %[freqt1],  %[freqt1]   \n\t"
+      "dpaq_s.w.ph    $ac2,           %[freqt2],  %[freqt2]   \n\t"
+      "addiu          %[freqp],       %[freqp],   12          \n\t"
+      "extr.w         %[tmp32no20],   $ac0,       1           \n\t"
+      "extr.w         %[tmp32no21],   $ac1,       1           \n\t"
+      "extr.w         %[tmp32no22],   $ac2,       1           \n\t"
+      : [freqt0] "=&r"(freqt0), [freqt1] "=&r"(freqt1), [freqt2] "=&r"(freqt2),
+        [freqp] "+r"(freqp), [tmp32no20] "=r"(tmp32no20),
+        [tmp32no21] "=r"(tmp32no21), [tmp32no22] "=r"(tmp32no22)
+      :
+      : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo");
 
   tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20);
   tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21);
@@ -734,57 +866,54 @@
   freqs += (uint32_t)tmp32no11;
   freqs += (uint32_t)tmp32no12;
   freqabsp = &(freq_signal_abs[4]);
-  for (i = 4; i < PART_LEN; i+=4)
-  {
-    __asm __volatile (
-      "ulw            %[freqt0],      0(%[freqp])                 \n\t"
-      "ulw            %[freqt1],      4(%[freqp])                 \n\t"
-      "ulw            %[freqt2],      8(%[freqp])                 \n\t"
-      "ulw            %[freqt3],      12(%[freqp])                \n\t"
-      "mult           $ac0,           $zero,          $zero       \n\t"
-      "mult           $ac1,           $zero,          $zero       \n\t"
-      "mult           $ac2,           $zero,          $zero       \n\t"
-      "mult           $ac3,           $zero,          $zero       \n\t"
-      "dpaq_s.w.ph    $ac0,           %[freqt0],      %[freqt0]   \n\t"
-      "dpaq_s.w.ph    $ac1,           %[freqt1],      %[freqt1]   \n\t"
-      "dpaq_s.w.ph    $ac2,           %[freqt2],      %[freqt2]   \n\t"
-      "dpaq_s.w.ph    $ac3,           %[freqt3],      %[freqt3]   \n\t"
-      "addiu          %[freqp],       %[freqp],       16          \n\t"
-      "addiu          %[freqabsp],    %[freqabsp],    8           \n\t"
-      "extr.w         %[tmp32no20],   $ac0,           1           \n\t"
-      "extr.w         %[tmp32no21],   $ac1,           1           \n\t"
-      "extr.w         %[tmp32no22],   $ac2,           1           \n\t"
-      "extr.w         %[tmp32no23],   $ac3,           1           \n\t"
-      : [freqt0] "=&r" (freqt0), [freqt1] "=&r" (freqt1),
-        [freqt2] "=&r" (freqt2), [freqt3] "=&r" (freqt3),
-        [tmp32no20] "=r" (tmp32no20), [tmp32no21] "=r" (tmp32no21),
-        [tmp32no22] "=r" (tmp32no22), [tmp32no23] "=r" (tmp32no23),
-        [freqabsp] "+r" (freqabsp), [freqp] "+r" (freqp)
-      :
-      : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
-        "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
-    );
+  for (i = 4; i < PART_LEN; i += 4) {
+    __asm __volatile(
+        "ulw            %[freqt0],      0(%[freqp])                 \n\t"
+        "ulw            %[freqt1],      4(%[freqp])                 \n\t"
+        "ulw            %[freqt2],      8(%[freqp])                 \n\t"
+        "ulw            %[freqt3],      12(%[freqp])                \n\t"
+        "mult           $ac0,           $zero,          $zero       \n\t"
+        "mult           $ac1,           $zero,          $zero       \n\t"
+        "mult           $ac2,           $zero,          $zero       \n\t"
+        "mult           $ac3,           $zero,          $zero       \n\t"
+        "dpaq_s.w.ph    $ac0,           %[freqt0],      %[freqt0]   \n\t"
+        "dpaq_s.w.ph    $ac1,           %[freqt1],      %[freqt1]   \n\t"
+        "dpaq_s.w.ph    $ac2,           %[freqt2],      %[freqt2]   \n\t"
+        "dpaq_s.w.ph    $ac3,           %[freqt3],      %[freqt3]   \n\t"
+        "addiu          %[freqp],       %[freqp],       16          \n\t"
+        "addiu          %[freqabsp],    %[freqabsp],    8           \n\t"
+        "extr.w         %[tmp32no20],   $ac0,           1           \n\t"
+        "extr.w         %[tmp32no21],   $ac1,           1           \n\t"
+        "extr.w         %[tmp32no22],   $ac2,           1           \n\t"
+        "extr.w         %[tmp32no23],   $ac3,           1           \n\t"
+        : [freqt0] "=&r"(freqt0), [freqt1] "=&r"(freqt1),
+          [freqt2] "=&r"(freqt2), [freqt3] "=&r"(freqt3),
+          [tmp32no20] "=r"(tmp32no20), [tmp32no21] "=r"(tmp32no21),
+          [tmp32no22] "=r"(tmp32no22), [tmp32no23] "=r"(tmp32no23),
+          [freqabsp] "+r"(freqabsp), [freqp] "+r"(freqp)
+        :
+        : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+          "$ac3hi", "$ac3lo");
 
     tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20);
     tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21);
     tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22);
     tmp32no13 = WebRtcSpl_SqrtFloor(tmp32no23);
 
-    __asm __volatile (
-      "sh             %[tmp32no10],   -8(%[freqabsp])                 \n\t"
-      "sh             %[tmp32no11],   -6(%[freqabsp])                 \n\t"
-      "sh             %[tmp32no12],   -4(%[freqabsp])                 \n\t"
-      "sh             %[tmp32no13],   -2(%[freqabsp])                 \n\t"
-      "addu           %[freqs],       %[freqs],       %[tmp32no10]    \n\t"
-      "addu           %[freqs],       %[freqs],       %[tmp32no11]    \n\t"
-      "addu           %[freqs],       %[freqs],       %[tmp32no12]    \n\t"
-      "addu           %[freqs],       %[freqs],       %[tmp32no13]    \n\t"
-      : [freqs] "+r" (freqs)
-      : [tmp32no10] "r" (tmp32no10), [tmp32no11] "r" (tmp32no11),
-        [tmp32no12] "r" (tmp32no12), [tmp32no13] "r" (tmp32no13),
-        [freqabsp] "r" (freqabsp)
-      : "memory"
-    );
+    __asm __volatile(
+        "sh             %[tmp32no10],   -8(%[freqabsp])                 \n\t"
+        "sh             %[tmp32no11],   -6(%[freqabsp])                 \n\t"
+        "sh             %[tmp32no12],   -4(%[freqabsp])                 \n\t"
+        "sh             %[tmp32no13],   -2(%[freqabsp])                 \n\t"
+        "addu           %[freqs],       %[freqs],       %[tmp32no10]    \n\t"
+        "addu           %[freqs],       %[freqs],       %[tmp32no11]    \n\t"
+        "addu           %[freqs],       %[freqs],       %[tmp32no12]    \n\t"
+        "addu           %[freqs],       %[freqs],       %[tmp32no13]    \n\t"
+        : [freqs] "+r"(freqs)
+        : [tmp32no10] "r"(tmp32no10), [tmp32no11] "r"(tmp32no11),
+          [tmp32no12] "r"(tmp32no12), [tmp32no13] "r"(tmp32no13),
+          [freqabsp] "r"(freqabsp)
+        : "memory");
   }
 
   (*freq_signal_sum_abs) = freqs;
@@ -813,13 +942,13 @@
   const uint16_t* far_spectrum_ptr = NULL;
 
   // 32 byte aligned buffers (with +8 or +16).
-  int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
+  int16_t fft_buf[PART_LEN4 + 2 + 16];  // +2 to make a loop safe.
   int32_t echoEst32_buf[PART_LEN1 + 8];
   int32_t dfw_buf[PART_LEN2 + 8];
   int32_t efw_buf[PART_LEN2 + 8];
 
-  int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~ 31);
-  int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~ 31);
+  int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
+  int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
   ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
   ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
 
@@ -856,35 +985,25 @@
   // (2) the rest
 
   if (aecm->startupState < 2) {
-    aecm->startupState = (aecm->totCount >= CONV_LEN) +
-                         (aecm->totCount >= CONV_LEN2);
+    aecm->startupState =
+        (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
   }
   // END: Determine startup state
 
   // Buffer near and far end signals
   memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
-  memcpy(aecm->dBufNoisy + PART_LEN,
-         nearendNoisy,
-         sizeof(int16_t) * PART_LEN);
+  memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN);
   if (nearendClean != NULL) {
-    memcpy(aecm->dBufClean + PART_LEN,
-           nearendClean,
+    memcpy(aecm->dBufClean + PART_LEN, nearendClean,
            sizeof(int16_t) * PART_LEN);
   }
 
   // Transform far end signal from time domain to frequency domain.
-  far_q = TimeToFrequencyDomain(aecm,
-                                aecm->xBuf,
-                                dfw,
-                                xfa,
-                                &xfaSum);
+  far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum);
 
   // Transform noisy near end signal from time domain to frequency domain.
-  zerosDBufNoisy = TimeToFrequencyDomain(aecm,
-                                         aecm->dBufNoisy,
-                                         dfw,
-                                         dfaNoisy,
-                                         &dfaNoisySum);
+  zerosDBufNoisy =
+      TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum);
   aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
   aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
 
@@ -895,10 +1014,7 @@
     dfaCleanSum = dfaNoisySum;
   } else {
     // Transform clean near end signal from time domain to frequency domain.
-    zerosDBufClean = TimeToFrequencyDomain(aecm,
-                                           aecm->dBufClean,
-                                           dfw,
-                                           dfaClean,
+    zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean,
                                            &dfaCleanSum);
     aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
     aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
@@ -912,14 +1028,11 @@
                                far_q) == -1) {
     return -1;
   }
-  delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
-                                          dfaNoisy,
-                                          PART_LEN1,
-                                          zerosDBufNoisy);
+  delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy,
+                                          PART_LEN1, zerosDBufNoisy);
   if (delay == -1) {
     return -1;
-  }
-  else if (delay == -2) {
+  } else if (delay == -2) {
     // If the delay is unknown, we assume zero.
     // NOTE: this will have to be adjusted if we ever add lookahead.
     delay = 0;
@@ -932,17 +1045,14 @@
 
   // Get aligned far end spectrum
   far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
-  zerosXBuf = (int16_t) far_q;
+  zerosXBuf = (int16_t)far_q;
 
   if (far_spectrum_ptr == NULL) {
     return -1;
   }
 
   // Calculate log(energy) and update energy threshold levels
-  WebRtcAecm_CalcEnergies(aecm,
-                          far_spectrum_ptr,
-                          zerosXBuf,
-                          dfaNoisySum,
+  WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum,
                           echoEst32);
   // Calculate stepsize
   mu = WebRtcAecm_CalcStepSize(aecm);
@@ -953,11 +1063,7 @@
   // This is the channel estimation algorithm.
   // It is base on NLMS but has a variable step length,
   // which was calculated above.
-  WebRtcAecm_UpdateChannel(aecm,
-                           far_spectrum_ptr,
-                           zerosXBuf,
-                           dfaNoisy,
-                           mu,
+  WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu,
                            echoEst32);
 
   supGain = WebRtcAecm_CalcSuppressionGain(aecm);
@@ -976,19 +1082,18 @@
       // Multiplication is safe
       // Result in
       // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff])
-      echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
-                                              (uint16_t)supGain);
+      echoEst32Gained =
+          WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], (uint16_t)supGain);
       resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
       resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
     } else {
       tmp16no1 = 17 - zeros32 - zeros16;
-      resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 -
-                       RESOLUTION_SUPGAIN;
+      resolutionDiff =
+          14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
       resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
       if (zeros32 > tmp16no1) {
-        echoEst32Gained = WEBRTC_SPL_UMUL_32_16(
-                            (uint32_t)aecm->echoFilt[i],
-                            supGain >> tmp16no1);
+        echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
+                                                supGain >> tmp16no1);
       } else {
         // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
         echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
@@ -1004,8 +1109,8 @@
       tmp16no2 = ptrDfaClean[i] >> -qDomainDiff;
     } else {
       tmp16no1 = dfa_clean_q_domain_diff < 0
-          ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
-          : aecm->nearFilt[i] << dfa_clean_q_domain_diff;
+                     ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
+                     : aecm->nearFilt[i] << dfa_clean_q_domain_diff;
       qDomainDiff = 0;
       tmp16no2 = ptrDfaClean[i];
     }
@@ -1017,8 +1122,8 @@
     if ((tmp16no2) & (-qDomainDiff > zeros16)) {
       aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
     } else {
-      aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 << -qDomainDiff
-                                          : tmp16no2 >> qDomainDiff;
+      aecm->nearFilt[i] =
+          qDomainDiff < 0 ? tmp16no2 << -qDomainDiff : tmp16no2 >> qDomainDiff;
     }
 
     // Wiener filter coefficients, resulting hnl in Q14
@@ -1031,8 +1136,8 @@
       // Multiply the suppression gain
       // Rounding
       echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
-      tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained,
-                                   (uint16_t)aecm->nearFilt[i]);
+      tmpU32 =
+          WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]);
 
       // Current resolution is
       // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN
@@ -1062,58 +1167,56 @@
     // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
     //               speech distortion in double-talk.
     for (i = 0; i < (PART_LEN1 >> 3); i++) {
-      __asm __volatile (
-        "lh         %[temp1],       0(%[ptr1])                  \n\t"
-        "lh         %[temp2],       2(%[ptr1])                  \n\t"
-        "lh         %[temp3],       4(%[ptr1])                  \n\t"
-        "lh         %[temp4],       6(%[ptr1])                  \n\t"
-        "lh         %[temp5],       8(%[ptr1])                  \n\t"
-        "lh         %[temp6],       10(%[ptr1])                 \n\t"
-        "lh         %[temp7],       12(%[ptr1])                 \n\t"
-        "lh         %[temp8],       14(%[ptr1])                 \n\t"
-        "mul        %[temp1],       %[temp1],       %[temp1]    \n\t"
-        "mul        %[temp2],       %[temp2],       %[temp2]    \n\t"
-        "mul        %[temp3],       %[temp3],       %[temp3]    \n\t"
-        "mul        %[temp4],       %[temp4],       %[temp4]    \n\t"
-        "mul        %[temp5],       %[temp5],       %[temp5]    \n\t"
-        "mul        %[temp6],       %[temp6],       %[temp6]    \n\t"
-        "mul        %[temp7],       %[temp7],       %[temp7]    \n\t"
-        "mul        %[temp8],       %[temp8],       %[temp8]    \n\t"
-        "sra        %[temp1],       %[temp1],       14          \n\t"
-        "sra        %[temp2],       %[temp2],       14          \n\t"
-        "sra        %[temp3],       %[temp3],       14          \n\t"
-        "sra        %[temp4],       %[temp4],       14          \n\t"
-        "sra        %[temp5],       %[temp5],       14          \n\t"
-        "sra        %[temp6],       %[temp6],       14          \n\t"
-        "sra        %[temp7],       %[temp7],       14          \n\t"
-        "sra        %[temp8],       %[temp8],       14          \n\t"
-        "sh         %[temp1],       0(%[ptr1])                  \n\t"
-        "sh         %[temp2],       2(%[ptr1])                  \n\t"
-        "sh         %[temp3],       4(%[ptr1])                  \n\t"
-        "sh         %[temp4],       6(%[ptr1])                  \n\t"
-        "sh         %[temp5],       8(%[ptr1])                  \n\t"
-        "sh         %[temp6],       10(%[ptr1])                 \n\t"
-        "sh         %[temp7],       12(%[ptr1])                 \n\t"
-        "sh         %[temp8],       14(%[ptr1])                 \n\t"
-        "addiu      %[ptr1],        %[ptr1],        16          \n\t"
-        : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
-          [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [temp6] "=&r" (temp6),
-          [temp7] "=&r" (temp7), [temp8] "=&r" (temp8), [ptr1] "+r" (ptr1)
-        :
-        : "memory", "hi", "lo"
-      );
+      __asm __volatile(
+          "lh         %[temp1],       0(%[ptr1])                  \n\t"
+          "lh         %[temp2],       2(%[ptr1])                  \n\t"
+          "lh         %[temp3],       4(%[ptr1])                  \n\t"
+          "lh         %[temp4],       6(%[ptr1])                  \n\t"
+          "lh         %[temp5],       8(%[ptr1])                  \n\t"
+          "lh         %[temp6],       10(%[ptr1])                 \n\t"
+          "lh         %[temp7],       12(%[ptr1])                 \n\t"
+          "lh         %[temp8],       14(%[ptr1])                 \n\t"
+          "mul        %[temp1],       %[temp1],       %[temp1]    \n\t"
+          "mul        %[temp2],       %[temp2],       %[temp2]    \n\t"
+          "mul        %[temp3],       %[temp3],       %[temp3]    \n\t"
+          "mul        %[temp4],       %[temp4],       %[temp4]    \n\t"
+          "mul        %[temp5],       %[temp5],       %[temp5]    \n\t"
+          "mul        %[temp6],       %[temp6],       %[temp6]    \n\t"
+          "mul        %[temp7],       %[temp7],       %[temp7]    \n\t"
+          "mul        %[temp8],       %[temp8],       %[temp8]    \n\t"
+          "sra        %[temp1],       %[temp1],       14          \n\t"
+          "sra        %[temp2],       %[temp2],       14          \n\t"
+          "sra        %[temp3],       %[temp3],       14          \n\t"
+          "sra        %[temp4],       %[temp4],       14          \n\t"
+          "sra        %[temp5],       %[temp5],       14          \n\t"
+          "sra        %[temp6],       %[temp6],       14          \n\t"
+          "sra        %[temp7],       %[temp7],       14          \n\t"
+          "sra        %[temp8],       %[temp8],       14          \n\t"
+          "sh         %[temp1],       0(%[ptr1])                  \n\t"
+          "sh         %[temp2],       2(%[ptr1])                  \n\t"
+          "sh         %[temp3],       4(%[ptr1])                  \n\t"
+          "sh         %[temp4],       6(%[ptr1])                  \n\t"
+          "sh         %[temp5],       8(%[ptr1])                  \n\t"
+          "sh         %[temp6],       10(%[ptr1])                 \n\t"
+          "sh         %[temp7],       12(%[ptr1])                 \n\t"
+          "sh         %[temp8],       14(%[ptr1])                 \n\t"
+          "addiu      %[ptr1],        %[ptr1],        16          \n\t"
+          : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+            [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp6] "=&r"(temp6),
+            [temp7] "=&r"(temp7), [temp8] "=&r"(temp8), [ptr1] "+r"(ptr1)
+          :
+          : "memory", "hi", "lo");
     }
-    for(i = 0; i < (PART_LEN1 & 7); i++) {
-      __asm __volatile (
-        "lh         %[temp1],       0(%[ptr1])                  \n\t"
-        "mul        %[temp1],       %[temp1],       %[temp1]    \n\t"
-        "sra        %[temp1],       %[temp1],       14          \n\t"
-        "sh         %[temp1],       0(%[ptr1])                  \n\t"
-        "addiu      %[ptr1],        %[ptr1],        2           \n\t"
-        : [temp1] "=&r" (temp1), [ptr1] "+r" (ptr1)
-        :
-        : "memory", "hi", "lo"
-      );
+    for (i = 0; i < (PART_LEN1 & 7); i++) {
+      __asm __volatile(
+          "lh         %[temp1],       0(%[ptr1])                  \n\t"
+          "mul        %[temp1],       %[temp1],       %[temp1]    \n\t"
+          "sra        %[temp1],       %[temp1],       14          \n\t"
+          "sh         %[temp1],       0(%[ptr1])                  \n\t"
+          "addiu      %[ptr1],        %[ptr1],        2           \n\t"
+          : [temp1] "=&r"(temp1), [ptr1] "+r"(ptr1)
+          :
+          : "memory", "hi", "lo");
     }
 
     for (i = kMinPrefBand; i <= kMaxPrefBand; i++) {
@@ -1141,102 +1244,95 @@
     } else {
       for (i = 0; i < PART_LEN1; i++) {
 #if defined(MIPS_DSP_R1_LE)
-        __asm __volatile (
-          ".set       push                                        \n\t"
-          ".set       noreorder                                   \n\t"
-          "lh         %[temp1],       0(%[ptr])                   \n\t"
-          "lh         %[temp2],       0(%[dr_ptr])                \n\t"
-          "slti       %[temp4],       %[temp1],       0x4001      \n\t"
-          "beqz       %[temp4],       3f                          \n\t"
-          " lh        %[temp3],       2(%[dr_ptr])                \n\t"
-          "slti       %[temp5],       %[temp1],       3277        \n\t"
-          "bnez       %[temp5],       2f                          \n\t"
-          " addiu     %[dr_ptr],      %[dr_ptr],      4           \n\t"
-          "mul        %[temp2],       %[temp2],       %[temp1]    \n\t"
-          "mul        %[temp3],       %[temp3],       %[temp1]    \n\t"
-          "shra_r.w   %[temp2],       %[temp2],       14          \n\t"
-          "shra_r.w   %[temp3],       %[temp3],       14          \n\t"
-          "b          4f                                          \n\t"
-          " nop                                                   \n\t"
-         "2:                                                      \n\t"
-          "addu       %[temp1],       $zero,          $zero       \n\t"
-          "addu       %[temp2],       $zero,          $zero       \n\t"
-          "addu       %[temp3],       $zero,          $zero       \n\t"
-          "b          1f                                          \n\t"
-          " nop                                                   \n\t"
-         "3:                                                      \n\t"
-          "addiu      %[temp1],       $0,             0x4000      \n\t"
-         "1:                                                      \n\t"
-          "sh         %[temp1],       0(%[ptr])                   \n\t"
-         "4:                                                      \n\t"
-          "sh         %[temp2],       0(%[er_ptr])                \n\t"
-          "sh         %[temp3],       2(%[er_ptr])                \n\t"
-          "addiu      %[ptr],         %[ptr],         2           \n\t"
-          "addiu      %[er_ptr],      %[er_ptr],      4           \n\t"
-          ".set       pop                                         \n\t"
-          : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
-            [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [ptr] "+r" (ptr),
-            [er_ptr] "+r" (er_ptr), [dr_ptr] "+r" (dr_ptr)
-          :
-          : "memory", "hi", "lo"
-        );
+        __asm __volatile(
+            ".set       push                                        \n\t"
+            ".set       noreorder                                   \n\t"
+            "lh         %[temp1],       0(%[ptr])                   \n\t"
+            "lh         %[temp2],       0(%[dr_ptr])                \n\t"
+            "slti       %[temp4],       %[temp1],       0x4001      \n\t"
+            "beqz       %[temp4],       3f                          \n\t"
+            " lh        %[temp3],       2(%[dr_ptr])                \n\t"
+            "slti       %[temp5],       %[temp1],       3277        \n\t"
+            "bnez       %[temp5],       2f                          \n\t"
+            " addiu     %[dr_ptr],      %[dr_ptr],      4           \n\t"
+            "mul        %[temp2],       %[temp2],       %[temp1]    \n\t"
+            "mul        %[temp3],       %[temp3],       %[temp1]    \n\t"
+            "shra_r.w   %[temp2],       %[temp2],       14          \n\t"
+            "shra_r.w   %[temp3],       %[temp3],       14          \n\t"
+            "b          4f                                          \n\t"
+            " nop                                                   \n\t"
+            "2:                                                      \n\t"
+            "addu       %[temp1],       $zero,          $zero       \n\t"
+            "addu       %[temp2],       $zero,          $zero       \n\t"
+            "addu       %[temp3],       $zero,          $zero       \n\t"
+            "b          1f                                          \n\t"
+            " nop                                                   \n\t"
+            "3:                                                      \n\t"
+            "addiu      %[temp1],       $0,             0x4000      \n\t"
+            "1:                                                      \n\t"
+            "sh         %[temp1],       0(%[ptr])                   \n\t"
+            "4:                                                      \n\t"
+            "sh         %[temp2],       0(%[er_ptr])                \n\t"
+            "sh         %[temp3],       2(%[er_ptr])                \n\t"
+            "addiu      %[ptr],         %[ptr],         2           \n\t"
+            "addiu      %[er_ptr],      %[er_ptr],      4           \n\t"
+            ".set       pop                                         \n\t"
+            : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+              [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [ptr] "+r"(ptr),
+              [er_ptr] "+r"(er_ptr), [dr_ptr] "+r"(dr_ptr)
+            :
+            : "memory", "hi", "lo");
 #else
-        __asm __volatile (
-          ".set       push                                        \n\t"
-          ".set       noreorder                                   \n\t"
-          "lh         %[temp1],       0(%[ptr])                   \n\t"
-          "lh         %[temp2],       0(%[dr_ptr])                \n\t"
-          "slti       %[temp4],       %[temp1],       0x4001      \n\t"
-          "beqz       %[temp4],       3f                          \n\t"
-          " lh        %[temp3],       2(%[dr_ptr])                \n\t"
-          "slti       %[temp5],       %[temp1],       3277        \n\t"
-          "bnez       %[temp5],       2f                          \n\t"
-          " addiu     %[dr_ptr],      %[dr_ptr],      4           \n\t"
-          "mul        %[temp2],       %[temp2],       %[temp1]    \n\t"
-          "mul        %[temp3],       %[temp3],       %[temp1]    \n\t"
-          "addiu      %[temp2],       %[temp2],       0x2000      \n\t"
-          "addiu      %[temp3],       %[temp3],       0x2000      \n\t"
-          "sra        %[temp2],       %[temp2],       14          \n\t"
-          "sra        %[temp3],       %[temp3],       14          \n\t"
-          "b          4f                                          \n\t"
-          " nop                                                   \n\t"
-         "2:                                                      \n\t"
-          "addu       %[temp1],       $zero,          $zero       \n\t"
-          "addu       %[temp2],       $zero,          $zero       \n\t"
-          "addu       %[temp3],       $zero,          $zero       \n\t"
-          "b          1f                                          \n\t"
-          " nop                                                   \n\t"
-         "3:                                                      \n\t"
-          "addiu      %[temp1],       $0,             0x4000      \n\t"
-         "1:                                                      \n\t"
-          "sh         %[temp1],       0(%[ptr])                   \n\t"
-         "4:                                                      \n\t"
-          "sh         %[temp2],       0(%[er_ptr])                \n\t"
-          "sh         %[temp3],       2(%[er_ptr])                \n\t"
-          "addiu      %[ptr],         %[ptr],         2           \n\t"
-          "addiu      %[er_ptr],      %[er_ptr],      4           \n\t"
-          ".set       pop                                         \n\t"
-          : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
-            [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [ptr] "+r" (ptr),
-            [er_ptr] "+r" (er_ptr), [dr_ptr] "+r" (dr_ptr)
-          :
-          : "memory", "hi", "lo"
-        );
+        __asm __volatile(
+            ".set       push                                        \n\t"
+            ".set       noreorder                                   \n\t"
+            "lh         %[temp1],       0(%[ptr])                   \n\t"
+            "lh         %[temp2],       0(%[dr_ptr])                \n\t"
+            "slti       %[temp4],       %[temp1],       0x4001      \n\t"
+            "beqz       %[temp4],       3f                          \n\t"
+            " lh        %[temp3],       2(%[dr_ptr])                \n\t"
+            "slti       %[temp5],       %[temp1],       3277        \n\t"
+            "bnez       %[temp5],       2f                          \n\t"
+            " addiu     %[dr_ptr],      %[dr_ptr],      4           \n\t"
+            "mul        %[temp2],       %[temp2],       %[temp1]    \n\t"
+            "mul        %[temp3],       %[temp3],       %[temp1]    \n\t"
+            "addiu      %[temp2],       %[temp2],       0x2000      \n\t"
+            "addiu      %[temp3],       %[temp3],       0x2000      \n\t"
+            "sra        %[temp2],       %[temp2],       14          \n\t"
+            "sra        %[temp3],       %[temp3],       14          \n\t"
+            "b          4f                                          \n\t"
+            " nop                                                   \n\t"
+            "2:                                                      \n\t"
+            "addu       %[temp1],       $zero,          $zero       \n\t"
+            "addu       %[temp2],       $zero,          $zero       \n\t"
+            "addu       %[temp3],       $zero,          $zero       \n\t"
+            "b          1f                                          \n\t"
+            " nop                                                   \n\t"
+            "3:                                                      \n\t"
+            "addiu      %[temp1],       $0,             0x4000      \n\t"
+            "1:                                                      \n\t"
+            "sh         %[temp1],       0(%[ptr])                   \n\t"
+            "4:                                                      \n\t"
+            "sh         %[temp2],       0(%[er_ptr])                \n\t"
+            "sh         %[temp3],       2(%[er_ptr])                \n\t"
+            "addiu      %[ptr],         %[ptr],         2           \n\t"
+            "addiu      %[er_ptr],      %[er_ptr],      4           \n\t"
+            ".set       pop                                         \n\t"
+            : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+              [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [ptr] "+r"(ptr),
+              [er_ptr] "+r"(er_ptr), [dr_ptr] "+r"(dr_ptr)
+            :
+            : "memory", "hi", "lo");
 #endif
       }
     }
-  }
-  else {
+  } else {
     // multiply with Wiener coefficients
     for (i = 0; i < PART_LEN1; i++) {
-      efw[i].real = (int16_t)
-                      (WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
-                                                            hnl[i],
-                                                            14));
-      efw[i].imag = (int16_t)
-                      (WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
-                                                            hnl[i],
-                                                            14));
+      efw[i].real = (int16_t)(
+          WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14));
+      efw[i].imag = (int16_t)(
+          WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14));
     }
   }
 
@@ -1284,26 +1380,25 @@
   // Generate a uniform random array on [0 2^15-1].
   WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
   int16_t* randW16p = (int16_t*)randW16;
-#if defined (MIPS_DSP_R1_LE)
+#if defined(MIPS_DSP_R1_LE)
   int16_t* kCosTablep = (int16_t*)WebRtcAecm_kCosTable;
   int16_t* kSinTablep = (int16_t*)WebRtcAecm_kSinTable;
-#endif   // #if defined(MIPS_DSP_R1_LE)
+#endif  // #if defined(MIPS_DSP_R1_LE)
   tmp1 = (int32_t*)aecm->noiseEst + 1;
   dfap = (int16_t*)dfa + 1;
   lambdap = (int16_t*)lambda + 1;
   // Estimate noise power.
-  for (i = 1; i < PART_LEN1; i+=2) {
-  // Shift to the noise domain.
-    __asm __volatile (
-      "lh     %[tmp32],       0(%[dfap])                              \n\t"
-      "lw     %[tnoise],      0(%[tmp1])                              \n\t"
-      "sllv   %[outLShift32], %[tmp32],   %[shiftFromNearToNoise]     \n\t"
-      : [tmp32] "=&r" (tmp32), [outLShift32] "=r" (outLShift32),
-        [tnoise] "=&r" (tnoise)
-      : [tmp1] "r" (tmp1), [dfap] "r" (dfap),
-        [shiftFromNearToNoise] "r" (shiftFromNearToNoise)
-      : "memory"
-    );
+  for (i = 1; i < PART_LEN1; i += 2) {
+    // Shift to the noise domain.
+    __asm __volatile(
+        "lh     %[tmp32],       0(%[dfap])                              \n\t"
+        "lw     %[tnoise],      0(%[tmp1])                              \n\t"
+        "sllv   %[outLShift32], %[tmp32],   %[shiftFromNearToNoise]     \n\t"
+        : [tmp32] "=&r"(tmp32), [outLShift32] "=r"(outLShift32),
+          [tnoise] "=&r"(tnoise)
+        : [tmp1] "r"(tmp1), [dfap] "r"(dfap),
+          [shiftFromNearToNoise] "r"(shiftFromNearToNoise)
+        : "memory");
 
     if (outLShift32 < tnoise) {
       // Reset "too low" counter
@@ -1319,13 +1414,13 @@
           aecm->noiseEstTooHighCtr[i] = 0;  // Reset the counter
         }
       } else {
-        __asm __volatile (
-          "subu   %[tmp32],       %[tnoise],      %[outLShift32]      \n\t"
-          "srav   %[tmp32],       %[tmp32],       %[minTrackShift]    \n\t"
-          "subu   %[tnoise],      %[tnoise],      %[tmp32]            \n\t"
-          : [tmp32] "=&r" (tmp32), [tnoise] "+r" (tnoise)
-          : [outLShift32] "r" (outLShift32), [minTrackShift] "r" (minTrackShift)
-        );
+        __asm __volatile(
+            "subu   %[tmp32],       %[tnoise],      %[outLShift32]      \n\t"
+            "srav   %[tmp32],       %[tmp32],       %[minTrackShift]    \n\t"
+            "subu   %[tnoise],      %[tnoise],      %[tmp32]            \n\t"
+            : [tmp32] "=&r"(tmp32), [tnoise] "+r"(tnoise)
+            :
+            [outLShift32] "r"(outLShift32), [minTrackShift] "r"(minTrackShift));
       }
     } else {
       // Reset "too high" counter
@@ -1334,53 +1429,49 @@
       if ((tnoise >> 19) <= 0) {
         if ((tnoise >> 11) > 0) {
           // Large enough for relative increase
-          __asm __volatile (
-            "mul    %[tnoise],  %[tnoise],  %[c2049]    \n\t"
-            "sra    %[tnoise],  %[tnoise],  11          \n\t"
-            : [tnoise] "+r" (tnoise)
-            : [c2049] "r" (c2049)
-            : "hi", "lo"
-          );
+          __asm __volatile(
+              "mul    %[tnoise],  %[tnoise],  %[c2049]    \n\t"
+              "sra    %[tnoise],  %[tnoise],  11          \n\t"
+              : [tnoise] "+r"(tnoise)
+              : [c2049] "r"(c2049)
+              : "hi", "lo");
         } else {
           // Make incremental increases based on size every
           // |kNoiseEstIncCount| block
           aecm->noiseEstTooLowCtr[i]++;
           if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) {
-            __asm __volatile (
-              "sra    %[tmp32],   %[tnoise],  9           \n\t"
-              "addi   %[tnoise],  %[tnoise],  1           \n\t"
-              "addu   %[tnoise],  %[tnoise],  %[tmp32]    \n\t"
-              : [tnoise] "+r" (tnoise), [tmp32] "=&r" (tmp32)
-              :
-            );
-            aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
+            __asm __volatile(
+                "sra    %[tmp32],   %[tnoise],  9           \n\t"
+                "addi   %[tnoise],  %[tnoise],  1           \n\t"
+                "addu   %[tnoise],  %[tnoise],  %[tmp32]    \n\t"
+                : [tnoise] "+r"(tnoise), [tmp32] "=&r"(tmp32)
+                :);
+            aecm->noiseEstTooLowCtr[i] = 0;  // Reset counter
           }
         }
       } else {
         // Avoid overflow.
         // Multiplication with 2049 will cause wrap around. Scale
         // down first and then multiply
-        __asm __volatile (
-          "sra    %[tnoise],  %[tnoise],  11          \n\t"
-          "mul    %[tnoise],  %[tnoise],  %[c2049]    \n\t"
-          : [tnoise] "+r" (tnoise)
-          : [c2049] "r" (c2049)
-          : "hi", "lo"
-        );
+        __asm __volatile(
+            "sra    %[tnoise],  %[tnoise],  11          \n\t"
+            "mul    %[tnoise],  %[tnoise],  %[c2049]    \n\t"
+            : [tnoise] "+r"(tnoise)
+            : [c2049] "r"(c2049)
+            : "hi", "lo");
       }
     }
 
     // Shift to the noise domain.
-    __asm __volatile (
-      "lh     %[tmp32],       2(%[dfap])                              \n\t"
-      "lw     %[tnoise1],     4(%[tmp1])                              \n\t"
-      "addiu  %[dfap],        %[dfap],    4                           \n\t"
-      "sllv   %[outLShift32], %[tmp32],   %[shiftFromNearToNoise]     \n\t"
-      : [tmp32] "=&r" (tmp32), [dfap] "+r" (dfap),
-        [outLShift32] "=r" (outLShift32), [tnoise1] "=&r" (tnoise1)
-      : [tmp1] "r" (tmp1), [shiftFromNearToNoise] "r" (shiftFromNearToNoise)
-      : "memory"
-    );
+    __asm __volatile(
+        "lh     %[tmp32],       2(%[dfap])                              \n\t"
+        "lw     %[tnoise1],     4(%[tmp1])                              \n\t"
+        "addiu  %[dfap],        %[dfap],    4                           \n\t"
+        "sllv   %[outLShift32], %[tmp32],   %[shiftFromNearToNoise]     \n\t"
+        : [tmp32] "=&r"(tmp32), [dfap] "+r"(dfap),
+          [outLShift32] "=r"(outLShift32), [tnoise1] "=&r"(tnoise1)
+        : [tmp1] "r"(tmp1), [shiftFromNearToNoise] "r"(shiftFromNearToNoise)
+        : "memory");
 
     if (outLShift32 < tnoise1) {
       // Reset "too low" counter
@@ -1393,16 +1484,16 @@
         aecm->noiseEstTooHighCtr[i + 1]++;
         if (aecm->noiseEstTooHighCtr[i + 1] >= kNoiseEstIncCount) {
           tnoise1--;
-          aecm->noiseEstTooHighCtr[i + 1] = 0; // Reset the counter
+          aecm->noiseEstTooHighCtr[i + 1] = 0;  // Reset the counter
         }
       } else {
-        __asm __volatile (
-          "subu   %[tmp32],       %[tnoise1],     %[outLShift32]      \n\t"
-          "srav   %[tmp32],       %[tmp32],       %[minTrackShift]    \n\t"
-          "subu   %[tnoise1],     %[tnoise1],     %[tmp32]            \n\t"
-          : [tmp32] "=&r" (tmp32), [tnoise1] "+r" (tnoise1)
-          : [outLShift32] "r" (outLShift32), [minTrackShift] "r" (minTrackShift)
-        );
+        __asm __volatile(
+            "subu   %[tmp32],       %[tnoise1],     %[outLShift32]      \n\t"
+            "srav   %[tmp32],       %[tmp32],       %[minTrackShift]    \n\t"
+            "subu   %[tnoise1],     %[tnoise1],     %[tmp32]            \n\t"
+            : [tmp32] "=&r"(tmp32), [tnoise1] "+r"(tnoise1)
+            :
+            [outLShift32] "r"(outLShift32), [minTrackShift] "r"(minTrackShift));
       }
     } else {
       // Reset "too high" counter
@@ -1411,59 +1502,55 @@
       if ((tnoise1 >> 19) <= 0) {
         if ((tnoise1 >> 11) > 0) {
           // Large enough for relative increase
-          __asm __volatile (
-            "mul    %[tnoise1], %[tnoise1], %[c2049]   \n\t"
-            "sra    %[tnoise1], %[tnoise1], 11         \n\t"
-            : [tnoise1] "+r" (tnoise1)
-            : [c2049] "r" (c2049)
-            : "hi", "lo"
-          );
+          __asm __volatile(
+              "mul    %[tnoise1], %[tnoise1], %[c2049]   \n\t"
+              "sra    %[tnoise1], %[tnoise1], 11         \n\t"
+              : [tnoise1] "+r"(tnoise1)
+              : [c2049] "r"(c2049)
+              : "hi", "lo");
         } else {
           // Make incremental increases based on size every
           // |kNoiseEstIncCount| block
           aecm->noiseEstTooLowCtr[i + 1]++;
           if (aecm->noiseEstTooLowCtr[i + 1] >= kNoiseEstIncCount) {
-            __asm __volatile (
-              "sra    %[tmp32],   %[tnoise1], 9           \n\t"
-              "addi   %[tnoise1], %[tnoise1], 1           \n\t"
-              "addu   %[tnoise1], %[tnoise1], %[tmp32]    \n\t"
-              : [tnoise1] "+r" (tnoise1), [tmp32] "=&r" (tmp32)
-              :
-            );
-            aecm->noiseEstTooLowCtr[i + 1] = 0; // Reset counter
+            __asm __volatile(
+                "sra    %[tmp32],   %[tnoise1], 9           \n\t"
+                "addi   %[tnoise1], %[tnoise1], 1           \n\t"
+                "addu   %[tnoise1], %[tnoise1], %[tmp32]    \n\t"
+                : [tnoise1] "+r"(tnoise1), [tmp32] "=&r"(tmp32)
+                :);
+            aecm->noiseEstTooLowCtr[i + 1] = 0;  // Reset counter
           }
         }
       } else {
         // Avoid overflow.
         // Multiplication with 2049 will cause wrap around. Scale
         // down first and then multiply
-        __asm __volatile (
-          "sra    %[tnoise1], %[tnoise1], 11          \n\t"
-          "mul    %[tnoise1], %[tnoise1], %[c2049]    \n\t"
-          : [tnoise1] "+r" (tnoise1)
-          : [c2049] "r" (c2049)
-          : "hi", "lo"
-        );
+        __asm __volatile(
+            "sra    %[tnoise1], %[tnoise1], 11          \n\t"
+            "mul    %[tnoise1], %[tnoise1], %[c2049]    \n\t"
+            : [tnoise1] "+r"(tnoise1)
+            : [c2049] "r"(c2049)
+            : "hi", "lo");
       }
     }
 
-    __asm __volatile (
-      "lh     %[tmp16],   0(%[lambdap])                           \n\t"
-      "lh     %[tmp161],  2(%[lambdap])                           \n\t"
-      "sw     %[tnoise],  0(%[tmp1])                              \n\t"
-      "sw     %[tnoise1], 4(%[tmp1])                              \n\t"
-      "subu   %[tmp16],   %[c114],        %[tmp16]                \n\t"
-      "subu   %[tmp161],  %[c114],        %[tmp161]               \n\t"
-      "srav   %[tmp32],   %[tnoise],      %[shiftFromNearToNoise] \n\t"
-      "srav   %[tmp321],  %[tnoise1],     %[shiftFromNearToNoise] \n\t"
-      "addiu  %[lambdap], %[lambdap],     4                       \n\t"
-      "addiu  %[tmp1],    %[tmp1],        8                       \n\t"
-      : [tmp16] "=&r" (tmp16), [tmp161] "=&r" (tmp161), [tmp1] "+r" (tmp1),
-        [tmp32] "=&r" (tmp32), [tmp321] "=&r" (tmp321), [lambdap] "+r" (lambdap)
-      : [tnoise] "r" (tnoise), [tnoise1] "r" (tnoise1), [c114] "r" (c114),
-        [shiftFromNearToNoise] "r" (shiftFromNearToNoise)
-      : "memory"
-    );
+    __asm __volatile(
+        "lh     %[tmp16],   0(%[lambdap])                           \n\t"
+        "lh     %[tmp161],  2(%[lambdap])                           \n\t"
+        "sw     %[tnoise],  0(%[tmp1])                              \n\t"
+        "sw     %[tnoise1], 4(%[tmp1])                              \n\t"
+        "subu   %[tmp16],   %[c114],        %[tmp16]                \n\t"
+        "subu   %[tmp161],  %[c114],        %[tmp161]               \n\t"
+        "srav   %[tmp32],   %[tnoise],      %[shiftFromNearToNoise] \n\t"
+        "srav   %[tmp321],  %[tnoise1],     %[shiftFromNearToNoise] \n\t"
+        "addiu  %[lambdap], %[lambdap],     4                       \n\t"
+        "addiu  %[tmp1],    %[tmp1],        8                       \n\t"
+        : [tmp16] "=&r"(tmp16), [tmp161] "=&r"(tmp161), [tmp1] "+r"(tmp1),
+          [tmp32] "=&r"(tmp32), [tmp321] "=&r"(tmp321), [lambdap] "+r"(lambdap)
+        : [tnoise] "r"(tnoise), [tnoise1] "r"(tnoise1), [c114] "r"(c114),
+          [shiftFromNearToNoise] "r"(shiftFromNearToNoise)
+        : "memory");
 
     if (tmp32 > 32767) {
       tmp32 = 32767;
@@ -1471,33 +1558,31 @@
     }
     if (tmp321 > 32767) {
       tmp321 = 32767;
-      aecm->noiseEst[i+1] = tmp321 << shiftFromNearToNoise;
+      aecm->noiseEst[i + 1] = tmp321 << shiftFromNearToNoise;
     }
 
-    __asm __volatile (
-      "mul    %[tmp32],   %[tmp32],       %[tmp16]                \n\t"
-      "mul    %[tmp321],  %[tmp321],      %[tmp161]               \n\t"
-      "sra    %[nrsh1],   %[tmp32],       14                      \n\t"
-      "sra    %[nrsh2],   %[tmp321],      14                      \n\t"
-      : [nrsh1] "=&r" (nrsh1), [nrsh2] "=r" (nrsh2)
-      : [tmp16] "r" (tmp16), [tmp161] "r" (tmp161), [tmp32] "r" (tmp32),
-        [tmp321] "r" (tmp321)
-      : "memory", "hi", "lo"
-    );
+    __asm __volatile(
+        "mul    %[tmp32],   %[tmp32],       %[tmp16]                \n\t"
+        "mul    %[tmp321],  %[tmp321],      %[tmp161]               \n\t"
+        "sra    %[nrsh1],   %[tmp32],       14                      \n\t"
+        "sra    %[nrsh2],   %[tmp321],      14                      \n\t"
+        : [nrsh1] "=&r"(nrsh1), [nrsh2] "=r"(nrsh2)
+        : [tmp16] "r"(tmp16), [tmp161] "r"(tmp161), [tmp32] "r"(tmp32),
+          [tmp321] "r"(tmp321)
+        : "memory", "hi", "lo");
 
-    __asm __volatile (
-      "lh     %[tmp32],       0(%[randW16p])              \n\t"
-      "lh     %[tmp321],      2(%[randW16p])              \n\t"
-      "addiu  %[randW16p],    %[randW16p],    4           \n\t"
-      "mul    %[tmp32],       %[tmp32],       %[c359]     \n\t"
-      "mul    %[tmp321],      %[tmp321],      %[c359]     \n\t"
-      "sra    %[tmp16],       %[tmp32],       15          \n\t"
-      "sra    %[tmp161],      %[tmp321],      15          \n\t"
-      : [randW16p] "+r" (randW16p), [tmp32] "=&r" (tmp32),
-        [tmp16] "=r" (tmp16), [tmp161] "=r" (tmp161), [tmp321] "=&r" (tmp321)
-      : [c359] "r" (c359)
-      : "memory", "hi", "lo"
-    );
+    __asm __volatile(
+        "lh     %[tmp32],       0(%[randW16p])              \n\t"
+        "lh     %[tmp321],      2(%[randW16p])              \n\t"
+        "addiu  %[randW16p],    %[randW16p],    4           \n\t"
+        "mul    %[tmp32],       %[tmp32],       %[c359]     \n\t"
+        "mul    %[tmp321],      %[tmp321],      %[c359]     \n\t"
+        "sra    %[tmp16],       %[tmp32],       15          \n\t"
+        "sra    %[tmp161],      %[tmp321],      15          \n\t"
+        : [randW16p] "+r"(randW16p), [tmp32] "=&r"(tmp32), [tmp16] "=r"(tmp16),
+          [tmp161] "=r"(tmp161), [tmp321] "=&r"(tmp321)
+        : [c359] "r"(c359)
+        : "memory", "hi", "lo");
 
 #if !defined(MIPS_DSP_R1_LE)
     tmp32 = WebRtcAecm_kCosTable[tmp16];
@@ -1505,36 +1590,34 @@
     tmp322 = WebRtcAecm_kCosTable[tmp161];
     tmp323 = WebRtcAecm_kSinTable[tmp161];
 #else
-    __asm __volatile (
-      "sll    %[tmp16],       %[tmp16],                   1           \n\t"
-      "sll    %[tmp161],      %[tmp161],                  1           \n\t"
-      "lhx    %[tmp32],       %[tmp16](%[kCosTablep])                 \n\t"
-      "lhx    %[tmp321],      %[tmp16](%[kSinTablep])                 \n\t"
-      "lhx    %[tmp322],      %[tmp161](%[kCosTablep])                \n\t"
-      "lhx    %[tmp323],      %[tmp161](%[kSinTablep])                \n\t"
-      : [tmp32] "=&r" (tmp32), [tmp321] "=&r" (tmp321),
-        [tmp322] "=&r" (tmp322), [tmp323] "=&r" (tmp323)
-      : [kCosTablep] "r" (kCosTablep), [tmp16] "r" (tmp16),
-        [tmp161] "r" (tmp161), [kSinTablep] "r" (kSinTablep)
-      : "memory"
-    );
+    __asm __volatile(
+        "sll    %[tmp16],       %[tmp16],                   1           \n\t"
+        "sll    %[tmp161],      %[tmp161],                  1           \n\t"
+        "lhx    %[tmp32],       %[tmp16](%[kCosTablep])                 \n\t"
+        "lhx    %[tmp321],      %[tmp16](%[kSinTablep])                 \n\t"
+        "lhx    %[tmp322],      %[tmp161](%[kCosTablep])                \n\t"
+        "lhx    %[tmp323],      %[tmp161](%[kSinTablep])                \n\t"
+        : [tmp32] "=&r"(tmp32), [tmp321] "=&r"(tmp321), [tmp322] "=&r"(tmp322),
+          [tmp323] "=&r"(tmp323)
+        : [kCosTablep] "r"(kCosTablep), [tmp16] "r"(tmp16),
+          [tmp161] "r"(tmp161), [kSinTablep] "r"(kSinTablep)
+        : "memory");
 #endif
-    __asm __volatile (
-      "mul    %[tmp32],       %[tmp32],                   %[nrsh1]    \n\t"
-      "negu   %[tmp162],      %[nrsh1]                                \n\t"
-      "mul    %[tmp322],      %[tmp322],                  %[nrsh2]    \n\t"
-      "negu   %[tmp163],      %[nrsh2]                                \n\t"
-      "sra    %[tmp32],       %[tmp32],                   13          \n\t"
-      "mul    %[tmp321],      %[tmp321],                  %[tmp162]   \n\t"
-      "sra    %[tmp322],      %[tmp322],                  13          \n\t"
-      "mul    %[tmp323],      %[tmp323],                  %[tmp163]   \n\t"
-      "sra    %[tmp321],      %[tmp321],                  13          \n\t"
-      "sra    %[tmp323],      %[tmp323],                  13          \n\t"
-      : [tmp32] "+r" (tmp32), [tmp321] "+r" (tmp321), [tmp162] "=&r" (tmp162),
-        [tmp322] "+r" (tmp322), [tmp323] "+r" (tmp323), [tmp163] "=&r" (tmp163)
-      : [nrsh1] "r" (nrsh1), [nrsh2] "r" (nrsh2)
-      : "hi", "lo"
-    );
+    __asm __volatile(
+        "mul    %[tmp32],       %[tmp32],                   %[nrsh1]    \n\t"
+        "negu   %[tmp162],      %[nrsh1]                                \n\t"
+        "mul    %[tmp322],      %[tmp322],                  %[nrsh2]    \n\t"
+        "negu   %[tmp163],      %[nrsh2]                                \n\t"
+        "sra    %[tmp32],       %[tmp32],                   13          \n\t"
+        "mul    %[tmp321],      %[tmp321],                  %[tmp162]   \n\t"
+        "sra    %[tmp322],      %[tmp322],                  13          \n\t"
+        "mul    %[tmp323],      %[tmp323],                  %[tmp163]   \n\t"
+        "sra    %[tmp321],      %[tmp321],                  13          \n\t"
+        "sra    %[tmp323],      %[tmp323],                  13          \n\t"
+        : [tmp32] "+r"(tmp32), [tmp321] "+r"(tmp321), [tmp162] "=&r"(tmp162),
+          [tmp322] "+r"(tmp322), [tmp323] "+r"(tmp323), [tmp163] "=&r"(tmp163)
+        : [nrsh1] "r"(nrsh1), [nrsh2] "r"(nrsh2)
+        : "hi", "lo");
     // Tables are in Q13.
     uReal[i] = (int16_t)tmp32;
     uImag[i] = (int16_t)tmp321;
diff --git a/modules/audio_processing/aecm/aecm_core_neon.cc b/modules/audio_processing/aecm/aecm_core_neon.cc
index ca7211f..a2153a2 100644
--- a/modules/audio_processing/aecm/aecm_core_neon.cc
+++ b/modules/audio_processing/aecm/aecm_core_neon.cc
@@ -77,12 +77,12 @@
     echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v);
     echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v);
 
-    echo_adapt_v = vmlal_u16(echo_adapt_v,
-                             vreinterpret_u16_s16(vget_low_s16(adapt_v)),
-                             vget_low_u16(spectrum_v));
-    echo_adapt_v = vmlal_u16(echo_adapt_v,
-                             vreinterpret_u16_s16(vget_high_s16(adapt_v)),
-                             vget_high_u16(spectrum_v));
+    echo_adapt_v =
+        vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_low_s16(adapt_v)),
+                  vget_low_u16(spectrum_v));
+    echo_adapt_v =
+        vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_high_s16(adapt_v)),
+                  vget_high_u16(spectrum_v));
 
     start_stored_p += 8;
     start_adapt_p += 8;
diff --git a/modules/audio_processing/aecm/aecm_defines.h b/modules/audio_processing/aecm/aecm_defines.h
index ae2d2bc..5805549 100644
--- a/modules/audio_processing/aecm/aecm_defines.h
+++ b/modules/audio_processing/aecm/aecm_defines.h
@@ -11,77 +11,77 @@
 #ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
 #define MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
 
-#define AECM_DYNAMIC_Q                 /* Turn on/off dynamic Q-domain. */
+#define AECM_DYNAMIC_Q /* Turn on/off dynamic Q-domain. */
 
 /* Algorithm parameters */
-#define FRAME_LEN       80             /* Total frame length, 10 ms. */
+#define FRAME_LEN 80 /* Total frame length, 10 ms. */
 
-#define PART_LEN        64             /* Length of partition. */
-#define PART_LEN_SHIFT  7              /* Length of (PART_LEN * 2) in base 2. */
+#define PART_LEN 64      /* Length of partition. */
+#define PART_LEN_SHIFT 7 /* Length of (PART_LEN * 2) in base 2. */
 
-#define PART_LEN1       (PART_LEN + 1)  /* Unique fft coefficients. */
-#define PART_LEN2       (PART_LEN << 1) /* Length of partition * 2. */
-#define PART_LEN4       (PART_LEN << 2) /* Length of partition * 4. */
-#define FAR_BUF_LEN     PART_LEN4       /* Length of buffers. */
-#define MAX_DELAY       100
+#define PART_LEN1 (PART_LEN + 1)  /* Unique fft coefficients. */
+#define PART_LEN2 (PART_LEN << 1) /* Length of partition * 2. */
+#define PART_LEN4 (PART_LEN << 2) /* Length of partition * 4. */
+#define FAR_BUF_LEN PART_LEN4     /* Length of buffers. */
+#define MAX_DELAY 100
 
 /* Counter parameters */
-#define CONV_LEN        512          /* Convergence length used at startup. */
-#define CONV_LEN2       (CONV_LEN << 1) /* Used at startup. */
+#define CONV_LEN 512              /* Convergence length used at startup. */
+#define CONV_LEN2 (CONV_LEN << 1) /* Used at startup. */
 
 /* Energy parameters */
-#define MAX_BUF_LEN     64           /* History length of energy signals. */
-#define FAR_ENERGY_MIN  1025         /* Lowest Far energy level: At least 2 */
-                                     /* in energy. */
-#define FAR_ENERGY_DIFF 929          /* Allowed difference between max */
-                                     /* and min. */
-#define ENERGY_DEV_OFFSET       0    /* The energy error offset in Q8. */
-#define ENERGY_DEV_TOL  400          /* The energy estimation tolerance (Q8). */
-#define FAR_ENERGY_VAD_REGION   230  /* Far VAD tolerance region. */
+#define MAX_BUF_LEN 64            /* History length of energy signals. */
+#define FAR_ENERGY_MIN 1025       /* Lowest Far energy level: At least 2 */
+                                  /* in energy. */
+#define FAR_ENERGY_DIFF 929       /* Allowed difference between max */
+                                  /* and min. */
+#define ENERGY_DEV_OFFSET 0       /* The energy error offset in Q8. */
+#define ENERGY_DEV_TOL 400        /* The energy estimation tolerance (Q8). */
+#define FAR_ENERGY_VAD_REGION 230 /* Far VAD tolerance region. */
 
 /* Stepsize parameters */
-#define MU_MIN          10          /* Min stepsize 2^-MU_MIN (far end energy */
-                                    /* dependent). */
-#define MU_MAX          1           /* Max stepsize 2^-MU_MAX (far end energy */
-                                    /* dependent). */
-#define MU_DIFF         9           /* MU_MIN - MU_MAX */
+#define MU_MIN 10 /* Min stepsize 2^-MU_MIN (far end energy */
+                  /* dependent). */
+#define MU_MAX 1  /* Max stepsize 2^-MU_MAX (far end energy */
+                  /* dependent). */
+#define MU_DIFF 9 /* MU_MIN - MU_MAX */
 
 /* Channel parameters */
-#define MIN_MSE_COUNT   20 /* Min number of consecutive blocks with enough */
-                           /* far end energy to compare channel estimates. */
-#define MIN_MSE_DIFF    29 /* The ratio between adapted and stored channel to */
-                           /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */
-#define MSE_RESOLUTION  5           /* MSE parameter resolution. */
-#define RESOLUTION_CHANNEL16    12  /* W16 Channel in Q-RESOLUTION_CHANNEL16. */
-#define RESOLUTION_CHANNEL32    28  /* W32 Channel in Q-RESOLUTION_CHANNEL. */
-#define CHANNEL_VAD     16          /* Minimum energy in frequency band */
-                                    /* to update channel. */
+#define MIN_MSE_COUNT 20 /* Min number of consecutive blocks with enough */
+                         /* far end energy to compare channel estimates. */
+#define MIN_MSE_DIFF 29  /* The ratio between adapted and stored channel to */
+                         /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */
+#define MSE_RESOLUTION 5 /* MSE parameter resolution. */
+#define RESOLUTION_CHANNEL16 12 /* W16 Channel in Q-RESOLUTION_CHANNEL16. */
+#define RESOLUTION_CHANNEL32 28 /* W32 Channel in Q-RESOLUTION_CHANNEL. */
+#define CHANNEL_VAD 16          /* Minimum energy in frequency band */
+                                /* to update channel. */
 
 /* Suppression gain parameters: SUPGAIN parameters in Q-(RESOLUTION_SUPGAIN). */
-#define RESOLUTION_SUPGAIN      8     /* Channel in Q-(RESOLUTION_SUPGAIN). */
-#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN)  /* Default. */
-#define SUPGAIN_ERROR_PARAM_A   3072  /* Estimation error parameter */
-                                      /* (Maximum gain) (8 in Q8). */
-#define SUPGAIN_ERROR_PARAM_B   1536  /* Estimation error parameter */
-                                      /* (Gain before going down). */
-#define SUPGAIN_ERROR_PARAM_D   SUPGAIN_DEFAULT /* Estimation error parameter */
-                                /* (Should be the same as Default) (1 in Q8). */
-#define SUPGAIN_EPC_DT  200     /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */
+#define RESOLUTION_SUPGAIN 8 /* Channel in Q-(RESOLUTION_SUPGAIN). */
+#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) /* Default. */
+#define SUPGAIN_ERROR_PARAM_A 3072            /* Estimation error parameter */
+                                              /* (Maximum gain) (8 in Q8). */
+#define SUPGAIN_ERROR_PARAM_B 1536            /* Estimation error parameter */
+                                              /* (Gain before going down). */
+#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT /* Estimation error parameter */
+/* (Should be the same as Default) (1 in Q8). */
+#define SUPGAIN_EPC_DT 200 /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */
 
 /* Defines for "check delay estimation" */
-#define CORR_WIDTH      31      /* Number of samples to correlate over. */
-#define CORR_MAX        16      /* Maximum correlation offset. */
-#define CORR_MAX_BUF    63
-#define CORR_DEV        4
-#define CORR_MAX_LEVEL  20
-#define CORR_MAX_LOW    4
-#define CORR_BUF_LEN    (CORR_MAX << 1) + 1
+#define CORR_WIDTH 31 /* Number of samples to correlate over. */
+#define CORR_MAX 16   /* Maximum correlation offset. */
+#define CORR_MAX_BUF 63
+#define CORR_DEV 4
+#define CORR_MAX_LEVEL 20
+#define CORR_MAX_LOW 4
+#define CORR_BUF_LEN (CORR_MAX << 1) + 1
 /* Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN. */
 
-#define ONE_Q14         (1 << 14)
+#define ONE_Q14 (1 << 14)
 
 /* NLP defines */
-#define NLP_COMP_LOW    3277    /* 0.2 in Q14 */
-#define NLP_COMP_HIGH   ONE_Q14 /* 1 in Q14 */
+#define NLP_COMP_LOW 3277     /* 0.2 in Q14 */
+#define NLP_COMP_HIGH ONE_Q14 /* 1 in Q14 */
 
 #endif
diff --git a/modules/audio_processing/aecm/echo_control_mobile.cc b/modules/audio_processing/aecm/echo_control_mobile.cc
index 36e2271..c947563 100644
--- a/modules/audio_processing/aecm/echo_control_mobile.cc
+++ b/modules/audio_processing/aecm/echo_control_mobile.cc
@@ -21,56 +21,56 @@
 }
 #include "modules/audio_processing/aecm/aecm_core.h"
 
-#define BUF_SIZE_FRAMES 50 // buffer size (frames)
+#define BUF_SIZE_FRAMES 50  // buffer size (frames)
 // Maximum length of resampled signal. Must be an integer multiple of frames
 // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
 // The factor of 2 handles wb, and the + 1 is as a safety margin
 #define MAX_RESAMP_LEN (5 * FRAME_LEN)
 
-static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
-static const int kSampMsNb = 8; // samples per ms in nb
+static const size_t kBufSizeSamp =
+    BUF_SIZE_FRAMES * FRAME_LEN;  // buffer size (samples)
+static const int kSampMsNb = 8;   // samples per ms in nb
 // Target suppression levels for nlp modes
 // log{0.001, 0.00001, 0.00000001}
 static const int kInitCheck = 42;
 
-typedef struct
-{
-    int sampFreq;
-    int scSampFreq;
-    short bufSizeStart;
-    int knownDelay;
+typedef struct {
+  int sampFreq;
+  int scSampFreq;
+  short bufSizeStart;
+  int knownDelay;
 
-    // Stores the last frame added to the farend buffer
-    short farendOld[2][FRAME_LEN];
-    short initFlag; // indicates if AEC has been initialized
+  // Stores the last frame added to the farend buffer
+  short farendOld[2][FRAME_LEN];
+  short initFlag;  // indicates if AEC has been initialized
 
-    // Variables used for averaging far end buffer size
-    short counter;
-    short sum;
-    short firstVal;
-    short checkBufSizeCtr;
+  // Variables used for averaging far end buffer size
+  short counter;
+  short sum;
+  short firstVal;
+  short checkBufSizeCtr;
 
-    // Variables used for delay shifts
-    short msInSndCardBuf;
-    short filtDelay;
-    int timeForDelayChange;
-    int ECstartup;
-    int checkBuffSize;
-    int delayChange;
-    short lastDelayDiff;
+  // Variables used for delay shifts
+  short msInSndCardBuf;
+  short filtDelay;
+  int timeForDelayChange;
+  int ECstartup;
+  int checkBuffSize;
+  int delayChange;
+  short lastDelayDiff;
 
-    int16_t echoMode;
+  int16_t echoMode;
 
 #ifdef AEC_DEBUG
-    FILE *bufFile;
-    FILE *delayFile;
-    FILE *preCompFile;
-    FILE *postCompFile;
-#endif // AEC_DEBUG
-    // Structures
-    RingBuffer *farendBuf;
+  FILE* bufFile;
+  FILE* delayFile;
+  FILE* preCompFile;
+  FILE* postCompFile;
+#endif  // AEC_DEBUG
+  // Structures
+  RingBuffer* farendBuf;
 
-    AecmCore* aecmCore;
+  AecmCore* aecmCore;
 } AecMobile;
 
 // Estimates delay to set the position of the farend buffer read pointer
@@ -81,123 +81,117 @@
 static int WebRtcAecm_DelayComp(AecMobile* aecm);
 
 void* WebRtcAecm_Create() {
-    AecMobile* aecm = static_cast<AecMobile*>(malloc(sizeof(AecMobile)));
+  AecMobile* aecm = static_cast<AecMobile*>(malloc(sizeof(AecMobile)));
 
-    WebRtcSpl_Init();
+  WebRtcSpl_Init();
 
-    aecm->aecmCore = WebRtcAecm_CreateCore();
-    if (!aecm->aecmCore) {
-        WebRtcAecm_Free(aecm);
-        return NULL;
-    }
+  aecm->aecmCore = WebRtcAecm_CreateCore();
+  if (!aecm->aecmCore) {
+    WebRtcAecm_Free(aecm);
+    return NULL;
+  }
 
-    aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
-                                          sizeof(int16_t));
-    if (!aecm->farendBuf)
-    {
-        WebRtcAecm_Free(aecm);
-        return NULL;
-    }
+  aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, sizeof(int16_t));
+  if (!aecm->farendBuf) {
+    WebRtcAecm_Free(aecm);
+    return NULL;
+  }
 
-    aecm->initFlag = 0;
+  aecm->initFlag = 0;
 
 #ifdef AEC_DEBUG
-    aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
-    aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb");
-    aecm->aecmCore->outFile = fopen("aecOut.pcm","wb");
-    //aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
+  aecm->aecmCore->farFile = fopen("aecFar.pcm", "wb");
+  aecm->aecmCore->nearFile = fopen("aecNear.pcm", "wb");
+  aecm->aecmCore->outFile = fopen("aecOut.pcm", "wb");
+  // aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
 
-    aecm->bufFile = fopen("aecBuf.dat", "wb");
-    aecm->delayFile = fopen("aecDelay.dat", "wb");
-    aecm->preCompFile = fopen("preComp.pcm", "wb");
-    aecm->postCompFile = fopen("postComp.pcm", "wb");
-#endif // AEC_DEBUG
-    return aecm;
+  aecm->bufFile = fopen("aecBuf.dat", "wb");
+  aecm->delayFile = fopen("aecDelay.dat", "wb");
+  aecm->preCompFile = fopen("preComp.pcm", "wb");
+  aecm->postCompFile = fopen("postComp.pcm", "wb");
+#endif  // AEC_DEBUG
+  return aecm;
 }
 
 void WebRtcAecm_Free(void* aecmInst) {
   AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
 
-    if (aecm == NULL) {
-      return;
-    }
+  if (aecm == NULL) {
+    return;
+  }
 
 #ifdef AEC_DEBUG
-    fclose(aecm->aecmCore->farFile);
-    fclose(aecm->aecmCore->nearFile);
-    fclose(aecm->aecmCore->outFile);
-    //fclose(aecm->aecmCore->outLpFile);
+  fclose(aecm->aecmCore->farFile);
+  fclose(aecm->aecmCore->nearFile);
+  fclose(aecm->aecmCore->outFile);
+  // fclose(aecm->aecmCore->outLpFile);
 
-    fclose(aecm->bufFile);
-    fclose(aecm->delayFile);
-    fclose(aecm->preCompFile);
-    fclose(aecm->postCompFile);
-#endif // AEC_DEBUG
-    WebRtcAecm_FreeCore(aecm->aecmCore);
-    WebRtc_FreeBuffer(aecm->farendBuf);
-    free(aecm);
+  fclose(aecm->bufFile);
+  fclose(aecm->delayFile);
+  fclose(aecm->preCompFile);
+  fclose(aecm->postCompFile);
+#endif  // AEC_DEBUG
+  WebRtcAecm_FreeCore(aecm->aecmCore);
+  WebRtc_FreeBuffer(aecm->farendBuf);
+  free(aecm);
 }
 
-int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
-{
-    AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
-    AecmConfig aecConfig;
+int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq) {
+  AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+  AecmConfig aecConfig;
 
-    if (aecm == NULL)
-    {
-        return -1;
-    }
+  if (aecm == NULL) {
+    return -1;
+  }
 
-    if (sampFreq != 8000 && sampFreq != 16000)
-    {
-        return AECM_BAD_PARAMETER_ERROR;
-    }
-    aecm->sampFreq = sampFreq;
+  if (sampFreq != 8000 && sampFreq != 16000) {
+    return AECM_BAD_PARAMETER_ERROR;
+  }
+  aecm->sampFreq = sampFreq;
 
-    // Initialize AECM core
-    if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
-    {
-        return AECM_UNSPECIFIED_ERROR;
-    }
+  // Initialize AECM core
+  if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) {
+    return AECM_UNSPECIFIED_ERROR;
+  }
 
-    // Initialize farend buffer
-    WebRtc_InitBuffer(aecm->farendBuf);
+  // Initialize farend buffer
+  WebRtc_InitBuffer(aecm->farendBuf);
 
-    aecm->initFlag = kInitCheck; // indicates that initialization has been done
+  aecm->initFlag = kInitCheck;  // indicates that initialization has been done
 
-    aecm->delayChange = 1;
+  aecm->delayChange = 1;
 
-    aecm->sum = 0;
-    aecm->counter = 0;
-    aecm->checkBuffSize = 1;
-    aecm->firstVal = 0;
+  aecm->sum = 0;
+  aecm->counter = 0;
+  aecm->checkBuffSize = 1;
+  aecm->firstVal = 0;
 
-    aecm->ECstartup = 1;
-    aecm->bufSizeStart = 0;
-    aecm->checkBufSizeCtr = 0;
-    aecm->filtDelay = 0;
-    aecm->timeForDelayChange = 0;
-    aecm->knownDelay = 0;
-    aecm->lastDelayDiff = 0;
+  aecm->ECstartup = 1;
+  aecm->bufSizeStart = 0;
+  aecm->checkBufSizeCtr = 0;
+  aecm->filtDelay = 0;
+  aecm->timeForDelayChange = 0;
+  aecm->knownDelay = 0;
+  aecm->lastDelayDiff = 0;
 
-    memset(&aecm->farendOld, 0, sizeof(aecm->farendOld));
+  memset(&aecm->farendOld, 0, sizeof(aecm->farendOld));
 
-    // Default settings.
-    aecConfig.cngMode = AecmTrue;
-    aecConfig.echoMode = 3;
+  // Default settings.
+  aecConfig.cngMode = AecmTrue;
+  aecConfig.echoMode = 3;
 
-    if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
-    {
-        return AECM_UNSPECIFIED_ERROR;
-    }
+  if (WebRtcAecm_set_config(aecm, aecConfig) == -1) {
+    return AECM_UNSPECIFIED_ERROR;
+  }
 
-    return 0;
+  return 0;
 }
 
 // Returns any error that is caused when buffering the
 // farend signal.
-int32_t WebRtcAecm_GetBufferFarendError(void *aecmInst, const int16_t *farend,
-                                size_t nrOfSamples) {
+int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
+                                        const int16_t* farend,
+                                        size_t nrOfSamples) {
   AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
 
   if (aecm == NULL)
@@ -215,8 +209,8 @@
   return 0;
 }
 
-
-int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
+int32_t WebRtcAecm_BufferFarend(void* aecmInst,
+                                const int16_t* farend,
                                 size_t nrOfSamples) {
   AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
 
@@ -227,8 +221,7 @@
     return err;
 
   // TODO(unknown): Is this really a good idea?
-  if (!aecm->ECstartup)
-  {
+  if (!aecm->ECstartup) {
     WebRtcAecm_DelayComp(aecm);
   }
 
@@ -237,412 +230,363 @@
   return 0;
 }
 
-int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
-                           const int16_t *nearendClean, int16_t *out,
-                           size_t nrOfSamples, int16_t msInSndCardBuf)
-{
-    AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
-    int32_t retVal = 0;
-    size_t i;
-    short nmbrOfFilledBuffers;
-    size_t nBlocks10ms;
-    size_t nFrames;
+int32_t WebRtcAecm_Process(void* aecmInst,
+                           const int16_t* nearendNoisy,
+                           const int16_t* nearendClean,
+                           int16_t* out,
+                           size_t nrOfSamples,
+                           int16_t msInSndCardBuf) {
+  AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+  int32_t retVal = 0;
+  size_t i;
+  short nmbrOfFilledBuffers;
+  size_t nBlocks10ms;
+  size_t nFrames;
 #ifdef AEC_DEBUG
-    short msInAECBuf;
+  short msInAECBuf;
 #endif
 
-    if (aecm == NULL)
-    {
+  if (aecm == NULL) {
+    return -1;
+  }
+
+  if (nearendNoisy == NULL) {
+    return AECM_NULL_POINTER_ERROR;
+  }
+
+  if (out == NULL) {
+    return AECM_NULL_POINTER_ERROR;
+  }
+
+  if (aecm->initFlag != kInitCheck) {
+    return AECM_UNINITIALIZED_ERROR;
+  }
+
+  if (nrOfSamples != 80 && nrOfSamples != 160) {
+    return AECM_BAD_PARAMETER_ERROR;
+  }
+
+  if (msInSndCardBuf < 0) {
+    msInSndCardBuf = 0;
+    retVal = AECM_BAD_PARAMETER_WARNING;
+  } else if (msInSndCardBuf > 500) {
+    msInSndCardBuf = 500;
+    retVal = AECM_BAD_PARAMETER_WARNING;
+  }
+  msInSndCardBuf += 10;
+  aecm->msInSndCardBuf = msInSndCardBuf;
+
+  nFrames = nrOfSamples / FRAME_LEN;
+  nBlocks10ms = nFrames / aecm->aecmCore->mult;
+
+  if (aecm->ECstartup) {
+    if (nearendClean == NULL) {
+      if (out != nearendNoisy) {
+        memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
+      }
+    } else if (out != nearendClean) {
+      memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
+    }
+
+    nmbrOfFilledBuffers =
+        (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
+    // The AECM is in the start up mode
+    // AECM is disabled until the soundcard buffer and farend buffers are OK
+
+    // Mechanism to ensure that the soundcard buffer is reasonably stable.
+    if (aecm->checkBuffSize) {
+      aecm->checkBufSizeCtr++;
+      // Before we fill up the far end buffer we require the amount of data on
+      // the sound card to be stable (+/-8 ms) compared to the first value. This
+      // comparison is made during the following 4 consecutive frames. If it
+      // seems to be stable then we start to fill up the far end buffer.
+
+      if (aecm->counter == 0) {
+        aecm->firstVal = aecm->msInSndCardBuf;
+        aecm->sum = 0;
+      }
+
+      if (abs(aecm->firstVal - aecm->msInSndCardBuf) <
+          WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) {
+        aecm->sum += aecm->msInSndCardBuf;
+        aecm->counter++;
+      } else {
+        aecm->counter = 0;
+      }
+
+      if (aecm->counter * nBlocks10ms >= 6) {
+        // The farend buffer size is determined in blocks of 80 samples
+        // Use 75% of the average value of the soundcard buffer
+        aecm->bufSizeStart = WEBRTC_SPL_MIN(
+            (3 * aecm->sum * aecm->aecmCore->mult) / (aecm->counter * 40),
+            BUF_SIZE_FRAMES);
+        // buffersize has now been determined
+        aecm->checkBuffSize = 0;
+      }
+
+      if (aecm->checkBufSizeCtr * nBlocks10ms > 50) {
+        // for really bad sound cards, don't disable echocanceller for more than
+        // 0.5 sec
+        aecm->bufSizeStart = WEBRTC_SPL_MIN(
+            (3 * aecm->msInSndCardBuf * aecm->aecmCore->mult) / 40,
+            BUF_SIZE_FRAMES);
+        aecm->checkBuffSize = 0;
+      }
+    }
+
+    // if checkBuffSize changed in the if-statement above
+    if (!aecm->checkBuffSize) {
+      // soundcard buffer is now reasonably stable
+      // When the far end buffer is filled with approximately the same amount of
+      // data as the amount on the sound card we end the start up phase and
+      // start to cancel echoes.
+
+      if (nmbrOfFilledBuffers == aecm->bufSizeStart) {
+        aecm->ECstartup = 0;  // Enable the AECM
+      } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) {
+        WebRtc_MoveReadPtr(aecm->farendBuf,
+                           (int)WebRtc_available_read(aecm->farendBuf) -
+                               (int)aecm->bufSizeStart * FRAME_LEN);
+        aecm->ECstartup = 0;
+      }
+    }
+
+  } else {
+    // AECM is enabled
+
+    // Note only 1 block supported for nb and 2 blocks for wb
+    for (i = 0; i < nFrames; i++) {
+      int16_t farend[FRAME_LEN];
+      const int16_t* farend_ptr = NULL;
+
+      nmbrOfFilledBuffers =
+          (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
+
+      // Check that there is data in the far end buffer
+      if (nmbrOfFilledBuffers > 0) {
+        // Get the next 80 samples from the farend buffer
+        WebRtc_ReadBuffer(aecm->farendBuf, (void**)&farend_ptr, farend,
+                          FRAME_LEN);
+
+        // Always store the last frame for use when we run out of data
+        memcpy(&(aecm->farendOld[i][0]), farend_ptr, FRAME_LEN * sizeof(short));
+      } else {
+        // We have no data so we use the last played frame
+        memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
+        farend_ptr = farend;
+      }
+
+      // Call buffer delay estimator when all data is extracted,
+      // i,e. i = 0 for NB and i = 1 for WB
+      if ((i == 0 && aecm->sampFreq == 8000) ||
+          (i == 1 && aecm->sampFreq == 16000)) {
+        WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
+      }
+
+      // Call the AECM
+      /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
+       &out[FRAME_LEN * i], aecm->knownDelay);*/
+      if (WebRtcAecm_ProcessFrame(
+              aecm->aecmCore, farend_ptr, &nearendNoisy[FRAME_LEN * i],
+              (nearendClean ? &nearendClean[FRAME_LEN * i] : NULL),
+              &out[FRAME_LEN * i]) == -1)
         return -1;
     }
-
-    if (nearendNoisy == NULL)
-    {
-        return AECM_NULL_POINTER_ERROR;
-    }
-
-    if (out == NULL)
-    {
-        return AECM_NULL_POINTER_ERROR;
-    }
-
-    if (aecm->initFlag != kInitCheck)
-    {
-        return AECM_UNINITIALIZED_ERROR;
-    }
-
-    if (nrOfSamples != 80 && nrOfSamples != 160)
-    {
-        return AECM_BAD_PARAMETER_ERROR;
-    }
-
-    if (msInSndCardBuf < 0)
-    {
-        msInSndCardBuf = 0;
-        retVal = AECM_BAD_PARAMETER_WARNING;
-    } else if (msInSndCardBuf > 500)
-    {
-        msInSndCardBuf = 500;
-        retVal = AECM_BAD_PARAMETER_WARNING;
-    }
-    msInSndCardBuf += 10;
-    aecm->msInSndCardBuf = msInSndCardBuf;
-
-    nFrames = nrOfSamples / FRAME_LEN;
-    nBlocks10ms = nFrames / aecm->aecmCore->mult;
-
-    if (aecm->ECstartup)
-    {
-        if (nearendClean == NULL)
-        {
-            if (out != nearendNoisy)
-            {
-                memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
-            }
-        } else if (out != nearendClean)
-        {
-            memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
-        }
-
-        nmbrOfFilledBuffers =
-            (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
-        // The AECM is in the start up mode
-        // AECM is disabled until the soundcard buffer and farend buffers are OK
-
-        // Mechanism to ensure that the soundcard buffer is reasonably stable.
-        if (aecm->checkBuffSize)
-        {
-            aecm->checkBufSizeCtr++;
-            // Before we fill up the far end buffer we require the amount of data on the
-            // sound card to be stable (+/-8 ms) compared to the first value. This
-            // comparison is made during the following 4 consecutive frames. If it seems
-            // to be stable then we start to fill up the far end buffer.
-
-            if (aecm->counter == 0)
-            {
-                aecm->firstVal = aecm->msInSndCardBuf;
-                aecm->sum = 0;
-            }
-
-            if (abs(aecm->firstVal - aecm->msInSndCardBuf)
-                    < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
-            {
-                aecm->sum += aecm->msInSndCardBuf;
-                aecm->counter++;
-            } else
-            {
-                aecm->counter = 0;
-            }
-
-            if (aecm->counter * nBlocks10ms >= 6)
-            {
-                // The farend buffer size is determined in blocks of 80 samples
-                // Use 75% of the average value of the soundcard buffer
-                aecm->bufSizeStart
-                        = WEBRTC_SPL_MIN((3 * aecm->sum
-                                        * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
-                // buffersize has now been determined
-                aecm->checkBuffSize = 0;
-            }
-
-            if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
-            {
-                // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
-                aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
-                                * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
-                aecm->checkBuffSize = 0;
-            }
-        }
-
-        // if checkBuffSize changed in the if-statement above
-        if (!aecm->checkBuffSize)
-        {
-            // soundcard buffer is now reasonably stable
-            // When the far end buffer is filled with approximately the same amount of
-            // data as the amount on the sound card we end the start up phase and start
-            // to cancel echoes.
-
-            if (nmbrOfFilledBuffers == aecm->bufSizeStart)
-            {
-                aecm->ECstartup = 0; // Enable the AECM
-            } else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
-            {
-                WebRtc_MoveReadPtr(aecm->farendBuf,
-                                   (int) WebRtc_available_read(aecm->farendBuf)
-                                   - (int) aecm->bufSizeStart * FRAME_LEN);
-                aecm->ECstartup = 0;
-            }
-        }
-
-    } else
-    {
-        // AECM is enabled
-
-        // Note only 1 block supported for nb and 2 blocks for wb
-        for (i = 0; i < nFrames; i++)
-        {
-            int16_t farend[FRAME_LEN];
-            const int16_t* farend_ptr = NULL;
-
-            nmbrOfFilledBuffers =
-                (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
-
-            // Check that there is data in the far end buffer
-            if (nmbrOfFilledBuffers > 0)
-            {
-                // Get the next 80 samples from the farend buffer
-                WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend,
-                                  FRAME_LEN);
-
-                // Always store the last frame for use when we run out of data
-                memcpy(&(aecm->farendOld[i][0]), farend_ptr,
-                       FRAME_LEN * sizeof(short));
-            } else
-            {
-                // We have no data so we use the last played frame
-                memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
-                farend_ptr = farend;
-            }
-
-            // Call buffer delay estimator when all data is extracted,
-            // i,e. i = 0 for NB and i = 1 for WB
-            if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
-            {
-                WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
-            }
-
-            // Call the AECM
-            /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
-             &out[FRAME_LEN * i], aecm->knownDelay);*/
-            if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
-                                        farend_ptr,
-                                        &nearendNoisy[FRAME_LEN * i],
-                                        (nearendClean
-                                         ? &nearendClean[FRAME_LEN * i]
-                                         : NULL),
-                                        &out[FRAME_LEN * i]) == -1)
-                return -1;
-        }
-    }
+  }
 
 #ifdef AEC_DEBUG
-    msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) /
-        (kSampMsNb * aecm->aecmCore->mult);
-    fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
-    fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
+  msInAECBuf = (short)WebRtc_available_read(aecm->farendBuf) /
+               (kSampMsNb * aecm->aecmCore->mult);
+  fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
+  fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
 #endif
 
-    return retVal;
+  return retVal;
 }
 
-int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
-{
-    AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config) {
+  AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
 
-    if (aecm == NULL)
-    {
-        return -1;
-    }
+  if (aecm == NULL) {
+    return -1;
+  }
 
-    if (aecm->initFlag != kInitCheck)
-    {
-        return AECM_UNINITIALIZED_ERROR;
-    }
+  if (aecm->initFlag != kInitCheck) {
+    return AECM_UNINITIALIZED_ERROR;
+  }
 
-    if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
-    {
-        return AECM_BAD_PARAMETER_ERROR;
-    }
-    aecm->aecmCore->cngMode = config.cngMode;
+  if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) {
+    return AECM_BAD_PARAMETER_ERROR;
+  }
+  aecm->aecmCore->cngMode = config.cngMode;
 
-    if (config.echoMode < 0 || config.echoMode > 4)
-    {
-        return AECM_BAD_PARAMETER_ERROR;
-    }
-    aecm->echoMode = config.echoMode;
+  if (config.echoMode < 0 || config.echoMode > 4) {
+    return AECM_BAD_PARAMETER_ERROR;
+  }
+  aecm->echoMode = config.echoMode;
 
-    if (aecm->echoMode == 0)
-    {
-        aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
-        aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
-        aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
-        aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
-        aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
-                - (SUPGAIN_ERROR_PARAM_B >> 3);
-        aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
-                - (SUPGAIN_ERROR_PARAM_D >> 3);
-    } else if (aecm->echoMode == 1)
-    {
-        aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
-        aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
-        aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
-        aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
-        aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
-                - (SUPGAIN_ERROR_PARAM_B >> 2);
-        aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
-                - (SUPGAIN_ERROR_PARAM_D >> 2);
-    } else if (aecm->echoMode == 2)
-    {
-        aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
-        aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
-        aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
-        aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
-        aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
-                - (SUPGAIN_ERROR_PARAM_B >> 1);
-        aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
-                - (SUPGAIN_ERROR_PARAM_D >> 1);
-    } else if (aecm->echoMode == 3)
-    {
-        aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
-        aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
-        aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
-        aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
-        aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
-        aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
-    } else if (aecm->echoMode == 4)
-    {
-        aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
-        aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
-        aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
-        aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
-        aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
-                - (SUPGAIN_ERROR_PARAM_B << 1);
-        aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
-                - (SUPGAIN_ERROR_PARAM_D << 1);
-    }
+  if (aecm->echoMode == 0) {
+    aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
+    aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
+    aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
+    aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
+    aecm->aecmCore->supGainErrParamDiffAB =
+        (SUPGAIN_ERROR_PARAM_A >> 3) - (SUPGAIN_ERROR_PARAM_B >> 3);
+    aecm->aecmCore->supGainErrParamDiffBD =
+        (SUPGAIN_ERROR_PARAM_B >> 3) - (SUPGAIN_ERROR_PARAM_D >> 3);
+  } else if (aecm->echoMode == 1) {
+    aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
+    aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
+    aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
+    aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
+    aecm->aecmCore->supGainErrParamDiffAB =
+        (SUPGAIN_ERROR_PARAM_A >> 2) - (SUPGAIN_ERROR_PARAM_B >> 2);
+    aecm->aecmCore->supGainErrParamDiffBD =
+        (SUPGAIN_ERROR_PARAM_B >> 2) - (SUPGAIN_ERROR_PARAM_D >> 2);
+  } else if (aecm->echoMode == 2) {
+    aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
+    aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
+    aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
+    aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
+    aecm->aecmCore->supGainErrParamDiffAB =
+        (SUPGAIN_ERROR_PARAM_A >> 1) - (SUPGAIN_ERROR_PARAM_B >> 1);
+    aecm->aecmCore->supGainErrParamDiffBD =
+        (SUPGAIN_ERROR_PARAM_B >> 1) - (SUPGAIN_ERROR_PARAM_D >> 1);
+  } else if (aecm->echoMode == 3) {
+    aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
+    aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
+    aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
+    aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
+    aecm->aecmCore->supGainErrParamDiffAB =
+        SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
+    aecm->aecmCore->supGainErrParamDiffBD =
+        SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
+  } else if (aecm->echoMode == 4) {
+    aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
+    aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
+    aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
+    aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
+    aecm->aecmCore->supGainErrParamDiffAB =
+        (SUPGAIN_ERROR_PARAM_A << 1) - (SUPGAIN_ERROR_PARAM_B << 1);
+    aecm->aecmCore->supGainErrParamDiffBD =
+        (SUPGAIN_ERROR_PARAM_B << 1) - (SUPGAIN_ERROR_PARAM_D << 1);
+  }
 
-    return 0;
+  return 0;
 }
 
 int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
                                 const void* echo_path,
-                                size_t size_bytes)
-{
-    AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
-    const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
+                                size_t size_bytes) {
+  AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+  const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
 
-    if (aecmInst == NULL) {
-      return -1;
-    }
-    if (echo_path == NULL) {
-      return AECM_NULL_POINTER_ERROR;
-    }
-    if (size_bytes != WebRtcAecm_echo_path_size_bytes())
-    {
-        // Input channel size does not match the size of AECM
-        return AECM_BAD_PARAMETER_ERROR;
-    }
-    if (aecm->initFlag != kInitCheck)
-    {
-        return AECM_UNINITIALIZED_ERROR;
-    }
+  if (aecmInst == NULL) {
+    return -1;
+  }
+  if (echo_path == NULL) {
+    return AECM_NULL_POINTER_ERROR;
+  }
+  if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
+    // Input channel size does not match the size of AECM
+    return AECM_BAD_PARAMETER_ERROR;
+  }
+  if (aecm->initFlag != kInitCheck) {
+    return AECM_UNINITIALIZED_ERROR;
+  }
 
-    WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
+  WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
 
-    return 0;
+  return 0;
 }
 
 int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
                                void* echo_path,
-                               size_t size_bytes)
-{
-    AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
-    int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
+                               size_t size_bytes) {
+  AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+  int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
 
-    if (aecmInst == NULL) {
-      return -1;
-    }
-    if (echo_path == NULL) {
-      return AECM_NULL_POINTER_ERROR;
-    }
-    if (size_bytes != WebRtcAecm_echo_path_size_bytes())
-    {
-        // Input channel size does not match the size of AECM
-        return AECM_BAD_PARAMETER_ERROR;
-    }
-    if (aecm->initFlag != kInitCheck)
-    {
-        return AECM_UNINITIALIZED_ERROR;
-    }
+  if (aecmInst == NULL) {
+    return -1;
+  }
+  if (echo_path == NULL) {
+    return AECM_NULL_POINTER_ERROR;
+  }
+  if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
+    // Input channel size does not match the size of AECM
+    return AECM_BAD_PARAMETER_ERROR;
+  }
+  if (aecm->initFlag != kInitCheck) {
+    return AECM_UNINITIALIZED_ERROR;
+  }
 
-    memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
-    return 0;
+  memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
+  return 0;
 }
 
-size_t WebRtcAecm_echo_path_size_bytes()
-{
-    return (PART_LEN1 * sizeof(int16_t));
+size_t WebRtcAecm_echo_path_size_bytes() {
+  return (PART_LEN1 * sizeof(int16_t));
 }
 
-
 static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
-    short delayNew, nSampSndCard;
-    short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
-    short diff;
+  short delayNew, nSampSndCard;
+  short nSampFar = (short)WebRtc_available_read(aecm->farendBuf);
+  short diff;
 
-    nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
+  nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
 
-    delayNew = nSampSndCard - nSampFar;
+  delayNew = nSampSndCard - nSampFar;
 
-    if (delayNew < FRAME_LEN)
-    {
-        WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
-        delayNew += FRAME_LEN;
+  if (delayNew < FRAME_LEN) {
+    WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
+    delayNew += FRAME_LEN;
+  }
+
+  aecm->filtDelay =
+      WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
+
+  diff = aecm->filtDelay - aecm->knownDelay;
+  if (diff > 224) {
+    if (aecm->lastDelayDiff < 96) {
+      aecm->timeForDelayChange = 0;
+    } else {
+      aecm->timeForDelayChange++;
     }
-
-    aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
-
-    diff = aecm->filtDelay - aecm->knownDelay;
-    if (diff > 224)
-    {
-        if (aecm->lastDelayDiff < 96)
-        {
-            aecm->timeForDelayChange = 0;
-        } else
-        {
-            aecm->timeForDelayChange++;
-        }
-    } else if (diff < 96 && aecm->knownDelay > 0)
-    {
-        if (aecm->lastDelayDiff > 224)
-        {
-            aecm->timeForDelayChange = 0;
-        } else
-        {
-            aecm->timeForDelayChange++;
-        }
-    } else
-    {
-        aecm->timeForDelayChange = 0;
+  } else if (diff < 96 && aecm->knownDelay > 0) {
+    if (aecm->lastDelayDiff > 224) {
+      aecm->timeForDelayChange = 0;
+    } else {
+      aecm->timeForDelayChange++;
     }
-    aecm->lastDelayDiff = diff;
+  } else {
+    aecm->timeForDelayChange = 0;
+  }
+  aecm->lastDelayDiff = diff;
 
-    if (aecm->timeForDelayChange > 25)
-    {
-        aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
-    }
-    return 0;
+  if (aecm->timeForDelayChange > 25) {
+    aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
+  }
+  return 0;
 }
 
 static int WebRtcAecm_DelayComp(AecMobile* aecm) {
-    int nSampFar = (int) WebRtc_available_read(aecm->farendBuf);
-    int nSampSndCard, delayNew, nSampAdd;
-    const int maxStuffSamp = 10 * FRAME_LEN;
+  int nSampFar = (int)WebRtc_available_read(aecm->farendBuf);
+  int nSampSndCard, delayNew, nSampAdd;
+  const int maxStuffSamp = 10 * FRAME_LEN;
 
-    nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
-    delayNew = nSampSndCard - nSampFar;
+  nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
+  delayNew = nSampSndCard - nSampFar;
 
-    if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
-    {
-        // The difference of the buffer sizes is larger than the maximum
-        // allowed known delay. Compensate by stuffing the buffer.
-        nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
-                FRAME_LEN));
-        nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
+  if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) {
+    // The difference of the buffer sizes is larger than the maximum
+    // allowed known delay. Compensate by stuffing the buffer.
+    nSampAdd =
+        (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), FRAME_LEN));
+    nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
 
-        WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
-        aecm->delayChange = 1; // the delay needs to be updated
-    }
+    WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
+    aecm->delayChange = 1;  // the delay needs to be updated
+  }
 
-    return 0;
+  return 0;
 }
diff --git a/modules/audio_processing/aecm/echo_control_mobile.h b/modules/audio_processing/aecm/echo_control_mobile.h
index e0091c3..576cf19 100644
--- a/modules/audio_processing/aecm/echo_control_mobile.h
+++ b/modules/audio_processing/aecm/echo_control_mobile.h
@@ -15,24 +15,21 @@
 
 #include "typedefs.h"  // NOLINT(build/include)
 
-enum {
-    AecmFalse = 0,
-    AecmTrue
-};
+enum { AecmFalse = 0, AecmTrue };
 
 // Errors
-#define AECM_UNSPECIFIED_ERROR           12000
-#define AECM_UNSUPPORTED_FUNCTION_ERROR  12001
-#define AECM_UNINITIALIZED_ERROR         12002
-#define AECM_NULL_POINTER_ERROR          12003
-#define AECM_BAD_PARAMETER_ERROR         12004
+#define AECM_UNSPECIFIED_ERROR 12000
+#define AECM_UNSUPPORTED_FUNCTION_ERROR 12001
+#define AECM_UNINITIALIZED_ERROR 12002
+#define AECM_NULL_POINTER_ERROR 12003
+#define AECM_BAD_PARAMETER_ERROR 12004
 
 // Warnings
-#define AECM_BAD_PARAMETER_WARNING       12100
+#define AECM_BAD_PARAMETER_WARNING 12100
 
 typedef struct {
-    int16_t cngMode;            // AECM_FALSE, AECM_TRUE (default)
-    int16_t echoMode;           // 0, 1, 2, 3 (default), 4
+  int16_t cngMode;   // AECM_FALSE, AECM_TRUE (default)
+  int16_t echoMode;  // 0, 1, 2, 3 (default), 4
 } AecmConfig;
 
 #ifdef __cplusplus
@@ -202,7 +199,6 @@
  */
 size_t WebRtcAecm_echo_path_size_bytes();
 
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/modules/audio_processing/agc/BUILD.gn b/modules/audio_processing/agc/BUILD.gn
new file mode 100644
index 0000000..fe2f107
--- /dev/null
+++ b/modules/audio_processing/agc/BUILD.gn
@@ -0,0 +1,130 @@
+# Copyright (c) 2018 The WebRTC 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.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("agc") {
+  sources = [
+    "agc_manager_direct.cc",
+    "agc_manager_direct.h",
+  ]
+  configs += [ "..:apm_debug_dump" ]
+  deps = [
+    ":gain_map",
+    ":level_estimation",
+    "..:apm_logging",
+    "..:gain_control_interface",
+    "../../..:typedefs",
+    "../../..:webrtc_common",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:logging",
+    "../../../rtc_base:macromagic",
+    "../../../rtc_base:safe_minmax",
+    "../../../system_wrappers:metrics_api",
+    "../agc2:level_estimation_agc",
+    "../vad",
+  ]
+}
+
+rtc_source_set("level_estimation") {
+  sources = [
+    "agc.cc",
+    "agc.h",
+    "loudness_histogram.cc",
+    "loudness_histogram.h",
+    "utility.cc",
+    "utility.h",
+  ]
+  deps = [
+    "../../..:typedefs",
+    "../../..:webrtc_common",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:macromagic",
+    "../vad",
+  ]
+}
+
+rtc_source_set("agc_legacy_c") {
+  visibility = [
+    ":*",
+    "..:*",
+  ]  # Only targets in this file and in
+     # audio_processing can depend on
+     # this.
+
+  sources = [
+    "legacy/analog_agc.c",
+    "legacy/analog_agc.h",
+    "legacy/digital_agc.c",
+    "legacy/digital_agc.h",
+    "legacy/gain_control.h",
+  ]
+
+  deps = [
+    "../../..:typedefs",
+    "../../..:webrtc_common",
+    "../../../common_audio",
+    "../../../common_audio:common_audio_c",
+    "../../../common_audio:fft4g",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../system_wrappers:cpu_features_api",
+  ]
+
+  if (rtc_build_with_neon) {
+    if (current_cpu != "arm64") {
+      # Enable compilation for the NEON instruction set. This is needed
+      # since //build/config/arm.gni only enables NEON for iOS, not Android.
+      # This provides the same functionality as webrtc/build/arm_neon.gypi.
+      suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+      cflags = [ "-mfpu=neon" ]
+    }
+
+    # Disable LTO on NEON targets due to compiler bug.
+    # TODO(fdegans): Enable this. See crbug.com/408997.
+    if (rtc_use_lto) {
+      cflags -= [
+        "-flto",
+        "-ffat-lto-objects",
+      ]
+    }
+  }
+}
+
+rtc_source_set("gain_map") {
+  sources = [
+    "gain_map_internal.h",
+  ]
+}
+
+if (rtc_include_tests) {
+  rtc_source_set("agc_unittests") {
+    testonly = true
+    sources = [
+      "agc_manager_direct_unittest.cc",
+      "loudness_histogram_unittest.cc",
+      "mock_agc.h",
+    ]
+    configs += [ "..:apm_debug_dump" ]
+
+    if ((!build_with_chromium || is_win) && is_clang) {
+      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+    }
+
+    deps = [
+      ":agc",
+      ":level_estimation",
+      "..:mocks",
+      "../../..:webrtc_common",
+      "../../../test:fileutils",
+      "../../../test:test_support",
+      "//testing/gtest",
+    ]
+  }
+}
diff --git a/modules/audio_processing/agc/agc_manager_direct.cc b/modules/audio_processing/agc/agc_manager_direct.cc
index 2d6ee81..132cf82 100644
--- a/modules/audio_processing/agc/agc_manager_direct.cc
+++ b/modules/audio_processing/agc/agc_manager_direct.cc
@@ -17,7 +17,8 @@
 #endif
 
 #include "modules/audio_processing/agc/gain_map_internal.h"
-#include "modules/audio_processing/gain_control_impl.h"
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h"
+#include "modules/audio_processing/include/gain_control.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_minmax.h"
@@ -25,6 +26,8 @@
 
 namespace webrtc {
 
+int AgcManagerDirect::instance_counter_ = 0;
+
 namespace {
 
 // Amount the microphone level is lowered with every clipping event.
@@ -69,12 +72,12 @@
   int new_level = level;
   if (gain_error > 0) {
     while (kGainMap[new_level] - kGainMap[level] < gain_error &&
-          new_level < kMaxMicLevel) {
+           new_level < kMaxMicLevel) {
       ++new_level;
     }
   } else {
     while (kGainMap[new_level] - kGainMap[level] > gain_error &&
-          new_level > kMinMicLevel) {
+           new_level > kMinMicLevel) {
       --new_level;
     }
   }
@@ -88,57 +91,60 @@
 class DebugFile {
 #ifdef WEBRTC_AGC_DEBUG_DUMP
  public:
-  explicit DebugFile(const char* filename)
-      : file_(fopen(filename, "wb")) {
+  explicit DebugFile(const char* filename) : file_(fopen(filename, "wb")) {
     RTC_DCHECK(file_);
   }
-  ~DebugFile() {
-    fclose(file_);
-  }
+  ~DebugFile() { fclose(file_); }
   void Write(const int16_t* data, size_t length_samples) {
     fwrite(data, 1, length_samples * sizeof(int16_t), file_);
   }
+
  private:
   FILE* file_;
 #else
  public:
-  explicit DebugFile(const char* filename) {
-  }
-  ~DebugFile() {
-  }
-  void Write(const int16_t* data, size_t length_samples) {
-  }
+  explicit DebugFile(const char* filename) {}
+  ~DebugFile() {}
+  void Write(const int16_t* data, size_t length_samples) {}
 #endif  // WEBRTC_AGC_DEBUG_DUMP
 };
 
 AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
                                    VolumeCallbacks* volume_callbacks,
                                    int startup_min_level,
-                                   int clipped_level_min)
-    : agc_(new Agc()),
-      gctrl_(gctrl),
-      volume_callbacks_(volume_callbacks),
-      frames_since_clipped_(kClippedWaitFrames),
-      level_(0),
-      max_level_(kMaxMicLevel),
-      max_compression_gain_(kMaxCompressionGain),
-      target_compression_(kDefaultCompressionGain),
-      compression_(target_compression_),
-      compression_accumulator_(compression_),
-      capture_muted_(false),
-      check_volume_on_next_process_(true),  // Check at startup.
-      startup_(true),
-      startup_min_level_(ClampLevel(startup_min_level)),
-      clipped_level_min_(clipped_level_min),
-      file_preproc_(new DebugFile("agc_preproc.pcm")),
-      file_postproc_(new DebugFile("agc_postproc.pcm")) {}
+                                   int clipped_level_min,
+                                   bool use_agc2_level_estimation,
+                                   bool use_agc2_digital_adaptive)
+    : AgcManagerDirect(new Agc(),
+                       gctrl,
+                       volume_callbacks,
+                       startup_min_level,
+                       clipped_level_min,
+                       use_agc2_level_estimation,
+                       use_agc2_digital_adaptive) {}
 
 AgcManagerDirect::AgcManagerDirect(Agc* agc,
                                    GainControl* gctrl,
                                    VolumeCallbacks* volume_callbacks,
                                    int startup_min_level,
                                    int clipped_level_min)
-    : agc_(agc),
+    : AgcManagerDirect(agc,
+                       gctrl,
+                       volume_callbacks,
+                       startup_min_level,
+                       clipped_level_min,
+                       false,
+                       false) {}
+
+AgcManagerDirect::AgcManagerDirect(Agc* agc,
+                                   GainControl* gctrl,
+                                   VolumeCallbacks* volume_callbacks,
+                                   int startup_min_level,
+                                   int clipped_level_min,
+                                   bool use_agc2_level_estimation,
+                                   bool use_agc2_digital_adaptive)
+    : data_dumper_(new ApmDataDumper(instance_counter_)),
+      agc_(agc),
       gctrl_(gctrl),
       volume_callbacks_(volume_callbacks),
       frames_since_clipped_(kClippedWaitFrames),
@@ -151,10 +157,23 @@
       capture_muted_(false),
       check_volume_on_next_process_(true),  // Check at startup.
       startup_(true),
+      use_agc2_level_estimation_(use_agc2_level_estimation),
+      use_agc2_digital_adaptive_(use_agc2_digital_adaptive),
       startup_min_level_(ClampLevel(startup_min_level)),
       clipped_level_min_(clipped_level_min),
       file_preproc_(new DebugFile("agc_preproc.pcm")),
-      file_postproc_(new DebugFile("agc_postproc.pcm")) {}
+      file_postproc_(new DebugFile("agc_postproc.pcm")) {
+  instance_counter_++;
+  if (use_agc2_level_estimation_) {
+    RTC_DCHECK(!agc);
+    agc_.reset(new AdaptiveModeLevelEstimatorAgc(data_dumper_.get()));
+  } else {
+    RTC_DCHECK(agc);
+  }
+  if (use_agc2_digital_adaptive_) {
+    RTC_NOTREACHED() << "Agc2 digital adaptive not implemented.";
+  }
+}
 
 AgcManagerDirect::~AgcManagerDirect() {}
 
@@ -169,6 +188,8 @@
   // TODO(bjornv): Investigate if we need to reset |startup_| as well. For
   // example, what happens when we change devices.
 
+  data_dumper_->InitiateNewSetOfRecordings();
+
   if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) {
     RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed.";
     return -1;
@@ -254,6 +275,9 @@
   UpdateCompressor();
 
   file_postproc_->Write(audio, length);
+
+  data_dumper_->DumpRaw("experimental_gain_control_compression_gain_db", 1,
+                        &compression_);
 }
 
 void AgcManagerDirect::SetLevel(int new_level) {
@@ -272,7 +296,8 @@
   if (voe_level > level_ + kLevelQuantizationSlack ||
       voe_level < level_ - kLevelQuantizationSlack) {
     RTC_DLOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating "
-                         "stored level from " << level_ << " to " << voe_level;
+                         "stored level from "
+                      << level_ << " to " << voe_level;
     level_ = voe_level;
     // Always allow the user to increase the volume.
     if (level_ > max_level_) {
@@ -383,15 +408,15 @@
   // target and the newly received target. This serves to soften perceptible
   // intra-talkspurt adjustments, at the cost of some adaptation speed.
   if ((raw_compression == max_compression_gain_ &&
-      target_compression_ == max_compression_gain_ - 1) ||
+       target_compression_ == max_compression_gain_ - 1) ||
       (raw_compression == kMinCompressionGain &&
-      target_compression_ == kMinCompressionGain + 1)) {
+       target_compression_ == kMinCompressionGain + 1)) {
     // Special case to allow the target to reach the endpoints of the
     // compression range. The deemphasis would otherwise halt it at 1 dB shy.
     target_compression_ = raw_compression;
   } else {
-    target_compression_ = (raw_compression - target_compression_) / 2
-        + target_compression_;
+    target_compression_ =
+        (raw_compression - target_compression_) / 2 + target_compression_;
   }
 
   // Residual error will be handled by adjusting the volume slider. Use the
diff --git a/modules/audio_processing/agc/agc_manager_direct.h b/modules/audio_processing/agc/agc_manager_direct.h
index 03d2607..de3d1cb 100644
--- a/modules/audio_processing/agc/agc_manager_direct.h
+++ b/modules/audio_processing/agc/agc_manager_direct.h
@@ -14,6 +14,7 @@
 #include <memory>
 
 #include "modules/audio_processing/agc/agc.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
@@ -47,14 +48,10 @@
   AgcManagerDirect(GainControl* gctrl,
                    VolumeCallbacks* volume_callbacks,
                    int startup_min_level,
-                   int clipped_level_min);
-  // Dependency injection for testing. Don't delete |agc| as the memory is owned
-  // by the manager.
-  AgcManagerDirect(Agc* agc,
-                   GainControl* gctrl,
-                   VolumeCallbacks* volume_callbacks,
-                   int startup_min_level,
-                   int clipped_level_min);
+                   int clipped_level_min,
+                   bool use_agc2_level_estimation,
+                   bool use_agc2_digital_adaptive);
+
   ~AgcManagerDirect();
 
   int Initialize();
@@ -72,6 +69,25 @@
   float voice_probability();
 
  private:
+  friend class AgcManagerDirectTest;
+
+  // Dependency injection for testing. Don't delete |agc| as the memory is owned
+  // by the manager.
+  AgcManagerDirect(Agc* agc,
+                   GainControl* gctrl,
+                   VolumeCallbacks* volume_callbacks,
+                   int startup_min_level,
+                   int clipped_level_min);
+
+  // Most general c-tor.
+  AgcManagerDirect(Agc* agc,
+                   GainControl* gctrl,
+                   VolumeCallbacks* volume_callbacks,
+                   int startup_min_level,
+                   int clipped_level_min,
+                   bool use_agc2_level_estimation,
+                   bool use_agc2_digital_adaptive);
+
   // Sets a new microphone level, after first checking that it hasn't been
   // updated by the user, in which case no action is taken.
   void SetLevel(int new_level);
@@ -85,6 +101,9 @@
   void UpdateGain();
   void UpdateCompressor();
 
+  std::unique_ptr<ApmDataDumper> data_dumper_;
+  static int instance_counter_;
+
   std::unique_ptr<Agc> agc_;
   GainControl* gctrl_;
   VolumeCallbacks* volume_callbacks_;
@@ -99,6 +118,8 @@
   bool capture_muted_;
   bool check_volume_on_next_process_;
   bool startup_;
+  const bool use_agc2_level_estimation_;
+  const bool use_agc2_digital_adaptive_;
   int startup_min_level_;
   const int clipped_level_min_;
 
diff --git a/modules/audio_processing/agc/gain_map_internal.h b/modules/audio_processing/agc/gain_map_internal.h
index f09c748..63d9b51 100644
--- a/modules/audio_processing/agc/gain_map_internal.h
+++ b/modules/audio_processing/agc/gain_map_internal.h
@@ -14,262 +14,23 @@
 static const int kGainMapSize = 256;
 // Uses parameters: si = 2, sf = 0.25, D = 8/256
 static const int kGainMap[kGainMapSize] = {
-  -56,
-  -54,
-  -52,
-  -50,
-  -48,
-  -47,
-  -45,
-  -43,
-  -42,
-  -40,
-  -38,
-  -37,
-  -35,
-  -34,
-  -33,
-  -31,
-  -30,
-  -29,
-  -27,
-  -26,
-  -25,
-  -24,
-  -23,
-  -22,
-  -20,
-  -19,
-  -18,
-  -17,
-  -16,
-  -15,
-  -14,
-  -14,
-  -13,
-  -12,
-  -11,
-  -10,
-  -9,
-  -8,
-  -8,
-  -7,
-  -6,
-  -5,
-  -5,
-  -4,
-  -3,
-  -2,
-  -2,
-  -1,
-  0,
-  0,
-  1,
-  1,
-  2,
-  3,
-  3,
-  4,
-  4,
-  5,
-  5,
-  6,
-  6,
-  7,
-  7,
-  8,
-  8,
-  9,
-  9,
-  10,
-  10,
-  11,
-  11,
-  12,
-  12,
-  13,
-  13,
-  13,
-  14,
-  14,
-  15,
-  15,
-  15,
-  16,
-  16,
-  17,
-  17,
-  17,
-  18,
-  18,
-  18,
-  19,
-  19,
-  19,
-  20,
-  20,
-  21,
-  21,
-  21,
-  22,
-  22,
-  22,
-  23,
-  23,
-  23,
-  24,
-  24,
-  24,
-  24,
-  25,
-  25,
-  25,
-  26,
-  26,
-  26,
-  27,
-  27,
-  27,
-  28,
-  28,
-  28,
-  28,
-  29,
-  29,
-  29,
-  30,
-  30,
-  30,
-  30,
-  31,
-  31,
-  31,
-  32,
-  32,
-  32,
-  32,
-  33,
-  33,
-  33,
-  33,
-  34,
-  34,
-  34,
-  35,
-  35,
-  35,
-  35,
-  36,
-  36,
-  36,
-  36,
-  37,
-  37,
-  37,
-  38,
-  38,
-  38,
-  38,
-  39,
-  39,
-  39,
-  39,
-  40,
-  40,
-  40,
-  40,
-  41,
-  41,
-  41,
-  41,
-  42,
-  42,
-  42,
-  42,
-  43,
-  43,
-  43,
-  44,
-  44,
-  44,
-  44,
-  45,
-  45,
-  45,
-  45,
-  46,
-  46,
-  46,
-  46,
-  47,
-  47,
-  47,
-  47,
-  48,
-  48,
-  48,
-  48,
-  49,
-  49,
-  49,
-  49,
-  50,
-  50,
-  50,
-  50,
-  51,
-  51,
-  51,
-  51,
-  52,
-  52,
-  52,
-  52,
-  53,
-  53,
-  53,
-  53,
-  54,
-  54,
-  54,
-  54,
-  55,
-  55,
-  55,
-  55,
-  56,
-  56,
-  56,
-  56,
-  57,
-  57,
-  57,
-  57,
-  58,
-  58,
-  58,
-  58,
-  59,
-  59,
-  59,
-  59,
-  60,
-  60,
-  60,
-  60,
-  61,
-  61,
-  61,
-  61,
-  62,
-  62,
-  62,
-  62,
-  63,
-  63,
-  63,
-  63,
-  64
-};
+    -56, -54, -52, -50, -48, -47, -45, -43, -42, -40, -38, -37, -35, -34, -33,
+    -31, -30, -29, -27, -26, -25, -24, -23, -22, -20, -19, -18, -17, -16, -15,
+    -14, -14, -13, -12, -11, -10, -9,  -8,  -8,  -7,  -6,  -5,  -5,  -4,  -3,
+    -2,  -2,  -1,  0,   0,   1,   1,   2,   3,   3,   4,   4,   5,   5,   6,
+    6,   7,   7,   8,   8,   9,   9,   10,  10,  11,  11,  12,  12,  13,  13,
+    13,  14,  14,  15,  15,  15,  16,  16,  17,  17,  17,  18,  18,  18,  19,
+    19,  19,  20,  20,  21,  21,  21,  22,  22,  22,  23,  23,  23,  24,  24,
+    24,  24,  25,  25,  25,  26,  26,  26,  27,  27,  27,  28,  28,  28,  28,
+    29,  29,  29,  30,  30,  30,  30,  31,  31,  31,  32,  32,  32,  32,  33,
+    33,  33,  33,  34,  34,  34,  35,  35,  35,  35,  36,  36,  36,  36,  37,
+    37,  37,  38,  38,  38,  38,  39,  39,  39,  39,  40,  40,  40,  40,  41,
+    41,  41,  41,  42,  42,  42,  42,  43,  43,  43,  44,  44,  44,  44,  45,
+    45,  45,  45,  46,  46,  46,  46,  47,  47,  47,  47,  48,  48,  48,  48,
+    49,  49,  49,  49,  50,  50,  50,  50,  51,  51,  51,  51,  52,  52,  52,
+    52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,  55,  55,  56,  56,
+    56,  56,  57,  57,  57,  57,  58,  58,  58,  58,  59,  59,  59,  59,  60,
+    60,  60,  60,  61,  61,  61,  61,  62,  62,  62,  62,  63,  63,  63,  63,
+    64};
 
 #endif  // MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
diff --git a/modules/audio_processing/agc/legacy/digital_agc.c b/modules/audio_processing/agc/legacy/digital_agc.c
index 3269a17..7801196 100644
--- a/modules/audio_processing/agc/legacy/digital_agc.c
+++ b/modules/audio_processing/agc/legacy/digital_agc.c
@@ -412,8 +412,10 @@
     }
     tmp32 = ((uint32_t)cur_level << zeros) & 0x7FFFFFFF;
     frac = (int16_t)(tmp32 >> 19);  // Q12.
-    tmp32 = (stt->gainTable[zeros - 1] - stt->gainTable[zeros]) * frac;
-    gains[k + 1] = stt->gainTable[zeros] + (tmp32 >> 12);
+    // Interpolate between gainTable[zeros] and gainTable[zeros-1].
+    tmp32 = ((stt->gainTable[zeros - 1] - stt->gainTable[zeros]) *
+             (int64_t)frac) >> 12;
+    gains[k + 1] = stt->gainTable[zeros] + tmp32;
 #ifdef WEBRTC_AGC_DEBUG_DUMP
     if (k == 0) {
       fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level,
@@ -465,9 +467,10 @@
 
   // Limit gain to avoid overload distortion
   for (k = 0; k < 10; k++) {
-    // To prevent wrap around
+    // Find a shift of gains[k + 1] such that it can be squared without
+    // overflow, but at least by 10 bits.
     zeros = 10;
-    if (gains[k + 1] > 47453132) {
+    if (gains[k + 1] > 47452159) {
       zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
     }
     gain32 = (gains[k + 1] >> zeros) + 1;
@@ -502,18 +505,16 @@
   // iterate over samples
   for (n = 0; n < L; n++) {
     for (i = 0; i < num_bands; ++i) {
-      tmp32 = out[i][n] * ((gain32 + 127) >> 7);
-      out_tmp = tmp32 >> 16;
+      out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16;
       if (out_tmp > 4095) {
         out[i][n] = (int16_t)32767;
       } else if (out_tmp < -4096) {
         out[i][n] = (int16_t)-32768;
       } else {
-        tmp32 = out[i][n] * (gain32 >> 4);
-        out[i][n] = (int16_t)(tmp32 >> 16);
+        tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16;
+        out[i][n] = (int16_t)tmp32;
       }
     }
-    //
 
     gain32 += delta;
   }
diff --git a/modules/audio_processing/agc/mock_agc.h b/modules/audio_processing/agc/mock_agc.h
index cf2a859..ff1e9fd 100644
--- a/modules/audio_processing/agc/mock_agc.h
+++ b/modules/audio_processing/agc/mock_agc.h
@@ -20,8 +20,8 @@
 class MockAgc : public Agc {
  public:
   MOCK_METHOD2(AnalyzePreproc, float(const int16_t* audio, size_t length));
-  MOCK_METHOD3(Process, void(const int16_t* audio, size_t length,
-                             int sample_rate_hz));
+  MOCK_METHOD3(Process,
+               void(const int16_t* audio, size_t length, int sample_rate_hz));
   MOCK_METHOD1(GetRmsErrorDb, bool(int* error));
   MOCK_METHOD0(Reset, void());
   MOCK_METHOD1(set_target_level_dbfs, int(int level));
diff --git a/modules/audio_processing/agc2/BUILD.gn b/modules/audio_processing/agc2/BUILD.gn
index 6f92f84..dcdc7fa 100644
--- a/modules/audio_processing/agc2/BUILD.gn
+++ b/modules/audio_processing/agc2/BUILD.gn
@@ -15,6 +15,31 @@
   ]
 }
 
+rtc_source_set("level_estimation_agc") {
+  sources = [
+    "adaptive_mode_level_estimator_agc.cc",
+    "adaptive_mode_level_estimator_agc.h",
+  ]
+  configs += [ "..:apm_debug_dump" ]
+  deps = [
+    ":adaptive_digital",
+    ":common",
+    ":gain_applier",
+    ":noise_level_estimator",
+    ":rnn_vad_with_level",
+    "..:apm_logging",
+    "..:audio_frame_view",
+    "../../..:typedefs",
+    "../../../api:array_view",
+    "../../../common_audio",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../rtc_base:safe_minmax",
+    "../agc:level_estimation",
+    "../vad",
+  ]
+}
+
 rtc_source_set("adaptive_digital") {
   sources = [
     "adaptive_agc.cc",
@@ -33,7 +58,7 @@
     ":common",
     ":gain_applier",
     ":noise_level_estimator",
-    "..:aec_core",
+    ":rnn_vad_with_level",
     "..:apm_logging",
     "..:audio_frame_view",
     "../../../api:array_view",
@@ -41,9 +66,27 @@
     "../../../rtc_base:checks",
     "../../../rtc_base:rtc_base_approved",
     "../../../rtc_base:safe_minmax",
-    "../vad",
-    "../vad:vad_with_level",
-    "rnn_vad",
+  ]
+}
+
+rtc_source_set("biquad_filter") {
+  visibility = [ "./*" ]
+  sources = [
+    "biquad_filter.cc",
+    "biquad_filter.h",
+  ]
+  deps = [
+    "../../../api:array_view",
+    "../../../rtc_base:rtc_base_approved",
+  ]
+}
+
+rtc_source_set("common") {
+  sources = [
+    "agc2_common.h",
+  ]
+  deps = [
+    "../../../rtc_base:rtc_base_approved",
   ]
 }
 
@@ -75,41 +118,6 @@
   ]
 }
 
-rtc_source_set("common") {
-  sources = [
-    "agc2_common.h",
-  ]
-  deps = [
-    "../../../rtc_base:rtc_base_approved",
-  ]
-}
-
-rtc_source_set("noise_level_estimator") {
-  sources = [
-    "biquad_filter.cc",
-    "biquad_filter.h",
-    "down_sampler.cc",
-    "down_sampler.h",
-    "noise_level_estimator.cc",
-    "noise_level_estimator.h",
-    "noise_spectrum_estimator.cc",
-    "noise_spectrum_estimator.h",
-    "signal_classifier.cc",
-    "signal_classifier.h",
-  ]
-  deps = [
-    "..:aec_core",
-    "..:apm_logging",
-    "..:audio_frame_view",
-    "../../../api:array_view",
-    "../../../common_audio",
-    "../../../rtc_base:checks",
-    "../../../rtc_base:macromagic",
-  ]
-
-  configs += [ "..:apm_debug_dump" ]
-}
-
 rtc_source_set("gain_applier") {
   sources = [
     "gain_applier.cc",
@@ -122,19 +130,78 @@
   ]
 }
 
-rtc_source_set("test_utils") {
-  testonly = true
-  visibility = [ ":*" ]
+rtc_source_set("noise_level_estimator") {
   sources = [
-    "agc2_testing_common.cc",
-    "agc2_testing_common.h",
-    "vector_float_frame.cc",
-    "vector_float_frame.h",
+    "down_sampler.cc",
+    "down_sampler.h",
+    "noise_level_estimator.cc",
+    "noise_level_estimator.h",
+    "noise_spectrum_estimator.cc",
+    "noise_spectrum_estimator.h",
+    "signal_classifier.cc",
+    "signal_classifier.h",
+  ]
+  deps = [
+    ":biquad_filter",
+    "..:apm_logging",
+    "..:audio_frame_view",
+    "../../../api:array_view",
+    "../../../common_audio",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:macromagic",
+    "../utility:ooura_fft",
+  ]
+
+  configs += [ "..:apm_debug_dump" ]
+}
+
+rtc_source_set("rnn_vad_with_level") {
+  sources = [
+    "vad_with_level.cc",
+    "vad_with_level.h",
   ]
   deps = [
     "..:audio_frame_view",
+    "../../../api:array_view",
+    "../../../common_audio",
+    "../../../rtc_base:checks",
+    "rnn_vad:lib",
+  ]
+}
+
+rtc_source_set("adaptive_digital_unittests") {
+  testonly = true
+  configs += [ "..:apm_debug_dump" ]
+
+  sources = [
+    "adaptive_digital_gain_applier_unittest.cc",
+    "adaptive_mode_level_estimator_unittest.cc",
+    "gain_applier_unittest.cc",
+    "saturation_protector_unittest.cc",
+  ]
+  deps = [
+    ":adaptive_digital",
+    ":common",
+    ":gain_applier",
+    ":test_utils",
+    "..:apm_logging",
+    "..:audio_frame_view",
+    "../../../api:array_view",
+    "../../../common_audio",
     "../../../rtc_base:checks",
     "../../../rtc_base:rtc_base_approved",
+    "../../../rtc_base:rtc_base_tests_utils",
+  ]
+}
+
+rtc_source_set("biquad_filter_unittests") {
+  testonly = true
+  sources = [
+    "biquad_filter_unittest.cc",
+  ]
+  deps = [
+    ":biquad_filter",
+    "../../../rtc_base:rtc_base_tests_utils",
   ]
 }
 
@@ -165,32 +232,7 @@
     "../../../rtc_base:checks",
     "../../../rtc_base:rtc_base_approved",
     "../../../rtc_base:rtc_base_tests_utils",
-  ]
-}
-
-rtc_source_set("adaptive_digital_unittests") {
-  testonly = true
-  configs += [ "..:apm_debug_dump" ]
-
-  sources = [
-    "adaptive_digital_gain_applier_unittest.cc",
-    "adaptive_mode_level_estimator_unittest.cc",
-    "gain_applier_unittest.cc",
-    "saturation_protector_unittest.cc",
-  ]
-  deps = [
-    ":adaptive_digital",
-    ":common",
-    ":gain_applier",
-    ":test_utils",
-    "..:apm_logging",
-    "..:audio_frame_view",
-    "../../../api:array_view",
-    "../../../common_audio",
-    "../../../rtc_base:checks",
-    "../../../rtc_base:rtc_base_approved",
-    "../../../rtc_base:rtc_base_tests_utils",
-    "../vad:vad_with_level",
+    "//third_party/abseil-cpp/absl/memory",
   ]
 }
 
@@ -213,3 +255,19 @@
     "../../../rtc_base:rtc_base_tests_utils",
   ]
 }
+
+rtc_source_set("test_utils") {
+  testonly = true
+  visibility = [ ":*" ]
+  sources = [
+    "agc2_testing_common.cc",
+    "agc2_testing_common.h",
+    "vector_float_frame.cc",
+    "vector_float_frame.h",
+  ]
+  deps = [
+    "..:audio_frame_view",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+  ]
+}
diff --git a/modules/audio_processing/agc2/adaptive_agc.cc b/modules/audio_processing/agc2/adaptive_agc.cc
index 45e8853..7b24244 100644
--- a/modules/audio_processing/agc2/adaptive_agc.cc
+++ b/modules/audio_processing/agc2/adaptive_agc.cc
@@ -14,8 +14,8 @@
 #include <numeric>
 
 #include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
-#include "modules/audio_processing/vad/voice_activity_detector.h"
 
 namespace webrtc {
 
@@ -38,17 +38,14 @@
   // frames, and no estimates for other frames. We want to feed all to
   // the level estimator, but only care about the last level it
   // produces.
-  rtc::ArrayView<const VadWithLevel::LevelAndProbability> vad_results =
+  const VadWithLevel::LevelAndProbability vad_result =
       vad_.AnalyzeFrame(float_frame);
-  for (const auto& vad_result : vad_results) {
-    apm_data_dumper_->DumpRaw("agc2_vad_probability",
-                              vad_result.speech_probability);
-    apm_data_dumper_->DumpRaw("agc2_vad_rms_dbfs", vad_result.speech_rms_dbfs);
+  apm_data_dumper_->DumpRaw("agc2_vad_probability",
+                            vad_result.speech_probability);
+  apm_data_dumper_->DumpRaw("agc2_vad_rms_dbfs", vad_result.speech_rms_dbfs);
 
-    apm_data_dumper_->DumpRaw("agc2_vad_peak_dbfs",
-                              vad_result.speech_peak_dbfs);
-    speech_level_estimator_.UpdateEstimation(vad_result);
-  }
+  apm_data_dumper_->DumpRaw("agc2_vad_peak_dbfs", vad_result.speech_peak_dbfs);
+  speech_level_estimator_.UpdateEstimation(vad_result);
 
   const float speech_level_dbfs = speech_level_estimator_.LatestLevelEstimate();
 
@@ -57,7 +54,7 @@
   apm_data_dumper_->DumpRaw("agc2_noise_estimate_dbfs", noise_level_dbfs);
 
   // The gain applier applies the gain.
-  gain_applier_.Process(speech_level_dbfs, noise_level_dbfs, vad_results,
+  gain_applier_.Process(speech_level_dbfs, noise_level_dbfs, vad_result,
                         float_frame);
 }
 
diff --git a/modules/audio_processing/agc2/adaptive_agc.h b/modules/audio_processing/agc2/adaptive_agc.h
index a91aa2a..dabe783 100644
--- a/modules/audio_processing/agc2/adaptive_agc.h
+++ b/modules/audio_processing/agc2/adaptive_agc.h
@@ -16,8 +16,8 @@
 #include "modules/audio_processing/agc2/adaptive_digital_gain_applier.h"
 #include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h"
 #include "modules/audio_processing/agc2/noise_level_estimator.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
 #include "modules/audio_processing/include/audio_frame_view.h"
-#include "modules/audio_processing/vad/vad_with_level.h"
 
 namespace webrtc {
 class ApmDataDumper;
diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc b/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
index 20b5a27..ca6ec5d 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
@@ -74,10 +74,11 @@
 void AdaptiveDigitalGainApplier::Process(
     float input_level_dbfs,
     float input_noise_level_dbfs,
-    rtc::ArrayView<const VadWithLevel::LevelAndProbability> vad_results,
+    const VadWithLevel::LevelAndProbability vad_result,
     AudioFrameView<float> float_frame) {
+  input_level_dbfs = std::min(input_level_dbfs, 0.f);
+
   RTC_DCHECK_GE(input_level_dbfs, -150.f);
-  RTC_DCHECK_LE(input_level_dbfs, 0.f);
   RTC_DCHECK_GE(float_frame.num_channels(), 1);
   RTC_DCHECK_GE(float_frame.samples_per_channel(), 1);
 
@@ -85,21 +86,9 @@
       LimitGainByNoise(ComputeGainDb(input_level_dbfs), input_noise_level_dbfs,
                        apm_data_dumper_);
 
-  // TODO(webrtc:7494): Remove this construct. Remove the vectors from
-  // VadWithData after we move to a VAD that outputs an estimate every
-  // kFrameDurationMs ms.
-  //
-  // Forbid increasing the gain when there is no speech. For some
-  // VADs, 'vad_results' has either many or 0 results. If there are 0
-  // results, keep the old flag. If there are many results, and at
-  // least one is confident speech, we allow attenuation.
-  if (!vad_results.empty()) {
-    gain_increase_allowed_ = std::all_of(
-        vad_results.begin(), vad_results.end(),
-        [](const VadWithLevel::LevelAndProbability& vad_result) {
-          return vad_result.speech_probability > kVadConfidenceThreshold;
-        });
-  }
+  // Forbid increasing the gain when there is no speech.
+  gain_increase_allowed_ =
+      vad_result.speech_probability > kVadConfidenceThreshold;
 
   const float gain_change_this_frame_db = ComputeGainChangeThisFrameDb(
       target_gain_db, last_gain_db_, gain_increase_allowed_);
diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier.h b/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
index b06c65b..31f87f1 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
@@ -13,8 +13,8 @@
 
 #include "modules/audio_processing/agc2/agc2_common.h"
 #include "modules/audio_processing/agc2/gain_applier.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
 #include "modules/audio_processing/include/audio_frame_view.h"
-#include "modules/audio_processing/vad/vad_with_level.h"
 
 namespace webrtc {
 
@@ -24,11 +24,10 @@
  public:
   explicit AdaptiveDigitalGainApplier(ApmDataDumper* apm_data_dumper);
   // Decide what gain to apply.
-  void Process(
-      float input_level_dbfs,
-      float input_noise_level_dbfs,
-      rtc::ArrayView<const VadWithLevel::LevelAndProbability> vad_results,
-      AudioFrameView<float> float_frame);
+  void Process(float input_level_dbfs,
+               float input_noise_level_dbfs,
+               const VadWithLevel::LevelAndProbability vad_result,
+               AudioFrameView<float> float_frame);
 
  private:
   float last_gain_db_ = kInitialAdaptiveDigitalGainDb;
diff --git a/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc b/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
index ebb040e..ea9e5c7 100644
--- a/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
+++ b/modules/audio_processing/agc2/adaptive_digital_gain_applier_unittest.cc
@@ -33,10 +33,8 @@
 
   for (int i = 0; i < num_iterations; ++i) {
     VectorFloatFrame fake_audio(1, 1, 1.f);
-    gain_applier->Process(
-        input_level_dbfs, kNoNoiseDbfs,
-        rtc::ArrayView<const VadWithLevel::LevelAndProbability>(&vad_data, 1),
-        fake_audio.float_frame_view());
+    gain_applier->Process(input_level_dbfs, kNoNoiseDbfs, vad_data,
+                          fake_audio.float_frame_view());
     gain_linear = fake_audio.float_frame_view().channel(0)[0];
   }
   return gain_linear;
@@ -54,10 +52,8 @@
 
   // Make one call with reasonable audio level values and settings.
   VectorFloatFrame fake_audio(2, 480, 10000.f);
-  gain_applier.Process(
-      -5.0, kNoNoiseDbfs,
-      rtc::ArrayView<const VadWithLevel::LevelAndProbability>(&kVadSpeech, 1),
-      fake_audio.float_frame_view());
+  gain_applier.Process(-5.0, kNoNoiseDbfs, kVadSpeech,
+                       fake_audio.float_frame_view());
 }
 
 // Check that the output is -kHeadroom dBFS.
@@ -107,10 +103,8 @@
   for (int i = 0; i < kNumFramesToAdapt; ++i) {
     SCOPED_TRACE(i);
     VectorFloatFrame fake_audio(1, 1, 1.f);
-    gain_applier.Process(
-        initial_level_dbfs, kNoNoiseDbfs,
-        rtc::ArrayView<const VadWithLevel::LevelAndProbability>(&kVadSpeech, 1),
-        fake_audio.float_frame_view());
+    gain_applier.Process(initial_level_dbfs, kNoNoiseDbfs, kVadSpeech,
+                         fake_audio.float_frame_view());
     float current_gain_linear = fake_audio.float_frame_view().channel(0)[0];
     EXPECT_LE(std::abs(current_gain_linear - last_gain_linear),
               kMaxChangePerFrameLinear);
@@ -121,10 +115,8 @@
   for (int i = 0; i < kNumFramesToAdapt; ++i) {
     SCOPED_TRACE(i);
     VectorFloatFrame fake_audio(1, 1, 1.f);
-    gain_applier.Process(
-        0.f, kNoNoiseDbfs,
-        rtc::ArrayView<const VadWithLevel::LevelAndProbability>(&kVadSpeech, 1),
-        fake_audio.float_frame_view());
+    gain_applier.Process(0.f, kNoNoiseDbfs, kVadSpeech,
+                         fake_audio.float_frame_view());
     float current_gain_linear = fake_audio.float_frame_view().channel(0)[0];
     EXPECT_LE(std::abs(current_gain_linear - last_gain_linear),
               kMaxChangePerFrameLinear);
@@ -140,10 +132,8 @@
   constexpr int num_samples = 480;
 
   VectorFloatFrame fake_audio(1, num_samples, 1.f);
-  gain_applier.Process(
-      initial_level_dbfs, kNoNoiseDbfs,
-      rtc::ArrayView<const VadWithLevel::LevelAndProbability>(&kVadSpeech, 1),
-      fake_audio.float_frame_view());
+  gain_applier.Process(initial_level_dbfs, kNoNoiseDbfs, kVadSpeech,
+                       fake_audio.float_frame_view());
   float maximal_difference = 0.f;
   float current_value = 1.f * DbToRatio(kInitialAdaptiveDigitalGainDb);
   for (const auto& x : fake_audio.float_frame_view().channel(0)) {
@@ -172,10 +162,8 @@
 
   for (int i = 0; i < num_initial_frames + num_frames; ++i) {
     VectorFloatFrame fake_audio(1, num_samples, 1.f);
-    gain_applier.Process(
-        initial_level_dbfs, kWithNoiseDbfs,
-        rtc::ArrayView<const VadWithLevel::LevelAndProbability>(&kVadSpeech, 1),
-        fake_audio.float_frame_view());
+    gain_applier.Process(initial_level_dbfs, kWithNoiseDbfs, kVadSpeech,
+                         fake_audio.float_frame_view());
 
     // Wait so that the adaptive gain applier has time to lower the gain.
     if (i > num_initial_frames) {
@@ -187,4 +175,14 @@
     }
   }
 }
+
+TEST(AutomaticGainController2GainApplier, CanHandlePositiveSpeechLevels) {
+  ApmDataDumper apm_data_dumper(0);
+  AdaptiveDigitalGainApplier gain_applier(&apm_data_dumper);
+
+  // Make one call with positive audio level values and settings.
+  VectorFloatFrame fake_audio(2, 480, 10000.f);
+  gain_applier.Process(5.0f, kNoNoiseDbfs, kVadSpeech,
+                       fake_audio.float_frame_view());
+}
 }  // namespace webrtc
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc b/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
index 6aa2e91..b670f4b 100644
--- a/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
@@ -56,7 +56,15 @@
 float AdaptiveModeLevelEstimator::LatestLevelEstimate() const {
   return rtc::SafeClamp<float>(
       last_estimate_with_offset_dbfs_ + saturation_protector_.LastMargin(),
-      -90.f, 0.f);
+      -90.f, 30.f);
+}
+
+void AdaptiveModeLevelEstimator::Reset() {
+  buffer_size_ms_ = 0;
+  last_estimate_with_offset_dbfs_ = kInitialSpeechLevelEstimateDbfs;
+  estimate_numerator_ = 0.f;
+  estimate_denominator_ = 0.f;
+  saturation_protector_.Reset();
 }
 
 void AdaptiveModeLevelEstimator::DebugDumpEstimate() {
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator.h b/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
index 9762f1f..5ca7c55 100644
--- a/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
@@ -12,7 +12,7 @@
 #define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_
 
 #include "modules/audio_processing/agc2/saturation_protector.h"
-#include "modules/audio_processing/vad/vad_with_level.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
 
 namespace webrtc {
 class ApmDataDumper;
@@ -22,6 +22,7 @@
   explicit AdaptiveModeLevelEstimator(ApmDataDumper* apm_data_dumper);
   void UpdateEstimation(const VadWithLevel::LevelAndProbability& vad_data);
   float LatestLevelEstimate() const;
+  void Reset();
 
  private:
   void DebugDumpEstimate();
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc b/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc
new file mode 100644
index 0000000..b0922be
--- /dev/null
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h"
+
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+
+AdaptiveModeLevelEstimatorAgc::AdaptiveModeLevelEstimatorAgc(
+    ApmDataDumper* apm_data_dumper)
+    : level_estimator_(apm_data_dumper) {
+  set_target_level_dbfs(kDefaultLevelDbfs);
+}
+
+// |audio| must be mono; in a multi-channel stream, provide the first (usually
+// left) channel.
+void AdaptiveModeLevelEstimatorAgc::Process(const int16_t* audio,
+                                            size_t length,
+                                            int sample_rate_hz) {
+  std::vector<float> float_audio_frame(audio, audio + length);
+  const float* const first_channel = &float_audio_frame[0];
+  AudioFrameView<const float> frame_view(&first_channel, 1 /* num channels */,
+                                         length);
+  const auto vad_prob = agc2_vad_.AnalyzeFrame(frame_view);
+  latest_voice_probability_ = vad_prob.speech_probability;
+  if (latest_voice_probability_ > kVadConfidenceThreshold) {
+    time_in_ms_since_last_estimate_ += kFrameDurationMs;
+  }
+  level_estimator_.UpdateEstimation(vad_prob);
+}
+
+// Retrieves the difference between the target RMS level and the current
+// signal RMS level in dB. Returns true if an update is available and false
+// otherwise, in which case |error| should be ignored and no action taken.
+bool AdaptiveModeLevelEstimatorAgc::GetRmsErrorDb(int* error) {
+  if (time_in_ms_since_last_estimate_ <= kTimeUntilConfidentMs) {
+    return false;
+  }
+  *error = std::floor(target_level_dbfs() -
+                      level_estimator_.LatestLevelEstimate() + 0.5f);
+  time_in_ms_since_last_estimate_ = 0;
+  return true;
+}
+
+void AdaptiveModeLevelEstimatorAgc::Reset() {
+  level_estimator_.Reset();
+}
+
+float AdaptiveModeLevelEstimatorAgc::voice_probability() const {
+  return latest_voice_probability_;
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h b/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h
new file mode 100644
index 0000000..df01dd9
--- /dev/null
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_
+
+#include <vector>
+
+#include "modules/audio_processing/agc/agc.h"
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
+
+namespace webrtc {
+class AdaptiveModeLevelEstimatorAgc : public Agc {
+ public:
+  explicit AdaptiveModeLevelEstimatorAgc(ApmDataDumper* apm_data_dumper);
+
+  // |audio| must be mono; in a multi-channel stream, provide the first (usually
+  // left) channel.
+  void Process(const int16_t* audio,
+               size_t length,
+               int sample_rate_hz) override;
+
+  // Retrieves the difference between the target RMS level and the current
+  // signal RMS level in dB. Returns true if an update is available and false
+  // otherwise, in which case |error| should be ignored and no action taken.
+  bool GetRmsErrorDb(int* error) override;
+  void Reset() override;
+
+  float voice_probability() const override;
+
+ private:
+  static constexpr int kTimeUntilConfidentMs = 700;
+  static constexpr int kDefaultLevelDbfs = 0;
+  int32_t time_in_ms_since_last_estimate_ = 0;
+  AdaptiveModeLevelEstimator level_estimator_;
+  VadWithLevel agc2_vad_;
+  float latest_voice_probability_ = 0.f;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_
diff --git a/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc b/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc
index 71909d0..1915ce2 100644
--- a/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc
+++ b/modules/audio_processing/agc2/adaptive_mode_level_estimator_unittest.cc
@@ -76,7 +76,7 @@
   ApmDataDumper apm_data_dumper(0);
   AdaptiveModeLevelEstimator level_estimator(&apm_data_dumper);
 
-  // Run for one 'window size' interval
+  // Run for one 'window size' interval.
   constexpr float kInitialSpeechRmsDbfs = -30.f;
   RunOnConstantLevel(
       kFullBufferSizeMs / kFrameDurationMs,
@@ -88,7 +88,7 @@
   // Run for one half 'window size' interval. This should not be enough to
   // adapt.
   constexpr float kDifferentSpeechRmsDbfs = -10.f;
-  // It should at most differ by 25% after one 'window size' interval.
+  // It should at most differ by 25% after one half 'window size' interval.
   const float kMaxDifferenceDb =
       0.25 * std::abs(kDifferentSpeechRmsDbfs - kInitialSpeechRmsDbfs);
   RunOnConstantLevel(
@@ -109,7 +109,41 @@
           kDifferentSpeechRmsDbfs),
       &level_estimator);
   EXPECT_NEAR(level_estimator.LatestLevelEstimate(), kDifferentSpeechRmsDbfs,
-              kMaxDifferenceDb);
+              kMaxDifferenceDb * 0.5f);
+}
+
+TEST(AutomaticGainController2AdaptiveModeLevelEstimator,
+     ResetGivesFastAdaptation) {
+  ApmDataDumper apm_data_dumper(0);
+  AdaptiveModeLevelEstimator level_estimator(&apm_data_dumper);
+
+  // Run the level estimator for one window size interval. This gives time to
+  // adapt.
+  constexpr float kInitialSpeechRmsDbfs = -30.f;
+  RunOnConstantLevel(
+      kFullBufferSizeMs / kFrameDurationMs,
+      VadWithLevel::LevelAndProbability(
+          1.f, kInitialSpeechRmsDbfs - kInitialSaturationMarginDb,
+          kInitialSpeechRmsDbfs),
+      &level_estimator);
+
+  constexpr float kDifferentSpeechRmsDbfs = -10.f;
+  // Reset and run one half window size interval.
+  level_estimator.Reset();
+
+  RunOnConstantLevel(
+      kFullBufferSizeMs / kFrameDurationMs / 2,
+      VadWithLevel::LevelAndProbability(
+          1.f, kDifferentSpeechRmsDbfs - kInitialSaturationMarginDb,
+          kDifferentSpeechRmsDbfs),
+      &level_estimator);
+
+  // The level should be close to 'kDifferentSpeechRmsDbfs'.
+  const float kMaxDifferenceDb =
+      0.1f * std::abs(kDifferentSpeechRmsDbfs - kInitialSpeechRmsDbfs);
+  EXPECT_LT(
+      std::abs(kDifferentSpeechRmsDbfs - level_estimator.LatestLevelEstimate()),
+      kMaxDifferenceDb);
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/agc2/agc2_common.h b/modules/audio_processing/agc2/agc2_common.h
index 3a499d9..35e8f58 100644
--- a/modules/audio_processing/agc2/agc2_common.h
+++ b/modules/audio_processing/agc2/agc2_common.h
@@ -11,9 +11,9 @@
 #ifndef MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_
 #define MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_
 
-#include <cmath>
+#include <stddef.h>
 
-#include "rtc_base/basictypes.h"
+#include <cmath>
 
 namespace webrtc {
 
@@ -38,13 +38,13 @@
 // This parameter must be tuned together with the noise estimator.
 constexpr float kMaxNoiseLevelDbfs = -50.f;
 
-// Used in the Level Estimator for deciding when to update the speech
-// level estimate. Also used in the adaptive digital gain applier to
-// decide when to allow target gain reduction.
-constexpr float kVadConfidenceThreshold = 0.9f;
+// This is the threshold for speech. Speech frames are used for updating the
+// speech level, measuring the amount of speech, and decide when to allow target
+// gain reduction.
+constexpr float kVadConfidenceThreshold = 0.4f;
 
 // The amount of 'memory' of the Level Estimator. Decides leak factors.
-constexpr size_t kFullBufferSizeMs = 1000;
+constexpr size_t kFullBufferSizeMs = 1600;
 constexpr float kFullBufferLeakFactor = 1.f - 1.f / kFullBufferSizeMs;
 
 constexpr float kInitialSpeechLevelEstimateDbfs = -30.f;
@@ -52,7 +52,10 @@
 // Saturation Protector settings.
 constexpr float kInitialSaturationMarginDb = 17.f;
 
-constexpr size_t kPeakEnveloperSuperFrameLengthMs = 500;
+constexpr size_t kPeakEnveloperSuperFrameLengthMs = 400;
+static_assert(kFullBufferSizeMs % kPeakEnveloperSuperFrameLengthMs == 0,
+              "Full buffer size should be a multiple of super frame length for "
+              "optimal Saturation Protector performance.");
 
 constexpr size_t kPeakEnveloperBufferSize =
     kFullBufferSizeMs / kPeakEnveloperSuperFrameLengthMs + 1;
diff --git a/modules/audio_processing/agc2/agc2_testing_common.h b/modules/audio_processing/agc2/agc2_testing_common.h
index 8c4f400..7bfadbb 100644
--- a/modules/audio_processing/agc2/agc2_testing_common.h
+++ b/modules/audio_processing/agc2/agc2_testing_common.h
@@ -16,7 +16,6 @@
 #include <limits>
 #include <vector>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/checks.h"
 
 namespace webrtc {
diff --git a/modules/audio_processing/agc2/biquad_filter.cc b/modules/audio_processing/agc2/biquad_filter.cc
index c15c644..9858d50 100644
--- a/modules/audio_processing/agc2/biquad_filter.cc
+++ b/modules/audio_processing/agc2/biquad_filter.cc
@@ -12,9 +12,8 @@
 
 namespace webrtc {
 
-// This method applies a biquad filter to an input signal x to produce an
-// output signal y. The biquad coefficients are specified at the construction
-// of the object.
+// Transposed direct form I implementation of a bi-quad filter applied to an
+// input signal |x| to produce an output signal |y|.
 void BiQuadFilter::Process(rtc::ArrayView<const float> x,
                            rtc::ArrayView<float> y) {
   for (size_t k = 0; k < x.size(); ++k) {
diff --git a/modules/audio_processing/agc2/biquad_filter.h b/modules/audio_processing/agc2/biquad_filter.h
index 4fd5e2e..284930c 100644
--- a/modules/audio_processing/agc2/biquad_filter.h
+++ b/modules/audio_processing/agc2/biquad_filter.h
@@ -19,6 +19,10 @@
 
 class BiQuadFilter {
  public:
+  // Normalized filter coefficients.
+  //        b_0 + b_1 • z^(-1) + b_2 • z^(-2)
+  // H(z) = ---------------------------------
+  //         1 + a_1 • z^(-1) + a_2 • z^(-2)
   struct BiQuadCoefficients {
     float b[3];
     float a[2];
@@ -30,13 +34,17 @@
     coefficients_ = coefficients;
   }
 
+  void Reset() { biquad_state_.Reset(); }
+
   // Produces a filtered output y of the input x. Both x and y need to
-  // have the same length.
+  // have the same length. In-place modification is allowed.
   void Process(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
 
  private:
   struct BiQuadState {
-    BiQuadState() {
+    BiQuadState() { Reset(); }
+
+    void Reset() {
       std::fill(b, b + arraysize(b), 0.f);
       std::fill(a, a + arraysize(a), 0.f);
     }
diff --git a/modules/audio_processing/agc2/biquad_filter_unittest.cc b/modules/audio_processing/agc2/biquad_filter_unittest.cc
new file mode 100644
index 0000000..cd9a272
--- /dev/null
+++ b/modules/audio_processing/agc2/biquad_filter_unittest.cc
@@ -0,0 +1,136 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/biquad_filter.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+
+// TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+// #include "test/fpe_observer.h"
+#include "rtc_base/gunit.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+constexpr size_t kFrameSize = 8;
+constexpr size_t kNumFrames = 4;
+using FloatArraySequence =
+    std::array<std::array<float, kFrameSize>, kNumFrames>;
+
+constexpr FloatArraySequence kBiQuadInputSeq = {
+    {{{-87.166290f, -8.029022f, 101.619583f, -0.294296f, -5.825764f, -8.890625f,
+       10.310432f, 54.845333f}},
+     {{-64.647644f, -6.883945f, 11.059189f, -95.242538f, -108.870834f,
+       11.024944f, 63.044102f, -52.709583f}},
+     {{-32.350529f, -18.108028f, -74.022339f, -8.986874f, -1.525581f,
+       103.705513f, 6.346226f, -14.319557f}},
+     {{22.645832f, -64.597153f, 55.462521f, -109.393188f, 10.117825f,
+       -40.019642f, -98.612228f, -8.330326f}}}};
+
+// Generated via "B, A = scipy.signal.butter(2, 30/12000, btype='highpass')"
+const BiQuadFilter::BiQuadCoefficients kBiQuadConfig = {
+    {0.99446179f, -1.98892358f, 0.99446179f},
+    {-1.98889291f, 0.98895425f}};
+
+// Comparing to scipy. The expected output is generated as follows:
+// zi = np.float32([0, 0])
+// for i in range(4):
+//   yn, zi = scipy.signal.lfilter(B, A, x[i], zi=zi)
+//   print(yn)
+constexpr FloatArraySequence kBiQuadOutputSeq = {
+    {{{-86.68354497f, -7.02175351f, 102.10290352f, -0.37487333f, -5.87205847f,
+       -8.85521608f, 10.33772563f, 54.51157181f}},
+     {{-64.92531604f, -6.76395978f, 11.15534507f, -94.68073341f, -107.18177856f,
+       13.24642474f, 64.84288941f, -50.97822629f}},
+     {{-30.1579652f, -15.64850899f, -71.06662821f, -5.5883229f, 1.91175353f,
+       106.5572003f, 8.57183046f, -12.06298473f}},
+     {{24.84286614f, -62.18094158f, 57.91488056f, -106.65685933f, 13.38760103f,
+       -36.60367134f, -94.44880104f, -3.59920354f}}}};
+
+// Fail for every pair from two equally sized rtc::ArrayView<float> views such
+// that their relative error is above a given threshold. If the expected value
+// of a pair is 0, the tolerance is used to check the absolute error.
+void ExpectNearRelative(rtc::ArrayView<const float> expected,
+                        rtc::ArrayView<const float> computed,
+                        const float tolerance) {
+  // The relative error is undefined when the expected value is 0.
+  // When that happens, check the absolute error instead. |safe_den| is used
+  // below to implement such logic.
+  auto safe_den = [](float x) { return (x == 0.f) ? 1.f : std::fabs(x); };
+  ASSERT_EQ(expected.size(), computed.size());
+  for (size_t i = 0; i < expected.size(); ++i) {
+    const float abs_diff = std::fabs(expected[i] - computed[i]);
+    // No failure when the values are equal.
+    if (abs_diff == 0.f)
+      continue;
+    SCOPED_TRACE(i);
+    SCOPED_TRACE(expected[i]);
+    SCOPED_TRACE(computed[i]);
+    EXPECT_LE(abs_diff / safe_den(expected[i]), tolerance);
+  }
+}
+
+}  // namespace
+
+TEST(BiQuadFilterTest, FilterNotInPlace) {
+  BiQuadFilter filter;
+  filter.Initialize(kBiQuadConfig);
+  std::array<float, kFrameSize> samples;
+
+  // TODO(https://bugs.webrtc.org/8948): Add when the issue is fixed.
+  // FloatingPointExceptionObserver fpe_observer;
+
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    SCOPED_TRACE(i);
+    filter.Process(kBiQuadInputSeq[i], samples);
+    ExpectNearRelative(kBiQuadOutputSeq[i], samples, 2e-4f);
+  }
+}
+
+TEST(BiQuadFilterTest, FilterInPlace) {
+  BiQuadFilter filter;
+  filter.Initialize(kBiQuadConfig);
+  std::array<float, kFrameSize> samples;
+
+  // TODO(https://bugs.webrtc.org/8948): Add when the issue is fixed.
+  // FloatingPointExceptionObserver fpe_observer;
+
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    SCOPED_TRACE(i);
+    std::copy(kBiQuadInputSeq[i].begin(), kBiQuadInputSeq[i].end(),
+              samples.begin());
+    filter.Process({samples}, {samples});
+    ExpectNearRelative(kBiQuadOutputSeq[i], samples, 2e-4f);
+  }
+}
+
+TEST(BiQuadFilterTest, Reset) {
+  BiQuadFilter filter;
+  filter.Initialize(kBiQuadConfig);
+
+  std::array<float, kFrameSize> samples1;
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    filter.Process(kBiQuadInputSeq[i], samples1);
+  }
+
+  filter.Reset();
+  std::array<float, kFrameSize> samples2;
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    filter.Process(kBiQuadInputSeq[i], samples2);
+  }
+
+  EXPECT_EQ(samples1, samples2);
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/fixed_gain_controller_unittest.cc b/modules/audio_processing/agc2/fixed_gain_controller_unittest.cc
index d688f6a..72bb409 100644
--- a/modules/audio_processing/agc2/fixed_gain_controller_unittest.cc
+++ b/modules/audio_processing/agc2/fixed_gain_controller_unittest.cc
@@ -10,12 +10,12 @@
 
 #include "modules/audio_processing/agc2/fixed_gain_controller.h"
 
+#include "absl/memory/memory.h"
 #include "api/array_view.h"
 #include "modules/audio_processing/agc2/agc2_testing_common.h"
 #include "modules/audio_processing/agc2/vector_float_frame.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/gunit.h"
-#include "rtc_base/ptr_util.h"
 
 namespace webrtc {
 namespace {
@@ -51,7 +51,7 @@
     float gain_to_apply,
     size_t rate) {
   std::unique_ptr<FixedGainController> fgc =
-      rtc::MakeUnique<FixedGainController>(&test_data_dumper);
+      absl::make_unique<FixedGainController>(&test_data_dumper);
   fgc->SetGain(gain_to_apply);
   fgc->SetSampleRate(rate);
   return fgc;
diff --git a/modules/audio_processing/agc2/gain_applier_unittest.cc b/modules/audio_processing/agc2/gain_applier_unittest.cc
index bbf3a85..3296345 100644
--- a/modules/audio_processing/agc2/gain_applier_unittest.cc
+++ b/modules/audio_processing/agc2/gain_applier_unittest.cc
@@ -72,8 +72,7 @@
     float last_signal_level = initial_signal_level;
     for (const auto sample : fake_audio.float_frame_view().channel(channel)) {
       const float current_change = fabs(last_signal_level - sample);
-      max_signal_change =
-          std::max(max_signal_change, current_change);
+      max_signal_change = std::max(max_signal_change, current_change);
       last_signal_level = sample;
     }
     const float total_gain_change =
diff --git a/modules/audio_processing/agc2/interpolated_gain_curve.h b/modules/audio_processing/agc2/interpolated_gain_curve.h
index ddceaaa..fc5842b 100644
--- a/modules/audio_processing/agc2/interpolated_gain_curve.h
+++ b/modules/audio_processing/agc2/interpolated_gain_curve.h
@@ -14,7 +14,7 @@
 #include <array>
 
 #include "modules/audio_processing/agc2/agc2_common.h"
-#include "rtc_base/basictypes.h"
+
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/gtest_prod_util.h"
 
diff --git a/modules/audio_processing/agc2/rnn_vad/BUILD.gn b/modules/audio_processing/agc2/rnn_vad/BUILD.gn
index e05dcab..41521df 100644
--- a/modules/audio_processing/agc2/rnn_vad/BUILD.gn
+++ b/modules/audio_processing/agc2/rnn_vad/BUILD.gn
@@ -14,9 +14,13 @@
   ]
 }
 
-source_set("lib") {
+rtc_source_set("lib") {
   sources = [
     "common.h",
+    "features_extraction.cc",
+    "features_extraction.h",
+    "fft_util.cc",
+    "fft_util.h",
     "lp_residual.cc",
     "lp_residual.h",
     "pitch_info.h",
@@ -25,17 +29,28 @@
     "pitch_search_internal.cc",
     "pitch_search_internal.h",
     "ring_buffer.h",
+    "rnn.cc",
+    "rnn.h",
     "sequence_buffer.h",
+    "spectral_features.cc",
+    "spectral_features.h",
+    "spectral_features_internal.cc",
+    "spectral_features_internal.h",
     "symmetric_matrix_buffer.h",
   ]
   deps = [
+    "..:biquad_filter",
     "../../../../api:array_view",
+    "../../../../common_audio/",
     "../../../../rtc_base:checks",
+    "../../../../rtc_base:rtc_base_approved",
+    "//third_party/rnnoise:kiss_fft",
+    "//third_party/rnnoise:rnn_vad",
   ]
 }
 
 if (rtc_include_tests) {
-  source_set("lib_test") {
+  rtc_source_set("lib_test") {
     testonly = true
     sources = [
       "test_utils.cc",
@@ -47,12 +62,19 @@
       "../../../../rtc_base:ptr_util",
       "../../../../test:fileutils",
       "../../../../test:test_support",
+      "//third_party/abseil-cpp/absl/memory",
     ]
   }
 
   unittest_resources = [
+    "../../../../resources/audio_processing/agc2/rnn_vad/band_energies.dat",
+    "../../../../resources/audio_processing/agc2/rnn_vad/fft.dat",
     "../../../../resources/audio_processing/agc2/rnn_vad/pitch_buf_24k.dat",
+    "../../../../resources/audio_processing/agc2/rnn_vad/pitch_search_int.dat",
     "../../../../resources/audio_processing/agc2/rnn_vad/pitch_lp_res.dat",
+    "../../../../resources/audio_processing/agc2/rnn_vad/samples.pcm",
+    "../../../../resources/audio_processing/agc2/rnn_vad/sil_features.dat",
+    "../../../../resources/audio_processing/agc2/rnn_vad/vad_prob.dat",
   ]
 
   if (is_ios) {
@@ -68,18 +90,29 @@
   rtc_source_set("unittests") {
     testonly = true
     sources = [
+      "features_extraction_unittest.cc",
+      "fft_util_unittest.cc",
       "lp_residual_unittest.cc",
       "pitch_search_internal_unittest.cc",
       "pitch_search_unittest.cc",
       "ring_buffer_unittest.cc",
+      "rnn_unittest.cc",
+      "rnn_vad_unittest.cc",
       "sequence_buffer_unittest.cc",
+      "spectral_features_internal_unittest.cc",
+      "spectral_features_unittest.cc",
       "symmetric_matrix_buffer_unittest.cc",
     ]
     deps = [
       ":lib",
       ":lib_test",
+      "../..:audioproc_test_utils",
       "../../../../api:array_view",
+      "../../../../common_audio/",
+      "../../../../rtc_base:checks",
+      "../../../../rtc_base:logging",
       "../../../../test:test_support",
+      "//third_party/rnnoise:rnn_vad",
     ]
     data = unittest_resources
     if (is_ios) {
diff --git a/modules/audio_processing/agc2/rnn_vad/DEPS b/modules/audio_processing/agc2/rnn_vad/DEPS
new file mode 100644
index 0000000..773c2d7
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/rnnoise",
+]
diff --git a/modules/audio_processing/agc2/rnn_vad/common.h b/modules/audio_processing/agc2/rnn_vad/common.h
index 252bf84..b98438d 100644
--- a/modules/audio_processing/agc2/rnn_vad/common.h
+++ b/modules/audio_processing/agc2/rnn_vad/common.h
@@ -14,6 +14,8 @@
 namespace webrtc {
 namespace rnn_vad {
 
+constexpr double kPi = 3.14159265358979323846;
+
 constexpr size_t kSampleRate24kHz = 24000;
 constexpr size_t kFrameSize10ms24kHz = kSampleRate24kHz / 100;
 constexpr size_t kFrameSize20ms24kHz = kFrameSize10ms24kHz * 2;
@@ -43,6 +45,22 @@
 constexpr size_t kMinPitch48kHz = kMinPitch24kHz * 2;
 constexpr size_t kMaxPitch48kHz = kMaxPitch24kHz * 2;
 
+// Sub-band frequency boundaries.
+constexpr size_t kNumBands = 22;
+constexpr int kBandFrequencyBoundaries[kNumBands] = {
+    0,    200,  400,  600,  800,  1000, 1200, 1400, 1600,  2000,  2400,
+    2800, 3200, 4000, 4800, 5600, 6800, 8000, 9600, 12000, 15600, 20000};
+
+// Feature extraction parameters.
+constexpr size_t kNumLowerBands = 6;
+static_assert((0 < kNumLowerBands) && (kNumLowerBands < kNumBands), "");
+constexpr size_t kSpectralCoeffsHistorySize = 8;
+static_assert(kSpectralCoeffsHistorySize > 2,
+              "The history size must at least be 3 to compute first and second "
+              "derivatives.");
+
+constexpr size_t kFeatureVectorSize = 42;
+
 }  // namespace rnn_vad
 }  // namespace webrtc
 
diff --git a/modules/audio_processing/agc2/rnn_vad/features_extraction.cc b/modules/audio_processing/agc2/rnn_vad/features_extraction.cc
new file mode 100644
index 0000000..8ab5673
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/features_extraction.cc
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+
+#include "modules/audio_processing/agc2/rnn_vad/lp_residual.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+// Generated via "B, A = scipy.signal.butter(2, 30/12000, btype='highpass')"
+const BiQuadFilter::BiQuadCoefficients kHpfConfig24k = {
+    {0.99446179f, -1.98892358f, 0.99446179f},
+    {-1.98889291f, 0.98895425f}};
+
+}  // namespace
+
+FeaturesExtractor::FeaturesExtractor()
+    : use_high_pass_filter_(false),
+      pitch_buf_24kHz_(),
+      pitch_buf_24kHz_view_(pitch_buf_24kHz_.GetBufferView()),
+      lp_residual_(kBufSize24kHz),
+      lp_residual_view_(lp_residual_.data(), kBufSize24kHz),
+      pitch_estimator_(),
+      reference_frame_view_(pitch_buf_24kHz_.GetMostRecentValuesView()) {
+  RTC_DCHECK_EQ(kBufSize24kHz, lp_residual_.size());
+  hpf_.Initialize(kHpfConfig24k);
+  Reset();
+}
+
+FeaturesExtractor::~FeaturesExtractor() = default;
+
+void FeaturesExtractor::Reset() {
+  pitch_buf_24kHz_.Reset();
+  spectral_features_extractor_.Reset();
+  if (use_high_pass_filter_)
+    hpf_.Reset();
+}
+
+bool FeaturesExtractor::CheckSilenceComputeFeatures(
+    rtc::ArrayView<const float, kFrameSize10ms24kHz> samples,
+    rtc::ArrayView<float, kFeatureVectorSize> feature_vector) {
+  // Pre-processing.
+  if (use_high_pass_filter_) {
+    std::array<float, kFrameSize10ms24kHz> samples_filtered;
+    hpf_.Process(samples, samples_filtered);
+    // Feed buffer with the pre-processed version of |samples|.
+    pitch_buf_24kHz_.Push(samples_filtered);
+  } else {
+    // Feed buffer with |samples|.
+    pitch_buf_24kHz_.Push(samples);
+  }
+  // Extract the LP residual.
+  float lpc_coeffs[kNumLpcCoefficients];
+  ComputeAndPostProcessLpcCoefficients(pitch_buf_24kHz_view_, lpc_coeffs);
+  ComputeLpResidual(lpc_coeffs, pitch_buf_24kHz_view_, lp_residual_view_);
+  // Estimate pitch on the LP-residual and write the normalized pitch period
+  // into the output vector (normalization based on training data stats).
+  pitch_info_48kHz_ = pitch_estimator_.Estimate(lp_residual_view_);
+  feature_vector[kFeatureVectorSize - 2] =
+      0.01f * (static_cast<int>(pitch_info_48kHz_.period) - 300);
+  // Extract lagged frames (according to the estimated pitch period).
+  RTC_DCHECK_LE(pitch_info_48kHz_.period / 2, kMaxPitch24kHz);
+  auto lagged_frame = pitch_buf_24kHz_view_.subview(
+      kMaxPitch24kHz - pitch_info_48kHz_.period / 2, kFrameSize20ms24kHz);
+  // Analyze reference and lagged frames checking if silence has been detected
+  // and write the feature vector.
+  return spectral_features_extractor_.CheckSilenceComputeFeatures(
+      reference_frame_view_, {lagged_frame.data(), kFrameSize20ms24kHz},
+      {{feature_vector.data() + kNumLowerBands, kNumBands - kNumLowerBands},
+       {feature_vector.data(), kNumLowerBands},
+       {feature_vector.data() + kNumBands, kNumLowerBands},
+       {feature_vector.data() + kNumBands + kNumLowerBands, kNumLowerBands},
+       {feature_vector.data() + kNumBands + 2 * kNumLowerBands, kNumLowerBands},
+       &feature_vector[kFeatureVectorSize - 1]});
+}
+
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/features_extraction.h b/modules/audio_processing/agc2/rnn_vad/features_extraction.h
new file mode 100644
index 0000000..1f63885
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/features_extraction.h
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/biquad_filter.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search.h"
+#include "modules/audio_processing/agc2/rnn_vad/sequence_buffer.h"
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Feature extractor to feed the VAD RNN.
+class FeaturesExtractor {
+ public:
+  FeaturesExtractor();
+  FeaturesExtractor(const FeaturesExtractor&) = delete;
+  FeaturesExtractor& operator=(const FeaturesExtractor&) = delete;
+  ~FeaturesExtractor();
+  void Reset();
+  // Analyzes the samples, computes the feature vector and returns true if
+  // silence is detected (false if not). When silence is detected,
+  // |feature_vector| is partially written and therefore must not be used to
+  // feed the VAD RNN.
+  bool CheckSilenceComputeFeatures(
+      rtc::ArrayView<const float, kFrameSize10ms24kHz> samples,
+      rtc::ArrayView<float, kFeatureVectorSize> feature_vector);
+
+ private:
+  const bool use_high_pass_filter_;
+  // TODO(bugs.webrtc.org/7494): Remove HPF depending on how AGC2 is used in APM
+  // and on whether an HPF is already used as pre-processing step in APM.
+  BiQuadFilter hpf_;
+  SequenceBuffer<float, kBufSize24kHz, kFrameSize10ms24kHz, kFrameSize20ms24kHz>
+      pitch_buf_24kHz_;
+  rtc::ArrayView<const float, kBufSize24kHz> pitch_buf_24kHz_view_;
+  std::vector<float> lp_residual_;
+  rtc::ArrayView<float, kBufSize24kHz> lp_residual_view_;
+  PitchEstimator pitch_estimator_;
+  rtc::ArrayView<const float, kFrameSize20ms24kHz> reference_frame_view_;
+  SpectralFeaturesExtractor spectral_features_extractor_;
+  PitchInfo pitch_info_48kHz_;
+};
+
+}  // namespace rnn_vad
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_
diff --git a/modules/audio_processing/agc2/rnn_vad/features_extraction_unittest.cc b/modules/audio_processing/agc2/rnn_vad/features_extraction_unittest.cc
new file mode 100644
index 0000000..c00fc23
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/features_extraction_unittest.cc
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+
+#include <cmath>
+#include <vector>
+
+#include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
+// TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+// #include "test/fpe_observer.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+namespace {
+
+constexpr size_t ceil(size_t n, size_t m) {
+  return (n + m - 1) / m;
+}
+
+// Number of 10 ms frames required to fill a pitch buffer having size
+// |kBufSize24kHz|.
+constexpr size_t kNumTestDataFrames = ceil(kBufSize24kHz, kFrameSize10ms24kHz);
+// Number of samples for the test data.
+constexpr size_t kNumTestDataSize = kNumTestDataFrames * kFrameSize10ms24kHz;
+
+// Verifies that the pitch in Hz is in the detectable range.
+bool PitchIsValid(float pitch_hz) {
+  const size_t pitch_period =
+      static_cast<size_t>(static_cast<float>(kSampleRate24kHz) / pitch_hz);
+  return kInitialMinPitch24kHz <= pitch_period &&
+         pitch_period <= kMaxPitch24kHz;
+}
+
+void CreatePureTone(float amplitude, float freq_hz, rtc::ArrayView<float> dst) {
+  for (size_t i = 0; i < dst.size(); ++i) {
+    dst[i] = amplitude * std::sin(2.f * kPi * freq_hz * i / kSampleRate24kHz);
+  }
+}
+
+// Feeds |features_extractor| with |samples| splitting it in 10 ms frames.
+// For every frame, the output is written into |feature_vector|. Returns true
+// if silence is detected in the last frame.
+bool FeedTestData(FeaturesExtractor* features_extractor,
+                  rtc::ArrayView<const float> samples,
+                  rtc::ArrayView<float, kFeatureVectorSize> feature_vector) {
+  // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+  // FloatingPointExceptionObserver fpe_observer;
+  bool is_silence = true;
+  const size_t num_frames = samples.size() / kFrameSize10ms24kHz;
+  for (size_t i = 0; i < num_frames; ++i) {
+    is_silence = features_extractor->CheckSilenceComputeFeatures(
+        {samples.data() + i * kFrameSize10ms24kHz, kFrameSize10ms24kHz},
+        feature_vector);
+  }
+  return is_silence;
+}
+
+}  // namespace
+
+// Extracts the features for two pure tones and verifies that the pitch field
+// values reflect the known tone frequencies.
+TEST(RnnVadTest, FeatureExtractionLowHighPitch) {
+  constexpr float amplitude = 1000.f;
+  constexpr float low_pitch_hz = 150.f;
+  constexpr float high_pitch_hz = 250.f;
+  ASSERT_TRUE(PitchIsValid(low_pitch_hz));
+  ASSERT_TRUE(PitchIsValid(high_pitch_hz));
+
+  FeaturesExtractor features_extractor;
+  std::vector<float> samples(kNumTestDataSize);
+  std::vector<float> feature_vector(kFeatureVectorSize);
+  ASSERT_EQ(kFeatureVectorSize, feature_vector.size());
+  rtc::ArrayView<float, kFeatureVectorSize> feature_vector_view(
+      feature_vector.data(), kFeatureVectorSize);
+
+  // Extract the normalized scalar feature that is proportional to the estimated
+  // pitch period.
+  constexpr size_t pitch_feature_index = kFeatureVectorSize - 2;
+  // Low frequency tone - i.e., high period.
+  CreatePureTone(amplitude, low_pitch_hz, samples);
+  ASSERT_FALSE(FeedTestData(&features_extractor, samples, feature_vector_view));
+  float high_pitch_period = feature_vector_view[pitch_feature_index];
+  // High frequency tone - i.e., low period.
+  features_extractor.Reset();
+  CreatePureTone(amplitude, high_pitch_hz, samples);
+  ASSERT_FALSE(FeedTestData(&features_extractor, samples, feature_vector_view));
+  float low_pitch_period = feature_vector_view[pitch_feature_index];
+  // Check.
+  EXPECT_LT(low_pitch_period, high_pitch_period);
+}
+
+}  // namespace test
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/fft_util.cc b/modules/audio_processing/agc2/rnn_vad/fft_util.cc
new file mode 100644
index 0000000..1017400
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/fft_util.cc
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/fft_util.h"
+
+#include <cmath>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+constexpr size_t kHalfFrameSize = kFrameSize20ms24kHz / 2;
+
+// Computes the first half of the Vorbis window.
+std::array<float, kHalfFrameSize> ComputeHalfVorbisWindow() {
+  std::array<float, kHalfFrameSize> half_window{};
+  for (size_t i = 0; i < kHalfFrameSize; ++i) {
+    half_window[i] =
+        std::sin(0.5 * kPi * std::sin(0.5 * kPi * (i + 0.5) / kHalfFrameSize) *
+                 std::sin(0.5 * kPi * (i + 0.5) / kHalfFrameSize));
+  }
+  return half_window;
+}
+
+}  // namespace
+
+BandAnalysisFft::BandAnalysisFft()
+    : half_window_(ComputeHalfVorbisWindow()),
+      fft_(static_cast<int>(input_buf_.size())) {}
+
+BandAnalysisFft::~BandAnalysisFft() = default;
+
+void BandAnalysisFft::ForwardFft(rtc::ArrayView<const float> samples,
+                                 rtc::ArrayView<std::complex<float>> dst) {
+  RTC_DCHECK_EQ(input_buf_.size(), samples.size());
+  RTC_DCHECK_EQ(samples.size(), dst.size());
+  // Apply windowing.
+  RTC_DCHECK_EQ(input_buf_.size(), 2 * half_window_.size());
+  for (size_t i = 0; i < input_buf_.size() / 2; ++i) {
+    input_buf_[i].real(samples[i] * half_window_[i]);
+    size_t j = kFrameSize20ms24kHz - i - 1;
+    input_buf_[j].real(samples[j] * half_window_[i]);
+  }
+  fft_.ForwardFft(kFrameSize20ms24kHz, input_buf_.data(), kFrameSize20ms24kHz,
+                  dst.data());
+}
+
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/fft_util.h b/modules/audio_processing/agc2/rnn_vad/fft_util.h
new file mode 100644
index 0000000..f4265f4
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/fft_util.h
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FFT_UTIL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FFT_UTIL_H_
+
+#include <array>
+#include <complex>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "third_party/rnnoise/src/kiss_fft.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// FFT implementation wrapper for the band-wise analysis step in which 20 ms
+// frames at 24 kHz are analyzed in the frequency domain. The goal of this class
+// are (i) making easy to switch to another FFT implementation, (ii) own the
+// input buffer for the FFT and (iii) apply a windowing function before
+// computing the FFT.
+class BandAnalysisFft {
+ public:
+  BandAnalysisFft();
+  BandAnalysisFft(const BandAnalysisFft&) = delete;
+  BandAnalysisFft& operator=(const BandAnalysisFft&) = delete;
+  ~BandAnalysisFft();
+  // Applies a windowing function to |samples|, computes the real forward FFT
+  // and writes the result in |dst|.
+  void ForwardFft(rtc::ArrayView<const float> samples,
+                  rtc::ArrayView<std::complex<float>> dst);
+
+ private:
+  static_assert((kFrameSize20ms24kHz & 1) == 0,
+                "kFrameSize20ms24kHz must be even.");
+  const std::array<float, kFrameSize20ms24kHz / 2> half_window_;
+  std::array<std::complex<float>, kFrameSize20ms24kHz> input_buf_{};
+  rnnoise::KissFft fft_;
+};
+
+}  // namespace rnn_vad
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FFT_UTIL_H_
diff --git a/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc b/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc
new file mode 100644
index 0000000..9854600
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/fft_util_unittest.cc
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include <array>
+
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/fft_util.h"
+#include "rtc_base/checks.h"
+// TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+// #include "test/fpe_observer.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+
+TEST(RnnVadTest, CheckBandAnalysisFftOutput) {
+  // Input data.
+  std::array<float, kFrameSize20ms24kHz> samples{};
+  for (int i = 0; i < static_cast<int>(kFrameSize20ms24kHz); ++i) {
+    samples[i] = i - static_cast<int>(kFrameSize20ms24kHz / 2);
+  }
+  // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+  // FloatingPointExceptionObserver fpe_observer;
+  BandAnalysisFft fft;
+  std::array<std::complex<float>, kFrameSize20ms24kHz> fft_coeffs;
+  fft.ForwardFft(samples, fft_coeffs);
+  // First coefficient is DC - i.e., real number.
+  EXPECT_EQ(0.f, fft_coeffs[0].imag());
+  // Check conjugated symmetry of the FFT output.
+  for (size_t i = 1; i < fft_coeffs.size() / 2; ++i) {
+    SCOPED_TRACE(i);
+    const auto& a = fft_coeffs[i];
+    const auto& b = fft_coeffs[fft_coeffs.size() - i];
+    EXPECT_NEAR(a.real(), b.real(), 2e-6f);
+    EXPECT_NEAR(a.imag(), -b.imag(), 2e-6f);
+  }
+}
+
+}  // namespace test
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/lp_residual.cc b/modules/audio_processing/agc2/rnn_vad/lp_residual.cc
index 483336d..1a124a3 100644
--- a/modules/audio_processing/agc2/rnn_vad/lp_residual.cc
+++ b/modules/audio_processing/agc2/rnn_vad/lp_residual.cc
@@ -12,6 +12,7 @@
 
 #include <algorithm>
 #include <array>
+#include <cmath>
 #include <numeric>
 
 #include "rtc_base/checks.h"
@@ -33,9 +34,10 @@
   constexpr size_t max_lag = x_corr.size();
   RTC_DCHECK_EQ(x.size(), y.size());
   RTC_DCHECK_LT(max_lag, x.size());
-  for (size_t lag = 0; lag < max_lag; ++lag)
+  for (size_t lag = 0; lag < max_lag; ++lag) {
     x_corr[lag] =
         std::inner_product(x.begin(), x.end() - lag, y.begin() + lag, 0.f);
+  }
 }
 
 // Applies denoising to the auto-correlation coefficients.
@@ -43,8 +45,9 @@
     rtc::ArrayView<float, kNumLpcCoefficients> auto_corr) {
   // Assume -40 dB white noise floor.
   auto_corr[0] *= 1.0001f;
-  for (size_t i = 1; i < kNumLpcCoefficients; ++i)
+  for (size_t i = 1; i < kNumLpcCoefficients; ++i) {
     auto_corr[i] -= auto_corr[i] * (0.008f * i) * (0.008f * i);
+  }
 }
 
 // Computes the initial inverse filter coefficients given the auto-correlation
@@ -55,9 +58,17 @@
   float error = auto_corr[0];
   for (size_t i = 0; i < kNumLpcCoefficients - 1; ++i) {
     float reflection_coeff = 0.f;
-    for (size_t j = 0; j < i; ++j)
+    for (size_t j = 0; j < i; ++j) {
       reflection_coeff += lpc_coeffs[j] * auto_corr[i - j];
+    }
     reflection_coeff += auto_corr[i + 1];
+
+    // Avoid division by numbers close to zero.
+    constexpr float kMinErrorMagnitude = 1e-6f;
+    if (std::fabs(error) < kMinErrorMagnitude) {
+      error = std::copysign(kMinErrorMagnitude, error);
+    }
+
     reflection_coeff /= -error;
     // Update LPC coefficients and total error.
     lpc_coeffs[i] = reflection_coeff;
@@ -68,8 +79,9 @@
       lpc_coeffs[i - 1 - j] = tmp2 + reflection_coeff * tmp1;
     }
     error -= reflection_coeff * reflection_coeff * error;
-    if (error < 0.001f * auto_corr[0])
+    if (error < 0.001f * auto_corr[0]) {
       break;
+    }
   }
 }
 
@@ -86,9 +98,7 @@
   }
   DenoiseAutoCorrelation({auto_corr.data(), auto_corr.size()});
   std::array<float, kNumLpcCoefficients - 1> lpc_coeffs_pre{};
-  ComputeInitialInverseFilterCoefficients(
-      {auto_corr.data(), auto_corr.size()},
-      {lpc_coeffs_pre.data(), lpc_coeffs_pre.size()});
+  ComputeInitialInverseFilterCoefficients(auto_corr, lpc_coeffs_pre);
   // LPC coefficients post-processing.
   // TODO(bugs.webrtc.org/9076): Consider removing these steps.
   float c1 = 1.f;
diff --git a/modules/audio_processing/agc2/rnn_vad/lp_residual_unittest.cc b/modules/audio_processing/agc2/rnn_vad/lp_residual_unittest.cc
index 23f1e14..47d8bf5 100644
--- a/modules/audio_processing/agc2/rnn_vad/lp_residual_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/lp_residual_unittest.cc
@@ -31,12 +31,10 @@
   empty_frame.fill(0.f);
   // Compute inverse filter coefficients.
   std::array<float, kNumLpcCoefficients> lpc_coeffs;
-  ComputeAndPostProcessLpcCoefficients({empty_frame},
-                                       {lpc_coeffs.data(), lpc_coeffs.size()});
+  ComputeAndPostProcessLpcCoefficients(empty_frame, lpc_coeffs);
   // Compute LP residual.
   std::array<float, kFrameSize10ms24kHz> lp_residual;
-  ComputeLpResidual({lpc_coeffs.data(), lpc_coeffs.size()}, {empty_frame},
-                    {lp_residual});
+  ComputeLpResidual(lpc_coeffs, empty_frame, lp_residual);
 }
 
 // TODO(bugs.webrtc.org/9076): Remove when the issue is fixed.
@@ -45,8 +43,6 @@
   auto pitch_buf_24kHz_reader = CreatePitchBuffer24kHzReader();
   const size_t num_frames = pitch_buf_24kHz_reader.second;
   std::array<float, kBufSize24kHz> pitch_buf_data;
-  rtc::ArrayView<float, kBufSize24kHz> pitch_buf_data_view(
-      pitch_buf_data.data(), pitch_buf_data.size());
   // Read ground-truth.
   auto lp_residual_reader = CreateLpResidualAndPitchPeriodGainReader();
   ASSERT_EQ(num_frames, lp_residual_reader.second);
@@ -63,20 +59,18 @@
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
     for (size_t i = 0; i < num_frames; ++i) {
       SCOPED_TRACE(i);
       // Read input and expected output.
-      pitch_buf_24kHz_reader.first->ReadChunk(pitch_buf_data_view);
+      pitch_buf_24kHz_reader.first->ReadChunk(pitch_buf_data);
       lp_residual_reader.first->ReadChunk(expected_lp_residual_view);
       // Skip pitch gain and period.
       float unused;
       lp_residual_reader.first->ReadValue(&unused);
       lp_residual_reader.first->ReadValue(&unused);
       // Run pipeline.
-      ComputeAndPostProcessLpcCoefficients(pitch_buf_data_view,
-                                           lpc_coeffs_view);
-      ComputeLpResidual(lpc_coeffs_view, pitch_buf_data_view,
+      ComputeAndPostProcessLpcCoefficients(pitch_buf_data, lpc_coeffs_view);
+      ComputeLpResidual(lpc_coeffs_view, pitch_buf_data,
                         computed_lp_residual_view);
       // Compare.
       ExpectNearAbsolute(expected_lp_residual_view, computed_lp_residual_view,
diff --git a/modules/audio_processing/agc2/rnn_vad/module.mk b/modules/audio_processing/agc2/rnn_vad/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search.cc
index 4d83588..1f8859d 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search.cc
@@ -9,26 +9,33 @@
  */
 
 #include "modules/audio_processing/agc2/rnn_vad/pitch_search.h"
-#include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h"
 
 namespace webrtc {
 namespace rnn_vad {
 
-PitchInfo PitchSearch(rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
-                      PitchInfo prev_pitch_48kHz) {
+PitchEstimator::PitchEstimator()
+    : fft_(RealFourier::Create(kAutoCorrelationFftOrder)),
+      pitch_buf_decimated_(kBufSize12kHz),
+      pitch_buf_decimated_view_(pitch_buf_decimated_.data(), kBufSize12kHz),
+      auto_corr_(kNumInvertedLags12kHz),
+      auto_corr_view_(auto_corr_.data(), kNumInvertedLags12kHz) {
+  RTC_DCHECK_EQ(kBufSize12kHz, pitch_buf_decimated_.size());
+  RTC_DCHECK_EQ(kNumInvertedLags12kHz, auto_corr_view_.size());
+}
+
+PitchEstimator::~PitchEstimator() = default;
+
+PitchInfo PitchEstimator::Estimate(
+    rtc::ArrayView<const float, kBufSize24kHz> pitch_buf) {
   // Perform the initial pitch search at 12 kHz.
-  std::array<float, kBufSize12kHz> pitch_buf_decimated;
-  Decimate2x(pitch_buf,
-             {pitch_buf_decimated.data(), pitch_buf_decimated.size()});
+  Decimate2x(pitch_buf, pitch_buf_decimated_view_);
   // Compute auto-correlation terms.
-  std::array<float, kNumInvertedLags12kHz> auto_corr;
-  ComputePitchAutoCorrelation(
-      {pitch_buf_decimated.data(), pitch_buf_decimated.size()}, kMaxPitch12kHz,
-      {auto_corr.data(), auto_corr.size()});
+  ComputePitchAutoCorrelation(pitch_buf_decimated_view_, kMaxPitch12kHz,
+                              auto_corr_view_, fft_.get());
+
   // Search for pitch at 12 kHz.
   std::array<size_t, 2> pitch_candidates_inv_lags = FindBestPitchPeriods(
-      {auto_corr.data(), auto_corr.size()},
-      {pitch_buf_decimated.data(), pitch_buf_decimated.size()}, kMaxPitch12kHz);
+      auto_corr_view_, pitch_buf_decimated_view_, kMaxPitch12kHz);
 
   // Refine the pitch period estimation.
   // The refinement is done using the pitch buffer that contains 24 kHz samples.
@@ -36,13 +43,13 @@
   // to 24 kHz.
   for (size_t i = 0; i < pitch_candidates_inv_lags.size(); ++i)
     pitch_candidates_inv_lags[i] *= 2;
-  size_t pitch_inv_lag_48kHz = RefinePitchPeriod48kHz(
-      pitch_buf,
-      {pitch_candidates_inv_lags.data(), pitch_candidates_inv_lags.size()});
+  size_t pitch_inv_lag_48kHz =
+      RefinePitchPeriod48kHz(pitch_buf, pitch_candidates_inv_lags);
   // Look for stronger harmonics to find the final pitch period and its gain.
   RTC_DCHECK_LT(pitch_inv_lag_48kHz, kMaxPitch48kHz);
-  return CheckLowerPitchPeriodsAndComputePitchGain(
-      pitch_buf, kMaxPitch48kHz - pitch_inv_lag_48kHz, prev_pitch_48kHz);
+  last_pitch_48kHz_ = CheckLowerPitchPeriodsAndComputePitchGain(
+      pitch_buf, kMaxPitch48kHz - pitch_inv_lag_48kHz, last_pitch_48kHz_);
+  return last_pitch_48kHz_;
 }
 
 }  // namespace rnn_vad
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search.h b/modules/audio_processing/agc2/rnn_vad/pitch_search.h
index a0af0eb..5914535 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search.h
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search.h
@@ -11,17 +11,37 @@
 #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_
 #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_
 
+#include <memory>
+#include <vector>
+
 #include "api/array_view.h"
+#include "common_audio/real_fourier.h"
 #include "modules/audio_processing/agc2/rnn_vad/common.h"
 #include "modules/audio_processing/agc2/rnn_vad/pitch_info.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h"
 
 namespace webrtc {
 namespace rnn_vad {
 
-// Searches the pitch period and gain. Return the pitch estimation data for
-// 48 kHz.
-PitchInfo PitchSearch(rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
-                      PitchInfo prev_pitch_48kHz);
+// Pitch estimator.
+class PitchEstimator {
+ public:
+  PitchEstimator();
+  PitchEstimator(const PitchEstimator&) = delete;
+  PitchEstimator& operator=(const PitchEstimator&) = delete;
+  ~PitchEstimator();
+  // Estimates the pitch period and gain. Returns the pitch estimation data for
+  // 48 kHz.
+  PitchInfo Estimate(rtc::ArrayView<const float, kBufSize24kHz> pitch_buf);
+
+ private:
+  PitchInfo last_pitch_48kHz_;
+  std::unique_ptr<RealFourier> fft_;
+  std::vector<float> pitch_buf_decimated_;
+  rtc::ArrayView<float, kBufSize12kHz> pitch_buf_decimated_view_;
+  std::vector<float> auto_corr_;
+  rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr_view_;
+};
 
 }  // namespace rnn_vad
 }  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
index 1ff4621..b7b44d2 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
@@ -140,8 +140,9 @@
                 rtc::ArrayView<float, kBufSize12kHz> dst) {
   // TODO(bugs.webrtc.org/9076): Consider adding anti-aliasing filter.
   static_assert(2 * dst.size() == src.size(), "");
-  for (size_t i = 0; i < dst.size(); ++i)
+  for (size_t i = 0; i < dst.size(); ++i) {
     dst[i] = src[2 * i];
+  }
 }
 
 float ComputePitchGainThreshold(size_t candidate_pitch_period,
@@ -205,18 +206,62 @@
   }
 }
 
-// TODO(bugs.webrtc.org/9076): Optimize using FFT and/or vectorization.
 void ComputePitchAutoCorrelation(
     rtc::ArrayView<const float, kBufSize12kHz> pitch_buf,
     size_t max_pitch_period,
-    rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr) {
+    rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr,
+    webrtc::RealFourier* fft) {
   RTC_DCHECK_GT(max_pitch_period, auto_corr.size());
   RTC_DCHECK_LT(max_pitch_period, pitch_buf.size());
-  // Compute auto-correlation coefficients.
-  for (size_t inv_lag = 0; inv_lag < auto_corr.size(); ++inv_lag) {
-    auto_corr[inv_lag] =
-        ComputeAutoCorrelationCoeff(pitch_buf, inv_lag, max_pitch_period);
+  RTC_DCHECK(fft);
+
+  constexpr size_t time_domain_fft_length = 1 << kAutoCorrelationFftOrder;
+  constexpr size_t freq_domain_fft_length = time_domain_fft_length / 2 + 1;
+
+  RTC_DCHECK_EQ(RealFourier::FftLength(fft->order()), time_domain_fft_length);
+  RTC_DCHECK_EQ(RealFourier::ComplexLength(fft->order()),
+                freq_domain_fft_length);
+
+  // Cross-correlation of y_i=pitch_buf[i:i+convolution_length] and
+  // x=pitch_buf[-convolution_length:] is equivalent to convolution of
+  // y_i and reversed(x). New notation: h=reversed(x), x=y.
+  std::array<float, time_domain_fft_length> h{};
+  std::array<float, time_domain_fft_length> x{};
+
+  const size_t convolution_length = kBufSize12kHz - max_pitch_period;
+  // Check that the FFT-length is big enough to avoid cyclic
+  // convolution errors.
+  RTC_DCHECK_GT(time_domain_fft_length,
+                kNumInvertedLags12kHz + convolution_length);
+
+  // h[0:convolution_length] is reversed pitch_buf[-convolution_length:].
+  std::reverse_copy(pitch_buf.end() - convolution_length, pitch_buf.end(),
+                    h.begin());
+
+  // x is pitch_buf[:kNumInvertedLags12kHz + convolution_length].
+  std::copy(pitch_buf.begin(),
+            pitch_buf.begin() + kNumInvertedLags12kHz + convolution_length,
+            x.begin());
+
+  // Shift to frequency domain.
+  std::array<std::complex<float>, freq_domain_fft_length> X{};
+  std::array<std::complex<float>, freq_domain_fft_length> H{};
+  fft->Forward(&x[0], &X[0]);
+  fft->Forward(&h[0], &H[0]);
+
+  // Convolve in frequency domain.
+  for (size_t i = 0; i < X.size(); ++i) {
+    X[i] *= H[i];
   }
+
+  // Shift back to time domain.
+  std::array<float, time_domain_fft_length> x_conv_h;
+  fft->Inverse(&X[0], &x_conv_h[0]);
+
+  // Collect the result.
+  std::copy(x_conv_h.begin() + convolution_length - 1,
+            x_conv_h.begin() + convolution_length + kNumInvertedLags12kHz - 1,
+            auto_corr.begin());
 }
 
 std::array<size_t, 2> FindBestPitchPeriods(
@@ -298,8 +343,7 @@
       {pitch_buf.data(), pitch_buf.size()}, kMaxPitch24kHz);
   const auto inv_lag = pitch_candidates_inv_lags[0];  // Refine the best.
   // Pseudo-interpolation.
-  return PitchPseudoInterpolationInvLagAutoCorr(
-      inv_lag, {auto_corr.data(), auto_corr.size()});
+  return PitchPseudoInterpolationInvLagAutoCorr(inv_lag, auto_corr);
 }
 
 PitchInfo CheckLowerPitchPeriodsAndComputePitchGain(
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
index dfe1b35..75f7f17 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
@@ -14,6 +14,7 @@
 #include <array>
 
 #include "api/array_view.h"
+#include "common_audio/real_fourier.h"
 #include "modules/audio_processing/agc2/rnn_vad/common.h"
 #include "modules/audio_processing/agc2/rnn_vad/pitch_info.h"
 
@@ -26,6 +27,11 @@
 static_assert(kMaxPitch24kHz > kInitialMinPitch24kHz, "");
 constexpr size_t kNumInvertedLags12kHz = kMaxPitch12kHz - kInitialMinPitch12kHz;
 constexpr size_t kNumInvertedLags24kHz = kMaxPitch24kHz - kInitialMinPitch24kHz;
+constexpr int kAutoCorrelationFftOrder = 9;  // Length-512 FFT.
+
+static_assert(1 << kAutoCorrelationFftOrder >
+                  kNumInvertedLags12kHz + kBufSize12kHz - kMaxPitch12kHz,
+              "");
 
 // Performs 2x decimation without any anti-aliasing filter.
 void Decimate2x(rtc::ArrayView<const float, kBufSize24kHz> src,
@@ -70,7 +76,8 @@
 void ComputePitchAutoCorrelation(
     rtc::ArrayView<const float, kBufSize12kHz> pitch_buf,
     size_t max_pitch_period,
-    rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr);
+    rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr,
+    webrtc::RealFourier* fft);
 
 // Given the auto-correlation coefficients stored according to
 // ComputePitchAutoCorrelation() (i.e., using inverted lags), returns the best
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc
index 9a6a267..82b4810 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_internal_unittest.cc
@@ -9,6 +9,7 @@
  */
 
 #include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h"
+#include "common_audio/real_fourier.h"
 
 #include <array>
 #include <tuple>
@@ -23,327 +24,39 @@
 namespace test {
 namespace {
 
-// TODO(bugs.webrtc.org/9076): Move to resource file.
-constexpr std::array<float, kBufSize24kHz> kPitchBufferData = {
-    -35.248100281f, -25.836528778f, 5.682674408f,  2.880297661f,  -1.648161888f,
-    -4.094896793f,  -3.500580072f,  -0.896141529f, -2.989939451f, -4.608089447f,
-    -3.721750736f,  -2.290785789f,  -3.326566458f, -4.370154381f, -3.221047878f,
-    -4.049056530f,  -2.846302271f,  -1.805017233f, -1.547624588f, -0.809937477f,
-    -1.446955442f,  -3.258146763f,  -1.849959373f, 0.005283833f,  -0.571619749f,
-    -0.630573988f,  -0.162780523f,  -2.699024916f, -0.856231451f, 2.748089552f,
-    2.026614428f,   -0.474685907f,  -0.571918726f, 1.186420918f,  1.770769954f,
-    2.017296791f,   1.154794335f,   1.082345366f,  1.954892635f,  2.249727726f,
-    2.643483400f,   1.857815385f,   0.064472735f,  0.015978813f,  0.301099658f,
-    0.478950322f,   -0.669701457f,  -0.654453993f, 1.338572979f,  -0.493052602f,
-    -1.763812065f,  0.524392128f,   0.010438919f,  -1.726593733f, -2.866710663f,
-    -2.065258503f,  -3.010460854f,  -3.994765282f, -4.102010250f, -3.135548830f,
-    -2.597487926f,  -2.255330563f,  -1.002008915f, 0.523116589f,  1.430158496f,
-    -1.655169368f,  -2.263641357f,  0.766040802f,  1.166070461f,  0.002490997f,
-    0.401043415f,   -0.158550858f,  -0.572042346f, 1.365390539f,  -1.397871614f,
-    -2.020734787f,  -1.979169965f,  -1.025816441f, 0.012545407f,  -1.042758584f,
-    -1.206598401f,  -1.140330791f,  -3.060853720f, -3.530077934f, -1.774474382f,
-    -1.342000484f,  -3.171817064f,  -2.489153862f, -1.593364000f, -2.552185535f,
-    -2.899760723f,  -4.698278427f,  -4.123534203f, -2.613421679f, -2.061793327f,
-    -4.113687515f,  -3.174087524f,  -2.367874622f, -4.523970604f, -4.250762939f,
-    -2.752931118f,  -1.547106743f,  -4.109455109f, -3.893044472f, -2.348384857f,
-    -3.194510698f,  -3.502159357f,  -2.785978794f, -1.981978416f, -3.279178143f,
-    -3.007923365f,  -1.801304340f,  -1.839247227f, -1.003675938f, -0.985928297f,
-    -1.647925615f,  -2.166392088f,  -1.947163343f, 0.488545895f,  1.567199469f,
-    -1.179960012f,  -2.710370064f,  -2.613196850f, -3.205850124f, -2.796218395f,
-    -0.715085745f,  1.406243801f,   -0.779834270f, -2.075612307f, -0.922246933f,
-    -1.849850416f,  0.979040504f,   3.570628166f,  0.945924520f,  -2.821768284f,
-    -6.262358189f,  -6.154916763f,  -0.567943573f, 2.386518955f,  1.673806906f,
-    -3.676584721f,  -7.129202843f,  -3.311969519f, 1.126702785f,  3.218248606f,
-    1.600885630f,   -1.709451079f,  -6.822564125f, -6.011950970f, -0.671678543f,
-    1.080205441f,   -1.342422366f,  -3.589303732f, -3.586701870f, -3.425134897f,
-    -1.078015327f,  2.556719542f,   0.469867468f,  0.139251709f,  -0.118916273f,
-    -1.284181952f,  0.941113472f,   0.550188303f,  -1.767568469f, -5.429461956f,
-    -5.065113068f,  -2.111886740f,  -3.606999397f, -2.410579205f, 1.013466120f,
-    1.057218194f,   0.305267453f,   2.898609161f,  5.776575565f,  4.792305946f,
-    -0.863526106f,  -2.439013481f,  -0.825202525f, -2.297998428f, -0.520106375f,
-    -0.653605103f,  -3.204111576f,  -2.455038786f, -2.160304308f, 0.622359931f,
-    3.803062916f,   4.340928555f,   2.390868664f,  1.645600080f,  0.405841053f,
-    -0.153203994f,  3.438643217f,   4.752261162f,  1.552502871f,  1.947945356f,
-    0.856451511f,   -0.606808305f,  -1.223945618f, -1.845071912f, -0.204472303f,
-    1.750840783f,   2.435559034f,   -1.253612280f, -2.675215721f, 1.614801407f,
-    3.002861023f,   1.743503809f,   3.409059286f,  4.303173542f,  2.441751957f,
-    1.752274275f,   1.874113560f,   2.070837736f,  1.401355743f,  -0.330647945f,
-    -0.664121151f,  1.196543574f,   1.506967187f,  0.985752344f,  -1.265938520f,
-    -1.433794141f,  0.380195618f,   0.061504841f,  1.079771042f,  1.773771763f,
-    3.226663589f,   4.170571804f,   4.220288277f,  3.619904041f,  2.316211224f,
-    2.012817860f,   0.370972633f,   0.517094851f,  1.869508862f,  0.357770681f,
-    -2.991472483f,  -3.216646433f,  0.232109070f,  1.803660274f,  2.928784370f,
-    4.909455776f,   5.913621426f,   4.653719902f,  4.387111187f,  4.793289661f,
-    4.744520187f,   5.214610100f,   3.996322632f,  2.619040728f,  0.758128643f,
-    -0.092789888f,  0.070066452f,   0.704165459f,  2.042234898f,  2.768569231f,
-    3.340583324f,   3.212181091f,   2.748130322f,  3.077554941f,  2.189792156f,
-    2.646749735f,   2.817450523f,   1.611892223f,  1.981805444f,  -1.088236094f,
-    -2.187484741f,  -0.654897690f,  -0.900939941f, 0.148309708f,  1.498139143f,
-    -0.261296749f,  -3.220157146f,  -1.727450609f, 0.807144105f,  -0.809251904f,
-    -2.361308336f,  -1.421746969f,  -0.793132067f, -0.313778281f, -0.641793191f,
-    -0.999286890f,  0.219423503f,   0.976444781f,  0.152786255f,  -0.405437022f,
-    0.120257735f,   -0.392024517f,  -0.019678771f, 1.492373466f,  0.926774263f,
-    0.566291928f,   1.307234287f,   1.496955752f,  1.448441863f,  2.212901354f,
-    1.314700723f,   0.213681281f,   1.011370897f,  1.827155828f,  0.250772655f,
-    -0.429592669f,  0.435638547f,   1.506532907f,  1.350761652f,  -0.387142301f,
-    -1.770648122f,  -2.690037489f,  -1.788924456f, -2.023291588f, -2.354584694f,
-    -2.587521076f,  -2.002159595f,  -0.355855435f, 0.825611115f,  3.075081587f,
-    2.687968254f,   0.074088633f,   0.439936757f,  1.214704275f,  2.670343399f,
-    1.567362547f,   -1.573154926f,  -3.216549397f, -3.596383333f, -3.893716335f,
-    -2.456265688f,  -4.313135624f,  -5.783064842f, -5.344826221f, -3.484399319f,
-    -2.235594273f,  -3.568959475f,  -2.447141886f, -0.755384564f, -1.178364277f,
-    1.034289122f,   1.746821165f,   -1.159413576f, -2.569937706f, -1.742212296f,
-    -0.270784855f,  1.886857986f,   0.831889153f,  0.636521816f,  -0.067433357f,
-    -0.256595969f,  0.907287478f,   1.575596929f,  0.393882513f,  -0.510042071f,
-    0.507258415f,   0.059408009f,   1.776192427f,  1.664948106f,  -0.341539711f,
-    -0.072047889f,  -0.795555651f,  0.704908550f,  2.127685547f,  1.486027241f,
-    1.973046541f,   2.456688404f,   2.871328354f,  4.989626408f,  5.076294422f,
-    4.262395859f,   3.622689009f,   3.241683960f,  4.222597599f,  3.575423479f,
-    1.997965097f,   1.391216874f,   2.329971790f,  2.898612261f,  3.871258736f,
-    2.857767582f,   2.960238218f,   3.047467470f,  2.790968180f,  2.183730364f,
-    1.991029263f,   2.727865934f,   1.561259747f,  0.787606239f,  3.036532879f,
-    2.430759192f,   1.475822210f,   2.307994127f,  1.857011318f,  1.538355589f,
-    2.320549965f,   3.305005074f,   2.554165363f,  2.630100727f,  3.506094217f,
-    4.454113483f,   2.894124269f,   4.061129570f,  4.425602436f,  3.218537807f,
-    2.712452173f,   5.546891212f,   6.138017654f,  5.897895813f,  5.698192596f,
-    4.096743584f,   2.661385298f,   3.646550655f,  4.626225948f,  5.025664330f,
-    3.861543894f,   4.374861717f,   5.388185978f,  3.376737356f,  2.751175404f,
-    3.299628258f,   2.025987387f,   1.094563961f,  0.128147125f,  -4.321690559f,
-    -6.165239811f,  -4.245608330f,  -2.974690914f, -5.110438824f, -6.619713306f,
-    -6.594148636f,  -7.972207069f,  -8.034727097f, -7.296438217f, -6.822746754f,
-    -6.375267029f,  -7.629575729f,  -8.404177666f, -5.002337456f, -7.024040699f,
-    -7.799823761f,  -5.423873901f,  -4.861459732f, -2.772324085f, 0.002551556f,
-    -1.445306778f,  -1.726813316f,  0.889497757f,  1.760663986f,  2.722227097f,
-    4.755805969f,   4.188167572f,   1.547533512f,  2.444593906f,  1.612852097f,
-    -0.508655310f,  0.046535015f,   1.720140934f,  1.265070438f,  0.976964772f,
-    2.446830273f,   6.308787823f,   7.798269272f,  5.347163200f,  3.540414810f,
-    3.510186911f,   4.305843830f,   5.957427025f,  7.200410843f,  7.049768448f,
-    7.179680824f,   8.508881569f,   9.094768524f,  12.307214737f, 14.215225220f,
-    11.316717148f,  8.660657883f,   7.528784275f,  7.616339207f,  6.968524933f,
-    4.246424198f,   0.214603424f,   0.449179649f,  1.695000648f,  0.110423088f,
-    -0.304885864f,  -2.038585663f,  -5.223299980f, -5.486608505f, -5.728059292f,
-    -4.866038799f,  -2.678806305f,  -3.464673519f, -3.407086372f, -2.490849733f,
-    -0.161162257f,  0.118952155f,   0.312392950f,  -0.341049194f, 0.013419867f,
-    3.722306252f,   3.901551247f,   1.781876802f,  2.446551561f,  3.659160852f,
-    2.530288696f,   3.577404499f,   3.201550961f,  0.281389952f,  -0.291333675f,
-    1.386508465f,   2.181721210f,   -2.802821159f, -1.531007886f, 1.608560324f,
-    -0.523656845f,  -0.281057000f,  0.571323991f,  0.668095112f,  -1.637194037f,
-    -2.756963253f,  -1.340666890f,  -2.180127621f, -1.874165773f, 0.660111070f,
-    0.197176635f,   0.781580091f,   1.749967933f,  0.674724638f,  -2.082683325f,
-    -3.159717083f,  -2.898023844f,  -4.691623211f, -5.614190102f, -6.157790661f,
-    -7.776132584f,  -8.029224396f,  -6.940879345f, -7.065263271f, -7.003522396f,
-    -5.691181183f,  -7.872379780f,  -7.614178658f, -5.778759003f, -4.605045319f,
-    -4.695390224f,  -5.865473270f,  -5.825413227f, -4.648111820f, -2.193091869f,
-    -0.172003269f,  1.482686043f,   -0.915655136f, -2.626194954f, 1.852293015f,
-    4.184171677f,   4.083235264f,   1.048256874f,  -1.361350536f, 0.438748837f,
-    1.716395378f,   2.916294813f,   2.639499664f,  0.059617281f,  -1.883811951f,
-    2.136622429f,   6.641947269f,   5.951328754f,  3.875293493f,  3.003573895f,
-    2.687273264f,   4.843512535f,   6.420391560f,  6.014624596f,  3.444208860f,
-    0.717782736f,   2.659932613f,   5.204012871f,  5.516477585f,  3.315031528f,
-    0.454023123f,   -0.026421070f,  0.802503586f,  2.606507778f,  1.679640770f,
-    -1.917723656f,  -3.348850250f,  -2.580049515f, -1.783200264f, -0.810425520f,
-    -0.374402523f,  -3.705567360f,  -5.367071629f, -4.344952106f, -0.968293428f,
-    1.147591949f,   -1.240655184f,  -2.621209621f, -2.452539444f, -1.543132067f,
-    0.422753096f,   1.026433110f,   0.858573675f,  -0.695377707f, -0.242624998f,
-    3.892488956f,   4.100893021f,   3.498974323f,  1.744507313f,  -0.912925899f,
-    0.929271877f,   3.531583786f,   4.938030243f,  4.081199646f,  0.061933577f,
-    -2.232783318f,  -1.356980443f,  1.794556737f,  3.510458231f,  1.323192716f,
-    -0.505770206f,  2.126557350f,   2.507567406f,  2.232018232f,  1.872283101f,
-    1.265762568f,   0.577634692f,   0.021484375f,  3.114191532f,  1.579384208f,
-    0.930754900f,   0.308351398f,   -0.425426602f, 3.359810352f,  2.437057972f,
-    1.210662127f,   0.708607912f,   -1.576705575f, 0.007833481f,  -0.178357601f,
-    -0.880272985f,  0.078738928f,   0.339336634f,  -0.763550043f, -1.669098496f,
-    -2.083987713f,  -1.946106076f,  -0.953974366f, -0.856883168f, -1.282670021f,
-    -1.551425457f,  -2.249363184f,  -2.555188894f, -1.254808664f, -1.368662596f,
-    -1.839509130f,  -0.839046180f,  -0.452676475f, 0.721064806f,  1.988085508f,
-    0.456556678f,   -0.255003691f,  0.384676337f,  1.075410485f,  0.617453933f,
-    1.470067143f,   1.493275523f,   0.954153359f,  1.027234554f,  -0.434967309f,
-    -0.694453120f,  0.477285773f,   0.436861426f,  1.486879349f,  -0.158989906f,
-    0.361879885f,   3.234876394f,   1.105287671f,  -0.982552111f, 1.514200211f,
-    0.821707547f,   -1.142312169f,  1.845819831f,  3.934516191f,  2.251807690f,
-    0.530044913f,   -1.043874860f,  -0.891365111f, -0.264675498f, 0.288083673f,
-    0.606682122f,   -1.132072091f,  -3.530973911f, -2.005296707f, 0.335011721f,
-    -0.240332901f,  -2.763209343f,  -2.148519516f, -1.864180326f, -0.814615071f,
-    -1.589591861f,  -2.455522776f,  -0.756391644f, 0.689822078f,  0.171640277f,
-    -0.225937843f,  0.363246441f,   0.098157287f,  -1.638891220f, -0.400456548f,
-    1.076233864f,   2.288599968f,   2.716089964f,  1.585703373f,  0.846301913f,
-    0.887506902f,   -0.439320147f,  -0.823126972f, 0.712436378f,  1.027045608f,
-    0.360925227f,   -2.289939404f,  -1.035227180f, 0.931313038f,  -0.133454978f,
-    0.160856903f,   0.700653732f,   0.817580283f,  -0.223383546f, 0.713623106f,
-    1.327106714f,   1.558022618f,   1.346337557f,  -0.661301017f, 0.707845926f,
-    2.435726643f,   0.763329387f,   0.485213757f,  2.295393229f,  4.525130272f,
-    2.354229450f,   -0.043517172f,  1.635316610f,  1.651852608f,  1.240020633f,
-    0.320237398f,   -0.571269870f,  -0.686546564f, -1.796948791f, -0.966899753f,
-    -0.404109240f,  -1.295783877f,  -2.058131218f, -2.279026985f, -2.183017731f,
-    -2.516988277f,  -0.276667058f,  -0.475267202f, -2.645681143f, -0.504431605f,
-    -1.031255722f,  -3.401877880f,  -1.075011969f, -0.667404234f, -2.419279575f,
-    -1.230643749f,  1.151491284f,   0.374734998f,  -2.004124880f, -1.923788905f,
-    -0.767004371f,  0.512374282f,   2.254727125f,  1.373157024f,  0.633022547f,
-    0.194831967f,   0.226476192f,   1.294842482f,  0.838023365f,  1.291390896f,
-    0.128176212f,   -1.109287858f,  0.166733295f,  0.847469866f,  -0.662097514f,
-    -0.489783406f,  1.523754478f,   1.903803706f,  -0.748670340f, 0.721136212f,
-    1.627746105f,   -0.731291413f,  0.646574259f,  1.722917080f,  0.372141778f,
-    -0.063563704f,  0.916404963f,   2.092662811f,  1.699481010f,  0.181074798f,
-    -1.361395121f,  0.581034362f,   1.451567292f,  0.526586652f,  1.206429839f,
-    -1.041464567f,  -2.891606331f,  0.638695598f,  1.198848009f,  -0.771047413f,
-    -1.074250221f,  -0.500067651f,  0.308775485f,  0.552724898f,  1.083443999f,
-    1.371356130f,   0.360372365f,   3.391613960f,  2.896605730f,  0.799045980f,
-    0.922905385f,   3.240214348f,   4.740911484f,  2.945639610f,  2.544054747f,
-    3.048654795f,   3.541822433f,   4.390746117f,  5.632675171f,  7.721554756f,
-    6.390114784f,   5.962307930f,   5.873732567f,  5.625522137f,  4.857854843f,
-    3.148367405f,   3.966898203f,   4.309705257f,  3.543770313f,  2.427399397f,
-    0.324177742f,   -1.809771061f,  -2.191485405f, 0.006873131f,  -0.876847267f,
-    -0.928904057f,  0.889565945f,   -0.127671242f, -1.695463657f, -1.193793774f,
-    -1.452976227f,  -3.406696558f,  -2.564189196f, -2.136555195f, -2.374645710f,
-    -3.230790854f,  -3.076714516f,  -3.245117664f, -2.254387617f, -0.245034039f,
-    -1.072510719f,  -1.887740970f,  0.431427240f,  1.132410765f,  -1.015120149f,
-    -0.274977922f,  -1.910447717f,  -2.865208864f, -0.131696820f};
-
-// TODO(bugs.webrtc.org/9076): Move to resource file.
-constexpr std::array<float, 385> kPitchBufferFrameSquareEnergies = {
-    5150.291992188f, 5150.894531250f, 5145.122558594f, 5148.914062500f,
-    5152.802734375f, 5156.541015625f, 5163.048339844f, 5172.149414062f,
-    5177.349121094f, 5184.365722656f, 5199.292480469f, 5202.612304688f,
-    5197.510253906f, 5189.979492188f, 5183.533203125f, 5190.677734375f,
-    5203.943359375f, 5207.876464844f, 5209.395019531f, 5225.451660156f,
-    5249.794921875f, 5271.816894531f, 5280.045410156f, 5285.289062500f,
-    5288.319335938f, 5289.758789062f, 5294.285644531f, 5289.979980469f,
-    5287.337402344f, 5287.237792969f, 5281.462402344f, 5271.676269531f,
-    5256.257324219f, 5240.524414062f, 5230.869628906f, 5207.531250000f,
-    5176.040039062f, 5144.021484375f, 5109.295410156f, 5068.527832031f,
-    5008.909667969f, 4977.587890625f, 4959.000976562f, 4950.016601562f,
-    4940.795410156f, 4937.358398438f, 4935.286132812f, 4914.154296875f,
-    4906.706542969f, 4906.924804688f, 4907.674804688f, 4899.855468750f,
-    4894.340820312f, 4906.948242188f, 4910.065429688f, 4921.032714844f,
-    4949.294433594f, 4982.643066406f, 5000.996093750f, 5005.875488281f,
-    5020.441894531f, 5031.938964844f, 5041.877441406f, 5035.990722656f,
-    5037.362792969f, 5043.038085938f, 5044.236328125f, 5042.322753906f,
-    5041.990722656f, 5047.362304688f, 5056.785644531f, 5054.579101562f,
-    5050.326171875f, 5053.495117188f, 5060.186523438f, 5065.591796875f,
-    5066.717285156f, 5069.499511719f, 5076.201171875f, 5076.687011719f,
-    5076.316894531f, 5077.581054688f, 5076.226074219f, 5074.094238281f,
-    5074.039062500f, 5073.663574219f, 5076.283691406f, 5077.278808594f,
-    5076.094238281f, 5077.806152344f, 5081.035644531f, 5082.431640625f,
-    5082.995605469f, 5084.653320312f, 5084.936035156f, 5085.394042969f,
-    5085.735351562f, 5080.651855469f, 5080.542968750f, 5079.969238281f,
-    5076.432617188f, 5072.439453125f, 5073.252441406f, 5071.974609375f,
-    5071.458496094f, 5066.017578125f, 5065.670898438f, 5065.144042969f,
-    5055.592773438f, 5060.104980469f, 5060.505371094f, 5054.157226562f,
-    5056.915039062f, 5067.208007812f, 5060.940917969f, 5058.419921875f,
-    5053.248046875f, 5049.823730469f, 5048.573242188f, 5053.195312500f,
-    5053.444335938f, 5054.143066406f, 5056.270019531f, 5063.881835938f,
-    5070.784667969f, 5074.042480469f, 5080.785156250f, 5085.663085938f,
-    5095.979003906f, 5101.596191406f, 5088.784667969f, 5087.686523438f,
-    5087.946777344f, 5087.369140625f, 5081.445312500f, 5081.519042969f,
-    5087.940917969f, 5102.099121094f, 5126.864257812f, 5147.613281250f,
-    5170.079589844f, 5189.276367188f, 5210.265136719f, 5244.745117188f,
-    5268.821777344f, 5277.381835938f, 5279.768066406f, 5278.750000000f,
-    5283.853027344f, 5292.671386719f, 5291.744628906f, 5294.732421875f,
-    5294.322265625f, 5294.267089844f, 5297.530761719f, 5302.179199219f,
-    5312.768066406f, 5323.202148438f, 5335.357910156f, 5344.610839844f,
-    5347.597167969f, 5346.077148438f, 5346.071289062f, 5346.083984375f,
-    5348.088378906f, 5349.661621094f, 5350.157226562f, 5351.855957031f,
-    5347.257812500f, 5345.171875000f, 5344.617675781f, 5343.106445312f,
-    5342.778808594f, 5338.655761719f, 5341.668457031f, 5347.518066406f,
-    5362.014160156f, 5361.167968750f, 5362.926269531f, 5371.575195312f,
-    5374.099609375f, 5381.186523438f, 5381.963867188f, 5386.806152344f,
-    5389.590820312f, 5384.562011719f, 5372.485839844f, 5370.576660156f,
-    5369.640136719f, 5369.698242188f, 5371.199707031f, 5372.644531250f,
-    5394.006835938f, 5395.366699219f, 5395.259277344f, 5395.398437500f,
-    5395.895507812f, 5401.420898438f, 5420.036621094f, 5434.017578125f,
-    5434.215820312f, 5437.827636719f, 5442.944335938f, 5450.980468750f,
-    5449.246582031f, 5449.135742188f, 5453.259765625f, 5453.792968750f,
-    5459.676757812f, 5460.213867188f, 5479.227539062f, 5512.076171875f,
-    5520.272949219f, 5519.662109375f, 5517.395996094f, 5516.550292969f,
-    5520.786621094f, 5527.268066406f, 5526.668457031f, 5549.916992188f,
-    5577.750976562f, 5580.141113281f, 5579.533691406f, 5576.632324219f,
-    5573.938476562f, 5571.166503906f, 5570.603027344f, 5570.708496094f,
-    5577.238769531f, 5577.625976562f, 5589.325683594f, 5602.189941406f,
-    5612.587402344f, 5613.887695312f, 5613.588867188f, 5608.100585938f,
-    5632.956054688f, 5679.322265625f, 5682.149414062f, 5683.846191406f,
-    5691.708496094f, 5683.279785156f, 5694.248535156f, 5744.740722656f,
-    5756.655761719f, 5755.952148438f, 5756.665527344f, 5750.700195312f,
-    5784.060546875f, 5823.021972656f, 5829.233398438f, 5817.804687500f,
-    5827.333984375f, 5826.451171875f, 5824.887695312f, 5825.734375000f,
-    5813.386230469f, 5789.609863281f, 5779.115234375f, 5778.762695312f,
-    5785.748046875f, 5792.981933594f, 5787.567871094f, 5778.096679688f,
-    5764.337402344f, 5766.734375000f, 5766.489746094f, 5769.543945312f,
-    5773.183593750f, 5775.720703125f, 5774.311523438f, 5769.303710938f,
-    5765.815917969f, 5767.521484375f, 5775.251953125f, 5785.067382812f,
-    5770.117187500f, 5749.073242188f, 5747.606933594f, 5757.671875000f,
-    5762.530273438f, 5774.506347656f, 5784.737304688f, 5775.916015625f,
-    5779.816894531f, 5795.064453125f, 5808.736816406f, 5813.699707031f,
-    5823.773925781f, 5840.490234375f, 5833.751953125f, 5810.150390625f,
-    5800.072265625f, 5815.070800781f, 5822.964355469f, 5817.615234375f,
-    5783.978027344f, 5748.952636719f, 5735.553710938f, 5730.132812500f,
-    5724.260253906f, 5721.703613281f, 5695.653808594f, 5652.838867188f,
-    5649.729980469f, 5647.268554688f, 5647.265136719f, 5641.350585938f,
-    5636.762695312f, 5637.900390625f, 5639.662109375f, 5639.672851562f,
-    5638.901367188f, 5622.253417969f, 5604.906738281f, 5601.475585938f,
-    5595.938476562f, 5595.687011719f, 5598.612792969f, 5601.322753906f,
-    5598.558593750f, 5577.227050781f, 5544.295410156f, 5514.978027344f,
-    5499.678222656f, 5488.303222656f, 5471.735839844f, 5429.718261719f,
-    5376.806640625f, 5348.682128906f, 5307.851074219f, 5260.914062500f,
-    5212.738281250f, 5148.544921875f, 5091.187500000f, 5053.512207031f,
-    5023.785156250f, 5002.202148438f, 4994.252441406f, 4984.498046875f,
-    4980.251464844f, 4979.796875000f, 4976.738769531f, 4979.579589844f,
-    4986.528320312f, 4991.153808594f, 4991.462890625f, 4987.881347656f,
-    4987.417480469f, 4983.885742188f, 4984.341308594f, 4985.302734375f,
-    4985.303710938f, 4985.449707031f, 4989.282226562f, 4994.246582031f,
-    4992.635742188f, 4992.064453125f, 4987.331054688f, 4985.806152344f,
-    4986.047851562f, 4985.968750000f, 4979.141113281f, 4976.958984375f,
-    4972.650390625f, 4959.916503906f, 4956.325683594f, 4956.408691406f,
-    4949.288085938f, 4951.827636719f, 4962.202636719f, 4981.184570312f,
-    4992.152832031f, 4997.386230469f, 5011.211914062f, 5026.242187500f,
-    5023.573730469f, 5012.373046875f, 5017.451171875f, 5010.541015625f,
-    4980.446777344f, 4958.639648438f, 4963.649902344f, 5627.020507812f,
-    6869.356445312f};
-
-// TODO(bugs.webrtc.org/9076): Move to resource file.
-constexpr std::array<float, 147> kPitchBufferAutoCorrCoeffs = {
-    -423.526794434f, -260.724456787f, -173.558380127f, -71.720344543f,
-    -1.149698257f,   71.451370239f,   71.455848694f,   149.755233765f,
-    199.401885986f,  243.961334229f,  269.339721680f,  243.776992798f,
-    294.753814697f,  209.465484619f,  139.224700928f,  131.474136353f,
-    42.872886658f,   -32.431114197f,  -90.191261292f,  -94.912338257f,
-    -172.627227783f, -138.089843750f, -89.236648560f,  -69.348426819f,
-    25.044368744f,   44.184486389f,   61.602676392f,   150.157394409f,
-    185.254760742f,  233.352676392f,  296.255371094f,  292.464141846f,
-    256.903472900f,  250.926574707f,  174.207122803f,  130.214172363f,
-    65.655899048f,   -68.448402405f,  -147.239669800f, -230.553405762f,
-    -311.217895508f, -447.173889160f, -509.306060791f, -551.155822754f,
-    -580.678405762f, -658.902709961f, -697.141967773f, -751.233032227f,
-    -690.860351562f, -571.689575195f, -521.124572754f, -429.477294922f,
-    -375.685913086f, -277.387329102f, -154.100753784f, -105.723197937f,
-    117.502632141f,  219.290512085f,  255.376770020f,  444.264831543f,
-    470.727416992f,  460.139129639f,  494.179931641f,  389.801116943f,
-    357.082763672f,  222.748138428f,  179.100601196f,  -26.893497467f,
-    -85.033767700f,  -223.577529907f, -247.136367798f, -223.011428833f,
-    -292.724914551f, -246.538131714f, -247.388458252f, -228.452484131f,
-    -30.476575851f,  4.652336121f,    64.730491638f,   156.081161499f,
-    177.569305420f,  261.671569824f,  336.274414062f,  424.203369141f,
-    564.190734863f,  608.841796875f,  671.252136230f,  712.249877930f,
-    623.135498047f,  564.775695801f,  576.405639648f,  380.181854248f,
-    306.687164307f,  180.344757080f,  -41.317466736f,  -183.548736572f,
-    -223.835021973f, -273.299652100f, -235.727813721f, -276.899627686f,
-    -302.224975586f, -349.227142334f, -370.935058594f, -364.022613525f,
-    -287.682952881f, -273.828704834f, -156.869720459f, -88.654510498f,
-    14.299798012f,   137.048034668f,  260.182342529f,  423.380767822f,
-    591.277282715f,  581.151306152f,  643.898864746f,  547.919006348f,
-    355.534271240f,  238.222915649f,  4.463035583f,    -193.763305664f,
-    -281.212432861f, -546.399353027f, -615.602600098f, -574.225891113f,
-    -726.701843262f, -564.840942383f, -588.488037109f, -651.052551270f,
-    -453.769104004f, -502.886627197f, -463.373016357f, -291.709564209f,
-    -288.857421875f, -152.114242554f, 105.401855469f,  211.479980469f,
-    468.501983643f,  796.984985352f,  880.254089355f,  1114.614379883f,
-    1219.664794922f, 1093.687377930f, 1125.042602539f, 1020.942382812f,
-    794.315246582f,  772.126831055f,  447.410736084f};
-
 constexpr std::array<size_t, 2> kTestPitchPeriods = {
     3 * kMinPitch48kHz / 2, (3 * kMinPitch48kHz + kMaxPitch48kHz) / 2,
 };
 constexpr std::array<float, 2> kTestPitchGains = {0.35f, 0.75f};
 
+constexpr size_t kNumPitchBufSquareEnergies = 385;
+constexpr size_t kNumPitchBufAutoCorrCoeffs = 147;
+constexpr size_t kTestDataSize =
+    kBufSize24kHz + kNumPitchBufSquareEnergies + kNumPitchBufAutoCorrCoeffs;
+
+class TestData {
+ public:
+  TestData() {
+    auto test_data_reader = CreatePitchSearchTestDataReader();
+    test_data_reader->ReadChunk(test_data_);
+  }
+  rtc::ArrayView<const float, kBufSize24kHz> GetPitchBufView() {
+    return {test_data_.data(), kBufSize24kHz};
+  }
+  rtc::ArrayView<const float, kNumPitchBufSquareEnergies>
+  GetPitchBufSquareEnergiesView() {
+    return {test_data_.data() + kBufSize24kHz, kNumPitchBufSquareEnergies};
+  }
+  rtc::ArrayView<const float, kNumPitchBufAutoCorrCoeffs>
+  GetPitchBufAutoCorrCoeffsView() {
+    return {test_data_.data() + kBufSize24kHz + kNumPitchBufSquareEnergies,
+            kNumPitchBufAutoCorrCoeffs};
+  }
+
+ private:
+  std::array<float, kTestDataSize> test_data_;
+};
+
 }  // namespace
 
 class ComputePitchGainThresholdTest
@@ -393,67 +106,90 @@
         std::make_tuple(78, 2, 156, 0.72750503f, 153, 0.85069299f, 0.618379f)));
 
 TEST(RnnVadTest, ComputeSlidingFrameSquareEnergiesBitExactness) {
-  std::array<float, kPitchBufferFrameSquareEnergies.size()> computed_output;
+  TestData test_data;
+  std::array<float, kNumPitchBufSquareEnergies> computed_output;
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
-    ComputeSlidingFrameSquareEnergies(
-        {kPitchBufferData.data(), kPitchBufferData.size()},
-        {computed_output.data(), computed_output.size()});
+    ComputeSlidingFrameSquareEnergies(test_data.GetPitchBufView(),
+                                      computed_output);
   }
-  ExpectNearAbsolute({kPitchBufferFrameSquareEnergies.data(),
-                      kPitchBufferFrameSquareEnergies.size()},
-                     {computed_output.data(), computed_output.size()}, 3e-2f);
+  auto square_energies_view = test_data.GetPitchBufSquareEnergiesView();
+  ExpectNearAbsolute({square_energies_view.data(), square_energies_view.size()},
+                     computed_output, 3e-2f);
 }
 
 TEST(RnnVadTest, ComputePitchAutoCorrelationBitExactness) {
+  TestData test_data;
   std::array<float, kBufSize12kHz> pitch_buf_decimated;
-  Decimate2x({kPitchBufferData.data(), kPitchBufferData.size()},
-             {pitch_buf_decimated.data(), pitch_buf_decimated.size()});
-  std::array<float, kPitchBufferAutoCorrCoeffs.size()> computed_output;
+  Decimate2x(test_data.GetPitchBufView(), pitch_buf_decimated);
+  std::array<float, kNumPitchBufAutoCorrCoeffs> computed_output;
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
-    ComputePitchAutoCorrelation(
-        {pitch_buf_decimated.data(), pitch_buf_decimated.size()},
-        kMaxPitch12kHz, {computed_output.data(), computed_output.size()});
+    std::unique_ptr<RealFourier> fft =
+        RealFourier::Create(kAutoCorrelationFftOrder);
+    ComputePitchAutoCorrelation(pitch_buf_decimated, kMaxPitch12kHz,
+                                computed_output, fft.get());
   }
-  ExpectNearAbsolute(
-      {kPitchBufferAutoCorrCoeffs.data(), kPitchBufferAutoCorrCoeffs.size()},
-      {computed_output.data(), computed_output.size()}, 3e-3f);
+  auto auto_corr_view = test_data.GetPitchBufAutoCorrCoeffsView();
+  ExpectNearAbsolute({auto_corr_view.data(), auto_corr_view.size()},
+                     computed_output, 3e-3f);
+}
+
+// Check that the auto correlation function computes the right thing for a
+// simple use case.
+TEST(RnnVadTest, ComputePitchAutoCorrelationConstantBuffer) {
+  // Create constant signal with no pitch.
+  std::array<float, kBufSize12kHz> pitch_buf_decimated;
+  std::fill(pitch_buf_decimated.begin(), pitch_buf_decimated.end(), 1.f);
+
+  std::array<float, kNumPitchBufAutoCorrCoeffs> computed_output;
+  {
+    // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+    // FloatingPointExceptionObserver fpe_observer;
+    std::unique_ptr<RealFourier> fft =
+        RealFourier::Create(kAutoCorrelationFftOrder);
+    ComputePitchAutoCorrelation(pitch_buf_decimated, kMaxPitch12kHz,
+                                computed_output, fft.get());
+  }
+
+  // The expected output is constantly the length of the fixed 'x'
+  // array in ComputePitchAutoCorrelation.
+  std::array<float, kNumPitchBufAutoCorrCoeffs> expected_output;
+  std::fill(expected_output.begin(), expected_output.end(),
+            kBufSize12kHz - kMaxPitch12kHz);
+  ExpectNearAbsolute(expected_output, computed_output, 4e-5f);
 }
 
 TEST(RnnVadTest, FindBestPitchPeriodsBitExactness) {
+  TestData test_data;
   std::array<float, kBufSize12kHz> pitch_buf_decimated;
-  Decimate2x({kPitchBufferData.data(), kPitchBufferData.size()},
-             {pitch_buf_decimated.data(), pitch_buf_decimated.size()});
+  Decimate2x(test_data.GetPitchBufView(), pitch_buf_decimated);
   std::array<size_t, 2> pitch_candidates_inv_lags;
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
-    pitch_candidates_inv_lags = FindBestPitchPeriods(
-        {kPitchBufferAutoCorrCoeffs}, {pitch_buf_decimated}, kMaxPitch12kHz);
+    auto auto_corr_view = test_data.GetPitchBufAutoCorrCoeffsView();
+    pitch_candidates_inv_lags =
+        FindBestPitchPeriods({auto_corr_view.data(), auto_corr_view.size()},
+                             pitch_buf_decimated, kMaxPitch12kHz);
   }
   const std::array<size_t, 2> expected_output = {140, 142};
   EXPECT_EQ(expected_output, pitch_candidates_inv_lags);
 }
 
 TEST(RnnVadTest, RefinePitchPeriod48kHzBitExactness) {
+  TestData test_data;
   std::array<float, kBufSize12kHz> pitch_buf_decimated;
-  Decimate2x({kPitchBufferData.data(), kPitchBufferData.size()},
-             {pitch_buf_decimated.data(), pitch_buf_decimated.size()});
+  Decimate2x(test_data.GetPitchBufView(), pitch_buf_decimated);
   size_t pitch_inv_lag;
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
     const std::array<size_t, 2> pitch_candidates_inv_lags = {280, 284};
-    pitch_inv_lag = RefinePitchPeriod48kHz(
-        {kPitchBufferData.data(), kPitchBufferData.size()},
-        {pitch_candidates_inv_lags.data(), pitch_candidates_inv_lags.size()});
+    pitch_inv_lag = RefinePitchPeriod48kHz(test_data.GetPitchBufView(),
+                                           pitch_candidates_inv_lags);
   }
   EXPECT_EQ(560u, pitch_inv_lag);
 }
@@ -470,14 +206,13 @@
   const float prev_pitch_gain = std::get<2>(params);
   const size_t expected_pitch_period = std::get<3>(params);
   const float expected_pitch_gain = std::get<4>(params);
-
+  TestData test_data;
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
     const auto computed_output = CheckLowerPitchPeriodsAndComputePitchGain(
-        {kPitchBufferData.data(), kPitchBufferData.size()},
-        initial_pitch_period, {prev_pitch_period, prev_pitch_gain});
+        test_data.GetPitchBufView(), initial_pitch_period,
+        {prev_pitch_period, prev_pitch_gain});
     EXPECT_EQ(expected_pitch_period, computed_output.period);
     EXPECT_NEAR(expected_pitch_gain, computed_output.gain, 1e-6f);
   }
diff --git a/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc b/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc
index 4417764..4c56238 100644
--- a/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/pitch_search_unittest.cc
@@ -9,6 +9,8 @@
  */
 
 #include "modules/audio_processing/agc2/rnn_vad/pitch_search.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_info.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h"
 
 #include <array>
 
@@ -27,21 +29,18 @@
   const size_t num_frames = lp_residual_reader.second;
   std::array<float, 864> lp_residual;
   float expected_pitch_period, expected_pitch_gain;
-  PitchInfo last_pitch;
+  PitchEstimator pitch_estimator;
   {
     // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
     // FloatingPointExceptionObserver fpe_observer;
-
     for (size_t i = 0; i < num_frames; ++i) {
       SCOPED_TRACE(i);
-      lp_residual_reader.first->ReadChunk(
-          {lp_residual.data(), lp_residual.size()});
+      lp_residual_reader.first->ReadChunk(lp_residual);
       lp_residual_reader.first->ReadValue(&expected_pitch_period);
       lp_residual_reader.first->ReadValue(&expected_pitch_gain);
-      last_pitch =
-          PitchSearch({lp_residual.data(), lp_residual.size()}, last_pitch);
-      EXPECT_EQ(static_cast<size_t>(expected_pitch_period), last_pitch.period);
-      EXPECT_NEAR(expected_pitch_gain, last_pitch.gain, 1e-5f);
+      PitchInfo pitch_info = pitch_estimator.Estimate(lp_residual);
+      EXPECT_EQ(static_cast<size_t>(expected_pitch_period), pitch_info.period);
+      EXPECT_NEAR(expected_pitch_gain, pitch_info.gain, 1e-5f);
     }
   }
 }
diff --git a/modules/audio_processing/agc2/rnn_vad/ring_buffer_unittest.cc b/modules/audio_processing/agc2/rnn_vad/ring_buffer_unittest.cc
index 91383d1..f064651 100644
--- a/modules/audio_processing/agc2/rnn_vad/ring_buffer_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/ring_buffer_unittest.cc
@@ -85,7 +85,7 @@
         EXPECT_NE(view_i, view_j);
       }
     }
-    ring_buf.Push({pushed_array.data(), pushed_array.size()});
+    ring_buf.Push(pushed_array);
   }
 }
 
diff --git a/modules/audio_processing/agc2/rnn_vad/rnn.cc b/modules/audio_processing/agc2/rnn_vad/rnn.cc
new file mode 100644
index 0000000..2b36034
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/rnn.cc
@@ -0,0 +1,232 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+
+#include "rtc_base/checks.h"
+#include "third_party/rnnoise/src/rnn_activations.h"
+#include "third_party/rnnoise/src/rnn_vad_weights.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+using rnnoise::kWeightsScale;
+
+using rnnoise::kInputLayerInputSize;
+static_assert(kFeatureVectorSize == kInputLayerInputSize, "");
+using rnnoise::kInputDenseWeights;
+using rnnoise::kInputDenseBias;
+using rnnoise::kInputLayerOutputSize;
+static_assert(kInputLayerOutputSize <= kFullyConnectedLayersMaxUnits,
+              "Increase kFullyConnectedLayersMaxUnits.");
+
+using rnnoise::kHiddenGruRecurrentWeights;
+using rnnoise::kHiddenGruWeights;
+using rnnoise::kHiddenGruBias;
+using rnnoise::kHiddenLayerOutputSize;
+static_assert(kHiddenLayerOutputSize <= kRecurrentLayersMaxUnits,
+              "Increase kRecurrentLayersMaxUnits.");
+
+using rnnoise::kOutputDenseWeights;
+using rnnoise::kOutputDenseBias;
+using rnnoise::kOutputLayerOutputSize;
+static_assert(kOutputLayerOutputSize <= kFullyConnectedLayersMaxUnits,
+              "Increase kFullyConnectedLayersMaxUnits.");
+
+using rnnoise::RectifiedLinearUnit;
+using rnnoise::SigmoidApproximated;
+using rnnoise::TansigApproximated;
+
+FullyConnectedLayer::FullyConnectedLayer(
+    const size_t input_size,
+    const size_t output_size,
+    const rtc::ArrayView<const int8_t> bias,
+    const rtc::ArrayView<const int8_t> weights,
+    float (*const activation_function)(float))
+    : input_size_(input_size),
+      output_size_(output_size),
+      bias_(bias),
+      weights_(weights),
+      activation_function_(activation_function) {
+  RTC_DCHECK_LE(output_size_, kFullyConnectedLayersMaxUnits)
+      << "Static over-allocation of fully-connected layers output vectors is "
+         "not sufficient.";
+  RTC_DCHECK_EQ(output_size_, bias_.size())
+      << "Mismatching output size and bias terms array size.";
+  RTC_DCHECK_EQ(input_size_ * output_size_, weights_.size())
+      << "Mismatching input-output size and weight coefficients array size.";
+}
+
+FullyConnectedLayer::~FullyConnectedLayer() = default;
+
+rtc::ArrayView<const float> FullyConnectedLayer::GetOutput() const {
+  return rtc::ArrayView<const float>(output_.data(), output_size_);
+}
+
+void FullyConnectedLayer::ComputeOutput(rtc::ArrayView<const float> input) {
+  // TODO(bugs.chromium.org/9076): Optimize using SSE/AVX fused multiply-add
+  // operations.
+  for (size_t o = 0; o < output_size_; ++o) {
+    output_[o] = bias_[o];
+    // TODO(bugs.chromium.org/9076): Benchmark how different layouts for
+    // |weights_| change the performance across different platforms.
+    for (size_t i = 0; i < input_size_; ++i) {
+      output_[o] += input[i] * weights_[i * output_size_ + o];
+    }
+    output_[o] = (*activation_function_)(kWeightsScale * output_[o]);
+  }
+}
+
+GatedRecurrentLayer::GatedRecurrentLayer(
+    const size_t input_size,
+    const size_t output_size,
+    const rtc::ArrayView<const int8_t> bias,
+    const rtc::ArrayView<const int8_t> weights,
+    const rtc::ArrayView<const int8_t> recurrent_weights,
+    float (*const activation_function)(float))
+    : input_size_(input_size),
+      output_size_(output_size),
+      bias_(bias),
+      weights_(weights),
+      recurrent_weights_(recurrent_weights),
+      activation_function_(activation_function) {
+  RTC_DCHECK_LE(output_size_, kRecurrentLayersMaxUnits)
+      << "Static over-allocation of recurrent layers state vectors is not "
+      << "sufficient.";
+  RTC_DCHECK_EQ(3 * output_size_, bias_.size())
+      << "Mismatching output size and bias terms array size.";
+  RTC_DCHECK_EQ(3 * input_size_ * output_size_, weights_.size())
+      << "Mismatching input-output size and weight coefficients array size.";
+  RTC_DCHECK_EQ(3 * input_size_ * output_size_, recurrent_weights_.size())
+      << "Mismatching input-output size and recurrent weight coefficients array"
+      << " size.";
+  Reset();
+}
+
+GatedRecurrentLayer::~GatedRecurrentLayer() = default;
+
+rtc::ArrayView<const float> GatedRecurrentLayer::GetOutput() const {
+  return rtc::ArrayView<const float>(state_.data(), output_size_);
+}
+
+void GatedRecurrentLayer::Reset() {
+  state_.fill(0.f);
+}
+
+void GatedRecurrentLayer::ComputeOutput(rtc::ArrayView<const float> input) {
+  // TODO(bugs.chromium.org/9076): Optimize using SSE/AVX fused multiply-add
+  // operations.
+  // Stride and offset used to read parameter arrays.
+  const size_t stride = 3 * output_size_;
+  size_t offset = 0;
+
+  // Compute update gates.
+  std::array<float, kRecurrentLayersMaxUnits> update;
+  for (size_t o = 0; o < output_size_; ++o) {
+    update[o] = bias_[o];
+    // TODO(bugs.chromium.org/9076): Benchmark how different layouts for
+    // |weights_| and |recurrent_weights_| change the performance across
+    // different platforms.
+    for (size_t i = 0; i < input_size_; ++i) {  // Add input.
+      update[o] += input[i] * weights_[i * stride + o];
+    }
+    for (size_t s = 0; s < output_size_; ++s) {
+      update[o] += state_[s] * recurrent_weights_[s * stride + o];
+    }  // Add state.
+    update[o] = SigmoidApproximated(kWeightsScale * update[o]);
+  }
+
+  // Compute reset gates.
+  offset += output_size_;
+  std::array<float, kRecurrentLayersMaxUnits> reset;
+  for (size_t o = 0; o < output_size_; ++o) {
+    reset[o] = bias_[offset + o];
+    for (size_t i = 0; i < input_size_; ++i) {  // Add input.
+      reset[o] += input[i] * weights_[offset + i * stride + o];
+    }
+    for (size_t s = 0; s < output_size_; ++s) {  // Add state.
+      reset[o] += state_[s] * recurrent_weights_[offset + s * stride + o];
+    }
+    reset[o] = SigmoidApproximated(kWeightsScale * reset[o]);
+  }
+
+  // Compute output.
+  offset += output_size_;
+  std::array<float, kRecurrentLayersMaxUnits> output;
+  for (size_t o = 0; o < output_size_; ++o) {
+    output[o] = bias_[offset + o];
+    for (size_t i = 0; i < input_size_; ++i) {  // Add input.
+      output[o] += input[i] * weights_[offset + i * stride + o];
+    }
+    for (size_t s = 0; s < output_size_;
+         ++s) {  // Add state through reset gates.
+      output[o] +=
+          state_[s] * recurrent_weights_[offset + s * stride + o] * reset[s];
+    }
+    output[o] = (*activation_function_)(kWeightsScale * output[o]);
+    // Update output through the update gates.
+    output[o] = update[o] * state_[o] + (1.f - update[o]) * output[o];
+  }
+
+  // Update the state. Not done in the previous loop since that would pollute
+  // the current state and lead to incorrect output values.
+  std::copy(output.begin(), output.end(), state_.begin());
+}
+
+RnnBasedVad::RnnBasedVad()
+    : input_layer_(kInputLayerInputSize,
+                   kInputLayerOutputSize,
+                   kInputDenseBias,
+                   kInputDenseWeights,
+                   TansigApproximated),
+      hidden_layer_(kInputLayerOutputSize,
+                    kHiddenLayerOutputSize,
+                    kHiddenGruBias,
+                    kHiddenGruWeights,
+                    kHiddenGruRecurrentWeights,
+                    RectifiedLinearUnit),
+      output_layer_(kHiddenLayerOutputSize,
+                    kOutputLayerOutputSize,
+                    kOutputDenseBias,
+                    kOutputDenseWeights,
+                    SigmoidApproximated) {
+  // Input-output chaining size checks.
+  RTC_DCHECK_EQ(input_layer_.output_size(), hidden_layer_.input_size())
+      << "The input and the hidden layers sizes do not match.";
+  RTC_DCHECK_EQ(hidden_layer_.output_size(), output_layer_.input_size())
+      << "The hidden and the output layers sizes do not match.";
+}
+
+RnnBasedVad::~RnnBasedVad() = default;
+
+void RnnBasedVad::Reset() {
+  hidden_layer_.Reset();
+}
+
+float RnnBasedVad::ComputeVadProbability(
+    rtc::ArrayView<const float, kFeatureVectorSize> feature_vector,
+    bool is_silence) {
+  if (is_silence) {
+    Reset();
+    return 0.f;
+  }
+  input_layer_.ComputeOutput(feature_vector);
+  hidden_layer_.ComputeOutput(input_layer_.GetOutput());
+  output_layer_.ComputeOutput(hidden_layer_.GetOutput());
+  const auto vad_output = output_layer_.GetOutput();
+  return vad_output[0];
+}
+
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/rnn.h b/modules/audio_processing/agc2/rnn_vad/rnn.h
new file mode 100644
index 0000000..b3a3b9c
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/rnn.h
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Maximum number of units for a fully-connected layer. This value is used to
+// over-allocate space for fully-connected layers output vectors (implemented as
+// std::array). The value should equal the number of units of the largest
+// fully-connected layer.
+constexpr size_t kFullyConnectedLayersMaxUnits = 24;
+
+// Maximum number of units for a recurrent layer. This value is used to
+// over-allocate space for recurrent layers state vectors (implemented as
+// std::array). The value should equal the number of units of the largest
+// recurrent layer.
+constexpr size_t kRecurrentLayersMaxUnits = 24;
+
+// Fully-connected layer.
+class FullyConnectedLayer {
+ public:
+  FullyConnectedLayer(const size_t input_size,
+                      const size_t output_size,
+                      const rtc::ArrayView<const int8_t> bias,
+                      const rtc::ArrayView<const int8_t> weights,
+                      float (*const activation_function)(float));
+  FullyConnectedLayer(const FullyConnectedLayer&) = delete;
+  FullyConnectedLayer& operator=(const FullyConnectedLayer&) = delete;
+  ~FullyConnectedLayer();
+  size_t input_size() const { return input_size_; }
+  size_t output_size() const { return output_size_; }
+  rtc::ArrayView<const float> GetOutput() const;
+  // Computes the fully-connected layer output.
+  void ComputeOutput(rtc::ArrayView<const float> input);
+
+ private:
+  const size_t input_size_;
+  const size_t output_size_;
+  const rtc::ArrayView<const int8_t> bias_;
+  const rtc::ArrayView<const int8_t> weights_;
+  float (*const activation_function_)(float);
+  // The output vector of a recurrent layer has length equal to |output_size_|.
+  // However, for efficiency, over-allocation is used.
+  std::array<float, kFullyConnectedLayersMaxUnits> output_;
+};
+
+// Recurrent layer with gated recurrent units (GRUs).
+class GatedRecurrentLayer {
+ public:
+  GatedRecurrentLayer(const size_t input_size,
+                      const size_t output_size,
+                      const rtc::ArrayView<const int8_t> bias,
+                      const rtc::ArrayView<const int8_t> weights,
+                      const rtc::ArrayView<const int8_t> recurrent_weights,
+                      float (*const activation_function)(float));
+  GatedRecurrentLayer(const GatedRecurrentLayer&) = delete;
+  GatedRecurrentLayer& operator=(const GatedRecurrentLayer&) = delete;
+  ~GatedRecurrentLayer();
+  size_t input_size() const { return input_size_; }
+  size_t output_size() const { return output_size_; }
+  rtc::ArrayView<const float> GetOutput() const;
+  void Reset();
+  // Computes the recurrent layer output and updates the status.
+  void ComputeOutput(rtc::ArrayView<const float> input);
+
+ private:
+  const size_t input_size_;
+  const size_t output_size_;
+  const rtc::ArrayView<const int8_t> bias_;
+  const rtc::ArrayView<const int8_t> weights_;
+  const rtc::ArrayView<const int8_t> recurrent_weights_;
+  float (*const activation_function_)(float);
+  // The state vector of a recurrent layer has length equal to |output_size_|.
+  // However, to avoid dynamic allocation, over-allocation is used.
+  std::array<float, kRecurrentLayersMaxUnits> state_;
+};
+
+// Recurrent network based VAD.
+class RnnBasedVad {
+ public:
+  RnnBasedVad();
+  RnnBasedVad(const RnnBasedVad&) = delete;
+  RnnBasedVad& operator=(const RnnBasedVad&) = delete;
+  ~RnnBasedVad();
+  void Reset();
+  // Compute and returns the probability of voice (range: [0.0, 1.0]).
+  float ComputeVadProbability(
+      rtc::ArrayView<const float, kFeatureVectorSize> feature_vector,
+      bool is_silence);
+
+ private:
+  FullyConnectedLayer input_layer_;
+  GatedRecurrentLayer hidden_layer_;
+  FullyConnectedLayer output_layer_;
+};
+
+}  // namespace rnn_vad
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_
diff --git a/modules/audio_processing/agc2/rnn_vad/rnn_unittest.cc b/modules/audio_processing/agc2/rnn_vad/rnn_unittest.cc
new file mode 100644
index 0000000..289ce8d
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/rnn_unittest.cc
@@ -0,0 +1,179 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include <algorithm>
+#include <array>
+#include <vector>
+
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+#include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
+#include "rtc_base/checks.h"
+#include "test/gtest.h"
+#include "third_party/rnnoise/src/rnn_activations.h"
+#include "third_party/rnnoise/src/rnn_vad_weights.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+
+using rnnoise::RectifiedLinearUnit;
+using rnnoise::SigmoidApproximated;
+
+namespace {
+
+void TestFullyConnectedLayer(FullyConnectedLayer* fc,
+                             rtc::ArrayView<const float> input_vector,
+                             const float expected_output) {
+  RTC_CHECK(fc);
+  fc->ComputeOutput(input_vector);
+  const auto output = fc->GetOutput();
+  EXPECT_NEAR(expected_output, output[0], 3e-6f);
+}
+
+void TestGatedRecurrentLayer(
+    GatedRecurrentLayer* gru,
+    rtc::ArrayView<const float> input_sequence,
+    rtc::ArrayView<const float> expected_output_sequence) {
+  RTC_CHECK(gru);
+  auto gru_output_view = gru->GetOutput();
+  const size_t input_sequence_length =
+      rtc::CheckedDivExact(input_sequence.size(), gru->input_size());
+  const size_t output_sequence_length =
+      rtc::CheckedDivExact(expected_output_sequence.size(), gru->output_size());
+  ASSERT_EQ(input_sequence_length, output_sequence_length)
+      << "The test data length is invalid.";
+  // Feed the GRU layer and check the output at every step.
+  gru->Reset();
+  for (size_t i = 0; i < input_sequence_length; ++i) {
+    SCOPED_TRACE(i);
+    gru->ComputeOutput(
+        input_sequence.subview(i * gru->input_size(), gru->input_size()));
+    const auto expected_output = expected_output_sequence.subview(
+        i * gru->output_size(), gru->output_size());
+    ExpectNearAbsolute(expected_output, gru_output_view, 3e-6f);
+  }
+}
+
+}  // namespace
+
+// Bit-exactness check for fully connected layers.
+TEST(RnnVadTest, CheckFullyConnectedLayerOutput) {
+  const std::array<int8_t, 1> bias = {-50};
+  const std::array<int8_t, 24> weights = {
+      127,  127,  127, 127,  127,  20,  127,  -126, -126, -54, 14,  125,
+      -126, -126, 127, -125, -126, 127, -127, -127, -57,  -30, 127, 80};
+  FullyConnectedLayer fc(24, 1, bias, weights, SigmoidApproximated);
+  // Test on different inputs.
+  {
+    const std::array<float, 24> input_vector = {
+        0.f,           0.f,           0.f,          0.f,          0.f,
+        0.f,           0.215833917f,  0.290601075f, 0.238759011f, 0.244751841f,
+        0.f,           0.0461241305f, 0.106401242f, 0.223070428f, 0.630603909f,
+        0.690453172f,  0.f,           0.387645692f, 0.166913897f, 0.f,
+        0.0327451192f, 0.f,           0.136149868f, 0.446351469f};
+    TestFullyConnectedLayer(&fc, input_vector, 0.436567038f);
+  }
+  {
+    const std::array<float, 24> input_vector = {
+        0.592162728f,  0.529089332f,  1.18205106f,
+        1.21736848f,   0.f,           0.470851123f,
+        0.130675942f,  0.320903003f,  0.305496395f,
+        0.0571633279f, 1.57001138f,   0.0182026215f,
+        0.0977443159f, 0.347477973f,  0.493206412f,
+        0.9688586f,    0.0320267938f, 0.244722098f,
+        0.312745273f,  0.f,           0.00650715502f,
+        0.312553257f,  1.62619662f,   0.782880902f};
+    TestFullyConnectedLayer(&fc, input_vector, 0.874741316f);
+  }
+  {
+    const std::array<float, 24> input_vector = {
+        0.395022154f,  0.333681047f,  0.76302278f,
+        0.965480626f,  0.f,           0.941198349f,
+        0.0892967582f, 0.745046318f,  0.635769248f,
+        0.238564298f,  0.970656633f,  0.014159563f,
+        0.094203949f,  0.446816623f,  0.640755892f,
+        1.20532358f,   0.0254284926f, 0.283327013f,
+        0.726210058f,  0.0550272502f, 0.000344108557f,
+        0.369803518f,  1.56680179f,   0.997883797f};
+    TestFullyConnectedLayer(&fc, input_vector, 0.672785878f);
+  }
+}
+
+TEST(RnnVadTest, CheckGatedRecurrentLayer) {
+  const std::array<int8_t, 12> bias = {96,   -99, -81, -114, 49,  119,
+                                       -118, 68,  -76, 91,   121, 125};
+  const std::array<int8_t, 60> weights = {
+      124, 9,    1,    116, -66, -21, -118, -110, 104,  75,  -23,  -51,
+      -72, -111, 47,   93,  77,  -98, 41,   -8,   40,   -23, -43,  -107,
+      9,   -73,  30,   -32, -2,  64,  -26,  91,   -48,  -24, -28,  -104,
+      74,  -46,  116,  15,  32,  52,  -126, -38,  -121, 12,  -16,  110,
+      -95, 66,   -103, -35, -38, 3,   -126, -61,  28,   98,  -117, -43};
+  const std::array<int8_t, 60> recurrent_weights = {
+      -3,  87,  50,  51,  -22,  27,  -39, 62,   31,  -83, -52,  -48,
+      -6,  83,  -19, 104, 105,  48,  23,  68,   23,  40,  7,    -120,
+      64,  -62, 117, 85,  -51,  -43, 54,  -105, 120, 56,  -128, -107,
+      39,  50,  -17, -47, -117, 14,  108, 12,   -7,  -72, 103,  -87,
+      -66, 82,  84,  100, -98,  102, -49, 44,   122, 106, -20,  -69};
+  GatedRecurrentLayer gru(5, 4, bias, weights, recurrent_weights,
+                          RectifiedLinearUnit);
+  // Test on different inputs.
+  {
+    const std::array<float, 20> input_sequence = {
+        0.89395463f, 0.93224651f, 0.55788344f, 0.32341808f, 0.93355054f,
+        0.13475326f, 0.97370994f, 0.14253306f, 0.93710381f, 0.76093364f,
+        0.65780413f, 0.41657975f, 0.49403164f, 0.46843281f, 0.75138855f,
+        0.24517593f, 0.47657707f, 0.57064998f, 0.435184f,   0.19319285f};
+    const std::array<float, 16> expected_output_sequence = {
+        0.0239123f,  0.5773077f,  0.f,         0.f,
+        0.01282811f, 0.64330572f, 0.f,         0.04863098f,
+        0.00781069f, 0.75267816f, 0.f,         0.02579715f,
+        0.00471378f, 0.59162533f, 0.11087593f, 0.01334511f};
+    TestGatedRecurrentLayer(&gru, input_sequence, expected_output_sequence);
+  }
+}
+
+// TODO(bugs.webrtc.org/9076): Remove when the issue is fixed.
+// Bit-exactness test checking that precomputed frame-wise features lead to the
+// expected VAD probabilities.
+TEST(RnnVadTest, RnnBitExactness) {
+  // Init.
+  auto features_reader = CreateSilenceFlagsFeatureMatrixReader();
+  auto vad_probs_reader = CreateVadProbsReader();
+  ASSERT_EQ(features_reader.second, vad_probs_reader.second);
+  const size_t num_frames = features_reader.second;
+  // Frame-wise buffers.
+  float expected_vad_probability;
+  float is_silence;
+  std::array<float, kFeatureVectorSize> features;
+
+  // Compute VAD probability using the precomputed features.
+  RnnBasedVad vad;
+  for (size_t i = 0; i < num_frames; ++i) {
+    SCOPED_TRACE(i);
+    // Read frame data.
+    RTC_CHECK(vad_probs_reader.first->ReadValue(&expected_vad_probability));
+    // The features file also includes a silence flag for each frame.
+    RTC_CHECK(features_reader.first->ReadValue(&is_silence));
+    RTC_CHECK(features_reader.first->ReadChunk(features));
+    // Compute and check VAD probability.
+    float vad_probability = vad.ComputeVadProbability(features, is_silence);
+    ASSERT_TRUE(is_silence == 0.f || is_silence == 1.f);
+    if (is_silence == 1.f) {
+      ASSERT_EQ(0.f, expected_vad_probability);
+      EXPECT_EQ(0.f, vad_probability);
+    } else {
+      EXPECT_NEAR(expected_vad_probability, vad_probability, 3e-6f);
+    }
+  }
+}
+
+}  // namespace test
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc b/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc
index 6ab932c..5fba0bf 100644
--- a/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc
+++ b/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc
@@ -15,15 +15,16 @@
 #include "common_audio/resampler/push_sinc_resampler.h"
 #include "common_audio/wav_file.h"
 #include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
 #include "rtc_base/flags.h"
 #include "rtc_base/logging.h"
 
 namespace webrtc {
+namespace rnn_vad {
 namespace test {
 namespace {
 
-using rnn_vad::kFrameSize10ms24kHz;
-
 DEFINE_string(i, "", "Path to the input wav file");
 std::string InputWavFile() {
   return static_cast<std::string>(FLAG_i);
@@ -71,15 +72,16 @@
     features_file = fopen(output_feature_file.c_str(), "wb");
   }
 
-  // Init resampling.
+  // Initialize.
   const size_t frame_size_10ms =
       rtc::CheckedDivExact(wav_reader.sample_rate(), 100);
   std::vector<float> samples_10ms;
   samples_10ms.resize(frame_size_10ms);
   std::array<float, kFrameSize10ms24kHz> samples_10ms_24kHz;
   PushSincResampler resampler(frame_size_10ms, kFrameSize10ms24kHz);
-
-  // TODO(bugs.webrtc.org/9076): Init feature extractor and RNN-based VAD.
+  FeaturesExtractor features_extractor;
+  std::array<float, kFeatureVectorSize> feature_vector;
+  RnnBasedVad rnn_vad;
 
   // Compute VAD probabilities.
   while (true) {
@@ -93,28 +95,24 @@
     resampler.Resample(samples_10ms.data(), samples_10ms.size(),
                        samples_10ms_24kHz.data(), samples_10ms_24kHz.size());
 
-    // TODO(bugs.webrtc.org/9076): Extract features.
-    float vad_probability;
-    bool is_silence = true;
-
+    // Extract features and feed the RNN.
+    bool is_silence = features_extractor.CheckSilenceComputeFeatures(
+        samples_10ms_24kHz, feature_vector);
+    float vad_probability =
+        rnn_vad.ComputeVadProbability(feature_vector, is_silence);
+    // Write voice probability.
+    RTC_DCHECK_GE(vad_probability, 0.f);
+    RTC_DCHECK_GE(1.f, vad_probability);
+    fwrite(&vad_probability, sizeof(float), 1, vad_probs_file);
     // Write features.
     if (features_file) {
       const float float_is_silence = is_silence ? 1.f : 0.f;
       fwrite(&float_is_silence, sizeof(float), 1, features_file);
-      // TODO(bugs.webrtc.org/9076): Write feature vector.
+      fwrite(feature_vector.data(), sizeof(float), kFeatureVectorSize,
+             features_file);
     }
-
-    // Compute VAD probability.
-    if (is_silence) {
-      vad_probability = 0.f;
-      // TODO(bugs.webrtc.org/9076): Reset VAD.
-    } else {
-      // TODO(bugs.webrtc.org/9076): Compute VAD probability.
-    }
-    RTC_DCHECK_GE(vad_probability, 0.f);
-    RTC_DCHECK_GE(1.f, vad_probability);
-    fwrite(&vad_probability, sizeof(float), 1, vad_probs_file);
   }
+
   // Close output file(s).
   fclose(vad_probs_file);
   RTC_LOG(LS_INFO) << "VAD probabilities written to " << FLAG_o;
@@ -127,8 +125,9 @@
 }
 
 }  // namespace test
+}  // namespace rnn_vad
 }  // namespace webrtc
 
 int main(int argc, char* argv[]) {
-  return webrtc::test::main(argc, argv);
+  return webrtc::rnn_vad::test::main(argc, argv);
 }
diff --git a/modules/audio_processing/agc2/rnn_vad/rnn_vad_unittest.cc b/modules/audio_processing/agc2/rnn_vad/rnn_vad_unittest.cc
new file mode 100644
index 0000000..4afe24b
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/rnn_vad_unittest.cc
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include <array>
+#include <vector>
+
+#include "common_audio/resampler/push_sinc_resampler.h"
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+#include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
+#include "modules/audio_processing/test/performance_timer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "test/gtest.h"
+#include "third_party/rnnoise/src/rnn_activations.h"
+#include "third_party/rnnoise/src/rnn_vad_weights.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+namespace {
+
+constexpr size_t kFrameSize10ms48kHz = 480;
+
+void DumpPerfStats(size_t num_samples,
+                   size_t sample_rate,
+                   double average_us,
+                   double standard_deviation) {
+  float audio_track_length_ms =
+      1e3f * static_cast<float>(num_samples) / static_cast<float>(sample_rate);
+  float average_ms = static_cast<float>(average_us) / 1e3f;
+  float speed = audio_track_length_ms / average_ms;
+  RTC_LOG(LS_INFO) << "track duration (ms): " << audio_track_length_ms;
+  RTC_LOG(LS_INFO) << "average processing time (ms): " << average_ms << " +/- "
+                   << (standard_deviation / 1e3);
+  RTC_LOG(LS_INFO) << "speed: " << speed << "x";
+}
+
+}  // namespace
+
+// Performance test for the RNN VAD (pre-fetching and downsampling are
+// excluded). Keep disabled and only enable locally to measure performance as
+// follows:
+// - on desktop: run the this unit test adding "--logs";
+// - on android: run the this unit test adding "--logcat-output-file".
+TEST(RnnVadTest, DISABLED_RnnVadPerformance) {
+  // PCM samples reader and buffers.
+  auto samples_reader = CreatePcmSamplesReader(kFrameSize10ms48kHz);
+  const size_t num_frames = samples_reader.second;
+  std::array<float, kFrameSize10ms48kHz> samples;
+  // Pre-fetch and decimate samples.
+  PushSincResampler decimator(kFrameSize10ms48kHz, kFrameSize10ms24kHz);
+  std::vector<float> prefetched_decimated_samples;
+  prefetched_decimated_samples.resize(num_frames * kFrameSize10ms24kHz);
+  for (size_t i = 0; i < num_frames; ++i) {
+    samples_reader.first->ReadChunk(samples);
+    decimator.Resample(samples.data(), samples.size(),
+                       &prefetched_decimated_samples[i * kFrameSize10ms24kHz],
+                       kFrameSize10ms24kHz);
+  }
+  // Initialize.
+  FeaturesExtractor features_extractor;
+  std::array<float, kFeatureVectorSize> feature_vector;
+  RnnBasedVad rnn_vad;
+  constexpr size_t number_of_tests = 100;
+  ::webrtc::test::PerformanceTimer perf_timer(number_of_tests);
+  for (size_t k = 0; k < number_of_tests; ++k) {
+    features_extractor.Reset();
+    rnn_vad.Reset();
+    // Process frames.
+    perf_timer.StartTimer();
+    for (size_t i = 0; i < num_frames; ++i) {
+      bool is_silence = features_extractor.CheckSilenceComputeFeatures(
+          {&prefetched_decimated_samples[i * kFrameSize10ms24kHz],
+           kFrameSize10ms24kHz},
+          feature_vector);
+      rnn_vad.ComputeVadProbability(feature_vector, is_silence);
+    }
+    perf_timer.StopTimer();
+    samples_reader.first->SeekBeginning();
+  }
+  DumpPerfStats(num_frames * kFrameSize10ms24kHz, kSampleRate24kHz,
+                perf_timer.GetDurationAverage(),
+                perf_timer.GetDurationStandardDeviation());
+}
+
+}  // namespace test
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h b/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h
index 7ae2f95..75d3d9b 100644
--- a/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h
+++ b/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h
@@ -11,9 +11,10 @@
 #ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_
 #define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_
 
-#include <array>
+#include <algorithm>
 #include <cstring>
 #include <type_traits>
+#include <vector>
 
 #include "api/array_view.h"
 #include "rtc_base/checks.h"
@@ -26,41 +27,38 @@
 // chunks have size S and N respectively. For instance, when S = 2N the first
 // half of the sequence buffer is replaced with its second half, and the new N
 // values are written at the end of the buffer.
-template <typename T, size_t S, size_t N>
+// The class also provides a view on the most recent M values, where 0 < M <= S
+// and by default M = N.
+template <typename T, size_t S, size_t N, size_t M = N>
 class SequenceBuffer {
-  static_assert(S >= N,
-                "The new chunk size is larger than the sequence buffer size.");
+  static_assert(N <= S,
+                "The new chunk size cannot be larger than the sequence buffer "
+                "size.");
   static_assert(std::is_arithmetic<T>::value,
                 "Integral or floating point required.");
 
  public:
-  SequenceBuffer() { buffer_.fill(0); }
+  SequenceBuffer() : buffer_(S) {
+    RTC_DCHECK_EQ(S, buffer_.size());
+    Reset();
+  }
   SequenceBuffer(const SequenceBuffer&) = delete;
   SequenceBuffer& operator=(const SequenceBuffer&) = delete;
   ~SequenceBuffer() = default;
   size_t size() const { return S; }
   size_t chunks_size() const { return N; }
   // Sets the sequence buffer values to zero.
-  void Reset() { buffer_.fill(0); }
+  void Reset() { std::fill(buffer_.begin(), buffer_.end(), 0); }
   // Returns a view on the whole buffer.
   rtc::ArrayView<const T, S> GetBufferView() const {
     return {buffer_.data(), S};
   }
-  // Returns a view on part of the buffer; the first element starts at the given
-  // offset and the last one is the last one in the buffer.
-  rtc::ArrayView<const T> GetBufferView(int offset) const {
-    RTC_DCHECK_LE(0, offset);
-    RTC_DCHECK_LT(offset, S);
-    return {buffer_.data() + offset, S - offset};
-  }
-  // Returns a view on part of the buffer; the first element starts at the given
-  // offset and the size of the view is |size|.
-  rtc::ArrayView<const T> GetBufferView(int offset, size_t size) const {
-    RTC_DCHECK_LE(0, offset);
-    RTC_DCHECK_LT(offset, S);
-    RTC_DCHECK_LT(0, size);
-    RTC_DCHECK_LE(size, S - offset);
-    return {buffer_.data() + offset, size};
+  // Returns a view on the M most recent values of the buffer.
+  rtc::ArrayView<const T, M> GetMostRecentValuesView() const {
+    static_assert(M <= S,
+                  "The number of most recent values cannot be larger than the "
+                  "sequence buffer size.");
+    return {buffer_.data() + S - M, M};
   }
   // Shifts left the buffer by N items and add new N items at the end.
   void Push(rtc::ArrayView<const T, N> new_values) {
@@ -72,7 +70,7 @@
   }
 
  private:
-  std::array<T, S> buffer_;
+  std::vector<T> buffer_;
 };
 
 }  // namespace rnn_vad
diff --git a/modules/audio_processing/agc2/rnn_vad/sequence_buffer_unittest.cc b/modules/audio_processing/agc2/rnn_vad/sequence_buffer_unittest.cc
index 7628c17..9b66dcf 100644
--- a/modules/audio_processing/agc2/rnn_vad/sequence_buffer_unittest.cc
+++ b/modules/audio_processing/agc2/rnn_vad/sequence_buffer_unittest.cc
@@ -11,6 +11,7 @@
 #include "modules/audio_processing/agc2/rnn_vad/sequence_buffer.h"
 
 #include <algorithm>
+#include <array>
 
 #include "test/gtest.h"
 
@@ -26,22 +27,21 @@
   SequenceBuffer<T, S, N> seq_buf;
   auto seq_buf_view = seq_buf.GetBufferView();
   std::array<T, N> chunk;
-  rtc::ArrayView<T, N> chunk_view(chunk.data(), chunk.size());
 
   // Check that a chunk is fully gone after ceil(S / N) push ops.
   chunk.fill(1);
-  seq_buf.Push(chunk_view);
+  seq_buf.Push(chunk);
   chunk.fill(0);
   constexpr size_t required_push_ops = (S % N) ? S / N + 1 : S / N;
   for (size_t i = 0; i < required_push_ops - 1; ++i) {
     SCOPED_TRACE(i);
-    seq_buf.Push(chunk_view);
+    seq_buf.Push(chunk);
     // Still in the buffer.
     const auto* m = std::max_element(seq_buf_view.begin(), seq_buf_view.end());
     EXPECT_EQ(1, *m);
   }
   // Gone after another push.
-  seq_buf.Push(chunk_view);
+  seq_buf.Push(chunk);
   const auto* m = std::max_element(seq_buf_view.begin(), seq_buf_view.end());
   EXPECT_EQ(0, *m);
 
@@ -50,12 +50,12 @@
     // Fill in with non-zero values.
     for (size_t i = 0; i < N; ++i)
       chunk[i] = static_cast<T>(i + 1);
-    seq_buf.Push(chunk_view);
+    seq_buf.Push(chunk);
     // With the next Push(), |last| will be moved left by N positions.
     const T last = chunk[N - 1];
     for (size_t i = 0; i < N; ++i)
       chunk[i] = static_cast<T>(last + i + 1);
-    seq_buf.Push(chunk_view);
+    seq_buf.Push(chunk);
     EXPECT_EQ(last, seq_buf_view[S - N - 1]);
   }
 }
@@ -74,7 +74,7 @@
   EXPECT_EQ(0, seq_buf_view[seq_buf_view.size() - 1]);
   constexpr std::array<int, chunk_size> chunk = {10, 20, 30, 40,
                                                  50, 60, 70, 80};
-  seq_buf.Push({chunk.data(), chunk_size});
+  seq_buf.Push(chunk);
   EXPECT_EQ(10, *seq_buf_view.begin());
   EXPECT_EQ(80, *(seq_buf_view.end() - 1));
 }
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features.cc b/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
new file mode 100644
index 0000000..695eed5
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
@@ -0,0 +1,198 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <numeric>
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+constexpr float kSilenceThreshold = 0.04f;
+
+// Computes the new spectral difference stats and pushes them into the passed
+// symmetric matrix buffer.
+void UpdateSpectralDifferenceStats(
+    rtc::ArrayView<const float, kNumBands> new_spectral_coeffs,
+    const RingBuffer<float, kNumBands, kSpectralCoeffsHistorySize>& ring_buf,
+    SymmetricMatrixBuffer<float, kSpectralCoeffsHistorySize>* sym_matrix_buf) {
+  RTC_DCHECK(sym_matrix_buf);
+  // Compute the new spectral distance stats.
+  std::array<float, kSpectralCoeffsHistorySize - 1> distances;
+  for (size_t i = 0; i < kSpectralCoeffsHistorySize - 1; ++i) {
+    const size_t delay = i + 1;
+    auto old_spectral_coeffs = ring_buf.GetArrayView(delay);
+    distances[i] = 0.f;
+    for (size_t k = 0; k < kNumBands; ++k) {
+      const float c = new_spectral_coeffs[k] - old_spectral_coeffs[k];
+      distances[i] += c * c;
+    }
+  }
+  // Push the new spectral distance stats into the symmetric matrix buffer.
+  sym_matrix_buf->Push(distances);
+}
+
+}  // namespace
+
+SpectralFeaturesView::SpectralFeaturesView(
+    rtc::ArrayView<float, kNumBands - kNumLowerBands> coeffs,
+    rtc::ArrayView<float, kNumLowerBands> average,
+    rtc::ArrayView<float, kNumLowerBands> first_derivative,
+    rtc::ArrayView<float, kNumLowerBands> second_derivative,
+    rtc::ArrayView<float, kNumLowerBands> cross_correlations,
+    float* variability)
+    : coeffs(coeffs),
+      average(average),
+      first_derivative(first_derivative),
+      second_derivative(second_derivative),
+      cross_correlations(cross_correlations),
+      variability(variability) {}
+
+SpectralFeaturesView::SpectralFeaturesView(const SpectralFeaturesView&) =
+    default;
+SpectralFeaturesView::~SpectralFeaturesView() = default;
+
+SpectralFeaturesExtractor::SpectralFeaturesExtractor()
+    : fft_(),
+      reference_frame_fft_(kFrameSize20ms24kHz),
+      lagged_frame_fft_(kFrameSize20ms24kHz),
+      band_boundaries_(
+          ComputeBandBoundaryIndexes(kSampleRate24kHz, kFrameSize20ms24kHz)),
+      dct_table_(ComputeDctTable()) {}
+
+SpectralFeaturesExtractor::~SpectralFeaturesExtractor() = default;
+
+void SpectralFeaturesExtractor::Reset() {
+  spectral_coeffs_ring_buf_.Reset();
+  spectral_diffs_buf_.Reset();
+}
+
+bool SpectralFeaturesExtractor::CheckSilenceComputeFeatures(
+    rtc::ArrayView<const float, kFrameSize20ms24kHz> reference_frame,
+    rtc::ArrayView<const float, kFrameSize20ms24kHz> lagged_frame,
+    SpectralFeaturesView spectral_features) {
+  // Analyze reference frame.
+  fft_.ForwardFft(reference_frame, reference_frame_fft_);
+  ComputeBandEnergies(reference_frame_fft_, band_boundaries_,
+                      reference_frame_energy_coeffs_);
+  // Check if the reference frame has silence.
+  const float tot_energy =
+      std::accumulate(reference_frame_energy_coeffs_.begin(),
+                      reference_frame_energy_coeffs_.end(), 0.f);
+  if (tot_energy < kSilenceThreshold)
+    return true;
+  // Analyze lagged frame.
+  fft_.ForwardFft(lagged_frame, lagged_frame_fft_);
+  ComputeBandEnergies(lagged_frame_fft_, band_boundaries_,
+                      lagged_frame_energy_coeffs_);
+  // Log of the band energies for the reference frame.
+  std::array<float, kNumBands> log_band_energy_coeffs;
+  ComputeLogBandEnergiesCoefficients(reference_frame_energy_coeffs_,
+                                     log_band_energy_coeffs);
+  // Decorrelate band-wise log energy coefficients via DCT.
+  std::array<float, kNumBands> log_band_energy_coeffs_decorrelated;
+  ComputeDct(log_band_energy_coeffs, dct_table_,
+             log_band_energy_coeffs_decorrelated);
+  // Normalize (based on training set stats).
+  log_band_energy_coeffs_decorrelated[0] -= 12;
+  log_band_energy_coeffs_decorrelated[1] -= 4;
+  // Update the ring buffer and the spectral difference stats.
+  spectral_coeffs_ring_buf_.Push(log_band_energy_coeffs_decorrelated);
+  UpdateSpectralDifferenceStats(log_band_energy_coeffs_decorrelated,
+                                spectral_coeffs_ring_buf_,
+                                &spectral_diffs_buf_);
+  // Write the higher bands spectral coefficients.
+  auto coeffs_src = spectral_coeffs_ring_buf_.GetArrayView(0);
+  RTC_DCHECK_EQ(coeffs_src.size() - kNumLowerBands,
+                spectral_features.coeffs.size());
+  std::copy(coeffs_src.begin() + kNumLowerBands, coeffs_src.end(),
+            spectral_features.coeffs.begin());
+  // Compute and write remaining features.
+  ComputeAvgAndDerivatives(spectral_features.average,
+                           spectral_features.first_derivative,
+                           spectral_features.second_derivative);
+  ComputeCrossCorrelation(spectral_features.cross_correlations);
+  RTC_DCHECK(spectral_features.variability);
+  *(spectral_features.variability) = ComputeVariability();
+  return false;
+}
+
+void SpectralFeaturesExtractor::ComputeAvgAndDerivatives(
+    rtc::ArrayView<float, kNumLowerBands> average,
+    rtc::ArrayView<float, kNumLowerBands> first_derivative,
+    rtc::ArrayView<float, kNumLowerBands> second_derivative) {
+  auto curr = spectral_coeffs_ring_buf_.GetArrayView(0);
+  auto prev1 = spectral_coeffs_ring_buf_.GetArrayView(1);
+  auto prev2 = spectral_coeffs_ring_buf_.GetArrayView(2);
+  RTC_DCHECK_EQ(average.size(), first_derivative.size());
+  RTC_DCHECK_EQ(first_derivative.size(), second_derivative.size());
+  RTC_DCHECK_LE(average.size(), curr.size());
+  for (size_t i = 0; i < average.size(); ++i) {
+    // Average, kernel: [1, 1, 1].
+    average[i] = curr[i] + prev1[i] + prev2[i];
+    // First derivative, kernel: [1, 0, - 1].
+    first_derivative[i] = curr[i] - prev2[i];
+    // Second derivative, Laplacian kernel: [1, -2, 1].
+    second_derivative[i] = curr[i] - 2 * prev1[i] + prev2[i];
+  }
+}
+
+void SpectralFeaturesExtractor::ComputeCrossCorrelation(
+    rtc::ArrayView<float, kNumLowerBands> cross_correlations) {
+  const auto& x = reference_frame_fft_;
+  const auto& y = lagged_frame_fft_;
+  auto cross_corr = [x, y](const size_t freq_bin_index) -> float {
+    return (x[freq_bin_index].real() * y[freq_bin_index].real() +
+            x[freq_bin_index].imag() * y[freq_bin_index].imag());
+  };
+  std::array<float, kNumBands> cross_corr_coeffs;
+  constexpr size_t kNumFftPoints = kFrameSize20ms24kHz / 2 + 1;
+  ComputeBandCoefficients(cross_corr, band_boundaries_, kNumFftPoints - 1,
+                          cross_corr_coeffs);
+  // Normalize.
+  for (size_t i = 0; i < cross_corr_coeffs.size(); ++i) {
+    cross_corr_coeffs[i] =
+        cross_corr_coeffs[i] /
+        std::sqrt(0.001f + reference_frame_energy_coeffs_[i] *
+                               lagged_frame_energy_coeffs_[i]);
+  }
+  // Decorrelate.
+  ComputeDct(cross_corr_coeffs, dct_table_, cross_correlations);
+  // Normalize (based on training set stats).
+  cross_correlations[0] -= 1.3f;
+  cross_correlations[1] -= 0.9f;
+}
+
+float SpectralFeaturesExtractor::ComputeVariability() {
+  // Compute spectral variability score.
+  float spec_variability = 0.f;
+  for (size_t delay1 = 0; delay1 < kSpectralCoeffsHistorySize; ++delay1) {
+    float min_dist = std::numeric_limits<float>::max();
+    for (size_t delay2 = 0; delay2 < kSpectralCoeffsHistorySize; ++delay2) {
+      if (delay1 == delay2)  // The distance would be 0.
+        continue;
+      min_dist =
+          std::min(min_dist, spectral_diffs_buf_.GetValue(delay1, delay2));
+    }
+    spec_variability += min_dist;
+  }
+  // Normalize (based on training set stats).
+  return spec_variability / kSpectralCoeffsHistorySize - 2.1f;
+}
+
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features.h b/modules/audio_processing/agc2/rnn_vad/spectral_features.h
new file mode 100644
index 0000000..bedd7ab
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features.h
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_
+
+#include <array>
+#include <complex>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/fft_util.h"
+#include "modules/audio_processing/agc2/rnn_vad/ring_buffer.h"
+#include "modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// View on spectral features.
+class SpectralFeaturesView {
+ public:
+  SpectralFeaturesView(rtc::ArrayView<float, kNumBands - kNumLowerBands> coeffs,
+                       rtc::ArrayView<float, kNumLowerBands> average,
+                       rtc::ArrayView<float, kNumLowerBands> first_derivative,
+                       rtc::ArrayView<float, kNumLowerBands> second_derivative,
+                       rtc::ArrayView<float, kNumLowerBands> cross_correlations,
+                       float* variability);
+  SpectralFeaturesView(const SpectralFeaturesView&);
+  ~SpectralFeaturesView();
+  // Higher bands spectral coefficients.
+  const rtc::ArrayView<float, kNumBands - kNumLowerBands> coeffs;
+  // Average and first and second derivative over time for the lower bands.
+  const rtc::ArrayView<float, kNumLowerBands> average;
+  const rtc::ArrayView<float, kNumLowerBands> first_derivative;
+  const rtc::ArrayView<float, kNumLowerBands> second_derivative;
+  // Spectral cross-correlation for the lower bands.
+  const rtc::ArrayView<float, kNumLowerBands> cross_correlations;
+  // Spectral variability score.
+  float* const variability;
+};
+
+// Class to compute spectral features.
+class SpectralFeaturesExtractor {
+ public:
+  SpectralFeaturesExtractor();
+  SpectralFeaturesExtractor(const SpectralFeaturesExtractor&) = delete;
+  SpectralFeaturesExtractor& operator=(const SpectralFeaturesExtractor&) =
+      delete;
+  ~SpectralFeaturesExtractor();
+  // Resets the internal state of the feature extractor.
+  void Reset();
+  // Analyzes a pair of reference and lagged frames from the pitch buffer,
+  // detects silence and computes features. If silence is detected, the output
+  // is neither computed nor written.
+  bool CheckSilenceComputeFeatures(
+      rtc::ArrayView<const float, kFrameSize20ms24kHz> reference_frame,
+      rtc::ArrayView<const float, kFrameSize20ms24kHz> lagged_frame,
+      SpectralFeaturesView spectral_features);
+
+ private:
+  void ComputeAvgAndDerivatives(
+      rtc::ArrayView<float, kNumLowerBands> average,
+      rtc::ArrayView<float, kNumLowerBands> first_derivative,
+      rtc::ArrayView<float, kNumLowerBands> second_derivative);
+  void ComputeCrossCorrelation(
+      rtc::ArrayView<float, kNumLowerBands> cross_correlations);
+  float ComputeVariability();
+
+  BandAnalysisFft fft_;
+  std::vector<std::complex<float>> reference_frame_fft_;
+  std::vector<std::complex<float>> lagged_frame_fft_;
+  std::array<float, kNumBands> reference_frame_energy_coeffs_{};
+  std::array<float, kNumBands> lagged_frame_energy_coeffs_{};
+  const std::array<size_t, kNumBands> band_boundaries_;
+  const std::array<float, kNumBands * kNumBands> dct_table_;
+  RingBuffer<float, kNumBands, kSpectralCoeffsHistorySize>
+      spectral_coeffs_ring_buf_;
+  SymmetricMatrixBuffer<float, kSpectralCoeffsHistorySize> spectral_diffs_buf_;
+};
+
+}  // namespace rnn_vad
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc b/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc
new file mode 100644
index 0000000..4cbe48a
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+// DCT scaling factor.
+const float kDctScalingFactor = std::sqrt(2.f / kNumBands);
+
+}  // namespace
+
+std::array<size_t, kNumBands> ComputeBandBoundaryIndexes(
+    size_t sample_rate_hz,
+    size_t frame_size_samples) {
+  std::array<size_t, kNumBands> indexes;
+  for (size_t i = 0; i < kNumBands; ++i) {
+    indexes[i] =
+        kBandFrequencyBoundaries[i] * frame_size_samples / sample_rate_hz;
+  }
+  return indexes;
+}
+
+void ComputeBandCoefficients(
+    rtc::FunctionView<float(size_t)> functor,
+    rtc::ArrayView<const size_t, kNumBands> band_boundaries,
+    size_t max_freq_bin_index,
+    rtc::ArrayView<float, kNumBands> coefficients) {
+  std::fill(coefficients.begin(), coefficients.end(), 0.f);
+  for (size_t i = 0; i < coefficients.size() - 1; ++i) {
+    RTC_DCHECK_EQ(0.f, coefficients[i + 1]);
+    RTC_DCHECK_GT(band_boundaries[i + 1], band_boundaries[i]);
+    const size_t first_freq_bin = band_boundaries[i];
+    const size_t last_freq_bin =
+        std::min(max_freq_bin_index, first_freq_bin + band_boundaries[i + 1] -
+                                         band_boundaries[i] - 1);
+    // Depending on the sample rate, the highest bands can have no FFT
+    // coefficients. Stop the iteration when coming across the first empty band.
+    if (first_freq_bin >= last_freq_bin)
+      break;
+    const size_t band_size = last_freq_bin - first_freq_bin + 1;
+    // Compute the band coefficient using a triangular band with peak response
+    // at the band boundary.
+    for (size_t j = first_freq_bin; j <= last_freq_bin; ++j) {
+      const float w = static_cast<float>(j - first_freq_bin) / band_size;
+      const float coefficient = functor(j);
+      coefficients[i] += (1.f - w) * coefficient;
+      coefficients[i + 1] += w * coefficient;
+    }
+  }
+  // The first and the last bands in the loop above only got half contribution.
+  coefficients[0] *= 2.f;
+  coefficients[coefficients.size() - 1] *= 2.f;
+  // TODO(bugs.webrtc.org/9076): Replace the line above with
+  // "coefficients[i] *= 2.f" (*) since we now assume that the last band is
+  // always |kNumBands| - 1.
+  // (*): "size_t i" must be declared before the main loop.
+}
+
+void ComputeBandEnergies(
+    rtc::ArrayView<const std::complex<float>> fft_coeffs,
+    rtc::ArrayView<const size_t, kNumBands> band_boundaries,
+    rtc::ArrayView<float, kNumBands> band_energies) {
+  RTC_DCHECK_EQ(band_boundaries.size(), band_energies.size());
+  auto functor = [fft_coeffs](const size_t freq_bin_index) -> float {
+    return std::norm(fft_coeffs[freq_bin_index]);
+  };
+  ComputeBandCoefficients(functor, band_boundaries, fft_coeffs.size() - 1,
+                          band_energies);
+}
+
+void ComputeLogBandEnergiesCoefficients(
+    rtc::ArrayView<const float, kNumBands> band_energy_coeffs,
+    rtc::ArrayView<float, kNumBands> log_band_energy_coeffs) {
+  float log_max = -2.f;
+  float follow = -2.f;
+  for (size_t i = 0; i < band_energy_coeffs.size(); ++i) {
+    log_band_energy_coeffs[i] = std::log10(1e-2f + band_energy_coeffs[i]);
+    // Smoothing across frequency bands.
+    log_band_energy_coeffs[i] = std::max(
+        log_max - 7.f, std::max(follow - 1.5f, log_band_energy_coeffs[i]));
+    log_max = std::max(log_max, log_band_energy_coeffs[i]);
+    follow = std::max(follow - 1.5f, log_band_energy_coeffs[i]);
+  }
+}
+
+std::array<float, kNumBands * kNumBands> ComputeDctTable() {
+  std::array<float, kNumBands * kNumBands> dct_table;
+  const double k = std::sqrt(0.5);
+  for (size_t i = 0; i < kNumBands; ++i) {
+    for (size_t j = 0; j < kNumBands; ++j)
+      dct_table[i * kNumBands + j] = std::cos((i + 0.5) * j * kPi / kNumBands);
+    dct_table[i * kNumBands] *= k;
+  }
+  return dct_table;
+}
+
+void ComputeDct(rtc::ArrayView<const float, kNumBands> in,
+                rtc::ArrayView<const float, kNumBands * kNumBands> dct_table,
+                rtc::ArrayView<float> out) {
+  RTC_DCHECK_NE(in.data(), out.data()) << "In-place DCT is not supported.";
+  RTC_DCHECK_LE(1, out.size());
+  RTC_DCHECK_LE(out.size(), in.size());
+  std::fill(out.begin(), out.end(), 0.f);
+  for (size_t i = 0; i < out.size(); ++i) {
+    for (size_t j = 0; j < in.size(); ++j) {
+      out[i] += in[j] * dct_table[j * in.size() + i];
+    }
+    out[i] *= kDctScalingFactor;
+  }
+}
+
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h b/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h
new file mode 100644
index 0000000..45bb382
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h
@@ -0,0 +1,65 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_
+
+#include <array>
+#include <complex>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "rtc_base/function_view.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Computes FFT boundary indexes corresponding to sub-bands.
+std::array<size_t, kNumBands> ComputeBandBoundaryIndexes(
+    size_t sample_rate_hz,
+    size_t frame_size_samples);
+
+// Iterates through frequency bands and computes coefficients via |functor| for
+// triangular bands with peak response at each band boundary. |functor| returns
+// a floating point value for the FFT coefficient having index equal to the
+// argument passed to |functor|; that argument is in the range {0, ...
+// |max_freq_bin_index| - 1}.
+void ComputeBandCoefficients(
+    rtc::FunctionView<float(size_t)> functor,
+    rtc::ArrayView<const size_t, kNumBands> band_boundaries,
+    const size_t max_freq_bin_index,
+    rtc::ArrayView<float, kNumBands> coefficients);
+
+// Given an array of FFT coefficients and a vector of band boundary indexes,
+// computes band energy coefficients.
+void ComputeBandEnergies(
+    rtc::ArrayView<const std::complex<float>> fft_coeffs,
+    rtc::ArrayView<const size_t, kNumBands> band_boundaries,
+    rtc::ArrayView<float, kNumBands> band_energies);
+
+// Computes log band energy coefficients.
+void ComputeLogBandEnergiesCoefficients(
+    rtc::ArrayView<const float, kNumBands> band_energy_coeffs,
+    rtc::ArrayView<float, kNumBands> log_band_energy_coeffs);
+
+// Creates a DCT table for arrays having size equal to |kNumBands|.
+std::array<float, kNumBands * kNumBands> ComputeDctTable();
+
+// Computes DCT for |in| given a pre-computed DCT table. In-place computation is
+// not allowed and |out| can be smaller than |in| in order to only compute the
+// first DCT coefficients.
+void ComputeDct(rtc::ArrayView<const float, kNumBands> in,
+                rtc::ArrayView<const float, kNumBands * kNumBands> dct_table,
+                rtc::ArrayView<float> out);
+
+}  // namespace rnn_vad
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features_internal_unittest.cc b/modules/audio_processing/agc2/rnn_vad/spectral_features_internal_unittest.cc
new file mode 100644
index 0000000..5e769bf
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features_internal_unittest.cc
@@ -0,0 +1,125 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h"
+
+#include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
+// TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+// #include "test/fpe_observer.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+namespace {
+
+constexpr size_t kSampleRate48kHz = 48000;
+constexpr size_t kFrameSize20ms48kHz = 2 * kSampleRate48kHz / 100;
+constexpr size_t kFftNumCoeffs20ms48kHz = kFrameSize20ms48kHz / 2 + 1;
+
+}  // namespace
+
+// TODO(bugs.webrtc.org/9076): Remove this test before closing the issue.
+// Check that when using precomputed FFT coefficients for frames at 48 kHz, the
+// output of ComputeBandEnergies() is bit exact.
+TEST(RnnVadTest, ComputeBandEnergies48kHzBitExactness) {
+  // Initialize input data reader and buffers.
+  auto fft_coeffs_reader = CreateFftCoeffsReader();
+  const size_t num_frames = fft_coeffs_reader.second;
+  ASSERT_EQ(
+      kFftNumCoeffs20ms48kHz,
+      rtc::CheckedDivExact(fft_coeffs_reader.first->data_length(), num_frames) /
+          2);
+  std::array<float, kFftNumCoeffs20ms48kHz> fft_coeffs_real;
+  std::array<float, kFftNumCoeffs20ms48kHz> fft_coeffs_imag;
+  std::array<std::complex<float>, kFftNumCoeffs20ms48kHz> fft_coeffs;
+  // Init expected output reader and buffer.
+  auto band_energies_reader = CreateBandEnergyCoeffsReader();
+  ASSERT_EQ(num_frames, band_energies_reader.second);
+  std::array<float, kNumBands> expected_band_energies;
+  // Init band energies coefficients computation.
+  const auto band_boundary_indexes =
+      ComputeBandBoundaryIndexes(kSampleRate48kHz, kFrameSize20ms48kHz);
+  std::array<float, kNumBands> computed_band_energies;
+
+  // Check output for every frame.
+  {
+    // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+    // FloatingPointExceptionObserver fpe_observer;
+    for (size_t i = 0; i < num_frames; ++i) {
+      SCOPED_TRACE(i);
+      // Read input.
+      fft_coeffs_reader.first->ReadChunk(fft_coeffs_real);
+      fft_coeffs_reader.first->ReadChunk(fft_coeffs_imag);
+      for (size_t i = 0; i < kFftNumCoeffs20ms48kHz; ++i) {
+        fft_coeffs[i].real(fft_coeffs_real[i]);
+        fft_coeffs[i].imag(fft_coeffs_imag[i]);
+      }
+      band_energies_reader.first->ReadChunk(expected_band_energies);
+      // Compute band energy coefficients and check output.
+      ComputeBandEnergies(fft_coeffs, band_boundary_indexes,
+                          computed_band_energies);
+      ExpectEqualFloatArray(expected_band_energies, computed_band_energies);
+    }
+  }
+}
+
+TEST(RnnVadTest, ComputeLogBandEnergiesCoefficientsBitExactness) {
+  constexpr std::array<float, kNumBands> input = {
+      {86.060539245605f, 275.668334960938f, 43.406528472900f, 6.541896820068f,
+       17.964015960693f, 8.090919494629f,   1.261920094490f,  1.212702631950f,
+       1.619154453278f,  0.508935272694f,   0.346316039562f,  0.237035423517f,
+       0.172424271703f,  0.271657168865f,   0.126088857651f,  0.139967113733f,
+       0.207200810313f,  0.155893072486f,   0.091090843081f,  0.033391401172f,
+       0.013879744336f,  0.011973354965f}};
+  constexpr std::array<float, kNumBands> expected_output = {
+      {1.934854507446f,  2.440402746201f,  1.637655138969f,  0.816367030144f,
+       1.254645109177f,  0.908534288406f,  0.104459829628f,  0.087320849299f,
+       0.211962252855f,  -0.284886807203f, -0.448164641857f, -0.607240796089f,
+       -0.738917350769f, -0.550279200077f, -0.866177439690f, -0.824003994465f,
+       -0.663138568401f, -0.780171751976f, -0.995288193226f, -1.362596273422f,
+       -1.621970295906f, -1.658103585243f}};
+  std::array<float, kNumBands> computed_output;
+  {
+    // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+    // FloatingPointExceptionObserver fpe_observer;
+    ComputeLogBandEnergiesCoefficients(input, computed_output);
+    ExpectNearAbsolute(expected_output, computed_output, 1e-5f);
+  }
+}
+
+TEST(RnnVadTest, ComputeDctBitExactness) {
+  constexpr std::array<float, kNumBands> input = {
+      {0.232155621052f,  0.678957760334f, 0.220818966627f,  -0.077363930643f,
+       -0.559227049351f, 0.432545185089f, 0.353900641203f,  0.398993015289f,
+       0.409774333239f,  0.454977899790f, 0.300520688295f,  -0.010286616161f,
+       0.272525429726f,  0.098067551851f, 0.083649002016f,  0.046226885170f,
+       -0.033228103071f, 0.144773483276f, -0.117661058903f, -0.005628800020f,
+       -0.009547689930f, -0.045382082462f}};
+  constexpr std::array<float, kNumBands> expected_output = {
+      {0.697072803974f,  0.442710995674f,  -0.293156713247f, -0.060711503029f,
+       0.292050391436f,  0.489301353693f,  0.402255415916f,  0.134404733777f,
+       -0.086305990815f, -0.199605688453f, -0.234511867166f, -0.413774639368f,
+       -0.388507157564f, -0.032798115164f, 0.044605545700f,  0.112466648221f,
+       -0.050096966326f, 0.045971218497f,  -0.029815061018f, -0.410366982222f,
+       -0.209233760834f, -0.128037497401f}};
+  auto dct_table = ComputeDctTable();
+  std::array<float, kNumBands> computed_output;
+  {
+    // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+    // FloatingPointExceptionObserver fpe_observer;
+    ComputeDct(input, dct_table, computed_output);
+    ExpectNearAbsolute(expected_output, computed_output, 1e-5f);
+  }
+}
+
+}  // namespace test
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/spectral_features_unittest.cc b/modules/audio_processing/agc2/rnn_vad/spectral_features_unittest.cc
new file mode 100644
index 0000000..557e41e
--- /dev/null
+++ b/modules/audio_processing/agc2/rnn_vad/spectral_features_unittest.cc
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
+#include "rtc_base/checks.h"
+// TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+// #include "test/fpe_observer.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+namespace {
+
+constexpr size_t kTestFeatureVectorSize = kNumBands + 3 * kNumLowerBands + 1;
+
+// Writes non-zero sample values.
+void WriteTestData(rtc::ArrayView<float> samples) {
+  for (size_t i = 0; i < samples.size(); ++i) {
+    samples[i] = i % 100;
+  }
+}
+
+SpectralFeaturesView GetSpectralFeaturesView(
+    std::array<float, kTestFeatureVectorSize>* feature_vector) {
+  return {
+      {feature_vector->data() + kNumLowerBands, kNumBands - kNumLowerBands},
+      {feature_vector->data(), kNumLowerBands},
+      {feature_vector->data() + kNumBands, kNumLowerBands},
+      {feature_vector->data() + kNumBands + kNumLowerBands, kNumLowerBands},
+      {feature_vector->data() + kNumBands + 2 * kNumLowerBands, kNumLowerBands},
+      &(*feature_vector)[kNumBands + 3 * kNumLowerBands]};
+}
+
+constexpr float kInitialFeatureVal = -9999.f;
+
+}  // namespace
+
+TEST(RnnVadTest, SpectralFeaturesWithAndWithoutSilence) {
+  // Initialize.
+  SpectralFeaturesExtractor sfe;
+  std::array<float, kFrameSize20ms24kHz> samples;
+  rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples);
+  bool is_silence;
+  std::array<float, kTestFeatureVectorSize> feature_vector;
+  auto feature_vector_view = GetSpectralFeaturesView(&feature_vector);
+
+  // Write an initial value in the feature vector to detect changes.
+  std::fill(feature_vector.begin(), feature_vector.end(), kInitialFeatureVal);
+
+  // TODO(bugs.webrtc.org/8948): Add when the issue is fixed.
+  // FloatingPointExceptionObserver fpe_observer;
+
+  // With silence.
+  std::fill(samples.begin(), samples.end(), 0.f);
+  is_silence = sfe.CheckSilenceComputeFeatures(samples_view, samples_view,
+                                               feature_vector_view);
+  // Silence is expected, the output won't be overwritten.
+  EXPECT_TRUE(is_silence);
+  EXPECT_TRUE(std::all_of(feature_vector.begin(), feature_vector.end(),
+                          [](float x) { return x == kInitialFeatureVal; }));
+
+  // With no silence.
+  WriteTestData(samples);
+  is_silence = sfe.CheckSilenceComputeFeatures(samples_view, samples_view,
+                                               feature_vector_view);
+  // Silence is not expected, the output will be overwritten.
+  EXPECT_FALSE(is_silence);
+  EXPECT_FALSE(std::all_of(feature_vector.begin(), feature_vector.end(),
+                           [](float x) { return x == kInitialFeatureVal; }));
+}
+
+// When the input signal does not change, the spectral coefficients average does
+// not change and the derivatives are zero. Similarly, the spectral variability
+// score does not change either.
+TEST(RnnVadTest, SpectralFeaturesConstantAverageZeroDerivative) {
+  // Initialize.
+  SpectralFeaturesExtractor sfe;
+  std::array<float, kFrameSize20ms24kHz> samples;
+  rtc::ArrayView<float, kFrameSize20ms24kHz> samples_view(samples);
+  WriteTestData(samples);
+  bool is_silence;
+
+  // Fill the spectral features with test data.
+  std::array<float, kTestFeatureVectorSize> feature_vector;
+  auto feature_vector_view = GetSpectralFeaturesView(&feature_vector);
+  for (size_t i = 0; i < kSpectralCoeffsHistorySize; ++i) {
+    is_silence = sfe.CheckSilenceComputeFeatures(samples_view, samples_view,
+                                                 feature_vector_view);
+  }
+
+  // Feed the test data one last time but using a different output vector.
+  std::array<float, kTestFeatureVectorSize> feature_vector_last;
+  auto feature_vector_last_view = GetSpectralFeaturesView(&feature_vector_last);
+  is_silence = sfe.CheckSilenceComputeFeatures(samples_view, samples_view,
+                                               feature_vector_last_view);
+
+  // Average is unchanged.
+  ExpectEqualFloatArray({feature_vector.data(), kNumLowerBands},
+                        {feature_vector_last.data(), kNumLowerBands});
+  // First and second derivatives are zero.
+  constexpr std::array<float, kNumLowerBands> zeros{};
+  ExpectEqualFloatArray(
+      {feature_vector_last.data() + kNumBands, kNumLowerBands}, zeros);
+  ExpectEqualFloatArray(
+      {feature_vector_last.data() + kNumBands + kNumLowerBands, kNumLowerBands},
+      zeros);
+  // Spectral variability is unchanged.
+  EXPECT_FLOAT_EQ(feature_vector[kNumBands + 3 * kNumLowerBands],
+                  feature_vector_last[kNumBands + 3 * kNumLowerBands]);
+}
+
+}  // namespace test
+}  // namespace rnn_vad
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/test_utils.cc b/modules/audio_processing/agc2/rnn_vad/test_utils.cc
index c6cf21e..db38cab 100644
--- a/modules/audio_processing/agc2/rnn_vad/test_utils.cc
+++ b/modules/audio_processing/agc2/rnn_vad/test_utils.cc
@@ -10,8 +10,8 @@
 
 #include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
 
+#include "absl/memory/memory.h"
 #include "rtc_base/checks.h"
-#include "rtc_base/ptr_util.h"
 #include "test/gtest.h"
 #include "test/testsupport/fileutils.h"
 
@@ -27,6 +27,15 @@
 
 using webrtc::test::ResourcePath;
 
+void ExpectEqualFloatArray(rtc::ArrayView<const float> expected,
+                           rtc::ArrayView<const float> computed) {
+  ASSERT_EQ(expected.size(), computed.size());
+  for (size_t i = 0; i < expected.size(); ++i) {
+    SCOPED_TRACE(i);
+    EXPECT_FLOAT_EQ(expected[i], computed[i]);
+  }
+}
+
 void ExpectNearAbsolute(rtc::ArrayView<const float> expected,
                         rtc::ArrayView<const float> computed,
                         float tolerance) {
@@ -37,22 +46,71 @@
   }
 }
 
+std::unique_ptr<BinaryFileReader<float>> CreatePitchSearchTestDataReader() {
+  constexpr size_t cols = 1396;
+  return absl::make_unique<BinaryFileReader<float>>(
+      ResourcePath("audio_processing/agc2/rnn_vad/pitch_search_int", "dat"),
+      cols);
+}
+
+std::pair<std::unique_ptr<BinaryFileReader<int16_t, float>>, const size_t>
+CreatePcmSamplesReader(const size_t frame_length) {
+  auto ptr = absl::make_unique<BinaryFileReader<int16_t, float>>(
+      test::ResourcePath("audio_processing/agc2/rnn_vad/samples", "pcm"),
+      frame_length);
+  // The last incomplete frame is ignored.
+  return {std::move(ptr), ptr->data_length() / frame_length};
+}
+
 ReaderPairType CreatePitchBuffer24kHzReader() {
-  auto ptr = rtc::MakeUnique<BinaryFileReader<float>>(
-      ResourcePath("audio_processing/agc2/rnn_vad/pitch_buf_24k", "dat"), 864);
-  return {std::move(ptr),
-          rtc::CheckedDivExact(ptr->data_length(), static_cast<size_t>(864))};
+  constexpr size_t cols = 864;
+  auto ptr = absl::make_unique<BinaryFileReader<float>>(
+      ResourcePath("audio_processing/agc2/rnn_vad/pitch_buf_24k", "dat"), cols);
+  return {std::move(ptr), rtc::CheckedDivExact(ptr->data_length(), cols)};
 }
 
 ReaderPairType CreateLpResidualAndPitchPeriodGainReader() {
   constexpr size_t num_lp_residual_coeffs = 864;
-  auto ptr = rtc::MakeUnique<BinaryFileReader<float>>(
+  auto ptr = absl::make_unique<BinaryFileReader<float>>(
       ResourcePath("audio_processing/agc2/rnn_vad/pitch_lp_res", "dat"),
       num_lp_residual_coeffs);
   return {std::move(ptr),
           rtc::CheckedDivExact(ptr->data_length(), 2 + num_lp_residual_coeffs)};
 }
 
+ReaderPairType CreateFftCoeffsReader() {
+  constexpr size_t num_fft_points = 481;
+  constexpr size_t row_size = 2 * num_fft_points;  // Real and imaginary values.
+  auto ptr = absl::make_unique<BinaryFileReader<float>>(
+      test::ResourcePath("audio_processing/agc2/rnn_vad/fft", "dat"),
+      num_fft_points);
+  return {std::move(ptr), rtc::CheckedDivExact(ptr->data_length(), row_size)};
+}
+
+ReaderPairType CreateBandEnergyCoeffsReader() {
+  constexpr size_t num_bands = 22;
+  auto ptr = absl::make_unique<BinaryFileReader<float>>(
+      test::ResourcePath("audio_processing/agc2/rnn_vad/band_energies", "dat"),
+      num_bands);
+  return {std::move(ptr), rtc::CheckedDivExact(ptr->data_length(), num_bands)};
+}
+
+ReaderPairType CreateSilenceFlagsFeatureMatrixReader() {
+  constexpr size_t feature_vector_size = 42;
+  auto ptr = absl::make_unique<BinaryFileReader<float>>(
+      test::ResourcePath("audio_processing/agc2/rnn_vad/sil_features", "dat"),
+      feature_vector_size);
+  // Features and silence flag.
+  return {std::move(ptr),
+          rtc::CheckedDivExact(ptr->data_length(), feature_vector_size + 1)};
+}
+
+ReaderPairType CreateVadProbsReader() {
+  auto ptr = absl::make_unique<BinaryFileReader<float>>(
+      test::ResourcePath("audio_processing/agc2/rnn_vad/vad_prob", "dat"));
+  return {std::move(ptr), ptr->data_length()};
+}
+
 }  // namespace test
 }  // namespace rnn_vad
 }  // namespace webrtc
diff --git a/modules/audio_processing/agc2/rnn_vad/test_utils.h b/modules/audio_processing/agc2/rnn_vad/test_utils.h
index 3f580ab..15be85a 100644
--- a/modules/audio_processing/agc2/rnn_vad/test_utils.h
+++ b/modules/audio_processing/agc2/rnn_vad/test_utils.h
@@ -28,7 +28,12 @@
 
 constexpr float kFloatMin = std::numeric_limits<float>::min();
 
-// Fail for every pair from two equally sized rtc::ArrayView<float> views such
+// Fails for every pair from two equally sized rtc::ArrayView<float> views such
+// that the values in the pair do not match.
+void ExpectEqualFloatArray(rtc::ArrayView<const float> expected,
+                           rtc::ArrayView<const float> computed);
+
+// Fails for every pair from two equally sized rtc::ArrayView<float> views such
 // that their absolute error is above a given threshold.
 void ExpectNearAbsolute(rtc::ArrayView<const float> expected,
                         rtc::ArrayView<const float> computed,
@@ -84,10 +89,15 @@
   std::vector<T> buf_;
 };
 
-// Factories for resource file readers; the functions below return a pair where
-// the first item is a reader unique pointer and the second the number of chunks
-// that can be read from the file.
-
+// Factories for resource file readers.
+// Creates a reader for the pitch search test data.
+std::unique_ptr<BinaryFileReader<float>> CreatePitchSearchTestDataReader();
+// The functions below return a pair where the first item is a reader unique
+// pointer and the second the number of chunks that can be read from the file.
+// Creates a reader for the PCM samples that casts from S16 to float and reads
+// chunks with length |frame_length|.
+std::pair<std::unique_ptr<BinaryFileReader<int16_t, float>>, const size_t>
+CreatePcmSamplesReader(const size_t frame_length);
 // Creates a reader for the pitch buffer content at 24 kHz.
 std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
 CreatePitchBuffer24kHzReader();
@@ -95,6 +105,18 @@
 // and gain values.
 std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
 CreateLpResidualAndPitchPeriodGainReader();
+// Creates a reader for the FFT coefficients.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreateFftCoeffsReader();
+// Instance a reader for the band energy coefficients.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreateBandEnergyCoeffsReader();
+// Creates a reader for the silence flags and the feature matrix.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreateSilenceFlagsFeatureMatrixReader();
+// Creates a reader for the VAD probabilities.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreateVadProbsReader();
 
 }  // namespace test
 }  // namespace rnn_vad
diff --git a/modules/audio_processing/agc2/saturation_protector.cc b/modules/audio_processing/agc2/saturation_protector.cc
index 216e1b6..dc9be47 100644
--- a/modules/audio_processing/agc2/saturation_protector.cc
+++ b/modules/audio_processing/agc2/saturation_protector.cc
@@ -80,6 +80,10 @@
   return last_margin_;
 }
 
+void SaturationProtector::Reset() {
+  peak_enveloper_ = PeakEnveloper();
+}
+
 void SaturationProtector::DebugDumpEstimate() const {
   apm_data_dumper_->DumpRaw(
       "agc2_adaptive_saturation_protector_delayed_peak_dbfs",
diff --git a/modules/audio_processing/agc2/saturation_protector.h b/modules/audio_processing/agc2/saturation_protector.h
index d330c15..3f207da 100644
--- a/modules/audio_processing/agc2/saturation_protector.h
+++ b/modules/audio_processing/agc2/saturation_protector.h
@@ -14,7 +14,7 @@
 #include <array>
 
 #include "modules/audio_processing/agc2/agc2_common.h"
-#include "modules/audio_processing/vad/vad_with_level.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
 
 namespace webrtc {
 
@@ -35,6 +35,9 @@
   // detected.
   float LastMargin() const;
 
+  // Resets the internal memory.
+  void Reset();
+
   void DebugDumpEstimate() const;
 
  private:
diff --git a/modules/audio_processing/agc2/saturation_protector_unittest.cc b/modules/audio_processing/agc2/saturation_protector_unittest.cc
index 88da2a2..6013e13 100644
--- a/modules/audio_processing/agc2/saturation_protector_unittest.cc
+++ b/modules/audio_processing/agc2/saturation_protector_unittest.cc
@@ -30,6 +30,7 @@
     max_difference =
         std::max(max_difference, std::abs(new_margin - last_margin));
     last_margin = new_margin;
+    saturation_protector->DebugDumpEstimate();
   }
   return max_difference;
 }
@@ -127,6 +128,12 @@
           kLaterSpeechLevelDbfs, &saturation_protector),
       max_difference);
 
+  // The saturation protector expects that the RMS changes roughly
+  // 'kFullBufferSizeMs' after peaks change. This is to account for
+  // delay introduces by the level estimator. Therefore, the input
+  // above is 'normal' and 'expected', and shouldn't influence the
+  // margin by much.
+
   const float total_difference =
       std::abs(saturation_protector.LastMargin() - kInitialSaturationMarginDb);
 
diff --git a/modules/audio_processing/agc2/vad_with_level.cc b/modules/audio_processing/agc2/vad_with_level.cc
new file mode 100644
index 0000000..decfacd
--- /dev/null
+++ b/modules/audio_processing/agc2/vad_with_level.cc
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/audio_processing/agc2/vad_with_level.h"
+
+#include <algorithm>
+
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+float ProcessForPeak(AudioFrameView<const float> frame) {
+  float current_max = 0;
+  for (const auto& x : frame.channel(0)) {
+    current_max = std::max(std::fabs(x), current_max);
+  }
+  return current_max;
+}
+
+float ProcessForRms(AudioFrameView<const float> frame) {
+  float rms = 0;
+  for (const auto& x : frame.channel(0)) {
+    rms += x * x;
+  }
+  return sqrt(rms / frame.samples_per_channel());
+}
+}  // namespace
+
+VadWithLevel::VadWithLevel() = default;
+VadWithLevel::~VadWithLevel() = default;
+
+VadWithLevel::LevelAndProbability VadWithLevel::AnalyzeFrame(
+    AudioFrameView<const float> frame) {
+  SetSampleRate(static_cast<int>(frame.samples_per_channel() * 100));
+  std::array<float, rnn_vad::kFrameSize10ms24kHz> work_frame;
+  // Feed the 1st channel to the resampler.
+  resampler_.Resample(frame.channel(0).data(), frame.samples_per_channel(),
+                      work_frame.data(), rnn_vad::kFrameSize10ms24kHz);
+
+  std::array<float, rnn_vad::kFeatureVectorSize> feature_vector;
+
+  const bool is_silence = features_extractor_.CheckSilenceComputeFeatures(
+      work_frame, feature_vector);
+  const float vad_probability =
+      rnn_vad_.ComputeVadProbability(feature_vector, is_silence);
+  return LevelAndProbability(vad_probability,
+                             FloatS16ToDbfs(ProcessForRms(frame)),
+                             FloatS16ToDbfs(ProcessForPeak(frame)));
+}
+
+void VadWithLevel::SetSampleRate(int sample_rate_hz) {
+  // The source number of channels in 1, because we always use the 1st
+  // channel.
+  resampler_.InitializeIfNeeded(sample_rate_hz, rnn_vad::kSampleRate24kHz,
+                                1 /* num_channels */);
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/vad_with_level.h b/modules/audio_processing/agc2/vad_with_level.h
new file mode 100644
index 0000000..67a00ce
--- /dev/null
+++ b/modules/audio_processing/agc2/vad_with_level.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_
+
+#include "api/array_view.h"
+#include "common_audio/resampler/include/push_resampler.h"
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+class VadWithLevel {
+ public:
+  struct LevelAndProbability {
+    constexpr LevelAndProbability(float prob, float rms, float peak)
+        : speech_probability(prob),
+          speech_rms_dbfs(rms),
+          speech_peak_dbfs(peak) {}
+    LevelAndProbability() = default;
+    float speech_probability = 0;
+    float speech_rms_dbfs = 0;  // Root mean square in decibels to full-scale.
+    float speech_peak_dbfs = 0;
+  };
+
+  VadWithLevel();
+  ~VadWithLevel();
+
+  LevelAndProbability AnalyzeFrame(AudioFrameView<const float> frame);
+
+ private:
+  void SetSampleRate(int sample_rate_hz);
+
+  rnn_vad::RnnBasedVad rnn_vad_;
+  rnn_vad::FeaturesExtractor features_extractor_;
+  PushResampler<float> resampler_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_
diff --git a/modules/audio_processing/audio_buffer.cc b/modules/audio_processing/audio_buffer.cc
index 16f1174..f163f5a 100644
--- a/modules/audio_processing/audio_buffer.cc
+++ b/modules/audio_processing/audio_buffer.cc
@@ -49,20 +49,20 @@
                          size_t process_num_frames,
                          size_t num_process_channels,
                          size_t output_num_frames)
-  : input_num_frames_(input_num_frames),
-    num_input_channels_(num_input_channels),
-    proc_num_frames_(process_num_frames),
-    num_proc_channels_(num_process_channels),
-    output_num_frames_(output_num_frames),
-    num_channels_(num_process_channels),
-    num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)),
-    num_split_frames_(rtc::CheckedDivExact(proc_num_frames_, num_bands_)),
-    mixed_low_pass_valid_(false),
-    reference_copied_(false),
-    activity_(AudioFrame::kVadUnknown),
-    keyboard_data_(NULL),
-    data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)),
-    output_buffer_(new IFChannelBuffer(output_num_frames_, num_channels_)) {
+    : input_num_frames_(input_num_frames),
+      num_input_channels_(num_input_channels),
+      proc_num_frames_(process_num_frames),
+      num_proc_channels_(num_process_channels),
+      output_num_frames_(output_num_frames),
+      num_channels_(num_process_channels),
+      num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)),
+      num_split_frames_(rtc::CheckedDivExact(proc_num_frames_, num_bands_)),
+      mixed_low_pass_valid_(false),
+      reference_copied_(false),
+      activity_(AudioFrame::kVadUnknown),
+      keyboard_data_(NULL),
+      data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)),
+      output_buffer_(new IFChannelBuffer(output_num_frames_, num_channels_)) {
   RTC_DCHECK_GT(input_num_frames_, 0);
   RTC_DCHECK_GT(proc_num_frames_, 0);
   RTC_DCHECK_GT(output_num_frames_, 0);
@@ -73,8 +73,8 @@
   if (input_num_frames_ != proc_num_frames_ ||
       output_num_frames_ != proc_num_frames_) {
     // Create an intermediate buffer for resampling.
-    process_buffer_.reset(new ChannelBuffer<float>(proc_num_frames_,
-                                                   num_proc_channels_));
+    process_buffer_.reset(
+        new ChannelBuffer<float>(proc_num_frames_, num_proc_channels_));
 
     if (input_num_frames_ != proc_num_frames_) {
       for (size_t i = 0; i < num_proc_channels_; ++i) {
@@ -92,12 +92,10 @@
   }
 
   if (num_bands_ > 1) {
-    split_data_.reset(new IFChannelBuffer(proc_num_frames_,
-                                          num_proc_channels_,
-                                          num_bands_));
-    splitting_filter_.reset(new SplittingFilter(num_proc_channels_,
-                                                num_bands_,
-                                                proc_num_frames_));
+    split_data_.reset(
+        new IFChannelBuffer(proc_num_frames_, num_proc_channels_, num_bands_));
+    splitting_filter_.reset(
+        new SplittingFilter(num_proc_channels_, num_bands_, proc_num_frames_));
   }
 }
 
@@ -132,8 +130,7 @@
   // Resample.
   if (input_num_frames_ != proc_num_frames_) {
     for (size_t i = 0; i < num_proc_channels_; ++i) {
-      input_resamplers_[i]->Resample(data_ptr[i],
-                                     input_num_frames_,
+      input_resamplers_[i]->Resample(data_ptr[i], input_num_frames_,
                                      process_buffer_->channels()[i],
                                      proc_num_frames_);
     }
@@ -142,8 +139,7 @@
 
   // Convert to the S16 range.
   for (size_t i = 0; i < num_proc_channels_; ++i) {
-    FloatToFloatS16(data_ptr[i],
-                    proc_num_frames_,
+    FloatToFloatS16(data_ptr[i], proc_num_frames_,
                     data_->fbuf()->channels()[i]);
   }
 }
@@ -161,17 +157,14 @@
     data_ptr = process_buffer_->channels();
   }
   for (size_t i = 0; i < num_channels_; ++i) {
-    FloatS16ToFloat(data_->fbuf()->channels()[i],
-                    proc_num_frames_,
+    FloatS16ToFloat(data_->fbuf()->channels()[i], proc_num_frames_,
                     data_ptr[i]);
   }
 
   // Resample.
   if (output_num_frames_ != proc_num_frames_) {
     for (size_t i = 0; i < num_channels_; ++i) {
-      output_resamplers_[i]->Resample(data_ptr[i],
-                                      proc_num_frames_,
-                                      data[i],
+      output_resamplers_[i]->Resample(data_ptr[i], proc_num_frames_, data[i],
                                       output_num_frames_);
     }
   }
@@ -204,16 +197,14 @@
 }
 
 const int16_t* const* AudioBuffer::split_bands_const(size_t channel) const {
-  return split_data_.get() ?
-         split_data_->ibuf_const()->bands(channel) :
-         data_->ibuf_const()->bands(channel);
+  return split_data_.get() ? split_data_->ibuf_const()->bands(channel)
+                           : data_->ibuf_const()->bands(channel);
 }
 
 int16_t* const* AudioBuffer::split_bands(size_t channel) {
   mixed_low_pass_valid_ = false;
-  return split_data_.get() ?
-         split_data_->ibuf()->bands(channel) :
-         data_->ibuf()->bands(channel);
+  return split_data_.get() ? split_data_->ibuf()->bands(channel)
+                           : data_->ibuf()->bands(channel);
 }
 
 const int16_t* const* AudioBuffer::split_channels_const(Band band) const {
@@ -261,16 +252,14 @@
 }
 
 const float* const* AudioBuffer::split_bands_const_f(size_t channel) const {
-  return split_data_.get() ?
-         split_data_->fbuf_const()->bands(channel) :
-         data_->fbuf_const()->bands(channel);
+  return split_data_.get() ? split_data_->fbuf_const()->bands(channel)
+                           : data_->fbuf_const()->bands(channel);
 }
 
 float* const* AudioBuffer::split_bands_f(size_t channel) {
   mixed_low_pass_valid_ = false;
-  return split_data_.get() ?
-         split_data_->fbuf()->bands(channel) :
-         data_->fbuf()->bands(channel);
+  return split_data_.get() ? split_data_->fbuf()->bands(channel)
+                           : data_->fbuf()->bands(channel);
 }
 
 const float* const* AudioBuffer::split_channels_const_f(Band band) const {
@@ -401,19 +390,16 @@
                              num_input_channels_, deinterleaved[0]);
   } else {
     RTC_DCHECK_EQ(num_proc_channels_, num_input_channels_);
-    Deinterleave(frame->data(),
-                 input_num_frames_,
-                 num_proc_channels_,
+    Deinterleave(frame->data(), input_num_frames_, num_proc_channels_,
                  deinterleaved);
   }
 
   // Resample.
   if (input_num_frames_ != proc_num_frames_) {
     for (size_t i = 0; i < num_proc_channels_; ++i) {
-      input_resamplers_[i]->Resample(input_buffer_->fbuf_const()->channels()[i],
-                                     input_num_frames_,
-                                     data_->fbuf()->channels()[i],
-                                     proc_num_frames_);
+      input_resamplers_[i]->Resample(
+          input_buffer_->fbuf_const()->channels()[i], input_num_frames_,
+          data_->fbuf()->channels()[i], proc_num_frames_);
     }
   }
 }
@@ -453,8 +439,7 @@
   if (!low_pass_reference_channels_.get() ||
       low_pass_reference_channels_->num_channels() != num_channels_) {
     low_pass_reference_channels_.reset(
-        new ChannelBuffer<int16_t>(num_split_frames_,
-                                   num_proc_channels_));
+        new ChannelBuffer<int16_t>(num_split_frames_, num_proc_channels_));
   }
   for (size_t i = 0; i < num_proc_channels_; i++) {
     memcpy(low_pass_reference_channels_->channels()[i],
diff --git a/modules/audio_processing/audio_buffer.h b/modules/audio_processing/audio_buffer.h
index 508f96f..3d7c4a8 100644
--- a/modules/audio_processing/audio_buffer.h
+++ b/modules/audio_processing/audio_buffer.h
@@ -25,11 +25,7 @@
 class PushSincResampler;
 class IFChannelBuffer;
 
-enum Band {
-  kBand0To8kHz = 0,
-  kBand8To16kHz = 1,
-  kBand16To24kHz = 2
-};
+enum Band { kBand0To8kHz = 0, kBand8To16kHz = 1, kBand16To24kHz = 2 };
 
 class AudioBuffer {
  public:
@@ -152,11 +148,11 @@
   std::unique_ptr<IFChannelBuffer> data_;
   std::unique_ptr<IFChannelBuffer> split_data_;
   std::unique_ptr<SplittingFilter> splitting_filter_;
-  std::unique_ptr<ChannelBuffer<int16_t> > mixed_low_pass_channels_;
-  std::unique_ptr<ChannelBuffer<int16_t> > low_pass_reference_channels_;
+  std::unique_ptr<ChannelBuffer<int16_t>> mixed_low_pass_channels_;
+  std::unique_ptr<ChannelBuffer<int16_t>> low_pass_reference_channels_;
   std::unique_ptr<IFChannelBuffer> input_buffer_;
   std::unique_ptr<IFChannelBuffer> output_buffer_;
-  std::unique_ptr<ChannelBuffer<float> > process_buffer_;
+  std::unique_ptr<ChannelBuffer<float>> process_buffer_;
   std::vector<std::unique_ptr<PushSincResampler>> input_resamplers_;
   std::vector<std::unique_ptr<PushSincResampler>> output_resamplers_;
 };
diff --git a/modules/audio_processing/audio_frame_view_unittest.cc b/modules/audio_processing/audio_frame_view_unittest.cc
index cf30496..7a9d126 100644
--- a/modules/audio_processing/audio_frame_view_unittest.cc
+++ b/modules/audio_processing/audio_frame_view_unittest.cc
@@ -13,6 +13,7 @@
 #include "modules/audio_processing/audio_buffer.h"
 #include "test/gtest.h"
 
+namespace webrtc {
 TEST(AudioFrameTest, ConstructFromAudioBuffer) {
   constexpr int kSampleRateHz = 48000;
   constexpr int kNumChannels = 2;
@@ -47,3 +48,4 @@
   non_const_int16_view.channel(0)[0] = kIntConstant;
   EXPECT_EQ(buffer.channels()[0][0], kIntConstant);
 }
+}  // namespace webrtc
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 8d1ccee..7e5955a 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -22,7 +22,6 @@
 #include "modules/audio_processing/agc/agc_manager_direct.h"
 #include "modules/audio_processing/agc2/gain_applier.h"
 #include "modules/audio_processing/audio_buffer.h"
-#include "modules/audio_processing/beamformer/nonlinear_beamformer.h"
 #include "modules/audio_processing/common.h"
 #include "modules/audio_processing/echo_cancellation_impl.h"
 #include "modules/audio_processing/echo_control_mobile_impl.h"
@@ -66,6 +65,7 @@
 namespace webrtc {
 
 constexpr int AudioProcessing::kNativeSampleRatesHz[];
+constexpr int kRuntimeSettingQueueSize = 100;
 
 namespace {
 
@@ -147,24 +147,6 @@
   AudioProcessingImpl* apm_;
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(HighPassFilterImpl);
 };
-
-webrtc::InternalAPMStreamsConfig ToStreamsConfig(
-    const ProcessingConfig& api_format) {
-  webrtc::InternalAPMStreamsConfig result;
-  result.input_sample_rate = api_format.input_stream().sample_rate_hz();
-  result.input_num_channels = api_format.input_stream().num_channels();
-  result.output_num_channels = api_format.output_stream().num_channels();
-  result.render_input_num_channels =
-      api_format.reverse_input_stream().num_channels();
-  result.render_input_sample_rate =
-      api_format.reverse_input_stream().sample_rate_hz();
-  result.output_sample_rate = api_format.output_stream().sample_rate_hz();
-  result.render_output_sample_rate =
-      api_format.reverse_output_stream().sample_rate_hz();
-  result.render_output_num_channels =
-      api_format.reverse_output_stream().num_channels();
-  return result;
-}
 }  // namespace
 
 // Throughout webrtc, it's assumed that success is represented by zero.
@@ -183,7 +165,6 @@
     bool residual_echo_detector_enabled,
     bool noise_suppressor_enabled,
     bool intelligibility_enhancer_enabled,
-    bool beamformer_enabled,
     bool adaptive_gain_controller_enabled,
     bool gain_controller2_enabled,
     bool pre_amplifier_enabled,
@@ -201,7 +182,6 @@
   changed |= (noise_suppressor_enabled != noise_suppressor_enabled_);
   changed |=
       (intelligibility_enhancer_enabled != intelligibility_enhancer_enabled_);
-  changed |= (beamformer_enabled != beamformer_enabled_);
   changed |=
       (adaptive_gain_controller_enabled != adaptive_gain_controller_enabled_);
   changed |=
@@ -219,7 +199,6 @@
     residual_echo_detector_enabled_ = residual_echo_detector_enabled;
     noise_suppressor_enabled_ = noise_suppressor_enabled;
     intelligibility_enhancer_enabled_ = intelligibility_enhancer_enabled;
-    beamformer_enabled_ = beamformer_enabled;
     adaptive_gain_controller_enabled_ = adaptive_gain_controller_enabled;
     gain_controller2_enabled_ = gain_controller2_enabled;
     pre_amplifier_enabled_ = pre_amplifier_enabled;
@@ -248,8 +227,7 @@
     const {
   return low_cut_filter_enabled_ || echo_canceller_enabled_ ||
          mobile_echo_controller_enabled_ || noise_suppressor_enabled_ ||
-         beamformer_enabled_ || adaptive_gain_controller_enabled_ ||
-         echo_controller_enabled_;
+         adaptive_gain_controller_enabled_ || echo_controller_enabled_;
 }
 
 bool AudioProcessingImpl::ApmSubmoduleStates::CaptureFullBandProcessingActive()
@@ -299,20 +277,17 @@
 };
 
 struct AudioProcessingImpl::ApmPrivateSubmodules {
-  ApmPrivateSubmodules(NonlinearBeamformer* beamformer,
-                       std::unique_ptr<CustomProcessing> capture_post_processor,
+  ApmPrivateSubmodules(std::unique_ptr<CustomProcessing> capture_post_processor,
                        std::unique_ptr<CustomProcessing> render_pre_processor,
-                       std::unique_ptr<EchoDetector> echo_detector)
-      : beamformer(beamformer),
-        echo_detector(std::move(echo_detector)),
+                       rtc::scoped_refptr<EchoDetector> echo_detector)
+      : echo_detector(std::move(echo_detector)),
         capture_post_processor(std::move(capture_post_processor)),
         render_pre_processor(std::move(render_pre_processor)) {}
   // Accessed internally from capture or during initialization
-  std::unique_ptr<NonlinearBeamformer> beamformer;
   std::unique_ptr<AgcManagerDirect> agc_manager;
   std::unique_ptr<GainController2> gain_controller2;
   std::unique_ptr<LowCutFilter> low_cut_filter;
-  std::unique_ptr<EchoDetector> echo_detector;
+  rtc::scoped_refptr<EchoDetector> echo_detector;
   std::unique_ptr<EchoControl> echo_controller;
   std::unique_ptr<CustomProcessing> capture_post_processor;
   std::unique_ptr<CustomProcessing> render_pre_processor;
@@ -340,14 +315,8 @@
   return *this;
 }
 
-AudioProcessingBuilder& AudioProcessingBuilder::SetNonlinearBeamformer(
-    std::unique_ptr<NonlinearBeamformer> nonlinear_beamformer) {
-  nonlinear_beamformer_ = std::move(nonlinear_beamformer);
-  return *this;
-}
-
 AudioProcessingBuilder& AudioProcessingBuilder::SetEchoDetector(
-    std::unique_ptr<EchoDetector> echo_detector) {
+    rtc::scoped_refptr<EchoDetector> echo_detector) {
   echo_detector_ = std::move(echo_detector);
   return *this;
 }
@@ -361,7 +330,7 @@
   AudioProcessingImpl* apm = new rtc::RefCountedObject<AudioProcessingImpl>(
       config, std::move(capture_post_processing_),
       std::move(render_pre_processing_), std::move(echo_control_factory_),
-      std::move(echo_detector_), nonlinear_beamformer_.release());
+      std::move(echo_detector_));
   if (apm->Initialize() != AudioProcessing::kNoError) {
     delete apm;
     apm = nullptr;
@@ -370,8 +339,7 @@
 }
 
 AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config)
-    : AudioProcessingImpl(config, nullptr, nullptr, nullptr, nullptr, nullptr) {
-}
+    : AudioProcessingImpl(config, nullptr, nullptr, nullptr, nullptr) {}
 
 int AudioProcessingImpl::instance_count_ = 0;
 
@@ -380,37 +348,38 @@
     std::unique_ptr<CustomProcessing> capture_post_processor,
     std::unique_ptr<CustomProcessing> render_pre_processor,
     std::unique_ptr<EchoControlFactory> echo_control_factory,
-    std::unique_ptr<EchoDetector> echo_detector,
-    NonlinearBeamformer* beamformer)
+    rtc::scoped_refptr<EchoDetector> echo_detector)
     : data_dumper_(
           new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
-      runtime_settings_(100),
-      runtime_settings_enqueuer_(&runtime_settings_),
+      capture_runtime_settings_(kRuntimeSettingQueueSize),
+      render_runtime_settings_(kRuntimeSettingQueueSize),
+      capture_runtime_settings_enqueuer_(&capture_runtime_settings_),
+      render_runtime_settings_enqueuer_(&render_runtime_settings_),
       high_pass_filter_impl_(new HighPassFilterImpl(this)),
       echo_control_factory_(std::move(echo_control_factory)),
       submodule_states_(!!capture_post_processor, !!render_pre_processor),
       public_submodules_(new ApmPublicSubmodules()),
       private_submodules_(
-          new ApmPrivateSubmodules(beamformer,
-                                   std::move(capture_post_processor),
+          new ApmPrivateSubmodules(std::move(capture_post_processor),
                                    std::move(render_pre_processor),
                                    std::move(echo_detector))),
       constants_(config.Get<ExperimentalAgc>().startup_min_volume,
                  config.Get<ExperimentalAgc>().clipped_level_min,
 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
+                 false,
+                 false,
                  false),
 #else
-                 config.Get<ExperimentalAgc>().enabled),
+                 config.Get<ExperimentalAgc>().enabled,
+                 config.Get<ExperimentalAgc>().enabled_agc2_level_estimator,
+                 config.Get<ExperimentalAgc>().enabled_agc2_digital_adaptive),
 #endif
 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
-      capture_(false,
+      capture_(false),
 #else
-      capture_(config.Get<ExperimentalNs>().enabled,
+      capture_(config.Get<ExperimentalNs>().enabled),
 #endif
-               config.Get<Beamforming>().array_geometry,
-               config.Get<Beamforming>().target_direction),
-      capture_nonlocked_(config.Get<Beamforming>().enabled,
-                         config.Get<Intelligibility>().enabled) {
+      capture_nonlocked_(config.Get<Intelligibility>().enabled) {
   {
     rtc::CritScope cs_render(&crit_render_);
     rtc::CritScope cs_capture(&crit_capture_);
@@ -424,7 +393,7 @@
     public_submodules_->echo_control_mobile.reset(
         new EchoControlMobileImpl(&crit_render_, &crit_capture_));
     public_submodules_->gain_control.reset(
-        new GainControlImpl(&crit_capture_, &crit_capture_));
+        new GainControlImpl(&crit_render_, &crit_capture_));
     public_submodules_->level_estimator.reset(
         new LevelEstimatorImpl(&crit_capture_));
     public_submodules_->noise_suppression.reset(
@@ -437,7 +406,8 @@
 
     // If no echo detector is injected, use the ResidualEchoDetector.
     if (!private_submodules_->echo_detector) {
-      private_submodules_->echo_detector.reset(new ResidualEchoDetector());
+      private_submodules_->echo_detector =
+          new rtc::RefCountedObject<ResidualEchoDetector>();
     }
 
     // TODO(alessiob): Move the injected gain controller once injection is
@@ -523,11 +493,6 @@
 int AudioProcessingImpl::InitializeLocked() {
   UpdateActiveSubmoduleStates();
 
-  const int capture_audiobuffer_num_channels =
-      capture_nonlocked_.beamformer_enabled
-          ? formats_.api_format.input_stream().num_channels()
-          : formats_.api_format.output_stream().num_channels();
-
   const int render_audiobuffer_num_output_frames =
       formats_.api_format.reverse_output_stream().num_frames() == 0
           ? formats_.render_processing_format.num_frames()
@@ -558,7 +523,7 @@
       new AudioBuffer(formats_.api_format.input_stream().num_frames(),
                       formats_.api_format.input_stream().num_channels(),
                       capture_nonlocked_.capture_processing_format.num_frames(),
-                      capture_audiobuffer_num_channels,
+                      formats_.api_format.output_stream().num_channels(),
                       formats_.api_format.output_stream().num_frames()));
 
   public_submodules_->echo_cancellation->Initialize(
@@ -581,7 +546,9 @@
       private_submodules_->agc_manager.reset(new AgcManagerDirect(
           public_submodules_->gain_control.get(),
           public_submodules_->gain_control_for_experimental_agc.get(),
-          constants_.agc_startup_min_volume, constants_.agc_clipped_level_min));
+          constants_.agc_startup_min_volume, constants_.agc_clipped_level_min,
+          constants_.use_experimental_agc_agc2_level_estimation,
+          constants_.use_experimental_agc_agc2_digital_adaptive));
     }
     private_submodules_->agc_manager->Initialize();
     private_submodules_->agc_manager->SetCaptureMuted(
@@ -589,7 +556,6 @@
     public_submodules_->gain_control_for_experimental_agc->Initialize();
   }
   InitializeTransient();
-  InitializeBeamformer();
 #if WEBRTC_INTELLIGIBILITY_ENHANCER
   InitializeIntelligibility();
 #endif
@@ -605,7 +571,7 @@
   InitializePreProcessor();
 
   if (aec_dump_) {
-    aec_dump_->WriteInitMessage(ToStreamsConfig(formats_.api_format));
+    aec_dump_->WriteInitMessage(formats_.api_format);
   }
   return kNoError;
 }
@@ -629,11 +595,6 @@
     return kBadNumberChannelsError;
   }
 
-  if (capture_nonlocked_.beamformer_enabled &&
-      num_in_channels != capture_.array_geometry.size()) {
-    return kBadNumberChannelsError;
-  }
-
   formats_.api_format = config;
 
   int capture_processing_rate = FindNativeProcessRateToUse(
@@ -749,18 +710,6 @@
     InitializeIntelligibility();
   }
 #endif
-
-#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
-  if (capture_nonlocked_.beamformer_enabled !=
-          config.Get<Beamforming>().enabled) {
-    capture_nonlocked_.beamformer_enabled = config.Get<Beamforming>().enabled;
-    if (config.Get<Beamforming>().array_geometry.size() > 1) {
-      capture_.array_geometry = config.Get<Beamforming>().array_geometry;
-    }
-    capture_.target_direction = config.Get<Beamforming>().target_direction;
-    InitializeBeamformer();
-  }
-#endif  // WEBRTC_ANDROID_PLATFORM_BUILD
 }
 
 int AudioProcessingImpl::proc_sample_rate_hz() const {
@@ -785,10 +734,7 @@
 
 size_t AudioProcessingImpl::num_proc_channels() const {
   // Used as callback from submodules, hence locking is not allowed.
-  return (capture_nonlocked_.beamformer_enabled ||
-          capture_nonlocked_.echo_controller_enabled)
-             ? 1
-             : num_output_channels();
+  return capture_nonlocked_.echo_controller_enabled ? 1 : num_output_channels();
 }
 
 size_t AudioProcessingImpl::num_output_channels() const {
@@ -806,8 +752,20 @@
 }
 
 void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) {
-  RTC_DCHECK(setting.type() != RuntimeSetting::Type::kNotSpecified);
-  runtime_settings_enqueuer_.Enqueue(setting);
+  switch (setting.type()) {
+    case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+      render_runtime_settings_enqueuer_.Enqueue(setting);
+      return;
+    case RuntimeSetting::Type::kNotSpecified:
+      RTC_NOTREACHED();
+      return;
+    case RuntimeSetting::Type::kCapturePreGain:
+      capture_runtime_settings_enqueuer_.Enqueue(setting);
+      return;
+  }
+  // The language allows the enum to have a non-enumerator
+  // value. Check that this doesn't happen.
+  RTC_NOTREACHED();
 }
 
 AudioProcessingImpl::RuntimeSettingEnqueuer::RuntimeSettingEnqueuer(
@@ -913,9 +871,9 @@
   return kNoError;
 }
 
-void AudioProcessingImpl::HandleRuntimeSettings() {
+void AudioProcessingImpl::HandleCaptureRuntimeSettings() {
   RuntimeSetting setting;
-  while (runtime_settings_.Remove(&setting)) {
+  while (capture_runtime_settings_.Remove(&setting)) {
     switch (setting.type()) {
       case RuntimeSetting::Type::kCapturePreGain:
         if (config_.pre_amplifier.enabled) {
@@ -925,6 +883,28 @@
         }
         // TODO(bugs.chromium.org/9138): Log setting handling by Aec Dump.
         break;
+      case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+        RTC_NOTREACHED();
+        break;
+      case RuntimeSetting::Type::kNotSpecified:
+        RTC_NOTREACHED();
+        break;
+    }
+  }
+}
+
+void AudioProcessingImpl::HandleRenderRuntimeSettings() {
+  RuntimeSetting setting;
+  while (render_runtime_settings_.Remove(&setting)) {
+    switch (setting.type()) {
+      case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+        if (private_submodules_->render_pre_processor) {
+          private_submodules_->render_pre_processor->SetRuntimeSetting(setting);
+        }
+        break;
+      case RuntimeSetting::Type::kCapturePreGain:
+        RTC_NOTREACHED();
+        break;
       case RuntimeSetting::Type::kNotSpecified:
         RTC_NOTREACHED();
         break;
@@ -1186,7 +1166,7 @@
 }
 
 int AudioProcessingImpl::ProcessCaptureStreamLocked() {
-  HandleRuntimeSettings();
+  HandleCaptureRuntimeSettings();
 
   // Ensure that not both the AEC and AECM are active at the same time.
   // TODO(peah): Simplify once the public API Enable functions for these
@@ -1218,9 +1198,13 @@
   }
 
   if (private_submodules_->echo_controller) {
-    // TODO(peah): Reactivate analogue AGC gain detection once the analogue AGC
-    // issues have been addressed.
-    capture_.echo_path_gain_change = false;
+    // Detect and flag any change in the analog gain.
+    int analog_mic_level = gain_control()->stream_analog_level();
+    capture_.echo_path_gain_change =
+        capture_.prev_analog_mic_level != analog_mic_level &&
+        capture_.prev_analog_mic_level != -1;
+    capture_.prev_analog_mic_level = analog_mic_level;
+
     private_submodules_->echo_controller->AnalyzeCapture(capture_buffer);
   }
 
@@ -1245,13 +1229,6 @@
     capture_buffer->set_num_channels(1);
   }
 
-  if (capture_nonlocked_.beamformer_enabled) {
-    private_submodules_->beamformer->AnalyzeChunk(
-        *capture_buffer->split_data_f());
-    // Discards all channels by the leftmost one.
-    capture_buffer->set_num_channels(1);
-  }
-
   // TODO(peah): Move the AEC3 low-cut filter to this place.
   if (private_submodules_->low_cut_filter &&
       !private_submodules_->echo_controller) {
@@ -1264,7 +1241,7 @@
   // Ensure that the stream delay was set before the call to the
   // AEC ProcessCaptureAudio function.
   if (public_submodules_->echo_cancellation->is_enabled() &&
-      !was_stream_delay_set()) {
+      !private_submodules_->echo_controller && !was_stream_delay_set()) {
     return AudioProcessing::kStreamParameterNotSetError;
   }
 
@@ -1314,16 +1291,10 @@
         capture_buffer, stream_delay_ms()));
   }
 
-  if (capture_nonlocked_.beamformer_enabled) {
-    private_submodules_->beamformer->PostFilter(capture_buffer->split_data_f());
-  }
-
   public_submodules_->voice_detection->ProcessCaptureAudio(capture_buffer);
 
   if (constants_.use_experimental_agc &&
-      public_submodules_->gain_control->is_enabled() &&
-      (!capture_nonlocked_.beamformer_enabled ||
-       private_submodules_->beamformer->is_target_present())) {
+      public_submodules_->gain_control->is_enabled()) {
     private_submodules_->agc_manager->Process(
         capture_buffer->split_bands_const(0)[kBand0To8kHz],
         capture_buffer->num_frames_per_band(), capture_nonlocked_.split_rate);
@@ -1509,6 +1480,8 @@
 
   QueueNonbandedRenderAudio(render_buffer);
 
+  HandleRenderRuntimeSettings();
+
   if (private_submodules_->render_pre_processor) {
     private_submodules_->render_pre_processor->Process(render_buffer);
   }
@@ -1599,7 +1572,7 @@
   // 'aec_dump' parameter, which is after locks are released.
   aec_dump_.swap(aec_dump);
   WriteAecDumpConfigMessage(true);
-  aec_dump_->WriteInitMessage(ToStreamsConfig(formats_.api_format));
+  aec_dump_->WriteInitMessage(formats_.api_format);
 }
 
 void AudioProcessingImpl::DetachAecDump() {
@@ -1701,15 +1674,15 @@
                Error::kNoError) {
       if (metrics.divergent_filter_fraction != -1.0f) {
         stats.divergent_filter_fraction =
-            rtc::Optional<double>(metrics.divergent_filter_fraction);
+            absl::optional<double>(metrics.divergent_filter_fraction);
       }
       if (metrics.echo_return_loss.instant != -100) {
         stats.echo_return_loss =
-            rtc::Optional<double>(metrics.echo_return_loss.instant);
+            absl::optional<double>(metrics.echo_return_loss.instant);
       }
       if (metrics.echo_return_loss_enhancement.instant != -100) {
-        stats.echo_return_loss_enhancement =
-            rtc::Optional<double>(metrics.echo_return_loss_enhancement.instant);
+        stats.echo_return_loss_enhancement = absl::optional<double>(
+            metrics.echo_return_loss_enhancement.instant);
       }
     }
     if (config_.residual_echo_detector.enabled) {
@@ -1726,10 +1699,10 @@
             &delay_median, &delay_std, &fraction_poor_delays) ==
         Error::kNoError) {
       if (delay_median >= 0) {
-        stats.delay_median_ms = rtc::Optional<int32_t>(delay_median);
+        stats.delay_median_ms = absl::optional<int32_t>(delay_median);
       }
       if (delay_std >= 0) {
-        stats.delay_standard_deviation_ms = rtc::Optional<int32_t>(delay_std);
+        stats.delay_standard_deviation_ms = absl::optional<int32_t>(delay_std);
       }
     }
   }
@@ -1789,7 +1762,6 @@
       config_.residual_echo_detector.enabled,
       public_submodules_->noise_suppression->is_enabled(),
       capture_nonlocked_.intelligibility_enabled,
-      capture_nonlocked_.beamformer_enabled,
       public_submodules_->gain_control->is_enabled(),
       config_.gain_controller2.enabled, config_.pre_amplifier.enabled,
       capture_nonlocked_.echo_controller_enabled,
@@ -1810,17 +1782,6 @@
   }
 }
 
-void AudioProcessingImpl::InitializeBeamformer() {
-  if (capture_nonlocked_.beamformer_enabled) {
-    if (!private_submodules_->beamformer) {
-      private_submodules_->beamformer.reset(new NonlinearBeamformer(
-          capture_.array_geometry, 1u, capture_.target_direction));
-    }
-    private_submodules_->beamformer->Initialize(kChunkSizeMs,
-                                                capture_nonlocked_.split_rate);
-  }
-}
-
 void AudioProcessingImpl::InitializeIntelligibility() {
 #if WEBRTC_INTELLIGIBILITY_ENHANCER
   if (capture_nonlocked_.intelligibility_enabled) {
@@ -2080,9 +2041,7 @@
 }
 
 AudioProcessingImpl::ApmCaptureState::ApmCaptureState(
-    bool transient_suppressor_enabled,
-    const std::vector<Point>& array_geometry,
-    SphericalPointf target_direction)
+    bool transient_suppressor_enabled)
     : aec_system_delay_jumps(-1),
       delay_offset_ms(0),
       was_stream_delay_set(false),
@@ -2092,11 +2051,10 @@
       output_will_be_muted(false),
       key_pressed(false),
       transient_suppressor_enabled(transient_suppressor_enabled),
-      array_geometry(array_geometry),
-      target_direction(target_direction),
       capture_processing_format(kSampleRate16kHz),
       split_rate(kSampleRate16kHz),
-      echo_path_gain_change(false) {}
+      echo_path_gain_change(false),
+      prev_analog_mic_level(-1) {}
 
 AudioProcessingImpl::ApmCaptureState::~ApmCaptureState() = default;
 
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index a49924d..44d0d08 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -31,21 +31,18 @@
 
 class ApmDataDumper;
 class AudioConverter;
-class NonlinearBeamformer;
 
 class AudioProcessingImpl : public AudioProcessing {
  public:
   // Methods forcing APM to run in a single-threaded manner.
   // Acquires both the render and capture locks.
   explicit AudioProcessingImpl(const webrtc::Config& config);
-  // AudioProcessingImpl takes ownership of capture post processor and
-  // beamformer.
+  // AudioProcessingImpl takes ownership of capture post processor.
   AudioProcessingImpl(const webrtc::Config& config,
                       std::unique_ptr<CustomProcessing> capture_post_processor,
                       std::unique_ptr<CustomProcessing> render_pre_processor,
                       std::unique_ptr<EchoControlFactory> echo_control_factory,
-                      std::unique_ptr<EchoDetector> echo_detector,
-                      NonlinearBeamformer* beamformer);
+                      rtc::scoped_refptr<EchoDetector> echo_detector);
   ~AudioProcessingImpl() override;
   int Initialize() override;
   int Initialize(int capture_input_sample_rate_hz,
@@ -143,13 +140,6 @@
   FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, DefaultBehavior);
   FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, ValidConfigBehavior);
   FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, InValidConfigBehavior);
-  struct ApmPublicSubmodules;
-  struct ApmPrivateSubmodules;
-
-  std::unique_ptr<ApmDataDumper> data_dumper_;
-  static int instance_count_;
-
-  SwapQueue<RuntimeSetting> runtime_settings_;
 
   // Class providing thread-safe message pipe functionality for
   // |runtime_settings_|.
@@ -162,7 +152,18 @@
 
    private:
     SwapQueue<RuntimeSetting>& runtime_settings_;
-  } runtime_settings_enqueuer_;
+  };
+  struct ApmPublicSubmodules;
+  struct ApmPrivateSubmodules;
+
+  std::unique_ptr<ApmDataDumper> data_dumper_;
+  static int instance_count_;
+
+  SwapQueue<RuntimeSetting> capture_runtime_settings_;
+  SwapQueue<RuntimeSetting> render_runtime_settings_;
+
+  RuntimeSettingEnqueuer capture_runtime_settings_enqueuer_;
+  RuntimeSettingEnqueuer render_runtime_settings_enqueuer_;
 
   // Submodule interface implementations.
   std::unique_ptr<HighPassFilter> high_pass_filter_impl_;
@@ -181,7 +182,6 @@
                 bool residual_echo_detector_enabled,
                 bool noise_suppressor_enabled,
                 bool intelligibility_enhancer_enabled,
-                bool beamformer_enabled,
                 bool adaptive_gain_controller_enabled,
                 bool gain_controller2_enabled,
                 bool pre_amplifier_enabled,
@@ -205,7 +205,6 @@
     bool residual_echo_detector_enabled_ = false;
     bool noise_suppressor_enabled_ = false;
     bool intelligibility_enhancer_enabled_ = false;
-    bool beamformer_enabled_ = false;
     bool adaptive_gain_controller_enabled_ = false;
     bool gain_controller2_enabled_ = false;
     bool pre_amplifier_enabled_ = false;
@@ -242,8 +241,6 @@
   // acquired.
   void InitializeTransient()
       RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_);
-  void InitializeBeamformer()
-      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_);
   void InitializeIntelligibility()
       RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_);
   int InitializeLocked(const ProcessingConfig& config)
@@ -257,8 +254,10 @@
   void InitializePostProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
   void InitializePreProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_);
 
-  // Handle all the runtime settings in the queue.
-  void HandleRuntimeSettings() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
+  // Empties and handles the respective RuntimeSetting queues.
+  void HandleCaptureRuntimeSettings()
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
+  void HandleRenderRuntimeSettings() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_);
 
   void EmptyQueuedRenderAudio();
   void AllocateRenderQueue()
@@ -353,20 +352,27 @@
   const struct ApmConstants {
     ApmConstants(int agc_startup_min_volume,
                  int agc_clipped_level_min,
-                 bool use_experimental_agc)
+                 bool use_experimental_agc,
+                 bool use_experimental_agc_agc2_level_estimation,
+                 bool use_experimental_agc_agc2_digital_adaptive)
         :  // Format of processing streams at input/output call sites.
           agc_startup_min_volume(agc_startup_min_volume),
           agc_clipped_level_min(agc_clipped_level_min),
-          use_experimental_agc(use_experimental_agc) {}
+          use_experimental_agc(use_experimental_agc),
+          use_experimental_agc_agc2_level_estimation(
+              use_experimental_agc_agc2_level_estimation),
+          use_experimental_agc_agc2_digital_adaptive(
+              use_experimental_agc_agc2_digital_adaptive) {}
     int agc_startup_min_volume;
     int agc_clipped_level_min;
     bool use_experimental_agc;
+    bool use_experimental_agc_agc2_level_estimation;
+    bool use_experimental_agc_agc2_digital_adaptive;
+
   } constants_;
 
   struct ApmCaptureState {
-    ApmCaptureState(bool transient_suppressor_enabled,
-                    const std::vector<Point>& array_geometry,
-                    SphericalPointf target_direction);
+    ApmCaptureState(bool transient_suppressor_enabled);
     ~ApmCaptureState();
     int aec_system_delay_jumps;
     int delay_offset_ms;
@@ -377,8 +383,6 @@
     bool output_will_be_muted;
     bool key_pressed;
     bool transient_suppressor_enabled;
-    std::vector<Point> array_geometry;
-    SphericalPointf target_direction;
     std::unique_ptr<AudioBuffer> capture_audio;
     // Only the rate and samples fields of capture_processing_format_ are used
     // because the capture processing number of channels is mutable and is
@@ -386,15 +390,14 @@
     StreamConfig capture_processing_format;
     int split_rate;
     bool echo_path_gain_change;
+    int prev_analog_mic_level;
   } capture_ RTC_GUARDED_BY(crit_capture_);
 
   struct ApmCaptureNonLockedState {
-    ApmCaptureNonLockedState(bool beamformer_enabled,
-                             bool intelligibility_enabled)
+    ApmCaptureNonLockedState(bool intelligibility_enabled)
         : capture_processing_format(kSampleRate16kHz),
           split_rate(kSampleRate16kHz),
           stream_delay_ms(0),
-          beamformer_enabled(beamformer_enabled),
           intelligibility_enabled(intelligibility_enabled) {}
     // Only the rate and samples fields of capture_processing_format_ are used
     // because the forward processing number of channels is mutable and is
@@ -402,7 +405,6 @@
     StreamConfig capture_processing_format;
     int split_rate;
     int stream_delay_ms;
-    bool beamformer_enabled;
     bool intelligibility_enabled;
     bool echo_controller_enabled = false;
   } capture_nonlocked_;
diff --git a/modules/audio_processing/audio_processing_impl_locking_unittest.cc b/modules/audio_processing/audio_processing_impl_locking_unittest.cc
index 39f8b8b..b770fef 100644
--- a/modules/audio_processing/audio_processing_impl_locking_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_locking_unittest.cc
@@ -146,8 +146,7 @@
 
       // Create test config for the first processing API function set.
       test_configs.push_back(test_config);
-      test_config.render_api_function =
-          RenderApiImpl::AnalyzeReverseStreamImpl;
+      test_config.render_api_function = RenderApiImpl::AnalyzeReverseStreamImpl;
       test_config.capture_api_function = CaptureApiImpl::ProcessStreamImpl3;
       test_configs.push_back(test_config);
     }
@@ -482,8 +481,7 @@
     for (size_t k = 0; k < frame->samples_per_channel_; k++) {
       // Store random 16 bit number between -(amplitude+1) and
       // amplitude.
-      frame_data[k * ch] =
-          rand_gen->RandInt(2 * amplitude + 1) - amplitude - 1;
+      frame_data[k * ch] = rand_gen->RandInt(2 * amplitude + 1) - amplitude - 1;
     }
   }
 }
diff --git a/modules/audio_processing/audio_processing_impl_unittest.cc b/modules/audio_processing/audio_processing_impl_unittest.cc
index 2ea0159..3ac5e71 100644
--- a/modules/audio_processing/audio_processing_impl_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_unittest.cc
@@ -72,15 +72,13 @@
 
   // New sample rate. (Only impacts ProcessStream).
   SetFrameSampleRate(&frame, 32000);
-  EXPECT_CALL(mock, InitializeLocked())
-      .Times(1);
+  EXPECT_CALL(mock, InitializeLocked()).Times(1);
   EXPECT_NOERR(mock.ProcessStream(&frame));
 
   // New number of channels.
   // TODO(peah): Investigate why this causes 2 inits.
   frame.num_channels_ = 2;
-  EXPECT_CALL(mock, InitializeLocked())
-      .Times(2);
+  EXPECT_CALL(mock, InitializeLocked()).Times(2);
   EXPECT_NOERR(mock.ProcessStream(&frame));
   // ProcessStream sets num_channels_ == num_output_channels.
   frame.num_channels_ = 2;
diff --git a/modules/audio_processing/audio_processing_performance_unittest.cc b/modules/audio_processing/audio_processing_performance_unittest.cc
index d312137..56615cb 100644
--- a/modules/audio_processing/audio_processing_performance_unittest.cc
+++ b/modules/audio_processing/audio_processing_performance_unittest.cc
@@ -49,7 +49,6 @@
 enum class SettingsType {
   kDefaultApmDesktop,
   kDefaultApmMobile,
-  kDefaultApmDesktopAndBeamformer,
   kDefaultApmDesktopAndIntelligibilityEnhancer,
   kAllSubmodulesTurnedOff,
   kDefaultApmDesktopWithoutDelayAgnostic,
@@ -114,17 +113,6 @@
       }
     }
 #endif
-
-    const SettingsType beamformer_settings[] = {
-        SettingsType::kDefaultApmDesktopAndBeamformer};
-
-    const int beamformer_sample_rates[] = {8000, 16000, 32000, 48000};
-
-    for (auto sample_rate : beamformer_sample_rates) {
-      for (auto settings : beamformer_settings) {
-        simulation_configs.push_back(SimulationConfig(sample_rate, settings));
-      }
-    }
 #endif
 
     const SettingsType mobile_settings[] = {SettingsType::kDefaultApmMobile};
@@ -149,9 +137,6 @@
       case SettingsType::kDefaultApmDesktop:
         description = "DefaultApmDesktop";
         break;
-      case SettingsType::kDefaultApmDesktopAndBeamformer:
-        description = "DefaultApmDesktopAndBeamformer";
-        break;
       case SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer:
         description = "DefaultApmDesktopAndIntelligibilityEnhancer";
         break;
@@ -175,13 +160,9 @@
 // Handler for the frame counters.
 class FrameCounters {
  public:
-  void IncreaseRenderCounter() {
-    rtc::AtomicOps::Increment(&render_count_);
-  }
+  void IncreaseRenderCounter() { rtc::AtomicOps::Increment(&render_count_); }
 
-  void IncreaseCaptureCounter() {
-    rtc::AtomicOps::Increment(&capture_count_);
-  }
+  void IncreaseCaptureCounter() { rtc::AtomicOps::Increment(&capture_count_); }
 
   int CaptureMinusRenderCounters() const {
     // The return value will be approximate, but that's good enough since
@@ -211,9 +192,7 @@
 // Class that represents a flag that can only be raised.
 class LockedFlag {
  public:
-  bool get_flag() const {
-    return rtc::AtomicOps::AcquireLoad(&flag_);
-  }
+  bool get_flag() const { return rtc::AtomicOps::AcquireLoad(&flag_); }
 
   void set_flag() {
     if (!get_flag())  // read-only operation to avoid affecting the cache-line.
@@ -263,9 +242,8 @@
         "_" + std::to_string(simulation_config_->sample_rate_hz) + "Hz";
 
     webrtc::test::PrintResultMeanAndError(
-        "apm_timing", sample_rate_name, processor_name,
-        GetDurationAverage(), GetDurationStandardDeviation(),
-        "us", false);
+        "apm_timing", sample_rate_name, processor_name, GetDurationAverage(),
+        GetDurationStandardDeviation(), "us", false);
 
     if (kPrintAllDurations) {
       webrtc::test::PrintResultList("apm_call_durations", sample_rate_name,
@@ -543,18 +521,6 @@
       config->Set<DelayAgnostic>(new DelayAgnostic(true));
     };
 
-    // Lambda function for adding beamformer settings to a config.
-    auto add_beamformer_config = [](Config* config) {
-      const size_t num_mics = 2;
-      const std::vector<Point> array_geometry =
-          ParseArrayGeometry("0 0 0 0.05 0 0", num_mics);
-      RTC_CHECK_EQ(array_geometry.size(), num_mics);
-
-      config->Set<Beamforming>(
-          new Beamforming(true, array_geometry,
-                          SphericalPointf(DegreesToRadians(90), 0.f, 1.f)));
-    };
-
     int num_capture_channels = 1;
     switch (simulation_config_.simulation_settings) {
       case SettingsType::kDefaultApmMobile: {
@@ -572,17 +538,6 @@
         apm_->SetExtraOptions(config);
         break;
       }
-      case SettingsType::kDefaultApmDesktopAndBeamformer: {
-        Config config;
-        add_beamformer_config(&config);
-        add_default_desktop_config(&config);
-        apm_.reset(AudioProcessingBuilder().Create(config));
-        ASSERT_TRUE(!!apm_);
-        set_default_desktop_apm_runtime_settings(apm_.get());
-        apm_->SetExtraOptions(config);
-        num_capture_channels = 2;
-        break;
-      }
       case SettingsType::kDefaultApmDesktopAndIntelligibilityEnhancer: {
         Config config;
         config.Set<Intelligibility>(new Intelligibility(true));
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index fbd81a1..4b244fc 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -21,7 +21,6 @@
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "modules/audio_processing/aec_dump/aec_dump_factory.h"
 #include "modules/audio_processing/audio_processing_impl.h"
-#include "modules/audio_processing/beamformer/mock_nonlinear_beamformer.h"
 #include "modules/audio_processing/common.h"
 #include "modules/audio_processing/include/audio_processing.h"
 #include "modules/audio_processing/include/mock_audio_processing.h"
@@ -1300,95 +1299,6 @@
   }
 }
 
-#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)
-TEST_F(ApmTest, AgcOnlyAdaptsWhenTargetSignalIsPresent) {
-  const int kSampleRateHz = 16000;
-  const size_t kSamplesPerChannel =
-      static_cast<size_t>(AudioProcessing::kChunkSizeMs * kSampleRateHz / 1000);
-  const size_t kNumInputChannels = 2;
-  const size_t kNumOutputChannels = 1;
-  const size_t kNumChunks = 700;
-  const float kScaleFactor = 0.25f;
-  Config config;
-  std::vector<webrtc::Point> geometry;
-  geometry.push_back(webrtc::Point(0.f, 0.f, 0.f));
-  geometry.push_back(webrtc::Point(0.05f, 0.f, 0.f));
-  config.Set<Beamforming>(new Beamforming(true, geometry));
-  testing::NiceMock<MockNonlinearBeamformer>* beamformer =
-      new testing::NiceMock<MockNonlinearBeamformer>(geometry, 1u);
-  std::unique_ptr<AudioProcessing> apm(
-      AudioProcessingBuilder()
-          .SetNonlinearBeamformer(
-              std::unique_ptr<webrtc::NonlinearBeamformer>(beamformer))
-          .Create(config));
-  EXPECT_EQ(kNoErr, apm->gain_control()->Enable(true));
-  ChannelBuffer<float> src_buf(kSamplesPerChannel, kNumInputChannels);
-  ChannelBuffer<float> dest_buf(kSamplesPerChannel, kNumOutputChannels);
-  const size_t max_length = kSamplesPerChannel * std::max(kNumInputChannels,
-                                                          kNumOutputChannels);
-  std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
-  std::unique_ptr<float[]> float_data(new float[max_length]);
-  std::string filename = ResourceFilePath("far", kSampleRateHz);
-  FILE* far_file = fopen(filename.c_str(), "rb");
-  ASSERT_TRUE(far_file != NULL) << "Could not open file " << filename << "\n";
-  const int kDefaultVolume = apm->gain_control()->stream_analog_level();
-  const int kDefaultCompressionGain =
-      apm->gain_control()->compression_gain_db();
-  bool is_target = false;
-  EXPECT_CALL(*beamformer, is_target_present())
-      .WillRepeatedly(testing::ReturnPointee(&is_target));
-  for (size_t i = 0; i < kNumChunks; ++i) {
-    ASSERT_TRUE(ReadChunk(far_file,
-                          int_data.get(),
-                          float_data.get(),
-                          &src_buf));
-    for (size_t j = 0; j < kNumInputChannels; ++j) {
-      for (size_t k = 0; k < kSamplesPerChannel; ++k) {
-        src_buf.channels()[j][k] *= kScaleFactor;
-      }
-    }
-    EXPECT_EQ(kNoErr,
-              apm->ProcessStream(src_buf.channels(),
-                                 src_buf.num_frames(),
-                                 kSampleRateHz,
-                                 LayoutFromChannels(src_buf.num_channels()),
-                                 kSampleRateHz,
-                                 LayoutFromChannels(dest_buf.num_channels()),
-                                 dest_buf.channels()));
-  }
-  EXPECT_EQ(kDefaultVolume,
-            apm->gain_control()->stream_analog_level());
-  EXPECT_EQ(kDefaultCompressionGain,
-            apm->gain_control()->compression_gain_db());
-  rewind(far_file);
-  is_target = true;
-  for (size_t i = 0; i < kNumChunks; ++i) {
-    ASSERT_TRUE(ReadChunk(far_file,
-                          int_data.get(),
-                          float_data.get(),
-                          &src_buf));
-    for (size_t j = 0; j < kNumInputChannels; ++j) {
-      for (size_t k = 0; k < kSamplesPerChannel; ++k) {
-        src_buf.channels()[j][k] *= kScaleFactor;
-      }
-    }
-    EXPECT_EQ(kNoErr,
-              apm->ProcessStream(src_buf.channels(),
-                                 src_buf.num_frames(),
-                                 kSampleRateHz,
-                                 LayoutFromChannels(src_buf.num_channels()),
-                                 kSampleRateHz,
-                                 LayoutFromChannels(dest_buf.num_channels()),
-                                 dest_buf.channels()));
-  }
-  EXPECT_LT(kDefaultVolume,
-            apm->gain_control()->stream_analog_level());
-  EXPECT_LT(kDefaultCompressionGain,
-            apm->gain_control()->compression_gain_db());
-  ASSERT_EQ(0, fclose(far_file));
-}
-#endif
-
 TEST_F(ApmTest, NoiseSuppression) {
   // Test valid suppression levels.
   NoiseSuppression::Level level[] = {
@@ -2850,7 +2760,6 @@
 
 TEST(ApmConfiguration, EnablePostProcessing) {
   // Verify that apm uses a capture post processing module if one is provided.
-  webrtc::Config webrtc_config;
   auto mock_post_processor_ptr =
       new testing::NiceMock<test::MockCustomProcessing>();
   auto mock_post_processor =
@@ -2858,7 +2767,7 @@
   rtc::scoped_refptr<AudioProcessing> apm =
       AudioProcessingBuilder()
           .SetCapturePostProcessing(std::move(mock_post_processor))
-          .Create(webrtc_config);
+          .Create();
 
   AudioFrame audio;
   audio.num_channels_ = 1;
@@ -2870,7 +2779,6 @@
 
 TEST(ApmConfiguration, EnablePreProcessing) {
   // Verify that apm uses a capture post processing module if one is provided.
-  webrtc::Config webrtc_config;
   auto mock_pre_processor_ptr =
       new testing::NiceMock<test::MockCustomProcessing>();
   auto mock_pre_processor =
@@ -2878,7 +2786,7 @@
   rtc::scoped_refptr<AudioProcessing> apm =
       AudioProcessingBuilder()
           .SetRenderPreProcessing(std::move(mock_pre_processor))
-          .Create(webrtc_config);
+          .Create();
 
   AudioFrame audio;
   audio.num_channels_ = 1;
@@ -2888,6 +2796,28 @@
   apm->ProcessReverseStream(&audio);
 }
 
+TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
+  auto mock_pre_processor_ptr =
+      new testing::NiceMock<test::MockCustomProcessing>();
+  auto mock_pre_processor =
+      std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
+  rtc::scoped_refptr<AudioProcessing> apm =
+      AudioProcessingBuilder()
+          .SetRenderPreProcessing(std::move(mock_pre_processor))
+          .Create();
+  apm->SetRuntimeSetting(
+      AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
+
+  // RuntimeSettings forwarded during 'Process*Stream' calls.
+  // Therefore we have to make one such call.
+  AudioFrame audio;
+  audio.num_channels_ = 1;
+  SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
+
+  EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(testing::_)).Times(1);
+  apm->ProcessReverseStream(&audio);
+}
+
 class MyEchoControlFactory : public EchoControlFactory {
  public:
   std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
diff --git a/modules/audio_processing/beamformer/array_util.cc b/modules/audio_processing/beamformer/array_util.cc
deleted file mode 100644
index e853559..0000000
--- a/modules/audio_processing/beamformer/array_util.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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.
- */
-
-#include "modules/audio_processing/beamformer/array_util.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-namespace {
-
-const float kMaxDotProduct = 1e-6f;
-
-}  // namespace
-
-float GetMinimumSpacing(const std::vector<Point>& array_geometry) {
-  RTC_CHECK_GT(array_geometry.size(), 1);
-  float mic_spacing = std::numeric_limits<float>::max();
-  for (size_t i = 0; i < (array_geometry.size() - 1); ++i) {
-    for (size_t j = i + 1; j < array_geometry.size(); ++j) {
-      mic_spacing =
-          std::min(mic_spacing, Distance(array_geometry[i], array_geometry[j]));
-    }
-  }
-  return mic_spacing;
-}
-
-Point PairDirection(const Point& a, const Point& b) {
-  return {b.x() - a.x(), b.y() - a.y(), b.z() - a.z()};
-}
-
-float DotProduct(const Point& a, const Point& b) {
-  return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
-}
-
-Point CrossProduct(const Point& a, const Point& b) {
-  return {a.y() * b.z() - a.z() * b.y(), a.z() * b.x() - a.x() * b.z(),
-          a.x() * b.y() - a.y() * b.x()};
-}
-
-bool AreParallel(const Point& a, const Point& b) {
-  Point cross_product = CrossProduct(a, b);
-  return DotProduct(cross_product, cross_product) < kMaxDotProduct;
-}
-
-bool ArePerpendicular(const Point& a, const Point& b) {
-  return std::abs(DotProduct(a, b)) < kMaxDotProduct;
-}
-
-rtc::Optional<Point> GetDirectionIfLinear(
-    const std::vector<Point>& array_geometry) {
-  RTC_DCHECK_GT(array_geometry.size(), 1);
-  const Point first_pair_direction =
-      PairDirection(array_geometry[0], array_geometry[1]);
-  for (size_t i = 2u; i < array_geometry.size(); ++i) {
-    const Point pair_direction =
-        PairDirection(array_geometry[i - 1], array_geometry[i]);
-    if (!AreParallel(first_pair_direction, pair_direction)) {
-      return rtc::nullopt;
-    }
-  }
-  return first_pair_direction;
-}
-
-rtc::Optional<Point> GetNormalIfPlanar(
-    const std::vector<Point>& array_geometry) {
-  RTC_DCHECK_GT(array_geometry.size(), 1);
-  const Point first_pair_direction =
-      PairDirection(array_geometry[0], array_geometry[1]);
-  Point pair_direction(0.f, 0.f, 0.f);
-  size_t i = 2u;
-  bool is_linear = true;
-  for (; i < array_geometry.size() && is_linear; ++i) {
-    pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]);
-    if (!AreParallel(first_pair_direction, pair_direction)) {
-      is_linear = false;
-    }
-  }
-  if (is_linear) {
-    return rtc::nullopt;
-  }
-  const Point normal_direction =
-      CrossProduct(first_pair_direction, pair_direction);
-  for (; i < array_geometry.size(); ++i) {
-    pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]);
-    if (!ArePerpendicular(normal_direction, pair_direction)) {
-      return rtc::nullopt;
-    }
-  }
-  return normal_direction;
-}
-
-rtc::Optional<Point> GetArrayNormalIfExists(
-    const std::vector<Point>& array_geometry) {
-  const rtc::Optional<Point> direction = GetDirectionIfLinear(array_geometry);
-  if (direction) {
-    return Point(direction->y(), -direction->x(), 0.f);
-  }
-  const rtc::Optional<Point> normal = GetNormalIfPlanar(array_geometry);
-  if (normal && normal->z() < kMaxDotProduct) {
-    return normal;
-  }
-  return rtc::nullopt;
-}
-
-Point AzimuthToPoint(float azimuth) {
-  return Point(std::cos(azimuth), std::sin(azimuth), 0.f);
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/array_util.h b/modules/audio_processing/beamformer/array_util.h
deleted file mode 100644
index f234929..0000000
--- a/modules/audio_processing/beamformer/array_util.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
-
-#include <cmath>
-#include <vector>
-
-#include "api/optional.h"
-
-namespace webrtc {
-
-// Coordinates in meters. The convention used is:
-// x: the horizontal dimension, with positive to the right from the camera's
-//    perspective.
-// y: the depth dimension, with positive forward from the camera's
-//    perspective.
-// z: the vertical dimension, with positive upwards.
-template<typename T>
-struct CartesianPoint {
-  CartesianPoint() {
-    c[0] = 0;
-    c[1] = 0;
-    c[2] = 0;
-  }
-  CartesianPoint(T x, T y, T z) {
-    c[0] = x;
-    c[1] = y;
-    c[2] = z;
-  }
-  T x() const { return c[0]; }
-  T y() const { return c[1]; }
-  T z() const { return c[2]; }
-  T c[3];
-};
-
-using Point = CartesianPoint<float>;
-
-// Calculates the direction from a to b.
-Point PairDirection(const Point& a, const Point& b);
-
-float DotProduct(const Point& a, const Point& b);
-Point CrossProduct(const Point& a, const Point& b);
-
-bool AreParallel(const Point& a, const Point& b);
-bool ArePerpendicular(const Point& a, const Point& b);
-
-// Returns the minimum distance between any two Points in the given
-// |array_geometry|.
-float GetMinimumSpacing(const std::vector<Point>& array_geometry);
-
-// If the given array geometry is linear it returns the direction without
-// normalizing.
-rtc::Optional<Point> GetDirectionIfLinear(
-    const std::vector<Point>& array_geometry);
-
-// If the given array geometry is planar it returns the normal without
-// normalizing.
-rtc::Optional<Point> GetNormalIfPlanar(
-    const std::vector<Point>& array_geometry);
-
-// Returns the normal of an array if it has one and it is in the xy-plane.
-rtc::Optional<Point> GetArrayNormalIfExists(
-    const std::vector<Point>& array_geometry);
-
-// The resulting Point will be in the xy-plane.
-Point AzimuthToPoint(float azimuth);
-
-template<typename T>
-float Distance(CartesianPoint<T> a, CartesianPoint<T> b) {
-  return std::sqrt((a.x() - b.x()) * (a.x() - b.x()) +
-                   (a.y() - b.y()) * (a.y() - b.y()) +
-                   (a.z() - b.z()) * (a.z() - b.z()));
-}
-
-// The convention used:
-// azimuth: zero is to the right from the camera's perspective, with positive
-//          angles in radians counter-clockwise.
-// elevation: zero is horizontal, with positive angles in radians upwards.
-// radius: distance from the camera in meters.
-template <typename T>
-struct SphericalPoint {
-  SphericalPoint(T azimuth, T elevation, T radius) {
-    s[0] = azimuth;
-    s[1] = elevation;
-    s[2] = radius;
-  }
-  T azimuth() const { return s[0]; }
-  T elevation() const { return s[1]; }
-  T distance() const { return s[2]; }
-  T s[3];
-};
-
-using SphericalPointf = SphericalPoint<float>;
-
-// Helper functions to transform degrees to radians and the inverse.
-template <typename T>
-T DegreesToRadians(T angle_degrees) {
-  return M_PI * angle_degrees / 180;
-}
-
-template <typename T>
-T RadiansToDegrees(T angle_radians) {
-  return 180 * angle_radians / M_PI;
-}
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
diff --git a/modules/audio_processing/beamformer/array_util_unittest.cc b/modules/audio_processing/beamformer/array_util_unittest.cc
deleted file mode 100644
index a5c075a..0000000
--- a/modules/audio_processing/beamformer/array_util_unittest.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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.
- */
-
-// MSVC++ requires this to be set before any other includes to get M_PI.
-#define _USE_MATH_DEFINES
-
-#include "modules/audio_processing/beamformer/array_util.h"
-
-#include <math.h>
-#include <vector>
-
-#include "test/gtest.h"
-
-namespace webrtc {
-
-bool operator==(const Point& lhs, const Point& rhs) {
-  return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
-}
-
-TEST(ArrayUtilTest, PairDirection) {
-  EXPECT_EQ(Point(1.f, 2.f, 3.f),
-            PairDirection(Point(0.f, 0.f, 0.f), Point(1.f, 2.f, 3.f)));
-  EXPECT_EQ(Point(-1.f, -2.f, -3.f),
-            PairDirection(Point(1.f, 2.f, 3.f), Point(0.f, 0.f, 0.f)));
-  EXPECT_EQ(Point(0.f, 0.f, 0.f),
-            PairDirection(Point(1.f, 0.f, 0.f), Point(1.f, 0.f, 0.f)));
-  EXPECT_EQ(Point(-1.f, 2.f, 0.f),
-            PairDirection(Point(1.f, 0.f, 0.f), Point(0.f, 2.f, 0.f)));
-  EXPECT_EQ(Point(-4.f, 4.f, -4.f),
-            PairDirection(Point(1.f, -2.f, 3.f), Point(-3.f, 2.f, -1.f)));
-}
-
-TEST(ArrayUtilTest, DotProduct) {
-  EXPECT_FLOAT_EQ(0.f, DotProduct(Point(0.f, 0.f, 0.f), Point(1.f, 2.f, 3.f)));
-  EXPECT_FLOAT_EQ(0.f, DotProduct(Point(1.f, 0.f, 2.f), Point(0.f, 3.f, 0.f)));
-  EXPECT_FLOAT_EQ(0.f, DotProduct(Point(1.f, 1.f, 0.f), Point(1.f, -1.f, 0.f)));
-  EXPECT_FLOAT_EQ(2.f, DotProduct(Point(1.f, 0.f, 0.f), Point(2.f, 0.f, 0.f)));
-  EXPECT_FLOAT_EQ(-6.f,
-                  DotProduct(Point(-2.f, 0.f, 0.f), Point(3.f, 0.f, 0.f)));
-  EXPECT_FLOAT_EQ(-10.f,
-                  DotProduct(Point(1.f, -2.f, 3.f), Point(-3.f, 2.f, -1.f)));
-}
-
-TEST(ArrayUtilTest, CrossProduct) {
-  EXPECT_EQ(Point(0.f, 0.f, 0.f),
-            CrossProduct(Point(0.f, 0.f, 0.f), Point(1.f, 2.f, 3.f)));
-  EXPECT_EQ(Point(0.f, 0.f, 1.f),
-            CrossProduct(Point(1.f, 0.f, 0.f), Point(0.f, 1.f, 0.f)));
-  EXPECT_EQ(Point(1.f, 0.f, 0.f),
-            CrossProduct(Point(0.f, 1.f, 0.f), Point(0.f, 0.f, 1.f)));
-  EXPECT_EQ(Point(0.f, -1.f, 0.f),
-            CrossProduct(Point(1.f, 0.f, 0.f), Point(0.f, 0.f, 1.f)));
-  EXPECT_EQ(Point(-4.f, -8.f, -4.f),
-            CrossProduct(Point(1.f, -2.f, 3.f), Point(-3.f, 2.f, -1.f)));
-}
-
-TEST(ArrayUtilTest, AreParallel) {
-  EXPECT_TRUE(AreParallel(Point(0.f, 0.f, 0.f), Point(1.f, 2.f, 3.f)));
-  EXPECT_FALSE(AreParallel(Point(1.f, 0.f, 2.f), Point(0.f, 3.f, 0.f)));
-  EXPECT_FALSE(AreParallel(Point(1.f, 2.f, 0.f), Point(1.f, -0.5f, 0.f)));
-  EXPECT_FALSE(AreParallel(Point(1.f, -2.f, 3.f), Point(-3.f, 2.f, -1.f)));
-  EXPECT_TRUE(AreParallel(Point(1.f, 0.f, 0.f), Point(2.f, 0.f, 0.f)));
-  EXPECT_TRUE(AreParallel(Point(1.f, 2.f, 3.f), Point(-2.f, -4.f, -6.f)));
-}
-
-TEST(ArrayUtilTest, ArePerpendicular) {
-  EXPECT_TRUE(ArePerpendicular(Point(0.f, 0.f, 0.f), Point(1.f, 2.f, 3.f)));
-  EXPECT_TRUE(ArePerpendicular(Point(1.f, 0.f, 2.f), Point(0.f, 3.f, 0.f)));
-  EXPECT_TRUE(ArePerpendicular(Point(1.f, 2.f, 0.f), Point(1.f, -0.5f, 0.f)));
-  EXPECT_FALSE(ArePerpendicular(Point(1.f, -2.f, 3.f), Point(-3.f, 2.f, -1.f)));
-  EXPECT_FALSE(ArePerpendicular(Point(1.f, 0.f, 0.f), Point(2.f, 0.f, 0.f)));
-  EXPECT_FALSE(ArePerpendicular(Point(1.f, 2.f, 3.f), Point(-2.f, -4.f, -6.f)));
-}
-
-TEST(ArrayUtilTest, GetMinimumSpacing) {
-  std::vector<Point> geometry;
-  geometry.push_back(Point(0.f, 0.f, 0.f));
-  geometry.push_back(Point(0.1f, 0.f, 0.f));
-  EXPECT_FLOAT_EQ(0.1f, GetMinimumSpacing(geometry));
-  geometry.push_back(Point(0.f, 0.05f, 0.f));
-  EXPECT_FLOAT_EQ(0.05f, GetMinimumSpacing(geometry));
-  geometry.push_back(Point(0.f, 0.f, 0.02f));
-  EXPECT_FLOAT_EQ(0.02f, GetMinimumSpacing(geometry));
-  geometry.push_back(Point(-0.003f, -0.004f, 0.02f));
-  EXPECT_FLOAT_EQ(0.005f, GetMinimumSpacing(geometry));
-}
-
-TEST(ArrayUtilTest, GetDirectionIfLinear) {
-  std::vector<Point> geometry;
-  geometry.push_back(Point(0.f, 0.f, 0.f));
-  geometry.push_back(Point(0.1f, 0.f, 0.f));
-  EXPECT_TRUE(
-      AreParallel(Point(1.f, 0.f, 0.f), *GetDirectionIfLinear(geometry)));
-  geometry.push_back(Point(0.15f, 0.f, 0.f));
-  EXPECT_TRUE(
-      AreParallel(Point(1.f, 0.f, 0.f), *GetDirectionIfLinear(geometry)));
-  geometry.push_back(Point(-0.2f, 0.f, 0.f));
-  EXPECT_TRUE(
-      AreParallel(Point(1.f, 0.f, 0.f), *GetDirectionIfLinear(geometry)));
-  geometry.push_back(Point(0.05f, 0.f, 0.f));
-  EXPECT_TRUE(
-      AreParallel(Point(1.f, 0.f, 0.f), *GetDirectionIfLinear(geometry)));
-  geometry.push_back(Point(0.1f, 0.1f, 0.f));
-  EXPECT_FALSE(GetDirectionIfLinear(geometry));
-  geometry.push_back(Point(0.f, 0.f, -0.2f));
-  EXPECT_FALSE(GetDirectionIfLinear(geometry));
-}
-
-TEST(ArrayUtilTest, GetNormalIfPlanar) {
-  std::vector<Point> geometry;
-  geometry.push_back(Point(0.f, 0.f, 0.f));
-  geometry.push_back(Point(0.1f, 0.f, 0.f));
-  EXPECT_FALSE(GetNormalIfPlanar(geometry));
-  geometry.push_back(Point(0.15f, 0.f, 0.f));
-  EXPECT_FALSE(GetNormalIfPlanar(geometry));
-  geometry.push_back(Point(0.1f, 0.2f, 0.f));
-  EXPECT_TRUE(AreParallel(Point(0.f, 0.f, 1.f), *GetNormalIfPlanar(geometry)));
-  geometry.push_back(Point(0.f, -0.15f, 0.f));
-  EXPECT_TRUE(AreParallel(Point(0.f, 0.f, 1.f), *GetNormalIfPlanar(geometry)));
-  geometry.push_back(Point(0.f, 0.1f, 0.2f));
-  EXPECT_FALSE(GetNormalIfPlanar(geometry));
-  geometry.push_back(Point(0.f, 0.f, -0.15f));
-  EXPECT_FALSE(GetNormalIfPlanar(geometry));
-  geometry.push_back(Point(0.1f, 0.2f, 0.f));
-  EXPECT_FALSE(GetNormalIfPlanar(geometry));
-}
-
-TEST(ArrayUtilTest, GetArrayNormalIfExists) {
-  std::vector<Point> geometry;
-  geometry.push_back(Point(0.f, 0.f, 0.f));
-  geometry.push_back(Point(0.1f, 0.f, 0.f));
-  EXPECT_TRUE(
-      AreParallel(Point(0.f, 1.f, 0.f), *GetArrayNormalIfExists(geometry)));
-  geometry.push_back(Point(0.15f, 0.f, 0.f));
-  EXPECT_TRUE(
-      AreParallel(Point(0.f, 1.f, 0.f), *GetArrayNormalIfExists(geometry)));
-  geometry.push_back(Point(0.1f, 0.f, 0.2f));
-  EXPECT_TRUE(
-      AreParallel(Point(0.f, 1.f, 0.f), *GetArrayNormalIfExists(geometry)));
-  geometry.push_back(Point(0.f, 0.f, -0.1f));
-  EXPECT_TRUE(
-      AreParallel(Point(0.f, 1.f, 0.f), *GetArrayNormalIfExists(geometry)));
-  geometry.push_back(Point(0.1f, 0.2f, 0.3f));
-  EXPECT_FALSE(GetArrayNormalIfExists(geometry));
-  geometry.push_back(Point(0.f, -0.1f, 0.f));
-  EXPECT_FALSE(GetArrayNormalIfExists(geometry));
-  geometry.push_back(Point(1.f, 0.f, -0.2f));
-  EXPECT_FALSE(GetArrayNormalIfExists(geometry));
-}
-
-TEST(ArrayUtilTest, DegreesToRadians) {
-  EXPECT_FLOAT_EQ(0.f, DegreesToRadians(0.f));
-  EXPECT_FLOAT_EQ(static_cast<float>(M_PI) / 6.f, DegreesToRadians(30.f));
-  EXPECT_FLOAT_EQ(-static_cast<float>(M_PI) / 4.f, DegreesToRadians(-45.f));
-  EXPECT_FLOAT_EQ(static_cast<float>(M_PI) / 3.f, DegreesToRadians(60.f));
-  EXPECT_FLOAT_EQ(-static_cast<float>(M_PI) / 2.f, DegreesToRadians(-90.f));
-  EXPECT_FLOAT_EQ(2.f * static_cast<float>(M_PI) / 3.f,
-                  DegreesToRadians(120.f));
-  EXPECT_FLOAT_EQ(-3.f * static_cast<float>(M_PI) / 4.f,
-                  DegreesToRadians(-135.f));
-  EXPECT_FLOAT_EQ(5.f * static_cast<float>(M_PI) / 6.f,
-                  DegreesToRadians(150.f));
-  EXPECT_FLOAT_EQ(-static_cast<float>(M_PI), DegreesToRadians(-180.f));
-}
-
-TEST(ArrayUtilTest, RadiansToDegrees) {
-  EXPECT_FLOAT_EQ(0.f, RadiansToDegrees(0.f));
-  EXPECT_FLOAT_EQ(30.f, RadiansToDegrees(M_PI / 6.f));
-  EXPECT_FLOAT_EQ(-45.f, RadiansToDegrees(-M_PI / 4.f));
-  EXPECT_FLOAT_EQ(60.f, RadiansToDegrees(M_PI / 3.f));
-  EXPECT_FLOAT_EQ(-90.f, RadiansToDegrees(-M_PI / 2.f));
-  EXPECT_FLOAT_EQ(120.f, RadiansToDegrees(2.f * M_PI / 3.f));
-  EXPECT_FLOAT_EQ(-135.f, RadiansToDegrees(-3.f * M_PI / 4.f));
-  EXPECT_FLOAT_EQ(150.f, RadiansToDegrees(5.f * M_PI / 6.f));
-  EXPECT_FLOAT_EQ(-180.f, RadiansToDegrees(-M_PI));
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/complex_matrix.h b/modules/audio_processing/beamformer/complex_matrix.h
deleted file mode 100644
index 9960e1d..0000000
--- a/modules/audio_processing/beamformer/complex_matrix.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
-
-#include <complex>
-
-#include "modules/audio_processing/beamformer/matrix.h"
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-
-using std::complex;
-
-// An extension of Matrix for operations that only work on a complex type.
-template <typename T>
-class ComplexMatrix : public Matrix<complex<T> > {
- public:
-  ComplexMatrix() : Matrix<complex<T> >() {}
-
-  ComplexMatrix(size_t num_rows, size_t num_columns)
-      : Matrix<complex<T> >(num_rows, num_columns) {}
-
-  ComplexMatrix(const complex<T>* data, size_t num_rows, size_t num_columns)
-      : Matrix<complex<T> >(data, num_rows, num_columns) {}
-
-  // Complex Matrix operations.
-  ComplexMatrix& PointwiseConjugate() {
-    complex<T>* const data = this->data();
-    size_t size = this->num_rows() * this->num_columns();
-    for (size_t i = 0; i < size; ++i) {
-      data[i] = conj(data[i]);
-    }
-
-    return *this;
-  }
-
-  ComplexMatrix& PointwiseConjugate(const ComplexMatrix& operand) {
-    this->CopyFrom(operand);
-    return PointwiseConjugate();
-  }
-
-  ComplexMatrix& ConjugateTranspose() {
-    this->CopyDataToScratch();
-    size_t num_rows = this->num_rows();
-    this->SetNumRows(this->num_columns());
-    this->SetNumColumns(num_rows);
-    this->Resize();
-    return ConjugateTranspose(this->scratch_elements());
-  }
-
-  ComplexMatrix& ConjugateTranspose(const ComplexMatrix& operand) {
-    RTC_CHECK_EQ(operand.num_rows(), this->num_columns());
-    RTC_CHECK_EQ(operand.num_columns(), this->num_rows());
-    return ConjugateTranspose(operand.elements());
-  }
-
-  ComplexMatrix& ZeroImag() {
-    complex<T>* const data = this->data();
-    size_t size = this->num_rows() * this->num_columns();
-    for (size_t i = 0; i < size; ++i) {
-      data[i] = complex<T>(data[i].real(), 0);
-    }
-
-    return *this;
-  }
-
-  ComplexMatrix& ZeroImag(const ComplexMatrix& operand) {
-    this->CopyFrom(operand);
-    return ZeroImag();
-  }
-
- private:
-  ComplexMatrix& ConjugateTranspose(const complex<T>* const* src) {
-    complex<T>* const* elements = this->elements();
-    for (size_t i = 0; i < this->num_rows(); ++i) {
-      for (size_t j = 0; j < this->num_columns(); ++j) {
-        elements[i][j] = conj(src[j][i]);
-      }
-    }
-
-    return *this;
-  }
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
diff --git a/modules/audio_processing/beamformer/complex_matrix_unittest.cc b/modules/audio_processing/beamformer/complex_matrix_unittest.cc
deleted file mode 100644
index e11dfd2..0000000
--- a/modules/audio_processing/beamformer/complex_matrix_unittest.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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.
- */
-
-#include "modules/audio_processing/beamformer/complex_matrix.h"
-#include "modules/audio_processing/beamformer/matrix_test_helpers.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-
-TEST(ComplexMatrixTest, TestPointwiseConjugate) {
-  const int kNumRows = 2;
-  const int kNumCols = 4;
-
-  const complex<float> kValuesInitial[kNumRows][kNumCols] = {
-      {complex<float>(1.1f, 1.1f), complex<float>(2.2f, -2.2f),
-       complex<float>(3.3f, 3.3f), complex<float>(4.4f, -4.4f)},
-      {complex<float>(5.5f, 5.5f), complex<float>(6.6f, -6.6f),
-       complex<float>(7.7f, 7.7f), complex<float>(8.8f, -8.8f)}};
-
-  const complex<float> kValuesExpected[kNumRows][kNumCols] = {
-      {complex<float>(1.1f, -1.1f), complex<float>(2.2f, 2.2f),
-       complex<float>(3.3f, -3.3f), complex<float>(4.4f, 4.4f)},
-      {complex<float>(5.5f, -5.5f), complex<float>(6.6f, 6.6f),
-       complex<float>(7.7f, -7.7f), complex<float>(8.8f, 8.8f)}};
-
-  ComplexMatrix<float> initial_mat(*kValuesInitial, kNumRows, kNumCols);
-  ComplexMatrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  ComplexMatrix<float> actual_result(kNumRows, kNumCols);
-
-  actual_result.PointwiseConjugate(initial_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(expected_result,
-                                                        actual_result);
-
-  initial_mat.PointwiseConjugate();
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(initial_mat,
-                                                        actual_result);
-}
-
-TEST(ComplexMatrixTest, TestConjugateTranspose) {
-  const int kNumInitialRows = 2;
-  const int kNumInitialCols = 4;
-  const int kNumResultRows = 4;
-  const int kNumResultCols = 2;
-
-  const complex<float> kValuesInitial[kNumInitialRows][kNumInitialCols] = {
-      {complex<float>(1.1f, 1.1f), complex<float>(2.2f, 2.2f),
-       complex<float>(3.3f, 3.3f), complex<float>(4.4f, 4.4f)},
-      {complex<float>(5.5f, 5.5f), complex<float>(6.6f, 6.6f),
-       complex<float>(7.7f, 7.7f), complex<float>(8.8f, 8.8f)}};
-
-  const complex<float> kValuesExpected[kNumResultRows][kNumResultCols] = {
-      {complex<float>(1.1f, -1.1f), complex<float>(5.5f, -5.5f)},
-      {complex<float>(2.2f, -2.2f), complex<float>(6.6f, -6.6f)},
-      {complex<float>(3.3f, -3.3f), complex<float>(7.7f, -7.7f)},
-      {complex<float>(4.4f, -4.4f), complex<float>(8.8f, -8.8f)}};
-
-  ComplexMatrix<float> initial_mat(
-      *kValuesInitial, kNumInitialRows, kNumInitialCols);
-  ComplexMatrix<float> expected_result(
-      *kValuesExpected, kNumResultRows, kNumResultCols);
-  ComplexMatrix<float> actual_result(kNumResultRows, kNumResultCols);
-
-  actual_result.ConjugateTranspose(initial_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(expected_result,
-                                                        actual_result);
-
-  initial_mat.ConjugateTranspose();
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(initial_mat,
-                                                        actual_result);
-}
-
-TEST(ComplexMatrixTest, TestZeroImag) {
-  const int kNumRows = 2;
-  const int kNumCols = 2;
-  const complex<float> kValuesInitial[kNumRows][kNumCols] = {
-      {complex<float>(1.1f, 1.1f), complex<float>(2.2f, 2.2f)},
-      {complex<float>(3.3f, 3.3f), complex<float>(4.4f, 4.4f)}};
-  const complex<float> kValuesExpected[kNumRows][kNumCols] = {
-      {complex<float>(1.1f, 0.f), complex<float>(2.2f, 0.f)},
-      {complex<float>(3.3f, 0.f), complex<float>(4.4f, 0.f)}};
-
-  ComplexMatrix<float> initial_mat(*kValuesInitial, kNumRows, kNumCols);
-  ComplexMatrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  ComplexMatrix<float> actual_result;
-
-  actual_result.ZeroImag(initial_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(expected_result,
-                                                        actual_result);
-
-  initial_mat.ZeroImag();
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(initial_mat,
-                                                        actual_result);
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/covariance_matrix_generator.cc b/modules/audio_processing/beamformer/covariance_matrix_generator.cc
deleted file mode 100644
index df36d59..0000000
--- a/modules/audio_processing/beamformer/covariance_matrix_generator.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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.
- */
-
-#define _USE_MATH_DEFINES
-
-#include "modules/audio_processing/beamformer/covariance_matrix_generator.h"
-
-#include <cmath>
-
-namespace webrtc {
-namespace {
-
-float BesselJ0(float x) {
-#ifdef WEBRTC_WIN
-  return _j0(x);
-#else
-  return j0(x);
-#endif
-}
-
-// Calculates the Euclidean norm for a row vector.
-float Norm(const ComplexMatrix<float>& x) {
-  RTC_CHECK_EQ(1, x.num_rows());
-  const size_t length = x.num_columns();
-  const complex<float>* elems = x.elements()[0];
-  float result = 0.f;
-  for (size_t i = 0u; i < length; ++i) {
-    result += std::norm(elems[i]);
-  }
-  return std::sqrt(result);
-}
-
-}  // namespace
-
-void CovarianceMatrixGenerator::UniformCovarianceMatrix(
-    float wave_number,
-    const std::vector<Point>& geometry,
-    ComplexMatrix<float>* mat) {
-  RTC_CHECK_EQ(geometry.size(), mat->num_rows());
-  RTC_CHECK_EQ(geometry.size(), mat->num_columns());
-
-  complex<float>* const* mat_els = mat->elements();
-  for (size_t i = 0; i < geometry.size(); ++i) {
-    for (size_t j = 0; j < geometry.size(); ++j) {
-      if (wave_number > 0.f) {
-        mat_els[i][j] =
-            BesselJ0(wave_number * Distance(geometry[i], geometry[j]));
-      } else {
-        mat_els[i][j] = i == j ? 1.f : 0.f;
-      }
-    }
-  }
-}
-
-void CovarianceMatrixGenerator::AngledCovarianceMatrix(
-    float sound_speed,
-    float angle,
-    size_t frequency_bin,
-    size_t fft_size,
-    size_t num_freq_bins,
-    int sample_rate,
-    const std::vector<Point>& geometry,
-    ComplexMatrix<float>* mat) {
-  RTC_CHECK_EQ(geometry.size(), mat->num_rows());
-  RTC_CHECK_EQ(geometry.size(), mat->num_columns());
-
-  ComplexMatrix<float> interf_cov_vector(1, geometry.size());
-  ComplexMatrix<float> interf_cov_vector_transposed(geometry.size(), 1);
-  PhaseAlignmentMasks(frequency_bin,
-                      fft_size,
-                      sample_rate,
-                      sound_speed,
-                      geometry,
-                      angle,
-                      &interf_cov_vector);
-  interf_cov_vector.Scale(1.f / Norm(interf_cov_vector));
-  interf_cov_vector_transposed.Transpose(interf_cov_vector);
-  interf_cov_vector.PointwiseConjugate();
-  mat->Multiply(interf_cov_vector_transposed, interf_cov_vector);
-}
-
-void CovarianceMatrixGenerator::PhaseAlignmentMasks(
-    size_t frequency_bin,
-    size_t fft_size,
-    int sample_rate,
-    float sound_speed,
-    const std::vector<Point>& geometry,
-    float angle,
-    ComplexMatrix<float>* mat) {
-  RTC_CHECK_EQ(1, mat->num_rows());
-  RTC_CHECK_EQ(geometry.size(), mat->num_columns());
-
-  float freq_in_hertz =
-      (static_cast<float>(frequency_bin) / fft_size) * sample_rate;
-
-  complex<float>* const* mat_els = mat->elements();
-  for (size_t c_ix = 0; c_ix < geometry.size(); ++c_ix) {
-    float distance = std::cos(angle) * geometry[c_ix].x() +
-                     std::sin(angle) * geometry[c_ix].y();
-    float phase_shift = -2.f * M_PI * distance * freq_in_hertz / sound_speed;
-
-    // Euler's formula for mat[0][c_ix] = e^(j * phase_shift).
-    mat_els[0][c_ix] = complex<float>(cos(phase_shift), sin(phase_shift));
-  }
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/covariance_matrix_generator.h b/modules/audio_processing/beamformer/covariance_matrix_generator.h
deleted file mode 100644
index 6a5841f..0000000
--- a/modules/audio_processing/beamformer/covariance_matrix_generator.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
-
-#include "modules/audio_processing/beamformer/complex_matrix.h"
-#include "modules/audio_processing/beamformer/array_util.h"
-
-namespace webrtc {
-
-// Helper class for Beamformer in charge of generating covariance matrices. For
-// each function, the passed-in ComplexMatrix is expected to be of size
-// |num_input_channels| x |num_input_channels|.
-class CovarianceMatrixGenerator {
- public:
-  // A uniform covariance matrix with a gap at the target location. WARNING:
-  // The target angle is assumed to be 0.
-  static void UniformCovarianceMatrix(float wave_number,
-                                      const std::vector<Point>& geometry,
-                                      ComplexMatrix<float>* mat);
-
-  // The covariance matrix of a source at the given angle.
-  static void AngledCovarianceMatrix(float sound_speed,
-                                     float angle,
-                                     size_t frequency_bin,
-                                     size_t fft_size,
-                                     size_t num_freq_bins,
-                                     int sample_rate,
-                                     const std::vector<Point>& geometry,
-                                     ComplexMatrix<float>* mat);
-
-  // Calculates phase shifts that, when applied to a multichannel signal and
-  // added together, cause constructive interferernce for sources located at
-  // the given angle.
-  static void PhaseAlignmentMasks(size_t frequency_bin,
-                                  size_t fft_size,
-                                  int sample_rate,
-                                  float sound_speed,
-                                  const std::vector<Point>& geometry,
-                                  float angle,
-                                  ComplexMatrix<float>* mat);
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_BF_HELPERS_H_
diff --git a/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc b/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc
deleted file mode 100644
index a6518e5..0000000
--- a/modules/audio_processing/beamformer/covariance_matrix_generator_unittest.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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.
- */
-
-#define _USE_MATH_DEFINES
-
-#include "modules/audio_processing/beamformer/covariance_matrix_generator.h"
-
-#include <cmath>
-
-#include "modules/audio_processing/beamformer/matrix_test_helpers.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-
-using std::complex;
-
-TEST(CovarianceMatrixGeneratorTest, TestUniformCovarianceMatrix2Mics) {
-  const float kWaveNumber = 0.5775f;
-  const int kNumberMics = 2;
-  const float kMicSpacing = 0.05f;
-  const float kTolerance = 0.0001f;
-  std::vector<Point> geometry;
-  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
-  for (int i = 0; i < kNumberMics; ++i) {
-    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
-  }
-  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::UniformCovarianceMatrix(kWaveNumber,
-                                                     geometry,
-                                                     &actual_covariance_matrix);
-
-  complex<float>* const* actual_els = actual_covariance_matrix.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 1.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.9998f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.9998f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 1.f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-}
-
-TEST(CovarianceMatrixGeneratorTest, TestUniformCovarianceMatrix3Mics) {
-  const float kWaveNumber = 10.3861f;
-  const int kNumberMics = 3;
-  const float kMicSpacing = 0.04f;
-  const float kTolerance = 0.0001f;
-  std::vector<Point> geometry;
-  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
-  for (int i = 0; i < kNumberMics; ++i) {
-    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
-  }
-  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::UniformCovarianceMatrix(kWaveNumber,
-                                                     geometry,
-                                                     &actual_covariance_matrix);
-
-  complex<float>* const* actual_els = actual_covariance_matrix.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 1.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.9573f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].real(), 0.8347f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.9573f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 1.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].real(), 0.9573f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].real(), 0.8347f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].real(), 0.9573f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].real(), 1.f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
-}
-
-TEST(CovarianceMatrixGeneratorTest, TestUniformCovarianceMatrix3DArray) {
-  const float kWaveNumber = 1.2345f;
-  const int kNumberMics = 4;
-  const float kTolerance = 0.0001f;
-  std::vector<Point> geometry;
-  geometry.push_back(Point(-0.025f, -0.05f, -0.075f));
-  geometry.push_back(Point(0.075f, -0.05f, -0.075f));
-  geometry.push_back(Point(-0.025f, 0.15f, -0.075f));
-  geometry.push_back(Point(-0.025f, -0.05f, 0.225f));
-  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::UniformCovarianceMatrix(kWaveNumber,
-                                                     geometry,
-                                                     &actual_covariance_matrix);
-
-  complex<float>* const* actual_els = actual_covariance_matrix.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 1.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.9962f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].real(), 0.9848f, kTolerance);
-  EXPECT_NEAR(actual_els[0][3].real(), 0.9660f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.9962f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 1.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].real(), 0.9810f, kTolerance);
-  EXPECT_NEAR(actual_els[1][3].real(), 0.9623f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].real(), 0.9848f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].real(), 0.9810f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].real(), 1.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][3].real(), 0.9511f, kTolerance);
-  EXPECT_NEAR(actual_els[3][0].real(), 0.9660f, kTolerance);
-  EXPECT_NEAR(actual_els[3][1].real(), 0.9623f, kTolerance);
-  EXPECT_NEAR(actual_els[3][2].real(), 0.9511f, kTolerance);
-  EXPECT_NEAR(actual_els[3][3].real(), 1.f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][3].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][3].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[2][3].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[3][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[3][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[3][2].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[3][3].imag(), 0.f, kTolerance);
-}
-
-TEST(CovarianceMatrixGeneratorTest, TestAngledCovarianceMatrix2Mics) {
-  const float kSpeedOfSound = 340;
-  const float kAngle = static_cast<float>(M_PI) / 4.f;
-  const float kFrequencyBin = 6;
-  const float kFftSize = 512;
-  const int kNumberFrequencyBins = 257;
-  const int kSampleRate = 16000;
-  const int kNumberMics = 2;
-  const float kMicSpacing = 0.04f;
-  const float kTolerance = 0.0001f;
-  std::vector<Point> geometry;
-  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
-  for (int i = 0; i < kNumberMics; ++i) {
-    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
-  }
-  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::AngledCovarianceMatrix(kSpeedOfSound,
-                                                    kAngle,
-                                                    kFrequencyBin,
-                                                    kFftSize,
-                                                    kNumberFrequencyBins,
-                                                    kSampleRate,
-                                                    geometry,
-                                                    &actual_covariance_matrix);
-
-  complex<float>* const* actual_els = actual_covariance_matrix.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 0.5f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.4976f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.4976f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.5f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.0489f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), -0.0489f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-}
-
-TEST(CovarianceMatrixGeneratorTest, TestAngledCovarianceMatrix3Mics) {
-  const float kSpeedOfSound = 340;
-  const float kAngle = static_cast<float>(M_PI) / 4.f;
-  const float kFrequencyBin = 9;
-  const float kFftSize = 512;
-  const int kNumberFrequencyBins = 257;
-  const int kSampleRate = 42000;
-  const int kNumberMics = 3;
-  const float kMicSpacing = 0.05f;
-  const float kTolerance = 0.0001f;
-  std::vector<Point> geometry;
-  float first_mic = (kNumberMics - 1) * kMicSpacing / 2.f;
-  for (int i = 0; i < kNumberMics; ++i) {
-    geometry.push_back(Point(i * kMicSpacing - first_mic, 0.f, 0.f));
-  }
-  ComplexMatrix<float> actual_covariance_matrix(kNumberMics, kNumberMics);
-  CovarianceMatrixGenerator::AngledCovarianceMatrix(kSpeedOfSound,
-                                                    kAngle,
-                                                    kFrequencyBin,
-                                                    kFftSize,
-                                                    kNumberFrequencyBins,
-                                                    kSampleRate,
-                                                    geometry,
-                                                    &actual_covariance_matrix);
-
-  complex<float>* const* actual_els = actual_covariance_matrix.elements();
-
-  EXPECT_NEAR(actual_els[0][0].real(), 0.3333f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].real(), 0.2953f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].real(), 0.1899f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].real(), 0.2953f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].real(), 0.3333f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].real(), 0.2953f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].real(), 0.1899f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].real(), 0.2953f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].real(), 0.3333f, kTolerance);
-
-  EXPECT_NEAR(actual_els[0][0].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[0][1].imag(), 0.1546f, kTolerance);
-  EXPECT_NEAR(actual_els[0][2].imag(), 0.274f, kTolerance);
-  EXPECT_NEAR(actual_els[1][0].imag(), -0.1546f, kTolerance);
-  EXPECT_NEAR(actual_els[1][1].imag(), 0.f, kTolerance);
-  EXPECT_NEAR(actual_els[1][2].imag(), 0.1546f, kTolerance);
-  EXPECT_NEAR(actual_els[2][0].imag(), -0.274f, kTolerance);
-  EXPECT_NEAR(actual_els[2][1].imag(), -0.1546f, kTolerance);
-  EXPECT_NEAR(actual_els[2][2].imag(), 0.f, kTolerance);
-}
-
-// PhaseAlignmentMasks is tested by AngledCovarianceMatrix and by
-// InitBeamformerWeights in BeamformerUnittest.
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/matrix.h b/modules/audio_processing/beamformer/matrix.h
deleted file mode 100644
index bf94c25..0000000
--- a/modules/audio_processing/beamformer/matrix.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
-
-#include <algorithm>
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "rtc_base/checks.h"
-#include "rtc_base/constructormagic.h"
-
-namespace {
-
-// Wrappers to get around the compiler warning resulting from the fact that
-// there's no std::sqrt overload for ints. We cast all non-complex types to
-// a double for the sqrt method.
-template <typename T>
-T sqrt_wrapper(T x) {
-  return sqrt(static_cast<double>(x));
-}
-
-template <typename S>
-std::complex<S> sqrt_wrapper(std::complex<S> x) {
-  return sqrt(x);
-}
-} // namespace
-
-namespace webrtc {
-
-// Matrix is a class for doing standard matrix operations on 2 dimensional
-// matrices of any size. Results of matrix operations are stored in the
-// calling object. Function overloads exist for both in-place (the calling
-// object is used as both an operand and the result) and out-of-place (all
-// operands are passed in as parameters) operations. If operand dimensions
-// mismatch, the program crashes. Out-of-place operations change the size of
-// the calling object, if necessary, before operating.
-//
-// 'In-place' operations that inherently change the size of the matrix (eg.
-// Transpose, Multiply on different-sized matrices) must make temporary copies
-// (|scratch_elements_| and |scratch_data_|) of existing data to complete the
-// operations.
-//
-// The data is stored contiguously. Data can be accessed internally as a flat
-// array, |data_|, or as an array of row pointers, |elements_|, but is
-// available to users only as an array of row pointers through |elements()|.
-// Memory for storage is allocated when a matrix is resized only if the new
-// size overflows capacity. Memory needed temporarily for any operations is
-// similarly resized only if the new size overflows capacity.
-//
-// If you pass in storage through the ctor, that storage is copied into the
-// matrix. TODO(claguna): albeit tricky, allow for data to be referenced
-// instead of copied, and owned by the user.
-template <typename T>
-class Matrix {
- public:
-  Matrix() : num_rows_(0), num_columns_(0) {}
-
-  // Allocates space for the elements and initializes all values to zero.
-  Matrix(size_t num_rows, size_t num_columns)
-      : num_rows_(num_rows), num_columns_(num_columns) {
-    Resize();
-    scratch_data_.resize(num_rows_ * num_columns_);
-    scratch_elements_.resize(num_rows_);
-  }
-
-  // Copies |data| into the new Matrix.
-  Matrix(const T* data, size_t num_rows, size_t num_columns)
-      : num_rows_(0), num_columns_(0) {
-    CopyFrom(data, num_rows, num_columns);
-    scratch_data_.resize(num_rows_ * num_columns_);
-    scratch_elements_.resize(num_rows_);
-  }
-
-  virtual ~Matrix() {}
-
-  // Deep copy an existing matrix.
-  void CopyFrom(const Matrix& other) {
-    CopyFrom(&other.data_[0], other.num_rows_, other.num_columns_);
-  }
-
-  // Copy |data| into the Matrix. The current data is lost.
-  void CopyFrom(const T* const data, size_t num_rows, size_t num_columns) {
-    Resize(num_rows, num_columns);
-    memcpy(&data_[0], data, num_rows_ * num_columns_ * sizeof(data_[0]));
-  }
-
-  Matrix& CopyFromColumn(const T* const* src,
-                         size_t column_index,
-                         size_t num_rows) {
-    Resize(1, num_rows);
-    for (size_t i = 0; i < num_columns_; ++i) {
-      data_[i] = src[i][column_index];
-    }
-
-    return *this;
-  }
-
-  void Resize(size_t num_rows, size_t num_columns) {
-    if (num_rows != num_rows_ || num_columns != num_columns_) {
-      num_rows_ = num_rows;
-      num_columns_ = num_columns;
-      Resize();
-    }
-  }
-
-  // Accessors and mutators.
-  size_t num_rows() const { return num_rows_; }
-  size_t num_columns() const { return num_columns_; }
-  T* const* elements() { return &elements_[0]; }
-  const T* const* elements() const { return &elements_[0]; }
-
-  T Trace() {
-    RTC_CHECK_EQ(num_rows_, num_columns_);
-
-    T trace = 0;
-    for (size_t i = 0; i < num_rows_; ++i) {
-      trace += elements_[i][i];
-    }
-    return trace;
-  }
-
-  // Matrix Operations. Returns *this to support method chaining.
-  Matrix& Transpose() {
-    CopyDataToScratch();
-    Resize(num_columns_, num_rows_);
-    return Transpose(scratch_elements());
-  }
-
-  Matrix& Transpose(const Matrix& operand) {
-    RTC_CHECK_EQ(operand.num_rows_, num_columns_);
-    RTC_CHECK_EQ(operand.num_columns_, num_rows_);
-
-    return Transpose(operand.elements());
-  }
-
-  template <typename S>
-  Matrix& Scale(const S& scalar) {
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] *= scalar;
-    }
-
-    return *this;
-  }
-
-  template <typename S>
-  Matrix& Scale(const Matrix& operand, const S& scalar) {
-    CopyFrom(operand);
-    return Scale(scalar);
-  }
-
-  Matrix& Add(const Matrix& operand) {
-    RTC_CHECK_EQ(num_rows_, operand.num_rows_);
-    RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] += operand.data_[i];
-    }
-
-    return *this;
-  }
-
-  Matrix& Add(const Matrix& lhs, const Matrix& rhs) {
-    CopyFrom(lhs);
-    return Add(rhs);
-  }
-
-  Matrix& Subtract(const Matrix& operand) {
-    RTC_CHECK_EQ(num_rows_, operand.num_rows_);
-    RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] -= operand.data_[i];
-    }
-
-    return *this;
-  }
-
-  Matrix& Subtract(const Matrix& lhs, const Matrix& rhs) {
-    CopyFrom(lhs);
-    return Subtract(rhs);
-  }
-
-  Matrix& PointwiseMultiply(const Matrix& operand) {
-    RTC_CHECK_EQ(num_rows_, operand.num_rows_);
-    RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] *= operand.data_[i];
-    }
-
-    return *this;
-  }
-
-  Matrix& PointwiseMultiply(const Matrix& lhs, const Matrix& rhs) {
-    CopyFrom(lhs);
-    return PointwiseMultiply(rhs);
-  }
-
-  Matrix& PointwiseDivide(const Matrix& operand) {
-    RTC_CHECK_EQ(num_rows_, operand.num_rows_);
-    RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] /= operand.data_[i];
-    }
-
-    return *this;
-  }
-
-  Matrix& PointwiseDivide(const Matrix& lhs, const Matrix& rhs) {
-    CopyFrom(lhs);
-    return PointwiseDivide(rhs);
-  }
-
-  Matrix& PointwiseSquareRoot() {
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] = sqrt_wrapper(data_[i]);
-    }
-
-    return *this;
-  }
-
-  Matrix& PointwiseSquareRoot(const Matrix& operand) {
-    CopyFrom(operand);
-    return PointwiseSquareRoot();
-  }
-
-  Matrix& PointwiseAbsoluteValue() {
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] = abs(data_[i]);
-    }
-
-    return *this;
-  }
-
-  Matrix& PointwiseAbsoluteValue(const Matrix& operand) {
-    CopyFrom(operand);
-    return PointwiseAbsoluteValue();
-  }
-
-  Matrix& PointwiseSquare() {
-    for (size_t i = 0; i < data_.size(); ++i) {
-      data_[i] *= data_[i];
-    }
-
-    return *this;
-  }
-
-  Matrix& PointwiseSquare(const Matrix& operand) {
-    CopyFrom(operand);
-    return PointwiseSquare();
-  }
-
-  Matrix& Multiply(const Matrix& lhs, const Matrix& rhs) {
-    RTC_CHECK_EQ(lhs.num_columns_, rhs.num_rows_);
-    RTC_CHECK_EQ(num_rows_, lhs.num_rows_);
-    RTC_CHECK_EQ(num_columns_, rhs.num_columns_);
-
-    return Multiply(lhs.elements(), rhs.num_rows_, rhs.elements());
-  }
-
-  Matrix& Multiply(const Matrix& rhs) {
-    RTC_CHECK_EQ(num_columns_, rhs.num_rows_);
-
-    CopyDataToScratch();
-    Resize(num_rows_, rhs.num_columns_);
-    return Multiply(scratch_elements(), rhs.num_rows_, rhs.elements());
-  }
-
-  std::string ToString() const {
-    std::ostringstream ss;
-    ss << std::endl << "Matrix" << std::endl;
-
-    for (size_t i = 0; i < num_rows_; ++i) {
-      for (size_t j = 0; j < num_columns_; ++j) {
-        ss << elements_[i][j] << " ";
-      }
-      ss << std::endl;
-    }
-    ss << std::endl;
-
-    return ss.str();
-  }
-
- protected:
-  void SetNumRows(const size_t num_rows) { num_rows_ = num_rows; }
-  void SetNumColumns(const size_t num_columns) { num_columns_ = num_columns; }
-  T* data() { return &data_[0]; }
-  const T* data() const { return &data_[0]; }
-  const T* const* scratch_elements() const { return &scratch_elements_[0]; }
-
-  // Resize the matrix. If an increase in capacity is required, the current
-  // data is lost.
-  void Resize() {
-    size_t size = num_rows_ * num_columns_;
-    data_.resize(size);
-    elements_.resize(num_rows_);
-
-    for (size_t i = 0; i < num_rows_; ++i) {
-      elements_[i] = &data_[i * num_columns_];
-    }
-  }
-
-  // Copies data_ into scratch_data_ and updates scratch_elements_ accordingly.
-  void CopyDataToScratch() {
-    scratch_data_ = data_;
-    scratch_elements_.resize(num_rows_);
-
-    for (size_t i = 0; i < num_rows_; ++i) {
-      scratch_elements_[i] = &scratch_data_[i * num_columns_];
-    }
-  }
-
- private:
-  size_t num_rows_;
-  size_t num_columns_;
-  std::vector<T> data_;
-  std::vector<T*> elements_;
-
-  // Stores temporary copies of |data_| and |elements_| for in-place operations
-  // where referring to original data is necessary.
-  std::vector<T> scratch_data_;
-  std::vector<T*> scratch_elements_;
-
-  // Helpers for Transpose and Multiply operations that unify in-place and
-  // out-of-place solutions.
-  Matrix& Transpose(const T* const* src) {
-    for (size_t i = 0; i < num_rows_; ++i) {
-      for (size_t j = 0; j < num_columns_; ++j) {
-        elements_[i][j] = src[j][i];
-      }
-    }
-
-    return *this;
-  }
-
-  Matrix& Multiply(const T* const* lhs,
-                   size_t num_rows_rhs,
-                   const T* const* rhs) {
-    for (size_t row = 0; row < num_rows_; ++row) {
-      for (size_t col = 0; col < num_columns_; ++col) {
-        T cur_element = 0;
-        for (size_t i = 0; i < num_rows_rhs; ++i) {
-          cur_element += lhs[row][i] * rhs[i][col];
-        }
-
-        elements_[row][col] = cur_element;
-      }
-    }
-
-    return *this;
-  }
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(Matrix);
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
diff --git a/modules/audio_processing/beamformer/matrix_test_helpers.h b/modules/audio_processing/beamformer/matrix_test_helpers.h
deleted file mode 100644
index 62b4708..0000000
--- a/modules/audio_processing/beamformer/matrix_test_helpers.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
-
-#include "modules/audio_processing/beamformer/complex_matrix.h"
-#include "modules/audio_processing/beamformer/matrix.h"
-#include "test/gtest.h"
-
-namespace {
-const float kTolerance = 0.001f;
-}
-
-namespace webrtc {
-
-using std::complex;
-
-// Functions used in both matrix_unittest and complex_matrix_unittest.
-class MatrixTestHelpers {
- public:
-  template <typename T>
-  static void ValidateMatrixEquality(const Matrix<T>& expected,
-                                     const Matrix<T>& actual) {
-    EXPECT_EQ(expected.num_rows(), actual.num_rows());
-    EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
-    const T* const* expected_elements = expected.elements();
-    const T* const* actual_elements = actual.elements();
-    for (size_t i = 0; i < expected.num_rows(); ++i) {
-      for (size_t j = 0; j < expected.num_columns(); ++j) {
-        EXPECT_EQ(expected_elements[i][j], actual_elements[i][j]);
-      }
-    }
-  }
-
-  static void ValidateMatrixEqualityFloat(const Matrix<float>& expected,
-                                          const Matrix<float>& actual) {
-    EXPECT_EQ(expected.num_rows(), actual.num_rows());
-    EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
-    const float* const* expected_elements = expected.elements();
-    const float* const* actual_elements = actual.elements();
-    for (size_t i = 0; i < expected.num_rows(); ++i) {
-      for (size_t j = 0; j < expected.num_columns(); ++j) {
-        EXPECT_NEAR(expected_elements[i][j], actual_elements[i][j], kTolerance);
-      }
-    }
-  }
-
-  static void ValidateMatrixEqualityComplexFloat(
-      const Matrix<complex<float> >& expected,
-      const Matrix<complex<float> >& actual) {
-    EXPECT_EQ(expected.num_rows(), actual.num_rows());
-    EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
-    const complex<float>* const* expected_elements = expected.elements();
-    const complex<float>* const* actual_elements = actual.elements();
-    for (size_t i = 0; i < expected.num_rows(); ++i) {
-      for (size_t j = 0; j < expected.num_columns(); ++j) {
-        EXPECT_NEAR(expected_elements[i][j].real(),
-                    actual_elements[i][j].real(),
-                    kTolerance);
-        EXPECT_NEAR(expected_elements[i][j].imag(),
-                    actual_elements[i][j].imag(),
-                    kTolerance);
-      }
-    }
-  }
-
-  static void ValidateMatrixNearEqualityComplexFloat(
-      const Matrix<complex<float> >& expected,
-      const Matrix<complex<float> >& actual,
-      float tolerance) {
-    EXPECT_EQ(expected.num_rows(), actual.num_rows());
-    EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
-    const complex<float>* const* expected_elements = expected.elements();
-    const complex<float>* const* actual_elements = actual.elements();
-    for (size_t i = 0; i < expected.num_rows(); ++i) {
-      for (size_t j = 0; j < expected.num_columns(); ++j) {
-        EXPECT_NEAR(expected_elements[i][j].real(),
-                    actual_elements[i][j].real(),
-                    tolerance);
-        EXPECT_NEAR(expected_elements[i][j].imag(),
-                    actual_elements[i][j].imag(),
-                    tolerance);
-      }
-    }
-  }
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
diff --git a/modules/audio_processing/beamformer/matrix_unittest.cc b/modules/audio_processing/beamformer/matrix_unittest.cc
deleted file mode 100644
index 4badfd0..0000000
--- a/modules/audio_processing/beamformer/matrix_unittest.cc
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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.
- */
-
-#include <complex>
-
-#include "modules/audio_processing/beamformer/matrix.h"
-#include "modules/audio_processing/beamformer/matrix_test_helpers.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-
-using std::complex;
-
-TEST(MatrixTest, TestMultiplySameSize) {
-  const int kNumRows = 2;
-  const int kNumCols = 2;
-  const float kValuesLeft[kNumRows][kNumCols] = {{1.1f, 2.2f}, {3.3f, 4.4f}};
-  const float kValuesRight[kNumRows][kNumCols] = {{5.4f, 127.f},
-                                                  {4600.f, -555.f}};
-  const float kValuesExpected[kNumRows][kNumCols] = {{10125.94f, -1081.3f},
-                                                     {20257.82f, -2022.9f}};
-
-  Matrix<float> lh_mat(*kValuesLeft, kNumRows, kNumCols);
-  Matrix<float> rh_mat(*kValuesRight, kNumRows, kNumCols);
-  Matrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<float> actual_result(kNumRows, kNumCols);
-
-  actual_result.Multiply(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEquality(expected_result, actual_result);
-
-  lh_mat.Multiply(rh_mat);
-  MatrixTestHelpers::ValidateMatrixEquality(lh_mat, actual_result);
-}
-
-TEST(MatrixTest, TestMultiplyDifferentSize) {
-  const int kNumRowsLeft = 2;
-  const int kNumColsLeft = 3;
-  const int kNumRowsRight = 3;
-  const int kNumColsRight = 2;
-  const int kValuesLeft[kNumRowsLeft][kNumColsLeft] = {{35, 466, -15},
-                                                       {-3, 3422, 9}};
-  const int kValuesRight[kNumRowsRight][kNumColsRight] = {
-      {765, -42}, {0, 194}, {625, 66321}};
-  const int kValuesExpected[kNumRowsLeft][kNumColsRight] = {{17400, -905881},
-                                                            {3330, 1260883}};
-
-  Matrix<int> lh_mat(*kValuesLeft, kNumRowsLeft, kNumColsLeft);
-  Matrix<int> rh_mat(*kValuesRight, kNumRowsRight, kNumColsRight);
-  Matrix<int> expected_result(*kValuesExpected, kNumRowsLeft, kNumColsRight);
-  Matrix<int> actual_result(kNumRowsLeft, kNumColsRight);
-
-  actual_result.Multiply(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEquality(expected_result, actual_result);
-
-  lh_mat.Multiply(rh_mat);
-  MatrixTestHelpers::ValidateMatrixEquality(lh_mat, actual_result);
-}
-
-TEST(MatrixTest, TestTranspose) {
-  const int kNumInitialRows = 2;
-  const int kNumInitialCols = 4;
-  const int kNumResultRows = 4;
-  const int kNumResultCols = 2;
-  const float kValuesInitial[kNumInitialRows][kNumInitialCols] = {
-      {1.1f, 2.2f, 3.3f, 4.4f}, {5.5f, 6.6f, 7.7f, 8.8f}};
-  const float kValuesExpected[kNumResultRows][kNumResultCols] = {
-      {1.1f, 5.5f}, {2.2f, 6.6f}, {3.3f, 7.7f}, {4.4f, 8.8f}};
-
-  Matrix<float> initial_mat(*kValuesInitial, kNumInitialRows, kNumInitialCols);
-  Matrix<float> expected_result(
-      *kValuesExpected, kNumResultRows, kNumResultCols);
-  Matrix<float> actual_result(kNumResultRows, kNumResultCols);
-
-  actual_result.Transpose(initial_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(expected_result,
-                                                 actual_result);
-  initial_mat.Transpose();
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(initial_mat, actual_result);
-}
-
-TEST(MatrixTest, TestScale) {
-  const int kNumRows = 3;
-  const int kNumCols = 3;
-  const int kScaleFactor = -9;
-  const int kValuesInitial[kNumRows][kNumCols] = {
-      {1, 20, 5000}, {-3, -29, 66}, {7654, 0, -23455}};
-  const int kValuesExpected[kNumRows][kNumCols] = {
-      {-9, -180, -45000}, {27, 261, -594}, {-68886, 0, 211095}};
-
-  Matrix<int> initial_mat(*kValuesInitial, kNumRows, kNumCols);
-  Matrix<int> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<int> actual_result;
-
-  actual_result.Scale(initial_mat, kScaleFactor);
-  MatrixTestHelpers::ValidateMatrixEquality(expected_result, actual_result);
-
-  initial_mat.Scale(kScaleFactor);
-  MatrixTestHelpers::ValidateMatrixEquality(initial_mat, actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseAdd) {
-  const int kNumRows = 2;
-  const int kNumCols = 3;
-  const float kValuesLeft[kNumRows][kNumCols] = {{1.1f, 210.45f, -549.2f},
-                                                 {11.876f, 586.7f, -64.35f}};
-  const float kValuesRight[kNumRows][kNumCols] = {{-50.4f, 1.f, 0.5f},
-                                                  {460.f, -554.2f, 4566.f}};
-  const float kValuesExpected[kNumRows][kNumCols] = {
-      {-49.3f, 211.45f, -548.7f}, {471.876f, 32.5f, 4501.65f}};
-
-  Matrix<float> lh_mat(*kValuesLeft, kNumRows, kNumCols);
-  Matrix<float> rh_mat(*kValuesRight, kNumRows, kNumCols);
-  Matrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<float> actual_result;
-
-  actual_result.Add(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(expected_result,
-                                                 actual_result);
-  lh_mat.Add(rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(lh_mat, actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseSubtract) {
-  const int kNumRows = 3;
-  const int kNumCols = 2;
-  const float kValuesLeft[kNumRows][kNumCols] = {
-      {1.1f, 210.45f}, {-549.2f, 11.876f}, {586.7f, -64.35f}};
-  const float kValuesRight[kNumRows][kNumCols] = {
-      {-50.4f, 1.f}, {0.5f, 460.f}, {-554.2f, 4566.f}};
-  const float kValuesExpected[kNumRows][kNumCols] = {
-      {51.5f, 209.45f}, {-549.7f, -448.124f}, {1140.9f, -4630.35f}};
-
-  Matrix<float> lh_mat(*kValuesLeft, kNumRows, kNumCols);
-  Matrix<float> rh_mat(*kValuesRight, kNumRows, kNumCols);
-  Matrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<float> actual_result;
-
-  actual_result.Subtract(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(expected_result,
-                                                 actual_result);
-
-  lh_mat.Subtract(rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(lh_mat, actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseMultiply) {
-  const int kNumRows = 1;
-  const int kNumCols = 5;
-  const float kValuesLeft[kNumRows][kNumCols] = {
-      {1.1f, 6.4f, 0.f, -1.f, -88.3f}};
-  const float kValuesRight[kNumRows][kNumCols] = {
-      {53.2f, -210.45f, -549.2f, 99.99f, -45.2f}};
-  const float kValuesExpected[kNumRows][kNumCols] = {
-      {58.52f, -1346.88f, 0.f, -99.99f, 3991.16f}};
-
-  Matrix<float> lh_mat(*kValuesLeft, kNumRows, kNumCols);
-  Matrix<float> rh_mat(*kValuesRight, kNumRows, kNumCols);
-  Matrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<float> actual_result;
-
-  actual_result.PointwiseMultiply(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(expected_result,
-                                                 actual_result);
-
-  lh_mat.PointwiseMultiply(rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(lh_mat, actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseDivide) {
-  const int kNumRows = 5;
-  const int kNumCols = 1;
-  const float kValuesLeft[kNumRows][kNumCols] = {
-      {1.1f}, {6.4f}, {0.f}, {-1.f}, {-88.3f}};
-  const float kValuesRight[kNumRows][kNumCols] = {
-      {53.2f}, {-210.45f}, {-549.2f}, {99.99f}, {-45.2f}};
-  const float kValuesExpected[kNumRows][kNumCols] = {
-      {0.020676691f}, {-0.03041102399f}, {0.f}, {-0.010001f}, {1.9535398f}};
-
-  Matrix<float> lh_mat(*kValuesLeft, kNumRows, kNumCols);
-  Matrix<float> rh_mat(*kValuesRight, kNumRows, kNumCols);
-  Matrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<float> actual_result;
-
-  actual_result.PointwiseDivide(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(expected_result,
-                                                 actual_result);
-
-  lh_mat.PointwiseDivide(rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(lh_mat, actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseSquareRoot) {
-  const int kNumRows = 2;
-  const int kNumCols = 2;
-  const int kValues[kNumRows][kNumCols] = {{4, 9}, {16, 0}};
-  const int kValuesExpected[kNumRows][kNumCols] = {{2, 3}, {4, 0}};
-
-  Matrix<int> operand_mat(*kValues, kNumRows, kNumCols);
-  Matrix<int> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<int> actual_result;
-
-  actual_result.PointwiseSquareRoot(operand_mat);
-  MatrixTestHelpers::ValidateMatrixEquality(expected_result, actual_result);
-
-  operand_mat.PointwiseSquareRoot();
-  MatrixTestHelpers::ValidateMatrixEquality(operand_mat, actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseSquareRootComplex) {
-  const int kNumRows = 1;
-  const int kNumCols = 3;
-  const complex<float> kValues[kNumRows][kNumCols] = {
-      {complex<float>(-4.f, 0), complex<float>(0, 9), complex<float>(3, -4)}};
-  const complex<float> kValuesExpected[kNumRows][kNumCols] = {
-      {complex<float>(0.f, 2.f), complex<float>(2.1213202f, 2.1213202f),
-       complex<float>(2.f, -1.f)}};
-
-  Matrix<complex<float> > operand_mat(*kValues, kNumRows, kNumCols);
-  Matrix<complex<float> > expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<complex<float> > actual_result;
-
-  actual_result.PointwiseSquareRoot(operand_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(expected_result,
-                                                        actual_result);
-
-  operand_mat.PointwiseSquareRoot();
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(operand_mat,
-                                                        actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseAbsoluteValue) {
-  const int kNumRows = 1;
-  const int kNumCols = 3;
-  const complex<float> kValues[kNumRows][kNumCols] = {
-      {complex<float>(-4.f, 0), complex<float>(0, 9), complex<float>(3, -4)}};
-  const complex<float> kValuesExpected[kNumRows][kNumCols] = {
-      {complex<float>(4.f, 0), complex<float>(9.f, 0), complex<float>(5.f, 0)}};
-
-  Matrix<complex<float> > operand_mat(*kValues, kNumRows, kNumCols);
-  Matrix<complex<float> > expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<complex<float> > actual_result;
-
-  actual_result.PointwiseAbsoluteValue(operand_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(expected_result,
-                                                        actual_result);
-
-  operand_mat.PointwiseAbsoluteValue();
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(operand_mat,
-                                                        actual_result);
-}
-
-TEST(MatrixTest, TestPointwiseSquare) {
-  const int kNumRows = 1;
-  const int kNumCols = 3;
-  const float kValues[kNumRows][kNumCols] = {{2.4f, -4.f, 3.3f}};
-  const float kValuesExpected[kNumRows][kNumCols] = {{5.76f, 16.f, 10.89f}};
-
-  Matrix<float> operand_mat(*kValues, kNumRows, kNumCols);
-  Matrix<float> expected_result(*kValuesExpected, kNumRows, kNumCols);
-  Matrix<float> actual_result;
-
-  actual_result.PointwiseSquare(operand_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(expected_result,
-                                                 actual_result);
-
-  operand_mat.PointwiseSquare();
-  MatrixTestHelpers::ValidateMatrixEqualityFloat(operand_mat, actual_result);
-}
-
-TEST(MatrixTest, TestComplexOperations) {
-  const int kNumRows = 2;
-  const int kNumCols = 2;
-
-  const complex<float> kValuesLeft[kNumRows][kNumCols] = {
-      {complex<float>(1.f, 1.f), complex<float>(2.f, 2.f)},
-      {complex<float>(3.f, 3.f), complex<float>(4.f, 4.f)}};
-
-  const complex<float> kValuesRight[kNumRows][kNumCols] = {
-      {complex<float>(5.f, 5.f), complex<float>(6.f, 6.f)},
-      {complex<float>(7.f, 7.f), complex<float>(8.f, 8.f)}};
-
-  const complex<float> kValuesExpectedAdd[kNumRows][kNumCols] = {
-      {complex<float>(6.f, 6.f), complex<float>(8.f, 8.f)},
-      {complex<float>(10.f, 10.f), complex<float>(12.f, 12.f)}};
-
-  const complex<float> kValuesExpectedMultiply[kNumRows][kNumCols] = {
-      {complex<float>(0.f, 38.f), complex<float>(0.f, 44.f)},
-      {complex<float>(0.f, 86.f), complex<float>(0.f, 100.f)}};
-
-  const complex<float> kValuesExpectedPointwiseDivide[kNumRows][kNumCols] = {
-      {complex<float>(0.2f, 0.f), complex<float>(0.33333333f, 0.f)},
-      {complex<float>(0.42857143f, 0.f), complex<float>(0.5f, 0.f)}};
-
-  Matrix<complex<float> > lh_mat(*kValuesLeft, kNumRows, kNumCols);
-  Matrix<complex<float> > rh_mat(*kValuesRight, kNumRows, kNumCols);
-  Matrix<complex<float> > expected_result_add(
-      *kValuesExpectedAdd, kNumRows, kNumCols);
-  Matrix<complex<float> > expected_result_multiply(
-      *kValuesExpectedMultiply, kNumRows, kNumCols);
-  Matrix<complex<float> > expected_result_pointwise_divide(
-      *kValuesExpectedPointwiseDivide, kNumRows, kNumCols);
-  Matrix<complex<float> > actual_result_add;
-  Matrix<complex<float> > actual_result_multiply(kNumRows, kNumCols);
-  Matrix<complex<float> > actual_result_pointwise_divide;
-
-  actual_result_add.Add(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(expected_result_add,
-                                                        actual_result_add);
-
-  actual_result_multiply.Multiply(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(
-      expected_result_multiply, actual_result_multiply);
-
-  actual_result_pointwise_divide.PointwiseDivide(lh_mat, rh_mat);
-  MatrixTestHelpers::ValidateMatrixEqualityComplexFloat(
-      expected_result_pointwise_divide, actual_result_pointwise_divide);
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/mock_nonlinear_beamformer.h b/modules/audio_processing/beamformer/mock_nonlinear_beamformer.h
deleted file mode 100644
index c4c7358..0000000
--- a/modules/audio_processing/beamformer/mock_nonlinear_beamformer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_MOCK_BEAMFORMER_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_MOCK_BEAMFORMER_H_
-
-#include <vector>
-
-#include "modules/audio_processing/beamformer/nonlinear_beamformer.h"
-#include "test/gmock.h"
-
-namespace webrtc {
-
-class MockNonlinearBeamformer : public NonlinearBeamformer {
- public:
-  MockNonlinearBeamformer(const std::vector<Point>& array_geometry,
-                          size_t num_postfilter_channels)
-      : NonlinearBeamformer(array_geometry, num_postfilter_channels) {}
-
-  MockNonlinearBeamformer(const std::vector<Point>& array_geometry)
-      : NonlinearBeamformer(array_geometry, 1u) {}
-
-  MOCK_METHOD2(Initialize, void(int chunk_size_ms, int sample_rate_hz));
-  MOCK_METHOD1(AnalyzeChunk, void(const ChannelBuffer<float>& data));
-  MOCK_METHOD1(PostFilter, void(ChannelBuffer<float>* data));
-  MOCK_METHOD1(IsInBeam, bool(const SphericalPointf& spherical_point));
-  MOCK_METHOD0(is_target_present, bool());
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_MOCK_BEAMFORMER_H_
diff --git a/modules/audio_processing/beamformer/nonlinear_beamformer.cc b/modules/audio_processing/beamformer/nonlinear_beamformer.cc
deleted file mode 100644
index 12f6d2f..0000000
--- a/modules/audio_processing/beamformer/nonlinear_beamformer.cc
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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.
- */
-
-#define _USE_MATH_DEFINES
-
-#include "modules/audio_processing/beamformer/nonlinear_beamformer.h"
-
-#include <algorithm>
-#include <cmath>
-#include <numeric>
-#include <vector>
-
-#include "common_audio/window_generator.h"
-#include "modules/audio_processing/beamformer/covariance_matrix_generator.h"
-#include "rtc_base/arraysize.h"
-
-namespace webrtc {
-namespace {
-
-// Alpha for the Kaiser Bessel Derived window.
-const float kKbdAlpha = 1.5f;
-
-const float kSpeedOfSoundMeterSeconds = 343;
-
-// The minimum separation in radians between the target direction and an
-// interferer scenario.
-const float kMinAwayRadians = 0.2f;
-
-// The separation between the target direction and the closest interferer
-// scenario is proportional to this constant.
-const float kAwaySlope = 0.008f;
-
-// When calculating the interference covariance matrix, this is the weight for
-// the weighted average between the uniform covariance matrix and the angled
-// covariance matrix.
-// Rpsi = Rpsi_angled * kBalance + Rpsi_uniform * (1 - kBalance)
-const float kBalance = 0.95f;
-
-// Alpha coefficients for mask smoothing.
-const float kMaskTimeSmoothAlpha = 0.2f;
-const float kMaskFrequencySmoothAlpha = 0.6f;
-
-// The average mask is computed from masks in this mid-frequency range. If these
-// ranges are changed |kMaskQuantile| might need to be adjusted.
-const int kLowMeanStartHz = 200;
-const int kLowMeanEndHz = 400;
-
-// Range limiter for subtractive terms in the nominator and denominator of the
-// postfilter expression. It handles the scenario mismatch between the true and
-// model sources (target and interference).
-const float kCutOffConstant = 0.9999f;
-
-// Quantile of mask values which is used to estimate target presence.
-const float kMaskQuantile = 0.7f;
-// Mask threshold over which the data is considered signal and not interference.
-// It has to be updated every time the postfilter calculation is changed
-// significantly.
-// TODO(aluebs): Write a tool to tune the target threshold automatically based
-// on files annotated with target and interference ground truth.
-const float kMaskTargetThreshold = 0.01f;
-// Time in seconds after which the data is considered interference if the mask
-// does not pass |kMaskTargetThreshold|.
-const float kHoldTargetSeconds = 0.25f;
-
-// To compensate for the attenuation this algorithm introduces to the target
-// signal. It was estimated empirically from a low-noise low-reverberation
-// recording from broadside.
-const float kCompensationGain = 2.f;
-
-// Does conjugate(|norm_mat|) * |mat| * transpose(|norm_mat|). No extra space is
-// used; to accomplish this, we compute both multiplications in the same loop.
-// The returned norm is clamped to be non-negative.
-float Norm(const ComplexMatrix<float>& mat,
-           const ComplexMatrix<float>& norm_mat) {
-  RTC_CHECK_EQ(1, norm_mat.num_rows());
-  RTC_CHECK_EQ(norm_mat.num_columns(), mat.num_rows());
-  RTC_CHECK_EQ(norm_mat.num_columns(), mat.num_columns());
-
-  complex<float> first_product = complex<float>(0.f, 0.f);
-  complex<float> second_product = complex<float>(0.f, 0.f);
-
-  const complex<float>* const* mat_els = mat.elements();
-  const complex<float>* const* norm_mat_els = norm_mat.elements();
-
-  for (size_t i = 0; i < norm_mat.num_columns(); ++i) {
-    for (size_t j = 0; j < norm_mat.num_columns(); ++j) {
-      first_product += conj(norm_mat_els[0][j]) * mat_els[j][i];
-    }
-    second_product += first_product * norm_mat_els[0][i];
-    first_product = 0.f;
-  }
-  return std::max(second_product.real(), 0.f);
-}
-
-// Does conjugate(|lhs|) * |rhs| for row vectors |lhs| and |rhs|.
-complex<float> ConjugateDotProduct(const ComplexMatrix<float>& lhs,
-                                   const ComplexMatrix<float>& rhs) {
-  RTC_CHECK_EQ(1, lhs.num_rows());
-  RTC_CHECK_EQ(1, rhs.num_rows());
-  RTC_CHECK_EQ(lhs.num_columns(), rhs.num_columns());
-
-  const complex<float>* const* lhs_elements = lhs.elements();
-  const complex<float>* const* rhs_elements = rhs.elements();
-
-  complex<float> result = complex<float>(0.f, 0.f);
-  for (size_t i = 0; i < lhs.num_columns(); ++i) {
-    result += conj(lhs_elements[0][i]) * rhs_elements[0][i];
-  }
-
-  return result;
-}
-
-// Works for positive numbers only.
-size_t Round(float x) {
-  return static_cast<size_t>(std::floor(x + 0.5f));
-}
-
-// Calculates the sum of squares of a complex matrix.
-float SumSquares(const ComplexMatrix<float>& mat) {
-  float sum_squares = 0.f;
-  const complex<float>* const* mat_els = mat.elements();
-  for (size_t i = 0; i < mat.num_rows(); ++i) {
-    for (size_t j = 0; j < mat.num_columns(); ++j) {
-      float abs_value = std::abs(mat_els[i][j]);
-      sum_squares += abs_value * abs_value;
-    }
-  }
-  return sum_squares;
-}
-
-// Does |out| = |in|.' * conj(|in|) for row vector |in|.
-void TransposedConjugatedProduct(const ComplexMatrix<float>& in,
-                                 ComplexMatrix<float>* out) {
-  RTC_CHECK_EQ(1, in.num_rows());
-  RTC_CHECK_EQ(out->num_rows(), in.num_columns());
-  RTC_CHECK_EQ(out->num_columns(), in.num_columns());
-  const complex<float>* in_elements = in.elements()[0];
-  complex<float>* const* out_elements = out->elements();
-  for (size_t i = 0; i < out->num_rows(); ++i) {
-    for (size_t j = 0; j < out->num_columns(); ++j) {
-      out_elements[i][j] = in_elements[i] * conj(in_elements[j]);
-    }
-  }
-}
-
-std::vector<Point> GetCenteredArray(std::vector<Point> array_geometry) {
-  for (size_t dim = 0; dim < 3; ++dim) {
-    float center = 0.f;
-    for (size_t i = 0; i < array_geometry.size(); ++i) {
-      center += array_geometry[i].c[dim];
-    }
-    center /= array_geometry.size();
-    for (size_t i = 0; i < array_geometry.size(); ++i) {
-      array_geometry[i].c[dim] -= center;
-    }
-  }
-  return array_geometry;
-}
-
-}  // namespace
-
-const float NonlinearBeamformer::kHalfBeamWidthRadians = DegreesToRadians(20.f);
-
-// static
-const size_t NonlinearBeamformer::kNumFreqBins;
-
-PostFilterTransform::PostFilterTransform(size_t num_channels,
-                                         size_t chunk_length,
-                                         float* window,
-                                         size_t fft_size)
-    : transform_(num_channels,
-                 num_channels,
-                 chunk_length,
-                 window,
-                 fft_size,
-                 fft_size / 2,
-                 this),
-      num_freq_bins_(fft_size / 2 + 1) {}
-
-void PostFilterTransform::ProcessChunk(float* const* data, float* final_mask) {
-  final_mask_ = final_mask;
-  transform_.ProcessChunk(data, data);
-}
-
-void PostFilterTransform::ProcessAudioBlock(const complex<float>* const* input,
-                                            size_t num_input_channels,
-                                            size_t num_freq_bins,
-                                            size_t num_output_channels,
-                                            complex<float>* const* output) {
-  RTC_DCHECK_EQ(num_freq_bins_, num_freq_bins);
-  RTC_DCHECK_EQ(num_input_channels, num_output_channels);
-
-  for (size_t ch = 0; ch < num_input_channels; ++ch) {
-    for (size_t f_ix = 0; f_ix < num_freq_bins_; ++f_ix) {
-      output[ch][f_ix] =
-          kCompensationGain * final_mask_[f_ix] * input[ch][f_ix];
-    }
-  }
-}
-
-NonlinearBeamformer::NonlinearBeamformer(
-    const std::vector<Point>& array_geometry,
-    size_t num_postfilter_channels,
-    SphericalPointf target_direction)
-    : num_input_channels_(array_geometry.size()),
-      num_postfilter_channels_(num_postfilter_channels),
-      array_geometry_(GetCenteredArray(array_geometry)),
-      array_normal_(GetArrayNormalIfExists(array_geometry)),
-      min_mic_spacing_(GetMinimumSpacing(array_geometry)),
-      target_angle_radians_(target_direction.azimuth()),
-      away_radians_(std::min(
-          static_cast<float>(M_PI),
-          std::max(kMinAwayRadians,
-                   kAwaySlope * static_cast<float>(M_PI) / min_mic_spacing_))) {
-  WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_);
-}
-
-NonlinearBeamformer::~NonlinearBeamformer() = default;
-
-void NonlinearBeamformer::Initialize(int chunk_size_ms, int sample_rate_hz) {
-  chunk_length_ =
-      static_cast<size_t>(sample_rate_hz / (1000.f / chunk_size_ms));
-  sample_rate_hz_ = sample_rate_hz;
-
-  high_pass_postfilter_mask_ = 1.f;
-  is_target_present_ = false;
-  hold_target_blocks_ = kHoldTargetSeconds * 2 * sample_rate_hz / kFftSize;
-  interference_blocks_count_ = hold_target_blocks_;
-
-  process_transform_.reset(new LappedTransform(num_input_channels_,
-                                               0u,
-                                               chunk_length_,
-                                               window_,
-                                               kFftSize,
-                                               kFftSize / 2,
-                                               this));
-  postfilter_transform_.reset(new PostFilterTransform(
-      num_postfilter_channels_, chunk_length_, window_, kFftSize));
-  const float wave_number_step =
-      (2.f * M_PI * sample_rate_hz_) / (kFftSize * kSpeedOfSoundMeterSeconds);
-  for (size_t i = 0; i < kNumFreqBins; ++i) {
-    time_smooth_mask_[i] = 1.f;
-    final_mask_[i] = 1.f;
-    wave_numbers_[i] = i * wave_number_step;
-  }
-
-  InitLowFrequencyCorrectionRanges();
-  InitDiffuseCovMats();
-  AimAt(SphericalPointf(target_angle_radians_, 0.f, 1.f));
-}
-
-// These bin indexes determine the regions over which a mean is taken. This is
-// applied as a constant value over the adjacent end "frequency correction"
-// regions.
-//
-//             low_mean_start_bin_     high_mean_start_bin_
-//                   v                         v              constant
-// |----------------|--------|----------------|-------|----------------|
-//   constant               ^                        ^
-//             low_mean_end_bin_       high_mean_end_bin_
-//
-void NonlinearBeamformer::InitLowFrequencyCorrectionRanges() {
-  low_mean_start_bin_ = Round(static_cast<float>(kLowMeanStartHz) *
-                                  kFftSize / sample_rate_hz_);
-  low_mean_end_bin_ = Round(static_cast<float>(kLowMeanEndHz) *
-                                  kFftSize / sample_rate_hz_);
-
-  RTC_DCHECK_GT(low_mean_start_bin_, 0U);
-  RTC_DCHECK_LT(low_mean_start_bin_, low_mean_end_bin_);
-}
-
-void NonlinearBeamformer::InitHighFrequencyCorrectionRanges() {
-  const float kAliasingFreqHz =
-      kSpeedOfSoundMeterSeconds /
-      (min_mic_spacing_ * (1.f + std::abs(std::cos(target_angle_radians_))));
-  const float kHighMeanStartHz = std::min(0.5f *  kAliasingFreqHz,
-                                          sample_rate_hz_ / 2.f);
-  const float kHighMeanEndHz = std::min(0.75f *  kAliasingFreqHz,
-                                        sample_rate_hz_ / 2.f);
-  high_mean_start_bin_ = Round(kHighMeanStartHz * kFftSize / sample_rate_hz_);
-  high_mean_end_bin_ = Round(kHighMeanEndHz * kFftSize / sample_rate_hz_);
-
-  RTC_DCHECK_LT(low_mean_end_bin_, high_mean_end_bin_);
-  RTC_DCHECK_LT(high_mean_start_bin_, high_mean_end_bin_);
-  RTC_DCHECK_LT(high_mean_end_bin_, kNumFreqBins - 1);
-}
-
-void NonlinearBeamformer::InitInterfAngles() {
-  interf_angles_radians_.clear();
-  const Point target_direction = AzimuthToPoint(target_angle_radians_);
-  const Point clockwise_interf_direction =
-      AzimuthToPoint(target_angle_radians_ - away_radians_);
-  if (!array_normal_ ||
-      DotProduct(*array_normal_, target_direction) *
-              DotProduct(*array_normal_, clockwise_interf_direction) >=
-          0.f) {
-    // The target and clockwise interferer are in the same half-plane defined
-    // by the array.
-    interf_angles_radians_.push_back(target_angle_radians_ - away_radians_);
-  } else {
-    // Otherwise, the interferer will begin reflecting back at the target.
-    // Instead rotate it away 180 degrees.
-    interf_angles_radians_.push_back(target_angle_radians_ - away_radians_ +
-                                     M_PI);
-  }
-  const Point counterclock_interf_direction =
-      AzimuthToPoint(target_angle_radians_ + away_radians_);
-  if (!array_normal_ ||
-      DotProduct(*array_normal_, target_direction) *
-              DotProduct(*array_normal_, counterclock_interf_direction) >=
-          0.f) {
-    // The target and counter-clockwise interferer are in the same half-plane
-    // defined by the array.
-    interf_angles_radians_.push_back(target_angle_radians_ + away_radians_);
-  } else {
-    // Otherwise, the interferer will begin reflecting back at the target.
-    // Instead rotate it away 180 degrees.
-    interf_angles_radians_.push_back(target_angle_radians_ + away_radians_ -
-                                     M_PI);
-  }
-}
-
-void NonlinearBeamformer::InitDelaySumMasks() {
-  for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
-    delay_sum_masks_[f_ix].Resize(1, num_input_channels_);
-    CovarianceMatrixGenerator::PhaseAlignmentMasks(
-        f_ix, kFftSize, sample_rate_hz_, kSpeedOfSoundMeterSeconds,
-        array_geometry_, target_angle_radians_, &delay_sum_masks_[f_ix]);
-
-    complex_f norm_factor = sqrt(
-        ConjugateDotProduct(delay_sum_masks_[f_ix], delay_sum_masks_[f_ix]));
-    delay_sum_masks_[f_ix].Scale(1.f / norm_factor);
-  }
-}
-
-void NonlinearBeamformer::InitTargetCovMats() {
-  for (size_t i = 0; i < kNumFreqBins; ++i) {
-    target_cov_mats_[i].Resize(num_input_channels_, num_input_channels_);
-    TransposedConjugatedProduct(delay_sum_masks_[i], &target_cov_mats_[i]);
-  }
-}
-
-void NonlinearBeamformer::InitDiffuseCovMats() {
-  for (size_t i = 0; i < kNumFreqBins; ++i) {
-    uniform_cov_mat_[i].Resize(num_input_channels_, num_input_channels_);
-    CovarianceMatrixGenerator::UniformCovarianceMatrix(
-        wave_numbers_[i], array_geometry_, &uniform_cov_mat_[i]);
-    complex_f normalization_factor = uniform_cov_mat_[i].elements()[0][0];
-    uniform_cov_mat_[i].Scale(1.f / normalization_factor);
-    uniform_cov_mat_[i].Scale(1 - kBalance);
-  }
-}
-
-void NonlinearBeamformer::InitInterfCovMats() {
-  for (size_t i = 0; i < kNumFreqBins; ++i) {
-    interf_cov_mats_[i].clear();
-    for (size_t j = 0; j < interf_angles_radians_.size(); ++j) {
-      interf_cov_mats_[i].push_back(std::unique_ptr<ComplexMatrixF>(
-          new ComplexMatrixF(num_input_channels_, num_input_channels_)));
-      ComplexMatrixF angled_cov_mat(num_input_channels_, num_input_channels_);
-      CovarianceMatrixGenerator::AngledCovarianceMatrix(
-          kSpeedOfSoundMeterSeconds,
-          interf_angles_radians_[j],
-          i,
-          kFftSize,
-          kNumFreqBins,
-          sample_rate_hz_,
-          array_geometry_,
-          &angled_cov_mat);
-      // Normalize matrices before averaging them.
-      complex_f normalization_factor = angled_cov_mat.elements()[0][0];
-      angled_cov_mat.Scale(1.f / normalization_factor);
-      // Weighted average of matrices.
-      angled_cov_mat.Scale(kBalance);
-      interf_cov_mats_[i][j]->Add(uniform_cov_mat_[i], angled_cov_mat);
-    }
-  }
-}
-
-void NonlinearBeamformer::NormalizeCovMats() {
-  for (size_t i = 0; i < kNumFreqBins; ++i) {
-    rxiws_[i] = Norm(target_cov_mats_[i], delay_sum_masks_[i]);
-    rpsiws_[i].clear();
-    for (size_t j = 0; j < interf_angles_radians_.size(); ++j) {
-      rpsiws_[i].push_back(Norm(*interf_cov_mats_[i][j], delay_sum_masks_[i]));
-    }
-  }
-}
-
-void NonlinearBeamformer::AnalyzeChunk(const ChannelBuffer<float>& data) {
-  RTC_DCHECK_EQ(data.num_channels(), num_input_channels_);
-  RTC_DCHECK_EQ(data.num_frames_per_band(), chunk_length_);
-
-  old_high_pass_mask_ = high_pass_postfilter_mask_;
-  process_transform_->ProcessChunk(data.channels(0), nullptr);
-}
-
-void NonlinearBeamformer::PostFilter(ChannelBuffer<float>* data) {
-  RTC_DCHECK_EQ(data->num_frames_per_band(), chunk_length_);
-  // TODO(aluebs): Change to RTC_CHECK_EQ once the ChannelBuffer is updated.
-  RTC_DCHECK_GE(data->num_channels(), num_postfilter_channels_);
-
-  postfilter_transform_->ProcessChunk(data->channels(0), final_mask_);
-
-  // Ramp up/down for smoothing is needed in order to avoid discontinuities in
-  // the transitions between 10 ms frames.
-  const float ramp_increment =
-      (high_pass_postfilter_mask_ - old_high_pass_mask_) /
-      data->num_frames_per_band();
-  for (size_t i = 1; i < data->num_bands(); ++i) {
-    float smoothed_mask = old_high_pass_mask_;
-    for (size_t j = 0; j < data->num_frames_per_band(); ++j) {
-      smoothed_mask += ramp_increment;
-      for (size_t k = 0; k < num_postfilter_channels_; ++k) {
-        data->channels(i)[k][j] *= smoothed_mask;
-      }
-    }
-  }
-}
-
-void NonlinearBeamformer::AimAt(const SphericalPointf& target_direction) {
-  target_angle_radians_ = target_direction.azimuth();
-  InitHighFrequencyCorrectionRanges();
-  InitInterfAngles();
-  InitDelaySumMasks();
-  InitTargetCovMats();
-  InitInterfCovMats();
-  NormalizeCovMats();
-}
-
-bool NonlinearBeamformer::IsInBeam(const SphericalPointf& spherical_point) {
-  // If more than half-beamwidth degrees away from the beam's center,
-  // you are out of the beam.
-  return fabs(spherical_point.azimuth() - target_angle_radians_) <
-         kHalfBeamWidthRadians;
-}
-
-bool NonlinearBeamformer::is_target_present() { return is_target_present_; }
-
-void NonlinearBeamformer::ProcessAudioBlock(const complex_f* const* input,
-                                            size_t num_input_channels,
-                                            size_t num_freq_bins,
-                                            size_t num_output_channels,
-                                            complex_f* const* output) {
-  RTC_CHECK_EQ(kNumFreqBins, num_freq_bins);
-  RTC_CHECK_EQ(num_input_channels_, num_input_channels);
-  RTC_CHECK_EQ(0, num_output_channels);
-
-  // Calculating the post-filter masks. Note that we need two for each
-  // frequency bin to account for the positive and negative interferer
-  // angle.
-  for (size_t i = low_mean_start_bin_; i <= high_mean_end_bin_; ++i) {
-    eig_m_.CopyFromColumn(input, i, num_input_channels_);
-    float eig_m_norm_factor = std::sqrt(SumSquares(eig_m_));
-    if (eig_m_norm_factor != 0.f) {
-      eig_m_.Scale(1.f / eig_m_norm_factor);
-    }
-
-    float rxim = Norm(target_cov_mats_[i], eig_m_);
-    float ratio_rxiw_rxim = 0.f;
-    if (rxim > 0.f) {
-      ratio_rxiw_rxim = rxiws_[i] / rxim;
-    }
-
-    complex_f rmw = abs(ConjugateDotProduct(delay_sum_masks_[i], eig_m_));
-    rmw *= rmw;
-    float rmw_r = rmw.real();
-
-    new_mask_[i] = CalculatePostfilterMask(*interf_cov_mats_[i][0],
-                                           rpsiws_[i][0],
-                                           ratio_rxiw_rxim,
-                                           rmw_r);
-    for (size_t j = 1; j < interf_angles_radians_.size(); ++j) {
-      float tmp_mask = CalculatePostfilterMask(*interf_cov_mats_[i][j],
-                                               rpsiws_[i][j],
-                                               ratio_rxiw_rxim,
-                                               rmw_r);
-      if (tmp_mask < new_mask_[i]) {
-        new_mask_[i] = tmp_mask;
-      }
-    }
-  }
-
-  ApplyMaskTimeSmoothing();
-  EstimateTargetPresence();
-  ApplyLowFrequencyCorrection();
-  ApplyHighFrequencyCorrection();
-  ApplyMaskFrequencySmoothing();
-}
-
-float NonlinearBeamformer::CalculatePostfilterMask(
-    const ComplexMatrixF& interf_cov_mat,
-    float rpsiw,
-    float ratio_rxiw_rxim,
-    float rmw_r) {
-  float rpsim = Norm(interf_cov_mat, eig_m_);
-
-  float ratio = 0.f;
-  if (rpsim > 0.f) {
-    ratio = rpsiw / rpsim;
-  }
-
-  float numerator = 1.f - kCutOffConstant;
-  if (rmw_r > 0.f) {
-    numerator = 1.f - std::min(kCutOffConstant, ratio / rmw_r);
-  }
-
-  float denominator = 1.f - kCutOffConstant;
-  if (ratio_rxiw_rxim > 0.f) {
-    denominator = 1.f - std::min(kCutOffConstant, ratio / ratio_rxiw_rxim);
-  }
-
-  return numerator / denominator;
-}
-
-// Smooth new_mask_ into time_smooth_mask_.
-void NonlinearBeamformer::ApplyMaskTimeSmoothing() {
-  for (size_t i = low_mean_start_bin_; i <= high_mean_end_bin_; ++i) {
-    time_smooth_mask_[i] = kMaskTimeSmoothAlpha * new_mask_[i] +
-                           (1 - kMaskTimeSmoothAlpha) * time_smooth_mask_[i];
-  }
-}
-
-// Copy time_smooth_mask_ to final_mask_ and smooth over frequency.
-void NonlinearBeamformer::ApplyMaskFrequencySmoothing() {
-  // Smooth over frequency in both directions. The "frequency correction"
-  // regions have constant value, but we enter them to smooth over the jump
-  // that exists at the boundary. However, this does mean when smoothing "away"
-  // from the region that we only need to use the last element.
-  //
-  // Upward smoothing:
-  //   low_mean_start_bin_
-  //         v
-  // |------|------------|------|
-  //       ^------------------>^
-  //
-  // Downward smoothing:
-  //         high_mean_end_bin_
-  //                    v
-  // |------|------------|------|
-  //  ^<------------------^
-  std::copy(time_smooth_mask_, time_smooth_mask_ + kNumFreqBins, final_mask_);
-  for (size_t i = low_mean_start_bin_; i < kNumFreqBins; ++i) {
-    final_mask_[i] = kMaskFrequencySmoothAlpha * final_mask_[i] +
-                     (1 - kMaskFrequencySmoothAlpha) * final_mask_[i - 1];
-  }
-  for (size_t i = high_mean_end_bin_ + 1; i > 0; --i) {
-    final_mask_[i - 1] = kMaskFrequencySmoothAlpha * final_mask_[i - 1] +
-                         (1 - kMaskFrequencySmoothAlpha) * final_mask_[i];
-  }
-}
-
-// Apply low frequency correction to time_smooth_mask_.
-void NonlinearBeamformer::ApplyLowFrequencyCorrection() {
-  const float low_frequency_mask =
-      MaskRangeMean(low_mean_start_bin_, low_mean_end_bin_ + 1);
-  std::fill(time_smooth_mask_, time_smooth_mask_ + low_mean_start_bin_,
-            low_frequency_mask);
-}
-
-// Apply high frequency correction to time_smooth_mask_. Update
-// high_pass_postfilter_mask_ to use for the high frequency time-domain bands.
-void NonlinearBeamformer::ApplyHighFrequencyCorrection() {
-  high_pass_postfilter_mask_ =
-      MaskRangeMean(high_mean_start_bin_, high_mean_end_bin_ + 1);
-  std::fill(time_smooth_mask_ + high_mean_end_bin_ + 1,
-            time_smooth_mask_ + kNumFreqBins, high_pass_postfilter_mask_);
-}
-
-// Compute mean over the given range of time_smooth_mask_, [first, last).
-float NonlinearBeamformer::MaskRangeMean(size_t first, size_t last) {
-  RTC_DCHECK_GT(last, first);
-  const float sum = std::accumulate(time_smooth_mask_ + first,
-                                    time_smooth_mask_ + last, 0.f);
-  return sum / (last - first);
-}
-
-void NonlinearBeamformer::EstimateTargetPresence() {
-  const size_t quantile = static_cast<size_t>(
-      (high_mean_end_bin_ - low_mean_start_bin_) * kMaskQuantile +
-      low_mean_start_bin_);
-  std::nth_element(new_mask_ + low_mean_start_bin_, new_mask_ + quantile,
-                   new_mask_ + high_mean_end_bin_ + 1);
-  if (new_mask_[quantile] > kMaskTargetThreshold) {
-    is_target_present_ = true;
-    interference_blocks_count_ = 0;
-  } else {
-    is_target_present_ = interference_blocks_count_++ < hold_target_blocks_;
-  }
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/beamformer/nonlinear_beamformer.h b/modules/audio_processing/beamformer/nonlinear_beamformer.h
deleted file mode 100644
index 5b79dc4..0000000
--- a/modules/audio_processing/beamformer/nonlinear_beamformer.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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 MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
-#define MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
-
-// MSVC++ requires this to be set before any other includes to get M_PI.
-#ifndef _USE_MATH_DEFINES
-#define _USE_MATH_DEFINES
-#endif
-
-#include <math.h>
-
-#include <memory>
-#include <vector>
-
-#include "common_audio/lapped_transform.h"
-#include "common_audio/channel_buffer.h"
-#include "modules/audio_processing/beamformer/array_util.h"
-#include "modules/audio_processing/beamformer/complex_matrix.h"
-
-namespace webrtc {
-
-class PostFilterTransform : public LappedTransform::Callback {
- public:
-  PostFilterTransform(size_t num_channels,
-                      size_t chunk_length,
-                      float* window,
-                      size_t fft_size);
-
-  void ProcessChunk(float* const* data, float* final_mask);
-
- protected:
-  void ProcessAudioBlock(const complex<float>* const* input,
-                         size_t num_input_channels,
-                         size_t num_freq_bins,
-                         size_t num_output_channels,
-                         complex<float>* const* output) override;
-
- private:
-  LappedTransform transform_;
-  const size_t num_freq_bins_;
-  float* final_mask_;
-};
-
-// Enhances sound sources coming directly in front of a uniform linear array
-// and suppresses sound sources coming from all other directions. Operates on
-// multichannel signals and produces single-channel output.
-//
-// The implemented nonlinear postfilter algorithm taken from "A Robust Nonlinear
-// Beamforming Postprocessor" by Bastiaan Kleijn.
-class NonlinearBeamformer : public LappedTransform::Callback {
- public:
-  static const float kHalfBeamWidthRadians;
-
-  explicit NonlinearBeamformer(
-      const std::vector<Point>& array_geometry,
-      size_t num_postfilter_channels = 1u,
-      SphericalPointf target_direction =
-          SphericalPointf(static_cast<float>(M_PI) / 2.f, 0.f, 1.f));
-  ~NonlinearBeamformer() override;
-
-  // Sample rate corresponds to the lower band.
-  // Needs to be called before the NonlinearBeamformer can be used.
-  virtual void Initialize(int chunk_size_ms, int sample_rate_hz);
-
-  // Analyzes one time-domain chunk of audio. The audio is expected to be split
-  // into frequency bands inside the ChannelBuffer. The number of frames and
-  // channels must correspond to the constructor parameters.
-  virtual void AnalyzeChunk(const ChannelBuffer<float>& data);
-
-  // Applies the postfilter mask to one chunk of audio. The audio is expected to
-  // be split into frequency bands inside the ChannelBuffer. The number of
-  // frames and channels must correspond to the constructor parameters.
-  virtual void PostFilter(ChannelBuffer<float>* data);
-
-  virtual void AimAt(const SphericalPointf& target_direction);
-
-  virtual bool IsInBeam(const SphericalPointf& spherical_point);
-
-  // After processing each block |is_target_present_| is set to true if the
-  // target signal es present and to false otherwise. This methods can be called
-  // to know if the data is target signal or interference and process it
-  // accordingly.
-  virtual bool is_target_present();
-
- protected:
-  // Process one frequency-domain block of audio. This is where the fun
-  // happens. Implements LappedTransform::Callback.
-  void ProcessAudioBlock(const complex<float>* const* input,
-                         size_t num_input_channels,
-                         size_t num_freq_bins,
-                         size_t num_output_channels,
-                         complex<float>* const* output) override;
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(NonlinearBeamformerTest,
-                           InterfAnglesTakeAmbiguityIntoAccount);
-
-  typedef Matrix<float> MatrixF;
-  typedef ComplexMatrix<float> ComplexMatrixF;
-  typedef complex<float> complex_f;
-
-  void InitLowFrequencyCorrectionRanges();
-  void InitHighFrequencyCorrectionRanges();
-  void InitInterfAngles();
-  void InitDelaySumMasks();
-  void InitTargetCovMats();
-  void InitDiffuseCovMats();
-  void InitInterfCovMats();
-  void NormalizeCovMats();
-
-  // Calculates postfilter masks that minimize the mean squared error of our
-  // estimation of the desired signal.
-  float CalculatePostfilterMask(const ComplexMatrixF& interf_cov_mat,
-                                float rpsiw,
-                                float ratio_rxiw_rxim,
-                                float rmxi_r);
-
-  // Prevents the postfilter masks from degenerating too quickly (a cause of
-  // musical noise).
-  void ApplyMaskTimeSmoothing();
-  void ApplyMaskFrequencySmoothing();
-
-  // The postfilter masks are unreliable at low frequencies. Calculates a better
-  // mask by averaging mid-low frequency values.
-  void ApplyLowFrequencyCorrection();
-
-  // Postfilter masks are also unreliable at high frequencies. Average mid-high
-  // frequency masks to calculate a single mask per block which can be applied
-  // in the time-domain. Further, we average these block-masks over a chunk,
-  // resulting in one postfilter mask per audio chunk. This allows us to skip
-  // both transforming and blocking the high-frequency signal.
-  void ApplyHighFrequencyCorrection();
-
-  // Compute the means needed for the above frequency correction.
-  float MaskRangeMean(size_t start_bin, size_t end_bin);
-
-  // Applies post-filter mask to |input| and store in |output|.
-  void ApplyPostFilter(const complex_f* input, complex_f* output);
-
-  void EstimateTargetPresence();
-
-  static const size_t kFftSize = 256;
-  static const size_t kNumFreqBins = kFftSize / 2 + 1;
-
-  // Deals with the fft transform and blocking.
-  size_t chunk_length_;
-  std::unique_ptr<LappedTransform> process_transform_;
-  std::unique_ptr<PostFilterTransform> postfilter_transform_;
-  float window_[kFftSize];
-
-  // Parameters exposed to the user.
-  const size_t num_input_channels_;
-  const size_t num_postfilter_channels_;
-  int sample_rate_hz_;
-
-  const std::vector<Point> array_geometry_;
-  // The normal direction of the array if it has one and it is in the xy-plane.
-  const rtc::Optional<Point> array_normal_;
-
-  // Minimum spacing between microphone pairs.
-  const float min_mic_spacing_;
-
-  // Calculated based on user-input and constants in the .cc file.
-  size_t low_mean_start_bin_;
-  size_t low_mean_end_bin_;
-  size_t high_mean_start_bin_;
-  size_t high_mean_end_bin_;
-
-  // Quickly varying mask updated every block.
-  float new_mask_[kNumFreqBins];
-  // Time smoothed mask.
-  float time_smooth_mask_[kNumFreqBins];
-  // Time and frequency smoothed mask.
-  float final_mask_[kNumFreqBins];
-
-  float target_angle_radians_;
-  // Angles of the interferer scenarios.
-  std::vector<float> interf_angles_radians_;
-  // The angle between the target and the interferer scenarios.
-  const float away_radians_;
-
-  // Array of length |kNumFreqBins|, Matrix of size |1| x |num_channels_|.
-  ComplexMatrixF delay_sum_masks_[kNumFreqBins];
-
-  // Arrays of length |kNumFreqBins|, Matrix of size |num_input_channels_| x
-  // |num_input_channels_|.
-  ComplexMatrixF target_cov_mats_[kNumFreqBins];
-  ComplexMatrixF uniform_cov_mat_[kNumFreqBins];
-  // Array of length |kNumFreqBins|, Matrix of size |num_input_channels_| x
-  // |num_input_channels_|. The vector has a size equal to the number of
-  // interferer scenarios.
-  std::vector<std::unique_ptr<ComplexMatrixF>> interf_cov_mats_[kNumFreqBins];
-
-  // Of length |kNumFreqBins|.
-  float wave_numbers_[kNumFreqBins];
-
-  // Preallocated for ProcessAudioBlock()
-  // Of length |kNumFreqBins|.
-  float rxiws_[kNumFreqBins];
-  // The vector has a size equal to the number of interferer scenarios.
-  std::vector<float> rpsiws_[kNumFreqBins];
-
-  // The microphone normalization factor.
-  ComplexMatrixF eig_m_;
-
-  // For processing the high-frequency input signal.
-  float high_pass_postfilter_mask_;
-  float old_high_pass_mask_;
-
-  // True when the target signal is present.
-  bool is_target_present_;
-  // Number of blocks after which the data is considered interference if the
-  // mask does not pass |kMaskSignalThreshold|.
-  size_t hold_target_blocks_;
-  // Number of blocks since the last mask that passed |kMaskSignalThreshold|.
-  size_t interference_blocks_count_;
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
diff --git a/modules/audio_processing/beamformer/nonlinear_beamformer_test.cc b/modules/audio_processing/beamformer/nonlinear_beamformer_test.cc
deleted file mode 100644
index 296cd6d..0000000
--- a/modules/audio_processing/beamformer/nonlinear_beamformer_test.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC 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.
- */
-
-#include <vector>
-
-#include "common_audio/channel_buffer.h"
-#include "common_audio/wav_file.h"
-#include "modules/audio_processing/beamformer/nonlinear_beamformer.h"
-#include "modules/audio_processing/test/test_utils.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/flags.h"
-#include "rtc_base/format_macros.h"
-
-DEFINE_string(i, "", "The name of the input file to read from.");
-DEFINE_string(o, "out.wav", "Name of the output file to write to.");
-DEFINE_string(mic_positions, "",
-    "Space delimited cartesian coordinates of microphones in meters. "
-    "The coordinates of each point are contiguous. "
-    "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
-DEFINE_bool(help, false, "Prints this message.");
-
-namespace webrtc {
-namespace {
-
-const int kChunksPerSecond = 100;
-const int kChunkSizeMs = 1000 / kChunksPerSecond;
-
-const char kUsage[] =
-    "Command-line tool to run beamforming on WAV files. The signal is passed\n"
-    "in as a single band, unlike the audio processing interface which splits\n"
-    "signals into multiple bands.\n";
-
-}  // namespace
-
-int main(int argc, char* argv[]) {
-  if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) ||
-      FLAG_help || argc != 1) {
-    printf("%s", kUsage);
-    if (FLAG_help) {
-      rtc::FlagList::Print(nullptr, false);
-      return 0;
-    }
-    return 1;
-  }
-
-  WavReader in_file(FLAG_i);
-  WavWriter out_file(FLAG_o, in_file.sample_rate(), in_file.num_channels());
-
-  const size_t num_mics = in_file.num_channels();
-  const std::vector<Point> array_geometry =
-      ParseArrayGeometry(FLAG_mic_positions, num_mics);
-  RTC_CHECK_EQ(array_geometry.size(), num_mics);
-
-  NonlinearBeamformer bf(array_geometry, array_geometry.size());
-  bf.Initialize(kChunkSizeMs, in_file.sample_rate());
-
-  printf("Input file: %s\nChannels: %" PRIuS ", Sample rate: %d Hz\n\n",
-         FLAG_i, in_file.num_channels(), in_file.sample_rate());
-  printf("Output file: %s\nChannels: %" PRIuS ", Sample rate: %d Hz\n\n",
-         FLAG_o, out_file.num_channels(), out_file.sample_rate());
-
-  ChannelBuffer<float> buf(
-      rtc::CheckedDivExact(in_file.sample_rate(), kChunksPerSecond),
-      in_file.num_channels());
-
-  std::vector<float> interleaved(buf.size());
-  while (in_file.ReadSamples(interleaved.size(),
-                             &interleaved[0]) == interleaved.size()) {
-    FloatS16ToFloat(&interleaved[0], interleaved.size(), &interleaved[0]);
-    Deinterleave(&interleaved[0], buf.num_frames(),
-                 buf.num_channels(), buf.channels());
-
-    bf.AnalyzeChunk(buf);
-    bf.PostFilter(&buf);
-
-    Interleave(buf.channels(), buf.num_frames(),
-               buf.num_channels(), &interleaved[0]);
-    FloatToFloatS16(&interleaved[0], interleaved.size(), &interleaved[0]);
-    out_file.WriteSamples(&interleaved[0], interleaved.size());
-  }
-
-  return 0;
-}
-
-}  // namespace webrtc
-
-int main(int argc, char* argv[]) {
-  return webrtc::main(argc, argv);
-}
diff --git a/modules/audio_processing/beamformer/nonlinear_beamformer_unittest.cc b/modules/audio_processing/beamformer/nonlinear_beamformer_unittest.cc
deleted file mode 100644
index 78b2f0a..0000000
--- a/modules/audio_processing/beamformer/nonlinear_beamformer_unittest.cc
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- *  Copyright (c) 2015 The WebRTC 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.
- */
-
-// MSVC++ requires this to be set before any other includes to get M_PI.
-#define _USE_MATH_DEFINES
-
-#include "modules/audio_processing/beamformer/nonlinear_beamformer.h"
-
-#include <math.h>
-
-#include "api/array_view.h"
-#include "modules/audio_processing/audio_buffer.h"
-#include "modules/audio_processing/test/audio_buffer_tools.h"
-#include "modules/audio_processing/test/bitexactness_tools.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace {
-
-const int kChunkSizeMs = 10;
-const int kSampleRateHz = 16000;
-
-SphericalPointf AzimuthToSphericalPoint(float azimuth_radians) {
-  return SphericalPointf(azimuth_radians, 0.f, 1.f);
-}
-
-void Verify(NonlinearBeamformer* bf, float target_azimuth_radians) {
-  EXPECT_TRUE(bf->IsInBeam(AzimuthToSphericalPoint(target_azimuth_radians)));
-  EXPECT_TRUE(bf->IsInBeam(AzimuthToSphericalPoint(
-      target_azimuth_radians - NonlinearBeamformer::kHalfBeamWidthRadians +
-      0.001f)));
-  EXPECT_TRUE(bf->IsInBeam(AzimuthToSphericalPoint(
-      target_azimuth_radians + NonlinearBeamformer::kHalfBeamWidthRadians -
-      0.001f)));
-  EXPECT_FALSE(bf->IsInBeam(AzimuthToSphericalPoint(
-      target_azimuth_radians - NonlinearBeamformer::kHalfBeamWidthRadians -
-      0.001f)));
-  EXPECT_FALSE(bf->IsInBeam(AzimuthToSphericalPoint(
-      target_azimuth_radians + NonlinearBeamformer::kHalfBeamWidthRadians +
-      0.001f)));
-}
-
-void AimAndVerify(NonlinearBeamformer* bf, float target_azimuth_radians) {
-  bf->AimAt(AzimuthToSphericalPoint(target_azimuth_radians));
-  Verify(bf, target_azimuth_radians);
-}
-
-// Bitexactness test code.
-const size_t kNumFramesToProcess = 1000;
-
-void ProcessOneFrame(int sample_rate_hz,
-                     AudioBuffer* capture_audio_buffer,
-                     NonlinearBeamformer* beamformer) {
-  if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
-    capture_audio_buffer->SplitIntoFrequencyBands();
-  }
-
-  beamformer->AnalyzeChunk(*capture_audio_buffer->split_data_f());
-  capture_audio_buffer->set_num_channels(1);
-  beamformer->PostFilter(capture_audio_buffer->split_data_f());
-
-  if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
-    capture_audio_buffer->MergeFrequencyBands();
-  }
-}
-
-int BeamformerSampleRate(int sample_rate_hz) {
-  return (sample_rate_hz > AudioProcessing::kSampleRate16kHz
-              ? AudioProcessing::kSampleRate16kHz
-              : sample_rate_hz);
-}
-
-void RunBitExactnessTest(int sample_rate_hz,
-                         const std::vector<Point>& array_geometry,
-                         const SphericalPointf& target_direction,
-                         rtc::ArrayView<const float> output_reference) {
-  NonlinearBeamformer beamformer(array_geometry, 1u, target_direction);
-  beamformer.Initialize(AudioProcessing::kChunkSizeMs,
-                        BeamformerSampleRate(sample_rate_hz));
-
-  const StreamConfig capture_config(sample_rate_hz, array_geometry.size(),
-                                    false);
-  AudioBuffer capture_buffer(
-      capture_config.num_frames(), capture_config.num_channels(),
-      capture_config.num_frames(), capture_config.num_channels(),
-      capture_config.num_frames());
-  test::InputAudioFile capture_file(
-      test::GetApmCaptureTestVectorFileName(sample_rate_hz));
-  std::vector<float> capture_input(capture_config.num_frames() *
-                                   capture_config.num_channels());
-  for (size_t frame_no = 0u; frame_no < kNumFramesToProcess; ++frame_no) {
-    ReadFloatSamplesFromStereoFile(capture_config.num_frames(),
-                                   capture_config.num_channels(), &capture_file,
-                                   capture_input);
-
-    test::CopyVectorToAudioBuffer(capture_config, capture_input,
-                                  &capture_buffer);
-
-    ProcessOneFrame(sample_rate_hz, &capture_buffer, &beamformer);
-  }
-
-  // Extract and verify the test results.
-  std::vector<float> capture_output;
-  test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer,
-                                     &capture_output);
-
-  const float kElementErrorBound = 1.f / static_cast<float>(1 << 15);
-
-  // Compare the output with the reference. Only the first values of the output
-  // from last frame processed are compared in order not having to specify all
-  // preceeding frames as testvectors. As the algorithm being tested has a
-  // memory, testing only the last frame implicitly also tests the preceeding
-  // frames.
-  EXPECT_TRUE(test::VerifyDeinterleavedArray(
-      capture_config.num_frames(), capture_config.num_channels(),
-      output_reference, capture_output, kElementErrorBound));
-}
-
-// TODO(peah): Add bitexactness tests for scenarios with more than 2 input
-// channels.
-std::vector<Point> CreateArrayGeometry(int variant) {
-  std::vector<Point> array_geometry;
-  switch (variant) {
-    case 1:
-      array_geometry.push_back(Point(-0.025f, 0.f, 0.f));
-      array_geometry.push_back(Point(0.025f, 0.f, 0.f));
-      break;
-    case 2:
-      array_geometry.push_back(Point(-0.035f, 0.f, 0.f));
-      array_geometry.push_back(Point(0.035f, 0.f, 0.f));
-      break;
-    case 3:
-      array_geometry.push_back(Point(-0.5f, 0.f, 0.f));
-      array_geometry.push_back(Point(0.5f, 0.f, 0.f));
-      break;
-    default:
-      RTC_CHECK(false);
-  }
-  return array_geometry;
-}
-
-const SphericalPointf TargetDirection1(0.4f * static_cast<float>(M_PI) / 2.f,
-                                       0.f,
-                                       1.f);
-const SphericalPointf TargetDirection2(static_cast<float>(M_PI) / 2.f,
-                                       1.f,
-                                       2.f);
-
-}  // namespace
-
-TEST(NonlinearBeamformerTest, AimingModifiesBeam) {
-  std::vector<Point> array_geometry;
-  array_geometry.push_back(Point(-0.025f, 0.f, 0.f));
-  array_geometry.push_back(Point(0.025f, 0.f, 0.f));
-  NonlinearBeamformer bf(array_geometry, 1u);
-  bf.Initialize(kChunkSizeMs, kSampleRateHz);
-  // The default constructor parameter sets the target angle to PI / 2.
-  Verify(&bf, static_cast<float>(M_PI) / 2.f);
-  AimAndVerify(&bf, static_cast<float>(M_PI) / 3.f);
-  AimAndVerify(&bf, 3.f * static_cast<float>(M_PI) / 4.f);
-  AimAndVerify(&bf, static_cast<float>(M_PI) / 6.f);
-  AimAndVerify(&bf, static_cast<float>(M_PI));
-}
-
-TEST(NonlinearBeamformerTest, InterfAnglesTakeAmbiguityIntoAccount) {
-  {
-    // For linear arrays there is ambiguity.
-    std::vector<Point> array_geometry;
-    array_geometry.push_back(Point(-0.1f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.2f, 0.f, 0.f));
-    NonlinearBeamformer bf(array_geometry, 1u);
-    bf.Initialize(kChunkSizeMs, kSampleRateHz);
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
-                    bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
-                    bf.interf_angles_radians_[1]);
-    bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(M_PI - bf.away_radians_ / 2.f,
-                    bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
-  }
-  {
-    // For planar arrays with normal in the xy-plane there is ambiguity.
-    std::vector<Point> array_geometry;
-    array_geometry.push_back(Point(-0.1f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.2f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.1f, 0.f, 0.2f));
-    array_geometry.push_back(Point(0.f, 0.f, -0.1f));
-    NonlinearBeamformer bf(array_geometry, 1u);
-    bf.Initialize(kChunkSizeMs, kSampleRateHz);
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
-                    bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
-                    bf.interf_angles_radians_[1]);
-    bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(M_PI - bf.away_radians_ / 2.f,
-                    bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
-  }
-  {
-    // For planar arrays with normal not in the xy-plane there is no ambiguity.
-    std::vector<Point> array_geometry;
-    array_geometry.push_back(Point(0.f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.2f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.f, 0.1f, -0.2f));
-    NonlinearBeamformer bf(array_geometry, 1u);
-    bf.Initialize(kChunkSizeMs, kSampleRateHz);
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
-                    bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
-                    bf.interf_angles_radians_[1]);
-    bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(-bf.away_radians_ / 2.f, bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
-  }
-  {
-    // For arrays which are not linear or planar there is no ambiguity.
-    std::vector<Point> array_geometry;
-    array_geometry.push_back(Point(0.f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.1f, 0.f, 0.f));
-    array_geometry.push_back(Point(0.f, 0.2f, 0.f));
-    array_geometry.push_back(Point(0.f, 0.f, 0.3f));
-    NonlinearBeamformer bf(array_geometry, 1u);
-    bf.Initialize(kChunkSizeMs, kSampleRateHz);
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(M_PI / 2.f - bf.away_radians_,
-                    bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(M_PI / 2.f + bf.away_radians_,
-                    bf.interf_angles_radians_[1]);
-    bf.AimAt(AzimuthToSphericalPoint(bf.away_radians_ / 2.f));
-    EXPECT_EQ(2u, bf.interf_angles_radians_.size());
-    EXPECT_FLOAT_EQ(-bf.away_radians_ / 2.f, bf.interf_angles_radians_[0]);
-    EXPECT_FLOAT_EQ(3.f * bf.away_radians_ / 2.f, bf.interf_angles_radians_[1]);
-  }
-}
-
-// TODO(peah): Investigate why the nonlinear_beamformer.cc causes a DCHECK in
-// this setup.
-TEST(BeamformerBitExactnessTest,
-     DISABLED_Stereo8kHz_ArrayGeometry1_TargetDirection1) {
-  const float kOutputReference[] = {0.001318f, -0.001091f, 0.000990f,
-                                    0.001318f, -0.001091f, 0.000990f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate8kHz, CreateArrayGeometry(1),
-                      TargetDirection1, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo16kHz_ArrayGeometry1_TargetDirection1) {
-  const float kOutputReference[] = {-0.000077f, -0.000147f, -0.000138f,
-                                    -0.000077f, -0.000147f, -0.000138f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate16kHz, CreateArrayGeometry(1),
-                      TargetDirection1, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo32kHz_ArrayGeometry1_TargetDirection1) {
-  const float kOutputReference[] = {-0.000061f, -0.000061f, -0.000061f,
-                                    -0.000061f, -0.000061f, -0.000061f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate32kHz, CreateArrayGeometry(1),
-                      TargetDirection1, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo48kHz_ArrayGeometry1_TargetDirection1) {
-  const float kOutputReference[] = {0.000450f, 0.000436f, 0.000433f,
-                                    0.000450f, 0.000436f, 0.000433f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate48kHz, CreateArrayGeometry(1),
-                      TargetDirection1, kOutputReference);
-}
-
-// TODO(peah): Investigate why the nonlinear_beamformer.cc causes a DCHECK in
-// this setup.
-TEST(BeamformerBitExactnessTest,
-     DISABLED_Stereo8kHz_ArrayGeometry1_TargetDirection2) {
-  const float kOutputReference[] = {0.001144f,  -0.001026f, 0.001074f,
-                                    -0.016205f, -0.007324f, -0.015656f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate8kHz, CreateArrayGeometry(1),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo16kHz_ArrayGeometry1_TargetDirection2) {
-  const float kOutputReference[] = {0.000221f, -0.000249f, 0.000140f,
-                                    0.000221f, -0.000249f, 0.000140f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate16kHz, CreateArrayGeometry(1),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo32kHz_ArrayGeometry1_TargetDirection2) {
-  const float kOutputReference[] = {0.000763f, -0.000336f, 0.000549f,
-                                    0.000763f, -0.000336f, 0.000549f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate32kHz, CreateArrayGeometry(1),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo48kHz_ArrayGeometry1_TargetDirection2) {
-  const float kOutputReference[] = {-0.000004f, -0.000494f, 0.000255f,
-                                    -0.000004f, -0.000494f, 0.000255f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate48kHz, CreateArrayGeometry(1),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo8kHz_ArrayGeometry2_TargetDirection2) {
-  const float kOutputReference[] = {-0.000914f, 0.002170f, -0.002382f,
-                                    -0.000914f, 0.002170f, -0.002382f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate8kHz, CreateArrayGeometry(2),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo16kHz_ArrayGeometry2_TargetDirection2) {
-  const float kOutputReference[] = {0.000179f, -0.000179f, 0.000081f,
-                                    0.000179f, -0.000179f, 0.000081f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate16kHz, CreateArrayGeometry(2),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo32kHz_ArrayGeometry2_TargetDirection2) {
-  const float kOutputReference[] = {0.000549f, -0.000214f, 0.000366f,
-                                    0.000549f, -0.000214f, 0.000366f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate32kHz, CreateArrayGeometry(2),
-                      TargetDirection2, kOutputReference);
-}
-
-TEST(BeamformerBitExactnessTest,
-     Stereo48kHz_ArrayGeometry2_TargetDirection2) {
-  const float kOutputReference[] = {0.000019f, -0.000310f, 0.000182f,
-                                    0.000019f, -0.000310f, 0.000182f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate48kHz, CreateArrayGeometry(2),
-                      TargetDirection2, kOutputReference);
-}
-
-// TODO(peah): Investigate why the nonlinear_beamformer.cc causes a DCHECK in
-// this setup.
-TEST(BeamformerBitExactnessTest,
-     DISABLED_Stereo16kHz_ArrayGeometry3_TargetDirection1) {
-  const float kOutputReference[] = {-0.000161f, 0.000171f, -0.000096f,
-                                    0.001007f,  0.000427f, 0.000977f};
-
-  RunBitExactnessTest(AudioProcessing::kSampleRate16kHz, CreateArrayGeometry(3),
-                      TargetDirection1, kOutputReference);
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/config_unittest.cc b/modules/audio_processing/config_unittest.cc
index 8776ee3..19e9ab3 100644
--- a/modules/audio_processing/config_unittest.cc
+++ b/modules/audio_processing/config_unittest.cc
@@ -19,11 +19,9 @@
   static const int kDefaultFactor;
   static const int kDefaultOffset;
 
-  MyExperiment()
-    : factor(kDefaultFactor), offset(kDefaultOffset) {}
+  MyExperiment() : factor(kDefaultFactor), offset(kDefaultOffset) {}
 
-  MyExperiment(int factor, int offset)
-    : factor(factor), offset(offset) {}
+  MyExperiment(int factor, int offset) : factor(factor), offset(offset) {}
 
   int factor;
   int offset;
@@ -61,17 +59,13 @@
       ConfigOptionID::kAlgo1CostFunctionForTest;
   Algo1_CostFunction() {}
 
-  virtual int cost(int x) const {
-    return x;
-  }
+  virtual int cost(int x) const { return x; }
 
   virtual ~Algo1_CostFunction() {}
 };
 
 struct SqrCost : Algo1_CostFunction {
-  virtual int cost(int x) const {
-    return x*x;
-  }
+  virtual int cost(int x) const { return x * x; }
 };
 
 TEST(Config, SupportsPolymorphism) {
diff --git a/modules/audio_processing/echo_cancellation_impl.cc b/modules/audio_processing/echo_cancellation_impl.cc
index 99f676c..15cd0db 100644
--- a/modules/audio_processing/echo_cancellation_impl.cc
+++ b/modules/audio_processing/echo_cancellation_impl.cc
@@ -147,7 +147,6 @@
   }
 }
 
-
 int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio,
                                               int stream_delay_ms) {
   rtc::CritScope cs_capture(crit_capture_);
@@ -376,7 +375,8 @@
   return GetDelayMetrics(median, std, &fraction_poor_delays);
 }
 
-int EchoCancellationImpl::GetDelayMetrics(int* median, int* std,
+int EchoCancellationImpl::GetDelayMetrics(int* median,
+                                          int* std,
                                           float* fraction_poor_delays) {
   rtc::CritScope cs(crit_capture_);
   if (median == NULL) {
@@ -445,8 +445,7 @@
   rtc::CritScope cs(crit_capture_);
   RTC_DCHECK(enabled_);
   // Report the delay for the first AEC component.
-  return WebRtcAec_system_delay(
-      WebRtcAec_aec_core(cancellers_[0]->state()));
+  return WebRtcAec_system_delay(WebRtcAec_aec_core(cancellers_[0]->state()));
 }
 
 void EchoCancellationImpl::PackRenderAudioBuffer(
diff --git a/modules/audio_processing/echo_control_mobile_impl.cc b/modules/audio_processing/echo_control_mobile_impl.cc
index 0ff1bce..841364f 100644
--- a/modules/audio_processing/echo_control_mobile_impl.cc
+++ b/modules/audio_processing/echo_control_mobile_impl.cc
@@ -120,10 +120,10 @@
 }
 
 EchoControlMobileImpl::~EchoControlMobileImpl() {
-    if (external_echo_path_ != NULL) {
-      delete [] external_echo_path_;
-      external_echo_path_ = NULL;
-    }
+  if (external_echo_path_ != NULL) {
+    delete[] external_echo_path_;
+    external_echo_path_ = NULL;
+  }
 }
 
 void EchoControlMobileImpl::ProcessRenderAudio(
@@ -218,8 +218,7 @@
       ++handle_index;
     }
     for (size_t band = 1u; band < audio->num_bands(); ++band) {
-      memset(audio->split_bands(capture)[band],
-             0,
+      memset(audio->split_bands(capture)[band], 0,
              audio->num_frames_per_band() *
                  sizeof(audio->split_bands(capture)[band][0]));
     }
@@ -269,8 +268,7 @@
   return Configure();
 }
 
-EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
-    const {
+EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() const {
   rtc::CritScope cs(crit_capture_);
   return routing_mode_;
 }
diff --git a/modules/audio_processing/echo_detector/circular_buffer.cc b/modules/audio_processing/echo_detector/circular_buffer.cc
index 0c6cc8a..a6d10ed 100644
--- a/modules/audio_processing/echo_detector/circular_buffer.cc
+++ b/modules/audio_processing/echo_detector/circular_buffer.cc
@@ -28,9 +28,9 @@
   RTC_DCHECK_LE(nr_elements_in_buffer_, buffer_.size());
 }
 
-rtc::Optional<float> CircularBuffer::Pop() {
+absl::optional<float> CircularBuffer::Pop() {
   if (nr_elements_in_buffer_ == 0) {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
   const size_t index =
       (buffer_.size() + next_insertion_index_ - nr_elements_in_buffer_) %
diff --git a/modules/audio_processing/echo_detector/circular_buffer.h b/modules/audio_processing/echo_detector/circular_buffer.h
index 53d4afb..9f5cdfa 100644
--- a/modules/audio_processing/echo_detector/circular_buffer.h
+++ b/modules/audio_processing/echo_detector/circular_buffer.h
@@ -13,7 +13,7 @@
 
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace webrtc {
 
@@ -24,7 +24,7 @@
   ~CircularBuffer();
 
   void Push(float value);
-  rtc::Optional<float> Pop();
+  absl::optional<float> Pop();
   size_t Size() const { return nr_elements_in_buffer_; }
   // This function fills the buffer with zeros, but does not change its size.
   void Clear();
diff --git a/modules/audio_processing/echo_detector/circular_buffer_unittest.cc b/modules/audio_processing/echo_detector/circular_buffer_unittest.cc
index 657bd05..0fa2a2b 100644
--- a/modules/audio_processing/echo_detector/circular_buffer_unittest.cc
+++ b/modules/audio_processing/echo_detector/circular_buffer_unittest.cc
@@ -46,7 +46,7 @@
 
 TEST(CircularBufferTests, ReadFromEmpty) {
   CircularBuffer test_buffer(3);
-  EXPECT_EQ(rtc::nullopt, test_buffer.Pop());
+  EXPECT_EQ(absl::nullopt, test_buffer.Pop());
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/gain_control_impl.cc b/modules/audio_processing/gain_control_impl.cc
index e550ebb..685a27f 100644
--- a/modules/audio_processing/gain_control_impl.cc
+++ b/modules/audio_processing/gain_control_impl.cc
@@ -10,7 +10,7 @@
 
 #include "modules/audio_processing/gain_control_impl.h"
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/audio_processing/agc/legacy/gain_control.h"
 #include "modules/audio_processing/audio_buffer.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
@@ -67,9 +67,7 @@
     set_capture_level(capture_level);
   }
 
-  void set_capture_level(int capture_level) {
-    capture_level_ = capture_level;
-  }
+  void set_capture_level(int capture_level) { capture_level_ = capture_level; }
 
   int get_capture_level() {
     RTC_DCHECK(capture_level_);
@@ -80,7 +78,7 @@
   Handle* state_;
   // TODO(peah): Remove the optional once the initialization is moved into the
   // ctor.
-  rtc::Optional<int> capture_level_;
+  absl::optional<int> capture_level_;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(GainController);
 };
@@ -259,7 +257,7 @@
   data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
                         &analog_capture_level_);
   // TODO(ajm): enable this assertion?
-  //RTC_DCHECK_EQ(kAdaptiveAnalog, mode_);
+  // RTC_DCHECK_EQ(kAdaptiveAnalog, mode_);
 
   return analog_capture_level_;
 }
@@ -303,8 +301,7 @@
   return mode_;
 }
 
-int GainControlImpl::set_analog_level_limits(int minimum,
-                                             int maximum) {
+int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
   if (minimum < 0) {
     return AudioProcessing::kBadParameterError;
   }
@@ -419,11 +416,10 @@
   WebRtcAgcConfig config;
   // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
   //            change the interface.
-  //RTC_DCHECK_LE(target_level_dbfs_, 0);
-  //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
+  // RTC_DCHECK_LE(target_level_dbfs_, 0);
+  // config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
   config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
-  config.compressionGaindB =
-      static_cast<int16_t>(compression_gain_db_);
+  config.compressionGaindB = static_cast<int16_t>(compression_gain_db_);
   config.limiterEnable = limiter_enabled_;
 
   int error = AudioProcessing::kNoError;
diff --git a/modules/audio_processing/gain_control_impl.h b/modules/audio_processing/gain_control_impl.h
index 2674506..959422f 100644
--- a/modules/audio_processing/gain_control_impl.h
+++ b/modules/audio_processing/gain_control_impl.h
@@ -86,8 +86,8 @@
 
   std::vector<std::unique_ptr<GainController>> gain_controllers_;
 
-  rtc::Optional<size_t> num_proc_channels_ RTC_GUARDED_BY(crit_capture_);
-  rtc::Optional<int> sample_rate_hz_ RTC_GUARDED_BY(crit_capture_);
+  absl::optional<size_t> num_proc_channels_ RTC_GUARDED_BY(crit_capture_);
+  absl::optional<int> sample_rate_hz_ RTC_GUARDED_BY(crit_capture_);
 
   static int instance_counter_;
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GainControlImpl);
diff --git a/modules/audio_processing/include/aec_dump.h b/modules/audio_processing/include/aec_dump.h
index e824892..25c08b8 100644
--- a/modules/audio_processing/include/aec_dump.h
+++ b/modules/audio_processing/include/aec_dump.h
@@ -18,6 +18,7 @@
 #include "api/array_view.h"
 #include "api/audio/audio_frame.h"
 #include "modules/audio_processing/include/audio_frame_view.h"
+#include "modules/audio_processing/include/audio_processing.h"
 
 namespace webrtc {
 
@@ -55,18 +56,6 @@
   std::string experiments_description = "";
 };
 
-struct InternalAPMStreamsConfig {
-  int input_sample_rate = 0;
-  int output_sample_rate = 0;
-  int render_input_sample_rate = 0;
-  int render_output_sample_rate = 0;
-
-  size_t input_num_channels = 0;
-  size_t output_num_channels = 0;
-  size_t render_input_num_channels = 0;
-  size_t render_output_num_channels = 0;
-};
-
 // An interface for recording configuration and input/output streams
 // of the Audio Processing Module. The recordings are called
 // 'aec-dumps' and are stored in a protobuf format defined in
@@ -87,8 +76,7 @@
   virtual ~AecDump() = default;
 
   // Logs Event::Type INIT message.
-  virtual void WriteInitMessage(
-      const InternalAPMStreamsConfig& streams_config) = 0;
+  virtual void WriteInitMessage(const ProcessingConfig& api_format) = 0;
 
   // Logs Event::Type STREAM message. To log an input/output pair,
   // call the AddCapture* and AddAudioProcessingState methods followed
diff --git a/modules/audio_processing/include/audio_frame_view.h b/modules/audio_processing/include/audio_frame_view.h
index 366fc32..ab5779a 100644
--- a/modules/audio_processing/include/audio_frame_view.h
+++ b/modules/audio_processing/include/audio_frame_view.h
@@ -13,6 +13,8 @@
 
 #include "api/array_view.h"
 
+namespace webrtc {
+
 // Class to pass audio data in T** format, where T is a numeric type.
 template <class T>
 class AudioFrameView {
@@ -60,5 +62,6 @@
   size_t num_channels_;
   size_t channel_size_;
 };
+}  // namespace webrtc
 
 #endif  // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_
diff --git a/modules/audio_processing/include/audio_generator_factory.cc b/modules/audio_processing/include/audio_generator_factory.cc
index 9084a1e..69a5401 100644
--- a/modules/audio_processing/include/audio_generator_factory.cc
+++ b/modules/audio_processing/include/audio_generator_factory.cc
@@ -10,16 +10,16 @@
 
 #include "modules/audio_processing/include/audio_generator_factory.h"
 
+#include "absl/memory/memory.h"
 #include "common_audio/wav_file.h"
 #include "modules/audio_processing/audio_generator/file_audio_generator.h"
-#include "rtc_base/ptr_util.h"
 
 namespace webrtc {
 
 std::unique_ptr<AudioGenerator> AudioGeneratorFactory::Create(
     const std::string& file_name) {
   std::unique_ptr<WavReader> input_audio_file(new WavReader(file_name));
-  return rtc::MakeUnique<FileAudioGenerator>(std::move(input_audio_file));
+  return absl::make_unique<FileAudioGenerator>(std::move(input_audio_file));
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/include/audio_processing.cc b/modules/audio_processing/include/audio_processing.cc
index e9c56e8..75eedaf 100644
--- a/modules/audio_processing/include/audio_processing.cc
+++ b/modules/audio_processing/include/audio_processing.cc
@@ -14,23 +14,7 @@
 
 namespace webrtc {
 
-Beamforming::Beamforming()
-    : enabled(false),
-      array_geometry(),
-      target_direction(
-          SphericalPointf(static_cast<float>(M_PI) / 2.f, 0.f, 1.f)) {}
-Beamforming::Beamforming(bool enabled, const std::vector<Point>& array_geometry)
-    : Beamforming(enabled,
-                  array_geometry,
-                  SphericalPointf(static_cast<float>(M_PI) / 2.f, 0.f, 1.f)) {}
-
-Beamforming::Beamforming(bool enabled,
-                         const std::vector<Point>& array_geometry,
-                         SphericalPointf target_direction)
-    : enabled(enabled),
-      array_geometry(array_geometry),
-      target_direction(target_direction) {}
-
-Beamforming::~Beamforming() {}
+void CustomProcessing::SetRuntimeSetting(
+    AudioProcessing::RuntimeSetting setting) {}
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index 379a664..9d27f16 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -18,17 +18,17 @@
 
 #include <math.h>
 #include <stddef.h>  // size_t
-#include <stdio.h>  // FILE
+#include <stdio.h>   // FILE
 #include <string.h>
 #include <vector>
 
+#include "absl/types/optional.h"
 #include "api/audio/echo_canceller3_config.h"
 #include "api/audio/echo_control.h"
-#include "api/optional.h"
-#include "modules/audio_processing/beamformer/array_util.h"
 #include "modules/audio_processing/include/audio_generator.h"
 #include "modules/audio_processing/include/audio_processing_statistics.h"
 #include "modules/audio_processing/include/config.h"
+#include "modules/audio_processing/include/gain_control.h"
 #include "rtc_base/arraysize.h"
 #include "rtc_base/deprecation.h"
 #include "rtc_base/platform_file.h"
@@ -44,8 +44,6 @@
 class AudioBuffer;
 class AudioFrame;
 
-class NonlinearBeamformer;
-
 class StreamConfig;
 class ProcessingConfig;
 
@@ -125,6 +123,13 @@
 struct ExperimentalAgc {
   ExperimentalAgc() = default;
   explicit ExperimentalAgc(bool enabled) : enabled(enabled) {}
+  ExperimentalAgc(bool enabled,
+                  bool enabled_agc2_level_estimator,
+                  bool enabled_agc2_digital_adaptive)
+      : enabled(enabled),
+        enabled_agc2_level_estimator(enabled_agc2_level_estimator),
+        enabled_agc2_digital_adaptive(enabled_agc2_digital_adaptive) {}
+
   ExperimentalAgc(bool enabled, int startup_min_volume)
       : enabled(enabled), startup_min_volume(startup_min_volume) {}
   ExperimentalAgc(bool enabled, int startup_min_volume, int clipped_level_min)
@@ -136,6 +141,8 @@
   int startup_min_volume = kAgcStartupMinVolume;
   // Lowest microphone level that will be applied in response to clipping.
   int clipped_level_min = kClippedLevelMin;
+  bool enabled_agc2_level_estimator = false;
+  bool enabled_agc2_digital_adaptive = false;
 };
 
 // Use to enable experimental noise suppression. It can be set in the
@@ -147,22 +154,6 @@
   bool enabled;
 };
 
-// Use to enable beamforming. Must be provided through the constructor. It will
-// have no impact if used with AudioProcessing::SetExtraOptions().
-struct Beamforming {
-  Beamforming();
-  Beamforming(bool enabled, const std::vector<Point>& array_geometry);
-  Beamforming(bool enabled,
-              const std::vector<Point>& array_geometry,
-              SphericalPointf target_direction);
-  ~Beamforming();
-
-  static const ConfigOptionID identifier = ConfigOptionID::kBeamforming;
-  const bool enabled;
-  const std::vector<Point> array_geometry;
-  const SphericalPointf target_direction;
-};
-
 // Use to enable intelligibility enhancer in audio processing.
 //
 // Note: If enabled and the reverse stream has more than one output channel,
@@ -313,7 +304,11 @@
   // runtime.
   class RuntimeSetting {
    public:
-    enum class Type { kNotSpecified, kCapturePreGain };
+    enum class Type {
+      kNotSpecified,
+      kCapturePreGain,
+      kCustomRenderProcessingRuntimeSetting
+    };
 
     RuntimeSetting() : type_(Type::kNotSpecified), value_(0.f) {}
     ~RuntimeSetting() = default;
@@ -323,6 +318,10 @@
       return {Type::kCapturePreGain, gain};
     }
 
+    static RuntimeSetting CreateCustomRenderSetting(float payload) {
+      return {Type::kCustomRenderProcessingRuntimeSetting, payload};
+    }
+
     Type type() const { return type_; }
     void GetFloat(float* value) const {
       RTC_DCHECK(value);
@@ -665,12 +664,9 @@
   // The AudioProcessingBuilder takes ownership of the render_pre_processing.
   AudioProcessingBuilder& SetRenderPreProcessing(
       std::unique_ptr<CustomProcessing> render_pre_processing);
-  // The AudioProcessingBuilder takes ownership of the nonlinear beamformer.
-  AudioProcessingBuilder& SetNonlinearBeamformer(
-      std::unique_ptr<NonlinearBeamformer> nonlinear_beamformer);
   // The AudioProcessingBuilder takes ownership of the echo_detector.
   AudioProcessingBuilder& SetEchoDetector(
-      std::unique_ptr<EchoDetector> echo_detector);
+      rtc::scoped_refptr<EchoDetector> echo_detector);
   // This creates an APM instance using the previously set components. Calling
   // the Create function resets the AudioProcessingBuilder to its initial state.
   AudioProcessing* Create();
@@ -680,8 +676,7 @@
   std::unique_ptr<EchoControlFactory> echo_control_factory_;
   std::unique_ptr<CustomProcessing> capture_post_processing_;
   std::unique_ptr<CustomProcessing> render_pre_processing_;
-  std::unique_ptr<NonlinearBeamformer> nonlinear_beamformer_;
-  std::unique_ptr<EchoDetector> echo_detector_;
+  rtc::scoped_refptr<EchoDetector> echo_detector_;
   RTC_DISALLOW_COPY_AND_ASSIGN(AudioProcessingBuilder);
 };
 
@@ -734,8 +729,8 @@
 
  private:
   static size_t calculate_frames(int sample_rate_hz) {
-    return static_cast<size_t>(
-        AudioProcessing::kChunkSizeMs * sample_rate_hz / 1000);
+    return static_cast<size_t>(AudioProcessing::kChunkSizeMs * sample_rate_hz /
+                               1000);
   }
 
   int sample_rate_hz_;
@@ -884,7 +879,8 @@
   // Deprecated. Use GetStatistics on the AudioProcessing interface instead.
   virtual int GetDelayMetrics(int* median, int* std) = 0;
   // Deprecated. Use GetStatistics on the AudioProcessing interface instead.
-  virtual int GetDelayMetrics(int* median, int* std,
+  virtual int GetDelayMetrics(int* median,
+                              int* std,
                               float* fraction_poor_delays) = 0;
 
   // Returns a pointer to the low level AEC component.  In case of multiple
@@ -953,97 +949,6 @@
   virtual ~EchoControlMobile() {}
 };
 
-// The automatic gain control (AGC) component brings the signal to an
-// appropriate range. This is done by applying a digital gain directly and, in
-// the analog mode, prescribing an analog gain to be applied at the audio HAL.
-//
-// Recommended to be enabled on the client-side.
-class GainControl {
- public:
-  virtual int Enable(bool enable) = 0;
-  virtual bool is_enabled() const = 0;
-
-  // When an analog mode is set, this must be called prior to |ProcessStream()|
-  // to pass the current analog level from the audio HAL. Must be within the
-  // range provided to |set_analog_level_limits()|.
-  virtual int set_stream_analog_level(int level) = 0;
-
-  // When an analog mode is set, this should be called after |ProcessStream()|
-  // to obtain the recommended new analog level for the audio HAL. It is the
-  // users responsibility to apply this level.
-  virtual int stream_analog_level() = 0;
-
-  enum Mode {
-    // Adaptive mode intended for use if an analog volume control is available
-    // on the capture device. It will require the user to provide coupling
-    // between the OS mixer controls and AGC through the |stream_analog_level()|
-    // functions.
-    //
-    // It consists of an analog gain prescription for the audio device and a
-    // digital compression stage.
-    kAdaptiveAnalog,
-
-    // Adaptive mode intended for situations in which an analog volume control
-    // is unavailable. It operates in a similar fashion to the adaptive analog
-    // mode, but with scaling instead applied in the digital domain. As with
-    // the analog mode, it additionally uses a digital compression stage.
-    kAdaptiveDigital,
-
-    // Fixed mode which enables only the digital compression stage also used by
-    // the two adaptive modes.
-    //
-    // It is distinguished from the adaptive modes by considering only a
-    // short time-window of the input signal. It applies a fixed gain through
-    // most of the input level range, and compresses (gradually reduces gain
-    // with increasing level) the input signal at higher levels. This mode is
-    // preferred on embedded devices where the capture signal level is
-    // predictable, so that a known gain can be applied.
-    kFixedDigital
-  };
-
-  virtual int set_mode(Mode mode) = 0;
-  virtual Mode mode() const = 0;
-
-  // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels
-  // from digital full-scale). The convention is to use positive values. For
-  // instance, passing in a value of 3 corresponds to -3 dBFs, or a target
-  // level 3 dB below full-scale. Limited to [0, 31].
-  //
-  // TODO(ajm): use a negative value here instead, if/when VoE will similarly
-  //            update its interface.
-  virtual int set_target_level_dbfs(int level) = 0;
-  virtual int target_level_dbfs() const = 0;
-
-  // Sets the maximum |gain| the digital compression stage may apply, in dB. A
-  // higher number corresponds to greater compression, while a value of 0 will
-  // leave the signal uncompressed. Limited to [0, 90].
-  virtual int set_compression_gain_db(int gain) = 0;
-  virtual int compression_gain_db() const = 0;
-
-  // When enabled, the compression stage will hard limit the signal to the
-  // target level. Otherwise, the signal will be compressed but not limited
-  // above the target level.
-  virtual int enable_limiter(bool enable) = 0;
-  virtual bool is_limiter_enabled() const = 0;
-
-  // Sets the |minimum| and |maximum| analog levels of the audio capture device.
-  // Must be set if and only if an analog mode is used. Limited to [0, 65535].
-  virtual int set_analog_level_limits(int minimum,
-                                      int maximum) = 0;
-  virtual int analog_level_minimum() const = 0;
-  virtual int analog_level_maximum() const = 0;
-
-  // Returns true if the AGC has detected a saturation event (period where the
-  // signal reaches digital full-scale) in the current frame and the analog
-  // level cannot be reduced.
-  //
-  // This could be used as an indicator to reduce or disable analog mic gain at
-  // the audio HAL.
-  virtual bool stream_is_saturated() const = 0;
-
- protected:
-  virtual ~GainControl() {}
-};
 // TODO(peah): Remove this interface.
 // A filtering component which removes DC offset and low-frequency noise.
 // Recommended to be enabled on the client-side.
@@ -1088,12 +993,7 @@
 
   // Determines the aggressiveness of the suppression. Increasing the level
   // will reduce the noise level at the expense of a higher speech distortion.
-  enum Level {
-    kLow,
-    kModerate,
-    kHigh,
-    kVeryHigh
-  };
+  enum Level { kLow, kModerate, kHigh, kVeryHigh };
 
   virtual int set_level(Level level) = 0;
   virtual Level level() const = 0;
@@ -1119,12 +1019,15 @@
   virtual void Process(AudioBuffer* audio) = 0;
   // Returns a string representation of the module state.
   virtual std::string ToString() const = 0;
+  // Handles RuntimeSettings. TODO(webrtc:9262): make pure virtual
+  // after updating dependencies.
+  virtual void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting);
 
   virtual ~CustomProcessing() {}
 };
 
 // Interface for an echo detector submodule.
-class EchoDetector {
+class EchoDetector : public rtc::RefCountInterface {
  public:
   // (Re-)Initializes the submodule.
   virtual void Initialize(int capture_sample_rate_hz,
@@ -1150,8 +1053,6 @@
 
   // Collect current metrics from the echo detector.
   virtual Metrics GetMetrics() const = 0;
-
-  virtual ~EchoDetector() {}
 };
 
 // The voice activity detection (VAD) component analyzes the stream to
diff --git a/modules/audio_processing/include/audio_processing_statistics.h b/modules/audio_processing/include/audio_processing_statistics.h
index 05c5905..237d23c 100644
--- a/modules/audio_processing/include/audio_processing_statistics.h
+++ b/modules/audio_processing/include/audio_processing_statistics.h
@@ -11,7 +11,7 @@
 #ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_
 #define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace webrtc {
 // This version of the stats uses Optionals, it will replace the regular
@@ -23,12 +23,12 @@
 
   // AEC Statistics.
   // ERL = 10log_10(P_far / P_echo)
-  rtc::Optional<double> echo_return_loss;
+  absl::optional<double> echo_return_loss;
   // ERLE = 10log_10(P_echo / P_out)
-  rtc::Optional<double> echo_return_loss_enhancement;
+  absl::optional<double> echo_return_loss_enhancement;
   // Fraction of time that the AEC linear filter is divergent, in a 1-second
   // non-overlapped aggregation window.
-  rtc::Optional<double> divergent_filter_fraction;
+  absl::optional<double> divergent_filter_fraction;
 
   // The delay metrics consists of the delay median and standard deviation. It
   // also consists of the fraction of delay estimates that can make the echo
@@ -37,18 +37,18 @@
   // second. Note that if there are several clients pulling metrics from
   // |GetStatistics()| during a session the first call from any of them will
   // change to one second aggregation window for all.
-  rtc::Optional<int32_t> delay_median_ms;
-  rtc::Optional<int32_t> delay_standard_deviation_ms;
+  absl::optional<int32_t> delay_median_ms;
+  absl::optional<int32_t> delay_standard_deviation_ms;
 
   // Residual echo detector likelihood.
-  rtc::Optional<double> residual_echo_likelihood;
+  absl::optional<double> residual_echo_likelihood;
   // Maximum residual echo likelihood from the last time period.
-  rtc::Optional<double> residual_echo_likelihood_recent_max;
+  absl::optional<double> residual_echo_likelihood_recent_max;
 
   // The instantaneous delay estimate produced in the AEC. The unit is in
   // milliseconds and the value is the instantaneous value at the time of the
   // call to |GetStatistics()|.
-  rtc::Optional<int32_t> delay_ms;
+  absl::optional<int32_t> delay_ms;
 };
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/include/config.h b/modules/audio_processing/include/config.h
index 7615f62..9232b2e 100644
--- a/modules/audio_processing/include/config.h
+++ b/modules/audio_processing/include/config.h
@@ -13,7 +13,6 @@
 
 #include <map>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/constructormagic.h"
 
 namespace webrtc {
@@ -31,7 +30,7 @@
   kDelayAgnostic,
   kExperimentalAgc,
   kExperimentalNs,
-  kBeamforming,
+  kBeamforming,  // Deprecated
   kIntelligibility,
   kEchoCanceller3,  // Deprecated
   kAecRefinedAdaptiveFilter,
@@ -65,11 +64,13 @@
   // Returned references are owned by this.
   //
   // Requires std::is_default_constructible<T>
-  template<typename T> const T& Get() const;
+  template <typename T>
+  const T& Get() const;
 
   // Set the option, deleting any previous instance of the same.
   // This instance gets ownership of the newly set value.
-  template<typename T> void Set(T* value);
+  template <typename T>
+  void Set(T* value);
 
   Config();
   ~Config();
@@ -79,16 +80,14 @@
     virtual ~BaseOption() {}
   };
 
-  template<typename T>
+  template <typename T>
   struct Option : BaseOption {
-    explicit Option(T* v): value(v) {}
-    ~Option() {
-      delete value;
-    }
+    explicit Option(T* v) : value(v) {}
+    ~Option() { delete value; }
     T* value;
   };
 
-  template<typename T>
+  template <typename T>
   static ConfigOptionID identifier() {
     return T::identifier;
   }
@@ -96,10 +95,10 @@
   // Used to instantiate a default constructed object that doesn't needs to be
   // owned. This allows Get<T> to be implemented without requiring explicitly
   // locks.
-  template<typename T>
+  template <typename T>
   static const T& default_value() {
-    RTC_DEFINE_STATIC_LOCAL(const T, def, ());
-    return def;
+    static const T* const def = new T();
+    return *def;
   }
 
   typedef std::map<ConfigOptionID, BaseOption*> OptionMap;
@@ -110,7 +109,7 @@
   void operator=(const Config&);
 };
 
-template<typename T>
+template <typename T>
 const T& Config::Get() const {
   OptionMap::const_iterator it = options_.find(identifier<T>());
   if (it != options_.end()) {
@@ -122,7 +121,7 @@
   return default_value<T>();
 }
 
-template<typename T>
+template <typename T>
 void Config::Set(T* value) {
   BaseOption*& it = options_[identifier<T>()];
   delete it;
diff --git a/modules/audio_processing/include/gain_control.h b/modules/audio_processing/include/gain_control.h
new file mode 100644
index 0000000..420b1c6
--- /dev/null
+++ b/modules/audio_processing/include/gain_control.h
@@ -0,0 +1,108 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_INCLUDE_GAIN_CONTROL_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_GAIN_CONTROL_H_
+
+namespace webrtc {
+
+// The automatic gain control (AGC) component brings the signal to an
+// appropriate range. This is done by applying a digital gain directly and, in
+// the analog mode, prescribing an analog gain to be applied at the audio HAL.
+//
+// Recommended to be enabled on the client-side.
+class GainControl {
+ public:
+  virtual int Enable(bool enable) = 0;
+  virtual bool is_enabled() const = 0;
+
+  // When an analog mode is set, this must be called prior to |ProcessStream()|
+  // to pass the current analog level from the audio HAL. Must be within the
+  // range provided to |set_analog_level_limits()|.
+  virtual int set_stream_analog_level(int level) = 0;
+
+  // When an analog mode is set, this should be called after |ProcessStream()|
+  // to obtain the recommended new analog level for the audio HAL. It is the
+  // users responsibility to apply this level.
+  virtual int stream_analog_level() = 0;
+
+  enum Mode {
+    // Adaptive mode intended for use if an analog volume control is available
+    // on the capture device. It will require the user to provide coupling
+    // between the OS mixer controls and AGC through the |stream_analog_level()|
+    // functions.
+    //
+    // It consists of an analog gain prescription for the audio device and a
+    // digital compression stage.
+    kAdaptiveAnalog,
+
+    // Adaptive mode intended for situations in which an analog volume control
+    // is unavailable. It operates in a similar fashion to the adaptive analog
+    // mode, but with scaling instead applied in the digital domain. As with
+    // the analog mode, it additionally uses a digital compression stage.
+    kAdaptiveDigital,
+
+    // Fixed mode which enables only the digital compression stage also used by
+    // the two adaptive modes.
+    //
+    // It is distinguished from the adaptive modes by considering only a
+    // short time-window of the input signal. It applies a fixed gain through
+    // most of the input level range, and compresses (gradually reduces gain
+    // with increasing level) the input signal at higher levels. This mode is
+    // preferred on embedded devices where the capture signal level is
+    // predictable, so that a known gain can be applied.
+    kFixedDigital
+  };
+
+  virtual int set_mode(Mode mode) = 0;
+  virtual Mode mode() const = 0;
+
+  // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels
+  // from digital full-scale). The convention is to use positive values. For
+  // instance, passing in a value of 3 corresponds to -3 dBFs, or a target
+  // level 3 dB below full-scale. Limited to [0, 31].
+  //
+  // TODO(ajm): use a negative value here instead, if/when VoE will similarly
+  //            update its interface.
+  virtual int set_target_level_dbfs(int level) = 0;
+  virtual int target_level_dbfs() const = 0;
+
+  // Sets the maximum |gain| the digital compression stage may apply, in dB. A
+  // higher number corresponds to greater compression, while a value of 0 will
+  // leave the signal uncompressed. Limited to [0, 90].
+  virtual int set_compression_gain_db(int gain) = 0;
+  virtual int compression_gain_db() const = 0;
+
+  // When enabled, the compression stage will hard limit the signal to the
+  // target level. Otherwise, the signal will be compressed but not limited
+  // above the target level.
+  virtual int enable_limiter(bool enable) = 0;
+  virtual bool is_limiter_enabled() const = 0;
+
+  // Sets the |minimum| and |maximum| analog levels of the audio capture device.
+  // Must be set if and only if an analog mode is used. Limited to [0, 65535].
+  virtual int set_analog_level_limits(int minimum, int maximum) = 0;
+  virtual int analog_level_minimum() const = 0;
+  virtual int analog_level_maximum() const = 0;
+
+  // Returns true if the AGC has detected a saturation event (period where the
+  // signal reaches digital full-scale) in the current frame and the analog
+  // level cannot be reduced.
+  //
+  // This could be used as an indicator to reduce or disable analog mic gain at
+  // the audio HAL.
+  virtual bool stream_is_saturated() const = 0;
+
+ protected:
+  virtual ~GainControl() {}
+};
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_INCLUDE_GAIN_CONTROL_H_
diff --git a/modules/audio_processing/include/mock_audio_processing.h b/modules/audio_processing/include/mock_audio_processing.h
index 5fa3b1b..9ceee10 100644
--- a/modules/audio_processing/include/mock_audio_processing.h
+++ b/modules/audio_processing/include/mock_audio_processing.h
@@ -40,8 +40,8 @@
   MOCK_METHOD1(enable_delay_logging, int(bool enable));
   MOCK_CONST_METHOD0(is_delay_logging_enabled, bool());
   MOCK_METHOD2(GetDelayMetrics, int(int* median, int* std));
-  MOCK_METHOD3(GetDelayMetrics, int(int* median, int* std,
-                                    float* fraction_poor_delays));
+  MOCK_METHOD3(GetDelayMetrics,
+               int(int* median, int* std, float* fraction_poor_delays));
   MOCK_CONST_METHOD0(aec_core, struct AecCore*());
 };
 
@@ -110,6 +110,8 @@
   virtual ~MockCustomProcessing() {}
   MOCK_METHOD2(Initialize, void(int sample_rate_hz, int num_channels));
   MOCK_METHOD1(Process, void(AudioBuffer* audio));
+  MOCK_METHOD1(SetRuntimeSetting,
+               void(AudioProcessing::RuntimeSetting setting));
   MOCK_CONST_METHOD0(ToString, std::string());
 };
 
@@ -146,18 +148,18 @@
         high_pass_filter_(new testing::NiceMock<MockHighPassFilter>()),
         level_estimator_(new testing::NiceMock<MockLevelEstimator>()),
         noise_suppression_(new testing::NiceMock<MockNoiseSuppression>()),
-        voice_detection_(new testing::NiceMock<MockVoiceDetection>()) {
-  }
+        voice_detection_(new testing::NiceMock<MockVoiceDetection>()) {}
 
   virtual ~MockAudioProcessing() {}
 
   MOCK_METHOD0(Initialize, int());
-  MOCK_METHOD6(Initialize, int(int capture_input_sample_rate_hz,
-                               int capture_output_sample_rate_hz,
-                               int render_sample_rate_hz,
-                               ChannelLayout capture_input_layout,
-                               ChannelLayout capture_output_layout,
-                               ChannelLayout render_input_layout));
+  MOCK_METHOD6(Initialize,
+               int(int capture_input_sample_rate_hz,
+                   int capture_output_sample_rate_hz,
+                   int render_sample_rate_hz,
+                   ChannelLayout capture_input_layout,
+                   ChannelLayout capture_output_layout,
+                   ChannelLayout render_input_layout));
   MOCK_METHOD1(Initialize, int(const ProcessingConfig& processing_config));
   MOCK_METHOD1(ApplyConfig, void(const Config& config));
   MOCK_METHOD1(SetExtraOptions, void(const webrtc::Config& config));
@@ -170,26 +172,30 @@
   MOCK_METHOD1(set_output_will_be_muted, void(bool muted));
   MOCK_METHOD1(SetRuntimeSetting, void(RuntimeSetting setting));
   MOCK_METHOD1(ProcessStream, int(AudioFrame* frame));
-  MOCK_METHOD7(ProcessStream, int(const float* const* src,
-                                  size_t samples_per_channel,
-                                  int input_sample_rate_hz,
-                                  ChannelLayout input_layout,
-                                  int output_sample_rate_hz,
-                                  ChannelLayout output_layout,
-                                  float* const* dest));
-  MOCK_METHOD4(ProcessStream, int(const float* const* src,
-                                 const StreamConfig& input_config,
-                                 const StreamConfig& output_config,
-                                 float* const* dest));
+  MOCK_METHOD7(ProcessStream,
+               int(const float* const* src,
+                   size_t samples_per_channel,
+                   int input_sample_rate_hz,
+                   ChannelLayout input_layout,
+                   int output_sample_rate_hz,
+                   ChannelLayout output_layout,
+                   float* const* dest));
+  MOCK_METHOD4(ProcessStream,
+               int(const float* const* src,
+                   const StreamConfig& input_config,
+                   const StreamConfig& output_config,
+                   float* const* dest));
   MOCK_METHOD1(ProcessReverseStream, int(AudioFrame* frame));
-  MOCK_METHOD4(AnalyzeReverseStream, int(const float* const* data,
-                                         size_t samples_per_channel,
-                                         int sample_rate_hz,
-                                         ChannelLayout layout));
-  MOCK_METHOD4(ProcessReverseStream, int(const float* const* src,
-                                         const StreamConfig& input_config,
-                                         const StreamConfig& output_config,
-                                         float* const* dest));
+  MOCK_METHOD4(AnalyzeReverseStream,
+               int(const float* const* data,
+                   size_t samples_per_channel,
+                   int sample_rate_hz,
+                   ChannelLayout layout));
+  MOCK_METHOD4(ProcessReverseStream,
+               int(const float* const* src,
+                   const StreamConfig& input_config,
+                   const StreamConfig& output_config,
+                   float* const* dest));
   MOCK_METHOD1(set_stream_delay_ms, int(int delay));
   MOCK_CONST_METHOD0(stream_delay_ms, int());
   MOCK_CONST_METHOD0(was_stream_delay_set, bool());
@@ -213,9 +219,7 @@
   virtual MockEchoControlMobile* echo_control_mobile() const {
     return echo_control_mobile_.get();
   }
-  virtual MockGainControl* gain_control() const {
-    return gain_control_.get();
-  }
+  virtual MockGainControl* gain_control() const { return gain_control_.get(); }
   virtual MockHighPassFilter* high_pass_filter() const {
     return high_pass_filter_.get();
   }
diff --git a/modules/audio_processing/intelligibility/intelligibility_enhancer.cc b/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
index 0e696d9..0f7b118 100644
--- a/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
+++ b/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
@@ -31,16 +31,16 @@
 const int kChunkSizeMs = 10;  // Size provided by APM.
 const float kClipFreqKhz = 0.2f;
 const float kKbdAlpha = 1.5f;
-const float kLambdaBot = -1.f;      // Extreme values in bisection
-const float kLambdaTop = -1e-5f;      // search for lamda.
+const float kLambdaBot = -1.f;    // Extreme values in bisection
+const float kLambdaTop = -1e-5f;  // search for lamda.
 const float kVoiceProbabilityThreshold = 0.5f;
 // Number of chunks after voice activity which is still considered speech.
 const size_t kSpeechOffsetDelay = 10;
-const float kDecayRate = 0.995f;              // Power estimation decay rate.
+const float kDecayRate = 0.995f;  // Power estimation decay rate.
 const float kMaxRelativeGainChange = 0.005f;
 const float kRho = 0.0004f;  // Default production and interpretation SNR.
 const float kPowerNormalizationFactor = 1.f / (1 << 30);
-const float kMaxActiveSNR = 128.f;  // 21dB
+const float kMaxActiveSNR = 128.f;   // 21dB
 const float kMinInactiveSNR = 32.f;  // 15dB
 const size_t kGainUpdatePeriod = 10u;
 
@@ -133,8 +133,8 @@
   }
 }
 
-void IntelligibilityEnhancer::SetCaptureNoiseEstimate(
-    std::vector<float> noise, float gain) {
+void IntelligibilityEnhancer::SetCaptureNoiseEstimate(std::vector<float> noise,
+                                                      float gain) {
   RTC_DCHECK_EQ(noise.size(), num_noise_bins_);
   for (auto& bin : noise) {
     bin *= gain;
@@ -176,10 +176,9 @@
       MapToErbBands(noise_power_estimator_.power().data(), capture_filter_bank_,
                     filtered_noise_pow_.data());
       SolveForGainsGivenLambda(kLambdaTop, start_freq_, gains_eq_.data());
-      const float power_target = std::accumulate(
-          filtered_clear_pow_.data(),
-          filtered_clear_pow_.data() + bank_size_,
-          0.f);
+      const float power_target =
+          std::accumulate(filtered_clear_pow_.data(),
+                          filtered_clear_pow_.data() + bank_size_, 0.f);
       const float power_top =
           DotProduct(gains_eq_.data(), filtered_clear_pow_.data(), bank_size_);
       SolveForGainsGivenLambda(kLambdaBot, start_freq_, gains_eq_.data());
@@ -199,12 +198,11 @@
 void IntelligibilityEnhancer::SnrBasedEffectActivation() {
   const float* clear_psd = clear_power_estimator_.power().data();
   const float* noise_psd = noise_power_estimator_.power().data();
-  const float clear_power =
-      std::accumulate(clear_psd, clear_psd + freqs_, 0.f);
-  const float noise_power =
-      std::accumulate(noise_psd, noise_psd + freqs_, 0.f);
-  snr_ = kDecayRate * snr_ + (1.f - kDecayRate) * clear_power /
-      (noise_power + std::numeric_limits<float>::epsilon());
+  const float clear_power = std::accumulate(clear_psd, clear_psd + freqs_, 0.f);
+  const float noise_power = std::accumulate(noise_psd, noise_psd + freqs_, 0.f);
+  snr_ = kDecayRate * snr_ +
+         (1.f - kDecayRate) * clear_power /
+             (noise_power + std::numeric_limits<float>::epsilon());
   if (is_active_) {
     if (snr_ > kMaxActiveSNR) {
       RTC_LOG(LS_INFO) << "Intelligibility Enhancer was deactivated at chunk "
diff --git a/modules/audio_processing/intelligibility/intelligibility_enhancer.h b/modules/audio_processing/intelligibility/intelligibility_enhancer.h
index 3e0e269..3513092 100644
--- a/modules/audio_processing/intelligibility/intelligibility_enhancer.h
+++ b/modules/audio_processing/intelligibility/intelligibility_enhancer.h
@@ -93,7 +93,7 @@
 
   static const size_t kMaxNumNoiseEstimatesToBuffer = 5;
 
-  const size_t freqs_;         // Num frequencies in frequency domain.
+  const size_t freqs_;  // Num frequencies in frequency domain.
   const size_t num_noise_bins_;
   const size_t chunk_length_;  // Chunk size in samples.
   const size_t bank_size_;     // Num ERB filters.
diff --git a/modules/audio_processing/intelligibility/intelligibility_utils.cc b/modules/audio_processing/intelligibility/intelligibility_utils.cc
index b6917f4..b606d95 100644
--- a/modules/audio_processing/intelligibility/intelligibility_utils.cc
+++ b/modules/audio_processing/intelligibility/intelligibility_utils.cc
@@ -37,11 +37,11 @@
 
 }  // namespace
 
-template<typename T>
+template <typename T>
 PowerEstimator<T>::PowerEstimator(size_t num_freqs, float decay)
     : power_(num_freqs, 0.f), decay_(decay) {}
 
-template<typename T>
+template <typename T>
 void PowerEstimator<T>::Step(const T* data) {
   for (size_t i = 0; i < power_.size(); ++i) {
     power_[i] = decay_ * power_[i] +
diff --git a/modules/audio_processing/low_cut_filter_unittest.cc b/modules/audio_processing/low_cut_filter_unittest.cc
index d98d665..d7b3cb9 100644
--- a/modules/audio_processing/low_cut_filter_unittest.cc
+++ b/modules/audio_processing/low_cut_filter_unittest.cc
@@ -51,12 +51,10 @@
       (stream_config.num_frames() * stream_config.num_channels());
   for (size_t frame_no = 0; frame_no < num_frames_to_process; ++frame_no) {
     std::vector<float> frame_input(
-        input.begin() +
-            stream_config.num_frames() * stream_config.num_channels() *
-                frame_no,
-        input.begin() +
-            stream_config.num_frames() * stream_config.num_channels() *
-                (frame_no + 1));
+        input.begin() + stream_config.num_frames() *
+                            stream_config.num_channels() * frame_no,
+        input.begin() + stream_config.num_frames() *
+                            stream_config.num_channels() * (frame_no + 1));
 
     output = ProcessOneFrame(frame_input, stream_config, &low_cut_filter);
   }
diff --git a/modules/audio_processing/module.mk b/modules/audio_processing/module.mk
index a6c8dad..d45b414 100644
--- a/modules/audio_processing/module.mk
+++ b/modules/audio_processing/module.mk
@@ -13,9 +13,6 @@
 	modules/audio_processing/agc/utility.o \
 	modules/audio_processing/audio_buffer.o \
 	modules/audio_processing/audio_processing_impl.o \
-	modules/audio_processing/beamformer/array_util.o \
-	modules/audio_processing/beamformer/covariance_matrix_generator.o \
-	modules/audio_processing/beamformer/nonlinear_beamformer.o \
 	modules/audio_processing/echo_cancellation_impl.o \
 	modules/audio_processing/echo_control_mobile_impl.o \
 	modules/audio_processing/echo_detector/circular_buffer.o \
@@ -116,16 +113,22 @@
 	modules/audio_processing/aec3/matched_filter.o \
 	modules/audio_processing/aec3/matched_filter_lag_aggregator.o \
 	modules/audio_processing/aec3/matrix_buffer.o \
+	modules/audio_processing/aec3/moving_average.o \
 	modules/audio_processing/aec3/render_buffer.o \
 	modules/audio_processing/aec3/render_delay_buffer.o \
 	modules/audio_processing/aec3/render_delay_controller.o \
 	modules/audio_processing/aec3/render_delay_controller_metrics.o \
 	modules/audio_processing/aec3/render_signal_analyzer.o \
 	modules/audio_processing/aec3/residual_echo_estimator.o \
+	modules/audio_processing/aec3/reverb_model.o \
+	modules/audio_processing/aec3/reverb_model_estimator.o \
+	modules/audio_processing/aec3/reverb_model_fallback.o \
 	modules/audio_processing/aec3/shadow_filter_update_gain.o \
 	modules/audio_processing/aec3/skew_estimator.o \
 	modules/audio_processing/aec3/stationarity_estimator.o \
 	modules/audio_processing/aec3/subtractor.o \
+	modules/audio_processing/aec3/subtractor_output.o \
+	modules/audio_processing/aec3/subtractor_output_analyzer.o \
 	modules/audio_processing/aec3/suppression_filter.o \
 	modules/audio_processing/aec3/suppression_gain.o \
 	modules/audio_processing/aec3/suppression_gain_limiter.o \
@@ -141,6 +144,7 @@
 	modules/audio_processing/agc2/adaptive_agc.o \
 	modules/audio_processing/agc2/adaptive_digital_gain_applier.o \
 	modules/audio_processing/agc2/adaptive_mode_level_estimator.o \
+	modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.o \
 	modules/audio_processing/agc2/biquad_filter.o \
 	modules/audio_processing/agc2/compute_interpolated_gain_curve.o \
 	modules/audio_processing/agc2/down_sampler.o \
@@ -154,7 +158,18 @@
 	modules/audio_processing/agc2/noise_spectrum_estimator.o \
 	modules/audio_processing/agc2/saturation_protector.o \
 	modules/audio_processing/agc2/signal_classifier.o \
-	modules/audio_processing/agc2/vector_float_frame.o
+	modules/audio_processing/agc2/vad_with_level.o \
+	modules/audio_processing/agc2/vector_float_frame.o \
+	modules/audio_processing/agc2/rnn_vad/features_extraction.o \
+	modules/audio_processing/agc2/rnn_vad/fft_util.o \
+	modules/audio_processing/agc2/rnn_vad/lp_residual.o \
+	modules/audio_processing/agc2/rnn_vad/pitch_search.o \
+	modules/audio_processing/agc2/rnn_vad/pitch_search_internal.o \
+	modules/audio_processing/agc2/rnn_vad/rnn.o \
+	modules/audio_processing/agc2/rnn_vad/spectral_features.o \
+	modules/audio_processing/agc2/rnn_vad/spectral_features_internal.o \
+	third_party/rnnoise/src/kiss_fft.o \
+	third_party/rnnoise/src/rnn_vad_weights.o
 
 # Dependency of agc/agc.o
 vad_CXX_OBJECTS = \
diff --git a/modules/audio_processing/noise_suppression_impl.cc b/modules/audio_processing/noise_suppression_impl.cc
index 8dd713f..15d4043 100644
--- a/modules/audio_processing/noise_suppression_impl.cc
+++ b/modules/audio_processing/noise_suppression_impl.cc
@@ -37,10 +37,9 @@
     int error = NS_INIT(state_, sample_rate_hz);
     RTC_DCHECK_EQ(0, error);
   }
-  ~Suppressor() {
-    NS_FREE(state_);
-  }
+  ~Suppressor() { NS_FREE(state_); }
   NsState* state() { return state_; }
+
  private:
   NsState* state_ = nullptr;
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Suppressor);
@@ -96,15 +95,11 @@
   RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
   for (size_t i = 0; i < suppressors_.size(); i++) {
 #if defined(WEBRTC_NS_FLOAT)
-    WebRtcNs_Process(suppressors_[i]->state(),
-                     audio->split_bands_const_f(i),
-                     audio->num_bands(),
-                     audio->split_bands_f(i));
+    WebRtcNs_Process(suppressors_[i]->state(), audio->split_bands_const_f(i),
+                     audio->num_bands(), audio->split_bands_f(i));
 #elif defined(WEBRTC_NS_FIXED)
-    WebRtcNsx_Process(suppressors_[i]->state(),
-                      audio->split_bands_const(i),
-                      audio->num_bands(),
-                      audio->split_bands(i));
+    WebRtcNsx_Process(suppressors_[i]->state(), audio->split_bands_const(i),
+                      audio->num_bands(), audio->split_bands(i));
 #endif
   }
 }
@@ -190,8 +185,8 @@
   noise_estimate.assign(WebRtcNsx_num_freq(), 0.f);
   for (auto& suppressor : suppressors_) {
     int q_noise;
-    const uint32_t* noise = WebRtcNsx_noise_estimate(suppressor->state(),
-                                                     &q_noise);
+    const uint32_t* noise =
+        WebRtcNsx_noise_estimate(suppressor->state(), &q_noise);
     const float kNormalizationFactor =
         1.f / ((1 << q_noise) * suppressors_.size());
     for (size_t i = 0; i < noise_estimate.size(); ++i) {
diff --git a/modules/audio_processing/noise_suppression_unittest.cc b/modules/audio_processing/noise_suppression_unittest.cc
index 0b734fd..b207485 100644
--- a/modules/audio_processing/noise_suppression_unittest.cc
+++ b/modules/audio_processing/noise_suppression_unittest.cc
@@ -97,18 +97,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono8kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {1432.341431f, 3321.919922f, 7677.521973f};
+  const float kNoiseEstimateReference[] = {1432.341431f, 3321.919922f,
+                                           7677.521973f};
   const float kOutputReference[] = {0.003510f, 0.004517f, 0.004669f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {1432.341431f, 3321.919922f, 7677.521973f};
+  const float kNoiseEstimateReference[] = {1432.341431f, 3321.919922f,
+                                           7677.521973f};
   const float kOutputReference[] = {0.003510f, 0.004517f, 0.004669f};
 #else
   const float kSpeechProbabilityReference = 0.73421317f;
-  const float kNoiseEstimateReference[] =
-      {1175.266113f, 3289.305908f, 7532.991211f};
+  const float kNoiseEstimateReference[] = {1175.266113f, 3289.305908f,
+                                           7532.991211f};
   const float kOutputReference[] = {0.003263f, 0.004402f, 0.004537f};
 #endif
 
@@ -120,18 +120,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono16kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2534.461914f, 6277.638672f, 14367.499023f};
+  const float kNoiseEstimateReference[] = {2534.461914f, 6277.638672f,
+                                           14367.499023f};
   const float kOutputReference[] = {0.003449f, 0.004334f, 0.004303f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2534.461914f, 6277.638672f, 14367.499023f};
+  const float kNoiseEstimateReference[] = {2534.461914f, 6277.638672f,
+                                           14367.499023f};
   const float kOutputReference[] = {0.003449f, 0.004334f, 0.004303f};
 #else
   const float kSpeechProbabilityReference = 0.71672988f;
-  const float kNoiseEstimateReference[] =
-      {2151.313965f, 6509.765137f, 15658.848633f};
+  const float kNoiseEstimateReference[] = {2151.313965f, 6509.765137f,
+                                           15658.848633f};
   const float kOutputReference[] = {0.003574f, 0.004494f, 0.004499f};
 #endif
 
@@ -143,18 +143,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono32kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2540.059082f, 6317.822754f, 14440.845703f};
+  const float kNoiseEstimateReference[] = {2540.059082f, 6317.822754f,
+                                           14440.845703f};
   const float kOutputReference[] = {0.001679f, 0.002411f, 0.002594f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2540.059082f, 6317.822754f, 14440.845703f};
+  const float kNoiseEstimateReference[] = {2540.059082f, 6317.822754f,
+                                           14440.845703f};
   const float kOutputReference[] = {0.001679f, 0.002411f, 0.002594f};
 #else
   const float kSpeechProbabilityReference = 0.67999554f;
-  const float kNoiseEstimateReference[] =
-      {2149.780518f, 7076.936035f, 14939.945312f};
+  const float kNoiseEstimateReference[] = {2149.780518f, 7076.936035f,
+                                           14939.945312f};
   const float kOutputReference[] = {0.001221f, 0.001984f, 0.002228f};
 #endif
 
@@ -166,18 +166,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono48kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2564.605713f, 6213.656250f, 13372.284180f};
+  const float kNoiseEstimateReference[] = {2564.605713f, 6213.656250f,
+                                           13372.284180f};
   const float kOutputReference[] = {-0.013185f, -0.012769f, -0.012023f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2564.605713f, 6213.656250f, 13372.284180f};
+  const float kNoiseEstimateReference[] = {2564.605713f, 6213.656250f,
+                                           13372.284180f};
   const float kOutputReference[] = {-0.013185f, -0.012769f, -0.012023f};
 #else
   const float kSpeechProbabilityReference = 0.70645678f;
-  const float kNoiseEstimateReference[] =
-      {2168.783203f, 6902.895508f, 13190.677734f};
+  const float kNoiseEstimateReference[] = {2168.783203f, 6902.895508f,
+                                           13190.677734f};
   const float kOutputReference[] = {-0.013062f, -0.012657f, -0.011934f};
 #endif
 
@@ -189,20 +189,20 @@
 TEST(NoiseSuppresionBitExactnessTest, Stereo16kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {9992.127930f, 12689.569336f, 11589.296875f};
+  const float kNoiseEstimateReference[] = {9992.127930f, 12689.569336f,
+                                           11589.296875f};
   const float kOutputReference[] = {-0.011108f, -0.007904f, -0.012390f,
                                     -0.002441f, 0.000855f,  -0.003204f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {10321.353516f, 12133.852539f, 10923.060547f};
+  const float kNoiseEstimateReference[] = {10321.353516f, 12133.852539f,
+                                           10923.060547f};
   const float kOutputReference[] = {-0.011108f, -0.007904f, -0.012390f,
                                     -0.002472f, 0.000916f,  -0.003235f};
 #else
   const float kSpeechProbabilityReference = 0.67230678f;
-  const float kNoiseEstimateReference[] =
-      {9771.250000f, 11329.377930f, 10503.052734f};
+  const float kNoiseEstimateReference[] = {9771.250000f, 11329.377930f,
+                                           10503.052734f};
   const float kOutputReference[] = {-0.011459f, -0.008110f, -0.012728f,
                                     -0.002399f, 0.001018f,  -0.003189f};
 #endif
@@ -215,18 +215,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono16kHzModerate) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2057.085938f, 7601.055176f, 19666.187500f};
+  const float kNoiseEstimateReference[] = {2057.085938f, 7601.055176f,
+                                           19666.187500f};
   const float kOutputReference[] = {0.004669f, 0.005524f, 0.005432f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2244.497803f, 6864.164062f, 16726.523438f};
+  const float kNoiseEstimateReference[] = {2244.497803f, 6864.164062f,
+                                           16726.523438f};
   const float kOutputReference[] = {0.004669f, 0.005615f, 0.005585f};
 #else
   const float kSpeechProbabilityReference = 0.70897013f;
-  const float kNoiseEstimateReference[] =
-      {2171.490723f, 6553.567871f, 15626.562500f};
+  const float kNoiseEstimateReference[] = {2171.490723f, 6553.567871f,
+                                           15626.562500f};
   const float kOutputReference[] = {0.004513f, 0.005590f, 0.005614f};
 #endif
 
@@ -238,18 +238,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono16kHzHigh) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2095.148193f, 7698.553711f, 19689.533203f};
+  const float kNoiseEstimateReference[] = {2095.148193f, 7698.553711f,
+                                           19689.533203f};
   const float kOutputReference[] = {0.004639f, 0.005402f, 0.005310f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2282.515625f, 6984.408203f, 16920.960938f};
+  const float kNoiseEstimateReference[] = {2282.515625f, 6984.408203f,
+                                           16920.960938f};
   const float kOutputReference[] = {0.004547f, 0.005432f, 0.005402f};
 #else
   const float kSpeechProbabilityReference = 0.70106733f;
-  const float kNoiseEstimateReference[] =
-      {2224.968506f, 6712.025879f, 15785.087891f};
+  const float kNoiseEstimateReference[] = {2224.968506f, 6712.025879f,
+                                           15785.087891f};
   const float kOutputReference[] = {0.004394f, 0.005406f, 0.005416f};
 #endif
 
@@ -261,18 +261,18 @@
 TEST(NoiseSuppresionBitExactnessTest, Mono16kHzVeryHigh) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2677.733398f, 6186.987305f, 14365.744141f};
+  const float kNoiseEstimateReference[] = {2677.733398f, 6186.987305f,
+                                           14365.744141f};
   const float kOutputReference[] = {0.004273f, 0.005127f, 0.005188f};
 #elif defined(WEBRTC_ARCH_ARM)
   const float kSpeechProbabilityReference = -4.0f;
-  const float kNoiseEstimateReference[] =
-      {2677.733398f, 6186.987305f, 14365.744141f};
+  const float kNoiseEstimateReference[] = {2677.733398f, 6186.987305f,
+                                           14365.744141f};
   const float kOutputReference[] = {0.004273f, 0.005127f, 0.005188f};
 #else
   const float kSpeechProbabilityReference = 0.70281971f;
-  const float kNoiseEstimateReference[] =
-      {2254.347900f, 6723.699707f, 15771.625977f};
+  const float kNoiseEstimateReference[] = {2254.347900f, 6723.699707f,
+                                           15771.625977f};
   const float kOutputReference[] = {0.004321f, 0.005247f, 0.005263f};
 #endif
 
diff --git a/modules/audio_processing/ns/defines.h b/modules/audio_processing/ns/defines.h
index 66b45a9..d6abfea 100644
--- a/modules/audio_processing/ns/defines.h
+++ b/modules/audio_processing/ns/defines.h
@@ -11,39 +11,45 @@
 #ifndef MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
 #define MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
 
-#define BLOCKL_MAX          160 // max processing block length: 160
-#define ANAL_BLOCKL_MAX     256 // max analysis block length: 256
-#define HALF_ANAL_BLOCKL    129 // half max analysis block length + 1
-#define NUM_HIGH_BANDS_MAX  2   // max number of high bands: 2
+#define BLOCKL_MAX 160        // max processing block length: 160
+#define ANAL_BLOCKL_MAX 256   // max analysis block length: 256
+#define HALF_ANAL_BLOCKL 129  // half max analysis block length + 1
+#define NUM_HIGH_BANDS_MAX 2  // max number of high bands: 2
 
-#define QUANTILE            (float)0.25
+#define QUANTILE (float)0.25
 
-#define SIMULT              3
-#define END_STARTUP_LONG    200
-#define END_STARTUP_SHORT   50
-#define FACTOR              (float)40.0
-#define WIDTH               (float)0.01
+#define SIMULT 3
+#define END_STARTUP_LONG 200
+#define END_STARTUP_SHORT 50
+#define FACTOR (float)40.0
+#define WIDTH (float)0.01
 
 // Length of fft work arrays.
-#define IP_LENGTH (ANAL_BLOCKL_MAX >> 1) // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2))
+#define IP_LENGTH \
+  (ANAL_BLOCKL_MAX >> 1)  // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2))
 #define W_LENGTH (ANAL_BLOCKL_MAX >> 1)
 
-//PARAMETERS FOR NEW METHOD
-#define DD_PR_SNR           (float)0.98 // DD update of prior SNR
-#define LRT_TAVG            (float)0.50 // tavg parameter for LRT (previously 0.90)
-#define SPECT_FL_TAVG       (float)0.30 // tavg parameter for spectral flatness measure
-#define SPECT_DIFF_TAVG     (float)0.30 // tavg parameter for spectral difference measure
-#define PRIOR_UPDATE        (float)0.10 // update parameter of prior model
-#define NOISE_UPDATE        (float)0.90 // update parameter for noise
-#define SPEECH_UPDATE       (float)0.99 // update parameter when likely speech
-#define WIDTH_PR_MAP        (float)4.0  // width parameter in sigmoid map for prior model
-#define LRT_FEATURE_THR     (float)0.5  // default threshold for LRT feature
-#define SF_FEATURE_THR      (float)0.5  // default threshold for Spectral Flatness feature
-#define SD_FEATURE_THR      (float)0.5  // default threshold for Spectral Difference feature
-#define PROB_RANGE          (float)0.20 // probability threshold for noise state in
-                                        // speech/noise likelihood
-#define HIST_PAR_EST         1000       // histogram size for estimation of parameters
-#define GAMMA_PAUSE         (float)0.05 // update for conservative noise estimate
+// PARAMETERS FOR NEW METHOD
+#define DD_PR_SNR (float)0.98  // DD update of prior SNR
+#define LRT_TAVG (float)0.50   // tavg parameter for LRT (previously 0.90)
+#define SPECT_FL_TAVG \
+  (float)0.30  // tavg parameter for spectral flatness measure
+#define SPECT_DIFF_TAVG \
+  (float)0.30  // tavg parameter for spectral difference measure
+#define PRIOR_UPDATE (float)0.10   // update parameter of prior model
+#define NOISE_UPDATE (float)0.90   // update parameter for noise
+#define SPEECH_UPDATE (float)0.99  // update parameter when likely speech
+#define WIDTH_PR_MAP \
+  (float)4.0  // width parameter in sigmoid map for prior model
+#define LRT_FEATURE_THR (float)0.5  // default threshold for LRT feature
+#define SF_FEATURE_THR \
+  (float)0.5  // default threshold for Spectral Flatness feature
+#define SD_FEATURE_THR \
+  (float)0.5  // default threshold for Spectral Difference feature
+#define PROB_RANGE (float)0.20   // probability threshold for noise state in
+                                 // speech/noise likelihood
+#define HIST_PAR_EST 1000        // histogram size for estimation of parameters
+#define GAMMA_PAUSE (float)0.05  // update for conservative noise estimate
 //
-#define B_LIM               (float)0.5  // threshold in final energy gain factor calculation
-#endif // MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
+#define B_LIM (float)0.5  // threshold in final energy gain factor calculation
+#endif                    // MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
diff --git a/modules/audio_processing/ns/noise_suppression.h b/modules/audio_processing/ns/noise_suppression.h
index fa5da70..fd6aa96 100644
--- a/modules/audio_processing/ns/noise_suppression.h
+++ b/modules/audio_processing/ns/noise_suppression.h
@@ -93,9 +93,9 @@
  *      - outframe      : Pointer to output frame for each band
  */
 void WebRtcNs_Process(NsHandle* NS_inst,
-                     const float* const* spframe,
-                     size_t num_bands,
-                     float* const* outframe);
+                      const float* const* spframe,
+                      size_t num_bands,
+                      float* const* outframe);
 
 /* Returns the internally used prior speech probability of the current frame.
  * There is a frequency bin based one as well, with which this should not be
diff --git a/modules/audio_processing/ns/ns_core.h b/modules/audio_processing/ns/ns_core.h
index 990d363..e90b8ce 100644
--- a/modules/audio_processing/ns/ns_core.h
+++ b/modules/audio_processing/ns/ns_core.h
@@ -78,26 +78,26 @@
   float wfft[W_LENGTH];
 
   // Parameters for new method: some not needed, will reduce/cleanup later.
-  int32_t blockInd;  // Frame index counter.
+  int32_t blockInd;        // Frame index counter.
   int modelUpdatePars[4];  // Parameters for updating or estimating.
   // Thresholds/weights for prior model.
-  float priorModelPars[7];  // Parameters for prior model.
-  float noise[HALF_ANAL_BLOCKL];  // Noise spectrum from current frame.
+  float priorModelPars[7];            // Parameters for prior model.
+  float noise[HALF_ANAL_BLOCKL];      // Noise spectrum from current frame.
   float noisePrev[HALF_ANAL_BLOCKL];  // Noise spectrum from previous frame.
   // Magnitude spectrum of previous analyze frame.
   float magnPrevAnalyze[HALF_ANAL_BLOCKL];
   // Magnitude spectrum of previous process frame.
   float magnPrevProcess[HALF_ANAL_BLOCKL];
   float logLrtTimeAvg[HALF_ANAL_BLOCKL];  // Log LRT factor with time-smoothing.
-  float priorSpeechProb;  // Prior speech/noise probability.
+  float priorSpeechProb;                  // Prior speech/noise probability.
   float featureData[7];
   // Conservative noise spectrum estimate.
   float magnAvgPause[HALF_ANAL_BLOCKL];
   float signalEnergy;  // Energy of |magn|.
   float sumMagn;
-  float whiteNoiseLevel;  // Initial noise estimate.
+  float whiteNoiseLevel;                // Initial noise estimate.
   float initMagnEst[HALF_ANAL_BLOCKL];  // Initial magnitude spectrum estimate.
-  float pinkNoiseNumerator;  // Pink noise parameter: numerator.
+  float pinkNoiseNumerator;             // Pink noise parameter: numerator.
   float pinkNoiseExp;  // Pink noise parameter: power of frequencies.
   float parametricNoise[HALF_ANAL_BLOCKL];
   // Parameters for feature extraction.
diff --git a/modules/audio_processing/ns/nsx_core.h b/modules/audio_processing/ns/nsx_core.h
index c8097f7..479e90c 100644
--- a/modules/audio_processing/ns/nsx_core.h
+++ b/modules/audio_processing/ns/nsx_core.h
@@ -20,98 +20,97 @@
 #include "typedefs.h"  // NOLINT(build/include)
 
 typedef struct NoiseSuppressionFixedC_ {
-  uint32_t                fs;
+  uint32_t fs;
 
-  const int16_t*          window;
-  int16_t                 analysisBuffer[ANAL_BLOCKL_MAX];
-  int16_t                 synthesisBuffer[ANAL_BLOCKL_MAX];
-  uint16_t                noiseSupFilter[HALF_ANAL_BLOCKL];
-  uint16_t                overdrive; /* Q8 */
-  uint16_t                denoiseBound; /* Q14 */
-  const int16_t*          factor2Table;
-  int16_t                 noiseEstLogQuantile[SIMULT* HALF_ANAL_BLOCKL];
-  int16_t                 noiseEstDensity[SIMULT* HALF_ANAL_BLOCKL];
-  int16_t                 noiseEstCounter[SIMULT];
-  int16_t                 noiseEstQuantile[HALF_ANAL_BLOCKL];
+  const int16_t* window;
+  int16_t analysisBuffer[ANAL_BLOCKL_MAX];
+  int16_t synthesisBuffer[ANAL_BLOCKL_MAX];
+  uint16_t noiseSupFilter[HALF_ANAL_BLOCKL];
+  uint16_t overdrive;    /* Q8 */
+  uint16_t denoiseBound; /* Q14 */
+  const int16_t* factor2Table;
+  int16_t noiseEstLogQuantile[SIMULT * HALF_ANAL_BLOCKL];
+  int16_t noiseEstDensity[SIMULT * HALF_ANAL_BLOCKL];
+  int16_t noiseEstCounter[SIMULT];
+  int16_t noiseEstQuantile[HALF_ANAL_BLOCKL];
 
-  size_t                  anaLen;
-  size_t                  anaLen2;
-  size_t                  magnLen;
-  int                     aggrMode;
-  int                     stages;
-  int                     initFlag;
-  int                     gainMap;
+  size_t anaLen;
+  size_t anaLen2;
+  size_t magnLen;
+  int aggrMode;
+  int stages;
+  int initFlag;
+  int gainMap;
 
-  int32_t                 maxLrt;
-  int32_t                 minLrt;
+  int32_t maxLrt;
+  int32_t minLrt;
   // Log LRT factor with time-smoothing in Q8.
-  int32_t                 logLrtTimeAvgW32[HALF_ANAL_BLOCKL];
-  int32_t                 featureLogLrt;
-  int32_t                 thresholdLogLrt;
-  int16_t                 weightLogLrt;
+  int32_t logLrtTimeAvgW32[HALF_ANAL_BLOCKL];
+  int32_t featureLogLrt;
+  int32_t thresholdLogLrt;
+  int16_t weightLogLrt;
 
-  uint32_t                featureSpecDiff;
-  uint32_t                thresholdSpecDiff;
-  int16_t                 weightSpecDiff;
+  uint32_t featureSpecDiff;
+  uint32_t thresholdSpecDiff;
+  int16_t weightSpecDiff;
 
-  uint32_t                featureSpecFlat;
-  uint32_t                thresholdSpecFlat;
-  int16_t                 weightSpecFlat;
+  uint32_t featureSpecFlat;
+  uint32_t thresholdSpecFlat;
+  int16_t weightSpecFlat;
 
   // Conservative estimate of noise spectrum.
-  int32_t                 avgMagnPause[HALF_ANAL_BLOCKL];
-  uint32_t                magnEnergy;
-  uint32_t                sumMagn;
-  uint32_t                curAvgMagnEnergy;
-  uint32_t                timeAvgMagnEnergy;
-  uint32_t                timeAvgMagnEnergyTmp;
+  int32_t avgMagnPause[HALF_ANAL_BLOCKL];
+  uint32_t magnEnergy;
+  uint32_t sumMagn;
+  uint32_t curAvgMagnEnergy;
+  uint32_t timeAvgMagnEnergy;
+  uint32_t timeAvgMagnEnergyTmp;
 
-  uint32_t                whiteNoiseLevel;  // Initial noise estimate.
+  uint32_t whiteNoiseLevel;  // Initial noise estimate.
   // Initial magnitude spectrum estimate.
-  uint32_t                initMagnEst[HALF_ANAL_BLOCKL];
+  uint32_t initMagnEst[HALF_ANAL_BLOCKL];
   // Pink noise parameters:
-  int32_t                 pinkNoiseNumerator;  // Numerator.
-  int32_t                 pinkNoiseExp;  // Power of freq.
-  int                     minNorm;  // Smallest normalization factor.
-  int                     zeroInputSignal;  // Zero input signal flag.
+  int32_t pinkNoiseNumerator;  // Numerator.
+  int32_t pinkNoiseExp;        // Power of freq.
+  int minNorm;                 // Smallest normalization factor.
+  int zeroInputSignal;         // Zero input signal flag.
 
   // Noise spectrum from previous frame.
-  uint32_t                prevNoiseU32[HALF_ANAL_BLOCKL];
+  uint32_t prevNoiseU32[HALF_ANAL_BLOCKL];
   // Magnitude spectrum from previous frame.
-  uint16_t                prevMagnU16[HALF_ANAL_BLOCKL];
+  uint16_t prevMagnU16[HALF_ANAL_BLOCKL];
   // Prior speech/noise probability in Q14.
-  int16_t                 priorNonSpeechProb;
+  int16_t priorNonSpeechProb;
 
-  int                     blockIndex;  // Frame index counter.
+  int blockIndex;  // Frame index counter.
   // Parameter for updating or estimating thresholds/weights for prior model.
-  int                     modelUpdate;
-  int                     cntThresUpdate;
+  int modelUpdate;
+  int cntThresUpdate;
 
   // Histograms for parameter estimation.
-  int16_t                 histLrt[HIST_PAR_EST];
-  int16_t                 histSpecFlat[HIST_PAR_EST];
-  int16_t                 histSpecDiff[HIST_PAR_EST];
+  int16_t histLrt[HIST_PAR_EST];
+  int16_t histSpecFlat[HIST_PAR_EST];
+  int16_t histSpecDiff[HIST_PAR_EST];
 
   // Quantities for high band estimate.
-  int16_t                 dataBufHBFX[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
+  int16_t dataBufHBFX[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
 
-  int                     qNoise;
-  int                     prevQNoise;
-  int                     prevQMagn;
-  size_t                  blockLen10ms;
+  int qNoise;
+  int prevQNoise;
+  int prevQMagn;
+  size_t blockLen10ms;
 
-  int16_t                 real[ANAL_BLOCKL_MAX];
-  int16_t                 imag[ANAL_BLOCKL_MAX];
-  int32_t                 energyIn;
-  int                     scaleEnergyIn;
-  int                     normData;
+  int16_t real[ANAL_BLOCKL_MAX];
+  int16_t imag[ANAL_BLOCKL_MAX];
+  int32_t energyIn;
+  int scaleEnergyIn;
+  int normData;
 
   struct RealFFT* real_fft;
 } NoiseSuppressionFixedC;
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 /****************************************************************************
diff --git a/modules/audio_processing/ns/nsx_defines.h b/modules/audio_processing/ns/nsx_defines.h
index 12869b3..dc14dbc 100644
--- a/modules/audio_processing/ns/nsx_defines.h
+++ b/modules/audio_processing/ns/nsx_defines.h
@@ -11,54 +11,64 @@
 #ifndef MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_
 #define MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_
 
-#define ANAL_BLOCKL_MAX         256 /* Max analysis block length */
-#define HALF_ANAL_BLOCKL        129 /* Half max analysis block length + 1 */
-#define NUM_HIGH_BANDS_MAX      2   /* Max number of high bands */
-#define SIMULT                  3
-#define END_STARTUP_LONG        200
-#define END_STARTUP_SHORT       50
-#define FACTOR_Q16              2621440 /* 40 in Q16 */
-#define FACTOR_Q7               5120 /* 40 in Q7 */
-#define FACTOR_Q7_STARTUP       1024 /* 8 in Q7 */
-#define WIDTH_Q8                3 /* 0.01 in Q8 (or 25 ) */
+#define ANAL_BLOCKL_MAX 256  /* Max analysis block length */
+#define HALF_ANAL_BLOCKL 129 /* Half max analysis block length + 1 */
+#define NUM_HIGH_BANDS_MAX 2 /* Max number of high bands */
+#define SIMULT 3
+#define END_STARTUP_LONG 200
+#define END_STARTUP_SHORT 50
+#define FACTOR_Q16 2621440     /* 40 in Q16 */
+#define FACTOR_Q7 5120         /* 40 in Q7 */
+#define FACTOR_Q7_STARTUP 1024 /* 8 in Q7 */
+#define WIDTH_Q8 3             /* 0.01 in Q8 (or 25 ) */
 
 /* PARAMETERS FOR NEW METHOD */
-#define DD_PR_SNR_Q11           2007 /* ~= Q11(0.98) DD update of prior SNR */
+#define DD_PR_SNR_Q11 2007         /* ~= Q11(0.98) DD update of prior SNR */
 #define ONE_MINUS_DD_PR_SNR_Q11 41 /* DD update of prior SNR */
-#define SPECT_FLAT_TAVG_Q14     4915 /* (0.30) tavg parameter for spectral flatness measure */
-#define SPECT_DIFF_TAVG_Q8      77 /* (0.30) tavg parameter for spectral flatness measure */
-#define PRIOR_UPDATE_Q14        1638 /* Q14(0.1) Update parameter of prior model */
-#define NOISE_UPDATE_Q8         26 /* 26 ~= Q8(0.1) Update parameter for noise */
+#define SPECT_FLAT_TAVG_Q14 \
+  4915 /* (0.30) tavg parameter for spectral flatness measure */
+#define SPECT_DIFF_TAVG_Q8 \
+  77 /* (0.30) tavg parameter for spectral flatness measure */
+#define PRIOR_UPDATE_Q14 1638 /* Q14(0.1) Update parameter of prior model */
+#define NOISE_UPDATE_Q8 26    /* 26 ~= Q8(0.1) Update parameter for noise */
 
 /* Probability threshold for noise state in speech/noise likelihood. */
 #define ONE_MINUS_PROB_RANGE_Q8 205 /* 205 ~= Q8(0.8) */
-#define HIST_PAR_EST            1000 /* Histogram size for estimation of parameters */
+#define HIST_PAR_EST 1000 /* Histogram size for estimation of parameters */
 
 /* FEATURE EXTRACTION CONFIG  */
 /* Bin size of histogram */
-#define BIN_SIZE_LRT            10
-/* Scale parameters: multiply dominant peaks of the histograms by scale factor to obtain. */
+#define BIN_SIZE_LRT 10
+/* Scale parameters: multiply dominant peaks of the histograms by scale factor
+ * to obtain. */
 /* Thresholds for prior model */
-#define FACTOR_1_LRT_DIFF       6 /* For LRT and spectral difference (5 times bigger) */
-/* For spectral_flatness: used when noise is flatter than speech (10 times bigger). */
-#define FACTOR_2_FLAT_Q10       922
+#define FACTOR_1_LRT_DIFF \
+  6 /* For LRT and spectral difference (5 times bigger) */
+/* For spectral_flatness: used when noise is flatter than speech (10 times
+ * bigger). */
+#define FACTOR_2_FLAT_Q10 922
 /* Peak limit for spectral flatness (varies between 0 and 1) */
-#define THRES_PEAK_FLAT         24 /* * 2 * BIN_SIZE_FLAT_FX */
-/* Limit on spacing of two highest peaks in histogram: spacing determined by bin size. */
-#define LIM_PEAK_SPACE_FLAT_DIFF    4 /* * 2 * BIN_SIZE_DIFF_FX */
+#define THRES_PEAK_FLAT 24 /* * 2 * BIN_SIZE_FLAT_FX */
+/* Limit on spacing of two highest peaks in histogram: spacing determined by bin
+ * size. */
+#define LIM_PEAK_SPACE_FLAT_DIFF 4 /* * 2 * BIN_SIZE_DIFF_FX */
 /* Limit on relevance of second peak */
-#define LIM_PEAK_WEIGHT_FLAT_DIFF   2
-#define THRES_FLUCT_LRT         10240 /* = 20 * inst->modelUpdate; fluctuation limit of LRT feat. */
+#define LIM_PEAK_WEIGHT_FLAT_DIFF 2
+#define THRES_FLUCT_LRT \
+  10240 /* = 20 * inst->modelUpdate; fluctuation limit of LRT feat. */
 /* Limit on the max and min values for the feature thresholds */
-#define MAX_FLAT_Q10            38912 /*  * 2 * BIN_SIZE_FLAT_FX */
-#define MIN_FLAT_Q10            4096 /*  * 2 * BIN_SIZE_FLAT_FX */
-#define MAX_DIFF                100 /* * 2 * BIN_SIZE_DIFF_FX */
-#define MIN_DIFF                16 /* * 2 * BIN_SIZE_DIFF_FX */
+#define MAX_FLAT_Q10 38912 /*  * 2 * BIN_SIZE_FLAT_FX */
+#define MIN_FLAT_Q10 4096  /*  * 2 * BIN_SIZE_FLAT_FX */
+#define MAX_DIFF 100       /* * 2 * BIN_SIZE_DIFF_FX */
+#define MIN_DIFF 16        /* * 2 * BIN_SIZE_DIFF_FX */
 /* Criteria of weight of histogram peak  to accept/reject feature */
-#define THRES_WEIGHT_FLAT_DIFF  154 /*(int)(0.3*(inst->modelUpdate)) for flatness and difference */
+#define THRES_WEIGHT_FLAT_DIFF \
+  154 /*(int)(0.3*(inst->modelUpdate)) for flatness and difference */
 
-#define STAT_UPDATES            9 /* Update every 512 = 1 << 9 block */
-#define ONE_MINUS_GAMMA_PAUSE_Q8    13 /* ~= Q8(0.05) Update for conservative noise estimate */
-#define GAMMA_NOISE_TRANS_AND_SPEECH_Q8 3 /* ~= Q8(0.01) Update for transition and noise region */
+#define STAT_UPDATES 9 /* Update every 512 = 1 << 9 block */
+#define ONE_MINUS_GAMMA_PAUSE_Q8 \
+  13 /* ~= Q8(0.05) Update for conservative noise estimate */
+#define GAMMA_NOISE_TRANS_AND_SPEECH_Q8 \
+  3 /* ~= Q8(0.01) Update for transition and noise region */
 
 #endif /* MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_ */
diff --git a/modules/audio_processing/ns/windows_private.h b/modules/audio_processing/ns/windows_private.h
index 2ffd693..17792ec 100644
--- a/modules/audio_processing/ns/windows_private.h
+++ b/modules/audio_processing/ns/windows_private.h
@@ -13,562 +13,660 @@
 
 // Hanning window for 4ms 16kHz
 static const float kHanning64w128[128] = {
-  0.00000000000000f, 0.02454122852291f, 0.04906767432742f,
-  0.07356456359967f, 0.09801714032956f, 0.12241067519922f,
-  0.14673047445536f, 0.17096188876030f, 0.19509032201613f,
-  0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
-  0.29028467725446f, 0.31368174039889f, 0.33688985339222f,
-  0.35989503653499f, 0.38268343236509f, 0.40524131400499f,
-  0.42755509343028f, 0.44961132965461f, 0.47139673682600f,
-  0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
-  0.55557023301960f, 0.57580819141785f, 0.59569930449243f,
-  0.61523159058063f, 0.63439328416365f, 0.65317284295378f,
-  0.67155895484702f, 0.68954054473707f, 0.70710678118655f,
-  0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
-  0.77301045336274f, 0.78834642762661f, 0.80320753148064f,
-  0.81758481315158f, 0.83146961230255f, 0.84485356524971f,
-  0.85772861000027f, 0.87008699110871f, 0.88192126434835f,
-  0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
-  0.92387953251129f, 0.93299279883474f, 0.94154406518302f,
-  0.94952818059304f, 0.95694033573221f, 0.96377606579544f,
-  0.97003125319454f, 0.97570213003853f, 0.98078528040323f,
-  0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
-  0.99518472667220f, 0.99729045667869f, 0.99879545620517f,
-  0.99969881869620f, 1.00000000000000f,
-  0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
-  0.99518472667220f, 0.99247953459871f, 0.98917650996478f,
-  0.98527764238894f, 0.98078528040323f, 0.97570213003853f,
-  0.97003125319454f, 0.96377606579544f, 0.95694033573221f,
-  0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
-  0.92387953251129f, 0.91420975570353f, 0.90398929312344f,
-  0.89322430119552f, 0.88192126434835f, 0.87008699110871f,
-  0.85772861000027f, 0.84485356524971f, 0.83146961230255f,
-  0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
-  0.77301045336274f, 0.75720884650648f, 0.74095112535496f,
-  0.72424708295147f, 0.70710678118655f, 0.68954054473707f,
-  0.67155895484702f, 0.65317284295378f, 0.63439328416365f,
-  0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
-  0.55557023301960f, 0.53499761988710f, 0.51410274419322f,
-  0.49289819222978f, 0.47139673682600f, 0.44961132965461f,
-  0.42755509343028f, 0.40524131400499f, 0.38268343236509f,
-  0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
-  0.29028467725446f, 0.26671275747490f, 0.24298017990326f,
-  0.21910124015687f, 0.19509032201613f, 0.17096188876030f,
-  0.14673047445536f, 0.12241067519922f, 0.09801714032956f,
-  0.07356456359967f, 0.04906767432742f, 0.02454122852291f
-};
-
-
+    0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
+    0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
+    0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
+    0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
+    0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
+    0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
+    0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
+    0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
+    0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
+    0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
+    0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
+    0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
+    0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
+    0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
+    0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
+    0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
+    1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
+    0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
+    0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
+    0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
+    0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
+    0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
+    0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
+    0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
+    0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
+    0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
+    0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
+    0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
+    0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
+    0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
+    0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
+    0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
 
 // hybrib Hanning & flat window
 static const float kBlocks80w128[128] = {
-  (float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714, (float)0.13052619,
-  (float)0.16289547, (float)0.19509032, (float)0.22707626, (float)0.25881905, (float)0.29028468,
-  (float)0.32143947, (float)0.35225005, (float)0.38268343, (float)0.41270703, (float)0.44228869,
-  (float)0.47139674, (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770,
-  (float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230, (float)0.70710678,
-  (float)0.72986407, (float)0.75183981, (float)0.77301045, (float)0.79335334, (float)0.81284668,
-  (float)0.83146961, (float)0.84920218, (float)0.86602540, (float)0.88192126, (float)0.89687274,
-  (float)0.91086382, (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034,
-  (float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333, (float)0.99144486,
-  (float)0.99518473, (float)0.99785892, (float)0.99946459, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473, (float)0.99144486,
-  (float)0.98664333, (float)0.98078528, (float)0.97387698, (float)0.96592583, (float)0.95694034,
-  (float)0.94693013, (float)0.93590593, (float)0.92387953, (float)0.91086382, (float)0.89687274,
-  (float)0.88192126, (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668,
-  (float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407, (float)0.70710678,
-  (float)0.68359230, (float)0.65934582, (float)0.63439328, (float)0.60876143, (float)0.58247770,
-  (float)0.55557023, (float)0.52806785, (float)0.50000000, (float)0.47139674, (float)0.44228869,
-  (float)0.41270703, (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468,
-  (float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547, (float)0.13052619,
-  (float)0.09801714, (float)0.06540313, (float)0.03271908
-};
+    (float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714,
+    (float)0.13052619, (float)0.16289547, (float)0.19509032, (float)0.22707626,
+    (float)0.25881905, (float)0.29028468, (float)0.32143947, (float)0.35225005,
+    (float)0.38268343, (float)0.41270703, (float)0.44228869, (float)0.47139674,
+    (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770,
+    (float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230,
+    (float)0.70710678, (float)0.72986407, (float)0.75183981, (float)0.77301045,
+    (float)0.79335334, (float)0.81284668, (float)0.83146961, (float)0.84920218,
+    (float)0.86602540, (float)0.88192126, (float)0.89687274, (float)0.91086382,
+    (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034,
+    (float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333,
+    (float)0.99144486, (float)0.99518473, (float)0.99785892, (float)0.99946459,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473,
+    (float)0.99144486, (float)0.98664333, (float)0.98078528, (float)0.97387698,
+    (float)0.96592583, (float)0.95694034, (float)0.94693013, (float)0.93590593,
+    (float)0.92387953, (float)0.91086382, (float)0.89687274, (float)0.88192126,
+    (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668,
+    (float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407,
+    (float)0.70710678, (float)0.68359230, (float)0.65934582, (float)0.63439328,
+    (float)0.60876143, (float)0.58247770, (float)0.55557023, (float)0.52806785,
+    (float)0.50000000, (float)0.47139674, (float)0.44228869, (float)0.41270703,
+    (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468,
+    (float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547,
+    (float)0.13052619, (float)0.09801714, (float)0.06540313, (float)0.03271908};
 
 // hybrib Hanning & flat window
 static const float kBlocks160w256[256] = {
-  (float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767, (float)0.06540313,
-  (float)0.08172107, (float)0.09801714, (float)0.11428696, (float)0.13052619, (float)0.14673047,
-  (float)0.16289547, (float)0.17901686, (float)0.19509032, (float)0.21111155, (float)0.22707626,
-  (float)0.24298018, (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302,
-  (float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594, (float)0.38268343,
-  (float)0.39774847, (float)0.41270703, (float)0.42755509, (float)0.44228869, (float)0.45690388,
-  (float)0.47139674, (float)0.48576339, (float)0.50000000, (float)0.51410274, (float)0.52806785,
-  (float)0.54189158, (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930,
-  (float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615, (float)0.65934582,
-  (float)0.67155895, (float)0.68359230, (float)0.69544264, (float)0.70710678, (float)0.71858162,
-  (float)0.72986407, (float)0.74095113, (float)0.75183981, (float)0.76252720, (float)0.77301045,
-  (float)0.78328675, (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822,
-  (float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861, (float)0.86602540,
-  (float)0.87409034, (float)0.88192126, (float)0.88951608, (float)0.89687274, (float)0.90398929,
-  (float)0.91086382, (float)0.91749450, (float)0.92387953, (float)0.93001722, (float)0.93590593,
-  (float)0.94154407, (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180,
-  (float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197, (float)0.98078528,
-  (float)0.98384601, (float)0.98664333, (float)0.98917651, (float)0.99144486, (float)0.99344778,
-  (float)0.99518473, (float)0.99665524, (float)0.99785892, (float)0.99879546, (float)0.99946459,
-  (float)0.99986614, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546, (float)0.99785892,
-  (float)0.99665524, (float)0.99518473, (float)0.99344778, (float)0.99144486, (float)0.98917651,
-  (float)0.98664333, (float)0.98384601, (float)0.98078528, (float)0.97746197, (float)0.97387698,
-  (float)0.97003125, (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268,
-  (float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722, (float)0.92387953,
-  (float)0.91749450, (float)0.91086382, (float)0.90398929, (float)0.89687274, (float)0.88951608,
-  (float)0.88192126, (float)0.87409034, (float)0.86602540, (float)0.85772861, (float)0.84920218,
-  (float)0.84044840, (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753,
-  (float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720, (float)0.75183981,
-  (float)0.74095113, (float)0.72986407, (float)0.71858162, (float)0.70710678, (float)0.69544264,
-  (float)0.68359230, (float)0.67155895, (float)0.65934582, (float)0.64695615, (float)0.63439328,
-  (float)0.62166057, (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015,
-  (float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274, (float)0.50000000,
-  (float)0.48576339, (float)0.47139674, (float)0.45690388, (float)0.44228869, (float)0.42755509,
-  (float)0.41270703, (float)0.39774847, (float)0.38268343, (float)0.36751594, (float)0.35225005,
-  (float)0.33688985, (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862,
-  (float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155, (float)0.19509032,
-  (float)0.17901686, (float)0.16289547, (float)0.14673047, (float)0.13052619, (float)0.11428696,
-  (float)0.09801714, (float)0.08172107, (float)0.06540313, (float)0.04906767, (float)0.03271908,
-  (float)0.01636173
-};
+    (float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767,
+    (float)0.06540313, (float)0.08172107, (float)0.09801714, (float)0.11428696,
+    (float)0.13052619, (float)0.14673047, (float)0.16289547, (float)0.17901686,
+    (float)0.19509032, (float)0.21111155, (float)0.22707626, (float)0.24298018,
+    (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302,
+    (float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594,
+    (float)0.38268343, (float)0.39774847, (float)0.41270703, (float)0.42755509,
+    (float)0.44228869, (float)0.45690388, (float)0.47139674, (float)0.48576339,
+    (float)0.50000000, (float)0.51410274, (float)0.52806785, (float)0.54189158,
+    (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930,
+    (float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615,
+    (float)0.65934582, (float)0.67155895, (float)0.68359230, (float)0.69544264,
+    (float)0.70710678, (float)0.71858162, (float)0.72986407, (float)0.74095113,
+    (float)0.75183981, (float)0.76252720, (float)0.77301045, (float)0.78328675,
+    (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822,
+    (float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861,
+    (float)0.86602540, (float)0.87409034, (float)0.88192126, (float)0.88951608,
+    (float)0.89687274, (float)0.90398929, (float)0.91086382, (float)0.91749450,
+    (float)0.92387953, (float)0.93001722, (float)0.93590593, (float)0.94154407,
+    (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180,
+    (float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197,
+    (float)0.98078528, (float)0.98384601, (float)0.98664333, (float)0.98917651,
+    (float)0.99144486, (float)0.99344778, (float)0.99518473, (float)0.99665524,
+    (float)0.99785892, (float)0.99879546, (float)0.99946459, (float)0.99986614,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546,
+    (float)0.99785892, (float)0.99665524, (float)0.99518473, (float)0.99344778,
+    (float)0.99144486, (float)0.98917651, (float)0.98664333, (float)0.98384601,
+    (float)0.98078528, (float)0.97746197, (float)0.97387698, (float)0.97003125,
+    (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268,
+    (float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722,
+    (float)0.92387953, (float)0.91749450, (float)0.91086382, (float)0.90398929,
+    (float)0.89687274, (float)0.88951608, (float)0.88192126, (float)0.87409034,
+    (float)0.86602540, (float)0.85772861, (float)0.84920218, (float)0.84044840,
+    (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753,
+    (float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720,
+    (float)0.75183981, (float)0.74095113, (float)0.72986407, (float)0.71858162,
+    (float)0.70710678, (float)0.69544264, (float)0.68359230, (float)0.67155895,
+    (float)0.65934582, (float)0.64695615, (float)0.63439328, (float)0.62166057,
+    (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015,
+    (float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274,
+    (float)0.50000000, (float)0.48576339, (float)0.47139674, (float)0.45690388,
+    (float)0.44228869, (float)0.42755509, (float)0.41270703, (float)0.39774847,
+    (float)0.38268343, (float)0.36751594, (float)0.35225005, (float)0.33688985,
+    (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862,
+    (float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155,
+    (float)0.19509032, (float)0.17901686, (float)0.16289547, (float)0.14673047,
+    (float)0.13052619, (float)0.11428696, (float)0.09801714, (float)0.08172107,
+    (float)0.06540313, (float)0.04906767, (float)0.03271908, (float)0.01636173};
 
 // hybrib Hanning & flat window: for 20ms
 static const float kBlocks320w512[512] = {
-  (float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123, (float)0.03271908,
-  (float)0.04089475, (float)0.04906767, (float)0.05723732, (float)0.06540313, (float)0.07356456,
-  (float)0.08172107, (float)0.08987211, (float)0.09801714, (float)0.10615561, (float)0.11428696,
-  (float)0.12241068, (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816,
-  (float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985, (float)0.19509032,
-  (float)0.20310773, (float)0.21111155, (float)0.21910124, (float)0.22707626, (float)0.23503609,
-  (float)0.24298018, (float)0.25090801, (float)0.25881905, (float)0.26671276, (float)0.27458862,
-  (float)0.28244610, (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174,
-  (float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148, (float)0.35225005,
-  (float)0.35989504, (float)0.36751594, (float)0.37511224, (float)0.38268343, (float)0.39022901,
-  (float)0.39774847, (float)0.40524131, (float)0.41270703, (float)0.42014512, (float)0.42755509,
-  (float)0.43493645, (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584,
-  (float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819, (float)0.50000000,
-  (float)0.50706834, (float)0.51410274, (float)0.52110274, (float)0.52806785, (float)0.53499762,
-  (float)0.54189158, (float)0.54874927, (float)0.55557023, (float)0.56235401, (float)0.56910015,
-  (float)0.57580819, (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052,
-  (float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795, (float)0.63439328,
-  (float)0.64069616, (float)0.64695615, (float)0.65317284, (float)0.65934582, (float)0.66547466,
-  (float)0.67155895, (float)0.67759830, (float)0.68359230, (float)0.68954054, (float)0.69544264,
-  (float)0.70129818, (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708,
-  (float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045, (float)0.75183981,
-  (float)0.75720885, (float)0.76252720, (float)0.76779452, (float)0.77301045, (float)0.77817464,
-  (float)0.78328675, (float)0.78834643, (float)0.79335334, (float)0.79830715, (float)0.80320753,
-  (float)0.80805415, (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659,
-  (float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357, (float)0.84920218,
-  (float)0.85349396, (float)0.85772861, (float)0.86190585, (float)0.86602540, (float)0.87008699,
-  (float)0.87409034, (float)0.87803519, (float)0.88192126, (float)0.88574831, (float)0.88951608,
-  (float)0.89322430, (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693,
-  (float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783, (float)0.92387953,
-  (float)0.92697940, (float)0.93001722, (float)0.93299280, (float)0.93590593, (float)0.93875641,
-  (float)0.94154407, (float)0.94426870, (float)0.94693013, (float)0.94952818, (float)0.95206268,
-  (float)0.95453345, (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607,
-  (float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664, (float)0.97387698,
-  (float)0.97570213, (float)0.97746197, (float)0.97915640, (float)0.98078528, (float)0.98234852,
-  (float)0.98384601, (float)0.98527764, (float)0.98664333, (float)0.98794298, (float)0.98917651,
-  (float)0.99034383, (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953,
-  (float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046, (float)0.99785892,
-  (float)0.99836060, (float)0.99879546, (float)0.99916346, (float)0.99946459, (float)0.99969882,
-  (float)0.99986614, (float)0.99996653, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-  (float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882, (float)0.99946459,
-  (float)0.99916346, (float)0.99879546, (float)0.99836060, (float)0.99785892, (float)0.99729046,
-  (float)0.99665524, (float)0.99595331, (float)0.99518473, (float)0.99434953, (float)0.99344778,
-  (float)0.99247953, (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298,
-  (float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852, (float)0.98078528,
-  (float)0.97915640, (float)0.97746197, (float)0.97570213, (float)0.97387698, (float)0.97198664,
-  (float)0.97003125, (float)0.96801094, (float)0.96592583, (float)0.96377607, (float)0.96156180,
-  (float)0.95928317, (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818,
-  (float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641, (float)0.93590593,
-  (float)0.93299280, (float)0.93001722, (float)0.92697940, (float)0.92387953, (float)0.92071783,
-  (float)0.91749450, (float)0.91420976, (float)0.91086382, (float)0.90745693, (float)0.90398929,
-  (float)0.90046115, (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831,
-  (float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699, (float)0.86602540,
-  (float)0.86190585, (float)0.85772861, (float)0.85349396, (float)0.84920218, (float)0.84485357,
-  (float)0.84044840, (float)0.83598698, (float)0.83146961, (float)0.82689659, (float)0.82226822,
-  (float)0.81758481, (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715,
-  (float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464, (float)0.77301045,
-  (float)0.76779452, (float)0.76252720, (float)0.75720885, (float)0.75183981, (float)0.74642045,
-  (float)0.74095113, (float)0.73543221, (float)0.72986407, (float)0.72424708, (float)0.71858162,
-  (float)0.71286806, (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054,
-  (float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466, (float)0.65934582,
-  (float)0.65317284, (float)0.64695615, (float)0.64069616, (float)0.63439328, (float)0.62804795,
-  (float)0.62166057, (float)0.61523159, (float)0.60876143, (float)0.60225052, (float)0.59569930,
-  (float)0.58910822, (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401,
-  (float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762, (float)0.52806785,
-  (float)0.52110274, (float)0.51410274, (float)0.50706834, (float)0.50000000, (float)0.49289819,
-  (float)0.48576339, (float)0.47859608, (float)0.47139674, (float)0.46416584, (float)0.45690388,
-  (float)0.44961133, (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512,
-  (float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901, (float)0.38268343,
-  (float)0.37511224, (float)0.36751594, (float)0.35989504, (float)0.35225005, (float)0.34458148,
-  (float)0.33688985, (float)0.32917568, (float)0.32143947, (float)0.31368174, (float)0.30590302,
-  (float)0.29810383, (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276,
-  (float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609, (float)0.22707626,
-  (float)0.21910124, (float)0.21111155, (float)0.20310773, (float)0.19509032, (float)0.18705985,
-  (float)0.17901686, (float)0.17096189, (float)0.16289547, (float)0.15481816, (float)0.14673047,
-  (float)0.13863297, (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561,
-  (float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456, (float)0.06540313,
-  (float)0.05723732, (float)0.04906767, (float)0.04089475, (float)0.03271908, (float)0.02454123,
-  (float)0.01636173, (float)0.00818114
-};
-
+    (float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123,
+    (float)0.03271908, (float)0.04089475, (float)0.04906767, (float)0.05723732,
+    (float)0.06540313, (float)0.07356456, (float)0.08172107, (float)0.08987211,
+    (float)0.09801714, (float)0.10615561, (float)0.11428696, (float)0.12241068,
+    (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816,
+    (float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985,
+    (float)0.19509032, (float)0.20310773, (float)0.21111155, (float)0.21910124,
+    (float)0.22707626, (float)0.23503609, (float)0.24298018, (float)0.25090801,
+    (float)0.25881905, (float)0.26671276, (float)0.27458862, (float)0.28244610,
+    (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174,
+    (float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148,
+    (float)0.35225005, (float)0.35989504, (float)0.36751594, (float)0.37511224,
+    (float)0.38268343, (float)0.39022901, (float)0.39774847, (float)0.40524131,
+    (float)0.41270703, (float)0.42014512, (float)0.42755509, (float)0.43493645,
+    (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584,
+    (float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819,
+    (float)0.50000000, (float)0.50706834, (float)0.51410274, (float)0.52110274,
+    (float)0.52806785, (float)0.53499762, (float)0.54189158, (float)0.54874927,
+    (float)0.55557023, (float)0.56235401, (float)0.56910015, (float)0.57580819,
+    (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052,
+    (float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795,
+    (float)0.63439328, (float)0.64069616, (float)0.64695615, (float)0.65317284,
+    (float)0.65934582, (float)0.66547466, (float)0.67155895, (float)0.67759830,
+    (float)0.68359230, (float)0.68954054, (float)0.69544264, (float)0.70129818,
+    (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708,
+    (float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045,
+    (float)0.75183981, (float)0.75720885, (float)0.76252720, (float)0.76779452,
+    (float)0.77301045, (float)0.77817464, (float)0.78328675, (float)0.78834643,
+    (float)0.79335334, (float)0.79830715, (float)0.80320753, (float)0.80805415,
+    (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659,
+    (float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357,
+    (float)0.84920218, (float)0.85349396, (float)0.85772861, (float)0.86190585,
+    (float)0.86602540, (float)0.87008699, (float)0.87409034, (float)0.87803519,
+    (float)0.88192126, (float)0.88574831, (float)0.88951608, (float)0.89322430,
+    (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693,
+    (float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783,
+    (float)0.92387953, (float)0.92697940, (float)0.93001722, (float)0.93299280,
+    (float)0.93590593, (float)0.93875641, (float)0.94154407, (float)0.94426870,
+    (float)0.94693013, (float)0.94952818, (float)0.95206268, (float)0.95453345,
+    (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607,
+    (float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664,
+    (float)0.97387698, (float)0.97570213, (float)0.97746197, (float)0.97915640,
+    (float)0.98078528, (float)0.98234852, (float)0.98384601, (float)0.98527764,
+    (float)0.98664333, (float)0.98794298, (float)0.98917651, (float)0.99034383,
+    (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953,
+    (float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046,
+    (float)0.99785892, (float)0.99836060, (float)0.99879546, (float)0.99916346,
+    (float)0.99946459, (float)0.99969882, (float)0.99986614, (float)0.99996653,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
+    (float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882,
+    (float)0.99946459, (float)0.99916346, (float)0.99879546, (float)0.99836060,
+    (float)0.99785892, (float)0.99729046, (float)0.99665524, (float)0.99595331,
+    (float)0.99518473, (float)0.99434953, (float)0.99344778, (float)0.99247953,
+    (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298,
+    (float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852,
+    (float)0.98078528, (float)0.97915640, (float)0.97746197, (float)0.97570213,
+    (float)0.97387698, (float)0.97198664, (float)0.97003125, (float)0.96801094,
+    (float)0.96592583, (float)0.96377607, (float)0.96156180, (float)0.95928317,
+    (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818,
+    (float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641,
+    (float)0.93590593, (float)0.93299280, (float)0.93001722, (float)0.92697940,
+    (float)0.92387953, (float)0.92071783, (float)0.91749450, (float)0.91420976,
+    (float)0.91086382, (float)0.90745693, (float)0.90398929, (float)0.90046115,
+    (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831,
+    (float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699,
+    (float)0.86602540, (float)0.86190585, (float)0.85772861, (float)0.85349396,
+    (float)0.84920218, (float)0.84485357, (float)0.84044840, (float)0.83598698,
+    (float)0.83146961, (float)0.82689659, (float)0.82226822, (float)0.81758481,
+    (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715,
+    (float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464,
+    (float)0.77301045, (float)0.76779452, (float)0.76252720, (float)0.75720885,
+    (float)0.75183981, (float)0.74642045, (float)0.74095113, (float)0.73543221,
+    (float)0.72986407, (float)0.72424708, (float)0.71858162, (float)0.71286806,
+    (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054,
+    (float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466,
+    (float)0.65934582, (float)0.65317284, (float)0.64695615, (float)0.64069616,
+    (float)0.63439328, (float)0.62804795, (float)0.62166057, (float)0.61523159,
+    (float)0.60876143, (float)0.60225052, (float)0.59569930, (float)0.58910822,
+    (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401,
+    (float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762,
+    (float)0.52806785, (float)0.52110274, (float)0.51410274, (float)0.50706834,
+    (float)0.50000000, (float)0.49289819, (float)0.48576339, (float)0.47859608,
+    (float)0.47139674, (float)0.46416584, (float)0.45690388, (float)0.44961133,
+    (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512,
+    (float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901,
+    (float)0.38268343, (float)0.37511224, (float)0.36751594, (float)0.35989504,
+    (float)0.35225005, (float)0.34458148, (float)0.33688985, (float)0.32917568,
+    (float)0.32143947, (float)0.31368174, (float)0.30590302, (float)0.29810383,
+    (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276,
+    (float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609,
+    (float)0.22707626, (float)0.21910124, (float)0.21111155, (float)0.20310773,
+    (float)0.19509032, (float)0.18705985, (float)0.17901686, (float)0.17096189,
+    (float)0.16289547, (float)0.15481816, (float)0.14673047, (float)0.13863297,
+    (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561,
+    (float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456,
+    (float)0.06540313, (float)0.05723732, (float)0.04906767, (float)0.04089475,
+    (float)0.03271908, (float)0.02454123, (float)0.01636173, (float)0.00818114};
 
 // Hanning window: for 15ms at 16kHz with symmetric zeros
 static const float kBlocks240w512[512] = {
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369,
-  (float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887, (float)0.05233596,
-  (float)0.05887080, (float)0.06540313, (float)0.07193266, (float)0.07845910, (float)0.08498218,
-  (float)0.09150162, (float)0.09801714, (float)0.10452846, (float)0.11103531, (float)0.11753740,
-  (float)0.12403446, (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676,
-  (float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629, (float)0.18223552,
-  (float)0.18866697, (float)0.19509032, (float)0.20150533, (float)0.20791170, (float)0.21430916,
-  (float)0.22069745, (float)0.22707628, (float)0.23344538, (float)0.23980446, (float)0.24615330,
-  (float)0.25249159, (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386,
-  (float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578, (float)0.30901700,
-  (float)0.31523499, (float)0.32143945, (float)0.32763019, (float)0.33380687, (float)0.33996925,
-  (float)0.34611708, (float)0.35225007, (float)0.35836795, (float)0.36447051, (float)0.37055743,
-  (float)0.37662852, (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885,
-  (float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452, (float)0.43051112,
-  (float)0.43640924, (float)0.44228873, (float)0.44814920, (float)0.45399052, (float)0.45981237,
-  (float)0.46561453, (float)0.47139674, (float)0.47715878, (float)0.48290035, (float)0.48862126,
-  (float)0.49432120, (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692,
-  (float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832, (float)0.54463905,
-  (float)0.55011642, (float)0.55557024, (float)0.56100029, (float)0.56640625, (float)0.57178795,
-  (float)0.57714522, (float)0.58247769, (float)0.58778524, (float)0.59306765, (float)0.59832460,
-  (float)0.60355598, (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055,
-  (float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734, (float)0.64944810,
-  (float)0.65441096, (float)0.65934587, (float)0.66425246, (float)0.66913062, (float)0.67398012,
-  (float)0.67880076, (float)0.68359232, (float)0.68835455, (float)0.69308740, (float)0.69779050,
-  (float)0.70246369, (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363,
-  (float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950, (float)0.74314487,
-  (float)0.74750835, (float)0.75183982, (float)0.75613910, (float)0.76040596, (float)0.76464027,
-  (float)0.76884186, (float)0.77301043, (float)0.77714598, (float)0.78124821, (float)0.78531694,
-  (float)0.78935206, (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265,
-  (float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149, (float)0.82412618,
-  (float)0.82781565, (float)0.83146966, (float)0.83508795, (float)0.83867061, (float)0.84221727,
-  (float)0.84572780, (float)0.84920216, (float)0.85264021, (float)0.85604161, (float)0.85940641,
-  (float)0.86273444, (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532,
-  (float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610, (float)0.89100653,
-  (float)0.89395881, (float)0.89687276, (float)0.89974827, (float)0.90258533, (float)0.90538365,
-  (float)0.90814316, (float)0.91086388, (float)0.91354549, (float)0.91618794, (float)0.91879123,
-  (float)0.92135513, (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493,
-  (float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654, (float)0.94264150,
-  (float)0.94480604, (float)0.94693011, (float)0.94901365, (float)0.95105654, (float)0.95305866,
-  (float)0.95501995, (float)0.95694035, (float)0.95881975, (float)0.96065807, (float)0.96245527,
-  (float)0.96421117, (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120,
-  (float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587, (float)0.97814763,
-  (float)0.97948742, (float)0.98078531, (float)0.98204112, (float)0.98325491, (float)0.98442656,
-  (float)0.98555607, (float)0.98664331, (float)0.98768836, (float)0.98869103, (float)0.98965138,
-  (float)0.99056935, (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649,
-  (float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247, (float)0.99691731,
-  (float)0.99740952, (float)0.99785894, (float)0.99826562, (float)0.99862951, (float)0.99895066,
-  (float)0.99922901, (float)0.99946457, (float)0.99965733, (float)0.99980724, (float)0.99991435,
-  (float)0.99997860, (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724,
-  (float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066, (float)0.99862951,
-  (float)0.99826562, (float)0.99785894, (float)0.99740946, (float)0.99691731, (float)0.99638247,
-  (float)0.99580491, (float)0.99518472, (float)0.99452192, (float)0.99381644, (float)0.99306846,
-  (float)0.99227792, (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103,
-  (float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656, (float)0.98325491,
-  (float)0.98204112, (float)0.98078525, (float)0.97948742, (float)0.97814757, (float)0.97676587,
-  (float)0.97534227, (float)0.97387695, (float)0.97236991, (float)0.97082120, (float)0.96923089,
-  (float)0.96759909, (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807,
-  (float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860, (float)0.95105648,
-  (float)0.94901365, (float)0.94693011, (float)0.94480604, (float)0.94264150, (float)0.94043654,
-  (float)0.93819129, (float)0.93590593, (float)0.93358046, (float)0.93121493, (float)0.92880952,
-  (float)0.92636436, (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794,
-  (float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365, (float)0.90258527,
-  (float)0.89974827, (float)0.89687276, (float)0.89395875, (float)0.89100647, (float)0.88801610,
-  (float)0.88498759, (float)0.88192123, (float)0.87881714, (float)0.87567532, (float)0.87249595,
-  (float)0.86927933, (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161,
-  (float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715, (float)0.83867055,
-  (float)0.83508795, (float)0.83146954, (float)0.82781565, (float)0.82412612, (float)0.82040137,
-  (float)0.81664157, (float)0.81284660, (float)0.80901700, (float)0.80515265, (float)0.80125374,
-  (float)0.79732066, (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815,
-  (float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021, (float)0.76040596,
-  (float)0.75613904, (float)0.75183970, (float)0.74750835, (float)0.74314481, (float)0.73874938,
-  (float)0.73432249, (float)0.72986400, (float)0.72537428, (float)0.72085363, (float)0.71630186,
-  (float)0.71171951, (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734,
-  (float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006, (float)0.66913044,
-  (float)0.66425240, (float)0.65934575, (float)0.65441096, (float)0.64944804, (float)0.64445722,
-  (float)0.63943905, (float)0.63439327, (float)0.62932026, (float)0.62422055, (float)0.61909389,
-  (float)0.61394072, (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765,
-  (float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789, (float)0.56640613,
-  (float)0.56100023, (float)0.55557019, (float)0.55011630, (float)0.54463905, (float)0.53913826,
-  (float)0.53361434, (float)0.52806783, (float)0.52249849, (float)0.51690674, (float)0.51129305,
-  (float)0.50565726, (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038,
-  (float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231, (float)0.45399037,
-  (float)0.44814920, (float)0.44228864, (float)0.43640912, (float)0.43051112, (float)0.42459446,
-  (float)0.41865960, (float)0.41270703, (float)0.40673658, (float)0.40074870, (float)0.39474386,
-  (float)0.38872188, (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033,
-  (float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922, (float)0.33380675,
-  (float)0.32763001, (float)0.32143945, (float)0.31523487, (float)0.30901679, (float)0.30278572,
-  (float)0.29654145, (float)0.29028472, (float)0.28401530, (float)0.27773371, (float)0.27144048,
-  (float)0.26513538, (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433,
-  (float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916, (float)0.20791161,
-  (float)0.20150517, (float)0.19509031, (float)0.18866688, (float)0.18223536, (float)0.17579627,
-  (float)0.16934940, (float)0.16289529, (float)0.15643445, (float)0.14996666, (float)0.14349243,
-  (float)0.13701232, (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519,
-  (float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220, (float)0.07845904,
-  (float)0.07193252, (float)0.06540315, (float)0.05887074, (float)0.05233581, (float)0.04579888,
-  (float)0.03925974, (float)0.03271893, (float)0.02617695, (float)0.01963361, (float)0.01308943,
-  (float)0.00654493, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000
-};
-
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369,
+    (float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887,
+    (float)0.05233596, (float)0.05887080, (float)0.06540313, (float)0.07193266,
+    (float)0.07845910, (float)0.08498218, (float)0.09150162, (float)0.09801714,
+    (float)0.10452846, (float)0.11103531, (float)0.11753740, (float)0.12403446,
+    (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676,
+    (float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629,
+    (float)0.18223552, (float)0.18866697, (float)0.19509032, (float)0.20150533,
+    (float)0.20791170, (float)0.21430916, (float)0.22069745, (float)0.22707628,
+    (float)0.23344538, (float)0.23980446, (float)0.24615330, (float)0.25249159,
+    (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386,
+    (float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578,
+    (float)0.30901700, (float)0.31523499, (float)0.32143945, (float)0.32763019,
+    (float)0.33380687, (float)0.33996925, (float)0.34611708, (float)0.35225007,
+    (float)0.35836795, (float)0.36447051, (float)0.37055743, (float)0.37662852,
+    (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885,
+    (float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452,
+    (float)0.43051112, (float)0.43640924, (float)0.44228873, (float)0.44814920,
+    (float)0.45399052, (float)0.45981237, (float)0.46561453, (float)0.47139674,
+    (float)0.47715878, (float)0.48290035, (float)0.48862126, (float)0.49432120,
+    (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692,
+    (float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832,
+    (float)0.54463905, (float)0.55011642, (float)0.55557024, (float)0.56100029,
+    (float)0.56640625, (float)0.57178795, (float)0.57714522, (float)0.58247769,
+    (float)0.58778524, (float)0.59306765, (float)0.59832460, (float)0.60355598,
+    (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055,
+    (float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734,
+    (float)0.64944810, (float)0.65441096, (float)0.65934587, (float)0.66425246,
+    (float)0.66913062, (float)0.67398012, (float)0.67880076, (float)0.68359232,
+    (float)0.68835455, (float)0.69308740, (float)0.69779050, (float)0.70246369,
+    (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363,
+    (float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950,
+    (float)0.74314487, (float)0.74750835, (float)0.75183982, (float)0.75613910,
+    (float)0.76040596, (float)0.76464027, (float)0.76884186, (float)0.77301043,
+    (float)0.77714598, (float)0.78124821, (float)0.78531694, (float)0.78935206,
+    (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265,
+    (float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149,
+    (float)0.82412618, (float)0.82781565, (float)0.83146966, (float)0.83508795,
+    (float)0.83867061, (float)0.84221727, (float)0.84572780, (float)0.84920216,
+    (float)0.85264021, (float)0.85604161, (float)0.85940641, (float)0.86273444,
+    (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532,
+    (float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610,
+    (float)0.89100653, (float)0.89395881, (float)0.89687276, (float)0.89974827,
+    (float)0.90258533, (float)0.90538365, (float)0.90814316, (float)0.91086388,
+    (float)0.91354549, (float)0.91618794, (float)0.91879123, (float)0.92135513,
+    (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493,
+    (float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654,
+    (float)0.94264150, (float)0.94480604, (float)0.94693011, (float)0.94901365,
+    (float)0.95105654, (float)0.95305866, (float)0.95501995, (float)0.95694035,
+    (float)0.95881975, (float)0.96065807, (float)0.96245527, (float)0.96421117,
+    (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120,
+    (float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587,
+    (float)0.97814763, (float)0.97948742, (float)0.98078531, (float)0.98204112,
+    (float)0.98325491, (float)0.98442656, (float)0.98555607, (float)0.98664331,
+    (float)0.98768836, (float)0.98869103, (float)0.98965138, (float)0.99056935,
+    (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649,
+    (float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247,
+    (float)0.99691731, (float)0.99740952, (float)0.99785894, (float)0.99826562,
+    (float)0.99862951, (float)0.99895066, (float)0.99922901, (float)0.99946457,
+    (float)0.99965733, (float)0.99980724, (float)0.99991435, (float)0.99997860,
+    (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724,
+    (float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066,
+    (float)0.99862951, (float)0.99826562, (float)0.99785894, (float)0.99740946,
+    (float)0.99691731, (float)0.99638247, (float)0.99580491, (float)0.99518472,
+    (float)0.99452192, (float)0.99381644, (float)0.99306846, (float)0.99227792,
+    (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103,
+    (float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656,
+    (float)0.98325491, (float)0.98204112, (float)0.98078525, (float)0.97948742,
+    (float)0.97814757, (float)0.97676587, (float)0.97534227, (float)0.97387695,
+    (float)0.97236991, (float)0.97082120, (float)0.96923089, (float)0.96759909,
+    (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807,
+    (float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860,
+    (float)0.95105648, (float)0.94901365, (float)0.94693011, (float)0.94480604,
+    (float)0.94264150, (float)0.94043654, (float)0.93819129, (float)0.93590593,
+    (float)0.93358046, (float)0.93121493, (float)0.92880952, (float)0.92636436,
+    (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794,
+    (float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365,
+    (float)0.90258527, (float)0.89974827, (float)0.89687276, (float)0.89395875,
+    (float)0.89100647, (float)0.88801610, (float)0.88498759, (float)0.88192123,
+    (float)0.87881714, (float)0.87567532, (float)0.87249595, (float)0.86927933,
+    (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161,
+    (float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715,
+    (float)0.83867055, (float)0.83508795, (float)0.83146954, (float)0.82781565,
+    (float)0.82412612, (float)0.82040137, (float)0.81664157, (float)0.81284660,
+    (float)0.80901700, (float)0.80515265, (float)0.80125374, (float)0.79732066,
+    (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815,
+    (float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021,
+    (float)0.76040596, (float)0.75613904, (float)0.75183970, (float)0.74750835,
+    (float)0.74314481, (float)0.73874938, (float)0.73432249, (float)0.72986400,
+    (float)0.72537428, (float)0.72085363, (float)0.71630186, (float)0.71171951,
+    (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734,
+    (float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006,
+    (float)0.66913044, (float)0.66425240, (float)0.65934575, (float)0.65441096,
+    (float)0.64944804, (float)0.64445722, (float)0.63943905, (float)0.63439327,
+    (float)0.62932026, (float)0.62422055, (float)0.61909389, (float)0.61394072,
+    (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765,
+    (float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789,
+    (float)0.56640613, (float)0.56100023, (float)0.55557019, (float)0.55011630,
+    (float)0.54463905, (float)0.53913826, (float)0.53361434, (float)0.52806783,
+    (float)0.52249849, (float)0.51690674, (float)0.51129305, (float)0.50565726,
+    (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038,
+    (float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231,
+    (float)0.45399037, (float)0.44814920, (float)0.44228864, (float)0.43640912,
+    (float)0.43051112, (float)0.42459446, (float)0.41865960, (float)0.41270703,
+    (float)0.40673658, (float)0.40074870, (float)0.39474386, (float)0.38872188,
+    (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033,
+    (float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922,
+    (float)0.33380675, (float)0.32763001, (float)0.32143945, (float)0.31523487,
+    (float)0.30901679, (float)0.30278572, (float)0.29654145, (float)0.29028472,
+    (float)0.28401530, (float)0.27773371, (float)0.27144048, (float)0.26513538,
+    (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433,
+    (float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916,
+    (float)0.20791161, (float)0.20150517, (float)0.19509031, (float)0.18866688,
+    (float)0.18223536, (float)0.17579627, (float)0.16934940, (float)0.16289529,
+    (float)0.15643445, (float)0.14996666, (float)0.14349243, (float)0.13701232,
+    (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519,
+    (float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220,
+    (float)0.07845904, (float)0.07193252, (float)0.06540315, (float)0.05887074,
+    (float)0.05233581, (float)0.04579888, (float)0.03925974, (float)0.03271893,
+    (float)0.02617695, (float)0.01963361, (float)0.01308943, (float)0.00654493,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000};
 
 // Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz
 static const float kBlocks480w1024[1024] = {
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00327249, (float)0.00654494,
-  (float)0.00981732, (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544,
-  (float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964, (float)0.03925982,
-  (float)0.04252957, (float)0.04579887, (float)0.04906768, (float)0.05233596, (float)0.05560368,
-  (float)0.05887080, (float)0.06213730, (float)0.06540313, (float)0.06866825, (float)0.07193266,
-  (float)0.07519628, (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237,
-  (float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335, (float)0.10452846,
-  (float)0.10778246, (float)0.11103531, (float)0.11428697, (float)0.11753740, (float)0.12078657,
-  (float)0.12403446, (float)0.12728101, (float)0.13052620, (float)0.13376999, (float)0.13701233,
-  (float)0.14025325, (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145,
-  (float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339, (float)0.16934951,
-  (float)0.17257382, (float)0.17579629, (float)0.17901687, (float)0.18223552, (float)0.18545224,
-  (float)0.18866697, (float)0.19187967, (float)0.19509032, (float)0.19829889, (float)0.20150533,
-  (float)0.20470962, (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447,
-  (float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206, (float)0.23344538,
-  (float)0.23662618, (float)0.23980446, (float)0.24298020, (float)0.24615330, (float)0.24932377,
-  (float)0.25249159, (float)0.25565669, (float)0.25881904, (float)0.26197866, (float)0.26513544,
-  (float)0.26828939, (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610,
-  (float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471, (float)0.29654160,
-  (float)0.29966527, (float)0.30278578, (float)0.30590302, (float)0.30901700, (float)0.31212768,
-  (float)0.31523499, (float)0.31833893, (float)0.32143945, (float)0.32453656, (float)0.32763019,
-  (float)0.33072028, (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500,
-  (float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089, (float)0.35836795,
-  (float)0.36142117, (float)0.36447051, (float)0.36751595, (float)0.37055743, (float)0.37359497,
-  (float)0.37662852, (float)0.37965801, (float)0.38268346, (float)0.38570479, (float)0.38872197,
-  (float)0.39173502, (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491,
-  (float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562, (float)0.41865975,
-  (float)0.42162940, (float)0.42459452, (float)0.42755508, (float)0.43051112, (float)0.43346250,
-  (float)0.43640924, (float)0.43935132, (float)0.44228873, (float)0.44522133, (float)0.44814920,
-  (float)0.45107228, (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592,
-  (float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030, (float)0.47715878,
-  (float)0.48003215, (float)0.48290035, (float)0.48576337, (float)0.48862126, (float)0.49147385,
-  (float)0.49432120, (float)0.49716330, (float)0.50000000, (float)0.50283140, (float)0.50565743,
-  (float)0.50847799, (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553,
-  (float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403, (float)0.53361452,
-  (float)0.53637928, (float)0.53913832, (float)0.54189163, (float)0.54463905, (float)0.54738063,
-  (float)0.55011642, (float)0.55284631, (float)0.55557024, (float)0.55828828, (float)0.56100029,
-  (float)0.56370628, (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963,
-  (float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463, (float)0.58778524,
-  (float)0.59042960, (float)0.59306765, (float)0.59569931, (float)0.59832460, (float)0.60094351,
-  (float)0.60355598, (float)0.60616195, (float)0.60876143, (float)0.61135441, (float)0.61394083,
-  (float)0.61652070, (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383,
-  (float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956, (float)0.63943899,
-  (float)0.64195162, (float)0.64445734, (float)0.64695615, (float)0.64944810, (float)0.65193301,
-  (float)0.65441096, (float)0.65688187, (float)0.65934587, (float)0.66180271, (float)0.66425246,
-  (float)0.66669512, (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405,
-  (float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710, (float)0.68835455,
-  (float)0.69072467, (float)0.69308740, (float)0.69544262, (float)0.69779050, (float)0.70013082,
-  (float)0.70246369, (float)0.70478904, (float)0.70710677, (float)0.70941699, (float)0.71171963,
-  (float)0.71401459, (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789,
-  (float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721, (float)0.73432255,
-  (float)0.73653996, (float)0.73874950, (float)0.74095118, (float)0.74314487, (float)0.74533057,
-  (float)0.74750835, (float)0.74967808, (float)0.75183982, (float)0.75399351, (float)0.75613910,
-  (float)0.75827658, (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515,
-  (float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241, (float)0.77714598,
-  (float)0.77920127, (float)0.78124821, (float)0.78328675, (float)0.78531694, (float)0.78733873,
-  (float)0.78935206, (float)0.79135692, (float)0.79335338, (float)0.79534125, (float)0.79732066,
-  (float)0.79929149, (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915,
-  (float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853, (float)0.81664157,
-  (float)0.81852591, (float)0.82040149, (float)0.82226825, (float)0.82412618, (float)0.82597536,
-  (float)0.82781565, (float)0.82964706, (float)0.83146966, (float)0.83328325, (float)0.83508795,
-  (float)0.83688378, (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703,
-  (float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574, (float)0.85264021,
-  (float)0.85434544, (float)0.85604161, (float)0.85772866, (float)0.85940641, (float)0.86107504,
-  (float)0.86273444, (float)0.86438453, (float)0.86602545, (float)0.86765707, (float)0.86927933,
-  (float)0.87089235, (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097,
-  (float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921, (float)0.88498765,
-  (float)0.88650668, (float)0.88801610, (float)0.88951612, (float)0.89100653, (float)0.89248741,
-  (float)0.89395881, (float)0.89542055, (float)0.89687276, (float)0.89831537, (float)0.89974827,
-  (float)0.90117162, (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826,
-  (float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951, (float)0.91354549,
-  (float)0.91487163, (float)0.91618794, (float)0.91749454, (float)0.91879123, (float)0.92007810,
-  (float)0.92135513, (float)0.92262226, (float)0.92387950, (float)0.92512691, (float)0.92636442,
-  (float)0.92759192, (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267,
-  (float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362, (float)0.93819135,
-  (float)0.93931901, (float)0.94043654, (float)0.94154406, (float)0.94264150, (float)0.94372880,
-  (float)0.94480604, (float)0.94587320, (float)0.94693011, (float)0.94797695, (float)0.94901365,
-  (float)0.95004016, (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440,
-  (float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521, (float)0.95881975,
-  (float)0.95974404, (float)0.96065807, (float)0.96156180, (float)0.96245527, (float)0.96333838,
-  (float)0.96421117, (float)0.96507370, (float)0.96592581, (float)0.96676767, (float)0.96759909,
-  (float)0.96842021, (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077,
-  (float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486, (float)0.97534233,
-  (float)0.97605932, (float)0.97676587, (float)0.97746199, (float)0.97814763, (float)0.97882277,
-  (float)0.97948742, (float)0.98014158, (float)0.98078531, (float)0.98141843, (float)0.98204112,
-  (float)0.98265332, (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662,
-  (float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111, (float)0.98768836,
-  (float)0.98819500, (float)0.98869103, (float)0.98917651, (float)0.98965138, (float)0.99011570,
-  (float)0.99056935, (float)0.99101239, (float)0.99144489, (float)0.99186671, (float)0.99227792,
-  (float)0.99267852, (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448,
-  (float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015, (float)0.99580491,
-  (float)0.99609905, (float)0.99638247, (float)0.99665523, (float)0.99691731, (float)0.99716878,
-  (float)0.99740952, (float)0.99763954, (float)0.99785894, (float)0.99806762, (float)0.99826562,
-  (float)0.99845290, (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520,
-  (float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632, (float)0.99965733,
-  (float)0.99973762, (float)0.99980724, (float)0.99986613, (float)0.99991435, (float)0.99995178,
-  (float)0.99997860, (float)0.99999464, (float)1.00000000, (float)0.99999464, (float)0.99997860,
-  (float)0.99995178, (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762,
-  (float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216, (float)0.99922901,
-  (float)0.99909520, (float)0.99895066, (float)0.99879545, (float)0.99862951, (float)0.99845290,
-  (float)0.99826562, (float)0.99806762, (float)0.99785894, (float)0.99763954, (float)0.99740946,
-  (float)0.99716872, (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905,
-  (float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862, (float)0.99452192,
-  (float)0.99417448, (float)0.99381644, (float)0.99344778, (float)0.99306846, (float)0.99267852,
-  (float)0.99227792, (float)0.99186671, (float)0.99144489, (float)0.99101239, (float)0.99056935,
-  (float)0.99011564, (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494,
-  (float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497, (float)0.98555607,
-  (float)0.98499656, (float)0.98442656, (float)0.98384601, (float)0.98325491, (float)0.98265326,
-  (float)0.98204112, (float)0.98141843, (float)0.98078525, (float)0.98014158, (float)0.97948742,
-  (float)0.97882277, (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932,
-  (float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862, (float)0.97236991,
-  (float)0.97160077, (float)0.97082120, (float)0.97003126, (float)0.96923089, (float)0.96842015,
-  (float)0.96759909, (float)0.96676761, (float)0.96592581, (float)0.96507365, (float)0.96421117,
-  (float)0.96333838, (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404,
-  (float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525, (float)0.95501995,
-  (float)0.95404440, (float)0.95305860, (float)0.95206267, (float)0.95105648, (float)0.95004016,
-  (float)0.94901365, (float)0.94797695, (float)0.94693011, (float)0.94587314, (float)0.94480604,
-  (float)0.94372880, (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895,
-  (float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817, (float)0.93358046,
-  (float)0.93240267, (float)0.93121493, (float)0.93001723, (float)0.92880952, (float)0.92759192,
-  (float)0.92636436, (float)0.92512691, (float)0.92387950, (float)0.92262226, (float)0.92135507,
-  (float)0.92007804, (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157,
-  (float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835, (float)0.90814310,
-  (float)0.90676820, (float)0.90538365, (float)0.90398932, (float)0.90258527, (float)0.90117157,
-  (float)0.89974827, (float)0.89831525, (float)0.89687276, (float)0.89542055, (float)0.89395875,
-  (float)0.89248741, (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662,
-  (float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384, (float)0.87881714,
-  (float)0.87725091, (float)0.87567532, (float)0.87409031, (float)0.87249595, (float)0.87089223,
-  (float)0.86927933, (float)0.86765701, (float)0.86602539, (float)0.86438447, (float)0.86273432,
-  (float)0.86107504, (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544,
-  (float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951, (float)0.84572780,
-  (float)0.84397697, (float)0.84221715, (float)0.84044844, (float)0.83867055, (float)0.83688372,
-  (float)0.83508795, (float)0.83328319, (float)0.83146954, (float)0.82964706, (float)0.82781565,
-  (float)0.82597530, (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591,
-  (float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609, (float)0.80901700,
-  (float)0.80708915, (float)0.80515265, (float)0.80320752, (float)0.80125374, (float)0.79929143,
-  (float)0.79732066, (float)0.79534125, (float)0.79335332, (float)0.79135686, (float)0.78935200,
-  (float)0.78733861, (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121,
-  (float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029, (float)0.76884180,
-  (float)0.76674509, (float)0.76464021, (float)0.76252711, (float)0.76040596, (float)0.75827658,
-  (float)0.75613904, (float)0.75399339, (float)0.75183970, (float)0.74967796, (float)0.74750835,
-  (float)0.74533057, (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996,
-  (float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305, (float)0.72537428,
-  (float)0.72311789, (float)0.72085363, (float)0.71858162, (float)0.71630186, (float)0.71401453,
-  (float)0.71171951, (float)0.70941705, (float)0.70710677, (float)0.70478898, (float)0.70246363,
-  (float)0.70013070, (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461,
-  (float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021, (float)0.67880070,
-  (float)0.67639399, (float)0.67398006, (float)0.67155886, (float)0.66913044, (float)0.66669512,
-  (float)0.66425240, (float)0.66180259, (float)0.65934575, (float)0.65688181, (float)0.65441096,
-  (float)0.65193301, (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150,
-  (float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014, (float)0.62932026,
-  (float)0.62677372, (float)0.62422055, (float)0.62166059, (float)0.61909389, (float)0.61652064,
-  (float)0.61394072, (float)0.61135429, (float)0.60876143, (float)0.60616189, (float)0.60355592,
-  (float)0.60094339, (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960,
-  (float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461, (float)0.57714522,
-  (float)0.57446963, (float)0.57178789, (float)0.56910002, (float)0.56640613, (float)0.56370628,
-  (float)0.56100023, (float)0.55828822, (float)0.55557019, (float)0.55284619, (float)0.55011630,
-  (float)0.54738069, (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916,
-  (float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596, (float)0.52249849,
-  (float)0.51970541, (float)0.51690674, (float)0.51410276, (float)0.51129305, (float)0.50847787,
-  (float)0.50565726, (float)0.50283122, (float)0.50000006, (float)0.49716327, (float)0.49432117,
-  (float)0.49147379, (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212,
-  (float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798, (float)0.46561456,
-  (float)0.46271589, (float)0.45981231, (float)0.45690379, (float)0.45399037, (float)0.45107210,
-  (float)0.44814920, (float)0.44522130, (float)0.44228864, (float)0.43935123, (float)0.43640912,
-  (float)0.43346232, (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928,
-  (float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400, (float)0.40673658,
-  (float)0.40374479, (float)0.40074870, (float)0.39774850, (float)0.39474386, (float)0.39173496,
-  (float)0.38872188, (float)0.38570464, (float)0.38268328, (float)0.37965804, (float)0.37662849,
-  (float)0.37359491, (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117,
-  (float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529, (float)0.34611690,
-  (float)0.34304500, (float)0.33996922, (float)0.33688980, (float)0.33380675, (float)0.33072016,
-  (float)0.32763001, (float)0.32453656, (float)0.32143945, (float)0.31833887, (float)0.31523487,
-  (float)0.31212750, (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521,
-  (float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155, (float)0.28401530,
-  (float)0.28087601, (float)0.27773371, (float)0.27458847, (float)0.27144048, (float)0.26828936,
-  (float)0.26513538, (float)0.26197854, (float)0.25881892, (float)0.25565651, (float)0.25249159,
-  (float)0.24932374, (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600,
-  (float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794, (float)0.22069728,
-  (float)0.21750426, (float)0.21430916, (float)0.21111152, (float)0.20791161, (float)0.20470949,
-  (float)0.20150517, (float)0.19829892, (float)0.19509031, (float)0.19187963, (float)0.18866688,
-  (float)0.18545210, (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376,
-  (float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584, (float)0.15643445,
-  (float)0.15320137, (float)0.14996666, (float)0.14673033, (float)0.14349243, (float)0.14025325,
-  (float)0.13701232, (float)0.13376991, (float)0.13052608, (float)0.12728085, (float)0.12403426,
-  (float)0.12078657, (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230,
-  (float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980, (float)0.09150149,
-  (float)0.08824220, (float)0.08498220, (float)0.08172106, (float)0.07845904, (float)0.07519618,
-  (float)0.07193252, (float)0.06866808, (float)0.06540315, (float)0.06213728, (float)0.05887074,
-  (float)0.05560357, (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954,
-  (float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798, (float)0.02617695,
-  (float)0.02290541, (float)0.01963361, (float)0.01636161, (float)0.01308943, (float)0.00981712,
-  (float)0.00654493, (float)0.00327244, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-  (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000
-};
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00327249, (float)0.00654494, (float)0.00981732,
+    (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544,
+    (float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964,
+    (float)0.03925982, (float)0.04252957, (float)0.04579887, (float)0.04906768,
+    (float)0.05233596, (float)0.05560368, (float)0.05887080, (float)0.06213730,
+    (float)0.06540313, (float)0.06866825, (float)0.07193266, (float)0.07519628,
+    (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237,
+    (float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335,
+    (float)0.10452846, (float)0.10778246, (float)0.11103531, (float)0.11428697,
+    (float)0.11753740, (float)0.12078657, (float)0.12403446, (float)0.12728101,
+    (float)0.13052620, (float)0.13376999, (float)0.13701233, (float)0.14025325,
+    (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145,
+    (float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339,
+    (float)0.16934951, (float)0.17257382, (float)0.17579629, (float)0.17901687,
+    (float)0.18223552, (float)0.18545224, (float)0.18866697, (float)0.19187967,
+    (float)0.19509032, (float)0.19829889, (float)0.20150533, (float)0.20470962,
+    (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447,
+    (float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206,
+    (float)0.23344538, (float)0.23662618, (float)0.23980446, (float)0.24298020,
+    (float)0.24615330, (float)0.24932377, (float)0.25249159, (float)0.25565669,
+    (float)0.25881904, (float)0.26197866, (float)0.26513544, (float)0.26828939,
+    (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610,
+    (float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471,
+    (float)0.29654160, (float)0.29966527, (float)0.30278578, (float)0.30590302,
+    (float)0.30901700, (float)0.31212768, (float)0.31523499, (float)0.31833893,
+    (float)0.32143945, (float)0.32453656, (float)0.32763019, (float)0.33072028,
+    (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500,
+    (float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089,
+    (float)0.35836795, (float)0.36142117, (float)0.36447051, (float)0.36751595,
+    (float)0.37055743, (float)0.37359497, (float)0.37662852, (float)0.37965801,
+    (float)0.38268346, (float)0.38570479, (float)0.38872197, (float)0.39173502,
+    (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491,
+    (float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562,
+    (float)0.41865975, (float)0.42162940, (float)0.42459452, (float)0.42755508,
+    (float)0.43051112, (float)0.43346250, (float)0.43640924, (float)0.43935132,
+    (float)0.44228873, (float)0.44522133, (float)0.44814920, (float)0.45107228,
+    (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592,
+    (float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030,
+    (float)0.47715878, (float)0.48003215, (float)0.48290035, (float)0.48576337,
+    (float)0.48862126, (float)0.49147385, (float)0.49432120, (float)0.49716330,
+    (float)0.50000000, (float)0.50283140, (float)0.50565743, (float)0.50847799,
+    (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553,
+    (float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403,
+    (float)0.53361452, (float)0.53637928, (float)0.53913832, (float)0.54189163,
+    (float)0.54463905, (float)0.54738063, (float)0.55011642, (float)0.55284631,
+    (float)0.55557024, (float)0.55828828, (float)0.56100029, (float)0.56370628,
+    (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963,
+    (float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463,
+    (float)0.58778524, (float)0.59042960, (float)0.59306765, (float)0.59569931,
+    (float)0.59832460, (float)0.60094351, (float)0.60355598, (float)0.60616195,
+    (float)0.60876143, (float)0.61135441, (float)0.61394083, (float)0.61652070,
+    (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383,
+    (float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956,
+    (float)0.63943899, (float)0.64195162, (float)0.64445734, (float)0.64695615,
+    (float)0.64944810, (float)0.65193301, (float)0.65441096, (float)0.65688187,
+    (float)0.65934587, (float)0.66180271, (float)0.66425246, (float)0.66669512,
+    (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405,
+    (float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710,
+    (float)0.68835455, (float)0.69072467, (float)0.69308740, (float)0.69544262,
+    (float)0.69779050, (float)0.70013082, (float)0.70246369, (float)0.70478904,
+    (float)0.70710677, (float)0.70941699, (float)0.71171963, (float)0.71401459,
+    (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789,
+    (float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721,
+    (float)0.73432255, (float)0.73653996, (float)0.73874950, (float)0.74095118,
+    (float)0.74314487, (float)0.74533057, (float)0.74750835, (float)0.74967808,
+    (float)0.75183982, (float)0.75399351, (float)0.75613910, (float)0.75827658,
+    (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515,
+    (float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241,
+    (float)0.77714598, (float)0.77920127, (float)0.78124821, (float)0.78328675,
+    (float)0.78531694, (float)0.78733873, (float)0.78935206, (float)0.79135692,
+    (float)0.79335338, (float)0.79534125, (float)0.79732066, (float)0.79929149,
+    (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915,
+    (float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853,
+    (float)0.81664157, (float)0.81852591, (float)0.82040149, (float)0.82226825,
+    (float)0.82412618, (float)0.82597536, (float)0.82781565, (float)0.82964706,
+    (float)0.83146966, (float)0.83328325, (float)0.83508795, (float)0.83688378,
+    (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703,
+    (float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574,
+    (float)0.85264021, (float)0.85434544, (float)0.85604161, (float)0.85772866,
+    (float)0.85940641, (float)0.86107504, (float)0.86273444, (float)0.86438453,
+    (float)0.86602545, (float)0.86765707, (float)0.86927933, (float)0.87089235,
+    (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097,
+    (float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921,
+    (float)0.88498765, (float)0.88650668, (float)0.88801610, (float)0.88951612,
+    (float)0.89100653, (float)0.89248741, (float)0.89395881, (float)0.89542055,
+    (float)0.89687276, (float)0.89831537, (float)0.89974827, (float)0.90117162,
+    (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826,
+    (float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951,
+    (float)0.91354549, (float)0.91487163, (float)0.91618794, (float)0.91749454,
+    (float)0.91879123, (float)0.92007810, (float)0.92135513, (float)0.92262226,
+    (float)0.92387950, (float)0.92512691, (float)0.92636442, (float)0.92759192,
+    (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267,
+    (float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362,
+    (float)0.93819135, (float)0.93931901, (float)0.94043654, (float)0.94154406,
+    (float)0.94264150, (float)0.94372880, (float)0.94480604, (float)0.94587320,
+    (float)0.94693011, (float)0.94797695, (float)0.94901365, (float)0.95004016,
+    (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440,
+    (float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521,
+    (float)0.95881975, (float)0.95974404, (float)0.96065807, (float)0.96156180,
+    (float)0.96245527, (float)0.96333838, (float)0.96421117, (float)0.96507370,
+    (float)0.96592581, (float)0.96676767, (float)0.96759909, (float)0.96842021,
+    (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077,
+    (float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486,
+    (float)0.97534233, (float)0.97605932, (float)0.97676587, (float)0.97746199,
+    (float)0.97814763, (float)0.97882277, (float)0.97948742, (float)0.98014158,
+    (float)0.98078531, (float)0.98141843, (float)0.98204112, (float)0.98265332,
+    (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662,
+    (float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111,
+    (float)0.98768836, (float)0.98819500, (float)0.98869103, (float)0.98917651,
+    (float)0.98965138, (float)0.99011570, (float)0.99056935, (float)0.99101239,
+    (float)0.99144489, (float)0.99186671, (float)0.99227792, (float)0.99267852,
+    (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448,
+    (float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015,
+    (float)0.99580491, (float)0.99609905, (float)0.99638247, (float)0.99665523,
+    (float)0.99691731, (float)0.99716878, (float)0.99740952, (float)0.99763954,
+    (float)0.99785894, (float)0.99806762, (float)0.99826562, (float)0.99845290,
+    (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520,
+    (float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632,
+    (float)0.99965733, (float)0.99973762, (float)0.99980724, (float)0.99986613,
+    (float)0.99991435, (float)0.99995178, (float)0.99997860, (float)0.99999464,
+    (float)1.00000000, (float)0.99999464, (float)0.99997860, (float)0.99995178,
+    (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762,
+    (float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216,
+    (float)0.99922901, (float)0.99909520, (float)0.99895066, (float)0.99879545,
+    (float)0.99862951, (float)0.99845290, (float)0.99826562, (float)0.99806762,
+    (float)0.99785894, (float)0.99763954, (float)0.99740946, (float)0.99716872,
+    (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905,
+    (float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862,
+    (float)0.99452192, (float)0.99417448, (float)0.99381644, (float)0.99344778,
+    (float)0.99306846, (float)0.99267852, (float)0.99227792, (float)0.99186671,
+    (float)0.99144489, (float)0.99101239, (float)0.99056935, (float)0.99011564,
+    (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494,
+    (float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497,
+    (float)0.98555607, (float)0.98499656, (float)0.98442656, (float)0.98384601,
+    (float)0.98325491, (float)0.98265326, (float)0.98204112, (float)0.98141843,
+    (float)0.98078525, (float)0.98014158, (float)0.97948742, (float)0.97882277,
+    (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932,
+    (float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862,
+    (float)0.97236991, (float)0.97160077, (float)0.97082120, (float)0.97003126,
+    (float)0.96923089, (float)0.96842015, (float)0.96759909, (float)0.96676761,
+    (float)0.96592581, (float)0.96507365, (float)0.96421117, (float)0.96333838,
+    (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404,
+    (float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525,
+    (float)0.95501995, (float)0.95404440, (float)0.95305860, (float)0.95206267,
+    (float)0.95105648, (float)0.95004016, (float)0.94901365, (float)0.94797695,
+    (float)0.94693011, (float)0.94587314, (float)0.94480604, (float)0.94372880,
+    (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895,
+    (float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817,
+    (float)0.93358046, (float)0.93240267, (float)0.93121493, (float)0.93001723,
+    (float)0.92880952, (float)0.92759192, (float)0.92636436, (float)0.92512691,
+    (float)0.92387950, (float)0.92262226, (float)0.92135507, (float)0.92007804,
+    (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157,
+    (float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835,
+    (float)0.90814310, (float)0.90676820, (float)0.90538365, (float)0.90398932,
+    (float)0.90258527, (float)0.90117157, (float)0.89974827, (float)0.89831525,
+    (float)0.89687276, (float)0.89542055, (float)0.89395875, (float)0.89248741,
+    (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662,
+    (float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384,
+    (float)0.87881714, (float)0.87725091, (float)0.87567532, (float)0.87409031,
+    (float)0.87249595, (float)0.87089223, (float)0.86927933, (float)0.86765701,
+    (float)0.86602539, (float)0.86438447, (float)0.86273432, (float)0.86107504,
+    (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544,
+    (float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951,
+    (float)0.84572780, (float)0.84397697, (float)0.84221715, (float)0.84044844,
+    (float)0.83867055, (float)0.83688372, (float)0.83508795, (float)0.83328319,
+    (float)0.83146954, (float)0.82964706, (float)0.82781565, (float)0.82597530,
+    (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591,
+    (float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609,
+    (float)0.80901700, (float)0.80708915, (float)0.80515265, (float)0.80320752,
+    (float)0.80125374, (float)0.79929143, (float)0.79732066, (float)0.79534125,
+    (float)0.79335332, (float)0.79135686, (float)0.78935200, (float)0.78733861,
+    (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121,
+    (float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029,
+    (float)0.76884180, (float)0.76674509, (float)0.76464021, (float)0.76252711,
+    (float)0.76040596, (float)0.75827658, (float)0.75613904, (float)0.75399339,
+    (float)0.75183970, (float)0.74967796, (float)0.74750835, (float)0.74533057,
+    (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996,
+    (float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305,
+    (float)0.72537428, (float)0.72311789, (float)0.72085363, (float)0.71858162,
+    (float)0.71630186, (float)0.71401453, (float)0.71171951, (float)0.70941705,
+    (float)0.70710677, (float)0.70478898, (float)0.70246363, (float)0.70013070,
+    (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461,
+    (float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021,
+    (float)0.67880070, (float)0.67639399, (float)0.67398006, (float)0.67155886,
+    (float)0.66913044, (float)0.66669512, (float)0.66425240, (float)0.66180259,
+    (float)0.65934575, (float)0.65688181, (float)0.65441096, (float)0.65193301,
+    (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150,
+    (float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014,
+    (float)0.62932026, (float)0.62677372, (float)0.62422055, (float)0.62166059,
+    (float)0.61909389, (float)0.61652064, (float)0.61394072, (float)0.61135429,
+    (float)0.60876143, (float)0.60616189, (float)0.60355592, (float)0.60094339,
+    (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960,
+    (float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461,
+    (float)0.57714522, (float)0.57446963, (float)0.57178789, (float)0.56910002,
+    (float)0.56640613, (float)0.56370628, (float)0.56100023, (float)0.55828822,
+    (float)0.55557019, (float)0.55284619, (float)0.55011630, (float)0.54738069,
+    (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916,
+    (float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596,
+    (float)0.52249849, (float)0.51970541, (float)0.51690674, (float)0.51410276,
+    (float)0.51129305, (float)0.50847787, (float)0.50565726, (float)0.50283122,
+    (float)0.50000006, (float)0.49716327, (float)0.49432117, (float)0.49147379,
+    (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212,
+    (float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798,
+    (float)0.46561456, (float)0.46271589, (float)0.45981231, (float)0.45690379,
+    (float)0.45399037, (float)0.45107210, (float)0.44814920, (float)0.44522130,
+    (float)0.44228864, (float)0.43935123, (float)0.43640912, (float)0.43346232,
+    (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928,
+    (float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400,
+    (float)0.40673658, (float)0.40374479, (float)0.40074870, (float)0.39774850,
+    (float)0.39474386, (float)0.39173496, (float)0.38872188, (float)0.38570464,
+    (float)0.38268328, (float)0.37965804, (float)0.37662849, (float)0.37359491,
+    (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117,
+    (float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529,
+    (float)0.34611690, (float)0.34304500, (float)0.33996922, (float)0.33688980,
+    (float)0.33380675, (float)0.33072016, (float)0.32763001, (float)0.32453656,
+    (float)0.32143945, (float)0.31833887, (float)0.31523487, (float)0.31212750,
+    (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521,
+    (float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155,
+    (float)0.28401530, (float)0.28087601, (float)0.27773371, (float)0.27458847,
+    (float)0.27144048, (float)0.26828936, (float)0.26513538, (float)0.26197854,
+    (float)0.25881892, (float)0.25565651, (float)0.25249159, (float)0.24932374,
+    (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600,
+    (float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794,
+    (float)0.22069728, (float)0.21750426, (float)0.21430916, (float)0.21111152,
+    (float)0.20791161, (float)0.20470949, (float)0.20150517, (float)0.19829892,
+    (float)0.19509031, (float)0.19187963, (float)0.18866688, (float)0.18545210,
+    (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376,
+    (float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584,
+    (float)0.15643445, (float)0.15320137, (float)0.14996666, (float)0.14673033,
+    (float)0.14349243, (float)0.14025325, (float)0.13701232, (float)0.13376991,
+    (float)0.13052608, (float)0.12728085, (float)0.12403426, (float)0.12078657,
+    (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230,
+    (float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980,
+    (float)0.09150149, (float)0.08824220, (float)0.08498220, (float)0.08172106,
+    (float)0.07845904, (float)0.07519618, (float)0.07193252, (float)0.06866808,
+    (float)0.06540315, (float)0.06213728, (float)0.05887074, (float)0.05560357,
+    (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954,
+    (float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798,
+    (float)0.02617695, (float)0.02290541, (float)0.01963361, (float)0.01636161,
+    (float)0.01308943, (float)0.00981712, (float)0.00654493, (float)0.00327244,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
+    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000};
 
 #endif  // MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
diff --git a/modules/audio_processing/residual_echo_detector.cc b/modules/audio_processing/residual_echo_detector.cc
index f506579..e805013 100644
--- a/modules/audio_processing/residual_echo_detector.cc
+++ b/modules/audio_processing/residual_echo_detector.cc
@@ -90,7 +90,7 @@
   }
 
   // Get the next render value.
-  const rtc::Optional<float> buffered_render_power = render_buffer_.Pop();
+  const absl::optional<float> buffered_render_power = render_buffer_.Pop();
   if (!buffered_render_power) {
     // This can happen in a few cases: at the start of a call, due to a glitch
     // or due to clock drift. The excess capture value will be ignored.
@@ -141,19 +141,20 @@
         read_index -= kLookbackFrames;
       }
       RTC_DCHECK_LT(read_index, render_power_.size());
-      RTC_LOG_F(LS_ERROR)
-          << "Echo detector internal state: {"
-             "Echo likelihood: " << echo_likelihood_
-          << ", Best Delay: " << best_delay
-          << ", Covariance: " << covariances_[best_delay].covariance()
-          << ", Last capture power: " << capture_power
-          << ", Capture mean: " << capture_mean
-          << ", Capture_standard deviation: " << capture_std_deviation
-          << ", Last render power: " << render_power_[read_index]
-          << ", Render mean: " << render_power_mean_[read_index]
-          << ", Render standard deviation: "
-          << render_power_std_dev_[read_index]
-          << ", Reliability: " << reliability_ << "}";
+      RTC_LOG_F(LS_ERROR) << "Echo detector internal state: {"
+                             "Echo likelihood: "
+                          << echo_likelihood_ << ", Best Delay: " << best_delay
+                          << ", Covariance: "
+                          << covariances_[best_delay].covariance()
+                          << ", Last capture power: " << capture_power
+                          << ", Capture mean: " << capture_mean
+                          << ", Capture_standard deviation: "
+                          << capture_std_deviation << ", Last render power: "
+                          << render_power_[read_index]
+                          << ", Render mean: " << render_power_mean_[read_index]
+                          << ", Render standard deviation: "
+                          << render_power_std_dev_[read_index]
+                          << ", Reliability: " << reliability_ << "}";
       log_counter_++;
     }
   }
diff --git a/modules/audio_processing/residual_echo_detector_unittest.cc b/modules/audio_processing/residual_echo_detector_unittest.cc
index 7bfa0d2..c6fb8e4 100644
--- a/modules/audio_processing/residual_echo_detector_unittest.cc
+++ b/modules/audio_processing/residual_echo_detector_unittest.cc
@@ -11,13 +11,15 @@
 #include <vector>
 
 #include "modules/audio_processing/residual_echo_detector.h"
+#include "rtc_base/refcountedobject.h"
 #include "test/gtest.h"
 
 namespace webrtc {
 
 TEST(ResidualEchoDetectorTests, Echo) {
-  ResidualEchoDetector echo_detector;
-  echo_detector.SetReliabilityForTest(1.0f);
+  rtc::scoped_refptr<ResidualEchoDetector> echo_detector =
+      new rtc::RefCountedObject<ResidualEchoDetector>();
+  echo_detector->SetReliabilityForTest(1.0f);
   std::vector<float> ones(160, 1.f);
   std::vector<float> zeros(160, 0.f);
 
@@ -26,24 +28,25 @@
   // frame interval.
   for (int i = 0; i < 1000; i++) {
     if (i % 20 == 0) {
-      echo_detector.AnalyzeRenderAudio(ones);
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(ones);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     } else if (i % 20 == 10) {
-      echo_detector.AnalyzeRenderAudio(zeros);
-      echo_detector.AnalyzeCaptureAudio(ones);
+      echo_detector->AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(ones);
     } else {
-      echo_detector.AnalyzeRenderAudio(zeros);
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     }
   }
   // We expect to detect echo with near certain likelihood.
-  auto ed_metrics = echo_detector.GetMetrics();
+  auto ed_metrics = echo_detector->GetMetrics();
   EXPECT_NEAR(1.f, ed_metrics.echo_likelihood, 0.01f);
 }
 
 TEST(ResidualEchoDetectorTests, NoEcho) {
-  ResidualEchoDetector echo_detector;
-  echo_detector.SetReliabilityForTest(1.0f);
+  rtc::scoped_refptr<ResidualEchoDetector> echo_detector =
+      new rtc::RefCountedObject<ResidualEchoDetector>();
+  echo_detector->SetReliabilityForTest(1.0f);
   std::vector<float> ones(160, 1.f);
   std::vector<float> zeros(160, 0.f);
 
@@ -51,20 +54,21 @@
   // detected.
   for (int i = 0; i < 1000; i++) {
     if (i % 20 == 0) {
-      echo_detector.AnalyzeRenderAudio(ones);
+      echo_detector->AnalyzeRenderAudio(ones);
     } else {
-      echo_detector.AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(zeros);
     }
-    echo_detector.AnalyzeCaptureAudio(zeros);
+    echo_detector->AnalyzeCaptureAudio(zeros);
   }
   // We expect to not detect any echo.
-  auto ed_metrics = echo_detector.GetMetrics();
+  auto ed_metrics = echo_detector->GetMetrics();
   EXPECT_NEAR(0.f, ed_metrics.echo_likelihood, 0.01f);
 }
 
 TEST(ResidualEchoDetectorTests, EchoWithRenderClockDrift) {
-  ResidualEchoDetector echo_detector;
-  echo_detector.SetReliabilityForTest(1.0f);
+  rtc::scoped_refptr<ResidualEchoDetector> echo_detector =
+      new rtc::RefCountedObject<ResidualEchoDetector>();
+  echo_detector->SetReliabilityForTest(1.0f);
   std::vector<float> ones(160, 1.f);
   std::vector<float> zeros(160, 0.f);
 
@@ -74,18 +78,18 @@
   // the render side producing data slightly faster.
   for (int i = 0; i < 1000; i++) {
     if (i % 20 == 0) {
-      echo_detector.AnalyzeRenderAudio(ones);
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(ones);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     } else if (i % 20 == 10) {
-      echo_detector.AnalyzeRenderAudio(zeros);
-      echo_detector.AnalyzeCaptureAudio(ones);
+      echo_detector->AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(ones);
     } else {
-      echo_detector.AnalyzeRenderAudio(zeros);
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     }
     if (i % 100 == 0) {
       // This is causing the simulated clock drift.
-      echo_detector.AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(zeros);
     }
   }
   // We expect to detect echo with high likelihood. Clock drift is harder to
@@ -94,13 +98,14 @@
   // A growing buffer can be caused by jitter or clock drift and it's not
   // possible to make this decision right away. For this reason we only expect
   // an echo likelihood of 75% in this test.
-  auto ed_metrics = echo_detector.GetMetrics();
+  auto ed_metrics = echo_detector->GetMetrics();
   EXPECT_GT(ed_metrics.echo_likelihood, 0.75f);
 }
 
 TEST(ResidualEchoDetectorTests, EchoWithCaptureClockDrift) {
-  ResidualEchoDetector echo_detector;
-  echo_detector.SetReliabilityForTest(1.0f);
+  rtc::scoped_refptr<ResidualEchoDetector> echo_detector =
+      new rtc::RefCountedObject<ResidualEchoDetector>();
+  echo_detector->SetReliabilityForTest(1.0f);
   std::vector<float> ones(160, 1.f);
   std::vector<float> zeros(160, 0.f);
 
@@ -110,22 +115,22 @@
   // the capture side producing data slightly faster.
   for (int i = 0; i < 1000; i++) {
     if (i % 20 == 0) {
-      echo_detector.AnalyzeRenderAudio(ones);
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(ones);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     } else if (i % 20 == 10) {
-      echo_detector.AnalyzeRenderAudio(zeros);
-      echo_detector.AnalyzeCaptureAudio(ones);
+      echo_detector->AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(ones);
     } else {
-      echo_detector.AnalyzeRenderAudio(zeros);
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeRenderAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     }
     if (i % 100 == 0) {
       // This is causing the simulated clock drift.
-      echo_detector.AnalyzeCaptureAudio(zeros);
+      echo_detector->AnalyzeCaptureAudio(zeros);
     }
   }
   // We expect to detect echo with near certain likelihood.
-  auto ed_metrics = echo_detector.GetMetrics();
+  auto ed_metrics = echo_detector->GetMetrics();
   EXPECT_NEAR(1.f, ed_metrics.echo_likelihood, 0.01f);
 }
 
diff --git a/modules/audio_processing/rms_level.cc b/modules/audio_processing/rms_level.cc
index 55db226..727ecfc 100644
--- a/modules/audio_processing/rms_level.cc
+++ b/modules/audio_processing/rms_level.cc
@@ -54,7 +54,7 @@
   sum_square_ = 0.f;
   sample_count_ = 0;
   max_sum_square_ = 0.f;
-  block_size_ = rtc::nullopt;
+  block_size_ = absl::nullopt;
 }
 
 void RmsLevel::Analyze(rtc::ArrayView<const int16_t> data) {
@@ -88,7 +88,7 @@
 
 RmsLevel::Levels RmsLevel::AverageAndPeak() {
   // Note that block_size_ should by design always be non-empty when
-  // sample_count_ != 0. Also, the * operator of rtc::Optional enforces this
+  // sample_count_ != 0. Also, the * operator of absl::optional enforces this
   // with a DCHECK.
   Levels levels = (sample_count_ == 0)
                       ? Levels{RmsLevel::kMinLevelDb, RmsLevel::kMinLevelDb}
diff --git a/modules/audio_processing/rms_level.h b/modules/audio_processing/rms_level.h
index 6fe22fd..ae45a45 100644
--- a/modules/audio_processing/rms_level.h
+++ b/modules/audio_processing/rms_level.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
 #define MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
 
+#include "absl/types/optional.h"
 #include "api/array_view.h"
-#include "api/optional.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
@@ -66,10 +66,9 @@
   float sum_square_;
   size_t sample_count_;
   float max_sum_square_;
-  rtc::Optional<size_t> block_size_;
+  absl::optional<size_t> block_size_;
 };
 
 }  // namespace webrtc
 
 #endif  // MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
-
diff --git a/modules/audio_processing/splitting_filter.cc b/modules/audio_processing/splitting_filter.cc
index e2b8f82..122bc9c 100644
--- a/modules/audio_processing/splitting_filter.cc
+++ b/modules/audio_processing/splitting_filter.cc
@@ -63,8 +63,7 @@
                                        IFChannelBuffer* bands) {
   RTC_DCHECK_EQ(two_bands_states_.size(), data->num_channels());
   for (size_t i = 0; i < two_bands_states_.size(); ++i) {
-    WebRtcSpl_AnalysisQMF(data->ibuf_const()->channels()[i],
-                          data->num_frames(),
+    WebRtcSpl_AnalysisQMF(data->ibuf_const()->channels()[i], data->num_frames(),
                           bands->ibuf()->channels(0)[i],
                           bands->ibuf()->channels(1)[i],
                           two_bands_states_[i].analysis_state1,
@@ -76,12 +75,11 @@
                                         IFChannelBuffer* data) {
   RTC_DCHECK_LE(data->num_channels(), two_bands_states_.size());
   for (size_t i = 0; i < data->num_channels(); ++i) {
-    WebRtcSpl_SynthesisQMF(bands->ibuf_const()->channels(0)[i],
-                           bands->ibuf_const()->channels(1)[i],
-                           bands->num_frames_per_band(),
-                           data->ibuf()->channels()[i],
-                           two_bands_states_[i].synthesis_state1,
-                           two_bands_states_[i].synthesis_state2);
+    WebRtcSpl_SynthesisQMF(
+        bands->ibuf_const()->channels(0)[i],
+        bands->ibuf_const()->channels(1)[i], bands->num_frames_per_band(),
+        data->ibuf()->channels()[i], two_bands_states_[i].synthesis_state1,
+        two_bands_states_[i].synthesis_state2);
   }
 }
 
diff --git a/modules/audio_processing/splitting_filter_unittest.cc b/modules/audio_processing/splitting_filter_unittest.cc
index 3e0dbb9..1caee64 100644
--- a/modules/audio_processing/splitting_filter_unittest.cc
+++ b/modules/audio_processing/splitting_filter_unittest.cc
@@ -39,8 +39,7 @@
   static const int kFrequenciesHz[kNumBands] = {1000, 12000, 18000};
   static const float kAmplitude = 8192.f;
   static const size_t kChunks = 8;
-  SplittingFilter splitting_filter(kChannels,
-                                   kNumBands,
+  SplittingFilter splitting_filter(kChannels, kNumBands,
                                    kSamplesPer48kHzChannel);
   IFChannelBuffer in_data(kSamplesPer48kHzChannel, kChannels, kNumBands);
   IFChannelBuffer bands(kSamplesPer48kHzChannel, kChannels, kNumBands);
@@ -48,8 +47,7 @@
   for (size_t i = 0; i < kChunks; ++i) {
     // Input signal generation.
     bool is_present[kNumBands];
-    memset(in_data.fbuf()->channels()[0],
-           0,
+    memset(in_data.fbuf()->channels()[0], 0,
            kSamplesPer48kHzChannel * sizeof(in_data.fbuf()->channels()[0][0]));
     for (size_t j = 0; j < kNumBands; ++j) {
       is_present[j] = i & (static_cast<size_t>(1) << j);
@@ -57,7 +55,7 @@
       for (size_t k = 0; k < kSamplesPer48kHzChannel; ++k) {
         in_data.fbuf()->channels()[0][k] +=
             amplitude * sin(2.f * M_PI * kFrequenciesHz[j] *
-                (i * kSamplesPer48kHzChannel + k) / kSampleRateHz);
+                            (i * kSamplesPer48kHzChannel + k) / kSampleRateHz);
       }
     }
     // Three band splitting filter.
diff --git a/modules/audio_processing/three_band_filter_bank.cc b/modules/audio_processing/three_band_filter_bank.cc
index f5a319b..dbbfc28 100644
--- a/modules/audio_processing/three_band_filter_bank.cc
+++ b/modules/audio_processing/three_band_filter_bank.cc
@@ -68,19 +68,19 @@
 // A Kaiser window is used because of its flexibility and the alpha is set to
 // 3.5, since that sets a stop band attenuation of 40dB ensuring a fast
 // transition.
-const float kLowpassCoeffs[kNumBands * kSparsity][kNumCoeffs] =
-    {{-0.00047749f, -0.00496888f, +0.16547118f, +0.00425496f},
-     {-0.00173287f, -0.01585778f, +0.14989004f, +0.00994113f},
-     {-0.00304815f, -0.02536082f, +0.12154542f, +0.01157993f},
-     {-0.00383509f, -0.02982767f, +0.08543175f, +0.00983212f},
-     {-0.00346946f, -0.02587886f, +0.04760441f, +0.00607594f},
-     {-0.00154717f, -0.01136076f, +0.01387458f, +0.00186353f},
-     {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f},
-     {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f},
-     {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f},
-     {+0.01157993f, +0.12154542f, -0.02536082f, -0.00304815f},
-     {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f},
-     {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}};
+const float kLowpassCoeffs[kNumBands * kSparsity][kNumCoeffs] = {
+    {-0.00047749f, -0.00496888f, +0.16547118f, +0.00425496f},
+    {-0.00173287f, -0.01585778f, +0.14989004f, +0.00994113f},
+    {-0.00304815f, -0.02536082f, +0.12154542f, +0.01157993f},
+    {-0.00383509f, -0.02982767f, +0.08543175f, +0.00983212f},
+    {-0.00346946f, -0.02587886f, +0.04760441f, +0.00607594f},
+    {-0.00154717f, -0.01136076f, +0.01387458f, +0.00186353f},
+    {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f},
+    {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f},
+    {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f},
+    {+0.01157993f, +0.12154542f, -0.02536082f, -0.00304815f},
+    {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f},
+    {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}};
 
 // Downsamples |in| into |out|, taking one every |kNumbands| starting from
 // |offset|. |split_length| is the |out| length. |in| has to be at least
@@ -150,8 +150,7 @@
     Downsample(in, in_buffer_.size(), kNumBands - i - 1, &in_buffer_[0]);
     for (size_t j = 0; j < kSparsity; ++j) {
       const size_t offset = i + j * kNumBands;
-      analysis_filters_[offset]->Filter(&in_buffer_[0],
-                                        in_buffer_.size(),
+      analysis_filters_[offset]->Filter(&in_buffer_[0], in_buffer_.size(),
                                         &out_buffer_[0]);
       DownModulate(&out_buffer_[0], out_buffer_.size(), offset, out);
     }
@@ -173,15 +172,13 @@
     for (size_t j = 0; j < kSparsity; ++j) {
       const size_t offset = i + j * kNumBands;
       UpModulate(in, in_buffer_.size(), offset, &in_buffer_[0]);
-      synthesis_filters_[offset]->Filter(&in_buffer_[0],
-                                         in_buffer_.size(),
+      synthesis_filters_[offset]->Filter(&in_buffer_[0], in_buffer_.size(),
                                          &out_buffer_[0]);
       Upsample(&out_buffer_[0], out_buffer_.size(), i, out);
     }
   }
 }
 
-
 // Modulates |in| by |dct_modulation_| and accumulates it in each of the
 // |kNumBands| bands of |out|. |offset| is the index in the period of the
 // cosines used for modulation. |split_length| is the length of |in| and each
diff --git a/modules/audio_processing/transient/click_annotate.cc b/modules/audio_processing/transient/click_annotate.cc
index 1f01d01..ce646b5 100644
--- a/modules/audio_processing/transient/click_annotate.cc
+++ b/modules/audio_processing/transient/click_annotate.cc
@@ -73,9 +73,7 @@
 
   // Read first buffer from the PCM test file.
   size_t file_samples_read = ReadInt16FromFileToFloatBuffer(
-      pcm_file.get(),
-      audio_buffer_length,
-      audio_buffer.get());
+      pcm_file.get(), audio_buffer_length, audio_buffer.get());
   for (int time = 0; file_samples_read > 0; time += chunk_size_ms) {
     // Pad the rest of the buffer with zeros.
     for (size_t i = file_samples_read; i < audio_buffer_length; ++i) {
@@ -92,14 +90,12 @@
     send_times.push_back(value);
 
     // Read next buffer from the PCM test file.
-    file_samples_read = ReadInt16FromFileToFloatBuffer(pcm_file.get(),
-                                                       audio_buffer_length,
-                                                       audio_buffer.get());
+    file_samples_read = ReadInt16FromFileToFloatBuffer(
+        pcm_file.get(), audio_buffer_length, audio_buffer.get());
   }
 
-  size_t floats_written = WriteFloatBufferToFile(dat_file.get(),
-                                                 send_times.size(),
-                                                 &send_times[0]);
+  size_t floats_written =
+      WriteFloatBufferToFile(dat_file.get(), send_times.size(), &send_times[0]);
 
   if (floats_written == 0) {
     printf("\nThe send times could not be written to DAT file\n\n");
diff --git a/modules/audio_processing/transient/common.h b/modules/audio_processing/transient/common.h
index 69546fc..63c9a7b 100644
--- a/modules/audio_processing/transient/common.h
+++ b/modules/audio_processing/transient/common.h
@@ -22,6 +22,6 @@
   kSampleRate48kHz = 48000
 };
 
-} // namespace ts
-} // namespace webrtc
+}  // namespace ts
+}  // namespace webrtc
 #endif  // MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
diff --git a/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h b/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
index 4de24e0..92233bf 100644
--- a/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
+++ b/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
@@ -19,44 +19,25 @@
 
 const int kDaubechies8CoefficientsLength = 16;
 
-const float kDaubechies8HighPassCoefficients[kDaubechies8CoefficientsLength]
-    = {
-  -5.44158422430816093862e-02f,
-  3.12871590914465924627e-01f,
-  -6.75630736298012846142e-01f,
-  5.85354683654869090148e-01f,
-  1.58291052560238926228e-02f,
-  -2.84015542962428091389e-01f,
-  -4.72484573997972536787e-04f,
-  1.28747426620186011803e-01f,
-  1.73693010020221083600e-02f,
-  -4.40882539310647192377e-02f,
-  -1.39810279170155156436e-02f,
-  8.74609404701565465445e-03f,
-  4.87035299301066034600e-03f,
-  -3.91740372995977108837e-04f,
-  -6.75449405998556772109e-04f,
-  -1.17476784002281916305e-04f
-};
+const float kDaubechies8HighPassCoefficients[kDaubechies8CoefficientsLength] = {
+    -5.44158422430816093862e-02f, 3.12871590914465924627e-01f,
+    -6.75630736298012846142e-01f, 5.85354683654869090148e-01f,
+    1.58291052560238926228e-02f,  -2.84015542962428091389e-01f,
+    -4.72484573997972536787e-04f, 1.28747426620186011803e-01f,
+    1.73693010020221083600e-02f,  -4.40882539310647192377e-02f,
+    -1.39810279170155156436e-02f, 8.74609404701565465445e-03f,
+    4.87035299301066034600e-03f,  -3.91740372995977108837e-04f,
+    -6.75449405998556772109e-04f, -1.17476784002281916305e-04f};
 
 const float kDaubechies8LowPassCoefficients[kDaubechies8CoefficientsLength] = {
-  -1.17476784002281916305e-04f,
-  6.75449405998556772109e-04f,
-  -3.91740372995977108837e-04f,
-  -4.87035299301066034600e-03f,
-  8.74609404701565465445e-03f,
-  1.39810279170155156436e-02f,
-  -4.40882539310647192377e-02f,
-  -1.73693010020221083600e-02f,
-  1.28747426620186011803e-01f,
-  4.72484573997972536787e-04f,
-  -2.84015542962428091389e-01f,
-  -1.58291052560238926228e-02f,
-  5.85354683654869090148e-01f,
-  6.75630736298012846142e-01f,
-  3.12871590914465924627e-01f,
-  5.44158422430816093862e-02f
-};
+    -1.17476784002281916305e-04f, 6.75449405998556772109e-04f,
+    -3.91740372995977108837e-04f, -4.87035299301066034600e-03f,
+    8.74609404701565465445e-03f,  1.39810279170155156436e-02f,
+    -4.40882539310647192377e-02f, -1.73693010020221083600e-02f,
+    1.28747426620186011803e-01f,  4.72484573997972536787e-04f,
+    -2.84015542962428091389e-01f, -1.58291052560238926228e-02f,
+    5.85354683654869090148e-01f,  6.75630736298012846142e-01f,
+    3.12871590914465924627e-01f,  5.44158422430816093862e-02f};
 
 }  // namespace webrtc
 
diff --git a/modules/audio_processing/transient/dyadic_decimator.h b/modules/audio_processing/transient/dyadic_decimator.h
index 104f95d..e5b1961 100644
--- a/modules/audio_processing/transient/dyadic_decimator.h
+++ b/modules/audio_processing/transient/dyadic_decimator.h
@@ -44,7 +44,7 @@
 //         GetOutLengthToDyadicDecimate().
 //         Must be previously allocated.
 // Returns the number of output samples, -1 on error.
-template<typename T>
+template <typename T>
 static size_t DyadicDecimate(const T* in,
                              size_t in_length,
                              bool odd_sequence,
diff --git a/modules/audio_processing/transient/dyadic_decimator_unittest.cc b/modules/audio_processing/transient/dyadic_decimator_unittest.cc
index c407f47..3e65a7b 100644
--- a/modules/audio_processing/transient/dyadic_decimator_unittest.cc
+++ b/modules/audio_processing/transient/dyadic_decimator_unittest.cc
@@ -19,7 +19,7 @@
 static const size_t kOutBufferLength = 3;
 
 int16_t const test_buffer_even_len[] = {0, 1, 2, 3, 4, 5};
-int16_t const test_buffer_odd_len[]  = {0, 1, 2, 3, 4};
+int16_t const test_buffer_odd_len[] = {0, 1, 2, 3, 4};
 int16_t test_buffer_out[kOutBufferLength];
 
 TEST(DyadicDecimatorTest, GetOutLengthToDyadicDecimate) {
@@ -29,30 +29,23 @@
   EXPECT_EQ(2u, GetOutLengthToDyadicDecimate(5, true));
 }
 
-
 TEST(DyadicDecimatorTest, DyadicDecimateErrorValues) {
   size_t out_samples = 0;
 
-  out_samples = DyadicDecimate(static_cast<int16_t*>(NULL),
-                               kEvenBufferLength,
+  out_samples = DyadicDecimate(static_cast<int16_t*>(NULL), kEvenBufferLength,
                                false,  // Even sequence.
-                               test_buffer_out,
-                               kOutBufferLength);
+                               test_buffer_out, kOutBufferLength);
   EXPECT_EQ(0u, out_samples);
 
-  out_samples = DyadicDecimate(test_buffer_even_len,
-                               kEvenBufferLength,
+  out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
                                false,  // Even sequence.
-                               static_cast<int16_t*>(NULL),
-                               kOutBufferLength);
+                               static_cast<int16_t*>(NULL), kOutBufferLength);
   EXPECT_EQ(0u, out_samples);
 
   // Less than required |out_length|.
-  out_samples = DyadicDecimate(test_buffer_even_len,
-                               kEvenBufferLength,
+  out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
                                false,  // Even sequence.
-                               test_buffer_out,
-                               2);
+                               test_buffer_out, 2);
   EXPECT_EQ(0u, out_samples);
 }
 
@@ -60,11 +53,9 @@
   size_t expected_out_samples =
       GetOutLengthToDyadicDecimate(kEvenBufferLength, false);
 
-  size_t out_samples = DyadicDecimate(test_buffer_even_len,
-                                      kEvenBufferLength,
+  size_t out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
                                       false,  // Even sequence.
-                                      test_buffer_out,
-                                      kOutBufferLength);
+                                      test_buffer_out, kOutBufferLength);
 
   EXPECT_EQ(expected_out_samples, out_samples);
 
@@ -77,11 +68,9 @@
   size_t expected_out_samples =
       GetOutLengthToDyadicDecimate(kEvenBufferLength, true);
 
-  size_t out_samples = DyadicDecimate(test_buffer_even_len,
-                                      kEvenBufferLength,
+  size_t out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
                                       true,  // Odd sequence.
-                                      test_buffer_out,
-                                      kOutBufferLength);
+                                      test_buffer_out, kOutBufferLength);
 
   EXPECT_EQ(expected_out_samples, out_samples);
 
@@ -94,11 +83,9 @@
   size_t expected_out_samples =
       GetOutLengthToDyadicDecimate(kOddBufferLength, false);
 
-  size_t out_samples = DyadicDecimate(test_buffer_odd_len,
-                                      kOddBufferLength,
+  size_t out_samples = DyadicDecimate(test_buffer_odd_len, kOddBufferLength,
                                       false,  // Even sequence.
-                                      test_buffer_out,
-                                      kOutBufferLength);
+                                      test_buffer_out, kOutBufferLength);
 
   EXPECT_EQ(expected_out_samples, out_samples);
 
@@ -111,11 +98,9 @@
   size_t expected_out_samples =
       GetOutLengthToDyadicDecimate(kOddBufferLength, true);
 
-  size_t out_samples = DyadicDecimate(test_buffer_odd_len,
-                                      kOddBufferLength,
+  size_t out_samples = DyadicDecimate(test_buffer_odd_len, kOddBufferLength,
                                       true,  // Odd sequence.
-                                      test_buffer_out,
-                                      kOutBufferLength);
+                                      test_buffer_out, kOutBufferLength);
 
   EXPECT_EQ(expected_out_samples, out_samples);
 
diff --git a/modules/audio_processing/transient/file_utils_unittest.cc b/modules/audio_processing/transient/file_utils_unittest.cc
index d9880f9..05f8341 100644
--- a/modules/audio_processing/transient/file_utils_unittest.cc
+++ b/modules/audio_processing/transient/file_utils_unittest.cc
@@ -11,8 +11,8 @@
 #include "modules/audio_processing/transient/file_utils.h"
 
 #include <string.h>
-#include <string>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "rtc_base/system/file_wrapper.h"
@@ -26,18 +26,18 @@
 static const uint8_t kEBytesf[4] = {0x54, 0xF8, 0x2D, 0x40};
 static const uint8_t kAvogadroBytesf[4] = {0x2F, 0x0C, 0xFF, 0x66};
 
-static const uint8_t kPiBytes[8] =
-    {0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40};
-static const uint8_t kEBytes[8] =
-    {0x69, 0x57, 0x14, 0x8B, 0x0A, 0xBF, 0x05, 0x40};
-static const uint8_t kAvogadroBytes[8] =
-    {0xF4, 0xBC, 0xA8, 0xDF, 0x85, 0xE1, 0xDF, 0x44};
+static const uint8_t kPiBytes[8] = {0x18, 0x2D, 0x44, 0x54,
+                                    0xFB, 0x21, 0x09, 0x40};
+static const uint8_t kEBytes[8] = {0x69, 0x57, 0x14, 0x8B,
+                                   0x0A, 0xBF, 0x05, 0x40};
+static const uint8_t kAvogadroBytes[8] = {0xF4, 0xBC, 0xA8, 0xDF,
+                                          0x85, 0xE1, 0xDF, 0x44};
 
 static const double kPi = 3.14159265358979323846;
 static const double kE = 2.71828182845904523536;
 static const double kAvogadro = 602214100000000000000000.0;
 
-class TransientFileUtilsTest: public ::testing::Test {
+class TransientFileUtilsTest : public ::testing::Test {
  protected:
   TransientFileUtilsTest()
       : kTestFileName(
@@ -47,12 +47,10 @@
             test::ResourcePath("audio_processing/transient/float-utils",
                                "dat")) {}
 
-  ~TransientFileUtilsTest() override {
-    CleanupTempFiles();
-  }
+  ~TransientFileUtilsTest() override { CleanupTempFiles(); }
 
   std::string CreateTempFilename(const std::string& dir,
-      const std::string& prefix) {
+                                 const std::string& prefix) {
     std::string filename = test::TempFilename(dir, prefix);
     temp_filenames_.push_back(filename);
     return filename;
@@ -170,9 +168,8 @@
   const size_t kBufferLength = 12;
   std::unique_ptr<int16_t[]> buffer(new int16_t[kBufferLength]);
 
-  EXPECT_EQ(kBufferLength, ReadInt16BufferFromFile(file.get(),
-                                                   kBufferLength,
-                                                   buffer.get()));
+  EXPECT_EQ(kBufferLength,
+            ReadInt16BufferFromFile(file.get(), kBufferLength, buffer.get()));
   EXPECT_EQ(22377, buffer[4]);
   EXPECT_EQ(16389, buffer[7]);
   EXPECT_EQ(17631, buffer[kBufferLength - 1]);
@@ -184,9 +181,9 @@
   // int16s read.
   const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
   buffer.reset(new int16_t[kBufferLenghtLargerThanFile]);
-  EXPECT_EQ(kBufferLength, ReadInt16BufferFromFile(file.get(),
-                                                   kBufferLenghtLargerThanFile,
-                                                   buffer.get()));
+  EXPECT_EQ(kBufferLength,
+            ReadInt16BufferFromFile(file.get(), kBufferLenghtLargerThanFile,
+                                    buffer.get()));
   EXPECT_EQ(11544, buffer[0]);
   EXPECT_EQ(22377, buffer[4]);
   EXPECT_EQ(16389, buffer[7]);
@@ -211,9 +208,8 @@
   const size_t kBufferLength = 12;
   std::unique_ptr<float[]> buffer(new float[kBufferLength]);
 
-  EXPECT_EQ(kBufferLength, ReadInt16FromFileToFloatBuffer(file.get(),
-                                                          kBufferLength,
-                                                          buffer.get()));
+  EXPECT_EQ(kBufferLength, ReadInt16FromFileToFloatBuffer(
+                               file.get(), kBufferLength, buffer.get()));
 
   EXPECT_DOUBLE_EQ(11544, buffer[0]);
   EXPECT_DOUBLE_EQ(22377, buffer[4]);
@@ -228,9 +224,8 @@
   const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
   buffer.reset(new float[kBufferLenghtLargerThanFile]);
   EXPECT_EQ(kBufferLength,
-            ReadInt16FromFileToFloatBuffer(file.get(),
-                                           kBufferLenghtLargerThanFile,
-                                           buffer.get()));
+            ReadInt16FromFileToFloatBuffer(
+                file.get(), kBufferLenghtLargerThanFile, buffer.get()));
   EXPECT_DOUBLE_EQ(11544, buffer[0]);
   EXPECT_DOUBLE_EQ(22377, buffer[4]);
   EXPECT_DOUBLE_EQ(16389, buffer[7]);
@@ -255,9 +250,8 @@
   const size_t kBufferLength = 12;
   std::unique_ptr<double[]> buffer(new double[kBufferLength]);
 
-  EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer(file.get(),
-                                                           kBufferLength,
-                                                           buffer.get()));
+  EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer(
+                               file.get(), kBufferLength, buffer.get()));
   EXPECT_DOUBLE_EQ(11544, buffer[0]);
   EXPECT_DOUBLE_EQ(22377, buffer[4]);
   EXPECT_DOUBLE_EQ(16389, buffer[7]);
@@ -271,9 +265,8 @@
   const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
   buffer.reset(new double[kBufferLenghtLargerThanFile]);
   EXPECT_EQ(kBufferLength,
-            ReadInt16FromFileToDoubleBuffer(file.get(),
-                                            kBufferLenghtLargerThanFile,
-                                            buffer.get()));
+            ReadInt16FromFileToDoubleBuffer(
+                file.get(), kBufferLenghtLargerThanFile, buffer.get()));
   EXPECT_DOUBLE_EQ(11544, buffer[0]);
   EXPECT_DOUBLE_EQ(22377, buffer[4]);
   EXPECT_DOUBLE_EQ(16389, buffer[7]);
@@ -297,9 +290,8 @@
   const size_t kBufferLength = 3;
   std::unique_ptr<float[]> buffer(new float[kBufferLength]);
 
-  EXPECT_EQ(kBufferLength, ReadFloatBufferFromFile(file.get(),
-                                                   kBufferLength,
-                                                   buffer.get()));
+  EXPECT_EQ(kBufferLength,
+            ReadFloatBufferFromFile(file.get(), kBufferLength, buffer.get()));
   EXPECT_FLOAT_EQ(kPi, buffer[0]);
   EXPECT_FLOAT_EQ(kE, buffer[1]);
   EXPECT_FLOAT_EQ(kAvogadro, buffer[2]);
@@ -311,9 +303,9 @@
   // doubles read.
   const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
   buffer.reset(new float[kBufferLenghtLargerThanFile]);
-  EXPECT_EQ(kBufferLength, ReadFloatBufferFromFile(file.get(),
-                                                   kBufferLenghtLargerThanFile,
-                                                   buffer.get()));
+  EXPECT_EQ(kBufferLength,
+            ReadFloatBufferFromFile(file.get(), kBufferLenghtLargerThanFile,
+                                    buffer.get()));
   EXPECT_FLOAT_EQ(kPi, buffer[0]);
   EXPECT_FLOAT_EQ(kE, buffer[1]);
   EXPECT_FLOAT_EQ(kAvogadro, buffer[2]);
@@ -336,9 +328,8 @@
   const size_t kBufferLength = 3;
   std::unique_ptr<double[]> buffer(new double[kBufferLength]);
 
-  EXPECT_EQ(kBufferLength, ReadDoubleBufferFromFile(file.get(),
-                                                    kBufferLength,
-                                                    buffer.get()));
+  EXPECT_EQ(kBufferLength,
+            ReadDoubleBufferFromFile(file.get(), kBufferLength, buffer.get()));
   EXPECT_DOUBLE_EQ(kPi, buffer[0]);
   EXPECT_DOUBLE_EQ(kE, buffer[1]);
   EXPECT_DOUBLE_EQ(kAvogadro, buffer[2]);
@@ -350,9 +341,9 @@
   // doubles read.
   const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
   buffer.reset(new double[kBufferLenghtLargerThanFile]);
-  EXPECT_EQ(kBufferLength, ReadDoubleBufferFromFile(file.get(),
-                                                    kBufferLenghtLargerThanFile,
-                                                    buffer.get()));
+  EXPECT_EQ(kBufferLength,
+            ReadDoubleBufferFromFile(file.get(), kBufferLenghtLargerThanFile,
+                                     buffer.get()));
   EXPECT_DOUBLE_EQ(kPi, buffer[0]);
   EXPECT_DOUBLE_EQ(kE, buffer[1]);
   EXPECT_DOUBLE_EQ(kAvogadro, buffer[2]);
@@ -366,8 +357,8 @@
 TEST_F(TransientFileUtilsTest, MAYBE_WriteInt16BufferToFile) {
   std::unique_ptr<FileWrapper> file(FileWrapper::Create());
 
-  std::string kOutFileName = CreateTempFilename(test::OutputPath(),
-                                                "utils_test");
+  std::string kOutFileName =
+      CreateTempFilename(test::OutputPath(), "utils_test");
 
   file->OpenFile(kOutFileName.c_str(), false);  // Write mode.
   ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
@@ -381,8 +372,7 @@
   written_buffer[1] = 2;
   written_buffer[2] = 3;
 
-  EXPECT_EQ(kBufferLength, WriteInt16BufferToFile(file.get(),
-                                                  kBufferLength,
+  EXPECT_EQ(kBufferLength, WriteInt16BufferToFile(file.get(), kBufferLength,
                                                   written_buffer.get()));
 
   file->CloseFile();
@@ -391,11 +381,9 @@
   ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
                                << kOutFileName.c_str();
 
-  EXPECT_EQ(kBufferLength, ReadInt16BufferFromFile(file.get(),
-                                                   kBufferLength,
+  EXPECT_EQ(kBufferLength, ReadInt16BufferFromFile(file.get(), kBufferLength,
                                                    read_buffer.get()));
-  EXPECT_EQ(0, memcmp(written_buffer.get(),
-                      read_buffer.get(),
+  EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
                       kBufferLength * sizeof(written_buffer[0])));
 }
 
@@ -407,8 +395,8 @@
 TEST_F(TransientFileUtilsTest, MAYBE_WriteFloatBufferToFile) {
   std::unique_ptr<FileWrapper> file(FileWrapper::Create());
 
-  std::string kOutFileName = CreateTempFilename(test::OutputPath(),
-                                                "utils_test");
+  std::string kOutFileName =
+      CreateTempFilename(test::OutputPath(), "utils_test");
 
   file->OpenFile(kOutFileName.c_str(), false);  // Write mode.
   ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
@@ -422,8 +410,7 @@
   written_buffer[1] = static_cast<float>(kE);
   written_buffer[2] = static_cast<float>(kAvogadro);
 
-  EXPECT_EQ(kBufferLength, WriteFloatBufferToFile(file.get(),
-                                                  kBufferLength,
+  EXPECT_EQ(kBufferLength, WriteFloatBufferToFile(file.get(), kBufferLength,
                                                   written_buffer.get()));
 
   file->CloseFile();
@@ -432,11 +419,9 @@
   ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
                                << kOutFileName.c_str();
 
-  EXPECT_EQ(kBufferLength, ReadFloatBufferFromFile(file.get(),
-                                                   kBufferLength,
+  EXPECT_EQ(kBufferLength, ReadFloatBufferFromFile(file.get(), kBufferLength,
                                                    read_buffer.get()));
-  EXPECT_EQ(0, memcmp(written_buffer.get(),
-                      read_buffer.get(),
+  EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
                       kBufferLength * sizeof(written_buffer[0])));
 }
 
@@ -448,8 +433,8 @@
 TEST_F(TransientFileUtilsTest, MAYBE_WriteDoubleBufferToFile) {
   std::unique_ptr<FileWrapper> file(FileWrapper::Create());
 
-  std::string kOutFileName = CreateTempFilename(test::OutputPath(),
-                                                "utils_test");
+  std::string kOutFileName =
+      CreateTempFilename(test::OutputPath(), "utils_test");
 
   file->OpenFile(kOutFileName.c_str(), false);  // Write mode.
   ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
@@ -463,8 +448,7 @@
   written_buffer[1] = kE;
   written_buffer[2] = kAvogadro;
 
-  EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(file.get(),
-                                                   kBufferLength,
+  EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(file.get(), kBufferLength,
                                                    written_buffer.get()));
 
   file->CloseFile();
@@ -473,11 +457,9 @@
   ASSERT_TRUE(file->is_open()) << "File could not be opened:\n"
                                << kOutFileName.c_str();
 
-  EXPECT_EQ(kBufferLength, ReadDoubleBufferFromFile(file.get(),
-                                                    kBufferLength,
+  EXPECT_EQ(kBufferLength, ReadDoubleBufferFromFile(file.get(), kBufferLength,
                                                     read_buffer.get()));
-  EXPECT_EQ(0, memcmp(written_buffer.get(),
-                      read_buffer.get(),
+  EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
                       kBufferLength * sizeof(written_buffer[0])));
 }
 
@@ -501,9 +483,8 @@
 
   // Tests with file not opened.
   EXPECT_EQ(0u, ReadInt16BufferFromFile(file.get(), 1, int16_buffer.get()));
-  EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(file.get(),
-                                                1,
-                                                double_buffer.get()));
+  EXPECT_EQ(
+      0u, ReadInt16FromFileToDoubleBuffer(file.get(), 1, double_buffer.get()));
   EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 1, double_buffer.get()));
   EXPECT_EQ(0u, WriteInt16BufferToFile(file.get(), 1, int16_buffer.get()));
   EXPECT_EQ(0u, WriteDoubleBufferToFile(file.get(), 1, double_buffer.get()));
@@ -518,9 +499,8 @@
 
   EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(NULL, 1, double_buffer.get()));
   EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(file.get(), 1, NULL));
-  EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(file.get(),
-                                                0,
-                                                double_buffer.get()));
+  EXPECT_EQ(
+      0u, ReadInt16FromFileToDoubleBuffer(file.get(), 0, double_buffer.get()));
 
   EXPECT_EQ(0u, ReadDoubleBufferFromFile(NULL, 1, double_buffer.get()));
   EXPECT_EQ(0u, ReadDoubleBufferFromFile(file.get(), 1, NULL));
@@ -536,4 +516,3 @@
 }
 
 }  // namespace webrtc
-
diff --git a/modules/audio_processing/transient/moving_moments.cc b/modules/audio_processing/transient/moving_moments.cc
index 46b16b8..4be4d6a 100644
--- a/modules/audio_processing/transient/moving_moments.cc
+++ b/modules/audio_processing/transient/moving_moments.cc
@@ -18,10 +18,7 @@
 namespace webrtc {
 
 MovingMoments::MovingMoments(size_t length)
-    : length_(length),
-      queue_(),
-      sum_(0.0),
-      sum_of_squares_(0.0) {
+    : length_(length), queue_(), sum_(0.0), sum_of_squares_(0.0) {
   RTC_DCHECK_GT(length, 0);
   for (size_t i = 0; i < length; ++i) {
     queue_.push(0.0);
@@ -30,8 +27,10 @@
 
 MovingMoments::~MovingMoments() {}
 
-void MovingMoments::CalculateMoments(const float* in, size_t in_length,
-                                     float* first, float* second) {
+void MovingMoments::CalculateMoments(const float* in,
+                                     size_t in_length,
+                                     float* first,
+                                     float* second) {
   RTC_DCHECK(in);
   RTC_DCHECK_GT(in_length, 0);
   RTC_DCHECK(first);
diff --git a/modules/audio_processing/transient/moving_moments.h b/modules/audio_processing/transient/moving_moments.h
index f1b3e38..6dc0520 100644
--- a/modules/audio_processing/transient/moving_moments.h
+++ b/modules/audio_processing/transient/moving_moments.h
@@ -33,8 +33,10 @@
 
   // Calculates the new values using |in|. Results will be in the out buffers.
   // |first| and |second| must be allocated with at least |in_length|.
-  void CalculateMoments(const float* in, size_t in_length,
-                        float* first, float* second);
+  void CalculateMoments(const float* in,
+                        size_t in_length,
+                        float* first,
+                        float* second);
 
  private:
   size_t length_;
@@ -48,5 +50,4 @@
 
 }  // namespace webrtc
 
-
 #endif  // MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
diff --git a/modules/audio_processing/transient/moving_moments_unittest.cc b/modules/audio_processing/transient/moving_moments_unittest.cc
index 057bc45..b0e613e 100644
--- a/modules/audio_processing/transient/moving_moments_unittest.cc
+++ b/modules/audio_processing/transient/moving_moments_unittest.cc
@@ -26,7 +26,8 @@
   virtual void SetUp();
   // Calls CalculateMoments and verifies that it produces the expected
   // outputs.
-  void CalculateMomentsAndVerify(const float* input, size_t input_length,
+  void CalculateMomentsAndVerify(const float* input,
+                                 size_t input_length,
                                  const float* expected_mean,
                                  const float* expected_mean_squares);
 
@@ -42,14 +43,13 @@
 }
 
 void MovingMomentsTest::CalculateMomentsAndVerify(
-    const float* input, size_t input_length,
+    const float* input,
+    size_t input_length,
     const float* expected_mean,
     const float* expected_mean_squares) {
   ASSERT_LE(input_length, kMaxOutputLength);
 
-  moving_moments_->CalculateMoments(input,
-                                    input_length,
-                                    output_mean_,
+  moving_moments_->CalculateMoments(input, input_length, output_mean_,
                                     output_mean_squares_);
 
   for (size_t i = 1; i < input_length; ++i) {
@@ -73,10 +73,10 @@
   const float kInput[] = {5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f};
   const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
-  const float expected_mean[kInputLength] =
-      {1.f, 2.f, 3.f, 4.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f};
-  const float expected_mean_squares[kInputLength] =
-      {5.f, 10.f, 15.f, 20.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f};
+  const float expected_mean[kInputLength] = {1.f, 2.f, 3.f, 4.f, 5.f,
+                                             5.f, 5.f, 5.f, 5.f, 5.f};
+  const float expected_mean_squares[kInputLength] = {
+      5.f, 10.f, 15.f, 20.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f};
 
   CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
                             expected_mean_squares);
@@ -86,24 +86,23 @@
   const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f};
   const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
-  const float expected_mean[kInputLength] =
-      {0.2f, 0.6f, 1.2f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f};
-  const float expected_mean_squares[kInputLength] =
-      {0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
+  const float expected_mean[kInputLength] = {0.2f, 0.6f, 1.2f, 2.f, 3.f,
+                                             4.f,  5.f,  6.f,  7.f};
+  const float expected_mean_squares[kInputLength] = {
+      0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
 
   CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
                             expected_mean_squares);
 }
 
 TEST_F(MovingMomentsTest, CorrectMomentsOfADecreasingBuffer) {
-  const float kInput[] =
-      {-1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f, -8.f, -9.f};
+  const float kInput[] = {-1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f, -8.f, -9.f};
   const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
-  const float expected_mean[kInputLength] =
-      {-0.2f, -0.6f, -1.2f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f};
-  const float expected_mean_squares[kInputLength] =
-      {0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
+  const float expected_mean[kInputLength] = {-0.2f, -0.6f, -1.2f, -2.f, -3.f,
+                                             -4.f,  -5.f,  -6.f,  -7.f};
+  const float expected_mean_squares[kInputLength] = {
+      0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
 
   CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
                             expected_mean_squares);
@@ -112,76 +111,78 @@
 TEST_F(MovingMomentsTest, CorrectMomentsOfAZeroMeanSequence) {
   const size_t kMovingMomentsBufferLength = 4;
   moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
-  const float kInput[] =
-      {1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f};
+  const float kInput[] = {1.f,  -1.f, 1.f,  -1.f, 1.f,
+                          -1.f, 1.f,  -1.f, 1.f,  -1.f};
   const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
-  const float expected_mean[kInputLength] =
-      {0.25f, 0.f, 0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
-  const float expected_mean_squares[kInputLength] =
-      {0.25f, 0.5f, 0.75f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
+  const float expected_mean[kInputLength] = {0.25f, 0.f, 0.25f, 0.f, 0.f,
+                                             0.f,   0.f, 0.f,   0.f, 0.f};
+  const float expected_mean_squares[kInputLength] = {
+      0.25f, 0.5f, 0.75f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
 
   CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
                             expected_mean_squares);
 }
 
 TEST_F(MovingMomentsTest, CorrectMomentsOfAnArbitraryBuffer) {
-  const float kInput[] =
-      {0.2f, 0.3f, 0.5f, 0.7f, 0.11f, 0.13f, 0.17f, 0.19f, 0.23f};
+  const float kInput[] = {0.2f,  0.3f,  0.5f,  0.7f, 0.11f,
+                          0.13f, 0.17f, 0.19f, 0.23f};
   const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
-  const float expected_mean[kInputLength] =
-      {0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
-  const float expected_mean_squares[kInputLength] =
-      {0.008f, 0.026f, 0.076f, 0.174f, 0.1764f, 0.1718f, 0.1596f, 0.1168f,
-      0.0294f};
+  const float expected_mean[kInputLength] = {
+      0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
+  const float expected_mean_squares[kInputLength] = {0.008f,  0.026f,  0.076f,
+                                                     0.174f,  0.1764f, 0.1718f,
+                                                     0.1596f, 0.1168f, 0.0294f};
 
   CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
                             expected_mean_squares);
 }
 
 TEST_F(MovingMomentsTest, MutipleCalculateMomentsCalls) {
-  const float kInputFirstCall[] =
-      {0.2f, 0.3f, 0.5f, 0.7f, 0.11f, 0.13f, 0.17f, 0.19f, 0.23f};
-  const size_t kInputFirstCallLength = sizeof(kInputFirstCall) /
-                                    sizeof(kInputFirstCall[0]);
+  const float kInputFirstCall[] = {0.2f,  0.3f,  0.5f,  0.7f, 0.11f,
+                                   0.13f, 0.17f, 0.19f, 0.23f};
+  const size_t kInputFirstCallLength =
+      sizeof(kInputFirstCall) / sizeof(kInputFirstCall[0]);
   const float kInputSecondCall[] = {0.29f, 0.31f};
-  const size_t kInputSecondCallLength = sizeof(kInputSecondCall) /
-                                     sizeof(kInputSecondCall[0]);
+  const size_t kInputSecondCallLength =
+      sizeof(kInputSecondCall) / sizeof(kInputSecondCall[0]);
   const float kInputThirdCall[] = {0.37f, 0.41f, 0.43f, 0.47f};
-  const size_t kInputThirdCallLength = sizeof(kInputThirdCall) /
-                                    sizeof(kInputThirdCall[0]);
+  const size_t kInputThirdCallLength =
+      sizeof(kInputThirdCall) / sizeof(kInputThirdCall[0]);
 
-  const float expected_mean_first_call[kInputFirstCallLength] =
-      {0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
-  const float expected_mean_squares_first_call[kInputFirstCallLength] =
-      {0.008f, 0.026f, 0.076f, 0.174f, 0.1764f, 0.1718f, 0.1596f, 0.1168f,
-      0.0294f};
+  const float expected_mean_first_call[kInputFirstCallLength] = {
+      0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
+  const float expected_mean_squares_first_call[kInputFirstCallLength] = {
+      0.008f,  0.026f,  0.076f,  0.174f, 0.1764f,
+      0.1718f, 0.1596f, 0.1168f, 0.0294f};
 
-  const float expected_mean_second_call[kInputSecondCallLength] =
-      {0.202f, 0.238f};
-  const float expected_mean_squares_second_call[kInputSecondCallLength] =
-      {0.0438f, 0.0596f};
+  const float expected_mean_second_call[kInputSecondCallLength] = {0.202f,
+                                                                   0.238f};
+  const float expected_mean_squares_second_call[kInputSecondCallLength] = {
+      0.0438f, 0.0596f};
 
-  const float expected_mean_third_call[kInputThirdCallLength] =
-      {0.278f, 0.322f, 0.362f, 0.398f};
-  const float expected_mean_squares_third_call[kInputThirdCallLength] =
-      {0.0812f, 0.1076f, 0.134f, 0.1614f};
+  const float expected_mean_third_call[kInputThirdCallLength] = {
+      0.278f, 0.322f, 0.362f, 0.398f};
+  const float expected_mean_squares_third_call[kInputThirdCallLength] = {
+      0.0812f, 0.1076f, 0.134f, 0.1614f};
 
   CalculateMomentsAndVerify(kInputFirstCall, kInputFirstCallLength,
-      expected_mean_first_call, expected_mean_squares_first_call);
+                            expected_mean_first_call,
+                            expected_mean_squares_first_call);
 
   CalculateMomentsAndVerify(kInputSecondCall, kInputSecondCallLength,
-      expected_mean_second_call, expected_mean_squares_second_call);
+                            expected_mean_second_call,
+                            expected_mean_squares_second_call);
 
   CalculateMomentsAndVerify(kInputThirdCall, kInputThirdCallLength,
-      expected_mean_third_call, expected_mean_squares_third_call);
+                            expected_mean_third_call,
+                            expected_mean_squares_third_call);
 }
 
-TEST_F(MovingMomentsTest,
-       VerifySampleBasedVsBlockBasedCalculation) {
-  const float kInput[] =
-      {0.2f, 0.3f, 0.5f, 0.7f, 0.11f, 0.13f, 0.17f, 0.19f, 0.23f};
+TEST_F(MovingMomentsTest, VerifySampleBasedVsBlockBasedCalculation) {
+  const float kInput[] = {0.2f,  0.3f,  0.5f,  0.7f, 0.11f,
+                          0.13f, 0.17f, 0.19f, 0.23f};
   const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
 
   float output_mean_block_based[kInputLength];
@@ -190,17 +191,16 @@
   float output_mean_sample_based;
   float output_mean_squares_sample_based;
 
-  moving_moments_->CalculateMoments(
-      kInput, kInputLength, output_mean_block_based,
-      output_mean_squares_block_based);
+  moving_moments_->CalculateMoments(kInput, kInputLength,
+                                    output_mean_block_based,
+                                    output_mean_squares_block_based);
   moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
   for (size_t i = 0; i < kInputLength; ++i) {
-    moving_moments_->CalculateMoments(
-        &kInput[i], 1, &output_mean_sample_based,
-        &output_mean_squares_sample_based);
+    moving_moments_->CalculateMoments(&kInput[i], 1, &output_mean_sample_based,
+                                      &output_mean_squares_sample_based);
     EXPECT_FLOAT_EQ(output_mean_block_based[i], output_mean_sample_based);
     EXPECT_FLOAT_EQ(output_mean_squares_block_based[i],
-                     output_mean_squares_sample_based);
+                    output_mean_squares_sample_based);
   }
 }
 
diff --git a/modules/audio_processing/transient/transient_detector.cc b/modules/audio_processing/transient/transient_detector.cc
index 1bb6f9f..c3bf282 100644
--- a/modules/audio_processing/transient/transient_detector.cc
+++ b/modules/audio_processing/transient/transient_detector.cc
@@ -51,8 +51,7 @@
   wpd_tree_.reset(new WPDTree(samples_per_chunk_,
                               kDaubechies8HighPassCoefficients,
                               kDaubechies8LowPassCoefficients,
-                              kDaubechies8CoefficientsLength,
-                              kLevels));
+                              kDaubechies8CoefficientsLength, kLevels));
   for (size_t i = 0; i < kLeaves; ++i) {
     moving_moments_[i].reset(
         new MovingMoments(samples_per_transient / kLeaves));
@@ -86,8 +85,7 @@
   for (size_t i = 0; i < kLeaves; ++i) {
     WPDNode* leaf = wpd_tree_->NodeAt(kLevels, i);
 
-    moving_moments_[i]->CalculateMoments(leaf->data(),
-                                         tree_leaves_data_length_,
+    moving_moments_[i]->CalculateMoments(leaf->data(), tree_leaves_data_length_,
                                          first_moments_.get(),
                                          second_moments_.get());
 
@@ -127,8 +125,9 @@
     const float kVerticalScaling = 0.5f;
     const float kVerticalShift = 1.f;
 
-    result = (cos(result * horizontal_scaling + kHorizontalShift)
-        + kVerticalShift) * kVerticalScaling;
+    result =
+        (cos(result * horizontal_scaling + kHorizontalShift) + kVerticalShift) *
+        kVerticalScaling;
     result *= result;
   }
 
diff --git a/modules/audio_processing/transient/transient_detector_unittest.cc b/modules/audio_processing/transient/transient_detector_unittest.cc
index 8f60954..69a669f 100644
--- a/modules/audio_processing/transient/transient_detector_unittest.cc
+++ b/modules/audio_processing/transient/transient_detector_unittest.cc
@@ -23,8 +23,7 @@
 
 namespace webrtc {
 
-static const int kSampleRatesHz[] = {ts::kSampleRate8kHz,
-                                     ts::kSampleRate16kHz,
+static const int kSampleRatesHz[] = {ts::kSampleRate8kHz, ts::kSampleRate16kHz,
                                      ts::kSampleRate32kHz,
                                      ts::kSampleRate48kHz};
 static const size_t kNumberOfSampleRates =
@@ -57,7 +56,7 @@
 
     bool file_opened = detect_file->is_open();
     ASSERT_TRUE(file_opened) << "File could not be opened.\n"
-          << detect_file_name.str().c_str();
+                             << detect_file_name.str().c_str();
 
     // Prepare audio file.
     std::stringstream audio_file_name;
@@ -80,8 +79,7 @@
 
     size_t frames_read = 0;
 
-    while (ReadInt16FromFileToFloatBuffer(audio_file.get(),
-                                          buffer_length,
+    while (ReadInt16FromFileToFloatBuffer(audio_file.get(), buffer_length,
                                           buffer.get()) == buffer_length) {
       ++frames_read;
 
@@ -92,8 +90,8 @@
           << "Detect test file is malformed.\n";
 
       // Compare results with data from the matlab test file.
-      EXPECT_NEAR(file_value, detector_value, kTolerance) << "Frame: "
-          << frames_read;
+      EXPECT_NEAR(file_value, detector_value, kTolerance)
+          << "Frame: " << frames_read;
     }
 
     detect_file->CloseFile();
diff --git a/modules/audio_processing/transient/transient_suppression_test.cc b/modules/audio_processing/transient/transient_suppression_test.cc
index 8512e01..00e1989 100644
--- a/modules/audio_processing/transient/transient_suppression_test.cc
+++ b/modules/audio_processing/transient/transient_suppression_test.cc
@@ -10,8 +10,8 @@
 
 #include "modules/audio_processing/transient/transient_suppressor.h"
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <memory>
@@ -36,9 +36,7 @@
            10,
            "Time between each chunk of samples in milliseconds.");
 
-DEFINE_int(sample_rate_hz,
-           16000,
-           "Sampling frequency of the signal in Hertz.");
+DEFINE_int(sample_rate_hz, 16000, "Sampling frequency of the signal in Hertz.");
 DEFINE_int(detection_rate_hz,
            0,
            "Sampling frequency of the detection signal in Hertz.");
@@ -79,9 +77,7 @@
     tmpbuf.reset(new int16_t[num_channels * audio_buffer_size]);
     read_ptr = tmpbuf.get();
   }
-  if (fread(read_ptr,
-            sizeof(*read_ptr),
-            num_channels * audio_buffer_size,
+  if (fread(read_ptr, sizeof(*read_ptr), num_channels * audio_buffer_size,
             in_file) != num_channels * audio_buffer_size) {
     return false;
   }
@@ -104,8 +100,8 @@
   }
   if (reference_file) {
     std::unique_ptr<int16_t[]> ibuf(new int16_t[audio_buffer_size]);
-    if (fread(ibuf.get(), sizeof(ibuf[0]), audio_buffer_size, reference_file)
-        != audio_buffer_size)
+    if (fread(ibuf.get(), sizeof(ibuf[0]), audio_buffer_size, reference_file) !=
+        audio_buffer_size)
       return false;
     S16ToFloat(ibuf.get(), audio_buffer_size, reference_buffer);
   }
@@ -163,8 +159,8 @@
   Agc agc;
 
   TransientSuppressor suppressor;
-  suppressor.Initialize(
-      FLAG_sample_rate_hz, detection_rate_hz, FLAG_num_channels);
+  suppressor.Initialize(FLAG_sample_rate_hz, detection_rate_hz,
+                        FLAG_num_channels);
 
   const size_t audio_buffer_size =
       FLAG_chunk_size_ms * FLAG_sample_rate_hz / 1000;
@@ -184,38 +180,27 @@
   if (reference_file)
     reference_buffer.reset(new float[audio_buffer_size]);
 
-  while (ReadBuffers(in_file,
-                     audio_buffer_size,
-                     FLAG_num_channels,
-                     audio_buffer_i.get(),
-                     detection_file,
-                     detection_buffer_size,
-                     detection_buffer.get(),
-                     reference_file,
-                     reference_buffer.get())) {
-    agc.Process(audio_buffer_i.get(),
-                static_cast<int>(audio_buffer_size),
+  while (ReadBuffers(in_file, audio_buffer_size, FLAG_num_channels,
+                     audio_buffer_i.get(), detection_file,
+                     detection_buffer_size, detection_buffer.get(),
+                     reference_file, reference_buffer.get())) {
+    agc.Process(audio_buffer_i.get(), static_cast<int>(audio_buffer_size),
                 FLAG_sample_rate_hz);
 
     for (size_t i = 0; i < FLAG_num_channels * audio_buffer_size; ++i) {
       audio_buffer_f[i] = audio_buffer_i[i];
     }
 
-    ASSERT_EQ(0,
-              suppressor.Suppress(audio_buffer_f.get(),
-                                  audio_buffer_size,
-                                  FLAG_num_channels,
-                                  detection_buffer.get(),
-                                  detection_buffer_size,
-                                  reference_buffer.get(),
-                                  audio_buffer_size,
-                                  agc.voice_probability(),
-                                  true))
+    ASSERT_EQ(0, suppressor.Suppress(audio_buffer_f.get(), audio_buffer_size,
+                                     FLAG_num_channels, detection_buffer.get(),
+                                     detection_buffer_size,
+                                     reference_buffer.get(), audio_buffer_size,
+                                     agc.voice_probability(), true))
         << "The transient suppressor could not suppress the frame";
 
     // Write result to out file.
-    WritePCM(
-        out_file, audio_buffer_size, FLAG_num_channels, audio_buffer_f.get());
+    WritePCM(out_file, audio_buffer_size, FLAG_num_channels,
+             audio_buffer_f.get());
   }
 
   fclose(in_file);
@@ -231,8 +216,8 @@
 }  // namespace webrtc
 
 int main(int argc, char* argv[]) {
-  if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) ||
-      FLAG_help || argc != 1) {
+  if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || FLAG_help ||
+      argc != 1) {
     printf("%s", webrtc::kUsage);
     if (FLAG_help) {
       rtc::FlagList::Print(nullptr, false);
diff --git a/modules/audio_processing/transient/transient_suppressor.cc b/modules/audio_processing/transient/transient_suppressor.cc
index 9bbd7d9..28eb666 100644
--- a/modules/audio_processing/transient/transient_suppressor.cc
+++ b/modules/audio_processing/transient/transient_suppressor.cc
@@ -60,8 +60,7 @@
       use_hard_restoration_(false),
       chunks_since_voice_change_(0),
       seed_(182),
-      using_reference_(false) {
-}
+      using_reference_(false) {}
 
 TransientSuppressor::~TransientSuppressor() {}
 
@@ -110,17 +109,14 @@
   RTC_DCHECK_GE(complex_analysis_length_, kMaxVoiceBin);
   num_channels_ = num_channels;
   in_buffer_.reset(new float[analysis_length_ * num_channels_]);
-  memset(in_buffer_.get(),
-         0,
+  memset(in_buffer_.get(), 0,
          analysis_length_ * num_channels_ * sizeof(in_buffer_[0]));
   detection_length_ = detection_rate_hz * ts::kChunkSizeMs / 1000;
   detection_buffer_.reset(new float[detection_length_]);
-  memset(detection_buffer_.get(),
-         0,
+  memset(detection_buffer_.get(), 0,
          detection_length_ * sizeof(detection_buffer_[0]));
   out_buffer_.reset(new float[analysis_length_ * num_channels_]);
-  memset(out_buffer_.get(),
-         0,
+  memset(out_buffer_.get(), 0,
          analysis_length_ * num_channels_ * sizeof(out_buffer_[0]));
   // ip[0] must be zero to trigger initialization using rdft().
   size_t ip_length = 2 + sqrtf(analysis_length_);
@@ -129,14 +125,12 @@
   wfft_.reset(new float[complex_analysis_length_ - 1]);
   memset(wfft_.get(), 0, (complex_analysis_length_ - 1) * sizeof(wfft_[0]));
   spectral_mean_.reset(new float[complex_analysis_length_ * num_channels_]);
-  memset(spectral_mean_.get(),
-         0,
+  memset(spectral_mean_.get(), 0,
          complex_analysis_length_ * num_channels_ * sizeof(spectral_mean_[0]));
   fft_buffer_.reset(new float[analysis_length_ + 2]);
   memset(fft_buffer_.get(), 0, (analysis_length_ + 2) * sizeof(fft_buffer_[0]));
   magnitudes_.reset(new float[complex_analysis_length_]);
-  memset(magnitudes_.get(),
-         0,
+  memset(magnitudes_.get(), 0,
          complex_analysis_length_ * sizeof(magnitudes_[0]));
   mean_factor_.reset(new float[complex_analysis_length_]);
 
@@ -190,8 +184,8 @@
       detection_data = &in_buffer_[buffer_delay_];
     }
 
-    float detector_result = detector_->Detect(
-        detection_data, detection_length, reference_data, reference_length);
+    float detector_result = detector_->Detect(detection_data, detection_length,
+                                              reference_data, reference_length);
     if (detector_result < 0) {
       return -1;
     }
@@ -247,8 +241,8 @@
   fft_buffer_[1] = 0.f;
 
   for (size_t i = 0; i < complex_analysis_length_; ++i) {
-    magnitudes_[i] = ComplexMagnitude(fft_buffer_[i * 2],
-                                      fft_buffer_[i * 2 + 1]);
+    magnitudes_[i] =
+        ComplexMagnitude(fft_buffer_[i * 2], fft_buffer_[i * 2 + 1]);
   }
   // Restore audio if necessary.
   if (suppression_enabled_) {
@@ -269,11 +263,7 @@
   // Put R[n/2] back in fft_buffer_[1].
   fft_buffer_[1] = fft_buffer_[analysis_length_];
 
-  WebRtc_rdft(analysis_length_,
-              -1,
-              fft_buffer_.get(),
-              ip_.get(),
-              wfft_.get());
+  WebRtc_rdft(analysis_length_, -1, fft_buffer_.get(), ip_.get(), wfft_.get());
   const float fft_scaling = 2.f / analysis_length_;
 
   for (size_t i = 0; i < analysis_length_; ++i) {
@@ -301,8 +291,7 @@
     keypress_counter_ = 0;
   }
 
-  if (detection_enabled_ &&
-      ++chunks_since_keypress_ > kChunksUntilNotTyping) {
+  if (detection_enabled_ && ++chunks_since_keypress_ > kChunksUntilNotTyping) {
     if (suppression_enabled_) {
       RTC_LOG(LS_INFO) << "[ts] Transient suppression is now disabled.";
     }
@@ -337,26 +326,22 @@
 // |detection_enabled_| is updated by UpdateKeypress().
 void TransientSuppressor::UpdateBuffers(float* data) {
   // TODO(aluebs): Change to ring buffer.
-  memmove(in_buffer_.get(),
-          &in_buffer_[data_length_],
+  memmove(in_buffer_.get(), &in_buffer_[data_length_],
           (buffer_delay_ + (num_channels_ - 1) * analysis_length_) *
               sizeof(in_buffer_[0]));
   // Copy new chunk to buffer.
   for (int i = 0; i < num_channels_; ++i) {
     memcpy(&in_buffer_[buffer_delay_ + i * analysis_length_],
-           &data[i * data_length_],
-           data_length_ * sizeof(*data));
+           &data[i * data_length_], data_length_ * sizeof(*data));
   }
   if (detection_enabled_) {
     // Shift previous chunk in out buffer.
-    memmove(out_buffer_.get(),
-            &out_buffer_[data_length_],
+    memmove(out_buffer_.get(), &out_buffer_[data_length_],
             (buffer_delay_ + (num_channels_ - 1) * analysis_length_) *
                 sizeof(out_buffer_[0]));
     // Initialize new chunk in out buffer.
     for (int i = 0; i < num_channels_; ++i) {
-      memset(&out_buffer_[buffer_delay_ + i * analysis_length_],
-             0,
+      memset(&out_buffer_[buffer_delay_ + i * analysis_length_], 0,
              data_length_ * sizeof(out_buffer_[0]));
     }
   }
@@ -375,7 +360,7 @@
     if (magnitudes_[i] > spectral_mean[i] && magnitudes_[i] > 0) {
       // RandU() generates values on [0, int16::max()]
       const float phase = 2 * ts::kPi * WebRtcSpl_RandU(&seed_) /
-          std::numeric_limits<int16_t>::max();
+                          std::numeric_limits<int16_t>::max();
       const float scaled_mean = detector_result * spectral_mean[i];
 
       fft_buffer_[i * 2] = (1 - detector_result) * fft_buffer_[i * 2] +
diff --git a/modules/audio_processing/transient/wpd_node.cc b/modules/audio_processing/transient/wpd_node.cc
index 20d6a90..2e0ee7e 100644
--- a/modules/audio_processing/transient/wpd_node.cc
+++ b/modules/audio_processing/transient/wpd_node.cc
@@ -23,13 +23,12 @@
 WPDNode::WPDNode(size_t length,
                  const float* coefficients,
                  size_t coefficients_length)
-    : // The data buffer has parent data length to be able to contain and filter
-      // it.
+    :  // The data buffer has parent data length to be able to contain and
+       // filter it.
       data_(new float[2 * length + 1]),
       length_(length),
-      filter_(CreateFirFilter(coefficients,
-                              coefficients_length,
-                              2 * length + 1)) {
+      filter_(
+          CreateFirFilter(coefficients, coefficients_length, 2 * length + 1)) {
   RTC_DCHECK_GT(length, 0);
   RTC_DCHECK(coefficients);
   RTC_DCHECK_GT(coefficients_length, 0);
@@ -48,8 +47,8 @@
 
   // Decimate data.
   const bool kOddSequence = true;
-  size_t output_samples = DyadicDecimate(
-      data_.get(), parent_data_length, kOddSequence, data_.get(), length_);
+  size_t output_samples = DyadicDecimate(data_.get(), parent_data_length,
+                                         kOddSequence, data_.get(), length_);
   if (output_samples != length_) {
     return -1;
   }
diff --git a/modules/audio_processing/transient/wpd_node_unittest.cc b/modules/audio_processing/transient/wpd_node_unittest.cc
index 1929361..5f92382 100644
--- a/modules/audio_processing/transient/wpd_node_unittest.cc
+++ b/modules/audio_processing/transient/wpd_node_unittest.cc
@@ -20,18 +20,17 @@
 static const float kTolerance = 0.0001f;
 
 static const size_t kParentDataLength = kDataLength * 2;
-static const float kParentData[kParentDataLength] =
-    {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f};
+static const float kParentData[kParentDataLength] = {1.f, 2.f, 3.f, 4.f, 5.f,
+                                                     6.f, 7.f, 8.f, 9.f, 10.f};
 
 static const float kCoefficients[] = {0.2f, -0.3f, 0.5f, -0.7f, 0.11f};
-static const size_t kCoefficientsLength = sizeof(kCoefficients) /
-                                       sizeof(kCoefficients[0]);
+static const size_t kCoefficientsLength =
+    sizeof(kCoefficients) / sizeof(kCoefficients[0]);
 
 TEST(WPDNodeTest, Accessors) {
   WPDNode node(kDataLength, kCoefficients, kCoefficientsLength);
   EXPECT_EQ(0, node.set_data(kParentData, kDataLength));
-  EXPECT_EQ(0, memcmp(node.data(),
-                      kParentData,
+  EXPECT_EQ(0, memcmp(node.data(), kParentData,
                       kDataLength * sizeof(node.data()[0])));
 }
 
diff --git a/modules/audio_processing/transient/wpd_tree.cc b/modules/audio_processing/transient/wpd_tree.cc
index a01b816..72f4d76 100644
--- a/modules/audio_processing/transient/wpd_tree.cc
+++ b/modules/audio_processing/transient/wpd_tree.cc
@@ -19,8 +19,10 @@
 
 namespace webrtc {
 
-WPDTree::WPDTree(size_t data_length, const float* high_pass_coefficients,
-                 const float* low_pass_coefficients, size_t coefficients_length,
+WPDTree::WPDTree(size_t data_length,
+                 const float* high_pass_coefficients,
+                 const float* low_pass_coefficients,
+                 size_t coefficients_length,
                  int levels)
     : data_length_(data_length),
       levels_(levels),
@@ -98,8 +100,8 @@
       index_left_child = index * 2;
       index_right_child = index_left_child + 1;
 
-      update_result = nodes_[index_left_child]->Update(
-          nodes_[index]->data(), nodes_[index]->length());
+      update_result = nodes_[index_left_child]->Update(nodes_[index]->data(),
+                                                       nodes_[index]->length());
       if (update_result != 0) {
         return -1;
       }
diff --git a/modules/audio_processing/transient/wpd_tree.h b/modules/audio_processing/transient/wpd_tree.h
index 53fc06b..707a89d 100644
--- a/modules/audio_processing/transient/wpd_tree.h
+++ b/modules/audio_processing/transient/wpd_tree.h
@@ -47,9 +47,7 @@
   ~WPDTree();
 
   // Returns the number of nodes at any given level.
-  static int NumberOfNodesAtLevel(int level) {
-    return 1 << level;
-  }
+  static int NumberOfNodesAtLevel(int level) { return 1 << level; }
 
   // Returns a pointer to the node at the given level and index(of that level).
   // Level goes from 0 to levels().
diff --git a/modules/audio_processing/transient/wpd_tree_unittest.cc b/modules/audio_processing/transient/wpd_tree_unittest.cc
index 02c7f51..88f0739 100644
--- a/modules/audio_processing/transient/wpd_tree_unittest.cc
+++ b/modules/audio_processing/transient/wpd_tree_unittest.cc
@@ -30,13 +30,10 @@
   float test_buffer[kTestBufferSize];
   memset(test_buffer, 0.f, kTestBufferSize * sizeof(*test_buffer));
   float test_coefficients[] = {1.f, 2.f, 3.f, 4.f, 5.f};
-  const size_t kTestCoefficientsLength = sizeof(test_coefficients) /
-      sizeof(test_coefficients[0]);
-  WPDTree tree(kTestBufferSize,
-               test_coefficients,
-               test_coefficients,
-               kTestCoefficientsLength,
-               kLevels);
+  const size_t kTestCoefficientsLength =
+      sizeof(test_coefficients) / sizeof(test_coefficients[0]);
+  WPDTree tree(kTestBufferSize, test_coefficients, test_coefficients,
+               kTestCoefficientsLength, kLevels);
   ASSERT_EQ(kExpectedNumberOfNodes, tree.num_nodes());
   // Checks for NodeAt(level, index).
   int nodes_at_level = 0;
@@ -79,10 +76,8 @@
   const int kLeaves = 1 << kLevels;
   const size_t kLeavesSamples = kTestBufferSize >> kLevels;
   // Create tree with Discrete Meyer Wavelet Coefficients.
-  WPDTree tree(kTestBufferSize,
-               kDaubechies8HighPassCoefficients,
-               kDaubechies8LowPassCoefficients,
-               kDaubechies8CoefficientsLength,
+  WPDTree tree(kTestBufferSize, kDaubechies8HighPassCoefficients,
+               kDaubechies8LowPassCoefficients, kDaubechies8CoefficientsLength,
                kLevels);
   // Allocate and open all matlab and out files.
   std::unique_ptr<FileWrapper> matlab_files_data[kLeaves];
@@ -134,9 +129,8 @@
   size_t frames_read = 0;
 
   // Read first buffer from the PCM test file.
-  size_t file_samples_read = ReadInt16FromFileToFloatBuffer(test_file.get(),
-                                                            kTestBufferSize,
-                                                            test_buffer);
+  size_t file_samples_read = ReadInt16FromFileToFloatBuffer(
+      test_file.get(), kTestBufferSize, test_buffer);
   while (file_samples_read > 0 && frames_read < kMaxFramesToTest) {
     ++frames_read;
 
@@ -152,10 +146,8 @@
     // Compare results with data from the matlab test files.
     for (int i = 0; i < kLeaves; ++i) {
       // Compare data values
-      size_t matlab_samples_read =
-          ReadDoubleBufferFromFile(matlab_files_data[i].get(),
-                                   kLeavesSamples,
-                                   matlab_buffer);
+      size_t matlab_samples_read = ReadDoubleBufferFromFile(
+          matlab_files_data[i].get(), kLeavesSamples, matlab_buffer);
 
       ASSERT_EQ(kLeavesSamples, matlab_samples_read)
           << "Matlab test files are malformed.\n"
@@ -170,15 +162,13 @@
       }
 
       // Write results to out files.
-      WriteFloatBufferToFile(out_files_data[i].get(),
-                             kLeavesSamples,
+      WriteFloatBufferToFile(out_files_data[i].get(), kLeavesSamples,
                              node_data);
     }
 
     // Read next buffer from the PCM test file.
-    file_samples_read = ReadInt16FromFileToFloatBuffer(test_file.get(),
-                                                       kTestBufferSize,
-                                                       test_buffer);
+    file_samples_read = ReadInt16FromFileToFloatBuffer(
+        test_file.get(), kTestBufferSize, test_buffer);
   }
 
   // Close all matlab and out files.
diff --git a/modules/audio_processing/typing_detection.cc b/modules/audio_processing/typing_detection.cc
index 6e18124..e725b26 100644
--- a/modules/audio_processing/typing_detection.cc
+++ b/modules/audio_processing/typing_detection.cc
@@ -24,8 +24,7 @@
       reporting_threshold_(300),
       penalty_decay_(1),
       type_event_delay_(2),
-      report_detection_update_period_(1) {
-}
+      report_detection_update_period_(1) {}
 
 TypingDetection::~TypingDetection() {}
 
@@ -41,8 +40,7 @@
   else
     ++time_since_last_typing_;
 
-  if (time_since_last_typing_ < type_event_delay_ &&
-      vad_activity &&
+  if (time_since_last_typing_ < type_event_delay_ && vad_activity &&
       time_active_ < time_window_) {
     penalty_counter_ += cost_per_typing_;
     if (penalty_counter_ > reporting_threshold_)
@@ -73,15 +71,20 @@
                                     int penalty_decay,
                                     int type_event_delay,
                                     int report_detection_update_period) {
-  if (time_window) time_window_ = time_window;
+  if (time_window)
+    time_window_ = time_window;
 
-  if (cost_per_typing) cost_per_typing_ = cost_per_typing;
+  if (cost_per_typing)
+    cost_per_typing_ = cost_per_typing;
 
-  if (reporting_threshold) reporting_threshold_ = reporting_threshold;
+  if (reporting_threshold)
+    reporting_threshold_ = reporting_threshold;
 
-  if (penalty_decay) penalty_decay_ = penalty_decay;
+  if (penalty_decay)
+    penalty_decay_ = penalty_decay;
 
-  if (type_event_delay) type_event_delay_ = type_event_delay;
+  if (type_event_delay)
+    type_event_delay_ = type_event_delay;
 
   if (report_detection_update_period)
     report_detection_update_period_ = report_detection_update_period;
diff --git a/modules/audio_processing/utility/BUILD.gn b/modules/audio_processing/utility/BUILD.gn
new file mode 100644
index 0000000..cd23d01
--- /dev/null
+++ b/modules/audio_processing/utility/BUILD.gn
@@ -0,0 +1,118 @@
+# Copyright (c) 2014 The WebRTC 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.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("block_mean_calculator") {
+  sources = [
+    "block_mean_calculator.cc",
+    "block_mean_calculator.h",
+  ]
+  deps = [
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+  ]
+}
+
+rtc_source_set("legacy_delay_estimator") {
+  sources = [
+    "delay_estimator.cc",
+    "delay_estimator.h",
+    "delay_estimator_internal.h",
+    "delay_estimator_wrapper.cc",
+    "delay_estimator_wrapper.h",
+  ]
+  deps = [
+    "../../..:typedefs",
+    "../../../rtc_base:checks",
+  ]
+}
+
+rtc_source_set("ooura_fft") {
+  sources = [
+    "ooura_fft.cc",
+    "ooura_fft.h",
+    "ooura_fft_tables_common.h",
+  ]
+  deps = [
+    "../../..:typedefs",
+    "../../../system_wrappers:cpu_features_api",
+  ]
+  cflags = []
+
+  if (current_cpu == "x86" || current_cpu == "x64") {
+    sources += [
+      "ooura_fft_sse2.cc",
+      "ooura_fft_tables_neon_sse2.h",
+    ]
+    if (is_posix || is_fuchsia) {
+      cflags += [ "-msse2" ]
+    }
+  }
+
+  if (rtc_build_with_neon) {
+    sources += [
+      "ooura_fft_neon.cc",
+      "ooura_fft_tables_neon_sse2.h",
+    ]
+
+    deps += [ "../../../common_audio" ]
+
+    if (current_cpu != "arm64") {
+      # Enable compilation for the NEON instruction set. This is needed
+      # since //build/config/arm.gni only enables NEON for iOS, not Android.
+      # This provides the same functionality as webrtc/build/arm_neon.gypi.
+      suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+      cflags += [ "-mfpu=neon" ]
+    }
+
+    # Disable LTO on NEON targets due to compiler bug.
+    # TODO(fdegans): Enable this. See crbug.com/408997.
+    if (rtc_use_lto) {
+      cflags -= [
+        "-flto",
+        "-ffat-lto-objects",
+      ]
+    }
+  }
+
+  if (current_cpu == "mipsel" && mips_float_abi == "hard") {
+    sources += [ "ooura_fft_mips.cc" ]
+  }
+}
+
+if (rtc_include_tests) {
+  rtc_source_set("block_mean_calculator_unittest") {
+    testonly = true
+
+    sources = [
+      "block_mean_calculator_unittest.cc",
+    ]
+    deps = [
+      ":block_mean_calculator",
+      "../../../rtc_base:rtc_base_approved",
+      "../../../test:test_support",
+      "//testing/gtest",
+    ]
+  }
+
+  rtc_source_set("legacy_delay_estimator_unittest") {
+    testonly = true
+
+    sources = [
+      "delay_estimator_unittest.cc",
+    ]
+    deps = [
+      ":legacy_delay_estimator",
+      "../../..:typedefs",
+      "../../../rtc_base:rtc_base_approved",
+      "../../../test:test_support",
+      "//testing/gtest",
+    ]
+  }
+}
diff --git a/modules/audio_processing/utility/block_mean_calculator.cc b/modules/audio_processing/utility/block_mean_calculator.cc
index 3d76692..82c1c0f 100644
--- a/modules/audio_processing/utility/block_mean_calculator.cc
+++ b/modules/audio_processing/utility/block_mean_calculator.cc
@@ -15,10 +15,7 @@
 namespace webrtc {
 
 BlockMeanCalculator::BlockMeanCalculator(size_t block_length)
-    : block_length_(block_length),
-      count_(0),
-      sum_(0.0),
-      mean_(0.0) {
+    : block_length_(block_length), count_(0), sum_(0.0), mean_(0.0) {
   RTC_DCHECK(block_length_ != 0);
 }
 
diff --git a/modules/audio_processing/utility/delay_estimator.cc b/modules/audio_processing/utility/delay_estimator.cc
index 871b541..a15b914 100644
--- a/modules/audio_processing/utility/delay_estimator.cc
+++ b/modules/audio_processing/utility/delay_estimator.cc
@@ -21,9 +21,9 @@
 static const int kShiftsAtZero = 13;  // Right shifts at zero binary spectrum.
 static const int kShiftsLinearSlope = 3;
 
-static const int32_t kProbabilityOffset = 1024;  // 2 in Q9.
+static const int32_t kProbabilityOffset = 1024;      // 2 in Q9.
 static const int32_t kProbabilityLowerLimit = 8704;  // 17 in Q9.
-static const int32_t kProbabilityMinSpread = 2816;  // 5.5 in Q9.
+static const int32_t kProbabilityMinSpread = 2816;   // 5.5 in Q9.
 
 // Robust validation settings
 static const float kHistogramMax = 3000.f;
@@ -39,13 +39,13 @@
 
 // Counts and returns number of bits of a 32-bit word.
 static int BitCount(uint32_t u32) {
-  uint32_t tmp = u32 - ((u32 >> 1) & 033333333333) -
-      ((u32 >> 2) & 011111111111);
+  uint32_t tmp =
+      u32 - ((u32 >> 1) & 033333333333) - ((u32 >> 2) & 011111111111);
   tmp = ((tmp + (tmp >> 3)) & 030707070707);
   tmp = (tmp + (tmp >> 6));
   tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077;
 
-  return ((int) tmp);
+  return ((int)tmp);
 }
 
 // Compares the |binary_vector| with all rows of the |binary_matrix| and counts
@@ -69,7 +69,7 @@
 
   // Compare |binary_vector| with all rows of the |binary_matrix|
   for (; n < matrix_size; n++) {
-    bit_counts[n] = (int32_t) BitCount(binary_vector ^ binary_matrix[n]);
+    bit_counts[n] = (int32_t)BitCount(binary_vector ^ binary_matrix[n]);
   }
 }
 
@@ -96,8 +96,9 @@
                                              int32_t valley_level_q14) {
   const float valley_depth = valley_depth_q14 * kQ14Scaling;
   float decrease_in_last_set = valley_depth;
-  const int max_hits_for_slow_change = (candidate_delay < self->last_delay) ?
-      kMaxHitsWhenPossiblyNonCausal : kMaxHitsWhenPossiblyCausal;
+  const int max_hits_for_slow_change = (candidate_delay < self->last_delay)
+                                           ? kMaxHitsWhenPossiblyNonCausal
+                                           : kMaxHitsWhenPossiblyCausal;
   int i = 0;
 
   RTC_DCHECK_EQ(self->history_size, self->farend->history_size);
@@ -127,18 +128,20 @@
   //    |candidate_delay| is a "potential" candidate and we start decreasing
   //    these histogram bins more rapidly with |valley_depth|.
   if (self->candidate_hits < max_hits_for_slow_change) {
-    decrease_in_last_set = (self->mean_bit_counts[self->compare_delay] -
-        valley_level_q14) * kQ14Scaling;
+    decrease_in_last_set =
+        (self->mean_bit_counts[self->compare_delay] - valley_level_q14) *
+        kQ14Scaling;
   }
   // 4. All other bins are decreased with |valley_depth|.
   // TODO(bjornv): Investigate how to make this loop more efficient.  Split up
   // the loop?  Remove parts that doesn't add too much.
   for (i = 0; i < self->history_size; ++i) {
     int is_in_last_set = (i >= self->last_delay - 2) &&
-        (i <= self->last_delay + 1) && (i != candidate_delay);
-    int is_in_candidate_set = (i >= candidate_delay - 2) &&
-        (i <= candidate_delay + 1);
-    self->histogram[i] -= decrease_in_last_set * is_in_last_set +
+                         (i <= self->last_delay + 1) && (i != candidate_delay);
+    int is_in_candidate_set =
+        (i >= candidate_delay - 2) && (i <= candidate_delay + 1);
+    self->histogram[i] -=
+        decrease_in_last_set * is_in_last_set +
         valley_depth * (!is_in_last_set && !is_in_candidate_set);
     // 5. No histogram bin can go below 0.
     if (self->histogram[i] < 0) {
@@ -196,16 +199,18 @@
   // into tables?
   if (delay_difference > self->allowed_offset) {
     fraction = 1.f - kFractionSlope * (delay_difference - self->allowed_offset);
-    fraction = (fraction > kMinFractionWhenPossiblyCausal ? fraction :
-        kMinFractionWhenPossiblyCausal);
+    fraction = (fraction > kMinFractionWhenPossiblyCausal
+                    ? fraction
+                    : kMinFractionWhenPossiblyCausal);
   } else if (delay_difference < 0) {
-    fraction = kMinFractionWhenPossiblyNonCausal -
-        kFractionSlope * delay_difference;
+    fraction =
+        kMinFractionWhenPossiblyNonCausal - kFractionSlope * delay_difference;
     fraction = (fraction > 1.f ? 1.f : fraction);
   }
   histogram_threshold *= fraction;
-  histogram_threshold = (histogram_threshold > kMinHistogramThreshold ?
-      histogram_threshold : kMinHistogramThreshold);
+  histogram_threshold =
+      (histogram_threshold > kMinHistogramThreshold ? histogram_threshold
+                                                    : kMinHistogramThreshold);
 
   is_histogram_valid =
       (self->histogram[candidate_delay] >= histogram_threshold) &&
@@ -243,8 +248,8 @@
   //   i) Before we actually have a valid estimate (|last_delay| == -2), we say
   //      a candidate is valid if either algorithm states so
   //      (|is_instantaneous_valid| OR |is_histogram_valid|).
-  is_robust = (self->last_delay < 0) &&
-      (is_instantaneous_valid || is_histogram_valid);
+  is_robust =
+      (self->last_delay < 0) && (is_instantaneous_valid || is_histogram_valid);
   //  ii) Otherwise, we need both algorithms to be certain
   //      (|is_instantaneous_valid| AND |is_histogram_valid|)
   is_robust |= is_instantaneous_valid && is_histogram_valid;
@@ -252,13 +257,12 @@
   //      the instantaneous one if |is_histogram_valid| = 1 and the histogram
   //      is significantly strong.
   is_robust |= is_histogram_valid &&
-      (self->histogram[candidate_delay] > self->last_delay_histogram);
+               (self->histogram[candidate_delay] > self->last_delay_histogram);
 
   return is_robust;
 }
 
 void WebRtc_FreeBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) {
-
   if (self == NULL) {
     return;
   }
@@ -302,20 +306,17 @@
   self->binary_far_history = static_cast<uint32_t*>(
       realloc(self->binary_far_history,
               history_size * sizeof(*self->binary_far_history)));
-  self->far_bit_counts = static_cast<int*>(
-      realloc(self->far_bit_counts,
-              history_size * sizeof(*self->far_bit_counts)));
+  self->far_bit_counts = static_cast<int*>(realloc(
+      self->far_bit_counts, history_size * sizeof(*self->far_bit_counts)));
   if ((self->binary_far_history == NULL) || (self->far_bit_counts == NULL)) {
     history_size = 0;
   }
   // Fill with zeros if we have expanded the buffers.
   if (history_size > self->history_size) {
     int size_diff = history_size - self->history_size;
-    memset(&self->binary_far_history[self->history_size],
-           0,
+    memset(&self->binary_far_history[self->history_size], 0,
            sizeof(*self->binary_far_history) * size_diff);
-    memset(&self->far_bit_counts[self->history_size],
-           0,
+    memset(&self->far_bit_counts[self->history_size], 0,
            sizeof(*self->far_bit_counts) * size_diff);
   }
   self->history_size = history_size;
@@ -330,7 +331,8 @@
 }
 
 void WebRtc_SoftResetBinaryDelayEstimatorFarend(
-    BinaryDelayEstimatorFarend* self, int delay_shift) {
+    BinaryDelayEstimatorFarend* self,
+    int delay_shift) {
   int abs_shift = abs(delay_shift);
   int shift_size = 0;
   int dest_index = 0;
@@ -355,8 +357,7 @@
           sizeof(*self->binary_far_history) * shift_size);
   memset(&self->binary_far_history[padding_index], 0,
          sizeof(*self->binary_far_history) * abs_shift);
-  memmove(&self->far_bit_counts[dest_index],
-          &self->far_bit_counts[src_index],
+  memmove(&self->far_bit_counts[dest_index], &self->far_bit_counts[src_index],
           sizeof(*self->far_bit_counts) * shift_size);
   memset(&self->far_bit_counts[padding_index], 0,
          sizeof(*self->far_bit_counts) * abs_shift);
@@ -378,7 +379,6 @@
 }
 
 void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self) {
-
   if (self == NULL) {
     return;
   }
@@ -403,7 +403,8 @@
 }
 
 BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
-    BinaryDelayEstimatorFarend* farend, int max_lookahead) {
+    BinaryDelayEstimatorFarend* farend,
+    int max_lookahead) {
   BinaryDelayEstimator* self = NULL;
 
   if ((farend != NULL) && (max_lookahead >= 0)) {
@@ -457,22 +458,18 @@
   self->histogram = static_cast<float*>(
       realloc(self->histogram, (history_size + 1) * sizeof(*self->histogram)));
 
-  if ((self->mean_bit_counts == NULL) ||
-      (self->bit_counts == NULL) ||
+  if ((self->mean_bit_counts == NULL) || (self->bit_counts == NULL) ||
       (self->histogram == NULL)) {
     history_size = 0;
   }
   // Fill with zeros if we have expanded the buffers.
   if (history_size > self->history_size) {
     int size_diff = history_size - self->history_size;
-    memset(&self->mean_bit_counts[self->history_size],
-           0,
+    memset(&self->mean_bit_counts[self->history_size], 0,
            sizeof(*self->mean_bit_counts) * size_diff);
-    memset(&self->bit_counts[self->history_size],
-           0,
+    memset(&self->bit_counts[self->history_size], 0,
            sizeof(*self->bit_counts) * size_diff);
-    memset(&self->histogram[self->history_size],
-           0,
+    memset(&self->histogram[self->history_size], 0,
            sizeof(*self->histogram) * size_diff);
   }
   self->history_size = history_size;
@@ -485,15 +482,14 @@
   RTC_DCHECK(self);
 
   memset(self->bit_counts, 0, sizeof(int32_t) * self->history_size);
-  memset(self->binary_near_history,
-         0,
+  memset(self->binary_near_history, 0,
          sizeof(uint32_t) * self->near_history_size);
   for (i = 0; i <= self->history_size; ++i) {
     self->mean_bit_counts[i] = (20 << 9);  // 20 in Q9.
     self->histogram[i] = 0.f;
   }
-  self->minimum_probability = kMaxBitCountsQ9;  // 32 in Q9.
-  self->last_delay_probability = (int) kMaxBitCountsQ9;  // 32 in Q9.
+  self->minimum_probability = kMaxBitCountsQ9;          // 32 in Q9.
+  self->last_delay_probability = (int)kMaxBitCountsQ9;  // 32 in Q9.
 
   // Default return value if we're unable to estimate. -1 is used for errors.
   self->last_delay = -2;
@@ -617,8 +613,8 @@
   //     and deeper than the best estimate so far
   //      (|value_best_candidate| < |last_delay_probability|)
   valid_candidate = ((valley_depth > kProbabilityOffset) &&
-      ((value_best_candidate < self->minimum_probability) ||
-          (value_best_candidate < self->last_delay_probability)));
+                     ((value_best_candidate < self->minimum_probability) ||
+                      (value_best_candidate < self->last_delay_probability)));
 
   // Check for nonstationary farend signal.
   const bool non_stationary_farend =
@@ -637,7 +633,6 @@
     int is_histogram_valid = HistogramBasedValidation(self, candidate_delay);
     valid_candidate = RobustValidation(self, candidate_delay, valid_candidate,
                                        is_histogram_valid);
-
   }
 
   // Only update the delay estimate when the farend is nonstationary and when
@@ -645,8 +640,9 @@
   if (non_stationary_farend && valid_candidate) {
     if (candidate_delay != self->last_delay) {
       self->last_delay_histogram =
-          (self->histogram[candidate_delay] > kLastHistogramMax ?
-              kLastHistogramMax : self->histogram[candidate_delay]);
+          (self->histogram[candidate_delay] > kLastHistogramMax
+               ? kLastHistogramMax
+               : self->histogram[candidate_delay]);
       // Adjust the histogram if we made a change to |last_delay|, though it was
       // not the most likely one according to the histogram.
       if (self->histogram[candidate_delay] <
@@ -679,8 +675,8 @@
   } else {
     // Note that |last_delay_probability| states how deep the minimum of the
     // cost function is, so it is rather an error probability.
-    quality = (float) (kMaxBitCountsQ9 - self->last_delay_probability) /
-        kMaxBitCountsQ9;
+    quality = (float)(kMaxBitCountsQ9 - self->last_delay_probability) /
+              kMaxBitCountsQ9;
     if (quality < 0) {
       quality = 0;
     }
diff --git a/modules/audio_processing/utility/delay_estimator.h b/modules/audio_processing/utility/delay_estimator.h
index cce6113..11483ec 100644
--- a/modules/audio_processing/utility/delay_estimator.h
+++ b/modules/audio_processing/utility/delay_estimator.h
@@ -117,7 +117,8 @@
 //    - delay_shift   : The amount of blocks to shift history buffers.
 //
 void WebRtc_SoftResetBinaryDelayEstimatorFarend(
-    BinaryDelayEstimatorFarend* self, int delay_shift);
+    BinaryDelayEstimatorFarend* self,
+    int delay_shift);
 
 // Adds the binary far-end spectrum to the internal far-end history buffer. This
 // spectrum is used as reference when calculating the delay using
@@ -153,7 +154,8 @@
 // See WebRtc_CreateDelayEstimator(..) in delay_estimator_wrapper.c for detailed
 // description.
 BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
-    BinaryDelayEstimatorFarend* farend, int max_lookahead);
+    BinaryDelayEstimatorFarend* farend,
+    int max_lookahead);
 
 // Re-allocates |history_size| dependent buffers. The far-end buffers will be
 // updated at the same time if needed.
diff --git a/modules/audio_processing/utility/delay_estimator_unittest.cc b/modules/audio_processing/utility/delay_estimator_unittest.cc
index 36700e5..8d65cb9 100644
--- a/modules/audio_processing/utility/delay_estimator_unittest.cc
+++ b/modules/audio_processing/utility/delay_estimator_unittest.cc
@@ -27,23 +27,27 @@
 const int kDifferentHistorySize = 3;
 const int kDifferentLookahead = 1;
 
-const int kEnable[] = { 0, 1 };
+const int kEnable[] = {0, 1};
 const size_t kSizeEnable = sizeof(kEnable) / sizeof(*kEnable);
 
 class DelayEstimatorTest : public ::testing::Test {
  protected:
   DelayEstimatorTest();
-  virtual void SetUp();
-  virtual void TearDown();
+  void SetUp() override;
+  void TearDown() override;
 
   void Init();
   void InitBinary();
   void VerifyDelay(BinaryDelayEstimator* binary_handle, int offset, int delay);
   void RunBinarySpectra(BinaryDelayEstimator* binary1,
                         BinaryDelayEstimator* binary2,
-                        int near_offset, int lookahead_offset, int far_offset);
-  void RunBinarySpectraTest(int near_offset, int lookahead_offset,
-                            int ref_robust_validation, int robust_validation);
+                        int near_offset,
+                        int lookahead_offset,
+                        int far_offset);
+  void RunBinarySpectraTest(int near_offset,
+                            int lookahead_offset,
+                            int ref_robust_validation,
+                            int robust_validation);
 
   void* handle_;
   DelayEstimator* self_;
@@ -83,8 +87,8 @@
 }
 
 void DelayEstimatorTest::SetUp() {
-  farend_handle_ = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize,
-                                                     kHistorySize);
+  farend_handle_ =
+      WebRtc_CreateDelayEstimatorFarend(kSpectrumSize, kHistorySize);
   ASSERT_TRUE(farend_handle_ != NULL);
   farend_self_ = reinterpret_cast<DelayEstimatorFarend*>(farend_handle_);
   handle_ = WebRtc_CreateDelayEstimator(farend_handle_, kLookahead);
@@ -131,7 +135,8 @@
 }
 
 void DelayEstimatorTest::VerifyDelay(BinaryDelayEstimator* binary_handle,
-                                     int offset, int delay) {
+                                     int offset,
+                                     int delay) {
   // Verify that we WebRtc_binary_last_delay() returns correct delay.
   EXPECT_EQ(delay, WebRtc_binary_last_delay(binary_handle));
 
@@ -147,8 +152,8 @@
                                           int near_offset,
                                           int lookahead_offset,
                                           int far_offset) {
-  int different_validations = binary1->robust_validation_enabled ^
-      binary2->robust_validation_enabled;
+  int different_validations =
+      binary1->robust_validation_enabled ^ binary2->robust_validation_enabled;
   WebRtc_InitBinaryDelayEstimatorFarend(binary_farend_);
   WebRtc_InitBinaryDelayEstimator(binary1);
   WebRtc_InitBinaryDelayEstimator(binary2);
@@ -160,9 +165,8 @@
     WebRtc_AddBinaryFarSpectrum(binary_farend_,
                                 binary_spectrum_[i + far_offset]);
     int delay_1 = WebRtc_ProcessBinarySpectrum(binary1, binary_spectrum_[i]);
-    int delay_2 =
-        WebRtc_ProcessBinarySpectrum(binary2,
-                                     binary_spectrum_[i - near_offset]);
+    int delay_2 = WebRtc_ProcessBinarySpectrum(
+        binary2, binary_spectrum_[i - near_offset]);
 
     VerifyDelay(binary1, far_offset + kLookahead, delay_1);
     VerifyDelay(binary2,
@@ -177,7 +181,7 @@
     // all the time, unless one of them has robust validation turned on.  In
     // that case the robust validation leaves the initial state faster.
     if ((near_offset == 0) && (lookahead_offset == 0)) {
-      if  (!different_validations) {
+      if (!different_validations) {
         EXPECT_EQ(delay_1, delay_2);
       } else {
         if (binary1->robust_validation_enabled) {
@@ -199,9 +203,8 @@
                                               int lookahead_offset,
                                               int ref_robust_validation,
                                               int robust_validation) {
-  BinaryDelayEstimator* binary2 =
-      WebRtc_CreateBinaryDelayEstimator(binary_farend_,
-                                        kLookahead + lookahead_offset);
+  BinaryDelayEstimator* binary2 = WebRtc_CreateBinaryDelayEstimator(
+      binary_farend_, kLookahead + lookahead_offset);
   // Verify the delay for both causal and non-causal systems. For causal systems
   // the delay is equivalent with a positive |offset| of the far-end sequence.
   // For non-causal systems the delay is equivalent with a negative |offset| of
@@ -209,8 +212,7 @@
   binary_->robust_validation_enabled = ref_robust_validation;
   binary2->robust_validation_enabled = robust_validation;
   for (int offset = -kLookahead;
-      offset < kMaxDelay - lookahead_offset - near_offset;
-      offset++) {
+       offset < kMaxDelay - lookahead_offset - near_offset; offset++) {
     RunBinarySpectra(binary_, binary2, near_offset, lookahead_offset, offset);
   }
   WebRtc_FreeBinaryDelayEstimator(binary2);
@@ -248,8 +250,8 @@
   // 3) Incorrect spectrum size.
   EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(NULL, far_f_, spectrum_size_));
   // Use |farend_handle_| which is properly created at SetUp().
-  EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(farend_handle_, NULL,
-                                           spectrum_size_));
+  EXPECT_EQ(-1,
+            WebRtc_AddFarSpectrumFloat(farend_handle_, NULL, spectrum_size_));
   EXPECT_EQ(-1, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
                                            spectrum_size_ + 1));
 
@@ -259,8 +261,8 @@
   // 3) Incorrect spectrum size.
   // 4) Too high precision in far-end spectrum (Q-domain > 15).
   EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(NULL, far_u16_, spectrum_size_, 0));
-  EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, NULL, spectrum_size_,
-                                         0));
+  EXPECT_EQ(-1,
+            WebRtc_AddFarSpectrumFix(farend_handle_, NULL, spectrum_size_, 0));
   EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
                                          spectrum_size_ + 1, 0));
   EXPECT_EQ(-1, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
@@ -313,16 +315,15 @@
   // 3) Incorrect spectrum size.
   // 4) Non matching history sizes if multiple delay estimators using the same
   //    far-end reference.
-  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(NULL, near_f_,
-                                                  spectrum_size_));
+  EXPECT_EQ(-1,
+            WebRtc_DelayEstimatorProcessFloat(NULL, near_f_, spectrum_size_));
   // Use |handle_| which is properly created at SetUp().
-  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, NULL,
-                                                  spectrum_size_));
+  EXPECT_EQ(-1,
+            WebRtc_DelayEstimatorProcessFloat(handle_, NULL, spectrum_size_));
   EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
                                                   spectrum_size_ + 1));
   // |tmp_handle| is already in a non-matching state.
-  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(tmp_handle,
-                                                  near_f_,
+  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFloat(tmp_handle, near_f_,
                                                   spectrum_size_));
 
   // WebRtc_DelayEstimatorProcessFix() should return -1 if we have:
@@ -332,19 +333,17 @@
   // 4) Too high precision in near-end spectrum (Q-domain > 15).
   // 5) Non matching history sizes if multiple delay estimators using the same
   //    far-end reference.
-  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(NULL, near_u16_, spectrum_size_,
-                                                0));
-  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, NULL, spectrum_size_,
-                                                0));
+  EXPECT_EQ(
+      -1, WebRtc_DelayEstimatorProcessFix(NULL, near_u16_, spectrum_size_, 0));
+  EXPECT_EQ(-1,
+            WebRtc_DelayEstimatorProcessFix(handle_, NULL, spectrum_size_, 0));
   EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
                                                 spectrum_size_ + 1, 0));
   EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
                                                 spectrum_size_, 16));
   // |tmp_handle| is already in a non-matching state.
-  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(tmp_handle,
-                                                near_u16_,
-                                                spectrum_size_,
-                                                0));
+  EXPECT_EQ(-1, WebRtc_DelayEstimatorProcessFix(tmp_handle, near_u16_,
+                                                spectrum_size_, 0));
   WebRtc_FreeDelayEstimator(tmp_handle);
 
   // WebRtc_last_delay() should return -1 if we have a NULL pointer as |handle|.
@@ -382,8 +381,8 @@
   // In this test we verify that the mean spectra are initialized after first
   // time we call WebRtc_AddFarSpectrum() and Process() respectively. The test
   // also verifies the state is not left for zero spectra.
-  const float kZerosFloat[kSpectrumSize] = { 0.0 };
-  const uint16_t kZerosU16[kSpectrumSize] = { 0 };
+  const float kZerosFloat[kSpectrumSize] = {0.0};
+  const uint16_t kZerosU16[kSpectrumSize] = {0};
 
   // For floating point operations, process one frame and verify initialization
   // flag.
@@ -391,14 +390,14 @@
   EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, kZerosFloat,
                                           spectrum_size_));
   EXPECT_EQ(0, farend_self_->far_spectrum_initialized);
-  EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
-                                           spectrum_size_));
+  EXPECT_EQ(0,
+            WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_, spectrum_size_));
   EXPECT_EQ(1, farend_self_->far_spectrum_initialized);
   EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFloat(handle_, kZerosFloat,
                                                   spectrum_size_));
   EXPECT_EQ(0, self_->near_spectrum_initialized);
-  EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
-                                                  spectrum_size_));
+  EXPECT_EQ(
+      -2, WebRtc_DelayEstimatorProcessFloat(handle_, near_f_, spectrum_size_));
   EXPECT_EQ(1, self_->near_spectrum_initialized);
 
   // For fixed point operations, process one frame and verify initialization
@@ -407,8 +406,8 @@
   EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, kZerosU16,
                                         spectrum_size_, 0));
   EXPECT_EQ(0, farend_self_->far_spectrum_initialized);
-  EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
-                                         spectrum_size_, 0));
+  EXPECT_EQ(
+      0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_, spectrum_size_, 0));
   EXPECT_EQ(1, farend_self_->far_spectrum_initialized);
   EXPECT_EQ(-2, WebRtc_DelayEstimatorProcessFix(handle_, kZerosU16,
                                                 spectrum_size_, 0));
@@ -429,10 +428,10 @@
   // Floating point operations.
   Init();
   for (int i = 0; i < 200; i++) {
-    EXPECT_EQ(0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_,
-                                            spectrum_size_));
-    last_delay = WebRtc_DelayEstimatorProcessFloat(handle_, near_f_,
-                                                   spectrum_size_);
+    EXPECT_EQ(
+        0, WebRtc_AddFarSpectrumFloat(farend_handle_, far_f_, spectrum_size_));
+    last_delay =
+        WebRtc_DelayEstimatorProcessFloat(handle_, near_f_, spectrum_size_);
     if (last_delay != -2) {
       EXPECT_EQ(last_delay, WebRtc_last_delay(handle_));
       if (!WebRtc_is_robust_validation_enabled(handle_)) {
@@ -451,8 +450,8 @@
   for (int i = 0; i < 200; i++) {
     EXPECT_EQ(0, WebRtc_AddFarSpectrumFix(farend_handle_, far_u16_,
                                           spectrum_size_, 0));
-    last_delay = WebRtc_DelayEstimatorProcessFix(handle_, near_u16_,
-                                                 spectrum_size_, 0);
+    last_delay =
+        WebRtc_DelayEstimatorProcessFix(handle_, near_u16_, spectrum_size_, 0);
     if (last_delay != -2) {
       EXPECT_EQ(last_delay, WebRtc_last_delay(handle_));
       if (!WebRtc_is_robust_validation_enabled(handle_)) {
@@ -577,8 +576,8 @@
 }
 
 TEST_F(DelayEstimatorTest, VerifyLookaheadAtCreate) {
-  void* farend_handle = WebRtc_CreateDelayEstimatorFarend(kSpectrumSize,
-                                                          kMaxDelay);
+  void* farend_handle =
+      WebRtc_CreateDelayEstimatorFarend(kSpectrumSize, kMaxDelay);
   ASSERT_TRUE(farend_handle != NULL);
   void* handle = WebRtc_CreateDelayEstimator(farend_handle, kLookahead);
   ASSERT_TRUE(handle != NULL);
diff --git a/modules/audio_processing/utility/delay_estimator_wrapper.cc b/modules/audio_processing/utility/delay_estimator_wrapper.cc
index f907c80..27c2a3a 100644
--- a/modules/audio_processing/utility/delay_estimator_wrapper.cc
+++ b/modules/audio_processing/utility/delay_estimator_wrapper.cc
@@ -72,7 +72,7 @@
     for (i = kBandFirst; i <= kBandLast; i++) {
       if (spectrum[i] > 0) {
         // Convert input spectrum from Q(|q_domain|) to Q15.
-        int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain);
+        int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain);
         threshold_spectrum[i].int32_ = (spectrum_q15 >> 1);
         *threshold_initialized = 1;
       }
@@ -80,7 +80,7 @@
   }
   for (i = kBandFirst; i <= kBandLast; i++) {
     // Convert input spectrum from Q(|q_domain|) to Q15.
-    int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain);
+    int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain);
     // Update the |threshold_spectrum|.
     WebRtc_MeanEstimatorFix(spectrum_q15, 6, &(threshold_spectrum[i].int32_));
     // Convert |spectrum| at current frequency bin to a binary value.
@@ -123,7 +123,7 @@
 }
 
 void WebRtc_FreeDelayEstimatorFarend(void* handle) {
-  DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+  DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
 
   if (handle == NULL) {
     return;
@@ -158,8 +158,8 @@
     memory_fail |= (self->binary_farend == NULL);
 
     // Allocate memory for spectrum buffers.
-    self->mean_far_spectrum =
-        static_cast<SpectrumType*>(malloc(spectrum_size * sizeof(SpectrumType)));
+    self->mean_far_spectrum = static_cast<SpectrumType*>(
+        malloc(spectrum_size * sizeof(SpectrumType)));
     memory_fail |= (self->mean_far_spectrum == NULL);
 
     self->spectrum_size = spectrum_size;
@@ -174,7 +174,7 @@
 }
 
 int WebRtc_InitDelayEstimatorFarend(void* handle) {
-  DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+  DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
 
   if (self == NULL) {
     return -1;
@@ -193,7 +193,7 @@
 }
 
 void WebRtc_SoftResetDelayEstimatorFarend(void* handle, int delay_shift) {
-  DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+  DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
   RTC_DCHECK(self);
   WebRtc_SoftResetBinaryDelayEstimatorFarend(self->binary_farend, delay_shift);
 }
@@ -202,7 +202,7 @@
                              const uint16_t* far_spectrum,
                              int spectrum_size,
                              int far_q) {
-  DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+  DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
   uint32_t binary_spectrum = 0;
 
   if (self == NULL) {
@@ -232,7 +232,7 @@
 int WebRtc_AddFarSpectrumFloat(void* handle,
                                const float* far_spectrum,
                                int spectrum_size) {
-  DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+  DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
   uint32_t binary_spectrum = 0;
 
   if (self == NULL) {
@@ -256,7 +256,7 @@
 }
 
 void WebRtc_FreeDelayEstimator(void* handle) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
 
   if (handle == NULL) {
     return;
@@ -273,7 +273,7 @@
 
 void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
   DelayEstimator* self = NULL;
-  DelayEstimatorFarend* farend = (DelayEstimatorFarend*) farend_handle;
+  DelayEstimatorFarend* farend = (DelayEstimatorFarend*)farend_handle;
 
   if (farend_handle != NULL) {
     self = static_cast<DelayEstimator*>(malloc(sizeof(DelayEstimator)));
@@ -304,7 +304,7 @@
 }
 
 int WebRtc_InitDelayEstimator(void* handle) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
 
   if (self == NULL) {
     return -1;
@@ -323,7 +323,7 @@
 }
 
 int WebRtc_SoftResetDelayEstimator(void* handle, int delay_shift) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
   RTC_DCHECK(self);
   return WebRtc_SoftResetBinaryDelayEstimator(self->binary_handle, delay_shift);
 }
@@ -352,7 +352,7 @@
 }
 
 int WebRtc_set_lookahead(void* handle, int lookahead) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
   RTC_DCHECK(self);
   RTC_DCHECK(self->binary_handle);
   if ((lookahead > self->binary_handle->near_history_size - 1) ||
@@ -364,14 +364,14 @@
 }
 
 int WebRtc_lookahead(void* handle) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
   RTC_DCHECK(self);
   RTC_DCHECK(self->binary_handle);
   return self->binary_handle->lookahead;
 }
 
 int WebRtc_set_allowed_offset(void* handle, int allowed_offset) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
 
   if ((self == NULL) || (allowed_offset < 0)) {
     return -1;
@@ -381,7 +381,7 @@
 }
 
 int WebRtc_get_allowed_offset(const void* handle) {
-  const DelayEstimator* self = (const DelayEstimator*) handle;
+  const DelayEstimator* self = (const DelayEstimator*)handle;
 
   if (self == NULL) {
     return -1;
@@ -390,7 +390,7 @@
 }
 
 int WebRtc_enable_robust_validation(void* handle, int enable) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
 
   if (self == NULL) {
     return -1;
@@ -404,7 +404,7 @@
 }
 
 int WebRtc_is_robust_validation_enabled(const void* handle) {
-  const DelayEstimator* self = (const DelayEstimator*) handle;
+  const DelayEstimator* self = (const DelayEstimator*)handle;
 
   if (self == NULL) {
     return -1;
@@ -416,7 +416,7 @@
                                     const uint16_t* near_spectrum,
                                     int spectrum_size,
                                     int near_q) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
   uint32_t binary_spectrum = 0;
 
   if (self == NULL) {
@@ -436,10 +436,9 @@
   }
 
   // Get binary spectra.
-  binary_spectrum = BinarySpectrumFix(near_spectrum,
-                                      self->mean_near_spectrum,
-                                      near_q,
-                                      &(self->near_spectrum_initialized));
+  binary_spectrum =
+      BinarySpectrumFix(near_spectrum, self->mean_near_spectrum, near_q,
+                        &(self->near_spectrum_initialized));
 
   return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum);
 }
@@ -447,7 +446,7 @@
 int WebRtc_DelayEstimatorProcessFloat(void* handle,
                                       const float* near_spectrum,
                                       int spectrum_size) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
   uint32_t binary_spectrum = 0;
 
   if (self == NULL) {
@@ -470,7 +469,7 @@
 }
 
 int WebRtc_last_delay(void* handle) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
 
   if (self == NULL) {
     return -1;
@@ -480,7 +479,7 @@
 }
 
 float WebRtc_last_delay_quality(void* handle) {
-  DelayEstimator* self = (DelayEstimator*) handle;
+  DelayEstimator* self = (DelayEstimator*)handle;
   RTC_DCHECK(self);
   return WebRtc_binary_last_delay_quality(self->binary_handle);
 }
diff --git a/modules/audio_processing/utility/ooura_fft.cc b/modules/audio_processing/utility/ooura_fft.cc
index d753a81..2add4eb 100644
--- a/modules/audio_processing/utility/ooura_fft.cc
+++ b/modules/audio_processing/utility/ooura_fft.cc
@@ -313,7 +313,6 @@
 }
 #endif
 
-
 }  // namespace
 
 OouraFft::OouraFft() {
diff --git a/modules/audio_processing/utility/ooura_fft_mips.cc b/modules/audio_processing/utility/ooura_fft_mips.cc
index 569e1d7..c782ee7 100644
--- a/modules/audio_processing/utility/ooura_fft_mips.cc
+++ b/modules/audio_processing/utility/ooura_fft_mips.cc
@@ -279,533 +279,600 @@
   const float* first = rdft_wk3ri_first;
   const float* second = rdft_wk3ri_second;
 
-  __asm __volatile (
-    ".set       push                                                    \n\t"
-    ".set       noreorder                                               \n\t"
-    // first 8
-    "lwc1       %[f0],        0(%[a])                                   \n\t"
-    "lwc1       %[f1],        4(%[a])                                   \n\t"
-    "lwc1       %[f2],        8(%[a])                                   \n\t"
-    "lwc1       %[f3],        12(%[a])                                  \n\t"
-    "lwc1       %[f4],        16(%[a])                                  \n\t"
-    "lwc1       %[f5],        20(%[a])                                  \n\t"
-    "lwc1       %[f6],        24(%[a])                                  \n\t"
-    "lwc1       %[f7],        28(%[a])                                  \n\t"
-    "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
-    "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
-    "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
-    "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
-    "add.s      %[f7],        %[f8],        %[f2]                       \n\t"
-    "sub.s      %[f8],        %[f8],        %[f2]                       \n\t"
-    "sub.s      %[f2],        %[f1],        %[f4]                       \n\t"
-    "add.s      %[f1],        %[f1],        %[f4]                       \n\t"
-    "add.s      %[f4],        %[f6],        %[f3]                       \n\t"
-    "sub.s      %[f6],        %[f6],        %[f3]                       \n\t"
-    "sub.s      %[f3],        %[f0],        %[f5]                       \n\t"
-    "add.s      %[f0],        %[f0],        %[f5]                       \n\t"
-    "swc1       %[f7],        0(%[a])                                   \n\t"
-    "swc1       %[f8],        16(%[a])                                  \n\t"
-    "swc1       %[f2],        28(%[a])                                  \n\t"
-    "swc1       %[f1],        12(%[a])                                  \n\t"
-    "swc1       %[f4],        4(%[a])                                   \n\t"
-    "swc1       %[f6],        20(%[a])                                  \n\t"
-    "swc1       %[f3],        8(%[a])                                   \n\t"
-    "swc1       %[f0],        24(%[a])                                  \n\t"
-    // second 8
-    "lwc1       %[f0],        32(%[a])                                  \n\t"
-    "lwc1       %[f1],        36(%[a])                                  \n\t"
-    "lwc1       %[f2],        40(%[a])                                  \n\t"
-    "lwc1       %[f3],        44(%[a])                                  \n\t"
-    "lwc1       %[f4],        48(%[a])                                  \n\t"
-    "lwc1       %[f5],        52(%[a])                                  \n\t"
-    "lwc1       %[f6],        56(%[a])                                  \n\t"
-    "lwc1       %[f7],        60(%[a])                                  \n\t"
-    "add.s      %[f8],        %[f4],        %[f6]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
-    "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
-    "add.s      %[f3],        %[f0],        %[f2]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f5],        %[f7]                       \n\t"
-    "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
-    "add.s      %[f7],        %[f4],        %[f1]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f1]                       \n\t"
-    "add.s      %[f1],        %[f3],        %[f8]                       \n\t"
-    "sub.s      %[f3],        %[f3],        %[f8]                       \n\t"
-    "sub.s      %[f8],        %[f0],        %[f5]                       \n\t"
-    "add.s      %[f0],        %[f0],        %[f5]                       \n\t"
-    "add.s      %[f5],        %[f6],        %[f2]                       \n\t"
-    "sub.s      %[f6],        %[f2],        %[f6]                       \n\t"
-    "lwc1       %[f9],        8(%[rdft_w])                              \n\t"
-    "sub.s      %[f2],        %[f8],        %[f7]                       \n\t"
-    "add.s      %[f8],        %[f8],        %[f7]                       \n\t"
-    "sub.s      %[f7],        %[f4],        %[f0]                       \n\t"
-    "add.s      %[f4],        %[f4],        %[f0]                       \n\t"
-    // prepare for loop
-    "addiu      %[a_ptr],     %[a],         64                          \n\t"
-    "addiu      %[p1_rdft],   %[rdft_w],    8                           \n\t"
-    "addiu      %[p2_rdft],   %[rdft_w],    16                          \n\t"
-    "addiu      %[count],     $zero,        7                           \n\t"
-    // finish second 8
-    "mul.s      %[f2],        %[f9],        %[f2]                       \n\t"
-    "mul.s      %[f8],        %[f9],        %[f8]                       \n\t"
-    "mul.s      %[f7],        %[f9],        %[f7]                       \n\t"
-    "mul.s      %[f4],        %[f9],        %[f4]                       \n\t"
-    "swc1       %[f1],        32(%[a])                                  \n\t"
-    "swc1       %[f3],        52(%[a])                                  \n\t"
-    "swc1       %[f5],        36(%[a])                                  \n\t"
-    "swc1       %[f6],        48(%[a])                                  \n\t"
-    "swc1       %[f2],        40(%[a])                                  \n\t"
-    "swc1       %[f8],        44(%[a])                                  \n\t"
-    "swc1       %[f7],        56(%[a])                                  \n\t"
-    "swc1       %[f4],        60(%[a])                                  \n\t"
-    // loop
-   "1:                                                                  \n\t"
-    "lwc1       %[f0],        0(%[a_ptr])                               \n\t"
-    "lwc1       %[f1],        4(%[a_ptr])                               \n\t"
-    "lwc1       %[f2],        8(%[a_ptr])                               \n\t"
-    "lwc1       %[f3],        12(%[a_ptr])                              \n\t"
-    "lwc1       %[f4],        16(%[a_ptr])                              \n\t"
-    "lwc1       %[f5],        20(%[a_ptr])                              \n\t"
-    "lwc1       %[f6],        24(%[a_ptr])                              \n\t"
-    "lwc1       %[f7],        28(%[a_ptr])                              \n\t"
-    "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
-    "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
-    "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
-    "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
-    "lwc1       %[f10],       4(%[p1_rdft])                             \n\t"
-    "lwc1       %[f11],       0(%[p2_rdft])                             \n\t"
-    "lwc1       %[f12],       4(%[p2_rdft])                             \n\t"
-    "lwc1       %[f13],       8(%[first])                               \n\t"
-    "lwc1       %[f14],       12(%[first])                              \n\t"
-    "add.s      %[f7],        %[f8],        %[f2]                       \n\t"
-    "sub.s      %[f8],        %[f8],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f6],        %[f3]                       \n\t"
-    "sub.s      %[f6],        %[f6],        %[f3]                       \n\t"
-    "add.s      %[f3],        %[f0],        %[f5]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f5]                       \n\t"
-    "add.s      %[f5],        %[f1],        %[f4]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f4]                       \n\t"
-    "swc1       %[f7],        0(%[a_ptr])                               \n\t"
-    "swc1       %[f2],        4(%[a_ptr])                               \n\t"
-    "mul.s      %[f4],        %[f9],        %[f8]                       \n\t"
+  __asm __volatile(
+      ".set       push                                                    \n\t"
+      ".set       noreorder                                               \n\t"
+      // first 8
+      "lwc1       %[f0],        0(%[a])                                   \n\t"
+      "lwc1       %[f1],        4(%[a])                                   \n\t"
+      "lwc1       %[f2],        8(%[a])                                   \n\t"
+      "lwc1       %[f3],        12(%[a])                                  \n\t"
+      "lwc1       %[f4],        16(%[a])                                  \n\t"
+      "lwc1       %[f5],        20(%[a])                                  \n\t"
+      "lwc1       %[f6],        24(%[a])                                  \n\t"
+      "lwc1       %[f7],        28(%[a])                                  \n\t"
+      "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
+      "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
+      "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
+      "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
+      "add.s      %[f7],        %[f8],        %[f2]                       \n\t"
+      "sub.s      %[f8],        %[f8],        %[f2]                       \n\t"
+      "sub.s      %[f2],        %[f1],        %[f4]                       \n\t"
+      "add.s      %[f1],        %[f1],        %[f4]                       \n\t"
+      "add.s      %[f4],        %[f6],        %[f3]                       \n\t"
+      "sub.s      %[f6],        %[f6],        %[f3]                       \n\t"
+      "sub.s      %[f3],        %[f0],        %[f5]                       \n\t"
+      "add.s      %[f0],        %[f0],        %[f5]                       \n\t"
+      "swc1       %[f7],        0(%[a])                                   \n\t"
+      "swc1       %[f8],        16(%[a])                                  \n\t"
+      "swc1       %[f2],        28(%[a])                                  \n\t"
+      "swc1       %[f1],        12(%[a])                                  \n\t"
+      "swc1       %[f4],        4(%[a])                                   \n\t"
+      "swc1       %[f6],        20(%[a])                                  \n\t"
+      "swc1       %[f3],        8(%[a])                                   \n\t"
+      "swc1       %[f0],        24(%[a])                                  \n\t"
+      // second 8
+      "lwc1       %[f0],        32(%[a])                                  \n\t"
+      "lwc1       %[f1],        36(%[a])                                  \n\t"
+      "lwc1       %[f2],        40(%[a])                                  \n\t"
+      "lwc1       %[f3],        44(%[a])                                  \n\t"
+      "lwc1       %[f4],        48(%[a])                                  \n\t"
+      "lwc1       %[f5],        52(%[a])                                  \n\t"
+      "lwc1       %[f6],        56(%[a])                                  \n\t"
+      "lwc1       %[f7],        60(%[a])                                  \n\t"
+      "add.s      %[f8],        %[f4],        %[f6]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
+      "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
+      "add.s      %[f3],        %[f0],        %[f2]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f5],        %[f7]                       \n\t"
+      "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
+      "add.s      %[f7],        %[f4],        %[f1]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f1]                       \n\t"
+      "add.s      %[f1],        %[f3],        %[f8]                       \n\t"
+      "sub.s      %[f3],        %[f3],        %[f8]                       \n\t"
+      "sub.s      %[f8],        %[f0],        %[f5]                       \n\t"
+      "add.s      %[f0],        %[f0],        %[f5]                       \n\t"
+      "add.s      %[f5],        %[f6],        %[f2]                       \n\t"
+      "sub.s      %[f6],        %[f2],        %[f6]                       \n\t"
+      "lwc1       %[f9],        8(%[rdft_w])                              \n\t"
+      "sub.s      %[f2],        %[f8],        %[f7]                       \n\t"
+      "add.s      %[f8],        %[f8],        %[f7]                       \n\t"
+      "sub.s      %[f7],        %[f4],        %[f0]                       \n\t"
+      "add.s      %[f4],        %[f4],        %[f0]                       \n\t"
+      // prepare for loop
+      "addiu      %[a_ptr],     %[a],         64                          \n\t"
+      "addiu      %[p1_rdft],   %[rdft_w],    8                           \n\t"
+      "addiu      %[p2_rdft],   %[rdft_w],    16                          \n\t"
+      "addiu      %[count],     $zero,        7                           \n\t"
+      // finish second 8
+      "mul.s      %[f2],        %[f9],        %[f2]                       \n\t"
+      "mul.s      %[f8],        %[f9],        %[f8]                       \n\t"
+      "mul.s      %[f7],        %[f9],        %[f7]                       \n\t"
+      "mul.s      %[f4],        %[f9],        %[f4]                       \n\t"
+      "swc1       %[f1],        32(%[a])                                  \n\t"
+      "swc1       %[f3],        52(%[a])                                  \n\t"
+      "swc1       %[f5],        36(%[a])                                  \n\t"
+      "swc1       %[f6],        48(%[a])                                  \n\t"
+      "swc1       %[f2],        40(%[a])                                  \n\t"
+      "swc1       %[f8],        44(%[a])                                  \n\t"
+      "swc1       %[f7],        56(%[a])                                  \n\t"
+      "swc1       %[f4],        60(%[a])                                  \n\t"
+      // loop
+      "1:                                                                  \n\t"
+      "lwc1       %[f0],        0(%[a_ptr])                               \n\t"
+      "lwc1       %[f1],        4(%[a_ptr])                               \n\t"
+      "lwc1       %[f2],        8(%[a_ptr])                               \n\t"
+      "lwc1       %[f3],        12(%[a_ptr])                              \n\t"
+      "lwc1       %[f4],        16(%[a_ptr])                              \n\t"
+      "lwc1       %[f5],        20(%[a_ptr])                              \n\t"
+      "lwc1       %[f6],        24(%[a_ptr])                              \n\t"
+      "lwc1       %[f7],        28(%[a_ptr])                              \n\t"
+      "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
+      "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
+      "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
+      "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
+      "lwc1       %[f10],       4(%[p1_rdft])                             \n\t"
+      "lwc1       %[f11],       0(%[p2_rdft])                             \n\t"
+      "lwc1       %[f12],       4(%[p2_rdft])                             \n\t"
+      "lwc1       %[f13],       8(%[first])                               \n\t"
+      "lwc1       %[f14],       12(%[first])                              \n\t"
+      "add.s      %[f7],        %[f8],        %[f2]                       \n\t"
+      "sub.s      %[f8],        %[f8],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f6],        %[f3]                       \n\t"
+      "sub.s      %[f6],        %[f6],        %[f3]                       \n\t"
+      "add.s      %[f3],        %[f0],        %[f5]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f5]                       \n\t"
+      "add.s      %[f5],        %[f1],        %[f4]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f4]                       \n\t"
+      "swc1       %[f7],        0(%[a_ptr])                               \n\t"
+      "swc1       %[f2],        4(%[a_ptr])                               \n\t"
+      "mul.s      %[f4],        %[f9],        %[f8]                       \n\t"
 #if defined(MIPS32_R2_LE)
-    "mul.s      %[f8],        %[f10],       %[f8]                       \n\t"
-    "mul.s      %[f7],        %[f11],       %[f0]                       \n\t"
-    "mul.s      %[f0],        %[f12],       %[f0]                       \n\t"
-    "mul.s      %[f2],        %[f13],       %[f3]                       \n\t"
-    "mul.s      %[f3],        %[f14],       %[f3]                       \n\t"
-    "nmsub.s    %[f4],        %[f4],        %[f10],       %[f6]         \n\t"
-    "madd.s     %[f8],        %[f8],        %[f9],        %[f6]         \n\t"
-    "nmsub.s    %[f7],        %[f7],        %[f12],       %[f5]         \n\t"
-    "madd.s     %[f0],        %[f0],        %[f11],       %[f5]         \n\t"
-    "nmsub.s    %[f2],        %[f2],        %[f14],       %[f1]         \n\t"
-    "madd.s     %[f3],        %[f3],        %[f13],       %[f1]         \n\t"
+      "mul.s      %[f8],        %[f10],       %[f8]                       \n\t"
+      "mul.s      %[f7],        %[f11],       %[f0]                       \n\t"
+      "mul.s      %[f0],        %[f12],       %[f0]                       \n\t"
+      "mul.s      %[f2],        %[f13],       %[f3]                       \n\t"
+      "mul.s      %[f3],        %[f14],       %[f3]                       \n\t"
+      "nmsub.s    %[f4],        %[f4],        %[f10],       %[f6]         \n\t"
+      "madd.s     %[f8],        %[f8],        %[f9],        %[f6]         \n\t"
+      "nmsub.s    %[f7],        %[f7],        %[f12],       %[f5]         \n\t"
+      "madd.s     %[f0],        %[f0],        %[f11],       %[f5]         \n\t"
+      "nmsub.s    %[f2],        %[f2],        %[f14],       %[f1]         \n\t"
+      "madd.s     %[f3],        %[f3],        %[f13],       %[f1]         \n\t"
 #else
-    "mul.s      %[f7],        %[f10],       %[f6]                       \n\t"
-    "mul.s      %[f6],        %[f9],        %[f6]                       \n\t"
-    "mul.s      %[f8],        %[f10],       %[f8]                       \n\t"
-    "mul.s      %[f2],        %[f11],       %[f0]                       \n\t"
-    "mul.s      %[f11],       %[f11],       %[f5]                       \n\t"
-    "mul.s      %[f5],        %[f12],       %[f5]                       \n\t"
-    "mul.s      %[f0],        %[f12],       %[f0]                       \n\t"
-    "mul.s      %[f12],       %[f13],       %[f3]                       \n\t"
-    "mul.s      %[f13],       %[f13],       %[f1]                       \n\t"
-    "mul.s      %[f1],        %[f14],       %[f1]                       \n\t"
-    "mul.s      %[f3],        %[f14],       %[f3]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f7]                       \n\t"
-    "add.s      %[f8],        %[f6],        %[f8]                       \n\t"
-    "sub.s      %[f7],        %[f2],        %[f5]                       \n\t"
-    "add.s      %[f0],        %[f11],       %[f0]                       \n\t"
-    "sub.s      %[f2],        %[f12],       %[f1]                       \n\t"
-    "add.s      %[f3],        %[f13],       %[f3]                       \n\t"
+      "mul.s      %[f7],        %[f10],       %[f6]                       \n\t"
+      "mul.s      %[f6],        %[f9],        %[f6]                       \n\t"
+      "mul.s      %[f8],        %[f10],       %[f8]                       \n\t"
+      "mul.s      %[f2],        %[f11],       %[f0]                       \n\t"
+      "mul.s      %[f11],       %[f11],       %[f5]                       \n\t"
+      "mul.s      %[f5],        %[f12],       %[f5]                       \n\t"
+      "mul.s      %[f0],        %[f12],       %[f0]                       \n\t"
+      "mul.s      %[f12],       %[f13],       %[f3]                       \n\t"
+      "mul.s      %[f13],       %[f13],       %[f1]                       \n\t"
+      "mul.s      %[f1],        %[f14],       %[f1]                       \n\t"
+      "mul.s      %[f3],        %[f14],       %[f3]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f7]                       \n\t"
+      "add.s      %[f8],        %[f6],        %[f8]                       \n\t"
+      "sub.s      %[f7],        %[f2],        %[f5]                       \n\t"
+      "add.s      %[f0],        %[f11],       %[f0]                       \n\t"
+      "sub.s      %[f2],        %[f12],       %[f1]                       \n\t"
+      "add.s      %[f3],        %[f13],       %[f3]                       \n\t"
 #endif
-    "swc1       %[f4],        16(%[a_ptr])                              \n\t"
-    "swc1       %[f8],        20(%[a_ptr])                              \n\t"
-    "swc1       %[f7],        8(%[a_ptr])                               \n\t"
-    "swc1       %[f0],        12(%[a_ptr])                              \n\t"
-    "swc1       %[f2],        24(%[a_ptr])                              \n\t"
-    "swc1       %[f3],        28(%[a_ptr])                              \n\t"
-    "lwc1       %[f0],        32(%[a_ptr])                              \n\t"
-    "lwc1       %[f1],        36(%[a_ptr])                              \n\t"
-    "lwc1       %[f2],        40(%[a_ptr])                              \n\t"
-    "lwc1       %[f3],        44(%[a_ptr])                              \n\t"
-    "lwc1       %[f4],        48(%[a_ptr])                              \n\t"
-    "lwc1       %[f5],        52(%[a_ptr])                              \n\t"
-    "lwc1       %[f6],        56(%[a_ptr])                              \n\t"
-    "lwc1       %[f7],        60(%[a_ptr])                              \n\t"
-    "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
-    "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
-    "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
-    "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
-    "lwc1       %[f11],       8(%[p2_rdft])                             \n\t"
-    "lwc1       %[f12],       12(%[p2_rdft])                            \n\t"
-    "lwc1       %[f13],       8(%[second])                              \n\t"
-    "lwc1       %[f14],       12(%[second])                             \n\t"
-    "add.s      %[f7],        %[f8],        %[f2]                       \n\t"
-    "sub.s      %[f8],        %[f2],        %[f8]                       \n\t"
-    "add.s      %[f2],        %[f6],        %[f3]                       \n\t"
-    "sub.s      %[f6],        %[f3],        %[f6]                       \n\t"
-    "add.s      %[f3],        %[f0],        %[f5]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f5]                       \n\t"
-    "add.s      %[f5],        %[f1],        %[f4]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f4]                       \n\t"
-    "swc1       %[f7],        32(%[a_ptr])                              \n\t"
-    "swc1       %[f2],        36(%[a_ptr])                              \n\t"
-    "mul.s      %[f4],        %[f10],       %[f8]                       \n\t"
+      "swc1       %[f4],        16(%[a_ptr])                              \n\t"
+      "swc1       %[f8],        20(%[a_ptr])                              \n\t"
+      "swc1       %[f7],        8(%[a_ptr])                               \n\t"
+      "swc1       %[f0],        12(%[a_ptr])                              \n\t"
+      "swc1       %[f2],        24(%[a_ptr])                              \n\t"
+      "swc1       %[f3],        28(%[a_ptr])                              \n\t"
+      "lwc1       %[f0],        32(%[a_ptr])                              \n\t"
+      "lwc1       %[f1],        36(%[a_ptr])                              \n\t"
+      "lwc1       %[f2],        40(%[a_ptr])                              \n\t"
+      "lwc1       %[f3],        44(%[a_ptr])                              \n\t"
+      "lwc1       %[f4],        48(%[a_ptr])                              \n\t"
+      "lwc1       %[f5],        52(%[a_ptr])                              \n\t"
+      "lwc1       %[f6],        56(%[a_ptr])                              \n\t"
+      "lwc1       %[f7],        60(%[a_ptr])                              \n\t"
+      "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
+      "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
+      "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
+      "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
+      "lwc1       %[f11],       8(%[p2_rdft])                             \n\t"
+      "lwc1       %[f12],       12(%[p2_rdft])                            \n\t"
+      "lwc1       %[f13],       8(%[second])                              \n\t"
+      "lwc1       %[f14],       12(%[second])                             \n\t"
+      "add.s      %[f7],        %[f8],        %[f2]                       \n\t"
+      "sub.s      %[f8],        %[f2],        %[f8]                       \n\t"
+      "add.s      %[f2],        %[f6],        %[f3]                       \n\t"
+      "sub.s      %[f6],        %[f3],        %[f6]                       \n\t"
+      "add.s      %[f3],        %[f0],        %[f5]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f5]                       \n\t"
+      "add.s      %[f5],        %[f1],        %[f4]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f4]                       \n\t"
+      "swc1       %[f7],        32(%[a_ptr])                              \n\t"
+      "swc1       %[f2],        36(%[a_ptr])                              \n\t"
+      "mul.s      %[f4],        %[f10],       %[f8]                       \n\t"
 #if defined(MIPS32_R2_LE)
-    "mul.s      %[f10],       %[f10],       %[f6]                       \n\t"
-    "mul.s      %[f7],        %[f11],       %[f0]                       \n\t"
-    "mul.s      %[f11],       %[f11],       %[f5]                       \n\t"
-    "mul.s      %[f2],        %[f13],       %[f3]                       \n\t"
-    "mul.s      %[f13],       %[f13],       %[f1]                       \n\t"
-    "madd.s     %[f4],        %[f4],        %[f9],        %[f6]         \n\t"
-    "nmsub.s    %[f10],       %[f10],       %[f9],        %[f8]         \n\t"
-    "nmsub.s    %[f7],        %[f7],        %[f12],       %[f5]         \n\t"
-    "madd.s     %[f11],       %[f11],       %[f12],       %[f0]         \n\t"
-    "nmsub.s    %[f2],        %[f2],        %[f14],       %[f1]         \n\t"
-    "madd.s     %[f13],       %[f13],       %[f14],       %[f3]         \n\t"
+      "mul.s      %[f10],       %[f10],       %[f6]                       \n\t"
+      "mul.s      %[f7],        %[f11],       %[f0]                       \n\t"
+      "mul.s      %[f11],       %[f11],       %[f5]                       \n\t"
+      "mul.s      %[f2],        %[f13],       %[f3]                       \n\t"
+      "mul.s      %[f13],       %[f13],       %[f1]                       \n\t"
+      "madd.s     %[f4],        %[f4],        %[f9],        %[f6]         \n\t"
+      "nmsub.s    %[f10],       %[f10],       %[f9],        %[f8]         \n\t"
+      "nmsub.s    %[f7],        %[f7],        %[f12],       %[f5]         \n\t"
+      "madd.s     %[f11],       %[f11],       %[f12],       %[f0]         \n\t"
+      "nmsub.s    %[f2],        %[f2],        %[f14],       %[f1]         \n\t"
+      "madd.s     %[f13],       %[f13],       %[f14],       %[f3]         \n\t"
 #else
-    "mul.s      %[f2],        %[f9],        %[f6]                       \n\t"
-    "mul.s      %[f10],       %[f10],       %[f6]                       \n\t"
-    "mul.s      %[f9],        %[f9],        %[f8]                       \n\t"
-    "mul.s      %[f7],        %[f11],       %[f0]                       \n\t"
-    "mul.s      %[f8],        %[f12],       %[f5]                       \n\t"
-    "mul.s      %[f11],       %[f11],       %[f5]                       \n\t"
-    "mul.s      %[f12],       %[f12],       %[f0]                       \n\t"
-    "mul.s      %[f5],        %[f13],       %[f3]                       \n\t"
-    "mul.s      %[f0],        %[f14],       %[f1]                       \n\t"
-    "mul.s      %[f13],       %[f13],       %[f1]                       \n\t"
-    "mul.s      %[f14],       %[f14],       %[f3]                       \n\t"
-    "add.s      %[f4],        %[f4],        %[f2]                       \n\t"
-    "sub.s      %[f10],       %[f10],       %[f9]                       \n\t"
-    "sub.s      %[f7],        %[f7],        %[f8]                       \n\t"
-    "add.s      %[f11],       %[f11],       %[f12]                      \n\t"
-    "sub.s      %[f2],        %[f5],        %[f0]                       \n\t"
-    "add.s      %[f13],       %[f13],       %[f14]                      \n\t"
+      "mul.s      %[f2],        %[f9],        %[f6]                       \n\t"
+      "mul.s      %[f10],       %[f10],       %[f6]                       \n\t"
+      "mul.s      %[f9],        %[f9],        %[f8]                       \n\t"
+      "mul.s      %[f7],        %[f11],       %[f0]                       \n\t"
+      "mul.s      %[f8],        %[f12],       %[f5]                       \n\t"
+      "mul.s      %[f11],       %[f11],       %[f5]                       \n\t"
+      "mul.s      %[f12],       %[f12],       %[f0]                       \n\t"
+      "mul.s      %[f5],        %[f13],       %[f3]                       \n\t"
+      "mul.s      %[f0],        %[f14],       %[f1]                       \n\t"
+      "mul.s      %[f13],       %[f13],       %[f1]                       \n\t"
+      "mul.s      %[f14],       %[f14],       %[f3]                       \n\t"
+      "add.s      %[f4],        %[f4],        %[f2]                       \n\t"
+      "sub.s      %[f10],       %[f10],       %[f9]                       \n\t"
+      "sub.s      %[f7],        %[f7],        %[f8]                       \n\t"
+      "add.s      %[f11],       %[f11],       %[f12]                      \n\t"
+      "sub.s      %[f2],        %[f5],        %[f0]                       \n\t"
+      "add.s      %[f13],       %[f13],       %[f14]                      \n\t"
 #endif
-    "swc1       %[f4],        48(%[a_ptr])                              \n\t"
-    "swc1       %[f10],       52(%[a_ptr])                              \n\t"
-    "swc1       %[f7],        40(%[a_ptr])                              \n\t"
-    "swc1       %[f11],       44(%[a_ptr])                              \n\t"
-    "swc1       %[f2],        56(%[a_ptr])                              \n\t"
-    "swc1       %[f13],       60(%[a_ptr])                              \n\t"
-    "addiu      %[count],     %[count],     -1                          \n\t"
-    "lwc1       %[f9],        8(%[p1_rdft])                             \n\t"
-    "addiu      %[a_ptr],     %[a_ptr],     64                          \n\t"
-    "addiu      %[p1_rdft],   %[p1_rdft],   8                           \n\t"
-    "addiu      %[p2_rdft],   %[p2_rdft],   16                          \n\t"
-    "addiu      %[first],     %[first],     8                           \n\t"
-    "bgtz       %[count],     1b                                        \n\t"
-    " addiu     %[second],    %[second],    8                           \n\t"
-    ".set       pop                                                     \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
-      [f12] "=&f" (f12), [f13] "=&f" (f13), [f14] "=&f" (f14),
-      [a_ptr] "=&r" (a_ptr), [p1_rdft] "=&r" (p1_rdft), [first] "+r" (first),
-      [p2_rdft] "=&r" (p2_rdft), [count] "=&r" (count), [second] "+r" (second)
-    : [a] "r" (a), [rdft_w] "r" (rdft_w)
-    : "memory"
-  );
+      "swc1       %[f4],        48(%[a_ptr])                              \n\t"
+      "swc1       %[f10],       52(%[a_ptr])                              \n\t"
+      "swc1       %[f7],        40(%[a_ptr])                              \n\t"
+      "swc1       %[f11],       44(%[a_ptr])                              \n\t"
+      "swc1       %[f2],        56(%[a_ptr])                              \n\t"
+      "swc1       %[f13],       60(%[a_ptr])                              \n\t"
+      "addiu      %[count],     %[count],     -1                          \n\t"
+      "lwc1       %[f9],        8(%[p1_rdft])                             \n\t"
+      "addiu      %[a_ptr],     %[a_ptr],     64                          \n\t"
+      "addiu      %[p1_rdft],   %[p1_rdft],   8                           \n\t"
+      "addiu      %[p2_rdft],   %[p2_rdft],   16                          \n\t"
+      "addiu      %[first],     %[first],     8                           \n\t"
+      "bgtz       %[count],     1b                                        \n\t"
+      " addiu     %[second],    %[second],    8                           \n\t"
+      ".set       pop                                                     \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11),
+        [f12] "=&f"(f12), [f13] "=&f"(f13), [f14] "=&f"(f14),
+        [a_ptr] "=&r"(a_ptr), [p1_rdft] "=&r"(p1_rdft), [first] "+r"(first),
+        [p2_rdft] "=&r"(p2_rdft), [count] "=&r"(count), [second] "+r"(second)
+      : [a] "r"(a), [rdft_w] "r"(rdft_w)
+      : "memory");
 }
 
 void cftmdl_128_mips(float* a) {
   float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14;
   int tmp_a, count;
-  __asm __volatile (
-    ".set       push                                      \n\t"
-    ".set       noreorder                                 \n\t"
-    "addiu      %[tmp_a],   %[a],         0               \n\t"
-    "addiu      %[count],   $zero,        4               \n\t"
-   "1:                                                    \n\t"
-    "addiu      %[count],   %[count],     -1              \n\t"
-    "lwc1       %[f0],      0(%[tmp_a])                   \n\t"
-    "lwc1       %[f2],      32(%[tmp_a])                  \n\t"
-    "lwc1       %[f4],      64(%[tmp_a])                  \n\t"
-    "lwc1       %[f6],      96(%[tmp_a])                  \n\t"
-    "lwc1       %[f1],      4(%[tmp_a])                   \n\t"
-    "lwc1       %[f3],      36(%[tmp_a])                  \n\t"
-    "lwc1       %[f5],      68(%[tmp_a])                  \n\t"
-    "lwc1       %[f7],      100(%[tmp_a])                 \n\t"
-    "add.s      %[f8],      %[f0],        %[f2]           \n\t"
-    "sub.s      %[f0],      %[f0],        %[f2]           \n\t"
-    "add.s      %[f2],      %[f4],        %[f6]           \n\t"
-    "sub.s      %[f4],      %[f4],        %[f6]           \n\t"
-    "add.s      %[f6],      %[f1],        %[f3]           \n\t"
-    "sub.s      %[f1],      %[f1],        %[f3]           \n\t"
-    "add.s      %[f3],      %[f5],        %[f7]           \n\t"
-    "sub.s      %[f5],      %[f5],        %[f7]           \n\t"
-    "add.s      %[f7],      %[f8],        %[f2]           \n\t"
-    "sub.s      %[f8],      %[f8],        %[f2]           \n\t"
-    "add.s      %[f2],      %[f1],        %[f4]           \n\t"
-    "sub.s      %[f1],      %[f1],        %[f4]           \n\t"
-    "add.s      %[f4],      %[f6],        %[f3]           \n\t"
-    "sub.s      %[f6],      %[f6],        %[f3]           \n\t"
-    "sub.s      %[f3],      %[f0],        %[f5]           \n\t"
-    "add.s      %[f0],      %[f0],        %[f5]           \n\t"
-    "swc1       %[f7],      0(%[tmp_a])                   \n\t"
-    "swc1       %[f8],      64(%[tmp_a])                  \n\t"
-    "swc1       %[f2],      36(%[tmp_a])                  \n\t"
-    "swc1       %[f1],      100(%[tmp_a])                 \n\t"
-    "swc1       %[f4],      4(%[tmp_a])                   \n\t"
-    "swc1       %[f6],      68(%[tmp_a])                  \n\t"
-    "swc1       %[f3],      32(%[tmp_a])                  \n\t"
-    "swc1       %[f0],      96(%[tmp_a])                  \n\t"
-    "bgtz       %[count],   1b                            \n\t"
-    " addiu     %[tmp_a],   %[tmp_a],     8               \n\t"
-    ".set       pop                                       \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
-    : [a] "r" (a)
-    : "memory"
-  );
+  __asm __volatile(
+      ".set       push                                      \n\t"
+      ".set       noreorder                                 \n\t"
+      "addiu      %[tmp_a],   %[a],         0               \n\t"
+      "addiu      %[count],   $zero,        4               \n\t"
+      "1:                                                    \n\t"
+      "addiu      %[count],   %[count],     -1              \n\t"
+      "lwc1       %[f0],      0(%[tmp_a])                   \n\t"
+      "lwc1       %[f2],      32(%[tmp_a])                  \n\t"
+      "lwc1       %[f4],      64(%[tmp_a])                  \n\t"
+      "lwc1       %[f6],      96(%[tmp_a])                  \n\t"
+      "lwc1       %[f1],      4(%[tmp_a])                   \n\t"
+      "lwc1       %[f3],      36(%[tmp_a])                  \n\t"
+      "lwc1       %[f5],      68(%[tmp_a])                  \n\t"
+      "lwc1       %[f7],      100(%[tmp_a])                 \n\t"
+      "add.s      %[f8],      %[f0],        %[f2]           \n\t"
+      "sub.s      %[f0],      %[f0],        %[f2]           \n\t"
+      "add.s      %[f2],      %[f4],        %[f6]           \n\t"
+      "sub.s      %[f4],      %[f4],        %[f6]           \n\t"
+      "add.s      %[f6],      %[f1],        %[f3]           \n\t"
+      "sub.s      %[f1],      %[f1],        %[f3]           \n\t"
+      "add.s      %[f3],      %[f5],        %[f7]           \n\t"
+      "sub.s      %[f5],      %[f5],        %[f7]           \n\t"
+      "add.s      %[f7],      %[f8],        %[f2]           \n\t"
+      "sub.s      %[f8],      %[f8],        %[f2]           \n\t"
+      "add.s      %[f2],      %[f1],        %[f4]           \n\t"
+      "sub.s      %[f1],      %[f1],        %[f4]           \n\t"
+      "add.s      %[f4],      %[f6],        %[f3]           \n\t"
+      "sub.s      %[f6],      %[f6],        %[f3]           \n\t"
+      "sub.s      %[f3],      %[f0],        %[f5]           \n\t"
+      "add.s      %[f0],      %[f0],        %[f5]           \n\t"
+      "swc1       %[f7],      0(%[tmp_a])                   \n\t"
+      "swc1       %[f8],      64(%[tmp_a])                  \n\t"
+      "swc1       %[f2],      36(%[tmp_a])                  \n\t"
+      "swc1       %[f1],      100(%[tmp_a])                 \n\t"
+      "swc1       %[f4],      4(%[tmp_a])                   \n\t"
+      "swc1       %[f6],      68(%[tmp_a])                  \n\t"
+      "swc1       %[f3],      32(%[tmp_a])                  \n\t"
+      "swc1       %[f0],      96(%[tmp_a])                  \n\t"
+      "bgtz       %[count],   1b                            \n\t"
+      " addiu     %[tmp_a],   %[tmp_a],     8               \n\t"
+      ".set       pop                                       \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+      : [a] "r"(a)
+      : "memory");
   f9 = rdft_w[2];
-  __asm __volatile (
-    ".set       push                                      \n\t"
-    ".set       noreorder                                 \n\t"
-    "addiu      %[tmp_a],   %[a],         128             \n\t"
-    "addiu      %[count],   $zero,        4               \n\t"
-   "1:                                                    \n\t"
-    "addiu      %[count],   %[count],     -1              \n\t"
-    "lwc1       %[f0],      0(%[tmp_a])                   \n\t"
-    "lwc1       %[f2],      32(%[tmp_a])                  \n\t"
-    "lwc1       %[f5],      68(%[tmp_a])                  \n\t"
-    "lwc1       %[f7],      100(%[tmp_a])                 \n\t"
-    "lwc1       %[f1],      4(%[tmp_a])                   \n\t"
-    "lwc1       %[f3],      36(%[tmp_a])                  \n\t"
-    "lwc1       %[f4],      64(%[tmp_a])                  \n\t"
-    "lwc1       %[f6],      96(%[tmp_a])                  \n\t"
-    "sub.s      %[f8],      %[f0],        %[f2]           \n\t"
-    "add.s      %[f0],      %[f0],        %[f2]           \n\t"
-    "sub.s      %[f2],      %[f5],        %[f7]           \n\t"
-    "add.s      %[f5],      %[f5],        %[f7]           \n\t"
-    "sub.s      %[f7],      %[f1],        %[f3]           \n\t"
-    "add.s      %[f1],      %[f1],        %[f3]           \n\t"
-    "sub.s      %[f3],      %[f4],        %[f6]           \n\t"
-    "add.s      %[f4],      %[f4],        %[f6]           \n\t"
-    "sub.s      %[f6],      %[f8],        %[f2]           \n\t"
-    "add.s      %[f8],      %[f8],        %[f2]           \n\t"
-    "add.s      %[f2],      %[f5],        %[f1]           \n\t"
-    "sub.s      %[f5],      %[f5],        %[f1]           \n\t"
-    "add.s      %[f1],      %[f3],        %[f7]           \n\t"
-    "sub.s      %[f3],      %[f3],        %[f7]           \n\t"
-    "add.s      %[f7],      %[f0],        %[f4]           \n\t"
-    "sub.s      %[f0],      %[f0],        %[f4]           \n\t"
-    "sub.s      %[f4],      %[f6],        %[f1]           \n\t"
-    "add.s      %[f6],      %[f6],        %[f1]           \n\t"
-    "sub.s      %[f1],      %[f3],        %[f8]           \n\t"
-    "add.s      %[f3],      %[f3],        %[f8]           \n\t"
-    "mul.s      %[f4],      %[f4],        %[f9]           \n\t"
-    "mul.s      %[f6],      %[f6],        %[f9]           \n\t"
-    "mul.s      %[f1],      %[f1],        %[f9]           \n\t"
-    "mul.s      %[f3],      %[f3],        %[f9]           \n\t"
-    "swc1       %[f7],      0(%[tmp_a])                   \n\t"
-    "swc1       %[f2],      4(%[tmp_a])                   \n\t"
-    "swc1       %[f5],      64(%[tmp_a])                  \n\t"
-    "swc1       %[f0],      68(%[tmp_a])                  \n\t"
-    "swc1       %[f4],      32(%[tmp_a])                  \n\t"
-    "swc1       %[f6],      36(%[tmp_a])                  \n\t"
-    "swc1       %[f1],      96(%[tmp_a])                  \n\t"
-    "swc1       %[f3],      100(%[tmp_a])                 \n\t"
-    "bgtz       %[count],   1b                            \n\t"
-    " addiu     %[tmp_a],   %[tmp_a],     8               \n\t"
-    ".set       pop                                       \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
-    : [a] "r" (a), [f9] "f" (f9)
-    : "memory"
-  );
+  __asm __volatile(
+      ".set       push                                      \n\t"
+      ".set       noreorder                                 \n\t"
+      "addiu      %[tmp_a],   %[a],         128             \n\t"
+      "addiu      %[count],   $zero,        4               \n\t"
+      "1:                                                    \n\t"
+      "addiu      %[count],   %[count],     -1              \n\t"
+      "lwc1       %[f0],      0(%[tmp_a])                   \n\t"
+      "lwc1       %[f2],      32(%[tmp_a])                  \n\t"
+      "lwc1       %[f5],      68(%[tmp_a])                  \n\t"
+      "lwc1       %[f7],      100(%[tmp_a])                 \n\t"
+      "lwc1       %[f1],      4(%[tmp_a])                   \n\t"
+      "lwc1       %[f3],      36(%[tmp_a])                  \n\t"
+      "lwc1       %[f4],      64(%[tmp_a])                  \n\t"
+      "lwc1       %[f6],      96(%[tmp_a])                  \n\t"
+      "sub.s      %[f8],      %[f0],        %[f2]           \n\t"
+      "add.s      %[f0],      %[f0],        %[f2]           \n\t"
+      "sub.s      %[f2],      %[f5],        %[f7]           \n\t"
+      "add.s      %[f5],      %[f5],        %[f7]           \n\t"
+      "sub.s      %[f7],      %[f1],        %[f3]           \n\t"
+      "add.s      %[f1],      %[f1],        %[f3]           \n\t"
+      "sub.s      %[f3],      %[f4],        %[f6]           \n\t"
+      "add.s      %[f4],      %[f4],        %[f6]           \n\t"
+      "sub.s      %[f6],      %[f8],        %[f2]           \n\t"
+      "add.s      %[f8],      %[f8],        %[f2]           \n\t"
+      "add.s      %[f2],      %[f5],        %[f1]           \n\t"
+      "sub.s      %[f5],      %[f5],        %[f1]           \n\t"
+      "add.s      %[f1],      %[f3],        %[f7]           \n\t"
+      "sub.s      %[f3],      %[f3],        %[f7]           \n\t"
+      "add.s      %[f7],      %[f0],        %[f4]           \n\t"
+      "sub.s      %[f0],      %[f0],        %[f4]           \n\t"
+      "sub.s      %[f4],      %[f6],        %[f1]           \n\t"
+      "add.s      %[f6],      %[f6],        %[f1]           \n\t"
+      "sub.s      %[f1],      %[f3],        %[f8]           \n\t"
+      "add.s      %[f3],      %[f3],        %[f8]           \n\t"
+      "mul.s      %[f4],      %[f4],        %[f9]           \n\t"
+      "mul.s      %[f6],      %[f6],        %[f9]           \n\t"
+      "mul.s      %[f1],      %[f1],        %[f9]           \n\t"
+      "mul.s      %[f3],      %[f3],        %[f9]           \n\t"
+      "swc1       %[f7],      0(%[tmp_a])                   \n\t"
+      "swc1       %[f2],      4(%[tmp_a])                   \n\t"
+      "swc1       %[f5],      64(%[tmp_a])                  \n\t"
+      "swc1       %[f0],      68(%[tmp_a])                  \n\t"
+      "swc1       %[f4],      32(%[tmp_a])                  \n\t"
+      "swc1       %[f6],      36(%[tmp_a])                  \n\t"
+      "swc1       %[f1],      96(%[tmp_a])                  \n\t"
+      "swc1       %[f3],      100(%[tmp_a])                 \n\t"
+      "bgtz       %[count],   1b                            \n\t"
+      " addiu     %[tmp_a],   %[tmp_a],     8               \n\t"
+      ".set       pop                                       \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+      : [a] "r"(a), [f9] "f"(f9)
+      : "memory");
   f10 = rdft_w[3];
   f11 = rdft_w[4];
   f12 = rdft_w[5];
   f13 = rdft_wk3ri_first[2];
   f14 = rdft_wk3ri_first[3];
 
-  __asm __volatile (
-    ".set       push                                                    \n\t"
-    ".set       noreorder                                               \n\t"
-    "addiu      %[tmp_a],     %[a],         256                         \n\t"
-    "addiu      %[count],     $zero,        4                           \n\t"
-   "1:                                                                  \n\t"
-    "addiu      %[count],     %[count],     -1                          \n\t"
-    "lwc1       %[f0],        0(%[tmp_a])                               \n\t"
-    "lwc1       %[f2],        32(%[tmp_a])                              \n\t"
-    "lwc1       %[f4],        64(%[tmp_a])                              \n\t"
-    "lwc1       %[f6],        96(%[tmp_a])                              \n\t"
-    "lwc1       %[f1],        4(%[tmp_a])                               \n\t"
-    "lwc1       %[f3],        36(%[tmp_a])                              \n\t"
-    "lwc1       %[f5],        68(%[tmp_a])                              \n\t"
-    "lwc1       %[f7],        100(%[tmp_a])                             \n\t"
-    "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
-    "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
-    "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
-    "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
-    "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
-    "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
-    "sub.s      %[f7],        %[f8],        %[f2]                       \n\t"
-    "add.s      %[f8],        %[f8],        %[f2]                       \n\t"
-    "add.s      %[f2],        %[f1],        %[f4]                       \n\t"
-    "sub.s      %[f1],        %[f1],        %[f4]                       \n\t"
-    "sub.s      %[f4],        %[f6],        %[f3]                       \n\t"
-    "add.s      %[f6],        %[f6],        %[f3]                       \n\t"
-    "sub.s      %[f3],        %[f0],        %[f5]                       \n\t"
-    "add.s      %[f0],        %[f0],        %[f5]                       \n\t"
-    "swc1       %[f8],        0(%[tmp_a])                               \n\t"
-    "swc1       %[f6],        4(%[tmp_a])                               \n\t"
-    "mul.s      %[f5],        %[f9],        %[f7]                       \n\t"
+  __asm __volatile(
+      ".set       push                                                    \n\t"
+      ".set       noreorder                                               \n\t"
+      "addiu      %[tmp_a],     %[a],         256                         \n\t"
+      "addiu      %[count],     $zero,        4                           \n\t"
+      "1:                                                                  \n\t"
+      "addiu      %[count],     %[count],     -1                          \n\t"
+      "lwc1       %[f0],        0(%[tmp_a])                               \n\t"
+      "lwc1       %[f2],        32(%[tmp_a])                              \n\t"
+      "lwc1       %[f4],        64(%[tmp_a])                              \n\t"
+      "lwc1       %[f6],        96(%[tmp_a])                              \n\t"
+      "lwc1       %[f1],        4(%[tmp_a])                               \n\t"
+      "lwc1       %[f3],        36(%[tmp_a])                              \n\t"
+      "lwc1       %[f5],        68(%[tmp_a])                              \n\t"
+      "lwc1       %[f7],        100(%[tmp_a])                             \n\t"
+      "add.s      %[f8],        %[f0],        %[f2]                       \n\t"
+      "sub.s      %[f0],        %[f0],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f4],        %[f6]                       \n\t"
+      "sub.s      %[f4],        %[f4],        %[f6]                       \n\t"
+      "add.s      %[f6],        %[f1],        %[f3]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f3]                       \n\t"
+      "add.s      %[f3],        %[f5],        %[f7]                       \n\t"
+      "sub.s      %[f5],        %[f5],        %[f7]                       \n\t"
+      "sub.s      %[f7],        %[f8],        %[f2]                       \n\t"
+      "add.s      %[f8],        %[f8],        %[f2]                       \n\t"
+      "add.s      %[f2],        %[f1],        %[f4]                       \n\t"
+      "sub.s      %[f1],        %[f1],        %[f4]                       \n\t"
+      "sub.s      %[f4],        %[f6],        %[f3]                       \n\t"
+      "add.s      %[f6],        %[f6],        %[f3]                       \n\t"
+      "sub.s      %[f3],        %[f0],        %[f5]                       \n\t"
+      "add.s      %[f0],        %[f0],        %[f5]                       \n\t"
+      "swc1       %[f8],        0(%[tmp_a])                               \n\t"
+      "swc1       %[f6],        4(%[tmp_a])                               \n\t"
+      "mul.s      %[f5],        %[f9],        %[f7]                       \n\t"
 #if defined(MIPS32_R2_LE)
-    "mul.s      %[f7],        %[f10],       %[f7]                       \n\t"
-    "mul.s      %[f8],        %[f11],       %[f3]                       \n\t"
-    "mul.s      %[f3],        %[f12],       %[f3]                       \n\t"
-    "mul.s      %[f6],        %[f13],       %[f0]                       \n\t"
-    "mul.s      %[f0],        %[f14],       %[f0]                       \n\t"
-    "nmsub.s    %[f5],        %[f5],        %[f10],       %[f4]         \n\t"
-    "madd.s     %[f7],        %[f7],        %[f9],        %[f4]         \n\t"
-    "nmsub.s    %[f8],        %[f8],        %[f12],       %[f2]         \n\t"
-    "madd.s     %[f3],        %[f3],        %[f11],       %[f2]         \n\t"
-    "nmsub.s    %[f6],        %[f6],        %[f14],       %[f1]         \n\t"
-    "madd.s     %[f0],        %[f0],        %[f13],       %[f1]         \n\t"
-    "swc1       %[f5],        64(%[tmp_a])                              \n\t"
-    "swc1       %[f7],        68(%[tmp_a])                              \n\t"
+      "mul.s      %[f7],        %[f10],       %[f7]                       \n\t"
+      "mul.s      %[f8],        %[f11],       %[f3]                       \n\t"
+      "mul.s      %[f3],        %[f12],       %[f3]                       \n\t"
+      "mul.s      %[f6],        %[f13],       %[f0]                       \n\t"
+      "mul.s      %[f0],        %[f14],       %[f0]                       \n\t"
+      "nmsub.s    %[f5],        %[f5],        %[f10],       %[f4]         \n\t"
+      "madd.s     %[f7],        %[f7],        %[f9],        %[f4]         \n\t"
+      "nmsub.s    %[f8],        %[f8],        %[f12],       %[f2]         \n\t"
+      "madd.s     %[f3],        %[f3],        %[f11],       %[f2]         \n\t"
+      "nmsub.s    %[f6],        %[f6],        %[f14],       %[f1]         \n\t"
+      "madd.s     %[f0],        %[f0],        %[f13],       %[f1]         \n\t"
+      "swc1       %[f5],        64(%[tmp_a])                              \n\t"
+      "swc1       %[f7],        68(%[tmp_a])                              \n\t"
 #else
-    "mul.s      %[f8],        %[f10],       %[f4]                       \n\t"
-    "mul.s      %[f4],        %[f9],        %[f4]                       \n\t"
-    "mul.s      %[f7],        %[f10],       %[f7]                       \n\t"
-    "mul.s      %[f6],        %[f11],       %[f3]                       \n\t"
-    "mul.s      %[f3],        %[f12],       %[f3]                       \n\t"
-    "sub.s      %[f5],        %[f5],        %[f8]                       \n\t"
-    "mul.s      %[f8],        %[f12],       %[f2]                       \n\t"
-    "mul.s      %[f2],        %[f11],       %[f2]                       \n\t"
-    "add.s      %[f7],        %[f4],        %[f7]                       \n\t"
-    "mul.s      %[f4],        %[f13],       %[f0]                       \n\t"
-    "mul.s      %[f0],        %[f14],       %[f0]                       \n\t"
-    "sub.s      %[f8],        %[f6],        %[f8]                       \n\t"
-    "mul.s      %[f6],        %[f14],       %[f1]                       \n\t"
-    "mul.s      %[f1],        %[f13],       %[f1]                       \n\t"
-    "add.s      %[f3],        %[f2],        %[f3]                       \n\t"
-    "swc1       %[f5],        64(%[tmp_a])                              \n\t"
-    "swc1       %[f7],        68(%[tmp_a])                              \n\t"
-    "sub.s      %[f6],        %[f4],        %[f6]                       \n\t"
-    "add.s      %[f0],        %[f1],        %[f0]                       \n\t"
+      "mul.s      %[f8],        %[f10],       %[f4]                       \n\t"
+      "mul.s      %[f4],        %[f9],        %[f4]                       \n\t"
+      "mul.s      %[f7],        %[f10],       %[f7]                       \n\t"
+      "mul.s      %[f6],        %[f11],       %[f3]                       \n\t"
+      "mul.s      %[f3],        %[f12],       %[f3]                       \n\t"
+      "sub.s      %[f5],        %[f5],        %[f8]                       \n\t"
+      "mul.s      %[f8],        %[f12],       %[f2]                       \n\t"
+      "mul.s      %[f2],        %[f11],       %[f2]                       \n\t"
+      "add.s      %[f7],        %[f4],        %[f7]                       \n\t"
+      "mul.s      %[f4],        %[f13],       %[f0]                       \n\t"
+      "mul.s      %[f0],        %[f14],       %[f0]                       \n\t"
+      "sub.s      %[f8],        %[f6],        %[f8]                       \n\t"
+      "mul.s      %[f6],        %[f14],       %[f1]                       \n\t"
+      "mul.s      %[f1],        %[f13],       %[f1]                       \n\t"
+      "add.s      %[f3],        %[f2],        %[f3]                       \n\t"
+      "swc1       %[f5],        64(%[tmp_a])                              \n\t"
+      "swc1       %[f7],        68(%[tmp_a])                              \n\t"
+      "sub.s      %[f6],        %[f4],        %[f6]                       \n\t"
+      "add.s      %[f0],        %[f1],        %[f0]                       \n\t"
 #endif
-    "swc1       %[f8],        32(%[tmp_a])                              \n\t"
-    "swc1       %[f3],        36(%[tmp_a])                              \n\t"
-    "swc1       %[f6],        96(%[tmp_a])                              \n\t"
-    "swc1       %[f0],        100(%[tmp_a])                             \n\t"
-    "bgtz       %[count],     1b                                        \n\t"
-    " addiu     %[tmp_a],     %[tmp_a],     8                           \n\t"
-    ".set       pop                                                     \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
-    : [a] "r" (a),  [f9] "f" (f9), [f10] "f" (f10), [f11] "f" (f11),
-      [f12] "f" (f12), [f13] "f" (f13), [f14] "f" (f14)
-    : "memory"
-  );
+      "swc1       %[f8],        32(%[tmp_a])                              \n\t"
+      "swc1       %[f3],        36(%[tmp_a])                              \n\t"
+      "swc1       %[f6],        96(%[tmp_a])                              \n\t"
+      "swc1       %[f0],        100(%[tmp_a])                             \n\t"
+      "bgtz       %[count],     1b                                        \n\t"
+      " addiu     %[tmp_a],     %[tmp_a],     8                           \n\t"
+      ".set       pop                                                     \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+      : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11),
+        [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14)
+      : "memory");
   f11 = rdft_w[6];
   f12 = rdft_w[7];
   f13 = rdft_wk3ri_second[2];
   f14 = rdft_wk3ri_second[3];
-  __asm __volatile (
-    ".set       push                                                       \n\t"
-    ".set       noreorder                                                  \n\t"
-    "addiu      %[tmp_a],       %[a],           384                        \n\t"
-    "addiu      %[count],       $zero,          4                          \n\t"
-   "1:                                                                     \n\t"
-    "addiu      %[count],       %[count],       -1                         \n\t"
-    "lwc1       %[f0],          0(%[tmp_a])                                \n\t"
-    "lwc1       %[f1],          4(%[tmp_a])                                \n\t"
-    "lwc1       %[f2],          32(%[tmp_a])                               \n\t"
-    "lwc1       %[f3],          36(%[tmp_a])                               \n\t"
-    "lwc1       %[f4],          64(%[tmp_a])                               \n\t"
-    "lwc1       %[f5],          68(%[tmp_a])                               \n\t"
-    "lwc1       %[f6],          96(%[tmp_a])                               \n\t"
-    "lwc1       %[f7],          100(%[tmp_a])                              \n\t"
-    "add.s      %[f8],          %[f0],          %[f2]                      \n\t"
-    "sub.s      %[f0],          %[f0],          %[f2]                      \n\t"
-    "add.s      %[f2],          %[f4],          %[f6]                      \n\t"
-    "sub.s      %[f4],          %[f4],          %[f6]                      \n\t"
-    "add.s      %[f6],          %[f1],          %[f3]                      \n\t"
-    "sub.s      %[f1],          %[f1],          %[f3]                      \n\t"
-    "add.s      %[f3],          %[f5],          %[f7]                      \n\t"
-    "sub.s      %[f5],          %[f5],          %[f7]                      \n\t"
-    "sub.s      %[f7],          %[f2],          %[f8]                      \n\t"
-    "add.s      %[f2],          %[f2],          %[f8]                      \n\t"
-    "add.s      %[f8],          %[f1],          %[f4]                      \n\t"
-    "sub.s      %[f1],          %[f1],          %[f4]                      \n\t"
-    "sub.s      %[f4],          %[f3],          %[f6]                      \n\t"
-    "add.s      %[f3],          %[f3],          %[f6]                      \n\t"
-    "sub.s      %[f6],          %[f0],          %[f5]                      \n\t"
-    "add.s      %[f0],          %[f0],          %[f5]                      \n\t"
-    "swc1       %[f2],          0(%[tmp_a])                                \n\t"
-    "swc1       %[f3],          4(%[tmp_a])                                \n\t"
-    "mul.s      %[f5],          %[f10],         %[f7]                      \n\t"
+  __asm __volatile(
+      ".set       push                                                       "
+      "\n\t"
+      ".set       noreorder                                                  "
+      "\n\t"
+      "addiu      %[tmp_a],       %[a],           384                        "
+      "\n\t"
+      "addiu      %[count],       $zero,          4                          "
+      "\n\t"
+      "1:                                                                     "
+      "\n\t"
+      "addiu      %[count],       %[count],       -1                         "
+      "\n\t"
+      "lwc1       %[f0],          0(%[tmp_a])                                "
+      "\n\t"
+      "lwc1       %[f1],          4(%[tmp_a])                                "
+      "\n\t"
+      "lwc1       %[f2],          32(%[tmp_a])                               "
+      "\n\t"
+      "lwc1       %[f3],          36(%[tmp_a])                               "
+      "\n\t"
+      "lwc1       %[f4],          64(%[tmp_a])                               "
+      "\n\t"
+      "lwc1       %[f5],          68(%[tmp_a])                               "
+      "\n\t"
+      "lwc1       %[f6],          96(%[tmp_a])                               "
+      "\n\t"
+      "lwc1       %[f7],          100(%[tmp_a])                              "
+      "\n\t"
+      "add.s      %[f8],          %[f0],          %[f2]                      "
+      "\n\t"
+      "sub.s      %[f0],          %[f0],          %[f2]                      "
+      "\n\t"
+      "add.s      %[f2],          %[f4],          %[f6]                      "
+      "\n\t"
+      "sub.s      %[f4],          %[f4],          %[f6]                      "
+      "\n\t"
+      "add.s      %[f6],          %[f1],          %[f3]                      "
+      "\n\t"
+      "sub.s      %[f1],          %[f1],          %[f3]                      "
+      "\n\t"
+      "add.s      %[f3],          %[f5],          %[f7]                      "
+      "\n\t"
+      "sub.s      %[f5],          %[f5],          %[f7]                      "
+      "\n\t"
+      "sub.s      %[f7],          %[f2],          %[f8]                      "
+      "\n\t"
+      "add.s      %[f2],          %[f2],          %[f8]                      "
+      "\n\t"
+      "add.s      %[f8],          %[f1],          %[f4]                      "
+      "\n\t"
+      "sub.s      %[f1],          %[f1],          %[f4]                      "
+      "\n\t"
+      "sub.s      %[f4],          %[f3],          %[f6]                      "
+      "\n\t"
+      "add.s      %[f3],          %[f3],          %[f6]                      "
+      "\n\t"
+      "sub.s      %[f6],          %[f0],          %[f5]                      "
+      "\n\t"
+      "add.s      %[f0],          %[f0],          %[f5]                      "
+      "\n\t"
+      "swc1       %[f2],          0(%[tmp_a])                                "
+      "\n\t"
+      "swc1       %[f3],          4(%[tmp_a])                                "
+      "\n\t"
+      "mul.s      %[f5],          %[f10],         %[f7]                      "
+      "\n\t"
 #if defined(MIPS32_R2_LE)
-    "mul.s      %[f7],          %[f9],          %[f7]                      \n\t"
-    "mul.s      %[f2],          %[f12],         %[f8]                      \n\t"
-    "mul.s      %[f8],          %[f11],         %[f8]                      \n\t"
-    "mul.s      %[f3],          %[f14],         %[f1]                      \n\t"
-    "mul.s      %[f1],          %[f13],         %[f1]                      \n\t"
-    "madd.s     %[f5],          %[f5],          %[f9],       %[f4]         \n\t"
-    "msub.s     %[f7],          %[f7],          %[f10],      %[f4]         \n\t"
-    "msub.s     %[f2],          %[f2],          %[f11],      %[f6]         \n\t"
-    "madd.s     %[f8],          %[f8],          %[f12],      %[f6]         \n\t"
-    "msub.s     %[f3],          %[f3],          %[f13],      %[f0]         \n\t"
-    "madd.s     %[f1],          %[f1],          %[f14],      %[f0]         \n\t"
-    "swc1       %[f5],          64(%[tmp_a])                               \n\t"
-    "swc1       %[f7],          68(%[tmp_a])                               \n\t"
+      "mul.s      %[f7],          %[f9],          %[f7]                      "
+      "\n\t"
+      "mul.s      %[f2],          %[f12],         %[f8]                      "
+      "\n\t"
+      "mul.s      %[f8],          %[f11],         %[f8]                      "
+      "\n\t"
+      "mul.s      %[f3],          %[f14],         %[f1]                      "
+      "\n\t"
+      "mul.s      %[f1],          %[f13],         %[f1]                      "
+      "\n\t"
+      "madd.s     %[f5],          %[f5],          %[f9],       %[f4]         "
+      "\n\t"
+      "msub.s     %[f7],          %[f7],          %[f10],      %[f4]         "
+      "\n\t"
+      "msub.s     %[f2],          %[f2],          %[f11],      %[f6]         "
+      "\n\t"
+      "madd.s     %[f8],          %[f8],          %[f12],      %[f6]         "
+      "\n\t"
+      "msub.s     %[f3],          %[f3],          %[f13],      %[f0]         "
+      "\n\t"
+      "madd.s     %[f1],          %[f1],          %[f14],      %[f0]         "
+      "\n\t"
+      "swc1       %[f5],          64(%[tmp_a])                               "
+      "\n\t"
+      "swc1       %[f7],          68(%[tmp_a])                               "
+      "\n\t"
 #else
-    "mul.s      %[f2],          %[f9],          %[f4]                      \n\t"
-    "mul.s      %[f4],          %[f10],         %[f4]                      \n\t"
-    "mul.s      %[f7],          %[f9],          %[f7]                      \n\t"
-    "mul.s      %[f3],          %[f11],         %[f6]                      \n\t"
-    "mul.s      %[f6],          %[f12],         %[f6]                      \n\t"
-    "add.s      %[f5],          %[f5],          %[f2]                      \n\t"
-    "sub.s      %[f7],          %[f4],          %[f7]                      \n\t"
-    "mul.s      %[f2],          %[f12],         %[f8]                      \n\t"
-    "mul.s      %[f8],          %[f11],         %[f8]                      \n\t"
-    "mul.s      %[f4],          %[f14],         %[f1]                      \n\t"
-    "mul.s      %[f1],          %[f13],         %[f1]                      \n\t"
-    "sub.s      %[f2],          %[f3],          %[f2]                      \n\t"
-    "mul.s      %[f3],          %[f13],         %[f0]                      \n\t"
-    "mul.s      %[f0],          %[f14],         %[f0]                      \n\t"
-    "add.s      %[f8],          %[f8],          %[f6]                      \n\t"
-    "swc1       %[f5],          64(%[tmp_a])                               \n\t"
-    "swc1       %[f7],          68(%[tmp_a])                               \n\t"
-    "sub.s      %[f3],          %[f3],          %[f4]                      \n\t"
-    "add.s      %[f1],          %[f1],          %[f0]                      \n\t"
+      "mul.s      %[f2],          %[f9],          %[f4]                      "
+      "\n\t"
+      "mul.s      %[f4],          %[f10],         %[f4]                      "
+      "\n\t"
+      "mul.s      %[f7],          %[f9],          %[f7]                      "
+      "\n\t"
+      "mul.s      %[f3],          %[f11],         %[f6]                      "
+      "\n\t"
+      "mul.s      %[f6],          %[f12],         %[f6]                      "
+      "\n\t"
+      "add.s      %[f5],          %[f5],          %[f2]                      "
+      "\n\t"
+      "sub.s      %[f7],          %[f4],          %[f7]                      "
+      "\n\t"
+      "mul.s      %[f2],          %[f12],         %[f8]                      "
+      "\n\t"
+      "mul.s      %[f8],          %[f11],         %[f8]                      "
+      "\n\t"
+      "mul.s      %[f4],          %[f14],         %[f1]                      "
+      "\n\t"
+      "mul.s      %[f1],          %[f13],         %[f1]                      "
+      "\n\t"
+      "sub.s      %[f2],          %[f3],          %[f2]                      "
+      "\n\t"
+      "mul.s      %[f3],          %[f13],         %[f0]                      "
+      "\n\t"
+      "mul.s      %[f0],          %[f14],         %[f0]                      "
+      "\n\t"
+      "add.s      %[f8],          %[f8],          %[f6]                      "
+      "\n\t"
+      "swc1       %[f5],          64(%[tmp_a])                               "
+      "\n\t"
+      "swc1       %[f7],          68(%[tmp_a])                               "
+      "\n\t"
+      "sub.s      %[f3],          %[f3],          %[f4]                      "
+      "\n\t"
+      "add.s      %[f1],          %[f1],          %[f0]                      "
+      "\n\t"
 #endif
-    "swc1       %[f2],          32(%[tmp_a])                               \n\t"
-    "swc1       %[f8],          36(%[tmp_a])                               \n\t"
-    "swc1       %[f3],          96(%[tmp_a])                               \n\t"
-    "swc1       %[f1],          100(%[tmp_a])                              \n\t"
-    "bgtz       %[count],       1b                                         \n\t"
-    " addiu     %[tmp_a],       %[tmp_a],       8                          \n\t"
-    ".set       pop                                                        \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
-    : [a] "r" (a), [f9] "f" (f9), [f10] "f" (f10), [f11] "f" (f11),
-      [f12] "f" (f12), [f13] "f" (f13), [f14] "f" (f14)
-    : "memory"
-  );
+      "swc1       %[f2],          32(%[tmp_a])                               "
+      "\n\t"
+      "swc1       %[f8],          36(%[tmp_a])                               "
+      "\n\t"
+      "swc1       %[f3],          96(%[tmp_a])                               "
+      "\n\t"
+      "swc1       %[f1],          100(%[tmp_a])                              "
+      "\n\t"
+      "bgtz       %[count],       1b                                         "
+      "\n\t"
+      " addiu     %[tmp_a],       %[tmp_a],       8                          "
+      "\n\t"
+      ".set       pop                                                        "
+      "\n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+      : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11),
+        [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14)
+      : "memory");
 }
 
 void cftfsub_128_mips(float* a) {
@@ -815,55 +882,53 @@
   cft1st_128_mips(a);
   cftmdl_128_mips(a);
 
-  __asm __volatile (
-    ".set       push                                      \n\t"
-    ".set       noreorder                                 \n\t"
-    "addiu      %[tmp_a],       %[a],         0           \n\t"
-    "addiu      %[count],       $zero,        16          \n\t"
-   "1:                                                    \n\t"
-    "addiu      %[count],       %[count],     -1          \n\t"
-    "lwc1       %[f0],          0(%[tmp_a])               \n\t"
-    "lwc1       %[f2],          128(%[tmp_a])             \n\t"
-    "lwc1       %[f4],          256(%[tmp_a])             \n\t"
-    "lwc1       %[f6],          384(%[tmp_a])             \n\t"
-    "lwc1       %[f1],          4(%[tmp_a])               \n\t"
-    "lwc1       %[f3],          132(%[tmp_a])             \n\t"
-    "lwc1       %[f5],          260(%[tmp_a])             \n\t"
-    "lwc1       %[f7],          388(%[tmp_a])             \n\t"
-    "add.s      %[f8],          %[f0],        %[f2]       \n\t"
-    "sub.s      %[f0],          %[f0],        %[f2]       \n\t"
-    "add.s      %[f2],          %[f4],        %[f6]       \n\t"
-    "sub.s      %[f4],          %[f4],        %[f6]       \n\t"
-    "add.s      %[f6],          %[f1],        %[f3]       \n\t"
-    "sub.s      %[f1],          %[f1],        %[f3]       \n\t"
-    "add.s      %[f3],          %[f5],        %[f7]       \n\t"
-    "sub.s      %[f5],          %[f5],        %[f7]       \n\t"
-    "add.s      %[f7],          %[f8],        %[f2]       \n\t"
-    "sub.s      %[f8],          %[f8],        %[f2]       \n\t"
-    "add.s      %[f2],          %[f1],        %[f4]       \n\t"
-    "sub.s      %[f1],          %[f1],        %[f4]       \n\t"
-    "add.s      %[f4],          %[f6],        %[f3]       \n\t"
-    "sub.s      %[f6],          %[f6],        %[f3]       \n\t"
-    "sub.s      %[f3],          %[f0],        %[f5]       \n\t"
-    "add.s      %[f0],          %[f0],        %[f5]       \n\t"
-    "swc1       %[f7],          0(%[tmp_a])               \n\t"
-    "swc1       %[f8],          256(%[tmp_a])             \n\t"
-    "swc1       %[f2],          132(%[tmp_a])             \n\t"
-    "swc1       %[f1],          388(%[tmp_a])             \n\t"
-    "swc1       %[f4],          4(%[tmp_a])               \n\t"
-    "swc1       %[f6],          260(%[tmp_a])             \n\t"
-    "swc1       %[f3],          128(%[tmp_a])             \n\t"
-    "swc1       %[f0],          384(%[tmp_a])             \n\t"
-    "bgtz       %[count],       1b                        \n\t"
-    " addiu     %[tmp_a],       %[tmp_a],   8             \n\t"
-    ".set       pop                                       \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a),
-      [count] "=&r" (count)
-    : [a] "r" (a)
-    : "memory"
-  );
+  __asm __volatile(
+      ".set       push                                      \n\t"
+      ".set       noreorder                                 \n\t"
+      "addiu      %[tmp_a],       %[a],         0           \n\t"
+      "addiu      %[count],       $zero,        16          \n\t"
+      "1:                                                    \n\t"
+      "addiu      %[count],       %[count],     -1          \n\t"
+      "lwc1       %[f0],          0(%[tmp_a])               \n\t"
+      "lwc1       %[f2],          128(%[tmp_a])             \n\t"
+      "lwc1       %[f4],          256(%[tmp_a])             \n\t"
+      "lwc1       %[f6],          384(%[tmp_a])             \n\t"
+      "lwc1       %[f1],          4(%[tmp_a])               \n\t"
+      "lwc1       %[f3],          132(%[tmp_a])             \n\t"
+      "lwc1       %[f5],          260(%[tmp_a])             \n\t"
+      "lwc1       %[f7],          388(%[tmp_a])             \n\t"
+      "add.s      %[f8],          %[f0],        %[f2]       \n\t"
+      "sub.s      %[f0],          %[f0],        %[f2]       \n\t"
+      "add.s      %[f2],          %[f4],        %[f6]       \n\t"
+      "sub.s      %[f4],          %[f4],        %[f6]       \n\t"
+      "add.s      %[f6],          %[f1],        %[f3]       \n\t"
+      "sub.s      %[f1],          %[f1],        %[f3]       \n\t"
+      "add.s      %[f3],          %[f5],        %[f7]       \n\t"
+      "sub.s      %[f5],          %[f5],        %[f7]       \n\t"
+      "add.s      %[f7],          %[f8],        %[f2]       \n\t"
+      "sub.s      %[f8],          %[f8],        %[f2]       \n\t"
+      "add.s      %[f2],          %[f1],        %[f4]       \n\t"
+      "sub.s      %[f1],          %[f1],        %[f4]       \n\t"
+      "add.s      %[f4],          %[f6],        %[f3]       \n\t"
+      "sub.s      %[f6],          %[f6],        %[f3]       \n\t"
+      "sub.s      %[f3],          %[f0],        %[f5]       \n\t"
+      "add.s      %[f0],          %[f0],        %[f5]       \n\t"
+      "swc1       %[f7],          0(%[tmp_a])               \n\t"
+      "swc1       %[f8],          256(%[tmp_a])             \n\t"
+      "swc1       %[f2],          132(%[tmp_a])             \n\t"
+      "swc1       %[f1],          388(%[tmp_a])             \n\t"
+      "swc1       %[f4],          4(%[tmp_a])               \n\t"
+      "swc1       %[f6],          260(%[tmp_a])             \n\t"
+      "swc1       %[f3],          128(%[tmp_a])             \n\t"
+      "swc1       %[f0],          384(%[tmp_a])             \n\t"
+      "bgtz       %[count],       1b                        \n\t"
+      " addiu     %[tmp_a],       %[tmp_a],   8             \n\t"
+      ".set       pop                                       \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+      : [a] "r"(a)
+      : "memory");
 }
 
 void cftbsub_128_mips(float* a) {
@@ -873,55 +938,54 @@
   cft1st_128_mips(a);
   cftmdl_128_mips(a);
 
-  __asm __volatile (
-    ".set       push                                        \n\t"
-    ".set       noreorder                                   \n\t"
-    "addiu      %[tmp_a],   %[a],           0               \n\t"
-    "addiu      %[count],   $zero,          16              \n\t"
-   "1:                                                      \n\t"
-    "addiu      %[count],   %[count],       -1              \n\t"
-    "lwc1       %[f0],      0(%[tmp_a])                     \n\t"
-    "lwc1       %[f2],      128(%[tmp_a])                   \n\t"
-    "lwc1       %[f4],      256(%[tmp_a])                   \n\t"
-    "lwc1       %[f6],      384(%[tmp_a])                   \n\t"
-    "lwc1       %[f1],      4(%[tmp_a])                     \n\t"
-    "lwc1       %[f3],      132(%[tmp_a])                   \n\t"
-    "lwc1       %[f5],      260(%[tmp_a])                   \n\t"
-    "lwc1       %[f7],      388(%[tmp_a])                   \n\t"
-    "add.s      %[f8],      %[f0],          %[f2]           \n\t"
-    "sub.s      %[f0],      %[f0],          %[f2]           \n\t"
-    "add.s      %[f2],      %[f4],          %[f6]           \n\t"
-    "sub.s      %[f4],      %[f4],          %[f6]           \n\t"
-    "add.s      %[f6],      %[f1],          %[f3]           \n\t"
-    "sub.s      %[f1],      %[f3],          %[f1]           \n\t"
-    "add.s      %[f3],      %[f5],          %[f7]           \n\t"
-    "sub.s      %[f5],      %[f5],          %[f7]           \n\t"
-    "add.s      %[f7],      %[f8],          %[f2]           \n\t"
-    "sub.s      %[f8],      %[f8],          %[f2]           \n\t"
-    "sub.s      %[f2],      %[f1],          %[f4]           \n\t"
-    "add.s      %[f1],      %[f1],          %[f4]           \n\t"
-    "add.s      %[f4],      %[f3],          %[f6]           \n\t"
-    "sub.s      %[f6],      %[f3],          %[f6]           \n\t"
-    "sub.s      %[f3],      %[f0],          %[f5]           \n\t"
-    "add.s      %[f0],      %[f0],          %[f5]           \n\t"
-    "neg.s      %[f4],      %[f4]                           \n\t"
-    "swc1       %[f7],      0(%[tmp_a])                     \n\t"
-    "swc1       %[f8],      256(%[tmp_a])                   \n\t"
-    "swc1       %[f2],      132(%[tmp_a])                   \n\t"
-    "swc1       %[f1],      388(%[tmp_a])                   \n\t"
-    "swc1       %[f6],      260(%[tmp_a])                   \n\t"
-    "swc1       %[f3],      128(%[tmp_a])                   \n\t"
-    "swc1       %[f0],      384(%[tmp_a])                   \n\t"
-    "swc1       %[f4],       4(%[tmp_a])                     \n\t"
-    "bgtz       %[count],   1b                              \n\t"
-    " addiu     %[tmp_a],   %[tmp_a],       8               \n\t"
-    ".set       pop                                         \n\t"
-    : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
-      [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
-      [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
-    : [a] "r" (a)
-    : "memory"
-  );
+  __asm __volatile(
+      ".set       push                                        \n\t"
+      ".set       noreorder                                   \n\t"
+      "addiu      %[tmp_a],   %[a],           0               \n\t"
+      "addiu      %[count],   $zero,          16              \n\t"
+      "1:                                                      \n\t"
+      "addiu      %[count],   %[count],       -1              \n\t"
+      "lwc1       %[f0],      0(%[tmp_a])                     \n\t"
+      "lwc1       %[f2],      128(%[tmp_a])                   \n\t"
+      "lwc1       %[f4],      256(%[tmp_a])                   \n\t"
+      "lwc1       %[f6],      384(%[tmp_a])                   \n\t"
+      "lwc1       %[f1],      4(%[tmp_a])                     \n\t"
+      "lwc1       %[f3],      132(%[tmp_a])                   \n\t"
+      "lwc1       %[f5],      260(%[tmp_a])                   \n\t"
+      "lwc1       %[f7],      388(%[tmp_a])                   \n\t"
+      "add.s      %[f8],      %[f0],          %[f2]           \n\t"
+      "sub.s      %[f0],      %[f0],          %[f2]           \n\t"
+      "add.s      %[f2],      %[f4],          %[f6]           \n\t"
+      "sub.s      %[f4],      %[f4],          %[f6]           \n\t"
+      "add.s      %[f6],      %[f1],          %[f3]           \n\t"
+      "sub.s      %[f1],      %[f3],          %[f1]           \n\t"
+      "add.s      %[f3],      %[f5],          %[f7]           \n\t"
+      "sub.s      %[f5],      %[f5],          %[f7]           \n\t"
+      "add.s      %[f7],      %[f8],          %[f2]           \n\t"
+      "sub.s      %[f8],      %[f8],          %[f2]           \n\t"
+      "sub.s      %[f2],      %[f1],          %[f4]           \n\t"
+      "add.s      %[f1],      %[f1],          %[f4]           \n\t"
+      "add.s      %[f4],      %[f3],          %[f6]           \n\t"
+      "sub.s      %[f6],      %[f3],          %[f6]           \n\t"
+      "sub.s      %[f3],      %[f0],          %[f5]           \n\t"
+      "add.s      %[f0],      %[f0],          %[f5]           \n\t"
+      "neg.s      %[f4],      %[f4]                           \n\t"
+      "swc1       %[f7],      0(%[tmp_a])                     \n\t"
+      "swc1       %[f8],      256(%[tmp_a])                   \n\t"
+      "swc1       %[f2],      132(%[tmp_a])                   \n\t"
+      "swc1       %[f1],      388(%[tmp_a])                   \n\t"
+      "swc1       %[f6],      260(%[tmp_a])                   \n\t"
+      "swc1       %[f3],      128(%[tmp_a])                   \n\t"
+      "swc1       %[f0],      384(%[tmp_a])                   \n\t"
+      "swc1       %[f4],       4(%[tmp_a])                     \n\t"
+      "bgtz       %[count],   1b                              \n\t"
+      " addiu     %[tmp_a],   %[tmp_a],       8               \n\t"
+      ".set       pop                                         \n\t"
+      : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+        [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+        [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+      : [a] "r"(a)
+      : "memory");
 }
 
 void rftfsub_128_mips(float* a) {
@@ -931,254 +995,252 @@
   float* a2 = &a[126];
   const float* c1 = &c[1];
   const float* c2 = &c[31];
-  float f1, f2, f3 ,f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
+  float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
   int count;
 
-  __asm __volatile (
-    ".set      push                                             \n\t"
-    ".set      noreorder                                        \n\t"
-    "lwc1      %[f6],       0(%[c2])                            \n\t"
-    "lwc1      %[f1],       0(%[a1])                            \n\t"
-    "lwc1      %[f2],       0(%[a2])                            \n\t"
-    "lwc1      %[f3],       4(%[a1])                            \n\t"
-    "lwc1      %[f4],       4(%[a2])                            \n\t"
-    "lwc1      %[f5],       0(%[c1])                            \n\t"
-    "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
-    "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
-    "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
-    "addiu     %[count],    $zero,        15                    \n\t"
-    "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
-    "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
+  __asm __volatile(
+      ".set      push                                             \n\t"
+      ".set      noreorder                                        \n\t"
+      "lwc1      %[f6],       0(%[c2])                            \n\t"
+      "lwc1      %[f1],       0(%[a1])                            \n\t"
+      "lwc1      %[f2],       0(%[a2])                            \n\t"
+      "lwc1      %[f3],       4(%[a1])                            \n\t"
+      "lwc1      %[f4],       4(%[a2])                            \n\t"
+      "lwc1      %[f5],       0(%[c1])                            \n\t"
+      "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
+      "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
+      "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
+      "addiu     %[count],    $zero,        15                    \n\t"
+      "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
+      "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
 #if !defined(MIPS32_R2_LE)
-    "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
-    "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
-    "sub.s     %[f9],       %[f9],        %[f8]                 \n\t"
-    "add.s     %[f6],       %[f6],        %[f5]                 \n\t"
+      "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
+      "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
+      "sub.s     %[f9],       %[f9],        %[f8]                 \n\t"
+      "add.s     %[f6],       %[f6],        %[f5]                 \n\t"
 #else
-    "nmsub.s   %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
-    "madd.s    %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
+      "nmsub.s   %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
+      "madd.s    %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
 #endif
-    "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
-    "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
-    "sub.s     %[f3],       %[f3],        %[f6]                 \n\t"
-    "sub.s     %[f4],       %[f4],        %[f6]                 \n\t"
-    "swc1      %[f1],       0(%[a1])                            \n\t"
-    "swc1      %[f2],       0(%[a2])                            \n\t"
-    "swc1      %[f3],       4(%[a1])                            \n\t"
-    "swc1      %[f4],       4(%[a2])                            \n\t"
-    "addiu     %[a1],       %[a1],        8                     \n\t"
-    "addiu     %[a2],       %[a2],        -8                    \n\t"
-    "addiu     %[c1],       %[c1],        4                     \n\t"
-    "addiu     %[c2],       %[c2],        -4                    \n\t"
-   "1:                                                          \n\t"
-    "lwc1      %[f6],       0(%[c2])                            \n\t"
-    "lwc1      %[f1],       0(%[a1])                            \n\t"
-    "lwc1      %[f2],       0(%[a2])                            \n\t"
-    "lwc1      %[f3],       4(%[a1])                            \n\t"
-    "lwc1      %[f4],       4(%[a2])                            \n\t"
-    "lwc1      %[f5],       0(%[c1])                            \n\t"
-    "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
-    "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
-    "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
-    "lwc1      %[f10],      -4(%[c2])                           \n\t"
-    "lwc1      %[f11],      8(%[a1])                            \n\t"
-    "lwc1      %[f12],      -8(%[a2])                           \n\t"
-    "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
-    "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
+      "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
+      "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
+      "sub.s     %[f3],       %[f3],        %[f6]                 \n\t"
+      "sub.s     %[f4],       %[f4],        %[f6]                 \n\t"
+      "swc1      %[f1],       0(%[a1])                            \n\t"
+      "swc1      %[f2],       0(%[a2])                            \n\t"
+      "swc1      %[f3],       4(%[a1])                            \n\t"
+      "swc1      %[f4],       4(%[a2])                            \n\t"
+      "addiu     %[a1],       %[a1],        8                     \n\t"
+      "addiu     %[a2],       %[a2],        -8                    \n\t"
+      "addiu     %[c1],       %[c1],        4                     \n\t"
+      "addiu     %[c2],       %[c2],        -4                    \n\t"
+      "1:                                                          \n\t"
+      "lwc1      %[f6],       0(%[c2])                            \n\t"
+      "lwc1      %[f1],       0(%[a1])                            \n\t"
+      "lwc1      %[f2],       0(%[a2])                            \n\t"
+      "lwc1      %[f3],       4(%[a1])                            \n\t"
+      "lwc1      %[f4],       4(%[a2])                            \n\t"
+      "lwc1      %[f5],       0(%[c1])                            \n\t"
+      "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
+      "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
+      "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
+      "lwc1      %[f10],      -4(%[c2])                           \n\t"
+      "lwc1      %[f11],      8(%[a1])                            \n\t"
+      "lwc1      %[f12],      -8(%[a2])                           \n\t"
+      "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
+      "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
 #if !defined(MIPS32_R2_LE)
-    "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
-    "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
-    "lwc1      %[f13],      12(%[a1])                           \n\t"
-    "lwc1      %[f14],      -4(%[a2])                           \n\t"
-    "lwc1      %[f15],      4(%[c1])                            \n\t"
-    "sub.s     %[f9],       %[f9],        %[f8]                 \n\t"
-    "add.s     %[f6],       %[f6],        %[f5]                 \n\t"
+      "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
+      "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
+      "lwc1      %[f13],      12(%[a1])                           \n\t"
+      "lwc1      %[f14],      -4(%[a2])                           \n\t"
+      "lwc1      %[f15],      4(%[c1])                            \n\t"
+      "sub.s     %[f9],       %[f9],        %[f8]                 \n\t"
+      "add.s     %[f6],       %[f6],        %[f5]                 \n\t"
 #else
-    "lwc1      %[f13],      12(%[a1])                           \n\t"
-    "lwc1      %[f14],      -4(%[a2])                           \n\t"
-    "lwc1      %[f15],      4(%[c1])                            \n\t"
-    "nmsub.s   %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
-    "madd.s    %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
+      "lwc1      %[f13],      12(%[a1])                           \n\t"
+      "lwc1      %[f14],      -4(%[a2])                           \n\t"
+      "lwc1      %[f15],      4(%[c1])                            \n\t"
+      "nmsub.s   %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
+      "madd.s    %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
 #endif
-    "sub.s     %[f10],      %[f0],        %[f10]                \n\t"
-    "sub.s     %[f5],       %[f11],       %[f12]                \n\t"
-    "add.s     %[f7],       %[f13],       %[f14]                \n\t"
-    "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
-    "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
-    "sub.s     %[f3],       %[f3],        %[f6]                 \n\t"
-    "mul.s     %[f8],       %[f10],       %[f5]                 \n\t"
-    "mul.s     %[f10],      %[f10],       %[f7]                 \n\t"
+      "sub.s     %[f10],      %[f0],        %[f10]                \n\t"
+      "sub.s     %[f5],       %[f11],       %[f12]                \n\t"
+      "add.s     %[f7],       %[f13],       %[f14]                \n\t"
+      "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
+      "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
+      "sub.s     %[f3],       %[f3],        %[f6]                 \n\t"
+      "mul.s     %[f8],       %[f10],       %[f5]                 \n\t"
+      "mul.s     %[f10],      %[f10],       %[f7]                 \n\t"
 #if !defined(MIPS32_R2_LE)
-    "mul.s     %[f9],       %[f15],       %[f7]                 \n\t"
-    "mul.s     %[f15],      %[f15],       %[f5]                 \n\t"
-    "sub.s     %[f4],       %[f4],        %[f6]                 \n\t"
-    "swc1      %[f1],       0(%[a1])                            \n\t"
-    "swc1      %[f2],       0(%[a2])                            \n\t"
-    "sub.s     %[f8],       %[f8],        %[f9]                 \n\t"
-    "add.s     %[f10],      %[f10],       %[f15]                \n\t"
+      "mul.s     %[f9],       %[f15],       %[f7]                 \n\t"
+      "mul.s     %[f15],      %[f15],       %[f5]                 \n\t"
+      "sub.s     %[f4],       %[f4],        %[f6]                 \n\t"
+      "swc1      %[f1],       0(%[a1])                            \n\t"
+      "swc1      %[f2],       0(%[a2])                            \n\t"
+      "sub.s     %[f8],       %[f8],        %[f9]                 \n\t"
+      "add.s     %[f10],      %[f10],       %[f15]                \n\t"
 #else
-    "swc1      %[f1],       0(%[a1])                            \n\t"
-    "swc1      %[f2],       0(%[a2])                            \n\t"
-    "sub.s     %[f4],       %[f4],        %[f6]                 \n\t"
-    "nmsub.s   %[f8],       %[f8],        %[f15],     %[f7]     \n\t"
-    "madd.s    %[f10],      %[f10],       %[f15],     %[f5]     \n\t"
+      "swc1      %[f1],       0(%[a1])                            \n\t"
+      "swc1      %[f2],       0(%[a2])                            \n\t"
+      "sub.s     %[f4],       %[f4],        %[f6]                 \n\t"
+      "nmsub.s   %[f8],       %[f8],        %[f15],     %[f7]     \n\t"
+      "madd.s    %[f10],      %[f10],       %[f15],     %[f5]     \n\t"
 #endif
-    "swc1      %[f3],       4(%[a1])                            \n\t"
-    "swc1      %[f4],       4(%[a2])                            \n\t"
-    "sub.s     %[f11],      %[f11],       %[f8]                 \n\t"
-    "add.s     %[f12],      %[f12],       %[f8]                 \n\t"
-    "sub.s     %[f13],      %[f13],       %[f10]                \n\t"
-    "sub.s     %[f14],      %[f14],       %[f10]                \n\t"
-    "addiu     %[c2],       %[c2],        -8                    \n\t"
-    "addiu     %[c1],       %[c1],        8                     \n\t"
-    "swc1      %[f11],      8(%[a1])                            \n\t"
-    "swc1      %[f12],      -8(%[a2])                           \n\t"
-    "swc1      %[f13],      12(%[a1])                           \n\t"
-    "swc1      %[f14],      -4(%[a2])                           \n\t"
-    "addiu     %[a1],       %[a1],        16                    \n\t"
-    "addiu     %[count],    %[count],     -1                    \n\t"
-    "bgtz      %[count],    1b                                  \n\t"
-    " addiu    %[a2],       %[a2],        -16                   \n\t"
-    ".set      pop                                              \n\t"
-    : [a1] "+r" (a1), [a2] "+r" (a2), [c1] "+r" (c1), [c2] "+r" (c2),
-      [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3), [f4] "=&f" (f4),
-      [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
-      [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11), [f12] "=&f" (f12),
-      [f13] "=&f" (f13), [f14] "=&f" (f14), [f15] "=&f" (f15),
-      [count] "=&r" (count)
-    : [f0] "f" (f0)
-    : "memory"
-  );
+      "swc1      %[f3],       4(%[a1])                            \n\t"
+      "swc1      %[f4],       4(%[a2])                            \n\t"
+      "sub.s     %[f11],      %[f11],       %[f8]                 \n\t"
+      "add.s     %[f12],      %[f12],       %[f8]                 \n\t"
+      "sub.s     %[f13],      %[f13],       %[f10]                \n\t"
+      "sub.s     %[f14],      %[f14],       %[f10]                \n\t"
+      "addiu     %[c2],       %[c2],        -8                    \n\t"
+      "addiu     %[c1],       %[c1],        8                     \n\t"
+      "swc1      %[f11],      8(%[a1])                            \n\t"
+      "swc1      %[f12],      -8(%[a2])                           \n\t"
+      "swc1      %[f13],      12(%[a1])                           \n\t"
+      "swc1      %[f14],      -4(%[a2])                           \n\t"
+      "addiu     %[a1],       %[a1],        16                    \n\t"
+      "addiu     %[count],    %[count],     -1                    \n\t"
+      "bgtz      %[count],    1b                                  \n\t"
+      " addiu    %[a2],       %[a2],        -16                   \n\t"
+      ".set      pop                                              \n\t"
+      : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2),
+        [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4),
+        [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8),
+        [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12),
+        [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15),
+        [count] "=&r"(count)
+      : [f0] "f"(f0)
+      : "memory");
 }
 
 void rftbsub_128_mips(float* a) {
-  const float *c = rdft_w + 32;
+  const float* c = rdft_w + 32;
   const float f0 = 0.5f;
   float* a1 = &a[2];
   float* a2 = &a[126];
   const float* c1 = &c[1];
   const float* c2 = &c[31];
-  float f1, f2, f3 ,f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
+  float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
   int count;
 
   a[1] = -a[1];
   a[65] = -a[65];
 
-  __asm __volatile (
-    ".set      push                                             \n\t"
-    ".set      noreorder                                        \n\t"
-    "lwc1      %[f6],       0(%[c2])                            \n\t"
-    "lwc1      %[f1],       0(%[a1])                            \n\t"
-    "lwc1      %[f2],       0(%[a2])                            \n\t"
-    "lwc1      %[f3],       4(%[a1])                            \n\t"
-    "lwc1      %[f4],       4(%[a2])                            \n\t"
-    "lwc1      %[f5],       0(%[c1])                            \n\t"
-    "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
-    "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
-    "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
-    "addiu     %[count],    $zero,        15                    \n\t"
-    "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
-    "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
+  __asm __volatile(
+      ".set      push                                             \n\t"
+      ".set      noreorder                                        \n\t"
+      "lwc1      %[f6],       0(%[c2])                            \n\t"
+      "lwc1      %[f1],       0(%[a1])                            \n\t"
+      "lwc1      %[f2],       0(%[a2])                            \n\t"
+      "lwc1      %[f3],       4(%[a1])                            \n\t"
+      "lwc1      %[f4],       4(%[a2])                            \n\t"
+      "lwc1      %[f5],       0(%[c1])                            \n\t"
+      "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
+      "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
+      "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
+      "addiu     %[count],    $zero,        15                    \n\t"
+      "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
+      "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
 #if !defined(MIPS32_R2_LE)
-    "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
-    "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
-    "add.s     %[f9],       %[f9],        %[f8]                 \n\t"
-    "sub.s     %[f6],       %[f6],        %[f5]                 \n\t"
+      "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
+      "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
+      "add.s     %[f9],       %[f9],        %[f8]                 \n\t"
+      "sub.s     %[f6],       %[f6],        %[f5]                 \n\t"
 #else
-    "madd.s    %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
-    "nmsub.s   %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
+      "madd.s    %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
+      "nmsub.s   %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
 #endif
-    "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
-    "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
-    "sub.s     %[f3],       %[f6],        %[f3]                 \n\t"
-    "sub.s     %[f4],       %[f6],        %[f4]                 \n\t"
-    "swc1      %[f1],       0(%[a1])                            \n\t"
-    "swc1      %[f2],       0(%[a2])                            \n\t"
-    "swc1      %[f3],       4(%[a1])                            \n\t"
-    "swc1      %[f4],       4(%[a2])                            \n\t"
-    "addiu     %[a1],       %[a1],        8                     \n\t"
-    "addiu     %[a2],       %[a2],        -8                    \n\t"
-    "addiu     %[c1],       %[c1],        4                     \n\t"
-    "addiu     %[c2],       %[c2],        -4                    \n\t"
-   "1:                                                          \n\t"
-    "lwc1      %[f6],       0(%[c2])                            \n\t"
-    "lwc1      %[f1],       0(%[a1])                            \n\t"
-    "lwc1      %[f2],       0(%[a2])                            \n\t"
-    "lwc1      %[f3],       4(%[a1])                            \n\t"
-    "lwc1      %[f4],       4(%[a2])                            \n\t"
-    "lwc1      %[f5],       0(%[c1])                            \n\t"
-    "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
-    "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
-    "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
-    "lwc1      %[f10],      -4(%[c2])                           \n\t"
-    "lwc1      %[f11],      8(%[a1])                            \n\t"
-    "lwc1      %[f12],      -8(%[a2])                           \n\t"
-    "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
-    "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
+      "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
+      "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
+      "sub.s     %[f3],       %[f6],        %[f3]                 \n\t"
+      "sub.s     %[f4],       %[f6],        %[f4]                 \n\t"
+      "swc1      %[f1],       0(%[a1])                            \n\t"
+      "swc1      %[f2],       0(%[a2])                            \n\t"
+      "swc1      %[f3],       4(%[a1])                            \n\t"
+      "swc1      %[f4],       4(%[a2])                            \n\t"
+      "addiu     %[a1],       %[a1],        8                     \n\t"
+      "addiu     %[a2],       %[a2],        -8                    \n\t"
+      "addiu     %[c1],       %[c1],        4                     \n\t"
+      "addiu     %[c2],       %[c2],        -4                    \n\t"
+      "1:                                                          \n\t"
+      "lwc1      %[f6],       0(%[c2])                            \n\t"
+      "lwc1      %[f1],       0(%[a1])                            \n\t"
+      "lwc1      %[f2],       0(%[a2])                            \n\t"
+      "lwc1      %[f3],       4(%[a1])                            \n\t"
+      "lwc1      %[f4],       4(%[a2])                            \n\t"
+      "lwc1      %[f5],       0(%[c1])                            \n\t"
+      "sub.s     %[f6],       %[f0],        %[f6]                 \n\t"
+      "sub.s     %[f7],       %[f1],        %[f2]                 \n\t"
+      "add.s     %[f8],       %[f3],        %[f4]                 \n\t"
+      "lwc1      %[f10],      -4(%[c2])                           \n\t"
+      "lwc1      %[f11],      8(%[a1])                            \n\t"
+      "lwc1      %[f12],      -8(%[a2])                           \n\t"
+      "mul.s     %[f9],       %[f6],        %[f7]                 \n\t"
+      "mul.s     %[f6],       %[f6],        %[f8]                 \n\t"
 #if !defined(MIPS32_R2_LE)
-    "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
-    "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
-    "lwc1      %[f13],      12(%[a1])                           \n\t"
-    "lwc1      %[f14],      -4(%[a2])                           \n\t"
-    "lwc1      %[f15],      4(%[c1])                            \n\t"
-    "add.s     %[f9],       %[f9],        %[f8]                 \n\t"
-    "sub.s     %[f6],       %[f6],        %[f5]                 \n\t"
+      "mul.s     %[f8],       %[f5],        %[f8]                 \n\t"
+      "mul.s     %[f5],       %[f5],        %[f7]                 \n\t"
+      "lwc1      %[f13],      12(%[a1])                           \n\t"
+      "lwc1      %[f14],      -4(%[a2])                           \n\t"
+      "lwc1      %[f15],      4(%[c1])                            \n\t"
+      "add.s     %[f9],       %[f9],        %[f8]                 \n\t"
+      "sub.s     %[f6],       %[f6],        %[f5]                 \n\t"
 #else
-    "lwc1      %[f13],      12(%[a1])                           \n\t"
-    "lwc1      %[f14],      -4(%[a2])                           \n\t"
-    "lwc1      %[f15],      4(%[c1])                            \n\t"
-    "madd.s    %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
-    "nmsub.s   %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
+      "lwc1      %[f13],      12(%[a1])                           \n\t"
+      "lwc1      %[f14],      -4(%[a2])                           \n\t"
+      "lwc1      %[f15],      4(%[c1])                            \n\t"
+      "madd.s    %[f9],       %[f9],        %[f5],      %[f8]     \n\t"
+      "nmsub.s   %[f6],       %[f6],        %[f5],      %[f7]     \n\t"
 #endif
-    "sub.s     %[f10],      %[f0],        %[f10]                \n\t"
-    "sub.s     %[f5],       %[f11],       %[f12]                \n\t"
-    "add.s     %[f7],       %[f13],       %[f14]                \n\t"
-    "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
-    "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
-    "sub.s     %[f3],       %[f6],        %[f3]                 \n\t"
-    "mul.s     %[f8],       %[f10],       %[f5]                 \n\t"
-    "mul.s     %[f10],      %[f10],       %[f7]                 \n\t"
+      "sub.s     %[f10],      %[f0],        %[f10]                \n\t"
+      "sub.s     %[f5],       %[f11],       %[f12]                \n\t"
+      "add.s     %[f7],       %[f13],       %[f14]                \n\t"
+      "sub.s     %[f1],       %[f1],        %[f9]                 \n\t"
+      "add.s     %[f2],       %[f2],        %[f9]                 \n\t"
+      "sub.s     %[f3],       %[f6],        %[f3]                 \n\t"
+      "mul.s     %[f8],       %[f10],       %[f5]                 \n\t"
+      "mul.s     %[f10],      %[f10],       %[f7]                 \n\t"
 #if !defined(MIPS32_R2_LE)
-    "mul.s     %[f9],       %[f15],       %[f7]                 \n\t"
-    "mul.s     %[f15],      %[f15],       %[f5]                 \n\t"
-    "sub.s     %[f4],       %[f6],        %[f4]                 \n\t"
-    "swc1      %[f1],       0(%[a1])                            \n\t"
-    "swc1      %[f2],       0(%[a2])                            \n\t"
-    "add.s     %[f8],       %[f8],        %[f9]                 \n\t"
-    "sub.s     %[f10],      %[f10],       %[f15]                \n\t"
+      "mul.s     %[f9],       %[f15],       %[f7]                 \n\t"
+      "mul.s     %[f15],      %[f15],       %[f5]                 \n\t"
+      "sub.s     %[f4],       %[f6],        %[f4]                 \n\t"
+      "swc1      %[f1],       0(%[a1])                            \n\t"
+      "swc1      %[f2],       0(%[a2])                            \n\t"
+      "add.s     %[f8],       %[f8],        %[f9]                 \n\t"
+      "sub.s     %[f10],      %[f10],       %[f15]                \n\t"
 #else
-    "swc1      %[f1],       0(%[a1])                            \n\t"
-    "swc1      %[f2],       0(%[a2])                            \n\t"
-    "sub.s     %[f4],       %[f6],        %[f4]                 \n\t"
-    "madd.s    %[f8],       %[f8],        %[f15],     %[f7]     \n\t"
-    "nmsub.s   %[f10],      %[f10],       %[f15],     %[f5]     \n\t"
+      "swc1      %[f1],       0(%[a1])                            \n\t"
+      "swc1      %[f2],       0(%[a2])                            \n\t"
+      "sub.s     %[f4],       %[f6],        %[f4]                 \n\t"
+      "madd.s    %[f8],       %[f8],        %[f15],     %[f7]     \n\t"
+      "nmsub.s   %[f10],      %[f10],       %[f15],     %[f5]     \n\t"
 #endif
-    "swc1      %[f3],       4(%[a1])                            \n\t"
-    "swc1      %[f4],       4(%[a2])                            \n\t"
-    "sub.s     %[f11],      %[f11],       %[f8]                 \n\t"
-    "add.s     %[f12],      %[f12],       %[f8]                 \n\t"
-    "sub.s     %[f13],      %[f10],       %[f13]                \n\t"
-    "sub.s     %[f14],      %[f10],       %[f14]                \n\t"
-    "addiu     %[c2],       %[c2],        -8                    \n\t"
-    "addiu     %[c1],       %[c1],        8                     \n\t"
-    "swc1      %[f11],      8(%[a1])                            \n\t"
-    "swc1      %[f12],      -8(%[a2])                           \n\t"
-    "swc1      %[f13],      12(%[a1])                           \n\t"
-    "swc1      %[f14],      -4(%[a2])                           \n\t"
-    "addiu     %[a1],       %[a1],        16                    \n\t"
-    "addiu     %[count],    %[count],     -1                    \n\t"
-    "bgtz      %[count],    1b                                  \n\t"
-    " addiu    %[a2],       %[a2],        -16                   \n\t"
-    ".set      pop                                              \n\t"
-    : [a1] "+r" (a1), [a2] "+r" (a2), [c1] "+r" (c1), [c2] "+r" (c2),
-      [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3), [f4] "=&f" (f4),
-      [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
-      [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11), [f12] "=&f" (f12),
-      [f13] "=&f" (f13), [f14] "=&f" (f14), [f15] "=&f" (f15),
-      [count] "=&r" (count)
-    : [f0] "f" (f0)
-    : "memory"
-  );
+      "swc1      %[f3],       4(%[a1])                            \n\t"
+      "swc1      %[f4],       4(%[a2])                            \n\t"
+      "sub.s     %[f11],      %[f11],       %[f8]                 \n\t"
+      "add.s     %[f12],      %[f12],       %[f8]                 \n\t"
+      "sub.s     %[f13],      %[f10],       %[f13]                \n\t"
+      "sub.s     %[f14],      %[f10],       %[f14]                \n\t"
+      "addiu     %[c2],       %[c2],        -8                    \n\t"
+      "addiu     %[c1],       %[c1],        8                     \n\t"
+      "swc1      %[f11],      8(%[a1])                            \n\t"
+      "swc1      %[f12],      -8(%[a2])                           \n\t"
+      "swc1      %[f13],      12(%[a1])                           \n\t"
+      "swc1      %[f14],      -4(%[a2])                           \n\t"
+      "addiu     %[a1],       %[a1],        16                    \n\t"
+      "addiu     %[count],    %[count],     -1                    \n\t"
+      "bgtz      %[count],    1b                                  \n\t"
+      " addiu    %[a2],       %[a2],        -16                   \n\t"
+      ".set      pop                                              \n\t"
+      : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2),
+        [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4),
+        [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8),
+        [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12),
+        [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15),
+        [count] "=&r"(count)
+      : [f0] "f"(f0)
+      : "memory");
 }
 #endif
 
diff --git a/modules/audio_processing/vad/BUILD.gn b/modules/audio_processing/vad/BUILD.gn
index f9f5974..e16b57f 100644
--- a/modules/audio_processing/vad/BUILD.gn
+++ b/modules/audio_processing/vad/BUILD.gn
@@ -39,18 +39,9 @@
     "../../../audio/utility:audio_frame_operations",
     "../../../common_audio",
     "../../../common_audio:common_audio_c",
+    "../../../common_audio:fft4g",
     "../../../rtc_base:checks",
-    "../../audio_coding:isac",
-  ]
-}
-
-rtc_source_set("vad_with_level") {
-  sources = [
-    "vad_with_level.h",
-  ]
-  deps = [
-    "..:audio_frame_view",
-    "../../../api:array_view",
+    "../../audio_coding:isac_vad",
   ]
 }
 
diff --git a/modules/audio_processing/vad/gmm_unittest.cc b/modules/audio_processing/vad/gmm_unittest.cc
index dfc8855..d895afa 100644
--- a/modules/audio_processing/vad/gmm_unittest.cc
+++ b/modules/audio_processing/vad/gmm_unittest.cc
@@ -37,10 +37,10 @@
   voice_gmm.covar_inverse = &kVoiceGmmCovarInverse[0][0][0];
 
   // Test vectors. These are the mean of the GMM means.
-  const double kXVoice[kVoiceGmmDim] = {
-      -1.35893162459863, 602.862491970368, 178.022069191324};
-  const double kXNoise[kNoiseGmmDim] = {
-      -2.33443722724409, 2827.97828765184, 141.114178166812};
+  const double kXVoice[kVoiceGmmDim] = {-1.35893162459863, 602.862491970368,
+                                        178.022069191324};
+  const double kXNoise[kNoiseGmmDim] = {-2.33443722724409, 2827.97828765184,
+                                        141.114178166812};
 
   // Expected pdf values. These values are computed in MATLAB using EvalGmm.m
   const double kPdfNoise = 1.88904409403101e-07;
diff --git a/modules/audio_processing/vad/noise_gmm_tables.h b/modules/audio_processing/vad/noise_gmm_tables.h
index c07dade..1556277 100644
--- a/modules/audio_processing/vad/noise_gmm_tables.h
+++ b/modules/audio_processing/vad/noise_gmm_tables.h
@@ -70,16 +70,8 @@
     {-2.30193040814533e+00, 1.43953696546439e+03, 7.04085275122649e+01}};
 
 static const double kNoiseGmmWeights[kNoiseGmmNumMixtures] = {
-    -1.09422832086193e+01,
-    -1.10847897513425e+01,
-    -1.36767587732187e+01,
-    -1.79789356118641e+01,
-    -1.42830169160894e+01,
-    -1.56500228061379e+01,
-    -1.83124990950113e+01,
-    -1.69979436177477e+01,
-    -1.12329424387828e+01,
-    -1.41311785780639e+01,
-    -1.47171861448585e+01,
-    -1.35963362781839e+01};
+    -1.09422832086193e+01, -1.10847897513425e+01, -1.36767587732187e+01,
+    -1.79789356118641e+01, -1.42830169160894e+01, -1.56500228061379e+01,
+    -1.83124990950113e+01, -1.69979436177477e+01, -1.12329424387828e+01,
+    -1.41311785780639e+01, -1.47171861448585e+01, -1.35963362781839e+01};
 #endif  // MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
diff --git a/modules/audio_processing/vad/pitch_based_vad.cc b/modules/audio_processing/vad/pitch_based_vad.cc
index 240ec63..025ef20 100644
--- a/modules/audio_processing/vad/pitch_based_vad.cc
+++ b/modules/audio_processing/vad/pitch_based_vad.cc
@@ -13,9 +13,9 @@
 #include <math.h>
 #include <string.h>
 
-#include "modules/audio_processing/vad/vad_circular_buffer.h"
 #include "modules/audio_processing/vad/common.h"
 #include "modules/audio_processing/vad/noise_gmm_tables.h"
+#include "modules/audio_processing/vad/vad_circular_buffer.h"
 #include "modules/audio_processing/vad/voice_gmm_tables.h"
 
 namespace webrtc {
@@ -58,8 +58,7 @@
   voice_gmm_.covar_inverse = &kVoiceGmmCovarInverse[0][0][0];
 }
 
-PitchBasedVad::~PitchBasedVad() {
-}
+PitchBasedVad::~PitchBasedVad() {}
 
 int PitchBasedVad::VoicingProbability(const AudioFeatures& features,
                                       double* p_combined) {
diff --git a/modules/audio_processing/vad/pitch_internal_unittest.cc b/modules/audio_processing/vad/pitch_internal_unittest.cc
index c1fde10..19c2e1a 100644
--- a/modules/audio_processing/vad/pitch_internal_unittest.cc
+++ b/modules/audio_processing/vad/pitch_internal_unittest.cc
@@ -26,12 +26,12 @@
   double lags[] = {90, 111, 122, 50};
 
   // Expected outputs
-  double expected_log_pitch_gain[] = {
-      -0.541212549898316, -1.45672279045507, -0.80471895621705};
+  double expected_log_pitch_gain[] = {-0.541212549898316, -1.45672279045507,
+                                      -0.80471895621705};
   double expected_log_old_gain = log(gains[kNumInputParameters - 1]);
 
-  double expected_pitch_lag_hz[] = {
-      92.3076923076923, 70.9010339734121, 93.0232558139535};
+  double expected_pitch_lag_hz[] = {92.3076923076923, 70.9010339734121,
+                                    93.0232558139535};
   double expected_old_lag = lags[kNumInputParameters - 1];
 
   double log_pitch_gain[kNumOutputParameters];
diff --git a/modules/audio_processing/vad/pole_zero_filter.cc b/modules/audio_processing/vad/pole_zero_filter.cc
index fa56a3c..b9967d7 100644
--- a/modules/audio_processing/vad/pole_zero_filter.cc
+++ b/modules/audio_processing/vad/pole_zero_filter.cc
@@ -53,7 +53,8 @@
 }
 
 template <typename T>
-static float FilterArPast(const T* past, size_t order,
+static float FilterArPast(const T* past,
+                          size_t order,
                           const float* coefficients) {
   float sum = 0.0f;
   size_t past_index = order - 1;
diff --git a/modules/audio_processing/vad/standalone_vad.cc b/modules/audio_processing/vad/standalone_vad.cc
index 2640892..813d375 100644
--- a/modules/audio_processing/vad/standalone_vad.cc
+++ b/modules/audio_processing/vad/standalone_vad.cc
@@ -21,8 +21,7 @@
 static const int kDefaultStandaloneVadMode = 3;
 
 StandaloneVad::StandaloneVad(VadInst* vad)
-    : vad_(vad), buffer_(), index_(0), mode_(kDefaultStandaloneVadMode) {
-}
+    : vad_(vad), buffer_(), index_(0), mode_(kDefaultStandaloneVadMode) {}
 
 StandaloneVad::~StandaloneVad() {
   WebRtcVad_Free(vad_);
diff --git a/modules/audio_processing/vad/standalone_vad.h b/modules/audio_processing/vad/standalone_vad.h
index b85de0a..3f6eb7f 100644
--- a/modules/audio_processing/vad/standalone_vad.h
+++ b/modules/audio_processing/vad/standalone_vad.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
 #define MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
 
-#include "modules/audio_processing/vad/common.h"
 #include "common_audio/vad/include/webrtc_vad.h"
+#include "modules/audio_processing/vad/common.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
diff --git a/modules/audio_processing/vad/vad_audio_proc.cc b/modules/audio_processing/vad/vad_audio_proc.cc
index 6b559d1..e9007c6 100644
--- a/modules/audio_processing/vad/vad_audio_proc.cc
+++ b/modules/audio_processing/vad/vad_audio_proc.cc
@@ -20,8 +20,8 @@
 #include "modules/audio_processing/vad/vad_audio_proc_internal.h"
 #include "rtc_base/checks.h"
 extern "C" {
-#include "modules/audio_coding/codecs/isac/main/source/codec.h"
-#include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
+#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
 #include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
 #include "modules/audio_coding/codecs/isac/main/source/structs.h"
 }
@@ -67,8 +67,7 @@
   WebRtcIsac_InitPitchAnalysis(pitch_analysis_handle_.get());
 }
 
-VadAudioProc::~VadAudioProc() {
-}
+VadAudioProc::~VadAudioProc() {}
 
 void VadAudioProc::ResetBuffer() {
   memcpy(audio_buffer_, &audio_buffer_[kNumSamplesToProcess],
diff --git a/modules/audio_processing/vad/vad_audio_proc_internal.h b/modules/audio_processing/vad/vad_audio_proc_internal.h
index ab1e636..915524f 100644
--- a/modules/audio_processing/vad/vad_audio_proc_internal.h
+++ b/modules/audio_processing/vad/vad_audio_proc_internal.h
@@ -14,23 +14,10 @@
 namespace webrtc {
 
 // These values should match MATLAB counterparts for unit-tests to pass.
-static const double kCorrWeight[] = {1.000000,
-                                     0.985000,
-                                     0.970225,
-                                     0.955672,
-                                     0.941337,
-                                     0.927217,
-                                     0.913308,
-                                     0.899609,
-                                     0.886115,
-                                     0.872823,
-                                     0.859730,
-                                     0.846834,
-                                     0.834132,
-                                     0.821620,
-                                     0.809296,
-                                     0.797156,
-                                     0.785199};
+static const double kCorrWeight[] = {
+    1.000000, 0.985000, 0.970225, 0.955672, 0.941337, 0.927217,
+    0.913308, 0.899609, 0.886115, 0.872823, 0.859730, 0.846834,
+    0.834132, 0.821620, 0.809296, 0.797156, 0.785199};
 
 static const double kLpcAnalWin[] = {
     0.00000000, 0.01314436, 0.02628645, 0.03942400, 0.05255473, 0.06567639,
@@ -75,11 +62,9 @@
     0.06567639, 0.05255473, 0.03942400, 0.02628645, 0.01314436, 0.00000000};
 
 static const size_t kFilterOrder = 2;
-static const float kCoeffNumerator[kFilterOrder + 1] = {0.974827f,
-                                                        -1.949650f,
+static const float kCoeffNumerator[kFilterOrder + 1] = {0.974827f, -1.949650f,
                                                         0.974827f};
-static const float kCoeffDenominator[kFilterOrder + 1] = {1.0f,
-                                                          -1.971999f,
+static const float kCoeffDenominator[kFilterOrder + 1] = {1.0f, -1.971999f,
                                                           0.972457f};
 
 static_assert(kFilterOrder + 1 ==
diff --git a/modules/audio_processing/vad/vad_circular_buffer.cc b/modules/audio_processing/vad/vad_circular_buffer.cc
index 3c4d5ad..31f14d7 100644
--- a/modules/audio_processing/vad/vad_circular_buffer.cc
+++ b/modules/audio_processing/vad/vad_circular_buffer.cc
@@ -19,11 +19,9 @@
       is_full_(false),
       index_(0),
       buffer_size_(buffer_size),
-      sum_(0) {
-}
+      sum_(0) {}
 
-VadCircularBuffer::~VadCircularBuffer() {
-}
+VadCircularBuffer::~VadCircularBuffer() {}
 
 void VadCircularBuffer::Reset() {
   is_full_ = false;
diff --git a/modules/audio_processing/vad/vad_with_level.h b/modules/audio_processing/vad/vad_with_level.h
deleted file mode 100644
index 9ad4d17..0000000
--- a/modules/audio_processing/vad/vad_with_level.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  Copyright (c) 2018 The WebRTC 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 MODULES_AUDIO_PROCESSING_VAD_VAD_WITH_LEVEL_H_
-#define MODULES_AUDIO_PROCESSING_VAD_VAD_WITH_LEVEL_H_
-
-#include "api/array_view.h"
-#include "modules/audio_processing/include/audio_frame_view.h"
-
-namespace webrtc {
-class VadWithLevel {
- public:
-  struct LevelAndProbability {
-    constexpr LevelAndProbability(float prob, float rms, float peak)
-        : speech_probability(prob),
-          speech_rms_dbfs(rms),
-          speech_peak_dbfs(peak) {}
-    LevelAndProbability() = default;
-    float speech_probability = 0;
-    float speech_rms_dbfs = 0;  // Root mean square in decibels to full-scale.
-    float speech_peak_dbfs = 0;
-  };
-
-  // TODO(webrtc:7494): This is a stub. Add implementation.
-  rtc::ArrayView<const LevelAndProbability> AnalyzeFrame(
-      AudioFrameView<const float> frame) {
-    return {nullptr, 0};
-  }
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_VAD_VAD_WITH_LEVEL_H_
diff --git a/modules/audio_processing/vad/voice_activity_detector.cc b/modules/audio_processing/vad/voice_activity_detector.cc
index 66a704f..f0d34c6 100644
--- a/modules/audio_processing/vad/voice_activity_detector.cc
+++ b/modules/audio_processing/vad/voice_activity_detector.cc
@@ -27,8 +27,7 @@
 
 VoiceActivityDetector::VoiceActivityDetector()
     : last_voice_probability_(kDefaultVoiceValue),
-      standalone_vad_(StandaloneVad::Create()) {
-}
+      standalone_vad_(StandaloneVad::Create()) {}
 
 VoiceActivityDetector::~VoiceActivityDetector() = default;
 
diff --git a/modules/audio_processing/vad/voice_activity_detector.h b/modules/audio_processing/vad/voice_activity_detector.h
index 0079cb2..e424ac1 100644
--- a/modules/audio_processing/vad/voice_activity_detector.h
+++ b/modules/audio_processing/vad/voice_activity_detector.h
@@ -15,10 +15,10 @@
 #include <vector>
 
 #include "common_audio/resampler/include/resampler.h"
-#include "modules/audio_processing/vad/vad_audio_proc.h"
 #include "modules/audio_processing/vad/common.h"
 #include "modules/audio_processing/vad/pitch_based_vad.h"
 #include "modules/audio_processing/vad/standalone_vad.h"
+#include "modules/audio_processing/vad/vad_audio_proc.h"
 
 namespace webrtc {
 
diff --git a/modules/audio_processing/vad/voice_gmm_tables.h b/modules/audio_processing/vad/voice_gmm_tables.h
index 29cc7d6..ef4ad7e 100644
--- a/modules/audio_processing/vad/voice_gmm_tables.h
+++ b/modules/audio_processing/vad/voice_gmm_tables.h
@@ -70,16 +70,8 @@
     {-7.29187507662854e-01, 5.22717685022855e+02, 1.16377942283991e+02}};
 
 static const double kVoiceGmmWeights[kVoiceGmmNumMixtures] = {
-    -1.39789694361035e+01,
-    -1.19527720202104e+01,
-    -1.32396317929055e+01,
-    -1.09436815209238e+01,
-    -1.13440027478149e+01,
-    -1.12200721834504e+01,
-    -1.02537324043693e+01,
-    -1.60789861938302e+01,
-    -1.03394494048344e+01,
-    -1.83207938586818e+01,
-    -1.31186044948288e+01,
-    -9.52479998673554e+00};
+    -1.39789694361035e+01, -1.19527720202104e+01, -1.32396317929055e+01,
+    -1.09436815209238e+01, -1.13440027478149e+01, -1.12200721834504e+01,
+    -1.02537324043693e+01, -1.60789861938302e+01, -1.03394494048344e+01,
+    -1.83207938586818e+01, -1.31186044948288e+01, -9.52479998673554e+00};
 #endif  // MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
diff --git a/modules/audio_processing/voice_detection_impl.cc b/modules/audio_processing/voice_detection_impl.cc
index 5ee0c7b..9280be1 100644
--- a/modules/audio_processing/voice_detection_impl.cc
+++ b/modules/audio_processing/voice_detection_impl.cc
@@ -23,10 +23,9 @@
     int error = WebRtcVad_Init(state_);
     RTC_DCHECK_EQ(0, error);
   }
-  ~Vad() {
-    WebRtcVad_Free(state_);
-  }
+  ~Vad() { WebRtcVad_Free(state_); }
   VadInst* state() { return state_; }
+
  private:
   VadInst* state_ = nullptr;
   RTC_DISALLOW_COPY_AND_ASSIGN(Vad);
@@ -65,9 +64,9 @@
 
   RTC_DCHECK_GE(160, audio->num_frames_per_band());
   // TODO(ajm): concatenate data in frame buffer here.
-  int vad_ret = WebRtcVad_Process(vad_->state(), sample_rate_hz_,
-                                  audio->mixed_low_pass_data(),
-                                  frame_size_samples_);
+  int vad_ret =
+      WebRtcVad_Process(vad_->state(), sample_rate_hz_,
+                        audio->mixed_low_pass_data(), frame_size_samples_);
   if (vad_ret == 0) {
     stream_has_voice_ = false;
     audio->set_activity(AudioFrame::kVadPassive);
@@ -103,7 +102,7 @@
 bool VoiceDetectionImpl::stream_has_voice() const {
   rtc::CritScope cs(crit_);
   // TODO(ajm): enable this assertion?
-  //RTC_DCHECK(using_external_vad_ || is_component_enabled());
+  // RTC_DCHECK(using_external_vad_ || is_component_enabled());
   return stream_has_voice_;
 }
 
@@ -142,7 +141,7 @@
 
 int VoiceDetectionImpl::set_frame_size_ms(int size) {
   rtc::CritScope cs(crit_);
-  RTC_DCHECK_EQ(10, size); // TODO(ajm): remove when supported.
+  RTC_DCHECK_EQ(10, size);  // TODO(ajm): remove when supported.
   frame_size_ms_ = size;
   Initialize(sample_rate_hz_);
   return AudioProcessing::kNoError;
diff --git a/modules/include/module_common_types.h b/modules/include/module_common_types.h
index 1c174a7..47fd3c2 100644
--- a/modules/include/module_common_types.h
+++ b/modules/include/module_common_types.h
@@ -17,15 +17,14 @@
 #include <algorithm>
 #include <limits>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "api/rtp_headers.h"
+#include "api/transport/network_types.h"
 #include "api/video/video_rotation.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/include/module_common_types_public.h"
 #include "modules/include/module_fec_types.h"
-#include "modules/video_coding/codecs/h264/include/h264_globals.h"
-#include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
-#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
+#include "modules/rtp_rtcp/source/rtp_video_header.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/deprecation.h"
 #include "rtc_base/numerics/safe_conversions.h"
@@ -34,55 +33,16 @@
 
 namespace webrtc {
 
-struct RTPAudioHeader {
-  uint8_t numEnergy;                  // number of valid entries in arrOfEnergy
-  uint8_t arrOfEnergy[kRtpCsrcSize];  // one energy byte (0-9) per channel
-  bool isCNG;                         // is this CNG
-  size_t channel;                     // number of channels 2 = stereo
-};
-
-enum RtpVideoCodecTypes {
-  kRtpVideoNone = 0,
-  kRtpVideoGeneric = 1,
-  kRtpVideoVp8 = 2,
-  kRtpVideoVp9 = 3,
-  kRtpVideoH264 = 4
-};
-
-union RTPVideoTypeHeader {
-  RTPVideoHeaderVP8 VP8;
-  RTPVideoHeaderVP9 VP9;
-  RTPVideoHeaderH264 H264;
-};
-
-// Since RTPVideoHeader is used as a member of a union, it can't have a
-// non-trivial default constructor.
-struct RTPVideoHeader {
-  uint16_t width;  // size
-  uint16_t height;
-  VideoRotation rotation;
-
-  PlayoutDelay playout_delay;
-
-  VideoContentType content_type;
-
-  VideoSendTiming video_timing;
-
-  bool is_first_packet_in_frame;
-  uint8_t simulcastIdx;  // Index if the simulcast encoder creating
-                         // this frame, 0 if not using simulcast.
-  RtpVideoCodecTypes codec;
-  RTPVideoTypeHeader codecHeader;
-};
-union RTPTypeHeader {
-  RTPAudioHeader Audio;
-  RTPVideoHeader Video;
-};
+// TODO(nisse): Deprecated, use webrtc::VideoCodecType instead.
+using RtpVideoCodecTypes = VideoCodecType;
 
 struct WebRtcRTPHeader {
+  RTPVideoHeader& video_header() { return video; }
+  const RTPVideoHeader& video_header() const { return video; }
+  RTPVideoHeader video;
+
   RTPHeader header;
   FrameType frameType;
-  RTPTypeHeader type;
   // NTP time of the capture time in local timebase in milliseconds.
   int64_t ntp_time_ms;
 };
@@ -189,8 +149,7 @@
         memset(fragmentationOffset + oldVectorSize, 0,
                sizeof(size_t) * (size16 - oldVectorSize));
         // copy old values
-        memcpy(fragmentationOffset, oldOffsets,
-               sizeof(size_t) * oldVectorSize);
+        memcpy(fragmentationOffset, oldOffsets, sizeof(size_t) * oldVectorSize);
         delete[] oldOffsets;
       }
       // length
@@ -199,8 +158,7 @@
         fragmentationLength = new size_t[size16];
         memset(fragmentationLength + oldVectorSize, 0,
                sizeof(size_t) * (size16 - oldVectorSize));
-        memcpy(fragmentationLength, oldLengths,
-               sizeof(size_t) * oldVectorSize);
+        memcpy(fragmentationLength, oldLengths, sizeof(size_t) * oldVectorSize);
         delete[] oldLengths;
       }
       // time diff
@@ -273,29 +231,32 @@
   virtual ~CallStatsObserver() {}
 };
 
-struct PacedPacketInfo {
-  PacedPacketInfo() {}
-  PacedPacketInfo(int probe_cluster_id,
-                  int probe_cluster_min_probes,
-                  int probe_cluster_min_bytes)
-      : probe_cluster_id(probe_cluster_id),
-        probe_cluster_min_probes(probe_cluster_min_probes),
-        probe_cluster_min_bytes(probe_cluster_min_bytes) {}
+// Interface used by NackModule and JitterBuffer.
+class NackSender {
+ public:
+  virtual void SendNack(const std::vector<uint16_t>& sequence_numbers) = 0;
 
-  bool operator==(const PacedPacketInfo& rhs) const {
-    return send_bitrate_bps == rhs.send_bitrate_bps &&
-           probe_cluster_id == rhs.probe_cluster_id &&
-           probe_cluster_min_probes == rhs.probe_cluster_min_probes &&
-           probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
-  }
-
-  static constexpr int kNotAProbe = -1;
-  int send_bitrate_bps = -1;
-  int probe_cluster_id = kNotAProbe;
-  int probe_cluster_min_probes = -1;
-  int probe_cluster_min_bytes = -1;
+ protected:
+  virtual ~NackSender() {}
 };
 
+// Interface used by NackModule and JitterBuffer.
+class KeyFrameRequestSender {
+ public:
+  virtual void RequestKeyFrame() = 0;
+
+ protected:
+  virtual ~KeyFrameRequestSender() {}
+};
+
+// Used to indicate if a received packet contain a complete NALU (or equivalent)
+enum VCMNaluCompleteness {
+  kNaluUnset = 0,     // Packet has not been filled.
+  kNaluComplete = 1,  // Packet can be decoded as is.
+  kNaluStart,         // Packet contain beginning of NALU
+  kNaluIncomplete,    // Packet is not beginning or end of NALU
+  kNaluEnd,           // Packet is the end of a NALU
+};
 }  // namespace webrtc
 
 #endif  // MODULES_INCLUDE_MODULE_COMMON_TYPES_H_
diff --git a/modules/include/module_common_types_public.h b/modules/include/module_common_types_public.h
index 2fbb49a..2afd9af 100644
--- a/modules/include/module_common_types_public.h
+++ b/modules/include/module_common_types_public.h
@@ -13,7 +13,7 @@
 
 #include <limits>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
@@ -68,9 +68,7 @@
   }
 
   // Only update the internal state to the specified last (unwrapped) value.
-  void UpdateLast(int64_t last_value) {
-    last_value_ = last_value;
-  }
+  void UpdateLast(int64_t last_value) { last_value_ = last_value; }
 
   // Unwrap the value and update the internal state.
   int64_t Unwrap(U value) {
@@ -80,7 +78,7 @@
   }
 
  private:
-  rtc::Optional<int64_t> last_value_;
+  absl::optional<int64_t> last_value_;
 };
 
 using SequenceNumberUnwrapper = Unwrapper<uint16_t>;
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
new file mode 100644
index 0000000..da546cd
--- /dev/null
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -0,0 +1,450 @@
+# Copyright (c) 2014 The WebRTC 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.
+
+import("../../webrtc.gni")
+
+rtc_source_set("rtp_rtcp_format") {
+  public = [
+    "include/rtp_cvo.h",
+    "include/rtp_header_extension_map.h",
+    "include/rtp_rtcp_defines.h",
+    "source/byte_io.h",
+    "source/rtcp_packet.h",
+    "source/rtcp_packet/app.h",
+    "source/rtcp_packet/bye.h",
+    "source/rtcp_packet/common_header.h",
+    "source/rtcp_packet/compound_packet.h",
+    "source/rtcp_packet/dlrr.h",
+    "source/rtcp_packet/extended_jitter_report.h",
+    "source/rtcp_packet/extended_reports.h",
+    "source/rtcp_packet/fir.h",
+    "source/rtcp_packet/nack.h",
+    "source/rtcp_packet/pli.h",
+    "source/rtcp_packet/psfb.h",
+    "source/rtcp_packet/rapid_resync_request.h",
+    "source/rtcp_packet/receiver_report.h",
+    "source/rtcp_packet/remb.h",
+    "source/rtcp_packet/report_block.h",
+    "source/rtcp_packet/rrtr.h",
+    "source/rtcp_packet/rtpfb.h",
+    "source/rtcp_packet/sdes.h",
+    "source/rtcp_packet/sender_report.h",
+    "source/rtcp_packet/target_bitrate.h",
+    "source/rtcp_packet/tmmb_item.h",
+    "source/rtcp_packet/tmmbn.h",
+    "source/rtcp_packet/tmmbr.h",
+    "source/rtcp_packet/transport_feedback.h",
+    "source/rtcp_packet/voip_metric.h",
+    "source/rtp_generic_frame_descriptor.h",
+    "source/rtp_generic_frame_descriptor_extension.h",
+    "source/rtp_header_extensions.h",
+    "source/rtp_packet.h",
+    "source/rtp_packet_received.h",
+    "source/rtp_packet_to_send.h",
+  ]
+  sources = [
+    "include/rtp_rtcp_defines.cc",
+    "source/rtcp_packet.cc",
+    "source/rtcp_packet/app.cc",
+    "source/rtcp_packet/bye.cc",
+    "source/rtcp_packet/common_header.cc",
+    "source/rtcp_packet/compound_packet.cc",
+    "source/rtcp_packet/dlrr.cc",
+    "source/rtcp_packet/extended_jitter_report.cc",
+    "source/rtcp_packet/extended_reports.cc",
+    "source/rtcp_packet/fir.cc",
+    "source/rtcp_packet/nack.cc",
+    "source/rtcp_packet/pli.cc",
+    "source/rtcp_packet/psfb.cc",
+    "source/rtcp_packet/rapid_resync_request.cc",
+    "source/rtcp_packet/receiver_report.cc",
+    "source/rtcp_packet/remb.cc",
+    "source/rtcp_packet/report_block.cc",
+    "source/rtcp_packet/rrtr.cc",
+    "source/rtcp_packet/rtpfb.cc",
+    "source/rtcp_packet/sdes.cc",
+    "source/rtcp_packet/sender_report.cc",
+    "source/rtcp_packet/target_bitrate.cc",
+    "source/rtcp_packet/tmmb_item.cc",
+    "source/rtcp_packet/tmmbn.cc",
+    "source/rtcp_packet/tmmbr.cc",
+    "source/rtcp_packet/transport_feedback.cc",
+    "source/rtcp_packet/voip_metric.cc",
+    "source/rtp_generic_frame_descriptor.cc",
+    "source/rtp_generic_frame_descriptor_extension.cc",
+    "source/rtp_header_extension_map.cc",
+    "source/rtp_header_extensions.cc",
+    "source/rtp_packet.cc",
+    "source/rtp_packet_received.cc",
+    "source/rtp_packet_to_send.cc",
+  ]
+
+  deps = [
+    "..:module_api",
+    "../..:webrtc_common",
+    "../../:typedefs",
+    "../../api:array_view",
+    "../../api:libjingle_peerconnection_api",
+    "../../api/audio_codecs:audio_codecs_api",
+    "../../api/video:video_frame",
+    "../../common_video",
+    "../../rtc_base:checks",
+    "../../rtc_base:deprecation",
+    "../../rtc_base:rtc_base_approved",
+    "../../system_wrappers",
+    "//third_party/abseil-cpp/absl/types:optional",
+    "//third_party/abseil-cpp/absl/types:variant",
+  ]
+}
+
+rtc_static_library("rtp_rtcp") {
+  visibility = [ "*" ]
+  sources = [
+    "include/flexfec_receiver.h",
+    "include/flexfec_sender.h",
+    "include/receive_statistics.h",
+    "include/remote_ntp_time_estimator.h",
+    "include/rtp_header_parser.h",
+    "include/rtp_payload_registry.h",
+    "include/rtp_receiver.h",
+    "include/rtp_rtcp.h",
+    "include/ulpfec_receiver.h",
+    "source/dtmf_queue.cc",
+    "source/dtmf_queue.h",
+    "source/fec_private_tables_bursty.cc",
+    "source/fec_private_tables_bursty.h",
+    "source/fec_private_tables_random.cc",
+    "source/fec_private_tables_random.h",
+    "source/flexfec_header_reader_writer.cc",
+    "source/flexfec_header_reader_writer.h",
+    "source/flexfec_receiver.cc",
+    "source/flexfec_sender.cc",
+    "source/forward_error_correction.cc",
+    "source/forward_error_correction.h",
+    "source/forward_error_correction_internal.cc",
+    "source/forward_error_correction_internal.h",
+    "source/packet_loss_stats.cc",
+    "source/packet_loss_stats.h",
+    "source/playout_delay_oracle.cc",
+    "source/playout_delay_oracle.h",
+    "source/receive_statistics_impl.cc",
+    "source/receive_statistics_impl.h",
+    "source/remote_ntp_time_estimator.cc",
+    "source/rtcp_nack_stats.cc",
+    "source/rtcp_nack_stats.h",
+    "source/rtcp_receiver.cc",
+    "source/rtcp_receiver.h",
+    "source/rtcp_sender.cc",
+    "source/rtcp_sender.h",
+    "source/rtp_format.cc",
+    "source/rtp_format.h",
+    "source/rtp_format_h264.cc",
+    "source/rtp_format_h264.h",
+    "source/rtp_format_video_generic.cc",
+    "source/rtp_format_video_generic.h",
+    "source/rtp_format_vp8.cc",
+    "source/rtp_format_vp8.h",
+    "source/rtp_format_vp9.cc",
+    "source/rtp_format_vp9.h",
+    "source/rtp_header_parser.cc",
+    "source/rtp_packet_history.cc",
+    "source/rtp_packet_history.h",
+    "source/rtp_payload_registry.cc",
+    "source/rtp_receiver_audio.cc",
+    "source/rtp_receiver_audio.h",
+    "source/rtp_receiver_impl.cc",
+    "source/rtp_receiver_impl.h",
+    "source/rtp_receiver_strategy.cc",
+    "source/rtp_receiver_strategy.h",
+    "source/rtp_receiver_video.cc",
+    "source/rtp_receiver_video.h",
+    "source/rtp_rtcp_config.h",
+    "source/rtp_rtcp_impl.cc",
+    "source/rtp_rtcp_impl.h",
+    "source/rtp_sender.cc",
+    "source/rtp_sender.h",
+    "source/rtp_sender_audio.cc",
+    "source/rtp_sender_audio.h",
+    "source/rtp_sender_video.cc",
+    "source/rtp_sender_video.h",
+    "source/rtp_utility.cc",
+    "source/rtp_utility.h",
+    "source/time_util.cc",
+    "source/time_util.h",
+    "source/tmmbr_help.cc",
+    "source/tmmbr_help.h",
+    "source/ulpfec_generator.cc",
+    "source/ulpfec_generator.h",
+    "source/ulpfec_header_reader_writer.cc",
+    "source/ulpfec_header_reader_writer.h",
+    "source/ulpfec_receiver_impl.cc",
+    "source/ulpfec_receiver_impl.h",
+  ]
+
+  if (rtc_enable_bwe_test_logging) {
+    defines = [ "BWE_TEST_LOGGING_COMPILE_TIME_ENABLE=1" ]
+  } else {
+    defines = [ "BWE_TEST_LOGGING_COMPILE_TIME_ENABLE=0" ]
+  }
+
+  deps = [
+    ":rtp_rtcp_format",
+    "..:module_api",
+    "../..:webrtc_common",
+    "../../:typedefs",
+    "../../api:array_view",
+    "../../api:libjingle_peerconnection_api",
+    "../../api:transport_api",
+    "../../api/audio_codecs:audio_codecs_api",
+    "../../api/video:video_bitrate_allocation",
+    "../../api/video_codecs:video_codecs_api",
+    "../../common_video",
+    "../../logging:rtc_event_audio",
+    "../../logging:rtc_event_log_api",
+    "../../logging:rtc_event_rtp_rtcp",
+    "../../rtc_base:checks",
+    "../../rtc_base:deprecation",
+    "../../rtc_base:gtest_prod",
+    "../../rtc_base:rate_limiter",
+    "../../rtc_base:rtc_base_approved",
+    "../../rtc_base:rtc_numerics",
+    "../../rtc_base:safe_minmax",
+    "../../rtc_base:sequenced_task_checker",
+    "../../rtc_base:stringutils",
+    "../../rtc_base/system:fallthrough",
+    "../../rtc_base/time:timestamp_extrapolator",
+    "../../system_wrappers",
+    "../../system_wrappers:field_trial_api",
+    "../../system_wrappers:metrics_api",
+    "../audio_coding:audio_format_conversion",
+    "../remote_bitrate_estimator",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
+rtc_source_set("rtcp_transceiver") {
+  visibility = [ "*" ]
+  public = [
+    "source/rtcp_transceiver.h",
+    "source/rtcp_transceiver_config.h",
+    "source/rtcp_transceiver_impl.h",
+  ]
+  sources = [
+    "source/rtcp_transceiver.cc",
+    "source/rtcp_transceiver_config.cc",
+    "source/rtcp_transceiver_impl.cc",
+  ]
+  deps = [
+    ":rtp_rtcp",
+    ":rtp_rtcp_format",
+    "../../:webrtc_common",
+    "../../api:array_view",
+    "../../api:libjingle_peerconnection_api",
+    "../../api:transport_api",
+    "../../api/video:video_bitrate_allocation",
+    "../../rtc_base:checks",
+    "../../rtc_base:rtc_base_approved",
+    "../../rtc_base:rtc_task_queue",
+    "../../rtc_base:weak_ptr",
+    "../../system_wrappers",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
+rtc_source_set("rtp_video_header") {
+  visibility = [ "*" ]
+  sources = [
+    "source/rtp_video_header.cc",
+    "source/rtp_video_header.h",
+  ]
+  deps = [
+    "../../:webrtc_common",
+    "../../api/video:video_frame",
+    "../../modules/video_coding:codec_globals_headers",
+    "//third_party/abseil-cpp/absl/types:variant",
+  ]
+}
+
+rtc_source_set("fec_test_helper") {
+  testonly = true
+  sources = [
+    "source/fec_test_helper.cc",
+    "source/fec_test_helper.h",
+  ]
+  deps = [
+    ":rtp_rtcp",
+    ":rtp_rtcp_format",
+    "..:module_api",
+    "../../rtc_base:checks",
+    "../../rtc_base:rtc_base_approved",
+  ]
+}
+
+rtc_source_set("mock_rtp_rtcp") {
+  testonly = true
+  sources = [
+    "mocks/mock_recovered_packet_receiver.cc",
+    "mocks/mock_rtcp_bandwidth_observer.cc",
+    "mocks/mock_rtcp_rtt_stats.cc",
+    "mocks/mock_rtp_rtcp.cc",
+  ]
+  public = [
+    "mocks/mock_recovered_packet_receiver.h",
+    "mocks/mock_rtcp_bandwidth_observer.h",
+    "mocks/mock_rtcp_rtt_stats.h",
+    "mocks/mock_rtp_rtcp.h",
+  ]
+  deps = [
+    ":rtp_rtcp",
+    ":rtp_rtcp_format",
+    "..:module_api",
+    "../../api/video:video_bitrate_allocation",
+    "../../rtc_base:checks",
+    "../../rtc_base:rtc_base_approved",
+    "../../test:test_support",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
+if (rtc_include_tests) {
+  rtc_executable("test_packet_masks_metrics") {
+    testonly = true
+
+    sources = [
+      "test/testFec/average_residual_loss_xor_codes.h",
+      "test/testFec/test_packet_masks_metrics.cc",
+    ]
+
+    deps = [
+      ":rtp_rtcp",
+      "../../test:fileutils",
+      "../../test:test_main",
+      "//testing/gtest",
+    ]
+  }  # test_packet_masks_metrics
+
+  rtc_source_set("rtp_rtcp_modules_tests") {
+    testonly = true
+
+    sources = [
+      "test/testFec/test_fec.cc",
+    ]
+    deps = [
+      ":rtp_rtcp",
+      ":rtp_rtcp_format",
+      "../../rtc_base:rtc_base_approved",
+      "../../test:fileutils",
+      "../../test:test_support",
+    ]
+  }
+
+  rtc_source_set("rtp_rtcp_unittests") {
+    testonly = true
+
+    sources = [
+      "source/byte_io_unittest.cc",
+      "source/fec_private_tables_bursty_unittest.cc",
+      "source/flexfec_header_reader_writer_unittest.cc",
+      "source/flexfec_receiver_unittest.cc",
+      "source/flexfec_sender_unittest.cc",
+      "source/nack_rtx_unittest.cc",
+      "source/packet_loss_stats_unittest.cc",
+      "source/playout_delay_oracle_unittest.cc",
+      "source/receive_statistics_unittest.cc",
+      "source/remote_ntp_time_estimator_unittest.cc",
+      "source/rtcp_nack_stats_unittest.cc",
+      "source/rtcp_packet/app_unittest.cc",
+      "source/rtcp_packet/bye_unittest.cc",
+      "source/rtcp_packet/common_header_unittest.cc",
+      "source/rtcp_packet/compound_packet_unittest.cc",
+      "source/rtcp_packet/dlrr_unittest.cc",
+      "source/rtcp_packet/extended_jitter_report_unittest.cc",
+      "source/rtcp_packet/extended_reports_unittest.cc",
+      "source/rtcp_packet/fir_unittest.cc",
+      "source/rtcp_packet/nack_unittest.cc",
+      "source/rtcp_packet/pli_unittest.cc",
+      "source/rtcp_packet/rapid_resync_request_unittest.cc",
+      "source/rtcp_packet/receiver_report_unittest.cc",
+      "source/rtcp_packet/remb_unittest.cc",
+      "source/rtcp_packet/report_block_unittest.cc",
+      "source/rtcp_packet/rrtr_unittest.cc",
+      "source/rtcp_packet/sdes_unittest.cc",
+      "source/rtcp_packet/sender_report_unittest.cc",
+      "source/rtcp_packet/target_bitrate_unittest.cc",
+      "source/rtcp_packet/tmmbn_unittest.cc",
+      "source/rtcp_packet/tmmbr_unittest.cc",
+      "source/rtcp_packet/transport_feedback_unittest.cc",
+      "source/rtcp_packet/voip_metric_unittest.cc",
+      "source/rtcp_packet_unittest.cc",
+      "source/rtcp_receiver_unittest.cc",
+      "source/rtcp_sender_unittest.cc",
+      "source/rtcp_transceiver_impl_unittest.cc",
+      "source/rtcp_transceiver_unittest.cc",
+      "source/rtp_fec_unittest.cc",
+      "source/rtp_format_h264_unittest.cc",
+      "source/rtp_format_video_generic_unittest.cc",
+      "source/rtp_format_vp8_test_helper.cc",
+      "source/rtp_format_vp8_test_helper.h",
+      "source/rtp_format_vp8_unittest.cc",
+      "source/rtp_format_vp9_unittest.cc",
+      "source/rtp_generic_frame_descriptor_extension_unittest.cc",
+      "source/rtp_header_extension_map_unittest.cc",
+      "source/rtp_packet_history_unittest.cc",
+      "source/rtp_packet_unittest.cc",
+      "source/rtp_payload_registry_unittest.cc",
+      "source/rtp_receiver_unittest.cc",
+      "source/rtp_rtcp_impl_unittest.cc",
+      "source/rtp_sender_unittest.cc",
+      "source/rtp_utility_unittest.cc",
+      "source/time_util_unittest.cc",
+      "source/ulpfec_generator_unittest.cc",
+      "source/ulpfec_header_reader_writer_unittest.cc",
+      "source/ulpfec_receiver_unittest.cc",
+      "test/testAPI/test_api.cc",
+      "test/testAPI/test_api.h",
+      "test/testAPI/test_api_audio.cc",
+      "test/testAPI/test_api_rtcp.cc",
+      "test/testAPI/test_api_video.cc",
+    ]
+    deps = [
+      ":fec_test_helper",
+      ":mock_rtp_rtcp",
+      ":rtcp_transceiver",
+      ":rtp_rtcp",
+      ":rtp_rtcp_format",
+      "..:module_api",
+      "../..:webrtc_common",
+      "../../:typedefs",
+      "../../api:array_view",
+      "../../api:libjingle_peerconnection_api",
+      "../../api:transport_api",
+      "../../api/video:video_bitrate_allocation",
+      "../../api/video:video_frame",
+      "../../api/video_codecs:video_codecs_api",
+      "../../call:rtp_receiver",
+      "../../common_video:common_video",
+      "../../logging:mocks",
+      "../../logging:rtc_event_log_api",
+      "../../rtc_base:checks",
+      "../../rtc_base:rate_limiter",
+      "../../rtc_base:rtc_base_approved",
+      "../../rtc_base:rtc_base_tests_utils",
+      "../../rtc_base:rtc_task_queue",
+      "../../system_wrappers",
+      "../../test:field_trial",
+      "../../test:rtp_test_utils",
+      "../../test:test_common",
+      "../../test:test_support",
+      "../audio_coding:audio_format_conversion",
+      "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/types:optional",
+    ]
+  }
+}
diff --git a/modules/rtp_rtcp/DEPS b/modules/rtp_rtcp/DEPS
new file mode 100644
index 0000000..9d9f33c
--- /dev/null
+++ b/modules/rtp_rtcp/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "+call",
+  "+common_video",
+  "+logging/rtc_event_log",
+  "+system_wrappers",
+]
diff --git a/modules/rtp_rtcp/OWNERS b/modules/rtp_rtcp/OWNERS
new file mode 100644
index 0000000..9377d87
--- /dev/null
+++ b/modules/rtp_rtcp/OWNERS
@@ -0,0 +1,10 @@
+stefan@webrtc.org
+henrik.lundin@webrtc.org
+mflodman@webrtc.org
+asapersson@webrtc.org
+danilchap@webrtc.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gn=*
+per-file *.gni=*
diff --git a/modules/rtp_rtcp/include/flexfec_receiver.h b/modules/rtp_rtcp/include/flexfec_receiver.h
new file mode 100644
index 0000000..f006111
--- /dev/null
+++ b/modules/rtp_rtcp/include/flexfec_receiver.h
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_FLEXFEC_RECEIVER_H_
+#define MODULES_RTP_RTCP_INCLUDE_FLEXFEC_RECEIVER_H_
+
+#include <memory>
+
+#include "modules/rtp_rtcp/include/ulpfec_receiver.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "rtc_base/sequenced_task_checker.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+class FlexfecReceiver {
+ public:
+  FlexfecReceiver(uint32_t ssrc,
+                  uint32_t protected_media_ssrc,
+                  RecoveredPacketReceiver* recovered_packet_receiver);
+  ~FlexfecReceiver();
+
+  // Inserts a received packet (can be either media or FlexFEC) into the
+  // internal buffer, and sends the received packets to the erasure code.
+  // All newly recovered packets are sent back through the callback.
+  void OnRtpPacket(const RtpPacketReceived& packet);
+
+  // Returns a counter describing the added and recovered packets.
+  FecPacketCounter GetPacketCounter() const;
+
+  // Protected to aid testing.
+ protected:
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> AddReceivedPacket(
+      const RtpPacketReceived& packet);
+  void ProcessReceivedPacket(
+      const ForwardErrorCorrection::ReceivedPacket& received_packet);
+
+ private:
+  // Config.
+  const uint32_t ssrc_;
+  const uint32_t protected_media_ssrc_;
+
+  // Erasure code interfacing and callback.
+  std::unique_ptr<ForwardErrorCorrection> erasure_code_
+      RTC_GUARDED_BY(sequence_checker_);
+  ForwardErrorCorrection::RecoveredPacketList recovered_packets_
+      RTC_GUARDED_BY(sequence_checker_);
+  RecoveredPacketReceiver* const recovered_packet_receiver_;
+
+  // Logging and stats.
+  Clock* const clock_;
+  int64_t last_recovered_packet_ms_ RTC_GUARDED_BY(sequence_checker_);
+  FecPacketCounter packet_counter_ RTC_GUARDED_BY(sequence_checker_);
+
+  rtc::SequencedTaskChecker sequence_checker_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_FLEXFEC_RECEIVER_H_
diff --git a/modules/rtp_rtcp/include/flexfec_sender.h b/modules/rtp_rtcp/include/flexfec_sender.h
new file mode 100644
index 0000000..57ba841
--- /dev/null
+++ b/modules/rtp_rtcp/include/flexfec_sender.h
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
+#define MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/rtpparameters.h"
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "modules/rtp_rtcp/source/ulpfec_generator.h"
+#include "rtc_base/random.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+class RtpPacketToSend;
+
+// Note that this class is not thread safe, and thus requires external
+// synchronization. Currently, this is done using the lock in PayloadRouter.
+
+class FlexfecSender {
+ public:
+  FlexfecSender(int payload_type,
+                uint32_t ssrc,
+                uint32_t protected_media_ssrc,
+                const std::string& mid,
+                const std::vector<RtpExtension>& rtp_header_extensions,
+                rtc::ArrayView<const RtpExtensionSize> extension_sizes,
+                const RtpState* rtp_state,
+                Clock* clock);
+  ~FlexfecSender();
+
+  uint32_t ssrc() const { return ssrc_; }
+
+  // Sets the FEC rate, max frames sent before FEC packets are sent,
+  // and what type of generator matrices are used.
+  void SetFecParameters(const FecProtectionParams& params);
+
+  // Adds a media packet to the internal buffer. When enough media packets
+  // have been added, the FEC packets are generated and stored internally.
+  // These FEC packets are then obtained by calling GetFecPackets().
+  // Returns true if the media packet was successfully added.
+  bool AddRtpPacketAndGenerateFec(const RtpPacketToSend& packet);
+
+  // Returns true if there are generated FEC packets available.
+  bool FecAvailable() const;
+
+  // Returns generated FlexFEC packets.
+  std::vector<std::unique_ptr<RtpPacketToSend>> GetFecPackets();
+
+  // Returns the overhead, per packet, for FlexFEC.
+  size_t MaxPacketOverhead() const;
+
+  // Only called on the VideoSendStream queue, after operation has shut down.
+  RtpState GetRtpState();
+
+ private:
+  // Utility.
+  Clock* const clock_;
+  Random random_;
+  int64_t last_generated_packet_ms_;
+
+  // Config.
+  const int payload_type_;
+  const uint32_t timestamp_offset_;
+  const uint32_t ssrc_;
+  const uint32_t protected_media_ssrc_;
+  // MID value to send in the MID header extension.
+  const std::string mid_;
+  // Sequence number of next packet to generate.
+  uint16_t seq_num_;
+
+  // Implementation.
+  UlpfecGenerator ulpfec_generator_;
+  const RtpHeaderExtensionMap rtp_header_extension_map_;
+  const size_t header_extensions_size_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
diff --git a/modules/rtp_rtcp/include/receive_statistics.h b/modules/rtp_rtcp/include/receive_statistics.h
new file mode 100644
index 0000000..a3b4798
--- /dev/null
+++ b/modules/rtp_rtcp/include/receive_statistics.h
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RECEIVE_STATISTICS_H_
+#define MODULES_RTP_RTCP_INCLUDE_RECEIVE_STATISTICS_H_
+
+#include <map>
+#include <vector>
+
+#include "modules/include/module.h"
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class Clock;
+
+class ReceiveStatisticsProvider {
+ public:
+  virtual ~ReceiveStatisticsProvider() = default;
+  // Collects receive statistic in a form of rtcp report blocks.
+  // Returns at most |max_blocks| report blocks.
+  virtual std::vector<rtcp::ReportBlock> RtcpReportBlocks(
+      size_t max_blocks) = 0;
+};
+
+class StreamStatistician {
+ public:
+  virtual ~StreamStatistician();
+
+  virtual bool GetStatistics(RtcpStatistics* statistics, bool reset) = 0;
+  virtual void GetDataCounters(size_t* bytes_received,
+                               uint32_t* packets_received) const = 0;
+
+  // Gets received stream data counters (includes reset counter values).
+  virtual void GetReceiveStreamDataCounters(
+      StreamDataCounters* data_counters) const = 0;
+
+  virtual uint32_t BitrateReceived() const = 0;
+
+  // Returns true if the packet with RTP header |header| is likely to be a
+  // retransmitted packet, false otherwise.
+  virtual bool IsRetransmitOfOldPacket(const RTPHeader& header) const = 0;
+};
+
+class ReceiveStatistics : public ReceiveStatisticsProvider {
+ public:
+  ~ReceiveStatistics() override = default;
+
+  static ReceiveStatistics* Create(Clock* clock);
+
+  // Updates the receive statistics with this packet.
+  virtual void IncomingPacket(const RTPHeader& rtp_header,
+                              size_t packet_length,
+                              bool retransmitted) = 0;
+
+  // Increment counter for number of FEC packets received.
+  virtual void FecPacketReceived(const RTPHeader& header,
+                                 size_t packet_length) = 0;
+
+  // Returns a pointer to the statistician of an ssrc.
+  virtual StreamStatistician* GetStatistician(uint32_t ssrc) const = 0;
+
+  // Sets the max reordering threshold in number of packets.
+  virtual void SetMaxReorderingThreshold(int max_reordering_threshold) = 0;
+
+  // Called on new RTCP stats creation.
+  virtual void RegisterRtcpStatisticsCallback(
+      RtcpStatisticsCallback* callback) = 0;
+
+  // Called on new RTP stats creation.
+  virtual void RegisterRtpStatisticsCallback(
+      StreamDataCountersCallback* callback) = 0;
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_INCLUDE_RECEIVE_STATISTICS_H_
diff --git a/modules/rtp_rtcp/include/remote_ntp_time_estimator.h b/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
new file mode 100644
index 0000000..5195e8a
--- /dev/null
+++ b/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_REMOTE_NTP_TIME_ESTIMATOR_H_
+#define MODULES_RTP_RTCP_INCLUDE_REMOTE_NTP_TIME_ESTIMATOR_H_
+
+#include <memory>
+
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/numerics/moving_median_filter.h"
+#include "system_wrappers/include/rtp_to_ntp_estimator.h"
+
+namespace webrtc {
+
+class Clock;
+
+// RemoteNtpTimeEstimator can be used to estimate a given RTP timestamp's NTP
+// time in local timebase.
+// Note that it needs to be trained with at least 2 RTCP SR (by calling
+// |UpdateRtcpTimestamp|) before it can be used.
+class RemoteNtpTimeEstimator {
+ public:
+  explicit RemoteNtpTimeEstimator(Clock* clock);
+
+  ~RemoteNtpTimeEstimator();
+
+  // Updates the estimator with round trip time |rtt|, NTP seconds |ntp_secs|,
+  // NTP fraction |ntp_frac| and RTP timestamp |rtcp_timestamp|.
+  bool UpdateRtcpTimestamp(int64_t rtt,
+                           uint32_t ntp_secs,
+                           uint32_t ntp_frac,
+                           uint32_t rtp_timestamp);
+
+  // Estimates the NTP timestamp in local timebase from |rtp_timestamp|.
+  // Returns the NTP timestamp in ms when success. -1 if failed.
+  int64_t Estimate(uint32_t rtp_timestamp);
+
+ private:
+  Clock* clock_;
+  MovingMedianFilter<int64_t> ntp_clocks_offset_estimator_;
+  RtpToNtpEstimator rtp_to_ntp_;
+  int64_t last_timing_log_ms_;
+  RTC_DISALLOW_COPY_AND_ASSIGN(RemoteNtpTimeEstimator);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_REMOTE_NTP_TIME_ESTIMATOR_H_
diff --git a/modules/rtp_rtcp/include/rtp_cvo.h b/modules/rtp_rtcp/include/rtp_cvo.h
new file mode 100644
index 0000000..bc0b4ee
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_cvo.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_CVO_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_CVO_H_
+
+#include "api/video/video_rotation.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Please refer to http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/
+// 12.07.00_60/ts_126114v120700p.pdf Section 7.4.5. The rotation of a frame is
+// the clockwise angle the frames must be rotated in order to display the frames
+// correctly if the display is rotated in its natural orientation.
+inline uint8_t ConvertVideoRotationToCVOByte(VideoRotation rotation) {
+  switch (rotation) {
+    case kVideoRotation_0:
+      return 0;
+    case kVideoRotation_90:
+      return 1;
+    case kVideoRotation_180:
+      return 2;
+    case kVideoRotation_270:
+      return 3;
+  }
+  RTC_NOTREACHED();
+  return 0;
+}
+
+inline VideoRotation ConvertCVOByteToVideoRotation(uint8_t cvo_byte) {
+  // CVO byte: |0 0 0 0 C F R R|.
+  const uint8_t rotation_bits = cvo_byte & 0x3;
+  switch (rotation_bits) {
+    case 0:
+      return kVideoRotation_0;
+    case 1:
+      return kVideoRotation_90;
+    case 2:
+      return kVideoRotation_180;
+    case 3:
+      return kVideoRotation_270;
+    default:
+      RTC_NOTREACHED();
+      return kVideoRotation_0;
+  }
+}
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_CVO_H_
diff --git a/modules/rtp_rtcp/include/rtp_header_extension_map.h b/modules/rtp_rtcp/include/rtp_header_extension_map.h
new file mode 100644
index 0000000..89a0ed5
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_header_extension_map.h
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_EXTENSION_MAP_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_EXTENSION_MAP_H_
+
+#include <string>
+
+#include "api/array_view.h"
+#include "api/rtpparameters.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+struct RtpExtensionSize {
+  RTPExtensionType type;
+  uint8_t value_size;
+};
+
+class RtpHeaderExtensionMap {
+ public:
+  static constexpr RTPExtensionType kInvalidType = kRtpExtensionNone;
+  static constexpr int kInvalidId = 0;
+
+  RtpHeaderExtensionMap();
+  explicit RtpHeaderExtensionMap(rtc::ArrayView<const RtpExtension> extensions);
+
+  template <typename Extension>
+  bool Register(int id) {
+    return Register(id, Extension::kId, Extension::kUri);
+  }
+  bool RegisterByType(int id, RTPExtensionType type);
+  bool RegisterByUri(int id, const std::string& uri);
+
+  bool IsRegistered(RTPExtensionType type) const {
+    return GetId(type) != kInvalidId;
+  }
+  // Return kInvalidType if not found.
+  RTPExtensionType GetType(int id) const {
+    RTC_DCHECK_GE(id, kMinId);
+    RTC_DCHECK_LE(id, kMaxId);
+    return types_[id];
+  }
+  // Return kInvalidId if not found.
+  uint8_t GetId(RTPExtensionType type) const {
+    RTC_DCHECK_GT(type, kRtpExtensionNone);
+    RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
+    return ids_[type];
+  }
+
+  size_t GetTotalLengthInBytes(
+      rtc::ArrayView<const RtpExtensionSize> extensions) const;
+
+  // TODO(danilchap): Remove use of the functions below.
+  int32_t Register(RTPExtensionType type, int id) {
+    return RegisterByType(id, type) ? 0 : -1;
+  }
+  int32_t Deregister(RTPExtensionType type);
+
+ private:
+  static constexpr int kMinId = 1;
+  static constexpr int kMaxId = 14;
+  bool Register(int id, RTPExtensionType type, const char* uri);
+
+  RTPExtensionType types_[kMaxId + 1];
+  uint8_t ids_[kRtpExtensionNumberOfExtensions];
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_EXTENSION_MAP_H_
diff --git a/modules/rtp_rtcp/include/rtp_header_parser.h b/modules/rtp_rtcp/include/rtp_header_parser.h
new file mode 100644
index 0000000..59012ce
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_header_parser.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+struct RTPHeader;
+
+class RtpHeaderParser {
+ public:
+  static RtpHeaderParser* Create();
+  virtual ~RtpHeaderParser() {}
+
+  // Returns true if the packet is an RTCP packet, false otherwise.
+  static bool IsRtcp(const uint8_t* packet, size_t length);
+
+  // Parses the packet and stores the parsed packet in |header|. Returns true on
+  // success, false otherwise.
+  // This method is thread-safe in the sense that it can parse multiple packets
+  // at once.
+  virtual bool Parse(const uint8_t* packet,
+                     size_t length,
+                     RTPHeader* header) const = 0;
+
+  // Registers an RTP header extension and binds it to |id|.
+  virtual bool RegisterRtpHeaderExtension(RTPExtensionType type,
+                                          uint8_t id) = 0;
+
+  // De-registers an RTP header extension.
+  virtual bool DeregisterRtpHeaderExtension(RTPExtensionType type) = 0;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_HEADER_PARSER_H_
diff --git a/modules/rtp_rtcp/include/rtp_payload_registry.h b/modules/rtp_rtcp/include/rtp_payload_registry.h
new file mode 100644
index 0000000..be296da
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_payload_registry.h
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_
+
+#include <map>
+#include <set>
+
+#include "absl/types/optional.h"
+#include "api/audio_codecs/audio_format.h"
+#include "api/video_codecs/video_codec.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/criticalsection.h"
+
+namespace webrtc {
+
+class RTPPayloadRegistry {
+ public:
+  RTPPayloadRegistry();
+  ~RTPPayloadRegistry();
+
+  // TODO(magjed): Split RTPPayloadRegistry into separate Audio and Video class
+  // and simplify the code. http://crbug/webrtc/6743.
+
+  // Replace all audio receive payload types with the given map.
+  void SetAudioReceivePayloads(std::map<int, SdpAudioFormat> codecs);
+
+  int32_t RegisterReceivePayload(int payload_type,
+                                 const SdpAudioFormat& audio_format,
+                                 bool* created_new_payload_type);
+  int32_t RegisterReceivePayload(const VideoCodec& video_codec);
+
+  int32_t DeRegisterReceivePayload(int8_t payload_type);
+
+  int GetPayloadTypeFrequency(uint8_t payload_type) const;
+
+  absl::optional<RtpUtility::Payload> PayloadTypeToPayload(
+      uint8_t payload_type) const;
+
+  void ResetLastReceivedPayloadTypes() {
+    rtc::CritScope cs(&crit_sect_);
+    last_received_payload_type_ = -1;
+  }
+
+  int8_t last_received_payload_type() const {
+    rtc::CritScope cs(&crit_sect_);
+    return last_received_payload_type_;
+  }
+  void set_last_received_payload_type(int8_t last_received_payload_type) {
+    rtc::CritScope cs(&crit_sect_);
+    last_received_payload_type_ = last_received_payload_type;
+  }
+
+ private:
+  // Prunes the payload type map of the specific payload type, if it exists.
+  void DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
+      const SdpAudioFormat& audio_format);
+
+  rtc::CriticalSection crit_sect_;
+  std::map<int, RtpUtility::Payload> payload_type_map_;
+  int8_t last_received_payload_type_;
+
+// As a first step in splitting this class up in separate cases for audio and
+// video, DCHECK that no instance is used for both audio and video.
+#if RTC_DCHECK_IS_ON
+  bool used_for_audio_ RTC_GUARDED_BY(crit_sect_) = false;
+  bool used_for_video_ RTC_GUARDED_BY(crit_sect_) = false;
+#endif
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_
diff --git a/modules/rtp_rtcp/include/rtp_receiver.h b/modules/rtp_rtcp/include/rtp_receiver.h
new file mode 100644
index 0000000..d2d73b4
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_receiver.h
@@ -0,0 +1,108 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_
+
+#include <vector>
+
+#include "api/rtpreceiverinterface.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class RTPPayloadRegistry;
+class VideoCodec;
+
+class TelephoneEventHandler {
+ public:
+  virtual ~TelephoneEventHandler() {}
+
+  // The following three methods implement the TelephoneEventHandler interface.
+  // Forward DTMFs to decoder for playout.
+  virtual void SetTelephoneEventForwardToDecoder(bool forward_to_decoder) = 0;
+
+  // Is forwarding of outband telephone events turned on/off?
+  virtual bool TelephoneEventForwardToDecoder() const = 0;
+
+  // Is TelephoneEvent configured with payload type payload_type
+  virtual bool TelephoneEventPayloadType(const int8_t payload_type) const = 0;
+};
+
+class RtpReceiver {
+ public:
+  // Creates a video-enabled RTP receiver.
+  static RtpReceiver* CreateVideoReceiver(
+      Clock* clock,
+      RtpData* incoming_payload_callback,
+      RTPPayloadRegistry* rtp_payload_registry);
+
+  // Creates an audio-enabled RTP receiver.
+  static RtpReceiver* CreateAudioReceiver(
+      Clock* clock,
+      RtpData* incoming_payload_callback,
+      RTPPayloadRegistry* rtp_payload_registry);
+
+  virtual ~RtpReceiver() {}
+
+  // Returns a TelephoneEventHandler if available.
+  virtual TelephoneEventHandler* GetTelephoneEventHandler() = 0;
+
+  // Registers a receive payload in the payload registry and notifies the media
+  // receiver strategy.
+  virtual int32_t RegisterReceivePayload(
+      int payload_type,
+      const SdpAudioFormat& audio_format) = 0;
+
+  // Deprecated version of the above.
+  int32_t RegisterReceivePayload(const CodecInst& audio_codec);
+
+  // Registers a receive payload in the payload registry.
+  virtual int32_t RegisterReceivePayload(const VideoCodec& video_codec) = 0;
+
+  // De-registers |payload_type| from the payload registry.
+  virtual int32_t DeRegisterReceivePayload(const int8_t payload_type) = 0;
+
+  // Parses the media specific parts of an RTP packet and updates the receiver
+  // state. This for instance means that any changes in SSRC and payload type is
+  // detected and acted upon.
+  virtual bool IncomingRtpPacket(const RTPHeader& rtp_header,
+                                 const uint8_t* payload,
+                                 size_t payload_length,
+                                 PayloadUnion payload_specific) = 0;
+  // TODO(nisse): Deprecated version, delete as soon as downstream
+  // applications are updated.
+  bool IncomingRtpPacket(const RTPHeader& rtp_header,
+                         const uint8_t* payload,
+                         size_t payload_length,
+                         PayloadUnion payload_specific,
+                         bool in_order /* Ignored */) {
+    return IncomingRtpPacket(rtp_header, payload, payload_length,
+                             payload_specific);
+  }
+
+  // Gets the RTP timestamp and the corresponding monotonic system
+  // time for the most recent in-order packet. Returns true on
+  // success, false if no packet has been received.
+  virtual bool GetLatestTimestamps(uint32_t* timestamp,
+                                   int64_t* receive_time_ms) const = 0;
+
+  // Returns the remote SSRC of the currently received RTP stream.
+  virtual uint32_t SSRC() const = 0;
+
+  // Returns the current remote CSRCs.
+  virtual int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const = 0;
+
+  virtual std::vector<RtpSource> GetSources() const = 0;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_
diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h
new file mode 100644
index 0000000..94237e0
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_rtcp.h
@@ -0,0 +1,455 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_H_
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/include/module.h"
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/deprecation.h"
+
+namespace webrtc {
+
+// Forward declarations.
+class OverheadObserver;
+class RateLimiter;
+class ReceiveStatisticsProvider;
+class RemoteBitrateEstimator;
+class RtcEventLog;
+class RtpReceiver;
+class Transport;
+class VideoBitrateAllocationObserver;
+
+RTPExtensionType StringToRtpExtensionType(const std::string& extension);
+
+namespace rtcp {
+class TransportFeedback;
+}
+
+class RtpRtcp : public Module, public RtcpFeedbackSenderInterface {
+ public:
+  struct Configuration {
+    Configuration();
+
+    // True for a audio version of the RTP/RTCP module object false will create
+    // a video version.
+    bool audio = false;
+    bool receiver_only = false;
+
+    // The clock to use to read time. If nullptr then system clock will be used.
+    Clock* clock = nullptr;
+
+    ReceiveStatisticsProvider* receive_statistics = nullptr;
+
+    // Transport object that will be called when packets are ready to be sent
+    // out on the network.
+    Transport* outgoing_transport = nullptr;
+
+    // Called when the receiver request a intra frame.
+    RtcpIntraFrameObserver* intra_frame_callback = nullptr;
+
+    // Called when we receive a changed estimate from the receiver of out
+    // stream.
+    RtcpBandwidthObserver* bandwidth_callback = nullptr;
+
+    TransportFeedbackObserver* transport_feedback_callback = nullptr;
+    VideoBitrateAllocationObserver* bitrate_allocation_observer = nullptr;
+    RtcpRttStats* rtt_stats = nullptr;
+    RtcpPacketTypeCounterObserver* rtcp_packet_type_counter_observer = nullptr;
+
+    // Estimates the bandwidth available for a set of streams from the same
+    // client.
+    RemoteBitrateEstimator* remote_bitrate_estimator = nullptr;
+
+    // Spread any bursts of packets into smaller bursts to minimize packet loss.
+    RtpPacketSender* paced_sender = nullptr;
+
+    // Generate FlexFEC packets.
+    // TODO(brandtr): Remove when FlexfecSender is wired up to PacedSender.
+    FlexfecSender* flexfec_sender = nullptr;
+
+    TransportSequenceNumberAllocator* transport_sequence_number_allocator =
+        nullptr;
+    BitrateStatisticsObserver* send_bitrate_observer = nullptr;
+    FrameCountObserver* send_frame_count_observer = nullptr;
+    SendSideDelayObserver* send_side_delay_observer = nullptr;
+    RtcEventLog* event_log = nullptr;
+    SendPacketObserver* send_packet_observer = nullptr;
+    RateLimiter* retransmission_rate_limiter = nullptr;
+    OverheadObserver* overhead_observer = nullptr;
+    RtpKeepAliveConfig keepalive_config;
+    RtcpIntervalConfig rtcp_interval_config;
+
+    // Update network2 instead of pacer_exit field of video timing extension.
+    bool populate_network2_timestamp = false;
+
+   private:
+    RTC_DISALLOW_COPY_AND_ASSIGN(Configuration);
+  };
+
+  // Create a RTP/RTCP module object using the system clock.
+  // |configuration|  - Configuration of the RTP/RTCP module.
+  static RtpRtcp* CreateRtpRtcp(const RtpRtcp::Configuration& configuration);
+
+  // **************************************************************************
+  // Receiver functions
+  // **************************************************************************
+
+  virtual void IncomingRtcpPacket(const uint8_t* incoming_packet,
+                                  size_t incoming_packet_length) = 0;
+
+  virtual void SetRemoteSSRC(uint32_t ssrc) = 0;
+
+  // **************************************************************************
+  // Sender
+  // **************************************************************************
+
+  // Sets the maximum size of an RTP packet, including RTP headers.
+  virtual void SetMaxRtpPacketSize(size_t size) = 0;
+
+  // Returns max RTP packet size. Takes into account RTP headers and
+  // FEC/ULP/RED overhead (when FEC is enabled).
+  virtual size_t MaxRtpPacketSize() const = 0;
+
+  // Sets codec name and payload type. Returns -1 on failure else 0.
+  virtual int32_t RegisterSendPayload(const CodecInst& voice_codec) = 0;
+
+  virtual void RegisterVideoSendPayload(int payload_type,
+                                        const char* payload_name) = 0;
+
+  // Unregisters a send payload.
+  // |payload_type| - payload type of codec
+  // Returns -1 on failure else 0.
+  virtual int32_t DeRegisterSendPayload(int8_t payload_type) = 0;
+
+  // (De)registers RTP header extension type and id.
+  // Returns -1 on failure else 0.
+  virtual int32_t RegisterSendRtpHeaderExtension(RTPExtensionType type,
+                                                 uint8_t id) = 0;
+
+  virtual int32_t DeregisterSendRtpHeaderExtension(RTPExtensionType type) = 0;
+
+  virtual bool HasBweExtensions() const = 0;
+
+  // Returns start timestamp.
+  virtual uint32_t StartTimestamp() const = 0;
+
+  // Sets start timestamp. Start timestamp is set to a random value if this
+  // function is never called.
+  virtual void SetStartTimestamp(uint32_t timestamp) = 0;
+
+  // Returns SequenceNumber.
+  virtual uint16_t SequenceNumber() const = 0;
+
+  // Sets SequenceNumber, default is a random number.
+  virtual void SetSequenceNumber(uint16_t seq) = 0;
+
+  virtual void SetRtpState(const RtpState& rtp_state) = 0;
+  virtual void SetRtxState(const RtpState& rtp_state) = 0;
+  virtual RtpState GetRtpState() const = 0;
+  virtual RtpState GetRtxState() const = 0;
+
+  // Returns SSRC.
+  uint32_t SSRC() const override = 0;
+
+  // Sets SSRC, default is a random number.
+  virtual void SetSSRC(uint32_t ssrc) = 0;
+
+  // Sets the value for sending in the MID RTP header extension.
+  // The MID RTP header extension should be registered for this to do anything.
+  // Once set, this value can not be changed or removed.
+  virtual void SetMid(const std::string& mid) = 0;
+
+  // Sets CSRC.
+  // |csrcs| - vector of CSRCs
+  virtual void SetCsrcs(const std::vector<uint32_t>& csrcs) = 0;
+
+  // Turns on/off sending RTX (RFC 4588). The modes can be set as a combination
+  // of values of the enumerator RtxMode.
+  virtual void SetRtxSendStatus(int modes) = 0;
+
+  // Returns status of sending RTX (RFC 4588). The returned value can be
+  // a combination of values of the enumerator RtxMode.
+  virtual int RtxSendStatus() const = 0;
+
+  // Sets the SSRC to use when sending RTX packets. This doesn't enable RTX,
+  // only the SSRC is set.
+  virtual void SetRtxSsrc(uint32_t ssrc) = 0;
+
+  // Sets the payload type to use when sending RTX packets. Note that this
+  // doesn't enable RTX, only the payload type is set.
+  virtual void SetRtxSendPayloadType(int payload_type,
+                                     int associated_payload_type) = 0;
+
+  // Returns the FlexFEC SSRC, if there is one.
+  virtual absl::optional<uint32_t> FlexfecSsrc() const = 0;
+
+  // Sets sending status. Sends kRtcpByeCode when going from true to false.
+  // Returns -1 on failure else 0.
+  virtual int32_t SetSendingStatus(bool sending) = 0;
+
+  // Returns current sending status.
+  virtual bool Sending() const = 0;
+
+  // Starts/Stops media packets. On by default.
+  virtual void SetSendingMediaStatus(bool sending) = 0;
+
+  // Returns current media sending status.
+  virtual bool SendingMedia() const = 0;
+
+  // Returns current bitrate in Kbit/s.
+  virtual void BitrateSent(uint32_t* total_rate,
+                           uint32_t* video_rate,
+                           uint32_t* fec_rate,
+                           uint32_t* nack_rate) const = 0;
+
+  // Used by the codec module to deliver a video or audio frame for
+  // packetization.
+  // |frame_type|    - type of frame to send
+  // |payload_type|  - payload type of frame to send
+  // |timestamp|     - timestamp of frame to send
+  // |payload_data|  - payload buffer of frame to send
+  // |payload_size|  - size of payload buffer to send
+  // |fragmentation| - fragmentation offset data for fragmented frames such
+  //                   as layers or RED
+  // |transport_frame_id_out| - set to RTP timestamp.
+  // Returns true on success.
+  virtual bool SendOutgoingData(FrameType frame_type,
+                                int8_t payload_type,
+                                uint32_t timestamp,
+                                int64_t capture_time_ms,
+                                const uint8_t* payload_data,
+                                size_t payload_size,
+                                const RTPFragmentationHeader* fragmentation,
+                                const RTPVideoHeader* rtp_video_header,
+                                uint32_t* transport_frame_id_out) = 0;
+
+  virtual bool TimeToSendPacket(uint32_t ssrc,
+                                uint16_t sequence_number,
+                                int64_t capture_time_ms,
+                                bool retransmission,
+                                const PacedPacketInfo& pacing_info) = 0;
+
+  virtual size_t TimeToSendPadding(size_t bytes,
+                                   const PacedPacketInfo& pacing_info) = 0;
+
+  // Called on generation of new statistics after an RTP send.
+  virtual void RegisterSendChannelRtpStatisticsCallback(
+      StreamDataCountersCallback* callback) = 0;
+  virtual StreamDataCountersCallback* GetSendChannelRtpStatisticsCallback()
+      const = 0;
+
+  // **************************************************************************
+  // RTCP
+  // **************************************************************************
+
+  // Returns RTCP status.
+  virtual RtcpMode RTCP() const = 0;
+
+  // Sets RTCP status i.e on(compound or non-compound)/off.
+  // |method| - RTCP method to use.
+  virtual void SetRTCPStatus(RtcpMode method) = 0;
+
+  // Sets RTCP CName (i.e unique identifier).
+  // Returns -1 on failure else 0.
+  virtual int32_t SetCNAME(const char* cname) = 0;
+
+  // Returns remote CName.
+  // Returns -1 on failure else 0.
+  virtual int32_t RemoteCNAME(uint32_t remote_ssrc,
+                              char cname[RTCP_CNAME_SIZE]) const = 0;
+
+  // Returns remote NTP.
+  // Returns -1 on failure else 0.
+  virtual int32_t RemoteNTP(uint32_t* received_ntp_secs,
+                            uint32_t* received_ntp_frac,
+                            uint32_t* rtcp_arrival_time_secs,
+                            uint32_t* rtcp_arrival_time_frac,
+                            uint32_t* rtcp_timestamp) const = 0;
+
+  // Returns -1 on failure else 0.
+  virtual int32_t AddMixedCNAME(uint32_t ssrc, const char* cname) = 0;
+
+  // Returns -1 on failure else 0.
+  virtual int32_t RemoveMixedCNAME(uint32_t ssrc) = 0;
+
+  // Returns current RTT (round-trip time) estimate.
+  // Returns -1 on failure else 0.
+  virtual int32_t RTT(uint32_t remote_ssrc,
+                      int64_t* rtt,
+                      int64_t* avg_rtt,
+                      int64_t* min_rtt,
+                      int64_t* max_rtt) const = 0;
+
+  // Forces a send of a RTCP packet. Periodic SR and RR are triggered via the
+  // process function.
+  // Returns -1 on failure else 0.
+  virtual int32_t SendRTCP(RTCPPacketType rtcp_packet_type) = 0;
+
+  // Forces a send of a RTCP packet with more than one packet type.
+  // periodic SR and RR are triggered via the process function
+  // Returns -1 on failure else 0.
+  virtual int32_t SendCompoundRTCP(
+      const std::set<RTCPPacketType>& rtcp_packet_types) = 0;
+
+  // Returns statistics of the amount of data sent.
+  // Returns -1 on failure else 0.
+  virtual int32_t DataCountersRTP(size_t* bytes_sent,
+                                  uint32_t* packets_sent) const = 0;
+
+  // Returns send statistics for the RTP and RTX stream.
+  virtual void GetSendStreamDataCounters(
+      StreamDataCounters* rtp_counters,
+      StreamDataCounters* rtx_counters) const = 0;
+
+  // Returns packet loss statistics for the RTP stream.
+  virtual void GetRtpPacketLossStats(
+      bool outgoing,
+      uint32_t ssrc,
+      struct RtpPacketLossStats* loss_stats) const = 0;
+
+  // Returns received RTCP report block.
+  // Returns -1 on failure else 0.
+  virtual int32_t RemoteRTCPStat(
+      std::vector<RTCPReportBlock>* receive_blocks) const = 0;
+
+  // (APP) Sets application specific data.
+  // Returns -1 on failure else 0.
+  virtual int32_t SetRTCPApplicationSpecificData(uint8_t sub_type,
+                                                 uint32_t name,
+                                                 const uint8_t* data,
+                                                 uint16_t length) = 0;
+  // (XR) Sets VOIP metric.
+  // Returns -1 on failure else 0.
+  virtual int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) = 0;
+
+  // (XR) Sets Receiver Reference Time Report (RTTR) status.
+  virtual void SetRtcpXrRrtrStatus(bool enable) = 0;
+
+  // Returns current Receiver Reference Time Report (RTTR) status.
+  virtual bool RtcpXrRrtrStatus() const = 0;
+
+  // (REMB) Receiver Estimated Max Bitrate.
+  // Schedules sending REMB on next and following sender/receiver reports.
+  void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) override = 0;
+  // Stops sending REMB on next and following sender/receiver reports.
+  void UnsetRemb() override = 0;
+
+  // (TMMBR) Temporary Max Media Bit Rate
+  virtual bool TMMBR() const = 0;
+
+  virtual void SetTMMBRStatus(bool enable) = 0;
+
+  // (NACK)
+
+  // TODO(holmer): Propagate this API to VideoEngine.
+  // Returns the currently configured selective retransmission settings.
+  virtual int SelectiveRetransmissions() const = 0;
+
+  // TODO(holmer): Propagate this API to VideoEngine.
+  // Sets the selective retransmission settings, which will decide which
+  // packets will be retransmitted if NACKed. Settings are constructed by
+  // combining the constants in enum RetransmissionMode with bitwise OR.
+  // All packets are retransmitted if kRetransmitAllPackets is set, while no
+  // packets are retransmitted if kRetransmitOff is set.
+  // By default all packets except FEC packets are retransmitted. For VP8
+  // with temporal scalability only base layer packets are retransmitted.
+  // Returns -1 on failure, otherwise 0.
+  virtual int SetSelectiveRetransmissions(uint8_t settings) = 0;
+
+  // Sends a Negative acknowledgement packet.
+  // Returns -1 on failure else 0.
+  // TODO(philipel): Deprecate this and start using SendNack instead, mostly
+  // because we want a function that actually send NACK for the specified
+  // packets.
+  virtual int32_t SendNACK(const uint16_t* nack_list, uint16_t size) = 0;
+
+  // Sends NACK for the packets specified.
+  // Note: This assumes the caller keeps track of timing and doesn't rely on
+  // the RTP module to do this.
+  virtual void SendNack(const std::vector<uint16_t>& sequence_numbers) = 0;
+
+  // Store the sent packets, needed to answer to a Negative acknowledgment
+  // requests.
+  virtual void SetStorePacketsStatus(bool enable, uint16_t numberToStore) = 0;
+
+  // Returns true if the module is configured to store packets.
+  virtual bool StorePackets() const = 0;
+
+  // Called on receipt of RTCP report block from remote side.
+  virtual void RegisterRtcpStatisticsCallback(
+      RtcpStatisticsCallback* callback) = 0;
+  virtual RtcpStatisticsCallback* GetRtcpStatisticsCallback() = 0;
+  // BWE feedback packets.
+  bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override = 0;
+
+  virtual void SetVideoBitrateAllocation(
+      const VideoBitrateAllocation& bitrate) = 0;
+
+  // **************************************************************************
+  // Audio
+  // **************************************************************************
+
+  // Sends a TelephoneEvent tone using RFC 2833 (4733).
+  // Returns -1 on failure else 0.
+  virtual int32_t SendTelephoneEventOutband(uint8_t key,
+                                            uint16_t time_ms,
+                                            uint8_t level) = 0;
+
+  // Store the audio level in dBov for header-extension-for-audio-level-
+  // indication.
+  // This API shall be called before transmision of an RTP packet to ensure
+  // that the |level| part of the extended RTP header is updated.
+  // return -1 on failure else 0.
+  virtual int32_t SetAudioLevel(uint8_t level_dbov) = 0;
+
+  // **************************************************************************
+  // Video
+  // **************************************************************************
+
+  // Set RED and ULPFEC payload types. A payload type of -1 means that the
+  // corresponding feature is turned off. Note that we DO NOT support enabling
+  // ULPFEC without enabling RED, and RED is only ever used when ULPFEC is
+  // enabled.
+  virtual void SetUlpfecConfig(int red_payload_type,
+                               int ulpfec_payload_type) = 0;
+
+  // Set FEC rates, max frames before FEC is sent, and type of FEC masks.
+  // Returns false on failure.
+  virtual bool SetFecParameters(const FecProtectionParams& delta_params,
+                                const FecProtectionParams& key_params) = 0;
+
+  // Deprecated version of member function above.
+  RTC_DEPRECATED
+  int32_t SetFecParameters(const FecProtectionParams* delta_params,
+                           const FecProtectionParams* key_params);
+
+  // Set method for requestion a new key frame.
+  // Returns -1 on failure else 0.
+  virtual int32_t SetKeyFrameRequestMethod(KeyFrameRequestMethod method) = 0;
+
+  // Sends a request for a keyframe.
+  // Returns -1 on failure else 0.
+  virtual int32_t RequestKeyFrame() = 0;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_H_
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.cc b/modules/rtp_rtcp/include/rtp_rtcp_defines.cc
new file mode 100644
index 0000000..ad9bd45
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+
+StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {}
+
+constexpr size_t StreamId::kMaxSize;
+
+bool StreamId::IsLegalName(rtc::ArrayView<const char> name) {
+  return (name.size() <= kMaxSize && name.size() > 0 &&
+          std::all_of(name.data(), name.data() + name.size(), isalnum));
+}
+
+void StreamId::Set(const char* data, size_t size) {
+  // If |data| contains \0, the stream id size might become less than |size|.
+  RTC_CHECK_LE(size, kMaxSize);
+  memcpy(value_, data, size);
+  if (size < kMaxSize)
+    value_[size] = 0;
+}
+
+// StreamId is used as member of RTPHeader that is sometimes copied with memcpy
+// and thus assume trivial destructibility.
+static_assert(std::is_trivially_destructible<StreamId>::value, "");
+
+PayloadUnion::PayloadUnion(const AudioPayload& payload) : payload_(payload) {}
+PayloadUnion::PayloadUnion(const VideoPayload& payload) : payload_(payload) {}
+PayloadUnion::PayloadUnion(const PayloadUnion&) = default;
+PayloadUnion::PayloadUnion(PayloadUnion&&) = default;
+PayloadUnion::~PayloadUnion() = default;
+
+PayloadUnion& PayloadUnion::operator=(const PayloadUnion&) = default;
+PayloadUnion& PayloadUnion::operator=(PayloadUnion&&) = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
new file mode 100644
index 0000000..cfd9030
--- /dev/null
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -0,0 +1,566 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_
+#define MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_
+
+#include <stddef.h>
+#include <list>
+#include <vector>
+
+#include "absl/types/variant.h"
+#include "api/audio_codecs/audio_format.h"
+#include "api/rtp_headers.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/include/module_common_types.h"
+#include "system_wrappers/include/clock.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+#define RTCP_CNAME_SIZE 256  // RFC 3550 page 44, including null termination
+#define IP_PACKET_SIZE 1500  // we assume ethernet
+#define MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS 10
+
+namespace webrtc {
+namespace rtcp {
+class TransportFeedback;
+}
+
+const int kVideoPayloadTypeFrequency = 90000;
+// TODO(solenberg): RTP time stamp rate for RTCP is fixed at 8k, this is legacy
+// and should be fixed.
+// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6458
+const int kBogusRtpRateForAudioRtcp = 8000;
+
+// Minimum RTP header size in bytes.
+const uint8_t kRtpHeaderSize = 12;
+
+struct RtcpIntervalConfig final {
+  RtcpIntervalConfig() = default;
+  RtcpIntervalConfig(int64_t video_interval_ms, int64_t audio_interval_ms)
+      : video_interval_ms(video_interval_ms),
+        audio_interval_ms(audio_interval_ms) {}
+  int64_t video_interval_ms = 1000;
+  int64_t audio_interval_ms = 5000;
+};
+
+struct AudioPayload {
+  SdpAudioFormat format;
+  uint32_t rate;
+};
+
+struct VideoPayload {
+  VideoCodecType videoCodecType;
+  // The H264 profile only matters if videoCodecType == kVideoCodecH264.
+  H264::Profile h264_profile;
+};
+
+class PayloadUnion {
+ public:
+  explicit PayloadUnion(const AudioPayload& payload);
+  explicit PayloadUnion(const VideoPayload& payload);
+  PayloadUnion(const PayloadUnion&);
+  PayloadUnion(PayloadUnion&&);
+  ~PayloadUnion();
+
+  PayloadUnion& operator=(const PayloadUnion&);
+  PayloadUnion& operator=(PayloadUnion&&);
+
+  bool is_audio() const {
+    return absl::holds_alternative<AudioPayload>(payload_);
+  }
+  bool is_video() const {
+    return absl::holds_alternative<VideoPayload>(payload_);
+  }
+  const AudioPayload& audio_payload() const {
+    return absl::get<AudioPayload>(payload_);
+  }
+  const VideoPayload& video_payload() const {
+    return absl::get<VideoPayload>(payload_);
+  }
+  AudioPayload& audio_payload() { return absl::get<AudioPayload>(payload_); }
+  VideoPayload& video_payload() { return absl::get<VideoPayload>(payload_); }
+
+ private:
+  absl::variant<AudioPayload, VideoPayload> payload_;
+};
+
+enum RTPAliveType { kRtpDead = 0, kRtpNoRtp = 1, kRtpAlive = 2 };
+
+enum ProtectionType { kUnprotectedPacket, kProtectedPacket };
+
+enum StorageType { kDontRetransmit, kAllowRetransmission };
+
+enum RTPExtensionType {
+  kRtpExtensionNone,
+  kRtpExtensionTransmissionTimeOffset,
+  kRtpExtensionAudioLevel,
+  kRtpExtensionAbsoluteSendTime,
+  kRtpExtensionVideoRotation,
+  kRtpExtensionTransportSequenceNumber,
+  kRtpExtensionPlayoutDelay,
+  kRtpExtensionVideoContentType,
+  kRtpExtensionVideoTiming,
+  kRtpExtensionRtpStreamId,
+  kRtpExtensionRepairedRtpStreamId,
+  kRtpExtensionMid,
+  kRtpExtensionGenericFrameDescriptor,
+  kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
+};
+
+enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
+
+// TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
+enum RTCPPacketType : uint32_t {
+  kRtcpReport = 0x0001,
+  kRtcpSr = 0x0002,
+  kRtcpRr = 0x0004,
+  kRtcpSdes = 0x0008,
+  kRtcpBye = 0x0010,
+  kRtcpPli = 0x0020,
+  kRtcpNack = 0x0040,
+  kRtcpFir = 0x0080,
+  kRtcpTmmbr = 0x0100,
+  kRtcpTmmbn = 0x0200,
+  kRtcpSrReq = 0x0400,
+  kRtcpXrVoipMetric = 0x0800,
+  kRtcpApp = 0x1000,
+  kRtcpRemb = 0x10000,
+  kRtcpTransmissionTimeOffset = 0x20000,
+  kRtcpXrReceiverReferenceTime = 0x40000,
+  kRtcpXrDlrrReportBlock = 0x80000,
+  kRtcpTransportFeedback = 0x100000,
+  kRtcpXrTargetBitrate = 0x200000
+};
+
+enum KeyFrameRequestMethod { kKeyFrameReqPliRtcp, kKeyFrameReqFirRtcp };
+
+enum RtpRtcpPacketType { kPacketRtp = 0, kPacketKeepAlive = 1 };
+
+// kConditionallyRetransmitHigherLayers allows retransmission of video frames
+// in higher layers if either the last frame in that layer was too far back in
+// time, or if we estimate that a new frame will be available in a lower layer
+// in a shorter time than it would take to request and receive a retransmission.
+enum RetransmissionMode : uint8_t {
+  kRetransmitOff = 0x0,
+  kRetransmitFECPackets = 0x1,
+  kRetransmitBaseLayer = 0x2,
+  kRetransmitHigherLayers = 0x4,
+  kConditionallyRetransmitHigherLayers = 0x8,
+  kRetransmitAllPackets = 0xFF
+};
+
+enum RtxMode {
+  kRtxOff = 0x0,
+  kRtxRetransmitted = 0x1,     // Only send retransmissions over RTX.
+  kRtxRedundantPayloads = 0x2  // Preventively send redundant payloads
+                               // instead of padding.
+};
+
+const size_t kRtxHeaderSize = 2;
+
+struct RTCPReportBlock {
+  RTCPReportBlock()
+      : sender_ssrc(0),
+        source_ssrc(0),
+        fraction_lost(0),
+        packets_lost(0),
+        extended_highest_sequence_number(0),
+        jitter(0),
+        last_sender_report_timestamp(0),
+        delay_since_last_sender_report(0) {}
+
+  RTCPReportBlock(uint32_t sender_ssrc,
+                  uint32_t source_ssrc,
+                  uint8_t fraction_lost,
+                  int32_t packets_lost,
+                  uint32_t extended_highest_sequence_number,
+                  uint32_t jitter,
+                  uint32_t last_sender_report_timestamp,
+                  uint32_t delay_since_last_sender_report)
+      : sender_ssrc(sender_ssrc),
+        source_ssrc(source_ssrc),
+        fraction_lost(fraction_lost),
+        packets_lost(packets_lost),
+        extended_highest_sequence_number(extended_highest_sequence_number),
+        jitter(jitter),
+        last_sender_report_timestamp(last_sender_report_timestamp),
+        delay_since_last_sender_report(delay_since_last_sender_report) {}
+
+  // Fields as described by RFC 3550 6.4.2.
+  uint32_t sender_ssrc;  // SSRC of sender of this report.
+  uint32_t source_ssrc;  // SSRC of the RTP packet sender.
+  uint8_t fraction_lost;
+  uint32_t packets_lost;  // 24 bits valid.
+  uint32_t extended_highest_sequence_number;
+  uint32_t jitter;
+  uint32_t last_sender_report_timestamp;
+  uint32_t delay_since_last_sender_report;
+};
+
+typedef std::list<RTCPReportBlock> ReportBlockList;
+
+struct RtpState {
+  RtpState()
+      : sequence_number(0),
+        start_timestamp(0),
+        timestamp(0),
+        capture_time_ms(-1),
+        last_timestamp_time_ms(-1),
+        media_has_been_sent(false) {}
+  uint16_t sequence_number;
+  uint32_t start_timestamp;
+  uint32_t timestamp;
+  int64_t capture_time_ms;
+  int64_t last_timestamp_time_ms;
+  bool media_has_been_sent;
+};
+
+class RtpData {
+ public:
+  virtual ~RtpData() {}
+
+  virtual int32_t OnReceivedPayloadData(const uint8_t* payload_data,
+                                        size_t payload_size,
+                                        const WebRtcRTPHeader* rtp_header) = 0;
+};
+
+// Callback interface for packets recovered by FlexFEC or ULPFEC. In
+// the FlexFEC case, the implementation should be able to demultiplex
+// the recovered RTP packets based on SSRC.
+class RecoveredPacketReceiver {
+ public:
+  virtual void OnRecoveredPacket(const uint8_t* packet, size_t length) = 0;
+
+ protected:
+  virtual ~RecoveredPacketReceiver() = default;
+};
+
+class RtcpIntraFrameObserver {
+ public:
+  virtual ~RtcpIntraFrameObserver() {}
+
+  virtual void OnReceivedIntraFrameRequest(uint32_t ssrc) = 0;
+};
+
+class RtcpBandwidthObserver {
+ public:
+  // REMB or TMMBR
+  virtual void OnReceivedEstimatedBitrate(uint32_t bitrate) = 0;
+
+  virtual void OnReceivedRtcpReceiverReport(
+      const ReportBlockList& report_blocks,
+      int64_t rtt,
+      int64_t now_ms) = 0;
+
+  virtual ~RtcpBandwidthObserver() {}
+};
+
+struct PacketFeedback {
+  PacketFeedback(int64_t arrival_time_ms, uint16_t sequence_number)
+      : PacketFeedback(-1,
+                       arrival_time_ms,
+                       kNoSendTime,
+                       sequence_number,
+                       0,
+                       0,
+                       0,
+                       PacedPacketInfo()) {}
+
+  PacketFeedback(int64_t arrival_time_ms,
+                 int64_t send_time_ms,
+                 uint16_t sequence_number,
+                 size_t payload_size,
+                 const PacedPacketInfo& pacing_info)
+      : PacketFeedback(-1,
+                       arrival_time_ms,
+                       send_time_ms,
+                       sequence_number,
+                       payload_size,
+                       0,
+                       0,
+                       pacing_info) {}
+
+  PacketFeedback(int64_t creation_time_ms,
+                 uint16_t sequence_number,
+                 size_t payload_size,
+                 uint16_t local_net_id,
+                 uint16_t remote_net_id,
+                 const PacedPacketInfo& pacing_info)
+      : PacketFeedback(creation_time_ms,
+                       kNotReceived,
+                       kNoSendTime,
+                       sequence_number,
+                       payload_size,
+                       local_net_id,
+                       remote_net_id,
+                       pacing_info) {}
+
+  PacketFeedback(int64_t creation_time_ms,
+                 int64_t arrival_time_ms,
+                 int64_t send_time_ms,
+                 uint16_t sequence_number,
+                 size_t payload_size,
+                 uint16_t local_net_id,
+                 uint16_t remote_net_id,
+                 const PacedPacketInfo& pacing_info)
+      : creation_time_ms(creation_time_ms),
+        arrival_time_ms(arrival_time_ms),
+        send_time_ms(send_time_ms),
+        sequence_number(sequence_number),
+        payload_size(payload_size),
+        local_net_id(local_net_id),
+        remote_net_id(remote_net_id),
+        pacing_info(pacing_info) {}
+
+  static constexpr int kNotAProbe = -1;
+  static constexpr int64_t kNotReceived = -1;
+  static constexpr int64_t kNoSendTime = -1;
+
+  // NOTE! The variable |creation_time_ms| is not used when testing equality.
+  //       This is due to |creation_time_ms| only being used by SendTimeHistory
+  //       for book-keeping, and is of no interest outside that class.
+  // TODO(philipel): Remove |creation_time_ms| from PacketFeedback when cleaning
+  //                 up SendTimeHistory.
+  bool operator==(const PacketFeedback& rhs) const {
+    return arrival_time_ms == rhs.arrival_time_ms &&
+           send_time_ms == rhs.send_time_ms &&
+           sequence_number == rhs.sequence_number &&
+           payload_size == rhs.payload_size && pacing_info == rhs.pacing_info;
+  }
+
+  // Time corresponding to when this object was created.
+  int64_t creation_time_ms;
+  // Time corresponding to when the packet was received. Timestamped with the
+  // receiver's clock. For unreceived packet, the sentinel value kNotReceived
+  // is used.
+  int64_t arrival_time_ms;
+  // Time corresponding to when the packet was sent, timestamped with the
+  // sender's clock.
+  int64_t send_time_ms;
+  // Packet identifier, incremented with 1 for every packet generated by the
+  // sender.
+  uint16_t sequence_number;
+  // Session unique packet identifier, incremented with 1 for every packet
+  // generated by the sender.
+  int64_t long_sequence_number;
+  // Size of the packet excluding RTP headers.
+  size_t payload_size;
+  // The network route ids that this packet is associated with.
+  uint16_t local_net_id;
+  uint16_t remote_net_id;
+  // Pacing information about this packet.
+  PacedPacketInfo pacing_info;
+};
+
+class PacketFeedbackComparator {
+ public:
+  inline bool operator()(const PacketFeedback& lhs, const PacketFeedback& rhs) {
+    if (lhs.arrival_time_ms != rhs.arrival_time_ms)
+      return lhs.arrival_time_ms < rhs.arrival_time_ms;
+    if (lhs.send_time_ms != rhs.send_time_ms)
+      return lhs.send_time_ms < rhs.send_time_ms;
+    return lhs.sequence_number < rhs.sequence_number;
+  }
+};
+
+class TransportFeedbackObserver {
+ public:
+  TransportFeedbackObserver() {}
+  virtual ~TransportFeedbackObserver() {}
+
+  // Note: Transport-wide sequence number as sequence number.
+  virtual void AddPacket(uint32_t ssrc,
+                         uint16_t sequence_number,
+                         size_t length,
+                         const PacedPacketInfo& pacing_info) = 0;
+
+  virtual void OnTransportFeedback(const rtcp::TransportFeedback& feedback) = 0;
+};
+
+// Interface for PacketRouter to send rtcp feedback on behalf of
+// congestion controller.
+// TODO(bugs.webrtc.org/8239): Remove and use RtcpTransceiver directly
+// when RtcpTransceiver always present in rtp transport.
+class RtcpFeedbackSenderInterface {
+ public:
+  virtual ~RtcpFeedbackSenderInterface() = default;
+  virtual uint32_t SSRC() const = 0;
+  virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& feedback) = 0;
+  virtual void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) = 0;
+  virtual void UnsetRemb() = 0;
+};
+
+class PacketFeedbackObserver {
+ public:
+  virtual ~PacketFeedbackObserver() = default;
+
+  virtual void OnPacketAdded(uint32_t ssrc, uint16_t seq_num) = 0;
+  virtual void OnPacketFeedbackVector(
+      const std::vector<PacketFeedback>& packet_feedback_vector) = 0;
+};
+
+class RtcpRttStats {
+ public:
+  virtual void OnRttUpdate(int64_t rtt) = 0;
+
+  virtual int64_t LastProcessedRtt() const = 0;
+
+  virtual ~RtcpRttStats() {}
+};
+
+// Statistics about packet loss for a single directional connection. All values
+// are totals since the connection initiated.
+struct RtpPacketLossStats {
+  // The number of packets lost in events where no adjacent packets were also
+  // lost.
+  uint64_t single_packet_loss_count;
+  // The number of events in which more than one adjacent packet was lost.
+  uint64_t multiple_packet_loss_event_count;
+  // The number of packets lost in events where more than one adjacent packet
+  // was lost.
+  uint64_t multiple_packet_loss_packet_count;
+};
+
+class RtpPacketSender {
+ public:
+  RtpPacketSender() {}
+  virtual ~RtpPacketSender() {}
+
+  enum Priority {
+    kHighPriority = 0,    // Pass through; will be sent immediately.
+    kNormalPriority = 2,  // Put in back of the line.
+    kLowPriority = 3,     // Put in back of the low priority line.
+  };
+  // Low priority packets are mixed with the normal priority packets
+  // while we are paused.
+
+  // Returns true if we send the packet now, else it will add the packet
+  // information to the queue and call TimeToSendPacket when it's time to send.
+  virtual void InsertPacket(Priority priority,
+                            uint32_t ssrc,
+                            uint16_t sequence_number,
+                            int64_t capture_time_ms,
+                            size_t bytes,
+                            bool retransmission) = 0;
+
+  // Currently audio traffic is not accounted by pacer and passed through.
+  // With the introduction of audio BWE audio traffic will be accounted for
+  // the pacer budget calculation. The audio traffic still will be injected
+  // at high priority.
+  // TODO(alexnarest): Make it pure virtual after rtp_sender_unittest will be
+  // updated to support it
+  virtual void SetAccountForAudioPackets(bool account_for_audio) {}
+};
+
+class TransportSequenceNumberAllocator {
+ public:
+  TransportSequenceNumberAllocator() {}
+  virtual ~TransportSequenceNumberAllocator() {}
+
+  virtual uint16_t AllocateSequenceNumber() = 0;
+};
+
+struct RtpPacketCounter {
+  RtpPacketCounter()
+      : header_bytes(0), payload_bytes(0), padding_bytes(0), packets(0) {}
+
+  void Add(const RtpPacketCounter& other) {
+    header_bytes += other.header_bytes;
+    payload_bytes += other.payload_bytes;
+    padding_bytes += other.padding_bytes;
+    packets += other.packets;
+  }
+
+  void Subtract(const RtpPacketCounter& other) {
+    RTC_DCHECK_GE(header_bytes, other.header_bytes);
+    header_bytes -= other.header_bytes;
+    RTC_DCHECK_GE(payload_bytes, other.payload_bytes);
+    payload_bytes -= other.payload_bytes;
+    RTC_DCHECK_GE(padding_bytes, other.padding_bytes);
+    padding_bytes -= other.padding_bytes;
+    RTC_DCHECK_GE(packets, other.packets);
+    packets -= other.packets;
+  }
+
+  void AddPacket(size_t packet_length, const RTPHeader& header) {
+    ++packets;
+    header_bytes += header.headerLength;
+    padding_bytes += header.paddingLength;
+    payload_bytes +=
+        packet_length - (header.headerLength + header.paddingLength);
+  }
+
+  size_t TotalBytes() const {
+    return header_bytes + payload_bytes + padding_bytes;
+  }
+
+  size_t header_bytes;   // Number of bytes used by RTP headers.
+  size_t payload_bytes;  // Payload bytes, excluding RTP headers and padding.
+  size_t padding_bytes;  // Number of padding bytes.
+  uint32_t packets;      // Number of packets.
+};
+
+// Data usage statistics for a (rtp) stream.
+struct StreamDataCounters {
+  StreamDataCounters();
+
+  void Add(const StreamDataCounters& other) {
+    transmitted.Add(other.transmitted);
+    retransmitted.Add(other.retransmitted);
+    fec.Add(other.fec);
+    if (other.first_packet_time_ms != -1 &&
+        (other.first_packet_time_ms < first_packet_time_ms ||
+         first_packet_time_ms == -1)) {
+      // Use oldest time.
+      first_packet_time_ms = other.first_packet_time_ms;
+    }
+  }
+
+  void Subtract(const StreamDataCounters& other) {
+    transmitted.Subtract(other.transmitted);
+    retransmitted.Subtract(other.retransmitted);
+    fec.Subtract(other.fec);
+    if (other.first_packet_time_ms != -1 &&
+        (other.first_packet_time_ms > first_packet_time_ms ||
+         first_packet_time_ms == -1)) {
+      // Use youngest time.
+      first_packet_time_ms = other.first_packet_time_ms;
+    }
+  }
+
+  int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
+    return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
+  }
+
+  // Returns the number of bytes corresponding to the actual media payload (i.e.
+  // RTP headers, padding, retransmissions and fec packets are excluded).
+  // Note this function does not have meaning for an RTX stream.
+  size_t MediaPayloadBytes() const {
+    return transmitted.payload_bytes - retransmitted.payload_bytes -
+           fec.payload_bytes;
+  }
+
+  int64_t first_packet_time_ms;    // Time when first packet is sent/received.
+  RtpPacketCounter transmitted;    // Number of transmitted packets/bytes.
+  RtpPacketCounter retransmitted;  // Number of retransmitted packets/bytes.
+  RtpPacketCounter fec;            // Number of redundancy packets/bytes.
+};
+
+// Callback, called whenever byte/packet counts have been updated.
+class StreamDataCountersCallback {
+ public:
+  virtual ~StreamDataCountersCallback() {}
+
+  virtual void DataCountersUpdated(const StreamDataCounters& counters,
+                                   uint32_t ssrc) = 0;
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_INCLUDE_RTP_RTCP_DEFINES_H_
diff --git a/modules/rtp_rtcp/include/ulpfec_receiver.h b/modules/rtp_rtcp/include/ulpfec_receiver.h
new file mode 100644
index 0000000..6ea8496
--- /dev/null
+++ b/modules/rtp_rtcp/include/ulpfec_receiver.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_INCLUDE_ULPFEC_RECEIVER_H_
+#define MODULES_RTP_RTCP_INCLUDE_ULPFEC_RECEIVER_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+struct FecPacketCounter {
+  FecPacketCounter()
+      : num_packets(0),
+        num_fec_packets(0),
+        num_recovered_packets(0),
+        first_packet_time_ms(-1) {}
+
+  size_t num_packets;            // Number of received packets.
+  size_t num_fec_packets;        // Number of received FEC packets.
+  size_t num_recovered_packets;  // Number of recovered media packets using FEC.
+  int64_t first_packet_time_ms;  // Time when first packet is received.
+};
+
+class UlpfecReceiver {
+ public:
+  static UlpfecReceiver* Create(uint32_t ssrc,
+                                RecoveredPacketReceiver* callback);
+
+  virtual ~UlpfecReceiver() {}
+
+  // Takes a RED packet, strips the RED header, and adds the resulting
+  // "virtual" RTP packet(s) into the internal buffer.
+  //
+  // TODO(brandtr): Set |ulpfec_payload_type| during constructor call,
+  // rather than as a parameter here.
+  virtual int32_t AddReceivedRedPacket(const RTPHeader& rtp_header,
+                                       const uint8_t* incoming_rtp_packet,
+                                       size_t packet_length,
+                                       uint8_t ulpfec_payload_type) = 0;
+
+  // Sends the received packets to the FEC and returns all packets
+  // (both original media and recovered) through the callback.
+  virtual int32_t ProcessReceivedFec() = 0;
+
+  // Returns a counter describing the added and recovered packets.
+  virtual FecPacketCounter GetPacketCounter() const = 0;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_INCLUDE_ULPFEC_RECEIVER_H_
diff --git a/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.cc b/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.cc
new file mode 100644
index 0000000..e0183f8
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.cc
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h"
+
+namespace webrtc {
+
+MockRecoveredPacketReceiver::MockRecoveredPacketReceiver() = default;
+MockRecoveredPacketReceiver::~MockRecoveredPacketReceiver() = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h b/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h
new file mode 100644
index 0000000..d6442ad
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_MOCKS_MOCK_RECOVERED_PACKET_RECEIVER_H_
+#define MODULES_RTP_RTCP_MOCKS_MOCK_RECOVERED_PACKET_RECEIVER_H_
+
+#include "modules/rtp_rtcp/include/flexfec_receiver.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRecoveredPacketReceiver : public RecoveredPacketReceiver {
+ public:
+  MockRecoveredPacketReceiver();
+  ~MockRecoveredPacketReceiver();
+  MOCK_METHOD2(OnRecoveredPacket, void(const uint8_t* packet, size_t length));
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_MOCKS_MOCK_RECOVERED_PACKET_RECEIVER_H_
diff --git a/modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.cc b/modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.cc
new file mode 100644
index 0000000..abaf129
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.cc
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h"
+
+namespace webrtc {
+
+MockRtcpBandwidthObserver::MockRtcpBandwidthObserver() = default;
+MockRtcpBandwidthObserver::~MockRtcpBandwidthObserver() = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h b/modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h
new file mode 100644
index 0000000..b9a8f79
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_BANDWIDTH_OBSERVER_H_
+#define MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_BANDWIDTH_OBSERVER_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtcpBandwidthObserver : public RtcpBandwidthObserver {
+ public:
+  MockRtcpBandwidthObserver();
+  ~MockRtcpBandwidthObserver();
+
+  MOCK_METHOD1(OnReceivedEstimatedBitrate, void(uint32_t));
+  MOCK_METHOD3(OnReceivedRtcpReceiverReport,
+               void(const ReportBlockList&, int64_t, int64_t));
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_BANDWIDTH_OBSERVER_H_
diff --git a/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.cc b/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.cc
new file mode 100644
index 0000000..1aca566
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.cc
@@ -0,0 +1,18 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h"
+
+namespace webrtc {
+
+MockRtcpRttStats::MockRtcpRttStats() = default;
+MockRtcpRttStats::~MockRtcpRttStats() = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h b/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h
new file mode 100644
index 0000000..6ccef61
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_RTT_STATS_H_
+#define MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_RTT_STATS_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtcpRttStats : public RtcpRttStats {
+ public:
+  MockRtcpRttStats();
+  ~MockRtcpRttStats();
+
+  MOCK_METHOD1(OnRttUpdate, void(int64_t rtt));
+  MOCK_CONST_METHOD0(LastProcessedRtt, int64_t());
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_MOCKS_MOCK_RTCP_RTT_STATS_H_
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.cc b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.cc
new file mode 100644
index 0000000..d24c1b0
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.cc
@@ -0,0 +1,21 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+
+namespace webrtc {
+
+MockRtpData::MockRtpData() = default;
+MockRtpData::~MockRtpData() = default;
+
+MockRtpRtcp::MockRtpRtcp() = default;
+MockRtpRtcp::~MockRtpRtcp() = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
new file mode 100644
index 0000000..d176930
--- /dev/null
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -0,0 +1,196 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_
+#define MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "modules/include/module.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "rtc_base/checks.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockRtpData : public RtpData {
+ public:
+  MockRtpData();
+  ~MockRtpData();
+
+  MOCK_METHOD3(OnReceivedPayloadData,
+               int32_t(const uint8_t* payload_data,
+                       size_t payload_size,
+                       const WebRtcRTPHeader* rtp_header));
+};
+
+class MockRtpRtcp : public RtpRtcp {
+ public:
+  MockRtpRtcp();
+  ~MockRtpRtcp();
+
+  MOCK_METHOD2(IncomingRtcpPacket,
+               void(const uint8_t* incoming_packet, size_t packet_length));
+  MOCK_METHOD1(SetRemoteSSRC, void(uint32_t ssrc));
+  MOCK_METHOD1(SetMaxRtpPacketSize, void(size_t size));
+  MOCK_CONST_METHOD0(MaxRtpPacketSize, size_t());
+  MOCK_METHOD1(RegisterSendPayload, int32_t(const CodecInst& voice_codec));
+  MOCK_METHOD2(RegisterVideoSendPayload,
+               void(int payload_type, const char* payload_name));
+  MOCK_METHOD1(DeRegisterSendPayload, int32_t(int8_t payload_type));
+  MOCK_METHOD2(RegisterSendRtpHeaderExtension,
+               int32_t(RTPExtensionType type, uint8_t id));
+  MOCK_METHOD1(DeregisterSendRtpHeaderExtension,
+               int32_t(RTPExtensionType type));
+  MOCK_CONST_METHOD0(HasBweExtensions, bool());
+  MOCK_CONST_METHOD0(StartTimestamp, uint32_t());
+  MOCK_METHOD1(SetStartTimestamp, void(uint32_t timestamp));
+  MOCK_CONST_METHOD0(SequenceNumber, uint16_t());
+  MOCK_METHOD1(SetSequenceNumber, void(uint16_t seq));
+  MOCK_METHOD1(SetRtpState, void(const RtpState& rtp_state));
+  MOCK_METHOD1(SetRtxState, void(const RtpState& rtp_state));
+  MOCK_CONST_METHOD0(GetRtpState, RtpState());
+  MOCK_CONST_METHOD0(GetRtxState, RtpState());
+  MOCK_CONST_METHOD0(SSRC, uint32_t());
+  MOCK_METHOD1(SetSSRC, void(uint32_t ssrc));
+  MOCK_METHOD1(SetMid, void(const std::string& mid));
+  MOCK_CONST_METHOD1(CSRCs, int32_t(uint32_t csrcs[kRtpCsrcSize]));
+  MOCK_METHOD1(SetCsrcs, void(const std::vector<uint32_t>& csrcs));
+  MOCK_METHOD1(SetCSRCStatus, int32_t(bool include));
+  MOCK_METHOD1(SetRtxSendStatus, void(int modes));
+  MOCK_CONST_METHOD0(RtxSendStatus, int());
+  MOCK_METHOD1(SetRtxSsrc, void(uint32_t));
+  MOCK_METHOD2(SetRtxSendPayloadType, void(int, int));
+  MOCK_CONST_METHOD0(FlexfecSsrc, absl::optional<uint32_t>());
+  MOCK_CONST_METHOD0(RtxSendPayloadType, std::pair<int, int>());
+  MOCK_METHOD1(SetSendingStatus, int32_t(bool sending));
+  MOCK_CONST_METHOD0(Sending, bool());
+  MOCK_METHOD1(SetSendingMediaStatus, void(bool sending));
+  MOCK_CONST_METHOD0(SendingMedia, bool());
+  MOCK_CONST_METHOD4(BitrateSent,
+                     void(uint32_t* total_rate,
+                          uint32_t* video_rate,
+                          uint32_t* fec_rate,
+                          uint32_t* nack_rate));
+  MOCK_CONST_METHOD1(EstimatedReceiveBandwidth,
+                     int(uint32_t* available_bandwidth));
+  MOCK_METHOD9(SendOutgoingData,
+               bool(FrameType frame_type,
+                    int8_t payload_type,
+                    uint32_t timestamp,
+                    int64_t capture_time_ms,
+                    const uint8_t* payload_data,
+                    size_t payload_size,
+                    const RTPFragmentationHeader* fragmentation,
+                    const RTPVideoHeader* rtp_video_header,
+                    uint32_t* frame_id_out));
+  MOCK_METHOD5(TimeToSendPacket,
+               bool(uint32_t ssrc,
+                    uint16_t sequence_number,
+                    int64_t capture_time_ms,
+                    bool retransmission,
+                    const PacedPacketInfo& pacing_info));
+  MOCK_METHOD2(TimeToSendPadding,
+               size_t(size_t bytes, const PacedPacketInfo& pacing_info));
+  MOCK_METHOD2(RegisterRtcpObservers,
+               void(RtcpIntraFrameObserver* intra_frame_callback,
+                    RtcpBandwidthObserver* bandwidth_callback));
+  MOCK_CONST_METHOD0(RTCP, RtcpMode());
+  MOCK_METHOD1(SetRTCPStatus, void(RtcpMode method));
+  MOCK_METHOD1(SetCNAME, int32_t(const char cname[RTCP_CNAME_SIZE]));
+  MOCK_CONST_METHOD2(RemoteCNAME,
+                     int32_t(uint32_t remote_ssrc,
+                             char cname[RTCP_CNAME_SIZE]));
+  MOCK_CONST_METHOD5(RemoteNTP,
+                     int32_t(uint32_t* received_ntp_secs,
+                             uint32_t* received_ntp_frac,
+                             uint32_t* rtcp_arrival_time_secs,
+                             uint32_t* rtcp_arrival_time_frac,
+                             uint32_t* rtcp_timestamp));
+  MOCK_METHOD2(AddMixedCNAME,
+               int32_t(uint32_t ssrc, const char cname[RTCP_CNAME_SIZE]));
+  MOCK_METHOD1(RemoveMixedCNAME, int32_t(uint32_t ssrc));
+  MOCK_CONST_METHOD5(RTT,
+                     int32_t(uint32_t remote_ssrc,
+                             int64_t* rtt,
+                             int64_t* avg_rtt,
+                             int64_t* min_rtt,
+                             int64_t* max_rtt));
+  MOCK_METHOD1(SendRTCP, int32_t(RTCPPacketType packet_type));
+  MOCK_METHOD1(SendCompoundRTCP,
+               int32_t(const std::set<RTCPPacketType>& packet_types));
+  MOCK_CONST_METHOD2(DataCountersRTP,
+                     int32_t(size_t* bytes_sent, uint32_t* packets_sent));
+  MOCK_CONST_METHOD2(GetSendStreamDataCounters,
+                     void(StreamDataCounters*, StreamDataCounters*));
+  MOCK_CONST_METHOD3(GetRtpPacketLossStats,
+                     void(bool, uint32_t, struct RtpPacketLossStats*));
+  MOCK_CONST_METHOD1(RemoteRTCPStat,
+                     int32_t(std::vector<RTCPReportBlock>* receive_blocks));
+  MOCK_METHOD4(SetRTCPApplicationSpecificData,
+               int32_t(uint8_t sub_type,
+                       uint32_t name,
+                       const uint8_t* data,
+                       uint16_t length));
+  MOCK_METHOD1(SetRTCPVoIPMetrics, int32_t(const RTCPVoIPMetric* voip_metric));
+  MOCK_METHOD1(SetRtcpXrRrtrStatus, void(bool enable));
+  MOCK_CONST_METHOD0(RtcpXrRrtrStatus, bool());
+  MOCK_METHOD2(SetRemb, void(int64_t bitrate, std::vector<uint32_t> ssrcs));
+  MOCK_METHOD0(UnsetRemb, void());
+  MOCK_CONST_METHOD0(TMMBR, bool());
+  MOCK_METHOD1(SetTMMBRStatus, void(bool enable));
+  MOCK_METHOD1(OnBandwidthEstimateUpdate, void(uint16_t bandwidth_kbit));
+  MOCK_CONST_METHOD0(SelectiveRetransmissions, int());
+  MOCK_METHOD1(SetSelectiveRetransmissions, int(uint8_t settings));
+  MOCK_METHOD2(SendNACK, int32_t(const uint16_t* nack_list, uint16_t size));
+  MOCK_METHOD1(SendNack, void(const std::vector<uint16_t>& sequence_numbers));
+  MOCK_METHOD2(SetStorePacketsStatus,
+               void(bool enable, uint16_t number_to_store));
+  MOCK_CONST_METHOD0(StorePackets, bool());
+  MOCK_METHOD1(RegisterRtcpStatisticsCallback, void(RtcpStatisticsCallback*));
+  MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*());
+  MOCK_METHOD1(SendFeedbackPacket, bool(const rtcp::TransportFeedback& packet));
+  MOCK_METHOD3(SendTelephoneEventOutband,
+               int32_t(uint8_t key, uint16_t time_ms, uint8_t level));
+  MOCK_METHOD1(SetAudioLevel, int32_t(uint8_t level_dbov));
+  MOCK_METHOD1(SetTargetSendBitrate, void(uint32_t bitrate_bps));
+  MOCK_METHOD2(SetUlpfecConfig,
+               void(int red_payload_type, int fec_payload_type));
+  MOCK_METHOD2(SetFecParameters,
+               bool(const FecProtectionParams& delta_params,
+                    const FecProtectionParams& key_params));
+  MOCK_METHOD1(SetKeyFrameRequestMethod, int32_t(KeyFrameRequestMethod method));
+  MOCK_METHOD0(RequestKeyFrame, int32_t());
+  MOCK_METHOD0(Process, void());
+  MOCK_METHOD1(RegisterSendChannelRtpStatisticsCallback,
+               void(StreamDataCountersCallback*));
+  MOCK_CONST_METHOD0(GetSendChannelRtpStatisticsCallback,
+                     StreamDataCountersCallback*(void));
+  MOCK_METHOD1(SetVideoBitrateAllocation, void(const VideoBitrateAllocation&));
+  // Members.
+  unsigned int remote_ssrc_;
+
+ private:
+  // Mocking this method is currently not required and having a default
+  // implementation like MOCK_METHOD0(TimeUntilNextProcess, int64_t())
+  // can be dangerous since it can cause a tight loop on a process thread.
+  virtual int64_t TimeUntilNextProcess() { return 0xffffffff; }
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_
diff --git a/modules/rtp_rtcp/source/byte_io.h b/modules/rtp_rtcp/source/byte_io.h
new file mode 100644
index 0000000..f9d973b
--- /dev/null
+++ b/modules/rtp_rtcp/source/byte_io.h
@@ -0,0 +1,402 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
+#define MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
+
+// This file contains classes for reading and writing integer types from/to
+// byte array representations. Signed/unsigned, partial (whole byte) sizes,
+// and big/little endian byte order is all supported.
+//
+// Usage examples:
+//
+// uint8_t* buffer = ...;
+//
+// // Read an unsigned 4 byte integer in big endian format
+// uint32_t val = ByteReader<uint32_t>::ReadBigEndian(buffer);
+//
+// // Read a signed 24-bit (3 byte) integer in little endian format
+// int32_t val = ByteReader<int32_t, 3>::ReadLittle(buffer);
+//
+// // Write an unsigned 8 byte integer in little endian format
+// ByteWriter<uint64_t>::WriteLittleEndian(buffer, val);
+//
+// Write an unsigned 40-bit (5 byte) integer in big endian format
+// ByteWriter<uint64_t, 5>::WriteBigEndian(buffer, val);
+//
+// These classes are implemented as recursive templetizations, inteded to make
+// it easy for the compiler to completely inline the reading/writing.
+
+#include <limits>
+
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+// According to ISO C standard ISO/IEC 9899, section 6.2.6.2 (2), the three
+// representations of signed integers allowed are two's complement, one's
+// complement and sign/magnitude. We can detect which is used by looking at
+// the two last bits of -1, which will be 11 in two's complement, 10 in one's
+// complement and 01 in sign/magnitude.
+// TODO(sprang): In the unlikely event that we actually need to support a
+// platform that doesn't use two's complement, implement conversion to/from
+// wire format.
+
+// Assume the if any one signed integer type is two's complement, then all
+// other will be too.
+static_assert(
+    (-1 & 0x03) == 0x03,
+    "Only two's complement representation of signed integers supported.");
+
+// Plain const char* won't work for static_assert, use #define instead.
+#define kSizeErrorMsg "Byte size must be less than or equal to data type size."
+
+// Utility class for getting the unsigned equivalent of a signed type.
+template <typename T>
+struct UnsignedOf;
+
+// Class for reading integers from a sequence of bytes.
+// T = type of integer, B = bytes to read, is_signed = true if signed integer.
+// If is_signed is true and B < sizeof(T), sign extension might be needed.
+template <typename T,
+          unsigned int B = sizeof(T),
+          bool is_signed = std::numeric_limits<T>::is_signed>
+class ByteReader;
+
+// Specialization of ByteReader for unsigned types.
+template <typename T, unsigned int B>
+class ByteReader<T, B, false> {
+ public:
+  static T ReadBigEndian(const uint8_t* data) {
+    static_assert(B <= sizeof(T), kSizeErrorMsg);
+    return InternalReadBigEndian(data);
+  }
+
+  static T ReadLittleEndian(const uint8_t* data) {
+    static_assert(B <= sizeof(T), kSizeErrorMsg);
+    return InternalReadLittleEndian(data);
+  }
+
+ private:
+  static T InternalReadBigEndian(const uint8_t* data) {
+    T val(0);
+    for (unsigned int i = 0; i < B; ++i)
+      val |= static_cast<T>(data[i]) << ((B - 1 - i) * 8);
+    return val;
+  }
+
+  static T InternalReadLittleEndian(const uint8_t* data) {
+    T val(0);
+    for (unsigned int i = 0; i < B; ++i)
+      val |= static_cast<T>(data[i]) << (i * 8);
+    return val;
+  }
+};
+
+// Specialization of ByteReader for signed types.
+template <typename T, unsigned int B>
+class ByteReader<T, B, true> {
+ public:
+  typedef typename UnsignedOf<T>::Type U;
+
+  static T ReadBigEndian(const uint8_t* data) {
+    U unsigned_val = ByteReader<T, B, false>::ReadBigEndian(data);
+    if (B < sizeof(T))
+      unsigned_val = SignExtend(unsigned_val);
+    return ReinterpretAsSigned(unsigned_val);
+  }
+
+  static T ReadLittleEndian(const uint8_t* data) {
+    U unsigned_val = ByteReader<T, B, false>::ReadLittleEndian(data);
+    if (B < sizeof(T))
+      unsigned_val = SignExtend(unsigned_val);
+    return ReinterpretAsSigned(unsigned_val);
+  }
+
+ private:
+  // As a hack to avoid implementation-specific or undefined behavior when
+  // bit-shifting or casting signed integers, read as a signed equivalent
+  // instead and convert to signed. This is safe since we have asserted that
+  // two's complement for is used.
+  static T ReinterpretAsSigned(U unsigned_val) {
+    // An unsigned value with only the highest order bit set (ex 0x80).
+    const U kUnsignedHighestBitMask = static_cast<U>(1)
+                                      << ((sizeof(U) * 8) - 1);
+    // A signed value with only the highest bit set. Since this is two's
+    // complement form, we can use the min value from std::numeric_limits.
+    const T kSignedHighestBitMask = std::numeric_limits<T>::min();
+
+    T val;
+    if ((unsigned_val & kUnsignedHighestBitMask) != 0) {
+      // Casting is only safe when unsigned value can be represented in the
+      // signed target type, so mask out highest bit and mask it back manually.
+      val = static_cast<T>(unsigned_val & ~kUnsignedHighestBitMask);
+      val |= kSignedHighestBitMask;
+    } else {
+      val = static_cast<T>(unsigned_val);
+    }
+    return val;
+  }
+
+  // If number of bytes is less than native data type (eg 24 bit, in int32_t),
+  // and the most significant bit of the actual data is set, we must sign
+  // extend the remaining byte(s) with ones so that the correct negative
+  // number is retained.
+  // Ex: 0x810A0B -> 0xFF810A0B, but 0x710A0B -> 0x00710A0B
+  static U SignExtend(const U val) {
+    const uint8_t kMsb = static_cast<uint8_t>(val >> ((B - 1) * 8));
+    if ((kMsb & 0x80) != 0) {
+      // Create a mask where all bits used by the B bytes are set to one,
+      // for instance 0x00FFFFFF for B = 3. Bit-wise invert that mask (to
+      // (0xFF000000 in the example above) and add it to the input value.
+      // The "B % sizeof(T)" is a workaround to undefined values warnings for
+      // B == sizeof(T), in which case this code won't be called anyway.
+      const U kUsedBitsMask = (1 << ((B % sizeof(T)) * 8)) - 1;
+      return ~kUsedBitsMask | val;
+    }
+    return val;
+  }
+};
+
+// Class for writing integers to a sequence of bytes
+// T = type of integer, B = bytes to write
+template <typename T,
+          unsigned int B = sizeof(T),
+          bool is_signed = std::numeric_limits<T>::is_signed>
+class ByteWriter;
+
+// Specialization of ByteWriter for unsigned types.
+template <typename T, unsigned int B>
+class ByteWriter<T, B, false> {
+ public:
+  static void WriteBigEndian(uint8_t* data, T val) {
+    static_assert(B <= sizeof(T), kSizeErrorMsg);
+    for (unsigned int i = 0; i < B; ++i) {
+      data[i] = val >> ((B - 1 - i) * 8);
+    }
+  }
+
+  static void WriteLittleEndian(uint8_t* data, T val) {
+    static_assert(B <= sizeof(T), kSizeErrorMsg);
+    for (unsigned int i = 0; i < B; ++i) {
+      data[i] = val >> (i * 8);
+    }
+  }
+};
+
+// Specialization of ByteWriter for signed types.
+template <typename T, unsigned int B>
+class ByteWriter<T, B, true> {
+ public:
+  typedef typename UnsignedOf<T>::Type U;
+
+  static void WriteBigEndian(uint8_t* data, T val) {
+    ByteWriter<U, B, false>::WriteBigEndian(data, ReinterpretAsUnsigned(val));
+  }
+
+  static void WriteLittleEndian(uint8_t* data, T val) {
+    ByteWriter<U, B, false>::WriteLittleEndian(data,
+                                               ReinterpretAsUnsigned(val));
+  }
+
+ private:
+  static U ReinterpretAsUnsigned(T val) {
+    // According to ISO C standard ISO/IEC 9899, section 6.3.1.3 (1, 2) a
+    // conversion from signed to unsigned keeps the value if the new type can
+    // represent it, and otherwise adds one more than the max value of T until
+    // the value is in range. For two's complement, this fortunately means
+    // that the bit-wise value will be intact. Thus, since we have asserted that
+    // two's complement form is actually used, a simple cast is sufficient.
+    return static_cast<U>(val);
+  }
+};
+
+// ----- Below follows specializations of UnsignedOf utility class -----
+
+template <>
+struct UnsignedOf<int8_t> {
+  typedef uint8_t Type;
+};
+template <>
+struct UnsignedOf<int16_t> {
+  typedef uint16_t Type;
+};
+template <>
+struct UnsignedOf<int32_t> {
+  typedef uint32_t Type;
+};
+template <>
+struct UnsignedOf<int64_t> {
+  typedef uint64_t Type;
+};
+
+// ----- Below follows specializations for unsigned, B in { 1, 2, 4, 8 } -----
+
+// TODO(sprang): Check if these actually help or if generic cases will be
+// unrolled to and optimized to similar performance.
+
+// Specializations for single bytes
+template <typename T>
+class ByteReader<T, 1, false> {
+ public:
+  static T ReadBigEndian(const uint8_t* data) {
+    static_assert(sizeof(T) == 1, kSizeErrorMsg);
+    return data[0];
+  }
+
+  static T ReadLittleEndian(const uint8_t* data) {
+    static_assert(sizeof(T) == 1, kSizeErrorMsg);
+    return data[0];
+  }
+};
+
+template <typename T>
+class ByteWriter<T, 1, false> {
+ public:
+  static void WriteBigEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) == 1, kSizeErrorMsg);
+    data[0] = val;
+  }
+
+  static void WriteLittleEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) == 1, kSizeErrorMsg);
+    data[0] = val;
+  }
+};
+
+// Specializations for two byte words
+template <typename T>
+class ByteReader<T, 2, false> {
+ public:
+  static T ReadBigEndian(const uint8_t* data) {
+    static_assert(sizeof(T) >= 2, kSizeErrorMsg);
+    return (data[0] << 8) | data[1];
+  }
+
+  static T ReadLittleEndian(const uint8_t* data) {
+    static_assert(sizeof(T) >= 2, kSizeErrorMsg);
+    return data[0] | (data[1] << 8);
+  }
+};
+
+template <typename T>
+class ByteWriter<T, 2, false> {
+ public:
+  static void WriteBigEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) >= 2, kSizeErrorMsg);
+    data[0] = val >> 8;
+    data[1] = val;
+  }
+
+  static void WriteLittleEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) >= 2, kSizeErrorMsg);
+    data[0] = val;
+    data[1] = val >> 8;
+  }
+};
+
+// Specializations for four byte words.
+template <typename T>
+class ByteReader<T, 4, false> {
+ public:
+  static T ReadBigEndian(const uint8_t* data) {
+    static_assert(sizeof(T) >= 4, kSizeErrorMsg);
+    return (Get(data, 0) << 24) | (Get(data, 1) << 16) | (Get(data, 2) << 8) |
+           Get(data, 3);
+  }
+
+  static T ReadLittleEndian(const uint8_t* data) {
+    static_assert(sizeof(T) >= 4, kSizeErrorMsg);
+    return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
+           (Get(data, 3) << 24);
+  }
+
+ private:
+  inline static T Get(const uint8_t* data, unsigned int index) {
+    return static_cast<T>(data[index]);
+  }
+};
+
+// Specializations for four byte words.
+template <typename T>
+class ByteWriter<T, 4, false> {
+ public:
+  static void WriteBigEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) >= 4, kSizeErrorMsg);
+    data[0] = val >> 24;
+    data[1] = val >> 16;
+    data[2] = val >> 8;
+    data[3] = val;
+  }
+
+  static void WriteLittleEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) >= 4, kSizeErrorMsg);
+    data[0] = val;
+    data[1] = val >> 8;
+    data[2] = val >> 16;
+    data[3] = val >> 24;
+  }
+};
+
+// Specializations for eight byte words.
+template <typename T>
+class ByteReader<T, 8, false> {
+ public:
+  static T ReadBigEndian(const uint8_t* data) {
+    static_assert(sizeof(T) >= 8, kSizeErrorMsg);
+    return (Get(data, 0) << 56) | (Get(data, 1) << 48) | (Get(data, 2) << 40) |
+           (Get(data, 3) << 32) | (Get(data, 4) << 24) | (Get(data, 5) << 16) |
+           (Get(data, 6) << 8) | Get(data, 7);
+  }
+
+  static T ReadLittleEndian(const uint8_t* data) {
+    static_assert(sizeof(T) >= 8, kSizeErrorMsg);
+    return Get(data, 0) | (Get(data, 1) << 8) | (Get(data, 2) << 16) |
+           (Get(data, 3) << 24) | (Get(data, 4) << 32) | (Get(data, 5) << 40) |
+           (Get(data, 6) << 48) | (Get(data, 7) << 56);
+  }
+
+ private:
+  inline static T Get(const uint8_t* data, unsigned int index) {
+    return static_cast<T>(data[index]);
+  }
+};
+
+template <typename T>
+class ByteWriter<T, 8, false> {
+ public:
+  static void WriteBigEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) >= 8, kSizeErrorMsg);
+    data[0] = val >> 56;
+    data[1] = val >> 48;
+    data[2] = val >> 40;
+    data[3] = val >> 32;
+    data[4] = val >> 24;
+    data[5] = val >> 16;
+    data[6] = val >> 8;
+    data[7] = val;
+  }
+
+  static void WriteLittleEndian(uint8_t* data, T val) {
+    static_assert(sizeof(T) >= 8, kSizeErrorMsg);
+    data[0] = val;
+    data[1] = val >> 8;
+    data[2] = val >> 16;
+    data[3] = val >> 24;
+    data[4] = val >> 32;
+    data[5] = val >> 40;
+    data[6] = val >> 48;
+    data[7] = val >> 56;
+  }
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_BYTE_IO_H_
diff --git a/modules/rtp_rtcp/source/byte_io_unittest.cc b/modules/rtp_rtcp/source/byte_io_unittest.cc
new file mode 100644
index 0000000..20b6636
--- /dev/null
+++ b/modules/rtp_rtcp/source/byte_io_unittest.cc
@@ -0,0 +1,269 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <limits>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+class ByteIoTest : public ::testing::Test {
+ protected:
+  ByteIoTest() = default;
+  ~ByteIoTest() override = default;
+
+  enum { kAlignments = sizeof(uint64_t) - 1 };
+
+  // Method to create a test value that is not the same when byte reversed.
+  template <typename T>
+  T CreateTestValue(bool negative, uint8_t num_bytes) {
+    // Examples of output:
+    // T = int32_t, negative = false, num_bytes = 4: 0x00010203
+    // T = int32_t, negative = true, num_bytes = 4: 0xFFFEFDFC
+    // T = int32_t, negative = false, num_bytes = 3: 0x000102
+    // * T = int32_t, negative = true, num_bytes = 3: 0xFFFEFD
+
+    T val = 0;
+    for (uint8_t i = 0; i != num_bytes; ++i) {
+      val = (val << 8) + (negative ? (0xFF - i) : (i + 1));
+    }
+
+    // This loop will create a sign extend mask if num_bytes if necessary.
+    // For the last example (marked * above), the number needs to be sign
+    // extended to be a valid int32_t. The sign extend mask is 0xFF000000.
+    // Comments for each step with this example below.
+    if (std::numeric_limits<T>::is_signed && negative &&
+        num_bytes < sizeof(T)) {
+      // Start with mask = 0xFFFFFFFF.
+      T mask = static_cast<T>(-1);
+      // Create a temporary for the lowest byte (0x000000FF).
+      const T neg_byte = static_cast<T>(0xFF);
+      for (int i = 0; i < num_bytes; ++i) {
+        // And the inverse of the temporary and the mask:
+        // 0xFFFFFFFF & 0xFFFFFF00 = 0xFFFFFF00.
+        // 0xFFFFFF00 & 0xFFFF00FF = 0xFFFF0000.
+        // 0xFFFF0000 & 0xFF00FFFF = 0xFF000000.
+        mask &= ~(neg_byte << (i * 8));
+      }
+      // Add the sign extension mask to the actual value.
+      val |= mask;
+    }
+    return val;
+  }
+
+  // Populate byte buffer with value, in big endian format.
+  template <typename T>
+  void PopulateTestData(uint8_t* data, T value, int num_bytes, bool bigendian) {
+    if (bigendian) {
+      for (int i = 0; i < num_bytes; ++i) {
+        data[i] = (value >> ((num_bytes - i - 1) * 8)) & 0xFF;
+      }
+    } else {
+      for (int i = 0; i < num_bytes; ++i) {
+        data[i] = (value >> (i * 8)) & 0xFF;
+      }
+    }
+  }
+
+  // Test reading big endian numbers.
+  // Template arguments: Type T, read method RM(buffer), B bytes of data.
+  template <typename T, T (*RM)(const uint8_t*), int B>
+  void TestRead(bool big_endian) {
+    // Test both for values that are positive and negative (if signed)
+    for (int neg = 0; neg < 2; ++neg) {
+      bool negative = neg > 0;
+
+      // Write test value to byte buffer, in big endian format.
+      T test_value = CreateTestValue<T>(negative, B);
+      uint8_t bytes[B + kAlignments];
+
+      // Make one test for each alignment.
+      for (int i = 0; i < kAlignments; ++i) {
+        PopulateTestData(bytes + i, test_value, B, big_endian);
+
+        // Check that test value is retrieved from buffer when used read method.
+        EXPECT_EQ(test_value, RM(bytes + i));
+      }
+    }
+  }
+
+  // Test writing big endian numbers.
+  // Template arguments: Type T, write method WM(buffer, value), B bytes of data
+  template <typename T, void (*WM)(uint8_t*, T), int B>
+  void TestWrite(bool big_endian) {
+    // Test both for values that are positive and negative (if signed).
+    for (int neg = 0; neg < 2; ++neg) {
+      bool negative = neg > 0;
+
+      // Write test value to byte buffer, in big endian format.
+      T test_value = CreateTestValue<T>(negative, B);
+      uint8_t expected_bytes[B + kAlignments];
+      uint8_t bytes[B + kAlignments];
+
+      // Make one test for each alignment.
+      for (int i = 0; i < kAlignments; ++i) {
+        PopulateTestData(expected_bytes + i, test_value, B, big_endian);
+
+        // Zero initialize buffer and let WM populate it.
+        memset(bytes, 0, B + kAlignments);
+        WM(bytes + i, test_value);
+
+        // Check that data produced by WM is big endian as expected.
+        for (int j = 0; j < B; ++j) {
+          EXPECT_EQ(expected_bytes[i + j], bytes[i + j]);
+        }
+      }
+    }
+  }
+};
+
+TEST_F(ByteIoTest, Test16UBitBigEndian) {
+  TestRead<uint16_t, ByteReader<uint16_t>::ReadBigEndian, sizeof(uint16_t)>(
+      true);
+  TestWrite<uint16_t, ByteWriter<uint16_t>::WriteBigEndian, sizeof(uint16_t)>(
+      true);
+}
+
+TEST_F(ByteIoTest, Test24UBitBigEndian) {
+  TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadBigEndian, 3>(true);
+  TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteBigEndian, 3>(true);
+}
+
+TEST_F(ByteIoTest, Test32UBitBigEndian) {
+  TestRead<uint32_t, ByteReader<uint32_t>::ReadBigEndian, sizeof(uint32_t)>(
+      true);
+  TestWrite<uint32_t, ByteWriter<uint32_t>::WriteBigEndian, sizeof(uint32_t)>(
+      true);
+}
+
+TEST_F(ByteIoTest, Test64UBitBigEndian) {
+  TestRead<uint64_t, ByteReader<uint64_t>::ReadBigEndian, sizeof(uint64_t)>(
+      true);
+  TestWrite<uint64_t, ByteWriter<uint64_t>::WriteBigEndian, sizeof(uint64_t)>(
+      true);
+}
+
+TEST_F(ByteIoTest, Test16SBitBigEndian) {
+  TestRead<int16_t, ByteReader<int16_t>::ReadBigEndian, sizeof(int16_t)>(true);
+  TestWrite<int16_t, ByteWriter<int16_t>::WriteBigEndian, sizeof(int16_t)>(
+      true);
+}
+
+TEST_F(ByteIoTest, Test24SBitBigEndian) {
+  TestRead<int32_t, ByteReader<int32_t, 3>::ReadBigEndian, 3>(true);
+  TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteBigEndian, 3>(true);
+}
+
+TEST_F(ByteIoTest, Test32SBitBigEndian) {
+  TestRead<int32_t, ByteReader<int32_t>::ReadBigEndian, sizeof(int32_t)>(true);
+  TestWrite<int32_t, ByteWriter<int32_t>::WriteBigEndian, sizeof(int32_t)>(
+      true);
+}
+
+TEST_F(ByteIoTest, Test64SBitBigEndian) {
+  TestRead<int64_t, ByteReader<int64_t>::ReadBigEndian, sizeof(int64_t)>(true);
+  TestWrite<int64_t, ByteWriter<int64_t>::WriteBigEndian, sizeof(int64_t)>(
+      true);
+}
+
+TEST_F(ByteIoTest, Test16UBitLittleEndian) {
+  TestRead<uint16_t, ByteReader<uint16_t>::ReadLittleEndian, sizeof(uint16_t)>(
+      false);
+  TestWrite<uint16_t, ByteWriter<uint16_t>::WriteLittleEndian,
+            sizeof(uint16_t)>(false);
+}
+
+TEST_F(ByteIoTest, Test24UBitLittleEndian) {
+  TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadLittleEndian, 3>(false);
+  TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteLittleEndian, 3>(false);
+}
+
+TEST_F(ByteIoTest, Test32UBitLittleEndian) {
+  TestRead<uint32_t, ByteReader<uint32_t>::ReadLittleEndian, sizeof(uint32_t)>(
+      false);
+  TestWrite<uint32_t, ByteWriter<uint32_t>::WriteLittleEndian,
+            sizeof(uint32_t)>(false);
+}
+
+TEST_F(ByteIoTest, Test64UBitLittleEndian) {
+  TestRead<uint64_t, ByteReader<uint64_t>::ReadLittleEndian, sizeof(uint64_t)>(
+      false);
+  TestWrite<uint64_t, ByteWriter<uint64_t>::WriteLittleEndian,
+            sizeof(uint64_t)>(false);
+}
+
+TEST_F(ByteIoTest, Test16SBitLittleEndian) {
+  TestRead<int16_t, ByteReader<int16_t>::ReadLittleEndian, sizeof(int16_t)>(
+      false);
+  TestWrite<int16_t, ByteWriter<int16_t>::WriteLittleEndian, sizeof(int16_t)>(
+      false);
+}
+
+TEST_F(ByteIoTest, Test24SBitLittleEndian) {
+  TestRead<int32_t, ByteReader<int32_t, 3>::ReadLittleEndian, 3>(false);
+  TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteLittleEndian, 3>(false);
+}
+
+TEST_F(ByteIoTest, Test32SBitLittleEndian) {
+  TestRead<int32_t, ByteReader<int32_t>::ReadLittleEndian, sizeof(int32_t)>(
+      false);
+  TestWrite<int32_t, ByteWriter<int32_t>::WriteLittleEndian, sizeof(int32_t)>(
+      false);
+}
+
+TEST_F(ByteIoTest, Test64SBitLittleEndian) {
+  TestRead<int64_t, ByteReader<int64_t>::ReadLittleEndian, sizeof(int64_t)>(
+      false);
+  TestWrite<int64_t, ByteWriter<int64_t>::WriteLittleEndian, sizeof(int64_t)>(
+      false);
+}
+
+// Sets up a fixed byte array and converts N bytes from the array into a
+// uint64_t. Verifies the value with hard-coded reference.
+TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadBigEndian) {
+  uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88};
+  uint64_t value = ByteReader<uint64_t, 2>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEE), value);
+  value = ByteReader<uint64_t, 3>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEEDD), value);
+  value = ByteReader<uint64_t, 4>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCC), value);
+  value = ByteReader<uint64_t, 5>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBB), value);
+  value = ByteReader<uint64_t, 6>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA), value);
+  value = ByteReader<uint64_t, 7>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA99), value);
+  value = ByteReader<uint64_t, 8>::ReadBigEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA9988), value);
+}
+
+// Same as above, but for little-endian reading.
+TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadLittleEndian) {
+  uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88};
+  uint64_t value = ByteReader<uint64_t, 2>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xEEFF), value);
+  value = ByteReader<uint64_t, 3>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xDDEEFF), value);
+  value = ByteReader<uint64_t, 4>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xCCDDEEFF), value);
+  value = ByteReader<uint64_t, 5>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xBBCCDDEEFF), value);
+  value = ByteReader<uint64_t, 6>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0xAABBCCDDEEFF), value);
+  value = ByteReader<uint64_t, 7>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0x99AABBCCDDEEFF), value);
+  value = ByteReader<uint64_t, 8>::ReadLittleEndian(data);
+  EXPECT_EQ(static_cast<uint64_t>(0x8899AABBCCDDEEFF), value);
+}
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/dtmf_queue.cc b/modules/rtp_rtcp/source/dtmf_queue.cc
new file mode 100644
index 0000000..86ddb10
--- /dev/null
+++ b/modules/rtp_rtcp/source/dtmf_queue.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2011 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/dtmf_queue.h"
+
+namespace {
+constexpr size_t kDtmfOutbandMax = 20;
+}
+
+namespace webrtc {
+DtmfQueue::DtmfQueue() {}
+
+DtmfQueue::~DtmfQueue() {}
+
+bool DtmfQueue::AddDtmf(const Event& event) {
+  rtc::CritScope lock(&dtmf_critsect_);
+  if (queue_.size() >= kDtmfOutbandMax) {
+    return false;
+  }
+  queue_.push_back(event);
+  return true;
+}
+
+bool DtmfQueue::NextDtmf(Event* event) {
+  RTC_DCHECK(event);
+  rtc::CritScope lock(&dtmf_critsect_);
+  if (queue_.empty()) {
+    return false;
+  }
+
+  *event = queue_.front();
+  queue_.pop_front();
+  return true;
+}
+
+bool DtmfQueue::PendingDtmf() const {
+  rtc::CritScope lock(&dtmf_critsect_);
+  return !queue_.empty();
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/dtmf_queue.h b/modules/rtp_rtcp/source/dtmf_queue.h
new file mode 100644
index 0000000..db70c97
--- /dev/null
+++ b/modules/rtp_rtcp/source/dtmf_queue.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2011 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_DTMF_QUEUE_H_
+#define MODULES_RTP_RTCP_SOURCE_DTMF_QUEUE_H_
+
+#include <list>
+
+#include "rtc_base/criticalsection.h"
+
+namespace webrtc {
+class DtmfQueue {
+ public:
+  struct Event {
+    uint16_t duration_ms = 0;
+    uint8_t payload_type = 0;
+    uint8_t key = 0;
+    uint8_t level = 0;
+  };
+
+  DtmfQueue();
+  ~DtmfQueue();
+
+  bool AddDtmf(const Event& event);
+  bool NextDtmf(Event* event);
+  bool PendingDtmf() const;
+
+ private:
+  rtc::CriticalSection dtmf_critsect_;
+  std::list<Event> queue_;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_DTMF_QUEUE_H_
diff --git a/modules/rtp_rtcp/source/fec_private_tables_bursty.cc b/modules/rtp_rtcp/source/fec_private_tables_bursty.cc
new file mode 100644
index 0000000..9dbc012
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_private_tables_bursty.cc
@@ -0,0 +1,660 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
+
+namespace {
+// clang-format off
+#define kMaskBursty1_1 \
+  0x80, 0x00
+
+#define kMaskBursty2_1 \
+  0xc0, 0x00
+
+#define kMaskBursty2_2 \
+  0x80, 0x00, \
+  0xc0, 0x00
+
+#define kMaskBursty3_1 \
+  0xe0, 0x00
+
+#define kMaskBursty3_2 \
+  0xc0, 0x00, \
+  0xa0, 0x00
+
+#define kMaskBursty3_3 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00
+
+#define kMaskBursty4_1 \
+  0xf0, 0x00
+
+#define kMaskBursty4_2 \
+  0xa0, 0x00, \
+  0xd0, 0x00
+
+#define kMaskBursty4_3 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x90, 0x00
+
+#define kMaskBursty4_4 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00
+
+#define kMaskBursty5_1 \
+  0xf8, 0x00
+
+#define kMaskBursty5_2 \
+  0xd0, 0x00, \
+  0xa8, 0x00
+
+#define kMaskBursty5_3 \
+  0x70, 0x00, \
+  0x90, 0x00, \
+  0xc8, 0x00
+
+#define kMaskBursty5_4 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x88, 0x00
+
+#define kMaskBursty5_5 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00
+
+#define kMaskBursty6_1 \
+  0xfc, 0x00
+
+#define kMaskBursty6_2 \
+  0xa8, 0x00, \
+  0xd4, 0x00
+
+#define kMaskBursty6_3 \
+  0x94, 0x00, \
+  0xc8, 0x00, \
+  0x64, 0x00
+
+#define kMaskBursty6_4 \
+  0x60, 0x00, \
+  0x38, 0x00, \
+  0x88, 0x00, \
+  0xc4, 0x00
+
+#define kMaskBursty6_5 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x84, 0x00
+
+#define kMaskBursty6_6 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00
+
+#define kMaskBursty7_1 \
+  0xfe, 0x00
+
+#define kMaskBursty7_2 \
+  0xd4, 0x00, \
+  0xaa, 0x00
+
+#define kMaskBursty7_3 \
+  0xc8, 0x00, \
+  0x74, 0x00, \
+  0x92, 0x00
+
+#define kMaskBursty7_4 \
+  0x38, 0x00, \
+  0x8a, 0x00, \
+  0xc4, 0x00, \
+  0x62, 0x00
+
+#define kMaskBursty7_5 \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x1c, 0x00, \
+  0x84, 0x00, \
+  0xc2, 0x00
+
+#define kMaskBursty7_6 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x82, 0x00
+
+#define kMaskBursty7_7 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00
+
+#define kMaskBursty8_1 \
+  0xff, 0x00
+
+#define kMaskBursty8_2 \
+  0xaa, 0x00, \
+  0xd5, 0x00
+
+#define kMaskBursty8_3 \
+  0x74, 0x00, \
+  0x92, 0x00, \
+  0xc9, 0x00
+
+#define kMaskBursty8_4 \
+  0x8a, 0x00, \
+  0xc5, 0x00, \
+  0x62, 0x00, \
+  0x31, 0x00
+
+#define kMaskBursty8_5 \
+  0x30, 0x00, \
+  0x1c, 0x00, \
+  0x85, 0x00, \
+  0xc2, 0x00, \
+  0x61, 0x00
+
+#define kMaskBursty8_6 \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0e, 0x00, \
+  0x82, 0x00, \
+  0xc1, 0x00
+
+#define kMaskBursty8_7 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x81, 0x00
+
+#define kMaskBursty8_8 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00
+
+#define kMaskBursty9_1 \
+  0xff, 0x80
+
+#define kMaskBursty9_2 \
+  0xd5, 0x00, \
+  0xaa, 0x80
+
+#define kMaskBursty9_3 \
+  0x92, 0x00, \
+  0xc9, 0x00, \
+  0x74, 0x80
+
+#define kMaskBursty9_4 \
+  0xc5, 0x00, \
+  0x62, 0x00, \
+  0x39, 0x00, \
+  0x8a, 0x80
+
+#define kMaskBursty9_5 \
+  0x1c, 0x00, \
+  0x85, 0x00, \
+  0xc2, 0x80, \
+  0x61, 0x00, \
+  0x30, 0x80
+
+#define kMaskBursty9_6 \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0e, 0x00, \
+  0x82, 0x80, \
+  0xc1, 0x00, \
+  0x60, 0x80
+
+#define kMaskBursty9_7 \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x07, 0x00, \
+  0x81, 0x00, \
+  0xc0, 0x80
+
+#define kMaskBursty9_8 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x80, 0x80
+
+#define kMaskBursty9_9 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80
+
+#define kMaskBursty10_1 \
+  0xff, 0xc0
+
+#define kMaskBursty10_2 \
+  0xaa, 0x80, \
+  0xd5, 0x40
+
+#define kMaskBursty10_3 \
+  0xc9, 0x00, \
+  0x74, 0x80, \
+  0x92, 0x40
+
+#define kMaskBursty10_4 \
+  0x62, 0x00, \
+  0x39, 0x00, \
+  0x8a, 0x80, \
+  0xc5, 0x40
+
+#define kMaskBursty10_5 \
+  0x85, 0x00, \
+  0xc2, 0x80, \
+  0x61, 0x40, \
+  0x30, 0x80, \
+  0x18, 0x40
+
+#define kMaskBursty10_6 \
+  0x18, 0x00, \
+  0x0e, 0x00, \
+  0x82, 0x80, \
+  0xc1, 0x40, \
+  0x60, 0x80, \
+  0x30, 0x40
+
+#define kMaskBursty10_7 \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x07, 0x00, \
+  0x81, 0x40, \
+  0xc0, 0x80, \
+  0x60, 0x40
+
+#define kMaskBursty10_8 \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x80, 0x80, \
+  0xc0, 0x40
+
+#define kMaskBursty10_9 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x80, 0x40
+
+#define kMaskBursty10_10 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x00, 0xc0
+
+#define kMaskBursty11_1 \
+  0xff, 0xe0
+
+#define kMaskBursty11_2 \
+  0xd5, 0x40, \
+  0xaa, 0xa0
+
+#define kMaskBursty11_3 \
+  0x74, 0x80, \
+  0x92, 0x40, \
+  0xc9, 0x20
+
+#define kMaskBursty11_4 \
+  0x39, 0x00, \
+  0x8a, 0x80, \
+  0xc5, 0x40, \
+  0x62, 0x20
+
+#define kMaskBursty11_5 \
+  0xc2, 0xc0, \
+  0x61, 0x00, \
+  0x30, 0xa0, \
+  0x1c, 0x40, \
+  0x85, 0x20
+
+#define kMaskBursty11_6 \
+  0x0e, 0x00, \
+  0x82, 0x80, \
+  0xc1, 0x40, \
+  0x60, 0xa0, \
+  0x30, 0x40, \
+  0x18, 0x20
+
+#define kMaskBursty11_7 \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x07, 0x00, \
+  0x81, 0x40, \
+  0xc0, 0xa0, \
+  0x60, 0x40, \
+  0x30, 0x20
+
+#define kMaskBursty11_8 \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x40, \
+  0x80, 0xa0, \
+  0xc0, 0x40, \
+  0x60, 0x20
+
+#define kMaskBursty11_9 \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x80, 0x40, \
+  0xc0, 0x20
+
+#define kMaskBursty11_10 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x00, 0xc0, \
+  0x80, 0x20
+
+#define kMaskBursty11_11 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x00, 0xc0, \
+  0x00, 0x60
+
+#define kMaskBursty12_1 \
+  0xff, 0xf0
+
+#define kMaskBursty12_2 \
+  0xaa, 0xa0, \
+  0xd5, 0x50
+
+#define kMaskBursty12_3 \
+  0x92, 0x40, \
+  0xc9, 0x20, \
+  0x74, 0x90
+
+#define kMaskBursty12_4 \
+  0x8a, 0x80, \
+  0xc5, 0x40, \
+  0x62, 0x20, \
+  0x39, 0x10
+
+#define kMaskBursty12_5 \
+  0x61, 0x00, \
+  0x30, 0xa0, \
+  0x1c, 0x50, \
+  0x85, 0x20, \
+  0xc2, 0x90
+
+#define kMaskBursty12_6 \
+  0x82, 0x90, \
+  0xc1, 0x40, \
+  0x60, 0xa0, \
+  0x30, 0x50, \
+  0x18, 0x20, \
+  0x0c, 0x10
+
+#define kMaskBursty12_7 \
+  0x0c, 0x00, \
+  0x07, 0x00, \
+  0x81, 0x40, \
+  0xc0, 0xa0, \
+  0x60, 0x50, \
+  0x30, 0x20, \
+  0x18, 0x10
+
+#define kMaskBursty12_8 \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x80, 0xa0, \
+  0xc0, 0x50, \
+  0x60, 0x20, \
+  0x30, 0x10
+
+#define kMaskBursty12_9 \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x80, 0x50, \
+  0xc0, 0x20, \
+  0x60, 0x10
+
+#define kMaskBursty12_10 \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x00, 0xc0, \
+  0x80, 0x20, \
+  0xc0, 0x10
+
+#define kMaskBursty12_11 \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x00, 0xc0, \
+  0x00, 0x60, \
+  0x80, 0x10
+
+#define kMaskBursty12_12 \
+  0x80, 0x00, \
+  0xc0, 0x00, \
+  0x60, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0x0c, 0x00, \
+  0x06, 0x00, \
+  0x03, 0x00, \
+  0x01, 0x80, \
+  0x00, 0xc0, \
+  0x00, 0x60, \
+  0x00, 0x30
+
+#define kPacketMaskBursty1 1, \
+  kMaskBursty1_1
+
+#define kPacketMaskBursty2 2, \
+  kMaskBursty2_1, \
+  kMaskBursty2_2
+
+#define kPacketMaskBursty3 3, \
+  kMaskBursty3_1, \
+  kMaskBursty3_2, \
+  kMaskBursty3_3
+
+#define kPacketMaskBursty4 4, \
+  kMaskBursty4_1, \
+  kMaskBursty4_2, \
+  kMaskBursty4_3, \
+  kMaskBursty4_4
+
+#define kPacketMaskBursty5 5, \
+  kMaskBursty5_1, \
+  kMaskBursty5_2, \
+  kMaskBursty5_3, \
+  kMaskBursty5_4, \
+  kMaskBursty5_5
+
+#define kPacketMaskBursty6 6, \
+  kMaskBursty6_1, \
+  kMaskBursty6_2, \
+  kMaskBursty6_3, \
+  kMaskBursty6_4, \
+  kMaskBursty6_5, \
+  kMaskBursty6_6
+
+#define kPacketMaskBursty7 7, \
+  kMaskBursty7_1, \
+  kMaskBursty7_2, \
+  kMaskBursty7_3, \
+  kMaskBursty7_4, \
+  kMaskBursty7_5, \
+  kMaskBursty7_6, \
+  kMaskBursty7_7
+
+#define kPacketMaskBursty8 8, \
+  kMaskBursty8_1, \
+  kMaskBursty8_2, \
+  kMaskBursty8_3, \
+  kMaskBursty8_4, \
+  kMaskBursty8_5, \
+  kMaskBursty8_6, \
+  kMaskBursty8_7, \
+  kMaskBursty8_8
+
+#define kPacketMaskBursty9 9, \
+  kMaskBursty9_1, \
+  kMaskBursty9_2, \
+  kMaskBursty9_3, \
+  kMaskBursty9_4, \
+  kMaskBursty9_5, \
+  kMaskBursty9_6, \
+  kMaskBursty9_7, \
+  kMaskBursty9_8, \
+  kMaskBursty9_9
+
+#define kPacketMaskBursty10 10, \
+  kMaskBursty10_1, \
+  kMaskBursty10_2, \
+  kMaskBursty10_3, \
+  kMaskBursty10_4, \
+  kMaskBursty10_5, \
+  kMaskBursty10_6, \
+  kMaskBursty10_7, \
+  kMaskBursty10_8, \
+  kMaskBursty10_9, \
+  kMaskBursty10_10
+
+#define kPacketMaskBursty11 11, \
+  kMaskBursty11_1, \
+  kMaskBursty11_2, \
+  kMaskBursty11_3, \
+  kMaskBursty11_4, \
+  kMaskBursty11_5, \
+  kMaskBursty11_6, \
+  kMaskBursty11_7, \
+  kMaskBursty11_8, \
+  kMaskBursty11_9, \
+  kMaskBursty11_10, \
+  kMaskBursty11_11
+
+#define kPacketMaskBursty12 12, \
+  kMaskBursty12_1, \
+  kMaskBursty12_2, \
+  kMaskBursty12_3, \
+  kMaskBursty12_4, \
+  kMaskBursty12_5, \
+  kMaskBursty12_6, \
+  kMaskBursty12_7, \
+  kMaskBursty12_8, \
+  kMaskBursty12_9, \
+  kMaskBursty12_10, \
+  kMaskBursty12_11, \
+  kMaskBursty12_12
+
+// clang-format on
+}  // namespace
+
+namespace webrtc {
+namespace fec_private_tables {
+
+const uint8_t kPacketMaskBurstyTbl[] = {
+    12,
+    kPacketMaskBursty1,
+    kPacketMaskBursty2,
+    kPacketMaskBursty3,
+    kPacketMaskBursty4,
+    kPacketMaskBursty5,
+    kPacketMaskBursty6,
+    kPacketMaskBursty7,
+    kPacketMaskBursty8,
+    kPacketMaskBursty9,
+    kPacketMaskBursty10,
+    kPacketMaskBursty11,
+    kPacketMaskBursty12,
+};
+
+}  // namespace fec_private_tables
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/fec_private_tables_bursty.h b/modules/rtp_rtcp/source/fec_private_tables_bursty.h
new file mode 100644
index 0000000..4120cf9
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_private_tables_bursty.h
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_
+#define MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_
+
+// This file contains a set of packets masks for the FEC code. The masks in
+// this table are specifically designed to favor recovery of bursty/consecutive
+// loss network conditions. The tradeoff is worse recovery for random losses.
+// These packet masks are currently defined to protect up to 12 media packets.
+// They have the following property: for any packet mask defined by the
+// parameters (k,m), where k = number of media packets, m = number of FEC
+// packets, all "consecutive" losses of size <= m are completely recoverable.
+// By consecutive losses we mean consecutive with respect to the sequence
+// number ordering of the list (media and FEC) of packets. The difference
+// between these masks (|kFecMaskBursty|) and |kFecMaskRandom| type, defined
+// in fec_private_tables.h, is more significant for longer codes
+// (i.e., more packets/symbols in the code, so larger (k,m), i.e.,  k > 4,
+// m > 3).
+
+#include <cstddef>
+
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+namespace fec_private_tables {
+
+extern const uint8_t kPacketMaskBurstyTbl[];
+
+}  // namespace fec_private_tables
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_
diff --git a/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc b/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc
new file mode 100644
index 0000000..fd116eb
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc
@@ -0,0 +1,82 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
+#include "modules/rtp_rtcp/source/fec_private_tables_random.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+constexpr uint8_t kMaskRandom15_6[] = {0x82, 0x08, 0x41, 0x04, 0x20, 0x82,
+                                       0x10, 0x40, 0x08, 0x20, 0x04, 0x10};
+}
+
+namespace fec_private_tables {
+
+using internal::LookUpInFecTable;
+
+TEST(FecTable, TestBurstyLookup) {
+  rtc::ArrayView<const uint8_t> result;
+  result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 0, 0);
+  // Should match kMaskBursty1_1.
+  EXPECT_EQ(2u, result.size());
+  EXPECT_EQ(0x80u, result[0]);
+
+  result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 3, 0);
+  // Should match kMaskBursty4_1.
+  EXPECT_EQ(2u, result.size());
+  EXPECT_EQ(0xf0u, result[0]);
+  EXPECT_EQ(0x00u, result[1]);
+
+  result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 1, 1);
+  // Should match kMaskBursty2_2.
+  EXPECT_EQ(4u, result.size());
+  EXPECT_EQ(0x80u, result[0]);
+  EXPECT_EQ(0xc0u, result[2]);
+
+  result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 11, 11);
+  // Should match kMaskBursty12_12.
+  EXPECT_EQ(24u, result.size());
+  EXPECT_EQ(0x80u, result[0]);
+  EXPECT_EQ(0x30u, result[23]);
+}
+
+TEST(FecTable, TestRandomLookup) {
+  rtc::ArrayView<const uint8_t> result;
+  result = LookUpInFecTable(&kPacketMaskRandomTbl[0], 0, 0);
+  EXPECT_EQ(2u, result.size());
+  EXPECT_EQ(0x80u, result[0]);
+  EXPECT_EQ(0x00u, result[1]);
+
+  result = LookUpInFecTable(&kPacketMaskRandomTbl[0], 4, 1);
+  // kMaskRandom5_2.
+  EXPECT_EQ(4u, result.size());
+  EXPECT_EQ(0xa8u, result[0]);
+  EXPECT_EQ(0xd0u, result[2]);
+}
+
+TEST(FecTable, TestRandomGenerated) {
+  FecMaskType fec_mask_type = kFecMaskRandom;
+  int num_media_packets = 15;
+  int num_fec_packets = 6;
+  size_t mask_size = sizeof(kMaskRandom15_6) / sizeof(uint8_t);
+  internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
+  rtc::ArrayView<const uint8_t> mask =
+      mask_table.LookUp(num_media_packets, num_fec_packets);
+  EXPECT_EQ(mask.size(), mask_size);
+  for (size_t i = 0; i < mask_size; ++i) {
+    EXPECT_EQ(mask[i], kMaskRandom15_6[i]);
+  }
+}
+
+}  // namespace fec_private_tables
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/fec_private_tables_random.cc b/modules/rtp_rtcp/source/fec_private_tables_random.cc
new file mode 100644
index 0000000..3cac5db
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_private_tables_random.cc
@@ -0,0 +1,660 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/fec_private_tables_random.h"
+
+namespace {
+// clang-format off
+#define kMaskRandom1_1 \
+  0x80, 0x00
+
+#define kMaskRandom2_1 \
+  0xc0, 0x00
+
+#define kMaskRandom2_2 \
+  0xc0, 0x00, \
+  0x80, 0x00
+
+#define kMaskRandom3_1 \
+  0xe0, 0x00
+
+#define kMaskRandom3_2 \
+  0xc0, 0x00, \
+  0xa0, 0x00
+
+#define kMaskRandom3_3 \
+  0xc0, 0x00, \
+  0xa0, 0x00, \
+  0x60, 0x00
+
+#define kMaskRandom4_1 \
+  0xf0, 0x00
+
+#define kMaskRandom4_2 \
+  0xc0, 0x00, \
+  0xb0, 0x00
+
+#define kMaskRandom4_3 \
+  0xc0, 0x00, \
+  0xb0, 0x00, \
+  0x60, 0x00
+
+#define kMaskRandom4_4 \
+  0xc0, 0x00, \
+  0xa0, 0x00, \
+  0x30, 0x00, \
+  0x50, 0x00
+
+#define kMaskRandom5_1 \
+  0xf8, 0x00
+
+#define kMaskRandom5_2 \
+  0xa8, 0x00, \
+  0xd0, 0x00
+
+#define kMaskRandom5_3 \
+  0xb0, 0x00, \
+  0xc8, 0x00, \
+  0x50, 0x00
+
+#define kMaskRandom5_4 \
+  0xc8, 0x00, \
+  0xb0, 0x00, \
+  0x50, 0x00, \
+  0x28, 0x00
+
+#define kMaskRandom5_5 \
+  0xc0, 0x00, \
+  0x30, 0x00, \
+  0x18, 0x00, \
+  0xa0, 0x00, \
+  0x48, 0x00
+
+#define kMaskRandom6_1 \
+  0xfc, 0x00
+
+#define kMaskRandom6_2 \
+  0xa8, 0x00, \
+  0xd4, 0x00
+
+#define kMaskRandom6_3 \
+  0xd0, 0x00, \
+  0x68, 0x00, \
+  0xa4, 0x00
+
+#define kMaskRandom6_4 \
+  0xa8, 0x00, \
+  0x58, 0x00, \
+  0x64, 0x00, \
+  0x94, 0x00
+
+#define kMaskRandom6_5 \
+  0xa8, 0x00, \
+  0x84, 0x00, \
+  0x64, 0x00, \
+  0x90, 0x00, \
+  0x58, 0x00
+
+#define kMaskRandom6_6 \
+  0x98, 0x00, \
+  0x64, 0x00, \
+  0x50, 0x00, \
+  0x14, 0x00, \
+  0xa8, 0x00, \
+  0xe0, 0x00
+
+#define kMaskRandom7_1 \
+  0xfe, 0x00
+
+#define kMaskRandom7_2 \
+  0xd4, 0x00, \
+  0xaa, 0x00
+
+#define kMaskRandom7_3 \
+  0xd0, 0x00, \
+  0xaa, 0x00, \
+  0x64, 0x00
+
+#define kMaskRandom7_4 \
+  0xd0, 0x00, \
+  0xaa, 0x00, \
+  0x64, 0x00, \
+  0x1c, 0x00
+
+#define kMaskRandom7_5 \
+  0x0c, 0x00, \
+  0xb0, 0x00, \
+  0x1a, 0x00, \
+  0xc4, 0x00, \
+  0x62, 0x00
+
+#define kMaskRandom7_6 \
+  0x8c, 0x00, \
+  0x4a, 0x00, \
+  0x64, 0x00, \
+  0xd0, 0x00, \
+  0xa0, 0x00, \
+  0x32, 0x00
+
+#define kMaskRandom7_7 \
+  0x4a, 0x00, \
+  0x94, 0x00, \
+  0x1a, 0x00, \
+  0xc4, 0x00, \
+  0x28, 0x00, \
+  0xc2, 0x00, \
+  0x34, 0x00
+
+#define kMaskRandom8_1 \
+  0xff, 0x00
+
+#define kMaskRandom8_2 \
+  0xaa, 0x00, \
+  0xd5, 0x00
+
+#define kMaskRandom8_3 \
+  0xc5, 0x00, \
+  0x92, 0x00, \
+  0x6a, 0x00
+
+#define kMaskRandom8_4 \
+  0x45, 0x00, \
+  0xb4, 0x00, \
+  0x6a, 0x00, \
+  0x89, 0x00
+
+#define kMaskRandom8_5 \
+  0x8c, 0x00, \
+  0x92, 0x00, \
+  0x2b, 0x00, \
+  0x51, 0x00, \
+  0x64, 0x00
+
+#define kMaskRandom8_6 \
+  0xa1, 0x00, \
+  0x52, 0x00, \
+  0x91, 0x00, \
+  0x2a, 0x00, \
+  0xc4, 0x00, \
+  0x4c, 0x00
+
+#define kMaskRandom8_7 \
+  0x15, 0x00, \
+  0xc2, 0x00, \
+  0x25, 0x00, \
+  0x62, 0x00, \
+  0x58, 0x00, \
+  0x8c, 0x00, \
+  0xa3, 0x00
+
+#define kMaskRandom8_8 \
+  0x25, 0x00, \
+  0x8a, 0x00, \
+  0x91, 0x00, \
+  0x68, 0x00, \
+  0x32, 0x00, \
+  0x43, 0x00, \
+  0xc4, 0x00, \
+  0x1c, 0x00
+
+#define kMaskRandom9_1 \
+  0xff, 0x80
+
+#define kMaskRandom9_2 \
+  0xaa, 0x80, \
+  0xd5, 0x00
+
+#define kMaskRandom9_3 \
+  0xa5, 0x00, \
+  0xc8, 0x00, \
+  0x52, 0x80
+
+#define kMaskRandom9_4 \
+  0xa2, 0x00, \
+  0xc9, 0x00, \
+  0x52, 0x80, \
+  0x24, 0x80
+
+#define kMaskRandom9_5 \
+  0x8c, 0x00, \
+  0x25, 0x00, \
+  0x92, 0x80, \
+  0x41, 0x80, \
+  0x58, 0x00
+
+#define kMaskRandom9_6 \
+  0x84, 0x80, \
+  0x27, 0x00, \
+  0x51, 0x80, \
+  0x1a, 0x00, \
+  0x68, 0x00, \
+  0x89, 0x00
+
+#define kMaskRandom9_7 \
+  0x8c, 0x00, \
+  0x47, 0x00, \
+  0x81, 0x80, \
+  0x12, 0x80, \
+  0x58, 0x00, \
+  0x28, 0x80, \
+  0xb4, 0x00
+
+#define kMaskRandom9_8 \
+  0x2c, 0x00, \
+  0x91, 0x00, \
+  0x40, 0x80, \
+  0x06, 0x80, \
+  0xc8, 0x00, \
+  0x45, 0x00, \
+  0x30, 0x80, \
+  0xa2, 0x00
+
+#define kMaskRandom9_9 \
+  0x4c, 0x00, \
+  0x62, 0x00, \
+  0x91, 0x00, \
+  0x42, 0x80, \
+  0xa4, 0x00, \
+  0x13, 0x00, \
+  0x30, 0x80, \
+  0x88, 0x80, \
+  0x09, 0x00
+
+#define kMaskRandom10_1 \
+  0xff, 0xc0
+
+#define kMaskRandom10_10 \
+  0x4c, 0x00, \
+  0x51, 0x00, \
+  0xa0, 0x40, \
+  0x04, 0xc0, \
+  0x03, 0x80, \
+  0x86, 0x00, \
+  0x29, 0x00, \
+  0x42, 0x40, \
+  0x98, 0x00, \
+  0x30, 0x80
+
+#define kMaskRandom10_2 \
+  0xaa, 0x80, \
+  0xd5, 0x40
+
+#define kMaskRandom10_3 \
+  0xa4, 0x40, \
+  0xc9, 0x00, \
+  0x52, 0x80
+
+#define kMaskRandom10_4 \
+  0xca, 0x00, \
+  0x32, 0x80, \
+  0xa1, 0x40, \
+  0x55, 0x00
+
+#define kMaskRandom10_5 \
+  0xca, 0x00, \
+  0x32, 0x80, \
+  0xa1, 0x40, \
+  0x55, 0x00, \
+  0x08, 0xc0
+
+#define kMaskRandom10_6 \
+  0x0e, 0x00, \
+  0x33, 0x00, \
+  0x10, 0xc0, \
+  0x45, 0x40, \
+  0x88, 0x80, \
+  0xe0, 0x00
+
+#define kMaskRandom10_7 \
+  0x46, 0x00, \
+  0x33, 0x00, \
+  0x80, 0xc0, \
+  0x0c, 0x40, \
+  0x28, 0x80, \
+  0x94, 0x00, \
+  0xc1, 0x00
+
+#define kMaskRandom10_8 \
+  0x2c, 0x00, \
+  0x81, 0x80, \
+  0xa0, 0x40, \
+  0x05, 0x40, \
+  0x18, 0x80, \
+  0xc2, 0x00, \
+  0x22, 0x80, \
+  0x50, 0x40
+
+#define kMaskRandom10_9 \
+  0x4c, 0x00, \
+  0x23, 0x00, \
+  0x88, 0xc0, \
+  0x21, 0x40, \
+  0x52, 0x80, \
+  0x94, 0x00, \
+  0x26, 0x00, \
+  0x48, 0x40, \
+  0x91, 0x80
+
+#define kMaskRandom11_1 \
+  0xff, 0xe0
+
+#define kMaskRandom11_10 \
+  0x64, 0x40, \
+  0x51, 0x40, \
+  0xa9, 0x00, \
+  0x04, 0xc0, \
+  0xd0, 0x00, \
+  0x82, 0x40, \
+  0x21, 0x20, \
+  0x0c, 0x20, \
+  0x4a, 0x00, \
+  0x12, 0xa0
+
+#define kMaskRandom11_11 \
+  0x46, 0x40, \
+  0x33, 0x20, \
+  0x99, 0x00, \
+  0x05, 0x80, \
+  0x80, 0xa0, \
+  0x84, 0x40, \
+  0x40, 0x60, \
+  0x0a, 0x80, \
+  0x68, 0x00, \
+  0x10, 0x20, \
+  0x30, 0x40
+
+#define kMaskRandom11_2 \
+  0xec, 0xc0, \
+  0x9b, 0xa0
+
+#define kMaskRandom11_3 \
+  0xca, 0xc0, \
+  0xf1, 0x40, \
+  0xb6, 0x20
+
+#define kMaskRandom11_4 \
+  0xc4, 0xc0, \
+  0x31, 0x60, \
+  0x4b, 0x20, \
+  0x2c, 0xa0
+
+#define kMaskRandom11_5 \
+  0x86, 0x80, \
+  0x23, 0x20, \
+  0x16, 0x20, \
+  0x4c, 0x20, \
+  0x41, 0xc0
+
+#define kMaskRandom11_6 \
+  0x64, 0x40, \
+  0x51, 0x40, \
+  0x0c, 0xa0, \
+  0xa1, 0x20, \
+  0x12, 0xa0, \
+  0x8a, 0x40
+
+#define kMaskRandom11_7 \
+  0x46, 0x40, \
+  0x33, 0x20, \
+  0x91, 0x80, \
+  0xa4, 0x20, \
+  0x50, 0xa0, \
+  0x84, 0xc0, \
+  0x09, 0x60
+
+#define kMaskRandom11_8 \
+  0x0c, 0x80, \
+  0x80, 0x60, \
+  0xa0, 0x80, \
+  0x05, 0x40, \
+  0x43, 0x00, \
+  0x1a, 0x00, \
+  0x60, 0x20, \
+  0x14, 0x20
+
+#define kMaskRandom11_9 \
+  0x46, 0x40, \
+  0x62, 0x60, \
+  0x8c, 0x00, \
+  0x01, 0x60, \
+  0x07, 0x80, \
+  0xa0, 0x80, \
+  0x18, 0xa0, \
+  0x91, 0x00, \
+  0x78, 0x00
+
+#define kMaskRandom12_1 \
+  0xff, 0xf0
+
+#define kMaskRandom12_10 \
+  0x51, 0x40, \
+  0x45, 0x10, \
+  0x80, 0xd0, \
+  0x24, 0x20, \
+  0x0a, 0x20, \
+  0x00, 0xe0, \
+  0xb8, 0x00, \
+  0x09, 0x10, \
+  0x56, 0x00, \
+  0xa2, 0x80
+
+#define kMaskRandom12_11 \
+  0x53, 0x60, \
+  0x21, 0x30, \
+  0x10, 0x90, \
+  0x00, 0x70, \
+  0x0c, 0x10, \
+  0x40, 0xc0, \
+  0x6a, 0x00, \
+  0x86, 0x00, \
+  0x24, 0x80, \
+  0x89, 0x00, \
+  0xc0, 0x20
+
+#define kMaskRandom12_12 \
+  0x10, 0x60, \
+  0x02, 0x30, \
+  0x40, 0x50, \
+  0x21, 0x80, \
+  0x81, 0x10, \
+  0x14, 0x80, \
+  0x98, 0x00, \
+  0x08, 0x90, \
+  0x62, 0x00, \
+  0x24, 0x20, \
+  0x8a, 0x00, \
+  0x84, 0x40
+
+#define kMaskRandom12_2 \
+  0xec, 0xc0, \
+  0x93, 0xb0
+
+#define kMaskRandom12_3 \
+  0x9b, 0x80, \
+  0x4f, 0x10, \
+  0x3c, 0x60
+
+#define kMaskRandom12_4 \
+  0x8b, 0x20, \
+  0x14, 0xb0, \
+  0x22, 0xd0, \
+  0x45, 0x50
+
+#define kMaskRandom12_5 \
+  0x53, 0x60, \
+  0x64, 0x20, \
+  0x0c, 0xc0, \
+  0x82, 0xa0, \
+  0x09, 0x30
+
+#define kMaskRandom12_6 \
+  0x51, 0x40, \
+  0xc5, 0x10, \
+  0x21, 0x80, \
+  0x12, 0x30, \
+  0x08, 0xe0, \
+  0x2e, 0x00
+
+#define kMaskRandom12_7 \
+  0x53, 0x60, \
+  0x21, 0x30, \
+  0x90, 0x90, \
+  0x02, 0x50, \
+  0x06, 0xa0, \
+  0x2c, 0x00, \
+  0x88, 0x60
+
+#define kMaskRandom12_8 \
+  0x20, 0x60, \
+  0x80, 0x30, \
+  0x42, 0x40, \
+  0x01, 0x90, \
+  0x14, 0x10, \
+  0x0a, 0x80, \
+  0x38, 0x00, \
+  0xc5, 0x00
+
+#define kMaskRandom12_9 \
+  0x53, 0x60, \
+  0xe4, 0x20, \
+  0x24, 0x40, \
+  0xa1, 0x10, \
+  0x18, 0x30, \
+  0x03, 0x90, \
+  0x8a, 0x10, \
+  0x04, 0x90, \
+  0x00, 0xe0
+
+#define kPacketMaskRandom1 1, \
+  kMaskRandom1_1
+
+#define kPacketMaskRandom2 2, \
+  kMaskRandom2_1, \
+  kMaskRandom2_2
+
+#define kPacketMaskRandom3 3, \
+  kMaskRandom3_1, \
+  kMaskRandom3_2, \
+  kMaskRandom3_3
+
+#define kPacketMaskRandom4 4, \
+  kMaskRandom4_1, \
+  kMaskRandom4_2, \
+  kMaskRandom4_3, \
+  kMaskRandom4_4
+
+#define kPacketMaskRandom5 5, \
+  kMaskRandom5_1, \
+  kMaskRandom5_2, \
+  kMaskRandom5_3, \
+  kMaskRandom5_4, \
+  kMaskRandom5_5
+
+#define kPacketMaskRandom6 6, \
+  kMaskRandom6_1, \
+  kMaskRandom6_2, \
+  kMaskRandom6_3, \
+  kMaskRandom6_4, \
+  kMaskRandom6_5, \
+  kMaskRandom6_6
+
+#define kPacketMaskRandom7 7, \
+  kMaskRandom7_1, \
+  kMaskRandom7_2, \
+  kMaskRandom7_3, \
+  kMaskRandom7_4, \
+  kMaskRandom7_5, \
+  kMaskRandom7_6, \
+  kMaskRandom7_7
+
+#define kPacketMaskRandom8 8, \
+  kMaskRandom8_1, \
+  kMaskRandom8_2, \
+  kMaskRandom8_3, \
+  kMaskRandom8_4, \
+  kMaskRandom8_5, \
+  kMaskRandom8_6, \
+  kMaskRandom8_7, \
+  kMaskRandom8_8
+
+#define kPacketMaskRandom9 9, \
+  kMaskRandom9_1, \
+  kMaskRandom9_2, \
+  kMaskRandom9_3, \
+  kMaskRandom9_4, \
+  kMaskRandom9_5, \
+  kMaskRandom9_6, \
+  kMaskRandom9_7, \
+  kMaskRandom9_8, \
+  kMaskRandom9_9
+
+#define kPacketMaskRandom10 10, \
+  kMaskRandom10_1, \
+  kMaskRandom10_2, \
+  kMaskRandom10_3, \
+  kMaskRandom10_4, \
+  kMaskRandom10_5, \
+  kMaskRandom10_6, \
+  kMaskRandom10_7, \
+  kMaskRandom10_8, \
+  kMaskRandom10_9, \
+  kMaskRandom10_10
+
+#define kPacketMaskRandom11 11, \
+  kMaskRandom11_1, \
+  kMaskRandom11_2, \
+  kMaskRandom11_3, \
+  kMaskRandom11_4, \
+  kMaskRandom11_5, \
+  kMaskRandom11_6, \
+  kMaskRandom11_7, \
+  kMaskRandom11_8, \
+  kMaskRandom11_9, \
+  kMaskRandom11_10, \
+  kMaskRandom11_11
+
+#define kPacketMaskRandom12 12, \
+  kMaskRandom12_1, \
+  kMaskRandom12_2, \
+  kMaskRandom12_3, \
+  kMaskRandom12_4, \
+  kMaskRandom12_5, \
+  kMaskRandom12_6, \
+  kMaskRandom12_7, \
+  kMaskRandom12_8, \
+  kMaskRandom12_9, \
+  kMaskRandom12_10, \
+  kMaskRandom12_11, \
+  kMaskRandom12_12
+
+// clang-format on
+}  // namespace
+
+namespace webrtc {
+namespace fec_private_tables {
+
+const uint8_t kPacketMaskRandomTbl[] = {
+    12,
+    kPacketMaskRandom1,  // 2 byte entries.
+    kPacketMaskRandom2,
+    kPacketMaskRandom3,
+    kPacketMaskRandom4,
+    kPacketMaskRandom5,
+    kPacketMaskRandom6,
+    kPacketMaskRandom7,
+    kPacketMaskRandom8,
+    kPacketMaskRandom9,
+    kPacketMaskRandom10,
+    kPacketMaskRandom11,
+    kPacketMaskRandom12,
+};
+
+}  // namespace fec_private_tables
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/fec_private_tables_random.h b/modules/rtp_rtcp/source/fec_private_tables_random.h
new file mode 100644
index 0000000..96c3cef
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_private_tables_random.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_RANDOM_H_
+#define MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_RANDOM_H_
+
+// This file contains a set of packets masks for the FEC code. The masks in
+// this table are specifically designed to favor recovery to random loss.
+// These packet masks are defined to protect up to maximum of 48 media packets.
+
+#include <cstddef>
+
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+namespace fec_private_tables {
+
+extern const uint8_t kPacketMaskRandomTbl[];
+
+}  // namespace fec_private_tables
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_RANDOM_H_
diff --git a/modules/rtp_rtcp/source/fec_test_helper.cc b/modules/rtp_rtcp/source/fec_test_helper.cc
new file mode 100644
index 0000000..b325d67
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_test_helper.cc
@@ -0,0 +1,227 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+namespace fec {
+
+namespace {
+constexpr uint8_t kFecPayloadType = 96;
+constexpr uint8_t kRedPayloadType = 97;
+constexpr uint8_t kVp8PayloadType = 120;
+
+constexpr int kPacketTimestampIncrement = 3000;
+}  // namespace
+
+MediaPacketGenerator::MediaPacketGenerator(uint32_t min_packet_size,
+                                           uint32_t max_packet_size,
+                                           uint32_t ssrc,
+                                           Random* random)
+    : min_packet_size_(min_packet_size),
+      max_packet_size_(max_packet_size),
+      ssrc_(ssrc),
+      random_(random) {}
+
+MediaPacketGenerator::~MediaPacketGenerator() = default;
+
+ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets(
+    int num_media_packets,
+    uint16_t start_seq_num) {
+  RTC_DCHECK_GT(num_media_packets, 0);
+  uint16_t seq_num = start_seq_num;
+  int time_stamp = random_->Rand<int>();
+
+  ForwardErrorCorrection::PacketList media_packets;
+
+  for (int i = 0; i < num_media_packets; ++i) {
+    std::unique_ptr<ForwardErrorCorrection::Packet> media_packet(
+        new ForwardErrorCorrection::Packet());
+    media_packet->length = random_->Rand(min_packet_size_, max_packet_size_);
+
+    // Generate random values for the first 2 bytes
+    media_packet->data[0] = random_->Rand<uint8_t>();
+    media_packet->data[1] = random_->Rand<uint8_t>();
+
+    // The first two bits are assumed to be 10 by the FEC encoder.
+    // In fact the FEC decoder will set the two first bits to 10 regardless of
+    // what they actually were. Set the first two bits to 10 so that a memcmp
+    // can be performed for the whole restored packet.
+    media_packet->data[0] |= 0x80;
+    media_packet->data[0] &= 0xbf;
+
+    // FEC is applied to a whole frame.
+    // A frame is signaled by multiple packets without the marker bit set
+    // followed by the last packet of the frame for which the marker bit is set.
+    // Only push one (fake) frame to the FEC.
+    media_packet->data[1] &= 0x7f;
+
+    webrtc::ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2],
+                                                 seq_num);
+    webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
+                                                 time_stamp);
+    webrtc::ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8], ssrc_);
+
+    // Generate random values for payload.
+    for (size_t j = 12; j < media_packet->length; ++j)
+      media_packet->data[j] = random_->Rand<uint8_t>();
+    seq_num++;
+    media_packets.push_back(std::move(media_packet));
+  }
+  // Last packet, set marker bit.
+  ForwardErrorCorrection::Packet* media_packet = media_packets.back().get();
+  RTC_DCHECK(media_packet);
+  media_packet->data[1] |= 0x80;
+
+  next_seq_num_ = seq_num;
+
+  return media_packets;
+}
+
+ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets(
+    int num_media_packets) {
+  return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>());
+}
+
+uint16_t MediaPacketGenerator::GetNextSeqNum() {
+  return next_seq_num_;
+}
+
+AugmentedPacketGenerator::AugmentedPacketGenerator(uint32_t ssrc)
+    : num_packets_(0), ssrc_(ssrc), seq_num_(0), timestamp_(0) {}
+
+void AugmentedPacketGenerator::NewFrame(size_t num_packets) {
+  num_packets_ = num_packets;
+  timestamp_ += kPacketTimestampIncrement;
+}
+
+uint16_t AugmentedPacketGenerator::NextPacketSeqNum() {
+  return ++seq_num_;
+}
+
+std::unique_ptr<AugmentedPacket> AugmentedPacketGenerator::NextPacket(
+    size_t offset,
+    size_t length) {
+  std::unique_ptr<AugmentedPacket> packet(new AugmentedPacket());
+
+  for (size_t i = 0; i < length; ++i)
+    packet->data[i + kRtpHeaderSize] = offset + i;
+  packet->length = length + kRtpHeaderSize;
+  packet->header.frameType = kVideoFrameDelta;
+  packet->header.header.headerLength = kRtpHeaderSize;
+  packet->header.header.markerBit = (num_packets_ == 1);
+  packet->header.header.payloadType = kVp8PayloadType;
+  packet->header.header.sequenceNumber = seq_num_;
+  packet->header.header.timestamp = timestamp_;
+  packet->header.header.ssrc = ssrc_;
+  WriteRtpHeader(packet->header.header, packet->data);
+  ++seq_num_;
+  --num_packets_;
+
+  return packet;
+}
+
+void AugmentedPacketGenerator::WriteRtpHeader(const RTPHeader& header,
+                                              uint8_t* data) {
+  data[0] = 0x80;  // Version 2.
+  data[1] = header.payloadType;
+  data[1] |= (header.markerBit ? kRtpMarkerBitMask : 0);
+  ByteWriter<uint16_t>::WriteBigEndian(data + 2, header.sequenceNumber);
+  ByteWriter<uint32_t>::WriteBigEndian(data + 4, header.timestamp);
+  ByteWriter<uint32_t>::WriteBigEndian(data + 8, header.ssrc);
+}
+
+FlexfecPacketGenerator::FlexfecPacketGenerator(uint32_t media_ssrc,
+                                               uint32_t flexfec_ssrc)
+    : AugmentedPacketGenerator(media_ssrc),
+      flexfec_ssrc_(flexfec_ssrc),
+      flexfec_seq_num_(0),
+      flexfec_timestamp_(0) {}
+
+std::unique_ptr<AugmentedPacket> FlexfecPacketGenerator::BuildFlexfecPacket(
+    const ForwardErrorCorrection::Packet& packet) {
+  RTC_DCHECK_LE(packet.length,
+                static_cast<size_t>(IP_PACKET_SIZE - kRtpHeaderSize));
+
+  RTPHeader header;
+  header.sequenceNumber = flexfec_seq_num_;
+  ++flexfec_seq_num_;
+  header.timestamp = flexfec_timestamp_;
+  flexfec_timestamp_ += kPacketTimestampIncrement;
+  header.ssrc = flexfec_ssrc_;
+
+  std::unique_ptr<AugmentedPacket> packet_with_rtp_header(
+      new AugmentedPacket());
+  WriteRtpHeader(header, packet_with_rtp_header->data);
+  memcpy(packet_with_rtp_header->data + kRtpHeaderSize, packet.data,
+         packet.length);
+  packet_with_rtp_header->length = kRtpHeaderSize + packet.length;
+
+  return packet_with_rtp_header;
+}
+
+UlpfecPacketGenerator::UlpfecPacketGenerator(uint32_t ssrc)
+    : AugmentedPacketGenerator(ssrc) {}
+
+std::unique_ptr<AugmentedPacket> UlpfecPacketGenerator::BuildMediaRedPacket(
+    const AugmentedPacket& packet) {
+  std::unique_ptr<AugmentedPacket> red_packet(new AugmentedPacket());
+
+  const size_t kHeaderLength = packet.header.header.headerLength;
+  red_packet->header = packet.header;
+  red_packet->length = packet.length + 1;  // 1 byte RED header.
+  // Copy RTP header.
+  memcpy(red_packet->data, packet.data, kHeaderLength);
+  SetRedHeader(red_packet->data[1] & 0x7f, kHeaderLength, red_packet.get());
+  memcpy(red_packet->data + kHeaderLength + 1, packet.data + kHeaderLength,
+         packet.length - kHeaderLength);
+
+  return red_packet;
+}
+
+std::unique_ptr<AugmentedPacket> UlpfecPacketGenerator::BuildUlpfecRedPacket(
+    const ForwardErrorCorrection::Packet& packet) {
+  // Create a fake media packet to get a correct header. 1 byte RED header.
+  ++num_packets_;
+  std::unique_ptr<AugmentedPacket> red_packet =
+      NextPacket(0, packet.length + 1);
+
+  red_packet->data[1] &= ~0x80;  // Clear marker bit.
+  const size_t kHeaderLength = red_packet->header.header.headerLength;
+  SetRedHeader(kFecPayloadType, kHeaderLength, red_packet.get());
+  memcpy(red_packet->data + kHeaderLength + 1, packet.data, packet.length);
+  red_packet->length = kHeaderLength + 1 + packet.length;
+
+  return red_packet;
+}
+
+void UlpfecPacketGenerator::SetRedHeader(uint8_t payload_type,
+                                         size_t header_length,
+                                         AugmentedPacket* red_packet) {
+  // Replace payload type.
+  red_packet->data[1] &= 0x80;             // Reset.
+  red_packet->data[1] += kRedPayloadType;  // Replace.
+
+  // Add RED header, f-bit always 0.
+  red_packet->data[header_length] = payload_type;
+}
+
+}  // namespace fec
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/fec_test_helper.h b/modules/rtp_rtcp/source/fec_test_helper.h
new file mode 100644
index 0000000..004edf7
--- /dev/null
+++ b/modules/rtp_rtcp/source/fec_test_helper.h
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
+#define MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
+
+#include <memory>
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "rtc_base/random.h"
+
+namespace webrtc {
+namespace test {
+namespace fec {
+
+struct AugmentedPacket : public ForwardErrorCorrection::Packet {
+  WebRtcRTPHeader header;
+};
+
+// TODO(brandtr): Consider merging MediaPacketGenerator and
+// AugmentedPacketGenerator into a single class, since their functionality is
+// similar.
+
+// This class generates media packets corresponding to a single frame.
+class MediaPacketGenerator {
+ public:
+  MediaPacketGenerator(uint32_t min_packet_size,
+                       uint32_t max_packet_size,
+                       uint32_t ssrc,
+                       Random* random);
+  ~MediaPacketGenerator();
+
+  // Construct the media packets, up to |num_media_packets| packets.
+  ForwardErrorCorrection::PacketList ConstructMediaPackets(
+      int num_media_packets,
+      uint16_t start_seq_num);
+  ForwardErrorCorrection::PacketList ConstructMediaPackets(
+      int num_media_packets);
+
+  uint16_t GetNextSeqNum();
+
+ private:
+  uint32_t min_packet_size_;
+  uint32_t max_packet_size_;
+  uint32_t ssrc_;
+  Random* random_;
+
+  ForwardErrorCorrection::PacketList media_packets_;
+  uint16_t next_seq_num_;
+};
+
+// This class generates media packets with a certain structure of the payload.
+class AugmentedPacketGenerator {
+ public:
+  explicit AugmentedPacketGenerator(uint32_t ssrc);
+
+  // Prepare for generating a new set of packets, corresponding to a frame.
+  void NewFrame(size_t num_packets);
+
+  // Increment and return the newly incremented sequence number.
+  uint16_t NextPacketSeqNum();
+
+  // Return the next packet in the current frame.
+  std::unique_ptr<AugmentedPacket> NextPacket(size_t offset, size_t length);
+
+ protected:
+  // Given |header|, writes the appropriate RTP header fields in |data|.
+  static void WriteRtpHeader(const RTPHeader& header, uint8_t* data);
+
+  // Number of packets left to generate, in the current frame.
+  size_t num_packets_;
+
+ private:
+  uint32_t ssrc_;
+  uint16_t seq_num_;
+  uint32_t timestamp_;
+};
+
+// This class generates media and FlexFEC packets for a single frame.
+class FlexfecPacketGenerator : public AugmentedPacketGenerator {
+ public:
+  FlexfecPacketGenerator(uint32_t media_ssrc, uint32_t flexfec_ssrc);
+
+  // Creates a new AugmentedPacket (with RTP headers) from a
+  // FlexFEC packet (without RTP headers).
+  std::unique_ptr<AugmentedPacket> BuildFlexfecPacket(
+      const ForwardErrorCorrection::Packet& packet);
+
+ private:
+  uint32_t flexfec_ssrc_;
+  uint16_t flexfec_seq_num_;
+  uint32_t flexfec_timestamp_;
+};
+
+// This class generates media and ULPFEC packets (both encapsulated in RED)
+// for a single frame.
+class UlpfecPacketGenerator : public AugmentedPacketGenerator {
+ public:
+  explicit UlpfecPacketGenerator(uint32_t ssrc);
+
+  // Creates a new AugmentedPacket with the RED header added to the packet.
+  static std::unique_ptr<AugmentedPacket> BuildMediaRedPacket(
+      const AugmentedPacket& packet);
+
+  // Creates a new AugmentedPacket with FEC payload and RED header. Does this by
+  // creating a new fake media AugmentedPacket, clears the marker bit and adds a
+  // RED header. Finally replaces the payload with the content of
+  // |packet->data|.
+  std::unique_ptr<AugmentedPacket> BuildUlpfecRedPacket(
+      const ForwardErrorCorrection::Packet& packet);
+
+ private:
+  static void SetRedHeader(uint8_t payload_type,
+                           size_t header_length,
+                           AugmentedPacket* red_packet);
+};
+
+}  // namespace fec
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_FEC_TEST_HELPER_H_
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
new file mode 100644
index 0000000..d7666e1
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.cc
@@ -0,0 +1,315 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
+
+#include <string.h>
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maximum number of media packets that can be protected in one batch.
+constexpr size_t kMaxMediaPackets = 48;  // Since we are reusing ULPFEC masks.
+
+// Maximum number of FEC packets stored inside ForwardErrorCorrection.
+constexpr size_t kMaxFecPackets = kMaxMediaPackets;
+
+// Size (in bytes) of packet masks, given number of K bits set.
+constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
+
+// Size (in bytes) of part of header which is not packet mask specific.
+constexpr size_t kBaseHeaderSize = 12;
+
+// Size (in bytes) of part of header which is stream specific.
+constexpr size_t kStreamSpecificHeaderSize = 6;
+
+// Size (in bytes) of header, given the single stream packet mask size, i.e.
+// the number of K-bits set.
+constexpr size_t kHeaderSizes[] = {
+    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[0],
+    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[1],
+    kBaseHeaderSize + kStreamSpecificHeaderSize + kFlexfecPacketMaskSizes[2]};
+
+// We currently only support single-stream protection.
+// TODO(brandtr): Update this when we support multistream protection.
+constexpr uint8_t kSsrcCount = 1;
+
+// There are three reserved bytes that MUST be set to zero in the header.
+constexpr uint32_t kReservedBits = 0;
+
+// TODO(brandtr): Update this when we support multistream protection.
+constexpr size_t kPacketMaskOffset =
+    kBaseHeaderSize + kStreamSpecificHeaderSize;
+
+// Here we count the K-bits as belonging to the packet mask.
+// This can be used in conjunction with FlexfecHeaderWriter::MinPacketMaskSize,
+// which calculates a bound on the needed packet mask size including K-bits,
+// given a packet mask without K-bits.
+size_t FlexfecHeaderSize(size_t packet_mask_size) {
+  RTC_DCHECK_LE(packet_mask_size, kFlexfecPacketMaskSizes[2]);
+  if (packet_mask_size <= kFlexfecPacketMaskSizes[0]) {
+    return kHeaderSizes[0];
+  } else if (packet_mask_size <= kFlexfecPacketMaskSizes[1]) {
+    return kHeaderSizes[1];
+  }
+  return kHeaderSizes[2];
+}
+
+}  // namespace
+
+FlexfecHeaderReader::FlexfecHeaderReader()
+    : FecHeaderReader(kMaxMediaPackets, kMaxFecPackets) {}
+
+FlexfecHeaderReader::~FlexfecHeaderReader() = default;
+
+// TODO(brandtr): Update this function when we support flexible masks,
+// retransmissions, and/or several protected SSRCs.
+bool FlexfecHeaderReader::ReadFecHeader(
+    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
+  if (fec_packet->pkt->length <= kBaseHeaderSize + kStreamSpecificHeaderSize) {
+    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+    return false;
+  }
+  bool r_bit = (fec_packet->pkt->data[0] & 0x80) != 0;
+  if (r_bit) {
+    RTC_LOG(LS_INFO)
+        << "FlexFEC packet with retransmission bit set. We do not yet "
+           "support this, thus discarding the packet.";
+    return false;
+  }
+  bool f_bit = (fec_packet->pkt->data[0] & 0x40) != 0;
+  if (f_bit) {
+    RTC_LOG(LS_INFO)
+        << "FlexFEC packet with inflexible generator matrix. We do "
+           "not yet support this, thus discarding packet.";
+    return false;
+  }
+  uint8_t ssrc_count =
+      ByteReader<uint8_t>::ReadBigEndian(&fec_packet->pkt->data[8]);
+  if (ssrc_count != 1) {
+    RTC_LOG(LS_INFO)
+        << "FlexFEC packet protecting multiple media SSRCs. We do not "
+           "yet support this, thus discarding packet.";
+    return false;
+  }
+  uint32_t protected_ssrc =
+      ByteReader<uint32_t>::ReadBigEndian(&fec_packet->pkt->data[12]);
+  uint16_t seq_num_base =
+      ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[16]);
+
+  // Parse the FlexFEC packet mask and remove the interleaved K-bits.
+  // (See FEC header schematic in flexfec_header_reader_writer.h.)
+  // We store the packed packet mask in-band, which "destroys" the standards
+  // compliance of the header. That is fine though, since the code that
+  // reads from the header (from this point and onwards) is aware of this.
+  // TODO(brandtr): When the FEC packet classes have been refactored, store
+  // the packed packet masks out-of-band, thus leaving the FlexFEC header as is.
+  //
+  // We treat the mask parts as unsigned integers with host order endianness
+  // in order to simplify the bit shifting between bytes.
+  if (fec_packet->pkt->length < kHeaderSizes[0]) {
+    RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+    return false;
+  }
+  uint8_t* const packet_mask = fec_packet->pkt->data + kPacketMaskOffset;
+  bool k_bit0 = (packet_mask[0] & 0x80) != 0;
+  uint16_t mask_part0 = ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+  // Shift away K-bit 0, implicitly clearing the last bit.
+  mask_part0 <<= 1;
+  ByteWriter<uint16_t>::WriteBigEndian(&packet_mask[0], mask_part0);
+  size_t packet_mask_size;
+  if (k_bit0) {
+    // The first K-bit is set, and the packet mask is thus only 2 bytes long.
+    // We have now read the entire FEC header, and the rest of the packet
+    // is payload.
+    packet_mask_size = kFlexfecPacketMaskSizes[0];
+  } else {
+    if (fec_packet->pkt->length < kHeaderSizes[1]) {
+      return false;
+    }
+    bool k_bit1 = (packet_mask[2] & 0x80) != 0;
+    // We have already shifted the first two bytes of the packet mask one step
+    // to the left, thus removing K-bit 0. We will now shift the next four bytes
+    // of the packet mask two steps to the left. (One step for the removed
+    // K-bit 0, and one step for the to be removed K-bit 1).
+    uint8_t bit15 = (packet_mask[2] >> 6) & 0x01;
+    packet_mask[1] |= bit15;
+    uint32_t mask_part1 = ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
+    // Shift away K-bit 1 and bit 15, implicitly clearing the last two bits.
+    mask_part1 <<= 2;
+    ByteWriter<uint32_t>::WriteBigEndian(&packet_mask[2], mask_part1);
+    if (k_bit1) {
+      // The first K-bit is clear, but the second K-bit is set. The packet
+      // mask is thus 6 bytes long.  We have now read the entire FEC header,
+      // and the rest of the packet is payload.
+      packet_mask_size = kFlexfecPacketMaskSizes[1];
+    } else {
+      if (fec_packet->pkt->length < kHeaderSizes[2]) {
+        RTC_LOG(LS_WARNING) << "Discarding truncated FlexFEC packet.";
+        return false;
+      }
+      bool k_bit2 = (packet_mask[6] & 0x80) != 0;
+      if (k_bit2) {
+        // The first and second K-bits are clear, but the third K-bit is set.
+        // The packet mask is thus 14 bytes long. We have now read the entire
+        // FEC header, and the rest of the packet is payload.
+        packet_mask_size = kFlexfecPacketMaskSizes[2];
+      } else {
+        RTC_LOG(LS_WARNING)
+            << "Discarding FlexFEC packet with malformed header.";
+        return false;
+      }
+      // At this point, K-bits 0 and 1 have been removed, and the front-most
+      // part of the FlexFEC packet mask has been packed accordingly. We will
+      // now shift the remaning part of the packet mask three steps to the left.
+      // This corresponds to the (in total) three K-bits, which have been
+      // removed.
+      uint8_t tail_bits = (packet_mask[6] >> 5) & 0x03;
+      packet_mask[5] |= tail_bits;
+      uint64_t mask_part2 =
+          ByteReader<uint64_t>::ReadBigEndian(&packet_mask[6]);
+      // Shift away K-bit 2, bit 46, and bit 47, implicitly clearing the last
+      // three bits.
+      mask_part2 <<= 3;
+      ByteWriter<uint64_t>::WriteBigEndian(&packet_mask[6], mask_part2);
+    }
+  }
+
+  // Store "ULPFECized" packet mask info.
+  fec_packet->fec_header_size = FlexfecHeaderSize(packet_mask_size);
+  fec_packet->protected_ssrc = protected_ssrc;
+  fec_packet->seq_num_base = seq_num_base;
+  fec_packet->packet_mask_offset = kPacketMaskOffset;
+  fec_packet->packet_mask_size = packet_mask_size;
+
+  // In FlexFEC, all media packets are protected in their entirety.
+  fec_packet->protection_length =
+      fec_packet->pkt->length - fec_packet->fec_header_size;
+
+  return true;
+}
+
+FlexfecHeaderWriter::FlexfecHeaderWriter()
+    : FecHeaderWriter(kMaxMediaPackets, kMaxFecPackets, kHeaderSizes[2]) {}
+
+FlexfecHeaderWriter::~FlexfecHeaderWriter() = default;
+
+size_t FlexfecHeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask,
+                                              size_t packet_mask_size) const {
+  if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear &&
+      (packet_mask[1] & 0x01) == 0) {
+    // Packet mask is 16 bits long, with bit 15 clear.
+    // It can be used as is.
+    return kFlexfecPacketMaskSizes[0];
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
+    // Packet mask is 16 bits long, with bit 15 set.
+    // We must expand the packet mask with zeros in the FlexFEC header.
+    return kFlexfecPacketMaskSizes[1];
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet &&
+             (packet_mask[5] & 0x03) == 0) {
+    // Packet mask is 48 bits long, with bits 46 and 47 clear.
+    // It can be used as is.
+    return kFlexfecPacketMaskSizes[1];
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
+    // Packet mask is 48 bits long, with at least one of bits 46 and 47 set.
+    // We must expand it with zeros.
+    return kFlexfecPacketMaskSizes[2];
+  }
+  RTC_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size << ".";
+  return kFlexfecPacketMaskSizes[2];
+}
+
+size_t FlexfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
+  return FlexfecHeaderSize(packet_mask_size);
+}
+
+// This function adapts the precomputed ULPFEC packet masks to the
+// FlexFEC header standard. Note that the header size is computed by
+// FecHeaderSize(), so in this function we can be sure that we are
+// writing in space that is intended for the header.
+//
+// TODO(brandtr): Update this function when we support offset-based masks,
+// retransmissions, and protecting multiple SSRCs.
+void FlexfecHeaderWriter::FinalizeFecHeader(
+    uint32_t media_ssrc,
+    uint16_t seq_num_base,
+    const uint8_t* packet_mask,
+    size_t packet_mask_size,
+    ForwardErrorCorrection::Packet* fec_packet) const {
+  fec_packet->data[0] &= 0x7f;  // Clear R bit.
+  fec_packet->data[0] &= 0xbf;  // Clear F bit.
+  ByteWriter<uint8_t>::WriteBigEndian(&fec_packet->data[8], kSsrcCount);
+  ByteWriter<uint32_t, 3>::WriteBigEndian(&fec_packet->data[9], kReservedBits);
+  ByteWriter<uint32_t>::WriteBigEndian(&fec_packet->data[12], media_ssrc);
+  ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[16], seq_num_base);
+  // Adapt ULPFEC packet mask to FlexFEC header.
+  //
+  // We treat the mask parts as unsigned integers with host order endianness
+  // in order to simplify the bit shifting between bytes.
+  uint8_t* const written_packet_mask = fec_packet->data + kPacketMaskOffset;
+  if (packet_mask_size == kUlpfecPacketMaskSizeLBitSet) {
+    // The packet mask is 48 bits long.
+    uint16_t tmp_mask_part0 =
+        ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+    uint32_t tmp_mask_part1 =
+        ByteReader<uint32_t>::ReadBigEndian(&packet_mask[2]);
+
+    tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
+    ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
+                                         tmp_mask_part0);
+    tmp_mask_part1 >>= 2;  // Shift, thus clearing K-bit 1 and bit 15.
+    ByteWriter<uint32_t>::WriteBigEndian(&written_packet_mask[2],
+                                         tmp_mask_part1);
+    bool bit15 = (packet_mask[1] & 0x01) != 0;
+    if (bit15)
+      written_packet_mask[2] |= 0x40;  // Set bit 15.
+    bool bit46 = (packet_mask[5] & 0x02) != 0;
+    bool bit47 = (packet_mask[5] & 0x01) != 0;
+    if (!bit46 && !bit47) {
+      written_packet_mask[2] |= 0x80;  // Set K-bit 1.
+    } else {
+      memset(&written_packet_mask[6], 0, 8);  // Clear all trailing bits.
+      written_packet_mask[6] |= 0x80;         // Set K-bit 2.
+      if (bit46)
+        written_packet_mask[6] |= 0x40;  // Set bit 46.
+      if (bit47)
+        written_packet_mask[6] |= 0x20;  // Set bit 47.
+    }
+  } else if (packet_mask_size == kUlpfecPacketMaskSizeLBitClear) {
+    // The packet mask is 16 bits long.
+    uint16_t tmp_mask_part0 =
+        ByteReader<uint16_t>::ReadBigEndian(&packet_mask[0]);
+
+    tmp_mask_part0 >>= 1;  // Shift, thus clearing K-bit 0.
+    ByteWriter<uint16_t>::WriteBigEndian(&written_packet_mask[0],
+                                         tmp_mask_part0);
+    bool bit15 = (packet_mask[1] & 0x01) != 0;
+    if (!bit15) {
+      written_packet_mask[0] |= 0x80;  // Set K-bit 0.
+    } else {
+      memset(&written_packet_mask[2], 0U, 4);  // Clear all trailing bits.
+      written_packet_mask[2] |= 0x80;          // Set K-bit 1.
+      written_packet_mask[2] |= 0x40;          // Set bit 15.
+    }
+  } else {
+    RTC_NOTREACHED() << "Incorrect packet mask size: " << packet_mask_size
+                     << ".";
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer.h b/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
new file mode 100644
index 0000000..1d6ddda
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer.h
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER_H_
+#define MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER_H_
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+namespace webrtc {
+
+// FlexFEC header, minimum 20 bytes.
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |R|F|P|X|  CC   |M| PT recovery |        length recovery        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                          TS recovery                          |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |   SSRCCount   |                    reserved                   |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// 12 |                             SSRC_i                            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |           SN base_i           |k|          Mask [0-14]        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 |k|                   Mask [15-45] (optional)                   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 24 |k|                                                             |
+//    +-+                   Mask [46-108] (optional)                  |
+// 28 |                                                               |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//    :                     ... next in SSRC_i ...                    :
+//
+//
+// FlexFEC header in 'inflexible' mode (F = 1), 20 bytes.
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |0|1|P|X|  CC   |M| PT recovery |        length recovery        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                          TS recovery                          |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |   SSRCCount   |                    reserved                   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |                             SSRC_i                            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |           SN base_i           |  M (columns)  |    N (rows)   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class FlexfecHeaderReader : public FecHeaderReader {
+ public:
+  FlexfecHeaderReader();
+  ~FlexfecHeaderReader() override;
+
+  bool ReadFecHeader(
+      ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override;
+};
+
+class FlexfecHeaderWriter : public FecHeaderWriter {
+ public:
+  FlexfecHeaderWriter();
+  ~FlexfecHeaderWriter() override;
+
+  size_t MinPacketMaskSize(const uint8_t* packet_mask,
+                           size_t packet_mask_size) const override;
+
+  size_t FecHeaderSize(size_t packet_mask_row_size) const override;
+
+  void FinalizeFecHeader(
+      uint32_t media_ssrc,
+      uint16_t seq_num_base,
+      const uint8_t* packet_mask,
+      size_t packet_mask_size,
+      ForwardErrorCorrection::Packet* fec_packet) const override;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_FLEXFEC_HEADER_READER_WRITER_H_
diff --git a/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
new file mode 100644
index 0000000..5da378c
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc
@@ -0,0 +1,558 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include <string.h>
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/random.h"
+#include "rtc_base/scoped_ref_ptr.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using Packet = ForwardErrorCorrection::Packet;
+using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
+
+// General. Assume single-stream protection.
+constexpr uint32_t kMediaSsrc = 1254983;
+constexpr uint16_t kMediaStartSeqNum = 825;
+constexpr size_t kMediaPacketLength = 1234;
+constexpr uint32_t kFlexfecSsrc = 52142;
+
+constexpr size_t kFlexfecHeaderSizes[] = {20, 24, 32};
+constexpr size_t kFlexfecPacketMaskOffset = 18;
+constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};
+constexpr size_t kFlexfecMaxPacketSize = kFlexfecPacketMaskSizes[2];
+
+// Reader tests.
+constexpr uint8_t kNoRBit = 0 << 7;
+constexpr uint8_t kNoFBit = 0 << 6;
+constexpr uint8_t kPtRecovery = 123;
+constexpr uint8_t kLengthRecov[] = {0xab, 0xcd};
+constexpr uint8_t kTsRecovery[] = {0x01, 0x23, 0x45, 0x67};
+constexpr uint8_t kSsrcCount = 1;
+constexpr uint8_t kReservedBits = 0x00;
+constexpr uint8_t kProtSsrc[] = {0x11, 0x22, 0x33, 0x44};
+constexpr uint8_t kSnBase[] = {0xaa, 0xbb};
+constexpr uint8_t kPayloadBits = 0x00;
+
+std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size,
+                                              uint64_t seed) {
+  Random random(seed);
+  std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[kFlexfecMaxPacketSize]);
+  memset(packet_mask.get(), 0, kFlexfecMaxPacketSize);
+  for (size_t i = 0; i < packet_mask_size; ++i) {
+    packet_mask[i] = random.Rand<uint8_t>();
+  }
+  return packet_mask;
+}
+
+void ClearBit(size_t index, uint8_t* packet_mask) {
+  packet_mask[index / 8] &= ~(1 << (7 - index % 8));
+}
+
+void SetBit(size_t index, uint8_t* packet_mask) {
+  packet_mask[index / 8] |= (1 << (7 - index % 8));
+}
+
+rtc::scoped_refptr<Packet> WriteHeader(const uint8_t* packet_mask,
+                                       size_t packet_mask_size) {
+  FlexfecHeaderWriter writer;
+  rtc::scoped_refptr<Packet> written_packet(new Packet());
+  written_packet->length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet->length; ++i) {
+    written_packet->data[i] = i;  // Actual content doesn't matter.
+  }
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask,
+                           packet_mask_size, written_packet.get());
+  return written_packet;
+}
+
+std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) {
+  FlexfecHeaderReader reader;
+  std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket());
+  read_packet->ssrc = kFlexfecSsrc;
+  read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet->pkt->data, written_packet.data, written_packet.length);
+  read_packet->pkt->length = written_packet.length;
+  EXPECT_TRUE(reader.ReadFecHeader(read_packet.get()));
+  return read_packet;
+}
+
+void VerifyReadHeaders(size_t expected_fec_header_size,
+                       const uint8_t* expected_packet_mask,
+                       size_t expected_packet_mask_size,
+                       const ReceivedFecPacket& read_packet) {
+  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
+  EXPECT_EQ(ByteReader<uint32_t>::ReadBigEndian(kProtSsrc),
+            read_packet.protected_ssrc);
+  EXPECT_EQ(ByteReader<uint16_t>::ReadBigEndian(kSnBase),
+            read_packet.seq_num_base);
+  const size_t packet_mask_offset = read_packet.packet_mask_offset;
+  EXPECT_EQ(kFlexfecPacketMaskOffset, packet_mask_offset);
+  EXPECT_EQ(expected_packet_mask_size, read_packet.packet_mask_size);
+  EXPECT_EQ(read_packet.pkt->length - expected_fec_header_size,
+            read_packet.protection_length);
+  // Ensure that the K-bits are removed and the packet mask has been packed.
+  EXPECT_THAT(::testing::make_tuple(read_packet.pkt->data + packet_mask_offset,
+                                    read_packet.packet_mask_size),
+              ::testing::ElementsAreArray(expected_packet_mask,
+                                          expected_packet_mask_size));
+}
+
+void VerifyFinalizedHeaders(const uint8_t* expected_packet_mask,
+                            size_t expected_packet_mask_size,
+                            const Packet& written_packet) {
+  const uint8_t* packet = written_packet.data;
+  EXPECT_EQ(0x00, packet[0] & 0x80);  // F bit clear.
+  EXPECT_EQ(0x00, packet[0] & 0x40);  // R bit clear.
+  EXPECT_EQ(0x01, packet[8]);         // SSRCCount = 1.
+  EXPECT_EQ(kMediaSsrc, ByteReader<uint32_t>::ReadBigEndian(packet + 12));
+  EXPECT_EQ(kMediaStartSeqNum,
+            ByteReader<uint16_t>::ReadBigEndian(packet + 16));
+  EXPECT_THAT(::testing::make_tuple(packet + kFlexfecPacketMaskOffset,
+                                    expected_packet_mask_size),
+              ::testing::ElementsAreArray(expected_packet_mask,
+                                          expected_packet_mask_size));
+}
+
+void VerifyWrittenAndReadHeaders(size_t expected_fec_header_size,
+                                 const uint8_t* expected_packet_mask,
+                                 size_t expected_packet_mask_size,
+                                 const Packet& written_packet,
+                                 const ReceivedFecPacket& read_packet) {
+  EXPECT_EQ(kFlexfecSsrc, read_packet.ssrc);
+  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
+  EXPECT_EQ(kMediaSsrc, read_packet.protected_ssrc);
+  EXPECT_EQ(kMediaStartSeqNum, read_packet.seq_num_base);
+  EXPECT_EQ(kFlexfecPacketMaskOffset, read_packet.packet_mask_offset);
+  ASSERT_EQ(expected_packet_mask_size, read_packet.packet_mask_size);
+  EXPECT_EQ(written_packet.length - expected_fec_header_size,
+            read_packet.protection_length);
+  // Verify that the call to ReadFecHeader did normalize the packet masks.
+  EXPECT_THAT(
+      ::testing::make_tuple(read_packet.pkt->data + kFlexfecPacketMaskOffset,
+                            read_packet.packet_mask_size),
+      ::testing::ElementsAreArray(expected_packet_mask,
+                                  expected_packet_mask_size));
+  // Verify that the call to ReadFecHeader did not tamper with the payload.
+  EXPECT_THAT(::testing::make_tuple(
+                  read_packet.pkt->data + read_packet.fec_header_size,
+                  read_packet.pkt->length - read_packet.fec_header_size),
+              ::testing::ElementsAreArray(
+                  written_packet.data + expected_fec_header_size,
+                  written_packet.length - expected_fec_header_size));
+}
+
+}  // namespace
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit0Set) {
+  constexpr uint8_t kKBit0 = 1 << 7;
+  constexpr size_t kExpectedPacketMaskSize = 2;
+  constexpr size_t kExpectedFecHeaderSize = 20;
+  // clang-format off
+  constexpr uint8_t kFlexfecPktMask[] = {kKBit0 | 0x08, 0x81};
+  constexpr uint8_t kUlpfecPacketMask[] =        {0x11, 0x02};
+  // clang-format on
+  constexpr uint8_t kPacketData[] = {
+      kNoRBit | kNoFBit, kPtRecovery,    kLengthRecov[0],    kLengthRecov[1],
+      kTsRecovery[0],    kTsRecovery[1], kTsRecovery[2],     kTsRecovery[3],
+      kSsrcCount,        kReservedBits,  kReservedBits,      kReservedBits,
+      kProtSsrc[0],      kProtSsrc[1],   kProtSsrc[2],       kProtSsrc[3],
+      kSnBase[0],        kSnBase[1],     kFlexfecPktMask[0], kFlexfecPktMask[1],
+      kPayloadBits,      kPayloadBits,   kPayloadBits,       kPayloadBits};
+  const size_t packet_length = sizeof(kPacketData);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet.pkt->data, kPacketData, packet_length);
+  read_packet.pkt->length = packet_length;
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
+                    kExpectedPacketMaskSize, read_packet);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit1Set) {
+  constexpr uint8_t kKBit0 = 0 << 7;
+  constexpr uint8_t kKBit1 = 1 << 7;
+  constexpr size_t kExpectedPacketMaskSize = 6;
+  constexpr size_t kExpectedFecHeaderSize = 24;
+  // clang-format off
+  constexpr uint8_t kFlxfecPktMsk[] = {kKBit0 | 0x48, 0x81,
+                                       kKBit1 | 0x02, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask[] =      {0x91, 0x02,
+                                                0x08, 0x44, 0x00, 0x84};
+  // clang-format on
+  constexpr uint8_t kPacketData[] = {
+      kNoRBit | kNoFBit, kPtRecovery,      kLengthRecov[0],  kLengthRecov[1],
+      kTsRecovery[0],    kTsRecovery[1],   kTsRecovery[2],   kTsRecovery[3],
+      kSsrcCount,        kReservedBits,    kReservedBits,    kReservedBits,
+      kProtSsrc[0],      kProtSsrc[1],     kProtSsrc[2],     kProtSsrc[3],
+      kSnBase[0],        kSnBase[1],       kFlxfecPktMsk[0], kFlxfecPktMsk[1],
+      kFlxfecPktMsk[2],  kFlxfecPktMsk[3], kFlxfecPktMsk[4], kFlxfecPktMsk[5],
+      kPayloadBits,      kPayloadBits,     kPayloadBits,     kPayloadBits};
+  const size_t packet_length = sizeof(kPacketData);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet.pkt->data, kPacketData, packet_length);
+  read_packet.pkt->length = packet_length;
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
+                    kExpectedPacketMaskSize, read_packet);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadsHeaderWithKBit2Set) {
+  constexpr uint8_t kKBit0 = 0 << 7;
+  constexpr uint8_t kKBit1 = 0 << 7;
+  constexpr uint8_t kKBit2 = 1 << 7;
+  constexpr size_t kExpectedPacketMaskSize = 14;
+  constexpr size_t kExpectedFecHeaderSize = 32;
+  // clang-format off
+  constexpr uint8_t kFlxfcPktMsk[] = {kKBit0 | 0x48, 0x81,
+                                      kKBit1 | 0x02, 0x11, 0x00, 0x21,
+                                      kKBit2 | 0x01, 0x11, 0x11, 0x11,
+                                               0x11, 0x11, 0x11, 0x11};
+  constexpr uint8_t kUlpfecPacketMask[] =     {0x91, 0x02,
+                                               0x08, 0x44, 0x00, 0x84,
+                                               0x08, 0x88, 0x88, 0x88,
+                                               0x88, 0x88, 0x88, 0x88};
+  // clang-format on
+  constexpr uint8_t kPacketData[] = {
+      kNoRBit | kNoFBit, kPtRecovery,      kLengthRecov[0],  kLengthRecov[1],
+      kTsRecovery[0],    kTsRecovery[1],   kTsRecovery[2],   kTsRecovery[3],
+      kSsrcCount,        kReservedBits,    kReservedBits,    kReservedBits,
+      kProtSsrc[0],      kProtSsrc[1],     kProtSsrc[2],     kProtSsrc[3],
+      kSnBase[0],        kSnBase[1],       kFlxfcPktMsk[0],  kFlxfcPktMsk[1],
+      kFlxfcPktMsk[2],   kFlxfcPktMsk[3],  kFlxfcPktMsk[4],  kFlxfcPktMsk[5],
+      kFlxfcPktMsk[6],   kFlxfcPktMsk[7],  kFlxfcPktMsk[8],  kFlxfcPktMsk[9],
+      kFlxfcPktMsk[10],  kFlxfcPktMsk[11], kFlxfcPktMsk[12], kFlxfcPktMsk[13],
+      kPayloadBits,      kPayloadBits,     kPayloadBits,     kPayloadBits};
+  const size_t packet_length = sizeof(kPacketData);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet.pkt->data, kPacketData, packet_length);
+  read_packet.pkt->length = packet_length;
+
+  FlexfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  VerifyReadHeaders(kExpectedFecHeaderSize, kUlpfecPacketMask,
+                    kExpectedPacketMaskSize, read_packet);
+}
+
+TEST(FlexfecHeaderReaderTest, ReadPacketWithoutStreamSpecificHeaderShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->length = 12;
+
+  FlexfecHeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit0SetShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->length = 18;
+
+  FlexfecHeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit1SetShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(15, packet_mask.get());  // This expands the packet mask "once".
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->length = 20;
+
+  FlexfecHeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(FlexfecHeaderReaderTest, ReadShortPacketWithKBit2SetShouldFail) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(47, packet_mask.get());  // This expands the packet mask "twice".
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+
+  // Simulate short received packet.
+  ReceivedFecPacket read_packet;
+  read_packet.ssrc = kFlexfecSsrc;
+  read_packet.pkt = std::move(written_packet);
+  read_packet.pkt->length = 24;
+
+  FlexfecHeaderReader reader;
+  EXPECT_FALSE(reader.ReadFecHeader(&read_packet));
+}
+
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit0Set) {
+  constexpr size_t kExpectedPacketMaskSize = 2;
+  constexpr uint8_t kFlexfecPacketMask[] = {0x88, 0x81};
+  constexpr uint8_t kUlpfecPacketMask[] = {0x11, 0x02};
+  Packet written_packet;
+  written_packet.length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet.length; ++i) {
+    written_packet.data[i] = i;
+  }
+
+  FlexfecHeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
+                           sizeof(kUlpfecPacketMask), &written_packet);
+
+  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
+                         written_packet);
+}
+
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit1Set) {
+  constexpr size_t kExpectedPacketMaskSize = 6;
+  constexpr uint8_t kFlexfecPacketMask[] = {0x48, 0x81, 0x82, 0x11, 0x00, 0x21};
+  constexpr uint8_t kUlpfecPacketMask[] = {0x91, 0x02, 0x08, 0x44, 0x00, 0x84};
+  Packet written_packet;
+  written_packet.length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet.length; ++i) {
+    written_packet.data[i] = i;
+  }
+
+  FlexfecHeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
+                           sizeof(kUlpfecPacketMask), &written_packet);
+
+  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
+                         written_packet);
+}
+
+TEST(FlexfecHeaderWriterTest, FinalizesHeaderWithKBit2Set) {
+  constexpr size_t kExpectedPacketMaskSize = 14;
+  constexpr uint8_t kFlexfecPacketMask[] = {
+      0x11, 0x11,                                     // K-bit 0 clear.
+      0x11, 0x11, 0x11, 0x10,                         // K-bit 1 clear.
+      0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // K-bit 2 set.
+  };
+  constexpr uint8_t kUlpfecPacketMask[] = {0x22, 0x22, 0x44, 0x44, 0x44, 0x41};
+  Packet written_packet;
+  written_packet.length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet.length; ++i) {
+    written_packet.data[i] = i;
+  }
+
+  FlexfecHeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, kUlpfecPacketMask,
+                           sizeof(kUlpfecPacketMask), &written_packet);
+
+  VerifyFinalizedHeaders(kFlexfecPacketMask, kExpectedPacketMaskSize,
+                         written_packet);
+}
+
+TEST(FlexfecHeaderWriterTest, ContractsShortUlpfecPacketMaskWithBit15Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(15, packet_mask.get());
+
+  FlexfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[0], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[0], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(FlexfecHeaderWriterTest, ExpandsShortUlpfecPacketMaskWithBit15Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(15, packet_mask.get());
+
+  FlexfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(FlexfecHeaderWriterTest,
+     ContractsLongUlpfecPacketMaskWithBit46ClearBit47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  FlexfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[1], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[1], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(FlexfecHeaderWriterTest,
+     ExpandsLongUlpfecPacketMaskWithBit46SetBit47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  FlexfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(FlexfecHeaderWriterTest,
+     ExpandsLongUlpfecPacketMaskWithBit46ClearBit47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  FlexfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(FlexfecHeaderWriterTest, ExpandsLongUlpfecPacketMaskWithBit46SetBit47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  FlexfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kFlexfecPacketMaskSizes[2], min_packet_mask_size);
+  EXPECT_EQ(kFlexfecHeaderSizes[2], writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(FlexfecHeaderReaderWriterTest,
+     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(15, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[0], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[0], *written_packet,
+                              *read_packet);
+}
+
+TEST(FlexfecHeaderReaderWriterTest,
+     WriteAndReadSmallUlpfecPacketHeaderWithMaskBit15Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(15, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[1], *written_packet,
+                              *read_packet);
+}
+
+TEST(FlexfecHeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[1], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[1], *written_packet,
+                              *read_packet);
+}
+
+TEST(FlexfecHeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBit46SetBit47Clear) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  ClearBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[2], *written_packet,
+                              *read_packet);
+}
+
+TEST(FlexfecHeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderMaskWithBit46ClearBit47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  ClearBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[2], *written_packet,
+                              *read_packet);
+}
+
+TEST(FlexfecHeaderReaderWriterTest,
+     WriteAndReadLargeUlpfecPacketHeaderWithMaskBits46And47Set) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  SetBit(46, packet_mask.get());
+  SetBit(47, packet_mask.get());
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyWrittenAndReadHeaders(kFlexfecHeaderSizes[2], packet_mask.get(),
+                              kFlexfecPacketMaskSizes[2], *written_packet,
+                              *read_packet);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_receiver.cc b/modules/rtp_rtcp/source/flexfec_receiver.cc
new file mode 100644
index 0000000..c3ed4d5
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_receiver.cc
@@ -0,0 +1,165 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/flexfec_receiver.h"
+
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/scoped_ref_ptr.h"
+
+namespace webrtc {
+
+namespace {
+
+using Packet = ForwardErrorCorrection::Packet;
+using ReceivedPacket = ForwardErrorCorrection::ReceivedPacket;
+
+// Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
+constexpr size_t kMinFlexfecHeaderSize = 20;
+
+// How often to log the recovered packets to the text log.
+constexpr int kPacketLogIntervalMs = 10000;
+
+}  // namespace
+
+FlexfecReceiver::FlexfecReceiver(
+    uint32_t ssrc,
+    uint32_t protected_media_ssrc,
+    RecoveredPacketReceiver* recovered_packet_receiver)
+    : ssrc_(ssrc),
+      protected_media_ssrc_(protected_media_ssrc),
+      erasure_code_(
+          ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
+      recovered_packet_receiver_(recovered_packet_receiver),
+      clock_(Clock::GetRealTimeClock()),
+      last_recovered_packet_ms_(-1) {
+  // It's OK to create this object on a different thread/task queue than
+  // the one used during main operation.
+  sequence_checker_.Detach();
+}
+
+FlexfecReceiver::~FlexfecReceiver() = default;
+
+void FlexfecReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
+
+  // If this packet was recovered, it might be originating from
+  // ProcessReceivedPacket in this object. To avoid lifetime issues with
+  // |recovered_packets_|, we therefore break the cycle here.
+  // This might reduce decoding efficiency a bit, since we can't disambiguate
+  // recovered packets by RTX from recovered packets by FlexFEC.
+  if (packet.recovered())
+    return;
+
+  std::unique_ptr<ReceivedPacket> received_packet = AddReceivedPacket(packet);
+  if (!received_packet)
+    return;
+
+  ProcessReceivedPacket(*received_packet);
+}
+
+FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
+  return packet_counter_;
+}
+
+// TODO(eladalon): Consider using packet.recovered() to avoid processing
+// recovered packets here.
+std::unique_ptr<ReceivedPacket> FlexfecReceiver::AddReceivedPacket(
+    const RtpPacketReceived& packet) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
+
+  // RTP packets with a full base header (12 bytes), but without payload,
+  // could conceivably be useful in the decoding. Therefore we check
+  // with a non-strict inequality here.
+  RTC_DCHECK_GE(packet.size(), kRtpHeaderSize);
+
+  // Demultiplex based on SSRC, and insert into erasure code decoder.
+  std::unique_ptr<ReceivedPacket> received_packet(new ReceivedPacket());
+  received_packet->seq_num = packet.SequenceNumber();
+  received_packet->ssrc = packet.Ssrc();
+  if (received_packet->ssrc == ssrc_) {
+    // This is a FlexFEC packet.
+    if (packet.payload_size() < kMinFlexfecHeaderSize) {
+      RTC_LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
+      return nullptr;
+    }
+    received_packet->is_fec = true;
+    ++packet_counter_.num_fec_packets;
+
+    // Insert packet payload into erasure code.
+    // TODO(brandtr): Remove this memcpy when the FEC packet classes
+    // are using COW buffers internally.
+    received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
+    auto payload = packet.payload();
+    memcpy(received_packet->pkt->data, payload.data(), payload.size());
+    received_packet->pkt->length = payload.size();
+  } else {
+    // This is a media packet, or a FlexFEC packet belonging to some
+    // other FlexFEC stream.
+    if (received_packet->ssrc != protected_media_ssrc_) {
+      return nullptr;
+    }
+    received_packet->is_fec = false;
+
+    // Insert entire packet into erasure code.
+    // TODO(brandtr): Remove this memcpy too.
+    received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
+    memcpy(received_packet->pkt->data, packet.data(), packet.size());
+    received_packet->pkt->length = packet.size();
+  }
+
+  ++packet_counter_.num_packets;
+
+  return received_packet;
+}
+
+// Note that the implementation of this member function and the implementation
+// in UlpfecReceiver::ProcessReceivedFec() are slightly different.
+// This implementation only returns _recovered_ media packets through the
+// callback, whereas the implementation in UlpfecReceiver returns _all inserted_
+// media packets through the callback. The latter behaviour makes sense
+// for ULPFEC, since the ULPFEC receiver is owned by the RtpVideoStreamReceiver.
+// Here, however, the received media pipeline is more decoupled from the
+// FlexFEC decoder, and we therefore do not interfere with the reception
+// of non-recovered media packets.
+void FlexfecReceiver::ProcessReceivedPacket(
+    const ReceivedPacket& received_packet) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
+
+  // Decode.
+  erasure_code_->DecodeFec(received_packet, &recovered_packets_);
+
+  // Return recovered packets through callback.
+  for (const auto& recovered_packet : recovered_packets_) {
+    RTC_CHECK(recovered_packet);
+    if (recovered_packet->returned) {
+      continue;
+    }
+    ++packet_counter_.num_recovered_packets;
+    // Set this flag first, since OnRecoveredPacket may end up here
+    // again, with the same packet.
+    recovered_packet->returned = true;
+    RTC_CHECK(recovered_packet->pkt);
+    recovered_packet_receiver_->OnRecoveredPacket(
+        recovered_packet->pkt->data, recovered_packet->pkt->length);
+    // Periodically log the incoming packets.
+    int64_t now_ms = clock_->TimeInMilliseconds();
+    if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) {
+      uint32_t media_ssrc =
+          ForwardErrorCorrection::ParseSsrc(recovered_packet->pkt->data);
+      RTC_LOG(LS_VERBOSE) << "Recovered media packet with SSRC: " << media_ssrc
+                          << " from FlexFEC stream with SSRC: " << ssrc_ << ".";
+      last_recovered_packet_ms_ = now_ms;
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc b/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc
new file mode 100644
index 0000000..378cf7d
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_receiver_unittest.cc
@@ -0,0 +1,647 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include <algorithm>
+#include <memory>
+
+#include "modules/rtp_rtcp/include/flexfec_receiver.h"
+#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Args;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+
+using test::fec::FlexfecPacketGenerator;
+using Packet = ForwardErrorCorrection::Packet;
+using PacketList = ForwardErrorCorrection::PacketList;
+
+constexpr size_t kPayloadLength = 500;
+constexpr uint32_t kFlexfecSsrc = 42984;
+constexpr uint32_t kMediaSsrc = 8353;
+
+RtpPacketReceived ParsePacket(const Packet& packet) {
+  RtpPacketReceived parsed_packet;
+  EXPECT_TRUE(parsed_packet.Parse(packet.data, packet.length));
+  return parsed_packet;
+}
+
+}  // namespace
+
+class FlexfecReceiverForTest : public FlexfecReceiver {
+ public:
+  FlexfecReceiverForTest(uint32_t ssrc,
+                         uint32_t protected_media_ssrc,
+                         RecoveredPacketReceiver* recovered_packet_receiver)
+      : FlexfecReceiver(ssrc, protected_media_ssrc, recovered_packet_receiver) {
+  }
+  // Expose methods for tests.
+  using FlexfecReceiver::AddReceivedPacket;
+  using FlexfecReceiver::ProcessReceivedPacket;
+};
+
+class FlexfecReceiverTest : public ::testing::Test {
+ protected:
+  FlexfecReceiverTest()
+      : receiver_(kFlexfecSsrc, kMediaSsrc, &recovered_packet_receiver_),
+        erasure_code_(
+            ForwardErrorCorrection::CreateFlexfec(kFlexfecSsrc, kMediaSsrc)),
+        packet_generator_(kMediaSsrc, kFlexfecSsrc) {}
+
+  // Generates |num_media_packets| corresponding to a single frame.
+  void PacketizeFrame(size_t num_media_packets,
+                      size_t frame_offset,
+                      PacketList* media_packets);
+
+  // Generates |num_fec_packets| FEC packets, given |media_packets|.
+  std::list<Packet*> EncodeFec(const PacketList& media_packets,
+                               size_t num_fec_packets);
+
+  FlexfecReceiverForTest receiver_;
+  std::unique_ptr<ForwardErrorCorrection> erasure_code_;
+
+  FlexfecPacketGenerator packet_generator_;
+  testing::StrictMock<MockRecoveredPacketReceiver> recovered_packet_receiver_;
+};
+
+void FlexfecReceiverTest::PacketizeFrame(size_t num_media_packets,
+                                         size_t frame_offset,
+                                         PacketList* media_packets) {
+  packet_generator_.NewFrame(num_media_packets);
+  for (size_t i = 0; i < num_media_packets; ++i) {
+    std::unique_ptr<Packet> next_packet(
+        packet_generator_.NextPacket(frame_offset + i, kPayloadLength));
+    media_packets->push_back(std::move(next_packet));
+  }
+}
+
+std::list<Packet*> FlexfecReceiverTest::EncodeFec(
+    const PacketList& media_packets,
+    size_t num_fec_packets) {
+  const uint8_t protection_factor =
+      num_fec_packets * 255 / media_packets.size();
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr FecMaskType kFecMaskType = kFecMaskRandom;
+  std::list<Packet*> fec_packets;
+  EXPECT_EQ(0, erasure_code_->EncodeFec(
+                   media_packets, protection_factor, kNumImportantPackets,
+                   kUseUnequalProtection, kFecMaskType, &fec_packets));
+  EXPECT_EQ(num_fec_packets, fec_packets.size());
+  return fec_packets;
+}
+
+TEST_F(FlexfecReceiverTest, ReceivesMediaPacket) {
+  packet_generator_.NewFrame(1);
+  std::unique_ptr<Packet> media_packet(
+      packet_generator_.NextPacket(0, kPayloadLength));
+
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
+      receiver_.AddReceivedPacket(ParsePacket(*media_packet));
+  ASSERT_TRUE(received_packet);
+  receiver_.ProcessReceivedPacket(*received_packet);
+}
+
+TEST_F(FlexfecReceiverTest, ReceivesMediaAndFecPackets) {
+  const size_t kNumMediaPackets = 1;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+  const auto& media_packet = media_packets.front();
+  auto fec_packet = packet_generator_.BuildFlexfecPacket(*fec_packets.front());
+
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
+      receiver_.AddReceivedPacket(ParsePacket(*media_packet));
+  ASSERT_TRUE(received_packet);
+  receiver_.ProcessReceivedPacket(*received_packet);
+  received_packet = receiver_.AddReceivedPacket(ParsePacket(*fec_packet));
+  ASSERT_TRUE(received_packet);
+  receiver_.ProcessReceivedPacket(*received_packet);
+}
+
+TEST_F(FlexfecReceiverTest, FailsOnTruncatedFecPacket) {
+  const size_t kNumMediaPackets = 1;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+  const auto& media_packet = media_packets.front();
+  // Simulate truncated FlexFEC payload.
+  fec_packets.front()->length = 1;
+  auto fec_packet = packet_generator_.BuildFlexfecPacket(*fec_packets.front());
+
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
+      receiver_.AddReceivedPacket(ParsePacket(*media_packet));
+  ASSERT_TRUE(received_packet);
+  receiver_.ProcessReceivedPacket(*received_packet);
+  EXPECT_FALSE(receiver_.AddReceivedPacket(ParsePacket(*fec_packet)));
+}
+
+TEST_F(FlexfecReceiverTest, FailsOnUnknownMediaSsrc) {
+  const size_t kNumMediaPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  auto& media_packet = media_packets.front();
+  // Corrupt the SSRC.
+  media_packet->data[8] = 0;
+  media_packet->data[9] = 1;
+  media_packet->data[10] = 2;
+  media_packet->data[11] = 3;
+
+  EXPECT_FALSE(receiver_.AddReceivedPacket(ParsePacket(*media_packet)));
+}
+
+TEST_F(FlexfecReceiverTest, FailsOnUnknownFecSsrc) {
+  const size_t kNumMediaPackets = 1;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+  const auto& media_packet = media_packets.front();
+  auto fec_packet = packet_generator_.BuildFlexfecPacket(*fec_packets.front());
+  // Corrupt the SSRC.
+  fec_packet->data[8] = 4;
+  fec_packet->data[9] = 5;
+  fec_packet->data[10] = 6;
+  fec_packet->data[11] = 7;
+
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
+      receiver_.AddReceivedPacket(ParsePacket(*media_packet));
+  ASSERT_TRUE(received_packet);
+  receiver_.ProcessReceivedPacket(*received_packet);
+  EXPECT_FALSE(receiver_.AddReceivedPacket(ParsePacket(*fec_packet)));
+}
+
+TEST_F(FlexfecReceiverTest, ReceivesMultiplePackets) {
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Receive all media packets.
+  for (const auto& media_packet : media_packets) {
+    std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
+        receiver_.AddReceivedPacket(ParsePacket(*media_packet));
+    ASSERT_TRUE(received_packet);
+    receiver_.ProcessReceivedPacket(*received_packet);
+  }
+
+  // Receive FEC packet.
+  auto* fec_packet = fec_packets.front();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(*fec_packet);
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
+      receiver_.AddReceivedPacket(ParsePacket(*packet_with_rtp_header));
+  ASSERT_TRUE(received_packet);
+  receiver_.ProcessReceivedPacket(*received_packet);
+}
+
+TEST_F(FlexfecReceiverTest, RecoversFromSingleMediaLoss) {
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Receive first media packet but drop second.
+  auto media_it = media_packets.begin();
+  receiver_.OnRtpPacket(ParsePacket(**media_it));
+
+  // Receive FEC packet and ensure recovery of lost media packet.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  media_it++;
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_it)->length))
+      .With(
+          Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length)));
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+}
+
+TEST_F(FlexfecReceiverTest, RecoversFromDoubleMediaLoss) {
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 2;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Drop both media packets.
+
+  // Receive first FEC packet and recover first lost media packet.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  auto media_it = media_packets.begin();
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_it)->length))
+      .With(
+          Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length)));
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+
+  // Receive second FEC packet and recover second lost media packet.
+  fec_it++;
+  packet_with_rtp_header = packet_generator_.BuildFlexfecPacket(**fec_it);
+  media_it++;
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_it)->length))
+      .With(
+          Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length)));
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+}
+
+TEST_F(FlexfecReceiverTest, DoesNotRecoverFromMediaAndFecLoss) {
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Receive first media packet.
+  auto media_it = media_packets.begin();
+  receiver_.OnRtpPacket(ParsePacket(**media_it));
+
+  // Drop second media packet and FEC packet. Do not expect call back.
+}
+
+TEST_F(FlexfecReceiverTest, DoesNotCallbackTwice) {
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Receive first media packet but drop second.
+  auto media_it = media_packets.begin();
+  receiver_.OnRtpPacket(ParsePacket(**media_it));
+
+  // Receive FEC packet and ensure recovery of lost media packet.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  media_it++;
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_it)->length))
+      .With(
+          Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length)));
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+
+  // Receive the FEC packet again, but do not call back.
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+
+  // Receive the first media packet again, but do not call back.
+  media_it = media_packets.begin();
+  receiver_.OnRtpPacket(ParsePacket(**media_it));
+
+  // Receive the second media packet again (the one recovered above),
+  // but do not call back again.
+  media_it++;
+  receiver_.OnRtpPacket(ParsePacket(**media_it));
+}
+
+// Here we are implicitly assuming packet masks that are suitable for
+// this type of 50% correlated loss. If we are changing our precomputed
+// packet masks, this test might need to be updated.
+TEST_F(FlexfecReceiverTest, RecoversFrom50PercentLoss) {
+  const size_t kNumFecPackets = 5;
+  const size_t kNumFrames = 2 * kNumFecPackets;
+  const size_t kNumMediaPacketsPerFrame = 1;
+
+  PacketList media_packets;
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    PacketizeFrame(kNumMediaPacketsPerFrame, i, &media_packets);
+  }
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Drop every second media packet.
+  auto media_it = media_packets.begin();
+  while (media_it != media_packets.end()) {
+    receiver_.OnRtpPacket(ParsePacket(**media_it));
+    ++media_it;
+    if (media_it == media_packets.end()) {
+      break;
+    }
+    ++media_it;
+  }
+
+  // Receive all FEC packets.
+  media_it = media_packets.begin();
+  for (const auto* fec_packet : fec_packets) {
+    std::unique_ptr<Packet> fec_packet_with_rtp_header =
+        packet_generator_.BuildFlexfecPacket(*fec_packet);
+    ++media_it;
+    if (media_it == media_packets.end()) {
+      break;
+    }
+    EXPECT_CALL(recovered_packet_receiver_,
+                OnRecoveredPacket(_, (*media_it)->length))
+        .With(Args<0, 1>(
+            ElementsAreArray((*media_it)->data, (*media_it)->length)));
+    receiver_.OnRtpPacket(ParsePacket(*fec_packet_with_rtp_header));
+    ++media_it;
+  }
+}
+
+TEST_F(FlexfecReceiverTest, DelayedFecPacketDoesHelp) {
+  // These values need to be updated if the underlying erasure code
+  // implementation changes.
+  const size_t kNumFrames = 48;
+  const size_t kNumMediaPacketsPerFrame = 1;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPacketsPerFrame, 0, &media_packets);
+  PacketizeFrame(kNumMediaPacketsPerFrame, 1, &media_packets);
+  // Protect two first frames.
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+  for (size_t i = 2; i < kNumFrames; ++i) {
+    PacketizeFrame(kNumMediaPacketsPerFrame, i, &media_packets);
+  }
+
+  // Drop first media packet and delay FEC packet.
+  auto media_it = media_packets.begin();
+  ++media_it;
+
+  // Receive all other media packets.
+  while (media_it != media_packets.end()) {
+    receiver_.OnRtpPacket(ParsePacket(**media_it));
+    ++media_it;
+  }
+
+  // Receive FEC packet and recover first media packet.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  media_it = media_packets.begin();
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_it)->length))
+      .With(
+          Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length)));
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+}
+
+TEST_F(FlexfecReceiverTest, TooDelayedFecPacketDoesNotHelp) {
+  // These values need to be updated if the underlying erasure code
+  // implementation changes.
+  const size_t kNumFrames = 49;
+  const size_t kNumMediaPacketsPerFrame = 1;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPacketsPerFrame, 0, &media_packets);
+  PacketizeFrame(kNumMediaPacketsPerFrame, 1, &media_packets);
+  // Protect two first frames.
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+  for (size_t i = 2; i < kNumFrames; ++i) {
+    PacketizeFrame(kNumMediaPacketsPerFrame, i, &media_packets);
+  }
+
+  // Drop first media packet and delay FEC packet.
+  auto media_it = media_packets.begin();
+  ++media_it;
+
+  // Receive all other media packets.
+  while (media_it != media_packets.end()) {
+    receiver_.OnRtpPacket(ParsePacket(**media_it));
+    ++media_it;
+  }
+
+  // Receive FEC packet.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+
+  // Do not expect a call back.
+}
+
+TEST_F(FlexfecReceiverTest, SurvivesOldRecoveredPacketBeingReinserted) {
+  // Simulates the behaviour of the
+  // Call->FlexfecReceiveStream->FlexfecReceiver->Call loop in production code.
+  class LoopbackRecoveredPacketReceiver : public RecoveredPacketReceiver {
+   public:
+    LoopbackRecoveredPacketReceiver() : receiver_(nullptr) {}
+
+    void SetReceiver(FlexfecReceiver* receiver) { receiver_ = receiver; }
+
+    // Implements RecoveredPacketReceiver.
+    void OnRecoveredPacket(const uint8_t* packet, size_t length) override {
+      RtpPacketReceived parsed_packet;
+      EXPECT_TRUE(parsed_packet.Parse(packet, length));
+      parsed_packet.set_recovered(true);
+
+      RTC_DCHECK(receiver_);
+      receiver_->OnRtpPacket(parsed_packet);
+    }
+
+   private:
+    FlexfecReceiver* receiver_;
+  } loopback_recovered_packet_receiver;
+
+  // Feed recovered packets back into |receiver|.
+  FlexfecReceiver receiver(kFlexfecSsrc, kMediaSsrc,
+                           &loopback_recovered_packet_receiver);
+  loopback_recovered_packet_receiver.SetReceiver(&receiver);
+
+  // Receive first set of packets.
+  PacketList first_media_packets;
+  for (int i = 0; i < 46; ++i) {
+    PacketizeFrame(1, 0, &first_media_packets);
+  }
+  for (const auto& media_packet : first_media_packets) {
+    receiver.OnRtpPacket(ParsePacket(*media_packet));
+  }
+
+  // Protect one media packet. Lose the media packet,
+  // but do not receive FEC packet yet.
+  PacketList protected_media_packet;
+  PacketizeFrame(1, 0, &protected_media_packet);
+  const std::list<Packet*> fec_packets = EncodeFec(protected_media_packet, 1);
+  EXPECT_EQ(1u, fec_packets.size());
+  std::unique_ptr<Packet> fec_packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(*fec_packets.front());
+
+  // Lose some packets, thus introducing a sequence number gap.
+  PacketList lost_packets;
+  for (int i = 0; i < 100; ++i) {
+    PacketizeFrame(1, 0, &lost_packets);
+  }
+
+  // Receive one more packet.
+  PacketList second_media_packets;
+  PacketizeFrame(1, 0, &second_media_packets);
+  for (const auto& media_packet : second_media_packets) {
+    receiver.OnRtpPacket(ParsePacket(*media_packet));
+  }
+
+  // Receive delayed FEC packet.
+  receiver.OnRtpPacket(ParsePacket(*fec_packet_with_rtp_header));
+
+  // Expect no crash.
+}
+
+TEST_F(FlexfecReceiverTest, RecoversWithMediaPacketsOutOfOrder) {
+  const size_t kNumMediaPackets = 6;
+  const size_t kNumFecPackets = 2;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Lose two media packets, and receive the others out of order.
+  auto media_it = media_packets.begin();
+  auto media_packet0 = media_it++;
+  auto media_packet1 = media_it++;
+  auto media_packet2 = media_it++;
+  auto media_packet3 = media_it++;
+  auto media_packet4 = media_it++;
+  auto media_packet5 = media_it++;
+  receiver_.OnRtpPacket(ParsePacket(**media_packet5));
+  receiver_.OnRtpPacket(ParsePacket(**media_packet2));
+  receiver_.OnRtpPacket(ParsePacket(**media_packet3));
+  receiver_.OnRtpPacket(ParsePacket(**media_packet0));
+
+  // Expect to recover lost media packets.
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_packet1)->length))
+      .With(Args<0, 1>(
+          ElementsAreArray((*media_packet1)->data, (*media_packet1)->length)));
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_packet4)->length))
+      .With(Args<0, 1>(
+          ElementsAreArray((*media_packet4)->data, (*media_packet4)->length)));
+
+  // Add FEC packets.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header;
+  while (fec_it != fec_packets.end()) {
+    packet_with_rtp_header = packet_generator_.BuildFlexfecPacket(**fec_it);
+    receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+    ++fec_it;
+  }
+}
+
+// Recovered media packets may be fed back into the FlexfecReceiver by the
+// callback. This test ensures the idempotency of such a situation.
+TEST_F(FlexfecReceiverTest, RecoveryCallbackDoesNotLoopInfinitely) {
+  class LoopbackRecoveredPacketReceiver : public RecoveredPacketReceiver {
+   public:
+    const int kMaxRecursionDepth = 10;
+
+    LoopbackRecoveredPacketReceiver()
+        : receiver_(nullptr),
+          did_receive_call_back_(false),
+          recursion_depth_(0),
+          deep_recursion_(false) {}
+
+    void SetReceiver(FlexfecReceiver* receiver) { receiver_ = receiver; }
+    bool DidReceiveCallback() const { return did_receive_call_back_; }
+    bool DeepRecursion() const { return deep_recursion_; }
+
+    // Implements RecoveredPacketReceiver.
+    void OnRecoveredPacket(const uint8_t* packet, size_t length) override {
+      RtpPacketReceived parsed_packet;
+      EXPECT_TRUE(parsed_packet.Parse(packet, length));
+
+      did_receive_call_back_ = true;
+
+      if (recursion_depth_ > kMaxRecursionDepth) {
+        deep_recursion_ = true;
+        return;
+      }
+      ++recursion_depth_;
+      RTC_DCHECK(receiver_);
+      receiver_->OnRtpPacket(parsed_packet);
+      --recursion_depth_;
+    }
+
+   private:
+    FlexfecReceiver* receiver_;
+    bool did_receive_call_back_;
+    int recursion_depth_;
+    bool deep_recursion_;
+  } loopback_recovered_packet_receiver;
+
+  // Feed recovered packets back into |receiver|.
+  FlexfecReceiver receiver(kFlexfecSsrc, kMediaSsrc,
+                           &loopback_recovered_packet_receiver);
+  loopback_recovered_packet_receiver.SetReceiver(&receiver);
+
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Receive first media packet but drop second.
+  auto media_it = media_packets.begin();
+  receiver.OnRtpPacket(ParsePacket(**media_it));
+
+  // Receive FEC packet and verify that a packet was recovered.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  receiver.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+  EXPECT_TRUE(loopback_recovered_packet_receiver.DidReceiveCallback());
+  EXPECT_FALSE(loopback_recovered_packet_receiver.DeepRecursion());
+}
+
+TEST_F(FlexfecReceiverTest, CalculatesNumberOfPackets) {
+  const size_t kNumMediaPackets = 2;
+  const size_t kNumFecPackets = 1;
+
+  PacketList media_packets;
+  PacketizeFrame(kNumMediaPackets, 0, &media_packets);
+  std::list<Packet*> fec_packets = EncodeFec(media_packets, kNumFecPackets);
+
+  // Receive first media packet but drop second.
+  auto media_it = media_packets.begin();
+  receiver_.OnRtpPacket(ParsePacket(**media_it));
+
+  // Receive FEC packet and ensure recovery of lost media packet.
+  auto fec_it = fec_packets.begin();
+  std::unique_ptr<Packet> packet_with_rtp_header =
+      packet_generator_.BuildFlexfecPacket(**fec_it);
+  media_it++;
+  EXPECT_CALL(recovered_packet_receiver_,
+              OnRecoveredPacket(_, (*media_it)->length))
+      .With(
+          Args<0, 1>(ElementsAreArray((*media_it)->data, (*media_it)->length)));
+  receiver_.OnRtpPacket(ParsePacket(*packet_with_rtp_header));
+
+  // Check stats calculations.
+  FecPacketCounter packet_counter = receiver_.GetPacketCounter();
+  EXPECT_EQ(2U, packet_counter.num_packets);
+  EXPECT_EQ(1U, packet_counter.num_fec_packets);
+  EXPECT_EQ(1U, packet_counter.num_recovered_packets);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_sender.cc b/modules/rtp_rtcp/source/flexfec_sender.cc
new file mode 100644
index 0000000..9704096
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_sender.cc
@@ -0,0 +1,180 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+
+// Let first sequence number be in the first half of the interval.
+constexpr uint16_t kMaxInitRtpSeqNumber = 0x7fff;
+
+// See breakdown in flexfec_header_reader_writer.cc.
+constexpr size_t kFlexfecMaxHeaderSize = 32;
+
+// Since we will mainly use FlexFEC to protect video streams, we use a 90 kHz
+// clock for the RTP timestamps. (This is according to the RFC, which states
+// that it is RECOMMENDED to use the same clock frequency for FlexFEC as for
+// the protected media stream.)
+// The constant converts from clock millisecond timestamps to the 90 kHz
+// RTP timestamp.
+const int kMsToRtpTimestamp = kVideoPayloadTypeFrequency / 1000;
+
+// How often to log the generated FEC packets to the text log.
+constexpr int64_t kPacketLogIntervalMs = 10000;
+
+RtpHeaderExtensionMap RegisterSupportedExtensions(
+    const std::vector<RtpExtension>& rtp_header_extensions) {
+  RtpHeaderExtensionMap map;
+  for (const auto& extension : rtp_header_extensions) {
+    if (extension.uri == TransportSequenceNumber::kUri) {
+      map.Register<TransportSequenceNumber>(extension.id);
+    } else if (extension.uri == AbsoluteSendTime::kUri) {
+      map.Register<AbsoluteSendTime>(extension.id);
+    } else if (extension.uri == TransmissionOffset::kUri) {
+      map.Register<TransmissionOffset>(extension.id);
+    } else if (extension.uri == RtpMid::kUri) {
+      map.Register<RtpMid>(extension.id);
+    } else {
+      RTC_LOG(LS_INFO)
+          << "FlexfecSender only supports RTP header extensions for "
+          << "BWE and MID, so the extension " << extension.ToString()
+          << " will not be used.";
+    }
+  }
+  return map;
+}
+
+}  // namespace
+
+FlexfecSender::FlexfecSender(
+    int payload_type,
+    uint32_t ssrc,
+    uint32_t protected_media_ssrc,
+    const std::string& mid,
+    const std::vector<RtpExtension>& rtp_header_extensions,
+    rtc::ArrayView<const RtpExtensionSize> extension_sizes,
+    const RtpState* rtp_state,
+    Clock* clock)
+    : clock_(clock),
+      random_(clock_->TimeInMicroseconds()),
+      last_generated_packet_ms_(-1),
+      payload_type_(payload_type),
+      // Reset RTP state if this is not the first time we are operating.
+      // Otherwise, randomize the initial timestamp offset and RTP sequence
+      // numbers. (This is not intended to be cryptographically strong.)
+      timestamp_offset_(rtp_state ? rtp_state->start_timestamp
+                                  : random_.Rand<uint32_t>()),
+      ssrc_(ssrc),
+      protected_media_ssrc_(protected_media_ssrc),
+      mid_(mid),
+      seq_num_(rtp_state ? rtp_state->sequence_number
+                         : random_.Rand(1, kMaxInitRtpSeqNumber)),
+      ulpfec_generator_(
+          ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
+      rtp_header_extension_map_(
+          RegisterSupportedExtensions(rtp_header_extensions)),
+      header_extensions_size_(
+          rtp_header_extension_map_.GetTotalLengthInBytes(extension_sizes)) {
+  // This object should not have been instantiated if FlexFEC is disabled.
+  RTC_DCHECK_GE(payload_type, 0);
+  RTC_DCHECK_LE(payload_type, 127);
+}
+
+FlexfecSender::~FlexfecSender() = default;
+
+// We are reusing the implementation from UlpfecGenerator for SetFecParameters,
+// AddRtpPacketAndGenerateFec, and FecAvailable.
+void FlexfecSender::SetFecParameters(const FecProtectionParams& params) {
+  ulpfec_generator_.SetFecParameters(params);
+}
+
+bool FlexfecSender::AddRtpPacketAndGenerateFec(const RtpPacketToSend& packet) {
+  // TODO(brandtr): Generalize this SSRC check when we support multistream
+  // protection.
+  RTC_DCHECK_EQ(packet.Ssrc(), protected_media_ssrc_);
+  return ulpfec_generator_.AddRtpPacketAndGenerateFec(
+             packet.data(), packet.payload_size(), packet.headers_size()) == 0;
+}
+
+bool FlexfecSender::FecAvailable() const {
+  return ulpfec_generator_.FecAvailable();
+}
+
+std::vector<std::unique_ptr<RtpPacketToSend>> FlexfecSender::GetFecPackets() {
+  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets_to_send;
+  fec_packets_to_send.reserve(ulpfec_generator_.generated_fec_packets_.size());
+  for (const auto* fec_packet : ulpfec_generator_.generated_fec_packets_) {
+    std::unique_ptr<RtpPacketToSend> fec_packet_to_send(
+        new RtpPacketToSend(&rtp_header_extension_map_));
+
+    // RTP header.
+    fec_packet_to_send->SetMarker(false);
+    fec_packet_to_send->SetPayloadType(payload_type_);
+    fec_packet_to_send->SetSequenceNumber(seq_num_++);
+    fec_packet_to_send->SetTimestamp(
+        timestamp_offset_ +
+        static_cast<uint32_t>(kMsToRtpTimestamp *
+                              clock_->TimeInMilliseconds()));
+    // Set "capture time" so that the TransmissionOffset header extension
+    // can be set by the RTPSender.
+    fec_packet_to_send->set_capture_time_ms(clock_->TimeInMilliseconds());
+    fec_packet_to_send->SetSsrc(ssrc_);
+    // Reserve extensions, if registered. These will be set by the RTPSender.
+    fec_packet_to_send->ReserveExtension<AbsoluteSendTime>();
+    fec_packet_to_send->ReserveExtension<TransmissionOffset>();
+    fec_packet_to_send->ReserveExtension<TransportSequenceNumber>();
+    // Possibly include the MID header extension.
+    if (!mid_.empty()) {
+      // This is a no-op if the MID header extension is not registered.
+      fec_packet_to_send->SetExtension<RtpMid>(mid_);
+    }
+
+    // RTP payload.
+    uint8_t* payload = fec_packet_to_send->AllocatePayload(fec_packet->length);
+    memcpy(payload, fec_packet->data, fec_packet->length);
+
+    fec_packets_to_send.push_back(std::move(fec_packet_to_send));
+  }
+  ulpfec_generator_.ResetState();
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  if (!fec_packets_to_send.empty() &&
+      now_ms - last_generated_packet_ms_ > kPacketLogIntervalMs) {
+    RTC_LOG(LS_VERBOSE) << "Generated " << fec_packets_to_send.size()
+                        << " FlexFEC packets with payload type: "
+                        << payload_type_ << " and SSRC: " << ssrc_ << ".";
+    last_generated_packet_ms_ = now_ms;
+  }
+
+  return fec_packets_to_send;
+}
+
+// The overhead is BWE RTP header extensions and FlexFEC header.
+size_t FlexfecSender::MaxPacketOverhead() const {
+  return header_extensions_size_ + kFlexfecMaxHeaderSize;
+}
+
+RtpState FlexfecSender::GetRtpState() {
+  RtpState rtp_state;
+  rtp_state.sequence_number = seq_num_;
+  rtp_state.start_timestamp = timestamp_offset_;
+  return rtp_state;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/flexfec_sender_unittest.cc b/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
new file mode 100644
index 0000000..ddc2805
--- /dev/null
+++ b/modules/rtp_rtcp/source/flexfec_sender_unittest.cc
@@ -0,0 +1,340 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include <vector>
+
+#include "api/rtpparameters.h"
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using RtpUtility::Word32Align;
+using test::fec::AugmentedPacket;
+using test::fec::AugmentedPacketGenerator;
+
+constexpr int kFlexfecPayloadType = 123;
+constexpr uint32_t kMediaSsrc = 1234;
+constexpr uint32_t kFlexfecSsrc = 5678;
+const char kNoMid[] = "";
+const std::vector<RtpExtension> kNoRtpHeaderExtensions;
+const std::vector<RtpExtensionSize> kNoRtpHeaderExtensionSizes;
+// Assume a single protected media SSRC.
+constexpr size_t kFlexfecMaxHeaderSize = 32;
+constexpr size_t kPayloadLength = 50;
+
+constexpr int64_t kInitialSimulatedClockTime = 1;
+// These values are deterministically given by the PRNG, due to our fixed seed.
+// They should be updated if the PRNG implementation changes.
+constexpr uint16_t kDeterministicSequenceNumber = 28732;
+constexpr uint32_t kDeterministicTimestamp = 2305613085;
+
+std::unique_ptr<RtpPacketToSend> GenerateSingleFlexfecPacket(
+    FlexfecSender* sender) {
+  // Parameters selected to generate a single FEC packet.
+  FecProtectionParams params;
+  params.fec_rate = 15;
+  params.max_fec_frames = 1;
+  params.fec_mask_type = kFecMaskRandom;
+  constexpr size_t kNumPackets = 4;
+
+  sender->SetFecParameters(params);
+  AugmentedPacketGenerator packet_generator(kMediaSsrc);
+  packet_generator.NewFrame(kNumPackets);
+  for (size_t i = 0; i < kNumPackets; ++i) {
+    std::unique_ptr<AugmentedPacket> packet =
+        packet_generator.NextPacket(i, kPayloadLength);
+    RtpPacketToSend rtp_packet(nullptr);  // No header extensions.
+    rtp_packet.Parse(packet->data, packet->length);
+    EXPECT_TRUE(sender->AddRtpPacketAndGenerateFec(rtp_packet));
+  }
+  EXPECT_TRUE(sender->FecAvailable());
+  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
+      sender->GetFecPackets();
+  EXPECT_FALSE(sender->FecAvailable());
+  EXPECT_EQ(1U, fec_packets.size());
+
+  return std::move(fec_packets.front());
+}
+
+}  // namespace
+
+TEST(FlexfecSenderTest, Ssrc) {
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+
+  EXPECT_EQ(kFlexfecSsrc, sender.ssrc());
+}
+
+TEST(FlexfecSenderTest, NoFecAvailableBeforeMediaAdded) {
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+
+  EXPECT_FALSE(sender.FecAvailable());
+  auto fec_packets = sender.GetFecPackets();
+  EXPECT_EQ(0U, fec_packets.size());
+}
+
+TEST(FlexfecSenderTest, ProtectOneFrameWithOneFecPacket) {
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size());
+  EXPECT_FALSE(fec_packet->Marker());
+  EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType());
+  EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber());
+  EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp());
+  EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc());
+  EXPECT_LE(kPayloadLength, fec_packet->payload_size());
+}
+
+TEST(FlexfecSenderTest, ProtectTwoFramesWithOneFecPacket) {
+  // FEC parameters selected to generate a single FEC packet per frame.
+  FecProtectionParams params;
+  params.fec_rate = 15;
+  params.max_fec_frames = 2;
+  params.fec_mask_type = kFecMaskRandom;
+  constexpr size_t kNumFrames = 2;
+  constexpr size_t kNumPacketsPerFrame = 2;
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  sender.SetFecParameters(params);
+
+  AugmentedPacketGenerator packet_generator(kMediaSsrc);
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    packet_generator.NewFrame(kNumPacketsPerFrame);
+    for (size_t j = 0; j < kNumPacketsPerFrame; ++j) {
+      std::unique_ptr<AugmentedPacket> packet =
+          packet_generator.NextPacket(i, kPayloadLength);
+      RtpPacketToSend rtp_packet(nullptr);
+      rtp_packet.Parse(packet->data, packet->length);
+      EXPECT_TRUE(sender.AddRtpPacketAndGenerateFec(rtp_packet));
+    }
+  }
+  EXPECT_TRUE(sender.FecAvailable());
+  std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
+      sender.GetFecPackets();
+  EXPECT_FALSE(sender.FecAvailable());
+  ASSERT_EQ(1U, fec_packets.size());
+
+  RtpPacketToSend* fec_packet = fec_packets.front().get();
+  EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size());
+  EXPECT_FALSE(fec_packet->Marker());
+  EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType());
+  EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber());
+  EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp());
+  EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc());
+}
+
+TEST(FlexfecSenderTest, ProtectTwoFramesWithTwoFecPackets) {
+  // FEC parameters selected to generate a single FEC packet per frame.
+  FecProtectionParams params;
+  params.fec_rate = 30;
+  params.max_fec_frames = 1;
+  params.fec_mask_type = kFecMaskRandom;
+  constexpr size_t kNumFrames = 2;
+  constexpr size_t kNumPacketsPerFrame = 2;
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  sender.SetFecParameters(params);
+
+  AugmentedPacketGenerator packet_generator(kMediaSsrc);
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    packet_generator.NewFrame(kNumPacketsPerFrame);
+    for (size_t j = 0; j < kNumPacketsPerFrame; ++j) {
+      std::unique_ptr<AugmentedPacket> packet =
+          packet_generator.NextPacket(i, kPayloadLength);
+      RtpPacketToSend rtp_packet(nullptr);
+      rtp_packet.Parse(packet->data, packet->length);
+      EXPECT_TRUE(sender.AddRtpPacketAndGenerateFec(rtp_packet));
+    }
+    EXPECT_TRUE(sender.FecAvailable());
+    std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
+        sender.GetFecPackets();
+    EXPECT_FALSE(sender.FecAvailable());
+    ASSERT_EQ(1U, fec_packets.size());
+
+    RtpPacketToSend* fec_packet = fec_packets.front().get();
+    EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size());
+    EXPECT_FALSE(fec_packet->Marker());
+    EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType());
+    EXPECT_EQ(static_cast<uint16_t>(kDeterministicSequenceNumber + i),
+              fec_packet->SequenceNumber());
+    EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp());
+    EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc());
+  }
+}
+
+// In the tests, we only consider RTP header extensions that are useful for BWE.
+TEST(FlexfecSenderTest, NoRtpHeaderExtensionsForBweByDefault) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
+  EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
+  EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
+}
+
+TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kAbsSendTimeUri, 1}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
+  EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
+  EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
+}
+
+TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kTimestampOffsetUri, 1}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
+  EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
+  EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
+}
+
+TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kTransportSequenceNumberUri, 1}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
+  EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
+  EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
+}
+
+TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kAbsSendTimeUri, 1},
+      {RtpExtension::kTimestampOffsetUri, 2},
+      {RtpExtension::kTransportSequenceNumberUri, 3}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
+  EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
+  EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
+}
+
+TEST(FlexfecSenderTest, MaxPacketOverhead) {
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       nullptr /* rtp_state */, &clock);
+
+  EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead());
+}
+
+TEST(FlexfecSenderTest, MaxPacketOverheadWithExtensions) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kAbsSendTimeUri, 1},
+      {RtpExtension::kTimestampOffsetUri, 2},
+      {RtpExtension::kTransportSequenceNumberUri, 3}};
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  const size_t kExtensionHeaderLength = 1;
+  const size_t kRtpOneByteHeaderLength = 4;
+  const size_t kExtensionsTotalSize =
+      Word32Align(kRtpOneByteHeaderLength + kExtensionHeaderLength +
+                  AbsoluteSendTime::kValueSizeBytes + kExtensionHeaderLength +
+                  TransmissionOffset::kValueSizeBytes + kExtensionHeaderLength +
+                  TransportSequenceNumber::kValueSizeBytes);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kRtpHeaderExtensions, RTPSender::FecExtensionSizes(),
+                       nullptr /* rtp_state */, &clock);
+
+  EXPECT_EQ(kExtensionsTotalSize + kFlexfecMaxHeaderSize,
+            sender.MaxPacketOverhead());
+}
+
+TEST(FlexfecSenderTest, MidIncludedInPacketsWhenSet) {
+  const std::vector<RtpExtension> kRtpHeaderExtensions{
+      {RtpExtension::kMidUri, 1}};
+  const char kMid[] = "mid";
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kMid,
+                       kRtpHeaderExtensions, RTPSender::FecExtensionSizes(),
+                       nullptr /* rtp_state */, &clock);
+
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+
+  std::string mid;
+  ASSERT_TRUE(fec_packet->GetExtension<RtpMid>(&mid));
+  EXPECT_EQ(kMid, mid);
+}
+
+TEST(FlexfecSenderTest, SetsAndGetsRtpState) {
+  RtpState initial_rtp_state;
+  initial_rtp_state.sequence_number = 100;
+  initial_rtp_state.start_timestamp = 200;
+  SimulatedClock clock(kInitialSimulatedClockTime);
+  FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kNoMid,
+                       kNoRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
+                       &initial_rtp_state, &clock);
+
+  auto fec_packet = GenerateSingleFlexfecPacket(&sender);
+  EXPECT_EQ(initial_rtp_state.sequence_number, fec_packet->SequenceNumber());
+  EXPECT_EQ(initial_rtp_state.start_timestamp, fec_packet->Timestamp());
+
+  clock.AdvanceTimeMilliseconds(1000);
+  fec_packet = GenerateSingleFlexfecPacket(&sender);
+  EXPECT_EQ(initial_rtp_state.sequence_number + 1,
+            fec_packet->SequenceNumber());
+  EXPECT_EQ(initial_rtp_state.start_timestamp + 1 * kVideoPayloadTypeFrequency,
+            fec_packet->Timestamp());
+
+  RtpState updated_rtp_state = sender.GetRtpState();
+  EXPECT_EQ(initial_rtp_state.sequence_number + 2,
+            updated_rtp_state.sequence_number);
+  EXPECT_EQ(initial_rtp_state.start_timestamp,
+            updated_rtp_state.start_timestamp);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/forward_error_correction.cc b/modules/rtp_rtcp/source/forward_error_correction.cc
new file mode 100644
index 0000000..b743110
--- /dev/null
+++ b/modules/rtp_rtcp/source/forward_error_correction.cc
@@ -0,0 +1,782 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/mod_ops.h"
+
+namespace webrtc {
+
+namespace {
+// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
+constexpr size_t kTransportOverhead = 28;
+}  // namespace
+
+ForwardErrorCorrection::Packet::Packet() : length(0), data(), ref_count_(0) {}
+ForwardErrorCorrection::Packet::~Packet() = default;
+
+int32_t ForwardErrorCorrection::Packet::AddRef() {
+  return ++ref_count_;
+}
+
+int32_t ForwardErrorCorrection::Packet::Release() {
+  int32_t ref_count;
+  ref_count = --ref_count_;
+  if (ref_count == 0)
+    delete this;
+  return ref_count;
+}
+
+// This comparator is used to compare std::unique_ptr's pointing to
+// subclasses of SortablePackets. It needs to be parametric since
+// the std::unique_ptr's are not covariant w.r.t. the types that
+// they are pointing to.
+template <typename S, typename T>
+bool ForwardErrorCorrection::SortablePacket::LessThan::operator()(
+    const S& first,
+    const T& second) {
+  RTC_DCHECK_EQ(first->ssrc, second->ssrc);
+  return IsNewerSequenceNumber(second->seq_num, first->seq_num);
+}
+
+ForwardErrorCorrection::ReceivedPacket::ReceivedPacket() = default;
+ForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() = default;
+
+ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() = default;
+ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() = default;
+
+ForwardErrorCorrection::ProtectedPacket::ProtectedPacket() = default;
+ForwardErrorCorrection::ProtectedPacket::~ProtectedPacket() = default;
+
+ForwardErrorCorrection::ReceivedFecPacket::ReceivedFecPacket() = default;
+ForwardErrorCorrection::ReceivedFecPacket::~ReceivedFecPacket() = default;
+
+ForwardErrorCorrection::ForwardErrorCorrection(
+    std::unique_ptr<FecHeaderReader> fec_header_reader,
+    std::unique_ptr<FecHeaderWriter> fec_header_writer,
+    uint32_t ssrc,
+    uint32_t protected_media_ssrc)
+    : ssrc_(ssrc),
+      protected_media_ssrc_(protected_media_ssrc),
+      fec_header_reader_(std::move(fec_header_reader)),
+      fec_header_writer_(std::move(fec_header_writer)),
+      generated_fec_packets_(fec_header_writer_->MaxFecPackets()),
+      packet_mask_size_(0) {}
+
+ForwardErrorCorrection::~ForwardErrorCorrection() = default;
+
+std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateUlpfec(
+    uint32_t ssrc) {
+  std::unique_ptr<FecHeaderReader> fec_header_reader(new UlpfecHeaderReader());
+  std::unique_ptr<FecHeaderWriter> fec_header_writer(new UlpfecHeaderWriter());
+  return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection(
+      std::move(fec_header_reader), std::move(fec_header_writer), ssrc, ssrc));
+}
+
+std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateFlexfec(
+    uint32_t ssrc,
+    uint32_t protected_media_ssrc) {
+  std::unique_ptr<FecHeaderReader> fec_header_reader(new FlexfecHeaderReader());
+  std::unique_ptr<FecHeaderWriter> fec_header_writer(new FlexfecHeaderWriter());
+  return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection(
+      std::move(fec_header_reader), std::move(fec_header_writer), ssrc,
+      protected_media_ssrc));
+}
+
+int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets,
+                                      uint8_t protection_factor,
+                                      int num_important_packets,
+                                      bool use_unequal_protection,
+                                      FecMaskType fec_mask_type,
+                                      std::list<Packet*>* fec_packets) {
+  const size_t num_media_packets = media_packets.size();
+
+  // Sanity check arguments.
+  RTC_DCHECK_GT(num_media_packets, 0);
+  RTC_DCHECK_GE(num_important_packets, 0);
+  RTC_DCHECK_LE(num_important_packets, num_media_packets);
+  RTC_DCHECK(fec_packets->empty());
+  const size_t max_media_packets = fec_header_writer_->MaxMediaPackets();
+  if (num_media_packets > max_media_packets) {
+    RTC_LOG(LS_WARNING) << "Can't protect " << num_media_packets
+                        << " media packets per frame. Max is "
+                        << max_media_packets << ".";
+    return -1;
+  }
+
+  // Error check the media packets.
+  for (const auto& media_packet : media_packets) {
+    RTC_DCHECK(media_packet);
+    if (media_packet->length < kRtpHeaderSize) {
+      RTC_LOG(LS_WARNING) << "Media packet " << media_packet->length
+                          << " bytes "
+                          << "is smaller than RTP header.";
+      return -1;
+    }
+    // Ensure the FEC packets will fit in a typical MTU.
+    if (media_packet->length + MaxPacketOverhead() + kTransportOverhead >
+        IP_PACKET_SIZE) {
+      RTC_LOG(LS_WARNING) << "Media packet " << media_packet->length
+                          << " bytes "
+                          << "with overhead is larger than " << IP_PACKET_SIZE
+                          << " bytes.";
+    }
+  }
+
+  // Prepare generated FEC packets.
+  int num_fec_packets = NumFecPackets(num_media_packets, protection_factor);
+  if (num_fec_packets == 0) {
+    return 0;
+  }
+  for (int i = 0; i < num_fec_packets; ++i) {
+    memset(generated_fec_packets_[i].data, 0, IP_PACKET_SIZE);
+    // Use this as a marker for untouched packets.
+    generated_fec_packets_[i].length = 0;
+    fec_packets->push_back(&generated_fec_packets_[i]);
+  }
+
+  internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
+  packet_mask_size_ = internal::PacketMaskSize(num_media_packets);
+  memset(packet_masks_, 0, num_fec_packets * packet_mask_size_);
+  internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
+                                num_important_packets, use_unequal_protection,
+                                &mask_table, packet_masks_);
+
+  // Adapt packet masks to missing media packets.
+  int num_mask_bits = InsertZerosInPacketMasks(media_packets, num_fec_packets);
+  if (num_mask_bits < 0) {
+    RTC_LOG(LS_INFO) << "Due to sequence number gaps, cannot protect media "
+                        "packets with a single block of FEC packets.";
+    fec_packets->clear();
+    return -1;
+  }
+  packet_mask_size_ = internal::PacketMaskSize(num_mask_bits);
+
+  // Write FEC packets to |generated_fec_packets_|.
+  GenerateFecPayloads(media_packets, num_fec_packets);
+  // TODO(brandtr): Generalize this when multistream protection support is
+  // added.
+  const uint32_t media_ssrc = ParseSsrc(media_packets.front()->data);
+  const uint16_t seq_num_base =
+      ParseSequenceNumber(media_packets.front()->data);
+  FinalizeFecHeaders(num_fec_packets, media_ssrc, seq_num_base);
+
+  return 0;
+}
+
+int ForwardErrorCorrection::NumFecPackets(int num_media_packets,
+                                          int protection_factor) {
+  // Result in Q0 with an unsigned round.
+  int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8;
+  // Generate at least one FEC packet if we need protection.
+  if (protection_factor > 0 && num_fec_packets == 0) {
+    num_fec_packets = 1;
+  }
+  RTC_DCHECK_LE(num_fec_packets, num_media_packets);
+  return num_fec_packets;
+}
+
+void ForwardErrorCorrection::GenerateFecPayloads(
+    const PacketList& media_packets,
+    size_t num_fec_packets) {
+  RTC_DCHECK(!media_packets.empty());
+  for (size_t i = 0; i < num_fec_packets; ++i) {
+    Packet* const fec_packet = &generated_fec_packets_[i];
+    size_t pkt_mask_idx = i * packet_mask_size_;
+    const size_t min_packet_mask_size = fec_header_writer_->MinPacketMaskSize(
+        &packet_masks_[pkt_mask_idx], packet_mask_size_);
+    const size_t fec_header_size =
+        fec_header_writer_->FecHeaderSize(min_packet_mask_size);
+
+    size_t media_pkt_idx = 0;
+    auto media_packets_it = media_packets.cbegin();
+    uint16_t prev_seq_num = ParseSequenceNumber((*media_packets_it)->data);
+    while (media_packets_it != media_packets.end()) {
+      Packet* const media_packet = media_packets_it->get();
+      // Should |media_packet| be protected by |fec_packet|?
+      if (packet_masks_[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) {
+        size_t media_payload_length = media_packet->length - kRtpHeaderSize;
+
+        bool first_protected_packet = (fec_packet->length == 0);
+        size_t fec_packet_length = fec_header_size + media_payload_length;
+        if (fec_packet_length > fec_packet->length) {
+          // Recall that XORing with zero (which the FEC packets are prefilled
+          // with) is the identity operator, thus all prior XORs are
+          // still correct even though we expand the packet length here.
+          fec_packet->length = fec_packet_length;
+        }
+        if (first_protected_packet) {
+          // Write P, X, CC, M, and PT recovery fields.
+          // Note that bits 0, 1, and 16 are overwritten in FinalizeFecHeaders.
+          memcpy(&fec_packet->data[0], &media_packet->data[0], 2);
+          // Write length recovery field. (This is a temporary location for
+          // ULPFEC.)
+          ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2],
+                                               media_payload_length);
+          // Write timestamp recovery field.
+          memcpy(&fec_packet->data[4], &media_packet->data[4], 4);
+          // Write payload.
+          memcpy(&fec_packet->data[fec_header_size],
+                 &media_packet->data[kRtpHeaderSize], media_payload_length);
+        } else {
+          XorHeaders(*media_packet, fec_packet);
+          XorPayloads(*media_packet, media_payload_length, fec_header_size,
+                      fec_packet);
+        }
+      }
+      media_packets_it++;
+      if (media_packets_it != media_packets.end()) {
+        uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data);
+        media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num);
+        prev_seq_num = seq_num;
+      }
+      pkt_mask_idx += media_pkt_idx / 8;
+      media_pkt_idx %= 8;
+    }
+    RTC_DCHECK_GT(fec_packet->length, 0)
+        << "Packet mask is wrong or poorly designed.";
+  }
+}
+
+int ForwardErrorCorrection::InsertZerosInPacketMasks(
+    const PacketList& media_packets,
+    size_t num_fec_packets) {
+  size_t num_media_packets = media_packets.size();
+  if (num_media_packets <= 1) {
+    return num_media_packets;
+  }
+  uint16_t last_seq_num = ParseSequenceNumber(media_packets.back()->data);
+  uint16_t first_seq_num = ParseSequenceNumber(media_packets.front()->data);
+  size_t total_missing_seq_nums =
+      static_cast<uint16_t>(last_seq_num - first_seq_num) - num_media_packets +
+      1;
+  if (total_missing_seq_nums == 0) {
+    // All sequence numbers are covered by the packet mask.
+    // No zero insertion required.
+    return num_media_packets;
+  }
+  const size_t max_media_packets = fec_header_writer_->MaxMediaPackets();
+  if (total_missing_seq_nums + num_media_packets > max_media_packets) {
+    return -1;
+  }
+  // Allocate the new mask.
+  size_t tmp_packet_mask_size =
+      internal::PacketMaskSize(total_missing_seq_nums + num_media_packets);
+  memset(tmp_packet_masks_, 0, num_fec_packets * tmp_packet_mask_size);
+
+  auto media_packets_it = media_packets.cbegin();
+  uint16_t prev_seq_num = first_seq_num;
+  ++media_packets_it;
+
+  // Insert the first column.
+  internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_,
+                       packet_mask_size_, num_fec_packets, 0, 0);
+  size_t new_bit_index = 1;
+  size_t old_bit_index = 1;
+  // Insert zeros in the bit mask for every hole in the sequence.
+  while (media_packets_it != media_packets.end()) {
+    if (new_bit_index == max_media_packets) {
+      // We can only cover up to 48 packets.
+      break;
+    }
+    uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data);
+    const int num_zeros_to_insert =
+        static_cast<uint16_t>(seq_num - prev_seq_num - 1);
+    if (num_zeros_to_insert > 0) {
+      internal::InsertZeroColumns(num_zeros_to_insert, tmp_packet_masks_,
+                                  tmp_packet_mask_size, num_fec_packets,
+                                  new_bit_index);
+    }
+    new_bit_index += num_zeros_to_insert;
+    internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_,
+                         packet_mask_size_, num_fec_packets, new_bit_index,
+                         old_bit_index);
+    ++new_bit_index;
+    ++old_bit_index;
+    prev_seq_num = seq_num;
+    ++media_packets_it;
+  }
+  if (new_bit_index % 8 != 0) {
+    // We didn't fill the last byte. Shift bits to correct position.
+    for (uint16_t row = 0; row < num_fec_packets; ++row) {
+      int new_byte_index = row * tmp_packet_mask_size + new_bit_index / 8;
+      tmp_packet_masks_[new_byte_index] <<= (7 - (new_bit_index % 8));
+    }
+  }
+  // Replace the old mask with the new.
+  memcpy(packet_masks_, tmp_packet_masks_,
+         num_fec_packets * tmp_packet_mask_size);
+  return new_bit_index;
+}
+
+void ForwardErrorCorrection::FinalizeFecHeaders(size_t num_fec_packets,
+                                                uint32_t media_ssrc,
+                                                uint16_t seq_num_base) {
+  for (size_t i = 0; i < num_fec_packets; ++i) {
+    fec_header_writer_->FinalizeFecHeader(
+        media_ssrc, seq_num_base, &packet_masks_[i * packet_mask_size_],
+        packet_mask_size_, &generated_fec_packets_[i]);
+  }
+}
+
+void ForwardErrorCorrection::ResetState(
+    RecoveredPacketList* recovered_packets) {
+  // Free the memory for any existing recovered packets, if the caller hasn't.
+  recovered_packets->clear();
+  received_fec_packets_.clear();
+}
+
+void ForwardErrorCorrection::InsertMediaPacket(
+    RecoveredPacketList* recovered_packets,
+    const ReceivedPacket& received_packet) {
+  RTC_DCHECK_EQ(received_packet.ssrc, protected_media_ssrc_);
+
+  // Search for duplicate packets.
+  for (const auto& recovered_packet : *recovered_packets) {
+    RTC_DCHECK_EQ(recovered_packet->ssrc, received_packet.ssrc);
+    if (recovered_packet->seq_num == received_packet.seq_num) {
+      // Duplicate packet, no need to add to list.
+      return;
+    }
+  }
+
+  std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket());
+  // This "recovered packet" was not recovered using parity packets.
+  recovered_packet->was_recovered = false;
+  // This media packet has already been passed on.
+  recovered_packet->returned = true;
+  recovered_packet->ssrc = received_packet.ssrc;
+  recovered_packet->seq_num = received_packet.seq_num;
+  recovered_packet->pkt = received_packet.pkt;
+  recovered_packet->pkt->length = received_packet.pkt->length;
+  // TODO(holmer): Consider replacing this with a binary search for the right
+  // position, and then just insert the new packet. Would get rid of the sort.
+  RecoveredPacket* recovered_packet_ptr = recovered_packet.get();
+  recovered_packets->push_back(std::move(recovered_packet));
+  recovered_packets->sort(SortablePacket::LessThan());
+  UpdateCoveringFecPackets(*recovered_packet_ptr);
+}
+
+void ForwardErrorCorrection::UpdateCoveringFecPackets(
+    const RecoveredPacket& packet) {
+  for (auto& fec_packet : received_fec_packets_) {
+    // Is this FEC packet protecting the media packet |packet|?
+    auto protected_it = std::lower_bound(fec_packet->protected_packets.begin(),
+                                         fec_packet->protected_packets.end(),
+                                         &packet, SortablePacket::LessThan());
+    if (protected_it != fec_packet->protected_packets.end() &&
+        (*protected_it)->seq_num == packet.seq_num) {
+      // Found an FEC packet which is protecting |packet|.
+      (*protected_it)->pkt = packet.pkt;
+    }
+  }
+}
+
+void ForwardErrorCorrection::InsertFecPacket(
+    const RecoveredPacketList& recovered_packets,
+    const ReceivedPacket& received_packet) {
+  RTC_DCHECK_EQ(received_packet.ssrc, ssrc_);
+
+  // Check for duplicate.
+  for (const auto& existing_fec_packet : received_fec_packets_) {
+    RTC_DCHECK_EQ(existing_fec_packet->ssrc, received_packet.ssrc);
+    if (existing_fec_packet->seq_num == received_packet.seq_num) {
+      // Drop duplicate FEC packet data.
+      return;
+    }
+  }
+
+  std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket());
+  fec_packet->pkt = received_packet.pkt;
+  fec_packet->ssrc = received_packet.ssrc;
+  fec_packet->seq_num = received_packet.seq_num;
+  // Parse ULPFEC/FlexFEC header specific info.
+  bool ret = fec_header_reader_->ReadFecHeader(fec_packet.get());
+  if (!ret) {
+    return;
+  }
+
+  // TODO(brandtr): Update here when we support multistream protection.
+  if (fec_packet->protected_ssrc != protected_media_ssrc_) {
+    RTC_LOG(LS_INFO)
+        << "Received FEC packet is protecting an unknown media SSRC; dropping.";
+    return;
+  }
+
+  // Parse packet mask from header and represent as protected packets.
+  for (uint16_t byte_idx = 0; byte_idx < fec_packet->packet_mask_size;
+       ++byte_idx) {
+    uint8_t packet_mask =
+        fec_packet->pkt->data[fec_packet->packet_mask_offset + byte_idx];
+    for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) {
+      if (packet_mask & (1 << (7 - bit_idx))) {
+        std::unique_ptr<ProtectedPacket> protected_packet(
+            new ProtectedPacket());
+        // This wraps naturally with the sequence number.
+        protected_packet->ssrc = protected_media_ssrc_;
+        protected_packet->seq_num = static_cast<uint16_t>(
+            fec_packet->seq_num_base + (byte_idx << 3) + bit_idx);
+        protected_packet->pkt = nullptr;
+        fec_packet->protected_packets.push_back(std::move(protected_packet));
+      }
+    }
+  }
+
+  if (fec_packet->protected_packets.empty()) {
+    // All-zero packet mask; we can discard this FEC packet.
+    RTC_LOG(LS_WARNING) << "Received FEC packet has an all-zero packet mask.";
+  } else {
+    AssignRecoveredPackets(recovered_packets, fec_packet.get());
+    // TODO(holmer): Consider replacing this with a binary search for the right
+    // position, and then just insert the new packet. Would get rid of the sort.
+    received_fec_packets_.push_back(std::move(fec_packet));
+    received_fec_packets_.sort(SortablePacket::LessThan());
+    const size_t max_fec_packets = fec_header_reader_->MaxFecPackets();
+    if (received_fec_packets_.size() > max_fec_packets) {
+      received_fec_packets_.pop_front();
+    }
+    RTC_DCHECK_LE(received_fec_packets_.size(), max_fec_packets);
+  }
+}
+
+void ForwardErrorCorrection::AssignRecoveredPackets(
+    const RecoveredPacketList& recovered_packets,
+    ReceivedFecPacket* fec_packet) {
+  ProtectedPacketList* protected_packets = &fec_packet->protected_packets;
+  std::vector<RecoveredPacket*> recovered_protected_packets;
+
+  // Find intersection between the (sorted) containers |protected_packets|
+  // and |recovered_packets|, i.e. all protected packets that have already
+  // been recovered. Update the corresponding protected packets to point to
+  // the recovered packets.
+  auto it_p = protected_packets->cbegin();
+  auto it_r = recovered_packets.cbegin();
+  SortablePacket::LessThan less_than;
+  while (it_p != protected_packets->end() && it_r != recovered_packets.end()) {
+    if (less_than(*it_p, *it_r)) {
+      ++it_p;
+    } else if (less_than(*it_r, *it_p)) {
+      ++it_r;
+    } else {  // *it_p == *it_r.
+      // This protected packet has already been recovered.
+      (*it_p)->pkt = (*it_r)->pkt;
+      ++it_p;
+      ++it_r;
+    }
+  }
+}
+
+void ForwardErrorCorrection::InsertPacket(
+    const ReceivedPacket& received_packet,
+    RecoveredPacketList* recovered_packets) {
+  // Discard old FEC packets such that the sequence numbers in
+  // |received_fec_packets_| span at most 1/2 of the sequence number space.
+  // This is important for keeping |received_fec_packets_| sorted, and may
+  // also reduce the possibility of incorrect decoding due to sequence number
+  // wrap-around.
+  // TODO(marpan/holmer): We should be able to improve detection/discarding of
+  // old FEC packets based on timestamp information or better sequence number
+  // thresholding (e.g., to distinguish between wrap-around and reordering).
+  if (!received_fec_packets_.empty() &&
+      received_packet.ssrc == received_fec_packets_.front()->ssrc) {
+    // It only makes sense to detect wrap-around when |received_packet|
+    // and |front_received_fec_packet| belong to the same sequence number
+    // space, i.e., the same SSRC. This happens when |received_packet|
+    // is a FEC packet, or if |received_packet| is a media packet and
+    // RED+ULPFEC is used.
+    auto it = received_fec_packets_.begin();
+    while (it != received_fec_packets_.end()) {
+      uint16_t seq_num_diff = MinDiff(received_packet.seq_num, (*it)->seq_num);
+      if (seq_num_diff > 0x3fff) {
+        it = received_fec_packets_.erase(it);
+      } else {
+        // No need to keep iterating, since |received_fec_packets_| is sorted.
+        break;
+      }
+    }
+  }
+
+  if (received_packet.is_fec) {
+    InsertFecPacket(*recovered_packets, received_packet);
+  } else {
+    InsertMediaPacket(recovered_packets, received_packet);
+  }
+
+  DiscardOldRecoveredPackets(recovered_packets);
+}
+
+bool ForwardErrorCorrection::StartPacketRecovery(
+    const ReceivedFecPacket& fec_packet,
+    RecoveredPacket* recovered_packet) {
+  // Sanity check packet length.
+  if (fec_packet.pkt->length < fec_packet.fec_header_size) {
+    RTC_LOG(LS_WARNING)
+        << "The FEC packet is truncated: it does not contain enough room "
+        << "for its own header.";
+    return false;
+  }
+  // Initialize recovered packet data.
+  recovered_packet->pkt = new Packet();
+  memset(recovered_packet->pkt->data, 0, IP_PACKET_SIZE);
+  recovered_packet->returned = false;
+  recovered_packet->was_recovered = true;
+  // Copy bytes corresponding to minimum RTP header size.
+  // Note that the sequence number and SSRC fields will be overwritten
+  // at the end of packet recovery.
+  memcpy(&recovered_packet->pkt->data, fec_packet.pkt->data, kRtpHeaderSize);
+  // Copy remaining FEC payload.
+  if (fec_packet.protection_length >
+      std::min(sizeof(recovered_packet->pkt->data) - kRtpHeaderSize,
+               sizeof(fec_packet.pkt->data) - fec_packet.fec_header_size)) {
+    RTC_LOG(LS_WARNING) << "Incorrect protection length, dropping FEC packet.";
+    return false;
+  }
+  memcpy(&recovered_packet->pkt->data[kRtpHeaderSize],
+         &fec_packet.pkt->data[fec_packet.fec_header_size],
+         fec_packet.protection_length);
+  return true;
+}
+
+bool ForwardErrorCorrection::FinishPacketRecovery(
+    const ReceivedFecPacket& fec_packet,
+    RecoveredPacket* recovered_packet) {
+  // Set the RTP version to 2.
+  recovered_packet->pkt->data[0] |= 0x80;  // Set the 1st bit.
+  recovered_packet->pkt->data[0] &= 0xbf;  // Clear the 2nd bit.
+  // Recover the packet length, from temporary location.
+  recovered_packet->pkt->length =
+      ByteReader<uint16_t>::ReadBigEndian(&recovered_packet->pkt->data[2]) +
+      kRtpHeaderSize;
+  if (recovered_packet->pkt->length >
+      sizeof(recovered_packet->pkt->data) - kRtpHeaderSize) {
+    RTC_LOG(LS_WARNING) << "The recovered packet had a length larger than a "
+                        << "typical IP packet, and is thus dropped.";
+    return false;
+  }
+  // Set the SN field.
+  ByteWriter<uint16_t>::WriteBigEndian(&recovered_packet->pkt->data[2],
+                                       recovered_packet->seq_num);
+  // Set the SSRC field.
+  ByteWriter<uint32_t>::WriteBigEndian(&recovered_packet->pkt->data[8],
+                                       fec_packet.protected_ssrc);
+  recovered_packet->ssrc = fec_packet.protected_ssrc;
+  return true;
+}
+
+void ForwardErrorCorrection::XorHeaders(const Packet& src, Packet* dst) {
+  // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields.
+  dst->data[0] ^= src.data[0];
+  dst->data[1] ^= src.data[1];
+
+  // XOR the length recovery field.
+  uint8_t src_payload_length_network_order[2];
+  ByteWriter<uint16_t>::WriteBigEndian(src_payload_length_network_order,
+                                       src.length - kRtpHeaderSize);
+  dst->data[2] ^= src_payload_length_network_order[0];
+  dst->data[3] ^= src_payload_length_network_order[1];
+
+  // XOR the 5th to 8th bytes of the header: the timestamp field.
+  dst->data[4] ^= src.data[4];
+  dst->data[5] ^= src.data[5];
+  dst->data[6] ^= src.data[6];
+  dst->data[7] ^= src.data[7];
+
+  // Skip the 9th to 12th bytes of the header.
+}
+
+void ForwardErrorCorrection::XorPayloads(const Packet& src,
+                                         size_t payload_length,
+                                         size_t dst_offset,
+                                         Packet* dst) {
+  // XOR the payload.
+  RTC_DCHECK_LE(kRtpHeaderSize + payload_length, sizeof(src.data));
+  RTC_DCHECK_LE(dst_offset + payload_length, sizeof(dst->data));
+  for (size_t i = 0; i < payload_length; ++i) {
+    dst->data[dst_offset + i] ^= src.data[kRtpHeaderSize + i];
+  }
+}
+
+bool ForwardErrorCorrection::RecoverPacket(const ReceivedFecPacket& fec_packet,
+                                           RecoveredPacket* recovered_packet) {
+  if (!StartPacketRecovery(fec_packet, recovered_packet)) {
+    return false;
+  }
+  for (const auto& protected_packet : fec_packet.protected_packets) {
+    if (protected_packet->pkt == nullptr) {
+      // This is the packet we're recovering.
+      recovered_packet->seq_num = protected_packet->seq_num;
+    } else {
+      XorHeaders(*protected_packet->pkt, recovered_packet->pkt);
+      XorPayloads(*protected_packet->pkt, protected_packet->pkt->length,
+                  kRtpHeaderSize, recovered_packet->pkt);
+    }
+  }
+  if (!FinishPacketRecovery(fec_packet, recovered_packet)) {
+    return false;
+  }
+  return true;
+}
+
+void ForwardErrorCorrection::AttemptRecovery(
+    RecoveredPacketList* recovered_packets) {
+  auto fec_packet_it = received_fec_packets_.begin();
+  while (fec_packet_it != received_fec_packets_.end()) {
+    // Search for each FEC packet's protected media packets.
+    int packets_missing = NumCoveredPacketsMissing(**fec_packet_it);
+
+    // We can only recover one packet with an FEC packet.
+    if (packets_missing == 1) {
+      // Recovery possible.
+      std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket());
+      recovered_packet->pkt = nullptr;
+      if (!RecoverPacket(**fec_packet_it, recovered_packet.get())) {
+        // Can't recover using this packet, drop it.
+        fec_packet_it = received_fec_packets_.erase(fec_packet_it);
+        continue;
+      }
+
+      auto* recovered_packet_ptr = recovered_packet.get();
+      // Add recovered packet to the list of recovered packets and update any
+      // FEC packets covering this packet with a pointer to the data.
+      // TODO(holmer): Consider replacing this with a binary search for the
+      // right position, and then just insert the new packet. Would get rid of
+      // the sort.
+      recovered_packets->push_back(std::move(recovered_packet));
+      recovered_packets->sort(SortablePacket::LessThan());
+      UpdateCoveringFecPackets(*recovered_packet_ptr);
+      DiscardOldRecoveredPackets(recovered_packets);
+      fec_packet_it = received_fec_packets_.erase(fec_packet_it);
+
+      // A packet has been recovered. We need to check the FEC list again, as
+      // this may allow additional packets to be recovered.
+      // Restart for first FEC packet.
+      fec_packet_it = received_fec_packets_.begin();
+    } else if (packets_missing == 0) {
+      // Either all protected packets arrived or have been recovered. We can
+      // discard this FEC packet.
+      fec_packet_it = received_fec_packets_.erase(fec_packet_it);
+    } else {
+      fec_packet_it++;
+    }
+  }
+}
+
+int ForwardErrorCorrection::NumCoveredPacketsMissing(
+    const ReceivedFecPacket& fec_packet) {
+  int packets_missing = 0;
+  for (const auto& protected_packet : fec_packet.protected_packets) {
+    if (protected_packet->pkt == nullptr) {
+      ++packets_missing;
+      if (packets_missing > 1) {
+        break;  // We can't recover more than one packet.
+      }
+    }
+  }
+  return packets_missing;
+}
+
+void ForwardErrorCorrection::DiscardOldRecoveredPackets(
+    RecoveredPacketList* recovered_packets) {
+  const size_t max_media_packets = fec_header_reader_->MaxMediaPackets();
+  while (recovered_packets->size() > max_media_packets) {
+    recovered_packets->pop_front();
+  }
+  RTC_DCHECK_LE(recovered_packets->size(), max_media_packets);
+}
+
+uint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) {
+  return (packet[2] << 8) + packet[3];
+}
+
+uint32_t ForwardErrorCorrection::ParseSsrc(uint8_t* packet) {
+  return (packet[8] << 24) + (packet[9] << 16) + (packet[10] << 8) + packet[11];
+}
+
+void ForwardErrorCorrection::DecodeFec(const ReceivedPacket& received_packet,
+                                       RecoveredPacketList* recovered_packets) {
+  RTC_DCHECK(recovered_packets);
+
+  const size_t max_media_packets = fec_header_reader_->MaxMediaPackets();
+  if (recovered_packets->size() == max_media_packets) {
+    const RecoveredPacket* back_recovered_packet =
+        recovered_packets->back().get();
+
+    if (received_packet.ssrc == back_recovered_packet->ssrc) {
+      const unsigned int seq_num_diff =
+          MinDiff(received_packet.seq_num, back_recovered_packet->seq_num);
+      if (seq_num_diff > max_media_packets) {
+        // A big gap in sequence numbers. The old recovered packets
+        // are now useless, so it's safe to do a reset.
+        RTC_LOG(LS_INFO) << "Big gap in media/ULPFEC sequence numbers. No need "
+                            "to keep the old packets in the FEC buffers, thus "
+                            "resetting them.";
+        ResetState(recovered_packets);
+      }
+    }
+  }
+
+  InsertPacket(received_packet, recovered_packets);
+  AttemptRecovery(recovered_packets);
+}
+
+size_t ForwardErrorCorrection::MaxPacketOverhead() const {
+  return fec_header_writer_->MaxPacketOverhead();
+}
+
+FecHeaderReader::FecHeaderReader(size_t max_media_packets,
+                                 size_t max_fec_packets)
+    : max_media_packets_(max_media_packets),
+      max_fec_packets_(max_fec_packets) {}
+
+FecHeaderReader::~FecHeaderReader() = default;
+
+size_t FecHeaderReader::MaxMediaPackets() const {
+  return max_media_packets_;
+}
+
+size_t FecHeaderReader::MaxFecPackets() const {
+  return max_fec_packets_;
+}
+
+FecHeaderWriter::FecHeaderWriter(size_t max_media_packets,
+                                 size_t max_fec_packets,
+                                 size_t max_packet_overhead)
+    : max_media_packets_(max_media_packets),
+      max_fec_packets_(max_fec_packets),
+      max_packet_overhead_(max_packet_overhead) {}
+
+FecHeaderWriter::~FecHeaderWriter() = default;
+
+size_t FecHeaderWriter::MaxMediaPackets() const {
+  return max_media_packets_;
+}
+
+size_t FecHeaderWriter::MaxFecPackets() const {
+  return max_fec_packets_;
+}
+
+size_t FecHeaderWriter::MaxPacketOverhead() const {
+  return max_packet_overhead_;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/forward_error_correction.h b/modules/rtp_rtcp/source/forward_error_correction.h
new file mode 100644
index 0000000..819f6bc
--- /dev/null
+++ b/modules/rtp_rtcp/source/forward_error_correction.h
@@ -0,0 +1,418 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
+#define MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/refcount.h"
+#include "rtc_base/scoped_ref_ptr.h"
+
+namespace webrtc {
+
+class FecHeaderReader;
+class FecHeaderWriter;
+
+// Performs codec-independent forward error correction (FEC), based on RFC 5109.
+// Option exists to enable unequal protection (UEP) across packets.
+// This is not to be confused with protection within packets
+// (referred to as uneven level protection (ULP) in RFC 5109).
+// TODO(brandtr): Split this class into a separate encoder
+// and a separate decoder.
+class ForwardErrorCorrection {
+ public:
+  // TODO(holmer): As a next step all these struct-like packet classes should be
+  // refactored into proper classes, and their members should be made private.
+  // This will require parts of the functionality in forward_error_correction.cc
+  // and receiver_fec.cc to be refactored into the packet classes.
+  class Packet {
+   public:
+    Packet();
+    virtual ~Packet();
+
+    // Add a reference.
+    virtual int32_t AddRef();
+
+    // Release a reference. Will delete the object if the reference count
+    // reaches zero.
+    virtual int32_t Release();
+
+    size_t length;                 // Length of packet in bytes.
+    uint8_t data[IP_PACKET_SIZE];  // Packet data.
+
+   private:
+    int32_t ref_count_;  // Counts the number of references to a packet.
+  };
+
+  // TODO(holmer): Refactor into a proper class.
+  class SortablePacket {
+   public:
+    // Functor which returns true if the sequence number of |first|
+    // is < the sequence number of |second|. Should only ever be called for
+    // packets belonging to the same SSRC.
+    struct LessThan {
+      template <typename S, typename T>
+      bool operator()(const S& first, const T& second);
+    };
+
+    uint32_t ssrc;
+    uint16_t seq_num;
+  };
+
+  // Used for the input to DecodeFec().
+  //
+  // TODO(nisse): Delete class, instead passing |is_fec| and |pkt| as separate
+  // arguments.
+  class ReceivedPacket : public SortablePacket {
+   public:
+    ReceivedPacket();
+    ~ReceivedPacket();
+
+    bool is_fec;  // Set to true if this is an FEC packet and false
+                  // otherwise.
+    rtc::scoped_refptr<Packet> pkt;  // Pointer to the packet storage.
+  };
+
+  // The recovered list parameter of DecodeFec() references structs of
+  // this type.
+  // TODO(holmer): Refactor into a proper class.
+  class RecoveredPacket : public SortablePacket {
+   public:
+    RecoveredPacket();
+    ~RecoveredPacket();
+
+    bool was_recovered;  // Will be true if this packet was recovered by
+                         // the FEC. Otherwise it was a media packet passed in
+                         // through the received packet list.
+    bool returned;  // True when the packet already has been returned to the
+                    // caller through the callback.
+    rtc::scoped_refptr<Packet> pkt;  // Pointer to the packet storage.
+  };
+
+  // Used to link media packets to their protecting FEC packets.
+  //
+  // TODO(holmer): Refactor into a proper class.
+  class ProtectedPacket : public SortablePacket {
+   public:
+    ProtectedPacket();
+    ~ProtectedPacket();
+
+    rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt;
+  };
+
+  using ProtectedPacketList = std::list<std::unique_ptr<ProtectedPacket>>;
+
+  // Used for internal storage of received FEC packets in a list.
+  //
+  // TODO(holmer): Refactor into a proper class.
+  class ReceivedFecPacket : public SortablePacket {
+   public:
+    ReceivedFecPacket();
+    ~ReceivedFecPacket();
+
+    // List of media packets that this FEC packet protects.
+    ProtectedPacketList protected_packets;
+    // RTP header fields.
+    uint32_t ssrc;
+    // FEC header fields.
+    size_t fec_header_size;
+    uint32_t protected_ssrc;
+    uint16_t seq_num_base;
+    size_t packet_mask_offset;  // Relative start of FEC header.
+    size_t packet_mask_size;
+    size_t protection_length;
+    // Raw data.
+    rtc::scoped_refptr<ForwardErrorCorrection::Packet> pkt;
+  };
+
+  using PacketList = std::list<std::unique_ptr<Packet>>;
+  using RecoveredPacketList = std::list<std::unique_ptr<RecoveredPacket>>;
+  using ReceivedFecPacketList = std::list<std::unique_ptr<ReceivedFecPacket>>;
+
+  ~ForwardErrorCorrection();
+
+  // Creates a ForwardErrorCorrection tailored for a specific FEC scheme.
+  static std::unique_ptr<ForwardErrorCorrection> CreateUlpfec(uint32_t ssrc);
+  static std::unique_ptr<ForwardErrorCorrection> CreateFlexfec(
+      uint32_t ssrc,
+      uint32_t protected_media_ssrc);
+
+  // Generates a list of FEC packets from supplied media packets.
+  //
+  // Input:  media_packets          List of media packets to protect, of type
+  //                                Packet. All packets must belong to the
+  //                                same frame and the list must not be empty.
+  // Input:  protection_factor      FEC protection overhead in the [0, 255]
+  //                                domain. To obtain 100% overhead, or an
+  //                                equal number of FEC packets as
+  //                                media packets, use 255.
+  // Input:  num_important_packets  The number of "important" packets in the
+  //                                frame. These packets may receive greater
+  //                                protection than the remaining packets.
+  //                                The important packets must be located at the
+  //                                start of the media packet list. For codecs
+  //                                with data partitioning, the important
+  //                                packets may correspond to first partition
+  //                                packets.
+  // Input:  use_unequal_protection Parameter to enable/disable unequal
+  //                                protection (UEP) across packets. Enabling
+  //                                UEP will allocate more protection to the
+  //                                num_important_packets from the start of the
+  //                                media_packets.
+  // Input:  fec_mask_type          The type of packet mask used in the FEC.
+  //                                Random or bursty type may be selected. The
+  //                                bursty type is only defined up to 12 media
+  //                                packets. If the number of media packets is
+  //                                above 12, the packet masks from the random
+  //                                table will be selected.
+  // Output: fec_packets            List of pointers to generated FEC packets,
+  //                                of type Packet. Must be empty on entry.
+  //                                The memory available through the list will
+  //                                be valid until the next call to
+  //                                EncodeFec().
+  //
+  // Returns 0 on success, -1 on failure.
+  //
+  int EncodeFec(const PacketList& media_packets,
+                uint8_t protection_factor,
+                int num_important_packets,
+                bool use_unequal_protection,
+                FecMaskType fec_mask_type,
+                std::list<Packet*>* fec_packets);
+
+  // Decodes a list of received media and FEC packets. It will parse the
+  // |received_packets|, storing FEC packets internally, and move
+  // media packets to |recovered_packets|. The recovered list will be
+  // sorted by ascending sequence number and have duplicates removed.
+  // The function should be called as new packets arrive, and
+  // |recovered_packets| will be progressively assembled with each call.
+  // When the function returns, |received_packets| will be empty.
+  //
+  // The caller will allocate packets submitted through |received_packets|.
+  // The function will handle allocation of recovered packets.
+  //
+  // Input:  received_packets   List of new received packets, of type
+  //                            ReceivedPacket, belonging to a single
+  //                            frame. At output the list will be empty,
+  //                            with packets either stored internally,
+  //                            or accessible through the recovered list.
+  // Output: recovered_packets  List of recovered media packets, of type
+  //                            RecoveredPacket, belonging to a single
+  //                            frame. The memory available through the
+  //                            list will be valid until the next call to
+  //                            DecodeFec().
+  //
+  void DecodeFec(const ReceivedPacket& received_packet,
+                 RecoveredPacketList* recovered_packets);
+
+  // Get the number of generated FEC packets, given the number of media packets
+  // and the protection factor.
+  static int NumFecPackets(int num_media_packets, int protection_factor);
+
+  // Gets the maximum size of the FEC headers in bytes, which must be
+  // accounted for as packet overhead.
+  size_t MaxPacketOverhead() const;
+
+  // Reset internal states from last frame and clear |recovered_packets|.
+  // Frees all memory allocated by this class.
+  void ResetState(RecoveredPacketList* recovered_packets);
+
+  // TODO(brandtr): Remove these functions when the Packet classes
+  // have been refactored.
+  static uint16_t ParseSequenceNumber(uint8_t* packet);
+  static uint32_t ParseSsrc(uint8_t* packet);
+
+ protected:
+  ForwardErrorCorrection(std::unique_ptr<FecHeaderReader> fec_header_reader,
+                         std::unique_ptr<FecHeaderWriter> fec_header_writer,
+                         uint32_t ssrc,
+                         uint32_t protected_media_ssrc);
+
+ private:
+  // Analyzes |media_packets| for holes in the sequence and inserts zero columns
+  // into the |packet_mask| where those holes are found. Zero columns means that
+  // those packets will have no protection.
+  // Returns the number of bits used for one row of the new packet mask.
+  // Requires that |packet_mask| has at least 6 * |num_fec_packets| bytes
+  // allocated.
+  int InsertZerosInPacketMasks(const PacketList& media_packets,
+                               size_t num_fec_packets);
+
+  // Writes FEC payloads and some recovery fields in the FEC headers.
+  void GenerateFecPayloads(const PacketList& media_packets,
+                           size_t num_fec_packets);
+
+  // Writes the FEC header fields that are not written by GenerateFecPayloads.
+  // This includes writing the packet masks.
+  void FinalizeFecHeaders(size_t num_fec_packets,
+                          uint32_t media_ssrc,
+                          uint16_t seq_num_base);
+
+  // Inserts the |received_packet| into the internal received FEC packet list
+  // or into |recovered_packets|.
+  void InsertPacket(const ReceivedPacket& received_packet,
+                    RecoveredPacketList* recovered_packets);
+
+  // Inserts the |received_packet| into |recovered_packets|. Deletes duplicates.
+  void InsertMediaPacket(RecoveredPacketList* recovered_packets,
+                         const ReceivedPacket& received_packet);
+
+  // Assigns pointers to the recovered packet from all FEC packets which cover
+  // it.
+  // Note: This reduces the complexity when we want to try to recover a packet
+  // since we don't have to find the intersection between recovered packets and
+  // packets covered by the FEC packet.
+  void UpdateCoveringFecPackets(const RecoveredPacket& packet);
+
+  // Insert |received_packet| into internal FEC list. Deletes duplicates.
+  void InsertFecPacket(const RecoveredPacketList& recovered_packets,
+                       const ReceivedPacket& received_packet);
+
+  // Assigns pointers to already recovered packets covered by |fec_packet|.
+  static void AssignRecoveredPackets(
+      const RecoveredPacketList& recovered_packets,
+      ReceivedFecPacket* fec_packet);
+
+  // Attempt to recover missing packets, using the internally stored
+  // received FEC packets.
+  void AttemptRecovery(RecoveredPacketList* recovered_packets);
+
+  // Initializes headers and payload before the XOR operation
+  // that recovers a packet.
+  static bool StartPacketRecovery(const ReceivedFecPacket& fec_packet,
+                                  RecoveredPacket* recovered_packet);
+
+  // Performs XOR between the first 8 bytes of |src| and |dst| and stores
+  // the result in |dst|. The 3rd and 4th bytes are used for storing
+  // the length recovery field.
+  static void XorHeaders(const Packet& src, Packet* dst);
+
+  // Performs XOR between the payloads of |src| and |dst| and stores the result
+  // in |dst|. The parameter |dst_offset| determines at  what byte the
+  // XOR operation starts in |dst|. In total, |payload_length| bytes are XORed.
+  static void XorPayloads(const Packet& src,
+                          size_t payload_length,
+                          size_t dst_offset,
+                          Packet* dst);
+
+  // Finalizes recovery of packet by setting RTP header fields.
+  // This is not specific to the FEC scheme used.
+  static bool FinishPacketRecovery(const ReceivedFecPacket& fec_packet,
+                                   RecoveredPacket* recovered_packet);
+
+  // Recover a missing packet.
+  static bool RecoverPacket(const ReceivedFecPacket& fec_packet,
+                            RecoveredPacket* recovered_packet);
+
+  // Get the number of missing media packets which are covered by |fec_packet|.
+  // An FEC packet can recover at most one packet, and if zero packets are
+  // missing the FEC packet can be discarded. This function returns 2 when two
+  // or more packets are missing.
+  static int NumCoveredPacketsMissing(const ReceivedFecPacket& fec_packet);
+
+  // Discards old packets in |recovered_packets|, which are no longer relevant
+  // for recovering lost packets.
+  void DiscardOldRecoveredPackets(RecoveredPacketList* recovered_packets);
+
+  // These SSRCs are only used by the decoder.
+  const uint32_t ssrc_;
+  const uint32_t protected_media_ssrc_;
+
+  std::unique_ptr<FecHeaderReader> fec_header_reader_;
+  std::unique_ptr<FecHeaderWriter> fec_header_writer_;
+
+  std::vector<Packet> generated_fec_packets_;
+  ReceivedFecPacketList received_fec_packets_;
+
+  // Arrays used to avoid dynamically allocating memory when generating
+  // the packet masks.
+  // (There are never more than |kUlpfecMaxMediaPackets| FEC packets generated.)
+  uint8_t packet_masks_[kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize];
+  uint8_t tmp_packet_masks_[kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize];
+  size_t packet_mask_size_;
+};
+
+// Classes derived from FecHeader{Reader,Writer} encapsulate the
+// specifics of reading and writing FEC header for, e.g., ULPFEC
+// and FlexFEC.
+class FecHeaderReader {
+ public:
+  virtual ~FecHeaderReader();
+
+  // The maximum number of media packets that can be covered by one FEC packet.
+  size_t MaxMediaPackets() const;
+
+  // The maximum number of FEC packets that is supported, per call
+  // to ForwardErrorCorrection::EncodeFec().
+  size_t MaxFecPackets() const;
+
+  // Parses FEC header and stores information in ReceivedFecPacket members.
+  virtual bool ReadFecHeader(
+      ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const = 0;
+
+ protected:
+  FecHeaderReader(size_t max_media_packets, size_t max_fec_packets);
+
+  const size_t max_media_packets_;
+  const size_t max_fec_packets_;
+};
+
+class FecHeaderWriter {
+ public:
+  virtual ~FecHeaderWriter();
+
+  // The maximum number of media packets that can be covered by one FEC packet.
+  size_t MaxMediaPackets() const;
+
+  // The maximum number of FEC packets that is supported, per call
+  // to ForwardErrorCorrection::EncodeFec().
+  size_t MaxFecPackets() const;
+
+  // The maximum overhead (in bytes) per packet, due to FEC headers.
+  size_t MaxPacketOverhead() const;
+
+  // Calculates the minimum packet mask size needed (in bytes),
+  // given the discrete options of the ULPFEC masks and the bits
+  // set in the current packet mask.
+  virtual size_t MinPacketMaskSize(const uint8_t* packet_mask,
+                                   size_t packet_mask_size) const = 0;
+
+  // The header size (in bytes), given the packet mask size.
+  virtual size_t FecHeaderSize(size_t packet_mask_size) const = 0;
+
+  // Writes FEC header.
+  virtual void FinalizeFecHeader(
+      uint32_t media_ssrc,
+      uint16_t seq_num_base,
+      const uint8_t* packet_mask,
+      size_t packet_mask_size,
+      ForwardErrorCorrection::Packet* fec_packet) const = 0;
+
+ protected:
+  FecHeaderWriter(size_t max_media_packets,
+                  size_t max_fec_packets,
+                  size_t max_packet_overhead);
+
+  const size_t max_media_packets_;
+  const size_t max_fec_packets_;
+  const size_t max_packet_overhead_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
diff --git a/modules/rtp_rtcp/source/forward_error_correction_internal.cc b/modules/rtp_rtcp/source/forward_error_correction_internal.cc
new file mode 100644
index 0000000..7e5fd91
--- /dev/null
+++ b/modules/rtp_rtcp/source/forward_error_correction_internal.cc
@@ -0,0 +1,517 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+
+#include <algorithm>
+
+#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
+#include "modules/rtp_rtcp/source/fec_private_tables_random.h"
+#include "rtc_base/checks.h"
+
+namespace {
+// Allow for different modes of protection for packets in UEP case.
+enum ProtectionMode {
+  kModeNoOverlap,
+  kModeOverlap,
+  kModeBiasFirstPacket,
+};
+
+// Fits an input mask (sub_mask) to an output mask.
+// The mask is a matrix where the rows are the FEC packets,
+// and the columns are the source packets the FEC is applied to.
+// Each row of the mask is represented by a number of mask bytes.
+//
+// \param[in]  num_mask_bytes     The number of mask bytes of output mask.
+// \param[in]  num_sub_mask_bytes The number of mask bytes of input mask.
+// \param[in]  num_rows           The number of rows of the input mask.
+// \param[in]  sub_mask           A pointer to hold the input mask, of size
+//                                [0, num_rows * num_sub_mask_bytes]
+// \param[out] packet_mask        A pointer to hold the output mask, of size
+//                                [0, x * num_mask_bytes], where x >= num_rows.
+void FitSubMask(int num_mask_bytes,
+                int num_sub_mask_bytes,
+                int num_rows,
+                const uint8_t* sub_mask,
+                uint8_t* packet_mask) {
+  if (num_mask_bytes == num_sub_mask_bytes) {
+    memcpy(packet_mask, sub_mask, num_rows * num_sub_mask_bytes);
+  } else {
+    for (int i = 0; i < num_rows; ++i) {
+      int pkt_mask_idx = i * num_mask_bytes;
+      int pkt_mask_idx2 = i * num_sub_mask_bytes;
+      for (int j = 0; j < num_sub_mask_bytes; ++j) {
+        packet_mask[pkt_mask_idx] = sub_mask[pkt_mask_idx2];
+        pkt_mask_idx++;
+        pkt_mask_idx2++;
+      }
+    }
+  }
+}
+
+// Shifts a mask by number of columns (bits), and fits it to an output mask.
+// The mask is a matrix where the rows are the FEC packets,
+// and the columns are the source packets the FEC is applied to.
+// Each row of the mask is represented by a number of mask bytes.
+//
+// \param[in]  num_mask_bytes     The number of mask bytes of output mask.
+// \param[in]  num_sub_mask_bytes The number of mask bytes of input mask.
+// \param[in]  num_column_shift   The number columns to be shifted, and
+//                                the starting row for the output mask.
+// \param[in]  end_row            The ending row for the output mask.
+// \param[in]  sub_mask           A pointer to hold the input mask, of size
+//                                [0, (end_row_fec - start_row_fec) *
+//                                    num_sub_mask_bytes]
+// \param[out] packet_mask        A pointer to hold the output mask, of size
+//                                [0, x * num_mask_bytes],
+//                                where x >= end_row_fec.
+// TODO(marpan): This function is doing three things at the same time:
+// shift within a byte, byte shift and resizing.
+// Split up into subroutines.
+void ShiftFitSubMask(int num_mask_bytes,
+                     int res_mask_bytes,
+                     int num_column_shift,
+                     int end_row,
+                     const uint8_t* sub_mask,
+                     uint8_t* packet_mask) {
+  // Number of bit shifts within a byte
+  const int num_bit_shifts = (num_column_shift % 8);
+  const int num_byte_shifts = num_column_shift >> 3;
+
+  // Modify new mask with sub-mask21.
+
+  // Loop over the remaining FEC packets.
+  for (int i = num_column_shift; i < end_row; ++i) {
+    // Byte index of new mask, for row i and column res_mask_bytes,
+    // offset by the number of bytes shifts
+    int pkt_mask_idx =
+        i * num_mask_bytes + res_mask_bytes - 1 + num_byte_shifts;
+    // Byte index of sub_mask, for row i and column res_mask_bytes
+    int pkt_mask_idx2 =
+        (i - num_column_shift) * res_mask_bytes + res_mask_bytes - 1;
+
+    uint8_t shift_right_curr_byte = 0;
+    uint8_t shift_left_prev_byte = 0;
+    uint8_t comb_new_byte = 0;
+
+    // Handle case of num_mask_bytes > res_mask_bytes:
+    // For a given row, copy the rightmost "numBitShifts" bits
+    // of the last byte of sub_mask into output mask.
+    if (num_mask_bytes > res_mask_bytes) {
+      shift_left_prev_byte = (sub_mask[pkt_mask_idx2] << (8 - num_bit_shifts));
+      packet_mask[pkt_mask_idx + 1] = shift_left_prev_byte;
+    }
+
+    // For each row i (FEC packet), shift the bit-mask of the sub_mask.
+    // Each row of the mask contains "resMaskBytes" of bytes.
+    // We start from the last byte of the sub_mask and move to first one.
+    for (int j = res_mask_bytes - 1; j > 0; j--) {
+      // Shift current byte of sub21 to the right by "numBitShifts".
+      shift_right_curr_byte = sub_mask[pkt_mask_idx2] >> num_bit_shifts;
+
+      // Fill in shifted bits with bits from the previous (left) byte:
+      // First shift the previous byte to the left by "8-numBitShifts".
+      shift_left_prev_byte =
+          (sub_mask[pkt_mask_idx2 - 1] << (8 - num_bit_shifts));
+
+      // Then combine both shifted bytes into new mask byte.
+      comb_new_byte = shift_right_curr_byte | shift_left_prev_byte;
+
+      // Assign to new mask.
+      packet_mask[pkt_mask_idx] = comb_new_byte;
+      pkt_mask_idx--;
+      pkt_mask_idx2--;
+    }
+    // For the first byte in the row (j=0 case).
+    shift_right_curr_byte = sub_mask[pkt_mask_idx2] >> num_bit_shifts;
+    packet_mask[pkt_mask_idx] = shift_right_curr_byte;
+  }
+}
+
+}  // namespace
+
+namespace webrtc {
+namespace internal {
+
+PacketMaskTable::PacketMaskTable(FecMaskType fec_mask_type,
+                                 int num_media_packets)
+    : table_(PickTable(fec_mask_type, num_media_packets)) {}
+
+PacketMaskTable::~PacketMaskTable() = default;
+
+rtc::ArrayView<const uint8_t> PacketMaskTable::LookUp(int num_media_packets,
+                                                      int num_fec_packets) {
+  RTC_DCHECK_GT(num_media_packets, 0);
+  RTC_DCHECK_GT(num_fec_packets, 0);
+  RTC_DCHECK_LE(num_media_packets, kUlpfecMaxMediaPackets);
+  RTC_DCHECK_LE(num_fec_packets, num_media_packets);
+
+  if (num_media_packets <= 12) {
+    return LookUpInFecTable(table_, num_media_packets - 1, num_fec_packets - 1);
+  }
+  int mask_length =
+      static_cast<int>(PacketMaskSize(static_cast<size_t>(num_media_packets)));
+
+  // Generate FEC code mask for {num_media_packets(M), num_fec_packets(N)} (use
+  // N FEC packets to protect M media packets) In the mask, each FEC packet
+  // occupies one row, each bit / coloumn represent one media packet. E.g. Row
+  // A, Col/Bit B is set to 1, means FEC packet A will have protection for media
+  // packet B.
+
+  // Loop through each fec packet.
+  for (int row = 0; row < num_fec_packets; row++) {
+    // Loop through each fec code in a row, one code has 8 bits.
+    // Bit X will be set to 1 if media packet X shall be protected by current
+    // FEC packet. In this implementation, the protection is interleaved, thus
+    // media packet X will be protected by FEC packet (X % N)
+    for (int col = 0; col < mask_length; col++) {
+      fec_packet_mask_[row * mask_length + col] =
+          ((col * 8) % num_fec_packets == row && (col * 8) < num_media_packets
+               ? 0x80
+               : 0x00) |
+          ((col * 8 + 1) % num_fec_packets == row &&
+                   (col * 8 + 1) < num_media_packets
+               ? 0x40
+               : 0x00) |
+          ((col * 8 + 2) % num_fec_packets == row &&
+                   (col * 8 + 2) < num_media_packets
+               ? 0x20
+               : 0x00) |
+          ((col * 8 + 3) % num_fec_packets == row &&
+                   (col * 8 + 3) < num_media_packets
+               ? 0x10
+               : 0x00) |
+          ((col * 8 + 4) % num_fec_packets == row &&
+                   (col * 8 + 4) < num_media_packets
+               ? 0x08
+               : 0x00) |
+          ((col * 8 + 5) % num_fec_packets == row &&
+                   (col * 8 + 5) < num_media_packets
+               ? 0x04
+               : 0x00) |
+          ((col * 8 + 6) % num_fec_packets == row &&
+                   (col * 8 + 6) < num_media_packets
+               ? 0x02
+               : 0x00) |
+          ((col * 8 + 7) % num_fec_packets == row &&
+                   (col * 8 + 7) < num_media_packets
+               ? 0x01
+               : 0x00);
+    }
+  }
+  return {&fec_packet_mask_[0],
+          static_cast<size_t>(num_fec_packets * mask_length)};
+}
+
+// If |num_media_packets| is larger than the maximum allowed by |fec_mask_type|
+// for the bursty type, or the random table is explicitly asked for, then the
+// random type is selected. Otherwise the bursty table callback is returned.
+const uint8_t* PacketMaskTable::PickTable(FecMaskType fec_mask_type,
+                                          int num_media_packets) {
+  RTC_DCHECK_GE(num_media_packets, 0);
+  RTC_DCHECK_LE(static_cast<size_t>(num_media_packets), kUlpfecMaxMediaPackets);
+
+  if (fec_mask_type != kFecMaskRandom &&
+      num_media_packets <=
+          static_cast<int>(fec_private_tables::kPacketMaskBurstyTbl[0])) {
+    return &fec_private_tables::kPacketMaskBurstyTbl[0];
+  }
+
+  return &fec_private_tables::kPacketMaskRandomTbl[0];
+}
+
+// Remaining protection after important (first partition) packet protection
+void RemainingPacketProtection(int num_media_packets,
+                               int num_fec_remaining,
+                               int num_fec_for_imp_packets,
+                               int num_mask_bytes,
+                               ProtectionMode mode,
+                               uint8_t* packet_mask,
+                               PacketMaskTable* mask_table) {
+  if (mode == kModeNoOverlap) {
+    // sub_mask21
+
+    const int res_mask_bytes =
+        PacketMaskSize(num_media_packets - num_fec_for_imp_packets);
+
+    auto end_row = (num_fec_for_imp_packets + num_fec_remaining);
+    rtc::ArrayView<const uint8_t> packet_mask_sub_21 = mask_table->LookUp(
+        num_media_packets - num_fec_for_imp_packets, num_fec_remaining);
+
+    ShiftFitSubMask(num_mask_bytes, res_mask_bytes, num_fec_for_imp_packets,
+                    end_row, &packet_mask_sub_21[0], packet_mask);
+
+  } else if (mode == kModeOverlap || mode == kModeBiasFirstPacket) {
+    // sub_mask22
+    rtc::ArrayView<const uint8_t> packet_mask_sub_22 =
+        mask_table->LookUp(num_media_packets, num_fec_remaining);
+
+    FitSubMask(num_mask_bytes, num_mask_bytes, num_fec_remaining,
+               &packet_mask_sub_22[0],
+               &packet_mask[num_fec_for_imp_packets * num_mask_bytes]);
+
+    if (mode == kModeBiasFirstPacket) {
+      for (int i = 0; i < num_fec_remaining; ++i) {
+        int pkt_mask_idx = i * num_mask_bytes;
+        packet_mask[pkt_mask_idx] = packet_mask[pkt_mask_idx] | (1 << 7);
+      }
+    }
+  } else {
+    RTC_NOTREACHED();
+  }
+}
+
+// Protection for important (first partition) packets
+void ImportantPacketProtection(int num_fec_for_imp_packets,
+                               int num_imp_packets,
+                               int num_mask_bytes,
+                               uint8_t* packet_mask,
+                               PacketMaskTable* mask_table) {
+  const int num_imp_mask_bytes = PacketMaskSize(num_imp_packets);
+
+  // Get sub_mask1 from table
+  rtc::ArrayView<const uint8_t> packet_mask_sub_1 =
+      mask_table->LookUp(num_imp_packets, num_fec_for_imp_packets);
+
+  FitSubMask(num_mask_bytes, num_imp_mask_bytes, num_fec_for_imp_packets,
+             &packet_mask_sub_1[0], packet_mask);
+}
+
+// This function sets the protection allocation: i.e., how many FEC packets
+// to use for num_imp (1st partition) packets, given the: number of media
+// packets, number of FEC packets, and number of 1st partition packets.
+int SetProtectionAllocation(int num_media_packets,
+                            int num_fec_packets,
+                            int num_imp_packets) {
+  // TODO(marpan): test different cases for protection allocation:
+
+  // Use at most (alloc_par * num_fec_packets) for important packets.
+  float alloc_par = 0.5;
+  int max_num_fec_for_imp = alloc_par * num_fec_packets;
+
+  int num_fec_for_imp_packets = (num_imp_packets < max_num_fec_for_imp)
+                                    ? num_imp_packets
+                                    : max_num_fec_for_imp;
+
+  // Fall back to equal protection in this case
+  if (num_fec_packets == 1 && (num_media_packets > 2 * num_imp_packets)) {
+    num_fec_for_imp_packets = 0;
+  }
+
+  return num_fec_for_imp_packets;
+}
+
+// Modification for UEP: reuse the off-line tables for the packet masks.
+// Note: these masks were designed for equal packet protection case,
+// assuming random packet loss.
+
+// Current version has 3 modes (options) to build UEP mask from existing ones.
+// Various other combinations may be added in future versions.
+// Longer-term, we may add another set of tables specifically for UEP cases.
+// TODO(marpan): also consider modification of masks for bursty loss cases.
+
+// Mask is characterized as (#packets_to_protect, #fec_for_protection).
+// Protection factor defined as: (#fec_for_protection / #packets_to_protect).
+
+// Let k=num_media_packets, n=total#packets, (n-k)=num_fec_packets,
+// m=num_imp_packets.
+
+// For ProtectionMode 0 and 1:
+// one mask (sub_mask1) is used for 1st partition packets,
+// the other mask (sub_mask21/22, for 0/1) is for the remaining FEC packets.
+
+// In both mode 0 and 1, the packets of 1st partition (num_imp_packets) are
+// treated equally important, and are afforded more protection than the
+// residual partition packets.
+
+// For num_imp_packets:
+// sub_mask1 = (m, t): protection = t/(m), where t=F(k,n-k,m).
+// t=F(k,n-k,m) is the number of packets used to protect first partition in
+// sub_mask1. This is determined from the function SetProtectionAllocation().
+
+// For the left-over protection:
+// Mode 0: sub_mask21 = (k-m,n-k-t): protection = (n-k-t)/(k-m)
+// mode 0 has no protection overlap between the two partitions.
+// For mode 0, we would typically set t = min(m, n-k).
+
+// Mode 1: sub_mask22 = (k, n-k-t), with protection (n-k-t)/(k)
+// mode 1 has protection overlap between the two partitions (preferred).
+
+// For ProtectionMode 2:
+// This gives 1st packet of list (which is 1st packet of 1st partition) more
+// protection. In mode 2, the equal protection mask (which is obtained from
+// mode 1 for t=0) is modified (more "1s" added in 1st column of packet mask)
+// to bias higher protection for the 1st source packet.
+
+// Protection Mode 2 may be extended for a sort of sliding protection
+// (i.e., vary the number/density of "1s" across columns) across packets.
+
+void UnequalProtectionMask(int num_media_packets,
+                           int num_fec_packets,
+                           int num_imp_packets,
+                           int num_mask_bytes,
+                           uint8_t* packet_mask,
+                           PacketMaskTable* mask_table) {
+  // Set Protection type and allocation
+  // TODO(marpan): test/update for best mode and some combinations thereof.
+
+  ProtectionMode mode = kModeOverlap;
+  int num_fec_for_imp_packets = 0;
+
+  if (mode != kModeBiasFirstPacket) {
+    num_fec_for_imp_packets = SetProtectionAllocation(
+        num_media_packets, num_fec_packets, num_imp_packets);
+  }
+
+  int num_fec_remaining = num_fec_packets - num_fec_for_imp_packets;
+  // Done with setting protection type and allocation
+
+  //
+  // Generate sub_mask1
+  //
+  if (num_fec_for_imp_packets > 0) {
+    ImportantPacketProtection(num_fec_for_imp_packets, num_imp_packets,
+                              num_mask_bytes, packet_mask, mask_table);
+  }
+
+  //
+  // Generate sub_mask2
+  //
+  if (num_fec_remaining > 0) {
+    RemainingPacketProtection(num_media_packets, num_fec_remaining,
+                              num_fec_for_imp_packets, num_mask_bytes, mode,
+                              packet_mask, mask_table);
+  }
+}
+
+// This algorithm is tailored to look up data in the |kPacketMaskRandomTbl| and
+// |kPacketMaskBurstyTbl| tables. These tables only cover fec code for up to 12
+// media packets. Starting from 13 media packets, the fec code will be generated
+// at runtime. The format of those arrays is that they're essentially a 3
+// dimensional array with the following dimensions: * media packet
+//   * Size for kPacketMaskRandomTbl: 12
+//   * Size for kPacketMaskBurstyTbl: 12
+// * fec index
+//   * Size for both random and bursty table increases from 1 to number of rows.
+//     (i.e. 1-48, or 1-12 respectively).
+// * Fec data (what actually gets returned)
+//   * Size for kPacketMaskRandomTbl: 2 bytes.
+//     * For all entries: 2 * fec index (1 based)
+//   * Size for kPacketMaskBurstyTbl: 2 bytes.
+//     * For all entries: 2 * fec index (1 based)
+rtc::ArrayView<const uint8_t> LookUpInFecTable(const uint8_t* table,
+                                               int media_packet_index,
+                                               int fec_index) {
+  RTC_DCHECK_LT(media_packet_index, table[0]);
+
+  // Skip over the table size.
+  const uint8_t* entry = &table[1];
+
+  uint8_t entry_size_increment = 2;  // 0-16 are 2 byte wide, then changes to 6.
+
+  // Hop over un-interesting array entries.
+  for (int i = 0; i < media_packet_index; ++i) {
+    if (i == 16)
+      entry_size_increment = 6;
+    uint8_t count = entry[0];
+    ++entry;  // skip over the count.
+    for (int j = 0; j < count; ++j) {
+      entry += entry_size_increment * (j + 1);  // skip over the data.
+    }
+  }
+
+  if (media_packet_index == 16)
+    entry_size_increment = 6;
+
+  RTC_DCHECK_LT(fec_index, entry[0]);
+  ++entry;  // Skip over the size.
+
+  // Find the appropriate data in the second dimension.
+
+  // Find the specific data we're looking for.
+  for (int i = 0; i < fec_index; ++i)
+    entry += entry_size_increment * (i + 1);  // skip over the data.
+
+  size_t size = entry_size_increment * (fec_index + 1);
+  return {&entry[0], size};
+}
+
+void GeneratePacketMasks(int num_media_packets,
+                         int num_fec_packets,
+                         int num_imp_packets,
+                         bool use_unequal_protection,
+                         PacketMaskTable* mask_table,
+                         uint8_t* packet_mask) {
+  RTC_DCHECK_GT(num_media_packets, 0);
+  RTC_DCHECK_GT(num_fec_packets, 0);
+  RTC_DCHECK_LE(num_fec_packets, num_media_packets);
+  RTC_DCHECK_LE(num_imp_packets, num_media_packets);
+  RTC_DCHECK_GE(num_imp_packets, 0);
+
+  const int num_mask_bytes = PacketMaskSize(num_media_packets);
+
+  // Equal-protection for these cases.
+  if (!use_unequal_protection || num_imp_packets == 0) {
+    // Retrieve corresponding mask table directly:for equal-protection case.
+    // Mask = (k,n-k), with protection factor = (n-k)/k,
+    // where k = num_media_packets, n=total#packets, (n-k)=num_fec_packets.
+    rtc::ArrayView<const uint8_t> mask =
+        mask_table->LookUp(num_media_packets, num_fec_packets);
+    memcpy(packet_mask, &mask[0], mask.size());
+  } else {  // UEP case
+    UnequalProtectionMask(num_media_packets, num_fec_packets, num_imp_packets,
+                          num_mask_bytes, packet_mask, mask_table);
+  }  // End of UEP modification
+}  // End of GetPacketMasks
+
+size_t PacketMaskSize(size_t num_sequence_numbers) {
+  RTC_DCHECK_LE(num_sequence_numbers, 8 * kUlpfecPacketMaskSizeLBitSet);
+  if (num_sequence_numbers > 8 * kUlpfecPacketMaskSizeLBitClear) {
+    return kUlpfecPacketMaskSizeLBitSet;
+  }
+  return kUlpfecPacketMaskSizeLBitClear;
+}
+
+void InsertZeroColumns(int num_zeros,
+                       uint8_t* new_mask,
+                       int new_mask_bytes,
+                       int num_fec_packets,
+                       int new_bit_index) {
+  for (uint16_t row = 0; row < num_fec_packets; ++row) {
+    const int new_byte_index = row * new_mask_bytes + new_bit_index / 8;
+    const int max_shifts = (7 - (new_bit_index % 8));
+    new_mask[new_byte_index] <<= std::min(num_zeros, max_shifts);
+  }
+}
+
+void CopyColumn(uint8_t* new_mask,
+                int new_mask_bytes,
+                uint8_t* old_mask,
+                int old_mask_bytes,
+                int num_fec_packets,
+                int new_bit_index,
+                int old_bit_index) {
+  RTC_CHECK_LT(new_bit_index, 8 * new_mask_bytes);
+
+  // Copy column from the old mask to the beginning of the new mask and shift it
+  // out from the old mask.
+  for (uint16_t row = 0; row < num_fec_packets; ++row) {
+    int new_byte_index = row * new_mask_bytes + new_bit_index / 8;
+    int old_byte_index = row * old_mask_bytes + old_bit_index / 8;
+    new_mask[new_byte_index] |= ((old_mask[old_byte_index] & 0x80) >> 7);
+    if (new_bit_index % 8 != 7) {
+      new_mask[new_byte_index] <<= 1;
+    }
+    old_mask[old_byte_index] <<= 1;
+  }
+}
+
+}  // namespace internal
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/forward_error_correction_internal.h b/modules/rtp_rtcp/source/forward_error_correction_internal.h
new file mode 100644
index 0000000..2e8a202
--- /dev/null
+++ b/modules/rtp_rtcp/source/forward_error_correction_internal.h
@@ -0,0 +1,119 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_
+#define MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_
+
+#include "modules/include/module_common_types.h"
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Maximum number of media packets that can be protected
+// by these packet masks.
+constexpr size_t kUlpfecMaxMediaPackets = 48;
+
+// Packet mask size in bytes (given L bit).
+constexpr size_t kUlpfecPacketMaskSizeLBitClear = 2;
+constexpr size_t kUlpfecPacketMaskSizeLBitSet = 6;
+
+// Packet code mask maximum length. kFECPacketMaskMaxSize = MaxNumFECPackets *
+// (kUlpfecMaxMediaPackets / 8), and MaxNumFECPackets is equal to maximum number
+// of media packets (kUlpfecMaxMediaPackets)
+constexpr size_t kFECPacketMaskMaxSize = 288;
+
+// Convenience constants.
+constexpr size_t kUlpfecMinPacketMaskSize = kUlpfecPacketMaskSizeLBitClear;
+constexpr size_t kUlpfecMaxPacketMaskSize = kUlpfecPacketMaskSizeLBitSet;
+
+namespace internal {
+
+class PacketMaskTable {
+ public:
+  PacketMaskTable(FecMaskType fec_mask_type, int num_media_packets);
+  ~PacketMaskTable();
+
+  rtc::ArrayView<const uint8_t> LookUp(int num_media_packets,
+                                       int num_fec_packets);
+
+ private:
+  static const uint8_t* PickTable(FecMaskType fec_mask_type,
+                                  int num_media_packets);
+  const uint8_t* table_;
+  uint8_t fec_packet_mask_[kFECPacketMaskMaxSize];
+};
+
+rtc::ArrayView<const uint8_t> LookUpInFecTable(const uint8_t* table,
+                                               int media_packet_index,
+                                               int fec_index);
+
+// Returns an array of packet masks. The mask of a single FEC packet
+// corresponds to a number of mask bytes. The mask indicates which
+// media packets should be protected by the FEC packet.
+
+// \param[in]  num_media_packets       The number of media packets to protect.
+//                                     [1, max_media_packets].
+// \param[in]  num_fec_packets         The number of FEC packets which will
+//                                     be generated. [1, num_media_packets].
+// \param[in]  num_imp_packets         The number of important packets.
+//                                     [0, num_media_packets].
+//                                     num_imp_packets = 0 is the equal
+//                                     protection scenario.
+// \param[in]  use_unequal_protection  Enables unequal protection: allocates
+//                                     more protection to the num_imp_packets.
+// \param[in]  mask_table              An instance of the |PacketMaskTable|
+//                                     class, which contains the type of FEC
+//                                     packet mask used, and a pointer to the
+//                                     corresponding packet masks.
+// \param[out] packet_mask             A pointer to hold the packet mask array,
+//                                     of size: num_fec_packets *
+//                                     "number of mask bytes".
+void GeneratePacketMasks(int num_media_packets,
+                         int num_fec_packets,
+                         int num_imp_packets,
+                         bool use_unequal_protection,
+                         PacketMaskTable* mask_table,
+                         uint8_t* packet_mask);
+
+// Returns the required packet mask size, given the number of sequence numbers
+// that will be covered.
+size_t PacketMaskSize(size_t num_sequence_numbers);
+
+// Inserts |num_zeros| zero columns into |new_mask| at position
+// |new_bit_index|. If the current byte of |new_mask| can't fit all zeros, the
+// byte will be filled with zeros from |new_bit_index|, but the next byte will
+// be untouched.
+void InsertZeroColumns(int num_zeros,
+                       uint8_t* new_mask,
+                       int new_mask_bytes,
+                       int num_fec_packets,
+                       int new_bit_index);
+
+// Copies the left most bit column from the byte pointed to by
+// |old_bit_index| in |old_mask| to the right most column of the byte pointed
+// to by |new_bit_index| in |new_mask|. |old_mask_bytes| and |new_mask_bytes|
+// represent the number of bytes used per row for each mask. |num_fec_packets|
+// represent the number of rows of the masks.
+// The copied bit is shifted out from |old_mask| and is shifted one step to
+// the left in |new_mask|. |new_mask| will contain "xxxx xxn0" after this
+// operation, where x are previously inserted bits and n is the new bit.
+void CopyColumn(uint8_t* new_mask,
+                int new_mask_bytes,
+                uint8_t* old_mask,
+                int old_mask_bytes,
+                int num_fec_packets,
+                int new_bit_index,
+                int old_bit_index);
+
+}  // namespace internal
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_INTERNAL_H_
diff --git a/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
new file mode 100644
index 0000000..53ff5d5
--- /dev/null
+++ b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
@@ -0,0 +1,286 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+
+#include <algorithm>
+#include <iterator>
+#include <list>
+#include <memory>
+#include <set>
+
+#include "api/call/transport.h"
+#include "call/rtp_stream_receiver_controller.h"
+#include "call/rtx_receive_stream.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "rtc_base/rate_limiter.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+const int kVideoNackListSize = 30;
+const uint32_t kTestSsrc = 3456;
+const uint32_t kTestRtxSsrc = kTestSsrc + 1;
+const uint16_t kTestSequenceNumber = 2345;
+const uint32_t kTestNumberOfPackets = 1350;
+const int kTestNumberOfRtxPackets = 149;
+const int kNumFrames = 30;
+const int kPayloadType = 123;
+const int kRtxPayloadType = 98;
+const int64_t kMaxRttMs = 1000;
+
+class VerifyingMediaStream : public RtpPacketSinkInterface {
+ public:
+  VerifyingMediaStream() {}
+
+  void OnRtpPacket(const RtpPacketReceived& packet) override {
+    if (!sequence_numbers_.empty())
+      EXPECT_EQ(kTestSsrc, packet.Ssrc());
+
+    sequence_numbers_.push_back(packet.SequenceNumber());
+  }
+  std::list<uint16_t> sequence_numbers_;
+};
+
+class RtxLoopBackTransport : public webrtc::Transport {
+ public:
+  explicit RtxLoopBackTransport(uint32_t rtx_ssrc)
+      : count_(0),
+        packet_loss_(0),
+        consecutive_drop_start_(0),
+        consecutive_drop_end_(0),
+        rtx_ssrc_(rtx_ssrc),
+        count_rtx_ssrc_(0),
+        module_(NULL) {}
+
+  void SetSendModule(RtpRtcp* rtpRtcpModule) { module_ = rtpRtcpModule; }
+
+  void DropEveryNthPacket(int n) { packet_loss_ = n; }
+
+  void DropConsecutivePackets(int start, int total) {
+    consecutive_drop_start_ = start;
+    consecutive_drop_end_ = start + total;
+    packet_loss_ = 0;
+  }
+
+  bool SendRtp(const uint8_t* data,
+               size_t len,
+               const PacketOptions& options) override {
+    count_++;
+    RtpPacketReceived packet;
+    if (!packet.Parse(data, len))
+      return false;
+    if (packet.Ssrc() == rtx_ssrc_) {
+      count_rtx_ssrc_++;
+    } else {
+      // For non-RTX packets only.
+      expected_sequence_numbers_.insert(expected_sequence_numbers_.end(),
+                                        packet.SequenceNumber());
+    }
+    if (packet_loss_ > 0) {
+      if ((count_ % packet_loss_) == 0) {
+        return true;
+      }
+    } else if (count_ >= consecutive_drop_start_ &&
+               count_ < consecutive_drop_end_) {
+      return true;
+    }
+    EXPECT_TRUE(stream_receiver_controller_.OnRtpPacket(packet));
+    return true;
+  }
+
+  bool SendRtcp(const uint8_t* data, size_t len) override {
+    module_->IncomingRtcpPacket((const uint8_t*)data, len);
+    return true;
+  }
+  int count_;
+  int packet_loss_;
+  int consecutive_drop_start_;
+  int consecutive_drop_end_;
+  uint32_t rtx_ssrc_;
+  int count_rtx_ssrc_;
+  RtpRtcp* module_;
+  RtpStreamReceiverController stream_receiver_controller_;
+  std::set<uint16_t> expected_sequence_numbers_;
+};
+
+class RtpRtcpRtxNackTest : public ::testing::Test {
+ protected:
+  RtpRtcpRtxNackTest()
+      : rtp_rtcp_module_(nullptr),
+        transport_(kTestRtxSsrc),
+        rtx_stream_(&media_stream_, rtx_associated_payload_types_, kTestSsrc),
+        payload_data_length(sizeof(payload_data)),
+        fake_clock(123456),
+        retransmission_rate_limiter_(&fake_clock, kMaxRttMs) {}
+  ~RtpRtcpRtxNackTest() override {}
+
+  void SetUp() override {
+    RtpRtcp::Configuration configuration;
+    configuration.audio = false;
+    configuration.clock = &fake_clock;
+    receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock));
+    configuration.receive_statistics = receive_statistics_.get();
+    configuration.outgoing_transport = &transport_;
+    configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
+    rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration);
+
+    rtp_rtcp_module_->SetSSRC(kTestSsrc);
+    rtp_rtcp_module_->SetRTCPStatus(RtcpMode::kCompound);
+    rtp_rtcp_module_->SetStorePacketsStatus(true, 600);
+    EXPECT_EQ(0, rtp_rtcp_module_->SetSendingStatus(true));
+    rtp_rtcp_module_->SetSequenceNumber(kTestSequenceNumber);
+    rtp_rtcp_module_->SetStartTimestamp(111111);
+
+    // Used for NACK processing.
+    // TODO(nisse): Unclear on which side? It's confusing to use a
+    // single rtp_rtcp module for both send and receive side.
+    rtp_rtcp_module_->SetRemoteSSRC(kTestSsrc);
+
+    rtp_rtcp_module_->RegisterVideoSendPayload(kPayloadType, "video");
+    rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
+    transport_.SetSendModule(rtp_rtcp_module_);
+    media_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
+        kTestSsrc, &media_stream_);
+
+    for (size_t n = 0; n < payload_data_length; n++) {
+      payload_data[n] = n % 10;
+    }
+  }
+
+  int BuildNackList(uint16_t* nack_list) {
+    media_stream_.sequence_numbers_.sort();
+    std::list<uint16_t> missing_sequence_numbers;
+    std::list<uint16_t>::iterator it = media_stream_.sequence_numbers_.begin();
+
+    while (it != media_stream_.sequence_numbers_.end()) {
+      uint16_t sequence_number_1 = *it;
+      ++it;
+      if (it != media_stream_.sequence_numbers_.end()) {
+        uint16_t sequence_number_2 = *it;
+        // Add all missing sequence numbers to list
+        for (uint16_t i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
+          missing_sequence_numbers.push_back(i);
+        }
+      }
+    }
+    int n = 0;
+    for (it = missing_sequence_numbers.begin();
+         it != missing_sequence_numbers.end(); ++it) {
+      nack_list[n++] = (*it);
+    }
+    return n;
+  }
+
+  bool ExpectedPacketsReceived() {
+    std::list<uint16_t> received_sorted;
+    std::copy(media_stream_.sequence_numbers_.begin(),
+              media_stream_.sequence_numbers_.end(),
+              std::back_inserter(received_sorted));
+    received_sorted.sort();
+    return received_sorted.size() ==
+               transport_.expected_sequence_numbers_.size() &&
+           std::equal(received_sorted.begin(), received_sorted.end(),
+                      transport_.expected_sequence_numbers_.begin());
+  }
+
+  void RunRtxTest(RtxMode rtx_method, int loss) {
+    rtx_receiver_ = transport_.stream_receiver_controller_.CreateReceiver(
+        kTestRtxSsrc, &rtx_stream_);
+    rtp_rtcp_module_->SetRtxSendStatus(rtx_method);
+    rtp_rtcp_module_->SetRtxSsrc(kTestRtxSsrc);
+    transport_.DropEveryNthPacket(loss);
+    uint32_t timestamp = 3000;
+    uint16_t nack_list[kVideoNackListSize];
+    for (int frame = 0; frame < kNumFrames; ++frame) {
+      EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
+          webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
+          payload_data, payload_data_length, nullptr, nullptr, nullptr));
+      // Min required delay until retransmit = 5 + RTT ms (RTT = 0).
+      fake_clock.AdvanceTimeMilliseconds(5);
+      int length = BuildNackList(nack_list);
+      if (length > 0)
+        rtp_rtcp_module_->SendNACK(nack_list, length);
+      fake_clock.AdvanceTimeMilliseconds(28);  //  33ms - 5ms delay.
+      rtp_rtcp_module_->Process();
+      // Prepare next frame.
+      timestamp += 3000;
+    }
+    media_stream_.sequence_numbers_.sort();
+  }
+
+  void TearDown() override { delete rtp_rtcp_module_; }
+
+  std::unique_ptr<ReceiveStatistics> receive_statistics_;
+  RtpRtcp* rtp_rtcp_module_;
+  RtxLoopBackTransport transport_;
+  const std::map<int, int> rtx_associated_payload_types_ = {
+      {kRtxPayloadType, kPayloadType}};
+  VerifyingMediaStream media_stream_;
+  RtxReceiveStream rtx_stream_;
+  uint8_t payload_data[65000];
+  size_t payload_data_length;
+  SimulatedClock fake_clock;
+  RateLimiter retransmission_rate_limiter_;
+  std::unique_ptr<RtpStreamReceiverInterface> media_receiver_;
+  std::unique_ptr<RtpStreamReceiverInterface> rtx_receiver_;
+};
+
+TEST_F(RtpRtcpRtxNackTest, LongNackList) {
+  const int kNumPacketsToDrop = 900;
+  const int kNumRequiredRtcp = 4;
+  uint32_t timestamp = 3000;
+  uint16_t nack_list[kNumPacketsToDrop];
+  // Disable StorePackets to be able to set a larger packet history.
+  rtp_rtcp_module_->SetStorePacketsStatus(false, 0);
+  // Enable StorePackets with a packet history of 2000 packets.
+  rtp_rtcp_module_->SetStorePacketsStatus(true, 2000);
+  // Drop 900 packets from the second one so that we get a NACK list which is
+  // big enough to require 4 RTCP packets to be fully transmitted to the sender.
+  transport_.DropConsecutivePackets(2, kNumPacketsToDrop);
+  // Send 30 frames which at the default size is roughly what we need to get
+  // enough packets.
+  for (int frame = 0; frame < kNumFrames; ++frame) {
+    EXPECT_TRUE(rtp_rtcp_module_->SendOutgoingData(
+        webrtc::kVideoFrameDelta, kPayloadType, timestamp, timestamp / 90,
+        payload_data, payload_data_length, nullptr, nullptr, nullptr));
+    // Prepare next frame.
+    timestamp += 3000;
+    fake_clock.AdvanceTimeMilliseconds(33);
+    rtp_rtcp_module_->Process();
+  }
+  EXPECT_FALSE(transport_.expected_sequence_numbers_.empty());
+  EXPECT_FALSE(media_stream_.sequence_numbers_.empty());
+  size_t last_receive_count = media_stream_.sequence_numbers_.size();
+  int length = BuildNackList(nack_list);
+  for (int i = 0; i < kNumRequiredRtcp - 1; ++i) {
+    rtp_rtcp_module_->SendNACK(nack_list, length);
+    EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count);
+    last_receive_count = media_stream_.sequence_numbers_.size();
+    EXPECT_FALSE(ExpectedPacketsReceived());
+  }
+  rtp_rtcp_module_->SendNACK(nack_list, length);
+  EXPECT_GT(media_stream_.sequence_numbers_.size(), last_receive_count);
+  EXPECT_TRUE(ExpectedPacketsReceived());
+}
+
+TEST_F(RtpRtcpRtxNackTest, RtxNack) {
+  RunRtxTest(kRtxRetransmitted, 10);
+  EXPECT_EQ(kTestSequenceNumber, *(media_stream_.sequence_numbers_.begin()));
+  EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
+            *(media_stream_.sequence_numbers_.rbegin()));
+  EXPECT_EQ(kTestNumberOfPackets, media_stream_.sequence_numbers_.size());
+  EXPECT_EQ(kTestNumberOfRtxPackets, transport_.count_rtx_ssrc_);
+  EXPECT_TRUE(ExpectedPacketsReceived());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/packet_loss_stats.cc b/modules/rtp_rtcp/source/packet_loss_stats.cc
new file mode 100644
index 0000000..076348d
--- /dev/null
+++ b/modules/rtp_rtcp/source/packet_loss_stats.cc
@@ -0,0 +1,139 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/packet_loss_stats.h"
+
+#include <vector>
+
+#include "rtc_base/checks.h"
+
+// After this many packets are added, adding additional packets will cause the
+// oldest packets to be pruned from the buffer.
+static const int kBufferSize = 100;
+
+namespace webrtc {
+
+PacketLossStats::PacketLossStats()
+    : single_loss_historic_count_(0),
+      multiple_loss_historic_event_count_(0),
+      multiple_loss_historic_packet_count_(0) {}
+
+PacketLossStats::~PacketLossStats() = default;
+
+void PacketLossStats::AddLostPacket(uint16_t sequence_number) {
+  // Detect sequence number wrap around.
+  if (!lost_packets_buffer_.empty() &&
+      static_cast<int>(*(lost_packets_buffer_.rbegin())) - sequence_number >
+          0x8000) {
+    // The buffer contains large numbers and this is a small number.
+    lost_packets_wrapped_buffer_.insert(sequence_number);
+  } else {
+    lost_packets_buffer_.insert(sequence_number);
+  }
+  if (lost_packets_wrapped_buffer_.size() + lost_packets_buffer_.size() >
+          kBufferSize ||
+      (!lost_packets_wrapped_buffer_.empty() &&
+       *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000)) {
+    PruneBuffer();
+  }
+}
+
+int PacketLossStats::GetSingleLossCount() const {
+  int single_loss_count, unused1, unused2;
+  ComputeLossCounts(&single_loss_count, &unused1, &unused2);
+  return single_loss_count;
+}
+
+int PacketLossStats::GetMultipleLossEventCount() const {
+  int event_count, unused1, unused2;
+  ComputeLossCounts(&unused1, &event_count, &unused2);
+  return event_count;
+}
+
+int PacketLossStats::GetMultipleLossPacketCount() const {
+  int packet_count, unused1, unused2;
+  ComputeLossCounts(&unused1, &unused2, &packet_count);
+  return packet_count;
+}
+
+void PacketLossStats::ComputeLossCounts(
+    int* out_single_loss_count,
+    int* out_multiple_loss_event_count,
+    int* out_multiple_loss_packet_count) const {
+  *out_single_loss_count = single_loss_historic_count_;
+  *out_multiple_loss_event_count = multiple_loss_historic_event_count_;
+  *out_multiple_loss_packet_count = multiple_loss_historic_packet_count_;
+  if (lost_packets_buffer_.empty()) {
+    RTC_DCHECK(lost_packets_wrapped_buffer_.empty());
+    return;
+  }
+  uint16_t last_num = 0;
+  int sequential_count = 0;
+  std::vector<const std::set<uint16_t>*> buffers;
+  buffers.push_back(&lost_packets_buffer_);
+  buffers.push_back(&lost_packets_wrapped_buffer_);
+  for (const auto* buffer : buffers) {
+    for (auto it = buffer->begin(); it != buffer->end(); ++it) {
+      uint16_t current_num = *it;
+      if (sequential_count > 0 && current_num != ((last_num + 1) & 0xFFFF)) {
+        if (sequential_count == 1) {
+          (*out_single_loss_count)++;
+        } else {
+          (*out_multiple_loss_event_count)++;
+          *out_multiple_loss_packet_count += sequential_count;
+        }
+        sequential_count = 0;
+      }
+      sequential_count++;
+      last_num = current_num;
+    }
+  }
+  if (sequential_count == 1) {
+    (*out_single_loss_count)++;
+  } else if (sequential_count > 1) {
+    (*out_multiple_loss_event_count)++;
+    *out_multiple_loss_packet_count += sequential_count;
+  }
+}
+
+void PacketLossStats::PruneBuffer() {
+  // Remove the oldest lost packet and any contiguous packets and move them
+  // into the historic counts.
+  auto it = lost_packets_buffer_.begin();
+  uint16_t last_removed = 0;
+  int remove_count = 0;
+  // Count adjacent packets and continue counting if it is wrap around by
+  // swapping in the wrapped buffer and letting our value wrap as well.
+  while (remove_count == 0 || (!lost_packets_buffer_.empty() &&
+                               *it == ((last_removed + 1) & 0xFFFF))) {
+    last_removed = *it;
+    remove_count++;
+    auto to_erase = it++;
+    lost_packets_buffer_.erase(to_erase);
+    if (lost_packets_buffer_.empty()) {
+      lost_packets_buffer_.swap(lost_packets_wrapped_buffer_);
+      it = lost_packets_buffer_.begin();
+    }
+  }
+  if (remove_count > 1) {
+    multiple_loss_historic_event_count_++;
+    multiple_loss_historic_packet_count_ += remove_count;
+  } else {
+    single_loss_historic_count_++;
+  }
+  // Continue pruning if the wrapped buffer is beyond a threshold and there are
+  // things left in the pre-wrapped buffer.
+  if (!lost_packets_wrapped_buffer_.empty() &&
+      *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000) {
+    PruneBuffer();
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/packet_loss_stats.h b/modules/rtp_rtcp/source/packet_loss_stats.h
new file mode 100644
index 0000000..7c4f658
--- /dev/null
+++ b/modules/rtp_rtcp/source/packet_loss_stats.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_
+#define MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_
+
+#include <stdint.h>
+#include <set>
+
+namespace webrtc {
+
+// Keeps track of statistics of packet loss including whether losses are a
+// single packet or multiple packets in a row.
+class PacketLossStats {
+ public:
+  PacketLossStats();
+  ~PacketLossStats();
+
+  // Adds a lost packet to the stats by sequence number.
+  void AddLostPacket(uint16_t sequence_number);
+
+  // Queries the number of packets that were lost by themselves, no neighboring
+  // packets were lost.
+  int GetSingleLossCount() const;
+
+  // Queries the number of times that multiple packets with sequential numbers
+  // were lost. This is the number of events with more than one packet lost,
+  // regardless of the size of the event;
+  int GetMultipleLossEventCount() const;
+
+  // Queries the number of packets lost in multiple packet loss events. Combined
+  // with the event count, this can be used to determine the average event size.
+  int GetMultipleLossPacketCount() const;
+
+ private:
+  std::set<uint16_t> lost_packets_buffer_;
+  std::set<uint16_t> lost_packets_wrapped_buffer_;
+  int single_loss_historic_count_;
+  int multiple_loss_historic_event_count_;
+  int multiple_loss_historic_packet_count_;
+
+  void ComputeLossCounts(int* out_single_loss_count,
+                         int* out_multiple_loss_event_count,
+                         int* out_multiple_loss_packet_count) const;
+  void PruneBuffer();
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_
diff --git a/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc b/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc
new file mode 100644
index 0000000..3731250
--- /dev/null
+++ b/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc
@@ -0,0 +1,197 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/packet_loss_stats.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+class PacketLossStatsTest : public ::testing::Test {
+ protected:
+  PacketLossStats stats_;
+};
+
+// Add a lost packet as every other packet, they should all count as single
+// losses.
+TEST_F(PacketLossStatsTest, EveryOtherPacket) {
+  for (int i = 0; i < 1000; i += 2) {
+    stats_.AddLostPacket(i);
+  }
+  EXPECT_EQ(500, stats_.GetSingleLossCount());
+  EXPECT_EQ(0, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(0, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as every other packet, but such that the sequence numbers
+// will wrap around while they are being added.
+TEST_F(PacketLossStatsTest, EveryOtherPacketWrapped) {
+  for (int i = 65500; i < 66500; i += 2) {
+    stats_.AddLostPacket(i & 0xFFFF);
+  }
+  EXPECT_EQ(500, stats_.GetSingleLossCount());
+  EXPECT_EQ(0, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(0, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as every other packet, but such that the sequence numbers
+// will wrap around close to the very end, such that the buffer contains packets
+// on either side of the wrapping.
+TEST_F(PacketLossStatsTest, EveryOtherPacketWrappedAtEnd) {
+  for (int i = 64600; i < 65600; i += 2) {
+    stats_.AddLostPacket(i & 0xFFFF);
+  }
+  EXPECT_EQ(500, stats_.GetSingleLossCount());
+  EXPECT_EQ(0, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(0, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as the first three of every eight packets. Each set of
+// three should count as a multiple loss event and three multiple loss packets.
+TEST_F(PacketLossStatsTest, FirstThreeOfEight) {
+  for (int i = 0; i < 1000; ++i) {
+    if ((i & 7) < 3) {
+      stats_.AddLostPacket(i);
+    }
+  }
+  EXPECT_EQ(0, stats_.GetSingleLossCount());
+  EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as the first three of every eight packets such that the
+// sequence numbers wrap in the middle of adding them.
+TEST_F(PacketLossStatsTest, FirstThreeOfEightWrapped) {
+  for (int i = 65500; i < 66500; ++i) {
+    if ((i & 7) < 3) {
+      stats_.AddLostPacket(i & 0xFFFF);
+    }
+  }
+  EXPECT_EQ(0, stats_.GetSingleLossCount());
+  EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as the first three of every eight packets such that the
+// sequence numbers wrap near the end of adding them and there are still numbers
+// in the buffer from before the wrapping.
+TEST_F(PacketLossStatsTest, FirstThreeOfEightWrappedAtEnd) {
+  for (int i = 64600; i < 65600; ++i) {
+    if ((i & 7) < 3) {
+      stats_.AddLostPacket(i & 0xFFFF);
+    }
+  }
+  EXPECT_EQ(0, stats_.GetSingleLossCount());
+  EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets as the first three and the fifth of every eight packets. The
+// set of three should be multiple loss and the fifth should be single loss.
+TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEight) {
+  for (int i = 0; i < 1000; ++i) {
+    if ((i & 7) < 3 || (i & 7) == 4) {
+      stats_.AddLostPacket(i);
+    }
+  }
+  EXPECT_EQ(125, stats_.GetSingleLossCount());
+  EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets as the first three and the fifth of every eight packets such
+// that the sequence numbers wrap in the middle of adding them.
+TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEightWrapped) {
+  for (int i = 65500; i < 66500; ++i) {
+    if ((i & 7) < 3 || (i & 7) == 4) {
+      stats_.AddLostPacket(i & 0xFFFF);
+    }
+  }
+  EXPECT_EQ(125, stats_.GetSingleLossCount());
+  EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets as the first three and the fifth of every eight packets such
+// that the sequence numbers wrap near the end of adding them and there are
+// packets from before the wrapping still in the buffer.
+TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEightWrappedAtEnd) {
+  for (int i = 64600; i < 65600; ++i) {
+    if ((i & 7) < 3 || (i & 7) == 4) {
+      stats_.AddLostPacket(i & 0xFFFF);
+    }
+  }
+  EXPECT_EQ(125, stats_.GetSingleLossCount());
+  EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets such that there is a multiple loss event that continues
+// around the wrapping of sequence numbers.
+TEST_F(PacketLossStatsTest, MultipleLossEventWrapped) {
+  for (int i = 60000; i < 60500; i += 2) {
+    stats_.AddLostPacket(i);
+  }
+  for (int i = 65530; i < 65540; ++i) {
+    stats_.AddLostPacket(i & 0xFFFF);
+  }
+  EXPECT_EQ(250, stats_.GetSingleLossCount());
+  EXPECT_EQ(1, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(10, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets such that there is a multiple loss event that continues
+// around the wrapping of sequence numbers and then is pushed out of the buffer.
+TEST_F(PacketLossStatsTest, MultipleLossEventWrappedPushedOut) {
+  for (int i = 60000; i < 60500; i += 2) {
+    stats_.AddLostPacket(i);
+  }
+  for (int i = 65530; i < 65540; ++i) {
+    stats_.AddLostPacket(i & 0xFFFF);
+  }
+  for (int i = 1000; i < 1500; i += 2) {
+    stats_.AddLostPacket(i);
+  }
+  EXPECT_EQ(500, stats_.GetSingleLossCount());
+  EXPECT_EQ(1, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(10, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets out of order and ensure that they still get counted
+// correctly as single or multiple loss events.
+TEST_F(PacketLossStatsTest, OutOfOrder) {
+  for (int i = 0; i < 1000; i += 10) {
+    stats_.AddLostPacket(i + 5);
+    stats_.AddLostPacket(i + 7);
+    stats_.AddLostPacket(i + 4);
+    stats_.AddLostPacket(i + 1);
+    stats_.AddLostPacket(i + 2);
+  }
+  EXPECT_EQ(100, stats_.GetSingleLossCount());
+  EXPECT_EQ(200, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(400, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets out of order and ensure that they still get counted
+// correctly as single or multiple loss events, and wrap in the middle of
+// adding.
+TEST_F(PacketLossStatsTest, OutOfOrderWrapped) {
+  for (int i = 65000; i < 66000; i += 10) {
+    stats_.AddLostPacket((i + 5) & 0xFFFF);
+    stats_.AddLostPacket((i + 7) & 0xFFFF);
+    stats_.AddLostPacket((i + 4) & 0xFFFF);
+    stats_.AddLostPacket((i + 1) & 0xFFFF);
+    stats_.AddLostPacket((i + 2) & 0xFFFF);
+  }
+  EXPECT_EQ(100, stats_.GetSingleLossCount());
+  EXPECT_EQ(200, stats_.GetMultipleLossEventCount());
+  EXPECT_EQ(400, stats_.GetMultipleLossPacketCount());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/playout_delay_oracle.cc b/modules/rtp_rtcp/source/playout_delay_oracle.cc
new file mode 100644
index 0000000..d3a75dd
--- /dev/null
+++ b/modules/rtp_rtcp/source/playout_delay_oracle.cc
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+PlayoutDelayOracle::PlayoutDelayOracle()
+    : high_sequence_number_(0),
+      send_playout_delay_(false),
+      ssrc_(0),
+      playout_delay_{-1, -1} {}
+
+PlayoutDelayOracle::~PlayoutDelayOracle() {}
+
+void PlayoutDelayOracle::UpdateRequest(uint32_t ssrc,
+                                       PlayoutDelay playout_delay,
+                                       uint16_t seq_num) {
+  rtc::CritScope lock(&crit_sect_);
+  RTC_DCHECK_LE(playout_delay.min_ms, PlayoutDelayLimits::kMaxMs);
+  RTC_DCHECK_LE(playout_delay.max_ms, PlayoutDelayLimits::kMaxMs);
+  RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
+  int64_t unwrapped_seq_num = unwrapper_.Unwrap(seq_num);
+  if (playout_delay.min_ms >= 0 &&
+      playout_delay.min_ms != playout_delay_.min_ms) {
+    send_playout_delay_ = true;
+    playout_delay_.min_ms = playout_delay.min_ms;
+    high_sequence_number_ = unwrapped_seq_num;
+  }
+
+  if (playout_delay.max_ms >= 0 &&
+      playout_delay.max_ms != playout_delay_.max_ms) {
+    send_playout_delay_ = true;
+    playout_delay_.max_ms = playout_delay.max_ms;
+    high_sequence_number_ = unwrapped_seq_num;
+  }
+  ssrc_ = ssrc;
+}
+
+// If an ACK is received on the packet containing the playout delay extension,
+// we stop sending the extension on future packets.
+void PlayoutDelayOracle::OnReceivedRtcpReportBlocks(
+    const ReportBlockList& report_blocks) {
+  rtc::CritScope lock(&crit_sect_);
+  for (const RTCPReportBlock& report_block : report_blocks) {
+    if ((ssrc_ == report_block.source_ssrc) && send_playout_delay_ &&
+        (report_block.extended_highest_sequence_number >
+         high_sequence_number_)) {
+      send_playout_delay_ = false;
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/playout_delay_oracle.h b/modules/rtp_rtcp/source/playout_delay_oracle.h
new file mode 100644
index 0000000..6e6e253
--- /dev/null
+++ b/modules/rtp_rtcp/source/playout_delay_oracle.h
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_PLAYOUT_DELAY_ORACLE_H_
+#define MODULES_RTP_RTCP_SOURCE_PLAYOUT_DELAY_ORACLE_H_
+
+#include <stdint.h>
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+// This class tracks the application requests to limit minimum and maximum
+// playout delay and makes a decision on whether the current RTP frame
+// should include the playout out delay extension header.
+//
+//  Playout delay can be defined in terms of capture and render time as follows:
+//
+// Render time = Capture time in receiver time + playout delay
+//
+// The application specifies a minimum and maximum limit for the playout delay
+// which are both communicated to the receiver and the receiver can adapt
+// the playout delay within this range based on observed network jitter.
+class PlayoutDelayOracle {
+ public:
+  PlayoutDelayOracle();
+  ~PlayoutDelayOracle();
+
+  // Returns true if the current frame should include the playout delay
+  // extension
+  bool send_playout_delay() const {
+    rtc::CritScope lock(&crit_sect_);
+    return send_playout_delay_;
+  }
+
+  // Returns current playout delay.
+  PlayoutDelay playout_delay() const {
+    rtc::CritScope lock(&crit_sect_);
+    return playout_delay_;
+  }
+
+  // Updates the application requested playout delay, current ssrc
+  // and the current sequence number.
+  void UpdateRequest(uint32_t ssrc,
+                     PlayoutDelay playout_delay,
+                     uint16_t seq_num);
+
+  void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks);
+
+ private:
+  // The playout delay information is updated from the encoder thread(s).
+  // The sequence number feedback is updated from the worker thread.
+  // Guards access to data across multiple threads.
+  rtc::CriticalSection crit_sect_;
+  // The current highest sequence number on which playout delay has been sent.
+  int64_t high_sequence_number_ RTC_GUARDED_BY(crit_sect_);
+  // Indicates whether the playout delay should go on the next frame.
+  bool send_playout_delay_ RTC_GUARDED_BY(crit_sect_);
+  // Sender ssrc.
+  uint32_t ssrc_ RTC_GUARDED_BY(crit_sect_);
+  // Sequence number unwrapper.
+  SequenceNumberUnwrapper unwrapper_ RTC_GUARDED_BY(crit_sect_);
+  // Playout delay values on the next frame if |send_playout_delay_| is set.
+  PlayoutDelay playout_delay_ RTC_GUARDED_BY(crit_sect_);
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(PlayoutDelayOracle);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_PLAYOUT_DELAY_ORACLE_H_
diff --git a/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc b/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc
new file mode 100644
index 0000000..099339d
--- /dev/null
+++ b/modules/rtp_rtcp/source/playout_delay_oracle_unittest.cc
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
+
+#include "rtc_base/logging.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+constexpr int kSsrc = 100;
+constexpr int kSequenceNumber = 100;
+constexpr int kMinPlayoutDelay = 0;
+constexpr int kMaxPlayoutDelay = 150;
+}  // namespace
+
+class PlayoutDelayOracleTest : public ::testing::Test {
+ protected:
+  void ReportRTCPFeedback(int ssrc, int seq_num) {
+    RTCPReportBlock report_block;
+    report_block.source_ssrc = ssrc;
+    report_block.extended_highest_sequence_number = seq_num;
+    report_blocks_.push_back(report_block);
+    playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks_);
+  }
+
+  ReportBlockList report_blocks_;
+  PlayoutDelayOracle playout_delay_oracle_;
+};
+
+TEST_F(PlayoutDelayOracleTest, DisabledByDefault) {
+  EXPECT_FALSE(playout_delay_oracle_.send_playout_delay());
+  EXPECT_EQ(-1, playout_delay_oracle_.playout_delay().min_ms);
+  EXPECT_EQ(-1, playout_delay_oracle_.playout_delay().max_ms);
+}
+
+TEST_F(PlayoutDelayOracleTest, SendPlayoutDelayUntilSeqNumberExceeds) {
+  PlayoutDelay playout_delay = {kMinPlayoutDelay, kMaxPlayoutDelay};
+  playout_delay_oracle_.UpdateRequest(kSsrc, playout_delay, kSequenceNumber);
+  EXPECT_TRUE(playout_delay_oracle_.send_playout_delay());
+  EXPECT_EQ(kMinPlayoutDelay, playout_delay_oracle_.playout_delay().min_ms);
+  EXPECT_EQ(kMaxPlayoutDelay, playout_delay_oracle_.playout_delay().max_ms);
+
+  // Oracle indicates playout delay should be sent if highest sequence number
+  // acked is lower than the sequence number of the first packet containing
+  // playout delay.
+  ReportRTCPFeedback(kSsrc, kSequenceNumber - 1);
+  EXPECT_TRUE(playout_delay_oracle_.send_playout_delay());
+
+  // An invalid ssrc feedback report is dropped by the oracle.
+  ReportRTCPFeedback(kSsrc + 1, kSequenceNumber + 1);
+  EXPECT_TRUE(playout_delay_oracle_.send_playout_delay());
+
+  // Oracle indicates playout delay should not be sent if sequence number
+  // acked on a matching ssrc indicates the receiver has received the playout
+  // delay values.
+  ReportRTCPFeedback(kSsrc, kSequenceNumber + 1);
+  EXPECT_FALSE(playout_delay_oracle_.send_playout_delay());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.cc b/modules/rtp_rtcp/source/receive_statistics_impl.cc
new file mode 100644
index 0000000..362a7cf
--- /dev/null
+++ b/modules/rtp_rtcp/source/receive_statistics_impl.cc
@@ -0,0 +1,494 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/receive_statistics_impl.h"
+
+#include <math.h>
+
+#include <cstdlib>
+#include <vector>
+
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+const int64_t kStatisticsTimeoutMs = 8000;
+const int64_t kStatisticsProcessIntervalMs = 1000;
+
+StreamStatistician::~StreamStatistician() {}
+
+StreamStatisticianImpl::StreamStatisticianImpl(
+    uint32_t ssrc,
+    Clock* clock,
+    RtcpStatisticsCallback* rtcp_callback,
+    StreamDataCountersCallback* rtp_callback)
+    : ssrc_(ssrc),
+      clock_(clock),
+      incoming_bitrate_(kStatisticsProcessIntervalMs,
+                        RateStatistics::kBpsScale),
+      max_reordering_threshold_(kDefaultMaxReorderingThreshold),
+      jitter_q4_(0),
+      cumulative_loss_(0),
+      last_receive_time_ms_(0),
+      last_received_timestamp_(0),
+      received_seq_first_(0),
+      received_seq_max_(0),
+      received_seq_wraps_(0),
+      received_packet_overhead_(12),
+      last_report_inorder_packets_(0),
+      last_report_old_packets_(0),
+      last_report_seq_max_(0),
+      rtcp_callback_(rtcp_callback),
+      rtp_callback_(rtp_callback) {}
+
+StreamStatisticianImpl::~StreamStatisticianImpl() = default;
+
+void StreamStatisticianImpl::IncomingPacket(const RTPHeader& header,
+                                            size_t packet_length,
+                                            bool retransmitted) {
+  auto counters = UpdateCounters(header, packet_length, retransmitted);
+  rtp_callback_->DataCountersUpdated(counters, ssrc_);
+}
+
+StreamDataCounters StreamStatisticianImpl::UpdateCounters(
+    const RTPHeader& header,
+    size_t packet_length,
+    bool retransmitted) {
+  rtc::CritScope cs(&stream_lock_);
+  bool in_order = InOrderPacketInternal(header.sequenceNumber);
+  RTC_DCHECK_EQ(ssrc_, header.ssrc);
+  incoming_bitrate_.Update(packet_length, clock_->TimeInMilliseconds());
+  receive_counters_.transmitted.AddPacket(packet_length, header);
+  if (!in_order && retransmitted) {
+    receive_counters_.retransmitted.AddPacket(packet_length, header);
+  }
+
+  if (receive_counters_.transmitted.packets == 1) {
+    received_seq_first_ = header.sequenceNumber;
+    receive_counters_.first_packet_time_ms = clock_->TimeInMilliseconds();
+  }
+
+  // Count only the new packets received. That is, if packets 1, 2, 3, 5, 4, 6
+  // are received, 4 will be ignored.
+  if (in_order) {
+    // Current time in samples.
+    NtpTime receive_time = clock_->CurrentNtpTime();
+
+    // Wrong if we use RetransmitOfOldPacket.
+    if (receive_counters_.transmitted.packets > 1 &&
+        received_seq_max_ > header.sequenceNumber) {
+      // Wrap around detected.
+      received_seq_wraps_++;
+    }
+    // New max.
+    received_seq_max_ = header.sequenceNumber;
+
+    // If new time stamp and more than one in-order packet received, calculate
+    // new jitter statistics.
+    if (header.timestamp != last_received_timestamp_ &&
+        (receive_counters_.transmitted.packets -
+         receive_counters_.retransmitted.packets) > 1) {
+      UpdateJitter(header, receive_time);
+    }
+    last_received_timestamp_ = header.timestamp;
+    last_receive_time_ntp_ = receive_time;
+    last_receive_time_ms_ = clock_->TimeInMilliseconds();
+  }
+
+  size_t packet_oh = header.headerLength + header.paddingLength;
+
+  // Our measured overhead. Filter from RFC 5104 4.2.1.2:
+  // avg_OH (new) = 15/16*avg_OH (old) + 1/16*pckt_OH,
+  received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4;
+  return receive_counters_;
+}
+
+void StreamStatisticianImpl::UpdateJitter(const RTPHeader& header,
+                                          NtpTime receive_time) {
+  uint32_t receive_time_rtp =
+      NtpToRtp(receive_time, header.payload_type_frequency);
+  uint32_t last_receive_time_rtp =
+      NtpToRtp(last_receive_time_ntp_, header.payload_type_frequency);
+  int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) -
+                              (header.timestamp - last_received_timestamp_);
+
+  time_diff_samples = std::abs(time_diff_samples);
+
+  // lib_jingle sometimes deliver crazy jumps in TS for the same stream.
+  // If this happens, don't update jitter value. Use 5 secs video frequency
+  // as the threshold.
+  if (time_diff_samples < 450000) {
+    // Note we calculate in Q4 to avoid using float.
+    int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_;
+    jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
+  }
+}
+
+void StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header,
+                                               size_t packet_length) {
+  StreamDataCounters counters;
+  {
+    rtc::CritScope cs(&stream_lock_);
+    receive_counters_.fec.AddPacket(packet_length, header);
+    counters = receive_counters_;
+  }
+  rtp_callback_->DataCountersUpdated(counters, ssrc_);
+}
+
+void StreamStatisticianImpl::SetMaxReorderingThreshold(
+    int max_reordering_threshold) {
+  rtc::CritScope cs(&stream_lock_);
+  max_reordering_threshold_ = max_reordering_threshold;
+}
+
+bool StreamStatisticianImpl::GetStatistics(RtcpStatistics* statistics,
+                                           bool reset) {
+  {
+    rtc::CritScope cs(&stream_lock_);
+    if (received_seq_first_ == 0 &&
+        receive_counters_.transmitted.payload_bytes == 0) {
+      // We have not received anything.
+      return false;
+    }
+
+    if (!reset) {
+      if (last_report_inorder_packets_ == 0) {
+        // No report.
+        return false;
+      }
+      // Just get last report.
+      *statistics = last_reported_statistics_;
+      return true;
+    }
+
+    *statistics = CalculateRtcpStatistics();
+  }
+
+  rtcp_callback_->StatisticsUpdated(*statistics, ssrc_);
+  return true;
+}
+
+bool StreamStatisticianImpl::GetActiveStatisticsAndReset(
+    RtcpStatistics* statistics) {
+  {
+    rtc::CritScope cs(&stream_lock_);
+    if (clock_->CurrentNtpInMilliseconds() - last_receive_time_ntp_.ToMs() >=
+        kStatisticsTimeoutMs) {
+      // Not active.
+      return false;
+    }
+    if (received_seq_first_ == 0 &&
+        receive_counters_.transmitted.payload_bytes == 0) {
+      // We have not received anything.
+      return false;
+    }
+
+    *statistics = CalculateRtcpStatistics();
+  }
+
+  rtcp_callback_->StatisticsUpdated(*statistics, ssrc_);
+  return true;
+}
+
+RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() {
+  RtcpStatistics stats;
+
+  if (last_report_inorder_packets_ == 0) {
+    // First time we send a report.
+    last_report_seq_max_ = received_seq_first_ - 1;
+  }
+
+  // Calculate fraction lost.
+  uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);
+
+  if (last_report_seq_max_ > received_seq_max_) {
+    // Can we assume that the seq_num can't go decrease over a full RTCP period?
+    exp_since_last = 0;
+  }
+
+  // Number of received RTP packets since last report, counts all packets but
+  // not re-transmissions.
+  uint32_t rec_since_last = (receive_counters_.transmitted.packets -
+                             receive_counters_.retransmitted.packets) -
+                            last_report_inorder_packets_;
+
+  // With NACK we don't know the expected retransmissions during the last
+  // second. We know how many "old" packets we have received. We just count
+  // the number of old received to estimate the loss, but it still does not
+  // guarantee an exact number since we run this based on time triggered by
+  // sending of an RTP packet. This should have a minimum effect.
+
+  // With NACK we don't count old packets as received since they are
+  // re-transmitted. We use RTT to decide if a packet is re-ordered or
+  // re-transmitted.
+  uint32_t retransmitted_packets =
+      receive_counters_.retransmitted.packets - last_report_old_packets_;
+  rec_since_last += retransmitted_packets;
+
+  int32_t missing = 0;
+  if (exp_since_last > rec_since_last) {
+    missing = (exp_since_last - rec_since_last);
+  }
+  uint8_t local_fraction_lost = 0;
+  if (exp_since_last) {
+    // Scale 0 to 255, where 255 is 100% loss.
+    local_fraction_lost = static_cast<uint8_t>(255 * missing / exp_since_last);
+  }
+  stats.fraction_lost = local_fraction_lost;
+
+  // We need a counter for cumulative loss too.
+  // TODO(danilchap): Ensure cumulative loss is below maximum value of 2^24.
+  cumulative_loss_ += missing;
+  stats.packets_lost = cumulative_loss_;
+  stats.extended_highest_sequence_number =
+      (received_seq_wraps_ << 16) + received_seq_max_;
+  // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
+  stats.jitter = jitter_q4_ >> 4;
+
+  // Store this report.
+  last_reported_statistics_ = stats;
+
+  // Only for report blocks in RTCP SR and RR.
+  last_report_inorder_packets_ = receive_counters_.transmitted.packets -
+                                 receive_counters_.retransmitted.packets;
+  last_report_old_packets_ = receive_counters_.retransmitted.packets;
+  last_report_seq_max_ = received_seq_max_;
+  BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "cumulative_loss_pkts",
+                                  clock_->TimeInMilliseconds(),
+                                  cumulative_loss_, ssrc_);
+  BWE_TEST_LOGGING_PLOT_WITH_SSRC(
+      1, "received_seq_max_pkts", clock_->TimeInMilliseconds(),
+      (received_seq_max_ - received_seq_first_), ssrc_);
+
+  return stats;
+}
+
+void StreamStatisticianImpl::GetDataCounters(size_t* bytes_received,
+                                             uint32_t* packets_received) const {
+  rtc::CritScope cs(&stream_lock_);
+  if (bytes_received) {
+    *bytes_received = receive_counters_.transmitted.payload_bytes +
+                      receive_counters_.transmitted.header_bytes +
+                      receive_counters_.transmitted.padding_bytes;
+  }
+  if (packets_received) {
+    *packets_received = receive_counters_.transmitted.packets;
+  }
+}
+
+void StreamStatisticianImpl::GetReceiveStreamDataCounters(
+    StreamDataCounters* data_counters) const {
+  rtc::CritScope cs(&stream_lock_);
+  *data_counters = receive_counters_;
+}
+
+uint32_t StreamStatisticianImpl::BitrateReceived() const {
+  rtc::CritScope cs(&stream_lock_);
+  return incoming_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+}
+
+bool StreamStatisticianImpl::IsRetransmitOfOldPacket(
+    const RTPHeader& header) const {
+  rtc::CritScope cs(&stream_lock_);
+  if (InOrderPacketInternal(header.sequenceNumber)) {
+    return false;
+  }
+  uint32_t frequency_khz = header.payload_type_frequency / 1000;
+  assert(frequency_khz > 0);
+
+  int64_t time_diff_ms = clock_->TimeInMilliseconds() - last_receive_time_ms_;
+
+  // Diff in time stamp since last received in order.
+  uint32_t timestamp_diff = header.timestamp - last_received_timestamp_;
+  uint32_t rtp_time_stamp_diff_ms = timestamp_diff / frequency_khz;
+
+  int64_t max_delay_ms = 0;
+
+  // Jitter standard deviation in samples.
+  float jitter_std = sqrt(static_cast<float>(jitter_q4_ >> 4));
+
+  // 2 times the standard deviation => 95% confidence.
+  // And transform to milliseconds by dividing by the frequency in kHz.
+  max_delay_ms = static_cast<int64_t>((2 * jitter_std) / frequency_khz);
+
+  // Min max_delay_ms is 1.
+  if (max_delay_ms == 0) {
+    max_delay_ms = 1;
+  }
+  return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms;
+}
+
+bool StreamStatisticianImpl::InOrderPacketInternal(
+    uint16_t sequence_number) const {
+  // First packet is always in order.
+  if (last_receive_time_ms_ == 0)
+    return true;
+
+  if (IsNewerSequenceNumber(sequence_number, received_seq_max_)) {
+    return true;
+  } else {
+    // If we have a restart of the remote side this packet is still in order.
+    return !IsNewerSequenceNumber(
+        sequence_number, received_seq_max_ - max_reordering_threshold_);
+  }
+}
+
+ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) {
+  return new ReceiveStatisticsImpl(clock);
+}
+
+ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
+    : clock_(clock),
+      last_returned_ssrc_(0),
+      rtcp_stats_callback_(NULL),
+      rtp_stats_callback_(NULL) {}
+
+ReceiveStatisticsImpl::~ReceiveStatisticsImpl() {
+  while (!statisticians_.empty()) {
+    delete statisticians_.begin()->second;
+    statisticians_.erase(statisticians_.begin());
+  }
+}
+
+void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
+                                           size_t packet_length,
+                                           bool retransmitted) {
+  StreamStatisticianImpl* impl;
+  {
+    rtc::CritScope cs(&receive_statistics_lock_);
+    auto it = statisticians_.find(header.ssrc);
+    if (it != statisticians_.end()) {
+      impl = it->second;
+    } else {
+      impl = new StreamStatisticianImpl(header.ssrc, clock_, this, this);
+      statisticians_[header.ssrc] = impl;
+    }
+  }
+  // StreamStatisticianImpl instance is created once and only destroyed when
+  // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has
+  // it's own locking so don't hold receive_statistics_lock_ (potential
+  // deadlock).
+  impl->IncomingPacket(header, packet_length, retransmitted);
+}
+
+void ReceiveStatisticsImpl::FecPacketReceived(const RTPHeader& header,
+                                              size_t packet_length) {
+  StreamStatisticianImpl* impl;
+  {
+    rtc::CritScope cs(&receive_statistics_lock_);
+    auto it = statisticians_.find(header.ssrc);
+    // Ignore FEC if it is the first packet.
+    if (it == statisticians_.end())
+      return;
+    impl = it->second;
+  }
+  impl->FecPacketReceived(header, packet_length);
+}
+
+StreamStatistician* ReceiveStatisticsImpl::GetStatistician(
+    uint32_t ssrc) const {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  auto it = statisticians_.find(ssrc);
+  if (it == statisticians_.end())
+    return NULL;
+  return it->second;
+}
+
+void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
+    int max_reordering_threshold) {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  for (auto& statistician : statisticians_) {
+    statistician.second->SetMaxReorderingThreshold(max_reordering_threshold);
+  }
+}
+
+void ReceiveStatisticsImpl::RegisterRtcpStatisticsCallback(
+    RtcpStatisticsCallback* callback) {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  if (callback != NULL)
+    assert(rtcp_stats_callback_ == NULL);
+  rtcp_stats_callback_ = callback;
+}
+
+void ReceiveStatisticsImpl::StatisticsUpdated(const RtcpStatistics& statistics,
+                                              uint32_t ssrc) {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  if (rtcp_stats_callback_)
+    rtcp_stats_callback_->StatisticsUpdated(statistics, ssrc);
+}
+
+void ReceiveStatisticsImpl::CNameChanged(const char* cname, uint32_t ssrc) {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  if (rtcp_stats_callback_)
+    rtcp_stats_callback_->CNameChanged(cname, ssrc);
+}
+
+void ReceiveStatisticsImpl::RegisterRtpStatisticsCallback(
+    StreamDataCountersCallback* callback) {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  if (callback != NULL)
+    assert(rtp_stats_callback_ == NULL);
+  rtp_stats_callback_ = callback;
+}
+
+void ReceiveStatisticsImpl::DataCountersUpdated(const StreamDataCounters& stats,
+                                                uint32_t ssrc) {
+  rtc::CritScope cs(&receive_statistics_lock_);
+  if (rtp_stats_callback_) {
+    rtp_stats_callback_->DataCountersUpdated(stats, ssrc);
+  }
+}
+
+std::vector<rtcp::ReportBlock> ReceiveStatisticsImpl::RtcpReportBlocks(
+    size_t max_blocks) {
+  std::map<uint32_t, StreamStatisticianImpl*> statisticians;
+  {
+    rtc::CritScope cs(&receive_statistics_lock_);
+    statisticians = statisticians_;
+  }
+  std::vector<rtcp::ReportBlock> result;
+  result.reserve(std::min(max_blocks, statisticians.size()));
+  auto add_report_block = [&result](uint32_t media_ssrc,
+                                    StreamStatisticianImpl* statistician) {
+    // Do we have receive statistics to send?
+    RtcpStatistics stats;
+    if (!statistician->GetActiveStatisticsAndReset(&stats))
+      return;
+    result.emplace_back();
+    rtcp::ReportBlock& block = result.back();
+    block.SetMediaSsrc(media_ssrc);
+    block.SetFractionLost(stats.fraction_lost);
+    if (!block.SetCumulativeLost(stats.packets_lost)) {
+      RTC_LOG(LS_WARNING) << "Cumulative lost is oversized.";
+      result.pop_back();
+      return;
+    }
+    block.SetExtHighestSeqNum(stats.extended_highest_sequence_number);
+    block.SetJitter(stats.jitter);
+  };
+
+  const auto start_it = statisticians.upper_bound(last_returned_ssrc_);
+  for (auto it = start_it;
+       result.size() < max_blocks && it != statisticians.end(); ++it)
+    add_report_block(it->first, it->second);
+  for (auto it = statisticians.begin();
+       result.size() < max_blocks && it != start_it; ++it)
+    add_report_block(it->first, it->second);
+
+  if (!result.empty())
+    last_returned_ssrc_ = result.back().source_ssrc();
+  return result;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.h b/modules/rtp_rtcp/source/receive_statistics_impl.h
new file mode 100644
index 0000000..5559b7c
--- /dev/null
+++ b/modules/rtp_rtcp/source/receive_statistics_impl.h
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_
+#define MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_
+
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+
+#include <algorithm>
+#include <map>
+#include <vector>
+
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/rate_statistics.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+
+class StreamStatisticianImpl : public StreamStatistician {
+ public:
+  StreamStatisticianImpl(uint32_t ssrc,
+                         Clock* clock,
+                         RtcpStatisticsCallback* rtcp_callback,
+                         StreamDataCountersCallback* rtp_callback);
+  ~StreamStatisticianImpl() override;
+
+  // |reset| here and in next method restarts calculation of fraction_lost stat.
+  bool GetStatistics(RtcpStatistics* statistics, bool reset) override;
+  bool GetActiveStatisticsAndReset(RtcpStatistics* statistics);
+  void GetDataCounters(size_t* bytes_received,
+                       uint32_t* packets_received) const override;
+  void GetReceiveStreamDataCounters(
+      StreamDataCounters* data_counters) const override;
+  uint32_t BitrateReceived() const override;
+  bool IsRetransmitOfOldPacket(const RTPHeader& header) const override;
+
+  void IncomingPacket(const RTPHeader& rtp_header,
+                      size_t packet_length,
+                      bool retransmitted);
+  void FecPacketReceived(const RTPHeader& header, size_t packet_length);
+  void SetMaxReorderingThreshold(int max_reordering_threshold);
+
+ private:
+  bool InOrderPacketInternal(uint16_t sequence_number) const;
+  RtcpStatistics CalculateRtcpStatistics()
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
+  void UpdateJitter(const RTPHeader& header, NtpTime receive_time);
+  StreamDataCounters UpdateCounters(const RTPHeader& rtp_header,
+                                    size_t packet_length,
+                                    bool retransmitted);
+
+  const uint32_t ssrc_;
+  Clock* const clock_;
+  rtc::CriticalSection stream_lock_;
+  RateStatistics incoming_bitrate_;
+  int max_reordering_threshold_;  // In number of packets or sequence numbers.
+
+  // Stats on received RTP packets.
+  uint32_t jitter_q4_;
+  uint32_t cumulative_loss_;
+
+  int64_t last_receive_time_ms_;
+  NtpTime last_receive_time_ntp_;
+  uint32_t last_received_timestamp_;
+  uint16_t received_seq_first_;
+  uint16_t received_seq_max_;
+  uint16_t received_seq_wraps_;
+
+  // Current counter values.
+  size_t received_packet_overhead_;
+  StreamDataCounters receive_counters_;
+
+  // Counter values when we sent the last report.
+  uint32_t last_report_inorder_packets_;
+  uint32_t last_report_old_packets_;
+  uint16_t last_report_seq_max_;
+  RtcpStatistics last_reported_statistics_;
+
+  // stream_lock_ shouldn't be held when calling callbacks.
+  RtcpStatisticsCallback* const rtcp_callback_;
+  StreamDataCountersCallback* const rtp_callback_;
+};
+
+class ReceiveStatisticsImpl : public ReceiveStatistics,
+                              public RtcpStatisticsCallback,
+                              public StreamDataCountersCallback {
+ public:
+  explicit ReceiveStatisticsImpl(Clock* clock);
+
+  ~ReceiveStatisticsImpl() override;
+
+  // Implement ReceiveStatisticsProvider.
+  std::vector<rtcp::ReportBlock> RtcpReportBlocks(size_t max_blocks) override;
+
+  // Implement ReceiveStatistics.
+  void IncomingPacket(const RTPHeader& header,
+                      size_t packet_length,
+                      bool retransmitted) override;
+  void FecPacketReceived(const RTPHeader& header,
+                         size_t packet_length) override;
+  StreamStatistician* GetStatistician(uint32_t ssrc) const override;
+  void SetMaxReorderingThreshold(int max_reordering_threshold) override;
+
+  void RegisterRtcpStatisticsCallback(
+      RtcpStatisticsCallback* callback) override;
+
+  void RegisterRtpStatisticsCallback(
+      StreamDataCountersCallback* callback) override;
+
+ private:
+  void StatisticsUpdated(const RtcpStatistics& statistics,
+                         uint32_t ssrc) override;
+  void CNameChanged(const char* cname, uint32_t ssrc) override;
+  void DataCountersUpdated(const StreamDataCounters& counters,
+                           uint32_t ssrc) override;
+
+  Clock* const clock_;
+  rtc::CriticalSection receive_statistics_lock_;
+  uint32_t last_returned_ssrc_;
+  std::map<uint32_t, StreamStatisticianImpl*> statisticians_;
+
+  RtcpStatisticsCallback* rtcp_stats_callback_;
+  StreamDataCountersCallback* rtp_stats_callback_;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_
diff --git a/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/modules/rtp_rtcp/source/receive_statistics_unittest.cc
new file mode 100644
index 0000000..29fc88d
--- /dev/null
+++ b/modules/rtp_rtcp/source/receive_statistics_unittest.cc
@@ -0,0 +1,422 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::SizeIs;
+using ::testing::UnorderedElementsAre;
+
+const size_t kPacketSize1 = 100;
+const size_t kPacketSize2 = 300;
+const uint32_t kSsrc1 = 101;
+const uint32_t kSsrc2 = 202;
+const uint32_t kSsrc3 = 203;
+const uint32_t kSsrc4 = 304;
+
+RTPHeader CreateRtpHeader(uint32_t ssrc) {
+  RTPHeader header;
+  memset(&header, 0, sizeof(header));
+  header.ssrc = ssrc;
+  header.sequenceNumber = 100;
+  return header;
+}
+
+class ReceiveStatisticsTest : public ::testing::Test {
+ public:
+  ReceiveStatisticsTest()
+      : clock_(0), receive_statistics_(ReceiveStatistics::Create(&clock_)) {
+    header1_ = CreateRtpHeader(kSsrc1);
+    header2_ = CreateRtpHeader(kSsrc2);
+  }
+
+ protected:
+  SimulatedClock clock_;
+  std::unique_ptr<ReceiveStatistics> receive_statistics_;
+  RTPHeader header1_;
+  RTPHeader header2_;
+};
+
+TEST_F(ReceiveStatisticsTest, TwoIncomingSsrcs) {
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+  receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
+  ++header2_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(100);
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+  receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
+  ++header2_.sequenceNumber;
+
+  StreamStatistician* statistician =
+      receive_statistics_->GetStatistician(kSsrc1);
+  ASSERT_TRUE(statistician != NULL);
+  EXPECT_GT(statistician->BitrateReceived(), 0u);
+  size_t bytes_received = 0;
+  uint32_t packets_received = 0;
+  statistician->GetDataCounters(&bytes_received, &packets_received);
+  EXPECT_EQ(200u, bytes_received);
+  EXPECT_EQ(2u, packets_received);
+
+  statistician = receive_statistics_->GetStatistician(kSsrc2);
+  ASSERT_TRUE(statistician != NULL);
+  EXPECT_GT(statistician->BitrateReceived(), 0u);
+  statistician->GetDataCounters(&bytes_received, &packets_received);
+  EXPECT_EQ(600u, bytes_received);
+  EXPECT_EQ(2u, packets_received);
+
+  EXPECT_EQ(2u, receive_statistics_->RtcpReportBlocks(3).size());
+  // Add more incoming packets and verify that they are registered in both
+  // access methods.
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+  receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
+  ++header2_.sequenceNumber;
+
+  receive_statistics_->GetStatistician(kSsrc1)->GetDataCounters(
+      &bytes_received, &packets_received);
+  EXPECT_EQ(300u, bytes_received);
+  EXPECT_EQ(3u, packets_received);
+  receive_statistics_->GetStatistician(kSsrc2)->GetDataCounters(
+      &bytes_received, &packets_received);
+  EXPECT_EQ(900u, bytes_received);
+  EXPECT_EQ(3u, packets_received);
+}
+
+TEST_F(ReceiveStatisticsTest,
+       RtcpReportBlocksReturnsMaxBlocksWhenThereAreMoreStatisticians) {
+  RTPHeader header1 = CreateRtpHeader(kSsrc1);
+  RTPHeader header2 = CreateRtpHeader(kSsrc2);
+  RTPHeader header3 = CreateRtpHeader(kSsrc3);
+  receive_statistics_->IncomingPacket(header1, kPacketSize1, false);
+  receive_statistics_->IncomingPacket(header2, kPacketSize1, false);
+  receive_statistics_->IncomingPacket(header3, kPacketSize1, false);
+
+  EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
+  EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
+  EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
+}
+
+TEST_F(ReceiveStatisticsTest,
+       RtcpReportBlocksReturnsAllObservedSsrcsWithMultipleCalls) {
+  RTPHeader header1 = CreateRtpHeader(kSsrc1);
+  RTPHeader header2 = CreateRtpHeader(kSsrc2);
+  RTPHeader header3 = CreateRtpHeader(kSsrc3);
+  RTPHeader header4 = CreateRtpHeader(kSsrc4);
+  receive_statistics_->IncomingPacket(header1, kPacketSize1, false);
+  receive_statistics_->IncomingPacket(header2, kPacketSize1, false);
+  receive_statistics_->IncomingPacket(header3, kPacketSize1, false);
+  receive_statistics_->IncomingPacket(header4, kPacketSize1, false);
+
+  std::vector<uint32_t> observed_ssrcs;
+  std::vector<rtcp::ReportBlock> report_blocks =
+      receive_statistics_->RtcpReportBlocks(2);
+  ASSERT_THAT(report_blocks, SizeIs(2));
+  observed_ssrcs.push_back(report_blocks[0].source_ssrc());
+  observed_ssrcs.push_back(report_blocks[1].source_ssrc());
+
+  report_blocks = receive_statistics_->RtcpReportBlocks(2);
+  ASSERT_THAT(report_blocks, SizeIs(2));
+  observed_ssrcs.push_back(report_blocks[0].source_ssrc());
+  observed_ssrcs.push_back(report_blocks[1].source_ssrc());
+
+  EXPECT_THAT(observed_ssrcs,
+              UnorderedElementsAre(kSsrc1, kSsrc2, kSsrc3, kSsrc4));
+}
+
+TEST_F(ReceiveStatisticsTest, ActiveStatisticians) {
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(1000);
+  receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
+  ++header2_.sequenceNumber;
+  // Nothing should time out since only 1000 ms has passed since the first
+  // packet came in.
+  EXPECT_EQ(2u, receive_statistics_->RtcpReportBlocks(3).size());
+
+  clock_.AdvanceTimeMilliseconds(7000);
+  // kSsrc1 should have timed out.
+  EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size());
+
+  clock_.AdvanceTimeMilliseconds(1000);
+  // kSsrc2 should have timed out.
+  EXPECT_EQ(0u, receive_statistics_->RtcpReportBlocks(3).size());
+
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+  // kSsrc1 should be active again and the data counters should have survived.
+  EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size());
+  StreamStatistician* statistician =
+      receive_statistics_->GetStatistician(kSsrc1);
+  ASSERT_TRUE(statistician != NULL);
+  size_t bytes_received = 0;
+  uint32_t packets_received = 0;
+  statistician->GetDataCounters(&bytes_received, &packets_received);
+  EXPECT_EQ(200u, bytes_received);
+  EXPECT_EQ(2u, packets_received);
+}
+
+TEST_F(ReceiveStatisticsTest, GetReceiveStreamDataCounters) {
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  StreamStatistician* statistician =
+      receive_statistics_->GetStatistician(kSsrc1);
+  ASSERT_TRUE(statistician != NULL);
+
+  StreamDataCounters counters;
+  statistician->GetReceiveStreamDataCounters(&counters);
+  EXPECT_GT(counters.first_packet_time_ms, -1);
+  EXPECT_EQ(1u, counters.transmitted.packets);
+
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  statistician->GetReceiveStreamDataCounters(&counters);
+  EXPECT_GT(counters.first_packet_time_ms, -1);
+  EXPECT_EQ(2u, counters.transmitted.packets);
+}
+
+TEST_F(ReceiveStatisticsTest, RtcpCallbacks) {
+  class TestCallback : public RtcpStatisticsCallback {
+   public:
+    TestCallback()
+        : RtcpStatisticsCallback(), num_calls_(0), ssrc_(0), stats_() {}
+    ~TestCallback() override {}
+
+    void StatisticsUpdated(const RtcpStatistics& statistics,
+                           uint32_t ssrc) override {
+      ssrc_ = ssrc;
+      stats_ = statistics;
+      ++num_calls_;
+    }
+
+    void CNameChanged(const char* cname, uint32_t ssrc) override {}
+
+    uint32_t num_calls_;
+    uint32_t ssrc_;
+    RtcpStatistics stats_;
+  } callback;
+
+  receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
+
+  // Add some arbitrary data, with loss and jitter.
+  header1_.sequenceNumber = 1;
+  clock_.AdvanceTimeMilliseconds(7);
+  header1_.timestamp += 3;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  header1_.sequenceNumber += 2;
+  clock_.AdvanceTimeMilliseconds(9);
+  header1_.timestamp += 9;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  --header1_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(13);
+  header1_.timestamp += 47;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, true);
+  header1_.sequenceNumber += 3;
+  clock_.AdvanceTimeMilliseconds(11);
+  header1_.timestamp += 17;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+
+  EXPECT_EQ(0u, callback.num_calls_);
+
+  // Call GetStatistics, simulating a timed rtcp sender thread.
+  RtcpStatistics statistics;
+  receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+                                                              true);
+
+  EXPECT_EQ(1u, callback.num_calls_);
+  EXPECT_EQ(callback.ssrc_, kSsrc1);
+  EXPECT_EQ(statistics.packets_lost, callback.stats_.packets_lost);
+  EXPECT_EQ(statistics.extended_highest_sequence_number,
+            callback.stats_.extended_highest_sequence_number);
+  EXPECT_EQ(statistics.fraction_lost, callback.stats_.fraction_lost);
+  EXPECT_EQ(statistics.jitter, callback.stats_.jitter);
+  EXPECT_EQ(51, statistics.fraction_lost);
+  EXPECT_EQ(1, statistics.packets_lost);
+  EXPECT_EQ(5u, statistics.extended_highest_sequence_number);
+  EXPECT_EQ(4u, statistics.jitter);
+
+  receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
+
+  // Add some more data.
+  header1_.sequenceNumber = 1;
+  clock_.AdvanceTimeMilliseconds(7);
+  header1_.timestamp += 3;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  header1_.sequenceNumber += 2;
+  clock_.AdvanceTimeMilliseconds(9);
+  header1_.timestamp += 9;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  --header1_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(13);
+  header1_.timestamp += 47;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, true);
+  header1_.sequenceNumber += 3;
+  clock_.AdvanceTimeMilliseconds(11);
+  header1_.timestamp += 17;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
+  ++header1_.sequenceNumber;
+
+  receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(&statistics,
+                                                              true);
+
+  // Should not have been called after deregister.
+  EXPECT_EQ(1u, callback.num_calls_);
+}
+
+class RtpTestCallback : public StreamDataCountersCallback {
+ public:
+  RtpTestCallback()
+      : StreamDataCountersCallback(), num_calls_(0), ssrc_(0), stats_() {}
+  ~RtpTestCallback() override = default;
+
+  void DataCountersUpdated(const StreamDataCounters& counters,
+                           uint32_t ssrc) override {
+    ssrc_ = ssrc;
+    stats_ = counters;
+    ++num_calls_;
+  }
+
+  void MatchPacketCounter(const RtpPacketCounter& expected,
+                          const RtpPacketCounter& actual) {
+    EXPECT_EQ(expected.payload_bytes, actual.payload_bytes);
+    EXPECT_EQ(expected.header_bytes, actual.header_bytes);
+    EXPECT_EQ(expected.padding_bytes, actual.padding_bytes);
+    EXPECT_EQ(expected.packets, actual.packets);
+  }
+
+  void Matches(uint32_t num_calls,
+               uint32_t ssrc,
+               const StreamDataCounters& expected) {
+    EXPECT_EQ(num_calls, num_calls_);
+    EXPECT_EQ(ssrc, ssrc_);
+    MatchPacketCounter(expected.transmitted, stats_.transmitted);
+    MatchPacketCounter(expected.retransmitted, stats_.retransmitted);
+    MatchPacketCounter(expected.fec, stats_.fec);
+  }
+
+  uint32_t num_calls_;
+  uint32_t ssrc_;
+  StreamDataCounters stats_;
+};
+
+TEST_F(ReceiveStatisticsTest, RtpCallbacks) {
+  RtpTestCallback callback;
+  receive_statistics_->RegisterRtpStatisticsCallback(&callback);
+
+  const size_t kHeaderLength = 20;
+  const size_t kPaddingLength = 9;
+
+  // One packet of size kPacketSize1.
+  header1_.headerLength = kHeaderLength;
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
+                                      false);
+  StreamDataCounters expected;
+  expected.transmitted.payload_bytes = kPacketSize1;
+  expected.transmitted.header_bytes = kHeaderLength;
+  expected.transmitted.padding_bytes = 0;
+  expected.transmitted.packets = 1;
+  expected.retransmitted.payload_bytes = 0;
+  expected.retransmitted.header_bytes = 0;
+  expected.retransmitted.padding_bytes = 0;
+  expected.retransmitted.packets = 0;
+  expected.fec.packets = 0;
+  callback.Matches(1, kSsrc1, expected);
+
+  ++header1_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(5);
+  header1_.paddingLength = 9;
+  // Another packet of size kPacketSize1 with 9 bytes padding.
+  receive_statistics_->IncomingPacket(
+      header1_, kPacketSize1 + kHeaderLength + kPaddingLength, false);
+  expected.transmitted.payload_bytes = kPacketSize1 * 2;
+  expected.transmitted.header_bytes = kHeaderLength * 2;
+  expected.transmitted.padding_bytes = kPaddingLength;
+  expected.transmitted.packets = 2;
+  callback.Matches(2, kSsrc1, expected);
+
+  clock_.AdvanceTimeMilliseconds(5);
+  // Retransmit last packet.
+  receive_statistics_->IncomingPacket(
+      header1_, kPacketSize1 + kHeaderLength + kPaddingLength, true);
+  expected.transmitted.payload_bytes = kPacketSize1 * 3;
+  expected.transmitted.header_bytes = kHeaderLength * 3;
+  expected.transmitted.padding_bytes = kPaddingLength * 2;
+  expected.transmitted.packets = 3;
+  expected.retransmitted.payload_bytes = kPacketSize1;
+  expected.retransmitted.header_bytes = kHeaderLength;
+  expected.retransmitted.padding_bytes = kPaddingLength;
+  expected.retransmitted.packets = 1;
+  callback.Matches(3, kSsrc1, expected);
+
+  header1_.paddingLength = 0;
+  ++header1_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(5);
+  // One FEC packet.
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
+                                      false);
+  receive_statistics_->FecPacketReceived(header1_,
+                                         kPacketSize1 + kHeaderLength);
+  expected.transmitted.payload_bytes = kPacketSize1 * 4;
+  expected.transmitted.header_bytes = kHeaderLength * 4;
+  expected.transmitted.packets = 4;
+  expected.fec.payload_bytes = kPacketSize1;
+  expected.fec.header_bytes = kHeaderLength;
+  expected.fec.packets = 1;
+  callback.Matches(5, kSsrc1, expected);
+
+  receive_statistics_->RegisterRtpStatisticsCallback(NULL);
+
+  // New stats, but callback should not be called.
+  ++header1_.sequenceNumber;
+  clock_.AdvanceTimeMilliseconds(5);
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
+                                      true);
+  callback.Matches(5, kSsrc1, expected);
+}
+
+TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) {
+  RtpTestCallback callback;
+  receive_statistics_->RegisterRtpStatisticsCallback(&callback);
+
+  const uint32_t kHeaderLength = 20;
+  header1_.headerLength = kHeaderLength;
+
+  // If first packet is FEC, ignore it.
+  receive_statistics_->FecPacketReceived(header1_,
+                                         kPacketSize1 + kHeaderLength);
+  EXPECT_EQ(0u, callback.num_calls_);
+
+  receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
+                                      false);
+  StreamDataCounters expected;
+  expected.transmitted.payload_bytes = kPacketSize1;
+  expected.transmitted.header_bytes = kHeaderLength;
+  expected.transmitted.padding_bytes = 0;
+  expected.transmitted.packets = 1;
+  expected.fec.packets = 0;
+  callback.Matches(1, kSsrc1, expected);
+
+  receive_statistics_->FecPacketReceived(header1_,
+                                         kPacketSize1 + kHeaderLength);
+  expected.fec.payload_bytes = kPacketSize1;
+  expected.fec.header_bytes = kHeaderLength;
+  expected.fec.packets = 1;
+  callback.Matches(2, kSsrc1, expected);
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc b/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
new file mode 100644
index 0000000..fc867a4
--- /dev/null
+++ b/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/remote_ntp_time_estimator.h"
+
+#include "rtc_base/logging.h"
+#include "rtc_base/time/timestamp_extrapolator.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+namespace {
+static const int kTimingLogIntervalMs = 10000;
+static const int kClocksOffsetSmoothingWindow = 100;
+
+}  // namespace
+
+// TODO(wu): Refactor this class so that it can be shared with
+// vie_sync_module.cc.
+RemoteNtpTimeEstimator::RemoteNtpTimeEstimator(Clock* clock)
+    : clock_(clock),
+      ntp_clocks_offset_estimator_(kClocksOffsetSmoothingWindow),
+      last_timing_log_ms_(-1) {}
+
+RemoteNtpTimeEstimator::~RemoteNtpTimeEstimator() {}
+
+bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
+                                                 uint32_t ntp_secs,
+                                                 uint32_t ntp_frac,
+                                                 uint32_t rtcp_timestamp) {
+  bool new_rtcp_sr = false;
+  if (!rtp_to_ntp_.UpdateMeasurements(ntp_secs, ntp_frac, rtcp_timestamp,
+                                      &new_rtcp_sr)) {
+    return false;
+  }
+  if (!new_rtcp_sr) {
+    // No new RTCP SR since last time this function was called.
+    return true;
+  }
+
+  // Update extrapolator with the new arrival time.
+  // The extrapolator assumes the TimeInMilliseconds time.
+  int64_t receiver_arrival_time_ms = clock_->TimeInMilliseconds();
+  int64_t sender_send_time_ms = Clock::NtpToMs(ntp_secs, ntp_frac);
+  int64_t sender_arrival_time_ms = sender_send_time_ms + rtt / 2;
+  int64_t remote_to_local_clocks_offset =
+      receiver_arrival_time_ms - sender_arrival_time_ms;
+  ntp_clocks_offset_estimator_.Insert(remote_to_local_clocks_offset);
+  return true;
+}
+
+int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) {
+  int64_t sender_capture_ntp_ms = 0;
+  if (!rtp_to_ntp_.Estimate(rtp_timestamp, &sender_capture_ntp_ms)) {
+    return -1;
+  }
+
+  int64_t remote_to_local_clocks_offset =
+      ntp_clocks_offset_estimator_.GetFilteredValue();
+  int64_t receiver_capture_ms =
+      sender_capture_ntp_ms + remote_to_local_clocks_offset;
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t ntp_offset = clock_->CurrentNtpInMilliseconds() - now_ms;
+  int64_t receiver_capture_ntp_ms = receiver_capture_ms + ntp_offset;
+
+  if (now_ms - last_timing_log_ms_ > kTimingLogIntervalMs) {
+    RTC_LOG(LS_INFO) << "RTP timestamp: " << rtp_timestamp
+                     << " in NTP clock: " << sender_capture_ntp_ms
+                     << " estimated time in receiver clock: "
+                     << receiver_capture_ms
+                     << " converted to NTP clock: " << receiver_capture_ntp_ms;
+    last_timing_log_ms_ = now_ms;
+  }
+  return receiver_capture_ntp_ms;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc b/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc
new file mode 100644
index 0000000..5254cd5
--- /dev/null
+++ b/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc
@@ -0,0 +1,147 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/remote_ntp_time_estimator.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+namespace webrtc {
+
+static const int64_t kTestRtt = 10;
+static const int64_t kLocalClockInitialTimeMs = 123;
+static const int64_t kRemoteClockInitialTimeMs = 345;
+static const uint32_t kTimestampOffset = 567;
+
+class RemoteNtpTimeEstimatorTest : public ::testing::Test {
+ protected:
+  RemoteNtpTimeEstimatorTest()
+      : local_clock_(kLocalClockInitialTimeMs * 1000),
+        remote_clock_(kRemoteClockInitialTimeMs * 1000),
+        estimator_(new RemoteNtpTimeEstimator(&local_clock_)) {}
+  ~RemoteNtpTimeEstimatorTest() override = default;
+
+  void AdvanceTimeMilliseconds(int64_t ms) {
+    local_clock_.AdvanceTimeMilliseconds(ms);
+    remote_clock_.AdvanceTimeMilliseconds(ms);
+  }
+
+  uint32_t GetRemoteTimestamp() {
+    return static_cast<uint32_t>(remote_clock_.TimeInMilliseconds()) * 90 +
+           kTimestampOffset;
+  }
+
+  void SendRtcpSr() {
+    uint32_t rtcp_timestamp = GetRemoteTimestamp();
+    NtpTime ntp = remote_clock_.CurrentNtpTime();
+
+    AdvanceTimeMilliseconds(kTestRtt / 2);
+    ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions());
+  }
+
+  void SendRtcpSrInaccurately(int64_t ntp_error_ms,
+                              int64_t networking_delay_ms) {
+    uint32_t rtcp_timestamp = GetRemoteTimestamp();
+    int64_t ntp_error_fractions =
+        ntp_error_ms * NtpTime::kFractionsPerSecond / 1000;
+    NtpTime ntp(static_cast<uint64_t>(remote_clock_.CurrentNtpTime()) +
+                ntp_error_fractions);
+    AdvanceTimeMilliseconds(kTestRtt / 2 + networking_delay_ms);
+    ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions());
+  }
+
+  void UpdateRtcpTimestamp(int64_t rtt,
+                           uint32_t ntp_secs,
+                           uint32_t ntp_frac,
+                           uint32_t rtp_timestamp,
+                           bool expected_result) {
+    EXPECT_EQ(expected_result, estimator_->UpdateRtcpTimestamp(
+                                   rtt, ntp_secs, ntp_frac, rtp_timestamp));
+  }
+
+  void ReceiveRtcpSr(int64_t rtt,
+                     uint32_t rtcp_timestamp,
+                     uint32_t ntp_seconds,
+                     uint32_t ntp_fractions) {
+    UpdateRtcpTimestamp(rtt, ntp_seconds, ntp_fractions, rtcp_timestamp, true);
+  }
+
+  SimulatedClock local_clock_;
+  SimulatedClock remote_clock_;
+  std::unique_ptr<RemoteNtpTimeEstimator> estimator_;
+};
+
+TEST_F(RemoteNtpTimeEstimatorTest, Estimate) {
+  // Failed without valid NTP.
+  UpdateRtcpTimestamp(kTestRtt, 0, 0, 0, false);
+
+  AdvanceTimeMilliseconds(1000);
+  // Remote peer sends first RTCP SR.
+  SendRtcpSr();
+
+  // Remote sends a RTP packet.
+  AdvanceTimeMilliseconds(15);
+  uint32_t rtp_timestamp = GetRemoteTimestamp();
+  int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
+
+  // Local peer needs at least 2 RTCP SR to calculate the capture time.
+  const int64_t kNotEnoughRtcpSr = -1;
+  EXPECT_EQ(kNotEnoughRtcpSr, estimator_->Estimate(rtp_timestamp));
+
+  AdvanceTimeMilliseconds(800);
+  // Remote sends second RTCP SR.
+  SendRtcpSr();
+
+  // Local peer gets enough RTCP SR to calculate the capture time.
+  EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
+}
+
+TEST_F(RemoteNtpTimeEstimatorTest, AveragesErrorsOut) {
+  // Remote peer sends first 5 RTCP SR without errors.
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSr();
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSr();
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSr();
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSr();
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSr();
+
+  AdvanceTimeMilliseconds(15);
+  uint32_t rtp_timestamp = GetRemoteTimestamp();
+  int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
+
+  // Local peer gets enough RTCP SR to calculate the capture time.
+  EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
+
+  // Remote sends corrupted RTCP SRs
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSrInaccurately(10, 10);
+  AdvanceTimeMilliseconds(1000);
+  SendRtcpSrInaccurately(-20, 5);
+
+  // New RTP packet to estimate timestamp.
+  AdvanceTimeMilliseconds(150);
+  rtp_timestamp = GetRemoteTimestamp();
+  capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
+
+  // Errors should be averaged out.
+  EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_nack_stats.cc b/modules/rtp_rtcp/source/rtcp_nack_stats.cc
new file mode 100644
index 0000000..24b7085
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_nack_stats.cc
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_nack_stats.h"
+
+#include "modules/include/module_common_types.h"
+
+namespace webrtc {
+
+RtcpNackStats::RtcpNackStats()
+    : max_sequence_number_(0), requests_(0), unique_requests_(0) {}
+
+void RtcpNackStats::ReportRequest(uint16_t sequence_number) {
+  if (requests_ == 0 ||
+      IsNewerSequenceNumber(sequence_number, max_sequence_number_)) {
+    max_sequence_number_ = sequence_number;
+    ++unique_requests_;
+  }
+  ++requests_;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_nack_stats.h b/modules/rtp_rtcp/source/rtcp_nack_stats.h
new file mode 100644
index 0000000..9da4351
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_nack_stats.h
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_NACK_STATS_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_NACK_STATS_H_
+
+#include <stdint.h>
+
+namespace webrtc {
+
+class RtcpNackStats {
+ public:
+  RtcpNackStats();
+
+  // Updates stats with requested sequence number.
+  // This function should be called for each NACK request to calculate the
+  // number of unique NACKed RTP packets.
+  void ReportRequest(uint16_t sequence_number);
+
+  // Gets the number of NACKed RTP packets.
+  uint32_t requests() const { return requests_; }
+
+  // Gets the number of unique NACKed RTP packets.
+  uint32_t unique_requests() const { return unique_requests_; }
+
+ private:
+  uint16_t max_sequence_number_;
+  uint32_t requests_;
+  uint32_t unique_requests_;
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_NACK_STATS_H_
diff --git a/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc b/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc
new file mode 100644
index 0000000..1c30173
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_nack_stats_unittest.cc
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_nack_stats.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(RtcpNackStatsTest, Requests) {
+  RtcpNackStats stats;
+  EXPECT_EQ(0U, stats.unique_requests());
+  EXPECT_EQ(0U, stats.requests());
+  stats.ReportRequest(10);
+  EXPECT_EQ(1U, stats.unique_requests());
+  EXPECT_EQ(1U, stats.requests());
+
+  stats.ReportRequest(10);
+  EXPECT_EQ(1U, stats.unique_requests());
+  stats.ReportRequest(11);
+  EXPECT_EQ(2U, stats.unique_requests());
+
+  stats.ReportRequest(11);
+  EXPECT_EQ(2U, stats.unique_requests());
+  stats.ReportRequest(13);
+  EXPECT_EQ(3U, stats.unique_requests());
+
+  stats.ReportRequest(11);
+  EXPECT_EQ(3U, stats.unique_requests());
+  EXPECT_EQ(6U, stats.requests());
+}
+
+TEST(RtcpNackStatsTest, RequestsWithWrap) {
+  RtcpNackStats stats;
+  stats.ReportRequest(65534);
+  EXPECT_EQ(1U, stats.unique_requests());
+
+  stats.ReportRequest(65534);
+  EXPECT_EQ(1U, stats.unique_requests());
+  stats.ReportRequest(65535);
+  EXPECT_EQ(2U, stats.unique_requests());
+
+  stats.ReportRequest(65535);
+  EXPECT_EQ(2U, stats.unique_requests());
+  stats.ReportRequest(0);
+  EXPECT_EQ(3U, stats.unique_requests());
+
+  stats.ReportRequest(65535);
+  EXPECT_EQ(3U, stats.unique_requests());
+  stats.ReportRequest(0);
+  EXPECT_EQ(3U, stats.unique_requests());
+  stats.ReportRequest(1);
+  EXPECT_EQ(4U, stats.unique_requests());
+  EXPECT_EQ(8U, stats.requests());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet.cc b/modules/rtp_rtcp/source/rtcp_packet.cc
new file mode 100644
index 0000000..194b992
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -0,0 +1,87 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr size_t RtcpPacket::kHeaderLength;
+
+rtc::Buffer RtcpPacket::Build() const {
+  rtc::Buffer packet(BlockLength());
+
+  size_t length = 0;
+  bool created = Create(packet.data(), &length, packet.capacity(), nullptr);
+  RTC_DCHECK(created) << "Invalid packet is not supported.";
+  RTC_DCHECK_EQ(length, packet.size())
+      << "BlockLength mispredicted size used by Create";
+
+  return packet;
+}
+
+bool RtcpPacket::Build(size_t max_length, PacketReadyCallback callback) const {
+  RTC_CHECK_LE(max_length, IP_PACKET_SIZE);
+  uint8_t buffer[IP_PACKET_SIZE];
+  size_t index = 0;
+  if (!Create(buffer, &index, max_length, callback))
+    return false;
+  return OnBufferFull(buffer, &index, callback);
+}
+
+bool RtcpPacket::OnBufferFull(uint8_t* packet,
+                              size_t* index,
+                              PacketReadyCallback callback) const {
+  if (*index == 0)
+    return false;
+  RTC_DCHECK(callback) << "Fragmentation not supported.";
+  callback(rtc::ArrayView<const uint8_t>(packet, *index));
+  *index = 0;
+  return true;
+}
+
+size_t RtcpPacket::HeaderLength() const {
+  size_t length_in_bytes = BlockLength();
+  RTC_DCHECK_GT(length_in_bytes, 0);
+  RTC_DCHECK_EQ(length_in_bytes % 4, 0) << "Padding not supported";
+  // Length in 32-bit words without common header.
+  return (length_in_bytes - kHeaderLength) / 4;
+}
+
+// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
+//
+// RTP header format.
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P| RC/FMT  |      PT       |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+void RtcpPacket::CreateHeader(
+    size_t count_or_format,  // Depends on packet type.
+    uint8_t packet_type,
+    size_t length,
+    uint8_t* buffer,
+    size_t* pos) {
+  RTC_DCHECK_LE(length, 0xffffU);
+  RTC_DCHECK_LE(count_or_format, 0x1f);
+  constexpr uint8_t kVersionBits = 2 << 6;
+  constexpr uint8_t kNoPaddingBit = 0 << 5;
+  buffer[*pos + 0] =
+      kVersionBits | kNoPaddingBit | static_cast<uint8_t>(count_or_format);
+  buffer[*pos + 1] = packet_type;
+  buffer[*pos + 2] = (length >> 8) & 0xff;
+  buffer[*pos + 3] = length & 0xff;
+  *pos += kHeaderLength;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet.h b/modules/rtp_rtcp/source/rtcp_packet.h
new file mode 100644
index 0000000..11037cb
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet.h
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_
+
+#include "rtc_base/buffer.h"
+#include "rtc_base/function_view.h"
+
+namespace webrtc {
+namespace rtcp {
+// Class for building RTCP packets.
+//
+//  Example:
+//  ReportBlock report_block;
+//  report_block.SetMediaSsrc(234);
+//  report_block.SetFractionLost(10);
+//
+//  ReceiverReport rr;
+//  rr.SetSenderSsrc(123);
+//  rr.AddReportBlock(report_block);
+//
+//  Fir fir;
+//  fir.SetSenderSsrc(123);
+//  fir.AddRequestTo(234, 56);
+//
+//  size_t length = 0;                     // Builds an intra frame request
+//  uint8_t packet[kPacketSize];           // with sequence number 56.
+//  fir.Build(packet, &length, kPacketSize);
+//
+//  rtc::Buffer packet = fir.Build();      // Returns a RawPacket holding
+//                                         // the built rtcp packet.
+//
+//  CompoundPacket compound;               // Builds a compound RTCP packet with
+//  compound.Append(&rr);                  // a receiver report, report block
+//  compound.Append(&fir);                 // and fir message.
+//  rtc::Buffer packet = compound.Build();
+
+class RtcpPacket {
+ public:
+  // Callback used to signal that an RTCP packet is ready. Note that this may
+  // not contain all data in this RtcpPacket; if a packet cannot fit in
+  // max_length bytes, it will be fragmented and multiple calls to this
+  // callback will be made.
+  using PacketReadyCallback =
+      rtc::FunctionView<void(rtc::ArrayView<const uint8_t> packet)>;
+
+  virtual ~RtcpPacket() {}
+
+  // Convenience method mostly used for test. Creates packet without
+  // fragmentation using BlockLength() to allocate big enough buffer.
+  rtc::Buffer Build() const;
+
+  // Returns true if call to Create succeeded.
+  bool Build(size_t max_length, PacketReadyCallback callback) const;
+
+  // Size of this packet in bytes (including headers).
+  virtual size_t BlockLength() const = 0;
+
+  // Creates packet in the given buffer at the given position.
+  // Calls PacketReadyCallback::OnPacketReady if remaining buffer is too small
+  // and assume buffer can be reused after OnPacketReady returns.
+  virtual bool Create(uint8_t* packet,
+                      size_t* index,
+                      size_t max_length,
+                      PacketReadyCallback callback) const = 0;
+
+ protected:
+  // Size of the rtcp common header.
+  static constexpr size_t kHeaderLength = 4;
+  RtcpPacket() {}
+
+  static void CreateHeader(size_t count_or_format,
+                           uint8_t packet_type,
+                           size_t block_length,  // Payload size in 32bit words.
+                           uint8_t* buffer,
+                           size_t* pos);
+
+  bool OnBufferFull(uint8_t* packet,
+                    size_t* index,
+                    PacketReadyCallback callback) const;
+  // Size of the rtcp packet as written in header.
+  size_t HeaderLength() const;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/app.cc b/modules/rtp_rtcp/source/rtcp_packet/app.cc
new file mode 100644
index 0000000..4e21bc9
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/app.cc
@@ -0,0 +1,97 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t App::kPacketType;
+constexpr size_t App::kMaxDataSize;
+// Application-Defined packet (APP) (RFC 3550).
+//
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |V=2|P| subtype |   PT=APP=204  |             length            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |                           SSRC/CSRC                           |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                          name (ASCII)                         |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |                   application-dependent data                ...
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+App::App() : sub_type_(0), ssrc_(0), name_(0) {}
+
+App::~App() = default;
+
+bool App::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  if (packet.payload_size_bytes() < kAppBaseLength) {
+    RTC_LOG(LS_WARNING) << "Packet is too small to be a valid APP packet";
+    return false;
+  }
+  if (packet.payload_size_bytes() % 4 != 0) {
+    RTC_LOG(LS_WARNING)
+        << "Packet payload must be 32 bits aligned to make a valid APP packet";
+    return false;
+  }
+  sub_type_ = packet.fmt();
+  ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&packet.payload()[0]);
+  name_ = ByteReader<uint32_t>::ReadBigEndian(&packet.payload()[4]);
+  data_.SetData(packet.payload() + kAppBaseLength,
+                packet.payload_size_bytes() - kAppBaseLength);
+  return true;
+}
+
+void App::SetSubType(uint8_t subtype) {
+  RTC_DCHECK_LE(subtype, 0x1f);
+  sub_type_ = subtype;
+}
+
+void App::SetData(const uint8_t* data, size_t data_length) {
+  RTC_DCHECK(data);
+  RTC_DCHECK_EQ(data_length % 4, 0) << "Data must be 32 bits aligned.";
+  RTC_DCHECK_LE(data_length, kMaxDataSize)
+      << "App data size " << data_length << " exceed maximum of "
+      << kMaxDataSize << " bytes.";
+  data_.SetData(data, data_length);
+}
+
+size_t App::BlockLength() const {
+  return kHeaderLength + kAppBaseLength + data_.size();
+}
+
+bool App::Create(uint8_t* packet,
+                 size_t* index,
+                 size_t max_length,
+                 PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+  CreateHeader(sub_type_, kPacketType, HeaderLength(), packet, index);
+
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], ssrc_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], name_);
+  memcpy(&packet[*index + 8], data_.data(), data_.size());
+  *index += (8 + data_.size());
+  RTC_DCHECK_EQ(index_end, *index);
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/app.h b/modules/rtp_rtcp/source/rtcp_packet/app.h
new file mode 100644
index 0000000..19a97e0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/app.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "rtc_base/buffer.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class App : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 204;
+  App();
+  ~App() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void SetSsrc(uint32_t ssrc) { ssrc_ = ssrc; }
+  void SetSubType(uint8_t subtype);
+  void SetName(uint32_t name) { name_ = name; }
+  void SetData(const uint8_t* data, size_t data_length);
+
+  uint8_t sub_type() const { return sub_type_; }
+  uint32_t ssrc() const { return ssrc_; }
+  uint32_t name() const { return name_; }
+  size_t data_size() const { return data_.size(); }
+  const uint8_t* data() const { return data_.data(); }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr size_t kAppBaseLength = 8;  // Ssrc and Name.
+  static constexpr size_t kMaxDataSize = 0xffff * 4 - kAppBaseLength;
+
+  uint8_t sub_type_;
+  uint32_t ssrc_;
+  uint32_t name_;
+  rtc::Buffer data_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_APP_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc
new file mode 100644
index 0000000..59356e5
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/app_unittest.cc
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+using ::testing::make_tuple;
+using ::webrtc::rtcp::App;
+
+constexpr uint32_t kName = ((uint32_t)'n' << 24) | ((uint32_t)'a' << 16) |
+                           ((uint32_t)'m' << 8) | (uint32_t)'e';
+constexpr uint8_t kSubtype = 0x1e;
+constexpr uint32_t kSenderSsrc = 0x12345678;
+constexpr uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
+constexpr uint8_t kVersionBits = 2 << 6;
+constexpr uint8_t kPaddingBit = 1 << 5;
+// clang-format off
+constexpr uint8_t kPacketWithoutData[] = {
+    kVersionBits | kSubtype, App::kPacketType, 0x00, 0x02,
+    0x12, 0x34, 0x56, 0x78,
+    'n',  'a',  'm',  'e'};
+constexpr uint8_t kPacketWithData[] = {
+    kVersionBits | kSubtype, App::kPacketType, 0x00, 0x04,
+    0x12, 0x34, 0x56, 0x78,
+    'n',  'a',  'm',  'e',
+    't',  'e',  's',  't',
+    'd',  'a',  't',  'a'};
+constexpr uint8_t kTooSmallPacket[] = {
+    kVersionBits | kSubtype, App::kPacketType, 0x00, 0x01,
+    0x12, 0x34, 0x56, 0x78};
+constexpr uint8_t kPaddingSize = 1;
+constexpr uint8_t kPacketWithUnalignedPayload[] = {
+    kVersionBits | kPaddingBit | kSubtype, App::kPacketType, 0x00, 0x03,
+    0x12, 0x34, 0x56, 0x78,
+     'n',  'a',  'm',  'e',
+     'd',  'a',  't', kPaddingSize};
+// clang-format on
+}  // namespace
+
+TEST(RtcpPacketAppTest, CreateWithoutData) {
+  App app;
+  app.SetSsrc(kSenderSsrc);
+  app.SetSubType(kSubtype);
+  app.SetName(kName);
+
+  rtc::Buffer raw = app.Build();
+
+  EXPECT_THAT(make_tuple(raw.data(), raw.size()),
+              ElementsAreArray(kPacketWithoutData));
+}
+
+TEST(RtcpPacketAppTest, ParseWithoutData) {
+  App parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacketWithoutData, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.ssrc());
+  EXPECT_EQ(kSubtype, parsed.sub_type());
+  EXPECT_EQ(kName, parsed.name());
+  EXPECT_EQ(0u, parsed.data_size());
+}
+
+TEST(RtcpPacketAppTest, CreateWithData) {
+  App app;
+  app.SetSsrc(kSenderSsrc);
+  app.SetSubType(kSubtype);
+  app.SetName(kName);
+  app.SetData(kData, sizeof(kData));
+
+  rtc::Buffer raw = app.Build();
+
+  EXPECT_THAT(make_tuple(raw.data(), raw.size()),
+              ElementsAreArray(kPacketWithData));
+}
+
+TEST(RtcpPacketAppTest, ParseWithData) {
+  App parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacketWithData, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.ssrc());
+  EXPECT_EQ(kSubtype, parsed.sub_type());
+  EXPECT_EQ(kName, parsed.name());
+  EXPECT_THAT(make_tuple(parsed.data(), parsed.data_size()),
+              ElementsAreArray(kData));
+}
+
+TEST(RtcpPacketAppTest, ParseFailsOnTooSmallPacket) {
+  App parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed));
+}
+
+TEST(RtcpPacketAppTest, ParseFailsOnUnalignedPayload) {
+  App parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kPacketWithUnalignedPayload, &parsed));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/bye.cc b/modules/rtp_rtcp/source/rtcp_packet/bye.cc
new file mode 100644
index 0000000..0e2eb9e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/bye.cc
@@ -0,0 +1,137 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Bye::kPacketType;
+// Bye packet (BYE) (RFC 3550).
+//
+//        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//       |V=2|P|    SC   |   PT=BYE=203  |             length            |
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//       |                           SSRC/CSRC                           |
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//       :                              ...                              :
+//       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// (opt) |     length    |               reason for leaving            ...
+//       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+Bye::Bye() : sender_ssrc_(0) {}
+
+Bye::~Bye() = default;
+
+bool Bye::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+
+  const uint8_t src_count = packet.count();
+  // Validate packet.
+  if (packet.payload_size_bytes() < 4u * src_count) {
+    RTC_LOG(LS_WARNING)
+        << "Packet is too small to contain CSRCs it promise to have.";
+    return false;
+  }
+  const uint8_t* const payload = packet.payload();
+  bool has_reason = packet.payload_size_bytes() > 4u * src_count;
+  uint8_t reason_length = 0;
+  if (has_reason) {
+    reason_length = payload[4u * src_count];
+    if (packet.payload_size_bytes() - 4u * src_count < 1u + reason_length) {
+      RTC_LOG(LS_WARNING) << "Invalid reason length: " << reason_length;
+      return false;
+    }
+  }
+  // Once sure packet is valid, copy values.
+  if (src_count == 0) {  // A count value of zero is valid, but useless.
+    sender_ssrc_ = 0;
+    csrcs_.clear();
+  } else {
+    sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload);
+    csrcs_.resize(src_count - 1);
+    for (size_t i = 1; i < src_count; ++i)
+      csrcs_[i - 1] = ByteReader<uint32_t>::ReadBigEndian(&payload[4 * i]);
+  }
+
+  if (has_reason) {
+    reason_.assign(reinterpret_cast<const char*>(&payload[4u * src_count + 1]),
+                   reason_length);
+  } else {
+    reason_.clear();
+  }
+
+  return true;
+}
+
+bool Bye::Create(uint8_t* packet,
+                 size_t* index,
+                 size_t max_length,
+                 PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+
+  CreateHeader(1 + csrcs_.size(), kPacketType, HeaderLength(), packet, index);
+  // Store srcs of the leaving clients.
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], sender_ssrc_);
+  *index += sizeof(uint32_t);
+  for (uint32_t csrc : csrcs_) {
+    ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], csrc);
+    *index += sizeof(uint32_t);
+  }
+  // Store the reason to leave.
+  if (!reason_.empty()) {
+    uint8_t reason_length = static_cast<uint8_t>(reason_.size());
+    packet[(*index)++] = reason_length;
+    memcpy(&packet[*index], reason_.data(), reason_length);
+    *index += reason_length;
+    // Add padding bytes if needed.
+    size_t bytes_to_pad = index_end - *index;
+    RTC_DCHECK_LE(bytes_to_pad, 3);
+    if (bytes_to_pad > 0) {
+      memset(&packet[*index], 0, bytes_to_pad);
+      *index += bytes_to_pad;
+    }
+  }
+  RTC_DCHECK_EQ(index_end, *index);
+  return true;
+}
+
+bool Bye::SetCsrcs(std::vector<uint32_t> csrcs) {
+  if (csrcs.size() > kMaxNumberOfCsrcs) {
+    RTC_LOG(LS_WARNING) << "Too many CSRCs for Bye packet.";
+    return false;
+  }
+  csrcs_ = std::move(csrcs);
+  return true;
+}
+
+void Bye::SetReason(std::string reason) {
+  RTC_DCHECK_LE(reason.size(), 0xffu);
+  reason_ = std::move(reason);
+}
+
+size_t Bye::BlockLength() const {
+  size_t src_count = (1 + csrcs_.size());
+  size_t reason_size_in_32bits = reason_.empty() ? 0 : (reason_.size() / 4 + 1);
+  return kHeaderLength + 4 * (src_count + reason_size_in_32bits);
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/bye.h b/modules/rtp_rtcp/source/rtcp_packet/bye.h
new file mode 100644
index 0000000..0a6555e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/bye.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_
+
+#include <string>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class Bye : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 203;
+
+  Bye();
+  ~Bye() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+  bool SetCsrcs(std::vector<uint32_t> csrcs);
+  void SetReason(std::string reason);
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  const std::vector<uint32_t>& csrcs() const { return csrcs_; }
+  const std::string& reason() const { return reason_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static const int kMaxNumberOfCsrcs = 0x1f - 1;  // First item is sender SSRC.
+
+  uint32_t sender_ssrc_;
+  std::vector<uint32_t> csrcs_;
+  std::string reason_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc
new file mode 100644
index 0000000..00944b3
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/bye_unittest.cc
@@ -0,0 +1,147 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAre;
+using webrtc::rtcp::Bye;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kCsrc1 = 0x22232425;
+const uint32_t kCsrc2 = 0x33343536;
+}  // namespace
+
+TEST(RtcpPacketByeTest, CreateAndParseWithoutReason) {
+  Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+
+  rtc::Buffer raw = bye.Build();
+  Bye parsed_bye;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye));
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_TRUE(parsed_bye.csrcs().empty());
+  EXPECT_TRUE(parsed_bye.reason().empty());
+}
+
+TEST(RtcpPacketByeTest, CreateAndParseWithCsrcs) {
+  Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(bye.SetCsrcs({kCsrc1, kCsrc2}));
+  EXPECT_TRUE(bye.reason().empty());
+
+  rtc::Buffer raw = bye.Build();
+  Bye parsed_bye;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye));
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2));
+  EXPECT_TRUE(parsed_bye.reason().empty());
+}
+
+TEST(RtcpPacketByeTest, CreateAndParseWithCsrcsAndAReason) {
+  Bye bye;
+  const std::string kReason = "Some Reason";
+
+  bye.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(bye.SetCsrcs({kCsrc1, kCsrc2}));
+  bye.SetReason(kReason);
+
+  rtc::Buffer raw = bye.Build();
+  Bye parsed_bye;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye));
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2));
+  EXPECT_EQ(kReason, parsed_bye.reason());
+}
+
+TEST(RtcpPacketByeTest, CreateWithTooManyCsrcs) {
+  Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+  const int kMaxCsrcs = (1 << 5) - 2;  // 5 bit len, first item is sender SSRC.
+  EXPECT_TRUE(bye.SetCsrcs(std::vector<uint32_t>(kMaxCsrcs, kCsrc1)));
+  EXPECT_FALSE(bye.SetCsrcs(std::vector<uint32_t>(kMaxCsrcs + 1, kCsrc1)));
+}
+
+TEST(RtcpPacketByeTest, CreateAndParseWithAReason) {
+  Bye bye;
+  const std::string kReason = "Some Random Reason";
+
+  bye.SetSenderSsrc(kSenderSsrc);
+  bye.SetReason(kReason);
+
+  rtc::Buffer raw = bye.Build();
+  Bye parsed_bye;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye));
+
+  EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
+  EXPECT_TRUE(parsed_bye.csrcs().empty());
+  EXPECT_EQ(kReason, parsed_bye.reason());
+}
+
+TEST(RtcpPacketByeTest, CreateAndParseWithReasons) {
+  // Test that packet creation/parsing behave with reasons of different length
+  // both when it require padding and when it does not.
+  for (size_t reminder = 0; reminder < 4; ++reminder) {
+    const std::string kReason(4 + reminder, 'a' + reminder);
+    Bye bye;
+    bye.SetSenderSsrc(kSenderSsrc);
+    bye.SetReason(kReason);
+
+    rtc::Buffer raw = bye.Build();
+    Bye parsed_bye;
+    EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed_bye));
+
+    EXPECT_EQ(kReason, parsed_bye.reason());
+  }
+}
+
+TEST(RtcpPacketByeTest, ParseEmptyPacket) {
+  uint8_t kEmptyPacket[] = {0x80, Bye::kPacketType, 0, 0};
+  Bye parsed_bye;
+  EXPECT_TRUE(test::ParseSinglePacket(kEmptyPacket, &parsed_bye));
+  EXPECT_EQ(0u, parsed_bye.sender_ssrc());
+  EXPECT_TRUE(parsed_bye.csrcs().empty());
+  EXPECT_TRUE(parsed_bye.reason().empty());
+}
+
+TEST(RtcpPacketByeTest, ParseFailOnInvalidSrcCount) {
+  Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+
+  rtc::Buffer raw = bye.Build();
+  raw[0]++;  // Damage the packet: increase ssrc count by one.
+
+  Bye parsed_bye;
+  EXPECT_FALSE(test::ParseSinglePacket(raw, &parsed_bye));
+}
+
+TEST(RtcpPacketByeTest, ParseFailOnInvalidReasonLength) {
+  Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+  bye.SetReason("18 characters long");
+
+  rtc::Buffer raw = bye.Build();
+  // Damage the packet: decrease payload size by 4 bytes
+  raw[3]--;
+  raw.SetSize(raw.size() - 4);
+
+  Bye parsed_bye;
+  EXPECT_FALSE(test::ParseSinglePacket(raw, &parsed_bye));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/common_header.cc b/modules/rtp_rtcp/source/rtcp_packet/common_header.cc
new file mode 100644
index 0000000..5b54982
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/common_header.cc
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr size_t CommonHeader::kHeaderSizeBytes;
+//    0                   1           1       2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 |V=2|P|   C/F   |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 1                 |  Packet Type  |
+//   ----------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 2                                 |             length            |
+//   --------------------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Common header for all RTCP packets, 4 octets.
+bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) {
+  const uint8_t kVersion = 2;
+
+  if (size_bytes < kHeaderSizeBytes) {
+    RTC_LOG(LS_WARNING)
+        << "Too little data (" << size_bytes << " byte"
+        << (size_bytes != 1 ? "s" : "")
+        << ") remaining in buffer to parse RTCP header (4 bytes).";
+    return false;
+  }
+
+  uint8_t version = buffer[0] >> 6;
+  if (version != kVersion) {
+    RTC_LOG(LS_WARNING) << "Invalid RTCP header: Version must be "
+                        << static_cast<int>(kVersion) << " but was "
+                        << static_cast<int>(version);
+    return false;
+  }
+
+  bool has_padding = (buffer[0] & 0x20) != 0;
+  count_or_format_ = buffer[0] & 0x1F;
+  packet_type_ = buffer[1];
+  payload_size_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) * 4;
+  payload_ = buffer + kHeaderSizeBytes;
+  padding_size_ = 0;
+
+  if (size_bytes < kHeaderSizeBytes + payload_size_) {
+    RTC_LOG(LS_WARNING) << "Buffer too small (" << size_bytes
+                        << " bytes) to fit an RtcpPacket with a header and "
+                        << payload_size_ << " bytes.";
+    return false;
+  }
+
+  if (has_padding) {
+    if (payload_size_ == 0) {
+      RTC_LOG(LS_WARNING)
+          << "Invalid RTCP header: Padding bit set but 0 payload "
+             "size specified.";
+      return false;
+    }
+
+    padding_size_ = payload_[payload_size_ - 1];
+    if (padding_size_ == 0) {
+      RTC_LOG(LS_WARNING)
+          << "Invalid RTCP header: Padding bit set but 0 padding "
+             "size specified.";
+      return false;
+    }
+    if (padding_size_ > payload_size_) {
+      RTC_LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
+                          << padding_size_ << ") for a packet payload size of "
+                          << payload_size_ << " bytes.";
+      return false;
+    }
+    payload_size_ -= padding_size_;
+  }
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/common_header.h b/modules/rtp_rtcp/source/rtcp_packet/common_header.h
new file mode 100644
index 0000000..5416406
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/common_header.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader {
+ public:
+  static constexpr size_t kHeaderSizeBytes = 4;
+
+  CommonHeader() {}
+  CommonHeader(const CommonHeader&) = default;
+  CommonHeader& operator=(const CommonHeader&) = default;
+
+  bool Parse(const uint8_t* buffer, size_t size_bytes);
+
+  uint8_t type() const { return packet_type_; }
+  // Depending on packet type same header field can be used either as count or
+  // as feedback message type (fmt). Caller expected to know how it is used.
+  uint8_t fmt() const { return count_or_format_; }
+  uint8_t count() const { return count_or_format_; }
+  size_t payload_size_bytes() const { return payload_size_; }
+  const uint8_t* payload() const { return payload_; }
+  size_t packet_size() const {
+    return kHeaderSizeBytes + payload_size_ + padding_size_;
+  }
+  // Returns pointer to the next RTCP packet in compound packet.
+  const uint8_t* NextPacket() const {
+    return payload_ + payload_size_ + padding_size_;
+  }
+
+ private:
+  uint8_t packet_type_ = 0;
+  uint8_t count_or_format_ = 0;
+  uint8_t padding_size_ = 0;
+  uint32_t payload_size_ = 0;
+  const uint8_t* payload_ = nullptr;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc
new file mode 100644
index 0000000..e8b4c52
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/common_header_unittest.cc
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+
+#include "test/gtest.h"
+
+using webrtc::rtcp::CommonHeader;
+
+namespace webrtc {
+
+TEST(RtcpCommonHeaderTest, TooSmallBuffer) {
+  uint8_t buffer[] = {0x80, 0x00, 0x00, 0x00};
+  CommonHeader header;
+  // Buffer needs to be able to hold the header.
+  EXPECT_FALSE(header.Parse(buffer, 0));
+  EXPECT_FALSE(header.Parse(buffer, 1));
+  EXPECT_FALSE(header.Parse(buffer, 2));
+  EXPECT_FALSE(header.Parse(buffer, 3));
+  EXPECT_TRUE(header.Parse(buffer, 4));
+}
+
+TEST(RtcpCommonHeaderTest, Version) {
+  uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00};
+  CommonHeader header;
+  // Version 2 is the only allowed.
+  buffer[0] = 0 << 6;
+  EXPECT_FALSE(header.Parse(buffer, sizeof(buffer)));
+  buffer[0] = 1 << 6;
+  EXPECT_FALSE(header.Parse(buffer, sizeof(buffer)));
+  buffer[0] = 2 << 6;
+  EXPECT_TRUE(header.Parse(buffer, sizeof(buffer)));
+  buffer[0] = 3 << 6;
+  EXPECT_FALSE(header.Parse(buffer, sizeof(buffer)));
+}
+
+TEST(RtcpCommonHeaderTest, PacketSize) {
+  uint8_t buffer[] = {0x80, 0x00, 0x00, 0x02, 0x00, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+  CommonHeader header;
+  EXPECT_FALSE(header.Parse(buffer, sizeof(buffer) - 1));
+  EXPECT_TRUE(header.Parse(buffer, sizeof(buffer)));
+  EXPECT_EQ(8u, header.payload_size_bytes());
+  EXPECT_EQ(buffer + sizeof(buffer), header.NextPacket());
+  EXPECT_EQ(sizeof(buffer), header.packet_size());
+}
+
+TEST(RtcpCommonHeaderTest, PaddingAndPayloadSize) {
+  // Set v = 2, p = 1, but leave fmt, pt as 0.
+  uint8_t buffer[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+  CommonHeader header;
+  // Padding bit set, but no byte for padding (can't specify padding length).
+  EXPECT_FALSE(header.Parse(buffer, 4));
+
+  buffer[3] = 2;  //  Set payload size to 2x32bit.
+  const size_t kPayloadSizeBytes = buffer[3] * 4;
+  const size_t kPaddingAddress =
+      CommonHeader::kHeaderSizeBytes + kPayloadSizeBytes - 1;
+
+  // Padding one byte larger than possible.
+  buffer[kPaddingAddress] = kPayloadSizeBytes + 1;
+  EXPECT_FALSE(header.Parse(buffer, sizeof(buffer)));
+
+  // Invalid zero padding size.
+  buffer[kPaddingAddress] = 0;
+  EXPECT_FALSE(header.Parse(buffer, sizeof(buffer)));
+
+  // Pure padding packet.
+  buffer[kPaddingAddress] = kPayloadSizeBytes;
+  EXPECT_TRUE(header.Parse(buffer, sizeof(buffer)));
+  EXPECT_EQ(0u, header.payload_size_bytes());
+  EXPECT_EQ(buffer + sizeof(buffer), header.NextPacket());
+  EXPECT_EQ(header.payload(), buffer + CommonHeader::kHeaderSizeBytes);
+  EXPECT_EQ(header.packet_size(), sizeof(buffer));
+
+  // Single byte of actual data.
+  buffer[kPaddingAddress] = kPayloadSizeBytes - 1;
+  EXPECT_TRUE(header.Parse(buffer, sizeof(buffer)));
+  EXPECT_EQ(1u, header.payload_size_bytes());
+  EXPECT_EQ(buffer + sizeof(buffer), header.NextPacket());
+  EXPECT_EQ(header.packet_size(), sizeof(buffer));
+}
+
+TEST(RtcpCommonHeaderTest, FormatAndPayloadType) {
+  uint8_t buffer[] = {0x9e, 0xab, 0x00, 0x00};
+  CommonHeader header;
+  EXPECT_TRUE(header.Parse(buffer, sizeof(buffer)));
+
+  EXPECT_EQ(header.count(), 0x1e);
+  EXPECT_EQ(header.fmt(), 0x1e);
+  EXPECT_EQ(header.type(), 0xab);
+  EXPECT_EQ(header.payload_size_bytes(), 0u);
+  EXPECT_EQ(header.payload(), buffer + CommonHeader::kHeaderSizeBytes);
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc b/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc
new file mode 100644
index 0000000..5e76233
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/compound_packet.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rtcp {
+
+CompoundPacket::CompoundPacket() = default;
+
+CompoundPacket::~CompoundPacket() = default;
+
+void CompoundPacket::Append(RtcpPacket* packet) {
+  RTC_CHECK(packet);
+  appended_packets_.push_back(packet);
+}
+
+bool CompoundPacket::Create(uint8_t* packet,
+                            size_t* index,
+                            size_t max_length,
+                            PacketReadyCallback callback) const {
+  for (RtcpPacket* appended : appended_packets_) {
+    if (!appended->Create(packet, index, max_length, callback))
+      return false;
+  }
+  return true;
+}
+
+size_t CompoundPacket::BlockLength() const {
+  size_t block_length = 0;
+  for (RtcpPacket* appended : appended_packets_) {
+    block_length += appended->BlockLength();
+  }
+  return block_length;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h b/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
new file mode 100644
index 0000000..89b7814
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class CompoundPacket : public RtcpPacket {
+ public:
+  CompoundPacket();
+  ~CompoundPacket() override;
+
+  void Append(RtcpPacket* packet);
+
+  // Size of this packet in bytes (i.e. total size of nested packets).
+  size_t BlockLength() const override;
+  // Returns true if all calls to Create succeeded.
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ protected:
+  std::vector<RtcpPacket*> appended_packets_;
+
+ private:
+  RTC_DISALLOW_COPY_AND_ASSIGN(CompoundPacket);
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMPOUND_PACKET_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc
new file mode 100644
index 0000000..02a4f11
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/compound_packet_unittest.cc
@@ -0,0 +1,151 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::MockFunction;
+using webrtc::rtcp::Bye;
+using webrtc::rtcp::CompoundPacket;
+using webrtc::rtcp::Fir;
+using webrtc::rtcp::ReceiverReport;
+using webrtc::rtcp::ReportBlock;
+using webrtc::rtcp::SenderReport;
+using webrtc::test::RtcpPacketParser;
+
+namespace webrtc {
+
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kSeqNo = 13;
+
+TEST(RtcpCompoundPacketTest, AppendPacket) {
+  CompoundPacket compound;
+  Fir fir;
+  fir.AddRequestTo(kRemoteSsrc, kSeqNo);
+  ReportBlock rb;
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(rr.AddReportBlock(rb));
+  compound.Append(&rr);
+  compound.Append(&fir);
+
+  rtc::Buffer packet = compound.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.data(), packet.size());
+  EXPECT_EQ(1, parser.receiver_report()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser.receiver_report()->sender_ssrc());
+  EXPECT_EQ(1u, parser.receiver_report()->report_blocks().size());
+  EXPECT_EQ(1, parser.fir()->num_packets());
+}
+
+TEST(RtcpCompoundPacketTest, AppendPacketWithOwnAppendedPacket) {
+  CompoundPacket root;
+  CompoundPacket leaf;
+  Fir fir;
+  fir.AddRequestTo(kRemoteSsrc, kSeqNo);
+  Bye bye;
+  ReportBlock rb;
+
+  ReceiverReport rr;
+  EXPECT_TRUE(rr.AddReportBlock(rb));
+  leaf.Append(&rr);
+  leaf.Append(&fir);
+
+  SenderReport sr;
+  root.Append(&sr);
+  root.Append(&bye);
+  root.Append(&leaf);
+
+  rtc::Buffer packet = root.Build();
+  RtcpPacketParser parser;
+  parser.Parse(packet.data(), packet.size());
+  EXPECT_EQ(1, parser.sender_report()->num_packets());
+  EXPECT_EQ(1, parser.receiver_report()->num_packets());
+  EXPECT_EQ(1u, parser.receiver_report()->report_blocks().size());
+  EXPECT_EQ(1, parser.bye()->num_packets());
+  EXPECT_EQ(1, parser.fir()->num_packets());
+}
+
+TEST(RtcpCompoundPacketTest, BuildWithInputBuffer) {
+  CompoundPacket compound;
+  Fir fir;
+  fir.AddRequestTo(kRemoteSsrc, kSeqNo);
+  ReportBlock rb;
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(rr.AddReportBlock(rb));
+  compound.Append(&rr);
+  compound.Append(&fir);
+
+  const size_t kRrLength = 8;
+  const size_t kReportBlockLength = 24;
+  const size_t kFirLength = 20;
+
+  const size_t kBufferSize = kRrLength + kReportBlockLength + kFirLength;
+  MockFunction<void(rtc::ArrayView<const uint8_t>)> callback;
+  EXPECT_CALL(callback, Call(_))
+      .WillOnce(Invoke([&](rtc::ArrayView<const uint8_t> packet) {
+        RtcpPacketParser parser;
+        parser.Parse(packet.data(), packet.size());
+        EXPECT_EQ(1, parser.receiver_report()->num_packets());
+        EXPECT_EQ(1u, parser.receiver_report()->report_blocks().size());
+        EXPECT_EQ(1, parser.fir()->num_packets());
+      }));
+
+  EXPECT_TRUE(compound.Build(kBufferSize, callback.AsStdFunction()));
+}
+
+TEST(RtcpCompoundPacketTest, BuildWithTooSmallBuffer_FragmentedSend) {
+  CompoundPacket compound;
+  Fir fir;
+  fir.AddRequestTo(kRemoteSsrc, kSeqNo);
+  ReportBlock rb;
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(rr.AddReportBlock(rb));
+  compound.Append(&rr);
+  compound.Append(&fir);
+
+  const size_t kRrLength = 8;
+  const size_t kReportBlockLength = 24;
+
+  const size_t kBufferSize = kRrLength + kReportBlockLength;
+  MockFunction<void(rtc::ArrayView<const uint8_t>)> callback;
+  EXPECT_CALL(callback, Call(_))
+      .WillOnce(Invoke([&](rtc::ArrayView<const uint8_t> packet) {
+        RtcpPacketParser parser;
+        parser.Parse(packet.data(), packet.size());
+        EXPECT_EQ(1, parser.receiver_report()->num_packets());
+        EXPECT_EQ(1U, parser.receiver_report()->report_blocks().size());
+        EXPECT_EQ(0, parser.fir()->num_packets());
+      }))
+      .WillOnce(Invoke([&](rtc::ArrayView<const uint8_t> packet) {
+        RtcpPacketParser parser;
+        parser.Parse(packet.data(), packet.size());
+        EXPECT_EQ(0, parser.receiver_report()->num_packets());
+        EXPECT_EQ(0U, parser.receiver_report()->report_blocks().size());
+        EXPECT_EQ(1, parser.fir()->num_packets());
+      }));
+
+  EXPECT_TRUE(compound.Build(kBufferSize, callback.AsStdFunction()));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc b/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc
new file mode 100644
index 0000000..6863def
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace rtcp {
+// DLRR Report Block (RFC 3611).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=5      |   reserved    |         block length          |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_1 (SSRC of first receiver)               | sub-
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+//  |                         last RR (LRR)                         |   1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                   delay since last RR (DLRR)                  |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                 SSRC_2 (SSRC of second receiver)              | sub-
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+//  :                               ...                             :   2
+
+Dlrr::Dlrr() = default;
+
+Dlrr::Dlrr(const Dlrr& other) = default;
+
+Dlrr::~Dlrr() = default;
+
+bool Dlrr::Parse(const uint8_t* buffer, uint16_t block_length_32bits) {
+  RTC_DCHECK(buffer[0] == kBlockType);
+  // kReserved = buffer[1];
+  RTC_DCHECK_EQ(block_length_32bits,
+                ByteReader<uint16_t>::ReadBigEndian(&buffer[2]));
+  if (block_length_32bits % 3 != 0) {
+    RTC_LOG(LS_WARNING) << "Invalid size for dlrr block.";
+    return false;
+  }
+
+  size_t blocks_count = block_length_32bits / 3;
+  const uint8_t* read_at = buffer + kBlockHeaderLength;
+  sub_blocks_.resize(blocks_count);
+  for (ReceiveTimeInfo& sub_block : sub_blocks_) {
+    sub_block.ssrc = ByteReader<uint32_t>::ReadBigEndian(&read_at[0]);
+    sub_block.last_rr = ByteReader<uint32_t>::ReadBigEndian(&read_at[4]);
+    sub_block.delay_since_last_rr =
+        ByteReader<uint32_t>::ReadBigEndian(&read_at[8]);
+    read_at += kSubBlockLength;
+  }
+  return true;
+}
+
+size_t Dlrr::BlockLength() const {
+  if (sub_blocks_.empty())
+    return 0;
+  return kBlockHeaderLength + kSubBlockLength * sub_blocks_.size();
+}
+
+void Dlrr::Create(uint8_t* buffer) const {
+  if (sub_blocks_.empty())  // No subblocks, no need to write header either.
+    return;
+  // Create block header.
+  const uint8_t kReserved = 0;
+  buffer[0] = kBlockType;
+  buffer[1] = kReserved;
+  ByteWriter<uint16_t>::WriteBigEndian(
+      &buffer[2], rtc::dchecked_cast<uint16_t>(3 * sub_blocks_.size()));
+  // Create sub blocks.
+  uint8_t* write_at = buffer + kBlockHeaderLength;
+  for (const ReceiveTimeInfo& sub_block : sub_blocks_) {
+    ByteWriter<uint32_t>::WriteBigEndian(&write_at[0], sub_block.ssrc);
+    ByteWriter<uint32_t>::WriteBigEndian(&write_at[4], sub_block.last_rr);
+    ByteWriter<uint32_t>::WriteBigEndian(&write_at[8],
+                                         sub_block.delay_since_last_rr);
+    write_at += kSubBlockLength;
+  }
+  RTC_DCHECK_EQ(buffer + BlockLength(), write_at);
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/dlrr.h b/modules/rtp_rtcp/source/rtcp_packet/dlrr.h
new file mode 100644
index 0000000..6fe2099
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/dlrr.h
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+namespace webrtc {
+namespace rtcp {
+struct ReceiveTimeInfo {
+  // RFC 3611 4.5
+  ReceiveTimeInfo() : ssrc(0), last_rr(0), delay_since_last_rr(0) {}
+  ReceiveTimeInfo(uint32_t ssrc, uint32_t last_rr, uint32_t delay)
+      : ssrc(ssrc), last_rr(last_rr), delay_since_last_rr(delay) {}
+  uint32_t ssrc;
+  uint32_t last_rr;
+  uint32_t delay_since_last_rr;
+};
+
+// DLRR Report Block: Delay since the Last Receiver Report (RFC 3611).
+class Dlrr {
+ public:
+  static const uint8_t kBlockType = 5;
+
+  Dlrr();
+  Dlrr(const Dlrr& other);
+  ~Dlrr();
+
+  Dlrr& operator=(const Dlrr& other) = default;
+
+  // Dlrr without items treated same as no dlrr block.
+  explicit operator bool() const { return !sub_blocks_.empty(); }
+
+  // Second parameter is value read from block header,
+  // i.e. size of block in 32bits excluding block header itself.
+  bool Parse(const uint8_t* buffer, uint16_t block_length_32bits);
+
+  size_t BlockLength() const;
+  // Fills buffer with the Dlrr.
+  // Consumes BlockLength() bytes.
+  void Create(uint8_t* buffer) const;
+
+  void ClearItems() { sub_blocks_.clear(); }
+  void AddDlrrItem(const ReceiveTimeInfo& time_info) {
+    sub_blocks_.push_back(time_info);
+  }
+
+  const std::vector<ReceiveTimeInfo>& sub_blocks() const { return sub_blocks_; }
+
+ private:
+  static const size_t kBlockHeaderLength = 4;
+  static const size_t kSubBlockLength = 12;
+
+  std::vector<ReceiveTimeInfo> sub_blocks_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc
new file mode 100644
index 0000000..408d001
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "test/gtest.h"
+
+using webrtc::rtcp::Dlrr;
+using webrtc::rtcp::ReceiveTimeInfo;
+
+namespace webrtc {
+namespace {
+const uint32_t kSsrc = 0x12345678;
+const uint32_t kLastRR = 0x23344556;
+const uint32_t kDelay = 0x33343536;
+const uint8_t kBlock[] = {0x05, 0x00, 0x00, 0x03, 0x12, 0x34, 0x56, 0x78,
+                          0x23, 0x34, 0x45, 0x56, 0x33, 0x34, 0x35, 0x36};
+const size_t kBlockSizeBytes = sizeof(kBlock);
+}  // namespace
+
+TEST(RtcpPacketDlrrTest, Empty) {
+  Dlrr dlrr;
+
+  EXPECT_EQ(0u, dlrr.BlockLength());
+}
+
+TEST(RtcpPacketDlrrTest, Create) {
+  Dlrr dlrr;
+  dlrr.AddDlrrItem(ReceiveTimeInfo(kSsrc, kLastRR, kDelay));
+
+  ASSERT_EQ(kBlockSizeBytes, dlrr.BlockLength());
+  uint8_t buffer[kBlockSizeBytes];
+
+  dlrr.Create(buffer);
+  EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
+}
+
+TEST(RtcpPacketDlrrTest, Parse) {
+  Dlrr dlrr;
+  uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&kBlock[2]);
+  EXPECT_TRUE(dlrr.Parse(kBlock, block_length));
+
+  EXPECT_EQ(1u, dlrr.sub_blocks().size());
+  const ReceiveTimeInfo& block = dlrr.sub_blocks().front();
+  EXPECT_EQ(kSsrc, block.ssrc);
+  EXPECT_EQ(kLastRR, block.last_rr);
+  EXPECT_EQ(kDelay, block.delay_since_last_rr);
+}
+
+TEST(RtcpPacketDlrrTest, ParseFailsOnBadSize) {
+  const size_t kBigBufferSize = 0x100;  // More than enough.
+  uint8_t buffer[kBigBufferSize];
+  buffer[0] = Dlrr::kBlockType;
+  buffer[1] = 0;  // Reserved.
+  buffer[2] = 0;  // Most significant size byte.
+  for (uint8_t size = 3; size < 6; ++size) {
+    buffer[3] = size;
+    Dlrr dlrr;
+    // Parse should be successful only when size is multiple of 3.
+    EXPECT_EQ(size % 3 == 0, dlrr.Parse(buffer, static_cast<uint16_t>(size)));
+  }
+}
+
+TEST(RtcpPacketDlrrTest, CreateAndParseManySubBlocks) {
+  const size_t kBufferSize = 0x1000;  // More than enough.
+  const size_t kManyDlrrItems = 50;
+  uint8_t buffer[kBufferSize];
+
+  // Create.
+  Dlrr dlrr;
+  for (size_t i = 1; i <= kManyDlrrItems; ++i)
+    dlrr.AddDlrrItem(ReceiveTimeInfo(kSsrc + i, kLastRR + i, kDelay + i));
+  size_t used_buffer_size = dlrr.BlockLength();
+  ASSERT_LE(used_buffer_size, kBufferSize);
+  dlrr.Create(buffer);
+
+  // Parse.
+  Dlrr parsed;
+  uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
+  EXPECT_EQ(used_buffer_size, (block_length + 1) * 4u);
+  EXPECT_TRUE(parsed.Parse(buffer, block_length));
+  EXPECT_EQ(kManyDlrrItems, parsed.sub_blocks().size());
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc
new file mode 100644
index 0000000..27ed4cc
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t ExtendedJitterReport::kPacketType;
+// Transmission Time Offsets in RTP Streams (RFC 5450).
+//
+//      0                   1                   2                   3
+//      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// hdr |V=2|P|    RC   |   PT=IJ=195   |             length            |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//     |                      inter-arrival jitter                     |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//     .                                                               .
+//     .                                                               .
+//     .                                                               .
+//     |                      inter-arrival jitter                     |
+//     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//  If present, this RTCP packet must be placed after a receiver report
+//  (inside a compound RTCP packet), and MUST have the same value for RC
+//  (reception report count) as the receiver report.
+
+ExtendedJitterReport::ExtendedJitterReport() = default;
+
+ExtendedJitterReport::~ExtendedJitterReport() = default;
+
+bool ExtendedJitterReport::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+
+  const uint8_t number_of_jitters = packet.count();
+
+  if (packet.payload_size_bytes() < number_of_jitters * kJitterSizeBytes) {
+    RTC_LOG(LS_WARNING) << "Packet is too small to contain all the jitter.";
+    return false;
+  }
+
+  inter_arrival_jitters_.resize(number_of_jitters);
+  for (size_t index = 0; index < number_of_jitters; ++index) {
+    inter_arrival_jitters_[index] = ByteReader<uint32_t>::ReadBigEndian(
+        &packet.payload()[index * kJitterSizeBytes]);
+  }
+
+  return true;
+}
+
+bool ExtendedJitterReport::SetJitterValues(std::vector<uint32_t> values) {
+  if (values.size() > kMaxNumberOfJitterValues) {
+    RTC_LOG(LS_WARNING) << "Too many inter-arrival jitter items.";
+    return false;
+  }
+  inter_arrival_jitters_ = std::move(values);
+  return true;
+}
+
+size_t ExtendedJitterReport::BlockLength() const {
+  return kHeaderLength + kJitterSizeBytes * inter_arrival_jitters_.size();
+}
+
+bool ExtendedJitterReport::Create(uint8_t* packet,
+                                  size_t* index,
+                                  size_t max_length,
+                                  PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+  size_t length = inter_arrival_jitters_.size();
+  CreateHeader(length, kPacketType, length, packet, index);
+
+  for (uint32_t jitter : inter_arrival_jitters_) {
+    ByteWriter<uint32_t>::WriteBigEndian(packet + *index, jitter);
+    *index += kJitterSizeBytes;
+  }
+  // Sanity check.
+  RTC_DCHECK_EQ(index_end, *index);
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h b/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h
new file mode 100644
index 0000000..c28b9d9
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class ExtendedJitterReport : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 195;
+  static constexpr size_t kMaxNumberOfJitterValues = 0x1f;
+
+  ExtendedJitterReport();
+  ~ExtendedJitterReport() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  bool SetJitterValues(std::vector<uint32_t> jitter_values);
+
+  const std::vector<uint32_t>& jitter_values() {
+    return inter_arrival_jitters_;
+  }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr size_t kJitterSizeBytes = 4;
+
+  std::vector<uint32_t> inter_arrival_jitters_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc
new file mode 100644
index 0000000..7598fef
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc
@@ -0,0 +1,76 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+using webrtc::rtcp::ExtendedJitterReport;
+
+namespace webrtc {
+namespace {
+constexpr uint32_t kJitter1 = 0x11121314;
+constexpr uint32_t kJitter2 = 0x22242628;
+}  // namespace
+
+TEST(RtcpPacketExtendedJitterReportTest, CreateAndParseWithoutItems) {
+  ExtendedJitterReport ij;
+  rtc::Buffer raw = ij.Build();
+
+  ExtendedJitterReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_THAT(parsed.jitter_values(), IsEmpty());
+}
+
+TEST(RtcpPacketExtendedJitterReportTest, CreateAndParseWithOneItem) {
+  ExtendedJitterReport ij;
+  EXPECT_TRUE(ij.SetJitterValues({kJitter1}));
+  rtc::Buffer raw = ij.Build();
+
+  ExtendedJitterReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_THAT(parsed.jitter_values(), ElementsAre(kJitter1));
+}
+
+TEST(RtcpPacketExtendedJitterReportTest, CreateAndParseWithTwoItems) {
+  ExtendedJitterReport ij;
+  EXPECT_TRUE(ij.SetJitterValues({kJitter1, kJitter2}));
+  rtc::Buffer raw = ij.Build();
+
+  ExtendedJitterReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_THAT(parsed.jitter_values(), ElementsAre(kJitter1, kJitter2));
+}
+
+TEST(RtcpPacketExtendedJitterReportTest, CreateWithTooManyItems) {
+  ExtendedJitterReport ij;
+  const int kMaxItems = ExtendedJitterReport::kMaxNumberOfJitterValues;
+  EXPECT_FALSE(
+      ij.SetJitterValues(std::vector<uint32_t>(kMaxItems + 1, kJitter1)));
+  EXPECT_TRUE(ij.SetJitterValues(std::vector<uint32_t>(kMaxItems, kJitter1)));
+}
+
+TEST(RtcpPacketExtendedJitterReportTest, ParseFailsWithTooManyItems) {
+  ExtendedJitterReport ij;
+  ij.SetJitterValues({kJitter1});
+  rtc::Buffer raw = ij.Build();
+  raw[0]++;  // Damage packet: increase jitter count by 1.
+  ExtendedJitterReport parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(raw, &parsed));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
new file mode 100644
index 0000000..06472ef
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc
@@ -0,0 +1,222 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t ExtendedReports::kPacketType;
+constexpr size_t ExtendedReports::kMaxNumberOfDlrrItems;
+// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
+//
+// Format for XR packets:
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P|reserved |   PT=XR=207   |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              SSRC                             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :                         report blocks                         :
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Extended report block:
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  Block Type   |   reserved    |         block length          |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :             type-specific block contents                      :
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ExtendedReports::ExtendedReports() : sender_ssrc_(0) {}
+ExtendedReports::~ExtendedReports() {}
+
+bool ExtendedReports::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+
+  if (packet.payload_size_bytes() < kXrBaseLength) {
+    RTC_LOG(LS_WARNING)
+        << "Packet is too small to be an ExtendedReports packet.";
+    return false;
+  }
+
+  sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(packet.payload());
+  rrtr_block_.reset();
+  dlrr_block_.ClearItems();
+  voip_metric_block_.reset();
+  target_bitrate_ = absl::nullopt;
+
+  const uint8_t* current_block = packet.payload() + kXrBaseLength;
+  const uint8_t* const packet_end =
+      packet.payload() + packet.payload_size_bytes();
+  constexpr size_t kBlockHeaderSizeBytes = 4;
+  while (current_block + kBlockHeaderSizeBytes <= packet_end) {
+    uint8_t block_type = ByteReader<uint8_t>::ReadBigEndian(current_block);
+    uint16_t block_length =
+        ByteReader<uint16_t>::ReadBigEndian(current_block + 2);
+    const uint8_t* next_block =
+        current_block + kBlockHeaderSizeBytes + block_length * 4;
+    if (next_block > packet_end) {
+      RTC_LOG(LS_WARNING)
+          << "Report block in extended report packet is too big.";
+      return false;
+    }
+    switch (block_type) {
+      case Rrtr::kBlockType:
+        ParseRrtrBlock(current_block, block_length);
+        break;
+      case Dlrr::kBlockType:
+        ParseDlrrBlock(current_block, block_length);
+        break;
+      case VoipMetric::kBlockType:
+        ParseVoipMetricBlock(current_block, block_length);
+        break;
+      case TargetBitrate::kBlockType:
+        ParseTargetBitrateBlock(current_block, block_length);
+        break;
+      default:
+        // Unknown block, ignore.
+        RTC_LOG(LS_WARNING)
+            << "Unknown extended report block type " << block_type;
+        break;
+    }
+    current_block = next_block;
+  }
+
+  return true;
+}
+
+void ExtendedReports::SetRrtr(const Rrtr& rrtr) {
+  if (rrtr_block_)
+    RTC_LOG(LS_WARNING) << "Rrtr already set, overwriting.";
+  rrtr_block_.emplace(rrtr);
+}
+
+bool ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) {
+  if (dlrr_block_.sub_blocks().size() >= kMaxNumberOfDlrrItems) {
+    RTC_LOG(LS_WARNING) << "Reached maximum number of DLRR items.";
+    return false;
+  }
+  dlrr_block_.AddDlrrItem(time_info);
+  return true;
+}
+
+void ExtendedReports::SetVoipMetric(const VoipMetric& voip_metric) {
+  if (voip_metric_block_)
+    RTC_LOG(LS_WARNING) << "Voip metric already set, overwriting.";
+  voip_metric_block_.emplace(voip_metric);
+}
+
+void ExtendedReports::SetTargetBitrate(const TargetBitrate& bitrate) {
+  if (target_bitrate_)
+    RTC_LOG(LS_WARNING) << "TargetBitrate already set, overwriting.";
+
+  target_bitrate_ = bitrate;
+}
+
+size_t ExtendedReports::BlockLength() const {
+  return kHeaderLength + kXrBaseLength + RrtrLength() + DlrrLength() +
+         VoipMetricLength() + TargetBitrateLength();
+}
+
+bool ExtendedReports::Create(uint8_t* packet,
+                             size_t* index,
+                             size_t max_length,
+                             PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  size_t index_end = *index + BlockLength();
+  const uint8_t kReserved = 0;
+  CreateHeader(kReserved, kPacketType, HeaderLength(), packet, index);
+  ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc_);
+  *index += sizeof(uint32_t);
+  if (rrtr_block_) {
+    rrtr_block_->Create(packet + *index);
+    *index += Rrtr::kLength;
+  }
+  if (dlrr_block_) {
+    dlrr_block_.Create(packet + *index);
+    *index += dlrr_block_.BlockLength();
+  }
+  if (voip_metric_block_) {
+    voip_metric_block_->Create(packet + *index);
+    *index += VoipMetric::kLength;
+  }
+  if (target_bitrate_) {
+    target_bitrate_->Create(packet + *index);
+    *index += target_bitrate_->BlockLength();
+  }
+  RTC_CHECK_EQ(*index, index_end);
+  return true;
+}
+
+size_t ExtendedReports::TargetBitrateLength() const {
+  if (target_bitrate_)
+    return target_bitrate_->BlockLength();
+  return 0;
+}
+
+void ExtendedReports::ParseRrtrBlock(const uint8_t* block,
+                                     uint16_t block_length) {
+  if (block_length != Rrtr::kBlockLength) {
+    RTC_LOG(LS_WARNING) << "Incorrect rrtr block size " << block_length
+                        << " Should be " << Rrtr::kBlockLength;
+    return;
+  }
+  if (rrtr_block_) {
+    RTC_LOG(LS_WARNING)
+        << "Two rrtr blocks found in same Extended Report packet";
+    return;
+  }
+  rrtr_block_.emplace();
+  rrtr_block_->Parse(block);
+}
+
+void ExtendedReports::ParseDlrrBlock(const uint8_t* block,
+                                     uint16_t block_length) {
+  if (dlrr_block_) {
+    RTC_LOG(LS_WARNING)
+        << "Two Dlrr blocks found in same Extended Report packet";
+    return;
+  }
+  dlrr_block_.Parse(block, block_length);
+}
+
+void ExtendedReports::ParseVoipMetricBlock(const uint8_t* block,
+                                           uint16_t block_length) {
+  if (block_length != VoipMetric::kBlockLength) {
+    RTC_LOG(LS_WARNING) << "Incorrect voip metric block size " << block_length
+                        << " Should be " << VoipMetric::kBlockLength;
+    return;
+  }
+  if (voip_metric_block_) {
+    RTC_LOG(LS_WARNING)
+        << "Two Voip Metric blocks found in same Extended Report packet";
+    return;
+  }
+  voip_metric_block_.emplace();
+  voip_metric_block_->Parse(block);
+}
+
+void ExtendedReports::ParseTargetBitrateBlock(const uint8_t* block,
+                                              uint16_t block_length) {
+  target_bitrate_.emplace();
+  target_bitrate_->Parse(block, block_length);
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
new file mode 100644
index 0000000..7855502
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h
@@ -0,0 +1,86 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
+class ExtendedReports : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 207;
+  static constexpr size_t kMaxNumberOfDlrrItems = 50;
+
+  ExtendedReports();
+  ~ExtendedReports() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+
+  void SetRrtr(const Rrtr& rrtr);
+  bool AddDlrrItem(const ReceiveTimeInfo& time_info);
+  void SetVoipMetric(const VoipMetric& voip_metric);
+  void SetTargetBitrate(const TargetBitrate& target_bitrate);
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  const absl::optional<Rrtr>& rrtr() const { return rrtr_block_; }
+  const Dlrr& dlrr() const { return dlrr_block_; }
+  const absl::optional<VoipMetric>& voip_metric() const {
+    return voip_metric_block_;
+  }
+  const absl::optional<TargetBitrate>& target_bitrate() const {
+    return target_bitrate_;
+  }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr size_t kXrBaseLength = 4;
+
+  size_t RrtrLength() const { return rrtr_block_ ? Rrtr::kLength : 0; }
+  size_t DlrrLength() const { return dlrr_block_.BlockLength(); }
+  size_t VoipMetricLength() const {
+    return voip_metric_block_ ? VoipMetric::kLength : 0;
+  }
+  size_t TargetBitrateLength() const;
+
+  void ParseRrtrBlock(const uint8_t* block, uint16_t block_length);
+  void ParseDlrrBlock(const uint8_t* block, uint16_t block_length);
+  void ParseVoipMetricBlock(const uint8_t* block, uint16_t block_length);
+  void ParseTargetBitrateBlock(const uint8_t* block, uint16_t block_length);
+
+  uint32_t sender_ssrc_;
+  absl::optional<Rrtr> rrtr_block_;
+  Dlrr dlrr_block_;  // Dlrr without items treated same as no dlrr block.
+  absl::optional<VoipMetric> voip_metric_block_;
+  absl::optional<TargetBitrate> target_bitrate_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc
new file mode 100644
index 0000000..c37f77e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc
@@ -0,0 +1,264 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+
+#include "rtc_base/random.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::make_tuple;
+using testing::SizeIs;
+using webrtc::rtcp::Dlrr;
+using webrtc::rtcp::ExtendedReports;
+using webrtc::rtcp::ReceiveTimeInfo;
+using webrtc::rtcp::Rrtr;
+using webrtc::rtcp::VoipMetric;
+
+namespace webrtc {
+// Define comparision operators that shouldn't be needed in production,
+// but make testing matches more clear.
+bool operator==(const RTCPVoIPMetric& metric1, const RTCPVoIPMetric& metric2) {
+  return metric1.lossRate == metric2.lossRate &&
+         metric1.discardRate == metric2.discardRate &&
+         metric1.burstDensity == metric2.burstDensity &&
+         metric1.gapDensity == metric2.gapDensity &&
+         metric1.burstDuration == metric2.burstDuration &&
+         metric1.gapDuration == metric2.gapDuration &&
+         metric1.roundTripDelay == metric2.roundTripDelay &&
+         metric1.endSystemDelay == metric2.endSystemDelay &&
+         metric1.signalLevel == metric2.signalLevel &&
+         metric1.noiseLevel == metric2.noiseLevel &&
+         metric1.RERL == metric2.RERL && metric1.Gmin == metric2.Gmin &&
+         metric1.Rfactor == metric2.Rfactor &&
+         metric1.extRfactor == metric2.extRfactor &&
+         metric1.MOSLQ == metric2.MOSLQ && metric1.MOSCQ == metric2.MOSCQ &&
+         metric1.RXconfig == metric2.RXconfig &&
+         metric1.JBnominal == metric2.JBnominal &&
+         metric1.JBmax == metric2.JBmax && metric1.JBabsMax == metric2.JBabsMax;
+}
+
+namespace rtcp {
+bool operator==(const Rrtr& rrtr1, const Rrtr& rrtr2) {
+  return rrtr1.ntp() == rrtr2.ntp();
+}
+
+bool operator==(const ReceiveTimeInfo& time1, const ReceiveTimeInfo& time2) {
+  return time1.ssrc == time2.ssrc && time1.last_rr == time2.last_rr &&
+         time1.delay_since_last_rr == time2.delay_since_last_rr;
+}
+
+bool operator==(const VoipMetric& metric1, const VoipMetric& metric2) {
+  return metric1.ssrc() == metric2.ssrc() &&
+         metric1.voip_metric() == metric2.voip_metric();
+}
+}  // namespace rtcp
+
+namespace {
+constexpr uint32_t kSenderSsrc = 0x12345678;
+constexpr uint8_t kEmptyPacket[] = {0x80, 207,  0x00, 0x01,
+                                    0x12, 0x34, 0x56, 0x78};
+}  // namespace
+
+class RtcpPacketExtendedReportsTest : public ::testing::Test {
+ public:
+  RtcpPacketExtendedReportsTest() : random_(0x123456789) {}
+
+ protected:
+  template <typename T>
+  T Rand() {
+    return random_.Rand<T>();
+  }
+
+ private:
+  Random random_;
+};
+
+template <>
+ReceiveTimeInfo RtcpPacketExtendedReportsTest::Rand<ReceiveTimeInfo>() {
+  uint32_t ssrc = Rand<uint32_t>();
+  uint32_t last_rr = Rand<uint32_t>();
+  uint32_t delay_since_last_rr = Rand<uint32_t>();
+  return ReceiveTimeInfo(ssrc, last_rr, delay_since_last_rr);
+}
+
+template <>
+NtpTime RtcpPacketExtendedReportsTest::Rand<NtpTime>() {
+  uint32_t secs = Rand<uint32_t>();
+  uint32_t frac = Rand<uint32_t>();
+  return NtpTime(secs, frac);
+}
+
+template <>
+Rrtr RtcpPacketExtendedReportsTest::Rand<Rrtr>() {
+  Rrtr rrtr;
+  rrtr.SetNtp(Rand<NtpTime>());
+  return rrtr;
+}
+
+template <>
+RTCPVoIPMetric RtcpPacketExtendedReportsTest::Rand<RTCPVoIPMetric>() {
+  RTCPVoIPMetric metric;
+  metric.lossRate = Rand<uint8_t>();
+  metric.discardRate = Rand<uint8_t>();
+  metric.burstDensity = Rand<uint8_t>();
+  metric.gapDensity = Rand<uint8_t>();
+  metric.burstDuration = Rand<uint16_t>();
+  metric.gapDuration = Rand<uint16_t>();
+  metric.roundTripDelay = Rand<uint16_t>();
+  metric.endSystemDelay = Rand<uint16_t>();
+  metric.signalLevel = Rand<uint8_t>();
+  metric.noiseLevel = Rand<uint8_t>();
+  metric.RERL = Rand<uint8_t>();
+  metric.Gmin = Rand<uint8_t>();
+  metric.Rfactor = Rand<uint8_t>();
+  metric.extRfactor = Rand<uint8_t>();
+  metric.MOSLQ = Rand<uint8_t>();
+  metric.MOSCQ = Rand<uint8_t>();
+  metric.RXconfig = Rand<uint8_t>();
+  metric.JBnominal = Rand<uint16_t>();
+  metric.JBmax = Rand<uint16_t>();
+  metric.JBabsMax = Rand<uint16_t>();
+  return metric;
+}
+
+template <>
+VoipMetric RtcpPacketExtendedReportsTest::Rand<VoipMetric>() {
+  VoipMetric voip_metric;
+  voip_metric.SetMediaSsrc(Rand<uint32_t>());
+  voip_metric.SetVoipMetric(Rand<RTCPVoIPMetric>());
+  return voip_metric;
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateWithoutReportBlocks) {
+  ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+
+  rtc::Buffer packet = xr.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kEmptyPacket));
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, ParseWithoutReportBlocks) {
+  ExtendedReports parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kEmptyPacket, &parsed));
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_FALSE(parsed.rrtr());
+  EXPECT_FALSE(parsed.dlrr());
+  EXPECT_FALSE(parsed.voip_metric());
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithRrtrBlock) {
+  const Rrtr kRrtr = Rand<Rrtr>();
+  ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetRrtr(kRrtr);
+  rtc::Buffer packet = xr.Build();
+
+  ExtendedReports mparsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed));
+  const ExtendedReports& parsed = mparsed;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kRrtr, parsed.rrtr());
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithOneSubBlock) {
+  const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>();
+  ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(kTimeInfo);
+
+  rtc::Buffer packet = xr.Build();
+
+  ExtendedReports mparsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed));
+  const ExtendedReports& parsed = mparsed;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo));
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithTwoSubBlocks) {
+  const ReceiveTimeInfo kTimeInfo1 = Rand<ReceiveTimeInfo>();
+  const ReceiveTimeInfo kTimeInfo2 = Rand<ReceiveTimeInfo>();
+  ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(kTimeInfo1);
+  xr.AddDlrrItem(kTimeInfo2);
+
+  rtc::Buffer packet = xr.Build();
+
+  ExtendedReports mparsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed));
+  const ExtendedReports& parsed = mparsed;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo1, kTimeInfo2));
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateLimitsTheNumberOfDlrrSubBlocks) {
+  const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>();
+  ExtendedReports xr;
+
+  for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
+    EXPECT_TRUE(xr.AddDlrrItem(kTimeInfo));
+  EXPECT_FALSE(xr.AddDlrrItem(kTimeInfo));
+
+  EXPECT_THAT(xr.dlrr().sub_blocks(),
+              SizeIs(ExtendedReports::kMaxNumberOfDlrrItems));
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) {
+  const VoipMetric kVoipMetric = Rand<VoipMetric>();
+
+  ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetVoipMetric(kVoipMetric);
+
+  rtc::Buffer packet = xr.Build();
+
+  ExtendedReports mparsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed));
+  const ExtendedReports& parsed = mparsed;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kVoipMetric, parsed.voip_metric());
+}
+
+TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMaximumReportBlocks) {
+  const Rrtr kRrtr = Rand<Rrtr>();
+  const VoipMetric kVoipMetric = Rand<VoipMetric>();
+
+  ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetRrtr(kRrtr);
+  for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
+    xr.AddDlrrItem(Rand<ReceiveTimeInfo>());
+  xr.SetVoipMetric(kVoipMetric);
+
+  rtc::Buffer packet = xr.Build();
+
+  ExtendedReports mparsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed));
+  const ExtendedReports& parsed = mparsed;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kRrtr, parsed.rrtr());
+  EXPECT_THAT(parsed.dlrr().sub_blocks(),
+              ElementsAreArray(xr.dlrr().sub_blocks()));
+  EXPECT_EQ(kVoipMetric, parsed.voip_metric());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir.cc b/modules/rtp_rtcp/source/rtcp_packet/fir.cc
new file mode 100644
index 0000000..517e991
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir.cc
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Fir::kFeedbackMessageType;
+// RFC 4585: Feedback format.
+// Common packet format:
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P|   FMT   |       PT      |          length               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  SSRC of packet sender                        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |             SSRC of media source (unused) = 0                 |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :            Feedback Control Information (FCI)                 :
+//  :                                                               :
+// Full intra request (FIR) (RFC 5104).
+// The Feedback Control Information (FCI) for the Full Intra Request
+// consists of one or more FCI entries.
+// FCI:
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              SSRC                             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | Seq nr.       |    Reserved = 0                               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Fir::Fir() = default;
+
+Fir::~Fir() = default;
+
+bool Fir::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  // The FCI field MUST contain one or more FIR entries.
+  if (packet.payload_size_bytes() < kCommonFeedbackLength + kFciLength) {
+    RTC_LOG(LS_WARNING) << "Packet is too small to be a valid FIR packet.";
+    return false;
+  }
+
+  if ((packet.payload_size_bytes() - kCommonFeedbackLength) % kFciLength != 0) {
+    RTC_LOG(LS_WARNING) << "Invalid size for a valid FIR packet.";
+    return false;
+  }
+
+  ParseCommonFeedback(packet.payload());
+
+  size_t number_of_fci_items =
+      (packet.payload_size_bytes() - kCommonFeedbackLength) / kFciLength;
+  const uint8_t* next_fci = packet.payload() + kCommonFeedbackLength;
+  items_.resize(number_of_fci_items);
+  for (Request& request : items_) {
+    request.ssrc = ByteReader<uint32_t>::ReadBigEndian(next_fci);
+    request.seq_nr = ByteReader<uint8_t>::ReadBigEndian(next_fci + 4);
+    next_fci += kFciLength;
+  }
+  return true;
+}
+
+size_t Fir::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength + kFciLength * items_.size();
+}
+
+bool Fir::Create(uint8_t* packet,
+                 size_t* index,
+                 size_t max_length,
+                 PacketReadyCallback callback) const {
+  RTC_DCHECK(!items_.empty());
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  size_t index_end = *index + BlockLength();
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               index);
+  RTC_DCHECK_EQ(Psfb::media_ssrc(), 0);
+  CreateCommonFeedback(packet + *index);
+  *index += kCommonFeedbackLength;
+
+  constexpr uint32_t kReserved = 0;
+  for (const Request& request : items_) {
+    ByteWriter<uint32_t>::WriteBigEndian(packet + *index, request.ssrc);
+    ByteWriter<uint8_t>::WriteBigEndian(packet + *index + 4, request.seq_nr);
+    ByteWriter<uint32_t, 3>::WriteBigEndian(packet + *index + 5, kReserved);
+    *index += kFciLength;
+  }
+  RTC_CHECK_EQ(*index, index_end);
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir.h b/modules/rtp_rtcp/source/rtcp_packet/fir.h
new file mode 100644
index 0000000..6fbc54c
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_FIR_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_FIR_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+// Full intra request (FIR) (RFC 5104).
+class Fir : public Psfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 4;
+  struct Request {
+    Request() : ssrc(0), seq_nr(0) {}
+    Request(uint32_t ssrc, uint8_t seq_nr) : ssrc(ssrc), seq_nr(seq_nr) {}
+    uint32_t ssrc;
+    uint8_t seq_nr;
+  };
+
+  Fir();
+  ~Fir() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void AddRequestTo(uint32_t ssrc, uint8_t seq_num) {
+    items_.emplace_back(ssrc, seq_num);
+  }
+  const std::vector<Request>& requests() const { return items_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr size_t kFciLength = 8;
+
+  // SSRC of media source is not used in FIR packet. Shadow base functions.
+  void SetMediaSsrc(uint32_t ssrc);
+  uint32_t media_ssrc() const;
+
+  std::vector<Request> items_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_FIR_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc
new file mode 100644
index 0000000..d9eb465
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/fir_unittest.cc
@@ -0,0 +1,93 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::AllOf;
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::Eq;
+using testing::Field;
+using testing::make_tuple;
+using webrtc::rtcp::Fir;
+
+namespace webrtc {
+namespace {
+
+constexpr uint32_t kSenderSsrc = 0x12345678;
+constexpr uint32_t kRemoteSsrc = 0x23456789;
+constexpr uint8_t kSeqNr = 13;
+// Manually created Fir packet matching constants above.
+constexpr uint8_t kPacket[] = {0x84, 206,  0x00, 0x04, 0x12, 0x34, 0x56,
+                               0x78, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+                               0x67, 0x89, 0x0d, 0x00, 0x00, 0x00};
+}  // namespace
+
+TEST(RtcpPacketFirTest, Parse) {
+  Fir mutable_parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &mutable_parsed));
+  const Fir& parsed = mutable_parsed;  // Read values from constant object.
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_THAT(parsed.requests(),
+              ElementsAre(AllOf(Field(&Fir::Request::ssrc, Eq(kRemoteSsrc)),
+                                Field(&Fir::Request::seq_nr, Eq(kSeqNr)))));
+}
+
+TEST(RtcpPacketFirTest, Create) {
+  Fir fir;
+  fir.SetSenderSsrc(kSenderSsrc);
+  fir.AddRequestTo(kRemoteSsrc, kSeqNr);
+
+  rtc::Buffer packet = fir.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketFirTest, TwoFciEntries) {
+  Fir fir;
+  fir.SetSenderSsrc(kSenderSsrc);
+  fir.AddRequestTo(kRemoteSsrc, kSeqNr);
+  fir.AddRequestTo(kRemoteSsrc + 1, kSeqNr + 1);
+
+  rtc::Buffer packet = fir.Build();
+  Fir parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_THAT(parsed.requests(),
+              ElementsAre(AllOf(Field(&Fir::Request::ssrc, Eq(kRemoteSsrc)),
+                                Field(&Fir::Request::seq_nr, Eq(kSeqNr))),
+                          AllOf(Field(&Fir::Request::ssrc, Eq(kRemoteSsrc + 1)),
+                                Field(&Fir::Request::seq_nr, Eq(kSeqNr + 1)))));
+}
+
+TEST(RtcpPacketFirTest, ParseFailsOnZeroFciEntries) {
+  constexpr uint8_t kPacketWithoutFci[] = {0x84, 206,  0x00, 0x02, 0x12, 0x34,
+                                           0x56, 0x78, 0x00, 0x00, 0x00, 0x00};
+  Fir parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kPacketWithoutFci, &parsed));
+}
+
+TEST(RtcpPacketFirTest, ParseFailsOnFractionalFciEntries) {
+  constexpr uint8_t kPacketWithOneAndHalfFci[] = {
+      0x84, 206,  0x00, 0x05, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00,
+      0x23, 0x45, 0x67, 0x89, 0x0d, 0x00, 0x00, 0x00, 'h',  'a',  'l',  'f'};
+
+  Fir parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kPacketWithOneAndHalfFci, &parsed));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/nack.cc b/modules/rtp_rtcp/source/rtcp_packet/nack.cc
new file mode 100644
index 0000000..f83e5c0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/nack.cc
@@ -0,0 +1,174 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Nack::kFeedbackMessageType;
+constexpr size_t Nack::kNackItemLength;
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |V=2|P|   FMT   |       PT      |          length               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 |                  SSRC of packet sender                        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 |                  SSRC of media source                         |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   :            Feedback Control Information (FCI)                 :
+//   :                                                               :
+//
+// Generic NACK (RFC 4585).
+//
+// FCI:
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |            PID                |             BLP               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+Nack::Nack() {}
+Nack::~Nack() {}
+
+bool Nack::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  if (packet.payload_size_bytes() < kCommonFeedbackLength + kNackItemLength) {
+    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
+                        << " is too small for a Nack.";
+    return false;
+  }
+  size_t nack_items =
+      (packet.payload_size_bytes() - kCommonFeedbackLength) / kNackItemLength;
+
+  ParseCommonFeedback(packet.payload());
+  const uint8_t* next_nack = packet.payload() + kCommonFeedbackLength;
+
+  packet_ids_.clear();
+  packed_.resize(nack_items);
+  for (size_t index = 0; index < nack_items; ++index) {
+    packed_[index].first_pid = ByteReader<uint16_t>::ReadBigEndian(next_nack);
+    packed_[index].bitmask = ByteReader<uint16_t>::ReadBigEndian(next_nack + 2);
+    next_nack += kNackItemLength;
+  }
+  Unpack();
+
+  return true;
+}
+
+size_t Nack::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength +
+         packed_.size() * kNackItemLength;
+}
+
+bool Nack::Create(uint8_t* packet,
+                  size_t* index,
+                  size_t max_length,
+                  PacketReadyCallback callback) const {
+  RTC_DCHECK(!packed_.empty());
+  // If nack list can't fit in packet, try to fragment.
+  constexpr size_t kNackHeaderLength = kHeaderLength + kCommonFeedbackLength;
+  for (size_t nack_index = 0; nack_index < packed_.size();) {
+    size_t bytes_left_in_buffer = max_length - *index;
+    if (bytes_left_in_buffer < kNackHeaderLength + kNackItemLength) {
+      if (!OnBufferFull(packet, index, callback))
+        return false;
+      continue;
+    }
+    size_t num_nack_fields =
+        std::min((bytes_left_in_buffer - kNackHeaderLength) / kNackItemLength,
+                 packed_.size() - nack_index);
+
+    size_t payload_size_bytes =
+        kCommonFeedbackLength + (num_nack_fields * kNackItemLength);
+    size_t payload_size_32bits =
+        rtc::CheckedDivExact<size_t>(payload_size_bytes, 4);
+    CreateHeader(kFeedbackMessageType, kPacketType, payload_size_32bits, packet,
+                 index);
+
+    CreateCommonFeedback(packet + *index);
+    *index += kCommonFeedbackLength;
+
+    size_t nack_end_index = nack_index + num_nack_fields;
+    for (; nack_index < nack_end_index; ++nack_index) {
+      const PackedNack& item = packed_[nack_index];
+      ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 0, item.first_pid);
+      ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 2, item.bitmask);
+      *index += kNackItemLength;
+    }
+    RTC_DCHECK_LE(*index, max_length);
+  }
+
+  return true;
+}
+
+void Nack::SetPacketIds(const uint16_t* nack_list, size_t length) {
+  RTC_DCHECK(nack_list);
+  SetPacketIds(std::vector<uint16_t>(nack_list, nack_list + length));
+}
+
+void Nack::SetPacketIds(std::vector<uint16_t> nack_list) {
+  RTC_DCHECK(packet_ids_.empty());
+  RTC_DCHECK(packed_.empty());
+  packet_ids_ = std::move(nack_list);
+  Pack();
+}
+
+void Nack::Pack() {
+  RTC_DCHECK(!packet_ids_.empty());
+  RTC_DCHECK(packed_.empty());
+  auto it = packet_ids_.begin();
+  const auto end = packet_ids_.end();
+  while (it != end) {
+    PackedNack item;
+    item.first_pid = *it++;
+    // Bitmask specifies losses in any of the 16 packets following the pid.
+    item.bitmask = 0;
+    while (it != end) {
+      uint16_t shift = static_cast<uint16_t>(*it - item.first_pid - 1);
+      if (shift <= 15) {
+        item.bitmask |= (1 << shift);
+        ++it;
+      } else {
+        break;
+      }
+    }
+    packed_.push_back(item);
+  }
+}
+
+void Nack::Unpack() {
+  RTC_DCHECK(packet_ids_.empty());
+  RTC_DCHECK(!packed_.empty());
+  for (const PackedNack& item : packed_) {
+    packet_ids_.push_back(item.first_pid);
+    uint16_t pid = item.first_pid + 1;
+    for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid) {
+      if (bitmask & 1)
+        packet_ids_.push_back(pid);
+    }
+  }
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/nack.h b/modules/rtp_rtcp/source/rtcp_packet/nack.h
new file mode 100644
index 0000000..0e462f9
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/nack.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class Nack : public Rtpfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 1;
+  Nack();
+  ~Nack() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void SetPacketIds(const uint16_t* nack_list, size_t length);
+  void SetPacketIds(std::vector<uint16_t> nack_list);
+  const std::vector<uint16_t>& packet_ids() const { return packet_ids_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr size_t kNackItemLength = 4;
+  struct PackedNack {
+    uint16_t first_pid;
+    uint16_t bitmask;
+  };
+
+  void Pack();    // Fills packed_ using packed_ids_. (used in SetPacketIds).
+  void Unpack();  // Fills packet_ids_ using packed_. (used in Parse).
+
+  std::vector<PackedNack> packed_;
+  std::vector<uint16_t> packet_ids_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_NACK_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc
new file mode 100644
index 0000000..c94513f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/nack_unittest.cc
@@ -0,0 +1,171 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+using ::testing::Invoke;
+using ::testing::MockFunction;
+using ::testing::UnorderedElementsAreArray;
+using ::testing::make_tuple;
+using ::webrtc::rtcp::Nack;
+
+constexpr uint32_t kSenderSsrc = 0x12345678;
+constexpr uint32_t kRemoteSsrc = 0x23456789;
+
+constexpr uint16_t kList[] = {0, 1, 3, 8, 16};
+constexpr size_t kListLength = sizeof(kList) / sizeof(kList[0]);
+constexpr uint8_t kVersionBits = 2 << 6;
+// clang-format off
+constexpr uint8_t kPacket[] = {
+    kVersionBits | Nack::kFeedbackMessageType, Nack::kPacketType, 0, 3,
+    0x12, 0x34, 0x56, 0x78,
+    0x23, 0x45, 0x67, 0x89,
+    0x00, 0x00, 0x80, 0x85};
+
+constexpr uint16_t kWrapList[] = {0xffdc, 0xffec, 0xfffe, 0xffff, 0x0000,
+                                  0x0001, 0x0003, 0x0014, 0x0064};
+constexpr size_t kWrapListLength = sizeof(kWrapList) / sizeof(kWrapList[0]);
+constexpr uint8_t kWrapPacket[] = {
+    kVersionBits | Nack::kFeedbackMessageType, Nack::kPacketType, 0, 6,
+    0x12, 0x34, 0x56, 0x78,
+    0x23, 0x45, 0x67, 0x89,
+    0xff, 0xdc, 0x80, 0x00,
+    0xff, 0xfe, 0x00, 0x17,
+    0x00, 0x14, 0x00, 0x00,
+    0x00, 0x64, 0x00, 0x00};
+constexpr uint8_t kTooSmallPacket[] = {
+    kVersionBits | Nack::kFeedbackMessageType, Nack::kPacketType, 0, 2,
+    0x12, 0x34, 0x56, 0x78,
+    0x23, 0x45, 0x67, 0x89};
+// clang-format on
+}  // namespace
+
+TEST(RtcpPacketNackTest, Create) {
+  Nack nack;
+  nack.SetSenderSsrc(kSenderSsrc);
+  nack.SetMediaSsrc(kRemoteSsrc);
+  nack.SetPacketIds(kList, kListLength);
+
+  rtc::Buffer packet = nack.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketNackTest, Parse) {
+  Nack parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed));
+  const Nack& const_parsed = parsed;
+
+  EXPECT_EQ(kSenderSsrc, const_parsed.sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, const_parsed.media_ssrc());
+  EXPECT_THAT(const_parsed.packet_ids(), ElementsAreArray(kList));
+}
+
+TEST(RtcpPacketNackTest, CreateWrap) {
+  Nack nack;
+  nack.SetSenderSsrc(kSenderSsrc);
+  nack.SetMediaSsrc(kRemoteSsrc);
+  nack.SetPacketIds(kWrapList, kWrapListLength);
+
+  rtc::Buffer packet = nack.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kWrapPacket));
+}
+
+TEST(RtcpPacketNackTest, ParseWrap) {
+  Nack parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kWrapPacket, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+  EXPECT_THAT(parsed.packet_ids(), ElementsAreArray(kWrapList));
+}
+
+TEST(RtcpPacketNackTest, BadOrder) {
+  // Does not guarantee optimal packing, but should guarantee correctness.
+  const uint16_t kUnorderedList[] = {1, 25, 13, 12, 9, 27, 29};
+  const size_t kUnorderedListLength =
+      sizeof(kUnorderedList) / sizeof(kUnorderedList[0]);
+  Nack nack;
+  nack.SetSenderSsrc(kSenderSsrc);
+  nack.SetMediaSsrc(kRemoteSsrc);
+  nack.SetPacketIds(kUnorderedList, kUnorderedListLength);
+
+  rtc::Buffer packet = nack.Build();
+
+  Nack parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+  EXPECT_THAT(parsed.packet_ids(), UnorderedElementsAreArray(kUnorderedList));
+}
+
+TEST(RtcpPacketNackTest, CreateFragmented) {
+  Nack nack;
+  const uint16_t kList[] = {1, 100, 200, 300, 400};
+  const uint16_t kListLength = sizeof(kList) / sizeof(kList[0]);
+  nack.SetSenderSsrc(kSenderSsrc);
+  nack.SetMediaSsrc(kRemoteSsrc);
+  nack.SetPacketIds(kList, kListLength);
+
+  const size_t kBufferSize = 12 + (3 * 4);  // Fits common header + 3 nack items
+
+  MockFunction<void(rtc::ArrayView<const uint8_t>)> callback;
+  EXPECT_CALL(callback, Call(_))
+      .WillOnce(Invoke([&](rtc::ArrayView<const uint8_t> packet) {
+        Nack nack;
+        EXPECT_TRUE(test::ParseSinglePacket(packet, &nack));
+        EXPECT_EQ(kSenderSsrc, nack.sender_ssrc());
+        EXPECT_EQ(kRemoteSsrc, nack.media_ssrc());
+        EXPECT_THAT(nack.packet_ids(), ElementsAre(1, 100, 200));
+      }))
+      .WillOnce(Invoke([&](rtc::ArrayView<const uint8_t> packet) {
+        Nack nack;
+        EXPECT_TRUE(test::ParseSinglePacket(packet, &nack));
+        EXPECT_EQ(kSenderSsrc, nack.sender_ssrc());
+        EXPECT_EQ(kRemoteSsrc, nack.media_ssrc());
+        EXPECT_THAT(nack.packet_ids(), ElementsAre(300, 400));
+      }));
+
+  EXPECT_TRUE(nack.Build(kBufferSize, callback.AsStdFunction()));
+}
+
+TEST(RtcpPacketNackTest, CreateFailsWithTooSmallBuffer) {
+  const uint16_t kList[] = {1};
+  const size_t kMinNackBlockSize = 16;
+  Nack nack;
+  nack.SetSenderSsrc(kSenderSsrc);
+  nack.SetMediaSsrc(kRemoteSsrc);
+  nack.SetPacketIds(kList, 1);
+
+  MockFunction<void(rtc::ArrayView<const uint8_t>)> callback;
+  EXPECT_CALL(callback, Call(_)).Times(0);
+  EXPECT_FALSE(nack.Build(kMinNackBlockSize - 1, callback.AsStdFunction()));
+}
+
+TEST(RtcpPacketNackTest, ParseFailsWithTooSmallBuffer) {
+  Nack parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli.cc b/modules/rtp_rtcp/source/rtcp_packet/pli.cc
new file mode 100644
index 0000000..274eb6b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli.cc
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Pli::kFeedbackMessageType;
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P|   FMT   |       PT      |          length               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  SSRC of packet sender                        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  SSRC of media source                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :            Feedback Control Information (FCI)                 :
+//  :                                                               :
+
+//
+// Picture loss indication (PLI) (RFC 4585).
+// FCI: no feedback control information.
+bool Pli::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  if (packet.payload_size_bytes() < kCommonFeedbackLength) {
+    RTC_LOG(LS_WARNING) << "Packet is too small to be a valid PLI packet";
+    return false;
+  }
+
+  ParseCommonFeedback(packet.payload());
+  return true;
+}
+
+size_t Pli::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength;
+}
+
+bool Pli::Create(uint8_t* packet,
+                 size_t* index,
+                 size_t max_length,
+                 PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               index);
+  CreateCommonFeedback(packet + *index);
+  *index += kCommonFeedbackLength;
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli.h b/modules/rtp_rtcp/source/rtcp_packet/pli.h
new file mode 100644
index 0000000..fc3c20a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli.h
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_
+
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+// Picture loss indication (PLI) (RFC 4585).
+class Pli : public Psfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 1;
+
+  Pli() {}
+  ~Pli() override {}
+
+  bool Parse(const CommonHeader& packet);
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PLI_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc
new file mode 100644
index 0000000..67e614d
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/pli_unittest.cc
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::make_tuple;
+using webrtc::rtcp::Pli;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+// Manually created Pli packet matching constants above.
+const uint8_t kPacket[] = {0x81, 206,  0x00, 0x02, 0x12, 0x34,
+                           0x56, 0x78, 0x23, 0x45, 0x67, 0x89};
+}  // namespace
+
+TEST(RtcpPacketPliTest, Parse) {
+  Pli mutable_parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &mutable_parsed));
+  const Pli& parsed = mutable_parsed;  // Read values from constant object.
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+}
+
+TEST(RtcpPacketPliTest, Create) {
+  Pli pli;
+  pli.SetSenderSsrc(kSenderSsrc);
+  pli.SetMediaSsrc(kRemoteSsrc);
+
+  rtc::Buffer packet = pli.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketPliTest, ParseFailsOnTooSmallPacket) {
+  const uint8_t kTooSmallPacket[] = {0x81, 206,  0x00, 0x01,
+                                     0x12, 0x34, 0x56, 0x78};
+
+  Pli parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/psfb.cc b/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
new file mode 100644
index 0000000..074413a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/psfb.cc
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Psfb::kPacketType;
+constexpr size_t Psfb::kCommonFeedbackLength;
+// RFC 4585: Feedback format.
+//
+// Common packet format:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |V=2|P|   FMT   |       PT      |          length               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 |                  SSRC of packet sender                        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 |                  SSRC of media source                         |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   :            Feedback Control Information (FCI)                 :
+//   :                                                               :
+
+void Psfb::ParseCommonFeedback(const uint8_t* payload) {
+  sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+  media_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+}
+
+void Psfb::CreateCommonFeedback(uint8_t* payload) const {
+  ByteWriter<uint32_t>::WriteBigEndian(&payload[0], sender_ssrc_);
+  ByteWriter<uint32_t>::WriteBigEndian(&payload[4], media_ssrc_);
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/psfb.h b/modules/rtp_rtcp/source/rtcp_packet/psfb.h
new file mode 100644
index 0000000..ae66a17
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/psfb.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// PSFB: Payload-specific feedback message.
+// RFC 4585, Section 6.3.
+class Psfb : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 206;
+
+  Psfb() : sender_ssrc_(0), media_ssrc_(0) {}
+  ~Psfb() override {}
+
+  void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+  void SetMediaSsrc(uint32_t ssrc) { media_ssrc_ = ssrc; }
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  uint32_t media_ssrc() const { return media_ssrc_; }
+
+ protected:
+  static constexpr size_t kCommonFeedbackLength = 8;
+  void ParseCommonFeedback(const uint8_t* payload);
+  void CreateCommonFeedback(uint8_t* payload) const;
+
+ private:
+  uint32_t sender_ssrc_;
+  uint32_t media_ssrc_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_PSFB_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc b/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc
new file mode 100644
index 0000000..8563c28
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.cc
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
+
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t RapidResyncRequest::kFeedbackMessageType;
+// RFC 4585: Feedback format.
+// Rapid Resynchronisation Request (draft-perkins-avt-rapid-rtp-sync-03).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P|  FMT=5  |     PT=205    |         length=2              |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  SSRC of packet sender                        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  SSRC of media source                         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+bool RapidResyncRequest::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  if (packet.payload_size_bytes() != kCommonFeedbackLength) {
+    RTC_LOG(LS_WARNING) << "Packet payload size should be "
+                        << kCommonFeedbackLength << " instead of "
+                        << packet.payload_size_bytes()
+                        << " to be a valid Rapid Resynchronisation Request";
+    return false;
+  }
+
+  ParseCommonFeedback(packet.payload());
+  return true;
+}
+
+size_t RapidResyncRequest::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength;
+}
+
+bool RapidResyncRequest::Create(uint8_t* packet,
+                                size_t* index,
+                                size_t max_length,
+                                PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               index);
+  CreateCommonFeedback(packet + *index);
+  *index += kCommonFeedbackLength;
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h b/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h
new file mode 100644
index 0000000..1955b98
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RAPID_RESYNC_REQUEST_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RAPID_RESYNC_REQUEST_H_
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+// draft-perkins-avt-rapid-rtp-sync-03
+class RapidResyncRequest : public Rtpfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 5;
+
+  RapidResyncRequest() {}
+  ~RapidResyncRequest() override {}
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& header);
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RAPID_RESYNC_REQUEST_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc
new file mode 100644
index 0000000..f10f93e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request_unittest.cc
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::make_tuple;
+using webrtc::rtcp::RapidResyncRequest;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+// Manually created packet matching constants above.
+const uint8_t kPacket[] = {0x85, 205,  0x00, 0x02, 0x12, 0x34,
+                           0x56, 0x78, 0x23, 0x45, 0x67, 0x89};
+}  // namespace
+
+TEST(RtcpPacketRapidResyncRequestTest, Parse) {
+  RapidResyncRequest mutable_parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &mutable_parsed));
+  const RapidResyncRequest& parsed = mutable_parsed;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, parsed.media_ssrc());
+}
+
+TEST(RtcpPacketRapidResyncRequestTest, Create) {
+  RapidResyncRequest rrr;
+  rrr.SetSenderSsrc(kSenderSsrc);
+  rrr.SetMediaSsrc(kRemoteSsrc);
+
+  rtc::Buffer packet = rrr.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketRapidResyncRequestTest, ParseFailsOnTooSmallPacket) {
+  const uint8_t kTooSmallPacket[] = {0x85, 205,  0x00, 0x01,
+                                     0x12, 0x34, 0x56, 0x78};
+  RapidResyncRequest parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kTooSmallPacket, &parsed));
+}
+
+TEST(RtcpPacketRapidResyncRequestTest, ParseFailsOnTooLargePacket) {
+  const uint8_t kTooLargePacket[] = {0x85, 205,  0x00, 0x03, 0x12, 0x34,
+                                     0x56, 0x78, 0x32, 0x21, 0x65, 0x87,
+                                     0x23, 0x45, 0x67, 0x89};
+  RapidResyncRequest parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kTooLargePacket, &parsed));
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc b/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc
new file mode 100644
index 0000000..5677db2
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/receiver_report.cc
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t ReceiverReport::kPacketType;
+constexpr size_t ReceiverReport::kMaxNumberOfReportBlocks;
+// RTCP receiver report (RFC 3550).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P|    RC   |   PT=RR=201   |             length            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                     SSRC of packet sender                     |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  |                         report block(s)                       |
+//  |                            ....                               |
+
+ReceiverReport::ReceiverReport() : sender_ssrc_(0) {}
+
+ReceiverReport::~ReceiverReport() = default;
+
+bool ReceiverReport::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+
+  const uint8_t report_blocks_count = packet.count();
+
+  if (packet.payload_size_bytes() <
+      kRrBaseLength + report_blocks_count * ReportBlock::kLength) {
+    RTC_LOG(LS_WARNING) << "Packet is too small to contain all the data.";
+    return false;
+  }
+
+  sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(packet.payload());
+
+  const uint8_t* next_report_block = packet.payload() + kRrBaseLength;
+
+  report_blocks_.resize(report_blocks_count);
+  for (ReportBlock& block : report_blocks_) {
+    block.Parse(next_report_block, ReportBlock::kLength);
+    next_report_block += ReportBlock::kLength;
+  }
+
+  RTC_DCHECK_LE(next_report_block - packet.payload(),
+                static_cast<ptrdiff_t>(packet.payload_size_bytes()));
+  return true;
+}
+
+size_t ReceiverReport::BlockLength() const {
+  return kHeaderLength + kRrBaseLength +
+         report_blocks_.size() * ReportBlock::kLength;
+}
+
+bool ReceiverReport::Create(uint8_t* packet,
+                            size_t* index,
+                            size_t max_length,
+                            PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet,
+               index);
+  ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc_);
+  *index += kRrBaseLength;
+  for (const ReportBlock& block : report_blocks_) {
+    block.Create(packet + *index);
+    *index += ReportBlock::kLength;
+  }
+  return true;
+}
+
+bool ReceiverReport::AddReportBlock(const ReportBlock& block) {
+  if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
+    RTC_LOG(LS_WARNING) << "Max report blocks reached.";
+    return false;
+  }
+  report_blocks_.push_back(block);
+  return true;
+}
+
+bool ReceiverReport::SetReportBlocks(std::vector<ReportBlock> blocks) {
+  if (blocks.size() > kMaxNumberOfReportBlocks) {
+    RTC_LOG(LS_WARNING) << "Too many report blocks (" << blocks.size()
+                        << ") for receiver report.";
+    return false;
+  }
+  report_blocks_ = std::move(blocks);
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h b/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h
new file mode 100644
index 0000000..3dc7920
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class ReceiverReport : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 201;
+  static constexpr size_t kMaxNumberOfReportBlocks = 0x1f;
+
+  ReceiverReport();
+  ~ReceiverReport() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+  bool AddReportBlock(const ReportBlock& block);
+  bool SetReportBlocks(std::vector<ReportBlock> blocks);
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  const std::vector<ReportBlock>& report_blocks() const {
+    return report_blocks_;
+  }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static const size_t kRrBaseLength = 4;
+
+  uint32_t sender_ssrc_;
+  std::vector<ReportBlock> report_blocks_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RECEIVER_REPORT_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc
new file mode 100644
index 0000000..fb434d9
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc
@@ -0,0 +1,161 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+
+#include <utility>
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::IsEmpty;
+using testing::make_tuple;
+using webrtc::rtcp::ReceiverReport;
+using webrtc::rtcp::ReportBlock;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kFractionLost = 55;
+const int32_t kCumulativeLost = 0x111213;
+const uint32_t kExtHighestSeqNum = 0x22232425;
+const uint32_t kJitter = 0x33343536;
+const uint32_t kLastSr = 0x44454647;
+const uint32_t kDelayLastSr = 0x55565758;
+// Manually created ReceiverReport with one ReportBlock matching constants
+// above.
+// Having this block allows to test Create and Parse separately.
+const uint8_t kPacket[] = {0x81, 201,  0x00, 0x07, 0x12, 0x34, 0x56, 0x78,
+                           0x23, 0x45, 0x67, 0x89, 55,   0x11, 0x12, 0x13,
+                           0x22, 0x23, 0x24, 0x25, 0x33, 0x34, 0x35, 0x36,
+                           0x44, 0x45, 0x46, 0x47, 0x55, 0x56, 0x57, 0x58};
+}  // namespace
+
+TEST(RtcpPacketReceiverReportTest, ParseWithOneReportBlock) {
+  ReceiverReport rr;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &rr));
+  const ReceiverReport& parsed = rr;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(1u, parsed.report_blocks().size());
+  const ReportBlock& rb = parsed.report_blocks().front();
+  EXPECT_EQ(kRemoteSsrc, rb.source_ssrc());
+  EXPECT_EQ(kFractionLost, rb.fraction_lost());
+  EXPECT_EQ(kCumulativeLost, rb.cumulative_lost_signed());
+  EXPECT_EQ(kExtHighestSeqNum, rb.extended_high_seq_num());
+  EXPECT_EQ(kJitter, rb.jitter());
+  EXPECT_EQ(kLastSr, rb.last_sr());
+  EXPECT_EQ(kDelayLastSr, rb.delay_since_last_sr());
+}
+
+TEST(RtcpPacketReceiverReportTest, ParseFailsOnIncorrectSize) {
+  rtc::Buffer damaged_packet(kPacket);
+  damaged_packet[0]++;  // Damage the packet: increase count field.
+  ReceiverReport rr;
+  EXPECT_FALSE(test::ParseSinglePacket(damaged_packet, &rr));
+}
+
+TEST(RtcpPacketReceiverReportTest, CreateWithOneReportBlock) {
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  ReportBlock rb;
+  rb.SetMediaSsrc(kRemoteSsrc);
+  rb.SetFractionLost(kFractionLost);
+  rb.SetCumulativeLost(kCumulativeLost);
+  rb.SetExtHighestSeqNum(kExtHighestSeqNum);
+  rb.SetJitter(kJitter);
+  rb.SetLastSr(kLastSr);
+  rb.SetDelayLastSr(kDelayLastSr);
+  rr.AddReportBlock(rb);
+
+  rtc::Buffer raw = rr.Build();
+
+  EXPECT_THAT(make_tuple(raw.data(), raw.size()), ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketReceiverReportTest, CreateAndParseWithoutReportBlocks) {
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+
+  rtc::Buffer raw = rr.Build();
+  ReceiverReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_THAT(parsed.report_blocks(), IsEmpty());
+}
+
+TEST(RtcpPacketReceiverReportTest, CreateAndParseWithTwoReportBlocks) {
+  ReceiverReport rr;
+  ReportBlock rb1;
+  rb1.SetMediaSsrc(kRemoteSsrc);
+  ReportBlock rb2;
+  rb2.SetMediaSsrc(kRemoteSsrc + 1);
+
+  rr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(rr.AddReportBlock(rb1));
+  EXPECT_TRUE(rr.AddReportBlock(rb2));
+
+  rtc::Buffer raw = rr.Build();
+  ReceiverReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(2u, parsed.report_blocks().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.report_blocks()[0].source_ssrc());
+  EXPECT_EQ(kRemoteSsrc + 1, parsed.report_blocks()[1].source_ssrc());
+}
+
+TEST(RtcpPacketReceiverReportTest, CreateWithTooManyReportBlocks) {
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  ReportBlock rb;
+  for (size_t i = 0; i < ReceiverReport::kMaxNumberOfReportBlocks; ++i) {
+    rb.SetMediaSsrc(kRemoteSsrc + i);
+    EXPECT_TRUE(rr.AddReportBlock(rb));
+  }
+  rb.SetMediaSsrc(kRemoteSsrc + ReceiverReport::kMaxNumberOfReportBlocks);
+  EXPECT_FALSE(rr.AddReportBlock(rb));
+}
+
+TEST(RtcpPacketReceiverReportTest, SetReportBlocksOverwritesOldBlocks) {
+  ReceiverReport rr;
+  ReportBlock report_block;
+  // Use jitter field of the report blocks to distinguish them.
+  report_block.SetJitter(1001u);
+  rr.AddReportBlock(report_block);
+  ASSERT_EQ(rr.report_blocks().size(), 1u);
+  ASSERT_EQ(rr.report_blocks()[0].jitter(), 1001u);
+
+  std::vector<ReportBlock> blocks(3u);
+  blocks[0].SetJitter(2001u);
+  blocks[1].SetJitter(3001u);
+  blocks[2].SetJitter(4001u);
+  EXPECT_TRUE(rr.SetReportBlocks(blocks));
+  ASSERT_EQ(rr.report_blocks().size(), 3u);
+  EXPECT_EQ(rr.report_blocks()[0].jitter(), 2001u);
+  EXPECT_EQ(rr.report_blocks()[1].jitter(), 3001u);
+  EXPECT_EQ(rr.report_blocks()[2].jitter(), 4001u);
+}
+
+TEST(RtcpPacketReceiverReportTest, SetReportBlocksMaxLimit) {
+  ReceiverReport rr;
+  std::vector<ReportBlock> max_blocks(ReceiverReport::kMaxNumberOfReportBlocks);
+  EXPECT_TRUE(rr.SetReportBlocks(std::move(max_blocks)));
+
+  std::vector<ReportBlock> one_too_many_blocks(
+      ReceiverReport::kMaxNumberOfReportBlocks + 1);
+  EXPECT_FALSE(rr.SetReportBlocks(std::move(one_too_many_blocks)));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/remb.cc b/modules/rtp_rtcp/source/rtcp_packet/remb.cc
new file mode 100644
index 0000000..2b492af
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/remb.cc
@@ -0,0 +1,141 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Remb::kFeedbackMessageType;
+// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
+//
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |V=2|P| FMT=15  |   PT=206      |             length            |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  0 |                  SSRC of packet sender                        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                       Unused = 0                              |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |  Unique identifier 'R' 'E' 'M' 'B'                            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |  Num SSRC     | BR Exp    |  BR Mantissa                      |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |   SSRC feedback                                               |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    :  ...                                                          :
+
+Remb::Remb() : bitrate_bps_(0) {}
+
+Remb::~Remb() = default;
+
+bool Remb::Parse(const CommonHeader& packet) {
+  RTC_DCHECK(packet.type() == kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  if (packet.payload_size_bytes() < 16) {
+    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
+                        << " is too small for Remb packet.";
+    return false;
+  }
+  const uint8_t* const payload = packet.payload();
+  if (kUniqueIdentifier != ByteReader<uint32_t>::ReadBigEndian(&payload[8])) {
+    RTC_LOG(LS_WARNING) << "REMB identifier not found, not a REMB packet.";
+    return false;
+  }
+  uint8_t number_of_ssrcs = payload[12];
+  if (packet.payload_size_bytes() !=
+      kCommonFeedbackLength + (2 + number_of_ssrcs) * 4) {
+    RTC_LOG(LS_WARNING) << "Payload size " << packet.payload_size_bytes()
+                        << " does not match " << number_of_ssrcs << " ssrcs.";
+    return false;
+  }
+
+  ParseCommonFeedback(payload);
+  uint8_t exponenta = payload[13] >> 2;
+  uint64_t mantissa = (static_cast<uint32_t>(payload[13] & 0x03) << 16) |
+                      ByteReader<uint16_t>::ReadBigEndian(&payload[14]);
+  bitrate_bps_ = (mantissa << exponenta);
+  bool shift_overflow = (bitrate_bps_ >> exponenta) != mantissa;
+  if (shift_overflow) {
+    RTC_LOG(LS_ERROR) << "Invalid remb bitrate value : " << mantissa << "*2^"
+                      << static_cast<int>(exponenta);
+    return false;
+  }
+
+  const uint8_t* next_ssrc = payload + 16;
+  ssrcs_.clear();
+  ssrcs_.reserve(number_of_ssrcs);
+  for (uint8_t i = 0; i < number_of_ssrcs; ++i) {
+    ssrcs_.push_back(ByteReader<uint32_t>::ReadBigEndian(next_ssrc));
+    next_ssrc += sizeof(uint32_t);
+  }
+
+  return true;
+}
+
+bool Remb::SetSsrcs(std::vector<uint32_t> ssrcs) {
+  if (ssrcs.size() > kMaxNumberOfSsrcs) {
+    RTC_LOG(LS_WARNING) << "Not enough space for all given SSRCs.";
+    return false;
+  }
+  ssrcs_ = std::move(ssrcs);
+  return true;
+}
+
+size_t Remb::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength + (2 + ssrcs_.size()) * 4;
+}
+
+bool Remb::Create(uint8_t* packet,
+                  size_t* index,
+                  size_t max_length,
+                  PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  size_t index_end = *index + BlockLength();
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               index);
+  RTC_DCHECK_EQ(0, Psfb::media_ssrc());
+  CreateCommonFeedback(packet + *index);
+  *index += kCommonFeedbackLength;
+
+  ByteWriter<uint32_t>::WriteBigEndian(packet + *index, kUniqueIdentifier);
+  *index += sizeof(uint32_t);
+  const uint32_t kMaxMantissa = 0x3ffff;  // 18 bits.
+  uint64_t mantissa = bitrate_bps_;
+  uint8_t exponenta = 0;
+  while (mantissa > kMaxMantissa) {
+    mantissa >>= 1;
+    ++exponenta;
+  }
+  packet[(*index)++] = static_cast<uint8_t>(ssrcs_.size());
+  packet[(*index)++] = (exponenta << 2) | (mantissa >> 16);
+  ByteWriter<uint16_t>::WriteBigEndian(packet + *index, mantissa & 0xffff);
+  *index += sizeof(uint16_t);
+
+  for (uint32_t ssrc : ssrcs_) {
+    ByteWriter<uint32_t>::WriteBigEndian(packet + *index, ssrc);
+    *index += sizeof(uint32_t);
+  }
+  RTC_DCHECK_EQ(index_end, *index);
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/remb.h b/modules/rtp_rtcp/source/rtcp_packet/remb.h
new file mode 100644
index 0000000..5f4aef8
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/remb.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMB_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMB_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet/psfb.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
+class Remb : public Psfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 15;
+  static constexpr size_t kMaxNumberOfSsrcs = 0xff;
+
+  Remb();
+  ~Remb() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  bool SetSsrcs(std::vector<uint32_t> ssrcs);
+  void SetBitrateBps(uint64_t bitrate_bps) { bitrate_bps_ = bitrate_bps; }
+
+  uint64_t bitrate_bps() const { return bitrate_bps_; }
+  const std::vector<uint32_t>& ssrcs() const { return ssrcs_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr uint32_t kUniqueIdentifier = 0x52454D42;  // 'R' 'E' 'M' 'B'.
+
+  // Media ssrc is unused, shadow base class setter and getter.
+  void SetMediaSsrc(uint32_t);
+  uint32_t media_ssrc() const;
+
+  uint64_t bitrate_bps_;
+  std::vector<uint32_t> ssrcs_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMB_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc
new file mode 100644
index 0000000..c939d9b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/remb_unittest.cc
@@ -0,0 +1,128 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::IsEmpty;
+using testing::make_tuple;
+using webrtc::rtcp::Remb;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrcs[] = {0x23456789, 0x2345678a, 0x2345678b};
+const uint32_t kBitrateBps = 0x3fb93 * 2;  // 522022;
+const uint64_t kBitrateBps64bit = 0x3fb93ULL << 30;
+const uint8_t kPacket[] = {0x8f, 206,  0x00, 0x07, 0x12, 0x34, 0x56, 0x78,
+                           0x00, 0x00, 0x00, 0x00, 'R',  'E',  'M',  'B',
+                           0x03, 0x07, 0xfb, 0x93, 0x23, 0x45, 0x67, 0x89,
+                           0x23, 0x45, 0x67, 0x8a, 0x23, 0x45, 0x67, 0x8b};
+const size_t kPacketLength = sizeof(kPacket);
+}  // namespace
+
+TEST(RtcpPacketRembTest, Create) {
+  Remb remb;
+  remb.SetSenderSsrc(kSenderSsrc);
+  remb.SetSsrcs(
+      std::vector<uint32_t>(std::begin(kRemoteSsrcs), std::end(kRemoteSsrcs)));
+  remb.SetBitrateBps(kBitrateBps);
+
+  rtc::Buffer packet = remb.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketRembTest, Parse) {
+  Remb remb;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &remb));
+  const Remb& parsed = remb;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kBitrateBps, parsed.bitrate_bps());
+  EXPECT_THAT(parsed.ssrcs(), ElementsAreArray(kRemoteSsrcs));
+}
+
+TEST(RtcpPacketRembTest, CreateAndParseWithoutSsrcs) {
+  Remb remb;
+  remb.SetSenderSsrc(kSenderSsrc);
+  remb.SetBitrateBps(kBitrateBps);
+  rtc::Buffer packet = remb.Build();
+
+  Remb parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kBitrateBps, parsed.bitrate_bps());
+  EXPECT_THAT(parsed.ssrcs(), IsEmpty());
+}
+
+TEST(RtcpPacketRembTest, CreateAndParse64bitBitrate) {
+  Remb remb;
+  remb.SetBitrateBps(kBitrateBps64bit);
+  rtc::Buffer packet = remb.Build();
+
+  Remb parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+  EXPECT_EQ(kBitrateBps64bit, parsed.bitrate_bps());
+}
+
+TEST(RtcpPacketRembTest, ParseFailsOnTooSmallPacketToBeRemb) {
+  // Make it too small.
+  constexpr size_t kTooSmallSize = (1 + 3) * 4;
+  uint8_t packet[kTooSmallSize];
+  memcpy(packet, kPacket, kTooSmallSize);
+  packet[3] = 3;
+
+  Remb remb;
+  EXPECT_FALSE(test::ParseSinglePacket(packet, &remb));
+}
+
+TEST(RtcpPacketRembTest, ParseFailsWhenUniqueIdentifierIsNotRemb) {
+  uint8_t packet[kPacketLength];
+  memcpy(packet, kPacket, kPacketLength);
+  packet[12] = 'N';  // Swap 'R' -> 'N' in the 'REMB' unique identifier.
+
+  Remb remb;
+  EXPECT_FALSE(test::ParseSinglePacket(packet, &remb));
+}
+
+TEST(RtcpPacketRembTest, ParseFailsWhenBitrateDoNotFitIn64bits) {
+  uint8_t packet[kPacketLength];
+  memcpy(packet, kPacket, kPacketLength);
+  packet[17] |= 0xfc;  // Set exponenta component to maximum of 63.
+  packet[19] |= 0x02;  // Ensure mantissa is at least 2.
+
+  Remb remb;
+  EXPECT_FALSE(test::ParseSinglePacket(packet, &remb));
+}
+
+TEST(RtcpPacketRembTest, ParseFailsWhenSsrcCountMismatchLength) {
+  uint8_t packet[kPacketLength];
+  memcpy(packet, kPacket, kPacketLength);
+  packet[16]++;  // Swap 3 -> 4 in the ssrcs count.
+
+  Remb remb;
+  EXPECT_FALSE(test::ParseSinglePacket(packet, &remb));
+}
+
+TEST(RtcpPacketRembTest, TooManySsrcs) {
+  Remb remb;
+  EXPECT_FALSE(remb.SetSsrcs(
+      std::vector<uint32_t>(Remb::kMaxNumberOfSsrcs + 1, kRemoteSsrcs[0])));
+  EXPECT_TRUE(remb.SetSsrcs(
+      std::vector<uint32_t>(Remb::kMaxNumberOfSsrcs, kRemoteSsrcs[0])));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/report_block.cc b/modules/rtp_rtcp/source/rtcp_packet/report_block.cc
new file mode 100644
index 0000000..4f98963
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/report_block.cc
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
+//
+// RTCP report block (RFC 3550).
+//
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  0 |                 SSRC_1 (SSRC of first source)                 |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 | fraction lost |       cumulative number of packets lost       |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |           extended highest sequence number received           |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |                      interarrival jitter                      |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |                         last SR (LSR)                         |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 |                   delay since last SR (DLSR)                  |
+// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ReportBlock::ReportBlock()
+    : source_ssrc_(0),
+      fraction_lost_(0),
+      cumulative_lost_(0),
+      extended_high_seq_num_(0),
+      jitter_(0),
+      last_sr_(0),
+      delay_since_last_sr_(0) {}
+
+bool ReportBlock::Parse(const uint8_t* buffer, size_t length) {
+  RTC_DCHECK(buffer != nullptr);
+  if (length < ReportBlock::kLength) {
+    RTC_LOG(LS_ERROR) << "Report Block should be 24 bytes long";
+    return false;
+  }
+
+  source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]);
+  fraction_lost_ = buffer[4];
+  cumulative_lost_ = ByteReader<uint32_t, 3>::ReadBigEndian(&buffer[5]);
+  extended_high_seq_num_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+  jitter_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[12]);
+  last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[16]);
+  delay_since_last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[20]);
+
+  return true;
+}
+
+void ReportBlock::Create(uint8_t* buffer) const {
+  // Runtime check should be done while setting cumulative_lost.
+  RTC_DCHECK_LT(cumulative_lost_signed(),
+                (1 << 23));  // Have only 3 bytes for it.
+
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[0], source_ssrc());
+  ByteWriter<uint8_t>::WriteBigEndian(&buffer[4], fraction_lost());
+  ByteWriter<int32_t, 3>::WriteBigEndian(&buffer[5], cumulative_lost_signed());
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], extended_high_seq_num());
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[12], jitter());
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[16], last_sr());
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[20], delay_since_last_sr());
+}
+
+bool ReportBlock::SetCumulativeLost(int32_t cumulative_lost) {
+  // We have only 3 bytes to store it, and it's a signed value.
+  if (cumulative_lost >= (1 << 23) || cumulative_lost < -(1 << 23)) {
+    RTC_LOG(LS_WARNING)
+        << "Cumulative lost is too big to fit into Report Block";
+    return false;
+  }
+  cumulative_lost_ = cumulative_lost;
+  return true;
+}
+
+uint32_t ReportBlock::cumulative_lost() const {
+  if (cumulative_lost_ < 0) {
+    RTC_LOG(LS_VERBOSE) << "Ignoring negative value of cumulative_lost";
+    return 0;
+  }
+  return cumulative_lost_;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/report_block.h b/modules/rtp_rtcp/source/rtcp_packet/report_block.h
new file mode 100644
index 0000000..eb16640
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/report_block.h
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace webrtc {
+namespace rtcp {
+
+// A ReportBlock represents the Sender Report packet from
+// RFC 3550 section 6.4.1.
+class ReportBlock {
+ public:
+  static const size_t kLength = 24;
+
+  ReportBlock();
+  ~ReportBlock() {}
+
+  bool Parse(const uint8_t* buffer, size_t length);
+
+  // Fills buffer with the ReportBlock.
+  // Consumes ReportBlock::kLength bytes.
+  void Create(uint8_t* buffer) const;
+
+  void SetMediaSsrc(uint32_t ssrc) { source_ssrc_ = ssrc; }
+  void SetFractionLost(uint8_t fraction_lost) {
+    fraction_lost_ = fraction_lost;
+  }
+  bool SetCumulativeLost(int32_t cumulative_lost);
+  void SetExtHighestSeqNum(uint32_t ext_highest_seq_num) {
+    extended_high_seq_num_ = ext_highest_seq_num;
+  }
+  void SetJitter(uint32_t jitter) { jitter_ = jitter; }
+  void SetLastSr(uint32_t last_sr) { last_sr_ = last_sr; }
+  void SetDelayLastSr(uint32_t delay_last_sr) {
+    delay_since_last_sr_ = delay_last_sr;
+  }
+
+  uint32_t source_ssrc() const { return source_ssrc_; }
+  uint8_t fraction_lost() const { return fraction_lost_; }
+  int32_t cumulative_lost_signed() const { return cumulative_lost_; }
+  // Deprecated - returns max(0, cumulative_lost_), not negative values.
+  uint32_t cumulative_lost() const;
+  uint32_t extended_high_seq_num() const { return extended_high_seq_num_; }
+  uint32_t jitter() const { return jitter_; }
+  uint32_t last_sr() const { return last_sr_; }
+  uint32_t delay_since_last_sr() const { return delay_since_last_sr_; }
+
+ private:
+  uint32_t source_ssrc_;     // 32 bits
+  uint8_t fraction_lost_;    // 8 bits representing a fixed point value 0..1
+  int32_t cumulative_lost_;  // Signed 24-bit value
+  uint32_t extended_high_seq_num_;  // 32 bits
+  uint32_t jitter_;                 // 32 bits
+  uint32_t last_sr_;                // 32 bits
+  uint32_t delay_since_last_sr_;    // 32 bits, units of 1/65536 seconds
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc
new file mode 100644
index 0000000..a074a2f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+
+#include <limits>
+
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+using webrtc::rtcp::ReportBlock;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kFractionLost = 55;
+// Use values that are streamed differently LE and BE.
+const int32_t kCumulativeLost = 0x111213;
+const uint32_t kExtHighestSeqNum = 0x22232425;
+const uint32_t kJitter = 0x33343536;
+const uint32_t kLastSr = 0x44454647;
+const uint32_t kDelayLastSr = 0x55565758;
+const size_t kBufferLength = ReportBlock::kLength;
+
+TEST(RtcpPacketReportBlockTest, ParseChecksLength) {
+  uint8_t buffer[kBufferLength];
+  memset(buffer, 0, sizeof(buffer));
+
+  ReportBlock rb;
+  EXPECT_FALSE(rb.Parse(buffer, kBufferLength - 1));
+  EXPECT_TRUE(rb.Parse(buffer, kBufferLength));
+}
+
+TEST(RtcpPacketReportBlockTest, ParseAnyData) {
+  uint8_t buffer[kBufferLength];
+  // Fill buffer with semi-random data.
+  Random generator(0x256F8A285EC829ull);
+  for (size_t i = 0; i < kBufferLength; ++i)
+    buffer[i] = static_cast<uint8_t>(generator.Rand(0, 0xff));
+
+  ReportBlock rb;
+  EXPECT_TRUE(rb.Parse(buffer, kBufferLength));
+}
+
+TEST(RtcpPacketReportBlockTest, ParseMatchCreate) {
+  ReportBlock rb;
+  rb.SetMediaSsrc(kRemoteSsrc);
+  rb.SetFractionLost(kFractionLost);
+  rb.SetCumulativeLost(kCumulativeLost);
+  rb.SetExtHighestSeqNum(kExtHighestSeqNum);
+  rb.SetJitter(kJitter);
+  rb.SetLastSr(kLastSr);
+  rb.SetDelayLastSr(kDelayLastSr);
+
+  uint8_t buffer[kBufferLength];
+  rb.Create(buffer);
+
+  ReportBlock parsed;
+  EXPECT_TRUE(parsed.Parse(buffer, kBufferLength));
+
+  EXPECT_EQ(kRemoteSsrc, parsed.source_ssrc());
+  EXPECT_EQ(kFractionLost, parsed.fraction_lost());
+  EXPECT_EQ(kCumulativeLost, parsed.cumulative_lost_signed());
+  EXPECT_EQ(kExtHighestSeqNum, parsed.extended_high_seq_num());
+  EXPECT_EQ(kJitter, parsed.jitter());
+  EXPECT_EQ(kLastSr, parsed.last_sr());
+  EXPECT_EQ(kDelayLastSr, parsed.delay_since_last_sr());
+}
+
+TEST(RtcpPacketReportBlockTest, ValidateCumulativeLost) {
+  // CumulativeLost is a signed 24-bit integer.
+  // However, existing code expects it to be an unsigned integer.
+  // The case of negative values should be unusual; we return 0
+  // when caller wants an unsigned integer.
+  const int32_t kMaxCumulativeLost = 0x7fffff;
+  const int32_t kMinCumulativeLost = -0x800000;
+  ReportBlock rb;
+  EXPECT_FALSE(rb.SetCumulativeLost(kMaxCumulativeLost + 1));
+  EXPECT_TRUE(rb.SetCumulativeLost(kMaxCumulativeLost));
+  EXPECT_FALSE(rb.SetCumulativeLost(kMinCumulativeLost - 1));
+  EXPECT_TRUE(rb.SetCumulativeLost(kMinCumulativeLost));
+  EXPECT_EQ(kMinCumulativeLost, rb.cumulative_lost_signed());
+  EXPECT_EQ(0u, rb.cumulative_lost());
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc b/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc
new file mode 100644
index 0000000..95fc890
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rrtr.cc
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rtcp {
+// Receiver Reference Time Report Block (RFC 3611).
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=4      |   reserved    |       block length = 2        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |              NTP timestamp, most significant word             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |             NTP timestamp, least significant word             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+void Rrtr::Parse(const uint8_t* buffer) {
+  RTC_DCHECK(buffer[0] == kBlockType);
+  // reserved = buffer[1];
+  RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength);
+  uint32_t seconds = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+  uint32_t fraction = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+  ntp_.Set(seconds, fraction);
+}
+
+void Rrtr::Create(uint8_t* buffer) const {
+  const uint8_t kReserved = 0;
+  buffer[0] = kBlockType;
+  buffer[1] = kReserved;
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength);
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ntp_.seconds());
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], ntp_.fractions());
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rrtr.h b/modules/rtp_rtcp/source/rtcp_packet/rrtr.h
new file mode 100644
index 0000000..a470b1a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rrtr.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_
+
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class Rrtr {
+ public:
+  static const uint8_t kBlockType = 4;
+  static const uint16_t kBlockLength = 2;
+  static const size_t kLength = 4 * (kBlockLength + 1);  // 12
+
+  Rrtr() {}
+  Rrtr(const Rrtr&) = default;
+  ~Rrtr() {}
+
+  Rrtr& operator=(const Rrtr&) = default;
+
+  void Parse(const uint8_t* buffer);
+
+  // Fills buffer with the Rrtr.
+  // Consumes Rrtr::kLength bytes.
+  void Create(uint8_t* buffer) const;
+
+  void SetNtp(NtpTime ntp) { ntp_ = ntp; }
+
+  NtpTime ntp() const { return ntp_; }
+
+ private:
+  NtpTime ntp_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RRTR_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc
new file mode 100644
index 0000000..56622ea
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rrtr_unittest.cc
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h"
+
+#include "test/gtest.h"
+
+using webrtc::rtcp::Rrtr;
+
+namespace webrtc {
+namespace {
+
+const uint32_t kNtpSec = 0x12345678;
+const uint32_t kNtpFrac = 0x23456789;
+const uint8_t kBlock[] = {0x04, 0x00, 0x00, 0x02, 0x12, 0x34,
+                          0x56, 0x78, 0x23, 0x45, 0x67, 0x89};
+const size_t kBlockSizeBytes = sizeof(kBlock);
+static_assert(
+    kBlockSizeBytes == Rrtr::kLength,
+    "Size of manually created Rrtr block should match class constant");
+
+TEST(RtcpPacketRrtrTest, Create) {
+  uint8_t buffer[Rrtr::kLength];
+  Rrtr rrtr;
+  rrtr.SetNtp(NtpTime(kNtpSec, kNtpFrac));
+
+  rrtr.Create(buffer);
+  EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
+}
+
+TEST(RtcpPacketRrtrTest, Parse) {
+  Rrtr read_rrtr;
+  read_rrtr.Parse(kBlock);
+
+  // Run checks on const object to ensure all accessors have const modifier.
+  const Rrtr& parsed = read_rrtr;
+
+  EXPECT_EQ(kNtpSec, parsed.ntp().seconds());
+  EXPECT_EQ(kNtpFrac, parsed.ntp().fractions());
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc b/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc
new file mode 100644
index 0000000..9b13e9a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rtpfb.cc
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Rtpfb::kPacketType;
+// RFC 4585, Section 6.1: Feedback format.
+//
+// Common packet format:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |V=2|P|   FMT   |       PT      |          length               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 |                  SSRC of packet sender                        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 |                  SSRC of media source                         |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   :            Feedback Control Information (FCI)                 :
+//   :                                                               :
+
+void Rtpfb::ParseCommonFeedback(const uint8_t* payload) {
+  sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+  media_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+}
+
+void Rtpfb::CreateCommonFeedback(uint8_t* payload) const {
+  ByteWriter<uint32_t>::WriteBigEndian(&payload[0], sender_ssrc_);
+  ByteWriter<uint32_t>::WriteBigEndian(&payload[4], media_ssrc_);
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h b/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h
new file mode 100644
index 0000000..a040741
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/rtpfb.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+
+// RTPFB: Transport layer feedback message.
+// RFC4585, Section 6.2
+class Rtpfb : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 205;
+
+  Rtpfb() : sender_ssrc_(0), media_ssrc_(0) {}
+  ~Rtpfb() override {}
+
+  void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+  void SetMediaSsrc(uint32_t ssrc) { media_ssrc_ = ssrc; }
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  uint32_t media_ssrc() const { return media_ssrc_; }
+
+ protected:
+  static constexpr size_t kCommonFeedbackLength = 8;
+  void ParseCommonFeedback(const uint8_t* payload);
+  void CreateCommonFeedback(uint8_t* payload) const;
+
+ private:
+  uint32_t sender_ssrc_;
+  uint32_t media_ssrc_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_RTPFB_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/sdes.cc b/modules/rtp_rtcp/source/rtcp_packet/sdes.cc
new file mode 100644
index 0000000..337c8b0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/sdes.cc
@@ -0,0 +1,196 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Sdes::kPacketType;
+constexpr size_t Sdes::kMaxNumberOfChunks;
+// Source Description (SDES) (RFC 3550).
+//
+//         0                   1                   2                   3
+//         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// header |V=2|P|    SC   |  PT=SDES=202  |             length            |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_1                          |
+//   1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// chunk  |                          SSRC/CSRC_2                          |
+//   2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//        |                           SDES items                          |
+//        |                              ...                              |
+//        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//
+// Canonical End-Point Identifier SDES Item (CNAME)
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |    CNAME=1    |     length    | user and domain name        ...
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+namespace {
+const uint8_t kTerminatorTag = 0;
+const uint8_t kCnameTag = 1;
+
+size_t ChunkSize(const Sdes::Chunk& chunk) {
+  // Chunk:
+  // SSRC/CSRC (4 bytes) | CNAME=1 (1 byte) | length (1 byte) | cname | padding.
+  size_t chunk_payload_size = 4 + 1 + 1 + chunk.cname.size();
+  size_t padding_size = 4 - (chunk_payload_size % 4);  // Minimum 1.
+  return chunk_payload_size + padding_size;
+}
+}  // namespace
+
+Sdes::Sdes() : block_length_(RtcpPacket::kHeaderLength) {}
+
+Sdes::~Sdes() {}
+
+bool Sdes::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+
+  uint8_t number_of_chunks = packet.count();
+  std::vector<Chunk> chunks;  // Read chunk into temporary array, so that in
+                              // case of an error original array would stay
+                              // unchanged.
+  size_t block_length = kHeaderLength;
+
+  if (packet.payload_size_bytes() % 4 != 0) {
+    RTC_LOG(LS_WARNING) << "Invalid payload size "
+                        << packet.payload_size_bytes()
+                        << " bytes for a valid Sdes packet. Size should be"
+                           " multiple of 4 bytes";
+  }
+  const uint8_t* const payload_end =
+      packet.payload() + packet.payload_size_bytes();
+  const uint8_t* looking_at = packet.payload();
+  chunks.resize(number_of_chunks);
+  for (size_t i = 0; i < number_of_chunks;) {
+    // Each chunk consumes at least 8 bytes.
+    if (payload_end - looking_at < 8) {
+      RTC_LOG(LS_WARNING) << "Not enough space left for chunk #" << (i + 1);
+      return false;
+    }
+    chunks[i].ssrc = ByteReader<uint32_t>::ReadBigEndian(looking_at);
+    looking_at += sizeof(uint32_t);
+    bool cname_found = false;
+
+    uint8_t item_type;
+    while ((item_type = *(looking_at++)) != kTerminatorTag) {
+      if (looking_at >= payload_end) {
+        RTC_LOG(LS_WARNING)
+            << "Unexpected end of packet while reading chunk #" << (i + 1)
+            << ". Expected to find size of the text.";
+        return false;
+      }
+      uint8_t item_length = *(looking_at++);
+      const size_t kTerminatorSize = 1;
+      if (looking_at + item_length + kTerminatorSize > payload_end) {
+        RTC_LOG(LS_WARNING)
+            << "Unexpected end of packet while reading chunk #" << (i + 1)
+            << ". Expected to find text of size " << item_length;
+        return false;
+      }
+      if (item_type == kCnameTag) {
+        if (cname_found) {
+          RTC_LOG(LS_WARNING)
+              << "Found extra CNAME for same ssrc in chunk #" << (i + 1);
+          return false;
+        }
+        cname_found = true;
+        chunks[i].cname.assign(reinterpret_cast<const char*>(looking_at),
+                               item_length);
+      }
+      looking_at += item_length;
+    }
+    if (cname_found) {
+      // block_length calculates length of the packet that would be generated by
+      // Build/Create functions. Adjust it same way WithCName function does.
+      block_length += ChunkSize(chunks[i]);
+      ++i;
+    } else {
+      // RFC states CNAME item is mandatory.
+      // But same time it allows chunk without items.
+      // So while parsing, ignore all chunks without cname,
+      // but do not fail the parse.
+      RTC_LOG(LS_WARNING) << "CNAME not found for ssrc " << chunks[i].ssrc;
+      --number_of_chunks;
+      chunks.resize(number_of_chunks);
+    }
+    // Adjust to 32bit boundary.
+    looking_at += (payload_end - looking_at) % 4;
+  }
+
+  chunks_ = std::move(chunks);
+  block_length_ = block_length;
+  return true;
+}
+
+bool Sdes::AddCName(uint32_t ssrc, std::string cname) {
+  RTC_DCHECK_LE(cname.length(), 0xffu);
+  if (chunks_.size() >= kMaxNumberOfChunks) {
+    RTC_LOG(LS_WARNING) << "Max SDES chunks reached.";
+    return false;
+  }
+  Chunk chunk;
+  chunk.ssrc = ssrc;
+  chunk.cname = std::move(cname);
+  chunks_.push_back(chunk);
+  block_length_ += ChunkSize(chunk);
+  return true;
+}
+
+size_t Sdes::BlockLength() const {
+  return block_length_;
+}
+
+bool Sdes::Create(uint8_t* packet,
+                  size_t* index,
+                  size_t max_length,
+                  PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+  CreateHeader(chunks_.size(), kPacketType, HeaderLength(), packet, index);
+
+  for (const Sdes::Chunk& chunk : chunks_) {
+    ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], chunk.ssrc);
+    ByteWriter<uint8_t>::WriteBigEndian(&packet[*index + 4], kCnameTag);
+    ByteWriter<uint8_t>::WriteBigEndian(
+        &packet[*index + 5], static_cast<uint8_t>(chunk.cname.size()));
+    memcpy(&packet[*index + 6], chunk.cname.data(), chunk.cname.size());
+    *index += (6 + chunk.cname.size());
+
+    // In each chunk, the list of items must be terminated by one or more null
+    // octets. The next chunk must start on a 32-bit boundary.
+    // CNAME (1 byte) | length (1 byte) | name | padding.
+    size_t padding_size = 4 - ((6 + chunk.cname.size()) % 4);
+    const int kPadding = 0;
+    memset(packet + *index, kPadding, padding_size);
+    *index += padding_size;
+  }
+
+  RTC_CHECK_EQ(*index, index_end);
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/sdes.h b/modules/rtp_rtcp/source/rtcp_packet/sdes.h
new file mode 100644
index 0000000..70e9385
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/sdes.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
+
+#include <string>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+// Source Description (SDES) (RFC 3550).
+class Sdes : public RtcpPacket {
+ public:
+  struct Chunk {
+    uint32_t ssrc;
+    std::string cname;
+  };
+  static constexpr uint8_t kPacketType = 202;
+  static constexpr size_t kMaxNumberOfChunks = 0x1f;
+
+  Sdes();
+  ~Sdes() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  bool AddCName(uint32_t ssrc, std::string cname);
+
+  const std::vector<Chunk>& chunks() const { return chunks_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  std::vector<Chunk> chunks_;
+  size_t block_length_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc
new file mode 100644
index 0000000..b903a4e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/sdes_unittest.cc
@@ -0,0 +1,243 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using webrtc::rtcp::Sdes;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint8_t kPadding = 0;
+const uint8_t kTerminatorTag = 0;
+const uint8_t kCnameTag = 1;
+const uint8_t kNameTag = 2;
+const uint8_t kEmailTag = 3;
+}  // namespace
+
+TEST(RtcpPacketSdesTest, CreateAndParseWithoutChunks) {
+  Sdes sdes;
+
+  rtc::Buffer packet = sdes.Build();
+  Sdes parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(0u, parsed.chunks().size());
+}
+
+TEST(RtcpPacketSdesTest, CreateAndParseWithOneChunk) {
+  const std::string kCname = "alice@host";
+
+  Sdes sdes;
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc, kCname));
+
+  rtc::Buffer packet = sdes.Build();
+  Sdes sdes_parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &sdes_parsed));
+  const Sdes& parsed = sdes_parsed;  // Ensure accessors are const.
+
+  EXPECT_EQ(1u, parsed.chunks().size());
+  EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
+  EXPECT_EQ(kCname, parsed.chunks()[0].cname);
+}
+
+TEST(RtcpPacketSdesTest, CreateAndParseWithMultipleChunks) {
+  Sdes sdes;
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 0, "a"));
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 1, "ab"));
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 2, "abc"));
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 3, "abcd"));
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 4, "abcde"));
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc + 5, "abcdef"));
+
+  rtc::Buffer packet = sdes.Build();
+  Sdes parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(6u, parsed.chunks().size());
+  EXPECT_EQ(kSenderSsrc + 5, parsed.chunks()[5].ssrc);
+  EXPECT_EQ("abcdef", parsed.chunks()[5].cname);
+}
+
+TEST(RtcpPacketSdesTest, CreateWithTooManyChunks) {
+  const size_t kMaxChunks = (1 << 5) - 1;
+  Sdes sdes;
+  for (size_t i = 0; i < kMaxChunks; ++i) {
+    uint32_t ssrc = kSenderSsrc + i;
+    std::ostringstream oss;
+    oss << "cname" << i;
+    EXPECT_TRUE(sdes.AddCName(ssrc, oss.str()));
+  }
+  EXPECT_FALSE(sdes.AddCName(kSenderSsrc + kMaxChunks, "foo"));
+}
+
+TEST(RtcpPacketSdesTest, CreateAndParseCnameItemWithEmptyString) {
+  Sdes sdes;
+  EXPECT_TRUE(sdes.AddCName(kSenderSsrc, ""));
+
+  rtc::Buffer packet = sdes.Build();
+  Sdes parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(1u, parsed.chunks().size());
+  EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
+  EXPECT_EQ("", parsed.chunks()[0].cname);
+}
+
+TEST(RtcpPacketSdesTest, ParseSkipsNonCNameField) {
+  const uint8_t kName[] = "abc";
+  const uint8_t kCname[] = "de";
+  const uint8_t kValidPacket[] = {
+      0x81, 202,       0x00,      0x04,           0x12,     0x34,     0x56,
+      0x78, kNameTag,  3,         kName[0],       kName[1], kName[2], kCnameTag,
+      2,    kCname[0], kCname[1], kTerminatorTag, kPadding, kPadding};
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kValidPacket) % 4);
+  ASSERT_EQ(kValidPacket[3] + 1u, sizeof(kValidPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kValidPacket, &parsed));
+
+  EXPECT_EQ(1u, parsed.chunks().size());
+  EXPECT_EQ(kSenderSsrc, parsed.chunks()[0].ssrc);
+  EXPECT_EQ("de", parsed.chunks()[0].cname);
+}
+
+TEST(RtcpPacketSdesTest, ParseSkipsChunksWithoutCName) {
+  const uint8_t kName[] = "ab";
+  const uint8_t kEmail[] = "de";
+  const uint8_t kCname[] = "def";
+  const uint8_t kPacket[] = {
+      0x82,           202,      0x00,      0x07,      0x12,
+      0x34,           0x56,     0x78,  // 1st chunk.
+      kNameTag,       3,        kName[0],  kName[1],  kName[2],
+      kEmailTag,      2,        kEmail[0], kEmail[1], kTerminatorTag,
+      kPadding,       kPadding, 0x23,      0x45,      0x67,
+      0x89,  // 2nd chunk.
+      kCnameTag,      3,        kCname[0], kCname[1], kCname[2],
+      kTerminatorTag, kPadding, kPadding};
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kPacket) % 4);
+  ASSERT_EQ(kPacket[3] + 1u, sizeof(kPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed));
+  ASSERT_EQ(1u, parsed.chunks().size());
+  EXPECT_EQ(0x23456789u, parsed.chunks()[0].ssrc);
+  EXPECT_EQ("def", parsed.chunks()[0].cname);
+}
+
+TEST(RtcpPacketSdesTest, ParseFailsWithoutChunkItemTerminator) {
+  const uint8_t kName[] = "abc";
+  const uint8_t kCname[] = "d";
+  // No place for next chunk item.
+  const uint8_t kInvalidPacket[] = {
+      0x81,     202, 0x00,     0x03,     0x12,     0x34,      0x56, 0x78,
+      kNameTag, 3,   kName[0], kName[1], kName[2], kCnameTag, 1,    kCname[0]};
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
+  ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
+}
+
+TEST(RtcpPacketSdesTest, ParseFailsWithDamagedChunkItem) {
+  const uint8_t kName[] = "ab";
+  const uint8_t kCname[] = "d";
+  // Next chunk item has non-terminator type, but not the size.
+  const uint8_t kInvalidPacket[] = {
+      0x81,     202, 0x00,     0x03,     0x12,      0x34, 0x56,      0x78,
+      kNameTag, 2,   kName[0], kName[1], kCnameTag, 1,    kCname[0], kEmailTag};
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
+  ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
+}
+
+TEST(RtcpPacketSdesTest, ParseFailsWithTooLongChunkItem) {
+  const uint8_t kName[] = "abc";
+  const uint8_t kCname[] = "d";
+  // Last chunk item has length that goes beyond the buffer end.
+  const uint8_t kInvalidPacket[] = {
+      0x81,     202, 0x00,     0x03,     0x12,     0x34,      0x56, 0x78,
+      kNameTag, 3,   kName[0], kName[1], kName[2], kCnameTag, 2,    kCname[0]};
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
+  ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
+}
+
+TEST(RtcpPacketSdesTest, ParseFailsWithTwoCNames) {
+  const uint8_t kCname1[] = "a";
+  const uint8_t kCname2[] = "de";
+  const uint8_t kInvalidPacket[] = {
+      0x81,       202,           0x00, 0x03,       0x12,      0x34, 0x56,
+      0x78,       kCnameTag,     1,    kCname1[0], kCnameTag, 2,    kCname2[0],
+      kCname2[1], kTerminatorTag};
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
+  ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
+}
+
+TEST(RtcpPacketSdesTest, ParseFailsWithTooLittleSpaceForNextChunk) {
+  const uint8_t kCname[] = "a";
+  const uint8_t kEmail[] = "de";
+  // Two chunks are promised in the header, but no place for the second chunk.
+  const uint8_t kInvalidPacket[] = {
+      0x82,           202,  0x00,      0x04,      0x12, 0x34,      0x56,
+      0x78,  // 1st chunk.
+      kCnameTag,      1,    kCname[0], kEmailTag, 2,    kEmail[0], kEmail[1],
+      kTerminatorTag, 0x23, 0x45,      0x67,      0x89};  // 2nd chunk.
+  // Sanity checks packet was assembled correctly.
+  ASSERT_EQ(0u, sizeof(kInvalidPacket) % 4);
+  ASSERT_EQ(kInvalidPacket[3] + 1u, sizeof(kInvalidPacket) / 4);
+
+  Sdes parsed;
+  EXPECT_FALSE(test::ParseSinglePacket(kInvalidPacket, &parsed));
+}
+
+TEST(RtcpPacketSdesTest, ParsedSdesCanBeReusedForBuilding) {
+  Sdes source;
+  const std::string kAlice = "alice@host";
+  const std::string kBob = "bob@host";
+  source.AddCName(kSenderSsrc, kAlice);
+
+  rtc::Buffer packet1 = source.Build();
+  Sdes middle;
+  test::ParseSinglePacket(packet1, &middle);
+
+  EXPECT_EQ(source.BlockLength(), middle.BlockLength());
+
+  middle.AddCName(kSenderSsrc + 1, kBob);
+
+  rtc::Buffer packet2 = middle.Build();
+  Sdes destination;
+  test::ParseSinglePacket(packet2, &destination);
+
+  EXPECT_EQ(middle.BlockLength(), destination.BlockLength());
+
+  EXPECT_EQ(2u, destination.chunks().size());
+  EXPECT_EQ(kSenderSsrc, destination.chunks()[0].ssrc);
+  EXPECT_EQ(kAlice, destination.chunks()[0].cname);
+  EXPECT_EQ(kSenderSsrc + 1, destination.chunks()[1].ssrc);
+  EXPECT_EQ(kBob, destination.chunks()[1].cname);
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc b/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc
new file mode 100644
index 0000000..e524aea
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/sender_report.cc
@@ -0,0 +1,144 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t SenderReport::kPacketType;
+constexpr size_t SenderReport::kMaxNumberOfReportBlocks;
+constexpr size_t SenderReport::kSenderBaseLength;
+//    Sender report (SR) (RFC 3550).
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |V=2|P|    RC   |   PT=SR=200   |             length            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |                         SSRC of sender                        |
+//    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//  4 |              NTP timestamp, most significant word             |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |             NTP timestamp, least significant word             |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |                         RTP timestamp                         |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |                     sender's packet count                     |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 |                      sender's octet count                     |
+// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+
+SenderReport::SenderReport()
+    : sender_ssrc_(0),
+      rtp_timestamp_(0),
+      sender_packet_count_(0),
+      sender_octet_count_(0) {}
+
+SenderReport::SenderReport(const SenderReport&) = default;
+SenderReport::SenderReport(SenderReport&&) = default;
+SenderReport& SenderReport::operator=(const SenderReport&) = default;
+SenderReport& SenderReport::operator=(SenderReport&&) = default;
+SenderReport::~SenderReport() = default;
+
+bool SenderReport::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+
+  const uint8_t report_block_count = packet.count();
+  if (packet.payload_size_bytes() <
+      kSenderBaseLength + report_block_count * ReportBlock::kLength) {
+    RTC_LOG(LS_WARNING) << "Packet is too small to contain all the data.";
+    return false;
+  }
+  // Read SenderReport header.
+  const uint8_t* const payload = packet.payload();
+  sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
+  uint32_t secs = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
+  uint32_t frac = ByteReader<uint32_t>::ReadBigEndian(&payload[8]);
+  ntp_.Set(secs, frac);
+  rtp_timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&payload[12]);
+  sender_packet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[16]);
+  sender_octet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[20]);
+  report_blocks_.resize(report_block_count);
+  const uint8_t* next_block = payload + kSenderBaseLength;
+  for (ReportBlock& block : report_blocks_) {
+    bool block_parsed = block.Parse(next_block, ReportBlock::kLength);
+    RTC_DCHECK(block_parsed);
+    next_block += ReportBlock::kLength;
+  }
+  // Double check we didn't read beyond provided buffer.
+  RTC_DCHECK_LE(next_block - payload,
+                static_cast<ptrdiff_t>(packet.payload_size_bytes()));
+  return true;
+}
+
+size_t SenderReport::BlockLength() const {
+  return kHeaderLength + kSenderBaseLength +
+         report_blocks_.size() * ReportBlock::kLength;
+}
+
+bool SenderReport::Create(uint8_t* packet,
+                          size_t* index,
+                          size_t max_length,
+                          PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+
+  CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet,
+               index);
+  // Write SenderReport header.
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], sender_ssrc_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], ntp_.seconds());
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 8], ntp_.fractions());
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 12], rtp_timestamp_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 16],
+                                       sender_packet_count_);
+  ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 20],
+                                       sender_octet_count_);
+  *index += kSenderBaseLength;
+  // Write report blocks.
+  for (const ReportBlock& block : report_blocks_) {
+    block.Create(packet + *index);
+    *index += ReportBlock::kLength;
+  }
+  // Ensure bytes written match expected.
+  RTC_DCHECK_EQ(*index, index_end);
+  return true;
+}
+
+bool SenderReport::AddReportBlock(const ReportBlock& block) {
+  if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
+    RTC_LOG(LS_WARNING) << "Max report blocks reached.";
+    return false;
+  }
+  report_blocks_.push_back(block);
+  return true;
+}
+
+bool SenderReport::SetReportBlocks(std::vector<ReportBlock> blocks) {
+  if (blocks.size() > kMaxNumberOfReportBlocks) {
+    RTC_LOG(LS_WARNING) << "Too many report blocks (" << blocks.size()
+                        << ") for sender report.";
+    return false;
+  }
+  report_blocks_ = std::move(blocks);
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/sender_report.h b/modules/rtp_rtcp/source/rtcp_packet/sender_report.h
new file mode 100644
index 0000000..f1ee525
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/sender_report.h
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class SenderReport : public RtcpPacket {
+ public:
+  static constexpr uint8_t kPacketType = 200;
+  static constexpr size_t kMaxNumberOfReportBlocks = 0x1f;
+
+  SenderReport();
+  SenderReport(const SenderReport&);
+  SenderReport(SenderReport&&);
+  SenderReport& operator=(const SenderReport&);
+  SenderReport& operator=(SenderReport&&);
+  ~SenderReport() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
+  void SetNtp(NtpTime ntp) { ntp_ = ntp; }
+  void SetRtpTimestamp(uint32_t rtp_timestamp) {
+    rtp_timestamp_ = rtp_timestamp;
+  }
+  void SetPacketCount(uint32_t packet_count) {
+    sender_packet_count_ = packet_count;
+  }
+  void SetOctetCount(uint32_t octet_count) {
+    sender_octet_count_ = octet_count;
+  }
+  bool AddReportBlock(const ReportBlock& block);
+  bool SetReportBlocks(std::vector<ReportBlock> blocks);
+  void ClearReportBlocks() { report_blocks_.clear(); }
+
+  uint32_t sender_ssrc() const { return sender_ssrc_; }
+  NtpTime ntp() const { return ntp_; }
+  uint32_t rtp_timestamp() const { return rtp_timestamp_; }
+  uint32_t sender_packet_count() const { return sender_packet_count_; }
+  uint32_t sender_octet_count() const { return sender_octet_count_; }
+
+  const std::vector<ReportBlock>& report_blocks() const {
+    return report_blocks_;
+  }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  static constexpr size_t kSenderBaseLength = 24;
+
+  uint32_t sender_ssrc_;
+  NtpTime ntp_;
+  uint32_t rtp_timestamp_;
+  uint32_t sender_packet_count_;
+  uint32_t sender_octet_count_;
+  std::vector<ReportBlock> report_blocks_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SENDER_REPORT_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc
new file mode 100644
index 0000000..a0c6e72
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/sender_report_unittest.cc
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+
+#include <utility>
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::make_tuple;
+using webrtc::rtcp::ReportBlock;
+using webrtc::rtcp::SenderReport;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+const NtpTime kNtp(0x11121418, 0x22242628);
+const uint32_t kRtpTimestamp = 0x33343536;
+const uint32_t kPacketCount = 0x44454647;
+const uint32_t kOctetCount = 0x55565758;
+const uint8_t kPacket[] = {0x80, 200,  0x00, 0x06, 0x12, 0x34, 0x56,
+                           0x78, 0x11, 0x12, 0x14, 0x18, 0x22, 0x24,
+                           0x26, 0x28, 0x33, 0x34, 0x35, 0x36, 0x44,
+                           0x45, 0x46, 0x47, 0x55, 0x56, 0x57, 0x58};
+}  // namespace
+
+TEST(RtcpPacketSenderReportTest, CreateWithoutReportBlocks) {
+  SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  sr.SetNtp(kNtp);
+  sr.SetRtpTimestamp(kRtpTimestamp);
+  sr.SetPacketCount(kPacketCount);
+  sr.SetOctetCount(kOctetCount);
+
+  rtc::Buffer raw = sr.Build();
+  EXPECT_THAT(make_tuple(raw.data(), raw.size()), ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketSenderReportTest, ParseWithoutReportBlocks) {
+  SenderReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(kNtp, parsed.ntp());
+  EXPECT_EQ(kRtpTimestamp, parsed.rtp_timestamp());
+  EXPECT_EQ(kPacketCount, parsed.sender_packet_count());
+  EXPECT_EQ(kOctetCount, parsed.sender_octet_count());
+  EXPECT_TRUE(parsed.report_blocks().empty());
+}
+
+TEST(RtcpPacketSenderReportTest, CreateAndParseWithOneReportBlock) {
+  ReportBlock rb;
+  rb.SetMediaSsrc(kRemoteSsrc);
+
+  SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(sr.AddReportBlock(rb));
+
+  rtc::Buffer raw = sr.Build();
+  SenderReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(1u, parsed.report_blocks().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.report_blocks()[0].source_ssrc());
+}
+
+TEST(RtcpPacketSenderReportTest, CreateAndParseWithTwoReportBlocks) {
+  ReportBlock rb1;
+  rb1.SetMediaSsrc(kRemoteSsrc);
+  ReportBlock rb2;
+  rb2.SetMediaSsrc(kRemoteSsrc + 1);
+
+  SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(sr.AddReportBlock(rb1));
+  EXPECT_TRUE(sr.AddReportBlock(rb2));
+
+  rtc::Buffer raw = sr.Build();
+  SenderReport parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(raw, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(2u, parsed.report_blocks().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.report_blocks()[0].source_ssrc());
+  EXPECT_EQ(kRemoteSsrc + 1, parsed.report_blocks()[1].source_ssrc());
+}
+
+TEST(RtcpPacketSenderReportTest, CreateWithTooManyReportBlocks) {
+  SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  ReportBlock rb;
+  for (size_t i = 0; i < SenderReport::kMaxNumberOfReportBlocks; ++i) {
+    rb.SetMediaSsrc(kRemoteSsrc + i);
+    EXPECT_TRUE(sr.AddReportBlock(rb));
+  }
+  rb.SetMediaSsrc(kRemoteSsrc + SenderReport::kMaxNumberOfReportBlocks);
+  EXPECT_FALSE(sr.AddReportBlock(rb));
+}
+
+TEST(RtcpPacketSenderReportTest, SetReportBlocksOverwritesOldBlocks) {
+  SenderReport sr;
+  ReportBlock report_block;
+  // Use jitter field of the report blocks to distinguish them.
+  report_block.SetJitter(1001u);
+  sr.AddReportBlock(report_block);
+  ASSERT_EQ(sr.report_blocks().size(), 1u);
+  ASSERT_EQ(sr.report_blocks()[0].jitter(), 1001u);
+
+  std::vector<ReportBlock> blocks(3u);
+  blocks[0].SetJitter(2001u);
+  blocks[1].SetJitter(3001u);
+  blocks[2].SetJitter(4001u);
+  EXPECT_TRUE(sr.SetReportBlocks(blocks));
+  ASSERT_EQ(sr.report_blocks().size(), 3u);
+  EXPECT_EQ(sr.report_blocks()[0].jitter(), 2001u);
+  EXPECT_EQ(sr.report_blocks()[1].jitter(), 3001u);
+  EXPECT_EQ(sr.report_blocks()[2].jitter(), 4001u);
+}
+
+TEST(RtcpPacketSenderReportTest, SetReportBlocksMaxLimit) {
+  SenderReport sr;
+  std::vector<ReportBlock> max_blocks(SenderReport::kMaxNumberOfReportBlocks);
+  EXPECT_TRUE(sr.SetReportBlocks(std::move(max_blocks)));
+
+  std::vector<ReportBlock> one_too_many_blocks(
+      SenderReport::kMaxNumberOfReportBlocks + 1);
+  EXPECT_FALSE(sr.SetReportBlocks(std::move(one_too_many_blocks)));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc b/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc
new file mode 100644
index 0000000..601b24f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.cc
@@ -0,0 +1,127 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr size_t kTargetBitrateHeaderSizeBytes = 4;
+constexpr uint8_t TargetBitrate::kBlockType;
+const size_t TargetBitrate::kBitrateItemSizeBytes = 4;
+
+TargetBitrate::BitrateItem::BitrateItem()
+    : spatial_layer(0), temporal_layer(0), target_bitrate_kbps(0) {}
+
+TargetBitrate::BitrateItem::BitrateItem(uint8_t spatial_layer,
+                                        uint8_t temporal_layer,
+                                        uint32_t target_bitrate_kbps)
+    : spatial_layer(spatial_layer),
+      temporal_layer(temporal_layer),
+      target_bitrate_kbps(target_bitrate_kbps) {}
+
+//  RFC 4585: Feedback format.
+//
+//  Common packet format:
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |     BT=42     |   reserved    |         block length          |
+//  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+//
+//  Target bitrate item (repeat as many times as necessary).
+//
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |   S   |   T   |                Target Bitrate                 |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :  ...                                                          :
+//
+//  Spatial Layer (S): 4 bits
+//    Indicates which temporal layer this bitrate concerns.
+//
+//  Temporal Layer (T): 4 bits
+//    Indicates which temporal layer this bitrate concerns.
+//
+//  Target Bitrate: 24 bits
+//    The encoder target bitrate for this layer, in kbps.
+//
+//  As an example of how S and T are intended to be used, VP8 simulcast will
+//  use a separate TargetBitrate message per stream, since they are transmitted
+//  on separate SSRCs, with temporal layers grouped by stream.
+//  If VP9 SVC is used, there will be only one SSRC, so each spatial and
+//  temporal layer combo used shall be specified in the TargetBitrate packet.
+
+TargetBitrate::TargetBitrate() = default;
+TargetBitrate::TargetBitrate(const TargetBitrate&) = default;
+TargetBitrate& TargetBitrate::operator=(const TargetBitrate&) = default;
+TargetBitrate::~TargetBitrate() = default;
+
+void TargetBitrate::Parse(const uint8_t* block, uint16_t block_length) {
+  // Validate block header (should already have been parsed and checked).
+  RTC_DCHECK_EQ(block[0], kBlockType);
+  RTC_DCHECK_EQ(block_length, ByteReader<uint16_t>::ReadBigEndian(&block[2]));
+
+  // Header specifies block length - 1, but since we ignore the header, which
+  // occupies exactly on block, we can just treat this as payload length.
+  const size_t payload_bytes = block_length * 4;
+  const size_t num_items = payload_bytes / kBitrateItemSizeBytes;
+  size_t index = kTargetBitrateHeaderSizeBytes;
+  bitrates_.clear();
+  for (size_t i = 0; i < num_items; ++i) {
+    uint8_t layers = block[index];
+    uint32_t bitrate_kbps =
+        ByteReader<uint32_t, 3>::ReadBigEndian(&block[index + 1]);
+    index += kBitrateItemSizeBytes;
+    AddTargetBitrate((layers >> 4) & 0x0F, layers & 0x0F, bitrate_kbps);
+  }
+}
+
+void TargetBitrate::AddTargetBitrate(uint8_t spatial_layer,
+                                     uint8_t temporal_layer,
+                                     uint32_t target_bitrate_kbps) {
+  RTC_DCHECK_LE(spatial_layer, 0x0F);
+  RTC_DCHECK_LE(temporal_layer, 0x0F);
+  RTC_DCHECK_LE(target_bitrate_kbps, 0x00FFFFFFU);
+  bitrates_.push_back(
+      BitrateItem(spatial_layer, temporal_layer, target_bitrate_kbps));
+}
+
+const std::vector<TargetBitrate::BitrateItem>&
+TargetBitrate::GetTargetBitrates() const {
+  return bitrates_;
+}
+
+size_t TargetBitrate::BlockLength() const {
+  return kTargetBitrateHeaderSizeBytes +
+         bitrates_.size() * kBitrateItemSizeBytes;
+}
+
+void TargetBitrate::Create(uint8_t* buffer) const {
+  buffer[0] = kBlockType;
+  buffer[1] = 0;  // Reserved.
+  uint16_t block_length_words =
+      rtc::dchecked_cast<uint16_t>((BlockLength() / 4) - 1);
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], block_length_words);
+
+  size_t index = kTargetBitrateHeaderSizeBytes;
+  for (const BitrateItem& item : bitrates_) {
+    buffer[index] = (item.spatial_layer << 4) | item.temporal_layer;
+    ByteWriter<uint32_t, 3>::WriteBigEndian(&buffer[index + 1],
+                                            item.target_bitrate_kbps);
+    index += kBitrateItemSizeBytes;
+  }
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h b/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h
new file mode 100644
index 0000000..07e5da1
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TARGET_BITRATE_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TARGET_BITRATE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+namespace webrtc {
+namespace rtcp {
+
+class TargetBitrate {
+ public:
+  // TODO(sprang): This block type is just a place holder. We need to get an
+  //               id assigned by IANA.
+  static constexpr uint8_t kBlockType = 42;
+  static const size_t kBitrateItemSizeBytes;
+
+  struct BitrateItem {
+    BitrateItem();
+    BitrateItem(uint8_t spatial_layer,
+                uint8_t temporal_layer,
+                uint32_t target_bitrate_kbps);
+
+    uint8_t spatial_layer;
+    uint8_t temporal_layer;
+    uint32_t target_bitrate_kbps;
+  };
+
+  TargetBitrate();
+  TargetBitrate(const TargetBitrate&);
+  TargetBitrate& operator=(const TargetBitrate&);
+  ~TargetBitrate();
+
+  void AddTargetBitrate(uint8_t spatial_layer,
+                        uint8_t temporal_layer,
+                        uint32_t target_bitrate_kbps);
+
+  const std::vector<BitrateItem>& GetTargetBitrates() const;
+
+  void Parse(const uint8_t* block, uint16_t block_length);
+
+  size_t BlockLength() const;
+
+  void Create(uint8_t* buffer) const;
+
+ private:
+  std::vector<BitrateItem> bitrates_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TARGET_BITRATE_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc
new file mode 100644
index 0000000..b16bb5b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/target_bitrate_unittest.cc
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "rtc_base/buffer.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+namespace webrtc {
+namespace {
+using BitrateItem = rtcp::TargetBitrate::BitrateItem;
+using rtcp::TargetBitrate;
+using test::ParseSinglePacket;
+
+constexpr uint32_t kSsrc = 0x12345678;
+
+// clang-format off
+const uint8_t kPacket[] = { TargetBitrate::kBlockType,  // Block ID.
+                                  0x00,                 // Reserved.
+                                        0x00, 0x04,     // Length = 4 words.
+                            0x00, 0x01, 0x02, 0x03,     // S0T0 0x010203 kbps.
+                            0x01, 0x02, 0x03, 0x04,     // S0T1 0x020304 kbps.
+                            0x10, 0x03, 0x04, 0x05,     // S1T0 0x030405 kbps.
+                            0x11, 0x04, 0x05, 0x06 };   // S1T1 0x040506 kbps.
+constexpr size_t kPacketLengthBlocks = ((sizeof(kPacket) + 3) / 4) - 1;
+// clang-format on
+
+void ExpectBirateItemEquals(const BitrateItem& expected,
+                            const BitrateItem& actual) {
+  EXPECT_EQ(expected.spatial_layer, actual.spatial_layer);
+  EXPECT_EQ(expected.temporal_layer, actual.temporal_layer);
+  EXPECT_EQ(expected.target_bitrate_kbps, actual.target_bitrate_kbps);
+}
+
+void CheckBitrateItems(const std::vector<BitrateItem>& bitrates) {
+  EXPECT_EQ(4U, bitrates.size());
+  ExpectBirateItemEquals(BitrateItem(0, 0, 0x010203), bitrates[0]);
+  ExpectBirateItemEquals(BitrateItem(0, 1, 0x020304), bitrates[1]);
+  ExpectBirateItemEquals(BitrateItem(1, 0, 0x030405), bitrates[2]);
+  ExpectBirateItemEquals(BitrateItem(1, 1, 0x040506), bitrates[3]);
+}
+
+}  // namespace
+
+TEST(TargetBitrateTest, Parse) {
+  TargetBitrate target_bitrate;
+  target_bitrate.Parse(kPacket, kPacketLengthBlocks);
+  CheckBitrateItems(target_bitrate.GetTargetBitrates());
+}
+
+TEST(TargetBitrateTest, FullPacket) {
+  const size_t kXRHeaderSize = 8;  // RTCP header (4) + SSRC (4).
+  const size_t kTotalSize = kXRHeaderSize + sizeof(kPacket);
+  uint8_t kRtcpPacket[kTotalSize] = {2 << 6, 207,  0x00, (kTotalSize / 4) - 1,
+                                     0x12,   0x34, 0x56, 0x78};  // SSRC.
+  memcpy(&kRtcpPacket[kXRHeaderSize], kPacket, sizeof(kPacket));
+  rtcp::ExtendedReports xr;
+  EXPECT_TRUE(ParseSinglePacket(kRtcpPacket, &xr));
+  EXPECT_EQ(kSsrc, xr.sender_ssrc());
+  const absl::optional<TargetBitrate>& target_bitrate = xr.target_bitrate();
+  ASSERT_TRUE(static_cast<bool>(target_bitrate));
+  CheckBitrateItems(target_bitrate->GetTargetBitrates());
+}
+
+TEST(TargetBitrateTest, Create) {
+  TargetBitrate target_bitrate;
+  target_bitrate.AddTargetBitrate(0, 0, 0x010203);
+  target_bitrate.AddTargetBitrate(0, 1, 0x020304);
+  target_bitrate.AddTargetBitrate(1, 0, 0x030405);
+  target_bitrate.AddTargetBitrate(1, 1, 0x040506);
+
+  uint8_t buffer[sizeof(kPacket)] = {};
+  ASSERT_EQ(sizeof(kPacket), target_bitrate.BlockLength());
+  target_bitrate.Create(buffer);
+
+  EXPECT_EQ(0, memcmp(kPacket, buffer, sizeof(kPacket)));
+}
+
+TEST(TargetBitrateTest, ParseNullBitratePacket) {
+  const uint8_t kNullPacket[] = {TargetBitrate::kBlockType, 0x00, 0x00, 0x00};
+  TargetBitrate target_bitrate;
+  target_bitrate.Parse(kNullPacket, 0);
+  EXPECT_TRUE(target_bitrate.GetTargetBitrates().empty());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc b/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc
new file mode 100644
index 0000000..810e1e2
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.cc
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+TmmbItem::TmmbItem(uint32_t ssrc, uint64_t bitrate_bps, uint16_t overhead)
+    : ssrc_(ssrc), bitrate_bps_(bitrate_bps), packet_overhead_(overhead) {
+  RTC_DCHECK_LE(overhead, 0x1ffu);
+}
+
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 0 |                              SSRC                             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 4 | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+bool TmmbItem::Parse(const uint8_t* buffer) {
+  ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]);
+  // Read 4 bytes into 1 block.
+  uint32_t compact = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+  // Split 1 block into 3 components.
+  uint8_t exponent = compact >> 26;              // 6 bits.
+  uint64_t mantissa = (compact >> 9) & 0x1ffff;  // 17 bits.
+  uint16_t overhead = compact & 0x1ff;           // 9 bits.
+  // Combine 3 components into 2 values.
+  bitrate_bps_ = (mantissa << exponent);
+
+  bool shift_overflow = (bitrate_bps_ >> exponent) != mantissa;
+  if (shift_overflow) {
+    RTC_LOG(LS_ERROR) << "Invalid tmmb bitrate value : " << mantissa << "*2^"
+                      << static_cast<int>(exponent);
+    return false;
+  }
+  packet_overhead_ = overhead;
+  return true;
+}
+
+void TmmbItem::Create(uint8_t* buffer) const {
+  constexpr uint64_t kMaxMantissa = 0x1ffff;  // 17 bits.
+  uint64_t mantissa = bitrate_bps_;
+  uint32_t exponent = 0;
+  while (mantissa > kMaxMantissa) {
+    mantissa >>= 1;
+    ++exponent;
+  }
+
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[0], ssrc_);
+  uint32_t compact = (exponent << 26) | (mantissa << 9) | packet_overhead_;
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], compact);
+}
+
+void TmmbItem::set_packet_overhead(uint16_t overhead) {
+  RTC_DCHECK_LE(overhead, 0x1ffu);
+  packet_overhead_ = overhead;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h b/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h
new file mode 100644
index 0000000..dc5d1b2
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMB_ITEM_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMB_ITEM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace webrtc {
+namespace rtcp {
+// RFC5104, Section 3.5.4
+// Temporary Maximum Media Stream Bitrate Request/Notification.
+// Used both by TMMBR and TMMBN rtcp packets.
+class TmmbItem {
+ public:
+  static const size_t kLength = 8;
+
+  TmmbItem() : ssrc_(0), bitrate_bps_(0), packet_overhead_(0) {}
+  TmmbItem(uint32_t ssrc, uint64_t bitrate_bps, uint16_t overhead);
+
+  bool Parse(const uint8_t* buffer);
+  void Create(uint8_t* buffer) const;
+
+  void set_ssrc(uint32_t ssrc) { ssrc_ = ssrc; }
+  void set_bitrate_bps(uint64_t bitrate_bps) { bitrate_bps_ = bitrate_bps; }
+  void set_packet_overhead(uint16_t overhead);
+
+  uint32_t ssrc() const { return ssrc_; }
+  uint64_t bitrate_bps() const { return bitrate_bps_; }
+  uint16_t packet_overhead() const { return packet_overhead_; }
+
+ private:
+  // Media stream id.
+  uint32_t ssrc_;
+  // Maximum total media bit rate that the media receiver is
+  // currently prepared to accept for this media stream.
+  uint64_t bitrate_bps_;
+  // Per-packet overhead that the media receiver has observed
+  // for this media stream at its chosen reference protocol layer.
+  uint16_t packet_overhead_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMB_ITEM_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc b/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc
new file mode 100644
index 0000000..4d38b3b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Tmmbn::kFeedbackMessageType;
+// RFC 4585: Feedback format.
+// Common packet format:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |V=2|P|   FMT   |       PT      |          length               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                  SSRC of packet sender                        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |             SSRC of media source (unused) = 0                 |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   :            Feedback Control Information (FCI)                 :
+//   :                                                               :
+// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
+// The Feedback Control Information (FCI) consists of zero, one, or more
+// TMMBN FCI entries.
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                              SSRC                             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Tmmbn::Tmmbn() = default;
+
+Tmmbn::~Tmmbn() = default;
+
+bool Tmmbn::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  if (packet.payload_size_bytes() < kCommonFeedbackLength) {
+    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
+                        << " is too small for TMMBN.";
+    return false;
+  }
+  size_t items_size_bytes = packet.payload_size_bytes() - kCommonFeedbackLength;
+  if (items_size_bytes % TmmbItem::kLength != 0) {
+    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
+                        << " is not valid for TMMBN.";
+    return false;
+  }
+  ParseCommonFeedback(packet.payload());
+  const uint8_t* next_item = packet.payload() + kCommonFeedbackLength;
+
+  size_t number_of_items = items_size_bytes / TmmbItem::kLength;
+  items_.resize(number_of_items);
+  for (TmmbItem& item : items_) {
+    if (!item.Parse(next_item))
+      return false;
+    next_item += TmmbItem::kLength;
+  }
+  return true;
+}
+
+void Tmmbn::AddTmmbr(const TmmbItem& item) {
+  items_.push_back(item);
+}
+
+size_t Tmmbn::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength +
+         TmmbItem::kLength * items_.size();
+}
+
+bool Tmmbn::Create(uint8_t* packet,
+                   size_t* index,
+                   size_t max_length,
+                   PacketReadyCallback callback) const {
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               index);
+  RTC_DCHECK_EQ(0, Rtpfb::media_ssrc());
+  CreateCommonFeedback(packet + *index);
+  *index += kCommonFeedbackLength;
+  for (const TmmbItem& item : items_) {
+    item.Create(packet + *index);
+    *index += TmmbItem::kLength;
+  }
+  RTC_CHECK_EQ(index_end, *index);
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h b/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h
new file mode 100644
index 0000000..ff7779d
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+// Temporary Maximum Media Stream Bit Rate Notification (TMMBN).
+// RFC 5104, Section 4.2.2.
+class Tmmbn : public Rtpfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 4;
+
+  Tmmbn();
+  ~Tmmbn() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void AddTmmbr(const TmmbItem& item);
+
+  const std::vector<TmmbItem>& items() const { return items_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  // Media ssrc is unused, shadow base class setter and getter.
+  void SetMediaSsrc(uint32_t ssrc);
+  uint32_t media_ssrc() const;
+
+  std::vector<TmmbItem> items_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBN_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc
new file mode 100644
index 0000000..e5d2e0b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmbn_unittest.cc
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::IsEmpty;
+using testing::make_tuple;
+using webrtc::rtcp::TmmbItem;
+using webrtc::rtcp::Tmmbn;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint32_t kBitrateBps = 312000;
+const uint16_t kOverhead = 0x1fe;
+const uint8_t kPacket[] = {0x84, 205,  0x00, 0x04, 0x12, 0x34, 0x56,
+                           0x78, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+                           0x67, 0x89, 0x0a, 0x61, 0x61, 0xfe};
+}  // namespace
+
+TEST(RtcpPacketTmmbnTest, Create) {
+  Tmmbn tmmbn;
+  tmmbn.SetSenderSsrc(kSenderSsrc);
+  tmmbn.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead));
+
+  rtc::Buffer packet = tmmbn.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketTmmbnTest, Parse) {
+  Tmmbn tmmbn;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &tmmbn));
+
+  const Tmmbn& parsed = tmmbn;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  ASSERT_EQ(1u, parsed.items().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.items().front().ssrc());
+  EXPECT_EQ(kBitrateBps, parsed.items().front().bitrate_bps());
+  EXPECT_EQ(kOverhead, parsed.items().front().packet_overhead());
+}
+
+TEST(RtcpPacketTmmbnTest, CreateAndParseWithoutItems) {
+  Tmmbn tmmbn;
+  tmmbn.SetSenderSsrc(kSenderSsrc);
+
+  rtc::Buffer packet = tmmbn.Build();
+  Tmmbn parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_THAT(parsed.items(), IsEmpty());
+}
+
+TEST(RtcpPacketTmmbnTest, CreateAndParseWithTwoItems) {
+  Tmmbn tmmbn;
+  tmmbn.SetSenderSsrc(kSenderSsrc);
+  tmmbn.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead));
+  tmmbn.AddTmmbr(TmmbItem(kRemoteSsrc + 1, 4 * kBitrateBps, 40));
+
+  rtc::Buffer packet = tmmbn.Build();
+  Tmmbn parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(2u, parsed.items().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.items()[0].ssrc());
+  EXPECT_EQ(kBitrateBps, parsed.items()[0].bitrate_bps());
+  EXPECT_EQ(kOverhead, parsed.items()[0].packet_overhead());
+  EXPECT_EQ(kRemoteSsrc + 1, parsed.items()[1].ssrc());
+  EXPECT_EQ(4 * kBitrateBps, parsed.items()[1].bitrate_bps());
+  EXPECT_EQ(40U, parsed.items()[1].packet_overhead());
+}
+
+TEST(RtcpPacketTmmbnTest, ParseFailsOnTooSmallPacket) {
+  const uint8_t kSmallPacket[] = {0x84, 205,  0x00, 0x01,
+                                  0x12, 0x34, 0x56, 0x78};
+  Tmmbn tmmbn;
+  EXPECT_FALSE(test::ParseSinglePacket(kSmallPacket, &tmmbn));
+}
+
+TEST(RtcpPacketTmmbnTest, ParseFailsOnUnAlignedPacket) {
+  const uint8_t kUnalignedPacket[] = {0x84, 205,  0x00, 0x03, 0x12, 0x34,
+                                      0x56, 0x78, 0x00, 0x00, 0x00, 0x00,
+                                      0x23, 0x45, 0x67, 0x89};
+
+  Tmmbn tmmbn;
+  EXPECT_FALSE(test::ParseSinglePacket(kUnalignedPacket, &tmmbn));
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc b/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc
new file mode 100644
index 0000000..d8f073b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace rtcp {
+constexpr uint8_t Tmmbr::kFeedbackMessageType;
+// RFC 4585: Feedback format.
+// Common packet format:
+//
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |V=2|P|   FMT   |       PT      |          length               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                  SSRC of packet sender                        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |             SSRC of media source (unused) = 0                 |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  :            Feedback Control Information (FCI)                 :
+//  :                                                               :
+// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
+// The Feedback Control Information (FCI) for the TMMBR
+// consists of one or more FCI entries.
+// FCI:
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                              SSRC                             |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  | MxTBR Exp |  MxTBR Mantissa                 |Measured Overhead|
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Tmmbr::Tmmbr() = default;
+
+Tmmbr::~Tmmbr() = default;
+
+bool Tmmbr::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+
+  if (packet.payload_size_bytes() < kCommonFeedbackLength + TmmbItem::kLength) {
+    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
+                        << " is too small for a TMMBR.";
+    return false;
+  }
+  size_t items_size_bytes = packet.payload_size_bytes() - kCommonFeedbackLength;
+  if (items_size_bytes % TmmbItem::kLength != 0) {
+    RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
+                        << " is not valid for a TMMBR.";
+    return false;
+  }
+  ParseCommonFeedback(packet.payload());
+
+  const uint8_t* next_item = packet.payload() + kCommonFeedbackLength;
+  size_t number_of_items = items_size_bytes / TmmbItem::kLength;
+  items_.resize(number_of_items);
+  for (TmmbItem& item : items_) {
+    if (!item.Parse(next_item))
+      return false;
+    next_item += TmmbItem::kLength;
+  }
+  return true;
+}
+
+void Tmmbr::AddTmmbr(const TmmbItem& item) {
+  items_.push_back(item);
+}
+
+size_t Tmmbr::BlockLength() const {
+  return kHeaderLength + kCommonFeedbackLength +
+         TmmbItem::kLength * items_.size();
+}
+
+bool Tmmbr::Create(uint8_t* packet,
+                   size_t* index,
+                   size_t max_length,
+                   PacketReadyCallback callback) const {
+  RTC_DCHECK(!items_.empty());
+  while (*index + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, index, callback))
+      return false;
+  }
+  const size_t index_end = *index + BlockLength();
+
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               index);
+  RTC_DCHECK_EQ(0, Rtpfb::media_ssrc());
+  CreateCommonFeedback(packet + *index);
+  *index += kCommonFeedbackLength;
+  for (const TmmbItem& item : items_) {
+    item.Create(packet + *index);
+    *index += TmmbItem::kLength;
+  }
+  RTC_CHECK_EQ(index_end, *index);
+  return true;
+}
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h b/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h
new file mode 100644
index 0000000..7482cb7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+// Temporary Maximum Media Stream Bit Rate Request (TMMBR).
+// RFC 5104, Section 4.2.1.
+class Tmmbr : public Rtpfb {
+ public:
+  static constexpr uint8_t kFeedbackMessageType = 3;
+
+  Tmmbr();
+  ~Tmmbr() override;
+
+  // Parse assumes header is already parsed and validated.
+  bool Parse(const CommonHeader& packet);
+
+  void AddTmmbr(const TmmbItem& item);
+
+  const std::vector<TmmbItem>& requests() const { return items_; }
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* index,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  // Media ssrc is unused, shadow base class setter.
+  void SetMediaSsrc(uint32_t ssrc);
+
+  std::vector<TmmbItem> items_;
+};
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TMMBR_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc
new file mode 100644
index 0000000..63fa911
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/tmmbr_unittest.cc
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using testing::ElementsAreArray;
+using testing::IsEmpty;
+using testing::make_tuple;
+using webrtc::rtcp::TmmbItem;
+using webrtc::rtcp::Tmmbr;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345678;
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint32_t kBitrateBps = 312000;
+const uint16_t kOverhead = 0x1fe;
+const uint8_t kPacket[] = {0x83, 205,  0x00, 0x04, 0x12, 0x34, 0x56,
+                           0x78, 0x00, 0x00, 0x00, 0x00, 0x23, 0x45,
+                           0x67, 0x89, 0x0a, 0x61, 0x61, 0xfe};
+}  // namespace
+
+TEST(RtcpPacketTmmbrTest, Create) {
+  Tmmbr tmmbr;
+  tmmbr.SetSenderSsrc(kSenderSsrc);
+  tmmbr.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead));
+
+  rtc::Buffer packet = tmmbr.Build();
+
+  EXPECT_THAT(make_tuple(packet.data(), packet.size()),
+              ElementsAreArray(kPacket));
+}
+
+TEST(RtcpPacketTmmbrTest, Parse) {
+  Tmmbr tmmbr;
+  EXPECT_TRUE(test::ParseSinglePacket(kPacket, &tmmbr));
+  const Tmmbr& parsed = tmmbr;
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  ASSERT_EQ(1u, parsed.requests().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.requests().front().ssrc());
+  EXPECT_EQ(kBitrateBps, parsed.requests().front().bitrate_bps());
+  EXPECT_EQ(kOverhead, parsed.requests().front().packet_overhead());
+}
+
+TEST(RtcpPacketTmmbrTest, CreateAndParseWithTwoEntries) {
+  Tmmbr tmmbr;
+  tmmbr.SetSenderSsrc(kSenderSsrc);
+  tmmbr.AddTmmbr(TmmbItem(kRemoteSsrc, kBitrateBps, kOverhead));
+  tmmbr.AddTmmbr(TmmbItem(kRemoteSsrc + 1, 4 * kBitrateBps, kOverhead + 1));
+
+  rtc::Buffer packet = tmmbr.Build();
+
+  Tmmbr parsed;
+  EXPECT_TRUE(test::ParseSinglePacket(packet, &parsed));
+
+  EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
+  EXPECT_EQ(2u, parsed.requests().size());
+  EXPECT_EQ(kRemoteSsrc, parsed.requests()[0].ssrc());
+  EXPECT_EQ(kRemoteSsrc + 1, parsed.requests()[1].ssrc());
+}
+
+TEST(RtcpPacketTmmbrTest, ParseFailsWithoutItems) {
+  const uint8_t kZeroItemsPacket[] = {0x83, 205,  0x00, 0x02, 0x12, 0x34,
+                                      0x56, 0x78, 0x00, 0x00, 0x00, 0x00};
+
+  Tmmbr tmmbr;
+  EXPECT_FALSE(test::ParseSinglePacket(kZeroItemsPacket, &tmmbr));
+}
+
+TEST(RtcpPacketTmmbrTest, ParseFailsOnUnAlignedPacket) {
+  const uint8_t kUnalignedPacket[] = {
+      0x83, 205,  0x00, 0x05, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00,
+      0x23, 0x45, 0x67, 0x89, 0x0a, 0x61, 0x61, 0xfe, 0x34, 0x56, 0x78, 0x9a};
+
+  Tmmbr tmmbr;
+  EXPECT_FALSE(test::ParseSinglePacket(kUnalignedPacket, &tmmbr));
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
new file mode 100644
index 0000000..4703d31
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
@@ -0,0 +1,613 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+namespace rtcp {
+namespace {
+// Header size:
+// * 4 bytes Common RTCP Packet Header
+// * 8 bytes Common Packet Format for RTCP Feedback Messages
+// * 8 bytes FeedbackPacket header
+constexpr size_t kTransportFeedbackHeaderSizeBytes = 4 + 8 + 8;
+constexpr size_t kChunkSizeBytes = 2;
+// TODO(sprang): Add support for dynamic max size for easier fragmentation,
+// eg. set it to what's left in the buffer or IP_PACKET_SIZE.
+// Size constraint imposed by RTCP common header: 16bit size field interpreted
+// as number of four byte words minus the first header word.
+constexpr size_t kMaxSizeBytes = (1 << 16) * 4;
+// Payload size:
+// * 8 bytes Common Packet Format for RTCP Feedback Messages
+// * 8 bytes FeedbackPacket header.
+// * 2 bytes for one chunk.
+constexpr size_t kMinPayloadSizeBytes = 8 + 8 + 2;
+constexpr int kBaseScaleFactor =
+    TransportFeedback::kDeltaScaleFactor * (1 << 8);
+constexpr int64_t kTimeWrapPeriodUs = (1ll << 24) * kBaseScaleFactor;
+
+//    Message format
+//
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |V=2|P|  FMT=15 |    PT=205     |           length              |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |                     SSRC of packet sender                     |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                      SSRC of media source                     |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |      base sequence number     |      packet status count      |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |                 reference time                | fb pkt. count |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |          packet chunk         |         packet chunk          |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    .                                                               .
+//    .                                                               .
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |         packet chunk          |  recv delta   |  recv delta   |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    .                                                               .
+//    .                                                               .
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |           recv delta          |  recv delta   | zero padding  |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+}  // namespace
+constexpr uint8_t TransportFeedback::kFeedbackMessageType;
+constexpr size_t TransportFeedback::kMaxReportedPackets;
+
+constexpr size_t TransportFeedback::LastChunk::kMaxRunLengthCapacity;
+constexpr size_t TransportFeedback::LastChunk::kMaxOneBitCapacity;
+constexpr size_t TransportFeedback::LastChunk::kMaxTwoBitCapacity;
+constexpr size_t TransportFeedback::LastChunk::kMaxVectorCapacity;
+
+TransportFeedback::LastChunk::LastChunk() {
+  Clear();
+}
+
+bool TransportFeedback::LastChunk::Empty() const {
+  return size_ == 0;
+}
+
+void TransportFeedback::LastChunk::Clear() {
+  size_ = 0;
+  all_same_ = true;
+  has_large_delta_ = false;
+}
+
+bool TransportFeedback::LastChunk::CanAdd(DeltaSize delta_size) const {
+  RTC_DCHECK_LE(delta_size, 2);
+  if (size_ < kMaxTwoBitCapacity)
+    return true;
+  if (size_ < kMaxOneBitCapacity && !has_large_delta_ && delta_size != kLarge)
+    return true;
+  if (size_ < kMaxRunLengthCapacity && all_same_ &&
+      delta_sizes_[0] == delta_size)
+    return true;
+  return false;
+}
+
+void TransportFeedback::LastChunk::Add(DeltaSize delta_size) {
+  RTC_DCHECK(CanAdd(delta_size));
+  if (size_ < kMaxVectorCapacity)
+    delta_sizes_[size_] = delta_size;
+  size_++;
+  all_same_ = all_same_ && delta_size == delta_sizes_[0];
+  has_large_delta_ = has_large_delta_ || delta_size == kLarge;
+}
+
+uint16_t TransportFeedback::LastChunk::Emit() {
+  RTC_DCHECK(!CanAdd(0) || !CanAdd(1) || !CanAdd(2));
+  if (all_same_) {
+    uint16_t chunk = EncodeRunLength();
+    Clear();
+    return chunk;
+  }
+  if (size_ == kMaxOneBitCapacity) {
+    uint16_t chunk = EncodeOneBit();
+    Clear();
+    return chunk;
+  }
+  RTC_DCHECK_GE(size_, kMaxTwoBitCapacity);
+  uint16_t chunk = EncodeTwoBit(kMaxTwoBitCapacity);
+  // Remove |kMaxTwoBitCapacity| encoded delta sizes:
+  // Shift remaining delta sizes and recalculate all_same_ && has_large_delta_.
+  size_ -= kMaxTwoBitCapacity;
+  all_same_ = true;
+  has_large_delta_ = false;
+  for (size_t i = 0; i < size_; ++i) {
+    DeltaSize delta_size = delta_sizes_[kMaxTwoBitCapacity + i];
+    delta_sizes_[i] = delta_size;
+    all_same_ = all_same_ && delta_size == delta_sizes_[0];
+    has_large_delta_ = has_large_delta_ || delta_size == kLarge;
+  }
+
+  return chunk;
+}
+
+uint16_t TransportFeedback::LastChunk::EncodeLast() const {
+  RTC_DCHECK_GT(size_, 0);
+  if (all_same_)
+    return EncodeRunLength();
+  if (size_ <= kMaxTwoBitCapacity)
+    return EncodeTwoBit(size_);
+  return EncodeOneBit();
+}
+
+// Appends content of the Lastchunk to |deltas|.
+void TransportFeedback::LastChunk::AppendTo(
+    std::vector<DeltaSize>* deltas) const {
+  if (all_same_) {
+    deltas->insert(deltas->end(), size_, delta_sizes_[0]);
+  } else {
+    deltas->insert(deltas->end(), delta_sizes_, delta_sizes_ + size_);
+  }
+}
+
+void TransportFeedback::LastChunk::Decode(uint16_t chunk, size_t max_size) {
+  if ((chunk & 0x8000) == 0) {
+    DecodeRunLength(chunk, max_size);
+  } else if ((chunk & 0x4000) == 0) {
+    DecodeOneBit(chunk, max_size);
+  } else {
+    DecodeTwoBit(chunk, max_size);
+  }
+}
+
+//  One Bit Status Vector Chunk
+//
+//  0                   1
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |T|S|       symbol list         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//  T = 1
+//  S = 0
+//  Symbol list = 14 entries where 0 = not received, 1 = received 1-byte delta.
+uint16_t TransportFeedback::LastChunk::EncodeOneBit() const {
+  RTC_DCHECK(!has_large_delta_);
+  RTC_DCHECK_LE(size_, kMaxOneBitCapacity);
+  uint16_t chunk = 0x8000;
+  for (size_t i = 0; i < size_; ++i)
+    chunk |= delta_sizes_[i] << (kMaxOneBitCapacity - 1 - i);
+  return chunk;
+}
+
+void TransportFeedback::LastChunk::DecodeOneBit(uint16_t chunk,
+                                                size_t max_size) {
+  RTC_DCHECK_EQ(chunk & 0xc000, 0x8000);
+  size_ = std::min(kMaxOneBitCapacity, max_size);
+  has_large_delta_ = false;
+  all_same_ = false;
+  for (size_t i = 0; i < size_; ++i)
+    delta_sizes_[i] = (chunk >> (kMaxOneBitCapacity - 1 - i)) & 0x01;
+}
+
+//  Two Bit Status Vector Chunk
+//
+//  0                   1
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |T|S|       symbol list         |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//  T = 1
+//  S = 1
+//  symbol list = 7 entries of two bits each.
+uint16_t TransportFeedback::LastChunk::EncodeTwoBit(size_t size) const {
+  RTC_DCHECK_LE(size, size_);
+  uint16_t chunk = 0xc000;
+  for (size_t i = 0; i < size; ++i)
+    chunk |= delta_sizes_[i] << 2 * (kMaxTwoBitCapacity - 1 - i);
+  return chunk;
+}
+
+void TransportFeedback::LastChunk::DecodeTwoBit(uint16_t chunk,
+                                                size_t max_size) {
+  RTC_DCHECK_EQ(chunk & 0xc000, 0xc000);
+  size_ = std::min(kMaxTwoBitCapacity, max_size);
+  has_large_delta_ = true;
+  all_same_ = false;
+  for (size_t i = 0; i < size_; ++i)
+    delta_sizes_[i] = (chunk >> 2 * (kMaxTwoBitCapacity - 1 - i)) & 0x03;
+}
+
+//  Run Length Status Vector Chunk
+//
+//  0                   1
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |T| S |       Run Length        |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//  T = 0
+//  S = symbol
+//  Run Length = Unsigned integer denoting the run length of the symbol
+uint16_t TransportFeedback::LastChunk::EncodeRunLength() const {
+  RTC_DCHECK(all_same_);
+  RTC_DCHECK_LE(size_, kMaxRunLengthCapacity);
+  return (delta_sizes_[0] << 13) | static_cast<uint16_t>(size_);
+}
+
+void TransportFeedback::LastChunk::DecodeRunLength(uint16_t chunk,
+                                                   size_t max_count) {
+  RTC_DCHECK_EQ(chunk & 0x8000, 0);
+  size_ = std::min<size_t>(chunk & 0x1fff, max_count);
+  DeltaSize delta_size = (chunk >> 13) & 0x03;
+  has_large_delta_ = delta_size >= kLarge;
+  all_same_ = true;
+  // To make it consistent with Add function, populate delta_sizes_ beyound 1st.
+  for (size_t i = 0; i < std::min<size_t>(size_, kMaxVectorCapacity); ++i)
+    delta_sizes_[i] = delta_size;
+}
+
+TransportFeedback::TransportFeedback()
+    : base_seq_no_(0),
+      num_seq_no_(0),
+      base_time_ticks_(0),
+      feedback_seq_(0),
+      last_timestamp_us_(0),
+      size_bytes_(kTransportFeedbackHeaderSizeBytes) {}
+
+TransportFeedback::TransportFeedback(const TransportFeedback&) = default;
+
+TransportFeedback::TransportFeedback(TransportFeedback&& other)
+    : base_seq_no_(other.base_seq_no_),
+      num_seq_no_(other.num_seq_no_),
+      base_time_ticks_(other.base_time_ticks_),
+      feedback_seq_(other.feedback_seq_),
+      last_timestamp_us_(other.last_timestamp_us_),
+      packets_(std::move(other.packets_)),
+      encoded_chunks_(std::move(other.encoded_chunks_)),
+      last_chunk_(other.last_chunk_),
+      size_bytes_(other.size_bytes_) {
+  other.Clear();
+}
+
+TransportFeedback::~TransportFeedback() {}
+
+void TransportFeedback::SetBase(uint16_t base_sequence,
+                                int64_t ref_timestamp_us) {
+  RTC_DCHECK_EQ(num_seq_no_, 0);
+  RTC_DCHECK_GE(ref_timestamp_us, 0);
+  base_seq_no_ = base_sequence;
+  base_time_ticks_ = (ref_timestamp_us % kTimeWrapPeriodUs) / kBaseScaleFactor;
+  last_timestamp_us_ = GetBaseTimeUs();
+}
+
+void TransportFeedback::SetFeedbackSequenceNumber(uint8_t feedback_sequence) {
+  feedback_seq_ = feedback_sequence;
+}
+
+bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number,
+                                          int64_t timestamp_us) {
+  // Convert to ticks and round.
+  int64_t delta_full = (timestamp_us - last_timestamp_us_) % kTimeWrapPeriodUs;
+  if (delta_full > kTimeWrapPeriodUs / 2)
+    delta_full -= kTimeWrapPeriodUs;
+  delta_full +=
+      delta_full < 0 ? -(kDeltaScaleFactor / 2) : kDeltaScaleFactor / 2;
+  delta_full /= kDeltaScaleFactor;
+
+  int16_t delta = static_cast<int16_t>(delta_full);
+  // If larger than 16bit signed, we can't represent it - need new fb packet.
+  if (delta != delta_full) {
+    RTC_LOG(LS_WARNING) << "Delta value too large ( >= 2^16 ticks )";
+    return false;
+  }
+
+  uint16_t next_seq_no = base_seq_no_ + num_seq_no_;
+  if (sequence_number != next_seq_no) {
+    uint16_t last_seq_no = next_seq_no - 1;
+    if (!IsNewerSequenceNumber(sequence_number, last_seq_no))
+      return false;
+    for (; next_seq_no != sequence_number; ++next_seq_no)
+      if (!AddDeltaSize(0))
+        return false;
+  }
+
+  DeltaSize delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2;
+  if (!AddDeltaSize(delta_size))
+    return false;
+
+  packets_.emplace_back(sequence_number, delta);
+  last_timestamp_us_ += delta * kDeltaScaleFactor;
+  size_bytes_ += delta_size;
+  return true;
+}
+
+const std::vector<TransportFeedback::ReceivedPacket>&
+TransportFeedback::GetReceivedPackets() const {
+  return packets_;
+}
+
+uint16_t TransportFeedback::GetBaseSequence() const {
+  return base_seq_no_;
+}
+
+int64_t TransportFeedback::GetBaseTimeUs() const {
+  return static_cast<int64_t>(base_time_ticks_) * kBaseScaleFactor;
+}
+
+// De-serialize packet.
+bool TransportFeedback::Parse(const CommonHeader& packet) {
+  RTC_DCHECK_EQ(packet.type(), kPacketType);
+  RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
+  TRACE_EVENT0("webrtc", "TransportFeedback::Parse");
+
+  if (packet.payload_size_bytes() < kMinPayloadSizeBytes) {
+    RTC_LOG(LS_WARNING) << "Buffer too small (" << packet.payload_size_bytes()
+                        << " bytes) to fit a "
+                           "FeedbackPacket. Minimum size = "
+                        << kMinPayloadSizeBytes;
+    return false;
+  }
+
+  const uint8_t* const payload = packet.payload();
+  ParseCommonFeedback(payload);
+
+  base_seq_no_ = ByteReader<uint16_t>::ReadBigEndian(&payload[8]);
+  uint16_t status_count = ByteReader<uint16_t>::ReadBigEndian(&payload[10]);
+  base_time_ticks_ = ByteReader<int32_t, 3>::ReadBigEndian(&payload[12]);
+  feedback_seq_ = payload[15];
+  Clear();
+  size_t index = 16;
+  const size_t end_index = packet.payload_size_bytes();
+
+  if (status_count == 0) {
+    RTC_LOG(LS_WARNING) << "Empty feedback messages not allowed.";
+    return false;
+  }
+
+  std::vector<uint8_t> delta_sizes;
+  delta_sizes.reserve(status_count);
+  while (delta_sizes.size() < status_count) {
+    if (index + kChunkSizeBytes > end_index) {
+      RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
+      Clear();
+      return false;
+    }
+
+    uint16_t chunk = ByteReader<uint16_t>::ReadBigEndian(&payload[index]);
+    index += kChunkSizeBytes;
+    encoded_chunks_.push_back(chunk);
+    last_chunk_.Decode(chunk, status_count - delta_sizes.size());
+    last_chunk_.AppendTo(&delta_sizes);
+  }
+  // Last chunk is stored in the |last_chunk_|.
+  encoded_chunks_.pop_back();
+  RTC_DCHECK_EQ(delta_sizes.size(), status_count);
+  num_seq_no_ = status_count;
+
+  uint16_t seq_no = base_seq_no_;
+  for (size_t delta_size : delta_sizes) {
+    if (index + delta_size > end_index) {
+      RTC_LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
+      Clear();
+      return false;
+    }
+    switch (delta_size) {
+      case 0:
+        break;
+      case 1: {
+        int16_t delta = payload[index];
+        packets_.emplace_back(seq_no, delta);
+        last_timestamp_us_ += delta * kDeltaScaleFactor;
+        index += delta_size;
+        break;
+      }
+      case 2: {
+        int16_t delta = ByteReader<int16_t>::ReadBigEndian(&payload[index]);
+        packets_.emplace_back(seq_no, delta);
+        last_timestamp_us_ += delta * kDeltaScaleFactor;
+        index += delta_size;
+        break;
+      }
+      case 3:
+        Clear();
+        RTC_LOG(LS_WARNING) << "Invalid delta_size for seq_no " << seq_no;
+        return false;
+      default:
+        RTC_NOTREACHED();
+        break;
+    }
+    ++seq_no;
+  }
+  size_bytes_ = RtcpPacket::kHeaderLength + index;
+  RTC_DCHECK_LE(index, end_index);
+  return true;
+}
+
+std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom(
+    const uint8_t* buffer,
+    size_t length) {
+  CommonHeader header;
+  if (!header.Parse(buffer, length))
+    return nullptr;
+  if (header.type() != kPacketType || header.fmt() != kFeedbackMessageType)
+    return nullptr;
+  std::unique_ptr<TransportFeedback> parsed(new TransportFeedback);
+  if (!parsed->Parse(header))
+    return nullptr;
+  return parsed;
+}
+
+bool TransportFeedback::IsConsistent() const {
+  size_t packet_size = kTransportFeedbackHeaderSizeBytes;
+  std::vector<DeltaSize> delta_sizes;
+  LastChunk chunk_decoder;
+  for (uint16_t chunk : encoded_chunks_) {
+    chunk_decoder.Decode(chunk, kMaxReportedPackets);
+    chunk_decoder.AppendTo(&delta_sizes);
+    packet_size += kChunkSizeBytes;
+  }
+  if (!last_chunk_.Empty()) {
+    last_chunk_.AppendTo(&delta_sizes);
+    packet_size += kChunkSizeBytes;
+  }
+  if (num_seq_no_ != delta_sizes.size()) {
+    RTC_LOG(LS_ERROR) << delta_sizes.size() << " packets encoded. Expected "
+                      << num_seq_no_;
+    return false;
+  }
+  int64_t timestamp_us = base_time_ticks_ * kBaseScaleFactor;
+  auto packet_it = packets_.begin();
+  uint16_t seq_no = base_seq_no_;
+  for (DeltaSize delta_size : delta_sizes) {
+    if (delta_size > 0) {
+      if (packet_it == packets_.end()) {
+        RTC_LOG(LS_ERROR) << "Failed to find delta for seq_no " << seq_no;
+        return false;
+      }
+      if (packet_it->sequence_number() != seq_no) {
+        RTC_LOG(LS_ERROR) << "Expected to find delta for seq_no " << seq_no
+                          << ". Next delta is for "
+                          << packet_it->sequence_number();
+        return false;
+      }
+      if (delta_size == 1 &&
+          (packet_it->delta_ticks() < 0 || packet_it->delta_ticks() > 0xff)) {
+        RTC_LOG(LS_ERROR) << "Delta " << packet_it->delta_ticks()
+                          << " for seq_no " << seq_no
+                          << " doesn't fit into one byte";
+        return false;
+      }
+      timestamp_us += packet_it->delta_us();
+      ++packet_it;
+    }
+    packet_size += delta_size;
+    ++seq_no;
+  }
+  if (packet_it != packets_.end()) {
+    RTC_LOG(LS_ERROR) << "Unencoded delta for seq_no "
+                      << packet_it->sequence_number();
+    return false;
+  }
+  if (timestamp_us != last_timestamp_us_) {
+    RTC_LOG(LS_ERROR) << "Last timestamp mismatch. Calculated: " << timestamp_us
+                      << ". Saved: " << last_timestamp_us_;
+    return false;
+  }
+  if (size_bytes_ != packet_size) {
+    RTC_LOG(LS_ERROR) << "Rtcp packet size mismatch. Calculated: "
+                      << packet_size << ". Saved: " << size_bytes_;
+    return false;
+  }
+  return true;
+}
+
+size_t TransportFeedback::BlockLength() const {
+  // Round size_bytes_ up to multiple of 32bits.
+  return (size_bytes_ + 3) & (~static_cast<size_t>(3));
+}
+
+// Serialize packet.
+bool TransportFeedback::Create(uint8_t* packet,
+                               size_t* position,
+                               size_t max_length,
+                               PacketReadyCallback callback) const {
+  if (num_seq_no_ == 0)
+    return false;
+
+  while (*position + BlockLength() > max_length) {
+    if (!OnBufferFull(packet, position, callback))
+      return false;
+  }
+  const size_t position_end = *position + BlockLength();
+
+  CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
+               position);
+  CreateCommonFeedback(packet + *position);
+  *position += kCommonFeedbackLength;
+
+  ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_no_);
+  *position += 2;
+
+  ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], num_seq_no_);
+  *position += 2;
+
+  ByteWriter<int32_t, 3>::WriteBigEndian(&packet[*position], base_time_ticks_);
+  *position += 3;
+
+  packet[(*position)++] = feedback_seq_;
+
+  for (uint16_t chunk : encoded_chunks_) {
+    ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk);
+    *position += 2;
+  }
+  if (!last_chunk_.Empty()) {
+    uint16_t chunk = last_chunk_.EncodeLast();
+    ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk);
+    *position += 2;
+  }
+
+  for (const auto& received_packet : packets_) {
+    int16_t delta = received_packet.delta_ticks();
+    if (delta >= 0 && delta <= 0xFF) {
+      packet[(*position)++] = delta;
+    } else {
+      ByteWriter<int16_t>::WriteBigEndian(&packet[*position], delta);
+      *position += 2;
+    }
+  }
+
+  while ((*position % 4) != 0)
+    packet[(*position)++] = 0;
+
+  RTC_DCHECK_EQ(*position, position_end);
+  return true;
+}
+
+void TransportFeedback::Clear() {
+  num_seq_no_ = 0;
+  last_timestamp_us_ = GetBaseTimeUs();
+  packets_.clear();
+  encoded_chunks_.clear();
+  last_chunk_.Clear();
+  size_bytes_ = kTransportFeedbackHeaderSizeBytes;
+}
+
+bool TransportFeedback::AddDeltaSize(DeltaSize delta_size) {
+  if (num_seq_no_ == kMaxReportedPackets)
+    return false;
+  size_t add_chunk_size = last_chunk_.Empty() ? kChunkSizeBytes : 0;
+  if (size_bytes_ + delta_size + add_chunk_size > kMaxSizeBytes)
+    return false;
+
+  if (last_chunk_.CanAdd(delta_size)) {
+    size_bytes_ += add_chunk_size;
+    last_chunk_.Add(delta_size);
+    ++num_seq_no_;
+    return true;
+  }
+  if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes)
+    return false;
+
+  encoded_chunks_.push_back(last_chunk_.Emit());
+  size_bytes_ += kChunkSizeBytes;
+  last_chunk_.Add(delta_size);
+  ++num_seq_no_;
+  return true;
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
new file mode 100644
index 0000000..fbdc38e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
@@ -0,0 +1,154 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_
+
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_packet/rtpfb.h"
+
+namespace webrtc {
+namespace rtcp {
+class CommonHeader;
+
+class TransportFeedback : public Rtpfb {
+ public:
+  class ReceivedPacket {
+   public:
+    ReceivedPacket(uint16_t sequence_number, int16_t delta_ticks)
+        : sequence_number_(sequence_number), delta_ticks_(delta_ticks) {}
+    ReceivedPacket(const ReceivedPacket&) = default;
+    ReceivedPacket& operator=(const ReceivedPacket&) = default;
+
+    uint16_t sequence_number() const { return sequence_number_; }
+    int16_t delta_ticks() const { return delta_ticks_; }
+    int32_t delta_us() const { return delta_ticks_ * kDeltaScaleFactor; }
+
+   private:
+    uint16_t sequence_number_;
+    int16_t delta_ticks_;
+  };
+  // TODO(sprang): IANA reg?
+  static constexpr uint8_t kFeedbackMessageType = 15;
+  // Convert to multiples of 0.25ms.
+  static constexpr int kDeltaScaleFactor = 250;
+  // Maximum number of packets (including missing) TransportFeedback can report.
+  static constexpr size_t kMaxReportedPackets = 0xffff;
+
+  TransportFeedback();
+  TransportFeedback(const TransportFeedback&);
+  TransportFeedback(TransportFeedback&&);
+
+  ~TransportFeedback() override;
+
+  void SetBase(uint16_t base_sequence,     // Seq# of first packet in this msg.
+               int64_t ref_timestamp_us);  // Reference timestamp for this msg.
+  void SetFeedbackSequenceNumber(uint8_t feedback_sequence);
+  // NOTE: This method requires increasing sequence numbers (excepting wraps).
+  bool AddReceivedPacket(uint16_t sequence_number, int64_t timestamp_us);
+  const std::vector<ReceivedPacket>& GetReceivedPackets() const;
+
+  uint16_t GetBaseSequence() const;
+
+  // Returns number of packets (including missing) this feedback describes.
+  size_t GetPacketStatusCount() const { return num_seq_no_; }
+
+  // Get the reference time in microseconds, including any precision loss.
+  int64_t GetBaseTimeUs() const;
+
+  bool Parse(const CommonHeader& packet);
+  static std::unique_ptr<TransportFeedback> ParseFrom(const uint8_t* buffer,
+                                                      size_t length);
+  // Pre and postcondition for all public methods. Should always return true.
+  // This function is for tests.
+  bool IsConsistent() const;
+
+  size_t BlockLength() const override;
+
+  bool Create(uint8_t* packet,
+              size_t* position,
+              size_t max_length,
+              PacketReadyCallback callback) const override;
+
+ private:
+  // Size in bytes of a delta time in rtcp packet.
+  // Valid values are 0 (packet wasn't received), 1 or 2.
+  using DeltaSize = uint8_t;
+  // Keeps DeltaSizes that can be encoded into single chunk if it is last chunk.
+  class LastChunk {
+   public:
+    using DeltaSize = TransportFeedback::DeltaSize;
+
+    LastChunk();
+
+    bool Empty() const;
+    void Clear();
+    // Return if delta sizes still can be encoded into single chunk with added
+    // |delta_size|.
+    bool CanAdd(DeltaSize delta_size) const;
+    // Add |delta_size|, assumes |CanAdd(delta_size)|,
+    void Add(DeltaSize delta_size);
+
+    // Encode chunk as large as possible removing encoded delta sizes.
+    // Assume CanAdd() == false for some valid delta_size.
+    uint16_t Emit();
+    // Encode all stored delta_sizes into single chunk, pad with 0s if needed.
+    uint16_t EncodeLast() const;
+
+    // Decode up to |max_size| delta sizes from |chunk|.
+    void Decode(uint16_t chunk, size_t max_size);
+    // Appends content of the Lastchunk to |deltas|.
+    void AppendTo(std::vector<DeltaSize>* deltas) const;
+
+   private:
+    static constexpr size_t kMaxRunLengthCapacity = 0x1fff;
+    static constexpr size_t kMaxOneBitCapacity = 14;
+    static constexpr size_t kMaxTwoBitCapacity = 7;
+    static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity;
+    static constexpr DeltaSize kLarge = 2;
+
+    uint16_t EncodeOneBit() const;
+    void DecodeOneBit(uint16_t chunk, size_t max_size);
+
+    uint16_t EncodeTwoBit(size_t size) const;
+    void DecodeTwoBit(uint16_t chunk, size_t max_size);
+
+    uint16_t EncodeRunLength() const;
+    void DecodeRunLength(uint16_t chunk, size_t max_size);
+
+    DeltaSize delta_sizes_[kMaxVectorCapacity];
+    size_t size_;
+    bool all_same_;
+    bool has_large_delta_;
+  };
+
+  // Reset packet to consistent empty state.
+  void Clear();
+
+  bool AddDeltaSize(DeltaSize delta_size);
+
+  uint16_t base_seq_no_;
+  uint16_t num_seq_no_;
+  int32_t base_time_ticks_;
+  uint8_t feedback_seq_;
+
+  int64_t last_timestamp_us_;
+  std::vector<ReceivedPacket> packets_;
+  // All but last encoded packet chunks.
+  std::vector<uint16_t> encoded_chunks_;
+  LastChunk last_chunk_;
+  size_t size_bytes_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_TRANSPORT_FEEDBACK_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
new file mode 100644
index 0000000..0496525
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc
@@ -0,0 +1,494 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+using rtcp::TransportFeedback;
+
+static const int kHeaderSize = 20;
+static const int kStatusChunkSize = 2;
+static const int kSmallDeltaSize = 1;
+static const int kLargeDeltaSize = 2;
+
+static const int64_t kDeltaLimit = 0xFF * TransportFeedback::kDeltaScaleFactor;
+
+class FeedbackTester {
+ public:
+  FeedbackTester()
+      : expected_size_(kAnySize),
+        default_delta_(TransportFeedback::kDeltaScaleFactor * 4) {}
+
+  void WithExpectedSize(size_t expected_size) {
+    expected_size_ = expected_size;
+  }
+
+  void WithDefaultDelta(int64_t delta) { default_delta_ = delta; }
+
+  void WithInput(const uint16_t received_seq[],
+                 const int64_t received_ts[],
+                 uint16_t length) {
+    std::unique_ptr<int64_t[]> temp_deltas;
+    if (received_ts == nullptr) {
+      temp_deltas.reset(new int64_t[length]);
+      GenerateDeltas(received_seq, length, temp_deltas.get());
+      received_ts = temp_deltas.get();
+    }
+
+    expected_seq_.clear();
+    expected_deltas_.clear();
+    feedback_.reset(new TransportFeedback());
+    feedback_->SetBase(received_seq[0], received_ts[0]);
+    ASSERT_TRUE(feedback_->IsConsistent());
+
+    int64_t last_time = feedback_->GetBaseTimeUs();
+    for (int i = 0; i < length; ++i) {
+      int64_t time = received_ts[i];
+      EXPECT_TRUE(feedback_->AddReceivedPacket(received_seq[i], time));
+
+      if (last_time != -1) {
+        int64_t delta = time - last_time;
+        expected_deltas_.push_back(delta);
+      }
+      last_time = time;
+    }
+    ASSERT_TRUE(feedback_->IsConsistent());
+    expected_seq_.insert(expected_seq_.begin(), &received_seq[0],
+                         &received_seq[length]);
+  }
+
+  void VerifyPacket() {
+    ASSERT_TRUE(feedback_->IsConsistent());
+    serialized_ = feedback_->Build();
+    VerifyInternal();
+    feedback_ =
+        TransportFeedback::ParseFrom(serialized_.data(), serialized_.size());
+    ASSERT_TRUE(feedback_->IsConsistent());
+    ASSERT_NE(nullptr, feedback_.get());
+    VerifyInternal();
+  }
+
+  static const size_t kAnySize = static_cast<size_t>(0) - 1;
+
+ private:
+  void VerifyInternal() {
+    if (expected_size_ != kAnySize) {
+      // Round up to whole 32-bit words.
+      size_t expected_size_words = (expected_size_ + 3) / 4;
+      size_t expected_size_bytes = expected_size_words * 4;
+      EXPECT_EQ(expected_size_bytes, serialized_.size());
+    }
+
+    std::vector<uint16_t> actual_seq_nos;
+    std::vector<int64_t> actual_deltas_us;
+    for (const auto& packet : feedback_->GetReceivedPackets()) {
+      actual_seq_nos.push_back(packet.sequence_number());
+      actual_deltas_us.push_back(packet.delta_us());
+    }
+    EXPECT_THAT(actual_seq_nos, ElementsAreArray(expected_seq_));
+    EXPECT_THAT(actual_deltas_us, ElementsAreArray(expected_deltas_));
+  }
+
+  void GenerateDeltas(const uint16_t seq[],
+                      const size_t length,
+                      int64_t* deltas) {
+    uint16_t last_seq = seq[0];
+    int64_t offset = 0;
+
+    for (size_t i = 0; i < length; ++i) {
+      if (seq[i] < last_seq)
+        offset += 0x10000 * default_delta_;
+      last_seq = seq[i];
+
+      deltas[i] = offset + (last_seq * default_delta_);
+    }
+  }
+
+  std::vector<uint16_t> expected_seq_;
+  std::vector<int64_t> expected_deltas_;
+  size_t expected_size_;
+  int64_t default_delta_;
+  std::unique_ptr<TransportFeedback> feedback_;
+  rtc::Buffer serialized_;
+};
+
+TEST(RtcpPacketTest, TransportFeedback_OneBitVector) {
+  const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, nullptr, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_FullOneBitVector) {
+  const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, nullptr, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapReceived) {
+  const uint16_t kMax = 0xFFFF;
+  const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, nullptr, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapMissing) {
+  const uint16_t kMax = 0xFFFF;
+  const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, nullptr, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_TwoBitVector) {
+  const uint16_t kReceived[] = {1, 2, 6, 7};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + (kLength * kLargeDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor);
+  test.WithInput(kReceived, nullptr, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_TwoBitVectorFull) {
+  const uint16_t kReceived[] = {1, 2, 6, 7, 8};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + (2 * kStatusChunkSize) + (kLength * kLargeDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor);
+  test.WithInput(kReceived, nullptr, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_LargeAndNegativeDeltas) {
+  const uint16_t kReceived[] = {1, 2, 6, 7, 8};
+  const int64_t kReceiveTimes[] = {
+      2000, 1000, 4000, 3000,
+      3000 + TransportFeedback::kDeltaScaleFactor * (1 << 8)};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + (3 * kLargeDeltaSize) + kSmallDeltaSize;
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, kReceiveTimes, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_MaxRle) {
+  // Expected chunks created:
+  // * 1-bit vector chunk (1xreceived + 13xdropped)
+  // * RLE chunk of max length for dropped symbol
+  // * 1-bit vector chunk (1xreceived + 13xdropped)
+
+  const size_t kPacketCount = (1 << 13) - 1 + 14;
+  const uint16_t kReceived[] = {0, kPacketCount};
+  const int64_t kReceiveTimes[] = {1000, 2000};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, kReceiveTimes, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_MinRle) {
+  // Expected chunks created:
+  // * 1-bit vector chunk (1xreceived + 13xdropped)
+  // * RLE chunk of length 15 for dropped symbol
+  // * 1-bit vector chunk (1xreceived + 13xdropped)
+
+  const uint16_t kReceived[] = {0, (14 * 2) + 1};
+  const int64_t kReceiveTimes[] = {1000, 2000};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize);
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, kReceiveTimes, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVector) {
+  const size_t kTwoBitVectorCapacity = 7;
+  const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1};
+  const int64_t kReceiveTimes[] = {
+      0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + kSmallDeltaSize + kLargeDeltaSize;
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, kReceiveTimes, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSimpleSplit) {
+  const size_t kTwoBitVectorCapacity = 7;
+  const uint16_t kReceived[] = {0, kTwoBitVectorCapacity};
+  const int64_t kReceiveTimes[] = {
+      0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor};
+  const size_t kLength = sizeof(kReceived) / sizeof(uint16_t);
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + (kStatusChunkSize * 2) + kSmallDeltaSize + kLargeDeltaSize;
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, kReceiveTimes, kLength);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSplit) {
+  // With received small delta = S, received large delta = L, use input
+  // SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L.
+  // After split there will be two symbols in symbol_vec: SL.
+
+  const int64_t kLargeDelta = TransportFeedback::kDeltaScaleFactor * (1 << 8);
+  const size_t kNumPackets = (3 * 7) + 1;
+  const size_t kExpectedSizeBytes = kHeaderSize + (kStatusChunkSize * 3) +
+                                    (kSmallDeltaSize * (kNumPackets - 1)) +
+                                    (kLargeDeltaSize * 1);
+
+  uint16_t kReceived[kNumPackets];
+  for (size_t i = 0; i < kNumPackets; ++i)
+    kReceived[i] = i;
+
+  int64_t kReceiveTimes[kNumPackets];
+  kReceiveTimes[0] = 1000;
+  for (size_t i = 1; i < kNumPackets; ++i) {
+    int delta = (i == 8) ? kLargeDelta : 1000;
+    kReceiveTimes[i] = kReceiveTimes[i - 1] + delta;
+  }
+
+  FeedbackTester test;
+  test.WithExpectedSize(kExpectedSizeBytes);
+  test.WithInput(kReceived, kReceiveTimes, kNumPackets);
+  test.VerifyPacket();
+}
+
+TEST(RtcpPacketTest, TransportFeedback_Aliasing) {
+  TransportFeedback feedback;
+  feedback.SetBase(0, 0);
+
+  const int kSamples = 100;
+  const int64_t kTooSmallDelta = TransportFeedback::kDeltaScaleFactor / 3;
+
+  for (int i = 0; i < kSamples; ++i)
+    feedback.AddReceivedPacket(i, i * kTooSmallDelta);
+
+  feedback.Build();
+
+  int64_t accumulated_delta = 0;
+  int num_samples = 0;
+  for (const auto& packet : feedback.GetReceivedPackets()) {
+    accumulated_delta += packet.delta_us();
+    int64_t expected_time = num_samples * kTooSmallDelta;
+    ++num_samples;
+
+    EXPECT_NEAR(expected_time, accumulated_delta,
+                TransportFeedback::kDeltaScaleFactor / 2);
+  }
+}
+
+TEST(RtcpPacketTest, TransportFeedback_Limits) {
+  // Sequence number wrap above 0x8000.
+  std::unique_ptr<TransportFeedback> packet(new TransportFeedback());
+  packet->SetBase(0, 0);
+  EXPECT_TRUE(packet->AddReceivedPacket(0x0, 0));
+  EXPECT_TRUE(packet->AddReceivedPacket(0x8000, 1000));
+
+  packet.reset(new TransportFeedback());
+  packet->SetBase(0, 0);
+  EXPECT_TRUE(packet->AddReceivedPacket(0x0, 0));
+  EXPECT_FALSE(packet->AddReceivedPacket(0x8000 + 1, 1000));
+
+  // Packet status count max 0xFFFF.
+  packet.reset(new TransportFeedback());
+  packet->SetBase(0, 0);
+  EXPECT_TRUE(packet->AddReceivedPacket(0x0, 0));
+  EXPECT_TRUE(packet->AddReceivedPacket(0x8000, 1000));
+  EXPECT_TRUE(packet->AddReceivedPacket(0xFFFE, 2000));
+  EXPECT_FALSE(packet->AddReceivedPacket(0xFFFF, 3000));
+
+  // Too large delta.
+  packet.reset(new TransportFeedback());
+  packet->SetBase(0, 0);
+  int64_t kMaxPositiveTimeDelta = std::numeric_limits<int16_t>::max() *
+                                  TransportFeedback::kDeltaScaleFactor;
+  EXPECT_FALSE(packet->AddReceivedPacket(
+      1, kMaxPositiveTimeDelta + TransportFeedback::kDeltaScaleFactor));
+  EXPECT_TRUE(packet->AddReceivedPacket(1, kMaxPositiveTimeDelta));
+
+  // Too large negative delta.
+  packet.reset(new TransportFeedback());
+  packet->SetBase(0, 0);
+  int64_t kMaxNegativeTimeDelta = std::numeric_limits<int16_t>::min() *
+                                  TransportFeedback::kDeltaScaleFactor;
+  EXPECT_FALSE(packet->AddReceivedPacket(
+      1, kMaxNegativeTimeDelta - TransportFeedback::kDeltaScaleFactor));
+  EXPECT_TRUE(packet->AddReceivedPacket(1, kMaxNegativeTimeDelta));
+
+  // Base time at maximum value.
+  int64_t kMaxBaseTime =
+      static_cast<int64_t>(TransportFeedback::kDeltaScaleFactor) * (1L << 8) *
+      ((1L << 23) - 1);
+  packet.reset(new TransportFeedback());
+  packet->SetBase(0, kMaxBaseTime);
+  EXPECT_TRUE(packet->AddReceivedPacket(0, kMaxBaseTime));
+  // Serialize and de-serialize (verify 24bit parsing).
+  rtc::Buffer raw_packet = packet->Build();
+  packet = TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size());
+  EXPECT_EQ(kMaxBaseTime, packet->GetBaseTimeUs());
+
+  // Base time above maximum value.
+  int64_t kTooLargeBaseTime =
+      kMaxBaseTime + (TransportFeedback::kDeltaScaleFactor * (1L << 8));
+  packet.reset(new TransportFeedback());
+  packet->SetBase(0, kTooLargeBaseTime);
+  packet->AddReceivedPacket(0, kTooLargeBaseTime);
+  raw_packet = packet->Build();
+  packet = TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size());
+  EXPECT_NE(kTooLargeBaseTime, packet->GetBaseTimeUs());
+
+  // TODO(sprang): Once we support max length lower than RTCP length limit,
+  // add back test for max size in bytes.
+}
+
+TEST(RtcpPacketTest, TransportFeedback_Padding) {
+  const size_t kExpectedSizeBytes =
+      kHeaderSize + kStatusChunkSize + kSmallDeltaSize;
+  const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4;
+
+  TransportFeedback feedback;
+  feedback.SetBase(0, 0);
+  EXPECT_TRUE(feedback.AddReceivedPacket(0, 0));
+
+  rtc::Buffer packet = feedback.Build();
+  EXPECT_EQ(kExpectedSizeWords * 4, packet.size());
+  ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes);
+  for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i)
+    EXPECT_EQ(0u, packet.data()[i]);
+
+  // Modify packet by adding 4 bytes of padding at the end. Not currently used
+  // when we're sending, but need to be able to handle it when receiving.
+
+  const int kPaddingBytes = 4;
+  const size_t kExpectedSizeWithPadding =
+      (kExpectedSizeWords * 4) + kPaddingBytes;
+  uint8_t mod_buffer[kExpectedSizeWithPadding];
+  memcpy(mod_buffer, packet.data(), kExpectedSizeWords * 4);
+  memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1);
+  mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes;
+  const uint8_t padding_flag = 1 << 5;
+  mod_buffer[0] |= padding_flag;
+  ByteWriter<uint16_t>::WriteBigEndian(
+      &mod_buffer[2], ByteReader<uint16_t>::ReadBigEndian(&mod_buffer[2]) +
+                          ((kPaddingBytes + 3) / 4));
+
+  std::unique_ptr<TransportFeedback> parsed_packet(
+      TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding));
+  ASSERT_TRUE(parsed_packet.get() != nullptr);
+  EXPECT_EQ(kExpectedSizeWords * 4, packet.size());  // Padding not included.
+}
+
+TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) {
+  const int kOneBitVectorCapacity = 14;
+  const int64_t kLargeTimeDelta =
+      TransportFeedback::kDeltaScaleFactor * (1 << 8);
+
+  // Test that a number of small deltas followed by a large delta results in a
+  // correct split into multiple chunks, as needed.
+
+  for (int deltas = 0; deltas <= kOneBitVectorCapacity + 1; ++deltas) {
+    TransportFeedback feedback;
+    feedback.SetBase(0, 0);
+    for (int i = 0; i < deltas; ++i)
+      feedback.AddReceivedPacket(i, i * 1000);
+    feedback.AddReceivedPacket(deltas, deltas * 1000 + kLargeTimeDelta);
+
+    rtc::Buffer serialized_packet = feedback.Build();
+    std::unique_ptr<TransportFeedback> deserialized_packet =
+        TransportFeedback::ParseFrom(serialized_packet.data(),
+                                     serialized_packet.size());
+    EXPECT_TRUE(deserialized_packet.get() != nullptr);
+  }
+}
+
+TEST(RtcpPacketTest, TransportFeedback_MoveConstructor) {
+  const int kSamples = 100;
+  const int64_t kDelta = TransportFeedback::kDeltaScaleFactor;
+  const uint16_t kBaseSeqNo = 7531;
+  const int64_t kBaseTimestampUs = 123456789;
+  const uint8_t kFeedbackSeqNo = 90;
+
+  TransportFeedback feedback;
+  feedback.SetBase(kBaseSeqNo, kBaseTimestampUs);
+  feedback.SetFeedbackSequenceNumber(kFeedbackSeqNo);
+  for (int i = 0; i < kSamples; ++i) {
+    feedback.AddReceivedPacket(kBaseSeqNo + i, kBaseTimestampUs + i * kDelta);
+  }
+  EXPECT_TRUE(feedback.IsConsistent());
+
+  TransportFeedback feedback_copy(feedback);
+  EXPECT_TRUE(feedback_copy.IsConsistent());
+  EXPECT_TRUE(feedback.IsConsistent());
+  EXPECT_EQ(feedback_copy.Build(), feedback.Build());
+
+  TransportFeedback moved(std::move(feedback));
+  EXPECT_TRUE(moved.IsConsistent());
+  EXPECT_TRUE(feedback.IsConsistent());
+  EXPECT_EQ(moved.Build(), feedback_copy.Build());
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc b/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc
new file mode 100644
index 0000000..b715b3d
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/voip_metric.cc
@@ -0,0 +1,107 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h"
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rtcp {
+// VoIP Metrics Report Block (RFC 3611).
+//
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  0 |     BT=7      |   reserved    |       block length = 8        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  4 |                        SSRC of source                         |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  8 |   loss rate   | discard rate  | burst density |  gap density  |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 12 |       burst duration          |         gap duration          |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 16 |     round trip delay          |       end system delay        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 20 | signal level  |  noise level  |     RERL      |     Gmin      |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 24 |   R factor    | ext. R factor |    MOS-LQ     |    MOS-CQ     |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 28 |   RX config   |   reserved    |          JB nominal           |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// 32 |          JB maximum           |          JB abs max           |
+// 36 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+VoipMetric::VoipMetric() : ssrc_(0) {
+  memset(&voip_metric_, 0, sizeof(voip_metric_));
+}
+
+void VoipMetric::Parse(const uint8_t* buffer) {
+  RTC_DCHECK(buffer[0] == kBlockType);
+  // reserved = buffer[1];
+  RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength);
+  ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+  voip_metric_.lossRate = buffer[8];
+  voip_metric_.discardRate = buffer[9];
+  voip_metric_.burstDensity = buffer[10];
+  voip_metric_.gapDensity = buffer[11];
+  voip_metric_.burstDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
+  voip_metric_.gapDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[14]);
+  voip_metric_.roundTripDelay =
+      ByteReader<uint16_t>::ReadBigEndian(&buffer[16]);
+  voip_metric_.endSystemDelay =
+      ByteReader<uint16_t>::ReadBigEndian(&buffer[18]);
+  voip_metric_.signalLevel = buffer[20];
+  voip_metric_.noiseLevel = buffer[21];
+  voip_metric_.RERL = buffer[22];
+  voip_metric_.Gmin = buffer[23];
+  voip_metric_.Rfactor = buffer[24];
+  voip_metric_.extRfactor = buffer[25];
+  voip_metric_.MOSLQ = buffer[26];
+  voip_metric_.MOSCQ = buffer[27];
+  voip_metric_.RXconfig = buffer[28];
+  // reserved = buffer[29];
+  voip_metric_.JBnominal = ByteReader<uint16_t>::ReadBigEndian(&buffer[30]);
+  voip_metric_.JBmax = ByteReader<uint16_t>::ReadBigEndian(&buffer[32]);
+  voip_metric_.JBabsMax = ByteReader<uint16_t>::ReadBigEndian(&buffer[34]);
+}
+
+void VoipMetric::Create(uint8_t* buffer) const {
+  const uint8_t kReserved = 0;
+  buffer[0] = kBlockType;
+  buffer[1] = kReserved;
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength);
+  ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ssrc_);
+  buffer[8] = voip_metric_.lossRate;
+  buffer[9] = voip_metric_.discardRate;
+  buffer[10] = voip_metric_.burstDensity;
+  buffer[11] = voip_metric_.gapDensity;
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[12], voip_metric_.burstDuration);
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[14], voip_metric_.gapDuration);
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[16],
+                                       voip_metric_.roundTripDelay);
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[18],
+                                       voip_metric_.endSystemDelay);
+  buffer[20] = voip_metric_.signalLevel;
+  buffer[21] = voip_metric_.noiseLevel;
+  buffer[22] = voip_metric_.RERL;
+  buffer[23] = voip_metric_.Gmin;
+  buffer[24] = voip_metric_.Rfactor;
+  buffer[25] = voip_metric_.extRfactor;
+  buffer[26] = voip_metric_.MOSLQ;
+  buffer[27] = voip_metric_.MOSCQ;
+  buffer[28] = voip_metric_.RXconfig;
+  buffer[29] = kReserved;
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[30], voip_metric_.JBnominal);
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[32], voip_metric_.JBmax);
+  ByteWriter<uint16_t>::WriteBigEndian(&buffer[34], voip_metric_.JBabsMax);
+}
+
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h b/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h
new file mode 100644
index 0000000..c5588a4
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
+
+#include "modules/include/module_common_types.h"
+
+namespace webrtc {
+namespace rtcp {
+
+class VoipMetric {
+ public:
+  static const uint8_t kBlockType = 7;
+  static const uint16_t kBlockLength = 8;
+  static const size_t kLength = 4 * (kBlockLength + 1);  // 36
+  VoipMetric();
+  VoipMetric(const VoipMetric&) = default;
+  ~VoipMetric() {}
+
+  VoipMetric& operator=(const VoipMetric&) = default;
+
+  void Parse(const uint8_t* buffer);
+
+  // Fills buffer with the VoipMetric.
+  // Consumes VoipMetric::kLength bytes.
+  void Create(uint8_t* buffer) const;
+
+  void SetMediaSsrc(uint32_t ssrc) { ssrc_ = ssrc; }
+  void SetVoipMetric(const RTCPVoIPMetric& voip_metric) {
+    voip_metric_ = voip_metric;
+  }
+
+  uint32_t ssrc() const { return ssrc_; }
+  const RTCPVoIPMetric& voip_metric() const { return voip_metric_; }
+
+ private:
+  uint32_t ssrc_;
+  RTCPVoIPMetric voip_metric_;
+};
+
+}  // namespace rtcp
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
diff --git a/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc
new file mode 100644
index 0000000..598b8c6
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet/voip_metric_unittest.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace rtcp {
+namespace {
+
+const uint32_t kRemoteSsrc = 0x23456789;
+const uint8_t kBlock[] = {0x07, 0x00, 0x00, 0x08, 0x23, 0x45, 0x67, 0x89, 0x01,
+                          0x02, 0x03, 0x04, 0x11, 0x12, 0x22, 0x23, 0x33, 0x34,
+                          0x44, 0x45, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+                          0x0c, 0x0d, 0x00, 0x55, 0x56, 0x66, 0x67, 0x77, 0x78};
+const size_t kBlockSizeBytes = sizeof(kBlock);
+static_assert(
+    kBlockSizeBytes == VoipMetric::kLength,
+    "Size of manually created Voip Metric block should match class constant");
+
+TEST(RtcpPacketVoipMetricTest, Create) {
+  uint8_t buffer[VoipMetric::kLength];
+  RTCPVoIPMetric metric;
+  metric.lossRate = 1;
+  metric.discardRate = 2;
+  metric.burstDensity = 3;
+  metric.gapDensity = 4;
+  metric.burstDuration = 0x1112;
+  metric.gapDuration = 0x2223;
+  metric.roundTripDelay = 0x3334;
+  metric.endSystemDelay = 0x4445;
+  metric.signalLevel = 5;
+  metric.noiseLevel = 6;
+  metric.RERL = 7;
+  metric.Gmin = 8;
+  metric.Rfactor = 9;
+  metric.extRfactor = 10;
+  metric.MOSLQ = 11;
+  metric.MOSCQ = 12;
+  metric.RXconfig = 13;
+  metric.JBnominal = 0x5556;
+  metric.JBmax = 0x6667;
+  metric.JBabsMax = 0x7778;
+  VoipMetric metric_block;
+  metric_block.SetMediaSsrc(kRemoteSsrc);
+  metric_block.SetVoipMetric(metric);
+
+  metric_block.Create(buffer);
+  EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
+}
+
+TEST(RtcpPacketVoipMetricTest, Parse) {
+  VoipMetric read_metric;
+  read_metric.Parse(kBlock);
+
+  // Run checks on const object to ensure all accessors have const modifier.
+  const VoipMetric& parsed = read_metric;
+
+  EXPECT_EQ(kRemoteSsrc, parsed.ssrc());
+  EXPECT_EQ(1, parsed.voip_metric().lossRate);
+  EXPECT_EQ(2, parsed.voip_metric().discardRate);
+  EXPECT_EQ(3, parsed.voip_metric().burstDensity);
+  EXPECT_EQ(4, parsed.voip_metric().gapDensity);
+  EXPECT_EQ(0x1112, parsed.voip_metric().burstDuration);
+  EXPECT_EQ(0x2223, parsed.voip_metric().gapDuration);
+  EXPECT_EQ(0x3334, parsed.voip_metric().roundTripDelay);
+  EXPECT_EQ(0x4445, parsed.voip_metric().endSystemDelay);
+  EXPECT_EQ(5, parsed.voip_metric().signalLevel);
+  EXPECT_EQ(6, parsed.voip_metric().noiseLevel);
+  EXPECT_EQ(7, parsed.voip_metric().RERL);
+  EXPECT_EQ(8, parsed.voip_metric().Gmin);
+  EXPECT_EQ(9, parsed.voip_metric().Rfactor);
+  EXPECT_EQ(10, parsed.voip_metric().extRfactor);
+  EXPECT_EQ(11, parsed.voip_metric().MOSLQ);
+  EXPECT_EQ(12, parsed.voip_metric().MOSCQ);
+  EXPECT_EQ(13, parsed.voip_metric().RXconfig);
+  EXPECT_EQ(0x5556, parsed.voip_metric().JBnominal);
+  EXPECT_EQ(0x6667, parsed.voip_metric().JBmax);
+  EXPECT_EQ(0x7778, parsed.voip_metric().JBabsMax);
+}
+
+}  // namespace
+}  // namespace rtcp
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
new file mode 100644
index 0000000..788028d
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace {
+
+using ::testing::_;
+using ::testing::MockFunction;
+using ::webrtc::rtcp::ReceiverReport;
+using ::webrtc::rtcp::ReportBlock;
+
+const uint32_t kSenderSsrc = 0x12345678;
+
+TEST(RtcpPacketTest, BuildWithTooSmallBuffer) {
+  ReportBlock rb;
+  ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_TRUE(rr.AddReportBlock(rb));
+
+  const size_t kRrLength = 8;
+  const size_t kReportBlockLength = 24;
+
+  // No packet.
+  MockFunction<void(rtc::ArrayView<const uint8_t>)> callback;
+  EXPECT_CALL(callback, Call(_)).Times(0);
+  const size_t kBufferSize = kRrLength + kReportBlockLength - 1;
+  EXPECT_FALSE(rr.Build(kBufferSize, callback.AsStdFunction()));
+}
+
+}  // namespace
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc
new file mode 100644
index 0000000..491bd45
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -0,0 +1,1084 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_receiver.h"
+
+#include <string.h>
+
+#include <limits>
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/video/video_bitrate_allocation.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "common_video/include/video_bitrate_allocator.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "modules/rtp_rtcp/source/tmmbr_help.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/trace_event.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+namespace {
+
+using rtcp::CommonHeader;
+using rtcp::ReportBlock;
+
+// The number of RTCP time intervals needed to trigger a timeout.
+const int kRrTimeoutIntervals = 3;
+
+const int64_t kTmmbrTimeoutIntervalMs = 5 * 5000;
+
+const int64_t kMaxWarningLogIntervalMs = 10000;
+const int64_t kRtcpMinFrameLengthMs = 17;
+
+// Maximum number of received RRTRs that will be stored.
+const size_t kMaxNumberOfStoredRrtrs = 200;
+
+}  // namespace
+
+struct RTCPReceiver::PacketInformation {
+  uint32_t packet_type_flags = 0;  // RTCPPacketTypeFlags bit field.
+
+  uint32_t remote_ssrc = 0;
+  std::vector<uint16_t> nack_sequence_numbers;
+  ReportBlockList report_blocks;
+  int64_t rtt_ms = 0;
+  uint32_t receiver_estimated_max_bitrate_bps = 0;
+  std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
+  absl::optional<VideoBitrateAllocation> target_bitrate_allocation;
+};
+
+// Structure for handing TMMBR and TMMBN rtcp messages (RFC5104, section 3.5.4).
+struct RTCPReceiver::TmmbrInformation {
+  struct TimedTmmbrItem {
+    rtcp::TmmbItem tmmbr_item;
+    int64_t last_updated_ms;
+  };
+
+  int64_t last_time_received_ms = 0;
+
+  bool ready_for_delete = false;
+
+  std::vector<rtcp::TmmbItem> tmmbn;
+  std::map<uint32_t, TimedTmmbrItem> tmmbr;
+};
+
+// Structure for storing received RRTR RTCP messages (RFC3611, section 4.4).
+struct RTCPReceiver::RrtrInformation {
+  RrtrInformation(uint32_t ssrc,
+                  uint32_t received_remote_mid_ntp_time,
+                  uint32_t local_receive_mid_ntp_time)
+      : ssrc(ssrc),
+        received_remote_mid_ntp_time(received_remote_mid_ntp_time),
+        local_receive_mid_ntp_time(local_receive_mid_ntp_time) {}
+
+  uint32_t ssrc;
+  // Received NTP timestamp in compact representation.
+  uint32_t received_remote_mid_ntp_time;
+  // NTP time when the report was received in compact representation.
+  uint32_t local_receive_mid_ntp_time;
+};
+
+struct RTCPReceiver::ReportBlockWithRtt {
+  RTCPReportBlock report_block;
+
+  int64_t last_rtt_ms = 0;
+  int64_t min_rtt_ms = 0;
+  int64_t max_rtt_ms = 0;
+  int64_t sum_rtt_ms = 0;
+  size_t num_rtts = 0;
+};
+
+struct RTCPReceiver::LastFirStatus {
+  LastFirStatus(int64_t now_ms, uint8_t sequence_number)
+      : request_ms(now_ms), sequence_number(sequence_number) {}
+  int64_t request_ms;
+  uint8_t sequence_number;
+};
+
+RTCPReceiver::RTCPReceiver(
+    Clock* clock,
+    bool receiver_only,
+    RtcpPacketTypeCounterObserver* packet_type_counter_observer,
+    RtcpBandwidthObserver* rtcp_bandwidth_observer,
+    RtcpIntraFrameObserver* rtcp_intra_frame_observer,
+    TransportFeedbackObserver* transport_feedback_observer,
+    VideoBitrateAllocationObserver* bitrate_allocation_observer,
+    ModuleRtpRtcp* owner)
+    : clock_(clock),
+      receiver_only_(receiver_only),
+      rtp_rtcp_(owner),
+      rtcp_bandwidth_observer_(rtcp_bandwidth_observer),
+      rtcp_intra_frame_observer_(rtcp_intra_frame_observer),
+      transport_feedback_observer_(transport_feedback_observer),
+      bitrate_allocation_observer_(bitrate_allocation_observer),
+      main_ssrc_(0),
+      remote_ssrc_(0),
+      remote_sender_rtp_time_(0),
+      xr_rrtr_status_(false),
+      xr_rr_rtt_ms_(0),
+      oldest_tmmbr_info_ms_(0),
+      last_received_rb_ms_(0),
+      last_increased_sequence_number_ms_(0),
+      stats_callback_(nullptr),
+      packet_type_counter_observer_(packet_type_counter_observer),
+      num_skipped_packets_(0),
+      last_skipped_packets_warning_ms_(clock->TimeInMilliseconds()) {
+  RTC_DCHECK(owner);
+}
+
+RTCPReceiver::~RTCPReceiver() {}
+
+void RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) {
+  if (packet_size == 0) {
+    RTC_LOG(LS_WARNING) << "Incoming empty RTCP packet";
+    return;
+  }
+
+  PacketInformation packet_information;
+  if (!ParseCompoundPacket(packet, packet + packet_size, &packet_information))
+    return;
+  TriggerCallbacksFromRtcpPacket(packet_information);
+}
+
+int64_t RTCPReceiver::LastReceivedReportBlockMs() const {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  return last_received_rb_ms_;
+}
+
+void RTCPReceiver::SetRemoteSSRC(uint32_t ssrc) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  // New SSRC reset old reports.
+  last_received_sr_ntp_.Reset();
+  remote_ssrc_ = ssrc;
+}
+
+uint32_t RTCPReceiver::RemoteSSRC() const {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  return remote_ssrc_;
+}
+
+void RTCPReceiver::SetSsrcs(uint32_t main_ssrc,
+                            const std::set<uint32_t>& registered_ssrcs) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  main_ssrc_ = main_ssrc;
+  registered_ssrcs_ = registered_ssrcs;
+}
+
+int32_t RTCPReceiver::RTT(uint32_t remote_ssrc,
+                          int64_t* last_rtt_ms,
+                          int64_t* avg_rtt_ms,
+                          int64_t* min_rtt_ms,
+                          int64_t* max_rtt_ms) const {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+
+  auto it = received_report_blocks_.find(main_ssrc_);
+  if (it == received_report_blocks_.end())
+    return -1;
+
+  auto it_info = it->second.find(remote_ssrc);
+  if (it_info == it->second.end())
+    return -1;
+
+  const ReportBlockWithRtt* report_block = &it_info->second;
+
+  if (report_block->num_rtts == 0)
+    return -1;
+
+  if (last_rtt_ms)
+    *last_rtt_ms = report_block->last_rtt_ms;
+
+  if (avg_rtt_ms)
+    *avg_rtt_ms = report_block->sum_rtt_ms / report_block->num_rtts;
+
+  if (min_rtt_ms)
+    *min_rtt_ms = report_block->min_rtt_ms;
+
+  if (max_rtt_ms)
+    *max_rtt_ms = report_block->max_rtt_ms;
+
+  return 0;
+}
+
+void RTCPReceiver::SetRtcpXrRrtrStatus(bool enable) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  xr_rrtr_status_ = enable;
+}
+
+bool RTCPReceiver::GetAndResetXrRrRtt(int64_t* rtt_ms) {
+  RTC_DCHECK(rtt_ms);
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  if (xr_rr_rtt_ms_ == 0) {
+    return false;
+  }
+  *rtt_ms = xr_rr_rtt_ms_;
+  xr_rr_rtt_ms_ = 0;
+  return true;
+}
+
+bool RTCPReceiver::NTP(uint32_t* received_ntp_secs,
+                       uint32_t* received_ntp_frac,
+                       uint32_t* rtcp_arrival_time_secs,
+                       uint32_t* rtcp_arrival_time_frac,
+                       uint32_t* rtcp_timestamp) const {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  if (!last_received_sr_ntp_.Valid())
+    return false;
+
+  // NTP from incoming SenderReport.
+  if (received_ntp_secs)
+    *received_ntp_secs = remote_sender_ntp_time_.seconds();
+  if (received_ntp_frac)
+    *received_ntp_frac = remote_sender_ntp_time_.fractions();
+
+  // Rtp time from incoming SenderReport.
+  if (rtcp_timestamp)
+    *rtcp_timestamp = remote_sender_rtp_time_;
+
+  // Local NTP time when we received a RTCP packet with a send block.
+  if (rtcp_arrival_time_secs)
+    *rtcp_arrival_time_secs = last_received_sr_ntp_.seconds();
+  if (rtcp_arrival_time_frac)
+    *rtcp_arrival_time_frac = last_received_sr_ntp_.fractions();
+
+  return true;
+}
+
+std::vector<rtcp::ReceiveTimeInfo>
+RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+
+  const size_t last_xr_rtis_size = std::min(
+      received_rrtrs_.size(), rtcp::ExtendedReports::kMaxNumberOfDlrrItems);
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis;
+  last_xr_rtis.reserve(last_xr_rtis_size);
+
+  const uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
+
+  for (size_t i = 0; i < last_xr_rtis_size; ++i) {
+    RrtrInformation& rrtr = received_rrtrs_.front();
+    last_xr_rtis.emplace_back(rrtr.ssrc, rrtr.received_remote_mid_ntp_time,
+                              now_ntp - rrtr.local_receive_mid_ntp_time);
+    received_rrtrs_ssrc_it_.erase(rrtr.ssrc);
+    received_rrtrs_.pop_front();
+  }
+
+  return last_xr_rtis;
+}
+
+// We can get multiple receive reports when we receive the report from a CE.
+int32_t RTCPReceiver::StatisticsReceived(
+    std::vector<RTCPReportBlock>* receive_blocks) const {
+  RTC_DCHECK(receive_blocks);
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  for (const auto& reports_per_receiver : received_report_blocks_)
+    for (const auto& report : reports_per_receiver.second)
+      receive_blocks->push_back(report.second.report_block);
+  return 0;
+}
+
+bool RTCPReceiver::ParseCompoundPacket(const uint8_t* packet_begin,
+                                       const uint8_t* packet_end,
+                                       PacketInformation* packet_information) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+
+  CommonHeader rtcp_block;
+  for (const uint8_t* next_block = packet_begin; next_block != packet_end;
+       next_block = rtcp_block.NextPacket()) {
+    ptrdiff_t remaining_blocks_size = packet_end - next_block;
+    RTC_DCHECK_GT(remaining_blocks_size, 0);
+    if (!rtcp_block.Parse(next_block, remaining_blocks_size)) {
+      if (next_block == packet_begin) {
+        // Failed to parse 1st header, nothing was extracted from this packet.
+        RTC_LOG(LS_WARNING) << "Incoming invalid RTCP packet";
+        return false;
+      }
+      ++num_skipped_packets_;
+      break;
+    }
+
+    if (packet_type_counter_.first_packet_time_ms == -1)
+      packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds();
+
+    switch (rtcp_block.type()) {
+      case rtcp::SenderReport::kPacketType:
+        HandleSenderReport(rtcp_block, packet_information);
+        break;
+      case rtcp::ReceiverReport::kPacketType:
+        HandleReceiverReport(rtcp_block, packet_information);
+        break;
+      case rtcp::Sdes::kPacketType:
+        HandleSdes(rtcp_block, packet_information);
+        break;
+      case rtcp::ExtendedReports::kPacketType:
+        HandleXr(rtcp_block, packet_information);
+        break;
+      case rtcp::Bye::kPacketType:
+        HandleBye(rtcp_block);
+        break;
+      case rtcp::Rtpfb::kPacketType:
+        switch (rtcp_block.fmt()) {
+          case rtcp::Nack::kFeedbackMessageType:
+            HandleNack(rtcp_block, packet_information);
+            break;
+          case rtcp::Tmmbr::kFeedbackMessageType:
+            HandleTmmbr(rtcp_block, packet_information);
+            break;
+          case rtcp::Tmmbn::kFeedbackMessageType:
+            HandleTmmbn(rtcp_block, packet_information);
+            break;
+          case rtcp::RapidResyncRequest::kFeedbackMessageType:
+            HandleSrReq(rtcp_block, packet_information);
+            break;
+          case rtcp::TransportFeedback::kFeedbackMessageType:
+            HandleTransportFeedback(rtcp_block, packet_information);
+            break;
+          default:
+            ++num_skipped_packets_;
+            break;
+        }
+        break;
+      case rtcp::Psfb::kPacketType:
+        switch (rtcp_block.fmt()) {
+          case rtcp::Pli::kFeedbackMessageType:
+            HandlePli(rtcp_block, packet_information);
+            break;
+          case rtcp::Fir::kFeedbackMessageType:
+            HandleFir(rtcp_block, packet_information);
+            break;
+          case rtcp::Remb::kFeedbackMessageType:
+            HandlePsfbApp(rtcp_block, packet_information);
+            break;
+          default:
+            ++num_skipped_packets_;
+            break;
+        }
+        break;
+      default:
+        ++num_skipped_packets_;
+        break;
+    }
+  }
+
+  if (packet_type_counter_observer_) {
+    packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
+        main_ssrc_, packet_type_counter_);
+  }
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  if (now_ms - last_skipped_packets_warning_ms_ >= kMaxWarningLogIntervalMs &&
+      num_skipped_packets_ > 0) {
+    last_skipped_packets_warning_ms_ = now_ms;
+    RTC_LOG(LS_WARNING)
+        << num_skipped_packets_
+        << " RTCP blocks were skipped due to being malformed or of "
+           "unrecognized/unsupported type, during the past "
+        << (kMaxWarningLogIntervalMs / 1000) << " second period.";
+  }
+
+  return true;
+}
+
+void RTCPReceiver::HandleSenderReport(const CommonHeader& rtcp_block,
+                                      PacketInformation* packet_information) {
+  rtcp::SenderReport sender_report;
+  if (!sender_report.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  const uint32_t remote_ssrc = sender_report.sender_ssrc();
+
+  packet_information->remote_ssrc = remote_ssrc;
+
+  UpdateTmmbrRemoteIsAlive(remote_ssrc);
+
+  // Have I received RTP packets from this party?
+  if (remote_ssrc_ == remote_ssrc) {
+    // Only signal that we have received a SR when we accept one.
+    packet_information->packet_type_flags |= kRtcpSr;
+
+    remote_sender_ntp_time_ = sender_report.ntp();
+    remote_sender_rtp_time_ = sender_report.rtp_timestamp();
+    last_received_sr_ntp_ = clock_->CurrentNtpTime();
+  } else {
+    // We will only store the send report from one source, but
+    // we will store all the receive blocks.
+    packet_information->packet_type_flags |= kRtcpRr;
+  }
+
+  for (const rtcp::ReportBlock report_block : sender_report.report_blocks())
+    HandleReportBlock(report_block, packet_information, remote_ssrc);
+}
+
+void RTCPReceiver::HandleReceiverReport(const CommonHeader& rtcp_block,
+                                        PacketInformation* packet_information) {
+  rtcp::ReceiverReport receiver_report;
+  if (!receiver_report.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  const uint32_t remote_ssrc = receiver_report.sender_ssrc();
+
+  packet_information->remote_ssrc = remote_ssrc;
+
+  UpdateTmmbrRemoteIsAlive(remote_ssrc);
+
+  packet_information->packet_type_flags |= kRtcpRr;
+
+  for (const ReportBlock& report_block : receiver_report.report_blocks())
+    HandleReportBlock(report_block, packet_information, remote_ssrc);
+}
+
+void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block,
+                                     PacketInformation* packet_information,
+                                     uint32_t remote_ssrc) {
+  // This will be called once per report block in the RTCP packet.
+  // We filter out all report blocks that are not for us.
+  // Each packet has max 31 RR blocks.
+  //
+  // We can calc RTT if we send a send report and get a report block back.
+
+  // |report_block.source_ssrc()| is the SSRC identifier of the source to
+  // which the information in this reception report block pertains.
+
+  // Filter out all report blocks that are not for us.
+  if (registered_ssrcs_.count(report_block.source_ssrc()) == 0)
+    return;
+
+  last_received_rb_ms_ = clock_->TimeInMilliseconds();
+
+  ReportBlockWithRtt* report_block_info =
+      &received_report_blocks_[report_block.source_ssrc()][remote_ssrc];
+  report_block_info->report_block.sender_ssrc = remote_ssrc;
+  report_block_info->report_block.source_ssrc = report_block.source_ssrc();
+  report_block_info->report_block.fraction_lost = report_block.fraction_lost();
+  report_block_info->report_block.packets_lost =
+      report_block.cumulative_lost_signed();
+  if (report_block.extended_high_seq_num() >
+      report_block_info->report_block.extended_highest_sequence_number) {
+    // We have successfully delivered new RTP packets to the remote side after
+    // the last RR was sent from the remote side.
+    last_increased_sequence_number_ms_ = clock_->TimeInMilliseconds();
+  }
+  report_block_info->report_block.extended_highest_sequence_number =
+      report_block.extended_high_seq_num();
+  report_block_info->report_block.jitter = report_block.jitter();
+  report_block_info->report_block.delay_since_last_sender_report =
+      report_block.delay_since_last_sr();
+  report_block_info->report_block.last_sender_report_timestamp =
+      report_block.last_sr();
+
+  int64_t rtt_ms = 0;
+  uint32_t send_time_ntp = report_block.last_sr();
+  // RFC3550, section 6.4.1, LSR field discription states:
+  // If no SR has been received yet, the field is set to zero.
+  // Receiver rtp_rtcp module is not expected to calculate rtt using
+  // Sender Reports even if it accidentally can.
+  if (!receiver_only_ && send_time_ntp != 0) {
+    uint32_t delay_ntp = report_block.delay_since_last_sr();
+    // Local NTP time.
+    uint32_t receive_time_ntp = CompactNtp(clock_->CurrentNtpTime());
+
+    // RTT in 1/(2^16) seconds.
+    uint32_t rtt_ntp = receive_time_ntp - delay_ntp - send_time_ntp;
+    // Convert to 1/1000 seconds (milliseconds).
+    rtt_ms = CompactNtpRttToMs(rtt_ntp);
+    if (rtt_ms > report_block_info->max_rtt_ms)
+      report_block_info->max_rtt_ms = rtt_ms;
+
+    if (report_block_info->num_rtts == 0 ||
+        rtt_ms < report_block_info->min_rtt_ms)
+      report_block_info->min_rtt_ms = rtt_ms;
+
+    report_block_info->last_rtt_ms = rtt_ms;
+    report_block_info->sum_rtt_ms += rtt_ms;
+    ++report_block_info->num_rtts;
+
+    packet_information->rtt_ms = rtt_ms;
+  }
+
+  packet_information->report_blocks.push_back(report_block_info->report_block);
+}
+
+RTCPReceiver::TmmbrInformation* RTCPReceiver::FindOrCreateTmmbrInfo(
+    uint32_t remote_ssrc) {
+  // Create or find receive information.
+  TmmbrInformation* tmmbr_info = &tmmbr_infos_[remote_ssrc];
+  // Update that this remote is alive.
+  tmmbr_info->last_time_received_ms = clock_->TimeInMilliseconds();
+  return tmmbr_info;
+}
+
+void RTCPReceiver::UpdateTmmbrRemoteIsAlive(uint32_t remote_ssrc) {
+  auto tmmbr_it = tmmbr_infos_.find(remote_ssrc);
+  if (tmmbr_it != tmmbr_infos_.end())
+    tmmbr_it->second.last_time_received_ms = clock_->TimeInMilliseconds();
+}
+
+RTCPReceiver::TmmbrInformation* RTCPReceiver::GetTmmbrInformation(
+    uint32_t remote_ssrc) {
+  auto it = tmmbr_infos_.find(remote_ssrc);
+  if (it == tmmbr_infos_.end())
+    return nullptr;
+  return &it->second;
+}
+
+bool RTCPReceiver::RtcpRrTimeout(int64_t rtcp_interval_ms) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  if (last_received_rb_ms_ == 0)
+    return false;
+
+  int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
+  if (clock_->TimeInMilliseconds() > last_received_rb_ms_ + time_out_ms) {
+    // Reset the timer to only trigger one log.
+    last_received_rb_ms_ = 0;
+    return true;
+  }
+  return false;
+}
+
+bool RTCPReceiver::RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  if (last_increased_sequence_number_ms_ == 0)
+    return false;
+
+  int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
+  if (clock_->TimeInMilliseconds() >
+      last_increased_sequence_number_ms_ + time_out_ms) {
+    // Reset the timer to only trigger one log.
+    last_increased_sequence_number_ms_ = 0;
+    return true;
+  }
+  return false;
+}
+
+bool RTCPReceiver::UpdateTmmbrTimers() {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t timeout_ms = now_ms - kTmmbrTimeoutIntervalMs;
+
+  if (oldest_tmmbr_info_ms_ >= timeout_ms)
+    return false;
+
+  bool update_bounding_set = false;
+  oldest_tmmbr_info_ms_ = -1;
+  for (auto tmmbr_it = tmmbr_infos_.begin(); tmmbr_it != tmmbr_infos_.end();) {
+    TmmbrInformation* tmmbr_info = &tmmbr_it->second;
+    if (tmmbr_info->last_time_received_ms > 0) {
+      if (tmmbr_info->last_time_received_ms < timeout_ms) {
+        // No rtcp packet for the last 5 regular intervals, reset limitations.
+        tmmbr_info->tmmbr.clear();
+        // Prevent that we call this over and over again.
+        tmmbr_info->last_time_received_ms = 0;
+        // Send new TMMBN to all channels using the default codec.
+        update_bounding_set = true;
+      } else if (oldest_tmmbr_info_ms_ == -1 ||
+                 tmmbr_info->last_time_received_ms < oldest_tmmbr_info_ms_) {
+        oldest_tmmbr_info_ms_ = tmmbr_info->last_time_received_ms;
+      }
+      ++tmmbr_it;
+    } else if (tmmbr_info->ready_for_delete) {
+      // When we dont have a last_time_received_ms and the object is marked
+      // ready_for_delete it's removed from the map.
+      tmmbr_it = tmmbr_infos_.erase(tmmbr_it);
+    } else {
+      ++tmmbr_it;
+    }
+  }
+  return update_bounding_set;
+}
+
+std::vector<rtcp::TmmbItem> RTCPReceiver::BoundingSet(bool* tmmbr_owner) {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  TmmbrInformation* tmmbr_info = GetTmmbrInformation(remote_ssrc_);
+  if (!tmmbr_info)
+    return std::vector<rtcp::TmmbItem>();
+
+  *tmmbr_owner = TMMBRHelp::IsOwner(tmmbr_info->tmmbn, main_ssrc_);
+  return tmmbr_info->tmmbn;
+}
+
+void RTCPReceiver::HandleSdes(const CommonHeader& rtcp_block,
+                              PacketInformation* packet_information) {
+  rtcp::Sdes sdes;
+  if (!sdes.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  for (const rtcp::Sdes::Chunk& chunk : sdes.chunks()) {
+    received_cnames_[chunk.ssrc] = chunk.cname;
+    {
+      rtc::CritScope lock(&feedbacks_lock_);
+      if (stats_callback_)
+        stats_callback_->CNameChanged(chunk.cname.c_str(), chunk.ssrc);
+    }
+  }
+  packet_information->packet_type_flags |= kRtcpSdes;
+}
+
+void RTCPReceiver::HandleNack(const CommonHeader& rtcp_block,
+                              PacketInformation* packet_information) {
+  rtcp::Nack nack;
+  if (!nack.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  if (receiver_only_ || main_ssrc_ != nack.media_ssrc())  // Not to us.
+    return;
+
+  packet_information->nack_sequence_numbers.insert(
+      packet_information->nack_sequence_numbers.end(),
+      nack.packet_ids().begin(), nack.packet_ids().end());
+  for (uint16_t packet_id : nack.packet_ids())
+    nack_stats_.ReportRequest(packet_id);
+
+  if (!nack.packet_ids().empty()) {
+    packet_information->packet_type_flags |= kRtcpNack;
+    ++packet_type_counter_.nack_packets;
+    packet_type_counter_.nack_requests = nack_stats_.requests();
+    packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
+  }
+}
+
+void RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) {
+  rtcp::Bye bye;
+  if (!bye.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  // Clear our lists.
+  for (auto& reports_per_receiver : received_report_blocks_)
+    reports_per_receiver.second.erase(bye.sender_ssrc());
+
+  TmmbrInformation* tmmbr_info = GetTmmbrInformation(bye.sender_ssrc());
+  if (tmmbr_info)
+    tmmbr_info->ready_for_delete = true;
+
+  last_fir_.erase(bye.sender_ssrc());
+  received_cnames_.erase(bye.sender_ssrc());
+  auto it = received_rrtrs_ssrc_it_.find(bye.sender_ssrc());
+  if (it != received_rrtrs_ssrc_it_.end()) {
+    received_rrtrs_.erase(it->second);
+    received_rrtrs_ssrc_it_.erase(it);
+  }
+  xr_rr_rtt_ms_ = 0;
+}
+
+void RTCPReceiver::HandleXr(const CommonHeader& rtcp_block,
+                            PacketInformation* packet_information) {
+  rtcp::ExtendedReports xr;
+  if (!xr.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  if (xr.rrtr())
+    HandleXrReceiveReferenceTime(xr.sender_ssrc(), *xr.rrtr());
+
+  for (const rtcp::ReceiveTimeInfo& time_info : xr.dlrr().sub_blocks())
+    HandleXrDlrrReportBlock(time_info);
+
+  if (xr.target_bitrate()) {
+    HandleXrTargetBitrate(xr.sender_ssrc(), *xr.target_bitrate(),
+                          packet_information);
+  }
+}
+
+void RTCPReceiver::HandleXrReceiveReferenceTime(uint32_t sender_ssrc,
+                                                const rtcp::Rrtr& rrtr) {
+  uint32_t received_remote_mid_ntp_time = CompactNtp(rrtr.ntp());
+  uint32_t local_receive_mid_ntp_time = CompactNtp(clock_->CurrentNtpTime());
+
+  auto it = received_rrtrs_ssrc_it_.find(sender_ssrc);
+  if (it != received_rrtrs_ssrc_it_.end()) {
+    it->second->received_remote_mid_ntp_time = received_remote_mid_ntp_time;
+    it->second->local_receive_mid_ntp_time = local_receive_mid_ntp_time;
+  } else {
+    if (received_rrtrs_.size() < kMaxNumberOfStoredRrtrs) {
+      received_rrtrs_.emplace_back(sender_ssrc, received_remote_mid_ntp_time,
+                                   local_receive_mid_ntp_time);
+      received_rrtrs_ssrc_it_[sender_ssrc] = std::prev(received_rrtrs_.end());
+    } else {
+      RTC_LOG(LS_WARNING) << "Discarding received RRTR for ssrc " << sender_ssrc
+                          << ", reached maximum number of stored RRTRs.";
+    }
+  }
+}
+
+void RTCPReceiver::HandleXrDlrrReportBlock(const rtcp::ReceiveTimeInfo& rti) {
+  if (registered_ssrcs_.count(rti.ssrc) == 0)  // Not to us.
+    return;
+
+  // Caller should explicitly enable rtt calculation using extended reports.
+  if (!xr_rrtr_status_)
+    return;
+
+  // The send_time and delay_rr fields are in units of 1/2^16 sec.
+  uint32_t send_time_ntp = rti.last_rr;
+  // RFC3611, section 4.5, LRR field discription states:
+  // If no such block has been received, the field is set to zero.
+  if (send_time_ntp == 0)
+    return;
+
+  uint32_t delay_ntp = rti.delay_since_last_rr;
+  uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
+
+  uint32_t rtt_ntp = now_ntp - delay_ntp - send_time_ntp;
+  xr_rr_rtt_ms_ = CompactNtpRttToMs(rtt_ntp);
+}
+
+void RTCPReceiver::HandleXrTargetBitrate(
+    uint32_t ssrc,
+    const rtcp::TargetBitrate& target_bitrate,
+    PacketInformation* packet_information) {
+  if (ssrc != remote_ssrc_) {
+    return;  // Not for us.
+  }
+
+  VideoBitrateAllocation bitrate_allocation;
+  for (const auto& item : target_bitrate.GetTargetBitrates()) {
+    if (item.spatial_layer >= kMaxSpatialLayers ||
+        item.temporal_layer >= kMaxTemporalStreams) {
+      RTC_LOG(LS_WARNING)
+          << "Invalid layer in XR target bitrate pack: spatial index "
+          << item.spatial_layer << ", temporal index " << item.temporal_layer
+          << ", dropping.";
+    } else {
+      bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
+                                    item.target_bitrate_kbps * 1000);
+    }
+  }
+  packet_information->target_bitrate_allocation.emplace(bitrate_allocation);
+}
+
+void RTCPReceiver::HandlePli(const CommonHeader& rtcp_block,
+                             PacketInformation* packet_information) {
+  rtcp::Pli pli;
+  if (!pli.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  if (main_ssrc_ == pli.media_ssrc()) {
+    ++packet_type_counter_.pli_packets;
+    // Received a signal that we need to send a new key frame.
+    packet_information->packet_type_flags |= kRtcpPli;
+  }
+}
+
+void RTCPReceiver::HandleTmmbr(const CommonHeader& rtcp_block,
+                               PacketInformation* packet_information) {
+  rtcp::Tmmbr tmmbr;
+  if (!tmmbr.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  uint32_t sender_ssrc = tmmbr.sender_ssrc();
+  if (tmmbr.media_ssrc()) {
+    // media_ssrc() SHOULD be 0 if same as SenderSSRC.
+    // In relay mode this is a valid number.
+    sender_ssrc = tmmbr.media_ssrc();
+  }
+
+  for (const rtcp::TmmbItem& request : tmmbr.requests()) {
+    if (main_ssrc_ != request.ssrc() || request.bitrate_bps() == 0)
+      continue;
+
+    TmmbrInformation* tmmbr_info = FindOrCreateTmmbrInfo(tmmbr.sender_ssrc());
+    auto* entry = &tmmbr_info->tmmbr[sender_ssrc];
+    entry->tmmbr_item = rtcp::TmmbItem(sender_ssrc, request.bitrate_bps(),
+                                       request.packet_overhead());
+    entry->last_updated_ms = clock_->TimeInMilliseconds();
+
+    packet_information->packet_type_flags |= kRtcpTmmbr;
+    break;
+  }
+}
+
+void RTCPReceiver::HandleTmmbn(const CommonHeader& rtcp_block,
+                               PacketInformation* packet_information) {
+  rtcp::Tmmbn tmmbn;
+  if (!tmmbn.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  TmmbrInformation* tmmbr_info = FindOrCreateTmmbrInfo(tmmbn.sender_ssrc());
+
+  packet_information->packet_type_flags |= kRtcpTmmbn;
+
+  tmmbr_info->tmmbn = tmmbn.items();
+}
+
+void RTCPReceiver::HandleSrReq(const CommonHeader& rtcp_block,
+                               PacketInformation* packet_information) {
+  rtcp::RapidResyncRequest sr_req;
+  if (!sr_req.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  packet_information->packet_type_flags |= kRtcpSrReq;
+}
+
+void RTCPReceiver::HandlePsfbApp(const CommonHeader& rtcp_block,
+                                 PacketInformation* packet_information) {
+  rtcp::Remb remb;
+  if (remb.Parse(rtcp_block)) {
+    packet_information->packet_type_flags |= kRtcpRemb;
+    packet_information->receiver_estimated_max_bitrate_bps = remb.bitrate_bps();
+    return;
+  }
+
+  ++num_skipped_packets_;
+}
+
+void RTCPReceiver::HandleFir(const CommonHeader& rtcp_block,
+                             PacketInformation* packet_information) {
+  rtcp::Fir fir;
+  if (!fir.Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  for (const rtcp::Fir::Request& fir_request : fir.requests()) {
+    // Is it our sender that is requested to generate a new keyframe.
+    if (main_ssrc_ != fir_request.ssrc)
+      continue;
+
+    ++packet_type_counter_.fir_packets;
+
+    int64_t now_ms = clock_->TimeInMilliseconds();
+    auto inserted = last_fir_.insert(std::make_pair(
+        fir.sender_ssrc(), LastFirStatus(now_ms, fir_request.seq_nr)));
+    if (!inserted.second) {  // There was already an entry.
+      LastFirStatus* last_fir = &inserted.first->second;
+
+      // Check if we have reported this FIRSequenceNumber before.
+      if (fir_request.seq_nr == last_fir->sequence_number)
+        continue;
+
+      // Sanity: don't go crazy with the callbacks.
+      if (now_ms - last_fir->request_ms < kRtcpMinFrameLengthMs)
+        continue;
+
+      last_fir->request_ms = now_ms;
+      last_fir->sequence_number = fir_request.seq_nr;
+    }
+    // Received signal that we need to send a new key frame.
+    packet_information->packet_type_flags |= kRtcpFir;
+  }
+}
+
+void RTCPReceiver::HandleTransportFeedback(
+    const CommonHeader& rtcp_block,
+    PacketInformation* packet_information) {
+  std::unique_ptr<rtcp::TransportFeedback> transport_feedback(
+      new rtcp::TransportFeedback());
+  if (!transport_feedback->Parse(rtcp_block)) {
+    ++num_skipped_packets_;
+    return;
+  }
+
+  packet_information->packet_type_flags |= kRtcpTransportFeedback;
+  packet_information->transport_feedback = std::move(transport_feedback);
+}
+
+void RTCPReceiver::NotifyTmmbrUpdated() {
+  // Find bounding set.
+  std::vector<rtcp::TmmbItem> bounding =
+      TMMBRHelp::FindBoundingSet(TmmbrReceived());
+
+  if (!bounding.empty() && rtcp_bandwidth_observer_) {
+    // We have a new bandwidth estimate on this channel.
+    uint64_t bitrate_bps = TMMBRHelp::CalcMinBitrateBps(bounding);
+    if (bitrate_bps <= std::numeric_limits<uint32_t>::max())
+      rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate(bitrate_bps);
+  }
+
+  // Send tmmbn to inform remote clients about the new bandwidth.
+  rtp_rtcp_->SetTmmbn(std::move(bounding));
+}
+
+void RTCPReceiver::RegisterRtcpStatisticsCallback(
+    RtcpStatisticsCallback* callback) {
+  rtc::CritScope cs(&feedbacks_lock_);
+  stats_callback_ = callback;
+}
+
+RtcpStatisticsCallback* RTCPReceiver::GetRtcpStatisticsCallback() {
+  rtc::CritScope cs(&feedbacks_lock_);
+  return stats_callback_;
+}
+
+// Holding no Critical section.
+void RTCPReceiver::TriggerCallbacksFromRtcpPacket(
+    const PacketInformation& packet_information) {
+  // Process TMMBR and REMB first to avoid multiple callbacks
+  // to OnNetworkChanged.
+  if (packet_information.packet_type_flags & kRtcpTmmbr) {
+    // Might trigger a OnReceivedBandwidthEstimateUpdate.
+    NotifyTmmbrUpdated();
+  }
+  uint32_t local_ssrc;
+  std::set<uint32_t> registered_ssrcs;
+  {
+    // We don't want to hold this critsect when triggering the callbacks below.
+    rtc::CritScope lock(&rtcp_receiver_lock_);
+    local_ssrc = main_ssrc_;
+    registered_ssrcs = registered_ssrcs_;
+  }
+  if (!receiver_only_ && (packet_information.packet_type_flags & kRtcpSrReq)) {
+    rtp_rtcp_->OnRequestSendReport();
+  }
+  if (!receiver_only_ && (packet_information.packet_type_flags & kRtcpNack)) {
+    if (!packet_information.nack_sequence_numbers.empty()) {
+      RTC_LOG(LS_VERBOSE) << "Incoming NACK length: "
+                          << packet_information.nack_sequence_numbers.size();
+      rtp_rtcp_->OnReceivedNack(packet_information.nack_sequence_numbers);
+    }
+  }
+
+  // We need feedback that we have received a report block(s) so that we
+  // can generate a new packet in a conference relay scenario, one received
+  // report can generate several RTCP packets, based on number relayed/mixed
+  // a send report block should go out to all receivers.
+  if (rtcp_intra_frame_observer_) {
+    RTC_DCHECK(!receiver_only_);
+    if ((packet_information.packet_type_flags & kRtcpPli) ||
+        (packet_information.packet_type_flags & kRtcpFir)) {
+      if (packet_information.packet_type_flags & kRtcpPli) {
+        RTC_LOG(LS_VERBOSE)
+            << "Incoming PLI from SSRC " << packet_information.remote_ssrc;
+      } else {
+        RTC_LOG(LS_VERBOSE)
+            << "Incoming FIR from SSRC " << packet_information.remote_ssrc;
+      }
+      rtcp_intra_frame_observer_->OnReceivedIntraFrameRequest(local_ssrc);
+    }
+  }
+  if (rtcp_bandwidth_observer_) {
+    RTC_DCHECK(!receiver_only_);
+    if (packet_information.packet_type_flags & kRtcpRemb) {
+      RTC_LOG(LS_VERBOSE)
+          << "Incoming REMB: "
+          << packet_information.receiver_estimated_max_bitrate_bps;
+      rtcp_bandwidth_observer_->OnReceivedEstimatedBitrate(
+          packet_information.receiver_estimated_max_bitrate_bps);
+    }
+    if ((packet_information.packet_type_flags & kRtcpSr) ||
+        (packet_information.packet_type_flags & kRtcpRr)) {
+      int64_t now_ms = clock_->TimeInMilliseconds();
+      rtcp_bandwidth_observer_->OnReceivedRtcpReceiverReport(
+          packet_information.report_blocks, packet_information.rtt_ms, now_ms);
+    }
+  }
+  if ((packet_information.packet_type_flags & kRtcpSr) ||
+      (packet_information.packet_type_flags & kRtcpRr)) {
+    rtp_rtcp_->OnReceivedRtcpReportBlocks(packet_information.report_blocks);
+  }
+
+  if (transport_feedback_observer_ &&
+      (packet_information.packet_type_flags & kRtcpTransportFeedback)) {
+    uint32_t media_source_ssrc =
+        packet_information.transport_feedback->media_ssrc();
+    if (media_source_ssrc == local_ssrc ||
+        registered_ssrcs.find(media_source_ssrc) != registered_ssrcs.end()) {
+      transport_feedback_observer_->OnTransportFeedback(
+          *packet_information.transport_feedback);
+    }
+  }
+
+  if (bitrate_allocation_observer_ &&
+      packet_information.target_bitrate_allocation) {
+    bitrate_allocation_observer_->OnBitrateAllocationUpdated(
+        *packet_information.target_bitrate_allocation);
+  }
+
+  if (!receiver_only_) {
+    rtc::CritScope cs(&feedbacks_lock_);
+    if (stats_callback_) {
+      for (const auto& report_block : packet_information.report_blocks) {
+        RtcpStatistics stats;
+        stats.packets_lost = report_block.packets_lost;
+        stats.extended_highest_sequence_number =
+            report_block.extended_highest_sequence_number;
+        stats.fraction_lost = report_block.fraction_lost;
+        stats.jitter = report_block.jitter;
+
+        stats_callback_->StatisticsUpdated(stats, report_block.source_ssrc);
+      }
+    }
+  }
+}
+
+int32_t RTCPReceiver::CNAME(uint32_t remoteSSRC,
+                            char cName[RTCP_CNAME_SIZE]) const {
+  RTC_DCHECK(cName);
+
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  auto received_cname_it = received_cnames_.find(remoteSSRC);
+  if (received_cname_it == received_cnames_.end())
+    return -1;
+
+  size_t length = received_cname_it->second.copy(cName, RTCP_CNAME_SIZE - 1);
+  cName[length] = 0;
+  return 0;
+}
+
+std::vector<rtcp::TmmbItem> RTCPReceiver::TmmbrReceived() {
+  rtc::CritScope lock(&rtcp_receiver_lock_);
+  std::vector<rtcp::TmmbItem> candidates;
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t timeout_ms = now_ms - kTmmbrTimeoutIntervalMs;
+
+  for (auto& kv : tmmbr_infos_) {
+    for (auto it = kv.second.tmmbr.begin(); it != kv.second.tmmbr.end();) {
+      if (it->second.last_updated_ms < timeout_ms) {
+        // Erase timeout entries.
+        it = kv.second.tmmbr.erase(it);
+      } else {
+        candidates.push_back(it->second.tmmbr_item);
+        ++it;
+      }
+    }
+  }
+  return candidates;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h
new file mode 100644
index 0000000..c868837
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -0,0 +1,271 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
+
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_nack_stats.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/thread_annotations.h"
+#include "system_wrappers/include/ntp_time.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+class VideoBitrateAllocationObserver;
+namespace rtcp {
+class CommonHeader;
+class ReportBlock;
+class Rrtr;
+class TargetBitrate;
+class TmmbItem;
+}  // namespace rtcp
+
+class RTCPReceiver {
+ public:
+  class ModuleRtpRtcp {
+   public:
+    virtual void SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) = 0;
+    virtual void OnRequestSendReport() = 0;
+    virtual void OnReceivedNack(
+        const std::vector<uint16_t>& nack_sequence_numbers) = 0;
+    virtual void OnReceivedRtcpReportBlocks(
+        const ReportBlockList& report_blocks) = 0;
+
+   protected:
+    virtual ~ModuleRtpRtcp() = default;
+  };
+
+  RTCPReceiver(Clock* clock,
+               bool receiver_only,
+               RtcpPacketTypeCounterObserver* packet_type_counter_observer,
+               RtcpBandwidthObserver* rtcp_bandwidth_observer,
+               RtcpIntraFrameObserver* rtcp_intra_frame_observer,
+               TransportFeedbackObserver* transport_feedback_observer,
+               VideoBitrateAllocationObserver* bitrate_allocation_observer,
+               ModuleRtpRtcp* owner);
+  virtual ~RTCPReceiver();
+
+  void IncomingPacket(const uint8_t* packet, size_t packet_size);
+
+  int64_t LastReceivedReportBlockMs() const;
+
+  void SetSsrcs(uint32_t main_ssrc, const std::set<uint32_t>& registered_ssrcs);
+  void SetRemoteSSRC(uint32_t ssrc);
+  uint32_t RemoteSSRC() const;
+
+  // Get received cname.
+  int32_t CNAME(uint32_t remote_ssrc, char cname[RTCP_CNAME_SIZE]) const;
+
+  // Get received NTP.
+  bool NTP(uint32_t* received_ntp_secs,
+           uint32_t* received_ntp_frac,
+           uint32_t* rtcp_arrival_time_secs,
+           uint32_t* rtcp_arrival_time_frac,
+           uint32_t* rtcp_timestamp) const;
+
+  std::vector<rtcp::ReceiveTimeInfo> ConsumeReceivedXrReferenceTimeInfo();
+
+  // Get rtt.
+  int32_t RTT(uint32_t remote_ssrc,
+              int64_t* last_rtt_ms,
+              int64_t* avg_rtt_ms,
+              int64_t* min_rtt_ms,
+              int64_t* max_rtt_ms) const;
+
+  void SetRtcpXrRrtrStatus(bool enable);
+  bool GetAndResetXrRrRtt(int64_t* rtt_ms);
+
+  // Get statistics.
+  int32_t StatisticsReceived(std::vector<RTCPReportBlock>* receiveBlocks) const;
+
+  // Returns true if we haven't received an RTCP RR for several RTCP
+  // intervals, but only triggers true once.
+  bool RtcpRrTimeout(int64_t rtcp_interval_ms);
+
+  // Returns true if we haven't received an RTCP RR telling the receive side
+  // has not received RTP packets for too long, i.e. extended highest sequence
+  // number hasn't increased for several RTCP intervals. The function only
+  // returns true once until a new RR is received.
+  bool RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms);
+
+  std::vector<rtcp::TmmbItem> TmmbrReceived();
+  // Return true if new bandwidth should be set.
+  bool UpdateTmmbrTimers();
+  std::vector<rtcp::TmmbItem> BoundingSet(bool* tmmbr_owner);
+  // Set new bandwidth and notify remote clients about it.
+  void NotifyTmmbrUpdated();
+
+  void RegisterRtcpStatisticsCallback(RtcpStatisticsCallback* callback);
+  RtcpStatisticsCallback* GetRtcpStatisticsCallback();
+
+ private:
+  struct PacketInformation;
+  struct TmmbrInformation;
+  struct RrtrInformation;
+  struct ReportBlockWithRtt;
+  struct LastFirStatus;
+  // RTCP report blocks mapped by remote SSRC.
+  using ReportBlockInfoMap = std::map<uint32_t, ReportBlockWithRtt>;
+  // RTCP report blocks map mapped by source SSRC.
+  using ReportBlockMap = std::map<uint32_t, ReportBlockInfoMap>;
+
+  bool ParseCompoundPacket(const uint8_t* packet_begin,
+                           const uint8_t* packet_end,
+                           PacketInformation* packet_information);
+
+  void TriggerCallbacksFromRtcpPacket(
+      const PacketInformation& packet_information);
+
+  TmmbrInformation* FindOrCreateTmmbrInfo(uint32_t remote_ssrc)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+  // Update TmmbrInformation (if present) is alive.
+  void UpdateTmmbrRemoteIsAlive(uint32_t remote_ssrc)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+  TmmbrInformation* GetTmmbrInformation(uint32_t remote_ssrc)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleSenderReport(const rtcp::CommonHeader& rtcp_block,
+                          PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleReceiverReport(const rtcp::CommonHeader& rtcp_block,
+                            PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleReportBlock(const rtcp::ReportBlock& report_block,
+                         PacketInformation* packet_information,
+                         uint32_t remote_ssrc)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleSdes(const rtcp::CommonHeader& rtcp_block,
+                  PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleXr(const rtcp::CommonHeader& rtcp_block,
+                PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleXrReceiveReferenceTime(uint32_t sender_ssrc,
+                                    const rtcp::Rrtr& rrtr)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleXrDlrrReportBlock(const rtcp::ReceiveTimeInfo& rti)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleXrTargetBitrate(uint32_t ssrc,
+                             const rtcp::TargetBitrate& target_bitrate,
+                             PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleNack(const rtcp::CommonHeader& rtcp_block,
+                  PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleBye(const rtcp::CommonHeader& rtcp_block)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandlePli(const rtcp::CommonHeader& rtcp_block,
+                 PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandlePsfbApp(const rtcp::CommonHeader& rtcp_block,
+                     PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleTmmbr(const rtcp::CommonHeader& rtcp_block,
+                   PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleTmmbn(const rtcp::CommonHeader& rtcp_block,
+                   PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleSrReq(const rtcp::CommonHeader& rtcp_block,
+                   PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleFir(const rtcp::CommonHeader& rtcp_block,
+                 PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  void HandleTransportFeedback(const rtcp::CommonHeader& rtcp_block,
+                               PacketInformation* packet_information)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
+
+  Clock* const clock_;
+  const bool receiver_only_;
+  ModuleRtpRtcp* const rtp_rtcp_;
+
+  rtc::CriticalSection feedbacks_lock_;
+  RtcpBandwidthObserver* const rtcp_bandwidth_observer_;
+  RtcpIntraFrameObserver* const rtcp_intra_frame_observer_;
+  TransportFeedbackObserver* const transport_feedback_observer_;
+  VideoBitrateAllocationObserver* const bitrate_allocation_observer_;
+
+  rtc::CriticalSection rtcp_receiver_lock_;
+  uint32_t main_ssrc_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  uint32_t remote_ssrc_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  std::set<uint32_t> registered_ssrcs_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+
+  // Received sender report.
+  NtpTime remote_sender_ntp_time_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  uint32_t remote_sender_rtp_time_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  // When did we receive the last send report.
+  NtpTime last_received_sr_ntp_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+
+  // Received RRTR information in ascending receive time order.
+  std::list<RrtrInformation> received_rrtrs_
+      RTC_GUARDED_BY(rtcp_receiver_lock_);
+  // Received RRTR information mapped by remote ssrc.
+  std::map<uint32_t, std::list<RrtrInformation>::iterator>
+      received_rrtrs_ssrc_it_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+
+  // Estimated rtt, zero when there is no valid estimate.
+  bool xr_rrtr_status_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  int64_t xr_rr_rtt_ms_;
+
+  int64_t oldest_tmmbr_info_ms_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  // Mapped by remote ssrc.
+  std::map<uint32_t, TmmbrInformation> tmmbr_infos_
+      RTC_GUARDED_BY(rtcp_receiver_lock_);
+
+  ReportBlockMap received_report_blocks_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+  std::map<uint32_t, LastFirStatus> last_fir_
+      RTC_GUARDED_BY(rtcp_receiver_lock_);
+  std::map<uint32_t, std::string> received_cnames_
+      RTC_GUARDED_BY(rtcp_receiver_lock_);
+
+  // The last time we received an RTCP Report block for this module.
+  int64_t last_received_rb_ms_ RTC_GUARDED_BY(rtcp_receiver_lock_);
+
+  // The time we last received an RTCP RR telling we have successfully
+  // delivered RTP packet to the remote side.
+  int64_t last_increased_sequence_number_ms_;
+
+  RtcpStatisticsCallback* stats_callback_ RTC_GUARDED_BY(feedbacks_lock_);
+
+  RtcpPacketTypeCounterObserver* const packet_type_counter_observer_;
+  RtcpPacketTypeCounter packet_type_counter_;
+
+  RtcpNackStats nack_stats_;
+
+  size_t num_skipped_packets_;
+  int64_t last_skipped_packets_warning_ms_;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
new file mode 100644
index 0000000..41d4725
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -0,0 +1,1369 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <memory>
+
+#include "api/array_view.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "common_video/include/video_bitrate_allocator.h"
+#include "modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtcp_receiver.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/random.h"
+#include "system_wrappers/include/ntp_time.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::ElementsAreArray;
+using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::NiceMock;
+using ::testing::Property;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+using ::testing::UnorderedElementsAre;
+using rtcp::ReceiveTimeInfo;
+
+class MockRtcpPacketTypeCounterObserver : public RtcpPacketTypeCounterObserver {
+ public:
+  MOCK_METHOD2(RtcpPacketTypesCounterUpdated,
+               void(uint32_t, const RtcpPacketTypeCounter&));
+};
+
+class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver {
+ public:
+  MOCK_METHOD1(OnReceivedIntraFrameRequest, void(uint32_t));
+};
+
+class MockRtcpCallbackImpl : public RtcpStatisticsCallback {
+ public:
+  MOCK_METHOD2(StatisticsUpdated, void(const RtcpStatistics&, uint32_t));
+  MOCK_METHOD2(CNameChanged, void(const char*, uint32_t));
+};
+
+class MockTransportFeedbackObserver : public TransportFeedbackObserver {
+ public:
+  MOCK_METHOD3(AddPacket, void(uint32_t, uint16_t, size_t));
+  MOCK_METHOD4(AddPacket,
+               void(uint32_t, uint16_t, size_t, const PacedPacketInfo&));
+  MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&));
+  MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>());
+};
+
+class MockModuleRtpRtcp : public RTCPReceiver::ModuleRtpRtcp {
+ public:
+  MOCK_METHOD1(SetTmmbn, void(std::vector<rtcp::TmmbItem>));
+  MOCK_METHOD0(OnRequestSendReport, void());
+  MOCK_METHOD1(OnReceivedNack, void(const std::vector<uint16_t>&));
+  MOCK_METHOD1(OnReceivedRtcpReportBlocks, void(const ReportBlockList&));
+};
+
+class MockVideoBitrateAllocationObserver
+    : public VideoBitrateAllocationObserver {
+ public:
+  MOCK_METHOD1(OnBitrateAllocationUpdated,
+               void(const VideoBitrateAllocation& allocation));
+};
+
+// SSRC of remote peer, that sends rtcp packet to the rtcp receiver under test.
+constexpr uint32_t kSenderSsrc = 0x10203;
+// SSRCs of local peer, that rtcp packet addressed to.
+constexpr uint32_t kReceiverMainSsrc = 0x123456;
+// RtcpReceiver can accept several ssrc, e.g. regular and rtx streams.
+constexpr uint32_t kReceiverExtraSsrc = 0x1234567;
+// SSRCs to ignore (i.e. not configured in RtcpReceiver).
+constexpr uint32_t kNotToUsSsrc = 0x654321;
+constexpr uint32_t kUnknownSenderSsrc = 0x54321;
+
+}  // namespace
+
+class RtcpReceiverTest : public ::testing::Test {
+ protected:
+  RtcpReceiverTest()
+      : system_clock_(1335900000),
+        rtcp_receiver_(&system_clock_,
+                       false,
+                       &packet_type_counter_observer_,
+                       &bandwidth_observer_,
+                       &intra_frame_observer_,
+                       &transport_feedback_observer_,
+                       &bitrate_allocation_observer_,
+                       &rtp_rtcp_impl_) {}
+  void SetUp() {
+    std::set<uint32_t> ssrcs = {kReceiverMainSsrc, kReceiverExtraSsrc};
+    rtcp_receiver_.SetSsrcs(kReceiverMainSsrc, ssrcs);
+
+    rtcp_receiver_.SetRemoteSSRC(kSenderSsrc);
+  }
+
+  void InjectRtcpPacket(rtc::ArrayView<const uint8_t> raw) {
+    rtcp_receiver_.IncomingPacket(raw.data(), raw.size());
+  }
+
+  void InjectRtcpPacket(const rtcp::RtcpPacket& packet) {
+    rtc::Buffer raw = packet.Build();
+    rtcp_receiver_.IncomingPacket(raw.data(), raw.size());
+  }
+
+  SimulatedClock system_clock_;
+  // Callbacks to packet_type_counter_observer are frequent but most of the time
+  // are not interesting.
+  NiceMock<MockRtcpPacketTypeCounterObserver> packet_type_counter_observer_;
+  StrictMock<MockRtcpBandwidthObserver> bandwidth_observer_;
+  StrictMock<MockRtcpIntraFrameObserver> intra_frame_observer_;
+  StrictMock<MockTransportFeedbackObserver> transport_feedback_observer_;
+  StrictMock<MockVideoBitrateAllocationObserver> bitrate_allocation_observer_;
+  StrictMock<MockModuleRtpRtcp> rtp_rtcp_impl_;
+
+  RTCPReceiver rtcp_receiver_;
+};
+
+TEST_F(RtcpReceiverTest, BrokenPacketIsIgnored) {
+  const uint8_t bad_packet[] = {0, 0, 0, 0};
+  EXPECT_CALL(packet_type_counter_observer_,
+              RtcpPacketTypesCounterUpdated(_, _))
+      .Times(0);
+  InjectRtcpPacket(bad_packet);
+}
+
+TEST_F(RtcpReceiverTest, InvalidFeedbackPacketIsIgnored) {
+  // Too short feedback packet.
+  const uint8_t bad_packet[] = {0x81, rtcp::Rtpfb::kPacketType, 0, 0};
+
+  // TODO(danilchap): Add expectation RtcpPacketTypesCounterUpdated
+  // is not called once parser would be adjusted to avoid that callback on
+  // semi-valid packets.
+  InjectRtcpPacket(bad_packet);
+}
+
+TEST_F(RtcpReceiverTest, InjectSrPacket) {
+  EXPECT_FALSE(rtcp_receiver_.NTP(nullptr, nullptr, nullptr, nullptr, nullptr));
+
+  int64_t now = system_clock_.TimeInMilliseconds();
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(IsEmpty()));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(IsEmpty(), _, now));
+  InjectRtcpPacket(sr);
+
+  EXPECT_TRUE(rtcp_receiver_.NTP(nullptr, nullptr, nullptr, nullptr, nullptr));
+}
+
+TEST_F(RtcpReceiverTest, InjectSrPacketFromUnknownSender) {
+  int64_t now = system_clock_.TimeInMilliseconds();
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kUnknownSenderSsrc);
+
+  // The parser will handle report blocks in Sender Report from other than his
+  // expected peer.
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, now));
+  InjectRtcpPacket(sr);
+
+  // But will not flag that he's gotten sender information.
+  EXPECT_FALSE(rtcp_receiver_.NTP(nullptr, nullptr, nullptr, nullptr, nullptr));
+}
+
+TEST_F(RtcpReceiverTest, InjectSrPacketCalculatesRTT) {
+  Random r(0x0123456789abcdef);
+  const int64_t kRttMs = r.Rand(1, 9 * 3600 * 1000);
+  const uint32_t kDelayNtp = r.Rand(0, 0x7fffffff);
+  const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
+
+  int64_t rtt_ms = 0;
+  EXPECT_EQ(
+      -1, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
+
+  uint32_t sent_ntp = CompactNtp(system_clock_.CurrentNtpTime());
+  system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
+
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::ReportBlock block;
+  block.SetMediaSsrc(kReceiverMainSsrc);
+  block.SetLastSr(sent_ntp);
+  block.SetDelayLastSr(kDelayNtp);
+  sr.AddReportBlock(block);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(sr);
+
+  EXPECT_EQ(
+      0, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
+  EXPECT_NEAR(kRttMs, rtt_ms, 1);
+}
+
+TEST_F(RtcpReceiverTest, InjectSrPacketCalculatesNegativeRTTAsOne) {
+  Random r(0x0123456789abcdef);
+  const int64_t kRttMs = r.Rand(-3600 * 1000, -1);
+  const uint32_t kDelayNtp = r.Rand(0, 0x7fffffff);
+  const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
+
+  int64_t rtt_ms = 0;
+  EXPECT_EQ(
+      -1, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
+
+  uint32_t sent_ntp = CompactNtp(system_clock_.CurrentNtpTime());
+  system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
+
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::ReportBlock block;
+  block.SetMediaSsrc(kReceiverMainSsrc);
+  block.SetLastSr(sent_ntp);
+  block.SetDelayLastSr(kDelayNtp);
+  sr.AddReportBlock(block);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(1), _, _));
+  InjectRtcpPacket(sr);
+
+  EXPECT_EQ(
+      0, rtcp_receiver_.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
+  EXPECT_EQ(1, rtt_ms);
+}
+
+TEST_F(
+    RtcpReceiverTest,
+    TwoReportBlocksWithLastOneWithoutLastSrCalculatesRttForBandwidthObserver) {
+  const int64_t kRttMs = 120;
+  const uint32_t kDelayNtp = 123000;
+  const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
+
+  uint32_t sent_ntp = CompactNtp(system_clock_.CurrentNtpTime());
+  system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
+
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::ReportBlock block;
+  block.SetMediaSsrc(kReceiverMainSsrc);
+  block.SetLastSr(sent_ntp);
+  block.SetDelayLastSr(kDelayNtp);
+  sr.AddReportBlock(block);
+  block.SetMediaSsrc(kReceiverExtraSsrc);
+  block.SetLastSr(0);
+  sr.AddReportBlock(block);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(2)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(2), kRttMs, _));
+  InjectRtcpPacket(sr);
+}
+
+TEST_F(RtcpReceiverTest, InjectRrPacket) {
+  int64_t now = system_clock_.TimeInMilliseconds();
+  rtcp::ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(IsEmpty()));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(IsEmpty(), _, now));
+  InjectRtcpPacket(rr);
+
+  std::vector<RTCPReportBlock> report_blocks;
+  rtcp_receiver_.StatisticsReceived(&report_blocks);
+  EXPECT_TRUE(report_blocks.empty());
+}
+
+TEST_F(RtcpReceiverTest, InjectRrPacketWithReportBlockNotToUsIgnored) {
+  int64_t now = system_clock_.TimeInMilliseconds();
+  rtcp::ReportBlock rb;
+  rb.SetMediaSsrc(kNotToUsSsrc);
+  rtcp::ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  rr.AddReportBlock(rb);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(IsEmpty()));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(IsEmpty(), _, now));
+  InjectRtcpPacket(rr);
+
+  EXPECT_EQ(0, rtcp_receiver_.LastReceivedReportBlockMs());
+  std::vector<RTCPReportBlock> received_blocks;
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_TRUE(received_blocks.empty());
+}
+
+TEST_F(RtcpReceiverTest, InjectRrPacketWithOneReportBlock) {
+  int64_t now = system_clock_.TimeInMilliseconds();
+
+  rtcp::ReportBlock rb;
+  rb.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp::ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  rr.AddReportBlock(rb);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(1), _, now));
+  InjectRtcpPacket(rr);
+
+  EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs());
+  std::vector<RTCPReportBlock> received_blocks;
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_EQ(1u, received_blocks.size());
+}
+
+TEST_F(RtcpReceiverTest, InjectSrPacketWithOneReportBlock) {
+  int64_t now = system_clock_.TimeInMilliseconds();
+
+  rtcp::ReportBlock rb;
+  rb.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  sr.AddReportBlock(rb);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(1), _, now));
+  InjectRtcpPacket(sr);
+
+  EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs());
+  std::vector<RTCPReportBlock> received_blocks;
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_EQ(1u, received_blocks.size());
+}
+
+TEST_F(RtcpReceiverTest, InjectRrPacketWithTwoReportBlocks) {
+  const uint16_t kSequenceNumbers[] = {10, 12423};
+  const uint32_t kCumLost[] = {13, 555};
+  const uint8_t kFracLost[] = {20, 11};
+  int64_t now = system_clock_.TimeInMilliseconds();
+
+  rtcp::ReportBlock rb1;
+  rb1.SetMediaSsrc(kReceiverMainSsrc);
+  rb1.SetExtHighestSeqNum(kSequenceNumbers[0]);
+  rb1.SetFractionLost(10);
+
+  rtcp::ReportBlock rb2;
+  rb2.SetMediaSsrc(kReceiverExtraSsrc);
+  rb2.SetExtHighestSeqNum(kSequenceNumbers[1]);
+  rb2.SetFractionLost(0);
+
+  rtcp::ReceiverReport rr1;
+  rr1.SetSenderSsrc(kSenderSsrc);
+  rr1.AddReportBlock(rb1);
+  rr1.AddReportBlock(rb2);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(2)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(2), _, now));
+  InjectRtcpPacket(rr1);
+
+  EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs());
+  std::vector<RTCPReportBlock> received_blocks;
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_THAT(received_blocks,
+              UnorderedElementsAre(Field(&RTCPReportBlock::fraction_lost, 0),
+                                   Field(&RTCPReportBlock::fraction_lost, 10)));
+
+  // Insert next receiver report with same ssrc but new values.
+  rtcp::ReportBlock rb3;
+  rb3.SetMediaSsrc(kReceiverMainSsrc);
+  rb3.SetExtHighestSeqNum(kSequenceNumbers[0]);
+  rb3.SetFractionLost(kFracLost[0]);
+  rb3.SetCumulativeLost(kCumLost[0]);
+
+  rtcp::ReportBlock rb4;
+  rb4.SetMediaSsrc(kReceiverExtraSsrc);
+  rb4.SetExtHighestSeqNum(kSequenceNumbers[1]);
+  rb4.SetFractionLost(kFracLost[1]);
+  rb4.SetCumulativeLost(kCumLost[1]);
+
+  rtcp::ReceiverReport rr2;
+  rr2.SetSenderSsrc(kSenderSsrc);
+  rr2.AddReportBlock(rb3);
+  rr2.AddReportBlock(rb4);
+
+  // Advance time to make 1st sent time and 2nd sent time different.
+  system_clock_.AdvanceTimeMilliseconds(500);
+  now = system_clock_.TimeInMilliseconds();
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(2)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(2), _, now));
+  InjectRtcpPacket(rr2);
+
+  received_blocks.clear();
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_EQ(2u, received_blocks.size());
+  EXPECT_THAT(
+      received_blocks,
+      UnorderedElementsAre(
+          AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc),
+                Field(&RTCPReportBlock::fraction_lost, kFracLost[0]),
+                Field(&RTCPReportBlock::packets_lost, kCumLost[0]),
+                Field(&RTCPReportBlock::extended_highest_sequence_number,
+                      kSequenceNumbers[0])),
+          AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverExtraSsrc),
+                Field(&RTCPReportBlock::fraction_lost, kFracLost[1]),
+                Field(&RTCPReportBlock::packets_lost, kCumLost[1]),
+                Field(&RTCPReportBlock::extended_highest_sequence_number,
+                      kSequenceNumbers[1]))));
+}
+
+TEST_F(RtcpReceiverTest, InjectRrPacketsFromTwoRemoteSsrcs) {
+  const uint32_t kSenderSsrc2 = 0x20304;
+  const uint16_t kSequenceNumbers[] = {10, 12423};
+  const uint32_t kCumLost[] = {13, 555};
+  const uint8_t kFracLost[] = {20, 11};
+
+  rtcp::ReportBlock rb1;
+  rb1.SetMediaSsrc(kReceiverMainSsrc);
+  rb1.SetExtHighestSeqNum(kSequenceNumbers[0]);
+  rb1.SetFractionLost(kFracLost[0]);
+  rb1.SetCumulativeLost(kCumLost[0]);
+  rtcp::ReceiverReport rr1;
+  rr1.SetSenderSsrc(kSenderSsrc);
+  rr1.AddReportBlock(rb1);
+
+  int64_t now = system_clock_.TimeInMilliseconds();
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(1), _, now));
+  InjectRtcpPacket(rr1);
+
+  EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs());
+
+  std::vector<RTCPReportBlock> received_blocks;
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_EQ(1u, received_blocks.size());
+  EXPECT_EQ(kSenderSsrc, received_blocks[0].sender_ssrc);
+  EXPECT_EQ(kReceiverMainSsrc, received_blocks[0].source_ssrc);
+  EXPECT_EQ(kFracLost[0], received_blocks[0].fraction_lost);
+  EXPECT_EQ(kCumLost[0], received_blocks[0].packets_lost);
+  EXPECT_EQ(kSequenceNumbers[0],
+            received_blocks[0].extended_highest_sequence_number);
+
+  rtcp::ReportBlock rb2;
+  rb2.SetMediaSsrc(kReceiverMainSsrc);
+  rb2.SetExtHighestSeqNum(kSequenceNumbers[1]);
+  rb2.SetFractionLost(kFracLost[1]);
+  rb2.SetCumulativeLost(kCumLost[1]);
+  rtcp::ReceiverReport rr2;
+  rr2.SetSenderSsrc(kSenderSsrc2);
+  rr2.AddReportBlock(rb2);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(SizeIs(1)));
+  EXPECT_CALL(bandwidth_observer_,
+              OnReceivedRtcpReceiverReport(SizeIs(1), _, now));
+  InjectRtcpPacket(rr2);
+
+  received_blocks.clear();
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  ASSERT_EQ(2u, received_blocks.size());
+  EXPECT_THAT(
+      received_blocks,
+      UnorderedElementsAre(
+          AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc),
+                Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc),
+                Field(&RTCPReportBlock::fraction_lost, kFracLost[0]),
+                Field(&RTCPReportBlock::packets_lost, kCumLost[0]),
+                Field(&RTCPReportBlock::extended_highest_sequence_number,
+                      kSequenceNumbers[0])),
+          AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc),
+                Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc2),
+                Field(&RTCPReportBlock::fraction_lost, kFracLost[1]),
+                Field(&RTCPReportBlock::packets_lost, kCumLost[1]),
+                Field(&RTCPReportBlock::extended_highest_sequence_number,
+                      kSequenceNumbers[1]))));
+}
+
+TEST_F(RtcpReceiverTest, GetRtt) {
+  const uint32_t kSentCompactNtp = 0x1234;
+  const uint32_t kDelayCompactNtp = 0x222;
+  // No report block received.
+  EXPECT_EQ(
+      -1, rtcp_receiver_.RTT(kSenderSsrc, nullptr, nullptr, nullptr, nullptr));
+
+  rtcp::ReportBlock rb;
+  rb.SetMediaSsrc(kReceiverMainSsrc);
+  rb.SetLastSr(kSentCompactNtp);
+  rb.SetDelayLastSr(kDelayCompactNtp);
+
+  rtcp::ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  rr.AddReportBlock(rb);
+  int64_t now = system_clock_.TimeInMilliseconds();
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr);
+
+  EXPECT_EQ(now, rtcp_receiver_.LastReceivedReportBlockMs());
+  EXPECT_EQ(
+      0, rtcp_receiver_.RTT(kSenderSsrc, nullptr, nullptr, nullptr, nullptr));
+}
+
+// Ij packets are ignored.
+TEST_F(RtcpReceiverTest, InjectIjWithNoItem) {
+  rtcp::ExtendedJitterReport ij;
+  InjectRtcpPacket(ij);
+}
+
+// App packets are ignored.
+TEST_F(RtcpReceiverTest, InjectApp) {
+  rtcp::App app;
+  app.SetSubType(30);
+  app.SetName(0x17a177e);
+  const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
+  app.SetData(kData, sizeof(kData));
+
+  InjectRtcpPacket(app);
+}
+
+TEST_F(RtcpReceiverTest, InjectSdesWithOneChunk) {
+  const char kCname[] = "alice@host";
+  MockRtcpCallbackImpl callback;
+  rtcp_receiver_.RegisterRtcpStatisticsCallback(&callback);
+  rtcp::Sdes sdes;
+  sdes.AddCName(kSenderSsrc, kCname);
+
+  EXPECT_CALL(callback, CNameChanged(StrEq(kCname), kSenderSsrc));
+  InjectRtcpPacket(sdes);
+
+  char cName[RTCP_CNAME_SIZE];
+  EXPECT_EQ(0, rtcp_receiver_.CNAME(kSenderSsrc, cName));
+  EXPECT_EQ(0, strncmp(cName, kCname, RTCP_CNAME_SIZE));
+}
+
+TEST_F(RtcpReceiverTest, InjectByePacket_RemovesCname) {
+  const char kCname[] = "alice@host";
+  rtcp::Sdes sdes;
+  sdes.AddCName(kSenderSsrc, kCname);
+
+  InjectRtcpPacket(sdes);
+
+  char cName[RTCP_CNAME_SIZE];
+  EXPECT_EQ(0, rtcp_receiver_.CNAME(kSenderSsrc, cName));
+
+  // Verify that BYE removes the CNAME.
+  rtcp::Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+
+  InjectRtcpPacket(bye);
+
+  EXPECT_EQ(-1, rtcp_receiver_.CNAME(kSenderSsrc, cName));
+}
+
+TEST_F(RtcpReceiverTest, InjectByePacket_RemovesReportBlocks) {
+  rtcp::ReportBlock rb1;
+  rb1.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp::ReportBlock rb2;
+  rb2.SetMediaSsrc(kReceiverExtraSsrc);
+  rtcp::ReceiverReport rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  rr.AddReportBlock(rb1);
+  rr.AddReportBlock(rb2);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr);
+
+  std::vector<RTCPReportBlock> received_blocks;
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_EQ(2u, received_blocks.size());
+
+  // Verify that BYE removes the report blocks.
+  rtcp::Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+
+  InjectRtcpPacket(bye);
+
+  received_blocks.clear();
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_TRUE(received_blocks.empty());
+
+  // Inject packet again.
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr);
+
+  received_blocks.clear();
+  rtcp_receiver_.StatisticsReceived(&received_blocks);
+  EXPECT_EQ(2u, received_blocks.size());
+}
+
+TEST_F(RtcpReceiverTest, InjectByePacketRemovesReferenceTimeInfo) {
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  rtcp::Rrtr rrtr;
+  rrtr.SetNtp(NtpTime(0x10203, 0x40506));
+  xr.SetRrtr(rrtr);
+  InjectRtcpPacket(xr);
+
+  rtcp::Bye bye;
+  bye.SetSenderSsrc(kSenderSsrc);
+  InjectRtcpPacket(bye);
+
+  EXPECT_THAT(rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(), IsEmpty());
+}
+
+TEST_F(RtcpReceiverTest, InjectPliPacket) {
+  rtcp::Pli pli;
+  pli.SetMediaSsrc(kReceiverMainSsrc);
+
+  EXPECT_CALL(
+      packet_type_counter_observer_,
+      RtcpPacketTypesCounterUpdated(
+          kReceiverMainSsrc, Field(&RtcpPacketTypeCounter::pli_packets, 1)));
+  EXPECT_CALL(intra_frame_observer_,
+              OnReceivedIntraFrameRequest(kReceiverMainSsrc));
+  InjectRtcpPacket(pli);
+}
+
+TEST_F(RtcpReceiverTest, PliPacketNotToUsIgnored) {
+  rtcp::Pli pli;
+  pli.SetMediaSsrc(kNotToUsSsrc);
+
+  EXPECT_CALL(
+      packet_type_counter_observer_,
+      RtcpPacketTypesCounterUpdated(
+          kReceiverMainSsrc, Field(&RtcpPacketTypeCounter::pli_packets, 0)));
+  EXPECT_CALL(intra_frame_observer_, OnReceivedIntraFrameRequest(_)).Times(0);
+  InjectRtcpPacket(pli);
+}
+
+TEST_F(RtcpReceiverTest, InjectFirPacket) {
+  rtcp::Fir fir;
+  fir.AddRequestTo(kReceiverMainSsrc, 13);
+
+  EXPECT_CALL(
+      packet_type_counter_observer_,
+      RtcpPacketTypesCounterUpdated(
+          kReceiverMainSsrc, Field(&RtcpPacketTypeCounter::fir_packets, 1)));
+  EXPECT_CALL(intra_frame_observer_,
+              OnReceivedIntraFrameRequest(kReceiverMainSsrc));
+  InjectRtcpPacket(fir);
+}
+
+TEST_F(RtcpReceiverTest, FirPacketNotToUsIgnored) {
+  rtcp::Fir fir;
+  fir.AddRequestTo(kNotToUsSsrc, 13);
+
+  EXPECT_CALL(intra_frame_observer_, OnReceivedIntraFrameRequest(_)).Times(0);
+  InjectRtcpPacket(fir);
+}
+
+TEST_F(RtcpReceiverTest, ExtendedReportsPacketWithZeroReportBlocksIgnored) {
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+
+  InjectRtcpPacket(xr);
+}
+
+// VOiP reports are ignored.
+TEST_F(RtcpReceiverTest, InjectExtendedReportsVoipPacket) {
+  const uint8_t kLossRate = 123;
+  rtcp::VoipMetric voip_metric;
+  voip_metric.SetMediaSsrc(kReceiverMainSsrc);
+  RTCPVoIPMetric metric;
+  metric.lossRate = kLossRate;
+  voip_metric.SetVoipMetric(metric);
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetVoipMetric(voip_metric);
+
+  InjectRtcpPacket(xr);
+}
+
+TEST_F(RtcpReceiverTest, ExtendedReportsVoipPacketNotToUsIgnored) {
+  rtcp::VoipMetric voip_metric;
+  voip_metric.SetMediaSsrc(kNotToUsSsrc);
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetVoipMetric(voip_metric);
+
+  InjectRtcpPacket(xr);
+}
+
+TEST_F(RtcpReceiverTest, InjectExtendedReportsReceiverReferenceTimePacket) {
+  const NtpTime kNtp(0x10203, 0x40506);
+  rtcp::Rrtr rrtr;
+  rrtr.SetNtp(kNtp);
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetRrtr(rrtr);
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  EXPECT_THAT(last_xr_rtis, IsEmpty());
+
+  InjectRtcpPacket(xr);
+
+  last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(1));
+  EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
+  EXPECT_EQ(CompactNtp(kNtp), last_xr_rtis[0].last_rr);
+  EXPECT_EQ(0U, last_xr_rtis[0].delay_since_last_rr);
+}
+
+TEST_F(RtcpReceiverTest, ExtendedReportsDlrrPacketNotToUsIgnored) {
+  // Allow calculate rtt using dlrr/rrtr, simulating media receiver side.
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(ReceiveTimeInfo(kNotToUsSsrc, 0x12345, 0x67890));
+
+  InjectRtcpPacket(xr);
+
+  int64_t rtt_ms = 0;
+  EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+}
+
+TEST_F(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithSubBlock) {
+  const uint32_t kLastRR = 0x12345;
+  const uint32_t kDelay = 0x23456;
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+  int64_t rtt_ms = 0;
+  EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, kLastRR, kDelay));
+
+  InjectRtcpPacket(xr);
+
+  uint32_t compact_ntp_now = CompactNtp(system_clock_.CurrentNtpTime());
+  EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+  uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR;
+  EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1);
+}
+
+TEST_F(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithMultipleSubBlocks) {
+  const uint32_t kLastRR = 0x12345;
+  const uint32_t kDelay = 0x56789;
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, kLastRR, kDelay));
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc + 1, 0x12345, 0x67890));
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc + 2, 0x12345, 0x67890));
+
+  InjectRtcpPacket(xr);
+
+  uint32_t compact_ntp_now = CompactNtp(system_clock_.CurrentNtpTime());
+  int64_t rtt_ms = 0;
+  EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+  uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR;
+  EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1);
+}
+
+TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithMultipleReportBlocks) {
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+
+  rtcp::Rrtr rrtr;
+  rtcp::VoipMetric metric;
+  metric.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetRrtr(rrtr);
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0x12345, 0x67890));
+  xr.SetVoipMetric(metric);
+
+  InjectRtcpPacket(xr);
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  EXPECT_THAT(last_xr_rtis, SizeIs(1));
+  int64_t rtt_ms = 0;
+  EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+}
+
+TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithUnknownReportBlock) {
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+
+  rtcp::Rrtr rrtr;
+  rtcp::VoipMetric metric;
+  metric.SetMediaSsrc(kReceiverMainSsrc);
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetRrtr(rrtr);
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0x12345, 0x67890));
+  xr.SetVoipMetric(metric);
+
+  rtc::Buffer packet = xr.Build();
+  // Modify the DLRR block to have an unsupported block type, from 5 to 6.
+  ASSERT_EQ(5, packet.data()[20]);
+  packet.data()[20] = 6;
+  InjectRtcpPacket(packet);
+
+  // Validate Rrtr was received and processed.
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  EXPECT_THAT(last_xr_rtis, SizeIs(1));
+  // Validate Dlrr report wasn't processed.
+  int64_t rtt_ms = 0;
+  EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+}
+
+TEST_F(RtcpReceiverTest, TestExtendedReportsRrRttInitiallyFalse) {
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+
+  int64_t rtt_ms;
+  EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+}
+
+TEST_F(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) {
+  Random rand(0x0123456789abcdef);
+  const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
+  const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
+  const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+  NtpTime now = system_clock_.CurrentNtpTime();
+  uint32_t sent_ntp = CompactNtp(now);
+  system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, sent_ntp, kDelayNtp));
+
+  InjectRtcpPacket(xr);
+
+  int64_t rtt_ms = 0;
+  EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+  EXPECT_NEAR(kRttMs, rtt_ms, 1);
+}
+
+TEST_F(RtcpReceiverTest, XrDlrrCalculatesNegativeRttAsOne) {
+  Random rand(0x0123456789abcdef);
+  const int64_t kRttMs = rand.Rand(-3600 * 1000, -1);
+  const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
+  const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
+  NtpTime now = system_clock_.CurrentNtpTime();
+  uint32_t sent_ntp = CompactNtp(now);
+  system_clock_.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
+  rtcp_receiver_.SetRtcpXrRrtrStatus(true);
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, sent_ntp, kDelayNtp));
+
+  InjectRtcpPacket(xr);
+
+  int64_t rtt_ms = 0;
+  EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
+  EXPECT_EQ(1, rtt_ms);
+}
+
+TEST_F(RtcpReceiverTest, ConsumeReceivedXrReferenceTimeInfoInitiallyEmpty) {
+  EXPECT_THAT(rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(), IsEmpty());
+}
+
+TEST_F(RtcpReceiverTest, ConsumeReceivedXrReferenceTimeInfo) {
+  const NtpTime kNtp(0x10203, 0x40506);
+  const uint32_t kNtpMid = CompactNtp(kNtp);
+
+  rtcp::Rrtr rrtr;
+  rrtr.SetNtp(kNtp);
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  xr.SetRrtr(rrtr);
+
+  InjectRtcpPacket(xr);
+
+  system_clock_.AdvanceTimeMilliseconds(1000);
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(1));
+  EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
+  EXPECT_EQ(kNtpMid, last_xr_rtis[0].last_rr);
+  EXPECT_EQ(65536U, last_xr_rtis[0].delay_since_last_rr);
+}
+
+TEST_F(RtcpReceiverTest,
+       ReceivedRrtrFromSameSsrcUpdatesReceivedReferenceTimeInfo) {
+  const NtpTime kNtp1(0x10203, 0x40506);
+  const NtpTime kNtp2(0x11223, 0x44556);
+  const int64_t kDelayMs = 2000;
+
+  rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kSenderSsrc);
+  rtcp::Rrtr rrtr1;
+  rrtr1.SetNtp(kNtp1);
+  xr.SetRrtr(rrtr1);
+  InjectRtcpPacket(xr);
+  system_clock_.AdvanceTimeMilliseconds(kDelayMs);
+  rtcp::Rrtr rrtr2;
+  rrtr2.SetNtp(kNtp2);
+  xr.SetRrtr(rrtr2);
+  InjectRtcpPacket(xr);
+  system_clock_.AdvanceTimeMilliseconds(kDelayMs);
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(1));
+  EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
+  EXPECT_EQ(CompactNtp(kNtp2), last_xr_rtis[0].last_rr);
+  EXPECT_EQ(kDelayMs * 65536 / 1000, last_xr_rtis[0].delay_since_last_rr);
+}
+
+TEST_F(RtcpReceiverTest, StoresLastReceivedRrtrPerSsrc) {
+  const size_t kNumBufferedReports = 1;
+  const size_t kNumReports =
+      rtcp::ExtendedReports::kMaxNumberOfDlrrItems + kNumBufferedReports;
+  for (size_t i = 0; i < kNumReports; ++i) {
+    rtcp::ExtendedReports xr;
+    xr.SetSenderSsrc(i * 100);
+    rtcp::Rrtr rrtr;
+    rrtr.SetNtp(NtpTime(i * 200, i * 300));
+    xr.SetRrtr(rrtr);
+    InjectRtcpPacket(xr);
+    system_clock_.AdvanceTimeMilliseconds(1000);
+  }
+
+  std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
+      rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis,
+              SizeIs(rtcp::ExtendedReports::kMaxNumberOfDlrrItems));
+  for (size_t i = 0; i < rtcp::ExtendedReports::kMaxNumberOfDlrrItems; ++i) {
+    EXPECT_EQ(i * 100, last_xr_rtis[i].ssrc);
+    EXPECT_EQ(CompactNtp(NtpTime(i * 200, i * 300)), last_xr_rtis[i].last_rr);
+    EXPECT_EQ(65536U * (kNumReports - i), last_xr_rtis[i].delay_since_last_rr);
+  }
+
+  last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+  ASSERT_THAT(last_xr_rtis, SizeIs(kNumBufferedReports));
+}
+
+TEST_F(RtcpReceiverTest, ReceiveReportTimeout) {
+  const int64_t kRtcpIntervalMs = 1000;
+  const uint16_t kSequenceNumber = 1234;
+  system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs);
+
+  // No RR received, shouldn't trigger a timeout.
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
+
+  // Add a RR and advance the clock just enough to not trigger a timeout.
+  rtcp::ReportBlock rb1;
+  rb1.SetMediaSsrc(kReceiverMainSsrc);
+  rb1.SetExtHighestSeqNum(kSequenceNumber);
+  rtcp::ReceiverReport rr1;
+  rr1.SetSenderSsrc(kSenderSsrc);
+  rr1.AddReportBlock(rb1);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr1);
+
+  system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs - 1);
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
+
+  // Add a RR with the same extended max as the previous RR to trigger a
+  // sequence number timeout, but not a RR timeout.
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr1);
+
+  system_clock_.AdvanceTimeMilliseconds(2);
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+  EXPECT_TRUE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
+
+  // Advance clock enough to trigger an RR timeout too.
+  system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs);
+  EXPECT_TRUE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+
+  // We should only get one timeout even though we still haven't received a new
+  // RR.
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
+
+  // Add a new RR with increase sequence number to reset timers.
+  rtcp::ReportBlock rb2;
+  rb2.SetMediaSsrc(kReceiverMainSsrc);
+  rb2.SetExtHighestSeqNum(kSequenceNumber + 1);
+  rtcp::ReceiverReport rr2;
+  rr2.SetSenderSsrc(kSenderSsrc);
+  rr2.AddReportBlock(rb2);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr2);
+
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
+
+  // Verify we can get a timeout again once we've received new RR.
+  system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs);
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr2);
+
+  system_clock_.AdvanceTimeMilliseconds(kRtcpIntervalMs + 1);
+  EXPECT_FALSE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+  EXPECT_TRUE(rtcp_receiver_.RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
+
+  system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs);
+  EXPECT_TRUE(rtcp_receiver_.RtcpRrTimeout(kRtcpIntervalMs));
+}
+
+TEST_F(RtcpReceiverTest, TmmbrReceivedWithNoIncomingPacket) {
+  EXPECT_EQ(0u, rtcp_receiver_.TmmbrReceived().size());
+}
+
+TEST_F(RtcpReceiverTest, TmmbrPacketAccepted) {
+  const uint32_t kBitrateBps = 30000;
+  rtcp::Tmmbr tmmbr;
+  tmmbr.SetSenderSsrc(kSenderSsrc);
+  tmmbr.AddTmmbr(rtcp::TmmbItem(kReceiverMainSsrc, kBitrateBps, 0));
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::CompoundPacket compound;
+  compound.Append(&sr);
+  compound.Append(&tmmbr);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(rtp_rtcp_impl_, SetTmmbn(SizeIs(1)));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(kBitrateBps));
+  InjectRtcpPacket(compound);
+
+  std::vector<rtcp::TmmbItem> tmmbr_received = rtcp_receiver_.TmmbrReceived();
+  ASSERT_EQ(1u, tmmbr_received.size());
+  EXPECT_EQ(kBitrateBps, tmmbr_received[0].bitrate_bps());
+  EXPECT_EQ(kSenderSsrc, tmmbr_received[0].ssrc());
+}
+
+TEST_F(RtcpReceiverTest, TmmbrPacketNotForUsIgnored) {
+  const uint32_t kBitrateBps = 30000;
+  rtcp::Tmmbr tmmbr;
+  tmmbr.SetSenderSsrc(kSenderSsrc);
+  tmmbr.AddTmmbr(rtcp::TmmbItem(kNotToUsSsrc, kBitrateBps, 0));
+
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::CompoundPacket compound;
+  compound.Append(&sr);
+  compound.Append(&tmmbr);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(_)).Times(0);
+  InjectRtcpPacket(compound);
+
+  EXPECT_EQ(0u, rtcp_receiver_.TmmbrReceived().size());
+}
+
+TEST_F(RtcpReceiverTest, TmmbrPacketZeroRateIgnored) {
+  rtcp::Tmmbr tmmbr;
+  tmmbr.SetSenderSsrc(kSenderSsrc);
+  tmmbr.AddTmmbr(rtcp::TmmbItem(kReceiverMainSsrc, 0, 0));
+  rtcp::SenderReport sr;
+  sr.SetSenderSsrc(kSenderSsrc);
+  rtcp::CompoundPacket compound;
+  compound.Append(&sr);
+  compound.Append(&tmmbr);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(_)).Times(0);
+  InjectRtcpPacket(compound);
+
+  EXPECT_EQ(0u, rtcp_receiver_.TmmbrReceived().size());
+}
+
+TEST_F(RtcpReceiverTest, TmmbrThreeConstraintsTimeOut) {
+  // Inject 3 packets "from" kSenderSsrc, kSenderSsrc+1, kSenderSsrc+2.
+  // The times of arrival are starttime + 0, starttime + 5 and starttime + 10.
+  for (uint32_t ssrc = kSenderSsrc; ssrc < kSenderSsrc + 3; ++ssrc) {
+    rtcp::Tmmbr tmmbr;
+    tmmbr.SetSenderSsrc(ssrc);
+    tmmbr.AddTmmbr(rtcp::TmmbItem(kReceiverMainSsrc, 30000, 0));
+    rtcp::SenderReport sr;
+    sr.SetSenderSsrc(ssrc);
+    rtcp::CompoundPacket compound;
+    compound.Append(&sr);
+    compound.Append(&tmmbr);
+
+    EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+    EXPECT_CALL(rtp_rtcp_impl_, SetTmmbn(_));
+    EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+    EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(_));
+    InjectRtcpPacket(compound);
+
+    // 5 seconds between each packet.
+    system_clock_.AdvanceTimeMilliseconds(5000);
+  }
+  // It is now starttime + 15.
+  std::vector<rtcp::TmmbItem> candidate_set = rtcp_receiver_.TmmbrReceived();
+  ASSERT_EQ(3u, candidate_set.size());
+  EXPECT_EQ(30000U, candidate_set[0].bitrate_bps());
+
+  // We expect the timeout to be 25 seconds. Advance the clock by 12
+  // seconds, timing out the first packet.
+  system_clock_.AdvanceTimeMilliseconds(12000);
+  candidate_set = rtcp_receiver_.TmmbrReceived();
+  ASSERT_EQ(2u, candidate_set.size());
+  EXPECT_EQ(kSenderSsrc + 1, candidate_set[0].ssrc());
+}
+
+TEST_F(RtcpReceiverTest, Callbacks) {
+  MockRtcpCallbackImpl callback;
+  rtcp_receiver_.RegisterRtcpStatisticsCallback(&callback);
+
+  const uint8_t kFractionLoss = 3;
+  const uint32_t kCumulativeLoss = 7;
+  const uint32_t kJitter = 9;
+  const uint16_t kSequenceNumber = 1234;
+
+  // First packet, all numbers should just propagate.
+  rtcp::ReportBlock rb1;
+  rb1.SetMediaSsrc(kReceiverMainSsrc);
+  rb1.SetExtHighestSeqNum(kSequenceNumber);
+  rb1.SetFractionLost(kFractionLoss);
+  rb1.SetCumulativeLost(kCumulativeLoss);
+  rb1.SetJitter(kJitter);
+
+  rtcp::ReceiverReport rr1;
+  rr1.SetSenderSsrc(kSenderSsrc);
+  rr1.AddReportBlock(rb1);
+  EXPECT_CALL(callback,
+              StatisticsUpdated(
+                  AllOf(Field(&RtcpStatistics::fraction_lost, kFractionLoss),
+                        Field(&RtcpStatistics::packets_lost, kCumulativeLoss),
+                        Field(&RtcpStatistics::extended_highest_sequence_number,
+                              kSequenceNumber),
+                        Field(&RtcpStatistics::jitter, kJitter)),
+                  kReceiverMainSsrc));
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  InjectRtcpPacket(rr1);
+
+  rtcp_receiver_.RegisterRtcpStatisticsCallback(nullptr);
+
+  // Add arbitrary numbers, callback should not be called.
+  rtcp::ReportBlock rb2;
+  rb2.SetMediaSsrc(kReceiverMainSsrc);
+  rb2.SetExtHighestSeqNum(kSequenceNumber + 1);
+  rb2.SetFractionLost(42);
+  rb2.SetCumulativeLost(137);
+  rb2.SetJitter(4711);
+
+  rtcp::ReceiverReport rr2;
+  rr2.SetSenderSsrc(kSenderSsrc);
+  rr2.AddReportBlock(rb2);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedRtcpReportBlocks(_));
+  EXPECT_CALL(bandwidth_observer_, OnReceivedRtcpReceiverReport(_, _, _));
+  EXPECT_CALL(callback, StatisticsUpdated(_, _)).Times(0);
+  InjectRtcpPacket(rr2);
+}
+
+TEST_F(RtcpReceiverTest, ReceivesTransportFeedback) {
+  rtcp::TransportFeedback packet;
+  packet.SetMediaSsrc(kReceiverMainSsrc);
+  packet.SetSenderSsrc(kSenderSsrc);
+  packet.SetBase(1, 1000);
+  packet.AddReceivedPacket(1, 1000);
+
+  EXPECT_CALL(
+      transport_feedback_observer_,
+      OnTransportFeedback(AllOf(
+          Property(&rtcp::TransportFeedback::media_ssrc, kReceiverMainSsrc),
+          Property(&rtcp::TransportFeedback::sender_ssrc, kSenderSsrc))));
+  InjectRtcpPacket(packet);
+}
+
+TEST_F(RtcpReceiverTest, ReceivesRemb) {
+  const uint32_t kBitrateBps = 500000;
+  rtcp::Remb remb;
+  remb.SetSenderSsrc(kSenderSsrc);
+  remb.SetBitrateBps(kBitrateBps);
+
+  EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(kBitrateBps));
+  InjectRtcpPacket(remb);
+}
+
+TEST_F(RtcpReceiverTest, HandlesInvalidTransportFeedback) {
+  // Send a compound packet with a TransportFeedback followed by something else.
+  rtcp::TransportFeedback packet;
+  packet.SetMediaSsrc(kReceiverMainSsrc);
+  packet.SetSenderSsrc(kSenderSsrc);
+  packet.SetBase(1, 1000);
+  packet.AddReceivedPacket(1, 1000);
+
+  static uint32_t kBitrateBps = 50000;
+  rtcp::Remb remb;
+  remb.SetSenderSsrc(kSenderSsrc);
+  remb.SetBitrateBps(kBitrateBps);
+  rtcp::CompoundPacket compound;
+  compound.Append(&packet);
+  compound.Append(&remb);
+  rtc::Buffer built_packet = compound.Build();
+
+  // Modify the TransportFeedback packet so that it is invalid.
+  const size_t kStatusCountOffset = 14;
+  ByteWriter<uint16_t>::WriteBigEndian(&built_packet.data()[kStatusCountOffset],
+                                       42);
+
+  // Stress no transport feedback is expected.
+  EXPECT_CALL(transport_feedback_observer_, OnTransportFeedback(_)).Times(0);
+  // But remb should be processed and cause a callback
+  EXPECT_CALL(bandwidth_observer_, OnReceivedEstimatedBitrate(kBitrateBps));
+  InjectRtcpPacket(built_packet);
+}
+
+TEST_F(RtcpReceiverTest, Nack) {
+  const uint16_t kNackList1[] = {1, 2, 3, 5};
+  const uint16_t kNackList23[] = {5, 7, 30, 40, 41, 58, 59, 61, 63};
+  const size_t kNackListLength2 = 4;
+  const size_t kNackListLength3 = arraysize(kNackList23) - kNackListLength2;
+  std::set<uint16_t> nack_set;
+  nack_set.insert(std::begin(kNackList1), std::end(kNackList1));
+  nack_set.insert(std::begin(kNackList23), std::end(kNackList23));
+
+  rtcp::Nack nack1;
+  nack1.SetSenderSsrc(kSenderSsrc);
+  nack1.SetMediaSsrc(kReceiverMainSsrc);
+  nack1.SetPacketIds(kNackList1, arraysize(kNackList1));
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedNack(ElementsAreArray(kNackList1)));
+  EXPECT_CALL(packet_type_counter_observer_,
+              RtcpPacketTypesCounterUpdated(
+                  kReceiverMainSsrc,
+                  AllOf(Field(&RtcpPacketTypeCounter::nack_requests,
+                              arraysize(kNackList1)),
+                        Field(&RtcpPacketTypeCounter::unique_nack_requests,
+                              arraysize(kNackList1)))));
+  InjectRtcpPacket(nack1);
+
+  rtcp::Nack nack2;
+  nack2.SetSenderSsrc(kSenderSsrc);
+  nack2.SetMediaSsrc(kReceiverMainSsrc);
+  nack2.SetPacketIds(kNackList23, kNackListLength2);
+
+  rtcp::Nack nack3;
+  nack3.SetSenderSsrc(kSenderSsrc);
+  nack3.SetMediaSsrc(kReceiverMainSsrc);
+  nack3.SetPacketIds(kNackList23 + kNackListLength2, kNackListLength3);
+
+  rtcp::CompoundPacket two_nacks;
+  two_nacks.Append(&nack2);
+  two_nacks.Append(&nack3);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnReceivedNack(ElementsAreArray(kNackList23)));
+  EXPECT_CALL(packet_type_counter_observer_,
+              RtcpPacketTypesCounterUpdated(
+                  kReceiverMainSsrc,
+                  AllOf(Field(&RtcpPacketTypeCounter::nack_requests,
+                              arraysize(kNackList1) + arraysize(kNackList23)),
+                        Field(&RtcpPacketTypeCounter::unique_nack_requests,
+                              nack_set.size()))));
+  InjectRtcpPacket(two_nacks);
+}
+
+TEST_F(RtcpReceiverTest, NackNotForUsIgnored) {
+  const uint16_t kNackList1[] = {1, 2, 3, 5};
+  const size_t kNackListLength1 = std::end(kNackList1) - std::begin(kNackList1);
+
+  rtcp::Nack nack;
+  nack.SetSenderSsrc(kSenderSsrc);
+  nack.SetMediaSsrc(kNotToUsSsrc);
+  nack.SetPacketIds(kNackList1, kNackListLength1);
+
+  EXPECT_CALL(packet_type_counter_observer_,
+              RtcpPacketTypesCounterUpdated(
+                  _, Field(&RtcpPacketTypeCounter::nack_requests, 0)));
+  InjectRtcpPacket(nack);
+}
+
+TEST_F(RtcpReceiverTest, ForceSenderReport) {
+  rtcp::RapidResyncRequest rr;
+  rr.SetSenderSsrc(kSenderSsrc);
+  rr.SetMediaSsrc(kReceiverMainSsrc);
+
+  EXPECT_CALL(rtp_rtcp_impl_, OnRequestSendReport());
+  InjectRtcpPacket(rr);
+}
+
+TEST_F(RtcpReceiverTest, ReceivesTargetBitrate) {
+  VideoBitrateAllocation expected_allocation;
+  expected_allocation.SetBitrate(0, 0, 10000);
+  expected_allocation.SetBitrate(0, 1, 20000);
+  expected_allocation.SetBitrate(1, 0, 40000);
+  expected_allocation.SetBitrate(1, 1, 80000);
+
+  rtcp::TargetBitrate bitrate;
+  bitrate.AddTargetBitrate(0, 0, expected_allocation.GetBitrate(0, 0) / 1000);
+  bitrate.AddTargetBitrate(0, 1, expected_allocation.GetBitrate(0, 1) / 1000);
+  bitrate.AddTargetBitrate(1, 0, expected_allocation.GetBitrate(1, 0) / 1000);
+  bitrate.AddTargetBitrate(1, 1, expected_allocation.GetBitrate(1, 1) / 1000);
+
+  rtcp::ExtendedReports xr;
+  xr.SetTargetBitrate(bitrate);
+
+  // Wrong sender ssrc, target bitrate should be discarded.
+  xr.SetSenderSsrc(kSenderSsrc + 1);
+  EXPECT_CALL(bitrate_allocation_observer_,
+              OnBitrateAllocationUpdated(expected_allocation))
+      .Times(0);
+  InjectRtcpPacket(xr);
+
+  // Set correct ssrc, callback should be called once.
+  xr.SetSenderSsrc(kSenderSsrc);
+  EXPECT_CALL(bitrate_allocation_observer_,
+              OnBitrateAllocationUpdated(expected_allocation));
+  InjectRtcpPacket(xr);
+}
+
+TEST_F(RtcpReceiverTest, HandlesIncorrectTargetBitrate) {
+  VideoBitrateAllocation expected_allocation;
+  expected_allocation.SetBitrate(0, 0, 10000);
+
+  rtcp::TargetBitrate bitrate;
+  bitrate.AddTargetBitrate(0, 0, expected_allocation.GetBitrate(0, 0) / 1000);
+  bitrate.AddTargetBitrate(0, kMaxTemporalStreams, 20000);
+  bitrate.AddTargetBitrate(kMaxSpatialLayers, 0, 40000);
+
+  rtcp::ExtendedReports xr;
+  xr.SetTargetBitrate(bitrate);
+  xr.SetSenderSsrc(kSenderSsrc);
+
+  EXPECT_CALL(bitrate_allocation_observer_,
+              OnBitrateAllocationUpdated(expected_allocation));
+  InjectRtcpPacket(xr);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc
new file mode 100644
index 0000000..55f545c
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -0,0 +1,941 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_sender.h"
+
+#include <string.h>  // memcpy
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "modules/rtp_rtcp/source/tmmbr_help.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+
+namespace {
+const uint32_t kRtcpAnyExtendedReports =
+    kRtcpXrVoipMetric | kRtcpXrReceiverReferenceTime | kRtcpXrDlrrReportBlock |
+    kRtcpXrTargetBitrate;
+}  // namespace
+
+RTCPSender::FeedbackState::FeedbackState()
+    : packets_sent(0),
+      media_bytes_sent(0),
+      send_bitrate(0),
+      last_rr_ntp_secs(0),
+      last_rr_ntp_frac(0),
+      remote_sr(0),
+      module(nullptr) {}
+
+RTCPSender::FeedbackState::FeedbackState(const FeedbackState&) = default;
+
+RTCPSender::FeedbackState::FeedbackState(FeedbackState&&) = default;
+
+RTCPSender::FeedbackState::~FeedbackState() = default;
+
+class PacketContainer : public rtcp::CompoundPacket {
+ public:
+  PacketContainer(Transport* transport, RtcEventLog* event_log)
+      : transport_(transport), event_log_(event_log) {}
+  ~PacketContainer() override {
+    for (RtcpPacket* packet : appended_packets_)
+      delete packet;
+  }
+
+  size_t SendPackets(size_t max_payload_length) {
+    size_t bytes_sent = 0;
+    Build(max_payload_length, [&](rtc::ArrayView<const uint8_t> packet) {
+      if (transport_->SendRtcp(packet.data(), packet.size())) {
+        bytes_sent += packet.size();
+        if (event_log_) {
+          event_log_->Log(
+              absl::make_unique<RtcEventRtcpPacketOutgoing>(packet));
+        }
+      }
+    });
+    return bytes_sent;
+  }
+
+ private:
+  Transport* transport_;
+  RtcEventLog* const event_log_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(PacketContainer);
+};
+
+class RTCPSender::RtcpContext {
+ public:
+  RtcpContext(const FeedbackState& feedback_state,
+              int32_t nack_size,
+              const uint16_t* nack_list,
+              NtpTime now)
+      : feedback_state_(feedback_state),
+        nack_size_(nack_size),
+        nack_list_(nack_list),
+        now_(now) {}
+
+  const FeedbackState& feedback_state_;
+  const int32_t nack_size_;
+  const uint16_t* nack_list_;
+  const NtpTime now_;
+};
+
+RTCPSender::RTCPSender(
+    bool audio,
+    Clock* clock,
+    ReceiveStatisticsProvider* receive_statistics,
+    RtcpPacketTypeCounterObserver* packet_type_counter_observer,
+    RtcEventLog* event_log,
+    Transport* outgoing_transport,
+    RtcpIntervalConfig interval_config)
+    : audio_(audio),
+      clock_(clock),
+      random_(clock_->TimeInMicroseconds()),
+      method_(RtcpMode::kOff),
+      event_log_(event_log),
+      transport_(outgoing_transport),
+      interval_config_(interval_config),
+      using_nack_(false),
+      sending_(false),
+      next_time_to_send_rtcp_(0),
+      timestamp_offset_(0),
+      last_rtp_timestamp_(0),
+      last_frame_capture_time_ms_(-1),
+      ssrc_(0),
+      remote_ssrc_(0),
+      receive_statistics_(receive_statistics),
+
+      sequence_number_fir_(0),
+
+      remb_bitrate_(0),
+
+      tmmbr_send_bps_(0),
+      packet_oh_send_(0),
+      max_packet_size_(IP_PACKET_SIZE - 28),  // IPv4 + UDP by default.
+
+      app_sub_type_(0),
+      app_name_(0),
+      app_data_(nullptr),
+      app_length_(0),
+
+      xr_send_receiver_reference_time_enabled_(false),
+      packet_type_counter_observer_(packet_type_counter_observer) {
+  RTC_DCHECK(transport_ != nullptr);
+
+  builders_[kRtcpSr] = &RTCPSender::BuildSR;
+  builders_[kRtcpRr] = &RTCPSender::BuildRR;
+  builders_[kRtcpSdes] = &RTCPSender::BuildSDES;
+  builders_[kRtcpPli] = &RTCPSender::BuildPLI;
+  builders_[kRtcpFir] = &RTCPSender::BuildFIR;
+  builders_[kRtcpRemb] = &RTCPSender::BuildREMB;
+  builders_[kRtcpBye] = &RTCPSender::BuildBYE;
+  builders_[kRtcpApp] = &RTCPSender::BuildAPP;
+  builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
+  builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
+  builders_[kRtcpNack] = &RTCPSender::BuildNACK;
+  builders_[kRtcpAnyExtendedReports] = &RTCPSender::BuildExtendedReports;
+}
+
+RTCPSender::~RTCPSender() {}
+
+RtcpMode RTCPSender::Status() const {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  return method_;
+}
+
+void RTCPSender::SetRTCPStatus(RtcpMode new_method) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+
+  if (method_ == RtcpMode::kOff && new_method != RtcpMode::kOff) {
+    // When switching on, reschedule the next packet
+    int64_t interval_ms = audio_ ? interval_config_.audio_interval_ms
+                                 : interval_config_.video_interval_ms;
+    next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + (interval_ms / 2);
+  }
+  method_ = new_method;
+}
+
+bool RTCPSender::Sending() const {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  return sending_;
+}
+
+int32_t RTCPSender::SetSendingStatus(const FeedbackState& feedback_state,
+                                     bool sending) {
+  bool sendRTCPBye = false;
+  {
+    rtc::CritScope lock(&critical_section_rtcp_sender_);
+
+    if (method_ != RtcpMode::kOff) {
+      if (sending == false && sending_ == true) {
+        // Trigger RTCP bye
+        sendRTCPBye = true;
+      }
+    }
+    sending_ = sending;
+  }
+  if (sendRTCPBye)
+    return SendRTCP(feedback_state, kRtcpBye);
+  return 0;
+}
+
+void RTCPSender::SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) {
+  RTC_CHECK_GE(bitrate_bps, 0);
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  remb_bitrate_ = bitrate_bps;
+  remb_ssrcs_ = std::move(ssrcs);
+
+  SetFlag(kRtcpRemb, /*is_volatile=*/false);
+  // Send a REMB immediately if we have a new REMB. The frequency of REMBs is
+  // throttled by the caller.
+  next_time_to_send_rtcp_ = clock_->TimeInMilliseconds();
+}
+
+void RTCPSender::UnsetRemb() {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  // Stop sending REMB each report until it is reenabled and REMB data set.
+  ConsumeFlag(kRtcpRemb, /*forced=*/true);
+}
+
+bool RTCPSender::TMMBR() const {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  return IsFlagPresent(RTCPPacketType::kRtcpTmmbr);
+}
+
+void RTCPSender::SetTMMBRStatus(bool enable) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  if (enable) {
+    SetFlag(RTCPPacketType::kRtcpTmmbr, false);
+  } else {
+    ConsumeFlag(RTCPPacketType::kRtcpTmmbr, true);
+  }
+}
+
+void RTCPSender::SetMaxRtpPacketSize(size_t max_packet_size) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  max_packet_size_ = max_packet_size;
+}
+
+void RTCPSender::SetTimestampOffset(uint32_t timestamp_offset) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  timestamp_offset_ = timestamp_offset;
+}
+
+void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
+                                int64_t capture_time_ms) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  last_rtp_timestamp_ = rtp_timestamp;
+  if (capture_time_ms < 0) {
+    // We don't currently get a capture time from VoiceEngine.
+    last_frame_capture_time_ms_ = clock_->TimeInMilliseconds();
+  } else {
+    last_frame_capture_time_ms_ = capture_time_ms;
+  }
+}
+
+uint32_t RTCPSender::SSRC() const {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  return ssrc_;
+}
+
+void RTCPSender::SetSSRC(uint32_t ssrc) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+
+  if (ssrc_ != 0) {
+    // not first SetSSRC, probably due to a collision
+    // schedule a new RTCP report
+    // make sure that we send a RTP packet
+    next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + 100;
+  }
+  ssrc_ = ssrc;
+}
+
+void RTCPSender::SetRemoteSSRC(uint32_t ssrc) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  remote_ssrc_ = ssrc;
+}
+
+int32_t RTCPSender::SetCNAME(const char* c_name) {
+  if (!c_name)
+    return -1;
+
+  RTC_DCHECK_LT(strlen(c_name), RTCP_CNAME_SIZE);
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  cname_ = c_name;
+  return 0;
+}
+
+int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC, const char* c_name) {
+  RTC_DCHECK(c_name);
+  RTC_DCHECK_LT(strlen(c_name), RTCP_CNAME_SIZE);
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  // One spot is reserved for ssrc_/cname_.
+  // TODO(danilchap): Add support for more than 30 contributes by sending
+  // several sdes packets.
+  if (csrc_cnames_.size() >= rtcp::Sdes::kMaxNumberOfChunks - 1)
+    return -1;
+
+  csrc_cnames_[SSRC] = c_name;
+  return 0;
+}
+
+int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  auto it = csrc_cnames_.find(SSRC);
+
+  if (it == csrc_cnames_.end())
+    return -1;
+
+  csrc_cnames_.erase(it);
+  return 0;
+}
+
+bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
+  /*
+      For audio we use a configurable interval (default: 5 seconds)
+
+      For video we use a configurable interval (default: 1 second) for a BW
+          smaller than 360 kbit/s, technicaly we break the max 5% RTCP BW for
+          video below 10 kbit/s but that should be extremely rare
+
+
+  From RFC 3550
+
+      MAX RTCP BW is 5% if the session BW
+          A send report is approximately 65 bytes inc CNAME
+          A receiver report is approximately 28 bytes
+
+      The RECOMMENDED value for the reduced minimum in seconds is 360
+        divided by the session bandwidth in kilobits/second.  This minimum
+        is smaller than 5 seconds for bandwidths greater than 72 kb/s.
+
+      If the participant has not yet sent an RTCP packet (the variable
+        initial is true), the constant Tmin is set to half of the configured
+        interval.
+
+      The interval between RTCP packets is varied randomly over the
+        range [0.5,1.5] times the calculated interval to avoid unintended
+        synchronization of all participants
+
+      if we send
+      If the participant is a sender (we_sent true), the constant C is
+        set to the average RTCP packet size (avg_rtcp_size) divided by 25%
+        of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
+        number of senders.
+
+      if we receive only
+        If we_sent is not true, the constant C is set
+        to the average RTCP packet size divided by 75% of the RTCP
+        bandwidth.  The constant n is set to the number of receivers
+        (members - senders).  If the number of senders is greater than
+        25%, senders and receivers are treated together.
+
+      reconsideration NOT required for peer-to-peer
+        "timer reconsideration" is
+        employed.  This algorithm implements a simple back-off mechanism
+        which causes users to hold back RTCP packet transmission if the
+        group sizes are increasing.
+
+        n = number of members
+        C = avg_size/(rtcpBW/4)
+
+     3. The deterministic calculated interval Td is set to max(Tmin, n*C).
+
+     4. The calculated interval T is set to a number uniformly distributed
+        between 0.5 and 1.5 times the deterministic calculated interval.
+
+     5. The resulting value of T is divided by e-3/2=1.21828 to compensate
+        for the fact that the timer reconsideration algorithm converges to
+        a value of the RTCP bandwidth below the intended average
+  */
+
+  int64_t now = clock_->TimeInMilliseconds();
+
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+
+  if (method_ == RtcpMode::kOff)
+    return false;
+
+  if (!audio_ && sendKeyframeBeforeRTP) {
+    // for video key-frames we want to send the RTCP before the large key-frame
+    // if we have a 100 ms margin
+    now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
+  }
+
+  if (now >= next_time_to_send_rtcp_) {
+    return true;
+  } else if (now < 0x0000ffff &&
+             next_time_to_send_rtcp_ > 0xffff0000) {  // 65 sec margin
+    // wrap
+    return true;
+  }
+  return false;
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildSR(const RtcpContext& ctx) {
+  // Timestamp shouldn't be estimated before first media frame.
+  RTC_DCHECK_GE(last_frame_capture_time_ms_, 0);
+  // The timestamp of this RTCP packet should be estimated as the timestamp of
+  // the frame being captured at this moment. We are calculating that
+  // timestamp as the last frame's timestamp + the time since the last frame
+  // was captured.
+  uint32_t rtp_rate =
+      (audio_ ? kBogusRtpRateForAudioRtcp : kVideoPayloadTypeFrequency) / 1000;
+  uint32_t rtp_timestamp =
+      timestamp_offset_ + last_rtp_timestamp_ +
+      (clock_->TimeInMilliseconds() - last_frame_capture_time_ms_) * rtp_rate;
+
+  rtcp::SenderReport* report = new rtcp::SenderReport();
+  report->SetSenderSsrc(ssrc_);
+  report->SetNtp(ctx.now_);
+  report->SetRtpTimestamp(rtp_timestamp);
+  report->SetPacketCount(ctx.feedback_state_.packets_sent);
+  report->SetOctetCount(ctx.feedback_state_.media_bytes_sent);
+  report->SetReportBlocks(CreateReportBlocks(ctx.feedback_state_));
+
+  return std::unique_ptr<rtcp::RtcpPacket>(report);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildSDES(
+    const RtcpContext& ctx) {
+  size_t length_cname = cname_.length();
+  RTC_CHECK_LT(length_cname, RTCP_CNAME_SIZE);
+
+  rtcp::Sdes* sdes = new rtcp::Sdes();
+  sdes->AddCName(ssrc_, cname_);
+
+  for (const auto& it : csrc_cnames_)
+    RTC_CHECK(sdes->AddCName(it.first, it.second));
+
+  return std::unique_ptr<rtcp::RtcpPacket>(sdes);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildRR(const RtcpContext& ctx) {
+  rtcp::ReceiverReport* report = new rtcp::ReceiverReport();
+  report->SetSenderSsrc(ssrc_);
+  report->SetReportBlocks(CreateReportBlocks(ctx.feedback_state_));
+
+  return std::unique_ptr<rtcp::RtcpPacket>(report);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildPLI(const RtcpContext& ctx) {
+  rtcp::Pli* pli = new rtcp::Pli();
+  pli->SetSenderSsrc(ssrc_);
+  pli->SetMediaSsrc(remote_ssrc_);
+
+  ++packet_type_counter_.pli_packets;
+
+  return std::unique_ptr<rtcp::RtcpPacket>(pli);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildFIR(const RtcpContext& ctx) {
+  ++sequence_number_fir_;
+
+  rtcp::Fir* fir = new rtcp::Fir();
+  fir->SetSenderSsrc(ssrc_);
+  fir->AddRequestTo(remote_ssrc_, sequence_number_fir_);
+
+  ++packet_type_counter_.fir_packets;
+
+  return std::unique_ptr<rtcp::RtcpPacket>(fir);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildREMB(
+    const RtcpContext& ctx) {
+  rtcp::Remb* remb = new rtcp::Remb();
+  remb->SetSenderSsrc(ssrc_);
+  remb->SetBitrateBps(remb_bitrate_);
+  remb->SetSsrcs(remb_ssrcs_);
+
+  return std::unique_ptr<rtcp::RtcpPacket>(remb);
+}
+
+void RTCPSender::SetTargetBitrate(unsigned int target_bitrate) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  tmmbr_send_bps_ = target_bitrate;
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBR(
+    const RtcpContext& ctx) {
+  if (ctx.feedback_state_.module == nullptr)
+    return nullptr;
+  // Before sending the TMMBR check the received TMMBN, only an owner is
+  // allowed to raise the bitrate:
+  // * If the sender is an owner of the TMMBN -> send TMMBR
+  // * If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
+
+  // get current bounding set from RTCP receiver
+  bool tmmbr_owner = false;
+
+  // holding critical_section_rtcp_sender_ while calling RTCPreceiver which
+  // will accuire criticalSectionRTCPReceiver_ is a potental deadlock but
+  // since RTCPreceiver is not doing the reverse we should be fine
+  std::vector<rtcp::TmmbItem> candidates =
+      ctx.feedback_state_.module->BoundingSet(&tmmbr_owner);
+
+  if (!candidates.empty()) {
+    for (const auto& candidate : candidates) {
+      if (candidate.bitrate_bps() == tmmbr_send_bps_ &&
+          candidate.packet_overhead() == packet_oh_send_) {
+        // Do not send the same tuple.
+        return nullptr;
+      }
+    }
+    if (!tmmbr_owner) {
+      // Use received bounding set as candidate set.
+      // Add current tuple.
+      candidates.emplace_back(ssrc_, tmmbr_send_bps_, packet_oh_send_);
+
+      // Find bounding set.
+      std::vector<rtcp::TmmbItem> bounding =
+          TMMBRHelp::FindBoundingSet(std::move(candidates));
+      tmmbr_owner = TMMBRHelp::IsOwner(bounding, ssrc_);
+      if (!tmmbr_owner) {
+        // Did not enter bounding set, no meaning to send this request.
+        return nullptr;
+      }
+    }
+  }
+
+  if (!tmmbr_send_bps_)
+    return nullptr;
+
+  rtcp::Tmmbr* tmmbr = new rtcp::Tmmbr();
+  tmmbr->SetSenderSsrc(ssrc_);
+  rtcp::TmmbItem request;
+  request.set_ssrc(remote_ssrc_);
+  request.set_bitrate_bps(tmmbr_send_bps_);
+  request.set_packet_overhead(packet_oh_send_);
+  tmmbr->AddTmmbr(request);
+
+  return std::unique_ptr<rtcp::RtcpPacket>(tmmbr);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBN(
+    const RtcpContext& ctx) {
+  rtcp::Tmmbn* tmmbn = new rtcp::Tmmbn();
+  tmmbn->SetSenderSsrc(ssrc_);
+  for (const rtcp::TmmbItem& tmmbr : tmmbn_to_send_) {
+    if (tmmbr.bitrate_bps() > 0) {
+      tmmbn->AddTmmbr(tmmbr);
+    }
+  }
+
+  return std::unique_ptr<rtcp::RtcpPacket>(tmmbn);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildAPP(const RtcpContext& ctx) {
+  rtcp::App* app = new rtcp::App();
+  app->SetSsrc(ssrc_);
+  app->SetSubType(app_sub_type_);
+  app->SetName(app_name_);
+  app->SetData(app_data_.get(), app_length_);
+
+  return std::unique_ptr<rtcp::RtcpPacket>(app);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK(
+    const RtcpContext& ctx) {
+  rtcp::Nack* nack = new rtcp::Nack();
+  nack->SetSenderSsrc(ssrc_);
+  nack->SetMediaSsrc(remote_ssrc_);
+  nack->SetPacketIds(ctx.nack_list_, ctx.nack_size_);
+
+  // Report stats.
+  for (int idx = 0; idx < ctx.nack_size_; ++idx) {
+    nack_stats_.ReportRequest(ctx.nack_list_[idx]);
+  }
+  packet_type_counter_.nack_requests = nack_stats_.requests();
+  packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
+
+  ++packet_type_counter_.nack_packets;
+
+  return std::unique_ptr<rtcp::RtcpPacket>(nack);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildBYE(const RtcpContext& ctx) {
+  rtcp::Bye* bye = new rtcp::Bye();
+  bye->SetSenderSsrc(ssrc_);
+  bye->SetCsrcs(csrcs_);
+
+  return std::unique_ptr<rtcp::RtcpPacket>(bye);
+}
+
+std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildExtendedReports(
+    const RtcpContext& ctx) {
+  std::unique_ptr<rtcp::ExtendedReports> xr(new rtcp::ExtendedReports());
+  xr->SetSenderSsrc(ssrc_);
+
+  if (!sending_ && xr_send_receiver_reference_time_enabled_) {
+    rtcp::Rrtr rrtr;
+    rrtr.SetNtp(ctx.now_);
+    xr->SetRrtr(rrtr);
+  }
+
+  for (const rtcp::ReceiveTimeInfo& rti : ctx.feedback_state_.last_xr_rtis) {
+    xr->AddDlrrItem(rti);
+  }
+
+  if (video_bitrate_allocation_) {
+    rtcp::TargetBitrate target_bitrate;
+
+    for (int sl = 0; sl < kMaxSpatialLayers; ++sl) {
+      for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
+        if (video_bitrate_allocation_->HasBitrate(sl, tl)) {
+          target_bitrate.AddTargetBitrate(
+              sl, tl, video_bitrate_allocation_->GetBitrate(sl, tl) / 1000);
+        }
+      }
+    }
+
+    xr->SetTargetBitrate(target_bitrate);
+    video_bitrate_allocation_.reset();
+  }
+
+  if (xr_voip_metric_) {
+    rtcp::VoipMetric voip;
+    voip.SetMediaSsrc(remote_ssrc_);
+    voip.SetVoipMetric(*xr_voip_metric_);
+    xr_voip_metric_.reset();
+
+    xr->SetVoipMetric(voip);
+  }
+
+  return std::move(xr);
+}
+
+int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
+                             RTCPPacketType packetType,
+                             int32_t nack_size,
+                             const uint16_t* nack_list) {
+  return SendCompoundRTCP(
+      feedback_state, std::set<RTCPPacketType>(&packetType, &packetType + 1),
+      nack_size, nack_list);
+}
+
+int32_t RTCPSender::SendCompoundRTCP(
+    const FeedbackState& feedback_state,
+    const std::set<RTCPPacketType>& packet_types,
+    int32_t nack_size,
+    const uint16_t* nack_list) {
+  PacketContainer container(transport_, event_log_);
+  size_t max_packet_size;
+
+  {
+    rtc::CritScope lock(&critical_section_rtcp_sender_);
+    if (method_ == RtcpMode::kOff) {
+      RTC_LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
+      return -1;
+    }
+    // Add all flags as volatile. Non volatile entries will not be overwritten.
+    // All new volatile flags added will be consumed by the end of this call.
+    SetFlags(packet_types, true);
+
+    // Prevent sending streams to send SR before any media has been sent.
+    const bool can_calculate_rtp_timestamp = (last_frame_capture_time_ms_ >= 0);
+    if (!can_calculate_rtp_timestamp) {
+      bool consumed_sr_flag = ConsumeFlag(kRtcpSr);
+      bool consumed_report_flag = sending_ && ConsumeFlag(kRtcpReport);
+      bool sender_report = consumed_report_flag || consumed_sr_flag;
+      if (sender_report && AllVolatileFlagsConsumed()) {
+        // This call was for Sender Report and nothing else.
+        return 0;
+      }
+      if (sending_ && method_ == RtcpMode::kCompound) {
+        // Not allowed to send any RTCP packet without sender report.
+        return -1;
+      }
+    }
+
+    if (packet_type_counter_.first_packet_time_ms == -1)
+      packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds();
+
+    // We need to send our NTP even if we haven't received any reports.
+    RtcpContext context(feedback_state, nack_size, nack_list,
+                        clock_->CurrentNtpTime());
+
+    PrepareReport(feedback_state);
+
+    std::unique_ptr<rtcp::RtcpPacket> packet_bye;
+
+    auto it = report_flags_.begin();
+    while (it != report_flags_.end()) {
+      auto builder_it = builders_.find(it->type);
+      RTC_DCHECK(builder_it != builders_.end())
+          << "Could not find builder for packet type " << it->type;
+      if (it->is_volatile) {
+        report_flags_.erase(it++);
+      } else {
+        ++it;
+      }
+
+      BuilderFunc func = builder_it->second;
+      std::unique_ptr<rtcp::RtcpPacket> packet = (this->*func)(context);
+      if (packet.get() == nullptr)
+        return -1;
+      // If there is a BYE, don't append now - save it and append it
+      // at the end later.
+      if (builder_it->first == kRtcpBye) {
+        packet_bye = std::move(packet);
+      } else {
+        container.Append(packet.release());
+      }
+    }
+
+    // Append the BYE now at the end
+    if (packet_bye) {
+      container.Append(packet_bye.release());
+    }
+
+    if (packet_type_counter_observer_ != nullptr) {
+      packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
+          remote_ssrc_, packet_type_counter_);
+    }
+
+    RTC_DCHECK(AllVolatileFlagsConsumed());
+    max_packet_size = max_packet_size_;
+  }
+
+  size_t bytes_sent = container.SendPackets(max_packet_size);
+  return bytes_sent == 0 ? -1 : 0;
+}
+
+void RTCPSender::PrepareReport(const FeedbackState& feedback_state) {
+  bool generate_report;
+  if (IsFlagPresent(kRtcpSr) || IsFlagPresent(kRtcpRr)) {
+    // Report type already explicitly set, don't automatically populate.
+    generate_report = true;
+    RTC_DCHECK(ConsumeFlag(kRtcpReport) == false);
+  } else {
+    generate_report =
+        (ConsumeFlag(kRtcpReport) && method_ == RtcpMode::kReducedSize) ||
+        method_ == RtcpMode::kCompound;
+    if (generate_report)
+      SetFlag(sending_ ? kRtcpSr : kRtcpRr, true);
+  }
+
+  if (IsFlagPresent(kRtcpSr) || (IsFlagPresent(kRtcpRr) && !cname_.empty()))
+    SetFlag(kRtcpSdes, true);
+
+  if (generate_report) {
+    if ((!sending_ && xr_send_receiver_reference_time_enabled_) ||
+        !feedback_state.last_xr_rtis.empty() || video_bitrate_allocation_) {
+      SetFlag(kRtcpAnyExtendedReports, true);
+    }
+
+    // generate next time to send an RTCP report
+    uint32_t minIntervalMs =
+        rtc::dchecked_cast<uint32_t>(interval_config_.audio_interval_ms);
+
+    if (!audio_) {
+      if (sending_) {
+        // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
+        uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
+        if (send_bitrate_kbit != 0)
+          minIntervalMs = 360000 / send_bitrate_kbit;
+      }
+      if (minIntervalMs >
+          rtc::dchecked_cast<uint32_t>(interval_config_.video_interval_ms)) {
+        minIntervalMs =
+            rtc::dchecked_cast<uint32_t>(interval_config_.video_interval_ms);
+      }
+    }
+
+    // The interval between RTCP packets is varied randomly over the
+    // range [1/2,3/2] times the calculated interval.
+    uint32_t timeToNext =
+        random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2);
+    next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext;
+
+    // RtcpSender expected to be used for sending either just sender reports
+    // or just receiver reports.
+    RTC_DCHECK(!(IsFlagPresent(kRtcpSr) && IsFlagPresent(kRtcpRr)));
+  }
+}
+
+std::vector<rtcp::ReportBlock> RTCPSender::CreateReportBlocks(
+    const FeedbackState& feedback_state) {
+  std::vector<rtcp::ReportBlock> result;
+  if (!receive_statistics_)
+    return result;
+
+  // TODO(danilchap): Support sending more than |RTCP_MAX_REPORT_BLOCKS| per
+  // compound rtcp packet when single rtcp module is used for multiple media
+  // streams.
+  result = receive_statistics_->RtcpReportBlocks(RTCP_MAX_REPORT_BLOCKS);
+
+  if (!result.empty() && ((feedback_state.last_rr_ntp_secs != 0) ||
+                          (feedback_state.last_rr_ntp_frac != 0))) {
+    // Get our NTP as late as possible to avoid a race.
+    uint32_t now = CompactNtp(clock_->CurrentNtpTime());
+
+    uint32_t receive_time = feedback_state.last_rr_ntp_secs & 0x0000FFFF;
+    receive_time <<= 16;
+    receive_time += (feedback_state.last_rr_ntp_frac & 0xffff0000) >> 16;
+
+    uint32_t delay_since_last_sr = now - receive_time;
+    // TODO(danilchap): Instead of setting same value on all report blocks,
+    // set only when media_ssrc match sender ssrc of the sender report
+    // remote times were taken from.
+    for (auto& report_block : result) {
+      report_block.SetLastSr(feedback_state.remote_sr);
+      report_block.SetDelayLastSr(delay_since_last_sr);
+    }
+  }
+  return result;
+}
+
+void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
+  RTC_DCHECK_LE(csrcs.size(), kRtpCsrcSize);
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  csrcs_ = csrcs;
+}
+
+int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
+                                               uint32_t name,
+                                               const uint8_t* data,
+                                               uint16_t length) {
+  if (length % 4 != 0) {
+    RTC_LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
+    return -1;
+  }
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+
+  SetFlag(kRtcpApp, true);
+  app_sub_type_ = subType;
+  app_name_ = name;
+  app_data_.reset(new uint8_t[length]);
+  app_length_ = length;
+  memcpy(app_data_.get(), data, length);
+  return 0;
+}
+
+// TODO(sprang): Remove support for VoIP metrics? (Not used in receiver.)
+int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  xr_voip_metric_.emplace(*VoIPMetric);
+
+  SetFlag(kRtcpAnyExtendedReports, true);
+  return 0;
+}
+
+void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  xr_send_receiver_reference_time_enabled_ = enable;
+}
+
+bool RTCPSender::RtcpXrReceiverReferenceTime() const {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  return xr_send_receiver_reference_time_enabled_;
+}
+
+void RTCPSender::SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  tmmbn_to_send_ = std::move(bounding_set);
+  SetFlag(kRtcpTmmbn, true);
+}
+
+void RTCPSender::SetFlag(uint32_t type, bool is_volatile) {
+  if (type & kRtcpAnyExtendedReports) {
+    report_flags_.insert(ReportFlag(kRtcpAnyExtendedReports, is_volatile));
+  } else {
+    report_flags_.insert(ReportFlag(type, is_volatile));
+  }
+}
+
+void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
+                          bool is_volatile) {
+  for (RTCPPacketType type : types)
+    SetFlag(type, is_volatile);
+}
+
+bool RTCPSender::IsFlagPresent(uint32_t type) const {
+  return report_flags_.find(ReportFlag(type, false)) != report_flags_.end();
+}
+
+bool RTCPSender::ConsumeFlag(uint32_t type, bool forced) {
+  auto it = report_flags_.find(ReportFlag(type, false));
+  if (it == report_flags_.end())
+    return false;
+  if (it->is_volatile || forced)
+    report_flags_.erase((it));
+  return true;
+}
+
+bool RTCPSender::AllVolatileFlagsConsumed() const {
+  for (const ReportFlag& flag : report_flags_) {
+    if (flag.is_volatile)
+      return false;
+  }
+  return true;
+}
+
+void RTCPSender::SetVideoBitrateAllocation(
+    const VideoBitrateAllocation& bitrate) {
+  rtc::CritScope lock(&critical_section_rtcp_sender_);
+  video_bitrate_allocation_.emplace(bitrate);
+  SetFlag(kRtcpAnyExtendedReports, true);
+}
+
+bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
+  size_t max_packet_size;
+  {
+    rtc::CritScope lock(&critical_section_rtcp_sender_);
+    if (method_ == RtcpMode::kOff)
+      return false;
+    max_packet_size = max_packet_size_;
+  }
+
+  RTC_DCHECK_LE(max_packet_size, IP_PACKET_SIZE);
+  bool send_failure = false;
+  auto callback = [&](rtc::ArrayView<const uint8_t> packet) {
+    if (transport_->SendRtcp(packet.data(), packet.size())) {
+      if (event_log_)
+        event_log_->Log(absl::make_unique<RtcEventRtcpPacketOutgoing>(packet));
+    } else {
+      send_failure = true;
+    }
+  };
+  return packet.Build(max_packet_size, callback) && !send_failure;
+}
+
+int64_t RTCPSender::RtcpAudioReportInverval() const {
+  return interval_config_.audio_interval_ms;
+}
+
+int64_t RTCPSender::RtcpVideoReportInverval() const {
+  return interval_config_.video_interval_ms;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h
new file mode 100644
index 0000000..e274915
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_sender.h
@@ -0,0 +1,283 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_SENDER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_SENDER_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/call/transport.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
+#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_nack_stats.h"
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/random.h"
+#include "rtc_base/thread_annotations.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class ModuleRtpRtcpImpl;
+class RtcEventLog;
+
+class RTCPSender {
+ public:
+  struct FeedbackState {
+    FeedbackState();
+    FeedbackState(const FeedbackState&);
+    FeedbackState(FeedbackState&&);
+
+    ~FeedbackState();
+
+    uint32_t packets_sent;
+    size_t media_bytes_sent;
+    uint32_t send_bitrate;
+
+    uint32_t last_rr_ntp_secs;
+    uint32_t last_rr_ntp_frac;
+    uint32_t remote_sr;
+
+    std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis;
+
+    // Used when generating TMMBR.
+    ModuleRtpRtcpImpl* module;
+  };
+
+  RTCPSender(bool audio,
+             Clock* clock,
+             ReceiveStatisticsProvider* receive_statistics,
+             RtcpPacketTypeCounterObserver* packet_type_counter_observer,
+             RtcEventLog* event_log,
+             Transport* outgoing_transport,
+             RtcpIntervalConfig interval_config);
+  virtual ~RTCPSender();
+
+  RtcpMode Status() const;
+  void SetRTCPStatus(RtcpMode method);
+
+  bool Sending() const;
+  int32_t SetSendingStatus(const FeedbackState& feedback_state,
+                           bool enabled);  // combine the functions
+
+  int32_t SetNackStatus(bool enable);
+
+  void SetTimestampOffset(uint32_t timestamp_offset);
+
+  void SetLastRtpTime(uint32_t rtp_timestamp, int64_t capture_time_ms);
+
+  uint32_t SSRC() const;
+
+  void SetSSRC(uint32_t ssrc);
+
+  void SetRemoteSSRC(uint32_t ssrc);
+
+  int32_t SetCNAME(const char* cName);
+
+  int32_t AddMixedCNAME(uint32_t SSRC, const char* c_name);
+
+  int32_t RemoveMixedCNAME(uint32_t SSRC);
+
+  bool TimeToSendRTCPReport(bool sendKeyframeBeforeRTP = false) const;
+
+  int32_t SendRTCP(const FeedbackState& feedback_state,
+                   RTCPPacketType packetType,
+                   int32_t nackSize = 0,
+                   const uint16_t* nackList = 0);
+
+  int32_t SendCompoundRTCP(const FeedbackState& feedback_state,
+                           const std::set<RTCPPacketType>& packetTypes,
+                           int32_t nackSize = 0,
+                           const uint16_t* nackList = 0);
+
+  void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs);
+
+  void UnsetRemb();
+
+  bool TMMBR() const;
+
+  void SetTMMBRStatus(bool enable);
+
+  void SetMaxRtpPacketSize(size_t max_packet_size);
+
+  void SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set);
+
+  int32_t SetApplicationSpecificData(uint8_t subType,
+                                     uint32_t name,
+                                     const uint8_t* data,
+                                     uint16_t length);
+  int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric);
+
+  void SendRtcpXrReceiverReferenceTime(bool enable);
+
+  bool RtcpXrReceiverReferenceTime() const;
+
+  void SetCsrcs(const std::vector<uint32_t>& csrcs);
+
+  void SetTargetBitrate(unsigned int target_bitrate);
+  void SetVideoBitrateAllocation(const VideoBitrateAllocation& bitrate);
+  bool SendFeedbackPacket(const rtcp::TransportFeedback& packet);
+
+  int64_t RtcpAudioReportInverval() const;
+  int64_t RtcpVideoReportInverval() const;
+
+ private:
+  class RtcpContext;
+
+  // Determine which RTCP messages should be sent and setup flags.
+  void PrepareReport(const FeedbackState& feedback_state)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+
+  std::vector<rtcp::ReportBlock> CreateReportBlocks(
+      const FeedbackState& feedback_state)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+
+  std::unique_ptr<rtcp::RtcpPacket> BuildSR(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildRR(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildSDES(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildPLI(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildREMB(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildTMMBR(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildTMMBN(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildAPP(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildExtendedReports(
+      const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildBYE(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildFIR(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  std::unique_ptr<rtcp::RtcpPacket> BuildNACK(const RtcpContext& context)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+
+ private:
+  const bool audio_;
+  Clock* const clock_;
+  Random random_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  RtcpMode method_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  RtcEventLog* const event_log_;
+  Transport* const transport_;
+
+  const RtcpIntervalConfig interval_config_;
+
+  rtc::CriticalSection critical_section_rtcp_sender_;
+  bool using_nack_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  bool sending_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  int64_t next_time_to_send_rtcp_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  uint32_t timestamp_offset_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  int64_t last_frame_capture_time_ms_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  uint32_t ssrc_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  // SSRC that we receive on our RTP channel
+  uint32_t remote_ssrc_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  std::string cname_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  ReceiveStatisticsProvider* receive_statistics_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  std::map<uint32_t, std::string> csrc_cnames_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  // send CSRCs
+  std::vector<uint32_t> csrcs_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  // Full intra request
+  uint8_t sequence_number_fir_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  // REMB
+  int64_t remb_bitrate_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  std::vector<uint32_t> remb_ssrcs_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  std::vector<rtcp::TmmbItem> tmmbn_to_send_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  uint32_t tmmbr_send_bps_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  uint32_t packet_oh_send_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  size_t max_packet_size_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  // APP
+  uint8_t app_sub_type_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  uint32_t app_name_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  std::unique_ptr<uint8_t[]> app_data_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+  uint16_t app_length_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  // True if sending of XR Receiver reference time report is enabled.
+  bool xr_send_receiver_reference_time_enabled_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  // XR VoIP metric
+  absl::optional<RTCPVoIPMetric> xr_voip_metric_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  RtcpPacketTypeCounterObserver* const packet_type_counter_observer_;
+  RtcpPacketTypeCounter packet_type_counter_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  RtcpNackStats nack_stats_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  absl::optional<VideoBitrateAllocation> video_bitrate_allocation_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  void SetFlag(uint32_t type, bool is_volatile)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  void SetFlags(const std::set<RTCPPacketType>& types, bool is_volatile)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  bool IsFlagPresent(uint32_t type) const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  bool ConsumeFlag(uint32_t type, bool forced = false)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  bool AllVolatileFlagsConsumed() const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
+  struct ReportFlag {
+    ReportFlag(uint32_t type, bool is_volatile)
+        : type(type), is_volatile(is_volatile) {}
+    bool operator<(const ReportFlag& flag) const { return type < flag.type; }
+    bool operator==(const ReportFlag& flag) const { return type == flag.type; }
+    const uint32_t type;
+    const bool is_volatile;
+  };
+
+  std::set<ReportFlag> report_flags_
+      RTC_GUARDED_BY(critical_section_rtcp_sender_);
+
+  typedef std::unique_ptr<rtcp::RtcpPacket> (RTCPSender::*BuilderFunc)(
+      const RtcpContext&);
+  // Map from RTCPPacketType to builder.
+  std::map<uint32_t, BuilderFunc> builders_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTCPSender);
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_SENDER_H_
diff --git a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
new file mode 100644
index 0000000..974f19f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
@@ -0,0 +1,703 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <memory>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h"
+#include "rtc_base/rate_limiter.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/mock_transport.h"
+#include "test/rtcp_packet_parser.h"
+
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::Invoke;
+using ::testing::SizeIs;
+
+namespace webrtc {
+
+class RtcpPacketTypeCounterObserverImpl : public RtcpPacketTypeCounterObserver {
+ public:
+  RtcpPacketTypeCounterObserverImpl() : ssrc_(0) {}
+  ~RtcpPacketTypeCounterObserverImpl() override = default;
+  void RtcpPacketTypesCounterUpdated(
+      uint32_t ssrc,
+      const RtcpPacketTypeCounter& packet_counter) override {
+    ssrc_ = ssrc;
+    counter_ = packet_counter;
+  }
+  uint32_t ssrc_;
+  RtcpPacketTypeCounter counter_;
+};
+
+class TestTransport : public Transport, public RtpData {
+ public:
+  TestTransport() {}
+
+  bool SendRtp(const uint8_t* /*data*/,
+               size_t /*len*/,
+               const PacketOptions& options) override {
+    return false;
+  }
+  bool SendRtcp(const uint8_t* data, size_t len) override {
+    parser_.Parse(data, len);
+    return true;
+  }
+  int OnReceivedPayloadData(const uint8_t* payload_data,
+                            size_t payload_size,
+                            const WebRtcRTPHeader* rtp_header) override {
+    return 0;
+  }
+  test::RtcpPacketParser parser_;
+};
+
+namespace {
+static const uint32_t kSenderSsrc = 0x11111111;
+static const uint32_t kRemoteSsrc = 0x22222222;
+static const uint32_t kStartRtpTimestamp = 0x34567;
+static const uint32_t kRtpTimestamp = 0x45678;
+}  // namespace
+
+class RtcpSenderTest : public ::testing::Test {
+ protected:
+  RtcpSenderTest()
+      : clock_(1335900000),
+        receive_statistics_(ReceiveStatistics::Create(&clock_)),
+        retransmission_rate_limiter_(&clock_, 1000) {
+    RtpRtcp::Configuration configuration;
+    configuration.audio = false;
+    configuration.clock = &clock_;
+    configuration.outgoing_transport = &test_transport_;
+    configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
+
+    rtp_rtcp_impl_.reset(new ModuleRtpRtcpImpl(configuration));
+    rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
+                                      nullptr, nullptr, &test_transport_,
+                                      configuration.rtcp_interval_config));
+    rtcp_sender_->SetSSRC(kSenderSsrc);
+    rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
+    rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
+    rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds());
+  }
+
+  void InsertIncomingPacket(uint32_t remote_ssrc, uint16_t seq_num) {
+    RTPHeader header;
+    header.ssrc = remote_ssrc;
+    header.sequenceNumber = seq_num;
+    header.timestamp = 12345;
+    header.headerLength = 12;
+    size_t kPacketLength = 100;
+    receive_statistics_->IncomingPacket(header, kPacketLength, false);
+  }
+
+  test::RtcpPacketParser* parser() { return &test_transport_.parser_; }
+
+  RTCPSender::FeedbackState feedback_state() {
+    return rtp_rtcp_impl_->GetFeedbackState();
+  }
+
+  SimulatedClock clock_;
+  TestTransport test_transport_;
+  std::unique_ptr<ReceiveStatistics> receive_statistics_;
+  std::unique_ptr<ModuleRtpRtcpImpl> rtp_rtcp_impl_;
+  std::unique_ptr<RTCPSender> rtcp_sender_;
+  RateLimiter retransmission_rate_limiter_;
+};
+
+TEST_F(RtcpSenderTest, SetRtcpStatus) {
+  EXPECT_EQ(RtcpMode::kOff, rtcp_sender_->Status());
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(RtcpMode::kReducedSize, rtcp_sender_->Status());
+}
+
+TEST_F(RtcpSenderTest, SetSendingStatus) {
+  EXPECT_FALSE(rtcp_sender_->Sending());
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true));
+  EXPECT_TRUE(rtcp_sender_->Sending());
+}
+
+TEST_F(RtcpSenderTest, NoPacketSentIfOff) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kOff);
+  EXPECT_EQ(-1, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr));
+}
+
+TEST_F(RtcpSenderTest, SendSr) {
+  const uint32_t kPacketCount = 0x12345;
+  const uint32_t kOctetCount = 0x23456;
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
+  rtcp_sender_->SetSendingStatus(feedback_state, true);
+  feedback_state.packets_sent = kPacketCount;
+  feedback_state.media_bytes_sent = kOctetCount;
+  NtpTime ntp = clock_.CurrentNtpTime();
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpSr));
+  EXPECT_EQ(1, parser()->sender_report()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->sender_report()->sender_ssrc());
+  EXPECT_EQ(ntp, parser()->sender_report()->ntp());
+  EXPECT_EQ(kPacketCount, parser()->sender_report()->sender_packet_count());
+  EXPECT_EQ(kOctetCount, parser()->sender_report()->sender_octet_count());
+  EXPECT_EQ(kStartRtpTimestamp + kRtpTimestamp,
+            parser()->sender_report()->rtp_timestamp());
+  EXPECT_EQ(0U, parser()->sender_report()->report_blocks().size());
+}
+
+TEST_F(RtcpSenderTest, DoNotSendSrBeforeRtp) {
+  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
+                                    nullptr, nullptr, &test_transport_,
+                                    RtcpIntervalConfig{}));
+  rtcp_sender_->SetSSRC(kSenderSsrc);
+  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  rtcp_sender_->SetSendingStatus(feedback_state(), true);
+
+  // Sender Report shouldn't be send as an SR nor as a Report.
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr);
+  EXPECT_EQ(0, parser()->sender_report()->num_packets());
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport);
+  EXPECT_EQ(0, parser()->sender_report()->num_packets());
+  // Other packets (e.g. Pli) are allowed, even if useless.
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
+  EXPECT_EQ(1, parser()->pli()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, DoNotSendCompundBeforeRtp) {
+  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
+                                    nullptr, nullptr, &test_transport_,
+                                    RtcpIntervalConfig{}));
+  rtcp_sender_->SetSSRC(kSenderSsrc);
+  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  rtcp_sender_->SetSendingStatus(feedback_state(), true);
+
+  // In compound mode no packets are allowed (e.g. Pli) because compound mode
+  // should start with Sender Report.
+  EXPECT_EQ(-1, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
+  EXPECT_EQ(0, parser()->pli()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, SendRr) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr));
+  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc());
+  EXPECT_EQ(0U, parser()->receiver_report()->report_blocks().size());
+}
+
+TEST_F(RtcpSenderTest, SendRrWithOneReportBlock) {
+  const uint16_t kSeqNum = 11111;
+  InsertIncomingPacket(kRemoteSsrc, kSeqNum);
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr));
+  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc());
+  ASSERT_EQ(1U, parser()->receiver_report()->report_blocks().size());
+  const rtcp::ReportBlock& rb = parser()->receiver_report()->report_blocks()[0];
+  EXPECT_EQ(kRemoteSsrc, rb.source_ssrc());
+  EXPECT_EQ(0U, rb.fraction_lost());
+  EXPECT_EQ(0, rb.cumulative_lost_signed());
+  EXPECT_EQ(kSeqNum, rb.extended_high_seq_num());
+}
+
+TEST_F(RtcpSenderTest, SendRrWithTwoReportBlocks) {
+  const uint16_t kSeqNum = 11111;
+  InsertIncomingPacket(kRemoteSsrc, kSeqNum);
+  InsertIncomingPacket(kRemoteSsrc + 1, kSeqNum + 1);
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr));
+  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->receiver_report()->sender_ssrc());
+  EXPECT_EQ(2U, parser()->receiver_report()->report_blocks().size());
+  EXPECT_EQ(kRemoteSsrc,
+            parser()->receiver_report()->report_blocks()[0].source_ssrc());
+  EXPECT_EQ(kRemoteSsrc + 1,
+            parser()->receiver_report()->report_blocks()[1].source_ssrc());
+}
+
+TEST_F(RtcpSenderTest, SendSdes) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host"));
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSdes));
+  EXPECT_EQ(1, parser()->sdes()->num_packets());
+  EXPECT_EQ(1U, parser()->sdes()->chunks().size());
+  EXPECT_EQ(kSenderSsrc, parser()->sdes()->chunks()[0].ssrc);
+  EXPECT_EQ("alice@host", parser()->sdes()->chunks()[0].cname);
+}
+
+TEST_F(RtcpSenderTest, SendSdesWithMaxChunks) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host"));
+  const char cname[] = "smith@host";
+  for (size_t i = 0; i < 30; ++i) {
+    const uint32_t csrc = 0x1234 + i;
+    EXPECT_EQ(0, rtcp_sender_->AddMixedCNAME(csrc, cname));
+  }
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSdes));
+  EXPECT_EQ(1, parser()->sdes()->num_packets());
+  EXPECT_EQ(31U, parser()->sdes()->chunks().size());
+}
+
+TEST_F(RtcpSenderTest, SdesIncludedInCompoundPacket) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_EQ(0, rtcp_sender_->SetCNAME("alice@host"));
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(1, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(1, parser()->sdes()->num_packets());
+  EXPECT_EQ(1U, parser()->sdes()->chunks().size());
+}
+
+TEST_F(RtcpSenderTest, SendBye) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
+  EXPECT_EQ(1, parser()->bye()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc());
+}
+
+TEST_F(RtcpSenderTest, StopSendingTriggersBye) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true));
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
+  EXPECT_EQ(1, parser()->bye()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->bye()->sender_ssrc());
+}
+
+TEST_F(RtcpSenderTest, SendApp) {
+  const uint8_t kSubType = 30;
+  uint32_t name = 'n' << 24;
+  name += 'a' << 16;
+  name += 'm' << 8;
+  name += 'e';
+  const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
+  EXPECT_EQ(0, rtcp_sender_->SetApplicationSpecificData(kSubType, name, kData,
+                                                        sizeof(kData)));
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpApp));
+  EXPECT_EQ(1, parser()->app()->num_packets());
+  EXPECT_EQ(kSubType, parser()->app()->sub_type());
+  EXPECT_EQ(name, parser()->app()->name());
+  EXPECT_EQ(sizeof(kData), parser()->app()->data_size());
+  EXPECT_EQ(0, memcmp(kData, parser()->app()->data(), sizeof(kData)));
+}
+
+TEST_F(RtcpSenderTest, SendEmptyApp) {
+  const uint8_t kSubType = 30;
+  const uint32_t kName = 0x6E616D65;
+
+  EXPECT_EQ(
+      0, rtcp_sender_->SetApplicationSpecificData(kSubType, kName, nullptr, 0));
+
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpApp));
+  EXPECT_EQ(1, parser()->app()->num_packets());
+  EXPECT_EQ(kSubType, parser()->app()->sub_type());
+  EXPECT_EQ(kName, parser()->app()->name());
+  EXPECT_EQ(0U, parser()->app()->data_size());
+}
+
+TEST_F(RtcpSenderTest, SetInvalidApplicationSpecificData) {
+  const uint8_t kData[] = {'t', 'e', 's', 't', 'd', 'a', 't'};
+  const uint16_t kInvalidDataLength = sizeof(kData) / sizeof(kData[0]);
+  EXPECT_EQ(-1,
+            rtcp_sender_->SetApplicationSpecificData(
+                0, 0, kData, kInvalidDataLength));  // Should by multiple of 4.
+}
+
+TEST_F(RtcpSenderTest, SendFir) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir));
+  EXPECT_EQ(1, parser()->fir()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->fir()->sender_ssrc());
+  EXPECT_EQ(1U, parser()->fir()->requests().size());
+  EXPECT_EQ(kRemoteSsrc, parser()->fir()->requests()[0].ssrc);
+  uint8_t seq = parser()->fir()->requests()[0].seq_nr;
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpFir));
+  EXPECT_EQ(2, parser()->fir()->num_packets());
+  EXPECT_EQ(seq + 1, parser()->fir()->requests()[0].seq_nr);
+}
+
+TEST_F(RtcpSenderTest, SendPli) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
+  EXPECT_EQ(1, parser()->pli()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->pli()->sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, parser()->pli()->media_ssrc());
+}
+
+TEST_F(RtcpSenderTest, SendNack) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  const uint16_t kList[] = {0, 1, 16};
+  const int32_t kListLength = sizeof(kList) / sizeof(kList[0]);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpNack, kListLength,
+                                      kList));
+  EXPECT_EQ(1, parser()->nack()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->nack()->sender_ssrc());
+  EXPECT_EQ(kRemoteSsrc, parser()->nack()->media_ssrc());
+  EXPECT_THAT(parser()->nack()->packet_ids(), ElementsAre(0, 1, 16));
+}
+
+TEST_F(RtcpSenderTest, RembNotIncludedBeforeSet) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr);
+
+  ASSERT_EQ(1, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(0, parser()->remb()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, RembNotIncludedAfterUnset) {
+  const uint64_t kBitrate = 261011;
+  const std::vector<uint32_t> kSsrcs = {kRemoteSsrc, kRemoteSsrc + 1};
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  rtcp_sender_->SetRemb(kBitrate, kSsrcs);
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr);
+  ASSERT_EQ(1, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(1, parser()->remb()->num_packets());
+
+  // Turn off REMB. rtcp_sender no longer should send it.
+  rtcp_sender_->UnsetRemb();
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpRr);
+  ASSERT_EQ(2, parser()->receiver_report()->num_packets());
+  EXPECT_EQ(1, parser()->remb()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, SendRemb) {
+  const uint64_t kBitrate = 261011;
+  const std::vector<uint32_t> kSsrcs = {kRemoteSsrc, kRemoteSsrc + 1};
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  rtcp_sender_->SetRemb(kBitrate, kSsrcs);
+
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpRemb);
+
+  EXPECT_EQ(1, parser()->remb()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->remb()->sender_ssrc());
+  EXPECT_EQ(kBitrate, parser()->remb()->bitrate_bps());
+  EXPECT_THAT(parser()->remb()->ssrcs(),
+              ElementsAre(kRemoteSsrc, kRemoteSsrc + 1));
+}
+
+TEST_F(RtcpSenderTest, RembIncludedInEachCompoundPacketAfterSet) {
+  const int kBitrate = 261011;
+  const std::vector<uint32_t> kSsrcs = {kRemoteSsrc, kRemoteSsrc + 1};
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  rtcp_sender_->SetRemb(kBitrate, kSsrcs);
+
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport);
+  EXPECT_EQ(1, parser()->remb()->num_packets());
+  // REMB should be included in each compound packet.
+  rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport);
+  EXPECT_EQ(2, parser()->remb()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, SendXrWithVoipMetric) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  RTCPVoIPMetric metric;
+  metric.lossRate = 1;
+  metric.discardRate = 2;
+  metric.burstDensity = 3;
+  metric.gapDensity = 4;
+  metric.burstDuration = 0x1111;
+  metric.gapDuration = 0x2222;
+  metric.roundTripDelay = 0x3333;
+  metric.endSystemDelay = 0x4444;
+  metric.signalLevel = 5;
+  metric.noiseLevel = 6;
+  metric.RERL = 7;
+  metric.Gmin = 8;
+  metric.Rfactor = 9;
+  metric.extRfactor = 10;
+  metric.MOSLQ = 11;
+  metric.MOSCQ = 12;
+  metric.RXconfig = 13;
+  metric.JBnominal = 0x5555;
+  metric.JBmax = 0x6666;
+  metric.JBabsMax = 0x7777;
+  EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric));
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpXrVoipMetric));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  ASSERT_TRUE(parser()->xr()->voip_metric());
+  EXPECT_EQ(kRemoteSsrc, parser()->xr()->voip_metric()->ssrc());
+  const auto& parsed_metric = parser()->xr()->voip_metric()->voip_metric();
+  EXPECT_EQ(metric.lossRate, parsed_metric.lossRate);
+  EXPECT_EQ(metric.discardRate, parsed_metric.discardRate);
+  EXPECT_EQ(metric.burstDensity, parsed_metric.burstDensity);
+  EXPECT_EQ(metric.gapDensity, parsed_metric.gapDensity);
+  EXPECT_EQ(metric.burstDuration, parsed_metric.burstDuration);
+  EXPECT_EQ(metric.gapDuration, parsed_metric.gapDuration);
+  EXPECT_EQ(metric.roundTripDelay, parsed_metric.roundTripDelay);
+  EXPECT_EQ(metric.endSystemDelay, parsed_metric.endSystemDelay);
+  EXPECT_EQ(metric.signalLevel, parsed_metric.signalLevel);
+  EXPECT_EQ(metric.noiseLevel, parsed_metric.noiseLevel);
+  EXPECT_EQ(metric.RERL, parsed_metric.RERL);
+  EXPECT_EQ(metric.Gmin, parsed_metric.Gmin);
+  EXPECT_EQ(metric.Rfactor, parsed_metric.Rfactor);
+  EXPECT_EQ(metric.extRfactor, parsed_metric.extRfactor);
+  EXPECT_EQ(metric.MOSLQ, parsed_metric.MOSLQ);
+  EXPECT_EQ(metric.MOSCQ, parsed_metric.MOSCQ);
+  EXPECT_EQ(metric.RXconfig, parsed_metric.RXconfig);
+  EXPECT_EQ(metric.JBnominal, parsed_metric.JBnominal);
+  EXPECT_EQ(metric.JBmax, parsed_metric.JBmax);
+  EXPECT_EQ(metric.JBabsMax, parsed_metric.JBabsMax);
+}
+
+TEST_F(RtcpSenderTest, SendXrWithDlrr) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
+  rtcp::ReceiveTimeInfo last_xr_rr;
+  last_xr_rr.ssrc = 0x11111111;
+  last_xr_rr.last_rr = 0x22222222;
+  last_xr_rr.delay_since_last_rr = 0x33333333;
+  feedback_state.last_xr_rtis.push_back(last_xr_rr);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  ASSERT_THAT(parser()->xr()->dlrr().sub_blocks(), SizeIs(1));
+  EXPECT_EQ(last_xr_rr.ssrc, parser()->xr()->dlrr().sub_blocks()[0].ssrc);
+  EXPECT_EQ(last_xr_rr.last_rr, parser()->xr()->dlrr().sub_blocks()[0].last_rr);
+  EXPECT_EQ(last_xr_rr.delay_since_last_rr,
+            parser()->xr()->dlrr().sub_blocks()[0].delay_since_last_rr);
+}
+
+TEST_F(RtcpSenderTest, SendXrWithMultipleDlrrSubBlocks) {
+  const size_t kNumReceivers = 2;
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
+  for (size_t i = 0; i < kNumReceivers; ++i) {
+    rtcp::ReceiveTimeInfo last_xr_rr;
+    last_xr_rr.ssrc = i;
+    last_xr_rr.last_rr = (i + 1) * 100;
+    last_xr_rr.delay_since_last_rr = (i + 2) * 200;
+    feedback_state.last_xr_rtis.push_back(last_xr_rr);
+  }
+
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  ASSERT_THAT(parser()->xr()->dlrr().sub_blocks(), SizeIs(kNumReceivers));
+  for (size_t i = 0; i < kNumReceivers; ++i) {
+    EXPECT_EQ(feedback_state.last_xr_rtis[i].ssrc,
+              parser()->xr()->dlrr().sub_blocks()[i].ssrc);
+    EXPECT_EQ(feedback_state.last_xr_rtis[i].last_rr,
+              parser()->xr()->dlrr().sub_blocks()[i].last_rr);
+    EXPECT_EQ(feedback_state.last_xr_rtis[i].delay_since_last_rr,
+              parser()->xr()->dlrr().sub_blocks()[i].delay_since_last_rr);
+  }
+}
+
+TEST_F(RtcpSenderTest, SendXrWithRrtr) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
+  NtpTime ntp = clock_.CurrentNtpTime();
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  EXPECT_FALSE(parser()->xr()->dlrr());
+  EXPECT_FALSE(parser()->xr()->voip_metric());
+  ASSERT_TRUE(parser()->xr()->rrtr());
+  EXPECT_EQ(ntp, parser()->xr()->rrtr()->ntp());
+}
+
+TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfSending) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), true));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(0, parser()->xr()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfNotEnabled) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(false);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(0, parser()->xr()->num_packets());
+}
+
+TEST_F(RtcpSenderTest, TestRegisterRtcpPacketTypeObserver) {
+  RtcpPacketTypeCounterObserverImpl observer;
+  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
+                                    &observer, nullptr, &test_transport_,
+                                    RtcpIntervalConfig{}));
+  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpPli));
+  EXPECT_EQ(1, parser()->pli()->num_packets());
+  EXPECT_EQ(kRemoteSsrc, observer.ssrc_);
+  EXPECT_EQ(1U, observer.counter_.pli_packets);
+  EXPECT_EQ(clock_.TimeInMilliseconds(),
+            observer.counter_.first_packet_time_ms);
+}
+
+TEST_F(RtcpSenderTest, SendTmmbr) {
+  const unsigned int kBitrateBps = 312000;
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
+  rtcp_sender_->SetTargetBitrate(kBitrateBps);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpTmmbr));
+  EXPECT_EQ(1, parser()->tmmbr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->tmmbr()->sender_ssrc());
+  EXPECT_EQ(1U, parser()->tmmbr()->requests().size());
+  EXPECT_EQ(kBitrateBps, parser()->tmmbr()->requests()[0].bitrate_bps());
+  // TODO(asapersson): tmmbr_item()->Overhead() looks broken, always zero.
+}
+
+TEST_F(RtcpSenderTest, TmmbrIncludedInCompoundPacketIfEnabled) {
+  const unsigned int kBitrateBps = 312000;
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  EXPECT_FALSE(rtcp_sender_->TMMBR());
+  rtcp_sender_->SetTMMBRStatus(true);
+  EXPECT_TRUE(rtcp_sender_->TMMBR());
+  rtcp_sender_->SetTargetBitrate(kBitrateBps);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(1, parser()->tmmbr()->num_packets());
+  EXPECT_EQ(1U, parser()->tmmbr()->requests().size());
+  // TMMBR should be included in each compound packet.
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(2, parser()->tmmbr()->num_packets());
+
+  rtcp_sender_->SetTMMBRStatus(false);
+  EXPECT_FALSE(rtcp_sender_->TMMBR());
+}
+
+TEST_F(RtcpSenderTest, SendTmmbn) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  rtcp_sender_->SetSendingStatus(feedback_state(), true);
+  std::vector<rtcp::TmmbItem> bounding_set;
+  const uint32_t kBitrateBps = 32768000;
+  const uint32_t kPacketOh = 40;
+  const uint32_t kSourceSsrc = 12345;
+  const rtcp::TmmbItem tmmbn(kSourceSsrc, kBitrateBps, kPacketOh);
+  bounding_set.push_back(tmmbn);
+  rtcp_sender_->SetTmmbn(bounding_set);
+
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr));
+  EXPECT_EQ(1, parser()->sender_report()->num_packets());
+  EXPECT_EQ(1, parser()->tmmbn()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->tmmbn()->sender_ssrc());
+  EXPECT_EQ(1U, parser()->tmmbn()->items().size());
+  EXPECT_EQ(kBitrateBps, parser()->tmmbn()->items()[0].bitrate_bps());
+  EXPECT_EQ(kPacketOh, parser()->tmmbn()->items()[0].packet_overhead());
+  EXPECT_EQ(kSourceSsrc, parser()->tmmbn()->items()[0].ssrc());
+}
+
+// This test is written to verify actual behaviour. It does not seem
+// to make much sense to send an empty TMMBN, since there is no place
+// to put an actual limit here. It's just information that no limit
+// is set, which is kind of the starting assumption.
+// See http://code.google.com/p/webrtc/issues/detail?id=468 for one
+// situation where this caused confusion.
+TEST_F(RtcpSenderTest, SendsTmmbnIfSetAndEmpty) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  rtcp_sender_->SetSendingStatus(feedback_state(), true);
+  std::vector<rtcp::TmmbItem> bounding_set;
+  rtcp_sender_->SetTmmbn(bounding_set);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpSr));
+  EXPECT_EQ(1, parser()->sender_report()->num_packets());
+  EXPECT_EQ(1, parser()->tmmbn()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->tmmbn()->sender_ssrc());
+  EXPECT_EQ(0U, parser()->tmmbn()->items().size());
+}
+
+TEST_F(RtcpSenderTest, SendCompoundPliRemb) {
+  const int kBitrate = 261011;
+  std::vector<uint32_t> ssrcs;
+  ssrcs.push_back(kRemoteSsrc);
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  rtcp_sender_->SetRemb(kBitrate, ssrcs);
+  std::set<RTCPPacketType> packet_types;
+  packet_types.insert(kRtcpRemb);
+  packet_types.insert(kRtcpPli);
+  EXPECT_EQ(0, rtcp_sender_->SendCompoundRTCP(feedback_state(), packet_types));
+  EXPECT_EQ(1, parser()->remb()->num_packets());
+  EXPECT_EQ(1, parser()->pli()->num_packets());
+}
+
+// This test is written to verify that BYE is always the last packet
+// type in a RTCP compoud packet.  The rtcp_sender_ is recreated with
+// mock_transport, which is used to check for whether BYE at the end
+// of a RTCP compound packet.
+TEST_F(RtcpSenderTest, ByeMustBeLast) {
+  MockTransport mock_transport;
+  EXPECT_CALL(mock_transport, SendRtcp(_, _))
+      .WillOnce(Invoke([](const uint8_t* data, size_t len) {
+        const uint8_t* next_packet = data;
+        const uint8_t* const packet_end = data + len;
+        rtcp::CommonHeader packet;
+        while (next_packet < packet_end) {
+          EXPECT_TRUE(packet.Parse(next_packet, packet_end - next_packet));
+          next_packet = packet.NextPacket();
+          if (packet.type() ==
+              rtcp::Bye::kPacketType)  // Main test expectation.
+            EXPECT_EQ(0, packet_end - next_packet)
+                << "Bye packet should be last in a compound RTCP packet.";
+          if (next_packet == packet_end)  // Validate test was set correctly.
+            EXPECT_EQ(packet.type(), rtcp::Bye::kPacketType)
+                << "Last packet in this test expected to be Bye.";
+        }
+
+        return true;
+      }));
+
+  // Re-configure rtcp_sender_ with mock_transport_
+  rtcp_sender_.reset(new RTCPSender(false, &clock_, receive_statistics_.get(),
+                                    nullptr, nullptr, &mock_transport,
+                                    RtcpIntervalConfig{}));
+  rtcp_sender_->SetSSRC(kSenderSsrc);
+  rtcp_sender_->SetRemoteSSRC(kRemoteSsrc);
+  rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
+  rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds());
+
+  // Set up XR VoIP metric to be included with BYE
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  RTCPVoIPMetric metric;
+  EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric));
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
+}
+
+TEST_F(RtcpSenderTest, SendXrWithTargetBitrate) {
+  rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
+  const size_t kNumSpatialLayers = 2;
+  const size_t kNumTemporalLayers = 2;
+  VideoBitrateAllocation allocation;
+  for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
+    uint32_t start_bitrate_bps = (sl + 1) * 100000;
+    for (size_t tl = 0; tl < kNumTemporalLayers; ++tl)
+      allocation.SetBitrate(sl, tl, start_bitrate_bps + (tl * 20000));
+  }
+  rtcp_sender_->SetVideoBitrateAllocation(allocation);
+
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
+  EXPECT_EQ(1, parser()->xr()->num_packets());
+  EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
+  const absl::optional<rtcp::TargetBitrate>& target_bitrate =
+      parser()->xr()->target_bitrate();
+  ASSERT_TRUE(target_bitrate);
+  const std::vector<rtcp::TargetBitrate::BitrateItem>& bitrates =
+      target_bitrate->GetTargetBitrates();
+  EXPECT_EQ(kNumSpatialLayers * kNumTemporalLayers, bitrates.size());
+
+  for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
+    uint32_t start_bitrate_bps = (sl + 1) * 100000;
+    for (size_t tl = 0; tl < kNumTemporalLayers; ++tl) {
+      size_t index = (sl * kNumSpatialLayers) + tl;
+      const rtcp::TargetBitrate::BitrateItem& item = bitrates[index];
+      EXPECT_EQ(sl, item.spatial_layer);
+      EXPECT_EQ(tl, item.temporal_layer);
+      EXPECT_EQ(start_bitrate_bps + (tl * 20000),
+                item.target_bitrate_kbps * 1000);
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.cc b/modules/rtp_rtcp/source/rtcp_transceiver.cc
new file mode 100644
index 0000000..9a17929
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.cc
@@ -0,0 +1,181 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_transceiver.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/event.h"
+#include "rtc_base/timeutils.h"
+
+namespace webrtc {
+
+RtcpTransceiver::RtcpTransceiver(const RtcpTransceiverConfig& config)
+    : task_queue_(config.task_queue),
+      rtcp_transceiver_(absl::make_unique<RtcpTransceiverImpl>(config)),
+      ptr_factory_(rtcp_transceiver_.get()),
+      // Creating first weak ptr can be done on any thread, but is not
+      // thread-safe, thus do it at construction. Creating second (e.g. making a
+      // copy) is thread-safe.
+      ptr_(ptr_factory_.GetWeakPtr()) {
+  RTC_DCHECK(task_queue_);
+}
+
+RtcpTransceiver::~RtcpTransceiver() {
+  if (task_queue_->IsCurrent())
+    return;
+
+  rtc::Event done(false, false);
+  // TODO(danilchap): Merge cleanup into main closure when task queue does not
+  // silently drop tasks.
+  task_queue_->PostTask(rtc::NewClosure(
+      [this] {
+        // Destructor steps that has to run on the task_queue_.
+        ptr_factory_.InvalidateWeakPtrs();
+        rtcp_transceiver_.reset();
+      },
+      /*cleanup=*/[&done] { done.Set(); }));
+  // Wait until destruction is complete to be sure weak pointers invalidated and
+  // rtcp_transceiver destroyed on the queue while |this| still valid.
+  done.Wait(rtc::Event::kForever);
+  RTC_CHECK(!rtcp_transceiver_) << "Task queue is too busy to handle rtcp";
+}
+
+void RtcpTransceiver::AddMediaReceiverRtcpObserver(
+    uint32_t remote_ssrc,
+    MediaReceiverRtcpObserver* observer) {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  task_queue_->PostTask([ptr, remote_ssrc, observer] {
+    if (ptr)
+      ptr->AddMediaReceiverRtcpObserver(remote_ssrc, observer);
+  });
+}
+
+void RtcpTransceiver::RemoveMediaReceiverRtcpObserver(
+    uint32_t remote_ssrc,
+    MediaReceiverRtcpObserver* observer,
+    std::unique_ptr<rtc::QueuedTask> on_removed) {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  auto remove = [ptr, remote_ssrc, observer] {
+    if (ptr)
+      ptr->RemoveMediaReceiverRtcpObserver(remote_ssrc, observer);
+  };
+  task_queue_->PostTaskAndReply(std::move(remove), std::move(on_removed));
+}
+
+void RtcpTransceiver::SetReadyToSend(bool ready) {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  task_queue_->PostTask([ptr, ready] {
+    if (ptr)
+      ptr->SetReadyToSend(ready);
+  });
+}
+
+void RtcpTransceiver::ReceivePacket(rtc::CopyOnWriteBuffer packet) {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  int64_t now_us = rtc::TimeMicros();
+  task_queue_->PostTask([ptr, packet, now_us] {
+    if (ptr)
+      ptr->ReceivePacket(packet, now_us);
+  });
+}
+
+void RtcpTransceiver::SendCompoundPacket() {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  task_queue_->PostTask([ptr] {
+    if (ptr)
+      ptr->SendCompoundPacket();
+  });
+}
+
+void RtcpTransceiver::SetRemb(int64_t bitrate_bps,
+                              std::vector<uint32_t> ssrcs) {
+  // TODO(danilchap): Replace with lambda with move capture when available.
+  struct SetRembClosure {
+    void operator()() {
+      if (ptr)
+        ptr->SetRemb(bitrate_bps, std::move(ssrcs));
+    }
+
+    rtc::WeakPtr<RtcpTransceiverImpl> ptr;
+    int64_t bitrate_bps;
+    std::vector<uint32_t> ssrcs;
+  };
+  task_queue_->PostTask(SetRembClosure{ptr_, bitrate_bps, std::move(ssrcs)});
+}
+
+void RtcpTransceiver::UnsetRemb() {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  task_queue_->PostTask([ptr] {
+    if (ptr)
+      ptr->UnsetRemb();
+  });
+}
+
+uint32_t RtcpTransceiver::SSRC() const {
+  return rtcp_transceiver_->sender_ssrc();
+}
+
+bool RtcpTransceiver::SendFeedbackPacket(
+    const rtcp::TransportFeedback& packet) {
+  struct Closure {
+    void operator()() {
+      if (ptr)
+        ptr->SendRawPacket(raw_packet);
+    }
+    rtc::WeakPtr<RtcpTransceiverImpl> ptr;
+    rtc::Buffer raw_packet;
+  };
+  task_queue_->PostTask(Closure{ptr_, packet.Build()});
+  return true;
+}
+
+void RtcpTransceiver::SendNack(uint32_t ssrc,
+                               std::vector<uint16_t> sequence_numbers) {
+  // TODO(danilchap): Replace with lambda with move capture when available.
+  struct Closure {
+    void operator()() {
+      if (ptr)
+        ptr->SendNack(ssrc, std::move(sequence_numbers));
+    }
+
+    rtc::WeakPtr<RtcpTransceiverImpl> ptr;
+    uint32_t ssrc;
+    std::vector<uint16_t> sequence_numbers;
+  };
+  task_queue_->PostTask(Closure{ptr_, ssrc, std::move(sequence_numbers)});
+}
+
+void RtcpTransceiver::SendPictureLossIndication(uint32_t ssrc) {
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr = ptr_;
+  task_queue_->PostTask([ptr, ssrc] {
+    if (ptr)
+      ptr->SendPictureLossIndication(ssrc);
+  });
+}
+
+void RtcpTransceiver::SendFullIntraRequest(std::vector<uint32_t> ssrcs) {
+  // TODO(danilchap): Replace with lambda with move capture when available.
+  struct Closure {
+    void operator()() {
+      if (ptr)
+        ptr->SendFullIntraRequest(ssrcs);
+    }
+
+    rtc::WeakPtr<RtcpTransceiverImpl> ptr;
+    std::vector<uint32_t> ssrcs;
+  };
+  task_queue_->PostTask(Closure{ptr_, std::move(ssrcs)});
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.h b/modules/rtp_rtcp/source/rtcp_transceiver.h
new file mode 100644
index 0000000..9125781
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.h
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
+#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/copyonwritebuffer.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/weak_ptr.h"
+
+namespace webrtc {
+//
+// Manage incoming and outgoing rtcp messages for multiple BUNDLED streams.
+//
+// This class is thread-safe wrapper of RtcpTransceiverImpl
+class RtcpTransceiver : public RtcpFeedbackSenderInterface {
+ public:
+  explicit RtcpTransceiver(const RtcpTransceiverConfig& config);
+  ~RtcpTransceiver() override;
+
+  // Registers observer to be notified about incoming rtcp packets.
+  // Calls to observer will be done on the |config.task_queue|.
+  void AddMediaReceiverRtcpObserver(uint32_t remote_ssrc,
+                                    MediaReceiverRtcpObserver* observer);
+  // Deregisters the observer. Might return before observer is deregistered.
+  // Posts |on_removed| task when observer is deregistered.
+  void RemoveMediaReceiverRtcpObserver(
+      uint32_t remote_ssrc,
+      MediaReceiverRtcpObserver* observer,
+      std::unique_ptr<rtc::QueuedTask> on_removed);
+
+  // Enables/disables sending rtcp packets eventually.
+  // Packets may be sent after the SetReadyToSend(false) returns, but no new
+  // packets will be scheduled.
+  void SetReadyToSend(bool ready);
+
+  // Handles incoming rtcp packets.
+  void ReceivePacket(rtc::CopyOnWriteBuffer packet);
+
+  // Sends RTCP packets starting with a sender or receiver report.
+  void SendCompoundPacket();
+
+  // (REMB) Receiver Estimated Max Bitrate.
+  // Includes REMB in following compound packets.
+  void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) override;
+  // Stops sending REMB in following compound packets.
+  void UnsetRemb() override;
+
+  // TODO(bugs.webrtc.org/8239): Remove SendFeedbackPacket and SSRC functions
+  // and move generating of the TransportFeedback message inside
+  // RtcpTransceiverImpl when there is one RtcpTransceiver per rtp transport.
+
+  // Returns ssrc to put as sender ssrc into rtcp::TransportFeedback.
+  uint32_t SSRC() const override;
+  bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override;
+
+  // Reports missing packets, https://tools.ietf.org/html/rfc4585#section-6.2.1
+  void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers);
+
+  // Requests new key frame.
+  // using PLI, https://tools.ietf.org/html/rfc4585#section-6.3.1.1
+  void SendPictureLossIndication(uint32_t ssrc);
+  // using FIR, https://tools.ietf.org/html/rfc5104#section-4.3.1.2
+  void SendFullIntraRequest(std::vector<uint32_t> ssrcs);
+
+ private:
+  rtc::TaskQueue* const task_queue_;
+  std::unique_ptr<RtcpTransceiverImpl> rtcp_transceiver_;
+  rtc::WeakPtrFactory<RtcpTransceiverImpl> ptr_factory_;
+  // TaskQueue, and thus tasks posted to it, may outlive this.
+  // Thus when Posting task class always pass copy of the weak_ptr to access
+  // the RtcpTransceiver and never guarantee it still will be alive when task
+  // runs.
+  rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtcpTransceiver);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_H_
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_config.cc b/modules/rtp_rtcp/source/rtcp_transceiver_config.cc
new file mode 100644
index 0000000..64e034a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_config.cc
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+RtcpTransceiverConfig::RtcpTransceiverConfig() = default;
+RtcpTransceiverConfig::RtcpTransceiverConfig(const RtcpTransceiverConfig&) =
+    default;
+RtcpTransceiverConfig& RtcpTransceiverConfig::operator=(
+    const RtcpTransceiverConfig&) = default;
+RtcpTransceiverConfig::~RtcpTransceiverConfig() = default;
+
+bool RtcpTransceiverConfig::Validate() const {
+  if (feedback_ssrc == 0)
+    RTC_LOG(LS_WARNING)
+        << debug_id
+        << "Ssrc 0 may be treated by some implementation as invalid.";
+  if (cname.empty())
+    RTC_LOG(LS_WARNING) << debug_id << "missing cname for ssrc "
+                        << feedback_ssrc;
+  if (cname.size() > 255) {
+    RTC_LOG(LS_ERROR) << debug_id << "cname can be maximum 255 characters.";
+    return false;
+  }
+  if (max_packet_size < 100) {
+    RTC_LOG(LS_ERROR) << debug_id << "max packet size " << max_packet_size
+                      << " is too small.";
+    return false;
+  }
+  if (max_packet_size > IP_PACKET_SIZE) {
+    RTC_LOG(LS_ERROR) << debug_id << "max packet size " << max_packet_size
+                      << " more than " << IP_PACKET_SIZE << " is unsupported.";
+    return false;
+  }
+  if (!outgoing_transport) {
+    RTC_LOG(LS_ERROR) << debug_id << "outgoing transport must be set";
+    return false;
+  }
+  if (initial_report_delay_ms < 0) {
+    RTC_LOG(LS_ERROR) << debug_id << "delay " << initial_report_delay_ms
+                      << "ms before first report shouldn't be negative.";
+    return false;
+  }
+  if (report_period_ms <= 0) {
+    RTC_LOG(LS_ERROR) << debug_id << "period " << report_period_ms
+                      << "ms between reports should be positive.";
+    return false;
+  }
+  if (schedule_periodic_compound_packets && !task_queue) {
+    RTC_LOG(LS_ERROR) << debug_id
+                      << "missing task queue for periodic compound packets";
+    return false;
+  }
+  if (rtcp_mode != RtcpMode::kCompound && rtcp_mode != RtcpMode::kReducedSize) {
+    RTC_LOG(LS_ERROR) << debug_id << "unsupported rtcp mode";
+    return false;
+  }
+  if (non_sender_rtt_measurement && !rtt_observer)
+    RTC_LOG(LS_WARNING) << debug_id
+                        << "Enabled special feature to calculate rtt, but no "
+                           "rtt observer is provided.";
+  // TODO(danilchap): Remove or update the warning when RtcpTransceiver supports
+  // send-only sessions.
+  if (receive_statistics == nullptr)
+    RTC_LOG(LS_WARNING)
+        << debug_id
+        << "receive statistic should be set to generate rtcp report blocks.";
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_config.h b/modules/rtp_rtcp/source/rtcp_transceiver_config.h
new file mode 100644
index 0000000..0da18e2
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_config.h
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_
+
+#include <string>
+
+#include "api/rtp_headers.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/task_queue.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+class ReceiveStatisticsProvider;
+class Transport;
+
+// Interface to watch incoming rtcp packets by media (rtp) receiver.
+class MediaReceiverRtcpObserver {
+ public:
+  virtual ~MediaReceiverRtcpObserver() = default;
+
+  // All message handlers have default empty implementation. This way user needs
+  // to implement only those she is interested in.
+  virtual void OnSenderReport(uint32_t sender_ssrc,
+                              NtpTime ntp_time,
+                              uint32_t rtp_time) {}
+  virtual void OnBye(uint32_t sender_ssrc) {}
+  virtual void OnBitrateAllocation(uint32_t sender_ssrc,
+                                   const VideoBitrateAllocation& allocation) {}
+};
+
+struct RtcpTransceiverConfig {
+  RtcpTransceiverConfig();
+  RtcpTransceiverConfig(const RtcpTransceiverConfig&);
+  RtcpTransceiverConfig& operator=(const RtcpTransceiverConfig&);
+  ~RtcpTransceiverConfig();
+
+  // Logs the error and returns false if configuration miss key objects or
+  // is inconsistant. May log warnings.
+  bool Validate() const;
+
+  // Used to prepend all log messages. Can be empty.
+  std::string debug_id;
+
+  // Ssrc to use as default sender ssrc, e.g. for transport-wide feedbacks.
+  uint32_t feedback_ssrc = 1;
+
+  // Canonical End-Point Identifier of the local particiapnt.
+  // Defined in rfc3550 section 6 note 2 and section 6.5.1.
+  std::string cname;
+
+  // Maximum packet size outgoing transport accepts.
+  size_t max_packet_size = 1200;
+
+  // Transport to send rtcp packets to. Should be set.
+  Transport* outgoing_transport = nullptr;
+
+  // Queue for scheduling delayed tasks, e.g. sending periodic compound packets.
+  rtc::TaskQueue* task_queue = nullptr;
+
+  // Rtcp report block generator for outgoing receiver reports.
+  ReceiveStatisticsProvider* receive_statistics = nullptr;
+
+  // Callback to pass result of rtt calculation. Should outlive RtcpTransceiver.
+  // Callbacks will be invoked on the task_queue.
+  RtcpRttStats* rtt_observer = nullptr;
+
+  // Configures if sending should
+  //  enforce compound packets: https://tools.ietf.org/html/rfc4585#section-3.1
+  //  or allow reduced size packets: https://tools.ietf.org/html/rfc5506
+  // Receiving accepts both compound and reduced-size packets.
+  RtcpMode rtcp_mode = RtcpMode::kCompound;
+  //
+  // Tuning parameters.
+  //
+  // Initial state if |outgoing_transport| ready to accept packets.
+  bool initial_ready_to_send = true;
+  // Delay before 1st periodic compound packet.
+  int initial_report_delay_ms = 500;
+
+  // Period between periodic compound packets.
+  int report_period_ms = 1000;
+
+  //
+  // Flags for features and experiments.
+  //
+  bool schedule_periodic_compound_packets = true;
+  // Estimate RTT as non-sender as described in
+  // https://tools.ietf.org/html/rfc3611#section-4.4 and #section-4.5
+  bool non_sender_rtt_measurement = false;
+  // Copies LastSR/DelaySinceLastSR for previous report block to avoid
+  // triggering bug in older version of RtcpReceiver.
+  // TODO(bugs.webrtc.org/8805): Change to false by default then remove when
+  // all major webrtc clients updated with the fix in RtcpReceiver.
+  bool avoid_zero_last_sr_in_last_report_block = true;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
new file mode 100644
index 0000000..a4da63a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
@@ -0,0 +1,454 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "api/call/transport.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/task_queue.h"
+#include "rtc_base/timeutils.h"
+
+namespace webrtc {
+namespace {
+
+struct SenderReportTimes {
+  int64_t local_received_time_us;
+  NtpTime remote_sent_time;
+};
+
+}  // namespace
+
+struct RtcpTransceiverImpl::RemoteSenderState {
+  uint8_t fir_sequence_number = 0;
+  absl::optional<SenderReportTimes> last_received_sender_report;
+  std::vector<MediaReceiverRtcpObserver*> observers;
+};
+
+// Helper to put several RTCP packets into lower layer datagram composing
+// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
+// TODO(danilchap): When in compound mode and packets are so many that several
+// compound RTCP packets need to be generated, ensure each packet is compound.
+class RtcpTransceiverImpl::PacketSender {
+ public:
+  PacketSender(rtcp::RtcpPacket::PacketReadyCallback callback,
+               size_t max_packet_size)
+      : callback_(callback), max_packet_size_(max_packet_size) {
+    RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
+  }
+  ~PacketSender() { RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; }
+
+  // Appends a packet to pending compound packet.
+  // Sends rtcp compound packet if buffer was already full and resets buffer.
+  void AppendPacket(const rtcp::RtcpPacket& packet) {
+    packet.Create(buffer_, &index_, max_packet_size_, callback_);
+  }
+
+  // Sends pending rtcp compound packet.
+  void Send() {
+    if (index_ > 0) {
+      callback_(rtc::ArrayView<const uint8_t>(buffer_, index_));
+      index_ = 0;
+    }
+  }
+
+  bool IsEmpty() const { return index_ == 0; }
+
+ private:
+  const rtcp::RtcpPacket::PacketReadyCallback callback_;
+  const size_t max_packet_size_;
+  size_t index_ = 0;
+  uint8_t buffer_[IP_PACKET_SIZE];
+};
+
+RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
+    : config_(config),
+      ready_to_send_(config.initial_ready_to_send),
+      ptr_factory_(this) {
+  RTC_CHECK(config_.Validate());
+  if (ready_to_send_ && config_.schedule_periodic_compound_packets)
+    SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
+}
+
+RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
+
+void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
+    uint32_t remote_ssrc,
+    MediaReceiverRtcpObserver* observer) {
+  auto& stored = remote_senders_[remote_ssrc].observers;
+  RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
+  stored.push_back(observer);
+}
+
+void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
+    uint32_t remote_ssrc,
+    MediaReceiverRtcpObserver* observer) {
+  auto remote_sender_it = remote_senders_.find(remote_ssrc);
+  if (remote_sender_it == remote_senders_.end())
+    return;
+  auto& stored = remote_sender_it->second.observers;
+  auto it = std::find(stored.begin(), stored.end(), observer);
+  if (it == stored.end())
+    return;
+  stored.erase(it);
+}
+
+void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
+  if (config_.schedule_periodic_compound_packets) {
+    if (ready_to_send_ && !ready)  // Stop existent send task.
+      ptr_factory_.InvalidateWeakPtrs();
+
+    if (!ready_to_send_ && ready)  // Restart periodic sending.
+      SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
+  }
+  ready_to_send_ = ready;
+}
+
+void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
+                                        int64_t now_us) {
+  while (!packet.empty()) {
+    rtcp::CommonHeader rtcp_block;
+    if (!rtcp_block.Parse(packet.data(), packet.size()))
+      return;
+
+    HandleReceivedPacket(rtcp_block, now_us);
+
+    // TODO(danilchap): Use packet.remove_prefix() when that function exists.
+    packet = packet.subview(rtcp_block.packet_size());
+  }
+}
+
+void RtcpTransceiverImpl::SendCompoundPacket() {
+  if (!ready_to_send_)
+    return;
+  SendPeriodicCompoundPacket();
+  ReschedulePeriodicCompoundPackets();
+}
+
+void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
+                                  std::vector<uint32_t> ssrcs) {
+  RTC_DCHECK_GE(bitrate_bps, 0);
+  remb_.emplace();
+  remb_->SetSsrcs(std::move(ssrcs));
+  remb_->SetBitrateBps(bitrate_bps);
+  // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
+  // immideately on large bitrate change when there is one RtcpTransceiver per
+  // rtp transport.
+}
+
+void RtcpTransceiverImpl::UnsetRemb() {
+  remb_.reset();
+}
+
+void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
+  if (!ready_to_send_)
+    return;
+  // Unlike other senders, this functions just tries to send packet away and
+  // disregard rtcp_mode, max_packet_size or anything else.
+  // TODO(bugs.webrtc.org/8239): respect config_ by creating the
+  // TransportFeedback inside this class when there is one per rtp transport.
+  config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
+}
+
+void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
+                                   std::vector<uint16_t> sequence_numbers) {
+  RTC_DCHECK(!sequence_numbers.empty());
+  if (!ready_to_send_)
+    return;
+  rtcp::Nack nack;
+  nack.SetSenderSsrc(config_.feedback_ssrc);
+  nack.SetMediaSsrc(ssrc);
+  nack.SetPacketIds(std::move(sequence_numbers));
+  SendImmediateFeedback(nack);
+}
+
+void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
+  if (!ready_to_send_)
+    return;
+  rtcp::Pli pli;
+  pli.SetSenderSsrc(config_.feedback_ssrc);
+  pli.SetMediaSsrc(ssrc);
+  SendImmediateFeedback(pli);
+}
+
+void RtcpTransceiverImpl::SendFullIntraRequest(
+    rtc::ArrayView<const uint32_t> ssrcs) {
+  RTC_DCHECK(!ssrcs.empty());
+  if (!ready_to_send_)
+    return;
+  rtcp::Fir fir;
+  fir.SetSenderSsrc(config_.feedback_ssrc);
+  for (uint32_t media_ssrc : ssrcs)
+    fir.AddRequestTo(media_ssrc,
+                     remote_senders_[media_ssrc].fir_sequence_number++);
+  SendImmediateFeedback(fir);
+}
+
+void RtcpTransceiverImpl::HandleReceivedPacket(
+    const rtcp::CommonHeader& rtcp_packet_header,
+    int64_t now_us) {
+  switch (rtcp_packet_header.type()) {
+    case rtcp::Bye::kPacketType:
+      HandleBye(rtcp_packet_header);
+      break;
+    case rtcp::SenderReport::kPacketType:
+      HandleSenderReport(rtcp_packet_header, now_us);
+      break;
+    case rtcp::ExtendedReports::kPacketType:
+      HandleExtendedReports(rtcp_packet_header, now_us);
+      break;
+  }
+}
+
+void RtcpTransceiverImpl::HandleBye(
+    const rtcp::CommonHeader& rtcp_packet_header) {
+  rtcp::Bye bye;
+  if (!bye.Parse(rtcp_packet_header))
+    return;
+  auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
+  if (remote_sender_it == remote_senders_.end())
+    return;
+  for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
+    observer->OnBye(bye.sender_ssrc());
+}
+
+void RtcpTransceiverImpl::HandleSenderReport(
+    const rtcp::CommonHeader& rtcp_packet_header,
+    int64_t now_us) {
+  rtcp::SenderReport sender_report;
+  if (!sender_report.Parse(rtcp_packet_header))
+    return;
+  RemoteSenderState& remote_sender =
+      remote_senders_[sender_report.sender_ssrc()];
+  absl::optional<SenderReportTimes>& last =
+      remote_sender.last_received_sender_report;
+  last.emplace();
+  last->local_received_time_us = now_us;
+  last->remote_sent_time = sender_report.ntp();
+
+  for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
+    observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
+                             sender_report.rtp_timestamp());
+}
+
+void RtcpTransceiverImpl::HandleExtendedReports(
+    const rtcp::CommonHeader& rtcp_packet_header,
+    int64_t now_us) {
+  rtcp::ExtendedReports extended_reports;
+  if (!extended_reports.Parse(rtcp_packet_header))
+    return;
+
+  if (extended_reports.dlrr())
+    HandleDlrr(extended_reports.dlrr(), now_us);
+
+  if (extended_reports.target_bitrate())
+    HandleTargetBitrate(*extended_reports.target_bitrate(),
+                        extended_reports.sender_ssrc());
+}
+
+void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
+  if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
+    return;
+
+  // Delay and last_rr are transferred using 32bit compact ntp resolution.
+  // Convert packet arrival time to same format through 64bit ntp format.
+  uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
+  for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
+    if (rti.ssrc != config_.feedback_ssrc)
+      continue;
+    uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
+    int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
+    config_.rtt_observer->OnRttUpdate(rtt_ms);
+  }
+}
+
+void RtcpTransceiverImpl::HandleTargetBitrate(
+    const rtcp::TargetBitrate& target_bitrate,
+    uint32_t remote_ssrc) {
+  auto remote_sender_it = remote_senders_.find(remote_ssrc);
+  if (remote_sender_it == remote_senders_.end() ||
+      remote_sender_it->second.observers.empty())
+    return;
+
+  // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
+  VideoBitrateAllocation bitrate_allocation;
+  for (const rtcp::TargetBitrate::BitrateItem& item :
+       target_bitrate.GetTargetBitrates()) {
+    if (item.spatial_layer >= kMaxSpatialLayers ||
+        item.temporal_layer >= kMaxTemporalStreams) {
+      RTC_DLOG(LS_WARNING)
+          << config_.debug_id
+          << "Invalid incoming TargetBitrate with spatial layer "
+          << item.spatial_layer << ", temporal layer " << item.temporal_layer;
+      continue;
+    }
+    bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
+                                  item.target_bitrate_kbps * 1000);
+  }
+
+  for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
+    observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
+}
+
+void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
+  if (!config_.schedule_periodic_compound_packets)
+    return;
+  // Stop existent send task.
+  ptr_factory_.InvalidateWeakPtrs();
+  SchedulePeriodicCompoundPackets(config_.report_period_ms);
+}
+
+void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
+  class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
+   public:
+    SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
+                                   rtc::WeakPtr<RtcpTransceiverImpl> ptr)
+        : task_queue_(task_queue), ptr_(std::move(ptr)) {}
+    bool Run() override {
+      RTC_DCHECK(task_queue_->IsCurrent());
+      if (!ptr_)
+        return true;
+      ptr_->SendPeriodicCompoundPacket();
+      task_queue_->PostDelayedTask(absl::WrapUnique(this),
+                                   ptr_->config_.report_period_ms);
+      return false;
+    }
+
+   private:
+    rtc::TaskQueue* const task_queue_;
+    const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
+  };
+
+  RTC_DCHECK(config_.schedule_periodic_compound_packets);
+
+  auto task = absl::make_unique<SendPeriodicCompoundPacketTask>(
+      config_.task_queue, ptr_factory_.GetWeakPtr());
+  if (delay_ms > 0)
+    config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
+  else
+    config_.task_queue->PostTask(std::move(task));
+}
+
+void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
+  RTC_DCHECK(sender->IsEmpty());
+  const uint32_t sender_ssrc = config_.feedback_ssrc;
+  int64_t now_us = rtc::TimeMicros();
+  rtcp::ReceiverReport receiver_report;
+  receiver_report.SetSenderSsrc(sender_ssrc);
+  receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
+  sender->AppendPacket(receiver_report);
+
+  if (!config_.cname.empty()) {
+    rtcp::Sdes sdes;
+    bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
+    RTC_DCHECK(added) << "Failed to add cname " << config_.cname
+                      << " to rtcp sdes packet.";
+    sender->AppendPacket(sdes);
+  }
+  if (remb_) {
+    remb_->SetSenderSsrc(sender_ssrc);
+    sender->AppendPacket(*remb_);
+  }
+  // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
+  // SenderReport instead of ReceiverReport
+  // when RtcpTransceiver supports rtp senders.
+  if (config_.non_sender_rtt_measurement) {
+    rtcp::ExtendedReports xr;
+
+    rtcp::Rrtr rrtr;
+    rrtr.SetNtp(TimeMicrosToNtp(now_us));
+    xr.SetRrtr(rrtr);
+
+    xr.SetSenderSsrc(sender_ssrc);
+    sender->AppendPacket(xr);
+  }
+}
+
+void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
+  auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
+    config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
+  };
+  PacketSender sender(send_packet, config_.max_packet_size);
+  CreateCompoundPacket(&sender);
+  sender.Send();
+}
+
+void RtcpTransceiverImpl::SendImmediateFeedback(
+    const rtcp::RtcpPacket& rtcp_packet) {
+  auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
+    config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
+  };
+  PacketSender sender(send_packet, config_.max_packet_size);
+  // Compound mode requires every sent rtcp packet to be compound, i.e. start
+  // with a sender or receiver report.
+  if (config_.rtcp_mode == RtcpMode::kCompound)
+    CreateCompoundPacket(&sender);
+
+  sender.AppendPacket(rtcp_packet);
+  sender.Send();
+
+  // If compound packet was sent, delay (reschedule) the periodic one.
+  if (config_.rtcp_mode == RtcpMode::kCompound)
+    ReschedulePeriodicCompoundPackets();
+}
+
+std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
+    int64_t now_us) {
+  if (!config_.receive_statistics)
+    return {};
+  // TODO(danilchap): Support sending more than
+  // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
+  std::vector<rtcp::ReportBlock> report_blocks =
+      config_.receive_statistics->RtcpReportBlocks(
+          rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
+  uint32_t last_sr = 0;
+  uint32_t last_delay = 0;
+  for (rtcp::ReportBlock& report_block : report_blocks) {
+    auto it = remote_senders_.find(report_block.source_ssrc());
+    if (it == remote_senders_.end() ||
+        !it->second.last_received_sender_report) {
+      if (config_.avoid_zero_last_sr_in_last_report_block && last_sr != 0) {
+        // Simulate behaviour of the RtcpSender to avoid hitting bug in
+        // RtcpReceiver.
+        report_block.SetLastSr(last_sr);
+        report_block.SetDelayLastSr(last_delay);
+      }
+      continue;
+    }
+    const SenderReportTimes& last_sender_report =
+        *it->second.last_received_sender_report;
+    last_sr = CompactNtp(last_sender_report.remote_sent_time);
+    last_delay = SaturatedUsToCompactNtp(
+        now_us - last_sender_report.local_received_time_us);
+    report_block.SetLastSr(last_sr);
+    report_block.SetDelayLastSr(last_delay);
+  }
+  return report_blocks;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
new file mode 100644
index 0000000..7bcd16f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
@@ -0,0 +1,105 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_
+#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
+#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/weak_ptr.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+//
+// Manage incoming and outgoing rtcp messages for multiple BUNDLED streams.
+//
+// This class is not thread-safe.
+class RtcpTransceiverImpl {
+ public:
+  explicit RtcpTransceiverImpl(const RtcpTransceiverConfig& config);
+  ~RtcpTransceiverImpl();
+
+  void AddMediaReceiverRtcpObserver(uint32_t remote_ssrc,
+                                    MediaReceiverRtcpObserver* observer);
+  void RemoveMediaReceiverRtcpObserver(uint32_t remote_ssrc,
+                                       MediaReceiverRtcpObserver* observer);
+
+  void SetReadyToSend(bool ready);
+
+  void ReceivePacket(rtc::ArrayView<const uint8_t> packet, int64_t now_us);
+
+  void SendCompoundPacket();
+
+  void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs);
+  void UnsetRemb();
+  // Temporary helpers to send pre-built TransportFeedback rtcp packet.
+  uint32_t sender_ssrc() const { return config_.feedback_ssrc; }
+  void SendRawPacket(rtc::ArrayView<const uint8_t> packet);
+
+  void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers);
+
+  void SendPictureLossIndication(uint32_t ssrc);
+  void SendFullIntraRequest(rtc::ArrayView<const uint32_t> ssrcs);
+
+ private:
+  class PacketSender;
+  struct RemoteSenderState;
+
+  void HandleReceivedPacket(const rtcp::CommonHeader& rtcp_packet_header,
+                            int64_t now_us);
+  // Individual rtcp packet handlers.
+  void HandleBye(const rtcp::CommonHeader& rtcp_packet_header);
+  void HandleSenderReport(const rtcp::CommonHeader& rtcp_packet_header,
+                          int64_t now_us);
+  void HandleExtendedReports(const rtcp::CommonHeader& rtcp_packet_header,
+                             int64_t now_us);
+  // Extended Reports blocks handlers.
+  void HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us);
+  void HandleTargetBitrate(const rtcp::TargetBitrate& target_bitrate,
+                           uint32_t remote_ssrc);
+
+  void ReschedulePeriodicCompoundPackets();
+  void SchedulePeriodicCompoundPackets(int64_t delay_ms);
+  // Creates compound RTCP packet, as defined in
+  // https://tools.ietf.org/html/rfc5506#section-2
+  void CreateCompoundPacket(PacketSender* sender);
+  // Sends RTCP packets.
+  void SendPeriodicCompoundPacket();
+  void SendImmediateFeedback(const rtcp::RtcpPacket& rtcp_packet);
+  // Generate Report Blocks to be send in Sender or Receiver Report.
+  std::vector<rtcp::ReportBlock> CreateReportBlocks(int64_t now_us);
+
+  const RtcpTransceiverConfig config_;
+
+  bool ready_to_send_;
+  absl::optional<rtcp::Remb> remb_;
+  // TODO(danilchap): Remove entries from remote_senders_ that are no longer
+  // needed.
+  std::map<uint32_t, RemoteSenderState> remote_senders_;
+  rtc::WeakPtrFactory<RtcpTransceiverImpl> ptr_factory_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtcpTransceiverImpl);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
new file mode 100644
index 0000000..1675b66
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
@@ -0,0 +1,981 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
+
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+#include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/app.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "rtc_base/event.h"
+#include "rtc_base/fakeclock.h"
+#include "rtc_base/task_queue.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/mock_transport.h"
+#include "test/rtcp_packet_parser.h"
+
+namespace {
+
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SizeIs;
+using ::testing::StrictMock;
+using ::webrtc::VideoBitrateAllocation;
+using ::webrtc::CompactNtp;
+using ::webrtc::CompactNtpRttToMs;
+using ::webrtc::MockRtcpRttStats;
+using ::webrtc::MockTransport;
+using ::webrtc::NtpTime;
+using ::webrtc::RtcpTransceiverConfig;
+using ::webrtc::RtcpTransceiverImpl;
+using ::webrtc::SaturatedUsToCompactNtp;
+using ::webrtc::TimeMicrosToNtp;
+using ::webrtc::rtcp::Bye;
+using ::webrtc::rtcp::CompoundPacket;
+using ::webrtc::rtcp::ReportBlock;
+using ::webrtc::rtcp::SenderReport;
+using ::webrtc::test::RtcpPacketParser;
+
+class MockReceiveStatisticsProvider : public webrtc::ReceiveStatisticsProvider {
+ public:
+  MOCK_METHOD1(RtcpReportBlocks, std::vector<ReportBlock>(size_t));
+};
+
+class MockMediaReceiverRtcpObserver : public webrtc::MediaReceiverRtcpObserver {
+ public:
+  MOCK_METHOD3(OnSenderReport, void(uint32_t, NtpTime, uint32_t));
+  MOCK_METHOD1(OnBye, void(uint32_t));
+  MOCK_METHOD2(OnBitrateAllocation,
+               void(uint32_t, const VideoBitrateAllocation&));
+};
+
+// Since some tests will need to wait for this period, make it small to avoid
+// slowing tests too much. As long as there are test bots with high scheduler
+// granularity, small period should be ok.
+constexpr int kReportPeriodMs = 10;
+// On some systems task queue might be slow, instead of guessing right
+// grace period, use very large timeout, 100x larger expected wait time.
+// Use finite timeout to fail tests rather than hang them.
+constexpr int kAlmostForeverMs = 1000;
+
+// Helper to wait for an rtcp packet produced on a different thread/task queue.
+class FakeRtcpTransport : public webrtc::Transport {
+ public:
+  FakeRtcpTransport() : sent_rtcp_(false, false) {}
+  bool SendRtcp(const uint8_t* data, size_t size) override {
+    sent_rtcp_.Set();
+    return true;
+  }
+  bool SendRtp(const uint8_t*, size_t, const webrtc::PacketOptions&) override {
+    ADD_FAILURE() << "RtcpTransciver shouldn't send rtp packets.";
+    return true;
+  }
+
+  // Returns true when packet was received by the transport.
+  bool WaitPacket() {
+    // Normally packet should be sent fast, long before the timeout.
+    bool packet_sent = sent_rtcp_.Wait(kAlmostForeverMs);
+    // Disallow tests to wait almost forever for no packets.
+    EXPECT_TRUE(packet_sent);
+    // Return wait result even though it is expected to be true, so that
+    // individual tests can EXPECT on it for better error message.
+    return packet_sent;
+  }
+
+ private:
+  rtc::Event sent_rtcp_;
+};
+
+class RtcpParserTransport : public webrtc::Transport {
+ public:
+  explicit RtcpParserTransport(RtcpPacketParser* parser) : parser_(parser) {}
+  // Returns total number of rtcp packet received.
+  int num_packets() const { return num_packets_; }
+
+ private:
+  bool SendRtcp(const uint8_t* data, size_t size) override {
+    ++num_packets_;
+    parser_->Parse(data, size);
+    return true;
+  }
+
+  bool SendRtp(const uint8_t*, size_t, const webrtc::PacketOptions&) override {
+    ADD_FAILURE() << "RtcpTransciver shouldn't send rtp packets.";
+    return true;
+  }
+
+  RtcpPacketParser* const parser_;
+  int num_packets_ = 0;
+};
+
+RtcpTransceiverConfig DefaultTestConfig() {
+  // RtcpTransceiverConfig default constructor sets default values for prod.
+  // Test doesn't need to support all key features: Default test config returns
+  // valid config with all features turned off.
+  static MockTransport null_transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &null_transport;
+  config.schedule_periodic_compound_packets = false;
+  config.initial_report_delay_ms = 10;
+  config.report_period_ms = kReportPeriodMs;
+  return config;
+}
+
+TEST(RtcpTransceiverImplTest, DelaysSendingFirstCompondPacket) {
+  rtc::TaskQueue queue("rtcp");
+  FakeRtcpTransport transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &transport;
+  config.initial_report_delay_ms = 10;
+  config.task_queue = &queue;
+  absl::optional<RtcpTransceiverImpl> rtcp_transceiver;
+
+  int64_t started_ms = rtc::TimeMillis();
+  queue.PostTask([&] { rtcp_transceiver.emplace(config); });
+  EXPECT_TRUE(transport.WaitPacket());
+
+  EXPECT_GE(rtc::TimeMillis() - started_ms, config.initial_report_delay_ms);
+
+  // Cleanup.
+  rtc::Event done(false, false);
+  queue.PostTask([&] {
+    rtcp_transceiver.reset();
+    done.Set();
+  });
+  ASSERT_TRUE(done.Wait(kAlmostForeverMs));
+}
+
+TEST(RtcpTransceiverImplTest, PeriodicallySendsPackets) {
+  rtc::TaskQueue queue("rtcp");
+  FakeRtcpTransport transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &transport;
+  config.initial_report_delay_ms = 0;
+  config.report_period_ms = kReportPeriodMs;
+  config.task_queue = &queue;
+  absl::optional<RtcpTransceiverImpl> rtcp_transceiver;
+  int64_t time_just_before_1st_packet_ms = 0;
+  queue.PostTask([&] {
+    // Because initial_report_delay_ms is set to 0, time_just_before_the_packet
+    // should be very close to the time_of_the_packet.
+    time_just_before_1st_packet_ms = rtc::TimeMillis();
+    rtcp_transceiver.emplace(config);
+  });
+
+  EXPECT_TRUE(transport.WaitPacket());
+  EXPECT_TRUE(transport.WaitPacket());
+  int64_t time_just_after_2nd_packet_ms = rtc::TimeMillis();
+
+  EXPECT_GE(time_just_after_2nd_packet_ms - time_just_before_1st_packet_ms,
+            config.report_period_ms - 1);
+
+  // Cleanup.
+  rtc::Event done(false, false);
+  queue.PostTask([&] {
+    rtcp_transceiver.reset();
+    done.Set();
+  });
+  ASSERT_TRUE(done.Wait(kAlmostForeverMs));
+}
+
+TEST(RtcpTransceiverImplTest, SendCompoundPacketDelaysPeriodicSendPackets) {
+  rtc::TaskQueue queue("rtcp");
+  FakeRtcpTransport transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &transport;
+  config.initial_report_delay_ms = 0;
+  config.report_period_ms = kReportPeriodMs;
+  config.task_queue = &queue;
+  absl::optional<RtcpTransceiverImpl> rtcp_transceiver;
+  queue.PostTask([&] { rtcp_transceiver.emplace(config); });
+
+  // Wait for first packet.
+  EXPECT_TRUE(transport.WaitPacket());
+  // Send non periodic one after half period.
+  rtc::Event non_periodic(false, false);
+  int64_t time_of_non_periodic_packet_ms = 0;
+  queue.PostDelayedTask(
+      [&] {
+        time_of_non_periodic_packet_ms = rtc::TimeMillis();
+        rtcp_transceiver->SendCompoundPacket();
+        non_periodic.Set();
+      },
+      config.report_period_ms / 2);
+  // Though non-periodic packet is scheduled just in between periodic, due to
+  // small period and task queue flakiness it migth end-up 1ms after next
+  // periodic packet. To be sure duration after non-periodic packet is tested
+  // wait for transport after ensuring non-periodic packet was sent.
+  EXPECT_TRUE(non_periodic.Wait(kAlmostForeverMs));
+  EXPECT_TRUE(transport.WaitPacket());
+  // Wait for next periodic packet.
+  EXPECT_TRUE(transport.WaitPacket());
+  int64_t time_of_last_periodic_packet_ms = rtc::TimeMillis();
+
+  EXPECT_GE(time_of_last_periodic_packet_ms - time_of_non_periodic_packet_ms,
+            config.report_period_ms - 1);
+
+  // Cleanup.
+  rtc::Event done(false, false);
+  queue.PostTask([&] {
+    rtcp_transceiver.reset();
+    done.Set();
+  });
+  ASSERT_TRUE(done.Wait(kAlmostForeverMs));
+}
+
+TEST(RtcpTransceiverImplTest, SendsNoRtcpWhenNetworkStateIsDown) {
+  MockTransport mock_transport;
+  RtcpTransceiverConfig config = DefaultTestConfig();
+  config.initial_ready_to_send = false;
+  config.outgoing_transport = &mock_transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  EXPECT_CALL(mock_transport, SendRtcp(_, _)).Times(0);
+
+  const uint8_t raw[] = {1, 2, 3, 4};
+  const std::vector<uint16_t> sequence_numbers = {45, 57};
+  const uint32_t ssrcs[] = {123};
+  rtcp_transceiver.SendCompoundPacket();
+  rtcp_transceiver.SendRawPacket(raw);
+  rtcp_transceiver.SendNack(ssrcs[0], sequence_numbers);
+  rtcp_transceiver.SendPictureLossIndication(ssrcs[0]);
+  rtcp_transceiver.SendFullIntraRequest(ssrcs);
+}
+
+TEST(RtcpTransceiverImplTest, SendsRtcpWhenNetworkStateIsUp) {
+  MockTransport mock_transport;
+  RtcpTransceiverConfig config = DefaultTestConfig();
+  config.initial_ready_to_send = false;
+  config.outgoing_transport = &mock_transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SetReadyToSend(true);
+
+  EXPECT_CALL(mock_transport, SendRtcp(_, _)).Times(5);
+
+  const uint8_t raw[] = {1, 2, 3, 4};
+  const std::vector<uint16_t> sequence_numbers = {45, 57};
+  const uint32_t ssrcs[] = {123};
+  rtcp_transceiver.SendCompoundPacket();
+  rtcp_transceiver.SendRawPacket(raw);
+  rtcp_transceiver.SendNack(ssrcs[0], sequence_numbers);
+  rtcp_transceiver.SendPictureLossIndication(ssrcs[0]);
+  rtcp_transceiver.SendFullIntraRequest(ssrcs);
+}
+
+TEST(RtcpTransceiverImplTest, SendsPeriodicRtcpWhenNetworkStateIsUp) {
+  rtc::TaskQueue queue("rtcp");
+  FakeRtcpTransport transport;
+  RtcpTransceiverConfig config = DefaultTestConfig();
+  config.schedule_periodic_compound_packets = true;
+  config.initial_ready_to_send = false;
+  config.outgoing_transport = &transport;
+  config.task_queue = &queue;
+  absl::optional<RtcpTransceiverImpl> rtcp_transceiver;
+  rtcp_transceiver.emplace(config);
+
+  rtcp_transceiver->SetReadyToSend(true);
+
+  EXPECT_TRUE(transport.WaitPacket());
+
+  // Cleanup.
+  rtc::Event done(false, false);
+  queue.PostTask([&] {
+    rtcp_transceiver.reset();
+    done.Set();
+  });
+  ASSERT_TRUE(done.Wait(kAlmostForeverMs));
+}
+
+TEST(RtcpTransceiverImplTest, SendsMinimalCompoundPacket) {
+  const uint32_t kSenderSsrc = 12345;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.cname = "cname";
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendCompoundPacket();
+
+  // Minimal compound RTCP packet contains sender or receiver report and sdes
+  // with cname.
+  ASSERT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
+  EXPECT_EQ(rtcp_parser.receiver_report()->sender_ssrc(), kSenderSsrc);
+  ASSERT_GT(rtcp_parser.sdes()->num_packets(), 0);
+  ASSERT_EQ(rtcp_parser.sdes()->chunks().size(), 1u);
+  EXPECT_EQ(rtcp_parser.sdes()->chunks()[0].ssrc, kSenderSsrc);
+  EXPECT_EQ(rtcp_parser.sdes()->chunks()[0].cname, config.cname);
+}
+
+TEST(RtcpTransceiverImplTest, SendsNoRembInitially) {
+  const uint32_t kSenderSsrc = 12345;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(transport.num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.remb()->num_packets(), 0);
+}
+
+TEST(RtcpTransceiverImplTest, SetRembIncludesRembInNextCompoundPacket) {
+  const uint32_t kSenderSsrc = 12345;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.remb()->sender_ssrc(), kSenderSsrc);
+  EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 10000u);
+  EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(54321, 64321));
+}
+
+TEST(RtcpTransceiverImplTest, SetRembUpdatesValuesToSend) {
+  const uint32_t kSenderSsrc = 12345;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 10000u);
+  EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(54321, 64321));
+
+  rtcp_transceiver.SetRemb(/*bitrate_bps=*/70000, /*ssrc=*/{67321});
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(rtcp_parser.remb()->num_packets(), 2);
+  EXPECT_EQ(rtcp_parser.remb()->bitrate_bps(), 70000u);
+  EXPECT_THAT(rtcp_parser.remb()->ssrcs(), ElementsAre(67321));
+}
+
+TEST(RtcpTransceiverImplTest, SetRembIncludesRembInAllCompoundPackets) {
+  const uint32_t kSenderSsrc = 12345;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+  rtcp_transceiver.SendCompoundPacket();
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(transport.num_packets(), 2);
+  EXPECT_EQ(rtcp_parser.remb()->num_packets(), 2);
+}
+
+TEST(RtcpTransceiverImplTest, SendsNoRembAfterUnset) {
+  const uint32_t kSenderSsrc = 12345;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SetRemb(/*bitrate_bps=*/10000, /*ssrc=*/{54321, 64321});
+  rtcp_transceiver.SendCompoundPacket();
+  EXPECT_EQ(transport.num_packets(), 1);
+  ASSERT_EQ(rtcp_parser.remb()->num_packets(), 1);
+
+  rtcp_transceiver.UnsetRemb();
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(transport.num_packets(), 2);
+  EXPECT_EQ(rtcp_parser.remb()->num_packets(), 1);
+}
+
+TEST(RtcpTransceiverImplTest, ReceiverReportUsesReceiveStatistics) {
+  const uint32_t kSenderSsrc = 12345;
+  const uint32_t kMediaSsrc = 54321;
+  MockReceiveStatisticsProvider receive_statistics;
+  std::vector<ReportBlock> report_blocks(1);
+  report_blocks[0].SetMediaSsrc(kMediaSsrc);
+  EXPECT_CALL(receive_statistics, RtcpReportBlocks(_))
+      .WillRepeatedly(Return(report_blocks));
+
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.receive_statistics = &receive_statistics;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendCompoundPacket();
+
+  ASSERT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
+  EXPECT_EQ(rtcp_parser.receiver_report()->sender_ssrc(), kSenderSsrc);
+  ASSERT_THAT(rtcp_parser.receiver_report()->report_blocks(),
+              SizeIs(report_blocks.size()));
+  EXPECT_EQ(rtcp_parser.receiver_report()->report_blocks()[0].source_ssrc(),
+            kMediaSsrc);
+}
+
+TEST(RtcpTransceiverImplTest, MultipleObserversOnSameSsrc) {
+  const uint32_t kRemoteSsrc = 12345;
+  StrictMock<MockMediaReceiverRtcpObserver> observer1;
+  StrictMock<MockMediaReceiverRtcpObserver> observer2;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer1);
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer2);
+
+  const NtpTime kRemoteNtp(0x9876543211);
+  const uint32_t kRemoteRtp = 0x444555;
+  SenderReport sr;
+  sr.SetSenderSsrc(kRemoteSsrc);
+  sr.SetNtp(kRemoteNtp);
+  sr.SetRtpTimestamp(kRemoteRtp);
+  auto raw_packet = sr.Build();
+
+  EXPECT_CALL(observer1, OnSenderReport(kRemoteSsrc, kRemoteNtp, kRemoteRtp));
+  EXPECT_CALL(observer2, OnSenderReport(kRemoteSsrc, kRemoteNtp, kRemoteRtp));
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, DoesntCallsObserverAfterRemoved) {
+  const uint32_t kRemoteSsrc = 12345;
+  StrictMock<MockMediaReceiverRtcpObserver> observer1;
+  StrictMock<MockMediaReceiverRtcpObserver> observer2;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer1);
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer2);
+
+  SenderReport sr;
+  sr.SetSenderSsrc(kRemoteSsrc);
+  auto raw_packet = sr.Build();
+
+  rtcp_transceiver.RemoveMediaReceiverRtcpObserver(kRemoteSsrc, &observer1);
+
+  EXPECT_CALL(observer1, OnSenderReport(_, _, _)).Times(0);
+  EXPECT_CALL(observer2, OnSenderReport(_, _, _));
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, CallsObserverOnSenderReportBySenderSsrc) {
+  const uint32_t kRemoteSsrc1 = 12345;
+  const uint32_t kRemoteSsrc2 = 22345;
+  StrictMock<MockMediaReceiverRtcpObserver> observer1;
+  StrictMock<MockMediaReceiverRtcpObserver> observer2;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc1, &observer1);
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc2, &observer2);
+
+  const NtpTime kRemoteNtp(0x9876543211);
+  const uint32_t kRemoteRtp = 0x444555;
+  SenderReport sr;
+  sr.SetSenderSsrc(kRemoteSsrc1);
+  sr.SetNtp(kRemoteNtp);
+  sr.SetRtpTimestamp(kRemoteRtp);
+  auto raw_packet = sr.Build();
+
+  EXPECT_CALL(observer1, OnSenderReport(kRemoteSsrc1, kRemoteNtp, kRemoteRtp));
+  EXPECT_CALL(observer2, OnSenderReport(_, _, _)).Times(0);
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, CallsObserverOnByeBySenderSsrc) {
+  const uint32_t kRemoteSsrc1 = 12345;
+  const uint32_t kRemoteSsrc2 = 22345;
+  StrictMock<MockMediaReceiverRtcpObserver> observer1;
+  StrictMock<MockMediaReceiverRtcpObserver> observer2;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc1, &observer1);
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc2, &observer2);
+
+  Bye bye;
+  bye.SetSenderSsrc(kRemoteSsrc1);
+  auto raw_packet = bye.Build();
+
+  EXPECT_CALL(observer1, OnBye(kRemoteSsrc1));
+  EXPECT_CALL(observer2, OnBye(_)).Times(0);
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, CallsObserverOnTargetBitrateBySenderSsrc) {
+  const uint32_t kRemoteSsrc1 = 12345;
+  const uint32_t kRemoteSsrc2 = 22345;
+  StrictMock<MockMediaReceiverRtcpObserver> observer1;
+  StrictMock<MockMediaReceiverRtcpObserver> observer2;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc1, &observer1);
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc2, &observer2);
+
+  webrtc::rtcp::TargetBitrate target_bitrate;
+  target_bitrate.AddTargetBitrate(0, 0, /*target_bitrate_kbps=*/10);
+  target_bitrate.AddTargetBitrate(0, 1, /*target_bitrate_kbps=*/20);
+  target_bitrate.AddTargetBitrate(1, 0, /*target_bitrate_kbps=*/40);
+  target_bitrate.AddTargetBitrate(1, 1, /*target_bitrate_kbps=*/80);
+  webrtc::rtcp::ExtendedReports xr;
+  xr.SetSenderSsrc(kRemoteSsrc1);
+  xr.SetTargetBitrate(target_bitrate);
+  auto raw_packet = xr.Build();
+
+  VideoBitrateAllocation bitrate_allocation;
+  bitrate_allocation.SetBitrate(0, 0, /*bitrate_bps=*/10000);
+  bitrate_allocation.SetBitrate(0, 1, /*bitrate_bps=*/20000);
+  bitrate_allocation.SetBitrate(1, 0, /*bitrate_bps=*/40000);
+  bitrate_allocation.SetBitrate(1, 1, /*bitrate_bps=*/80000);
+  EXPECT_CALL(observer1, OnBitrateAllocation(kRemoteSsrc1, bitrate_allocation));
+  EXPECT_CALL(observer2, OnBitrateAllocation(_, _)).Times(0);
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, SkipsIncorrectTargetBitrateEntries) {
+  const uint32_t kRemoteSsrc = 12345;
+  MockMediaReceiverRtcpObserver observer;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer);
+
+  webrtc::rtcp::TargetBitrate target_bitrate;
+  target_bitrate.AddTargetBitrate(0, 0, /*target_bitrate_kbps=*/10);
+  target_bitrate.AddTargetBitrate(0, webrtc::kMaxTemporalStreams, 20);
+  target_bitrate.AddTargetBitrate(webrtc::kMaxSpatialLayers, 0, 40);
+
+  webrtc::rtcp::ExtendedReports xr;
+  xr.SetTargetBitrate(target_bitrate);
+  xr.SetSenderSsrc(kRemoteSsrc);
+  auto raw_packet = xr.Build();
+
+  VideoBitrateAllocation expected_allocation;
+  expected_allocation.SetBitrate(0, 0, /*bitrate_bps=*/10000);
+  EXPECT_CALL(observer, OnBitrateAllocation(kRemoteSsrc, expected_allocation));
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, CallsObserverOnByeBehindSenderReport) {
+  const uint32_t kRemoteSsrc = 12345;
+  MockMediaReceiverRtcpObserver observer;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer);
+
+  CompoundPacket compound;
+  SenderReport sr;
+  sr.SetSenderSsrc(kRemoteSsrc);
+  compound.Append(&sr);
+  Bye bye;
+  bye.SetSenderSsrc(kRemoteSsrc);
+  compound.Append(&bye);
+  auto raw_packet = compound.Build();
+
+  EXPECT_CALL(observer, OnBye(kRemoteSsrc));
+  EXPECT_CALL(observer, OnSenderReport(kRemoteSsrc, _, _));
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest, CallsObserverOnByeBehindUnknownRtcpPacket) {
+  const uint32_t kRemoteSsrc = 12345;
+  MockMediaReceiverRtcpObserver observer;
+  RtcpTransceiverImpl rtcp_transceiver(DefaultTestConfig());
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, &observer);
+
+  CompoundPacket compound;
+  // Use Application-Defined rtcp packet as unknown.
+  webrtc::rtcp::App app;
+  compound.Append(&app);
+  Bye bye;
+  bye.SetSenderSsrc(kRemoteSsrc);
+  compound.Append(&bye);
+  auto raw_packet = compound.Build();
+
+  EXPECT_CALL(observer, OnBye(kRemoteSsrc));
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+}
+
+TEST(RtcpTransceiverImplTest,
+     WhenSendsReceiverReportSetsLastSenderReportTimestampPerRemoteSsrc) {
+  const uint32_t kRemoteSsrc1 = 4321;
+  const uint32_t kRemoteSsrc2 = 5321;
+  std::vector<ReportBlock> statistics_report_blocks(2);
+  statistics_report_blocks[0].SetMediaSsrc(kRemoteSsrc1);
+  statistics_report_blocks[1].SetMediaSsrc(kRemoteSsrc2);
+  MockReceiveStatisticsProvider receive_statistics;
+  EXPECT_CALL(receive_statistics, RtcpReportBlocks(_))
+      .WillOnce(Return(statistics_report_blocks));
+
+  RtcpTransceiverConfig config;
+  config.schedule_periodic_compound_packets = false;
+  config.avoid_zero_last_sr_in_last_report_block = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.receive_statistics = &receive_statistics;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  const NtpTime kRemoteNtp(0x9876543211);
+  // Receive SenderReport for RemoteSsrc1, but no report for RemoteSsrc2.
+  SenderReport sr;
+  sr.SetSenderSsrc(kRemoteSsrc1);
+  sr.SetNtp(kRemoteNtp);
+  auto raw_packet = sr.Build();
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+
+  // Trigger sending ReceiverReport.
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
+  const auto& report_blocks = rtcp_parser.receiver_report()->report_blocks();
+  ASSERT_EQ(report_blocks.size(), 2u);
+  // RtcpTransceiverImpl doesn't guarantee order of the report blocks
+  // match result of ReceiveStatisticsProvider::RtcpReportBlocks callback,
+  // but for simplicity of the test asume it is the same.
+  ASSERT_EQ(report_blocks[0].source_ssrc(), kRemoteSsrc1);
+  EXPECT_EQ(report_blocks[0].last_sr(), CompactNtp(kRemoteNtp));
+
+  ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2);
+  // No matching Sender Report for kRemoteSsrc2, LastSR fields has to be 0.
+  EXPECT_EQ(report_blocks[1].last_sr(), 0u);
+}
+
+TEST(RtcpTransceiverImplTest, AvoidLastReportBlockToHaveZeroLastSrField) {
+  const uint32_t kRemoteSsrc1 = 54321;
+  const uint32_t kRemoteSsrc2 = 54323;
+  MockReceiveStatisticsProvider receive_statistics;
+  std::vector<ReportBlock> statistics_report_blocks(2);
+  statistics_report_blocks[0].SetMediaSsrc(kRemoteSsrc1);
+  statistics_report_blocks[1].SetMediaSsrc(kRemoteSsrc2);
+  ON_CALL(receive_statistics, RtcpReportBlocks(_))
+      .WillByDefault(Return(statistics_report_blocks));
+
+  RtcpTransceiverConfig config;
+  config.schedule_periodic_compound_packets = false;
+  config.avoid_zero_last_sr_in_last_report_block = true;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.receive_statistics = &receive_statistics;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  const NtpTime kRemoteNtp(0x9876543211);
+  // Receive SenderReport for RemoteSsrc1, but no report for RemoteSsrc2.
+  SenderReport sr;
+  sr.SetSenderSsrc(kRemoteSsrc1);
+  sr.SetNtp(kRemoteNtp);
+  auto raw_packet = sr.Build();
+  rtcp_transceiver.ReceivePacket(raw_packet, /*now_us=*/0);
+
+  // Trigger sending ReceiverReport.
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
+  const auto& report_blocks = rtcp_parser.receiver_report()->report_blocks();
+  ASSERT_EQ(report_blocks.size(), 2u);
+  // RtcpTransceiverImpl doesn't guarantee order of the report blocks
+  // match result of ReceiveStatisticsProvider::RtcpReportBlocks callback,
+  // but for simplicity of the test asume it is the same.
+  ASSERT_EQ(report_blocks[0].source_ssrc(), kRemoteSsrc1);
+  EXPECT_NE(report_blocks[0].last_sr(), 0u);
+
+  ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2);
+  // No Sender Report for kRemoteSsrc2, use same LastSR as for kRemoteSsrc1
+  EXPECT_EQ(report_blocks[1].last_sr(), report_blocks[0].last_sr());
+  EXPECT_EQ(report_blocks[1].delay_since_last_sr(),
+            report_blocks[0].delay_since_last_sr());
+}
+
+TEST(RtcpTransceiverImplTest,
+     WhenSendsReceiverReportCalculatesDelaySinceLastSenderReport) {
+  const uint32_t kRemoteSsrc1 = 4321;
+  const uint32_t kRemoteSsrc2 = 5321;
+  rtc::ScopedFakeClock clock;
+  std::vector<ReportBlock> statistics_report_blocks(2);
+  statistics_report_blocks[0].SetMediaSsrc(kRemoteSsrc1);
+  statistics_report_blocks[1].SetMediaSsrc(kRemoteSsrc2);
+  MockReceiveStatisticsProvider receive_statistics;
+  EXPECT_CALL(receive_statistics, RtcpReportBlocks(_))
+      .WillOnce(Return(statistics_report_blocks));
+
+  RtcpTransceiverConfig config;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.receive_statistics = &receive_statistics;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  auto receive_sender_report = [&rtcp_transceiver](uint32_t remote_ssrc) {
+    SenderReport sr;
+    sr.SetSenderSsrc(remote_ssrc);
+    auto raw_packet = sr.Build();
+    rtcp_transceiver.ReceivePacket(raw_packet, rtc::TimeMicros());
+  };
+
+  receive_sender_report(kRemoteSsrc1);
+  clock.AdvanceTimeMicros(100 * rtc::kNumMicrosecsPerMillisec);
+
+  receive_sender_report(kRemoteSsrc2);
+  clock.AdvanceTimeMicros(100 * rtc::kNumMicrosecsPerMillisec);
+
+  // Trigger ReceiverReport back.
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
+  const auto& report_blocks = rtcp_parser.receiver_report()->report_blocks();
+  ASSERT_EQ(report_blocks.size(), 2u);
+  // RtcpTransceiverImpl doesn't guarantee order of the report blocks
+  // match result of ReceiveStatisticsProvider::RtcpReportBlocks callback,
+  // but for simplicity of the test asume it is the same.
+  ASSERT_EQ(report_blocks[0].source_ssrc(), kRemoteSsrc1);
+  EXPECT_EQ(CompactNtpRttToMs(report_blocks[0].delay_since_last_sr()), 200);
+
+  ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2);
+  EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100);
+}
+
+TEST(RtcpTransceiverImplTest, SendsNack) {
+  const uint32_t kSenderSsrc = 1234;
+  const uint32_t kRemoteSsrc = 4321;
+  std::vector<uint16_t> kMissingSequenceNumbers = {34, 37, 38};
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendNack(kRemoteSsrc, kMissingSequenceNumbers);
+
+  EXPECT_EQ(rtcp_parser.nack()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.nack()->sender_ssrc(), kSenderSsrc);
+  EXPECT_EQ(rtcp_parser.nack()->media_ssrc(), kRemoteSsrc);
+  EXPECT_EQ(rtcp_parser.nack()->packet_ids(), kMissingSequenceNumbers);
+}
+
+TEST(RtcpTransceiverImplTest, RequestKeyFrameWithPictureLossIndication) {
+  const uint32_t kSenderSsrc = 1234;
+  const uint32_t kRemoteSsrc = 4321;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendPictureLossIndication(kRemoteSsrc);
+
+  EXPECT_EQ(transport.num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.pli()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.pli()->sender_ssrc(), kSenderSsrc);
+  EXPECT_EQ(rtcp_parser.pli()->media_ssrc(), kRemoteSsrc);
+}
+
+TEST(RtcpTransceiverImplTest, RequestKeyFrameWithFullIntraRequest) {
+  const uint32_t kSenderSsrc = 1234;
+  const uint32_t kRemoteSsrcs[] = {4321, 5321};
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendFullIntraRequest(kRemoteSsrcs);
+
+  EXPECT_EQ(rtcp_parser.fir()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.fir()->sender_ssrc(), kSenderSsrc);
+  EXPECT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kRemoteSsrcs[0]);
+  EXPECT_EQ(rtcp_parser.fir()->requests()[1].ssrc, kRemoteSsrcs[1]);
+}
+
+TEST(RtcpTransceiverImplTest, RequestKeyFrameWithFirIncreaseSeqNoPerSsrc) {
+  RtcpTransceiverConfig config;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  const uint32_t kBothRemoteSsrcs[] = {4321, 5321};
+  const uint32_t kOneRemoteSsrc[] = {4321};
+
+  rtcp_transceiver.SendFullIntraRequest(kBothRemoteSsrcs);
+  ASSERT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kBothRemoteSsrcs[0]);
+  uint8_t fir_sequence_number0 = rtcp_parser.fir()->requests()[0].seq_nr;
+  ASSERT_EQ(rtcp_parser.fir()->requests()[1].ssrc, kBothRemoteSsrcs[1]);
+  uint8_t fir_sequence_number1 = rtcp_parser.fir()->requests()[1].seq_nr;
+
+  rtcp_transceiver.SendFullIntraRequest(kOneRemoteSsrc);
+  ASSERT_EQ(rtcp_parser.fir()->requests().size(), 1u);
+  ASSERT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kBothRemoteSsrcs[0]);
+  EXPECT_EQ(rtcp_parser.fir()->requests()[0].seq_nr, fir_sequence_number0 + 1);
+
+  rtcp_transceiver.SendFullIntraRequest(kBothRemoteSsrcs);
+  ASSERT_EQ(rtcp_parser.fir()->requests().size(), 2u);
+  ASSERT_EQ(rtcp_parser.fir()->requests()[0].ssrc, kBothRemoteSsrcs[0]);
+  EXPECT_EQ(rtcp_parser.fir()->requests()[0].seq_nr, fir_sequence_number0 + 2);
+  ASSERT_EQ(rtcp_parser.fir()->requests()[1].ssrc, kBothRemoteSsrcs[1]);
+  EXPECT_EQ(rtcp_parser.fir()->requests()[1].seq_nr, fir_sequence_number1 + 1);
+}
+
+TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesCompoundPacket) {
+  const uint32_t kRemoteSsrcs[] = {4321};
+  RtcpTransceiverConfig config;
+  // Turn periodic off to ensure sent rtcp packet is explicitly requested.
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+
+  config.rtcp_mode = webrtc::RtcpMode::kCompound;
+
+  RtcpTransceiverImpl rtcp_transceiver(config);
+  rtcp_transceiver.SendFullIntraRequest(kRemoteSsrcs);
+
+  // Test sent packet is compound by expecting presense of receiver report.
+  EXPECT_EQ(transport.num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 1);
+}
+
+TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesReducedSizePacket) {
+  const uint32_t kRemoteSsrcs[] = {4321};
+  RtcpTransceiverConfig config;
+  // Turn periodic off to ensure sent rtcp packet is explicitly requested.
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+
+  config.rtcp_mode = webrtc::RtcpMode::kReducedSize;
+
+  RtcpTransceiverImpl rtcp_transceiver(config);
+  rtcp_transceiver.SendFullIntraRequest(kRemoteSsrcs);
+
+  // Test sent packet is reduced size by expecting absense of receiver report.
+  EXPECT_EQ(transport.num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 0);
+}
+
+TEST(RtcpTransceiverImplTest, SendsXrRrtrWhenEnabled) {
+  const uint32_t kSenderSsrc = 4321;
+  rtc::ScopedFakeClock clock;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.non_sender_rtt_measurement = true;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendCompoundPacket();
+  NtpTime ntp_time_now = TimeMicrosToNtp(rtc::TimeMicros());
+
+  EXPECT_EQ(rtcp_parser.xr()->num_packets(), 1);
+  EXPECT_EQ(rtcp_parser.xr()->sender_ssrc(), kSenderSsrc);
+  ASSERT_TRUE(rtcp_parser.xr()->rrtr());
+  EXPECT_EQ(rtcp_parser.xr()->rrtr()->ntp(), ntp_time_now);
+}
+
+TEST(RtcpTransceiverImplTest, SendsNoXrRrtrWhenDisabled) {
+  RtcpTransceiverConfig config;
+  config.schedule_periodic_compound_packets = false;
+  RtcpPacketParser rtcp_parser;
+  RtcpParserTransport transport(&rtcp_parser);
+  config.outgoing_transport = &transport;
+  config.non_sender_rtt_measurement = false;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  rtcp_transceiver.SendCompoundPacket();
+
+  EXPECT_EQ(transport.num_packets(), 1);
+  // Extended reports rtcp packet might be included for another reason,
+  // but it shouldn't contain rrtr block.
+  EXPECT_FALSE(rtcp_parser.xr()->rrtr());
+}
+
+TEST(RtcpTransceiverImplTest, CalculatesRoundTripTimeOnDlrr) {
+  const uint32_t kSenderSsrc = 4321;
+  MockRtcpRttStats rtt_observer;
+  MockTransport null_transport;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  config.outgoing_transport = &null_transport;
+  config.non_sender_rtt_measurement = true;
+  config.rtt_observer = &rtt_observer;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  int64_t time_us = 12345678;
+  webrtc::rtcp::ReceiveTimeInfo rti;
+  rti.ssrc = kSenderSsrc;
+  rti.last_rr = CompactNtp(TimeMicrosToNtp(time_us));
+  rti.delay_since_last_rr = SaturatedUsToCompactNtp(10 * 1000);
+  webrtc::rtcp::ExtendedReports xr;
+  xr.AddDlrrItem(rti);
+  auto raw_packet = xr.Build();
+
+  EXPECT_CALL(rtt_observer, OnRttUpdate(100 /* rtt_ms */));
+  rtcp_transceiver.ReceivePacket(raw_packet, time_us + 110 * 1000);
+}
+
+TEST(RtcpTransceiverImplTest, IgnoresUnknownSsrcInDlrr) {
+  const uint32_t kSenderSsrc = 4321;
+  const uint32_t kUnknownSsrc = 4322;
+  MockRtcpRttStats rtt_observer;
+  MockTransport null_transport;
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.schedule_periodic_compound_packets = false;
+  config.outgoing_transport = &null_transport;
+  config.non_sender_rtt_measurement = true;
+  config.rtt_observer = &rtt_observer;
+  RtcpTransceiverImpl rtcp_transceiver(config);
+
+  int64_t time_us = 12345678;
+  webrtc::rtcp::ReceiveTimeInfo rti;
+  rti.ssrc = kUnknownSsrc;
+  rti.last_rr = CompactNtp(TimeMicrosToNtp(time_us));
+  webrtc::rtcp::ExtendedReports xr;
+  xr.AddDlrrItem(rti);
+  auto raw_packet = xr.Build();
+
+  EXPECT_CALL(rtt_observer, OnRttUpdate(_)).Times(0);
+  rtcp_transceiver.ReceivePacket(raw_packet, time_us + 100000);
+}
+
+}  // namespace
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc
new file mode 100644
index 0000000..1305d9a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_unittest.cc
@@ -0,0 +1,246 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtcp_transceiver.h"
+
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "rtc_base/event.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/mock_transport.h"
+
+namespace {
+
+using ::testing::AtLeast;
+using ::testing::Invoke;
+using ::testing::InvokeWithoutArgs;
+using ::testing::IsNull;
+using ::testing::NiceMock;
+using ::testing::_;
+using ::webrtc::MockTransport;
+using ::webrtc::RtcpTransceiver;
+using ::webrtc::RtcpTransceiverConfig;
+using ::webrtc::rtcp::TransportFeedback;
+
+class MockMediaReceiverRtcpObserver : public webrtc::MediaReceiverRtcpObserver {
+ public:
+  MOCK_METHOD3(OnSenderReport, void(uint32_t, webrtc::NtpTime, uint32_t));
+};
+
+constexpr int kTimeoutMs = 1000;
+
+void WaitPostedTasks(rtc::TaskQueue* queue) {
+  rtc::Event done(false, false);
+  queue->PostTask([&done] { done.Set(); });
+  ASSERT_TRUE(done.Wait(kTimeoutMs));
+}
+
+TEST(RtcpTransceiverTest, SendsRtcpOnTaskQueueWhenCreatedOffTaskQueue) {
+  rtc::TaskQueue queue("rtcp");
+  MockTransport outgoing_transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &outgoing_transport;
+  config.task_queue = &queue;
+  EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+      .WillRepeatedly(InvokeWithoutArgs([&] {
+        EXPECT_TRUE(queue.IsCurrent());
+        return true;
+      }));
+
+  RtcpTransceiver rtcp_transceiver(config);
+  rtcp_transceiver.SendCompoundPacket();
+  WaitPostedTasks(&queue);
+}
+
+TEST(RtcpTransceiverTest, SendsRtcpOnTaskQueueWhenCreatedOnTaskQueue) {
+  rtc::TaskQueue queue("rtcp");
+  MockTransport outgoing_transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &outgoing_transport;
+  config.task_queue = &queue;
+  EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+      .WillRepeatedly(InvokeWithoutArgs([&] {
+        EXPECT_TRUE(queue.IsCurrent());
+        return true;
+      }));
+
+  std::unique_ptr<RtcpTransceiver> rtcp_transceiver;
+  queue.PostTask([&] {
+    rtcp_transceiver = absl::make_unique<RtcpTransceiver>(config);
+    rtcp_transceiver->SendCompoundPacket();
+  });
+  WaitPostedTasks(&queue);
+}
+
+TEST(RtcpTransceiverTest, CanBeDestoryedOnTaskQueue) {
+  rtc::TaskQueue queue("rtcp");
+  NiceMock<MockTransport> outgoing_transport;
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &outgoing_transport;
+  config.task_queue = &queue;
+  auto rtcp_transceiver = absl::make_unique<RtcpTransceiver>(config);
+
+  queue.PostTask([&] { rtcp_transceiver.reset(); });
+  WaitPostedTasks(&queue);
+}
+
+// Use rtp timestamp to distinguish different incoming sender reports.
+rtc::CopyOnWriteBuffer CreateSenderReport(uint32_t ssrc, uint32_t rtp_time) {
+  webrtc::rtcp::SenderReport sr;
+  sr.SetSenderSsrc(ssrc);
+  sr.SetRtpTimestamp(rtp_time);
+  rtc::Buffer buffer = sr.Build();
+  // Switch to an efficient way creating CopyOnWriteBuffer from RtcpPacket when
+  // there is one. Until then do not worry about extra memcpy in test.
+  return rtc::CopyOnWriteBuffer(buffer.data(), buffer.size());
+}
+
+TEST(RtcpTransceiverTest, DoesntPostToRtcpObserverAfterCallToRemove) {
+  const uint32_t kRemoteSsrc = 1234;
+  MockTransport null_transport;
+  rtc::TaskQueue queue("rtcp");
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &null_transport;
+  config.task_queue = &queue;
+  RtcpTransceiver rtcp_transceiver(config);
+  rtc::Event observer_deleted(false, false);
+
+  auto observer = absl::make_unique<MockMediaReceiverRtcpObserver>();
+  EXPECT_CALL(*observer, OnSenderReport(kRemoteSsrc, _, 1));
+  EXPECT_CALL(*observer, OnSenderReport(kRemoteSsrc, _, 2)).Times(0);
+
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, observer.get());
+  rtcp_transceiver.ReceivePacket(CreateSenderReport(kRemoteSsrc, 1));
+  rtcp_transceiver.RemoveMediaReceiverRtcpObserver(
+      kRemoteSsrc, observer.get(),
+      /*on_removed=*/rtc::NewClosure([&] {
+        observer.reset();
+        observer_deleted.Set();
+      }));
+  rtcp_transceiver.ReceivePacket(CreateSenderReport(kRemoteSsrc, 2));
+
+  EXPECT_TRUE(observer_deleted.Wait(kTimeoutMs));
+  WaitPostedTasks(&queue);
+}
+
+TEST(RtcpTransceiverTest, RemoveMediaReceiverRtcpObserverIsNonBlocking) {
+  const uint32_t kRemoteSsrc = 1234;
+  MockTransport null_transport;
+  rtc::TaskQueue queue("rtcp");
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &null_transport;
+  config.task_queue = &queue;
+  RtcpTransceiver rtcp_transceiver(config);
+  auto observer = absl::make_unique<MockMediaReceiverRtcpObserver>();
+  rtcp_transceiver.AddMediaReceiverRtcpObserver(kRemoteSsrc, observer.get());
+
+  rtc::Event queue_blocker(false, false);
+  rtc::Event observer_deleted(false, false);
+  queue.PostTask([&] { EXPECT_TRUE(queue_blocker.Wait(kTimeoutMs)); });
+  rtcp_transceiver.RemoveMediaReceiverRtcpObserver(
+      kRemoteSsrc, observer.get(),
+      /*on_removed=*/rtc::NewClosure([&] {
+        observer.reset();
+        observer_deleted.Set();
+      }));
+
+  EXPECT_THAT(observer, Not(IsNull()));
+  queue_blocker.Set();
+  EXPECT_TRUE(observer_deleted.Wait(kTimeoutMs));
+}
+
+TEST(RtcpTransceiverTest, CanCallSendCompoundPacketFromAnyThread) {
+  MockTransport outgoing_transport;
+  rtc::TaskQueue queue("rtcp");
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &outgoing_transport;
+  config.task_queue = &queue;
+
+  EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+      // If test is slow, a periodic task may send an extra packet.
+      .Times(AtLeast(3))
+      .WillRepeatedly(InvokeWithoutArgs([&] {
+        EXPECT_TRUE(queue.IsCurrent());
+        return true;
+      }));
+
+  RtcpTransceiver rtcp_transceiver(config);
+
+  // Call from the construction thread.
+  rtcp_transceiver.SendCompoundPacket();
+  // Call from the same queue transceiver use for processing.
+  queue.PostTask([&] { rtcp_transceiver.SendCompoundPacket(); });
+  // Call from unrelated task queue.
+  rtc::TaskQueue queue_send("send_packet");
+  queue_send.PostTask([&] { rtcp_transceiver.SendCompoundPacket(); });
+
+  WaitPostedTasks(&queue_send);
+  WaitPostedTasks(&queue);
+}
+
+TEST(RtcpTransceiverTest, DoesntSendPacketsAfterDestruction) {
+  MockTransport outgoing_transport;
+  rtc::TaskQueue queue("rtcp");
+  RtcpTransceiverConfig config;
+  config.outgoing_transport = &outgoing_transport;
+  config.task_queue = &queue;
+  config.schedule_periodic_compound_packets = false;
+
+  EXPECT_CALL(outgoing_transport, SendRtcp(_, _)).Times(0);
+
+  auto rtcp_transceiver = absl::make_unique<RtcpTransceiver>(config);
+  rtc::Event pause(false, false);
+  queue.PostTask([&] {
+    pause.Wait(rtc::Event::kForever);
+    rtcp_transceiver.reset();
+  });
+  rtcp_transceiver->SendCompoundPacket();
+  pause.Set();
+  WaitPostedTasks(&queue);
+  EXPECT_FALSE(rtcp_transceiver);
+}
+
+TEST(RtcpTransceiverTest, SendsTransportFeedbackOnTaskQueue) {
+  static constexpr uint32_t kSenderSsrc = 12345;
+  MockTransport outgoing_transport;
+  rtc::TaskQueue queue("rtcp");
+  RtcpTransceiverConfig config;
+  config.feedback_ssrc = kSenderSsrc;
+  config.outgoing_transport = &outgoing_transport;
+  config.task_queue = &queue;
+  config.schedule_periodic_compound_packets = false;
+  RtcpTransceiver rtcp_transceiver(config);
+
+  EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+      .WillOnce(Invoke([&](const uint8_t* buffer, size_t size) {
+        EXPECT_TRUE(queue.IsCurrent());
+
+        std::unique_ptr<TransportFeedback> transport_feedback =
+            TransportFeedback::ParseFrom(buffer, size);
+        EXPECT_TRUE(transport_feedback);
+        EXPECT_EQ(transport_feedback->sender_ssrc(), kSenderSsrc);
+        return true;
+      }));
+
+  // Create minimalistic transport feedback packet.
+  TransportFeedback transport_feedback;
+  transport_feedback.SetSenderSsrc(rtcp_transceiver.SSRC());
+  transport_feedback.AddReceivedPacket(321, 10000);
+
+  EXPECT_TRUE(rtcp_transceiver.SendFeedbackPacket(transport_feedback));
+
+  WaitPostedTasks(&queue);
+}
+
+}  // namespace
diff --git a/modules/rtp_rtcp/source/rtp_fec_unittest.cc b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
new file mode 100644
index 0000000..cbad0ae
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_fec_unittest.cc
@@ -0,0 +1,1134 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <algorithm>
+#include <list>
+#include <memory>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+#include "modules/rtp_rtcp/source/flexfec_header_reader_writer.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+// Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum.
+constexpr size_t kTransportOverhead = 28;
+
+constexpr uint32_t kMediaSsrc = 83542;
+constexpr uint32_t kFlexfecSsrc = 43245;
+
+constexpr size_t kMaxMediaPackets = 48;
+
+// Deep copies |src| to |dst|, but only keeps every Nth packet.
+void DeepCopyEveryNthPacket(const ForwardErrorCorrection::PacketList& src,
+                            int n,
+                            ForwardErrorCorrection::PacketList* dst) {
+  RTC_DCHECK_GT(n, 0);
+  int i = 0;
+  for (const auto& packet : src) {
+    if (i % n == 0) {
+      dst->emplace_back(new ForwardErrorCorrection::Packet(*packet));
+    }
+    ++i;
+  }
+}
+
+}  // namespace
+
+using ::testing::Types;
+
+template <typename ForwardErrorCorrectionType>
+class RtpFecTest : public ::testing::Test {
+ protected:
+  RtpFecTest()
+      : random_(0xabcdef123456),
+        media_packet_generator_(
+            kRtpHeaderSize,  // Minimum packet size.
+            IP_PACKET_SIZE - kRtpHeaderSize - kTransportOverhead -
+                fec_.MaxPacketOverhead(),  // Maximum packet size.
+            kMediaSsrc,
+            &random_) {}
+
+  // Construct |received_packets_|: a subset of the media and FEC packets.
+  //
+  // Media packet "i" is lost if media_loss_mask_[i] = 1, received if
+  // media_loss_mask_[i] = 0.
+  // FEC packet "i" is lost if fec_loss_mask_[i] = 1, received if
+  // fec_loss_mask_[i] = 0.
+  void NetworkReceivedPackets(int* media_loss_mask, int* fec_loss_mask);
+
+  // Add packet from |packet_list| to list of received packets, using the
+  // |loss_mask|.
+  // The |packet_list| may be a media packet list (is_fec = false), or a
+  // FEC packet list (is_fec = true).
+  template <typename T>
+  void ReceivedPackets(const T& packet_list, int* loss_mask, bool is_fec);
+
+  // Check for complete recovery after FEC decoding.
+  bool IsRecoveryComplete();
+
+  ForwardErrorCorrectionType fec_;
+
+  Random random_;
+  test::fec::MediaPacketGenerator media_packet_generator_;
+
+  ForwardErrorCorrection::PacketList media_packets_;
+  std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_;
+  std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
+      received_packets_;
+  ForwardErrorCorrection::RecoveredPacketList recovered_packets_;
+
+  int media_loss_mask_[kUlpfecMaxMediaPackets];
+  int fec_loss_mask_[kUlpfecMaxMediaPackets];
+};
+
+template <typename ForwardErrorCorrectionType>
+void RtpFecTest<ForwardErrorCorrectionType>::NetworkReceivedPackets(
+    int* media_loss_mask,
+    int* fec_loss_mask) {
+  constexpr bool kFecPacket = true;
+  this->received_packets_.clear();
+  ReceivedPackets(media_packets_, media_loss_mask, !kFecPacket);
+  ReceivedPackets(generated_fec_packets_, fec_loss_mask, kFecPacket);
+}
+
+template <typename ForwardErrorCorrectionType>
+template <typename PacketListType>
+void RtpFecTest<ForwardErrorCorrectionType>::ReceivedPackets(
+    const PacketListType& packet_list,
+    int* loss_mask,
+    bool is_fec) {
+  uint16_t fec_seq_num = ForwardErrorCorrectionType::GetFirstFecSeqNum(
+      media_packet_generator_.GetNextSeqNum());
+  int packet_idx = 0;
+
+  for (const auto& packet : packet_list) {
+    if (loss_mask[packet_idx] == 0) {
+      std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
+          new ForwardErrorCorrection::ReceivedPacket());
+      received_packet->pkt = new ForwardErrorCorrection::Packet();
+      received_packet->pkt->length = packet->length;
+      memcpy(received_packet->pkt->data, packet->data, packet->length);
+      received_packet->is_fec = is_fec;
+      if (!is_fec) {
+        received_packet->ssrc = kMediaSsrc;
+        // For media packets, the sequence number is obtained from the
+        // RTP header as written by MediaPacketGenerator::ConstructMediaPackets.
+        received_packet->seq_num =
+            ByteReader<uint16_t>::ReadBigEndian(&packet->data[2]);
+      } else {
+        received_packet->ssrc = ForwardErrorCorrectionType::kFecSsrc;
+        // For FEC packets, we simulate the sequence numbers differently
+        // depending on if ULPFEC or FlexFEC is used. See the definition of
+        // ForwardErrorCorrectionType::GetFirstFecSeqNum.
+        received_packet->seq_num = fec_seq_num;
+      }
+      received_packets_.push_back(std::move(received_packet));
+    }
+    packet_idx++;
+    // Sequence number of FEC packets are defined as increment by 1 from
+    // last media packet in frame.
+    if (is_fec)
+      fec_seq_num++;
+  }
+}
+
+template <typename ForwardErrorCorrectionType>
+bool RtpFecTest<ForwardErrorCorrectionType>::IsRecoveryComplete() {
+  // We must have equally many recovered packets as original packets.
+  if (recovered_packets_.size() != media_packets_.size()) {
+    return false;
+  }
+
+  // All recovered packets must be identical to the corresponding
+  // original packets.
+  auto cmp =
+      [](const std::unique_ptr<ForwardErrorCorrection::Packet>& media_packet,
+         const std::unique_ptr<ForwardErrorCorrection::RecoveredPacket>&
+             recovered_packet) {
+        if (media_packet->length != recovered_packet->pkt->length) {
+          return false;
+        }
+        if (memcmp(media_packet->data, recovered_packet->pkt->data,
+                   media_packet->length) != 0) {
+          return false;
+        }
+        return true;
+      };
+  return std::equal(media_packets_.cbegin(), media_packets_.cend(),
+                    recovered_packets_.cbegin(), cmp);
+}
+
+// Define gTest typed test to loop over both ULPFEC and FlexFEC.
+// Since the tests now are parameterized, we need to access
+// member variables using |this|, thereby enforcing runtime
+// resolution.
+
+class FlexfecForwardErrorCorrection : public ForwardErrorCorrection {
+ public:
+  static const uint32_t kFecSsrc = kFlexfecSsrc;
+
+  FlexfecForwardErrorCorrection()
+      : ForwardErrorCorrection(
+            std::unique_ptr<FecHeaderReader>(new FlexfecHeaderReader()),
+            std::unique_ptr<FecHeaderWriter>(new FlexfecHeaderWriter()),
+            kFecSsrc,
+            kMediaSsrc) {}
+
+  // For FlexFEC we let the FEC packet sequence numbers be independent of
+  // the media packet sequence numbers.
+  static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
+    Random random(0xbe110);
+    return random.Rand<uint16_t>();
+  }
+};
+
+class UlpfecForwardErrorCorrection : public ForwardErrorCorrection {
+ public:
+  static const uint32_t kFecSsrc = kMediaSsrc;
+
+  UlpfecForwardErrorCorrection()
+      : ForwardErrorCorrection(
+            std::unique_ptr<FecHeaderReader>(new UlpfecHeaderReader()),
+            std::unique_ptr<FecHeaderWriter>(new UlpfecHeaderWriter()),
+            kFecSsrc,
+            kMediaSsrc) {}
+
+  // For ULPFEC we assume that the FEC packets are subsequent to the media
+  // packets in terms of sequence number.
+  static uint16_t GetFirstFecSeqNum(uint16_t next_media_seq_num) {
+    return next_media_seq_num;
+  }
+};
+
+using FecTypes =
+    Types<FlexfecForwardErrorCorrection, UlpfecForwardErrorCorrection>;
+TYPED_TEST_CASE(RtpFecTest, FecTypes);
+
+TYPED_TEST(RtpFecTest, WillProtectMediaPacketsWithLargeSequenceNumberGap) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 2;
+  constexpr uint8_t kProtectionFactor = 127;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  // Create |kMaxMediaPackets - 1| sequence number difference.
+  ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.front()->data[2],
+                                       1);
+  ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.back()->data[2],
+                                       kMaxMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+}
+
+TYPED_TEST(RtpFecTest,
+           WillNotProtectMediaPacketsWithTooLargeSequenceNumberGap) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 2;
+  constexpr uint8_t kProtectionFactor = 127;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  // Create |kMaxMediaPackets| sequence number difference.
+  ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.front()->data[2],
+                                       1);
+  ByteWriter<uint16_t>::WriteBigEndian(&this->media_packets_.back()->data[2],
+                                       kMaxMediaPackets + 1);
+
+  EXPECT_EQ(
+      -1, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                               kNumImportantPackets, kUseUnequalProtection,
+                               kFecMaskBursty, &this->generated_fec_packets_));
+  EXPECT_TRUE(this->generated_fec_packets_.empty());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryNoLoss) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 60;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // No packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // No packets lost, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryWithLoss) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 60;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // 1 media packet lost
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // One packet lost, one FEC packet, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 2 media packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // 2 packets lost, one FEC packet, cannot get complete recovery.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+// Verify that we don't use an old FEC packet for FEC decoding.
+TYPED_TEST(RtpFecTest, NoFecRecoveryWithOldFecPacket) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr uint8_t kProtectionFactor = 20;
+
+  // Two frames: first frame (old) with two media packets and 1 FEC packet.
+  // Third frame (new) with 3 media packets, and no FEC packets.
+  //
+  //  #0(media) #1(media) #2(FEC)              ----Frame 1-----
+  //  #32767(media) 32768(media) 32769(media)  ----Frame 2-----
+  //  #65535(media) #0(media) #1(media).       ----Frame 3-----
+  // If we lose either packet 0 or 1 of third frame, FEC decoding should not
+  // try to decode using "old" FEC packet #2.
+
+  // Construct media packets for first frame, starting at sequence number 0.
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(2, 0);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+  // Add FEC packet (seq#2) of this first frame to received list (i.e., assume
+  // the two media packet were lost).
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
+                        true);
+
+  // Construct media packets for second frame, with sequence number wrap.
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 32767);
+
+  // Expect 3 media packets for this frame.
+  EXPECT_EQ(3u, this->media_packets_.size());
+
+  // No packets lost
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
+
+  // Construct media packets for third frame, with sequence number wrap.
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 65535);
+
+  // Expect 3 media packets for this frame.
+  EXPECT_EQ(3u, this->media_packets_.size());
+
+  // Second media packet lost (seq#0).
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  // Add packets #65535, and #1 to received list.
+  this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Expect that no decoding is done to get missing packet (seq#0) of third
+  // frame, using old FEC packet (seq#2) from first (old) frame. So number of
+  // recovered packets is 5 (0 from first frame, three from second frame, and 2
+  // for the third frame, with no packets recovered via FEC).
+  EXPECT_EQ(5u, this->recovered_packets_.size());
+  EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
+}
+
+// Verify we can still recover frame if sequence number wrap occurs within
+// the frame and FEC packet following wrap is received after media packets.
+TYPED_TEST(RtpFecTest, FecRecoveryWithSeqNumGapOneFrameRecovery) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr uint8_t kProtectionFactor = 20;
+
+  // One frame, with sequence number wrap in media packets.
+  //         -----Frame 1----
+  //  #65534(media) #65535(media) #0(media) #1(FEC).
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 65534);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // Lose one media packet (seq# 65535).
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
+  // Add FEC packet to received list following the media packets.
+  this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
+                        true);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Expect 3 media packets in recovered list, and complete recovery.
+  // Wrap-around won't remove FEC packet, as it follows the wrap.
+  EXPECT_EQ(3u, this->recovered_packets_.size());
+  EXPECT_TRUE(this->IsRecoveryComplete());
+}
+
+// Sequence number wrap occurs within the ULPFEC packets for the frame.
+// Same problem will occur if wrap is within media packets but ULPFEC packet is
+// received before the media packets. This may be improved if timing information
+// is used to detect old ULPFEC packets.
+
+// TODO(nisse): There's some logic to discard ULPFEC packets at wrap-around,
+// however, that is not actually exercised by this test: When the first FEC
+// packet is processed, it results in full recovery of one media packet and the
+// FEC packet is forgotten. And then the wraparound isn't noticed when the next
+// FEC packet is received. We should fix wraparound handling, which currently
+// appears broken, and then figure out how to test it properly.
+using RtpFecTestUlpfecOnly = RtpFecTest<UlpfecForwardErrorCorrection>;
+TEST_F(RtpFecTestUlpfecOnly, FecRecoveryWithSeqNumGapOneFrameRecovery) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr uint8_t kProtectionFactor = 200;
+
+  // 1 frame: 3 media packets and 2 FEC packets.
+  // Sequence number wrap in FEC packets.
+  //           -----Frame 1----
+  // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 65532);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 2 FEC packets.
+  EXPECT_EQ(2u, this->generated_fec_packets_.size());
+
+  // Lose the last two media packets (seq# 65533, 65534).
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
+  this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
+                        true);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // The two FEC packets are received and should allow for complete recovery,
+  // but because of the wrap the first FEC packet will be discarded, and only
+  // one media packet is recoverable. So expect 2 media packets on recovered
+  // list and no complete recovery.
+  EXPECT_EQ(3u, this->recovered_packets_.size());
+  EXPECT_EQ(this->recovered_packets_.size(), this->media_packets_.size());
+  EXPECT_TRUE(this->IsRecoveryComplete());
+}
+
+// TODO(brandtr): This test mimics the one above, ensuring that the recovery
+// strategy of FlexFEC matches the recovery strategy of ULPFEC. Since FlexFEC
+// does not share the sequence number space with the media, however, having a
+// matching recovery strategy may be suboptimal. Study this further.
+// TODO(nisse): In this test, recovery based on the first FEC packet fails with
+// the log message "The recovered packet had a length larger than a typical IP
+// packet, and is thus dropped." This is probably not intended, and needs
+// investigation.
+using RtpFecTestFlexfecOnly = RtpFecTest<FlexfecForwardErrorCorrection>;
+TEST_F(RtpFecTestFlexfecOnly, FecRecoveryWithSeqNumGapOneFrameNoRecovery) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr uint8_t kProtectionFactor = 200;
+
+  // 1 frame: 3 media packets and 2 FEC packets.
+  // Sequence number wrap in FEC packets.
+  //           -----Frame 1----
+  // #65532(media) #65533(media) #65534(media) #65535(FEC) #0(FEC).
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 65532);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 2 FEC packets.
+  EXPECT_EQ(2u, this->generated_fec_packets_.size());
+
+  // Overwrite the sequence numbers generated by ConstructMediaPackets,
+  // to make sure that we do have a wrap.
+  auto it = this->generated_fec_packets_.begin();
+  ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 65535);
+  ++it;
+  ByteWriter<uint16_t>::WriteBigEndian(&(*it)->data[2], 0);
+
+  // Lose the last two media packets (seq# 65533, 65534).
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
+  this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
+                        true);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // The two FEC packets are received and should allow for complete recovery,
+  // but because of the wrap the first FEC packet will be discarded, and only
+  // one media packet is recoverable. So expect 2 media packets on recovered
+  // list and no complete recovery.
+  EXPECT_EQ(2u, this->recovered_packets_.size());
+  EXPECT_TRUE(this->recovered_packets_.size() != this->media_packets_.size());
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+// Verify we can still recover frame if media packets are reordered.
+TYPED_TEST(RtpFecTest, FecRecoveryWithMediaOutOfOrder) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr uint8_t kProtectionFactor = 20;
+
+  // One frame: 3 media packets, 1 FEC packet.
+  //         -----Frame 1----
+  //  #0(media) #1(media) #2(media) #3(FEC).
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 0);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // Lose one media packet (seq# 1).
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  // Reorder received media packets.
+  auto it0 = this->received_packets_.begin();
+  auto it1 = this->received_packets_.begin();
+  it1++;
+  std::swap(*it0, *it1);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Expect 3 media packets in recovered list, and complete recovery.
+  EXPECT_EQ(3u, this->recovered_packets_.size());
+  EXPECT_TRUE(this->IsRecoveryComplete());
+}
+
+// Verify we can still recover frame if FEC is received before media packets.
+TYPED_TEST(RtpFecTest, FecRecoveryWithFecOutOfOrder) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr uint8_t kProtectionFactor = 20;
+
+  // One frame: 3 media packets, 1 FEC packet.
+  //         -----Frame 1----
+  //  #0(media) #1(media) #2(media) #3(FEC).
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(3, 0);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // Lose one media packet (seq# 1).
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  // Add FEC packet to received list before the media packets.
+  this->ReceivedPackets(this->generated_fec_packets_, this->fec_loss_mask_,
+                        true);
+  // Add media packets to received list.
+  this->ReceivedPackets(this->media_packets_, this->media_loss_mask_, false);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Expect 3 media packets in recovered list, and complete recovery.
+  EXPECT_EQ(3u, this->recovered_packets_.size());
+  EXPECT_TRUE(this->IsRecoveryComplete());
+}
+
+// Test 50% protection with random mask type: Two cases are considered:
+// a 50% non-consecutive loss which can be fully recovered, and a 50%
+// consecutive loss which cannot be fully recovered.
+TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 255;
+
+  // Packet Mask for (4,4,0) code, from random mask table.
+  // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
+
+  //         media#0   media#1  media#2    media#3
+  // fec#0:    1          1        0          0
+  // fec#1:    1          0        1          0
+  // fec#2:    0          0        1          1
+  // fec#3:    0          1        0          1
+  //
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskRandom, &this->generated_fec_packets_));
+
+  // Expect 4 FEC packets.
+  EXPECT_EQ(4u, this->generated_fec_packets_.size());
+
+  // 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->fec_loss_mask_[0] = 1;
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 4 consecutive packets lost: media packets 0, 1, 2, 3.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Cannot get complete recovery for this loss configuration with random mask.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+// Test 50% protection with bursty type: Three cases are considered:
+// two 50% consecutive losses which can be fully recovered, and one
+// non-consecutive which cannot be fully recovered.
+TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 255;
+
+  // Packet Mask for (4,4,0) code, from bursty mask table.
+  // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
+
+  //         media#0   media#1  media#2    media#3
+  // fec#0:    1          0        0          0
+  // fec#1:    1          1        0          0
+  // fec#2:    0          1        1          0
+  // fec#3:    0          0        1          1
+  //
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 4 FEC packets.
+  EXPECT_EQ(4u, this->generated_fec_packets_.size());
+
+  // 4 consecutive packets lost: media packets 0,1,2,3.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Expect complete recovery for consecutive packet loss <= 50%.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->fec_loss_mask_[0] = 1;
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Expect complete recovery for consecutive packet loss <= 50%.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->fec_loss_mask_[0] = 1;
+  this->fec_loss_mask_[3] = 1;
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Cannot get complete recovery for this loss configuration.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryNoLossUep) {
+  constexpr int kNumImportantPackets = 2;
+  constexpr bool kUseUnequalProtection = true;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 60;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // No packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // No packets lost, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryWithLossUep) {
+  constexpr int kNumImportantPackets = 2;
+  constexpr bool kUseUnequalProtection = true;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 60;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // 1 media packet lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // One packet lost, one FEC packet, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 2 media packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // 2 packets lost, one FEC packet, cannot get complete recovery.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+// Test 50% protection with random mask type for UEP on.
+TYPED_TEST(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
+  constexpr int kNumImportantPackets = 1;
+  constexpr bool kUseUnequalProtection = true;
+  constexpr int kNumMediaPackets = 4;
+  constexpr uint8_t kProtectionFactor = 255;
+
+  // Packet Mask for (4,4,1) code, from random mask table.
+  // (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
+
+  //         media#0   media#1  media#2    media#3
+  // fec#0:    1          0        0          0
+  // fec#1:    1          1        0          0
+  // fec#2:    1          0        1          1
+  // fec#3:    0          1        1          0
+  //
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(this->media_packets_, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskRandom, &this->generated_fec_packets_));
+
+  // Expect 4 FEC packets.
+  EXPECT_EQ(4u, this->generated_fec_packets_.size());
+
+  // 4 packets lost: 3 media packets and FEC packet#1 lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->fec_loss_mask_[1] = 1;
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 5 packets lost: 4 media packets and one FEC packet#2 lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->fec_loss_mask_[2] = 1;
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[1] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->media_loss_mask_[3] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Cannot get complete recovery for this loss configuration.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePackets) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 5;
+  constexpr uint8_t kProtectionFactor = 60;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  // Create a new temporary packet list for generating FEC packets.
+  // This list should have every other packet removed.
+  ForwardErrorCorrection::PacketList protected_media_packets;
+  DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
+
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 1 FEC packet.
+  EXPECT_EQ(1u, this->generated_fec_packets_.size());
+
+  // 1 protected media packet lost
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[2] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // One packet lost, one FEC packet, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // Unprotected packet lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[1] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Unprotected packet lost. Recovery not possible.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 2 media packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[0] = 1;
+  this->media_loss_mask_[2] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // 2 protected packets lost, one FEC packet, cannot get complete recovery.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 21;
+  uint8_t kProtectionFactor = 127;
+
+  this->media_packets_ =
+      this->media_packet_generator_.ConstructMediaPackets(kNumMediaPackets);
+
+  // Create a new temporary packet list for generating FEC packets.
+  // This list should have every other packet removed.
+  ForwardErrorCorrection::PacketList protected_media_packets;
+  DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
+
+  // Zero column insertion will have to extend the size of the packet
+  // mask since the number of actual packets are 21, while the number
+  // of protected packets are 11.
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 5 FEC packet.
+  EXPECT_EQ(5u, this->generated_fec_packets_.size());
+
+  // Last protected media packet lost
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[kNumMediaPackets - 1] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // One packet lost, one FEC packet, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // Last unprotected packet lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[kNumMediaPackets - 2] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Unprotected packet lost. Recovery not possible.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 6 media packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[kNumMediaPackets - 11] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 9] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 7] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 5] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 3] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 1] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // 5 protected packets lost, one FEC packet, cannot get complete recovery.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+TYPED_TEST(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr int kNumMediaPackets = 21;
+  uint8_t kProtectionFactor = 127;
+
+  this->media_packets_ = this->media_packet_generator_.ConstructMediaPackets(
+      kNumMediaPackets, 0xFFFF - 5);
+
+  // Create a new temporary packet list for generating FEC packets.
+  // This list should have every other packet removed.
+  ForwardErrorCorrection::PacketList protected_media_packets;
+  DeepCopyEveryNthPacket(this->media_packets_, 2, &protected_media_packets);
+
+  // Zero column insertion will have to extend the size of the packet
+  // mask since the number of actual packets are 21, while the number
+  // of protected packets are 11.
+  EXPECT_EQ(
+      0, this->fec_.EncodeFec(protected_media_packets, kProtectionFactor,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              kFecMaskBursty, &this->generated_fec_packets_));
+
+  // Expect 5 FEC packet.
+  EXPECT_EQ(5u, this->generated_fec_packets_.size());
+
+  // Last protected media packet lost
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[kNumMediaPackets - 1] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // One packet lost, one FEC packet, expect complete recovery.
+  EXPECT_TRUE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // Last unprotected packet lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[kNumMediaPackets - 2] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // Unprotected packet lost. Recovery not possible.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+  this->recovered_packets_.clear();
+
+  // 6 media packets lost.
+  memset(this->media_loss_mask_, 0, sizeof(this->media_loss_mask_));
+  memset(this->fec_loss_mask_, 0, sizeof(this->fec_loss_mask_));
+  this->media_loss_mask_[kNumMediaPackets - 11] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 9] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 7] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 5] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 3] = 1;
+  this->media_loss_mask_[kNumMediaPackets - 1] = 1;
+  this->NetworkReceivedPackets(this->media_loss_mask_, this->fec_loss_mask_);
+
+  for (const auto& received_packet : this->received_packets_) {
+    this->fec_.DecodeFec(*received_packet, &this->recovered_packets_);
+  }
+
+  // 5 protected packets lost, one FEC packet, cannot get complete recovery.
+  EXPECT_FALSE(this->IsRecoveryComplete());
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format.cc b/modules/rtp_rtcp/source/rtp_format.cc
new file mode 100644
index 0000000..8bd27a7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format.cc
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_format.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/rtp_format_h264.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
+#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
+
+namespace webrtc {
+RtpPacketizer* RtpPacketizer::Create(VideoCodecType type,
+                                     size_t max_payload_len,
+                                     size_t last_packet_reduction_len,
+                                     const RTPVideoHeader* rtp_video_header,
+                                     FrameType frame_type) {
+  switch (type) {
+    case kVideoCodecH264:
+      RTC_CHECK(rtp_video_header);
+      return new RtpPacketizerH264(max_payload_len, last_packet_reduction_len,
+                                   rtp_video_header->h264().packetization_mode);
+    case kVideoCodecVP8:
+      RTC_CHECK(rtp_video_header);
+      return new RtpPacketizerVp8(rtp_video_header->vp8(), max_payload_len,
+                                  last_packet_reduction_len);
+    case kVideoCodecVP9:
+      RTC_CHECK(rtp_video_header);
+      return new RtpPacketizerVp9(rtp_video_header->vp9(), max_payload_len,
+                                  last_packet_reduction_len);
+    case kVideoCodecGeneric:
+      return new RtpPacketizerGeneric(frame_type, max_payload_len,
+                                      last_packet_reduction_len);
+    default:
+      RTC_NOTREACHED();
+  }
+  return nullptr;
+}
+
+RtpDepacketizer* RtpDepacketizer::Create(VideoCodecType type) {
+  switch (type) {
+    case kVideoCodecH264:
+      return new RtpDepacketizerH264();
+    case kVideoCodecVP8:
+      return new RtpDepacketizerVp8();
+    case kVideoCodecVP9:
+      return new RtpDepacketizerVp9();
+    case kVideoCodecGeneric:
+      return new RtpDepacketizerGeneric();
+    default:
+      RTC_NOTREACHED();
+  }
+  return nullptr;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format.h b/modules/rtp_rtcp/source/rtp_format.h
new file mode 100644
index 0000000..76d7f47
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format.h
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
+
+#include <string>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+class RtpPacketToSend;
+
+class RtpPacketizer {
+ public:
+  static RtpPacketizer* Create(VideoCodecType type,
+                               size_t max_payload_len,
+                               size_t last_packet_reduction_len,
+                               const RTPVideoHeader* rtp_video_header,
+                               FrameType frame_type);
+
+  virtual ~RtpPacketizer() {}
+
+  // Returns total number of packets which would be produced by the packetizer.
+  virtual size_t SetPayloadData(
+      const uint8_t* payload_data,
+      size_t payload_size,
+      const RTPFragmentationHeader* fragmentation) = 0;
+
+  // Get the next payload with payload header.
+  // Write payload and set marker bit of the |packet|.
+  // Returns true on success, false otherwise.
+  virtual bool NextPacket(RtpPacketToSend* packet) = 0;
+
+  virtual std::string ToString() = 0;
+};
+
+// TODO(sprang): Update the depacketizer to return a std::unqie_ptr with a copy
+// of the parsed payload, rather than just a pointer into the incoming buffer.
+// This way we can move some parsing out from the jitter buffer into here, and
+// the jitter buffer can just store that pointer rather than doing a copy there.
+class RtpDepacketizer {
+ public:
+  struct ParsedPayload {
+    RTPVideoHeader& video_header() { return video; }
+    const RTPVideoHeader& video_header() const { return video; }
+    RTPVideoHeader video;
+
+    const uint8_t* payload;
+    size_t payload_length;
+    FrameType frame_type;
+  };
+
+  static RtpDepacketizer* Create(VideoCodecType type);
+
+  virtual ~RtpDepacketizer() {}
+
+  // Parses the RTP payload, parsed result will be saved in |parsed_payload|.
+  virtual bool Parse(ParsedPayload* parsed_payload,
+                     const uint8_t* payload_data,
+                     size_t payload_data_length) = 0;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_h264.cc b/modules/rtp_rtcp/source/rtp_format_h264.cc
new file mode 100644
index 0000000..0b8c15f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_h264.cc
@@ -0,0 +1,689 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_format_h264.h"
+
+#include <string.h>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "common_video/h264/h264_common.h"
+#include "common_video/h264/pps_parser.h"
+#include "common_video/h264/sps_parser.h"
+#include "common_video/h264/sps_vui_rewriter.h"
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/system/fallthrough.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+namespace {
+
+static const size_t kNalHeaderSize = 1;
+static const size_t kFuAHeaderSize = 2;
+static const size_t kLengthFieldSize = 2;
+static const size_t kStapAHeaderSize = kNalHeaderSize + kLengthFieldSize;
+
+static const char* kSpsValidHistogramName = "WebRTC.Video.H264.SpsValid";
+enum SpsValidEvent {
+  kReceivedSpsPocOk = 0,
+  kReceivedSpsVuiOk = 1,
+  kReceivedSpsRewritten = 2,
+  kReceivedSpsParseFailure = 3,
+  kSentSpsPocOk = 4,
+  kSentSpsVuiOk = 5,
+  kSentSpsRewritten = 6,
+  kSentSpsParseFailure = 7,
+  kSpsRewrittenMax = 8
+};
+
+// Bit masks for FU (A and B) indicators.
+enum NalDefs : uint8_t { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
+
+// Bit masks for FU (A and B) headers.
+enum FuDefs : uint8_t { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
+
+// TODO(pbos): Avoid parsing this here as well as inside the jitter buffer.
+bool ParseStapAStartOffsets(const uint8_t* nalu_ptr,
+                            size_t length_remaining,
+                            std::vector<size_t>* offsets) {
+  size_t offset = 0;
+  while (length_remaining > 0) {
+    // Buffer doesn't contain room for additional nalu length.
+    if (length_remaining < sizeof(uint16_t))
+      return false;
+    uint16_t nalu_size = ByteReader<uint16_t>::ReadBigEndian(nalu_ptr);
+    nalu_ptr += sizeof(uint16_t);
+    length_remaining -= sizeof(uint16_t);
+    if (nalu_size > length_remaining)
+      return false;
+    nalu_ptr += nalu_size;
+    length_remaining -= nalu_size;
+
+    offsets->push_back(offset + kStapAHeaderSize);
+    offset += kLengthFieldSize + nalu_size;
+  }
+  return true;
+}
+
+}  // namespace
+
+RtpPacketizerH264::RtpPacketizerH264(size_t max_payload_len,
+                                     size_t last_packet_reduction_len,
+                                     H264PacketizationMode packetization_mode)
+    : max_payload_len_(max_payload_len),
+      last_packet_reduction_len_(last_packet_reduction_len),
+      num_packets_left_(0),
+      packetization_mode_(packetization_mode) {
+  // Guard against uninitialized memory in packetization_mode.
+  RTC_CHECK(packetization_mode == H264PacketizationMode::NonInterleaved ||
+            packetization_mode == H264PacketizationMode::SingleNalUnit);
+  RTC_CHECK_GT(max_payload_len, last_packet_reduction_len);
+}
+
+RtpPacketizerH264::~RtpPacketizerH264() {}
+
+RtpPacketizerH264::Fragment::~Fragment() = default;
+
+RtpPacketizerH264::Fragment::Fragment(const uint8_t* buffer, size_t length)
+    : buffer(buffer), length(length) {}
+RtpPacketizerH264::Fragment::Fragment(const Fragment& fragment)
+    : buffer(fragment.buffer), length(fragment.length) {}
+
+size_t RtpPacketizerH264::SetPayloadData(
+    const uint8_t* payload_data,
+    size_t payload_size,
+    const RTPFragmentationHeader* fragmentation) {
+  RTC_DCHECK(packets_.empty());
+  RTC_DCHECK(input_fragments_.empty());
+  RTC_DCHECK(fragmentation);
+  for (int i = 0; i < fragmentation->fragmentationVectorSize; ++i) {
+    const uint8_t* buffer =
+        &payload_data[fragmentation->fragmentationOffset[i]];
+    size_t length = fragmentation->fragmentationLength[i];
+
+    bool updated_sps = false;
+    H264::NaluType nalu_type = H264::ParseNaluType(buffer[0]);
+    if (nalu_type == H264::NaluType::kSps) {
+      // Check if stream uses picture order count type 0, and if so rewrite it
+      // to enable faster decoding. Streams in that format incur additional
+      // delay because it allows decode order to differ from render order.
+      // The mechanism used is to rewrite (edit or add) the SPS's VUI to contain
+      // restrictions on the maximum number of reordered pictures. This reduces
+      // latency significantly, though it still adds about a frame of latency to
+      // decoding.
+      // Note that we do this rewriting both here (send side, in order to
+      // protect legacy receive clients) and below in
+      // RtpDepacketizerH264::ParseSingleNalu (receive side, in orderer to
+      // protect us from unknown or legacy send clients).
+
+      absl::optional<SpsParser::SpsState> sps;
+
+      std::unique_ptr<rtc::Buffer> output_buffer(new rtc::Buffer());
+      // Add the type header to the output buffer first, so that the rewriter
+      // can append modified payload on top of that.
+      output_buffer->AppendData(buffer[0]);
+      SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
+          buffer + H264::kNaluTypeSize, length - H264::kNaluTypeSize, &sps,
+          output_buffer.get());
+
+      switch (result) {
+        case SpsVuiRewriter::ParseResult::kVuiRewritten:
+          input_fragments_.push_back(
+              Fragment(output_buffer->data(), output_buffer->size()));
+          input_fragments_.rbegin()->tmp_buffer = std::move(output_buffer);
+          updated_sps = true;
+          RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                    SpsValidEvent::kSentSpsRewritten,
+                                    SpsValidEvent::kSpsRewrittenMax);
+          break;
+        case SpsVuiRewriter::ParseResult::kPocOk:
+          RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                    SpsValidEvent::kSentSpsPocOk,
+                                    SpsValidEvent::kSpsRewrittenMax);
+          break;
+        case SpsVuiRewriter::ParseResult::kVuiOk:
+          RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                    SpsValidEvent::kSentSpsVuiOk,
+                                    SpsValidEvent::kSpsRewrittenMax);
+          break;
+        case SpsVuiRewriter::ParseResult::kFailure:
+          RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                    SpsValidEvent::kSentSpsParseFailure,
+                                    SpsValidEvent::kSpsRewrittenMax);
+          break;
+      }
+    }
+
+    if (!updated_sps)
+      input_fragments_.push_back(Fragment(buffer, length));
+  }
+  if (!GeneratePackets()) {
+    // If failed to generate all the packets, discard already generated
+    // packets in case the caller would ignore return value and still try to
+    // call NextPacket().
+    num_packets_left_ = 0;
+    while (!packets_.empty()) {
+      packets_.pop();
+    }
+    return 0;
+  }
+  return num_packets_left_;
+}
+
+bool RtpPacketizerH264::GeneratePackets() {
+  for (size_t i = 0; i < input_fragments_.size();) {
+    switch (packetization_mode_) {
+      case H264PacketizationMode::SingleNalUnit:
+        if (!PacketizeSingleNalu(i))
+          return false;
+        ++i;
+        break;
+      case H264PacketizationMode::NonInterleaved:
+        size_t fragment_len = input_fragments_[i].length;
+        if (i + 1 == input_fragments_.size()) {
+          // Pretend that last fragment is larger instead of making last packet
+          // smaller.
+          fragment_len += last_packet_reduction_len_;
+        }
+        if (fragment_len > max_payload_len_) {
+          PacketizeFuA(i);
+          ++i;
+        } else {
+          i = PacketizeStapA(i);
+        }
+        break;
+    }
+  }
+  return true;
+}
+
+void RtpPacketizerH264::PacketizeFuA(size_t fragment_index) {
+  // Fragment payload into packets (FU-A).
+  // Strip out the original header and leave room for the FU-A header.
+  const Fragment& fragment = input_fragments_[fragment_index];
+  bool is_last_fragment = fragment_index + 1 == input_fragments_.size();
+  size_t payload_left = fragment.length - kNalHeaderSize;
+  size_t offset = kNalHeaderSize;
+  size_t per_packet_capacity = max_payload_len_ - kFuAHeaderSize;
+
+  // Instead of making the last packet smaller we pretend that all packets are
+  // of the same size but we write additional virtual payload to the last
+  // packet.
+  size_t extra_len = is_last_fragment ? last_packet_reduction_len_ : 0;
+
+  // Integer divisions with rounding up. Minimal number of packets to fit all
+  // payload and virtual payload.
+  size_t num_packets = (payload_left + extra_len + (per_packet_capacity - 1)) /
+                       per_packet_capacity;
+  // Bytes per packet. Average rounded down.
+  size_t payload_per_packet = (payload_left + extra_len) / num_packets;
+  // We make several first packets to be 1 bytes smaller than the rest.
+  // i.e 14 bytes splitted in 4 packets would be 3+3+4+4.
+  size_t num_larger_packets = (payload_left + extra_len) % num_packets;
+
+  num_packets_left_ += num_packets;
+  while (payload_left > 0) {
+    // Increase payload per packet at the right time.
+    if (num_packets == num_larger_packets)
+      ++payload_per_packet;
+    size_t packet_length = payload_per_packet;
+    if (payload_left <= packet_length) {  // Last portion of the payload
+      packet_length = payload_left;
+      // One additional packet may be used for extensions in the last packet.
+      // Together with last payload packet there may be at most 2 of them.
+      RTC_DCHECK_LE(num_packets, 2);
+      if (num_packets == 2) {
+        // Whole payload fits in the first num_packets-1 packets but extra
+        // packet is used for virtual payload. Leave at least one byte of data
+        // for the last packet.
+        --packet_length;
+      }
+    }
+    RTC_CHECK_GT(packet_length, 0);
+    packets_.push(PacketUnit(Fragment(fragment.buffer + offset, packet_length),
+                             offset - kNalHeaderSize == 0,
+                             payload_left == packet_length, false,
+                             fragment.buffer[0]));
+    offset += packet_length;
+    payload_left -= packet_length;
+    --num_packets;
+  }
+  RTC_CHECK_EQ(0, payload_left);
+}
+
+size_t RtpPacketizerH264::PacketizeStapA(size_t fragment_index) {
+  // Aggregate fragments into one packet (STAP-A).
+  size_t payload_size_left = max_payload_len_;
+  int aggregated_fragments = 0;
+  size_t fragment_headers_length = 0;
+  const Fragment* fragment = &input_fragments_[fragment_index];
+  RTC_CHECK_GE(payload_size_left, fragment->length);
+  ++num_packets_left_;
+  while (payload_size_left >= fragment->length + fragment_headers_length &&
+         (fragment_index + 1 < input_fragments_.size() ||
+          payload_size_left >= fragment->length + fragment_headers_length +
+                                   last_packet_reduction_len_)) {
+    RTC_CHECK_GT(fragment->length, 0);
+    packets_.push(PacketUnit(*fragment, aggregated_fragments == 0, false, true,
+                             fragment->buffer[0]));
+    payload_size_left -= fragment->length;
+    payload_size_left -= fragment_headers_length;
+
+    fragment_headers_length = kLengthFieldSize;
+    // If we are going to try to aggregate more fragments into this packet
+    // we need to add the STAP-A NALU header and a length field for the first
+    // NALU of this packet.
+    if (aggregated_fragments == 0)
+      fragment_headers_length += kNalHeaderSize + kLengthFieldSize;
+    ++aggregated_fragments;
+
+    // Next fragment.
+    ++fragment_index;
+    if (fragment_index == input_fragments_.size())
+      break;
+    fragment = &input_fragments_[fragment_index];
+  }
+  RTC_CHECK_GT(aggregated_fragments, 0);
+  packets_.back().last_fragment = true;
+  return fragment_index;
+}
+
+bool RtpPacketizerH264::PacketizeSingleNalu(size_t fragment_index) {
+  // Add a single NALU to the queue, no aggregation.
+  size_t payload_size_left = max_payload_len_;
+  if (fragment_index + 1 == input_fragments_.size())
+    payload_size_left -= last_packet_reduction_len_;
+  const Fragment* fragment = &input_fragments_[fragment_index];
+  if (payload_size_left < fragment->length) {
+    RTC_LOG(LS_ERROR) << "Failed to fit a fragment to packet in SingleNalu "
+                         "packetization mode. Payload size left "
+                      << payload_size_left << ", fragment length "
+                      << fragment->length << ", packet capacity "
+                      << max_payload_len_;
+    return false;
+  }
+  RTC_CHECK_GT(fragment->length, 0u);
+  packets_.push(PacketUnit(*fragment, true /* first */, true /* last */,
+                           false /* aggregated */, fragment->buffer[0]));
+  ++num_packets_left_;
+  return true;
+}
+
+bool RtpPacketizerH264::NextPacket(RtpPacketToSend* rtp_packet) {
+  RTC_DCHECK(rtp_packet);
+  if (packets_.empty()) {
+    return false;
+  }
+
+  PacketUnit packet = packets_.front();
+  if (packet.first_fragment && packet.last_fragment) {
+    // Single NAL unit packet.
+    size_t bytes_to_send = packet.source_fragment.length;
+    uint8_t* buffer = rtp_packet->AllocatePayload(bytes_to_send);
+    memcpy(buffer, packet.source_fragment.buffer, bytes_to_send);
+    packets_.pop();
+    input_fragments_.pop_front();
+  } else if (packet.aggregated) {
+    RTC_CHECK(H264PacketizationMode::NonInterleaved == packetization_mode_);
+    bool is_last_packet = num_packets_left_ == 1;
+    NextAggregatePacket(rtp_packet, is_last_packet);
+  } else {
+    RTC_CHECK(H264PacketizationMode::NonInterleaved == packetization_mode_);
+    NextFragmentPacket(rtp_packet);
+  }
+  RTC_DCHECK_LE(rtp_packet->payload_size(), max_payload_len_);
+  if (packets_.empty()) {
+    RTC_DCHECK_LE(rtp_packet->payload_size(),
+                  max_payload_len_ - last_packet_reduction_len_);
+  }
+  rtp_packet->SetMarker(packets_.empty());
+  --num_packets_left_;
+  return true;
+}
+
+void RtpPacketizerH264::NextAggregatePacket(RtpPacketToSend* rtp_packet,
+                                            bool last) {
+  uint8_t* buffer = rtp_packet->AllocatePayload(
+      last ? max_payload_len_ - last_packet_reduction_len_ : max_payload_len_);
+  RTC_DCHECK(buffer);
+  PacketUnit* packet = &packets_.front();
+  RTC_CHECK(packet->first_fragment);
+  // STAP-A NALU header.
+  buffer[0] = (packet->header & (kFBit | kNriMask)) | H264::NaluType::kStapA;
+  size_t index = kNalHeaderSize;
+  bool is_last_fragment = packet->last_fragment;
+  while (packet->aggregated) {
+    const Fragment& fragment = packet->source_fragment;
+    // Add NAL unit length field.
+    ByteWriter<uint16_t>::WriteBigEndian(&buffer[index], fragment.length);
+    index += kLengthFieldSize;
+    // Add NAL unit.
+    memcpy(&buffer[index], fragment.buffer, fragment.length);
+    index += fragment.length;
+    packets_.pop();
+    input_fragments_.pop_front();
+    if (is_last_fragment)
+      break;
+    packet = &packets_.front();
+    is_last_fragment = packet->last_fragment;
+  }
+  RTC_CHECK(is_last_fragment);
+  rtp_packet->SetPayloadSize(index);
+}
+
+void RtpPacketizerH264::NextFragmentPacket(RtpPacketToSend* rtp_packet) {
+  PacketUnit* packet = &packets_.front();
+  // NAL unit fragmented over multiple packets (FU-A).
+  // We do not send original NALU header, so it will be replaced by the
+  // FU indicator header of the first packet.
+  uint8_t fu_indicator =
+      (packet->header & (kFBit | kNriMask)) | H264::NaluType::kFuA;
+  uint8_t fu_header = 0;
+
+  // S | E | R | 5 bit type.
+  fu_header |= (packet->first_fragment ? kSBit : 0);
+  fu_header |= (packet->last_fragment ? kEBit : 0);
+  uint8_t type = packet->header & kTypeMask;
+  fu_header |= type;
+  const Fragment& fragment = packet->source_fragment;
+  uint8_t* buffer =
+      rtp_packet->AllocatePayload(kFuAHeaderSize + fragment.length);
+  buffer[0] = fu_indicator;
+  buffer[1] = fu_header;
+  memcpy(buffer + kFuAHeaderSize, fragment.buffer, fragment.length);
+  if (packet->last_fragment)
+    input_fragments_.pop_front();
+  packets_.pop();
+}
+
+std::string RtpPacketizerH264::ToString() {
+  return "RtpPacketizerH264";
+}
+
+RtpDepacketizerH264::RtpDepacketizerH264() : offset_(0), length_(0) {}
+RtpDepacketizerH264::~RtpDepacketizerH264() {}
+
+bool RtpDepacketizerH264::Parse(ParsedPayload* parsed_payload,
+                                const uint8_t* payload_data,
+                                size_t payload_data_length) {
+  RTC_CHECK(parsed_payload != nullptr);
+  if (payload_data_length == 0) {
+    RTC_LOG(LS_ERROR) << "Empty payload.";
+    return false;
+  }
+
+  offset_ = 0;
+  length_ = payload_data_length;
+  modified_buffer_.reset();
+
+  uint8_t nal_type = payload_data[0] & kTypeMask;
+  parsed_payload->video_header().h264().nalus_length = 0;
+  if (nal_type == H264::NaluType::kFuA) {
+    // Fragmented NAL units (FU-A).
+    if (!ParseFuaNalu(parsed_payload, payload_data))
+      return false;
+  } else {
+    // We handle STAP-A and single NALU's the same way here. The jitter buffer
+    // will depacketize the STAP-A into NAL units later.
+    // TODO(sprang): Parse STAP-A offsets here and store in fragmentation vec.
+    if (!ProcessStapAOrSingleNalu(parsed_payload, payload_data))
+      return false;
+  }
+
+  const uint8_t* payload =
+      modified_buffer_ ? modified_buffer_->data() : payload_data;
+
+  parsed_payload->payload = payload + offset_;
+  parsed_payload->payload_length = length_;
+  return true;
+}
+
+bool RtpDepacketizerH264::ProcessStapAOrSingleNalu(
+    ParsedPayload* parsed_payload,
+    const uint8_t* payload_data) {
+  parsed_payload->video_header().width = 0;
+  parsed_payload->video_header().height = 0;
+  parsed_payload->video_header().codec = kVideoCodecH264;
+  parsed_payload->video_header().simulcastIdx = 0;
+  parsed_payload->video_header().is_first_packet_in_frame = true;
+  RTPVideoHeaderH264* h264_header = &parsed_payload->video_header().h264();
+
+  const uint8_t* nalu_start = payload_data + kNalHeaderSize;
+  const size_t nalu_length = length_ - kNalHeaderSize;
+  uint8_t nal_type = payload_data[0] & kTypeMask;
+  std::vector<size_t> nalu_start_offsets;
+  if (nal_type == H264::NaluType::kStapA) {
+    // Skip the StapA header (StapA NAL type + length).
+    if (length_ <= kStapAHeaderSize) {
+      RTC_LOG(LS_ERROR) << "StapA header truncated.";
+      return false;
+    }
+
+    if (!ParseStapAStartOffsets(nalu_start, nalu_length, &nalu_start_offsets)) {
+      RTC_LOG(LS_ERROR) << "StapA packet with incorrect NALU packet lengths.";
+      return false;
+    }
+
+    h264_header->packetization_type = kH264StapA;
+    nal_type = payload_data[kStapAHeaderSize] & kTypeMask;
+  } else {
+    h264_header->packetization_type = kH264SingleNalu;
+    nalu_start_offsets.push_back(0);
+  }
+  h264_header->nalu_type = nal_type;
+  parsed_payload->frame_type = kVideoFrameDelta;
+
+  nalu_start_offsets.push_back(length_ + kLengthFieldSize);  // End offset.
+  for (size_t i = 0; i < nalu_start_offsets.size() - 1; ++i) {
+    size_t start_offset = nalu_start_offsets[i];
+    // End offset is actually start offset for next unit, excluding length field
+    // so remove that from this units length.
+    size_t end_offset = nalu_start_offsets[i + 1] - kLengthFieldSize;
+    if (end_offset - start_offset < H264::kNaluTypeSize) {
+      RTC_LOG(LS_ERROR) << "STAP-A packet too short";
+      return false;
+    }
+
+    NaluInfo nalu;
+    nalu.type = payload_data[start_offset] & kTypeMask;
+    nalu.sps_id = -1;
+    nalu.pps_id = -1;
+    start_offset += H264::kNaluTypeSize;
+
+    switch (nalu.type) {
+      case H264::NaluType::kSps: {
+        // Check if VUI is present in SPS and if it needs to be modified to
+        // avoid
+        // excessive decoder latency.
+
+        // Copy any previous data first (likely just the first header).
+        std::unique_ptr<rtc::Buffer> output_buffer(new rtc::Buffer());
+        if (start_offset)
+          output_buffer->AppendData(payload_data, start_offset);
+
+        absl::optional<SpsParser::SpsState> sps;
+
+        SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
+            &payload_data[start_offset], end_offset - start_offset, &sps,
+            output_buffer.get());
+        switch (result) {
+          case SpsVuiRewriter::ParseResult::kVuiRewritten:
+            if (modified_buffer_) {
+              RTC_LOG(LS_WARNING)
+                  << "More than one H264 SPS NAL units needing "
+                     "rewriting found within a single STAP-A packet. "
+                     "Keeping the first and rewriting the last.";
+            }
+
+            // Rewrite length field to new SPS size.
+            if (h264_header->packetization_type == kH264StapA) {
+              size_t length_field_offset =
+                  start_offset - (H264::kNaluTypeSize + kLengthFieldSize);
+              // Stap-A Length includes payload data and type header.
+              size_t rewritten_size =
+                  output_buffer->size() - start_offset + H264::kNaluTypeSize;
+              ByteWriter<uint16_t>::WriteBigEndian(
+                  &(*output_buffer)[length_field_offset], rewritten_size);
+            }
+
+            // Append rest of packet.
+            output_buffer->AppendData(
+                &payload_data[end_offset],
+                nalu_length + kNalHeaderSize - end_offset);
+
+            modified_buffer_ = std::move(output_buffer);
+            length_ = modified_buffer_->size();
+
+            RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                      SpsValidEvent::kReceivedSpsRewritten,
+                                      SpsValidEvent::kSpsRewrittenMax);
+            break;
+          case SpsVuiRewriter::ParseResult::kPocOk:
+            RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                      SpsValidEvent::kReceivedSpsPocOk,
+                                      SpsValidEvent::kSpsRewrittenMax);
+            break;
+          case SpsVuiRewriter::ParseResult::kVuiOk:
+            RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                      SpsValidEvent::kReceivedSpsVuiOk,
+                                      SpsValidEvent::kSpsRewrittenMax);
+            break;
+          case SpsVuiRewriter::ParseResult::kFailure:
+            RTC_HISTOGRAM_ENUMERATION(kSpsValidHistogramName,
+                                      SpsValidEvent::kReceivedSpsParseFailure,
+                                      SpsValidEvent::kSpsRewrittenMax);
+            break;
+        }
+
+        if (sps) {
+          parsed_payload->video_header().width = sps->width;
+          parsed_payload->video_header().height = sps->height;
+          nalu.sps_id = sps->id;
+        } else {
+          RTC_LOG(LS_WARNING) << "Failed to parse SPS id from SPS slice.";
+        }
+        parsed_payload->frame_type = kVideoFrameKey;
+        break;
+      }
+      case H264::NaluType::kPps: {
+        uint32_t pps_id;
+        uint32_t sps_id;
+        if (PpsParser::ParsePpsIds(&payload_data[start_offset],
+                                   end_offset - start_offset, &pps_id,
+                                   &sps_id)) {
+          nalu.pps_id = pps_id;
+          nalu.sps_id = sps_id;
+        } else {
+          RTC_LOG(LS_WARNING)
+              << "Failed to parse PPS id and SPS id from PPS slice.";
+        }
+        break;
+      }
+      case H264::NaluType::kIdr:
+        parsed_payload->frame_type = kVideoFrameKey;
+        RTC_FALLTHROUGH();
+      case H264::NaluType::kSlice: {
+        absl::optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice(
+            &payload_data[start_offset], end_offset - start_offset);
+        if (pps_id) {
+          nalu.pps_id = *pps_id;
+        } else {
+          RTC_LOG(LS_WARNING) << "Failed to parse PPS id from slice of type: "
+                              << static_cast<int>(nalu.type);
+        }
+        break;
+      }
+      // Slices below don't contain SPS or PPS ids.
+      case H264::NaluType::kAud:
+      case H264::NaluType::kEndOfSequence:
+      case H264::NaluType::kEndOfStream:
+      case H264::NaluType::kFiller:
+      case H264::NaluType::kSei:
+        break;
+      case H264::NaluType::kStapA:
+      case H264::NaluType::kFuA:
+        RTC_LOG(LS_WARNING) << "Unexpected STAP-A or FU-A received.";
+        return false;
+    }
+    RTPVideoHeaderH264* h264 = &parsed_payload->video_header().h264();
+    if (h264->nalus_length == kMaxNalusPerPacket) {
+      RTC_LOG(LS_WARNING)
+          << "Received packet containing more than " << kMaxNalusPerPacket
+          << " NAL units. Will not keep track sps and pps ids for all of them.";
+    } else {
+      h264->nalus[h264->nalus_length++] = nalu;
+    }
+  }
+
+  return true;
+}
+
+bool RtpDepacketizerH264::ParseFuaNalu(
+    RtpDepacketizer::ParsedPayload* parsed_payload,
+    const uint8_t* payload_data) {
+  if (length_ < kFuAHeaderSize) {
+    RTC_LOG(LS_ERROR) << "FU-A NAL units truncated.";
+    return false;
+  }
+  uint8_t fnri = payload_data[0] & (kFBit | kNriMask);
+  uint8_t original_nal_type = payload_data[1] & kTypeMask;
+  bool first_fragment = (payload_data[1] & kSBit) > 0;
+  NaluInfo nalu;
+  nalu.type = original_nal_type;
+  nalu.sps_id = -1;
+  nalu.pps_id = -1;
+  if (first_fragment) {
+    offset_ = 0;
+    length_ -= kNalHeaderSize;
+    absl::optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice(
+        payload_data + 2 * kNalHeaderSize, length_ - kNalHeaderSize);
+    if (pps_id) {
+      nalu.pps_id = *pps_id;
+    } else {
+      RTC_LOG(LS_WARNING)
+          << "Failed to parse PPS from first fragment of FU-A NAL "
+             "unit with original type: "
+          << static_cast<int>(nalu.type);
+    }
+    uint8_t original_nal_header = fnri | original_nal_type;
+    modified_buffer_.reset(new rtc::Buffer());
+    modified_buffer_->AppendData(payload_data + kNalHeaderSize, length_);
+    (*modified_buffer_)[0] = original_nal_header;
+  } else {
+    offset_ = kFuAHeaderSize;
+    length_ -= kFuAHeaderSize;
+  }
+
+  if (original_nal_type == H264::NaluType::kIdr) {
+    parsed_payload->frame_type = kVideoFrameKey;
+  } else {
+    parsed_payload->frame_type = kVideoFrameDelta;
+  }
+  parsed_payload->video_header().width = 0;
+  parsed_payload->video_header().height = 0;
+  parsed_payload->video_header().codec = kVideoCodecH264;
+  parsed_payload->video_header().simulcastIdx = 0;
+  parsed_payload->video_header().is_first_packet_in_frame = first_fragment;
+  RTPVideoHeaderH264* h264 = &parsed_payload->video_header().h264();
+  h264->packetization_type = kH264FuA;
+  h264->nalu_type = original_nal_type;
+  if (first_fragment) {
+    h264->nalus[h264->nalus_length] = nalu;
+    h264->nalus_length = 1;
+  }
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_h264.h b/modules/rtp_rtcp/source/rtp_format_h264.h
new file mode 100644
index 0000000..99b080b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_h264.h
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_
+
+#include <deque>
+#include <memory>
+#include <queue>
+#include <string>
+
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+
+class RtpPacketizerH264 : public RtpPacketizer {
+ public:
+  // Initialize with payload from encoder.
+  // The payload_data must be exactly one encoded H264 frame.
+  RtpPacketizerH264(size_t max_payload_len,
+                    size_t last_packet_reduction_len,
+                    H264PacketizationMode packetization_mode);
+
+  ~RtpPacketizerH264() override;
+
+  size_t SetPayloadData(const uint8_t* payload_data,
+                        size_t payload_size,
+                        const RTPFragmentationHeader* fragmentation) override;
+
+  // Get the next payload with H264 payload header.
+  // Write payload and set marker bit of the |packet|.
+  // Returns true on success, false otherwise.
+  bool NextPacket(RtpPacketToSend* rtp_packet) override;
+
+  std::string ToString() override;
+
+ private:
+  // Input fragments (NAL units), with an optionally owned temporary buffer,
+  // used in case the fragment gets modified.
+  struct Fragment {
+    Fragment(const uint8_t* buffer, size_t length);
+    explicit Fragment(const Fragment& fragment);
+    ~Fragment();
+    const uint8_t* buffer = nullptr;
+    size_t length = 0;
+    std::unique_ptr<rtc::Buffer> tmp_buffer;
+  };
+
+  // A packet unit (H264 packet), to be put into an RTP packet:
+  // If a NAL unit is too large for an RTP packet, this packet unit will
+  // represent a FU-A packet of a single fragment of the NAL unit.
+  // If a NAL unit is small enough to fit within a single RTP packet, this
+  // packet unit may represent a single NAL unit or a STAP-A packet, of which
+  // there may be multiple in a single RTP packet (if so, aggregated = true).
+  struct PacketUnit {
+    PacketUnit(const Fragment& source_fragment,
+               bool first_fragment,
+               bool last_fragment,
+               bool aggregated,
+               uint8_t header)
+        : source_fragment(source_fragment),
+          first_fragment(first_fragment),
+          last_fragment(last_fragment),
+          aggregated(aggregated),
+          header(header) {}
+
+    const Fragment source_fragment;
+    bool first_fragment;
+    bool last_fragment;
+    bool aggregated;
+    uint8_t header;
+  };
+
+  bool GeneratePackets();
+  void PacketizeFuA(size_t fragment_index);
+  size_t PacketizeStapA(size_t fragment_index);
+  bool PacketizeSingleNalu(size_t fragment_index);
+  void NextAggregatePacket(RtpPacketToSend* rtp_packet, bool last);
+  void NextFragmentPacket(RtpPacketToSend* rtp_packet);
+
+  const size_t max_payload_len_;
+  const size_t last_packet_reduction_len_;
+  size_t num_packets_left_;
+  const H264PacketizationMode packetization_mode_;
+  std::deque<Fragment> input_fragments_;
+  std::queue<PacketUnit> packets_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerH264);
+};
+
+// Depacketizer for H264.
+class RtpDepacketizerH264 : public RtpDepacketizer {
+ public:
+  RtpDepacketizerH264();
+  ~RtpDepacketizerH264() override;
+
+  bool Parse(ParsedPayload* parsed_payload,
+             const uint8_t* payload_data,
+             size_t payload_data_length) override;
+
+ private:
+  bool ParseFuaNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
+                    const uint8_t* payload_data);
+  bool ProcessStapAOrSingleNalu(RtpDepacketizer::ParsedPayload* parsed_payload,
+                                const uint8_t* payload_data);
+
+  size_t offset_;
+  size_t length_;
+  std::unique_ptr<rtc::Buffer> modified_buffer_;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_H264_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
new file mode 100644
index 0000000..dc17b4f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_h264_unittest.cc
@@ -0,0 +1,938 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "common_video/h264/h264_common.h"
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+
+constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
+const size_t kMaxPayloadSize = 1200;
+const size_t kLengthFieldLength = 2;
+
+enum Nalu {
+  kSlice = 1,
+  kIdr = 5,
+  kSei = 6,
+  kSps = 7,
+  kPps = 8,
+  kStapA = 24,
+  kFuA = 28
+};
+
+static const size_t kNalHeaderSize = 1;
+static const size_t kFuAHeaderSize = 2;
+
+// Bit masks for FU (A and B) indicators.
+enum NalDefs { kFBit = 0x80, kNriMask = 0x60, kTypeMask = 0x1F };
+
+// Bit masks for FU (A and B) headers.
+enum FuDefs { kSBit = 0x80, kEBit = 0x40, kRBit = 0x20 };
+
+void CreateThreeFragments(RTPFragmentationHeader* fragmentation,
+                          size_t frameSize,
+                          size_t payloadOffset) {
+  fragmentation->VerifyAndAllocateFragmentationHeader(3);
+  fragmentation->fragmentationOffset[0] = 0;
+  fragmentation->fragmentationLength[0] = 2;
+  fragmentation->fragmentationOffset[1] = 2;
+  fragmentation->fragmentationLength[1] = 2;
+  fragmentation->fragmentationOffset[2] = 4;
+  fragmentation->fragmentationLength[2] =
+      kNalHeaderSize + frameSize - payloadOffset;
+}
+
+RtpPacketizer* CreateH264Packetizer(H264PacketizationMode mode,
+                                    size_t max_payload_size,
+                                    size_t last_packet_reduction) {
+  RTPVideoHeader header;
+  header.h264().packetization_mode = mode;
+  return RtpPacketizer::Create(kVideoCodecH264, max_payload_size,
+                               last_packet_reduction, &header, kEmptyFrame);
+}
+
+void VerifyFua(size_t fua_index,
+               const uint8_t* expected_payload,
+               int offset,
+               rtc::ArrayView<const uint8_t> packet,
+               const std::vector<size_t>& expected_sizes) {
+  ASSERT_EQ(expected_sizes[fua_index] + kFuAHeaderSize, packet.size())
+      << "FUA index: " << fua_index;
+  const uint8_t kFuIndicator = 0x1C;  // F=0, NRI=0, Type=28.
+  EXPECT_EQ(kFuIndicator, packet[0]) << "FUA index: " << fua_index;
+  bool should_be_last_fua = (fua_index == expected_sizes.size() - 1);
+  uint8_t fu_header = 0;
+  if (fua_index == 0)
+    fu_header = 0x85;  // S=1, E=0, R=0, Type=5.
+  else if (should_be_last_fua)
+    fu_header = 0x45;  // S=0, E=1, R=0, Type=5.
+  else
+    fu_header = 0x05;  // S=0, E=0, R=0, Type=5.
+  EXPECT_EQ(fu_header, packet[1]) << "FUA index: " << fua_index;
+  std::vector<uint8_t> expected_packet_payload(
+      &expected_payload[offset],
+      &expected_payload[offset + expected_sizes[fua_index]]);
+  EXPECT_THAT(expected_packet_payload,
+              ElementsAreArray(&packet[2], expected_sizes[fua_index]))
+      << "FUA index: " << fua_index;
+}
+
+void TestFua(size_t frame_size,
+             size_t max_payload_size,
+             size_t last_packet_reduction,
+             const std::vector<size_t>& expected_sizes) {
+  std::unique_ptr<uint8_t[]> frame;
+  frame.reset(new uint8_t[frame_size]);
+  frame[0] = 0x05;  // F=0, NRI=0, Type=5.
+  for (size_t i = 0; i < frame_size - kNalHeaderSize; ++i) {
+    frame[i + kNalHeaderSize] = i;
+  }
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(1);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = frame_size;
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(H264PacketizationMode::NonInterleaved,
+                           max_payload_size, last_packet_reduction));
+  EXPECT_EQ(
+      expected_sizes.size(),
+      packetizer->SetPayloadData(frame.get(), frame_size, &fragmentation));
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(max_payload_size, packet.FreeCapacity());
+  size_t offset = kNalHeaderSize;
+  for (size_t i = 0; i < expected_sizes.size(); ++i) {
+    ASSERT_TRUE(packetizer->NextPacket(&packet));
+    VerifyFua(i, frame.get(), offset, packet.payload(), expected_sizes);
+    offset += expected_sizes[i];
+  }
+
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+size_t GetExpectedNaluOffset(const RTPFragmentationHeader& fragmentation,
+                             size_t start_index,
+                             size_t nalu_index) {
+  assert(nalu_index < fragmentation.fragmentationVectorSize);
+  size_t expected_nalu_offset = kNalHeaderSize;  // STAP-A header.
+  for (size_t i = start_index; i < nalu_index; ++i) {
+    expected_nalu_offset +=
+        kLengthFieldLength + fragmentation.fragmentationLength[i];
+  }
+  return expected_nalu_offset;
+}
+
+void VerifyStapAPayload(const RTPFragmentationHeader& fragmentation,
+                        size_t first_stapa_index,
+                        size_t nalu_index,
+                        rtc::ArrayView<const uint8_t> frame,
+                        rtc::ArrayView<const uint8_t> packet) {
+  size_t expected_payload_offset =
+      GetExpectedNaluOffset(fragmentation, first_stapa_index, nalu_index) +
+      kLengthFieldLength;
+  size_t offset = fragmentation.fragmentationOffset[nalu_index];
+  const uint8_t* expected_payload = &frame[offset];
+  size_t expected_payload_length =
+      fragmentation.fragmentationLength[nalu_index];
+  ASSERT_LE(offset + expected_payload_length, frame.size());
+  ASSERT_LE(expected_payload_offset + expected_payload_length, packet.size());
+  std::vector<uint8_t> expected_payload_vector(
+      expected_payload, &expected_payload[expected_payload_length]);
+  EXPECT_THAT(expected_payload_vector,
+              ElementsAreArray(&packet[expected_payload_offset],
+                               expected_payload_length));
+}
+
+void VerifySingleNaluPayload(const RTPFragmentationHeader& fragmentation,
+                             size_t nalu_index,
+                             rtc::ArrayView<const uint8_t> frame,
+                             rtc::ArrayView<const uint8_t> packet) {
+  auto fragment = frame.subview(fragmentation.fragmentationOffset[nalu_index],
+                                fragmentation.fragmentationLength[nalu_index]);
+  EXPECT_THAT(packet, ElementsAreArray(fragment.begin(), fragment.end()));
+}
+}  // namespace
+
+// Tests that should work with both packetization mode 0 and
+// packetization mode 1.
+class RtpPacketizerH264ModeTest
+    : public ::testing::TestWithParam<H264PacketizationMode> {};
+
+TEST_P(RtpPacketizerH264ModeTest, TestSingleNalu) {
+  const uint8_t frame[2] = {0x05, 0xFF};  // F=0, NRI=0, Type=5.
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(1);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = sizeof(frame);
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(GetParam(), kMaxPayloadSize, 0));
+  ASSERT_EQ(1u,
+            packetizer->SetPayloadData(frame, sizeof(frame), &fragmentation));
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  EXPECT_EQ(2u, packet.payload_size());
+  VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload());
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+TEST_P(RtpPacketizerH264ModeTest, TestSingleNaluTwoPackets) {
+  const size_t kFrameSize = kMaxPayloadSize + 100;
+  uint8_t frame[kFrameSize] = {0};
+  for (size_t i = 0; i < kFrameSize; ++i)
+    frame[i] = i;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(2);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = kMaxPayloadSize;
+  fragmentation.fragmentationOffset[1] = kMaxPayloadSize;
+  fragmentation.fragmentationLength[1] = 100;
+  // Set NAL headers.
+  frame[fragmentation.fragmentationOffset[0]] = 0x01;
+  frame[fragmentation.fragmentationOffset[1]] = 0x01;
+
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(GetParam(), kMaxPayloadSize, 0));
+  ASSERT_EQ(2u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation));
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  ASSERT_EQ(fragmentation.fragmentationOffset[1], packet.payload_size());
+  VerifySingleNaluPayload(fragmentation, 0, frame, packet.payload());
+
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  ASSERT_EQ(fragmentation.fragmentationLength[1], packet.payload_size());
+  VerifySingleNaluPayload(fragmentation, 1, frame, packet.payload());
+
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    PacketMode,
+    RtpPacketizerH264ModeTest,
+    ::testing::Values(H264PacketizationMode::SingleNalUnit,
+                      H264PacketizationMode::NonInterleaved));
+
+TEST(RtpPacketizerH264Test, TestStapA) {
+  const size_t kFrameSize =
+      kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize;
+  uint8_t frame[kFrameSize] = {0x07, 0xFF,  // F=0, NRI=0, Type=7 (SPS).
+                               0x08, 0xFF,  // F=0, NRI=0, Type=8 (PPS).
+                               0x05};       // F=0, NRI=0, Type=5 (IDR).
+  const size_t kPayloadOffset = 5;
+  for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i)
+    frame[i + kPayloadOffset] = i;
+  RTPFragmentationHeader fragmentation;
+  CreateThreeFragments(&fragmentation, kFrameSize, kPayloadOffset);
+  std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer(
+      H264PacketizationMode::NonInterleaved, kMaxPayloadSize, 0));
+  ASSERT_EQ(1u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation));
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  size_t expected_packet_size =
+      kNalHeaderSize + 3 * kLengthFieldLength + kFrameSize;
+  ASSERT_EQ(expected_packet_size, packet.payload_size());
+
+  for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i)
+    VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload());
+
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+TEST(RtpPacketizerH264Test, TestStapARespectsPacketReduction) {
+  const size_t kLastPacketReduction = 100;
+  const size_t kFrameSize = kMaxPayloadSize - 1 - kLastPacketReduction;
+  uint8_t frame[kFrameSize] = {0x07, 0xFF,  // F=0, NRI=0, Type=7.
+                               0x08, 0xFF,  // F=0, NRI=0, Type=8.
+                               0x05};       // F=0, NRI=0, Type=5.
+  const size_t kPayloadOffset = 5;
+  for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i)
+    frame[i + kPayloadOffset] = i;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(3);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = 2;
+  fragmentation.fragmentationOffset[1] = 2;
+  fragmentation.fragmentationLength[1] = 2;
+  fragmentation.fragmentationOffset[2] = 4;
+  fragmentation.fragmentationLength[2] =
+      kNalHeaderSize + kFrameSize - kPayloadOffset;
+  std::unique_ptr<RtpPacketizer> packetizer(
+      CreateH264Packetizer(H264PacketizationMode::NonInterleaved,
+                           kMaxPayloadSize, kLastPacketReduction));
+  ASSERT_EQ(2u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation));
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  size_t expected_packet_size = kNalHeaderSize;
+  for (size_t i = 0; i < 2; ++i) {
+    expected_packet_size +=
+        kLengthFieldLength + fragmentation.fragmentationLength[i];
+  }
+  ASSERT_EQ(expected_packet_size, packet.payload_size());
+  for (size_t i = 0; i < 2; ++i)
+    VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload());
+
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  expected_packet_size = fragmentation.fragmentationLength[2];
+  ASSERT_EQ(expected_packet_size, packet.payload_size());
+  VerifySingleNaluPayload(fragmentation, 2, frame, packet.payload());
+
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+TEST(RtpPacketizerH264Test, TestSingleNalUnitModeHasNoStapA) {
+  // This is the same setup as for the TestStapA test.
+  const size_t kFrameSize =
+      kMaxPayloadSize - 3 * kLengthFieldLength - kNalHeaderSize;
+  uint8_t frame[kFrameSize] = {0x07, 0xFF,  // F=0, NRI=0, Type=7 (SPS).
+                               0x08, 0xFF,  // F=0, NRI=0, Type=8 (PPS).
+                               0x05};       // F=0, NRI=0, Type=5 (IDR).
+  const size_t kPayloadOffset = 5;
+  for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i)
+    frame[i + kPayloadOffset] = i;
+  RTPFragmentationHeader fragmentation;
+  CreateThreeFragments(&fragmentation, kFrameSize, kPayloadOffset);
+  std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer(
+      H264PacketizationMode::SingleNalUnit, kMaxPayloadSize, 0));
+  packetizer->SetPayloadData(frame, kFrameSize, &fragmentation);
+
+  RtpPacketToSend packet(kNoExtensions);
+  // The three fragments should be returned as three packets.
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+TEST(RtpPacketizerH264Test, TestTooSmallForStapAHeaders) {
+  const size_t kFrameSize = kMaxPayloadSize - 1;
+  uint8_t frame[kFrameSize] = {0x07, 0xFF,  // F=0, NRI=0, Type=7.
+                               0x08, 0xFF,  // F=0, NRI=0, Type=8.
+                               0x05};       // F=0, NRI=0, Type=5.
+  const size_t kPayloadOffset = 5;
+  for (size_t i = 0; i < kFrameSize - kPayloadOffset; ++i)
+    frame[i + kPayloadOffset] = i;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(3);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = 2;
+  fragmentation.fragmentationOffset[1] = 2;
+  fragmentation.fragmentationLength[1] = 2;
+  fragmentation.fragmentationOffset[2] = 4;
+  fragmentation.fragmentationLength[2] =
+      kNalHeaderSize + kFrameSize - kPayloadOffset;
+  std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer(
+      H264PacketizationMode::NonInterleaved, kMaxPayloadSize, 0));
+  ASSERT_EQ(2u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation));
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  size_t expected_packet_size = kNalHeaderSize;
+  for (size_t i = 0; i < 2; ++i) {
+    expected_packet_size +=
+        kLengthFieldLength + fragmentation.fragmentationLength[i];
+  }
+  ASSERT_EQ(expected_packet_size, packet.payload_size());
+  for (size_t i = 0; i < 2; ++i)
+    VerifyStapAPayload(fragmentation, 0, i, frame, packet.payload());
+
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  expected_packet_size = fragmentation.fragmentationLength[2];
+  ASSERT_EQ(expected_packet_size, packet.payload_size());
+  VerifySingleNaluPayload(fragmentation, 2, frame, packet.payload());
+
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+TEST(RtpPacketizerH264Test, TestMixedStapA_FUA) {
+  const size_t kFuaNaluSize = 2 * (kMaxPayloadSize - 100);
+  const size_t kStapANaluSize = 100;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(3);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = kFuaNaluSize;
+  fragmentation.fragmentationOffset[1] = kFuaNaluSize;
+  fragmentation.fragmentationLength[1] = kStapANaluSize;
+  fragmentation.fragmentationOffset[2] = kFuaNaluSize + kStapANaluSize;
+  fragmentation.fragmentationLength[2] = kStapANaluSize;
+  const size_t kFrameSize = kFuaNaluSize + 2 * kStapANaluSize;
+  uint8_t frame[kFrameSize];
+  size_t nalu_offset = 0;
+  for (size_t i = 0; i < fragmentation.fragmentationVectorSize; ++i) {
+    nalu_offset = fragmentation.fragmentationOffset[i];
+    frame[nalu_offset] = 0x05;  // F=0, NRI=0, Type=5.
+    for (size_t j = 1; j < fragmentation.fragmentationLength[i]; ++j) {
+      frame[nalu_offset + j] = i + j;
+    }
+  }
+  std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer(
+      H264PacketizationMode::NonInterleaved, kMaxPayloadSize, 0));
+  ASSERT_EQ(3u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation));
+
+  // First expecting two FU-A packets.
+  std::vector<size_t> fua_sizes;
+  fua_sizes.push_back(1099);
+  fua_sizes.push_back(1100);
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(kMaxPayloadSize, packet.FreeCapacity());
+  int fua_offset = kNalHeaderSize;
+  for (size_t i = 0; i < 2; ++i) {
+    ASSERT_TRUE(packetizer->NextPacket(&packet));
+    VerifyFua(i, frame, fua_offset, packet.payload(), fua_sizes);
+    fua_offset += fua_sizes[i];
+  }
+  // Then expecting one STAP-A packet with two nal units.
+  ASSERT_TRUE(packetizer->NextPacket(&packet));
+  size_t expected_packet_size =
+      kNalHeaderSize + 2 * kLengthFieldLength + 2 * kStapANaluSize;
+  ASSERT_EQ(expected_packet_size, packet.payload_size());
+  for (size_t i = 1; i < fragmentation.fragmentationVectorSize; ++i)
+    VerifyStapAPayload(fragmentation, 1, i, frame, packet.payload());
+
+  EXPECT_FALSE(packetizer->NextPacket(&packet));
+}
+
+TEST(RtpPacketizerH264Test, TestFUAOddSize) {
+  const size_t kExpectedPayloadSizes[2] = {600, 600};
+  TestFua(
+      kMaxPayloadSize + 1, kMaxPayloadSize, 0,
+      std::vector<size_t>(kExpectedPayloadSizes,
+                          kExpectedPayloadSizes +
+                              sizeof(kExpectedPayloadSizes) / sizeof(size_t)));
+}
+
+TEST(RtpPacketizerH264Test, TestFUAWithLastPacketReduction) {
+  const size_t kExpectedPayloadSizes[2] = {601, 597};
+  TestFua(
+      kMaxPayloadSize - 1, kMaxPayloadSize, 4,
+      std::vector<size_t>(kExpectedPayloadSizes,
+                          kExpectedPayloadSizes +
+                              sizeof(kExpectedPayloadSizes) / sizeof(size_t)));
+}
+
+TEST(RtpPacketizerH264Test, TestFUAEvenSize) {
+  const size_t kExpectedPayloadSizes[2] = {600, 601};
+  TestFua(
+      kMaxPayloadSize + 2, kMaxPayloadSize, 0,
+      std::vector<size_t>(kExpectedPayloadSizes,
+                          kExpectedPayloadSizes +
+                              sizeof(kExpectedPayloadSizes) / sizeof(size_t)));
+}
+
+TEST(RtpPacketizerH264Test, TestFUARounding) {
+  const size_t kExpectedPayloadSizes[8] = {1265, 1265, 1265, 1265,
+                                           1265, 1266, 1266, 1266};
+  TestFua(
+      10124, 1448, 0,
+      std::vector<size_t>(kExpectedPayloadSizes,
+                          kExpectedPayloadSizes +
+                              sizeof(kExpectedPayloadSizes) / sizeof(size_t)));
+}
+
+TEST(RtpPacketizerH264Test, TestFUABig) {
+  const size_t kExpectedPayloadSizes[10] = {1198, 1198, 1198, 1198, 1198,
+                                            1198, 1198, 1198, 1198, 1198};
+  // Generate 10 full sized packets, leave room for FU-A headers minus the NALU
+  // header.
+  TestFua(
+      10 * (kMaxPayloadSize - kFuAHeaderSize) + kNalHeaderSize, kMaxPayloadSize,
+      0,
+      std::vector<size_t>(kExpectedPayloadSizes,
+                          kExpectedPayloadSizes +
+                              sizeof(kExpectedPayloadSizes) / sizeof(size_t)));
+}
+
+TEST(RtpPacketizerH264Test, SendOverlongDataInPacketizationMode0) {
+  const size_t kFrameSize = kMaxPayloadSize + 1;
+  uint8_t frame[kFrameSize] = {0};
+  for (size_t i = 0; i < kFrameSize; ++i)
+    frame[i] = i;
+  RTPFragmentationHeader fragmentation;
+  fragmentation.VerifyAndAllocateFragmentationHeader(1);
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationLength[0] = kFrameSize;
+  // Set NAL headers.
+  frame[fragmentation.fragmentationOffset[0]] = 0x01;
+
+  std::unique_ptr<RtpPacketizer> packetizer(CreateH264Packetizer(
+      H264PacketizationMode::SingleNalUnit, kMaxPayloadSize, 0));
+  EXPECT_EQ(0u, packetizer->SetPayloadData(frame, kFrameSize, &fragmentation));
+}
+
+namespace {
+const uint8_t kStartSequence[] = {0x00, 0x00, 0x00, 0x01};
+const uint8_t kOriginalSps[] = {kSps, 0x00, 0x00, 0x03, 0x03,
+                                0xF4, 0x05, 0x03, 0xC7, 0xC0};
+const uint8_t kRewrittenSps[] = {kSps, 0x00, 0x00, 0x03, 0x03, 0xF4, 0x05, 0x03,
+                                 0xC7, 0xE0, 0x1B, 0x41, 0x10, 0x8D, 0x00};
+const uint8_t kIdrOne[] = {kIdr, 0xFF, 0x00, 0x00, 0x04};
+const uint8_t kIdrTwo[] = {kIdr, 0xFF, 0x00, 0x11};
+}  // namespace
+
+class RtpPacketizerH264TestSpsRewriting : public ::testing::Test {
+ public:
+  void SetUp() override {
+    fragmentation_header_.VerifyAndAllocateFragmentationHeader(3);
+    fragmentation_header_.fragmentationVectorSize = 3;
+    in_buffer_.AppendData(kStartSequence);
+
+    fragmentation_header_.fragmentationOffset[0] = in_buffer_.size();
+    fragmentation_header_.fragmentationLength[0] = sizeof(kOriginalSps);
+    in_buffer_.AppendData(kOriginalSps);
+
+    fragmentation_header_.fragmentationOffset[1] = in_buffer_.size();
+    fragmentation_header_.fragmentationLength[1] = sizeof(kIdrOne);
+    in_buffer_.AppendData(kIdrOne);
+
+    fragmentation_header_.fragmentationOffset[2] = in_buffer_.size();
+    fragmentation_header_.fragmentationLength[2] = sizeof(kIdrTwo);
+    in_buffer_.AppendData(kIdrTwo);
+  }
+
+ protected:
+  rtc::Buffer in_buffer_;
+  RTPFragmentationHeader fragmentation_header_;
+  std::unique_ptr<RtpPacketizer> packetizer_;
+};
+
+TEST_F(RtpPacketizerH264TestSpsRewriting, FuASps) {
+  const size_t kHeaderOverhead = kFuAHeaderSize + 1;
+
+  // Set size to fragment SPS into two FU-A packets.
+  packetizer_.reset(
+      CreateH264Packetizer(H264PacketizationMode::NonInterleaved,
+                           sizeof(kOriginalSps) - 2 + kHeaderOverhead, 0));
+
+  packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(),
+                              &fragmentation_header_);
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(sizeof(kOriginalSps) + kHeaderOverhead, packet.FreeCapacity());
+
+  EXPECT_TRUE(packetizer_->NextPacket(&packet));
+  size_t offset = H264::kNaluTypeSize;
+  size_t length = packet.payload_size() - kFuAHeaderSize;
+  EXPECT_THAT(packet.payload().subview(kFuAHeaderSize),
+              ElementsAreArray(&kRewrittenSps[offset], length));
+  offset += length;
+
+  EXPECT_TRUE(packetizer_->NextPacket(&packet));
+  length = packet.payload_size() - kFuAHeaderSize;
+  EXPECT_THAT(packet.payload().subview(kFuAHeaderSize),
+              ElementsAreArray(&kRewrittenSps[offset], length));
+  offset += length;
+
+  EXPECT_EQ(offset, sizeof(kRewrittenSps));
+}
+
+TEST_F(RtpPacketizerH264TestSpsRewriting, StapASps) {
+  const size_t kHeaderOverhead = kFuAHeaderSize + 1;
+  const size_t kExpectedTotalSize = H264::kNaluTypeSize +  // Stap-A type.
+                                    sizeof(kRewrittenSps) + sizeof(kIdrOne) +
+                                    sizeof(kIdrTwo) + (kLengthFieldLength * 3);
+
+  // Set size to include SPS and the rest of the packets in a Stap-A package.
+  packetizer_.reset(CreateH264Packetizer(H264PacketizationMode::NonInterleaved,
+                                         kExpectedTotalSize + kHeaderOverhead,
+                                         0));
+
+  packetizer_->SetPayloadData(in_buffer_.data(), in_buffer_.size(),
+                              &fragmentation_header_);
+
+  RtpPacketToSend packet(kNoExtensions);
+  ASSERT_LE(kExpectedTotalSize + kHeaderOverhead, packet.FreeCapacity());
+
+  EXPECT_TRUE(packetizer_->NextPacket(&packet));
+  EXPECT_EQ(kExpectedTotalSize, packet.payload_size());
+  EXPECT_THAT(packet.payload().subview(H264::kNaluTypeSize + kLengthFieldLength,
+                                       sizeof(kRewrittenSps)),
+              ElementsAreArray(kRewrittenSps));
+}
+
+class RtpDepacketizerH264Test : public ::testing::Test {
+ protected:
+  RtpDepacketizerH264Test()
+      : depacketizer_(RtpDepacketizer::Create(kVideoCodecH264)) {}
+
+  void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload,
+                    const uint8_t* data,
+                    size_t length) {
+    ASSERT_TRUE(parsed_payload != NULL);
+    EXPECT_THAT(std::vector<uint8_t>(
+                    parsed_payload->payload,
+                    parsed_payload->payload + parsed_payload->payload_length),
+                ::testing::ElementsAreArray(data, length));
+  }
+
+  std::unique_ptr<RtpDepacketizer> depacketizer_;
+};
+
+TEST_F(RtpDepacketizerH264Test, TestSingleNalu) {
+  uint8_t packet[2] = {0x05, 0xFF};  // F=0, NRI=0, Type=5 (IDR).
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet, sizeof(packet));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_TRUE(payload.video_header().is_first_packet_in_frame);
+  EXPECT_EQ(kH264SingleNalu, payload.video_header().h264().packetization_type);
+  EXPECT_EQ(kIdr, payload.video_header().h264().nalu_type);
+}
+
+TEST_F(RtpDepacketizerH264Test, TestSingleNaluSpsWithResolution) {
+  uint8_t packet[] = {kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50,
+                      0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0,
+                      0x00, 0x00, 0x03, 0x2A, 0xE0, 0xF1, 0x83, 0x25};
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet, sizeof(packet));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_TRUE(payload.video_header().is_first_packet_in_frame);
+  EXPECT_EQ(kH264SingleNalu, payload.video_header().h264().packetization_type);
+  EXPECT_EQ(1280u, payload.video_header().width);
+  EXPECT_EQ(720u, payload.video_header().height);
+}
+
+TEST_F(RtpDepacketizerH264Test, TestStapAKey) {
+  // clang-format off
+  const NaluInfo kExpectedNalus[] = { {H264::kSps, 0, -1},
+                                      {H264::kPps, 1, 2},
+                                      {H264::kIdr, -1, 0} };
+  uint8_t packet[] = {kStapA,  // F=0, NRI=0, Type=24.
+                      // Length, nal header, payload.
+                      0, 0x18, kExpectedNalus[0].type,
+                        0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40, 0x50, 0x05, 0xBA,
+                        0x10, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x03,
+                        0x2A, 0xE0, 0xF1, 0x83, 0x25,
+                      0, 0xD, kExpectedNalus[1].type,
+                        0x69, 0xFC, 0x0, 0x0, 0x3, 0x0, 0x7, 0xFF, 0xFF, 0xFF,
+                        0xF6, 0x40,
+                      0, 0xB, kExpectedNalus[2].type,
+                        0x85, 0xB8, 0x0, 0x4, 0x0, 0x0, 0x13, 0x93, 0x12, 0x0};
+  // clang-format on
+
+  RtpDepacketizer::ParsedPayload payload;
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet, sizeof(packet));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_TRUE(payload.video_header().is_first_packet_in_frame);
+  const RTPVideoHeaderH264& h264 = payload.video_header().h264();
+  EXPECT_EQ(kH264StapA, h264.packetization_type);
+  // NALU type for aggregated packets is the type of the first packet only.
+  EXPECT_EQ(kSps, h264.nalu_type);
+  ASSERT_EQ(3u, h264.nalus_length);
+  for (size_t i = 0; i < h264.nalus_length; ++i) {
+    EXPECT_EQ(kExpectedNalus[i].type, h264.nalus[i].type)
+        << "Failed parsing nalu " << i;
+    EXPECT_EQ(kExpectedNalus[i].sps_id, h264.nalus[i].sps_id)
+        << "Failed parsing nalu " << i;
+    EXPECT_EQ(kExpectedNalus[i].pps_id, h264.nalus[i].pps_id)
+        << "Failed parsing nalu " << i;
+  }
+}
+
+TEST_F(RtpDepacketizerH264Test, TestStapANaluSpsWithResolution) {
+  uint8_t packet[] = {kStapA,  // F=0, NRI=0, Type=24.
+                               // Length (2 bytes), nal header, payload.
+                      0x00, 0x19, kSps, 0x7A, 0x00, 0x1F, 0xBC, 0xD9, 0x40,
+                      0x50, 0x05, 0xBA, 0x10, 0x00, 0x00, 0x03, 0x00, 0xC0,
+                      0x00, 0x00, 0x03, 0x2A, 0xE0, 0xF1, 0x83, 0x25, 0x80,
+                      0x00, 0x03, kIdr, 0xFF, 0x00, 0x00, 0x04, kIdr, 0xFF,
+                      0x00, 0x11};
+
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet, sizeof(packet));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_TRUE(payload.video_header().is_first_packet_in_frame);
+  EXPECT_EQ(kH264StapA, payload.video_header().h264().packetization_type);
+  EXPECT_EQ(1280u, payload.video_header().width);
+  EXPECT_EQ(720u, payload.video_header().height);
+}
+
+TEST_F(RtpDepacketizerH264Test, TestEmptyStapARejected) {
+  uint8_t lone_empty_packet[] = {kStapA, 0x00, 0x00};
+
+  uint8_t leading_empty_packet[] = {kStapA, 0x00, 0x00, 0x00, 0x04,
+                                    kIdr,   0xFF, 0x00, 0x11};
+
+  uint8_t middle_empty_packet[] = {kStapA, 0x00, 0x03, kIdr, 0xFF, 0x00, 0x00,
+                                   0x00,   0x00, 0x04, kIdr, 0xFF, 0x00, 0x11};
+
+  uint8_t trailing_empty_packet[] = {kStapA, 0x00, 0x03, kIdr,
+                                     0xFF,   0x00, 0x00, 0x00};
+
+  RtpDepacketizer::ParsedPayload payload;
+
+  EXPECT_FALSE(depacketizer_->Parse(&payload, lone_empty_packet,
+                                    sizeof(lone_empty_packet)));
+  EXPECT_FALSE(depacketizer_->Parse(&payload, leading_empty_packet,
+                                    sizeof(leading_empty_packet)));
+  EXPECT_FALSE(depacketizer_->Parse(&payload, middle_empty_packet,
+                                    sizeof(middle_empty_packet)));
+  EXPECT_FALSE(depacketizer_->Parse(&payload, trailing_empty_packet,
+                                    sizeof(trailing_empty_packet)));
+}
+
+TEST_F(RtpDepacketizerH264Test, DepacketizeWithRewriting) {
+  rtc::Buffer in_buffer;
+  rtc::Buffer out_buffer;
+
+  uint8_t kHeader[2] = {kStapA};
+  in_buffer.AppendData(kHeader, 1);
+  out_buffer.AppendData(kHeader, 1);
+
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kOriginalSps);
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kRewrittenSps));
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kRewrittenSps);
+
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrOne));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kIdrOne);
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kIdrOne);
+
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrTwo));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kIdrTwo);
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kIdrTwo);
+
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_TRUE(
+      depacketizer_->Parse(&payload, in_buffer.data(), in_buffer.size()));
+
+  std::vector<uint8_t> expected_packet_payload(
+      out_buffer.data(), &out_buffer.data()[out_buffer.size()]);
+
+  EXPECT_THAT(
+      expected_packet_payload,
+      ::testing::ElementsAreArray(payload.payload, payload.payload_length));
+}
+
+TEST_F(RtpDepacketizerH264Test, DepacketizeWithDoubleRewriting) {
+  rtc::Buffer in_buffer;
+  rtc::Buffer out_buffer;
+
+  uint8_t kHeader[2] = {kStapA};
+  in_buffer.AppendData(kHeader, 1);
+  out_buffer.AppendData(kHeader, 1);
+
+  // First SPS will be kept...
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kOriginalSps);
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kOriginalSps);
+
+  // ...only the second one will be rewritten.
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kOriginalSps));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kOriginalSps);
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kRewrittenSps));
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kRewrittenSps);
+
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrOne));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kIdrOne);
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kIdrOne);
+
+  ByteWriter<uint16_t>::WriteBigEndian(kHeader, sizeof(kIdrTwo));
+  in_buffer.AppendData(kHeader, 2);
+  in_buffer.AppendData(kIdrTwo);
+  out_buffer.AppendData(kHeader, 2);
+  out_buffer.AppendData(kIdrTwo);
+
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_TRUE(
+      depacketizer_->Parse(&payload, in_buffer.data(), in_buffer.size()));
+
+  std::vector<uint8_t> expected_packet_payload(
+      out_buffer.data(), &out_buffer.data()[out_buffer.size()]);
+
+  EXPECT_THAT(
+      expected_packet_payload,
+      ::testing::ElementsAreArray(payload.payload, payload.payload_length));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestStapADelta) {
+  uint8_t packet[16] = {kStapA,  // F=0, NRI=0, Type=24.
+                                 // Length, nal header, payload.
+                        0, 0x02, kSlice, 0xFF, 0, 0x03, kSlice, 0xFF, 0x00, 0,
+                        0x04, kSlice, 0xFF, 0x00, 0x11};
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet, sizeof(packet));
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_TRUE(payload.video_header().is_first_packet_in_frame);
+  EXPECT_EQ(kH264StapA, payload.video_header().h264().packetization_type);
+  // NALU type for aggregated packets is the type of the first packet only.
+  EXPECT_EQ(kSlice, payload.video_header().h264().nalu_type);
+}
+
+TEST_F(RtpDepacketizerH264Test, TestFuA) {
+  // clang-format off
+  uint8_t packet1[] = {
+      kFuA,          // F=0, NRI=0, Type=28.
+      kSBit | kIdr,  // FU header.
+      0x85, 0xB8, 0x0, 0x4, 0x0, 0x0, 0x13, 0x93, 0x12, 0x0  // Payload.
+  };
+  // clang-format on
+  const uint8_t kExpected1[] = {kIdr, 0x85, 0xB8, 0x0,  0x4, 0x0,
+                                0x0,  0x13, 0x93, 0x12, 0x0};
+
+  uint8_t packet2[] = {
+      kFuA,  // F=0, NRI=0, Type=28.
+      kIdr,  // FU header.
+      0x02   // Payload.
+  };
+  const uint8_t kExpected2[] = {0x02};
+
+  uint8_t packet3[] = {
+      kFuA,          // F=0, NRI=0, Type=28.
+      kEBit | kIdr,  // FU header.
+      0x03           // Payload.
+  };
+  const uint8_t kExpected3[] = {0x03};
+
+  RtpDepacketizer::ParsedPayload payload;
+
+  // We expect that the first packet is one byte shorter since the FU-A header
+  // has been replaced by the original nal header.
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet1, sizeof(packet1)));
+  ExpectPacket(&payload, kExpected1, sizeof(kExpected1));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_TRUE(payload.video_header().is_first_packet_in_frame);
+  const RTPVideoHeaderH264& h264 = payload.video_header().h264();
+  EXPECT_EQ(kH264FuA, h264.packetization_type);
+  EXPECT_EQ(kIdr, h264.nalu_type);
+  ASSERT_EQ(1u, h264.nalus_length);
+  EXPECT_EQ(static_cast<H264::NaluType>(kIdr), h264.nalus[0].type);
+  EXPECT_EQ(-1, h264.nalus[0].sps_id);
+  EXPECT_EQ(0, h264.nalus[0].pps_id);
+
+  // Following packets will be 2 bytes shorter since they will only be appended
+  // onto the first packet.
+  payload = RtpDepacketizer::ParsedPayload();
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet2, sizeof(packet2)));
+  ExpectPacket(&payload, kExpected2, sizeof(kExpected2));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_FALSE(payload.video_header().is_first_packet_in_frame);
+  {
+    const RTPVideoHeaderH264& h264 = payload.video_header().h264();
+    EXPECT_EQ(kH264FuA, h264.packetization_type);
+    EXPECT_EQ(kIdr, h264.nalu_type);
+    // NALU info is only expected for the first FU-A packet.
+    EXPECT_EQ(0u, h264.nalus_length);
+  }
+
+  payload = RtpDepacketizer::ParsedPayload();
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet3, sizeof(packet3)));
+  ExpectPacket(&payload, kExpected3, sizeof(kExpected3));
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecH264, payload.video_header().codec);
+  EXPECT_FALSE(payload.video_header().is_first_packet_in_frame);
+  {
+    const RTPVideoHeaderH264& h264 = payload.video_header().h264();
+    EXPECT_EQ(kH264FuA, h264.packetization_type);
+    EXPECT_EQ(kIdr, h264.nalu_type);
+    // NALU info is only expected for the first FU-A packet.
+    ASSERT_EQ(0u, h264.nalus_length);
+  }
+}
+
+TEST_F(RtpDepacketizerH264Test, TestEmptyPayload) {
+  // Using a wild pointer to crash on accesses from inside the depacketizer.
+  uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711);
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestTruncatedFuaNalu) {
+  const uint8_t kPayload[] = {0x9c};
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestTruncatedSingleStapANalu) {
+  const uint8_t kPayload[] = {0xd8, 0x27};
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestStapAPacketWithTruncatedNalUnits) {
+  const uint8_t kPayload[] = {0x58, 0xCB, 0xED, 0xDF};
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestTruncationJustAfterSingleStapANalu) {
+  const uint8_t kPayload[] = {0x38, 0x27, 0x27};
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_FALSE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestShortSpsPacket) {
+  const uint8_t kPayload[] = {0x27, 0x80, 0x00};
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_TRUE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+}
+
+TEST_F(RtpDepacketizerH264Test, TestSeiPacket) {
+  const uint8_t kPayload[] = {
+      kSei,                   // F=0, NRI=0, Type=6.
+      0x03, 0x03, 0x03, 0x03  // Payload.
+  };
+  RtpDepacketizer::ParsedPayload payload;
+  ASSERT_TRUE(depacketizer_->Parse(&payload, kPayload, sizeof(kPayload)));
+  const RTPVideoHeaderH264& h264 = payload.video_header().h264();
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kH264SingleNalu, h264.packetization_type);
+  EXPECT_EQ(kSei, h264.nalu_type);
+  ASSERT_EQ(1u, h264.nalus_length);
+  EXPECT_EQ(static_cast<H264::NaluType>(kSei), h264.nalus[0].type);
+  EXPECT_EQ(-1, h264.nalus[0].sps_id);
+  EXPECT_EQ(-1, h264.nalus[0].pps_id);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic.cc b/modules/rtp_rtcp/source/rtp_format_video_generic.cc
new file mode 100644
index 0000000..a2a3ad1
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic.cc
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (c) 2014 The WebRTC 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.
+ */
+
+#include <string>
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+static const size_t kGenericHeaderLength = 1;
+
+RtpPacketizerGeneric::RtpPacketizerGeneric(FrameType frame_type,
+                                           size_t max_payload_len,
+                                           size_t last_packet_reduction_len)
+    : payload_data_(NULL),
+      payload_size_(0),
+      max_payload_len_(max_payload_len - kGenericHeaderLength),
+      last_packet_reduction_len_(last_packet_reduction_len),
+      frame_type_(frame_type),
+      num_packets_left_(0),
+      num_larger_packets_(0) {}
+
+RtpPacketizerGeneric::~RtpPacketizerGeneric() {}
+
+size_t RtpPacketizerGeneric::SetPayloadData(
+    const uint8_t* payload_data,
+    size_t payload_size,
+    const RTPFragmentationHeader* fragmentation) {
+  payload_data_ = payload_data;
+  payload_size_ = payload_size;
+
+  // Fragment packets such that they are almost the same size, even accounting
+  // for larger header in the last packet.
+  // Since we are given how much extra space is occupied by the longer header
+  // in the last packet, we can pretend that RTP headers are the same, but
+  // there's last_packet_reduction_len_ virtual payload, to be put at the end of
+  // the last packet.
+  //
+  size_t total_bytes = payload_size_ + last_packet_reduction_len_;
+
+  // Minimum needed number of packets to fit payload and virtual payload in the
+  // last packet.
+  num_packets_left_ = (total_bytes + max_payload_len_ - 1) / max_payload_len_;
+  // Given number of packets, calculate average size rounded down.
+  payload_len_per_packet_ = total_bytes / num_packets_left_;
+  // If we can't divide everything perfectly evenly, we put 1 extra byte in some
+  // last packets: 14 bytes in 4 packets would be split as 3+3+4+4.
+  num_larger_packets_ = total_bytes % num_packets_left_;
+  RTC_DCHECK_LE(payload_len_per_packet_, max_payload_len_);
+
+  generic_header_ = RtpFormatVideoGeneric::kFirstPacketBit;
+  if (frame_type_ == kVideoFrameKey) {
+    generic_header_ |= RtpFormatVideoGeneric::kKeyFrameBit;
+  }
+  return num_packets_left_;
+}
+
+bool RtpPacketizerGeneric::NextPacket(RtpPacketToSend* packet) {
+  RTC_DCHECK(packet);
+  if (num_packets_left_ == 0)
+    return false;
+  // Last larger_packets_ packets are 1 byte larger than previous packets.
+  // Increase per packet payload once needed.
+  if (num_packets_left_ == num_larger_packets_)
+    ++payload_len_per_packet_;
+  size_t next_packet_payload_len = payload_len_per_packet_;
+  if (payload_size_ <= next_packet_payload_len) {
+    // Whole payload fits into this packet.
+    next_packet_payload_len = payload_size_;
+    if (num_packets_left_ == 2) {
+      // This is the penultimate packet. Leave at least 1 payload byte for the
+      // last packet.
+      --next_packet_payload_len;
+      RTC_DCHECK_GT(next_packet_payload_len, 0);
+    }
+  }
+  RTC_DCHECK_LE(next_packet_payload_len, max_payload_len_);
+
+  uint8_t* out_ptr =
+      packet->AllocatePayload(kGenericHeaderLength + next_packet_payload_len);
+  // Put generic header in packet.
+  out_ptr[0] = generic_header_;
+  // Remove first-packet bit, following packets are intermediate.
+  generic_header_ &= ~RtpFormatVideoGeneric::kFirstPacketBit;
+
+  // Put payload in packet.
+  memcpy(out_ptr + kGenericHeaderLength, payload_data_,
+         next_packet_payload_len);
+  payload_data_ += next_packet_payload_len;
+  payload_size_ -= next_packet_payload_len;
+  --num_packets_left_;
+  // Packets left to produce and data left to split should end at the same time.
+  RTC_DCHECK_EQ(num_packets_left_ == 0, payload_size_ == 0);
+
+  packet->SetMarker(payload_size_ == 0);
+
+  return true;
+}
+
+std::string RtpPacketizerGeneric::ToString() {
+  return "RtpPacketizerGeneric";
+}
+
+RtpDepacketizerGeneric::~RtpDepacketizerGeneric() = default;
+
+bool RtpDepacketizerGeneric::Parse(ParsedPayload* parsed_payload,
+                                   const uint8_t* payload_data,
+                                   size_t payload_data_length) {
+  assert(parsed_payload != NULL);
+  if (payload_data_length == 0) {
+    RTC_LOG(LS_ERROR) << "Empty payload.";
+    return false;
+  }
+
+  uint8_t generic_header = *payload_data++;
+  --payload_data_length;
+
+  parsed_payload->frame_type =
+      ((generic_header & RtpFormatVideoGeneric::kKeyFrameBit) != 0)
+          ? kVideoFrameKey
+          : kVideoFrameDelta;
+  parsed_payload->video_header().is_first_packet_in_frame =
+      (generic_header & RtpFormatVideoGeneric::kFirstPacketBit) != 0;
+  parsed_payload->video_header().codec = kVideoCodecGeneric;
+  parsed_payload->video_header().width = 0;
+  parsed_payload->video_header().height = 0;
+
+  parsed_payload->payload = payload_data;
+  parsed_payload->payload_length = payload_data_length;
+  return true;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic.h b/modules/rtp_rtcp/source/rtp_format_video_generic.h
new file mode 100644
index 0000000..9a916bf
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic.h
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
+
+#include <string>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "rtc_base/constructormagic.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+namespace RtpFormatVideoGeneric {
+static const uint8_t kKeyFrameBit = 0x01;
+static const uint8_t kFirstPacketBit = 0x02;
+}  // namespace RtpFormatVideoGeneric
+
+class RtpPacketizerGeneric : public RtpPacketizer {
+ public:
+  // Initialize with payload from encoder.
+  // The payload_data must be exactly one encoded generic frame.
+  RtpPacketizerGeneric(FrameType frametype,
+                       size_t max_payload_len,
+                       size_t last_packet_reduction_len);
+
+  ~RtpPacketizerGeneric() override;
+
+  // Returns total number of packets to be generated.
+  size_t SetPayloadData(const uint8_t* payload_data,
+                        size_t payload_size,
+                        const RTPFragmentationHeader* fragmentation) override;
+
+  // Get the next payload with generic payload header.
+  // Write payload and set marker bit of the |packet|.
+  // Returns true on success, false otherwise.
+  bool NextPacket(RtpPacketToSend* packet) override;
+
+  std::string ToString() override;
+
+ private:
+  const uint8_t* payload_data_;
+  size_t payload_size_;
+  const size_t max_payload_len_;
+  const size_t last_packet_reduction_len_;
+  FrameType frame_type_;
+  size_t payload_len_per_packet_;
+  uint8_t generic_header_;
+  // Number of packets yet to be retrieved by NextPacket() call.
+  size_t num_packets_left_;
+  // Number of packets, which will be 1 byte more than the rest.
+  size_t num_larger_packets_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerGeneric);
+};
+
+// Depacketizer for generic codec.
+class RtpDepacketizerGeneric : public RtpDepacketizer {
+ public:
+  ~RtpDepacketizerGeneric() override;
+
+  bool Parse(ParsedPayload* parsed_payload,
+             const uint8_t* payload_data,
+             size_t payload_data_length) override;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VIDEO_GENERIC_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc b/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc
new file mode 100644
index 0000000..983bd8f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_video_generic_unittest.cc
@@ -0,0 +1,192 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::Each;
+using ::testing::ElementsAreArray;
+using ::testing::Le;
+using ::testing::SizeIs;
+
+const size_t kMaxPayloadSize = 1200;
+
+uint8_t kTestPayload[kMaxPayloadSize];
+
+std::vector<size_t> NextPacketFillPayloadSizes(
+    RtpPacketizerGeneric* packetizer) {
+  RtpPacketToSend packet(nullptr);
+  std::vector<size_t> result;
+  while (packetizer->NextPacket(&packet)) {
+    result.push_back(packet.payload_size());
+  }
+  return result;
+}
+
+size_t GetEffectivePacketsSizeDifference(std::vector<size_t>* payload_sizes,
+                                         size_t last_packet_reduction_len) {
+  // Account for larger last packet header.
+  payload_sizes->back() += last_packet_reduction_len;
+  auto minmax =
+      std::minmax_element(payload_sizes->begin(), payload_sizes->end());
+  // MAX-MIN
+  size_t difference = *minmax.second - *minmax.first;
+  // Revert temporary changes.
+  payload_sizes->back() -= last_packet_reduction_len;
+  return difference;
+}
+
+}  // namespace
+
+TEST(RtpPacketizerVideoGeneric, AllPacketsMayBeEqualAndRespectMaxPayloadSize) {
+  const size_t kMaxPayloadLen = 6;
+  const size_t kLastPacketReductionLen = 2;
+  const size_t kPayloadSize = 13;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  EXPECT_THAT(payload_sizes, Each(Le(kMaxPayloadLen)));
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     AllPacketsMayBeEqual_RespectsLastPacketReductionLength) {
+  const size_t kMaxPayloadLen = 6;
+  const size_t kLastPacketReductionLen = 2;
+  const size_t kPayloadSize = 13;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  EXPECT_LE(payload_sizes.back(), kMaxPayloadLen - kLastPacketReductionLen);
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     AllPacketsMayBeEqual_MakesPacketsAlmostEqualInSize) {
+  const size_t kMaxPayloadLen = 6;
+  const size_t kLastPacketReductionLen = 2;
+  const size_t kPayloadSize = 13;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  size_t sizes_difference = GetEffectivePacketsSizeDifference(
+      &payload_sizes, kLastPacketReductionLen);
+  EXPECT_LE(sizes_difference, 1u);
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     AllPacketsMayBeEqual_GeneratesMinimumNumberOfPackets) {
+  const size_t kMaxPayloadLen = 6;
+  const size_t kLastPacketReductionLen = 3;
+  const size_t kPayloadSize = 13;
+  // Computed by hand. 3 packets would have capacity 3*(6-1)-3=12 (max length -
+  // generic header lengh for each packet minus last packet reduction).
+  // 4 packets is enough for kPayloadSize.
+  const size_t kMinNumPackets = 4;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  EXPECT_EQ(num_packets, kMinNumPackets);
+}
+
+TEST(RtpPacketizerVideoGeneric, SomePacketsAreSmaller_RespectsMaxPayloadSize) {
+  const size_t kMaxPayloadLen = 8;
+  const size_t kLastPacketReductionLen = 5;
+  const size_t kPayloadSize = 28;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  EXPECT_THAT(payload_sizes, Each(Le(kMaxPayloadLen)));
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     SomePacketsAreSmaller_RespectsLastPacketReductionLength) {
+  const size_t kMaxPayloadLen = 8;
+  const size_t kLastPacketReductionLen = 5;
+  const size_t kPayloadSize = 28;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  EXPECT_LE(payload_sizes.back(), kMaxPayloadLen - kLastPacketReductionLen);
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     SomePacketsAreSmaller_MakesPacketsAlmostEqualInSize) {
+  const size_t kMaxPayloadLen = 8;
+  const size_t kLastPacketReductionLen = 5;
+  const size_t kPayloadSize = 28;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  size_t sizes_difference = GetEffectivePacketsSizeDifference(
+      &payload_sizes, kLastPacketReductionLen);
+  EXPECT_LE(sizes_difference, 1u);
+}
+
+TEST(RtpPacketizerVideoGeneric,
+     SomePacketsAreSmaller_GeneratesMinimumNumberOfPackets) {
+  const size_t kMaxPayloadLen = 8;
+  const size_t kLastPacketReductionLen = 5;
+  const size_t kPayloadSize = 28;
+  // Computed by hand. 4 packets would have capacity 4*(8-1)-5=23 (max length -
+  // generic header lengh for each packet minus last packet reduction).
+  // 5 packets is enough for kPayloadSize.
+  const size_t kMinNumPackets = 5;
+  RtpPacketizerGeneric packetizer(kVideoFrameKey, kMaxPayloadLen,
+                                  kLastPacketReductionLen);
+  size_t num_packets =
+      packetizer.SetPayloadData(kTestPayload, kPayloadSize, nullptr);
+  std::vector<size_t> payload_sizes = NextPacketFillPayloadSizes(&packetizer);
+  EXPECT_THAT(payload_sizes, SizeIs(num_packets));
+
+  EXPECT_EQ(num_packets, kMinNumPackets);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.cc b/modules/rtp_rtcp/source/rtp_format_vp8.cc
new file mode 100644
index 0000000..48c7351
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp8.cc
@@ -0,0 +1,544 @@
+/*
+ *  Copyright (c) 2011 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
+
+#include <string.h>  // memcpy
+
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+int ParseVP8PictureID(RTPVideoHeaderVP8* vp8,
+                      const uint8_t** data,
+                      size_t* data_length,
+                      size_t* parsed_bytes) {
+  if (*data_length == 0)
+    return -1;
+
+  vp8->pictureId = (**data & 0x7F);
+  if (**data & 0x80) {
+    (*data)++;
+    (*parsed_bytes)++;
+    if (--(*data_length) == 0)
+      return -1;
+    // PictureId is 15 bits
+    vp8->pictureId = (vp8->pictureId << 8) + **data;
+  }
+  (*data)++;
+  (*parsed_bytes)++;
+  (*data_length)--;
+  return 0;
+}
+
+int ParseVP8Tl0PicIdx(RTPVideoHeaderVP8* vp8,
+                      const uint8_t** data,
+                      size_t* data_length,
+                      size_t* parsed_bytes) {
+  if (*data_length == 0)
+    return -1;
+
+  vp8->tl0PicIdx = **data;
+  (*data)++;
+  (*parsed_bytes)++;
+  (*data_length)--;
+  return 0;
+}
+
+int ParseVP8TIDAndKeyIdx(RTPVideoHeaderVP8* vp8,
+                         const uint8_t** data,
+                         size_t* data_length,
+                         size_t* parsed_bytes,
+                         bool has_tid,
+                         bool has_key_idx) {
+  if (*data_length == 0)
+    return -1;
+
+  if (has_tid) {
+    vp8->temporalIdx = ((**data >> 6) & 0x03);
+    vp8->layerSync = (**data & 0x20) ? true : false;  // Y bit
+  }
+  if (has_key_idx) {
+    vp8->keyIdx = (**data & 0x1F);
+  }
+  (*data)++;
+  (*parsed_bytes)++;
+  (*data_length)--;
+  return 0;
+}
+
+int ParseVP8Extension(RTPVideoHeaderVP8* vp8,
+                      const uint8_t* data,
+                      size_t data_length) {
+  RTC_DCHECK_GT(data_length, 0);
+  size_t parsed_bytes = 0;
+  // Optional X field is present.
+  bool has_picture_id = (*data & 0x80) ? true : false;   // I bit
+  bool has_tl0_pic_idx = (*data & 0x40) ? true : false;  // L bit
+  bool has_tid = (*data & 0x20) ? true : false;          // T bit
+  bool has_key_idx = (*data & 0x10) ? true : false;      // K bit
+
+  // Advance data and decrease remaining payload size.
+  data++;
+  parsed_bytes++;
+  data_length--;
+
+  if (has_picture_id) {
+    if (ParseVP8PictureID(vp8, &data, &data_length, &parsed_bytes) != 0) {
+      return -1;
+    }
+  }
+
+  if (has_tl0_pic_idx) {
+    if (ParseVP8Tl0PicIdx(vp8, &data, &data_length, &parsed_bytes) != 0) {
+      return -1;
+    }
+  }
+
+  if (has_tid || has_key_idx) {
+    if (ParseVP8TIDAndKeyIdx(vp8, &data, &data_length, &parsed_bytes, has_tid,
+                             has_key_idx) != 0) {
+      return -1;
+    }
+  }
+  return static_cast<int>(parsed_bytes);
+}
+
+int ParseVP8FrameSize(RtpDepacketizer::ParsedPayload* parsed_payload,
+                      const uint8_t* data,
+                      size_t data_length) {
+  if (parsed_payload->frame_type != kVideoFrameKey) {
+    // Included in payload header for I-frames.
+    return 0;
+  }
+  if (data_length < 10) {
+    // For an I-frame we should always have the uncompressed VP8 header
+    // in the beginning of the partition.
+    return -1;
+  }
+  parsed_payload->video_header().width = ((data[7] << 8) + data[6]) & 0x3FFF;
+  parsed_payload->video_header().height = ((data[9] << 8) + data[8]) & 0x3FFF;
+  return 0;
+}
+
+bool ValidateHeader(const RTPVideoHeaderVP8& hdr_info) {
+  if (hdr_info.pictureId != kNoPictureId) {
+    RTC_DCHECK_GE(hdr_info.pictureId, 0);
+    RTC_DCHECK_LE(hdr_info.pictureId, 0x7FFF);
+  }
+  if (hdr_info.tl0PicIdx != kNoTl0PicIdx) {
+    RTC_DCHECK_GE(hdr_info.tl0PicIdx, 0);
+    RTC_DCHECK_LE(hdr_info.tl0PicIdx, 0xFF);
+  }
+  if (hdr_info.temporalIdx != kNoTemporalIdx) {
+    RTC_DCHECK_GE(hdr_info.temporalIdx, 0);
+    RTC_DCHECK_LE(hdr_info.temporalIdx, 3);
+  } else {
+    RTC_DCHECK(!hdr_info.layerSync);
+  }
+  if (hdr_info.keyIdx != kNoKeyIdx) {
+    RTC_DCHECK_GE(hdr_info.keyIdx, 0);
+    RTC_DCHECK_LE(hdr_info.keyIdx, 0x1F);
+  }
+  return true;
+}
+
+}  // namespace
+
+RtpPacketizerVp8::RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
+                                   size_t max_payload_len,
+                                   size_t last_packet_reduction_len)
+    : payload_data_(NULL),
+      payload_size_(0),
+      vp8_fixed_payload_descriptor_bytes_(1),
+      hdr_info_(hdr_info),
+      max_payload_len_(max_payload_len),
+      last_packet_reduction_len_(last_packet_reduction_len) {
+  RTC_DCHECK(ValidateHeader(hdr_info));
+}
+
+RtpPacketizerVp8::~RtpPacketizerVp8() {}
+
+size_t RtpPacketizerVp8::SetPayloadData(
+    const uint8_t* payload_data,
+    size_t payload_size,
+    const RTPFragmentationHeader* /* fragmentation */) {
+  payload_data_ = payload_data;
+  payload_size_ = payload_size;
+  if (GeneratePackets() < 0) {
+    return 0;
+  }
+  return packets_.size();
+}
+
+bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) {
+  RTC_DCHECK(packet);
+  if (packets_.empty()) {
+    return false;
+  }
+  InfoStruct packet_info = packets_.front();
+  packets_.pop();
+
+  uint8_t* buffer = packet->AllocatePayload(
+      packets_.empty() ? max_payload_len_ - last_packet_reduction_len_
+                       : max_payload_len_);
+  int bytes = WriteHeaderAndPayload(packet_info, buffer, max_payload_len_);
+  if (bytes < 0) {
+    return false;
+  }
+  packet->SetPayloadSize(bytes);
+  packet->SetMarker(packets_.empty());
+  return true;
+}
+
+std::string RtpPacketizerVp8::ToString() {
+  return "RtpPacketizerVp8";
+}
+
+int RtpPacketizerVp8::GeneratePackets() {
+  if (max_payload_len_ < vp8_fixed_payload_descriptor_bytes_ +
+                             PayloadDescriptorExtraLength() + 1 +
+                             last_packet_reduction_len_) {
+    // The provided payload length is not long enough for the payload
+    // descriptor and one payload byte in the last packet.
+    // Return an error.
+    return -1;
+  }
+
+  size_t per_packet_capacity =
+      max_payload_len_ -
+      (vp8_fixed_payload_descriptor_bytes_ + PayloadDescriptorExtraLength());
+
+  GeneratePacketsSplitPayloadBalanced(payload_size_, per_packet_capacity);
+  return 0;
+}
+
+void RtpPacketizerVp8::GeneratePacketsSplitPayloadBalanced(size_t payload_len,
+                                                           size_t capacity) {
+  // Last packet of the last partition is smaller. Pretend that it's the same
+  // size, but we must write more payload to it.
+  size_t total_bytes = payload_len + last_packet_reduction_len_;
+  // Integer divisions with rounding up.
+  size_t num_packets_left = (total_bytes + capacity - 1) / capacity;
+  size_t bytes_per_packet = total_bytes / num_packets_left;
+  size_t num_larger_packets = total_bytes % num_packets_left;
+  size_t remaining_data = payload_len;
+  while (remaining_data > 0) {
+    // Last num_larger_packets are 1 byte wider than the rest. Increase
+    // per-packet payload size when needed.
+    if (num_packets_left == num_larger_packets)
+      ++bytes_per_packet;
+    size_t current_packet_bytes = bytes_per_packet;
+    if (current_packet_bytes > remaining_data) {
+      current_packet_bytes = remaining_data;
+    }
+    // This is not the last packet in the whole payload, but there's no data
+    // left for the last packet. Leave at least one byte for the last packet.
+    if (num_packets_left == 2 && current_packet_bytes == remaining_data) {
+      --current_packet_bytes;
+    }
+    QueuePacket(payload_len - remaining_data, current_packet_bytes,
+                remaining_data == payload_len);
+    remaining_data -= current_packet_bytes;
+    --num_packets_left;
+  }
+}
+
+void RtpPacketizerVp8::QueuePacket(size_t start_pos,
+                                   size_t packet_size,
+                                   bool first_packet) {
+  // Write info to packet info struct and store in packet info queue.
+  InfoStruct packet_info;
+  packet_info.payload_start_pos = start_pos;
+  packet_info.size = packet_size;
+  packet_info.first_packet = first_packet;
+  packets_.push(packet_info);
+}
+
+int RtpPacketizerVp8::WriteHeaderAndPayload(const InfoStruct& packet_info,
+                                            uint8_t* buffer,
+                                            size_t buffer_length) const {
+  // Write the VP8 payload descriptor.
+  //       0
+  //       0 1 2 3 4 5 6 7 8
+  //      +-+-+-+-+-+-+-+-+-+
+  //      |X| |N|S| PART_ID |
+  //      +-+-+-+-+-+-+-+-+-+
+  // X:   |I|L|T|K|         | (mandatory if any of the below are used)
+  //      +-+-+-+-+-+-+-+-+-+
+  // I:   |PictureID (8/16b)| (optional)
+  //      +-+-+-+-+-+-+-+-+-+
+  // L:   |   TL0PIC_IDX    | (optional)
+  //      +-+-+-+-+-+-+-+-+-+
+  // T/K: |TID:Y|  KEYIDX   | (optional)
+  //      +-+-+-+-+-+-+-+-+-+
+
+  RTC_DCHECK_GT(packet_info.size, 0);
+  buffer[0] = 0;
+  if (XFieldPresent())
+    buffer[0] |= kXBit;
+  if (hdr_info_.nonReference)
+    buffer[0] |= kNBit;
+  if (packet_info.first_packet)
+    buffer[0] |= kSBit;
+
+  const int extension_length = WriteExtensionFields(buffer, buffer_length);
+  if (extension_length < 0)
+    return -1;
+
+  memcpy(&buffer[vp8_fixed_payload_descriptor_bytes_ + extension_length],
+         &payload_data_[packet_info.payload_start_pos], packet_info.size);
+
+  // Return total length of written data.
+  return packet_info.size + vp8_fixed_payload_descriptor_bytes_ +
+         extension_length;
+}
+
+int RtpPacketizerVp8::WriteExtensionFields(uint8_t* buffer,
+                                           size_t buffer_length) const {
+  size_t extension_length = 0;
+  if (XFieldPresent()) {
+    uint8_t* x_field = buffer + vp8_fixed_payload_descriptor_bytes_;
+    *x_field = 0;
+    extension_length = 1;  // One octet for the X field.
+    if (PictureIdPresent()) {
+      if (WritePictureIDFields(x_field, buffer, buffer_length,
+                               &extension_length) < 0) {
+        return -1;
+      }
+    }
+    if (TL0PicIdxFieldPresent()) {
+      if (WriteTl0PicIdxFields(x_field, buffer, buffer_length,
+                               &extension_length) < 0) {
+        return -1;
+      }
+    }
+    if (TIDFieldPresent() || KeyIdxFieldPresent()) {
+      if (WriteTIDAndKeyIdxFields(x_field, buffer, buffer_length,
+                                  &extension_length) < 0) {
+        return -1;
+      }
+    }
+    RTC_DCHECK_EQ(extension_length, PayloadDescriptorExtraLength());
+  }
+  return static_cast<int>(extension_length);
+}
+
+int RtpPacketizerVp8::WritePictureIDFields(uint8_t* x_field,
+                                           uint8_t* buffer,
+                                           size_t buffer_length,
+                                           size_t* extension_length) const {
+  *x_field |= kIBit;
+  RTC_DCHECK_GE(buffer_length,
+                vp8_fixed_payload_descriptor_bytes_ + *extension_length);
+  const int pic_id_length = WritePictureID(
+      buffer + vp8_fixed_payload_descriptor_bytes_ + *extension_length,
+      buffer_length - vp8_fixed_payload_descriptor_bytes_ - *extension_length);
+  if (pic_id_length < 0)
+    return -1;
+  *extension_length += pic_id_length;
+  return 0;
+}
+
+int RtpPacketizerVp8::WritePictureID(uint8_t* buffer,
+                                     size_t buffer_length) const {
+  const uint16_t pic_id = static_cast<uint16_t>(hdr_info_.pictureId);
+  size_t picture_id_len = PictureIdLength();
+  if (picture_id_len > buffer_length)
+    return -1;
+  if (picture_id_len == 2) {
+    buffer[0] = 0x80 | ((pic_id >> 8) & 0x7F);
+    buffer[1] = pic_id & 0xFF;
+  } else if (picture_id_len == 1) {
+    buffer[0] = pic_id & 0x7F;
+  }
+  return static_cast<int>(picture_id_len);
+}
+
+int RtpPacketizerVp8::WriteTl0PicIdxFields(uint8_t* x_field,
+                                           uint8_t* buffer,
+                                           size_t buffer_length,
+                                           size_t* extension_length) const {
+  if (buffer_length <
+      vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
+    return -1;
+  }
+  *x_field |= kLBit;
+  buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length] =
+      hdr_info_.tl0PicIdx;
+  ++*extension_length;
+  return 0;
+}
+
+int RtpPacketizerVp8::WriteTIDAndKeyIdxFields(uint8_t* x_field,
+                                              uint8_t* buffer,
+                                              size_t buffer_length,
+                                              size_t* extension_length) const {
+  if (buffer_length <
+      vp8_fixed_payload_descriptor_bytes_ + *extension_length + 1) {
+    return -1;
+  }
+  uint8_t* data_field =
+      &buffer[vp8_fixed_payload_descriptor_bytes_ + *extension_length];
+  *data_field = 0;
+  if (TIDFieldPresent()) {
+    *x_field |= kTBit;
+    *data_field |= hdr_info_.temporalIdx << 6;
+    *data_field |= hdr_info_.layerSync ? kYBit : 0;
+  }
+  if (KeyIdxFieldPresent()) {
+    *x_field |= kKBit;
+    *data_field |= (hdr_info_.keyIdx & kKeyIdxField);
+  }
+  ++*extension_length;
+  return 0;
+}
+
+size_t RtpPacketizerVp8::PayloadDescriptorExtraLength() const {
+  size_t length_bytes = PictureIdLength();
+  if (TL0PicIdxFieldPresent())
+    ++length_bytes;
+  if (TIDFieldPresent() || KeyIdxFieldPresent())
+    ++length_bytes;
+  if (length_bytes > 0)
+    ++length_bytes;  // Include the extension field.
+  return length_bytes;
+}
+
+size_t RtpPacketizerVp8::PictureIdLength() const {
+  if (hdr_info_.pictureId == kNoPictureId) {
+    return 0;
+  }
+  return 2;
+}
+
+bool RtpPacketizerVp8::XFieldPresent() const {
+  return (TIDFieldPresent() || TL0PicIdxFieldPresent() || PictureIdPresent() ||
+          KeyIdxFieldPresent());
+}
+
+bool RtpPacketizerVp8::TIDFieldPresent() const {
+  return (hdr_info_.temporalIdx != kNoTemporalIdx);
+}
+
+bool RtpPacketizerVp8::KeyIdxFieldPresent() const {
+  return (hdr_info_.keyIdx != kNoKeyIdx);
+}
+
+bool RtpPacketizerVp8::TL0PicIdxFieldPresent() const {
+  return (hdr_info_.tl0PicIdx != kNoTl0PicIdx);
+}
+
+//
+// VP8 format:
+//
+// Payload descriptor
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |X|R|N|S|PartID | (REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// X:   |I|L|T|K|  RSV  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// I:   |   PictureID   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// L:   |   TL0PICIDX   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// T/K: |TID:Y| KEYIDX  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+//
+// Payload header (considered part of the actual payload, sent to decoder)
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |Size0|H| VER |P|
+//      +-+-+-+-+-+-+-+-+
+//      |      ...      |
+//      +               +
+bool RtpDepacketizerVp8::Parse(ParsedPayload* parsed_payload,
+                               const uint8_t* payload_data,
+                               size_t payload_data_length) {
+  RTC_DCHECK(parsed_payload);
+  if (payload_data_length == 0) {
+    RTC_LOG(LS_ERROR) << "Empty payload.";
+    return false;
+  }
+
+  // Parse mandatory first byte of payload descriptor.
+  bool extension = (*payload_data & 0x80) ? true : false;               // X bit
+  bool beginning_of_partition = (*payload_data & 0x10) ? true : false;  // S bit
+  int partition_id = (*payload_data & 0x0F);  // PartID field
+
+  parsed_payload->video_header().width = 0;
+  parsed_payload->video_header().height = 0;
+  parsed_payload->video_header().is_first_packet_in_frame =
+      beginning_of_partition && (partition_id == 0);
+  parsed_payload->video_header().simulcastIdx = 0;
+  parsed_payload->video_header().codec = kVideoCodecVP8;
+  parsed_payload->video_header().vp8().nonReference =
+      (*payload_data & 0x20) ? true : false;  // N bit
+  parsed_payload->video_header().vp8().partitionId = partition_id;
+  parsed_payload->video_header().vp8().beginningOfPartition =
+      beginning_of_partition;
+  parsed_payload->video_header().vp8().pictureId = kNoPictureId;
+  parsed_payload->video_header().vp8().tl0PicIdx = kNoTl0PicIdx;
+  parsed_payload->video_header().vp8().temporalIdx = kNoTemporalIdx;
+  parsed_payload->video_header().vp8().layerSync = false;
+  parsed_payload->video_header().vp8().keyIdx = kNoKeyIdx;
+
+  if (partition_id > 8) {
+    // Weak check for corrupt payload_data: PartID MUST NOT be larger than 8.
+    return false;
+  }
+
+  // Advance payload_data and decrease remaining payload size.
+  payload_data++;
+  if (payload_data_length <= 1) {
+    RTC_LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
+    return false;
+  }
+  payload_data_length--;
+
+  if (extension) {
+    const int parsed_bytes =
+        ParseVP8Extension(&parsed_payload->video_header().vp8(), payload_data,
+                          payload_data_length);
+    if (parsed_bytes < 0)
+      return false;
+    payload_data += parsed_bytes;
+    payload_data_length -= parsed_bytes;
+    if (payload_data_length == 0) {
+      RTC_LOG(LS_ERROR) << "Error parsing VP8 payload descriptor!";
+      return false;
+    }
+  }
+
+  // Read P bit from payload header (only at beginning of first partition).
+  if (beginning_of_partition && partition_id == 0) {
+    parsed_payload->frame_type =
+        (*payload_data & 0x01) ? kVideoFrameDelta : kVideoFrameKey;
+  } else {
+    parsed_payload->frame_type = kVideoFrameDelta;
+  }
+
+  if (ParseVP8FrameSize(parsed_payload, payload_data, payload_data_length) !=
+      0) {
+    return false;
+  }
+
+  parsed_payload->payload = payload_data;
+  parsed_payload->payload_length = payload_data_length;
+  return true;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8.h b/modules/rtp_rtcp/source/rtp_format_vp8.h
new file mode 100644
index 0000000..3f0d7e5
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp8.h
@@ -0,0 +1,166 @@
+/*
+ *  Copyright (c) 2011 The WebRTC 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.
+ */
+
+/*
+ * This file contains the declaration of the VP8 packetizer class.
+ * A packetizer object is created for each encoded video frame. The
+ * constructor is called with the payload data and size,
+ * together with the fragmentation information and a packetizer mode
+ * of choice. Alternatively, if no fragmentation info is available, the
+ * second constructor can be used with only payload data and size; in that
+ * case the mode kEqualSize is used.
+ *
+ * After creating the packetizer, the method NextPacket is called
+ * repeatedly to get all packets for the frame. The method returns
+ * false as long as there are more packets left to fetch.
+ */
+
+#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "rtc_base/constructormagic.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+// Packetizer for VP8.
+class RtpPacketizerVp8 : public RtpPacketizer {
+ public:
+  // Initialize with payload from encoder.
+  // The payload_data must be exactly one encoded VP8 frame.
+  RtpPacketizerVp8(const RTPVideoHeaderVP8& hdr_info,
+                   size_t max_payload_len,
+                   size_t last_packet_reduction_len);
+
+  ~RtpPacketizerVp8() override;
+
+  size_t SetPayloadData(const uint8_t* payload_data,
+                        size_t payload_size,
+                        const RTPFragmentationHeader* fragmentation) override;
+
+  // Get the next payload with VP8 payload header.
+  // Write payload and set marker bit of the |packet|.
+  // Returns true on success, false otherwise.
+  bool NextPacket(RtpPacketToSend* packet) override;
+
+  std::string ToString() override;
+
+ private:
+  typedef struct {
+    size_t payload_start_pos;
+    size_t size;
+    bool first_packet;
+  } InfoStruct;
+  typedef std::queue<InfoStruct> InfoQueue;
+
+  static const int kXBit = 0x80;
+  static const int kNBit = 0x20;
+  static const int kSBit = 0x10;
+  static const int kPartIdField = 0x0F;
+  static const int kKeyIdxField = 0x1F;
+  static const int kIBit = 0x80;
+  static const int kLBit = 0x40;
+  static const int kTBit = 0x20;
+  static const int kKBit = 0x10;
+  static const int kYBit = 0x20;
+
+  // Calculate all packet sizes and load to packet info queue.
+  int GeneratePackets();
+
+  // Splits given part of payload to packets with a given capacity. The last
+  // packet should be reduced by last_packet_reduction_len_.
+  void GeneratePacketsSplitPayloadBalanced(size_t payload_len, size_t capacity);
+
+  // Insert packet into packet queue.
+  void QueuePacket(size_t start_pos, size_t packet_size, bool first_packet);
+
+  // Write the payload header and copy the payload to the buffer.
+  // The info in packet_info determines which part of the payload is written
+  // and what to write in the header fields.
+  int WriteHeaderAndPayload(const InfoStruct& packet_info,
+                            uint8_t* buffer,
+                            size_t buffer_length) const;
+
+  // Write the X field and the appropriate extension fields to buffer.
+  // The function returns the extension length (including X field), or -1
+  // on error.
+  int WriteExtensionFields(uint8_t* buffer, size_t buffer_length) const;
+
+  // Set the I bit in the x_field, and write PictureID to the appropriate
+  // position in buffer. The function returns 0 on success, -1 otherwise.
+  int WritePictureIDFields(uint8_t* x_field,
+                           uint8_t* buffer,
+                           size_t buffer_length,
+                           size_t* extension_length) const;
+
+  // Set the L bit in the x_field, and write Tl0PicIdx to the appropriate
+  // position in buffer. The function returns 0 on success, -1 otherwise.
+  int WriteTl0PicIdxFields(uint8_t* x_field,
+                           uint8_t* buffer,
+                           size_t buffer_length,
+                           size_t* extension_length) const;
+
+  // Set the T and K bits in the x_field, and write TID, Y and KeyIdx to the
+  // appropriate position in buffer. The function returns 0 on success,
+  // -1 otherwise.
+  int WriteTIDAndKeyIdxFields(uint8_t* x_field,
+                              uint8_t* buffer,
+                              size_t buffer_length,
+                              size_t* extension_length) const;
+
+  // Write the PictureID from codec_specific_info_ to buffer. One or two
+  // bytes are written, depending on magnitude of PictureID. The function
+  // returns the number of bytes written.
+  int WritePictureID(uint8_t* buffer, size_t buffer_length) const;
+
+  // Calculate and return length (octets) of the variable header fields in
+  // the next header (i.e., header length in addition to vp8_header_bytes_).
+  size_t PayloadDescriptorExtraLength() const;
+
+  // Calculate and return length (octets) of PictureID field in the next
+  // header. Can be 0, 1, or 2.
+  size_t PictureIdLength() const;
+
+  // Check whether each of the optional fields will be included in the header.
+  bool XFieldPresent() const;
+  bool TIDFieldPresent() const;
+  bool KeyIdxFieldPresent() const;
+  bool TL0PicIdxFieldPresent() const;
+  bool PictureIdPresent() const { return (PictureIdLength() > 0); }
+
+  const uint8_t* payload_data_;
+  size_t payload_size_;
+  const size_t vp8_fixed_payload_descriptor_bytes_;  // Length of VP8 payload
+                                                     // descriptors' fixed part.
+  const RTPVideoHeaderVP8 hdr_info_;
+  const size_t max_payload_len_;
+  const size_t last_packet_reduction_len_;
+  InfoQueue packets_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp8);
+};
+
+// Depacketizer for VP8.
+class RtpDepacketizerVp8 : public RtpDepacketizer {
+ public:
+  ~RtpDepacketizerVp8() override = default;
+
+  bool Parse(ParsedPayload* parsed_payload,
+             const uint8_t* payload_data,
+             size_t payload_data_length) override;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc
new file mode 100644
index 0000000..8dc7ba0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc
@@ -0,0 +1,242 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace test {
+
+constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
+
+RtpFormatVp8TestHelper::RtpFormatVp8TestHelper(const RTPVideoHeaderVP8* hdr)
+    : packet_(kNoExtensions),
+      payload_data_(NULL),
+      data_ptr_(NULL),
+      fragmentation_(NULL),
+      hdr_info_(hdr),
+      payload_start_(0),
+      payload_size_(0),
+      sloppy_partitioning_(false),
+      inited_(false) {}
+
+RtpFormatVp8TestHelper::~RtpFormatVp8TestHelper() {
+  delete fragmentation_;
+  delete[] payload_data_;
+}
+
+bool RtpFormatVp8TestHelper::Init(const size_t* partition_sizes,
+                                  size_t num_partitions) {
+  if (inited_)
+    return false;
+  fragmentation_ = new RTPFragmentationHeader;
+  fragmentation_->VerifyAndAllocateFragmentationHeader(num_partitions);
+  payload_size_ = 0;
+  // Calculate sum payload size.
+  for (size_t p = 0; p < num_partitions; ++p) {
+    payload_size_ += partition_sizes[p];
+  }
+  payload_data_ = new uint8_t[payload_size_];
+  size_t j = 0;
+  // Loop through the partitions again.
+  for (size_t p = 0; p < num_partitions; ++p) {
+    fragmentation_->fragmentationLength[p] = partition_sizes[p];
+    fragmentation_->fragmentationOffset[p] = j;
+    for (size_t i = 0; i < partition_sizes[p]; ++i) {
+      assert(j < payload_size_);
+      payload_data_[j++] = p;  // Set the payload value to the partition index.
+    }
+  }
+  data_ptr_ = payload_data_;
+  inited_ = true;
+  return true;
+}
+
+void RtpFormatVp8TestHelper::GetAllPacketsAndCheck(
+    RtpPacketizerVp8* packetizer,
+    const size_t* expected_sizes,
+    const int* expected_part,
+    const bool* expected_frag_start,
+    size_t expected_num_packets) {
+  ASSERT_TRUE(inited_);
+  for (size_t i = 0; i < expected_num_packets; ++i) {
+    std::ostringstream ss;
+    ss << "Checking packet " << i;
+    SCOPED_TRACE(ss.str());
+    EXPECT_TRUE(packetizer->NextPacket(&packet_));
+    CheckPacket(expected_sizes[i], i + 1 == expected_num_packets,
+                expected_frag_start[i]);
+  }
+}
+
+// Payload descriptor
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |X|R|N|S|PartID | (REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// X:   |I|L|T|K|  RSV  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// I:   |   PictureID   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// L:   |   TL0PICIDX   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// T/K: | TID | KEYIDX  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+
+// First octet tests.
+#define EXPECT_BIT_EQ(x, n, a) EXPECT_EQ((((x) >> (n)) & 0x1), a)
+
+#define EXPECT_RSV_ZERO(x) EXPECT_EQ(((x)&0xE0), 0)
+
+#define EXPECT_BIT_X_EQ(x, a) EXPECT_BIT_EQ(x, 7, a)
+
+#define EXPECT_BIT_N_EQ(x, a) EXPECT_BIT_EQ(x, 5, a)
+
+#define EXPECT_BIT_S_EQ(x, a) EXPECT_BIT_EQ(x, 4, a)
+
+#define EXPECT_PART_ID_EQ(x, a) EXPECT_EQ(((x)&0x0F), a)
+
+// Extension fields tests
+#define EXPECT_BIT_I_EQ(x, a) EXPECT_BIT_EQ(x, 7, a)
+
+#define EXPECT_BIT_L_EQ(x, a) EXPECT_BIT_EQ(x, 6, a)
+
+#define EXPECT_BIT_T_EQ(x, a) EXPECT_BIT_EQ(x, 5, a)
+
+#define EXPECT_BIT_K_EQ(x, a) EXPECT_BIT_EQ(x, 4, a)
+
+#define EXPECT_TID_EQ(x, a) EXPECT_EQ((((x)&0xC0) >> 6), a)
+
+#define EXPECT_BIT_Y_EQ(x, a) EXPECT_BIT_EQ(x, 5, a)
+
+#define EXPECT_KEYIDX_EQ(x, a) EXPECT_EQ(((x)&0x1F), a)
+
+void RtpFormatVp8TestHelper::CheckHeader(bool frag_start) {
+  payload_start_ = 1;
+  rtc::ArrayView<const uint8_t> buffer = packet_.payload();
+  EXPECT_BIT_EQ(buffer[0], 6, 0);  // Check reserved bit.
+
+  if (hdr_info_->pictureId != kNoPictureId ||
+      hdr_info_->temporalIdx != kNoTemporalIdx ||
+      hdr_info_->tl0PicIdx != kNoTl0PicIdx || hdr_info_->keyIdx != kNoKeyIdx) {
+    EXPECT_BIT_X_EQ(buffer[0], 1);
+    ++payload_start_;
+    CheckPictureID();
+    CheckTl0PicIdx();
+    CheckTIDAndKeyIdx();
+  } else {
+    EXPECT_BIT_X_EQ(buffer[0], 0);
+  }
+
+  EXPECT_BIT_N_EQ(buffer[0], hdr_info_->nonReference ? 1 : 0);
+  EXPECT_BIT_S_EQ(buffer[0], frag_start ? 1 : 0);
+
+  // Check partition index.
+  if (!sloppy_partitioning_) {
+    // The test payload data is constructed such that the payload value is the
+    // same as the partition index.
+    EXPECT_EQ(buffer[0] & 0x0F, buffer[payload_start_]);
+  } else {
+    // Partition should be set to 0.
+    EXPECT_EQ(buffer[0] & 0x0F, 0);
+  }
+}
+
+// Verify that the I bit and the PictureID field are both set in accordance
+// with the information in hdr_info_->pictureId.
+void RtpFormatVp8TestHelper::CheckPictureID() {
+  auto buffer = packet_.payload();
+  if (hdr_info_->pictureId != kNoPictureId) {
+    EXPECT_BIT_I_EQ(buffer[1], 1);
+    EXPECT_BIT_EQ(buffer[payload_start_], 7, 1);
+    EXPECT_EQ(buffer[payload_start_] & 0x7F,
+              (hdr_info_->pictureId >> 8) & 0x7F);
+    EXPECT_EQ(buffer[payload_start_ + 1], hdr_info_->pictureId & 0xFF);
+    payload_start_ += 2;
+  } else {
+    EXPECT_BIT_I_EQ(buffer[1], 0);
+  }
+}
+
+// Verify that the L bit and the TL0PICIDX field are both set in accordance
+// with the information in hdr_info_->tl0PicIdx.
+void RtpFormatVp8TestHelper::CheckTl0PicIdx() {
+  auto buffer = packet_.payload();
+  if (hdr_info_->tl0PicIdx != kNoTl0PicIdx) {
+    EXPECT_BIT_L_EQ(buffer[1], 1);
+    EXPECT_EQ(buffer[payload_start_], hdr_info_->tl0PicIdx);
+    ++payload_start_;
+  } else {
+    EXPECT_BIT_L_EQ(buffer[1], 0);
+  }
+}
+
+// Verify that the T bit and the TL0PICIDX field, and the K bit and KEYIDX
+// field are all set in accordance with the information in
+// hdr_info_->temporalIdx and hdr_info_->keyIdx, respectively.
+void RtpFormatVp8TestHelper::CheckTIDAndKeyIdx() {
+  auto buffer = packet_.payload();
+  if (hdr_info_->temporalIdx == kNoTemporalIdx &&
+      hdr_info_->keyIdx == kNoKeyIdx) {
+    EXPECT_BIT_T_EQ(buffer[1], 0);
+    EXPECT_BIT_K_EQ(buffer[1], 0);
+    return;
+  }
+  if (hdr_info_->temporalIdx != kNoTemporalIdx) {
+    EXPECT_BIT_T_EQ(buffer[1], 1);
+    EXPECT_TID_EQ(buffer[payload_start_], hdr_info_->temporalIdx);
+    EXPECT_BIT_Y_EQ(buffer[payload_start_], hdr_info_->layerSync ? 1 : 0);
+  } else {
+    EXPECT_BIT_T_EQ(buffer[1], 0);
+    EXPECT_TID_EQ(buffer[payload_start_], 0);
+    EXPECT_BIT_Y_EQ(buffer[payload_start_], 0);
+  }
+  if (hdr_info_->keyIdx != kNoKeyIdx) {
+    EXPECT_BIT_K_EQ(buffer[1], 1);
+    EXPECT_KEYIDX_EQ(buffer[payload_start_], hdr_info_->keyIdx);
+  } else {
+    EXPECT_BIT_K_EQ(buffer[1], 0);
+    EXPECT_KEYIDX_EQ(buffer[payload_start_], 0);
+  }
+  ++payload_start_;
+}
+
+// Verify that the payload (i.e., after the headers) of the packet stored in
+// buffer_ is identical to the expected (as found in data_ptr_).
+void RtpFormatVp8TestHelper::CheckPayload() {
+  auto buffer = packet_.payload();
+  size_t payload_end = buffer.size();
+  for (size_t i = payload_start_; i < payload_end; ++i, ++data_ptr_)
+    EXPECT_EQ(buffer[i], *data_ptr_);
+}
+
+// Verify that the input variable "last" agrees with the position of data_ptr_.
+// If data_ptr_ has advanced payload_size_ bytes from the start (payload_data_)
+// we are at the end and last should be true. Otherwise, it should be false.
+void RtpFormatVp8TestHelper::CheckLast(bool last) const {
+  EXPECT_EQ(last, data_ptr_ == payload_data_ + payload_size_);
+}
+
+// Verify the contents of a packet. Check the length versus expected_bytes,
+// the header, payload, and "last" flag.
+void RtpFormatVp8TestHelper::CheckPacket(size_t expect_bytes,
+                                         bool last,
+                                         bool frag_start) {
+  EXPECT_EQ(expect_bytes, packet_.payload_size());
+  CheckHeader(frag_start);
+  CheckPayload();
+  CheckLast(last);
+}
+
+}  // namespace test
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h
new file mode 100644
index 0000000..1ed63ab
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2011 The WebRTC 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.
+ */
+
+// This file contains the class RtpFormatVp8TestHelper. The class is
+// responsible for setting up a fake VP8 bitstream according to the
+// RTPVideoHeaderVP8 header, and partition information. After initialization,
+// an RTPFragmentationHeader is provided so that the tester can create a
+// packetizer. The packetizer can then be provided to this helper class, which
+// will then extract all packets and compare to the expected outcome.
+
+#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_TEST_HELPER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_TEST_HELPER_H_
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/constructormagic.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+namespace test {
+
+class RtpFormatVp8TestHelper {
+ public:
+  explicit RtpFormatVp8TestHelper(const RTPVideoHeaderVP8* hdr);
+  ~RtpFormatVp8TestHelper();
+  bool Init(const size_t* partition_sizes, size_t num_partitions);
+  void GetAllPacketsAndCheck(RtpPacketizerVp8* packetizer,
+                             const size_t* expected_sizes,
+                             const int* expected_part,
+                             const bool* expected_frag_start,
+                             size_t expected_num_packets);
+
+  uint8_t* payload_data() const { return payload_data_; }
+  size_t payload_size() const { return payload_size_; }
+  RTPFragmentationHeader* fragmentation() const { return fragmentation_; }
+  size_t buffer_size() const {
+    static constexpr size_t kVp8PayloadDescriptorMaxSize = 6;
+    return payload_size_ + kVp8PayloadDescriptorMaxSize;
+  }
+  void set_sloppy_partitioning(bool value) { sloppy_partitioning_ = value; }
+
+ private:
+  void CheckHeader(bool frag_start);
+  void CheckPictureID();
+  void CheckTl0PicIdx();
+  void CheckTIDAndKeyIdx();
+  void CheckPayload();
+  void CheckLast(bool last) const;
+  void CheckPacket(size_t expect_bytes, bool last, bool frag_start);
+
+  RtpPacketToSend packet_;
+  uint8_t* payload_data_;
+  uint8_t* data_ptr_;
+  RTPFragmentationHeader* fragmentation_;
+  const RTPVideoHeaderVP8* hdr_info_;
+  int payload_start_;
+  size_t payload_size_;
+  bool sloppy_partitioning_;
+  bool inited_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(RtpFormatVp8TestHelper);
+};
+
+}  // namespace test
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP8_TEST_HELPER_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc b/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
new file mode 100644
index 0000000..adcc5a2
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp8_unittest.cc
@@ -0,0 +1,465 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <memory>
+
+#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
+#include "modules/rtp_rtcp/source/rtp_format_vp8_test_helper.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+#define CHECK_ARRAY_SIZE(expected_size, array)                     \
+  static_assert(expected_size == sizeof(array) / sizeof(array[0]), \
+                "check array size");
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+using ::testing::make_tuple;
+
+constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
+// Payload descriptor
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |X|R|N|S|PartID | (REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// X:   |I|L|T|K|  RSV  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// I:   |   PictureID   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// L:   |   TL0PICIDX   | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+// T/K: |TID:Y| KEYIDX  | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+
+//
+// Payload header
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |Size0|H| VER |P|
+//      +-+-+-+-+-+-+-+-+
+//      |     Size1     |
+//      +-+-+-+-+-+-+-+-+
+//      |     Size2     |
+//      +-+-+-+-+-+-+-+-+
+//      | Bytes 4..N of |
+//      | VP8 payload   |
+//      :               :
+//      +-+-+-+-+-+-+-+-+
+//      | OPTIONAL RTP  |
+//      | padding       |
+//      :               :
+//      +-+-+-+-+-+-+-+-+
+void VerifyBasicHeader(RTPVideoHeader* header, bool N, bool S, int part_id) {
+  ASSERT_TRUE(header != NULL);
+  EXPECT_EQ(N, header->vp8().nonReference);
+  EXPECT_EQ(S, header->vp8().beginningOfPartition);
+  EXPECT_EQ(part_id, header->vp8().partitionId);
+}
+
+void VerifyExtensions(RTPVideoHeader* header,
+                      int16_t picture_id,   /* I */
+                      int16_t tl0_pic_idx,  /* L */
+                      uint8_t temporal_idx, /* T */
+                      int key_idx /* K */) {
+  ASSERT_TRUE(header != NULL);
+  EXPECT_EQ(picture_id, header->vp8().pictureId);
+  EXPECT_EQ(tl0_pic_idx, header->vp8().tl0PicIdx);
+  EXPECT_EQ(temporal_idx, header->vp8().temporalIdx);
+  EXPECT_EQ(key_idx, header->vp8().keyIdx);
+}
+}  // namespace
+
+class RtpPacketizerVp8Test : public ::testing::Test {
+ protected:
+  RtpPacketizerVp8Test() : helper_(NULL) {}
+  void TearDown() override { delete helper_; }
+  bool Init(const size_t* partition_sizes, size_t num_partitions) {
+    hdr_info_.pictureId = kNoPictureId;
+    hdr_info_.nonReference = false;
+    hdr_info_.temporalIdx = kNoTemporalIdx;
+    hdr_info_.layerSync = false;
+    hdr_info_.tl0PicIdx = kNoTl0PicIdx;
+    hdr_info_.keyIdx = kNoKeyIdx;
+    if (helper_ != NULL)
+      return false;
+    helper_ = new test::RtpFormatVp8TestHelper(&hdr_info_);
+    return helper_->Init(partition_sizes, num_partitions);
+  }
+
+  RTPVideoHeaderVP8 hdr_info_;
+  test::RtpFormatVp8TestHelper* helper_;
+};
+
+// Verify that EqualSize mode is forced if fragmentation info is missing.
+TEST_F(RtpPacketizerVp8Test, TestEqualSizeModeFallback) {
+  const size_t kSizeVector[] = {10, 10, 10};
+  const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
+  ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
+
+  hdr_info_.pictureId = 200;          // > 0x7F should produce 2-byte PictureID
+  const size_t kMaxPayloadSize = 12;  // Small enough to produce 4 packets.
+  RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
+  size_t num_packets = packetizer.SetPayloadData(
+      helper_->payload_data(), helper_->payload_size(), nullptr);
+
+  // Expecting three full packets, and one with the remainder.
+  const size_t kExpectedSizes[] = {11, 11, 12, 12};
+  const int kExpectedPart[] = {0, 0, 0, 0};  // Always 0 for equal size mode.
+  // Frag start only true for first packet in equal size mode.
+  const bool kExpectedFragStart[] = {true, false, false, false};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
+  ASSERT_EQ(num_packets, kExpectedNum);
+
+  helper_->set_sloppy_partitioning(true);
+  helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
+                                 kExpectedFragStart, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp8Test, TestEqualSizeWithLastPacketReduction) {
+  const size_t kSizeVector[] = {30, 10, 3};
+  const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
+  ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
+
+  hdr_info_.pictureId = 200;
+  const size_t kMaxPayloadSize = 15;  // Small enough to produce 5 packets.
+  const size_t kLastPacketReduction = 5;
+  RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, kLastPacketReduction);
+  size_t num_packets = packetizer.SetPayloadData(
+      helper_->payload_data(), helper_->payload_size(), nullptr);
+
+  // Calculated by hand. VP8 payload descriptors are 4 byte each. 5 packets is
+  // minimum possible to fit 43 payload bytes into packets with capacity of
+  // 15 - 4 = 11 and leave 5 free bytes in the last packet. All packets are
+  // almost equal in size, even last packet if counted with free space (which
+  // will be filled up the stack by extra long RTP header).
+  const size_t kExpectedSizes[] = {13, 13, 14, 14, 9};
+  const int kExpectedPart[] = {0, 0, 0, 0, 0};  // Always 0 for equal size mode.
+  // Frag start only true for first packet in equal size mode.
+  const bool kExpectedFragStart[] = {true, false, false, false, false};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
+  ASSERT_EQ(num_packets, kExpectedNum);
+
+  helper_->set_sloppy_partitioning(true);
+  helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
+                                 kExpectedFragStart, kExpectedNum);
+}
+
+// Verify that non-reference bit is set. EqualSize mode fallback is expected.
+TEST_F(RtpPacketizerVp8Test, TestNonReferenceBit) {
+  const size_t kSizeVector[] = {10, 10, 10};
+  const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
+  ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
+
+  hdr_info_.nonReference = true;
+  const size_t kMaxPayloadSize = 25;  // Small enough to produce two packets.
+  RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
+  size_t num_packets = packetizer.SetPayloadData(
+      helper_->payload_data(), helper_->payload_size(), nullptr);
+
+  // EqualSize mode => First packet full; other not.
+  const size_t kExpectedSizes[] = {16, 16};
+  const int kExpectedPart[] = {0, 0};  // Always 0 for equal size mode.
+  // Frag start only true for first packet in equal size mode.
+  const bool kExpectedFragStart[] = {true, false};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
+  ASSERT_EQ(num_packets, kExpectedNum);
+
+  helper_->set_sloppy_partitioning(true);
+  helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
+                                 kExpectedFragStart, kExpectedNum);
+}
+
+// Verify Tl0PicIdx and TID fields, and layerSync bit.
+TEST_F(RtpPacketizerVp8Test, TestTl0PicIdxAndTID) {
+  const size_t kSizeVector[] = {10, 10, 10};
+  const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
+  ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
+
+  hdr_info_.tl0PicIdx = 117;
+  hdr_info_.temporalIdx = 2;
+  hdr_info_.layerSync = true;
+  // kMaxPayloadSize is only limited by allocated buffer size.
+  const size_t kMaxPayloadSize = helper_->buffer_size();
+  RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
+  size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
+                                                 helper_->payload_size(),
+                                                 helper_->fragmentation());
+
+  // Expect one single packet of payload_size() + 4 bytes header.
+  const size_t kExpectedSizes[1] = {helper_->payload_size() + 4};
+  const int kExpectedPart[1] = {0};  // Packet starts with partition 0.
+  const bool kExpectedFragStart[1] = {true};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
+  ASSERT_EQ(num_packets, kExpectedNum);
+
+  helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
+                                 kExpectedFragStart, kExpectedNum);
+}
+
+// Verify KeyIdx field.
+TEST_F(RtpPacketizerVp8Test, TestKeyIdx) {
+  const size_t kSizeVector[] = {10, 10, 10};
+  const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
+  ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
+
+  hdr_info_.keyIdx = 17;
+  // kMaxPayloadSize is only limited by allocated buffer size.
+  const size_t kMaxPayloadSize = helper_->buffer_size();
+  RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
+  size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
+                                                 helper_->payload_size(),
+                                                 helper_->fragmentation());
+
+  // Expect one single packet of payload_size() + 3 bytes header.
+  const size_t kExpectedSizes[1] = {helper_->payload_size() + 3};
+  const int kExpectedPart[1] = {0};  // Packet starts with partition 0.
+  const bool kExpectedFragStart[1] = {true};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
+  ASSERT_EQ(num_packets, kExpectedNum);
+
+  helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
+                                 kExpectedFragStart, kExpectedNum);
+}
+
+// Verify TID field and KeyIdx field in combination.
+TEST_F(RtpPacketizerVp8Test, TestTIDAndKeyIdx) {
+  const size_t kSizeVector[] = {10, 10, 10};
+  const size_t kNumPartitions = GTEST_ARRAY_SIZE_(kSizeVector);
+  ASSERT_TRUE(Init(kSizeVector, kNumPartitions));
+
+  hdr_info_.temporalIdx = 1;
+  hdr_info_.keyIdx = 5;
+  // kMaxPayloadSize is only limited by allocated buffer size.
+  const size_t kMaxPayloadSize = helper_->buffer_size();
+  RtpPacketizerVp8 packetizer(hdr_info_, kMaxPayloadSize, 0);
+  size_t num_packets = packetizer.SetPayloadData(helper_->payload_data(),
+                                                 helper_->payload_size(),
+                                                 helper_->fragmentation());
+
+  // Expect one single packet of payload_size() + 3 bytes header.
+  const size_t kExpectedSizes[1] = {helper_->payload_size() + 3};
+  const int kExpectedPart[1] = {0};  // Packet starts with partition 0.
+  const bool kExpectedFragStart[1] = {true};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedPart);
+  CHECK_ARRAY_SIZE(kExpectedNum, kExpectedFragStart);
+  ASSERT_EQ(num_packets, kExpectedNum);
+
+  helper_->GetAllPacketsAndCheck(&packetizer, kExpectedSizes, kExpectedPart,
+                                 kExpectedFragStart, kExpectedNum);
+}
+
+class RtpDepacketizerVp8Test : public ::testing::Test {
+ protected:
+  RtpDepacketizerVp8Test()
+      : depacketizer_(RtpDepacketizer::Create(kVideoCodecVP8)) {}
+
+  void ExpectPacket(RtpDepacketizer::ParsedPayload* parsed_payload,
+                    const uint8_t* data,
+                    size_t length) {
+    ASSERT_TRUE(parsed_payload != NULL);
+    EXPECT_THAT(std::vector<uint8_t>(
+                    parsed_payload->payload,
+                    parsed_payload->payload + parsed_payload->payload_length),
+                ::testing::ElementsAreArray(data, length));
+  }
+
+  std::unique_ptr<RtpDepacketizer> depacketizer_;
+};
+
+TEST_F(RtpDepacketizerVp8Test, BasicHeader) {
+  const uint8_t kHeaderLength = 1;
+  uint8_t packet[4] = {0};
+  packet[0] = 0x14;  // Binary 0001 0100; S = 1, PartID = 4.
+  packet[1] = 0x01;  // P frame.
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength,
+               sizeof(packet) - kHeaderLength);
+
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 0, 1, 4);
+  VerifyExtensions(&payload.video_header(), kNoPictureId, kNoTl0PicIdx,
+                   kNoTemporalIdx, kNoKeyIdx);
+}
+
+TEST_F(RtpDepacketizerVp8Test, PictureID) {
+  const uint8_t kHeaderLength1 = 3;
+  const uint8_t kHeaderLength2 = 4;
+  const uint8_t kPictureId = 17;
+  uint8_t packet[10] = {0};
+  packet[0] = 0xA0;
+  packet[1] = 0x80;
+  packet[2] = kPictureId;
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength1,
+               sizeof(packet) - kHeaderLength1);
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 1, 0, 0);
+  VerifyExtensions(&payload.video_header(), kPictureId, kNoTl0PicIdx,
+                   kNoTemporalIdx, kNoKeyIdx);
+
+  // Re-use packet, but change to long PictureID.
+  packet[2] = 0x80 | kPictureId;
+  packet[3] = kPictureId;
+
+  payload = RtpDepacketizer::ParsedPayload();
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength2,
+               sizeof(packet) - kHeaderLength2);
+  VerifyBasicHeader(&payload.video_header(), 1, 0, 0);
+  VerifyExtensions(&payload.video_header(), (kPictureId << 8) + kPictureId,
+                   kNoTl0PicIdx, kNoTemporalIdx, kNoKeyIdx);
+}
+
+TEST_F(RtpDepacketizerVp8Test, Tl0PicIdx) {
+  const uint8_t kHeaderLength = 3;
+  const uint8_t kTl0PicIdx = 17;
+  uint8_t packet[13] = {0};
+  packet[0] = 0x90;
+  packet[1] = 0x40;
+  packet[2] = kTl0PicIdx;
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength,
+               sizeof(packet) - kHeaderLength);
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 0, 1, 0);
+  VerifyExtensions(&payload.video_header(), kNoPictureId, kTl0PicIdx,
+                   kNoTemporalIdx, kNoKeyIdx);
+}
+
+TEST_F(RtpDepacketizerVp8Test, TIDAndLayerSync) {
+  const uint8_t kHeaderLength = 3;
+  uint8_t packet[10] = {0};
+  packet[0] = 0x88;
+  packet[1] = 0x20;
+  packet[2] = 0x80;  // TID(2) + LayerSync(false)
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength,
+               sizeof(packet) - kHeaderLength);
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 0, 0, 8);
+  VerifyExtensions(&payload.video_header(), kNoPictureId, kNoTl0PicIdx, 2,
+                   kNoKeyIdx);
+  EXPECT_FALSE(payload.video_header().vp8().layerSync);
+}
+
+TEST_F(RtpDepacketizerVp8Test, KeyIdx) {
+  const uint8_t kHeaderLength = 3;
+  const uint8_t kKeyIdx = 17;
+  uint8_t packet[10] = {0};
+  packet[0] = 0x88;
+  packet[1] = 0x10;  // K = 1.
+  packet[2] = kKeyIdx;
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength,
+               sizeof(packet) - kHeaderLength);
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 0, 0, 8);
+  VerifyExtensions(&payload.video_header(), kNoPictureId, kNoTl0PicIdx,
+                   kNoTemporalIdx, kKeyIdx);
+}
+
+TEST_F(RtpDepacketizerVp8Test, MultipleExtensions) {
+  const uint8_t kHeaderLength = 6;
+  uint8_t packet[10] = {0};
+  packet[0] = 0x88;
+  packet[1] = 0x80 | 0x40 | 0x20 | 0x10;
+  packet[2] = 0x80 | 17;           // PictureID, high 7 bits.
+  packet[3] = 17;                  // PictureID, low 8 bits.
+  packet[4] = 42;                  // Tl0PicIdx.
+  packet[5] = 0x40 | 0x20 | 0x11;  // TID(1) + LayerSync(true) + KEYIDX(17).
+  RtpDepacketizer::ParsedPayload payload;
+
+  ASSERT_TRUE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+  ExpectPacket(&payload, packet + kHeaderLength,
+               sizeof(packet) - kHeaderLength);
+  EXPECT_EQ(kVideoFrameDelta, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 0, 0, 8);
+  VerifyExtensions(&payload.video_header(), (17 << 8) + 17, 42, 1, 17);
+}
+
+TEST_F(RtpDepacketizerVp8Test, TooShortHeader) {
+  uint8_t packet[4] = {0};
+  packet[0] = 0x88;
+  packet[1] = 0x80 | 0x40 | 0x20 | 0x10;  // All extensions are enabled...
+  packet[2] = 0x80 | 17;  // ... but only 2 bytes PictureID is provided.
+  packet[3] = 17;         // PictureID, low 8 bits.
+  RtpDepacketizer::ParsedPayload payload;
+
+  EXPECT_FALSE(depacketizer_->Parse(&payload, packet, sizeof(packet)));
+}
+
+TEST_F(RtpDepacketizerVp8Test, TestWithPacketizer) {
+  const uint8_t kHeaderLength = 5;
+  uint8_t data[10] = {0};
+  RtpPacketToSend packet(kNoExtensions);
+  RTPVideoHeaderVP8 input_header;
+  input_header.nonReference = true;
+  input_header.pictureId = 300;
+  input_header.temporalIdx = 1;
+  input_header.layerSync = false;
+  input_header.tl0PicIdx = kNoTl0PicIdx;  // Disable.
+  input_header.keyIdx = 31;
+  RtpPacketizerVp8 packetizer(input_header, 20, 0);
+  EXPECT_EQ(packetizer.SetPayloadData(data, 10, NULL), 1u);
+  ASSERT_TRUE(packetizer.NextPacket(&packet));
+  EXPECT_TRUE(packet.Marker());
+
+  auto rtp_payload = packet.payload();
+  RtpDepacketizer::ParsedPayload payload;
+  ASSERT_TRUE(
+      depacketizer_->Parse(&payload, rtp_payload.data(), rtp_payload.size()));
+  auto vp8_payload = rtp_payload.subview(kHeaderLength);
+  ExpectPacket(&payload, vp8_payload.data(), vp8_payload.size());
+  EXPECT_EQ(kVideoFrameKey, payload.frame_type);
+  EXPECT_EQ(kVideoCodecVP8, payload.video_header().codec);
+  VerifyBasicHeader(&payload.video_header(), 1, 1, 0);
+  VerifyExtensions(&payload.video_header(), input_header.pictureId,
+                   input_header.tl0PicIdx, input_header.temporalIdx,
+                   input_header.keyIdx);
+  EXPECT_EQ(payload.video_header().vp8().layerSync, input_header.layerSync);
+}
+
+TEST_F(RtpDepacketizerVp8Test, TestEmptyPayload) {
+  // Using a wild pointer to crash on accesses from inside the depacketizer.
+  uint8_t* garbage_ptr = reinterpret_cast<uint8_t*>(0x4711);
+  RtpDepacketizer::ParsedPayload payload;
+  EXPECT_FALSE(depacketizer_->Parse(&payload, garbage_ptr, 0));
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_vp9.cc b/modules/rtp_rtcp/source/rtp_format_vp9.cc
new file mode 100644
index 0000000..8fd1be8
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp9.cc
@@ -0,0 +1,770 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <cmath>
+
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/bitbuffer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+#define RETURN_FALSE_ON_ERROR(x) \
+  if (!(x)) {                    \
+    return false;                \
+  }
+
+namespace webrtc {
+namespace {
+// Length of VP9 payload descriptors' fixed part.
+const size_t kFixedPayloadDescriptorBytes = 1;
+
+const uint32_t kReservedBitValue0 = 0;
+
+uint8_t TemporalIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) {
+  return (hdr.temporal_idx == kNoTemporalIdx) ? def : hdr.temporal_idx;
+}
+
+uint8_t SpatialIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) {
+  return (hdr.spatial_idx == kNoSpatialIdx) ? def : hdr.spatial_idx;
+}
+
+int16_t Tl0PicIdxField(const RTPVideoHeaderVP9& hdr, uint8_t def) {
+  return (hdr.tl0_pic_idx == kNoTl0PicIdx) ? def : hdr.tl0_pic_idx;
+}
+
+// Picture ID:
+//
+//      +-+-+-+-+-+-+-+-+
+// I:   |M| PICTURE ID  |   M:0 => picture id is 7 bits.
+//      +-+-+-+-+-+-+-+-+   M:1 => picture id is 15 bits.
+// M:   | EXTENDED PID  |
+//      +-+-+-+-+-+-+-+-+
+//
+size_t PictureIdLength(const RTPVideoHeaderVP9& hdr) {
+  if (hdr.picture_id == kNoPictureId)
+    return 0;
+  return (hdr.max_picture_id == kMaxOneBytePictureId) ? 1 : 2;
+}
+
+bool PictureIdPresent(const RTPVideoHeaderVP9& hdr) {
+  return PictureIdLength(hdr) > 0;
+}
+
+// Layer indices:
+//
+// Flexible mode (F=1):     Non-flexible mode (F=0):
+//
+//      +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D|   |  T  |U|  S  |D|
+//      +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
+//                          |   TL0PICIDX   |
+//                          +-+-+-+-+-+-+-+-+
+//
+size_t LayerInfoLength(const RTPVideoHeaderVP9& hdr) {
+  if (hdr.temporal_idx == kNoTemporalIdx && hdr.spatial_idx == kNoSpatialIdx) {
+    return 0;
+  }
+  return hdr.flexible_mode ? 1 : 2;
+}
+
+bool LayerInfoPresent(const RTPVideoHeaderVP9& hdr) {
+  return LayerInfoLength(hdr) > 0;
+}
+
+// Reference indices:
+//
+//      +-+-+-+-+-+-+-+-+                P=1,F=1: At least one reference index
+// P,F: | P_DIFF      |N|  up to 3 times          has to be specified.
+//      +-+-+-+-+-+-+-+-+                    N=1: An additional P_DIFF follows
+//                                                current P_DIFF.
+//
+size_t RefIndicesLength(const RTPVideoHeaderVP9& hdr) {
+  if (!hdr.inter_pic_predicted || !hdr.flexible_mode)
+    return 0;
+
+  RTC_DCHECK_GT(hdr.num_ref_pics, 0U);
+  RTC_DCHECK_LE(hdr.num_ref_pics, kMaxVp9RefPics);
+  return hdr.num_ref_pics;
+}
+
+// Scalability structure (SS).
+//
+//      +-+-+-+-+-+-+-+-+
+// V:   | N_S |Y|G|-|-|-|
+//      +-+-+-+-+-+-+-+-+              -|
+// Y:   |     WIDTH     | (OPTIONAL)    .
+//      +               +               .
+//      |               | (OPTIONAL)    .
+//      +-+-+-+-+-+-+-+-+               . N_S + 1 times
+//      |     HEIGHT    | (OPTIONAL)    .
+//      +               +               .
+//      |               | (OPTIONAL)    .
+//      +-+-+-+-+-+-+-+-+              -|
+// G:   |      N_G      | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+                           -|
+// N_G: |  T  |U| R |-|-| (OPTIONAL)                 .
+//      +-+-+-+-+-+-+-+-+              -|            . N_G times
+//      |    P_DIFF     | (OPTIONAL)    . R times    .
+//      +-+-+-+-+-+-+-+-+              -|           -|
+//
+size_t SsDataLength(const RTPVideoHeaderVP9& hdr) {
+  if (!hdr.ss_data_available)
+    return 0;
+
+  RTC_DCHECK_GT(hdr.num_spatial_layers, 0U);
+  RTC_DCHECK_LE(hdr.num_spatial_layers, kMaxVp9NumberOfSpatialLayers);
+  RTC_DCHECK_LE(hdr.gof.num_frames_in_gof, kMaxVp9FramesInGof);
+  size_t length = 1;  // V
+  if (hdr.spatial_layer_resolution_present) {
+    length += 4 * hdr.num_spatial_layers;  // Y
+  }
+  if (hdr.gof.num_frames_in_gof > 0) {
+    ++length;  // G
+  }
+  // N_G
+  length += hdr.gof.num_frames_in_gof;  // T, U, R
+  for (size_t i = 0; i < hdr.gof.num_frames_in_gof; ++i) {
+    RTC_DCHECK_LE(hdr.gof.num_ref_pics[i], kMaxVp9RefPics);
+    length += hdr.gof.num_ref_pics[i];  // R times
+  }
+  return length;
+}
+
+size_t PayloadDescriptorLengthMinusSsData(const RTPVideoHeaderVP9& hdr) {
+  return kFixedPayloadDescriptorBytes + PictureIdLength(hdr) +
+         LayerInfoLength(hdr) + RefIndicesLength(hdr);
+}
+
+size_t PayloadDescriptorLength(const RTPVideoHeaderVP9& hdr) {
+  return PayloadDescriptorLengthMinusSsData(hdr) + SsDataLength(hdr);
+}
+
+void QueuePacket(size_t start_pos,
+                 size_t size,
+                 bool layer_begin,
+                 bool layer_end,
+                 RtpPacketizerVp9::PacketInfoQueue* packets) {
+  RtpPacketizerVp9::PacketInfo packet_info;
+  packet_info.payload_start_pos = start_pos;
+  packet_info.size = size;
+  packet_info.layer_begin = layer_begin;
+  packet_info.layer_end = layer_end;
+  packets->push(packet_info);
+}
+
+// Picture ID:
+//
+//      +-+-+-+-+-+-+-+-+
+// I:   |M| PICTURE ID  |   M:0 => picture id is 7 bits.
+//      +-+-+-+-+-+-+-+-+   M:1 => picture id is 15 bits.
+// M:   | EXTENDED PID  |
+//      +-+-+-+-+-+-+-+-+
+//
+bool WritePictureId(const RTPVideoHeaderVP9& vp9,
+                    rtc::BitBufferWriter* writer) {
+  bool m_bit = (PictureIdLength(vp9) == 2);
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(m_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.picture_id, m_bit ? 15 : 7));
+  return true;
+}
+
+// Layer indices:
+//
+// Flexible mode (F=1):
+//
+//      +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D|
+//      +-+-+-+-+-+-+-+-+
+//
+bool WriteLayerInfoCommon(const RTPVideoHeaderVP9& vp9,
+                          rtc::BitBufferWriter* writer) {
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(TemporalIdxField(vp9, 0), 3));
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.temporal_up_switch ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(SpatialIdxField(vp9, 0), 3));
+  RETURN_FALSE_ON_ERROR(
+      writer->WriteBits(vp9.inter_layer_predicted ? 1 : 0, 1));
+  return true;
+}
+
+// Non-flexible mode (F=0):
+//
+//      +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D|
+//      +-+-+-+-+-+-+-+-+
+//      |   TL0PICIDX   |
+//      +-+-+-+-+-+-+-+-+
+//
+bool WriteLayerInfoNonFlexibleMode(const RTPVideoHeaderVP9& vp9,
+                                   rtc::BitBufferWriter* writer) {
+  RETURN_FALSE_ON_ERROR(writer->WriteUInt8(Tl0PicIdxField(vp9, 0)));
+  return true;
+}
+
+bool WriteLayerInfo(const RTPVideoHeaderVP9& vp9,
+                    rtc::BitBufferWriter* writer) {
+  if (!WriteLayerInfoCommon(vp9, writer))
+    return false;
+
+  if (vp9.flexible_mode)
+    return true;
+
+  return WriteLayerInfoNonFlexibleMode(vp9, writer);
+}
+
+// Reference indices:
+//
+//      +-+-+-+-+-+-+-+-+                P=1,F=1: At least one reference index
+// P,F: | P_DIFF      |N|  up to 3 times          has to be specified.
+//      +-+-+-+-+-+-+-+-+                    N=1: An additional P_DIFF follows
+//                                                current P_DIFF.
+//
+bool WriteRefIndices(const RTPVideoHeaderVP9& vp9,
+                     rtc::BitBufferWriter* writer) {
+  if (!PictureIdPresent(vp9) || vp9.num_ref_pics == 0 ||
+      vp9.num_ref_pics > kMaxVp9RefPics) {
+    return false;
+  }
+  for (uint8_t i = 0; i < vp9.num_ref_pics; ++i) {
+    bool n_bit = !(i == vp9.num_ref_pics - 1);
+    RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.pid_diff[i], 7));
+    RETURN_FALSE_ON_ERROR(writer->WriteBits(n_bit ? 1 : 0, 1));
+  }
+  return true;
+}
+
+// Scalability structure (SS).
+//
+//      +-+-+-+-+-+-+-+-+
+// V:   | N_S |Y|G|-|-|-|
+//      +-+-+-+-+-+-+-+-+              -|
+// Y:   |     WIDTH     | (OPTIONAL)    .
+//      +               +               .
+//      |               | (OPTIONAL)    .
+//      +-+-+-+-+-+-+-+-+               . N_S + 1 times
+//      |     HEIGHT    | (OPTIONAL)    .
+//      +               +               .
+//      |               | (OPTIONAL)    .
+//      +-+-+-+-+-+-+-+-+              -|
+// G:   |      N_G      | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+                           -|
+// N_G: |  T  |U| R |-|-| (OPTIONAL)                 .
+//      +-+-+-+-+-+-+-+-+              -|            . N_G times
+//      |    P_DIFF     | (OPTIONAL)    . R times    .
+//      +-+-+-+-+-+-+-+-+              -|           -|
+//
+bool WriteSsData(const RTPVideoHeaderVP9& vp9, rtc::BitBufferWriter* writer) {
+  RTC_DCHECK_GT(vp9.num_spatial_layers, 0U);
+  RTC_DCHECK_LE(vp9.num_spatial_layers, kMaxVp9NumberOfSpatialLayers);
+  RTC_DCHECK_LE(vp9.gof.num_frames_in_gof, kMaxVp9FramesInGof);
+  bool g_bit = vp9.gof.num_frames_in_gof > 0;
+
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.num_spatial_layers - 1, 3));
+  RETURN_FALSE_ON_ERROR(
+      writer->WriteBits(vp9.spatial_layer_resolution_present ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(g_bit ? 1 : 0, 1));  // G
+  RETURN_FALSE_ON_ERROR(writer->WriteBits(kReservedBitValue0, 3));
+
+  if (vp9.spatial_layer_resolution_present) {
+    for (size_t i = 0; i < vp9.num_spatial_layers; ++i) {
+      RETURN_FALSE_ON_ERROR(writer->WriteUInt16(vp9.width[i]));
+      RETURN_FALSE_ON_ERROR(writer->WriteUInt16(vp9.height[i]));
+    }
+  }
+  if (g_bit) {
+    RETURN_FALSE_ON_ERROR(writer->WriteUInt8(vp9.gof.num_frames_in_gof));
+  }
+  for (size_t i = 0; i < vp9.gof.num_frames_in_gof; ++i) {
+    RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.gof.temporal_idx[i], 3));
+    RETURN_FALSE_ON_ERROR(
+        writer->WriteBits(vp9.gof.temporal_up_switch[i] ? 1 : 0, 1));
+    RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.gof.num_ref_pics[i], 2));
+    RETURN_FALSE_ON_ERROR(writer->WriteBits(kReservedBitValue0, 2));
+    for (uint8_t r = 0; r < vp9.gof.num_ref_pics[i]; ++r) {
+      RETURN_FALSE_ON_ERROR(writer->WriteUInt8(vp9.gof.pid_diff[i][r]));
+    }
+  }
+  return true;
+}
+
+// Picture ID:
+//
+//      +-+-+-+-+-+-+-+-+
+// I:   |M| PICTURE ID  |   M:0 => picture id is 7 bits.
+//      +-+-+-+-+-+-+-+-+   M:1 => picture id is 15 bits.
+// M:   | EXTENDED PID  |
+//      +-+-+-+-+-+-+-+-+
+//
+bool ParsePictureId(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
+  uint32_t picture_id;
+  uint32_t m_bit;
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&m_bit, 1));
+  if (m_bit) {
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&picture_id, 15));
+    vp9->max_picture_id = kMaxTwoBytePictureId;
+  } else {
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&picture_id, 7));
+    vp9->max_picture_id = kMaxOneBytePictureId;
+  }
+  vp9->picture_id = picture_id;
+  return true;
+}
+
+// Layer indices (flexible mode):
+//
+//      +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D|
+//      +-+-+-+-+-+-+-+-+
+//
+bool ParseLayerInfoCommon(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
+  uint32_t t, u_bit, s, d_bit;
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&t, 3));
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&u_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&s, 3));
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&d_bit, 1));
+  vp9->temporal_idx = t;
+  vp9->temporal_up_switch = u_bit ? true : false;
+  vp9->spatial_idx = s;
+  vp9->inter_layer_predicted = d_bit ? true : false;
+  return true;
+}
+
+// Layer indices (non-flexible mode):
+//
+//      +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D|
+//      +-+-+-+-+-+-+-+-+
+//      |   TL0PICIDX   |
+//      +-+-+-+-+-+-+-+-+
+//
+bool ParseLayerInfoNonFlexibleMode(rtc::BitBuffer* parser,
+                                   RTPVideoHeaderVP9* vp9) {
+  uint8_t tl0picidx;
+  RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&tl0picidx));
+  vp9->tl0_pic_idx = tl0picidx;
+  return true;
+}
+
+bool ParseLayerInfo(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
+  if (!ParseLayerInfoCommon(parser, vp9))
+    return false;
+
+  if (vp9->flexible_mode)
+    return true;
+
+  return ParseLayerInfoNonFlexibleMode(parser, vp9);
+}
+
+// Reference indices:
+//
+//      +-+-+-+-+-+-+-+-+                P=1,F=1: At least one reference index
+// P,F: | P_DIFF      |N|  up to 3 times          has to be specified.
+//      +-+-+-+-+-+-+-+-+                    N=1: An additional P_DIFF follows
+//                                                current P_DIFF.
+//
+bool ParseRefIndices(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
+  if (vp9->picture_id == kNoPictureId)
+    return false;
+
+  vp9->num_ref_pics = 0;
+  uint32_t n_bit;
+  do {
+    if (vp9->num_ref_pics == kMaxVp9RefPics)
+      return false;
+
+    uint32_t p_diff;
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&p_diff, 7));
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&n_bit, 1));
+
+    vp9->pid_diff[vp9->num_ref_pics] = p_diff;
+    uint32_t scaled_pid = vp9->picture_id;
+    if (p_diff > scaled_pid) {
+      // TODO(asapersson): Max should correspond to the picture id of last wrap.
+      scaled_pid += vp9->max_picture_id + 1;
+    }
+    vp9->ref_picture_id[vp9->num_ref_pics++] = scaled_pid - p_diff;
+  } while (n_bit);
+
+  return true;
+}
+
+// Scalability structure (SS).
+//
+//      +-+-+-+-+-+-+-+-+
+// V:   | N_S |Y|G|-|-|-|
+//      +-+-+-+-+-+-+-+-+              -|
+// Y:   |     WIDTH     | (OPTIONAL)    .
+//      +               +               .
+//      |               | (OPTIONAL)    .
+//      +-+-+-+-+-+-+-+-+               . N_S + 1 times
+//      |     HEIGHT    | (OPTIONAL)    .
+//      +               +               .
+//      |               | (OPTIONAL)    .
+//      +-+-+-+-+-+-+-+-+              -|
+// G:   |      N_G      | (OPTIONAL)
+//      +-+-+-+-+-+-+-+-+                           -|
+// N_G: |  T  |U| R |-|-| (OPTIONAL)                 .
+//      +-+-+-+-+-+-+-+-+              -|            . N_G times
+//      |    P_DIFF     | (OPTIONAL)    . R times    .
+//      +-+-+-+-+-+-+-+-+              -|           -|
+//
+bool ParseSsData(rtc::BitBuffer* parser, RTPVideoHeaderVP9* vp9) {
+  uint32_t n_s, y_bit, g_bit;
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&n_s, 3));
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&y_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser->ReadBits(&g_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser->ConsumeBits(3));
+  vp9->num_spatial_layers = n_s + 1;
+  vp9->spatial_layer_resolution_present = y_bit ? true : false;
+  vp9->gof.num_frames_in_gof = 0;
+
+  if (y_bit) {
+    for (size_t i = 0; i < vp9->num_spatial_layers; ++i) {
+      RETURN_FALSE_ON_ERROR(parser->ReadUInt16(&vp9->width[i]));
+      RETURN_FALSE_ON_ERROR(parser->ReadUInt16(&vp9->height[i]));
+    }
+  }
+  if (g_bit) {
+    uint8_t n_g;
+    RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&n_g));
+    vp9->gof.num_frames_in_gof = n_g;
+  }
+  for (size_t i = 0; i < vp9->gof.num_frames_in_gof; ++i) {
+    uint32_t t, u_bit, r;
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&t, 3));
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&u_bit, 1));
+    RETURN_FALSE_ON_ERROR(parser->ReadBits(&r, 2));
+    RETURN_FALSE_ON_ERROR(parser->ConsumeBits(2));
+    vp9->gof.temporal_idx[i] = t;
+    vp9->gof.temporal_up_switch[i] = u_bit ? true : false;
+    vp9->gof.num_ref_pics[i] = r;
+
+    for (uint8_t p = 0; p < vp9->gof.num_ref_pics[i]; ++p) {
+      uint8_t p_diff;
+      RETURN_FALSE_ON_ERROR(parser->ReadUInt8(&p_diff));
+      vp9->gof.pid_diff[i][p] = p_diff;
+    }
+  }
+  return true;
+}
+}  // namespace
+
+RtpPacketizerVp9::RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr,
+                                   size_t max_payload_length,
+                                   size_t last_packet_reduction_len)
+    : hdr_(hdr),
+      max_payload_length_(max_payload_length),
+      payload_(nullptr),
+      payload_size_(0),
+      last_packet_reduction_len_(last_packet_reduction_len) {}
+
+RtpPacketizerVp9::~RtpPacketizerVp9() {}
+
+std::string RtpPacketizerVp9::ToString() {
+  return "RtpPacketizerVp9";
+}
+
+size_t RtpPacketizerVp9::SetPayloadData(
+    const uint8_t* payload,
+    size_t payload_size,
+    const RTPFragmentationHeader* fragmentation) {
+  payload_ = payload;
+  payload_size_ = payload_size;
+  GeneratePackets();
+  return packets_.size();
+}
+
+// Splits payload in minimal number of roughly equal in size packets.
+void RtpPacketizerVp9::GeneratePackets() {
+  if (max_payload_length_ < PayloadDescriptorLength(hdr_) + 1) {
+    RTC_LOG(LS_ERROR) << "Payload header and one payload byte won't fit in the "
+                         "first packet.";
+    return;
+  }
+  if (max_payload_length_ < PayloadDescriptorLengthMinusSsData(hdr_) + 1 +
+                                last_packet_reduction_len_) {
+    RTC_LOG(LS_ERROR)
+        << "Payload header and one payload byte won't fit in the last"
+           " packet.";
+    return;
+  }
+  if (payload_size_ == 1 &&
+      max_payload_length_ <
+          PayloadDescriptorLength(hdr_) + 1 + last_packet_reduction_len_) {
+    RTC_LOG(LS_ERROR) << "Can't fit header and payload into single packet, but "
+                         "payload size is one: no way to generate packets with "
+                         "nonzero payload.";
+    return;
+  }
+
+  // Instead of making last packet smaller, we pretend that we must write
+  // additional data into it. We account for this virtual payload while
+  // calculating packets number and sizes. We also pretend that all packets
+  // headers are the same length and extra SS header data in the fits packet
+  // is also treated as a payload here.
+
+  size_t ss_data_len = SsDataLength(hdr_);
+  // Payload, virtual payload and SS hdr data in the first packet together.
+  size_t total_bytes = ss_data_len + payload_size_ + last_packet_reduction_len_;
+  // Now all packets will have the same lenght of vp9 headers.
+  size_t per_packet_capacity =
+      max_payload_length_ - PayloadDescriptorLengthMinusSsData(hdr_);
+  // Integer division rounding up.
+  size_t num_packets =
+      (total_bytes + per_packet_capacity - 1) / per_packet_capacity;
+  // Average rounded down.
+  size_t per_packet_bytes = total_bytes / num_packets;
+  // Several last packets are 1 byte larger than the rest.
+  // i.e. if 14 bytes were split between 4 packets, it would be 3+3+4+4.
+  size_t num_larger_packets = total_bytes % num_packets;
+  size_t bytes_processed = 0;
+  size_t num_packets_left = num_packets;
+  while (bytes_processed < payload_size_) {
+    if (num_packets_left == num_larger_packets)
+      ++per_packet_bytes;
+    size_t packet_bytes = per_packet_bytes;
+    // First packet also has SS hdr data.
+    if (bytes_processed == 0) {
+      // Must write at least one byte of the real payload to the packet.
+      if (packet_bytes > ss_data_len) {
+        packet_bytes -= ss_data_len;
+      } else {
+        packet_bytes = 1;
+      }
+    }
+    size_t rem_bytes = payload_size_ - bytes_processed;
+    if (packet_bytes >= rem_bytes) {
+      // All remaining payload fits into this packet.
+      packet_bytes = rem_bytes;
+      // If this is the penultimate packet, leave at least 1 byte of payload for
+      // the last packet.
+      if (num_packets_left == 2)
+        --packet_bytes;
+    }
+    QueuePacket(bytes_processed, packet_bytes, bytes_processed == 0,
+                rem_bytes == packet_bytes, &packets_);
+    --num_packets_left;
+    bytes_processed += packet_bytes;
+    // Last packet should be smaller
+    RTC_DCHECK(num_packets_left > 0 ||
+               per_packet_capacity >=
+                   packet_bytes + last_packet_reduction_len_);
+  }
+  RTC_CHECK_EQ(bytes_processed, payload_size_);
+}
+
+bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet) {
+  RTC_DCHECK(packet);
+  if (packets_.empty()) {
+    return false;
+  }
+  PacketInfo packet_info = packets_.front();
+  packets_.pop();
+
+  if (!WriteHeaderAndPayload(packet_info, packet, packets_.empty())) {
+    return false;
+  }
+
+  // Ensure end_of_picture is always set on top spatial layer when it is not
+  // dropped.
+  RTC_DCHECK(hdr_.spatial_idx < hdr_.num_spatial_layers - 1 ||
+             hdr_.end_of_picture);
+
+  packet->SetMarker(packets_.empty() && hdr_.end_of_picture);
+  return true;
+}
+
+// VP9 format:
+//
+// Payload descriptor for F = 1 (flexible mode)
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |I|P|L|F|B|E|V|Z| (REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// I:   |M| PICTURE ID  | (RECOMMENDED)
+//      +-+-+-+-+-+-+-+-+
+// M:   | EXTENDED PID  | (RECOMMENDED)
+//      +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D| (CONDITIONALLY RECOMMENDED)
+//      +-+-+-+-+-+-+-+-+                             -|
+// P,F: | P_DIFF      |N| (CONDITIONALLY RECOMMENDED)  . up to 3 times
+//      +-+-+-+-+-+-+-+-+                             -|
+// V:   | SS            |
+//      | ..            |
+//      +-+-+-+-+-+-+-+-+
+//
+// Payload descriptor for F = 0 (non-flexible mode)
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |I|P|L|F|B|E|V|Z| (REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// I:   |M| PICTURE ID  | (RECOMMENDED)
+//      +-+-+-+-+-+-+-+-+
+// M:   | EXTENDED PID  | (RECOMMENDED)
+//      +-+-+-+-+-+-+-+-+
+// L:   |  T  |U|  S  |D| (CONDITIONALLY RECOMMENDED)
+//      +-+-+-+-+-+-+-+-+
+//      |   TL0PICIDX   | (CONDITIONALLY REQUIRED)
+//      +-+-+-+-+-+-+-+-+
+// V:   | SS            |
+//      | ..            |
+//      +-+-+-+-+-+-+-+-+
+
+bool RtpPacketizerVp9::WriteHeaderAndPayload(const PacketInfo& packet_info,
+                                             RtpPacketToSend* packet,
+                                             bool last) const {
+  uint8_t* buffer = packet->AllocatePayload(
+      last ? max_payload_length_ - last_packet_reduction_len_
+           : max_payload_length_);
+  RTC_DCHECK(buffer);
+  size_t header_length;
+  if (!WriteHeader(packet_info, buffer, &header_length))
+    return false;
+
+  // Copy payload data.
+  memcpy(&buffer[header_length], &payload_[packet_info.payload_start_pos],
+         packet_info.size);
+
+  packet->SetPayloadSize(header_length + packet_info.size);
+  return true;
+}
+
+bool RtpPacketizerVp9::WriteHeader(const PacketInfo& packet_info,
+                                   uint8_t* buffer,
+                                   size_t* header_length) const {
+  // Required payload descriptor byte.
+  bool i_bit = PictureIdPresent(hdr_);
+  bool p_bit = hdr_.inter_pic_predicted;
+  bool l_bit = LayerInfoPresent(hdr_);
+  bool f_bit = hdr_.flexible_mode;
+  bool b_bit = packet_info.layer_begin;
+  bool e_bit = packet_info.layer_end;
+  bool v_bit = hdr_.ss_data_available && b_bit;
+  bool z_bit = hdr_.non_ref_for_inter_layer_pred;
+
+  rtc::BitBufferWriter writer(buffer, max_payload_length_);
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(i_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(p_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(l_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(f_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(b_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(e_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(v_bit ? 1 : 0, 1));
+  RETURN_FALSE_ON_ERROR(writer.WriteBits(z_bit ? 1 : 0, 1));
+
+  // Add fields that are present.
+  if (i_bit && !WritePictureId(hdr_, &writer)) {
+    RTC_LOG(LS_ERROR) << "Failed writing VP9 picture id.";
+    return false;
+  }
+  if (l_bit && !WriteLayerInfo(hdr_, &writer)) {
+    RTC_LOG(LS_ERROR) << "Failed writing VP9 layer info.";
+    return false;
+  }
+  if (p_bit && f_bit && !WriteRefIndices(hdr_, &writer)) {
+    RTC_LOG(LS_ERROR) << "Failed writing VP9 ref indices.";
+    return false;
+  }
+  if (v_bit && !WriteSsData(hdr_, &writer)) {
+    RTC_LOG(LS_ERROR) << "Failed writing VP9 SS data.";
+    return false;
+  }
+
+  size_t offset_bytes = 0;
+  size_t offset_bits = 0;
+  writer.GetCurrentOffset(&offset_bytes, &offset_bits);
+  assert(offset_bits == 0);
+
+  *header_length = offset_bytes;
+  return true;
+}
+
+bool RtpDepacketizerVp9::Parse(ParsedPayload* parsed_payload,
+                               const uint8_t* payload,
+                               size_t payload_length) {
+  assert(parsed_payload != nullptr);
+  if (payload_length == 0) {
+    RTC_LOG(LS_ERROR) << "Payload length is zero.";
+    return false;
+  }
+
+  // Parse mandatory first byte of payload descriptor.
+  rtc::BitBuffer parser(payload, payload_length);
+  uint32_t i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit, z_bit;
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&i_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&p_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&l_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&f_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&b_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&e_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&v_bit, 1));
+  RETURN_FALSE_ON_ERROR(parser.ReadBits(&z_bit, 1));
+
+  // Parsed payload.
+  parsed_payload->video_header().width = 0;
+  parsed_payload->video_header().height = 0;
+  parsed_payload->video_header().simulcastIdx = 0;
+  parsed_payload->video_header().codec = kVideoCodecVP9;
+
+  parsed_payload->frame_type = p_bit ? kVideoFrameDelta : kVideoFrameKey;
+
+  RTPVideoHeaderVP9* vp9 = &parsed_payload->video_header().vp9();
+  vp9->InitRTPVideoHeaderVP9();
+  vp9->inter_pic_predicted = p_bit ? true : false;
+  vp9->flexible_mode = f_bit ? true : false;
+  vp9->beginning_of_frame = b_bit ? true : false;
+  vp9->end_of_frame = e_bit ? true : false;
+  vp9->ss_data_available = v_bit ? true : false;
+  vp9->non_ref_for_inter_layer_pred = z_bit ? true : false;
+
+  // Parse fields that are present.
+  if (i_bit && !ParsePictureId(&parser, vp9)) {
+    RTC_LOG(LS_ERROR) << "Failed parsing VP9 picture id.";
+    return false;
+  }
+  if (l_bit && !ParseLayerInfo(&parser, vp9)) {
+    RTC_LOG(LS_ERROR) << "Failed parsing VP9 layer info.";
+    return false;
+  }
+  if (p_bit && f_bit && !ParseRefIndices(&parser, vp9)) {
+    RTC_LOG(LS_ERROR) << "Failed parsing VP9 ref indices.";
+    return false;
+  }
+  if (v_bit) {
+    if (!ParseSsData(&parser, vp9)) {
+      RTC_LOG(LS_ERROR) << "Failed parsing VP9 SS data.";
+      return false;
+    }
+    if (vp9->spatial_layer_resolution_present) {
+      // TODO(asapersson): Add support for spatial layers.
+      parsed_payload->video_header().width = vp9->width[0];
+      parsed_payload->video_header().height = vp9->height[0];
+    }
+  }
+  parsed_payload->video_header().is_first_packet_in_frame =
+      b_bit && (!l_bit || !vp9->inter_layer_predicted);
+
+  uint64_t rem_bits = parser.RemainingBitCount();
+  assert(rem_bits % 8 == 0);
+  parsed_payload->payload_length = rem_bits / 8;
+  if (parsed_payload->payload_length == 0) {
+    RTC_LOG(LS_ERROR) << "Failed parsing VP9 payload data.";
+    return false;
+  }
+  parsed_payload->payload =
+      payload + payload_length - parsed_payload->payload_length;
+
+  return true;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_format_vp9.h b/modules/rtp_rtcp/source/rtp_format_vp9.h
new file mode 100644
index 0000000..9017864
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp9.h
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+//
+// This file contains the declaration of the VP9 packetizer class.
+// A packetizer object is created for each encoded video frame. The
+// constructor is called with the payload data and size.
+//
+// After creating the packetizer, the method NextPacket is called
+// repeatedly to get all packets for the frame. The method returns
+// false as long as there are more packets left to fetch.
+//
+
+#ifndef MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP9_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP9_H_
+
+#include <queue>
+#include <string>
+
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "rtc_base/constructormagic.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class RtpPacketizerVp9 : public RtpPacketizer {
+ public:
+  RtpPacketizerVp9(const RTPVideoHeaderVP9& hdr,
+                   size_t max_payload_length,
+                   size_t last_packet_reduction_len);
+
+  ~RtpPacketizerVp9() override;
+
+  std::string ToString() override;
+
+  // The payload data must be one encoded VP9 layer frame.
+  size_t SetPayloadData(const uint8_t* payload,
+                        size_t payload_size,
+                        const RTPFragmentationHeader* fragmentation) override;
+
+  // Gets the next payload with VP9 payload header.
+  // Write payload and set marker bit of the |packet|.
+  // Returns true on success, false otherwise.
+  bool NextPacket(RtpPacketToSend* packet) override;
+
+  typedef struct {
+    size_t payload_start_pos;
+    size_t size;
+    bool layer_begin;
+    bool layer_end;
+  } PacketInfo;
+  typedef std::queue<PacketInfo> PacketInfoQueue;
+
+ private:
+  // Calculates all packet sizes and loads info to packet queue.
+  void GeneratePackets();
+
+  // Writes the payload descriptor header and copies payload to the |buffer|.
+  // |packet_info| determines which part of the payload to write.
+  // |last| indicates if the packet is the last packet in the frame.
+  // Returns true on success, false otherwise.
+  bool WriteHeaderAndPayload(const PacketInfo& packet_info,
+                             RtpPacketToSend* packet,
+                             bool last) const;
+
+  // Writes payload descriptor header to |buffer|.
+  // Returns true on success, false otherwise.
+  bool WriteHeader(const PacketInfo& packet_info,
+                   uint8_t* buffer,
+                   size_t* header_length) const;
+
+  const RTPVideoHeaderVP9 hdr_;
+  const size_t max_payload_length_;  // The max length in bytes of one packet.
+  const uint8_t* payload_;           // The payload data to be packetized.
+  size_t payload_size_;              // The size in bytes of the payload data.
+  const size_t last_packet_reduction_len_;
+  PacketInfoQueue packets_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(RtpPacketizerVp9);
+};
+
+class RtpDepacketizerVp9 : public RtpDepacketizer {
+ public:
+  ~RtpDepacketizerVp9() override = default;
+
+  bool Parse(ParsedPayload* parsed_payload,
+             const uint8_t* payload,
+             size_t payload_length) override;
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_FORMAT_VP9_H_
diff --git a/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc b/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc
new file mode 100644
index 0000000..b9480ef
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_format_vp9_unittest.cc
@@ -0,0 +1,825 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+namespace {
+void VerifyHeader(const RTPVideoHeaderVP9& expected,
+                  const RTPVideoHeaderVP9& actual) {
+  EXPECT_EQ(expected.inter_layer_predicted, actual.inter_layer_predicted);
+  EXPECT_EQ(expected.inter_pic_predicted, actual.inter_pic_predicted);
+  EXPECT_EQ(expected.flexible_mode, actual.flexible_mode);
+  EXPECT_EQ(expected.beginning_of_frame, actual.beginning_of_frame);
+  EXPECT_EQ(expected.end_of_frame, actual.end_of_frame);
+  EXPECT_EQ(expected.ss_data_available, actual.ss_data_available);
+  EXPECT_EQ(expected.non_ref_for_inter_layer_pred,
+            actual.non_ref_for_inter_layer_pred);
+  EXPECT_EQ(expected.picture_id, actual.picture_id);
+  EXPECT_EQ(expected.max_picture_id, actual.max_picture_id);
+  EXPECT_EQ(expected.temporal_idx, actual.temporal_idx);
+  EXPECT_EQ(expected.spatial_idx, actual.spatial_idx);
+  EXPECT_EQ(expected.gof_idx, actual.gof_idx);
+  EXPECT_EQ(expected.tl0_pic_idx, actual.tl0_pic_idx);
+  EXPECT_EQ(expected.temporal_up_switch, actual.temporal_up_switch);
+
+  EXPECT_EQ(expected.num_ref_pics, actual.num_ref_pics);
+  for (uint8_t i = 0; i < expected.num_ref_pics; ++i) {
+    EXPECT_EQ(expected.pid_diff[i], actual.pid_diff[i]);
+    EXPECT_EQ(expected.ref_picture_id[i], actual.ref_picture_id[i]);
+  }
+  if (expected.ss_data_available) {
+    EXPECT_EQ(expected.spatial_layer_resolution_present,
+              actual.spatial_layer_resolution_present);
+    EXPECT_EQ(expected.num_spatial_layers, actual.num_spatial_layers);
+    if (expected.spatial_layer_resolution_present) {
+      for (size_t i = 0; i < expected.num_spatial_layers; i++) {
+        EXPECT_EQ(expected.width[i], actual.width[i]);
+        EXPECT_EQ(expected.height[i], actual.height[i]);
+      }
+    }
+    EXPECT_EQ(expected.gof.num_frames_in_gof, actual.gof.num_frames_in_gof);
+    for (size_t i = 0; i < expected.gof.num_frames_in_gof; i++) {
+      EXPECT_EQ(expected.gof.temporal_up_switch[i],
+                actual.gof.temporal_up_switch[i]);
+      EXPECT_EQ(expected.gof.temporal_idx[i], actual.gof.temporal_idx[i]);
+      EXPECT_EQ(expected.gof.num_ref_pics[i], actual.gof.num_ref_pics[i]);
+      for (uint8_t j = 0; j < expected.gof.num_ref_pics[i]; j++) {
+        EXPECT_EQ(expected.gof.pid_diff[i][j], actual.gof.pid_diff[i][j]);
+      }
+    }
+  }
+}
+
+void VerifyPayload(const RtpDepacketizer::ParsedPayload& parsed,
+                   const uint8_t* payload,
+                   size_t payload_length) {
+  EXPECT_EQ(payload, parsed.payload);
+  EXPECT_EQ(payload_length, parsed.payload_length);
+  EXPECT_THAT(std::vector<uint8_t>(parsed.payload,
+                                   parsed.payload + parsed.payload_length),
+              ::testing::ElementsAreArray(payload, payload_length));
+}
+
+void ParseAndCheckPacket(const uint8_t* packet,
+                         const RTPVideoHeaderVP9& expected,
+                         size_t expected_hdr_length,
+                         size_t expected_length) {
+  std::unique_ptr<RtpDepacketizer> depacketizer(new RtpDepacketizerVp9());
+  RtpDepacketizer::ParsedPayload parsed;
+  ASSERT_TRUE(depacketizer->Parse(&parsed, packet, expected_length));
+  EXPECT_EQ(kVideoCodecVP9, parsed.video_header().codec);
+  VerifyHeader(expected, parsed.video_header().vp9());
+  const size_t kExpectedPayloadLength = expected_length - expected_hdr_length;
+  VerifyPayload(parsed, packet + expected_hdr_length, kExpectedPayloadLength);
+}
+}  // namespace
+
+// Payload descriptor for flexible mode
+//        0 1 2 3 4 5 6 7
+//        +-+-+-+-+-+-+-+-+
+//        |I|P|L|F|B|E|V|Z| (REQUIRED)
+//        +-+-+-+-+-+-+-+-+
+//   I:   |M| PICTURE ID  | (RECOMMENDED)
+//        +-+-+-+-+-+-+-+-+
+//   M:   | EXTENDED PID  | (RECOMMENDED)
+//        +-+-+-+-+-+-+-+-+
+//   L:   |  T  |U|  S  |D| (CONDITIONALLY RECOMMENDED)
+//        +-+-+-+-+-+-+-+-+                             -|
+//   P,F: | P_DIFF      |N| (CONDITIONALLY RECOMMENDED)  . up to 3 times
+//        +-+-+-+-+-+-+-+-+                             -|
+//   V:   | SS            |
+//        | ..            |
+//        +-+-+-+-+-+-+-+-+
+//
+// Payload descriptor for non-flexible mode
+//        0 1 2 3 4 5 6 7
+//        +-+-+-+-+-+-+-+-+
+//        |I|P|L|F|B|E|V|Z| (REQUIRED)
+//        +-+-+-+-+-+-+-+-+
+//   I:   |M| PICTURE ID  | (RECOMMENDED)
+//        +-+-+-+-+-+-+-+-+
+//   M:   | EXTENDED PID  | (RECOMMENDED)
+//        +-+-+-+-+-+-+-+-+
+//   L:   |  T  |U|  S  |D| (CONDITIONALLY RECOMMENDED)
+//        +-+-+-+-+-+-+-+-+
+//        |   TL0PICIDX   | (CONDITIONALLY REQUIRED)
+//        +-+-+-+-+-+-+-+-+
+//   V:   | SS            |
+//        | ..            |
+//        +-+-+-+-+-+-+-+-+
+
+class RtpPacketizerVp9Test : public ::testing::Test {
+ protected:
+  static constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
+  static constexpr size_t kMaxPacketSize = 1200;
+
+  RtpPacketizerVp9Test() : packet_(kNoExtensions, kMaxPacketSize) {}
+  void SetUp() override { expected_.InitRTPVideoHeaderVP9(); }
+
+  RtpPacketToSend packet_;
+  std::unique_ptr<uint8_t[]> payload_;
+  size_t payload_size_;
+  size_t payload_pos_;
+  RTPVideoHeaderVP9 expected_;
+  std::unique_ptr<RtpPacketizerVp9> packetizer_;
+  size_t num_packets_;
+
+  void Init(size_t payload_size, size_t packet_size) {
+    payload_.reset(new uint8_t[payload_size]);
+    memset(payload_.get(), 7, payload_size);
+    payload_size_ = payload_size;
+    payload_pos_ = 0;
+    packetizer_.reset(new RtpPacketizerVp9(expected_, packet_size,
+                                           /*last_packet_reduction_len=*/0));
+    num_packets_ =
+        packetizer_->SetPayloadData(payload_.get(), payload_size_, nullptr);
+  }
+
+  void CheckPayload(const uint8_t* packet,
+                    size_t start_pos,
+                    size_t end_pos,
+                    bool last) {
+    for (size_t i = start_pos; i < end_pos; ++i) {
+      EXPECT_EQ(packet[i], payload_[payload_pos_++]);
+    }
+    EXPECT_EQ(last, payload_pos_ == payload_size_);
+  }
+
+  void CreateParseAndCheckPackets(const size_t* expected_hdr_sizes,
+                                  const size_t* expected_sizes,
+                                  size_t expected_num_packets) {
+    ASSERT_TRUE(packetizer_.get() != NULL);
+    if (expected_num_packets == 0) {
+      EXPECT_FALSE(packetizer_->NextPacket(&packet_));
+      return;
+    }
+    EXPECT_EQ(expected_num_packets, num_packets_);
+    for (size_t i = 0; i < expected_num_packets; ++i) {
+      EXPECT_TRUE(packetizer_->NextPacket(&packet_));
+      auto rtp_payload = packet_.payload();
+      EXPECT_EQ(expected_sizes[i], rtp_payload.size());
+      RTPVideoHeaderVP9 hdr = expected_;
+      hdr.beginning_of_frame = (i == 0);
+      hdr.end_of_frame = (i + 1) == expected_num_packets;
+      ParseAndCheckPacket(rtp_payload.data(), hdr, expected_hdr_sizes[i],
+                          rtp_payload.size());
+      CheckPayload(rtp_payload.data(), expected_hdr_sizes[i],
+                   rtp_payload.size(), (i + 1) == expected_num_packets);
+      expected_.ss_data_available = false;
+    }
+  }
+};
+
+TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_OnePacket) {
+  const size_t kFrameSize = 25;
+  const size_t kPacketSize = 26;
+  Init(kFrameSize, kPacketSize);
+
+  // One packet:
+  // I:0, P:0, L:0, F:0, B:1, E:1, V:0, Z:0  (1hdr + 25 payload)
+  const size_t kExpectedHdrSizes[] = {1};
+  const size_t kExpectedSizes[] = {26};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_TwoPackets) {
+  const size_t kFrameSize = 27;
+  const size_t kPacketSize = 27;
+  Init(kFrameSize, kPacketSize);
+
+  // Two packets:
+  // I:0, P:0, L:0, F:0, B:1, E:0, V:0, Z:0  (1hdr + 14 payload)
+  // I:0, P:0, L:0, F:0, B:0, E:1, V:0, Z:0  (1hdr + 13 payload)
+  const size_t kExpectedHdrSizes[] = {1, 1};
+  const size_t kExpectedSizes[] = {14, 15};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestTooShortBufferToFitPayload) {
+  const size_t kFrameSize = 1;
+  const size_t kPacketSize = 1;
+  Init(kFrameSize, kPacketSize);  // 1hdr + 1 payload
+
+  const size_t kExpectedNum = 0;
+  CreateParseAndCheckPackets(NULL, NULL, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestOneBytePictureId) {
+  const size_t kFrameSize = 30;
+  const size_t kPacketSize = 12;
+
+  expected_.picture_id = kMaxOneBytePictureId;  // 2 byte payload descriptor
+  expected_.max_picture_id = kMaxOneBytePictureId;
+  Init(kFrameSize, kPacketSize);
+
+  // Three packets:
+  // I:1, P:0, L:0, F:0, B:1, E:0, V:0, Z:0 (2hdr + 10 payload)
+  // I:1, P:0, L:0, F:0, B:0, E:0, V:0, Z:0 (2hdr + 10 payload)
+  // I:1, P:0, L:0, F:0, B:0, E:1, V:0, Z:0 (2hdr + 10 payload)
+  const size_t kExpectedHdrSizes[] = {2, 2, 2};
+  const size_t kExpectedSizes[] = {12, 12, 12};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestTwoBytePictureId) {
+  const size_t kFrameSize = 31;
+  const size_t kPacketSize = 13;
+
+  expected_.picture_id = kMaxTwoBytePictureId;  // 3 byte payload descriptor
+  Init(kFrameSize, kPacketSize);
+
+  // Four packets:
+  // I:1, P:0, L:0, F:0, B:1, E:0, V:0, Z:0 (3hdr + 8 payload)
+  // I:1, P:0, L:0, F:0, B:0, E:0, V:0, Z:0 (3hdr + 8 payload)
+  // I:1, P:0, L:0, F:0, B:0, E:0, V:0, Z:0 (3hdr + 8 payload)
+  // I:1, P:0, L:0, F:0, B:0, E:1, V:0, Z:0 (3hdr + 7 payload)
+  const size_t kExpectedHdrSizes[] = {3, 3, 3, 3};
+  const size_t kExpectedSizes[] = {10, 11, 11, 11};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestLayerInfoWithNonFlexibleMode) {
+  const size_t kFrameSize = 30;
+  const size_t kPacketSize = 25;
+
+  expected_.temporal_idx = 3;
+  expected_.temporal_up_switch = true;  // U
+  expected_.num_spatial_layers = 3;
+  expected_.spatial_idx = 2;
+  expected_.inter_layer_predicted = true;  // D
+  expected_.tl0_pic_idx = 117;
+  Init(kFrameSize, kPacketSize);
+
+  // Two packets:
+  //    | I:0, P:0, L:1, F:0, B:1, E:0, V:0 Z:0 | (3hdr + 15 payload)
+  // L: | T:3, U:1, S:2, D:1 | TL0PICIDX:117 |
+  //    | I:0, P:0, L:1, F:0, B:0, E:1, V:0 Z:0 | (3hdr + 15 payload)
+  // L: | T:3, U:1, S:2, D:1 | TL0PICIDX:117 |
+  const size_t kExpectedHdrSizes[] = {3, 3};
+  const size_t kExpectedSizes[] = {18, 18};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestLayerInfoWithFlexibleMode) {
+  const size_t kFrameSize = 21;
+  const size_t kPacketSize = 23;
+
+  expected_.flexible_mode = true;
+  expected_.temporal_idx = 3;
+  expected_.temporal_up_switch = true;  // U
+  expected_.num_spatial_layers = 3;
+  expected_.spatial_idx = 2;
+  expected_.inter_layer_predicted = false;  // D
+  Init(kFrameSize, kPacketSize);
+
+  // One packet:
+  // I:0, P:0, L:1, F:1, B:1, E:1, V:0 (2hdr + 21 payload)
+  // L:   T:3, U:1, S:2, D:0
+  const size_t kExpectedHdrSizes[] = {2};
+  const size_t kExpectedSizes[] = {23};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestRefIdx) {
+  const size_t kFrameSize = 16;
+  const size_t kPacketSize = 21;
+
+  expected_.inter_pic_predicted = true;  // P
+  expected_.flexible_mode = true;        // F
+  expected_.picture_id = 2;
+  expected_.max_picture_id = kMaxOneBytePictureId;
+
+  expected_.num_ref_pics = 3;
+  expected_.pid_diff[0] = 1;
+  expected_.pid_diff[1] = 3;
+  expected_.pid_diff[2] = 127;
+  expected_.ref_picture_id[0] = 1;    // 2 - 1 = 1
+  expected_.ref_picture_id[1] = 127;  // (kMaxPictureId + 1) + 2 - 3 = 127
+  expected_.ref_picture_id[2] = 3;    // (kMaxPictureId + 1) + 2 - 127 = 3
+  Init(kFrameSize, kPacketSize);
+
+  // Two packets:
+  // I:1, P:1, L:0, F:1, B:1, E:1, V:0, Z:0 (5hdr + 16 payload)
+  // I:   2
+  // P,F: P_DIFF:1,   N:1
+  //      P_DIFF:3,   N:1
+  //      P_DIFF:127, N:0
+  const size_t kExpectedHdrSizes[] = {5};
+  const size_t kExpectedSizes[] = {21};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestRefIdxFailsWithoutPictureId) {
+  const size_t kFrameSize = 16;
+  const size_t kPacketSize = 21;
+
+  expected_.inter_pic_predicted = true;
+  expected_.flexible_mode = true;
+  expected_.num_ref_pics = 1;
+  expected_.pid_diff[0] = 3;
+  Init(kFrameSize, kPacketSize);
+
+  const size_t kExpectedNum = 0;
+  CreateParseAndCheckPackets(NULL, NULL, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestSsDataWithoutSpatialResolutionPresent) {
+  const size_t kFrameSize = 21;
+  const size_t kPacketSize = 26;
+
+  expected_.ss_data_available = true;
+  expected_.num_spatial_layers = 1;
+  expected_.spatial_layer_resolution_present = false;
+  expected_.gof.num_frames_in_gof = 1;
+  expected_.gof.temporal_idx[0] = 0;
+  expected_.gof.temporal_up_switch[0] = true;
+  expected_.gof.num_ref_pics[0] = 1;
+  expected_.gof.pid_diff[0][0] = 4;
+  Init(kFrameSize, kPacketSize);
+
+  // One packet:
+  // I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (5hdr + 21 payload)
+  // N_S:0, Y:0, G:1
+  // N_G:1
+  // T:0, U:1, R:1 | P_DIFF[0][0]:4
+  const size_t kExpectedHdrSizes[] = {5};
+  const size_t kExpectedSizes[] = {26};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestSsDataWithoutGbitPresent) {
+  const size_t kFrameSize = 21;
+  const size_t kPacketSize = 23;
+
+  expected_.ss_data_available = true;
+  expected_.num_spatial_layers = 1;
+  expected_.spatial_layer_resolution_present = false;
+  expected_.gof.num_frames_in_gof = 0;
+  Init(kFrameSize, kPacketSize);
+
+  // One packet:
+  // I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (2hdr + 21 payload)
+  // N_S:0, Y:0, G:0
+  const size_t kExpectedHdrSizes[] = {2};
+  const size_t kExpectedSizes[] = {23};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestSsData) {
+  const size_t kFrameSize = 21;
+  const size_t kPacketSize = 40;
+
+  expected_.ss_data_available = true;
+  expected_.num_spatial_layers = 2;
+  expected_.spatial_layer_resolution_present = true;
+  expected_.width[0] = 640;
+  expected_.width[1] = 1280;
+  expected_.height[0] = 360;
+  expected_.height[1] = 720;
+  expected_.gof.num_frames_in_gof = 3;
+  expected_.gof.temporal_idx[0] = 0;
+  expected_.gof.temporal_idx[1] = 1;
+  expected_.gof.temporal_idx[2] = 2;
+  expected_.gof.temporal_up_switch[0] = true;
+  expected_.gof.temporal_up_switch[1] = true;
+  expected_.gof.temporal_up_switch[2] = false;
+  expected_.gof.num_ref_pics[0] = 0;
+  expected_.gof.num_ref_pics[1] = 3;
+  expected_.gof.num_ref_pics[2] = 2;
+  expected_.gof.pid_diff[1][0] = 5;
+  expected_.gof.pid_diff[1][1] = 6;
+  expected_.gof.pid_diff[1][2] = 7;
+  expected_.gof.pid_diff[2][0] = 8;
+  expected_.gof.pid_diff[2][1] = 9;
+  Init(kFrameSize, kPacketSize);
+
+  // One packet:
+  // I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (19hdr + 21 payload)
+  // N_S:1, Y:1, G:1
+  // WIDTH:640   // 2 bytes
+  // HEIGHT:360  // 2 bytes
+  // WIDTH:1280  // 2 bytes
+  // HEIGHT:720  // 2 bytes
+  // N_G:3
+  // T:0, U:1, R:0
+  // T:1, U:1, R:3 | P_DIFF[1][0]:5 | P_DIFF[1][1]:6 | P_DIFF[1][2]:7
+  // T:2, U:0, R:2 | P_DIFF[2][0]:8 | P_DIFF[2][0]:9
+  const size_t kExpectedHdrSizes[] = {19};
+  const size_t kExpectedSizes[] = {40};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, TestSsDataDoesNotFitInAveragePacket) {
+  const size_t kFrameSize = 24;
+  const size_t kPacketSize = 20;
+
+  expected_.ss_data_available = true;
+  expected_.num_spatial_layers = 2;
+  expected_.spatial_layer_resolution_present = true;
+  expected_.width[0] = 640;
+  expected_.width[1] = 1280;
+  expected_.height[0] = 360;
+  expected_.height[1] = 720;
+  expected_.gof.num_frames_in_gof = 3;
+  expected_.gof.temporal_idx[0] = 0;
+  expected_.gof.temporal_idx[1] = 1;
+  expected_.gof.temporal_idx[2] = 2;
+  expected_.gof.temporal_up_switch[0] = true;
+  expected_.gof.temporal_up_switch[1] = true;
+  expected_.gof.temporal_up_switch[2] = false;
+  expected_.gof.num_ref_pics[0] = 0;
+  expected_.gof.num_ref_pics[1] = 3;
+  expected_.gof.num_ref_pics[2] = 2;
+  expected_.gof.pid_diff[1][0] = 5;
+  expected_.gof.pid_diff[1][1] = 6;
+  expected_.gof.pid_diff[1][2] = 7;
+  expected_.gof.pid_diff[2][0] = 8;
+  expected_.gof.pid_diff[2][1] = 9;
+  Init(kFrameSize, kPacketSize);
+
+  // Three packets:
+  // I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (19hdr + 1 payload)
+  // N_S:1, Y:1, G:1
+  // WIDTH:640   // 2 bytes
+  // HEIGHT:360  // 2 bytes
+  // WIDTH:1280  // 2 bytes
+  // HEIGHT:720  // 2 bytes
+  // N_G:3
+  // T:0, U:1, R:0
+  // T:1, U:1, R:3 | P_DIFF[1][0]:5 | P_DIFF[1][1]:6 | P_DIFF[1][2]:7
+  // T:2, U:0, R:2 | P_DIFF[2][0]:8 | P_DIFF[2][0]:9
+  // Last two packets 1 bytes vp9 hdrs and the rest of payload 14 and 9 bytes.
+  const size_t kExpectedHdrSizes[] = {19, 1, 1};
+  const size_t kExpectedSizes[] = {20, 15, 10};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+TEST_F(RtpPacketizerVp9Test, EndOfPictureSetsSetMarker) {
+  const size_t kFrameSize = 10;
+  const size_t kPacketSize = 8;
+  const size_t kLastPacketReductionLen = 0;
+  const uint8_t kFrame[kFrameSize] = {7};
+  const RTPFragmentationHeader* kNoFragmentation = nullptr;
+
+  RTPVideoHeaderVP9 vp9_header;
+  vp9_header.InitRTPVideoHeaderVP9();
+  vp9_header.flexible_mode = true;
+  vp9_header.num_spatial_layers = 3;
+
+  RtpPacketToSend packet(kNoExtensions);
+
+  // Drop top layer and ensure that marker bit is set on last encoded layer.
+  for (size_t spatial_idx = 0; spatial_idx < vp9_header.num_spatial_layers - 1;
+       ++spatial_idx) {
+    const bool end_of_picture =
+        spatial_idx + 1 == vp9_header.num_spatial_layers - 1;
+    vp9_header.spatial_idx = spatial_idx;
+    vp9_header.end_of_picture = end_of_picture;
+    RtpPacketizerVp9 packetizer(vp9_header, kPacketSize,
+                                kLastPacketReductionLen);
+    packetizer.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
+    ASSERT_TRUE(packetizer.NextPacket(&packet));
+    EXPECT_FALSE(packet.Marker());
+    ASSERT_TRUE(packetizer.NextPacket(&packet));
+    EXPECT_EQ(packet.Marker(), end_of_picture);
+  }
+}
+
+TEST_F(RtpPacketizerVp9Test, TestGeneratesMinimumNumberOfPackets) {
+  const size_t kFrameSize = 10;
+  const size_t kPacketSize = 8;
+  const size_t kLastPacketReductionLen = 0;
+  // Calculated by hand. One packet can contain
+  // |kPacketSize| - |kVp9MinDiscriptorSize| = 6 bytes of the frame payload,
+  // thus to fit 10 bytes two packets are required.
+  const size_t kMinNumberOfPackets = 2;
+  const uint8_t kFrame[kFrameSize] = {7};
+  const RTPFragmentationHeader* kNoFragmentation = nullptr;
+
+  RTPVideoHeaderVP9 vp9_header;
+  vp9_header.InitRTPVideoHeaderVP9();
+
+  RtpPacketToSend packet(kNoExtensions);
+
+  RtpPacketizerVp9 packetizer(vp9_header, kPacketSize, kLastPacketReductionLen);
+  EXPECT_EQ(kMinNumberOfPackets, packetizer.SetPayloadData(
+                                     kFrame, sizeof(kFrame), kNoFragmentation));
+  ASSERT_TRUE(packetizer.NextPacket(&packet));
+  EXPECT_FALSE(packet.Marker());
+  ASSERT_TRUE(packetizer.NextPacket(&packet));
+  EXPECT_TRUE(packet.Marker());
+}
+
+TEST_F(RtpPacketizerVp9Test, TestRespectsLastPacketReductionLen) {
+  const size_t kFrameSize = 10;
+  const size_t kPacketSize = 8;
+  const size_t kLastPacketReductionLen = 5;
+  // Calculated by hand. VP9 payload descriptor is 2 bytes. Like in the test
+  // above, 1 packet is not enough. 2 packets can contain
+  // 2*(|kPacketSize| - |kVp9MinDiscriptorSize|) - |kLastPacketReductionLen| = 7
+  // But three packets are enough, since they have capacity of 3*(8-2)-5=13
+  // bytes.
+  const size_t kMinNumberOfPackets = 3;
+  const uint8_t kFrame[kFrameSize] = {7};
+  const RTPFragmentationHeader* kNoFragmentation = nullptr;
+
+  RTPVideoHeaderVP9 vp9_header;
+  vp9_header.InitRTPVideoHeaderVP9();
+  vp9_header.flexible_mode = true;
+
+  RtpPacketToSend packet(kNoExtensions);
+
+  RtpPacketizerVp9 packetizer0(vp9_header, kPacketSize,
+                               kLastPacketReductionLen);
+  EXPECT_EQ(
+      packetizer0.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation),
+      kMinNumberOfPackets);
+  ASSERT_TRUE(packetizer0.NextPacket(&packet));
+  EXPECT_FALSE(packet.Marker());
+  ASSERT_TRUE(packetizer0.NextPacket(&packet));
+  EXPECT_FALSE(packet.Marker());
+  ASSERT_TRUE(packetizer0.NextPacket(&packet));
+  EXPECT_TRUE(packet.Marker());
+}
+
+TEST_F(RtpPacketizerVp9Test, TestNonRefForInterLayerPred) {
+  const size_t kFrameSize = 25;
+  const size_t kPacketSize = 26;
+
+  expected_.non_ref_for_inter_layer_pred = true;
+  Init(kFrameSize, kPacketSize);
+
+  // I:0, P:0, L:0, F:0, B:1, E:1, V:0, Z:1  (1hdr + 25 payload)
+  const size_t kExpectedHdrSizes[] = {1};
+  const size_t kExpectedSizes[] = {26};
+  const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
+  CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
+}
+
+class RtpDepacketizerVp9Test : public ::testing::Test {
+ protected:
+  RtpDepacketizerVp9Test() : depacketizer_(new RtpDepacketizerVp9()) {}
+
+  void SetUp() override { expected_.InitRTPVideoHeaderVP9(); }
+
+  RTPVideoHeaderVP9 expected_;
+  std::unique_ptr<RtpDepacketizer> depacketizer_;
+};
+
+TEST_F(RtpDepacketizerVp9Test, ParseBasicHeader) {
+  const uint8_t kHeaderLength = 1;
+  uint8_t packet[4] = {0};
+  packet[0] = 0x0C;  // I:0 P:0 L:0 F:0 B:1 E:1 V:0 Z:0
+  expected_.beginning_of_frame = true;
+  expected_.end_of_frame = true;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseOneBytePictureId) {
+  const uint8_t kHeaderLength = 2;
+  uint8_t packet[10] = {0};
+  packet[0] = 0x80;  // I:1 P:0 L:0 F:0 B:0 E:0 V:0 Z:0
+  packet[1] = kMaxOneBytePictureId;
+
+  expected_.picture_id = kMaxOneBytePictureId;
+  expected_.max_picture_id = kMaxOneBytePictureId;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseTwoBytePictureId) {
+  const uint8_t kHeaderLength = 3;
+  uint8_t packet[10] = {0};
+  packet[0] = 0x80;  // I:1 P:0 L:0 F:0 B:0 E:0 V:0 Z:0
+  packet[1] = 0x80 | ((kMaxTwoBytePictureId >> 8) & 0x7F);
+  packet[2] = kMaxTwoBytePictureId & 0xFF;
+
+  expected_.picture_id = kMaxTwoBytePictureId;
+  expected_.max_picture_id = kMaxTwoBytePictureId;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseLayerInfoWithNonFlexibleMode) {
+  const uint8_t kHeaderLength = 3;
+  const uint8_t kTemporalIdx = 2;
+  const uint8_t kUbit = 1;
+  const uint8_t kSpatialIdx = 1;
+  const uint8_t kDbit = 1;
+  const uint8_t kTl0PicIdx = 17;
+  uint8_t packet[13] = {0};
+  packet[0] = 0x20;  // I:0 P:0 L:1 F:0 B:0 E:0 V:0 Z:0
+  packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit;
+  packet[2] = kTl0PicIdx;
+
+  // T:2 U:1 S:1 D:1
+  // TL0PICIDX:17
+  expected_.temporal_idx = kTemporalIdx;
+  expected_.temporal_up_switch = kUbit ? true : false;
+  expected_.spatial_idx = kSpatialIdx;
+  expected_.inter_layer_predicted = kDbit ? true : false;
+  expected_.tl0_pic_idx = kTl0PicIdx;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseLayerInfoWithFlexibleMode) {
+  const uint8_t kHeaderLength = 2;
+  const uint8_t kTemporalIdx = 2;
+  const uint8_t kUbit = 1;
+  const uint8_t kSpatialIdx = 0;
+  const uint8_t kDbit = 0;
+  uint8_t packet[13] = {0};
+  packet[0] = 0x38;  // I:0 P:0 L:1 F:1 B:1 E:0 V:0 Z:0
+  packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit;
+
+  // I:0 P:0 L:1 F:1 B:1 E:0 V:0 Z:0
+  // L:   T:2 U:1 S:0 D:0
+  expected_.beginning_of_frame = true;
+  expected_.flexible_mode = true;
+  expected_.temporal_idx = kTemporalIdx;
+  expected_.temporal_up_switch = kUbit ? true : false;
+  expected_.spatial_idx = kSpatialIdx;
+  expected_.inter_layer_predicted = kDbit ? true : false;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseRefIdx) {
+  const uint8_t kHeaderLength = 6;
+  const int16_t kPictureId = 17;
+  const uint8_t kPdiff1 = 17;
+  const uint8_t kPdiff2 = 18;
+  const uint8_t kPdiff3 = 127;
+  uint8_t packet[13] = {0};
+  packet[0] = 0xD8;  // I:1 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
+  packet[1] = 0x80 | ((kPictureId >> 8) & 0x7F);  // Two byte pictureID.
+  packet[2] = kPictureId;
+  packet[3] = (kPdiff1 << 1) | 1;  // P_DIFF N:1
+  packet[4] = (kPdiff2 << 1) | 1;  // P_DIFF N:1
+  packet[5] = (kPdiff3 << 1) | 0;  // P_DIFF N:0
+
+  // I:1 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
+  // I:    PICTURE ID:17
+  // I:
+  // P,F:  P_DIFF:17  N:1 => refPicId = 17 - 17 = 0
+  // P,F:  P_DIFF:18  N:1 => refPicId = (kMaxPictureId + 1) + 17 - 18 = 0x7FFF
+  // P,F:  P_DIFF:127 N:0 => refPicId = (kMaxPictureId + 1) + 17 - 127 = 32658
+  expected_.beginning_of_frame = true;
+  expected_.inter_pic_predicted = true;
+  expected_.flexible_mode = true;
+  expected_.picture_id = kPictureId;
+  expected_.num_ref_pics = 3;
+  expected_.pid_diff[0] = kPdiff1;
+  expected_.pid_diff[1] = kPdiff2;
+  expected_.pid_diff[2] = kPdiff3;
+  expected_.ref_picture_id[0] = 0;
+  expected_.ref_picture_id[1] = 0x7FFF;
+  expected_.ref_picture_id[2] = 32658;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseRefIdxFailsWithNoPictureId) {
+  const uint8_t kPdiff = 3;
+  uint8_t packet[13] = {0};
+  packet[0] = 0x58;           // I:0 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
+  packet[1] = (kPdiff << 1);  // P,F:  P_DIFF:3 N:0
+
+  RtpDepacketizer::ParsedPayload parsed;
+  EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseRefIdxFailsWithTooManyRefPics) {
+  const uint8_t kPdiff = 3;
+  uint8_t packet[13] = {0};
+  packet[0] = 0xD8;                  // I:1 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
+  packet[1] = kMaxOneBytePictureId;  // I:    PICTURE ID:127
+  packet[2] = (kPdiff << 1) | 1;     // P,F:  P_DIFF:3 N:1
+  packet[3] = (kPdiff << 1) | 1;     // P,F:  P_DIFF:3 N:1
+  packet[4] = (kPdiff << 1) | 1;     // P,F:  P_DIFF:3 N:1
+  packet[5] = (kPdiff << 1) | 0;     // P,F:  P_DIFF:3 N:0
+
+  RtpDepacketizer::ParsedPayload parsed;
+  EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseSsData) {
+  const uint8_t kHeaderLength = 6;
+  const uint8_t kYbit = 0;
+  const size_t kNs = 2;
+  const size_t kNg = 2;
+  uint8_t packet[23] = {0};
+  packet[0] = 0x0A;  // I:0 P:0 L:0 F:0 B:1 E:0 V:1 Z:0
+  packet[1] = ((kNs - 1) << 5) | (kYbit << 4) | (1 << 3);  // N_S Y G:1 -
+  packet[2] = kNg;                                         // N_G
+  packet[3] = (0 << 5) | (1 << 4) | (0 << 2) | 0;          // T:0 U:1 R:0 -
+  packet[4] = (2 << 5) | (0 << 4) | (1 << 2) | 0;          // T:2 U:0 R:1 -
+  packet[5] = 33;
+
+  expected_.beginning_of_frame = true;
+  expected_.ss_data_available = true;
+  expected_.num_spatial_layers = kNs;
+  expected_.spatial_layer_resolution_present = kYbit ? true : false;
+  expected_.gof.num_frames_in_gof = kNg;
+  expected_.gof.temporal_idx[0] = 0;
+  expected_.gof.temporal_idx[1] = 2;
+  expected_.gof.temporal_up_switch[0] = true;
+  expected_.gof.temporal_up_switch[1] = false;
+  expected_.gof.num_ref_pics[0] = 0;
+  expected_.gof.num_ref_pics[1] = 1;
+  expected_.gof.pid_diff[1][0] = 33;
+  ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseFirstPacketInKeyFrame) {
+  uint8_t packet[2] = {0};
+  packet[0] = 0x08;  // I:0 P:0 L:0 F:0 B:1 E:0 V:0 Z:0
+
+  RtpDepacketizer::ParsedPayload parsed;
+  ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
+  EXPECT_EQ(kVideoFrameKey, parsed.frame_type);
+  EXPECT_TRUE(parsed.video_header().is_first_packet_in_frame);
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseLastPacketInDeltaFrame) {
+  uint8_t packet[2] = {0};
+  packet[0] = 0x44;  // I:0 P:1 L:0 F:0 B:0 E:1 V:0 Z:0
+
+  RtpDepacketizer::ParsedPayload parsed;
+  ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
+  EXPECT_EQ(kVideoFrameDelta, parsed.frame_type);
+  EXPECT_FALSE(parsed.video_header().is_first_packet_in_frame);
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseResolution) {
+  const uint16_t kWidth[2] = {640, 1280};
+  const uint16_t kHeight[2] = {360, 720};
+  uint8_t packet[20] = {0};
+  packet[0] = 0x0A;                     // I:0 P:0 L:0 F:0 B:1 E:0 V:1 Z:0
+  packet[1] = (1 << 5) | (1 << 4) | 0;  // N_S:1 Y:1 G:0
+  packet[2] = kWidth[0] >> 8;
+  packet[3] = kWidth[0] & 0xFF;
+  packet[4] = kHeight[0] >> 8;
+  packet[5] = kHeight[0] & 0xFF;
+  packet[6] = kWidth[1] >> 8;
+  packet[7] = kWidth[1] & 0xFF;
+  packet[8] = kHeight[1] >> 8;
+  packet[9] = kHeight[1] & 0xFF;
+
+  RtpDepacketizer::ParsedPayload parsed;
+  ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
+  EXPECT_EQ(kWidth[0], parsed.video_header().width);
+  EXPECT_EQ(kHeight[0], parsed.video_header().height);
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseFailsForNoPayloadLength) {
+  uint8_t packet[1] = {0};
+  RtpDepacketizer::ParsedPayload parsed;
+  EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, 0));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseFailsForTooShortBufferToFitPayload) {
+  const uint8_t kHeaderLength = 1;
+  uint8_t packet[kHeaderLength] = {0};
+  RtpDepacketizer::ParsedPayload parsed;
+  EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
+}
+
+TEST_F(RtpDepacketizerVp9Test, ParseNonRefForInterLayerPred) {
+  uint8_t packet[2] = {0};
+
+  packet[0] = 0x08;  // I:0 P:0 L:0 F:0 B:1 E:0 V:0 Z:0
+  expected_.beginning_of_frame = true;
+  expected_.non_ref_for_inter_layer_pred = false;
+  ParseAndCheckPacket(packet, expected_, 1, sizeof(packet));
+
+  packet[0] = 0x05;  // I:0 P:0 L:0 F:0 B:0 E:1 V:0 Z:1
+  expected_.beginning_of_frame = false;
+  expected_.end_of_frame = true;
+  expected_.non_ref_for_inter_layer_pred = true;
+  ParseAndCheckPacket(packet, expected_, 1, sizeof(packet));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc
new file mode 100644
index 0000000..080cac7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.cc
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+constexpr size_t RtpGenericFrameDescriptor::kMaxNumFrameDependencies;
+
+RtpGenericFrameDescriptor::RtpGenericFrameDescriptor() = default;
+
+int RtpGenericFrameDescriptor::TemporalLayer() const {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  return temporal_layer_;
+}
+
+void RtpGenericFrameDescriptor::SetTemporalLayer(int temporal_layer) {
+  RTC_DCHECK_GE(temporal_layer, 0);
+  RTC_DCHECK_LE(temporal_layer, 7);
+  temporal_layer_ = temporal_layer;
+}
+
+uint8_t RtpGenericFrameDescriptor::SpatialLayersBitmask() const {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  return spatial_layers_;
+}
+
+void RtpGenericFrameDescriptor::SetSpatialLayersBitmask(
+    uint8_t spatial_layers) {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  spatial_layers_ = spatial_layers;
+}
+
+uint16_t RtpGenericFrameDescriptor::FrameId() const {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  return frame_id_;
+}
+
+void RtpGenericFrameDescriptor::SetFrameId(uint16_t frame_id) {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  frame_id_ = frame_id;
+}
+
+rtc::ArrayView<const uint16_t>
+RtpGenericFrameDescriptor::FrameDependenciesDiffs() const {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  return rtc::MakeArrayView(frame_deps_id_diffs_, num_frame_deps_);
+}
+
+bool RtpGenericFrameDescriptor::AddFrameDependencyDiff(uint16_t fdiff) {
+  RTC_DCHECK(FirstPacketInSubFrame());
+  if (num_frame_deps_ == kMaxNumFrameDependencies)
+    return false;
+  if (fdiff == 0)
+    return false;
+  RTC_DCHECK_LT(fdiff, 1 << 14);
+  RTC_DCHECK_GT(fdiff, 0);
+  frame_deps_id_diffs_[num_frame_deps_] = fdiff;
+  num_frame_deps_++;
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h
new file mode 100644
index 0000000..51a9ac0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_GENERIC_FRAME_DESCRIPTOR_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_GENERIC_FRAME_DESCRIPTOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Data to put on the wire for FrameDescriptor rtp header extension.
+class RtpGenericFrameDescriptor {
+ public:
+  RtpGenericFrameDescriptor();
+
+  bool FirstPacketInSubFrame() const { return beginning_of_subframe_; }
+  void SetFirstPacketInSubFrame(bool first) { beginning_of_subframe_ = first; }
+  bool LastPacketInSubFrame() const { return end_of_subframe_; }
+  void SetLastPacketInSubFrame(bool last) { end_of_subframe_ = last; }
+
+  bool FirstSubFrameInFrame() const { return beginning_of_frame_; }
+  void SetFirstSubFrameInFrame(bool first) { beginning_of_frame_ = first; }
+  bool LastSubFrameInFrame() const { return end_of_frame_; }
+  void SetLastSubFrameInFrame(bool last) { end_of_frame_ = last; }
+
+  // Properties below undefined if !FirstPacketInSubFrame()
+  // Valid range for temporal layer: [0, 7]
+  int TemporalLayer() const;
+  void SetTemporalLayer(int temporal_layer);
+
+  // Frame might by used, possible indrectly, for spatial layer sid iff
+  // (bitmask & (1 << sid)) != 0
+  uint8_t SpatialLayersBitmask() const;
+  void SetSpatialLayersBitmask(uint8_t spatial_layers);
+
+  uint16_t FrameId() const;
+  void SetFrameId(uint16_t frame_id);
+
+  rtc::ArrayView<const uint16_t> FrameDependenciesDiffs() const;
+  void ClearFrameDependencies() { num_frame_deps_ = 0; }
+  // Returns false on failure, i.e. number of dependencies is too large.
+  bool AddFrameDependencyDiff(uint16_t fdiff);
+
+ private:
+  static constexpr size_t kMaxNumFrameDependencies = 8;
+
+  bool beginning_of_subframe_ = false;
+  bool end_of_subframe_ = false;
+  bool beginning_of_frame_ = false;
+  bool end_of_frame_ = false;
+
+  uint16_t frame_id_ = 0;
+  uint8_t spatial_layers_ = 1;
+  uint8_t temporal_layer_ = 0;
+  size_t num_frame_deps_ = 0;
+  uint16_t frame_deps_id_diffs_[kMaxNumFrameDependencies];
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_GENERIC_FRAME_DESCRIPTOR_H_
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc
new file mode 100644
index 0000000..c7b52d5
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc
@@ -0,0 +1,145 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+constexpr uint8_t kFlagBeginOfSubframe = 0x80;
+constexpr uint8_t kFlagEndOfSubframe = 0x40;
+constexpr uint8_t kFlagFirstSubframe = 0x20;
+constexpr uint8_t kFlagLastSubframe = 0x10;
+constexpr uint8_t kFlagDependencies = 0x08;
+constexpr uint8_t kMaskTemporalLayer = 0x07;
+
+constexpr uint8_t kFlagMoreDependencies = 0x01;
+constexpr uint8_t kFlageXtendedOffset = 0x02;
+
+}  // namespace
+//       0 1 2 3 4 5 6 7
+//      +-+-+-+-+-+-+-+-+
+//      |B|E|F|L|D|  T  |
+//      +-+-+-+-+-+-+-+-+
+// B:   |       S       |
+//      +-+-+-+-+-+-+-+-+
+//      |               |
+// B:   +      FID      +
+//      |               |
+//      +-+-+-+-+-+-+-+-+
+// D:   |    FDIFF  |X|M|
+//      +---------------+
+// X:   |      ...      |
+//      +-+-+-+-+-+-+-+-+
+// M:   |    FDIFF  |X|M|
+//      +---------------+
+//      |      ...      |
+//      +-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType RtpGenericFrameDescriptorExtension::kId;
+constexpr char RtpGenericFrameDescriptorExtension::kUri[];
+
+bool RtpGenericFrameDescriptorExtension::Parse(
+    rtc::ArrayView<const uint8_t> data,
+    RtpGenericFrameDescriptor* descriptor) {
+  if (data.empty()) {
+    return false;
+  }
+
+  bool begins_subframe = (data[0] & kFlagBeginOfSubframe) != 0;
+  descriptor->SetFirstPacketInSubFrame(begins_subframe);
+  descriptor->SetLastPacketInSubFrame((data[0] & kFlagEndOfSubframe) != 0);
+  descriptor->SetFirstSubFrameInFrame((data[0] & kFlagFirstSubframe) != 0);
+  descriptor->SetLastSubFrameInFrame((data[0] & kFlagLastSubframe) != 0);
+
+  // Parse Subframe details provided in 1st packet of subframe.
+  if (!begins_subframe) {
+    return data.size() == 1;
+  }
+  if (data.size() < 4) {
+    return false;
+  }
+  descriptor->SetTemporalLayer(data[0] & kMaskTemporalLayer);
+  descriptor->SetSpatialLayersBitmask(data[1]);
+  descriptor->SetFrameId(data[2] | (data[3] << 8));
+
+  // Parse dependencies.
+  descriptor->ClearFrameDependencies();
+  size_t offset = 4;
+  bool has_more_dependencies = (data[0] & kFlagDependencies) != 0;
+  while (has_more_dependencies) {
+    if (data.size() == offset)
+      return false;
+    has_more_dependencies = (data[offset] & kFlagMoreDependencies) != 0;
+    bool extended = (data[offset] & kFlageXtendedOffset) != 0;
+    uint16_t fdiff = data[offset] >> 2;
+    offset++;
+    if (extended) {
+      if (data.size() == offset)
+        return false;
+      fdiff |= (data[offset] << 6);
+      offset++;
+    }
+    if (!descriptor->AddFrameDependencyDiff(fdiff))
+      return false;
+  }
+  return data.size() == offset;
+}
+
+size_t RtpGenericFrameDescriptorExtension::ValueSize(
+    const RtpGenericFrameDescriptor& descriptor) {
+  if (!descriptor.FirstPacketInSubFrame())
+    return 1;
+
+  size_t size = 4;
+  for (uint16_t fdiff : descriptor.FrameDependenciesDiffs()) {
+    size += (fdiff >= (1 << 6)) ? 2 : 1;
+  }
+  return size;
+}
+
+bool RtpGenericFrameDescriptorExtension::Write(
+    rtc::ArrayView<uint8_t> data,
+    const RtpGenericFrameDescriptor& descriptor) {
+  RTC_CHECK_EQ(data.size(), ValueSize(descriptor));
+  uint8_t base_header =
+      (descriptor.FirstPacketInSubFrame() ? kFlagBeginOfSubframe : 0) |
+      (descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0) |
+      (descriptor.FirstSubFrameInFrame() ? kFlagFirstSubframe : 0) |
+      (descriptor.LastSubFrameInFrame() ? kFlagLastSubframe : 0);
+  if (!descriptor.FirstPacketInSubFrame()) {
+    data[0] = base_header;
+    return true;
+  }
+  data[0] =
+      base_header |
+      (descriptor.FrameDependenciesDiffs().empty() ? 0 : kFlagDependencies) |
+      descriptor.TemporalLayer();
+  data[1] = descriptor.SpatialLayersBitmask();
+  uint16_t frame_id = descriptor.FrameId();
+  data[2] = frame_id & 0xff;
+  data[3] = frame_id >> 8;
+  rtc::ArrayView<const uint16_t> fdiffs = descriptor.FrameDependenciesDiffs();
+  size_t offset = 4;
+  for (size_t i = 0; i < fdiffs.size(); i++) {
+    bool extended = fdiffs[i] >= (1 << 6);
+    bool more = i < fdiffs.size() - 1;
+    data[offset++] = ((fdiffs[i] & 0x3f) << 2) |
+                     (extended ? kFlageXtendedOffset : 0) |
+                     (more ? kFlagMoreDependencies : 0);
+    if (extended) {
+      data[offset++] = fdiffs[i] >> 6;
+    }
+  }
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h
new file mode 100644
index 0000000..d6acbe5
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_GENERIC_FRAME_DESCRIPTOR_EXTENSION_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_GENERIC_FRAME_DESCRIPTOR_EXTENSION_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "api/array_view.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
+
+namespace webrtc {
+
+class RtpGenericFrameDescriptorExtension {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor;
+  static constexpr char kUri[] =
+      "http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    RtpGenericFrameDescriptor* descriptor);
+  static size_t ValueSize(const RtpGenericFrameDescriptor&);
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    const RtpGenericFrameDescriptor& descriptor);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_GENERIC_FRAME_DESCRIPTOR_EXTENSION_H_
diff --git a/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc
new file mode 100644
index 0000000..bb69e14
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension_unittest.cc
@@ -0,0 +1,283 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+using ::testing::IsEmpty;
+
+// TODO(danilchap): Add fuzzer to test for various invalid inputs.
+
+TEST(RtpGenericFrameDescriptorExtensionTest,
+     ParseFirstPacketOfIndependenSubFrame) {
+  const int kTemporalLayer = 5;
+  constexpr uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+
+  EXPECT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_FALSE(descriptor.LastPacketInSubFrame());
+  EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
+  EXPECT_FALSE(descriptor.LastSubFrameInFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), IsEmpty());
+  EXPECT_EQ(descriptor.TemporalLayer(), kTemporalLayer);
+  EXPECT_EQ(descriptor.SpatialLayersBitmask(), 0x49);
+  EXPECT_EQ(descriptor.FrameId(), 0x3412);
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest,
+     WriteFirstPacketOfIndependenSubFrame) {
+  const int kTemporalLayer = 5;
+  constexpr uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
+  RtpGenericFrameDescriptor descriptor;
+
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.SetTemporalLayer(kTemporalLayer);
+  descriptor.SetSpatialLayersBitmask(0x49);
+  descriptor.SetFrameId(0x3412);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseLastPacketOfSubFrame) {
+  constexpr uint8_t kRaw[] = {0x40};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+
+  EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
+  EXPECT_TRUE(descriptor.LastPacketInSubFrame());
+  EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
+  EXPECT_FALSE(descriptor.LastSubFrameInFrame());
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteLastPacketOfSubFrame) {
+  constexpr uint8_t kRaw[] = {0x40};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetLastPacketInSubFrame(true);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseFirstSubFrameInFrame) {
+  constexpr uint8_t kRaw[] = {0x20};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+
+  EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
+  EXPECT_FALSE(descriptor.LastPacketInSubFrame());
+  EXPECT_TRUE(descriptor.FirstSubFrameInFrame());
+  EXPECT_FALSE(descriptor.LastSubFrameInFrame());
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteFirstSubFrameInFrame) {
+  constexpr uint8_t kRaw[] = {0x20};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstSubFrameInFrame(true);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseLastSubFrameInFrame) {
+  constexpr uint8_t kRaw[] = {0x10};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+
+  EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
+  EXPECT_FALSE(descriptor.LastPacketInSubFrame());
+  EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
+  EXPECT_TRUE(descriptor.LastSubFrameInFrame());
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteLastSubFrameInFrame) {
+  constexpr uint8_t kRaw[] = {0x10};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetLastSubFrameInFrame(true);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseMinShortFrameDependencies) {
+  constexpr uint16_t kDiff = 1;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+  ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteMinShortFrameDependencies) {
+  constexpr uint16_t kDiff = 1;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.AddFrameDependencyDiff(kDiff);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseMaxShortFrameDependencies) {
+  constexpr uint16_t kDiff = 0x3f;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+  ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteMaxShortFrameDependencies) {
+  constexpr uint16_t kDiff = 0x3f;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.AddFrameDependencyDiff(kDiff);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseMinLongFrameDependencies) {
+  constexpr uint16_t kDiff = 0x40;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+  ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteMinLongFrameDependencies) {
+  constexpr uint16_t kDiff = 0x40;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.AddFrameDependencyDiff(kDiff);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest,
+     ParseLongFrameDependenciesAsBigEndian) {
+  constexpr uint16_t kDiff = 0x7654 >> 2;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+  ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest,
+     WriteLongFrameDependenciesAsBigEndian) {
+  constexpr uint16_t kDiff = 0x7654 >> 2;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.AddFrameDependencyDiff(kDiff);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseMaxLongFrameDependencies) {
+  constexpr uint16_t kDiff = 0x3fff;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+  ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteMaxLongFrameDependencies) {
+  constexpr uint16_t kDiff = 0x3fff;
+  constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.AddFrameDependencyDiff(kDiff);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, ParseTwoFrameDependencies) {
+  constexpr uint16_t kDiff1 = 9;
+  constexpr uint16_t kDiff2 = 15;
+  constexpr uint8_t kRaw[] = {
+      0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
+  RtpGenericFrameDescriptor descriptor;
+
+  ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
+  ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
+  EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff1, kDiff2));
+}
+
+TEST(RtpGenericFrameDescriptorExtensionTest, WriteTwoFrameDependencies) {
+  constexpr uint16_t kDiff1 = 9;
+  constexpr uint16_t kDiff2 = 15;
+  constexpr uint8_t kRaw[] = {
+      0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
+  RtpGenericFrameDescriptor descriptor;
+  descriptor.SetFirstPacketInSubFrame(true);
+  descriptor.AddFrameDependencyDiff(kDiff1);
+  descriptor.AddFrameDependencyDiff(kDiff2);
+
+  ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
+            sizeof(kRaw));
+  uint8_t buffer[sizeof(kRaw)];
+  EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
+  EXPECT_THAT(buffer, ElementsAreArray(kRaw));
+}
+
+}  // namespace
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
new file mode 100644
index 0000000..9fa66c0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
@@ -0,0 +1,152 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+
+#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+
+struct ExtensionInfo {
+  RTPExtensionType type;
+  const char* uri;
+};
+
+template <typename Extension>
+constexpr ExtensionInfo CreateExtensionInfo() {
+  return {Extension::kId, Extension::kUri};
+}
+
+constexpr ExtensionInfo kExtensions[] = {
+    CreateExtensionInfo<TransmissionOffset>(),
+    CreateExtensionInfo<AudioLevel>(),
+    CreateExtensionInfo<AbsoluteSendTime>(),
+    CreateExtensionInfo<VideoOrientation>(),
+    CreateExtensionInfo<TransportSequenceNumber>(),
+    CreateExtensionInfo<PlayoutDelayLimits>(),
+    CreateExtensionInfo<VideoContentTypeExtension>(),
+    CreateExtensionInfo<VideoTimingExtension>(),
+    CreateExtensionInfo<RtpStreamId>(),
+    CreateExtensionInfo<RepairedRtpStreamId>(),
+    CreateExtensionInfo<RtpMid>(),
+    CreateExtensionInfo<RtpGenericFrameDescriptorExtension>(),
+};
+
+// Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
+// number of known extensions.
+static_assert(arraysize(kExtensions) ==
+                  static_cast<int>(kRtpExtensionNumberOfExtensions) - 1,
+              "kExtensions expect to list all known extensions");
+
+}  // namespace
+
+constexpr RTPExtensionType RtpHeaderExtensionMap::kInvalidType;
+constexpr int RtpHeaderExtensionMap::kInvalidId;
+constexpr int RtpHeaderExtensionMap::kMinId;
+constexpr int RtpHeaderExtensionMap::kMaxId;
+
+RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
+  for (auto& type : types_)
+    type = kInvalidType;
+  for (auto& id : ids_)
+    id = kInvalidId;
+}
+
+RtpHeaderExtensionMap::RtpHeaderExtensionMap(
+    rtc::ArrayView<const RtpExtension> extensions)
+    : RtpHeaderExtensionMap() {
+  for (const RtpExtension& extension : extensions)
+    RegisterByUri(extension.id, extension.uri);
+}
+
+bool RtpHeaderExtensionMap::RegisterByType(int id, RTPExtensionType type) {
+  for (const ExtensionInfo& extension : kExtensions)
+    if (type == extension.type)
+      return Register(id, extension.type, extension.uri);
+  RTC_NOTREACHED();
+  return false;
+}
+
+bool RtpHeaderExtensionMap::RegisterByUri(int id, const std::string& uri) {
+  for (const ExtensionInfo& extension : kExtensions)
+    if (uri == extension.uri)
+      return Register(id, extension.type, extension.uri);
+  RTC_LOG(LS_WARNING) << "Unknown extension uri:'" << uri << "', id: " << id
+                      << '.';
+  return false;
+}
+
+size_t RtpHeaderExtensionMap::GetTotalLengthInBytes(
+    rtc::ArrayView<const RtpExtensionSize> extensions) const {
+  // Header size of the extension block, see RFC3550 Section 5.3.1
+  static constexpr size_t kRtpOneByteHeaderLength = 4;
+  // Header size of each individual extension, see RFC5285 Section 4.2
+  static constexpr size_t kExtensionHeaderLength = 1;
+  size_t values_size = 0;
+  for (const RtpExtensionSize& extension : extensions) {
+    if (IsRegistered(extension.type))
+      values_size += extension.value_size + kExtensionHeaderLength;
+  }
+  if (values_size == 0)
+    return 0;
+  size_t size = kRtpOneByteHeaderLength + values_size;
+  // Round up to the nearest size that is a multiple of 4.
+  // Which is same as round down (size + 3).
+  return size + 3 - (size + 3) % 4;
+}
+
+int32_t RtpHeaderExtensionMap::Deregister(RTPExtensionType type) {
+  if (IsRegistered(type)) {
+    uint8_t id = GetId(type);
+    types_[id] = kInvalidType;
+    ids_[type] = kInvalidId;
+  }
+  return 0;
+}
+
+bool RtpHeaderExtensionMap::Register(int id,
+                                     RTPExtensionType type,
+                                     const char* uri) {
+  RTC_DCHECK_GT(type, kRtpExtensionNone);
+  RTC_DCHECK_LT(type, kRtpExtensionNumberOfExtensions);
+
+  if (id < kMinId || id > kMaxId) {
+    RTC_LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
+                        << "' with invalid id:" << id << ".";
+    return false;
+  }
+
+  if (GetType(id) == type) {  // Same type/id pair already registered.
+    RTC_LOG(LS_VERBOSE) << "Reregistering extension uri:'" << uri
+                        << "', id:" << id;
+    return true;
+  }
+
+  if (GetType(id) != kInvalidType) {  // |id| used by another extension type.
+    RTC_LOG(LS_WARNING) << "Failed to register extension uri:'" << uri
+                        << "', id:" << id
+                        << ". Id already in use by extension type "
+                        << static_cast<int>(GetType(id));
+    return false;
+  }
+  RTC_DCHECK(!IsRegistered(type));
+
+  types_[id] = type;
+  // There is a run-time check above id fits into uint8_t.
+  ids_[type] = static_cast<uint8_t>(id);
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc b/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc
new file mode 100644
index 0000000..5eb8f1a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_header_extension_map_unittest.cc
@@ -0,0 +1,114 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+
+#include <vector>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "test/gtest.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+TEST(RtpHeaderExtensionTest, RegisterByType) {
+  RtpHeaderExtensionMap map;
+  EXPECT_FALSE(map.IsRegistered(TransmissionOffset::kId));
+
+  EXPECT_TRUE(map.RegisterByType(3, TransmissionOffset::kId));
+
+  EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterByUri) {
+  RtpHeaderExtensionMap map;
+
+  EXPECT_TRUE(map.RegisterByUri(3, TransmissionOffset::kUri));
+
+  EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterWithTrait) {
+  RtpHeaderExtensionMap map;
+
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  EXPECT_TRUE(map.IsRegistered(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterDuringContruction) {
+  const std::vector<RtpExtension> config = {{TransmissionOffset::kUri, 1},
+                                            {AbsoluteSendTime::kUri, 3}};
+  const RtpHeaderExtensionMap map(config);
+
+  EXPECT_EQ(1, map.GetId(TransmissionOffset::kId));
+  EXPECT_EQ(3, map.GetId(AbsoluteSendTime::kId));
+}
+
+TEST(RtpHeaderExtensionTest, RegisterIllegalArg) {
+  RtpHeaderExtensionMap map;
+  // Valid range for id: [1-14].
+  EXPECT_FALSE(map.Register<TransmissionOffset>(0));
+  EXPECT_FALSE(map.Register<TransmissionOffset>(15));
+}
+
+TEST(RtpHeaderExtensionTest, Idempotent) {
+  RtpHeaderExtensionMap map;
+
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  map.Deregister(TransmissionOffset::kId);
+  map.Deregister(TransmissionOffset::kId);
+}
+
+TEST(RtpHeaderExtensionTest, NonUniqueId) {
+  RtpHeaderExtensionMap map;
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  EXPECT_FALSE(map.Register<AudioLevel>(3));
+  EXPECT_TRUE(map.Register<AudioLevel>(4));
+}
+
+TEST(RtpHeaderExtensionTest, GetTotalLength) {
+  RtpHeaderExtensionMap map;
+  constexpr RtpExtensionSize kExtensionSizes[] = {
+      {TransmissionOffset::kId, TransmissionOffset::kValueSizeBytes}};
+  EXPECT_EQ(0u, map.GetTotalLengthInBytes(kExtensionSizes));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+  static constexpr size_t kRtpOneByteHeaderLength = 4;
+  EXPECT_EQ(kRtpOneByteHeaderLength + (TransmissionOffset::kValueSizeBytes + 1),
+            map.GetTotalLengthInBytes(kExtensionSizes));
+}
+
+TEST(RtpHeaderExtensionTest, GetType) {
+  RtpHeaderExtensionMap map;
+  EXPECT_EQ(RtpHeaderExtensionMap::kInvalidType, map.GetType(3));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  EXPECT_EQ(TransmissionOffset::kId, map.GetType(3));
+}
+
+TEST(RtpHeaderExtensionTest, GetId) {
+  RtpHeaderExtensionMap map;
+  EXPECT_EQ(RtpHeaderExtensionMap::kInvalidId,
+            map.GetId(TransmissionOffset::kId));
+  EXPECT_TRUE(map.Register<TransmissionOffset>(3));
+
+  EXPECT_EQ(3, map.GetId(TransmissionOffset::kId));
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc
new file mode 100644
index 0000000..2dba4d7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -0,0 +1,403 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+// Absolute send time in RTP streams.
+//
+// The absolute send time is signaled to the receiver in-band using the
+// general mechanism for RTP header extensions [RFC5285]. The payload
+// of this extension (the transmitted value) is a 24-bit unsigned integer
+// containing the sender's current time in seconds as a fixed point number
+// with 18 bits fractional part.
+//
+// The form of the absolute send time extension block:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=2 |              absolute send time               |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType AbsoluteSendTime::kId;
+constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
+constexpr const char AbsoluteSendTime::kUri[];
+
+bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
+                             uint32_t* time_24bits) {
+  if (data.size() != 3)
+    return false;
+  *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
+  return true;
+}
+
+bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
+                             uint32_t time_24bits) {
+  RTC_DCHECK_EQ(data.size(), 3);
+  RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
+  ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
+  return true;
+}
+
+// An RTP Header Extension for Client-to-Mixer Audio Level Indication
+//
+// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
+//
+// The form of the audio level extension block:
+//
+//    0                   1
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=0 |V|   level     |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+constexpr RTPExtensionType AudioLevel::kId;
+constexpr uint8_t AudioLevel::kValueSizeBytes;
+constexpr const char AudioLevel::kUri[];
+
+bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
+                       bool* voice_activity,
+                       uint8_t* audio_level) {
+  if (data.size() != 1)
+    return false;
+  *voice_activity = (data[0] & 0x80) != 0;
+  *audio_level = data[0] & 0x7F;
+  return true;
+}
+
+bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
+                       bool voice_activity,
+                       uint8_t audio_level) {
+  RTC_DCHECK_EQ(data.size(), 1);
+  RTC_CHECK_LE(audio_level, 0x7f);
+  data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
+  return true;
+}
+
+// From RFC 5450: Transmission Time Offsets in RTP Streams.
+//
+// The transmission time is signaled to the receiver in-band using the
+// general mechanism for RTP header extensions [RFC5285]. The payload
+// of this extension (the transmitted value) is a 24-bit signed integer.
+// When added to the RTP timestamp of the packet, it represents the
+// "effective" RTP transmission time of the packet, on the RTP
+// timescale.
+//
+// The form of the transmission offset extension block:
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=2 |              transmission offset              |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType TransmissionOffset::kId;
+constexpr uint8_t TransmissionOffset::kValueSizeBytes;
+constexpr const char TransmissionOffset::kUri[];
+
+bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
+                               int32_t* rtp_time) {
+  if (data.size() != 3)
+    return false;
+  *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
+  return true;
+}
+
+bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
+  RTC_DCHECK_EQ(data.size(), 3);
+  RTC_DCHECK_LE(rtp_time, 0x00ffffff);
+  ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
+  return true;
+}
+
+//   0                   1                   2
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  ID   | L=1   |transport wide sequence number |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType TransportSequenceNumber::kId;
+constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
+constexpr const char TransportSequenceNumber::kUri[];
+
+bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
+                                    uint16_t* value) {
+  if (data.size() != 2)
+    return false;
+  *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
+  return true;
+}
+
+bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
+                                    uint16_t value) {
+  RTC_DCHECK_EQ(data.size(), 2);
+  ByteWriter<uint16_t>::WriteBigEndian(data.data(), value);
+  return true;
+}
+
+// Coordination of Video Orientation in RTP streams.
+//
+// Coordination of Video Orientation consists in signaling of the current
+// orientation of the image captured on the sender side to the receiver for
+// appropriate rendering and displaying.
+//
+//    0                   1
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=0 |0 0 0 0 C F R R|
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType VideoOrientation::kId;
+constexpr uint8_t VideoOrientation::kValueSizeBytes;
+constexpr const char VideoOrientation::kUri[];
+
+bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
+                             VideoRotation* rotation) {
+  if (data.size() != 1)
+    return false;
+  *rotation = ConvertCVOByteToVideoRotation(data[0]);
+  return true;
+}
+
+bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
+                             VideoRotation rotation) {
+  RTC_DCHECK_EQ(data.size(), 1);
+  data[0] = ConvertVideoRotationToCVOByte(rotation);
+  return true;
+}
+
+bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
+                             uint8_t* value) {
+  if (data.size() != 1)
+    return false;
+  *value = data[0];
+  return true;
+}
+
+bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
+  RTC_DCHECK_EQ(data.size(), 1);
+  data[0] = value;
+  return true;
+}
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  ID   | len=2 |   MIN delay           |   MAX delay           |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType PlayoutDelayLimits::kId;
+constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
+constexpr const char PlayoutDelayLimits::kUri[];
+
+bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
+                               PlayoutDelay* playout_delay) {
+  RTC_DCHECK(playout_delay);
+  if (data.size() != 3)
+    return false;
+  uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
+  uint16_t min_raw = (raw >> 12);
+  uint16_t max_raw = (raw & 0xfff);
+  if (min_raw > max_raw)
+    return false;
+  playout_delay->min_ms = min_raw * kGranularityMs;
+  playout_delay->max_ms = max_raw * kGranularityMs;
+  return true;
+}
+
+bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
+                               const PlayoutDelay& playout_delay) {
+  RTC_DCHECK_EQ(data.size(), 3);
+  RTC_DCHECK_LE(0, playout_delay.min_ms);
+  RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
+  RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
+  // Convert MS to value to be sent on extension header.
+  uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
+  uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
+  ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
+                                          (min_delay << 12) | max_delay);
+  return true;
+}
+
+// Video Content Type.
+//
+// E.g. default video or screenshare.
+//
+//    0                   1
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=0 | Content type  |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+constexpr RTPExtensionType VideoContentTypeExtension::kId;
+constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
+constexpr const char VideoContentTypeExtension::kUri[];
+
+bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
+                                      VideoContentType* content_type) {
+  if (data.size() == 1 &&
+      videocontenttypehelpers::IsValidContentType(data[0])) {
+    *content_type = static_cast<VideoContentType>(data[0]);
+    return true;
+  }
+  return false;
+}
+
+bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
+                                      VideoContentType content_type) {
+  RTC_DCHECK_EQ(data.size(), 1);
+  data[0] = static_cast<uint8_t>(content_type);
+  return true;
+}
+
+// Video Timing.
+// 6 timestamps in milliseconds counted from capture time stored in rtp header:
+// encode start/finish, packetization complete, pacer exit and reserved for
+// modification by the network modification. |flags| is a bitmask and has the
+// following allowed values:
+// 0 = Valid data, but no flags available (backwards compatibility)
+// 1 = Frame marked as timing frame due to cyclic timer.
+// 2 = Frame marked as timing frame due to size being outside limit.
+// 255 = Invalid. The whole timing frame extension should be ignored.
+//
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  ID   | len=12|     flags     |     encode start ms delta       |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |    encode finish ms delta     |   packetizer finish ms delta    |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |     pacer exit ms delta       |   network timestamp ms delta    |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |  network2 timestamp ms delta  |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+constexpr RTPExtensionType VideoTimingExtension::kId;
+constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
+constexpr const char VideoTimingExtension::kUri[];
+
+bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
+                                 VideoSendTiming* timing) {
+  RTC_DCHECK(timing);
+  // TODO(sprang): Deprecate support for old wire format.
+  ptrdiff_t off = 0;
+  switch (data.size()) {
+    case kValueSizeBytes - 1:
+      timing->flags = 0;
+      off = 1;  // Old wire format without the flags field.
+      break;
+    case kValueSizeBytes:
+      timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
+      break;
+    default:
+      return false;
+  }
+
+  timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
+      data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
+  timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
+      data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
+  timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
+      data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
+  timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
+      data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
+  timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
+      data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
+  timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
+      data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
+  return true;
+}
+
+bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
+                                 const VideoSendTiming& timing) {
+  RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
+  ByteWriter<uint8_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
+      timing.encode_start_delta_ms);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
+      timing.encode_finish_delta_ms);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
+      timing.packetization_finish_delta_ms);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kPacerExitDeltaOffset,
+      timing.pacer_exit_delta_ms);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
+      timing.network_timestamp_delta_ms);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
+      timing.network2_timestamp_delta_ms);
+  return true;
+}
+
+bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
+                                 uint16_t time_delta_ms,
+                                 uint8_t offset) {
+  RTC_DCHECK_GE(data.size(), offset + 2);
+  RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
+  ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
+  return true;
+}
+
+bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
+                                   StringRtpHeaderExtension* str) {
+  if (data.empty() || data[0] == 0)  // Valid string extension can't be empty.
+    return false;
+  str->Set(data);
+  RTC_DCHECK(!str->empty());
+  return true;
+}
+
+bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
+                                   const StringRtpHeaderExtension& str) {
+  RTC_DCHECK_EQ(data.size(), str.size());
+  RTC_DCHECK_GE(str.size(), 1);
+  RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
+  memcpy(data.data(), str.data(), str.size());
+  return true;
+}
+
+bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
+                                   std::string* str) {
+  if (data.empty() || data[0] == 0)  // Valid string extension can't be empty.
+    return false;
+  const char* cstr = reinterpret_cast<const char*>(data.data());
+  // If there is a \0 character in the middle of the |data|, treat it as end
+  // of the string. Well-formed string extensions shouldn't contain it.
+  str->assign(cstr, strnlen(cstr, data.size()));
+  RTC_DCHECK(!str->empty());
+  return true;
+}
+
+bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
+                                   const std::string& str) {
+  RTC_DCHECK_EQ(data.size(), str.size());
+  RTC_DCHECK_GE(str.size(), 1);
+  RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
+  memcpy(data.data(), str.data(), str.size());
+  return true;
+}
+
+// Constant declarations for string RTP header extension types.
+
+constexpr RTPExtensionType RtpStreamId::kId;
+constexpr const char RtpStreamId::kUri[];
+
+constexpr RTPExtensionType RepairedRtpStreamId::kId;
+constexpr const char RepairedRtpStreamId::kUri[];
+
+constexpr RTPExtensionType RtpMid::kId;
+constexpr const char RtpMid::kUri[];
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h
new file mode 100644
index 0000000..4e1afc1
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -0,0 +1,198 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "api/array_view.h"
+#include "api/video/video_content_type.h"
+#include "api/video/video_rotation.h"
+#include "api/video/video_timing.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+
+class AbsoluteSendTime {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionAbsoluteSendTime;
+  static constexpr uint8_t kValueSizeBytes = 3;
+  static constexpr const char kUri[] =
+      "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint32_t* time_24bits);
+  static size_t ValueSize(uint32_t time_24bits) { return kValueSizeBytes; }
+  static bool Write(rtc::ArrayView<uint8_t> data, uint32_t time_24bits);
+
+  static constexpr uint32_t MsTo24Bits(int64_t time_ms) {
+    return static_cast<uint32_t>(((time_ms << 18) + 500) / 1000) & 0x00FFFFFF;
+  }
+};
+
+class AudioLevel {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionAudioLevel;
+  static constexpr uint8_t kValueSizeBytes = 1;
+  static constexpr const char kUri[] =
+      "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    bool* voice_activity,
+                    uint8_t* audio_level);
+  static size_t ValueSize(bool voice_activity, uint8_t audio_level) {
+    return kValueSizeBytes;
+  }
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    bool voice_activity,
+                    uint8_t audio_level);
+};
+
+class TransmissionOffset {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionTransmissionTimeOffset;
+  static constexpr uint8_t kValueSizeBytes = 3;
+  static constexpr const char kUri[] = "urn:ietf:params:rtp-hdrext:toffset";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, int32_t* rtp_time);
+  static size_t ValueSize(int32_t rtp_time) { return kValueSizeBytes; }
+  static bool Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time);
+};
+
+class TransportSequenceNumber {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionTransportSequenceNumber;
+  static constexpr uint8_t kValueSizeBytes = 2;
+  static constexpr const char kUri[] =
+      "http://www.ietf.org/id/"
+      "draft-holmer-rmcat-transport-wide-cc-extensions-01";
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint16_t* value);
+  static size_t ValueSize(uint16_t value) { return kValueSizeBytes; }
+  static bool Write(rtc::ArrayView<uint8_t> data, uint16_t value);
+};
+
+class VideoOrientation {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionVideoRotation;
+  static constexpr uint8_t kValueSizeBytes = 1;
+  static constexpr const char kUri[] = "urn:3gpp:video-orientation";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, VideoRotation* value);
+  static size_t ValueSize(VideoRotation) { return kValueSizeBytes; }
+  static bool Write(rtc::ArrayView<uint8_t> data, VideoRotation value);
+  static bool Parse(rtc::ArrayView<const uint8_t> data, uint8_t* value);
+  static size_t ValueSize(uint8_t value) { return kValueSizeBytes; }
+  static bool Write(rtc::ArrayView<uint8_t> data, uint8_t value);
+};
+
+class PlayoutDelayLimits {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionPlayoutDelay;
+  static constexpr uint8_t kValueSizeBytes = 3;
+  static constexpr const char kUri[] =
+      "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
+
+  // Playout delay in milliseconds. A playout delay limit (min or max)
+  // has 12 bits allocated. This allows a range of 0-4095 values which
+  // translates to a range of 0-40950 in milliseconds.
+  static constexpr int kGranularityMs = 10;
+  // Maximum playout delay value in milliseconds.
+  static constexpr int kMaxMs = 0xfff * kGranularityMs;  // 40950.
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    PlayoutDelay* playout_delay);
+  static size_t ValueSize(const PlayoutDelay&) {
+    return kValueSizeBytes;
+  }
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    const PlayoutDelay& playout_delay);
+};
+
+class VideoContentTypeExtension {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionVideoContentType;
+  static constexpr uint8_t kValueSizeBytes = 1;
+  static constexpr const char kUri[] =
+      "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    VideoContentType* content_type);
+  static size_t ValueSize(VideoContentType) {
+    return kValueSizeBytes;
+  }
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    VideoContentType content_type);
+};
+
+class VideoTimingExtension {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionVideoTiming;
+  static constexpr uint8_t kValueSizeBytes = 13;
+  static constexpr const char kUri[] =
+      "http://www.webrtc.org/experiments/rtp-hdrext/video-timing";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    VideoSendTiming* timing);
+  static size_t ValueSize(const VideoSendTiming&) { return kValueSizeBytes; }
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    const VideoSendTiming& timing);
+
+  static size_t ValueSize(uint16_t time_delta_ms, uint8_t idx) {
+    return kValueSizeBytes;
+  }
+  // Writes only single time delta to position idx.
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    uint16_t time_delta_ms,
+                    uint8_t idx);
+};
+
+// Base extension class for RTP header extensions which are strings.
+// Subclasses must defined kId and kUri static constexpr members.
+class BaseRtpStringExtension {
+ public:
+  // String RTP header extensions are limited to 16 bytes because it is the
+  // maximum length that can be encoded with one-byte header extensions.
+  static constexpr uint8_t kMaxValueSizeBytes = 16;
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    StringRtpHeaderExtension* str);
+  static size_t ValueSize(const StringRtpHeaderExtension& str) {
+    return str.size();
+  }
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    const StringRtpHeaderExtension& str);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* str);
+  static size_t ValueSize(const std::string& str) { return str.size(); }
+  static bool Write(rtc::ArrayView<uint8_t> data, const std::string& str);
+};
+
+class RtpStreamId : public BaseRtpStringExtension {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionRtpStreamId;
+  static constexpr const char kUri[] =
+      "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
+};
+
+class RepairedRtpStreamId : public BaseRtpStringExtension {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionRepairedRtpStreamId;
+  static constexpr const char kUri[] =
+      "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
+};
+
+class RtpMid : public BaseRtpStringExtension {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionMid;
+  static constexpr const char kUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid";
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
diff --git a/modules/rtp_rtcp/source/rtp_header_parser.cc b/modules/rtp_rtcp/source/rtp_header_parser.cc
new file mode 100644
index 0000000..df68f74
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_header_parser.cc
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/criticalsection.h"
+
+namespace webrtc {
+
+class RtpHeaderParserImpl : public RtpHeaderParser {
+ public:
+  RtpHeaderParserImpl();
+  ~RtpHeaderParserImpl() override = default;
+
+  bool Parse(const uint8_t* packet,
+             size_t length,
+             RTPHeader* header) const override;
+
+  bool RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id) override;
+
+  bool DeregisterRtpHeaderExtension(RTPExtensionType type) override;
+
+ private:
+  rtc::CriticalSection critical_section_;
+  RtpHeaderExtensionMap rtp_header_extension_map_
+      RTC_GUARDED_BY(critical_section_);
+};
+
+RtpHeaderParser* RtpHeaderParser::Create() {
+  return new RtpHeaderParserImpl;
+}
+
+RtpHeaderParserImpl::RtpHeaderParserImpl() {}
+
+bool RtpHeaderParser::IsRtcp(const uint8_t* packet, size_t length) {
+  RtpUtility::RtpHeaderParser rtp_parser(packet, length);
+  return rtp_parser.RTCP();
+}
+
+bool RtpHeaderParserImpl::Parse(const uint8_t* packet,
+                                size_t length,
+                                RTPHeader* header) const {
+  RtpUtility::RtpHeaderParser rtp_parser(packet, length);
+  memset(header, 0, sizeof(*header));
+
+  RtpHeaderExtensionMap map;
+  {
+    rtc::CritScope cs(&critical_section_);
+    map = rtp_header_extension_map_;
+  }
+
+  const bool valid_rtpheader = rtp_parser.Parse(header, &map);
+  if (!valid_rtpheader) {
+    return false;
+  }
+  return true;
+}
+
+bool RtpHeaderParserImpl::RegisterRtpHeaderExtension(RTPExtensionType type,
+                                                     uint8_t id) {
+  rtc::CritScope cs(&critical_section_);
+  return rtp_header_extension_map_.RegisterByType(id, type);
+}
+
+bool RtpHeaderParserImpl::DeregisterRtpHeaderExtension(RTPExtensionType type) {
+  rtc::CritScope cs(&critical_section_);
+  return rtp_header_extension_map_.Deregister(type) == 0;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc
new file mode 100644
index 0000000..878942b
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet.cc
@@ -0,0 +1,558 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+
+#include <cstring>
+#include <utility>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/random.h"
+
+namespace webrtc {
+namespace {
+constexpr size_t kFixedHeaderSize = 12;
+constexpr uint8_t kRtpVersion = 2;
+constexpr uint16_t kOneByteExtensionId = 0xBEDE;
+constexpr size_t kOneByteHeaderSize = 1;
+constexpr size_t kDefaultPacketSize = 1500;
+}  // namespace
+
+constexpr int RtpPacket::kMaxExtensionHeaders;
+constexpr int RtpPacket::kMinExtensionId;
+constexpr int RtpPacket::kMaxExtensionId;
+
+//  0                   1                   2                   3
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |V=2|P|X|  CC   |M|     PT      |       sequence number         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                           timestamp                           |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |           synchronization source (SSRC) identifier            |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// |            Contributing source (CSRC) identifiers             |
+// |                             ....                              |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// |One-byte eXtensions id = 0xbede|       length in 32bits        |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                          Extensions                           |
+// |                             ....                              |
+// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+// |                           Payload                             |
+// |             ....              :  padding...                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |               padding         | Padding size  |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {}
+
+RtpPacket::RtpPacket(const ExtensionManager* extensions)
+    : RtpPacket(extensions, kDefaultPacketSize) {}
+
+RtpPacket::RtpPacket(const RtpPacket&) = default;
+
+RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
+    : buffer_(capacity) {
+  RTC_DCHECK_GE(capacity, kFixedHeaderSize);
+  Clear();
+  if (extensions) {
+    IdentifyExtensions(*extensions);
+  } else {
+    for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
+      extension_entries_[i].type = ExtensionManager::kInvalidType;
+  }
+}
+
+RtpPacket::~RtpPacket() {}
+
+void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) {
+  for (int i = 0; i < kMaxExtensionHeaders; ++i)
+    extension_entries_[i].type = extensions.GetType(i + 1);
+}
+
+bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) {
+  if (!ParseBuffer(buffer, buffer_size)) {
+    Clear();
+    return false;
+  }
+  buffer_.SetData(buffer, buffer_size);
+  RTC_DCHECK_EQ(size(), buffer_size);
+  return true;
+}
+
+bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) {
+  return Parse(packet.data(), packet.size());
+}
+
+bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) {
+  if (!ParseBuffer(buffer.cdata(), buffer.size())) {
+    Clear();
+    return false;
+  }
+  size_t buffer_size = buffer.size();
+  buffer_ = std::move(buffer);
+  RTC_DCHECK_EQ(size(), buffer_size);
+  return true;
+}
+
+bool RtpPacket::Marker() const {
+  RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
+  return marker_;
+}
+
+uint8_t RtpPacket::PayloadType() const {
+  RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
+  return payload_type_;
+}
+
+uint16_t RtpPacket::SequenceNumber() const {
+  RTC_DCHECK_EQ(sequence_number_,
+                ByteReader<uint16_t>::ReadBigEndian(data() + 2));
+  return sequence_number_;
+}
+
+uint32_t RtpPacket::Timestamp() const {
+  RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
+  return timestamp_;
+}
+
+uint32_t RtpPacket::Ssrc() const {
+  RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
+  return ssrc_;
+}
+
+std::vector<uint32_t> RtpPacket::Csrcs() const {
+  size_t num_csrc = data()[0] & 0x0F;
+  RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
+  std::vector<uint32_t> csrcs(num_csrc);
+  for (size_t i = 0; i < num_csrc; ++i) {
+    csrcs[i] =
+        ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
+  }
+  return csrcs;
+}
+
+size_t RtpPacket::headers_size() const {
+  return payload_offset_;
+}
+
+size_t RtpPacket::payload_size() const {
+  return payload_size_;
+}
+
+size_t RtpPacket::padding_size() const {
+  return padding_size_;
+}
+
+rtc::ArrayView<const uint8_t> RtpPacket::payload() const {
+  return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
+}
+
+rtc::CopyOnWriteBuffer RtpPacket::Buffer() const {
+  return buffer_;
+}
+
+size_t RtpPacket::capacity() const {
+  return buffer_.capacity();
+}
+
+size_t RtpPacket::size() const {
+  size_t ret = payload_offset_ + payload_size_ + padding_size_;
+  RTC_DCHECK_EQ(buffer_.size(), ret);
+  return ret;
+}
+
+const uint8_t* RtpPacket::data() const {
+  return buffer_.cdata();
+}
+
+size_t RtpPacket::FreeCapacity() const {
+  return capacity() - size();
+}
+
+size_t RtpPacket::MaxPayloadSize() const {
+  return capacity() - payload_offset_;
+}
+
+void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) {
+  RTC_DCHECK_GE(capacity(), packet.headers_size());
+
+  marker_ = packet.marker_;
+  payload_type_ = packet.payload_type_;
+  sequence_number_ = packet.sequence_number_;
+  timestamp_ = packet.timestamp_;
+  ssrc_ = packet.ssrc_;
+  payload_offset_ = packet.payload_offset_;
+  for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
+    extension_entries_[i] = packet.extension_entries_[i];
+  }
+  extensions_size_ = packet.extensions_size_;
+  buffer_.SetData(packet.data(), packet.headers_size());
+  // Reset payload and padding.
+  payload_size_ = 0;
+  padding_size_ = 0;
+}
+
+void RtpPacket::SetMarker(bool marker_bit) {
+  marker_ = marker_bit;
+  if (marker_) {
+    WriteAt(1, data()[1] | 0x80);
+  } else {
+    WriteAt(1, data()[1] & 0x7F);
+  }
+}
+
+void RtpPacket::SetPayloadType(uint8_t payload_type) {
+  RTC_DCHECK_LE(payload_type, 0x7Fu);
+  payload_type_ = payload_type;
+  WriteAt(1, (data()[1] & 0x80) | payload_type);
+}
+
+void RtpPacket::SetSequenceNumber(uint16_t seq_no) {
+  sequence_number_ = seq_no;
+  ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
+}
+
+void RtpPacket::SetTimestamp(uint32_t timestamp) {
+  timestamp_ = timestamp;
+  ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
+}
+
+void RtpPacket::SetSsrc(uint32_t ssrc) {
+  ssrc_ = ssrc;
+  ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
+}
+
+void RtpPacket::SetCsrcs(const std::vector<uint32_t>& csrcs) {
+  RTC_DCHECK_EQ(extensions_size_, 0);
+  RTC_DCHECK_EQ(payload_size_, 0);
+  RTC_DCHECK_EQ(padding_size_, 0);
+  RTC_DCHECK_LE(csrcs.size(), 0x0fu);
+  RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
+  payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
+  WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size()));
+  size_t offset = kFixedHeaderSize;
+  for (uint32_t csrc : csrcs) {
+    ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
+    offset += 4;
+  }
+  buffer_.SetSize(payload_offset_);
+}
+
+bool RtpPacket::HasRawExtension(int id) const {
+  if (id == ExtensionManager::kInvalidId)
+    return false;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  return extension_entries_[id - 1].offset != 0;
+}
+
+rtc::ArrayView<const uint8_t> RtpPacket::GetRawExtension(int id) const {
+  if (id == ExtensionManager::kInvalidId)
+    return nullptr;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  const ExtensionInfo& extension = extension_entries_[id - 1];
+  if (extension.offset == 0)
+    return nullptr;
+  return rtc::MakeArrayView(data() + extension.offset, extension.length);
+}
+
+bool RtpPacket::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
+  auto buffer = AllocateRawExtension(id, data.size());
+  if (buffer.empty())
+    return false;
+  RTC_DCHECK_EQ(buffer.size(), data.size());
+  memcpy(buffer.data(), data.data(), data.size());
+  return true;
+}
+
+rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
+  if (id == ExtensionManager::kInvalidId)
+    return nullptr;
+  RTC_DCHECK_GE(id, kMinExtensionId);
+  RTC_DCHECK_LE(id, kMaxExtensionId);
+  RTC_DCHECK_GE(length, 1);
+  RTC_DCHECK_LE(length, 16);
+
+  ExtensionInfo* extension_entry = &extension_entries_[id - 1];
+  if (extension_entry->offset != 0) {
+    // Extension already reserved. Check if same length is used.
+    if (extension_entry->length == length)
+      return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
+
+    RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
+                      << static_cast<int>(extension_entry->type)
+                      << ": expected "
+                      << static_cast<int>(extension_entry->length)
+                      << ". received " << length;
+    return nullptr;
+  }
+  if (payload_size_ > 0) {
+    RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
+                      << " after payload was set.";
+    return nullptr;
+  }
+  if (padding_size_ > 0) {
+    RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
+                      << " after padding was set.";
+    return nullptr;
+  }
+
+  size_t num_csrc = data()[0] & 0x0F;
+  size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
+  size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
+  if (extensions_offset + new_extensions_size > capacity()) {
+    RTC_LOG(LS_ERROR)
+        << "Extension cannot be registered: Not enough space left in buffer.";
+    return nullptr;
+  }
+
+  // All checks passed, write down the extension headers.
+  if (extensions_size_ == 0) {
+    RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
+    WriteAt(0, data()[0] | 0x10);  // Set extension bit.
+    // Profile specific ID always set to OneByteExtensionHeader.
+    ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
+                                         kOneByteExtensionId);
+  }
+
+  uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
+  one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1);
+  WriteAt(extensions_offset + extensions_size_, one_byte_header);
+
+  extension_entry->offset = rtc::dchecked_cast<uint16_t>(
+      extensions_offset + extensions_size_ + kOneByteHeaderSize);
+  extension_entry->length = rtc::dchecked_cast<uint8_t>(length);
+  extensions_size_ = new_extensions_size;
+
+  // Update header length field.
+  uint16_t extensions_words = rtc::dchecked_cast<uint16_t>(
+      (extensions_size_ + 3) / 4);  // Wrap up to 32bit.
+  ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
+                                       extensions_words);
+  // Fill extension padding place with zeroes.
+  size_t extension_padding_size = 4 * extensions_words - extensions_size_;
+  memset(WriteAt(extensions_offset + extensions_size_), 0,
+         extension_padding_size);
+  payload_offset_ = extensions_offset + 4 * extensions_words;
+  buffer_.SetSize(payload_offset_);
+  return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
+}
+
+uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) {
+  // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
+  // reallocation and memcpy. Keeping just header reduces memcpy size.
+  SetPayloadSize(0);
+  return SetPayloadSize(size_bytes);
+}
+
+uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) {
+  RTC_DCHECK_EQ(padding_size_, 0);
+  if (payload_offset_ + size_bytes > capacity()) {
+    RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
+    return nullptr;
+  }
+  payload_size_ = size_bytes;
+  buffer_.SetSize(payload_offset_ + payload_size_);
+  return WriteAt(payload_offset_);
+}
+
+bool RtpPacket::SetPadding(uint8_t size_bytes, Random* random) {
+  RTC_DCHECK(random);
+  if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
+    RTC_LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
+                        << (capacity() - payload_offset_ - payload_size_)
+                        << " bytes left in buffer.";
+    return false;
+  }
+  padding_size_ = size_bytes;
+  buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
+  if (padding_size_ > 0) {
+    size_t padding_offset = payload_offset_ + payload_size_;
+    size_t padding_end = padding_offset + padding_size_;
+    for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
+      WriteAt(offset, random->Rand<uint8_t>());
+    }
+    WriteAt(padding_end - 1, padding_size_);
+    WriteAt(0, data()[0] | 0x20);  // Set padding bit.
+  } else {
+    WriteAt(0, data()[0] & ~0x20);  // Clear padding bit.
+  }
+  return true;
+}
+
+void RtpPacket::Clear() {
+  marker_ = false;
+  payload_type_ = 0;
+  sequence_number_ = 0;
+  timestamp_ = 0;
+  ssrc_ = 0;
+  payload_offset_ = kFixedHeaderSize;
+  payload_size_ = 0;
+  padding_size_ = 0;
+  extensions_size_ = 0;
+  for (ExtensionInfo& location : extension_entries_) {
+    location.offset = 0;
+    location.length = 0;
+  }
+
+  memset(WriteAt(0), 0, kFixedHeaderSize);
+  buffer_.SetSize(kFixedHeaderSize);
+  WriteAt(0, kRtpVersion << 6);
+}
+
+bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
+  if (size < kFixedHeaderSize) {
+    return false;
+  }
+  const uint8_t version = buffer[0] >> 6;
+  if (version != kRtpVersion) {
+    return false;
+  }
+  const bool has_padding = (buffer[0] & 0x20) != 0;
+  const bool has_extension = (buffer[0] & 0x10) != 0;
+  const uint8_t number_of_crcs = buffer[0] & 0x0f;
+  marker_ = (buffer[1] & 0x80) != 0;
+  payload_type_ = buffer[1] & 0x7f;
+
+  sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
+  timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
+  ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
+  if (size < kFixedHeaderSize + number_of_crcs * 4) {
+    return false;
+  }
+  payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
+
+  if (has_padding) {
+    padding_size_ = buffer[size - 1];
+    if (padding_size_ == 0) {
+      RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
+      return false;
+    }
+  } else {
+    padding_size_ = 0;
+  }
+
+  extensions_size_ = 0;
+  for (ExtensionInfo& location : extension_entries_) {
+    location.offset = 0;
+    location.length = 0;
+  }
+  if (has_extension) {
+    /* RTP header extension, RFC 3550.
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      defined by profile       |           length              |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                        header extension                       |
+    |                             ....                              |
+    */
+    size_t extension_offset = payload_offset_ + 4;
+    if (extension_offset > size) {
+      return false;
+    }
+    uint16_t profile =
+        ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
+    size_t extensions_capacity =
+        ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
+    extensions_capacity *= 4;
+    if (extension_offset + extensions_capacity > size) {
+      return false;
+    }
+    if (profile != kOneByteExtensionId) {
+      RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
+    } else {
+      constexpr uint8_t kPaddingId = 0;
+      constexpr uint8_t kReservedId = 15;
+      while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
+        int id = buffer[extension_offset + extensions_size_] >> 4;
+        if (id == kReservedId) {
+          break;
+        } else if (id == kPaddingId) {
+          extensions_size_++;
+          continue;
+        }
+        uint8_t length =
+            1 + (buffer[extension_offset + extensions_size_] & 0xf);
+        if (extensions_size_ + kOneByteHeaderSize + length >
+            extensions_capacity) {
+          RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
+          break;
+        }
+
+        size_t idx = id - 1;
+        if (extension_entries_[idx].length != 0) {
+          RTC_LOG(LS_VERBOSE)
+              << "Duplicate rtp header extension id " << id << ". Overwriting.";
+        }
+
+        size_t offset =
+            extension_offset + extensions_size_ + kOneByteHeaderSize;
+        if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
+          RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
+          break;
+        }
+        extension_entries_[idx].offset = static_cast<uint16_t>(offset);
+        extension_entries_[idx].length = length;
+        extensions_size_ += kOneByteHeaderSize + length;
+      }
+    }
+    payload_offset_ = extension_offset + extensions_capacity;
+  }
+
+  if (payload_offset_ + padding_size_ > size) {
+    return false;
+  }
+  payload_size_ = size - payload_offset_ - padding_size_;
+  return true;
+}
+
+rtc::ArrayView<const uint8_t> RtpPacket::FindExtension(
+    ExtensionType type) const {
+  for (const ExtensionInfo& extension : extension_entries_) {
+    if (extension.type == type) {
+      if (extension.length == 0) {
+        // Extension is registered but not set.
+        return nullptr;
+      }
+      return rtc::MakeArrayView(data() + extension.offset, extension.length);
+    }
+  }
+  return nullptr;
+}
+
+rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
+                                                     size_t length) {
+  for (int i = 0; i < kMaxExtensionHeaders; ++i) {
+    if (extension_entries_[i].type == type) {
+      int extension_id = i + 1;
+      return AllocateRawExtension(extension_id, length);
+    }
+  }
+  // Extension not registered.
+  return nullptr;
+}
+
+uint8_t* RtpPacket::WriteAt(size_t offset) {
+  return buffer_.data() + offset;
+}
+
+void RtpPacket::WriteAt(size_t offset, uint8_t byte) {
+  buffer_.data()[offset] = byte;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet.h b/modules/rtp_rtcp/source/rtp_packet.h
new file mode 100644
index 0000000..2f0ef75
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet.h
@@ -0,0 +1,198 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/copyonwritebuffer.h"
+
+namespace webrtc {
+class RtpHeaderExtensionMap;
+class Random;
+
+class RtpPacket {
+ public:
+  using ExtensionType = RTPExtensionType;
+  using ExtensionManager = RtpHeaderExtensionMap;
+  static constexpr int kMaxExtensionHeaders = 14;
+  static constexpr int kMinExtensionId = 1;
+  static constexpr int kMaxExtensionId = 14;
+
+  // |extensions| required for SetExtension/ReserveExtension functions during
+  // packet creating and used if available in Parse function.
+  // Adding and getting extensions will fail until |extensions| is
+  // provided via constructor or IdentifyExtensions function.
+  RtpPacket();
+  explicit RtpPacket(const ExtensionManager* extensions);
+  RtpPacket(const RtpPacket&);
+  RtpPacket(const ExtensionManager* extensions, size_t capacity);
+  ~RtpPacket();
+
+  RtpPacket& operator=(const RtpPacket&) = default;
+
+  // Parse and copy given buffer into Packet.
+  bool Parse(const uint8_t* buffer, size_t size);
+  bool Parse(rtc::ArrayView<const uint8_t> packet);
+
+  // Parse and move given buffer into Packet.
+  bool Parse(rtc::CopyOnWriteBuffer packet);
+
+  // Maps extensions id to their types.
+  void IdentifyExtensions(const ExtensionManager& extensions);
+
+  // Header.
+  bool Marker() const;
+  uint8_t PayloadType() const;
+  uint16_t SequenceNumber() const;
+  uint32_t Timestamp() const;
+  uint32_t Ssrc() const;
+  std::vector<uint32_t> Csrcs() const;
+
+  size_t headers_size() const;
+
+  // Payload.
+  size_t payload_size() const;
+  size_t padding_size() const;
+  rtc::ArrayView<const uint8_t> payload() const;
+
+  // Buffer.
+  rtc::CopyOnWriteBuffer Buffer() const;
+  size_t capacity() const;
+  size_t size() const;
+  const uint8_t* data() const;
+  size_t FreeCapacity() const;
+  size_t MaxPayloadSize() const;
+
+  // Reset fields and buffer.
+  void Clear();
+
+  // Header setters.
+  void CopyHeaderFrom(const RtpPacket& packet);
+  void SetMarker(bool marker_bit);
+  void SetPayloadType(uint8_t payload_type);
+  void SetSequenceNumber(uint16_t seq_no);
+  void SetTimestamp(uint32_t timestamp);
+  void SetSsrc(uint32_t ssrc);
+
+  // Writes csrc list. Assumes:
+  // a) There is enough room left in buffer.
+  // b) Extension headers, payload or padding data has not already been added.
+  void SetCsrcs(const std::vector<uint32_t>& csrcs);
+
+  // Header extensions.
+  template <typename Extension>
+  bool HasExtension() const;
+
+  template <typename Extension, typename... Values>
+  bool GetExtension(Values...) const;
+
+  template <typename Extension, typename... Values>
+  bool SetExtension(Values...);
+
+  template <typename Extension>
+  bool ReserveExtension();
+
+  // Following 4 helpers identify rtp header extension by |id| negotiated with
+  // remote peer and written in an rtp packet.
+  bool HasRawExtension(int id) const;
+
+  // Returns place where extension with |id| is stored.
+  // Returns empty arrayview if extension is not present.
+  rtc::ArrayView<const uint8_t> GetRawExtension(int id) const;
+
+  // Allocates and store header extension. Returns true on success.
+  bool SetRawExtension(int id, rtc::ArrayView<const uint8_t> data);
+
+  // Allocates and returns place to store rtp header extension.
+  // Returns empty arrayview on failure.
+  rtc::ArrayView<uint8_t> AllocateRawExtension(int id, size_t length);
+
+  // Reserve size_bytes for payload. Returns nullptr on failure.
+  uint8_t* SetPayloadSize(size_t size_bytes);
+  // Same as SetPayloadSize but doesn't guarantee to keep current payload.
+  uint8_t* AllocatePayload(size_t size_bytes);
+  bool SetPadding(uint8_t size_bytes, Random* random);
+
+ private:
+  struct ExtensionInfo {
+    ExtensionType type;
+    uint16_t offset;
+    uint8_t length;
+  };
+
+  // Helper function for Parse. Fill header fields using data in given buffer,
+  // but does not touch packet own buffer, leaving packet in invalid state.
+  bool ParseBuffer(const uint8_t* buffer, size_t size);
+
+  // Find an extension |type|.
+  // Returns view of the raw extension or empty view on failure.
+  rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const;
+
+  // Find or allocate an extension |type|. Returns view of size |length|
+  // to write raw extension to or an empty view on failure.
+  rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
+
+  uint8_t* WriteAt(size_t offset);
+  void WriteAt(size_t offset, uint8_t byte);
+
+  // Header.
+  bool marker_;
+  uint8_t payload_type_;
+  uint8_t padding_size_;
+  uint16_t sequence_number_;
+  uint32_t timestamp_;
+  uint32_t ssrc_;
+  size_t payload_offset_;  // Match header size with csrcs and extensions.
+  size_t payload_size_;
+
+  ExtensionInfo extension_entries_[kMaxExtensionHeaders];
+  size_t extensions_size_ = 0;  // Unaligned.
+  rtc::CopyOnWriteBuffer buffer_;
+};
+
+template <typename Extension>
+bool RtpPacket::HasExtension() const {
+  return !FindExtension(Extension::kId).empty();
+}
+
+template <typename Extension, typename... Values>
+bool RtpPacket::GetExtension(Values... values) const {
+  auto raw = FindExtension(Extension::kId);
+  if (raw.empty())
+    return false;
+  return Extension::Parse(raw, values...);
+}
+
+template <typename Extension, typename... Values>
+bool RtpPacket::SetExtension(Values... values) {
+  const size_t value_size = Extension::ValueSize(values...);
+  if (value_size == 0 || value_size > 16)
+    return false;
+  auto buffer = AllocateExtension(Extension::kId, value_size);
+  if (buffer.empty())
+    return false;
+  return Extension::Write(buffer, values...);
+}
+
+template <typename Extension>
+bool RtpPacket::ReserveExtension() {
+  auto buffer = AllocateExtension(Extension::kId, Extension::kValueSizeBytes);
+  if (buffer.empty())
+    return false;
+  memset(buffer.data(), 0, Extension::kValueSizeBytes);
+  return true;
+}
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_H_
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.cc b/modules/rtp_rtcp/source/rtp_packet_history.cc
new file mode 100644
index 0000000..62f1c82
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_history.cc
@@ -0,0 +1,290 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_packet_history.h"
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+namespace {
+// Min packet size for BestFittingPacket() to honor.
+constexpr size_t kMinPacketRequestBytes = 50;
+
+// Utility function to get the absolute difference in size between the provided
+// target size and the size of packet.
+size_t SizeDiff(const std::unique_ptr<RtpPacketToSend>& packet, size_t size) {
+  size_t packet_size = packet->size();
+  if (packet_size > size) {
+    return packet_size - size;
+  }
+  return size - packet_size;
+}
+}  // namespace
+
+constexpr size_t RtpPacketHistory::kMaxCapacity;
+constexpr int64_t RtpPacketHistory::kMinPacketDurationMs;
+constexpr int RtpPacketHistory::kMinPacketDurationRtt;
+constexpr int RtpPacketHistory::kPacketCullingDelayFactor;
+
+RtpPacketHistory::PacketState::PacketState() = default;
+RtpPacketHistory::PacketState::PacketState(const PacketState&) = default;
+RtpPacketHistory::PacketState::~PacketState() = default;
+
+RtpPacketHistory::StoredPacket::StoredPacket() = default;
+RtpPacketHistory::StoredPacket::StoredPacket(StoredPacket&&) = default;
+RtpPacketHistory::StoredPacket& RtpPacketHistory::StoredPacket::operator=(
+    RtpPacketHistory::StoredPacket&&) = default;
+RtpPacketHistory::StoredPacket::~StoredPacket() = default;
+
+RtpPacketHistory::RtpPacketHistory(Clock* clock)
+    : clock_(clock),
+      number_to_store_(0),
+      mode_(StorageMode::kDisabled),
+      rtt_ms_(-1) {}
+
+RtpPacketHistory::~RtpPacketHistory() {}
+
+void RtpPacketHistory::SetStorePacketsStatus(StorageMode mode,
+                                             size_t number_to_store) {
+  RTC_DCHECK_LE(number_to_store, kMaxCapacity);
+  rtc::CritScope cs(&lock_);
+  if (mode != StorageMode::kDisabled && mode_ != StorageMode::kDisabled) {
+    RTC_LOG(LS_WARNING) << "Purging packet history in order to re-set status.";
+  }
+  Reset();
+  mode_ = mode;
+  number_to_store_ = std::min(kMaxCapacity, number_to_store);
+}
+
+RtpPacketHistory::StorageMode RtpPacketHistory::GetStorageMode() const {
+  rtc::CritScope cs(&lock_);
+  return mode_;
+}
+
+void RtpPacketHistory::SetRtt(int64_t rtt_ms) {
+  rtc::CritScope cs(&lock_);
+  RTC_DCHECK_GE(rtt_ms, 0);
+  rtt_ms_ = rtt_ms;
+}
+
+void RtpPacketHistory::PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet,
+                                    StorageType type,
+                                    absl::optional<int64_t> send_time_ms) {
+  RTC_DCHECK(packet);
+  rtc::CritScope cs(&lock_);
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  if (mode_ == StorageMode::kDisabled) {
+    return;
+  }
+
+  CullOldPackets(now_ms);
+
+  // Store packet.
+  const uint16_t rtp_seq_no = packet->SequenceNumber();
+  StoredPacket& stored_packet = packet_history_[rtp_seq_no];
+  RTC_DCHECK(stored_packet.packet == nullptr);
+  stored_packet.packet = std::move(packet);
+
+  if (stored_packet.packet->capture_time_ms() <= 0) {
+    stored_packet.packet->set_capture_time_ms(now_ms);
+  }
+  stored_packet.send_time_ms = send_time_ms;
+  stored_packet.storage_type = type;
+  stored_packet.times_retransmitted = 0;
+
+  if (!start_seqno_) {
+    start_seqno_ = rtp_seq_no;
+  }
+}
+
+std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndSetSendTime(
+    uint16_t sequence_number,
+    bool verify_rtt) {
+  rtc::CritScope cs(&lock_);
+  if (mode_ == StorageMode::kDisabled) {
+    return nullptr;
+  }
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  StoredPacketIterator rtp_it = packet_history_.find(sequence_number);
+  if (rtp_it == packet_history_.end()) {
+    return nullptr;
+  }
+
+  StoredPacket& packet = rtp_it->second;
+  if (verify_rtt && !VerifyRtt(rtp_it->second, now_ms)) {
+    return nullptr;
+  }
+
+  if (packet.send_time_ms) {
+    ++packet.times_retransmitted;
+  }
+
+  // Update send-time and return copy of packet instance.
+  packet.send_time_ms = now_ms;
+
+  if (packet.storage_type == StorageType::kDontRetransmit) {
+    // Non retransmittable packet, so call must come from paced sender.
+    // Remove from history and return actual packet instance.
+    return RemovePacket(rtp_it);
+  }
+  return absl::make_unique<RtpPacketToSend>(*packet.packet);
+}
+
+absl::optional<RtpPacketHistory::PacketState> RtpPacketHistory::GetPacketState(
+    uint16_t sequence_number,
+    bool verify_rtt) const {
+  rtc::CritScope cs(&lock_);
+  if (mode_ == StorageMode::kDisabled) {
+    return absl::nullopt;
+  }
+
+  auto rtp_it = packet_history_.find(sequence_number);
+  if (rtp_it == packet_history_.end()) {
+    return absl::nullopt;
+  }
+
+  if (verify_rtt && !VerifyRtt(rtp_it->second, clock_->TimeInMilliseconds())) {
+    return absl::nullopt;
+  }
+
+  return StoredPacketToPacketState(rtp_it->second);
+}
+
+bool RtpPacketHistory::VerifyRtt(const RtpPacketHistory::StoredPacket& packet,
+                                 int64_t now_ms) const {
+  if (packet.send_time_ms) {
+    // Send-time already set, this check must be for a retransmission.
+    if (packet.times_retransmitted > 0 &&
+        now_ms < *packet.send_time_ms + rtt_ms_) {
+      // This packet has already been retransmitted once, and the time since
+      // that even is lower than on RTT. Ignore request as this packet is
+      // likely already in the network pipe.
+      return false;
+    }
+  }
+
+  return true;
+}
+
+std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetBestFittingPacket(
+    size_t packet_length) const {
+  // TODO(sprang): Make this smarter, taking retransmit count etc into account.
+  rtc::CritScope cs(&lock_);
+  if (packet_length < kMinPacketRequestBytes || packet_history_.empty()) {
+    return nullptr;
+  }
+
+  size_t min_diff = std::numeric_limits<size_t>::max();
+  RtpPacketToSend* best_packet = nullptr;
+  for (auto& it : packet_history_) {
+    size_t diff = SizeDiff(it.second.packet, packet_length);
+    if (!min_diff || diff < min_diff) {
+      min_diff = diff;
+      best_packet = it.second.packet.get();
+      if (diff == 0) {
+        break;
+      }
+    }
+  }
+
+  return absl::make_unique<RtpPacketToSend>(*best_packet);
+}
+
+void RtpPacketHistory::Reset() {
+  packet_history_.clear();
+  start_seqno_.reset();
+}
+
+void RtpPacketHistory::CullOldPackets(int64_t now_ms) {
+  int64_t packet_duration_ms =
+      std::max(kMinPacketDurationRtt * rtt_ms_, kMinPacketDurationMs);
+  while (!packet_history_.empty()) {
+    auto stored_packet_it = packet_history_.find(*start_seqno_);
+    RTC_DCHECK(stored_packet_it != packet_history_.end());
+
+    if (packet_history_.size() >= kMaxCapacity) {
+      // We have reached the absolute max capacity, remove one packet
+      // unconditionally.
+      RemovePacket(stored_packet_it);
+      continue;
+    }
+
+    const StoredPacket& stored_packet = stored_packet_it->second;
+    if (!stored_packet.send_time_ms) {
+      // Don't remove packets that have not been sent.
+      return;
+    }
+
+    if (*stored_packet.send_time_ms + packet_duration_ms > now_ms) {
+      // Don't cull packets too early to avoid failed retransmission requests.
+      return;
+    }
+
+    if (packet_history_.size() >= number_to_store_ ||
+        (mode_ == StorageMode::kStoreAndCull &&
+         *stored_packet.send_time_ms +
+                 (packet_duration_ms * kPacketCullingDelayFactor) <=
+             now_ms)) {
+      // Too many packets in history, or this packet has timed out. Remove it
+      // and continue.
+      RemovePacket(stored_packet_it);
+    } else {
+      // No more packets can be removed right now.
+      return;
+    }
+  }
+}
+
+std::unique_ptr<RtpPacketToSend> RtpPacketHistory::RemovePacket(
+    StoredPacketIterator packet_it) {
+  // Move the packet out from the StoredPacket container.
+  std::unique_ptr<RtpPacketToSend> rtp_packet =
+      std::move(packet_it->second.packet);
+  // Erase the packet from the map, and capture iterator to the next one.
+  StoredPacketIterator next_it = packet_history_.erase(packet_it);
+
+  // |next_it| now points to the next element, or to the end. If the end,
+  // check if we can wrap around.
+  if (next_it == packet_history_.end()) {
+    next_it = packet_history_.begin();
+  }
+
+  // Update |start_seq_no| to the new oldest item.
+  if (next_it != packet_history_.end()) {
+    start_seqno_ = next_it->first;
+  } else {
+    start_seqno_.reset();
+  }
+
+  return rtp_packet;
+}
+
+RtpPacketHistory::PacketState RtpPacketHistory::StoredPacketToPacketState(
+    const RtpPacketHistory::StoredPacket& stored_packet) {
+  RtpPacketHistory::PacketState state;
+  state.rtp_sequence_number = stored_packet.packet->SequenceNumber();
+  state.send_time_ms = stored_packet.send_time_ms;
+  state.capture_time_ms = stored_packet.packet->capture_time_ms();
+  state.ssrc = stored_packet.packet->Ssrc();
+  state.payload_size = stored_packet.packet->size();
+  state.times_retransmitted = stored_packet.times_retransmitted;
+  return state;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h
new file mode 100644
index 0000000..03527ff
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_history.h
@@ -0,0 +1,148 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/thread_annotations.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class Clock;
+class RtpPacketToSend;
+
+class RtpPacketHistory {
+ public:
+  enum class StorageMode {
+    kDisabled,     // Don't store any packets.
+    kStore,        // Store and keep at least |number_to_store| packets.
+    kStoreAndCull  // Store up to |number_to_store| packets, but try to remove
+                   // packets as they time out or as signaled as received.
+  };
+
+  // Snapshot indicating the state of a packet in the history.
+  struct PacketState {
+    PacketState();
+    PacketState(const PacketState&);
+    ~PacketState();
+
+    uint16_t rtp_sequence_number = 0;
+    absl::optional<int64_t> send_time_ms;
+    int64_t capture_time_ms = 0;
+    uint32_t ssrc = 0;
+    size_t payload_size = 0;
+    // Number of times RE-transmitted, ie not including the first transmission.
+    size_t times_retransmitted = 0;
+  };
+
+  // Maximum number of packets we ever allow in the history.
+  static constexpr size_t kMaxCapacity = 9600;
+  // Don't remove packets within max(1000ms, 3x RTT).
+  static constexpr int64_t kMinPacketDurationMs = 1000;
+  static constexpr int kMinPacketDurationRtt = 3;
+  // With kStoreAndCull, always remove packets after 3x max(1000ms, 3x rtt).
+  static constexpr int kPacketCullingDelayFactor = 3;
+
+  explicit RtpPacketHistory(Clock* clock);
+  ~RtpPacketHistory();
+
+  // Set/get storage mode. Note that setting the state will clear the history,
+  // even if setting the same state as is currently used.
+  void SetStorePacketsStatus(StorageMode mode, size_t number_to_store);
+  StorageMode GetStorageMode() const;
+
+  // Set RTT, used to avoid premature retransmission and to prevent over-writing
+  // a packet in the history before we are reasonably sure it has been received.
+  void SetRtt(int64_t rtt_ms);
+
+  // If |send_time| is set, packet was sent without using pacer, so state will
+  // be set accordingly.
+  void PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet,
+                    StorageType type,
+                    absl::optional<int64_t> send_time_ms);
+
+  // Gets stored RTP packet corresponding to the input |sequence number|.
+  // Returns nullptr if packet is not found. If |verify_rtt| is true, doesn't
+  // return packet that was (re)sent too recently.
+  std::unique_ptr<RtpPacketToSend> GetPacketAndSetSendTime(
+      uint16_t sequence_number,
+      bool verify_rtt);
+
+  // Similar to GetPacketAndSetSendTime(), but only returns a snapshot of the
+  // current state for packet, and never updates internal state.
+  absl::optional<PacketState> GetPacketState(uint16_t sequence_number,
+                                             bool verify_rtt) const;
+
+  // Get the packet (if any) from the history, with size closest to
+  // |packet_size|. The exact size of the packet is not guaranteed.
+  std::unique_ptr<RtpPacketToSend> GetBestFittingPacket(
+      size_t packet_size) const;
+
+ private:
+  struct StoredPacket {
+    StoredPacket();
+    StoredPacket(StoredPacket&&);
+    StoredPacket& operator=(StoredPacket&&);
+    ~StoredPacket();
+
+    // The time of last transmission, including retransmissions.
+    absl::optional<int64_t> send_time_ms;
+
+    // Number of times RE-transmitted, ie excluding the first transmission.
+    size_t times_retransmitted = 0;
+
+    // Storing a packet with |storage_type| = kDontRetransmit indicates this is
+    // only used as temporary storage until sent by the pacer sender.
+    StorageType storage_type = kDontRetransmit;
+
+    // The actual packet.
+    std::unique_ptr<RtpPacketToSend> packet;
+  };
+
+  using StoredPacketIterator = std::map<uint16_t, StoredPacket>::iterator;
+
+  // Helper method used by GetPacketAndSetSendTime() and GetPacketState() to
+  // check if packet has too recently been sent.
+  bool VerifyRtt(const StoredPacket& packet, int64_t now_ms) const
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  void Reset() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  void CullOldPackets(int64_t now_ms) RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  // Removes the packet from the history, and context/mapping that has been
+  // stored. Returns the RTP packet instance contained within the StoredPacket.
+  std::unique_ptr<RtpPacketToSend> RemovePacket(StoredPacketIterator packet)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  static PacketState StoredPacketToPacketState(
+      const StoredPacket& stored_packet);
+
+  Clock* const clock_;
+  rtc::CriticalSection lock_;
+  size_t number_to_store_ RTC_GUARDED_BY(lock_);
+  StorageMode mode_ RTC_GUARDED_BY(lock_);
+  int64_t rtt_ms_ RTC_GUARDED_BY(lock_);
+
+  // Map from rtp sequence numbers to stored packet.
+  std::map<uint16_t, StoredPacket> packet_history_ RTC_GUARDED_BY(lock_);
+
+  // The earliest packet in the history. This might not be the lowest sequence
+  // number, in case there is a wraparound.
+  absl::optional<uint16_t> start_seqno_ RTC_GUARDED_BY(lock_);
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPacketHistory);
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_
diff --git a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
new file mode 100644
index 0000000..026c187
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
@@ -0,0 +1,492 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_packet_history.h"
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+namespace {
+// Set a high sequence number so we'll suffer a wrap-around.
+constexpr uint16_t kStartSeqNum = 65534u;
+
+// Utility method for truncating sequence numbers to uint16.
+uint16_t To16u(size_t sequence_number) {
+  return static_cast<uint16_t>(sequence_number & 0xFFFF);
+}
+}  // namespace
+
+using StorageMode = RtpPacketHistory::StorageMode;
+
+class RtpPacketHistoryTest : public ::testing::Test {
+ protected:
+  RtpPacketHistoryTest() : fake_clock_(123456), hist_(&fake_clock_) {}
+
+  SimulatedClock fake_clock_;
+  RtpPacketHistory hist_;
+
+  std::unique_ptr<RtpPacketToSend> CreateRtpPacket(uint16_t seq_num) {
+    // Payload, ssrc, timestamp and extensions are irrelevant for this tests.
+    std::unique_ptr<RtpPacketToSend> packet(new RtpPacketToSend(nullptr));
+    packet->SetSequenceNumber(seq_num);
+    packet->set_capture_time_ms(fake_clock_.TimeInMilliseconds());
+    return packet;
+  }
+};
+
+TEST_F(RtpPacketHistoryTest, SetStoreStatus) {
+  EXPECT_EQ(StorageMode::kDisabled, hist_.GetStorageMode());
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  EXPECT_EQ(StorageMode::kStore, hist_.GetStorageMode());
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10);
+  EXPECT_EQ(StorageMode::kStoreAndCull, hist_.GetStorageMode());
+  hist_.SetStorePacketsStatus(StorageMode::kDisabled, 0);
+  EXPECT_EQ(StorageMode::kDisabled, hist_.GetStorageMode());
+}
+
+TEST_F(RtpPacketHistoryTest, ClearsHistoryAfterSetStoreStatus) {
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  // Store a packet, but with send-time. It should then not be removed.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     absl::nullopt);
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Changing store status, even to the current one, will clear the history.
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, StartSeqResetAfterReset) {
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10);
+  // Store a packet, but with send-time. It should then not be removed.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     absl::nullopt);
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Changing store status, to clear the history.
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10);
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Add a new packet.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission,
+                     absl::nullopt);
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false));
+
+  // Advance time past where packet expires.
+  fake_clock_.AdvanceTimeMilliseconds(
+      RtpPacketHistory::kPacketCullingDelayFactor *
+      RtpPacketHistory::kMinPacketDurationMs);
+
+  // Add one more packet and verify no state left from packet before reset.
+  hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + 2)),
+                     kAllowRetransmission, absl::nullopt);
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false));
+  EXPECT_TRUE(hist_.GetPacketState(To16u(kStartSeqNum + 2), false));
+}
+
+TEST_F(RtpPacketHistoryTest, NoStoreStatus) {
+  EXPECT_EQ(StorageMode::kDisabled, hist_.GetStorageMode());
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, absl::nullopt);
+  // Packet should not be stored.
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, GetRtpPacket_NotStored) {
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  EXPECT_FALSE(hist_.GetPacketState(0, false));
+}
+
+TEST_F(RtpPacketHistoryTest, PutRtpPacket) {
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, absl::nullopt);
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, GetRtpPacket) {
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  int64_t capture_time_ms = 1;
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  packet->set_capture_time_ms(capture_time_ms);
+  rtc::CopyOnWriteBuffer buffer = packet->Buffer();
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, absl::nullopt);
+
+  std::unique_ptr<RtpPacketToSend> packet_out =
+      hist_.GetPacketAndSetSendTime(kStartSeqNum, false);
+  EXPECT_TRUE(packet_out);
+  EXPECT_EQ(buffer, packet_out->Buffer());
+  EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
+}
+
+TEST_F(RtpPacketHistoryTest, NoCaptureTime) {
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  packet->set_capture_time_ms(-1);
+  rtc::CopyOnWriteBuffer buffer = packet->Buffer();
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, absl::nullopt);
+
+  std::unique_ptr<RtpPacketToSend> packet_out =
+      hist_.GetPacketAndSetSendTime(kStartSeqNum, false);
+  EXPECT_TRUE(packet_out);
+  EXPECT_EQ(buffer, packet_out->Buffer());
+  EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
+}
+
+TEST_F(RtpPacketHistoryTest, DontRetransmit) {
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  rtc::CopyOnWriteBuffer buffer = packet->Buffer();
+  hist_.PutRtpPacket(std::move(packet), kDontRetransmit, absl::nullopt);
+
+  // Get the packet and verify data.
+  std::unique_ptr<RtpPacketToSend> packet_out;
+  packet_out = hist_.GetPacketAndSetSendTime(kStartSeqNum, false);
+  ASSERT_TRUE(packet_out);
+  EXPECT_EQ(buffer.size(), packet_out->size());
+  EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
+
+  // Non-retransmittable packets are immediately removed, so getting in again
+  // should fail.
+  EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, PacketStateIsCorrect) {
+  const uint32_t kSsrc = 92384762;
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 10);
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  packet->SetSsrc(kSsrc);
+  packet->SetPayloadSize(1234);
+  const size_t packet_size = packet->size();
+
+  hist_.PutRtpPacket(std::move(packet), StorageType::kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  absl::optional<RtpPacketHistory::PacketState> state =
+      hist_.GetPacketState(kStartSeqNum, false);
+  ASSERT_TRUE(state);
+  EXPECT_EQ(state->rtp_sequence_number, kStartSeqNum);
+  EXPECT_EQ(state->send_time_ms, fake_clock_.TimeInMilliseconds());
+  EXPECT_EQ(state->capture_time_ms, fake_clock_.TimeInMilliseconds());
+  EXPECT_EQ(state->ssrc, kSsrc);
+  EXPECT_EQ(state->payload_size, packet_size);
+  EXPECT_EQ(state->times_retransmitted, 0u);
+
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false));
+
+  state = hist_.GetPacketState(kStartSeqNum, false);
+  ASSERT_TRUE(state);
+  EXPECT_EQ(state->times_retransmitted, 1u);
+}
+
+TEST_F(RtpPacketHistoryTest, MinResendTimeWithPacer) {
+  static const int64_t kMinRetransmitIntervalMs = 100;
+
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  hist_.SetRtt(kMinRetransmitIntervalMs);
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  size_t len = packet->size();
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, absl::nullopt);
+
+  // First transmission: TimeToSendPacket() call from pacer.
+  EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false));
+
+  // First retransmission - allow early retransmission.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+
+  // With pacer there's two calls to history:
+  // 1) When the NACK request arrived, use GetPacketState() to see if the
+  //    packet is there and verify RTT constraints. Then we use the ssrc
+  //    and sequence number to enqueue the retransmission in the pacer
+  // 2) When the pacer determines that it is time to send the packet, it calls
+  //    GetPacketAndSetSendTime(). This time we do not need to verify RTT as
+  //    has that has already been done.
+  absl::optional<RtpPacketHistory::PacketState> packet_state =
+      hist_.GetPacketState(kStartSeqNum, /*verify_rtt=*/true);
+  EXPECT_TRUE(packet_state);
+  EXPECT_EQ(len, packet_state->payload_size);
+  EXPECT_EQ(capture_time_ms, packet_state->capture_time_ms);
+
+  // Retransmission was allowed, next send it from pacer.
+  EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum,
+                                            /*verify_rtt=*/false));
+
+  // Second retransmission - advance time to just before retransmission OK.
+  fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, /*verify_rtt=*/true));
+
+  // Advance time to just after retransmission OK.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, /*verify_rtt=*/true));
+  EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, MinResendTimeWithoutPacer) {
+  static const int64_t kMinRetransmitIntervalMs = 100;
+
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+  hist_.SetRtt(kMinRetransmitIntervalMs);
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  size_t len = packet->size();
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  // First retransmission - allow early retransmission.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  packet = hist_.GetPacketAndSetSendTime(kStartSeqNum, true);
+  EXPECT_TRUE(packet);
+  EXPECT_EQ(len, packet->size());
+  EXPECT_EQ(capture_time_ms, packet->capture_time_ms());
+
+  // Second retransmission - advance time to just before retransmission OK.
+  fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
+  EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kStartSeqNum, true));
+
+  // Advance time to just after retransmission OK.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kStartSeqNum, true));
+}
+
+TEST_F(RtpPacketHistoryTest, RemovesOldestSentPacketWhenAtMaxSize) {
+  const size_t kMaxNumPackets = 10;
+  hist_.SetStorePacketsStatus(StorageMode::kStore, kMaxNumPackets);
+
+  // History does not allow removing packets within kMinPacketDurationMs,
+  // so in order to test capacity, make sure insertion spans this time.
+  const int64_t kPacketIntervalMs =
+      RtpPacketHistory::kMinPacketDurationMs / kMaxNumPackets;
+
+  // Add packets until the buffer is full.
+  for (size_t i = 0; i < kMaxNumPackets; ++i) {
+    std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum + i);
+    // Immediate mark packet as sent.
+    hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                       fake_clock_.TimeInMilliseconds());
+    fake_clock_.AdvanceTimeMilliseconds(kPacketIntervalMs);
+  }
+
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // History is full, oldest one should be overwritten.
+  std::unique_ptr<RtpPacketToSend> packet =
+      CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets));
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  // Oldest packet should be gone, but packet after than one still present.
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false));
+}
+
+TEST_F(RtpPacketHistoryTest, RemovesOldestPacketWhenAtMaxCapacity) {
+  // Tests the absolute upper bound on number of stored packets. Don't allow
+  // storing more than this, even if packets have not yet been sent.
+  const size_t kMaxNumPackets = RtpPacketHistory::kMaxCapacity;
+  hist_.SetStorePacketsStatus(StorageMode::kStore,
+                              RtpPacketHistory::kMaxCapacity);
+
+  // Add packets until the buffer is full.
+  for (size_t i = 0; i < kMaxNumPackets; ++i) {
+    std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum + i);
+    // Don't mark packets as sent, preventing them from being removed.
+    hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, absl::nullopt);
+  }
+
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // History is full, oldest one should be overwritten.
+  std::unique_ptr<RtpPacketToSend> packet =
+      CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets));
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  // Oldest packet should be gone, but packet after than one still present.
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false));
+}
+
+TEST_F(RtpPacketHistoryTest, DontRemoveUnsentPackets) {
+  const size_t kMaxNumPackets = 10;
+  hist_.SetStorePacketsStatus(StorageMode::kStore, kMaxNumPackets);
+
+  // Add packets until the buffer is full.
+  for (size_t i = 0; i < kMaxNumPackets; ++i) {
+    // Mark packets as unsent.
+    hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + i)),
+                       kAllowRetransmission, absl::nullopt);
+  }
+  fake_clock_.AdvanceTimeMilliseconds(RtpPacketHistory::kMinPacketDurationMs);
+
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // History is full, but old packets not sent, so allow expansion.
+  hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets)),
+                     kAllowRetransmission, fake_clock_.TimeInMilliseconds());
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Set all packet as sent and advance time past min packet duration time,
+  // otherwise packets till still be prevented from being removed.
+  for (size_t i = 0; i <= kMaxNumPackets; ++i) {
+    EXPECT_TRUE(hist_.GetPacketAndSetSendTime(To16u(kStartSeqNum + i), false));
+  }
+  fake_clock_.AdvanceTimeMilliseconds(RtpPacketHistory::kMinPacketDurationMs);
+  // Add a new packet, this means the two oldest ones will be culled.
+  hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + kMaxNumPackets + 1)),
+                     kAllowRetransmission, fake_clock_.TimeInMilliseconds());
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum + 1, false));
+  EXPECT_TRUE(hist_.GetPacketState(To16u(kStartSeqNum + 2), false));
+}
+
+TEST_F(RtpPacketHistoryTest, DontRemoveTooRecentlyTransmittedPackets) {
+  // Set size to remove old packets as soon as possible.
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 1);
+
+  // Add a packet, marked as send, and advance time to just before removal time.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+  fake_clock_.AdvanceTimeMilliseconds(RtpPacketHistory::kMinPacketDurationMs -
+                                      1);
+
+  // Add a new packet to trigger culling.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Advance time to where packet will be eligible for removal and try again.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + 2)),
+                     kAllowRetransmission, fake_clock_.TimeInMilliseconds());
+  // First packet should no be gone, but next one still there.
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false));
+}
+
+TEST_F(RtpPacketHistoryTest, DontRemoveTooRecentlyTransmittedPacketsHighRtt) {
+  const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2;
+  const int64_t kPacketTimeoutMs =
+      kRttMs * RtpPacketHistory::kMinPacketDurationRtt;
+
+  // Set size to remove old packets as soon as possible.
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 1);
+  hist_.SetRtt(kRttMs);
+
+  // Add a packet, marked as send, and advance time to just before removal time.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+  fake_clock_.AdvanceTimeMilliseconds(kPacketTimeoutMs - 1);
+
+  // Add a new packet to trigger culling.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Advance time to where packet will be eligible for removal and try again.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  hist_.PutRtpPacket(CreateRtpPacket(To16u(kStartSeqNum + 2)),
+                     kAllowRetransmission, fake_clock_.TimeInMilliseconds());
+  // First packet should no be gone, but next one still there.
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum + 1, false));
+}
+
+TEST_F(RtpPacketHistoryTest, RemovesOldWithCulling) {
+  const size_t kMaxNumPackets = 10;
+  // Enable culling. Even without feedback, this can trigger early removal.
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, kMaxNumPackets);
+
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  int64_t kMaxPacketDurationMs = RtpPacketHistory::kMinPacketDurationMs *
+                                 RtpPacketHistory::kPacketCullingDelayFactor;
+  fake_clock_.AdvanceTimeMilliseconds(kMaxPacketDurationMs - 1);
+
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Advance to where packet can be culled, even if buffer is not full.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, RemovesOldWithCullingHighRtt) {
+  const size_t kMaxNumPackets = 10;
+  const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2;
+  // Enable culling. Even without feedback, this can trigger early removal.
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, kMaxNumPackets);
+  hist_.SetRtt(kRttMs);
+
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  int64_t kMaxPacketDurationMs = kRttMs *
+                                 RtpPacketHistory::kMinPacketDurationRtt *
+                                 RtpPacketHistory::kPacketCullingDelayFactor;
+  fake_clock_.AdvanceTimeMilliseconds(kMaxPacketDurationMs - 1);
+
+  // First packet should still be there.
+  EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum, false));
+
+  // Advance to where packet can be culled, even if buffer is not full.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum + 1), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum, false));
+}
+
+TEST_F(RtpPacketHistoryTest, GetBestFittingPacket) {
+  const size_t kTargetSize = 500;
+  hist_.SetStorePacketsStatus(StorageMode::kStore, 10);
+
+  // Add three packets of various sizes.
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  packet->SetPayloadSize(kTargetSize);
+  const size_t target_packet_size = packet->size();
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+  packet = CreateRtpPacket(kStartSeqNum + 1);
+  packet->SetPayloadSize(kTargetSize - 1);
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+  packet = CreateRtpPacket(To16u(kStartSeqNum + 2));
+  packet->SetPayloadSize(kTargetSize + 1);
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMilliseconds());
+
+  EXPECT_EQ(target_packet_size,
+            hist_.GetBestFittingPacket(target_packet_size)->size());
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet_received.cc b/modules/rtp_rtcp/source/rtp_packet_received.cc
new file mode 100644
index 0000000..6acc9b5
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_received.cc
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+
+#include <vector>
+
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+RtpPacketReceived::RtpPacketReceived() = default;
+RtpPacketReceived::RtpPacketReceived(const ExtensionManager* extensions)
+    : RtpPacket(extensions) {}
+RtpPacketReceived::RtpPacketReceived(const RtpPacketReceived& packet) = default;
+RtpPacketReceived::RtpPacketReceived(RtpPacketReceived&& packet) = default;
+
+RtpPacketReceived& RtpPacketReceived::operator=(
+    const RtpPacketReceived& packet) = default;
+RtpPacketReceived& RtpPacketReceived::operator=(RtpPacketReceived&& packet) =
+    default;
+
+RtpPacketReceived::~RtpPacketReceived() {}
+
+void RtpPacketReceived::GetHeader(RTPHeader* header) const {
+  header->markerBit = Marker();
+  header->payloadType = PayloadType();
+  header->sequenceNumber = SequenceNumber();
+  header->timestamp = Timestamp();
+  header->ssrc = Ssrc();
+  std::vector<uint32_t> csrcs = Csrcs();
+  header->numCSRCs = rtc::dchecked_cast<uint8_t>(csrcs.size());
+  for (size_t i = 0; i < csrcs.size(); ++i) {
+    header->arrOfCSRCs[i] = csrcs[i];
+  }
+  header->paddingLength = padding_size();
+  header->headerLength = headers_size();
+  header->payload_type_frequency = payload_type_frequency();
+  header->extension.hasTransmissionTimeOffset =
+      GetExtension<TransmissionOffset>(
+          &header->extension.transmissionTimeOffset);
+  header->extension.hasAbsoluteSendTime =
+      GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
+  header->extension.hasTransportSequenceNumber =
+      GetExtension<TransportSequenceNumber>(
+          &header->extension.transportSequenceNumber);
+  header->extension.hasAudioLevel = GetExtension<AudioLevel>(
+      &header->extension.voiceActivity, &header->extension.audioLevel);
+  header->extension.hasVideoRotation =
+      GetExtension<VideoOrientation>(&header->extension.videoRotation);
+  header->extension.hasVideoContentType =
+      GetExtension<VideoContentTypeExtension>(
+          &header->extension.videoContentType);
+  header->extension.has_video_timing =
+      GetExtension<VideoTimingExtension>(&header->extension.video_timing);
+  GetExtension<RtpStreamId>(&header->extension.stream_id);
+  GetExtension<RepairedRtpStreamId>(&header->extension.repaired_stream_id);
+  GetExtension<RtpMid>(&header->extension.mid);
+  GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet_received.h b/modules/rtp_rtcp/source/rtp_packet_received.h
new file mode 100644
index 0000000..8690031
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_received.h
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
+
+#include <vector>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+// Class to hold rtp packet with metadata for receiver side.
+class RtpPacketReceived : public RtpPacket {
+ public:
+  RtpPacketReceived();
+  explicit RtpPacketReceived(const ExtensionManager* extensions);
+  RtpPacketReceived(const RtpPacketReceived& packet);
+  RtpPacketReceived(RtpPacketReceived&& packet);
+
+  RtpPacketReceived& operator=(const RtpPacketReceived& packet);
+  RtpPacketReceived& operator=(RtpPacketReceived&& packet);
+
+  ~RtpPacketReceived();
+
+  // TODO(danilchap): Remove this function when all code update to use RtpPacket
+  // directly. Function is there just for easier backward compatibilty.
+  void GetHeader(RTPHeader* header) const;
+
+  // Time in local time base as close as it can to packet arrived on the
+  // network.
+  int64_t arrival_time_ms() const { return arrival_time_ms_; }
+  void set_arrival_time_ms(int64_t time) { arrival_time_ms_ = time; }
+
+  // Estimated from Timestamp() using rtcp Sender Reports.
+  NtpTime capture_ntp_time() const { return capture_time_; }
+  void set_capture_ntp_time(NtpTime time) { capture_time_ = time; }
+
+  // Flag if packet was recovered via RTX or FEC.
+  bool recovered() const { return recovered_; }
+  void set_recovered(bool value) { recovered_ = value; }
+
+  int payload_type_frequency() const { return payload_type_frequency_; }
+  void set_payload_type_frequency(int value) {
+    payload_type_frequency_ = value;
+  }
+
+  // Additional data bound to the RTP packet for use in application code,
+  // outside of WebRTC.
+  rtc::ArrayView<const uint8_t> application_data() const {
+    return application_data_;
+  }
+  void set_application_data(rtc::ArrayView<const uint8_t> data) {
+    application_data_.assign(data.begin(), data.end());
+  }
+
+ private:
+  NtpTime capture_time_;
+  int64_t arrival_time_ms_ = 0;
+  int payload_type_frequency_ = 0;
+  bool recovered_ = false;
+  std::vector<uint8_t> application_data_;
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_RECEIVED_H_
diff --git a/modules/rtp_rtcp/source/rtp_packet_to_send.cc b/modules/rtp_rtcp/source/rtp_packet_to_send.cc
new file mode 100644
index 0000000..0153bbe
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_to_send.cc
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+
+namespace webrtc {
+
+RtpPacketToSend::RtpPacketToSend(const ExtensionManager* extensions)
+    : RtpPacket(extensions) {}
+RtpPacketToSend::RtpPacketToSend(const ExtensionManager* extensions,
+                                 size_t capacity)
+    : RtpPacket(extensions, capacity) {}
+RtpPacketToSend::RtpPacketToSend(const RtpPacketToSend& packet) = default;
+RtpPacketToSend::RtpPacketToSend(RtpPacketToSend&& packet) = default;
+
+RtpPacketToSend& RtpPacketToSend::operator=(const RtpPacketToSend& packet) =
+    default;
+RtpPacketToSend& RtpPacketToSend::operator=(RtpPacketToSend&& packet) = default;
+
+RtpPacketToSend::~RtpPacketToSend() = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_packet_to_send.h b/modules/rtp_rtcp/source/rtp_packet_to_send.h
new file mode 100644
index 0000000..1ed7dda
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_to_send.h
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet.h"
+
+namespace webrtc {
+// Class to hold rtp packet with metadata for sender side.
+class RtpPacketToSend : public RtpPacket {
+ public:
+  explicit RtpPacketToSend(const ExtensionManager* extensions);
+  RtpPacketToSend(const ExtensionManager* extensions, size_t capacity);
+  RtpPacketToSend(const RtpPacketToSend& packet);
+  RtpPacketToSend(RtpPacketToSend&& packet);
+
+  RtpPacketToSend& operator=(const RtpPacketToSend& packet);
+  RtpPacketToSend& operator=(RtpPacketToSend&& packet);
+
+  ~RtpPacketToSend();
+
+  // Time in local time base as close as it can to frame capture time.
+  int64_t capture_time_ms() const { return capture_time_ms_; }
+
+  void set_capture_time_ms(int64_t time) { capture_time_ms_ = time; }
+
+  // Additional data bound to the RTP packet for use in application code,
+  // outside of WebRTC.
+  rtc::ArrayView<const uint8_t> application_data() const {
+    return application_data_;
+  }
+
+  void set_application_data(rtc::ArrayView<const uint8_t> data) {
+    application_data_.assign(data.begin(), data.end());
+  }
+
+  void set_packetization_finish_time_ms(int64_t time) {
+    SetExtension<VideoTimingExtension>(
+        VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time),
+        VideoSendTiming::kPacketizationFinishDeltaOffset);
+  }
+
+  void set_pacer_exit_time_ms(int64_t time) {
+    SetExtension<VideoTimingExtension>(
+        VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time),
+        VideoSendTiming::kPacerExitDeltaOffset);
+  }
+
+  void set_network_time_ms(int64_t time) {
+    SetExtension<VideoTimingExtension>(
+        VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time),
+        VideoSendTiming::kNetworkTimestampDeltaOffset);
+  }
+
+  void set_network2_time_ms(int64_t time) {
+    SetExtension<VideoTimingExtension>(
+        VideoSendTiming::GetDeltaCappedMs(capture_time_ms_, time),
+        VideoSendTiming::kNetwork2TimestampDeltaOffset);
+  }
+
+ private:
+  int64_t capture_time_ms_ = 0;
+  std::vector<uint8_t> application_data_;
+};
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_TO_SEND_H_
diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc
new file mode 100644
index 0000000..60d23d8
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -0,0 +1,566 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/random.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+using ::testing::ElementsAreArray;
+using ::testing::IsEmpty;
+using ::testing::make_tuple;
+
+constexpr int8_t kPayloadType = 100;
+constexpr uint32_t kSsrc = 0x12345678;
+constexpr uint16_t kSeqNum = 0x1234;
+constexpr uint8_t kSeqNumFirstByte = kSeqNum >> 8;
+constexpr uint8_t kSeqNumSecondByte = kSeqNum & 0xff;
+constexpr uint32_t kTimestamp = 0x65431278;
+constexpr uint8_t kTransmissionOffsetExtensionId = 1;
+constexpr uint8_t kAudioLevelExtensionId = 9;
+constexpr uint8_t kRtpStreamIdExtensionId = 0xa;
+constexpr uint8_t kRtpMidExtensionId = 0xb;
+constexpr uint8_t kVideoTimingExtensionId = 0xc;
+constexpr int32_t kTimeOffset = 0x56ce;
+constexpr bool kVoiceActive = true;
+constexpr uint8_t kAudioLevel = 0x5a;
+constexpr char kStreamId[] = "streamid";
+constexpr char kMid[] = "mid";
+constexpr size_t kMaxPaddingSize = 224u;
+// clang-format off
+constexpr uint8_t kMinimumPacket[] = {
+    0x80, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78};
+
+constexpr uint8_t kPacketWithTO[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x01,
+    0x12, 0x00, 0x56, 0xce};
+
+constexpr uint8_t kPacketWithTOAndAL[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x02,
+    0x12, 0x00, 0x56, 0xce,
+    0x90, 0x80|kAudioLevel, 0x00, 0x00};
+
+constexpr uint8_t kPacketWithRsid[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x03,
+    0xa7, 's',  't',  'r',
+    'e',  'a',  'm',  'i',
+    'd' , 0x00, 0x00, 0x00};
+
+constexpr uint8_t kPacketWithMid[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x01,
+    0xb2, 'm', 'i', 'd'};
+
+constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
+constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
+constexpr uint8_t kPacketPaddingSize = 8;
+constexpr uint8_t kPacket[] = {
+    0xb2, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0x34, 0x56, 0x78, 0x90,
+    0x32, 0x43, 0x54, 0x65,
+    0xbe, 0xde, 0x00, 0x01,
+    0x12, 0x00, 0x56, 0xce,
+    'p', 'a', 'y', 'l', 'o', 'a', 'd',
+    'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize};
+
+constexpr uint8_t kPacketWithInvalidExtension[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+    0x12, 0x34, 0x56, 0x78,  // kSSrc.
+    0xbe, 0xde, 0x00, 0x02,  // Extension block of size 2 x 32bit words.
+    (kTransmissionOffsetExtensionId << 4) | 6,  // (6+1)-byte extension, but
+           'e',  'x',  't',                     // Transmission Offset
+     'd',  'a',  't',  'a',                     // expected to be 3-bytes.
+     'p',  'a',  'y',  'l',  'o',  'a',  'd'};
+
+constexpr uint8_t kPacketWithLegacyTimingExtension[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+    0x12, 0x34, 0x56, 0x78,  // kSSrc.
+    0xbe, 0xde, 0x00, 0x04,    // Extension block of size 4 x 32bit words.
+    (kVideoTimingExtensionId << 4)
+      | VideoTimingExtension::kValueSizeBytes - 2,  // Old format without flags.
+          0x00, 0x01, 0x00,
+    0x02, 0x00, 0x03, 0x00,
+    0x04, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00};
+// clang-format on
+}  // namespace
+
+TEST(RtpPacketTest, CreateMinimum) {
+  RtpPacketToSend packet(nullptr);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  EXPECT_THAT(kMinimumPacket, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithExtension) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<TransmissionOffset>(kTimeOffset);
+  EXPECT_THAT(kPacketWithTO, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWith2Extensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<TransmissionOffset>(kTimeOffset);
+  packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel);
+  EXPECT_THAT(kPacketWithTOAndAL,
+              ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithDynamicSizedExtensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<RtpStreamId>(kStreamId);
+  EXPECT_THAT(kPacketWithRsid, ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, TryToCreateWithEmptyRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(""));
+}
+
+TEST(RtpPacketTest, TryToCreateWithLongRsid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  constexpr char kLongStreamId[] = "LoooooooooongRsid";
+  ASSERT_EQ(strlen(kLongStreamId), 17u);
+  extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpStreamId>(kLongStreamId));
+}
+
+TEST(RtpPacketTest, TryToCreateWithEmptyMid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpMid>(kRtpMidExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpMid>(""));
+}
+
+TEST(RtpPacketTest, TryToCreateWithLongMid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  constexpr char kLongMid[] = "LoooooooooonogMid";
+  ASSERT_EQ(strlen(kLongMid), 17u);
+  extensions.Register<RtpMid>(kRtpMidExtensionId);
+  RtpPacketToSend packet(&extensions);
+  EXPECT_FALSE(packet.SetExtension<RtpMid>(kLongMid));
+}
+
+TEST(RtpPacketTest, CreateWithExtensionsWithoutManager) {
+  RtpPacketToSend packet(nullptr);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+
+  auto raw = packet.AllocateRawExtension(kTransmissionOffsetExtensionId,
+                                         TransmissionOffset::kValueSizeBytes);
+  EXPECT_EQ(raw.size(), TransmissionOffset::kValueSizeBytes);
+  TransmissionOffset::Write(raw, kTimeOffset);
+
+  raw = packet.AllocateRawExtension(kAudioLevelExtensionId,
+                                    AudioLevel::kValueSizeBytes);
+  EXPECT_EQ(raw.size(), AudioLevel::kValueSizeBytes);
+  AudioLevel::Write(raw, kVoiceActive, kAudioLevel);
+
+  EXPECT_THAT(kPacketWithTOAndAL,
+              ElementsAreArray(packet.data(), packet.size()));
+}
+
+TEST(RtpPacketTest, CreateWithMaxSizeHeaderExtension) {
+  const size_t kMaxExtensionSize = 16;
+  const int kId = 1;
+  const uint8_t kValue[16] = "123456789abcdef";
+
+  // Write packet with a custom extension.
+  RtpPacketToSend packet(nullptr);
+  packet.SetRawExtension(kId, kValue);
+  // Using different size for same id is not allowed.
+  EXPECT_TRUE(packet.AllocateRawExtension(kId, kMaxExtensionSize - 1).empty());
+
+  packet.SetPayloadSize(42);
+  // Rewriting allocated extension is allowed.
+  EXPECT_EQ(packet.AllocateRawExtension(kId, kMaxExtensionSize).size(),
+            kMaxExtensionSize);
+  // Adding another extension after payload is set is not allowed.
+  EXPECT_TRUE(packet.AllocateRawExtension(kId + 1, kMaxExtensionSize).empty());
+
+  // Read packet with the custom extension.
+  RtpPacketReceived parsed;
+  EXPECT_TRUE(parsed.Parse(packet.Buffer()));
+  auto read_raw = parsed.GetRawExtension(kId);
+  EXPECT_THAT(read_raw, ElementsAreArray(kValue, kMaxExtensionSize));
+}
+
+TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) {
+  const size_t kPayloadSize = 4;
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+  RtpPacketToSend packet(&extensions);
+
+  EXPECT_TRUE(packet.ReserveExtension<TransmissionOffset>());
+  packet.SetPayloadSize(kPayloadSize);
+  // Can't set extension after payload.
+  EXPECT_FALSE(packet.SetExtension<AudioLevel>(kVoiceActive, kAudioLevel));
+  // Unless reserved.
+  EXPECT_TRUE(packet.SetExtension<TransmissionOffset>(kTimeOffset));
+}
+
+TEST(RtpPacketTest, CreatePurePadding) {
+  const size_t kPaddingSize = kMaxPaddingSize - 1;
+  RtpPacketToSend packet(nullptr, 12 + kPaddingSize);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  Random random(0x123456789);
+
+  EXPECT_LT(packet.size(), packet.capacity());
+  EXPECT_FALSE(packet.SetPadding(kPaddingSize + 1, &random));
+  EXPECT_TRUE(packet.SetPadding(kPaddingSize, &random));
+  EXPECT_EQ(packet.size(), packet.capacity());
+}
+
+TEST(RtpPacketTest, CreateUnalignedPadding) {
+  const size_t kPayloadSize = 3;  // Make padding start at unaligned address.
+  RtpPacketToSend packet(nullptr, 12 + kPayloadSize + kMaxPaddingSize);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetPayloadSize(kPayloadSize);
+  Random r(0x123456789);
+
+  EXPECT_LT(packet.size(), packet.capacity());
+  EXPECT_TRUE(packet.SetPadding(kMaxPaddingSize, &r));
+  EXPECT_EQ(packet.size(), packet.capacity());
+}
+
+TEST(RtpPacketTest, ParseMinimum) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kMinimumPacket, sizeof(kMinimumPacket)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  EXPECT_EQ(0u, packet.padding_size());
+  EXPECT_EQ(0u, packet.payload_size());
+}
+
+TEST(RtpPacketTest, ParseBuffer) {
+  rtc::CopyOnWriteBuffer unparsed(kMinimumPacket);
+  const uint8_t* raw = unparsed.data();
+
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(std::move(unparsed)));
+  EXPECT_EQ(raw, packet.data());  // Expect packet take the buffer without copy.
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  EXPECT_EQ(0u, packet.padding_size());
+  EXPECT_EQ(0u, packet.payload_size());
+}
+
+TEST(RtpPacketTest, ParseWithExtension) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  int32_t time_offset;
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  EXPECT_EQ(kTimeOffset, time_offset);
+  EXPECT_EQ(0u, packet.payload_size());
+  EXPECT_EQ(0u, packet.padding_size());
+}
+
+TEST(RtpPacketTest, ParseWithInvalidSizedExtension) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacketWithInvalidExtension,
+                           sizeof(kPacketWithInvalidExtension)));
+
+  // Extension should be ignored.
+  int32_t time_offset;
+  EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset));
+
+  // But shouldn't prevent reading payload.
+  EXPECT_THAT(packet.payload(), ElementsAreArray(kPayload));
+}
+
+TEST(RtpPacketTest, ParseWithOverSizedExtension) {
+  // clang-format off
+  const uint8_t bad_packet[] = {
+      0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x01,  // Extension of size 1x32bit word.
+      0x00,  // Add a byte of padding.
+            0x12,  // Extension id 1 size (2+1).
+                  0xda, 0x1a  // Only 2 bytes of extension payload.
+  };
+  // clang-format on
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(TransmissionOffset::kId, 1);
+  RtpPacketReceived packet(&extensions);
+
+  // Parse should ignore bad extension and proceed.
+  EXPECT_TRUE(packet.Parse(bad_packet, sizeof(bad_packet)));
+  int32_t time_offset;
+  // But extracting extension should fail.
+  EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset));
+}
+
+TEST(RtpPacketTest, ParseWith2Extensions) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  extensions.Register(kRtpExtensionAudioLevel, kAudioLevelExtensionId);
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacketWithTOAndAL, sizeof(kPacketWithTOAndAL)));
+  int32_t time_offset;
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  EXPECT_EQ(kTimeOffset, time_offset);
+  bool voice_active;
+  uint8_t audio_level;
+  EXPECT_TRUE(packet.GetExtension<AudioLevel>(&voice_active, &audio_level));
+  EXPECT_EQ(kVoiceActive, voice_active);
+  EXPECT_EQ(kAudioLevel, audio_level);
+}
+
+TEST(RtpPacketTest, ParseWithAllFeatures) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacket, sizeof(kPacket)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+  EXPECT_THAT(packet.Csrcs(), ElementsAreArray(kCsrcs));
+  EXPECT_THAT(packet.payload(), ElementsAreArray(kPayload));
+  EXPECT_EQ(kPacketPaddingSize, packet.padding_size());
+  int32_t time_offset;
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+}
+
+TEST(RtpPacketTest, ParseWithExtensionDelayed) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+  EXPECT_EQ(kPayloadType, packet.PayloadType());
+  EXPECT_EQ(kSeqNum, packet.SequenceNumber());
+  EXPECT_EQ(kTimestamp, packet.Timestamp());
+  EXPECT_EQ(kSsrc, packet.Ssrc());
+
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register(kRtpExtensionTransmissionTimeOffset,
+                      kTransmissionOffsetExtensionId);
+
+  int32_t time_offset;
+  EXPECT_FALSE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  packet.IdentifyExtensions(extensions);
+  EXPECT_TRUE(packet.GetExtension<TransmissionOffset>(&time_offset));
+  EXPECT_EQ(kTimeOffset, time_offset);
+  EXPECT_EQ(0u, packet.payload_size());
+  EXPECT_EQ(0u, packet.padding_size());
+}
+
+TEST(RtpPacketTest, ParseWithoutExtensionManager) {
+  RtpPacketReceived packet;
+  EXPECT_TRUE(packet.Parse(kPacketWithTO, sizeof(kPacketWithTO)));
+
+  EXPECT_FALSE(packet.HasRawExtension(kAudioLevelExtensionId));
+  EXPECT_TRUE(packet.GetRawExtension(kAudioLevelExtensionId).empty());
+
+  EXPECT_TRUE(packet.HasRawExtension(kTransmissionOffsetExtensionId));
+
+  int32_t time_offset = 0;
+  auto raw_extension = packet.GetRawExtension(kTransmissionOffsetExtensionId);
+  EXPECT_EQ(raw_extension.size(), TransmissionOffset::kValueSizeBytes);
+  EXPECT_TRUE(TransmissionOffset::Parse(raw_extension, &time_offset));
+
+  EXPECT_EQ(time_offset, kTimeOffset);
+}
+
+TEST(RtpPacketTest, ParseDynamicSizeExtension) {
+  // clang-format off
+  const uint8_t kPacket1[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x78,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x02,  // Extensions block of size 2x32bit words.
+    0x21, 'H', 'D',          // Extension with id = 2, size = (1+1).
+    0x12, 'r', 't', 'x',     // Extension with id = 1, size = (2+1).
+    0x00};  // Extension padding.
+  const uint8_t kPacket2[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x79,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x01,  // Extensions block of size 1x32bit words.
+    0x11, 'H', 'D',          // Extension with id = 1, size = (1+1).
+    0x00};  // Extension padding.
+  // clang-format on
+  RtpPacketReceived::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(1);
+  extensions.Register<RepairedRtpStreamId>(2);
+  RtpPacketReceived packet(&extensions);
+  ASSERT_TRUE(packet.Parse(kPacket1, sizeof(kPacket1)));
+
+  std::string rsid;
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "rtx");
+
+  std::string repaired_rsid;
+  EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+  EXPECT_EQ(repaired_rsid, "HD");
+
+  // Parse another packet with RtpStreamId extension of different size.
+  ASSERT_TRUE(packet.Parse(kPacket2, sizeof(kPacket2)));
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "HD");
+  EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+}
+
+TEST(RtpPacketTest, ParseWithMid) {
+  RtpPacketReceived::ExtensionManager extensions;
+  extensions.Register<RtpMid>(kRtpMidExtensionId);
+  RtpPacketReceived packet(&extensions);
+  ASSERT_TRUE(packet.Parse(kPacketWithMid, sizeof(kPacketWithMid)));
+
+  std::string mid;
+  EXPECT_TRUE(packet.GetExtension<RtpMid>(&mid));
+  EXPECT_EQ(mid, kMid);
+}
+
+TEST(RtpPacketTest, RawExtensionFunctionsAcceptZeroIdAndReturnFalse) {
+  RtpPacketReceived::ExtensionManager extensions;
+  RtpPacketReceived packet(&extensions);
+  // Use ExtensionManager to set kInvalidId to 0 to demonstrate natural way for
+  // using zero value as a parameter to Packet::*RawExtension functions.
+  const int kInvalidId = extensions.GetId(TransmissionOffset::kId);
+  ASSERT_EQ(kInvalidId, 0);
+
+  ASSERT_TRUE(packet.Parse(kPacket, sizeof(kPacket)));
+
+  EXPECT_FALSE(packet.HasRawExtension(kInvalidId));
+  EXPECT_THAT(packet.GetRawExtension(kInvalidId), IsEmpty());
+  const uint8_t kExtension[] = {'e', 'x', 't'};
+  EXPECT_FALSE(packet.SetRawExtension(kInvalidId, kExtension));
+  EXPECT_THAT(packet.AllocateRawExtension(kInvalidId, 3), IsEmpty());
+}
+
+TEST(RtpPacketTest, CreateAndParseTimingFrameExtension) {
+  // Create a packet with video frame timing extension populated.
+  RtpPacketToSend::ExtensionManager send_extensions;
+  send_extensions.Register(kRtpExtensionVideoTiming, kVideoTimingExtensionId);
+  RtpPacketToSend send_packet(&send_extensions);
+  send_packet.SetPayloadType(kPayloadType);
+  send_packet.SetSequenceNumber(kSeqNum);
+  send_packet.SetTimestamp(kTimestamp);
+  send_packet.SetSsrc(kSsrc);
+
+  VideoSendTiming timing;
+  timing.encode_start_delta_ms = 1;
+  timing.encode_finish_delta_ms = 2;
+  timing.packetization_finish_delta_ms = 3;
+  timing.pacer_exit_delta_ms = 4;
+  timing.flags =
+      VideoSendTiming::kTriggeredByTimer | VideoSendTiming::kTriggeredBySize;
+
+  send_packet.SetExtension<VideoTimingExtension>(timing);
+
+  // Serialize the packet and then parse it again.
+  RtpPacketReceived::ExtensionManager extensions;
+  extensions.Register<VideoTimingExtension>(kVideoTimingExtensionId);
+  RtpPacketReceived receive_packet(&extensions);
+  EXPECT_TRUE(receive_packet.Parse(send_packet.Buffer()));
+
+  VideoSendTiming receivied_timing;
+  EXPECT_TRUE(
+      receive_packet.GetExtension<VideoTimingExtension>(&receivied_timing));
+
+  // Only check first and last timestamp (covered by other tests) plus flags.
+  EXPECT_EQ(receivied_timing.encode_start_delta_ms,
+            timing.encode_start_delta_ms);
+  EXPECT_EQ(receivied_timing.pacer_exit_delta_ms, timing.pacer_exit_delta_ms);
+  EXPECT_EQ(receivied_timing.flags, timing.flags);
+}
+
+TEST(RtpPacketTest, ParseLegacyTimingFrameExtension) {
+  // Parse the modified packet.
+  RtpPacketReceived::ExtensionManager extensions;
+  extensions.Register<VideoTimingExtension>(kVideoTimingExtensionId);
+  RtpPacketReceived packet(&extensions);
+  EXPECT_TRUE(packet.Parse(kPacketWithLegacyTimingExtension,
+                           sizeof(kPacketWithLegacyTimingExtension)));
+  VideoSendTiming receivied_timing;
+  EXPECT_TRUE(packet.GetExtension<VideoTimingExtension>(&receivied_timing));
+
+  // Check first and last timestamp are still OK. Flags should now be 0.
+  EXPECT_EQ(receivied_timing.encode_start_delta_ms, 1);
+  EXPECT_EQ(receivied_timing.pacer_exit_delta_ms, 4);
+  EXPECT_EQ(receivied_timing.flags, 0);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_payload_registry.cc b/modules/rtp_rtcp/source/rtp_payload_registry.cc
new file mode 100644
index 0000000..f69940a
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_payload_registry.cc
@@ -0,0 +1,237 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
+
+#include <algorithm>
+
+#include "modules/audio_coding/codecs/audio_format_conversion.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/stringutils.h"
+
+namespace webrtc {
+
+namespace {
+
+bool PayloadIsCompatible(const RtpUtility::Payload& payload,
+                         const SdpAudioFormat& audio_format) {
+  return payload.typeSpecific.is_audio() &&
+         audio_format.Matches(payload.typeSpecific.audio_payload().format);
+}
+
+bool PayloadIsCompatible(const RtpUtility::Payload& payload,
+                         const VideoCodec& video_codec) {
+  if (!payload.typeSpecific.is_video() ||
+      _stricmp(payload.name, CodecTypeToPayloadString(video_codec.codecType)) !=
+          0)
+    return false;
+  // For H264, profiles must match as well.
+  if (video_codec.codecType == kVideoCodecH264) {
+    return video_codec.H264().profile ==
+           payload.typeSpecific.video_payload().h264_profile;
+  }
+  return true;
+}
+
+RtpUtility::Payload CreatePayloadType(const SdpAudioFormat& audio_format) {
+  RTC_DCHECK_GE(audio_format.clockrate_hz, 1000);
+  return {audio_format.name.c_str(),
+          PayloadUnion(AudioPayload{audio_format, 0})};
+}
+
+RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) {
+  switch (type) {
+    case kVideoCodecVP8:
+    case kVideoCodecVP9:
+    case kVideoCodecH264:
+      return type;
+    default:
+      return kVideoCodecGeneric;
+  }
+}
+
+RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
+  VideoPayload p;
+  p.videoCodecType = ConvertToRtpVideoCodecType(video_codec.codecType);
+  if (video_codec.codecType == kVideoCodecH264)
+    p.h264_profile = video_codec.H264().profile;
+  return {CodecTypeToPayloadString(video_codec.codecType), PayloadUnion(p)};
+}
+
+bool IsPayloadTypeValid(int8_t payload_type) {
+  assert(payload_type >= 0);
+
+  // Sanity check.
+  switch (payload_type) {
+    // Reserved payload types to avoid RTCP conflicts when marker bit is set.
+    case 64:  //  192 Full INTRA-frame request.
+    case 72:  //  200 Sender report.
+    case 73:  //  201 Receiver report.
+    case 74:  //  202 Source description.
+    case 75:  //  203 Goodbye.
+    case 76:  //  204 Application-defined.
+    case 77:  //  205 Transport layer FB message.
+    case 78:  //  206 Payload-specific FB message.
+    case 79:  //  207 Extended report.
+      RTC_LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
+                        << payload_type;
+      return false;
+    default:
+      return true;
+  }
+}
+
+}  // namespace
+
+RTPPayloadRegistry::RTPPayloadRegistry() : last_received_payload_type_(-1) {}
+
+RTPPayloadRegistry::~RTPPayloadRegistry() = default;
+
+void RTPPayloadRegistry::SetAudioReceivePayloads(
+    std::map<int, SdpAudioFormat> codecs) {
+  rtc::CritScope cs(&crit_sect_);
+
+#if RTC_DCHECK_IS_ON
+  RTC_DCHECK(!used_for_video_);
+  used_for_audio_ = true;
+#endif
+
+  payload_type_map_.clear();
+  for (const auto& kv : codecs) {
+    const int& rtp_payload_type = kv.first;
+    const SdpAudioFormat& audio_format = kv.second;
+    RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
+    payload_type_map_.emplace(rtp_payload_type,
+                              CreatePayloadType(audio_format));
+  }
+
+  // Clear the value of last received payload type since it might mean
+  // something else now.
+  last_received_payload_type_ = -1;
+}
+
+int32_t RTPPayloadRegistry::RegisterReceivePayload(
+    int payload_type,
+    const SdpAudioFormat& audio_format,
+    bool* created_new_payload) {
+  rtc::CritScope cs(&crit_sect_);
+
+#if RTC_DCHECK_IS_ON
+  RTC_DCHECK(!used_for_video_);
+  used_for_audio_ = true;
+#endif
+
+  *created_new_payload = false;
+  if (!IsPayloadTypeValid(payload_type))
+    return -1;
+
+  const auto it = payload_type_map_.find(payload_type);
+  if (it != payload_type_map_.end()) {
+    // We already use this payload type. Check if it's the same as we already
+    // have. If same, ignore sending an error.
+    if (PayloadIsCompatible(it->second, audio_format)) {
+      it->second.typeSpecific.audio_payload().rate = 0;
+      return 0;
+    }
+    RTC_LOG(LS_ERROR) << "Payload type already registered: " << payload_type;
+    return -1;
+  }
+
+  // Audio codecs must be unique.
+  DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_format);
+
+  const auto insert_status =
+      payload_type_map_.emplace(payload_type, CreatePayloadType(audio_format));
+  RTC_DCHECK(insert_status.second);  // Insertion succeeded.
+  *created_new_payload = true;
+
+  // Successful set of payload type, clear the value of last received payload
+  // type since it might mean something else.
+  last_received_payload_type_ = -1;
+  return 0;
+}
+
+int32_t RTPPayloadRegistry::RegisterReceivePayload(
+    const VideoCodec& video_codec) {
+  rtc::CritScope cs(&crit_sect_);
+
+#if RTC_DCHECK_IS_ON
+  RTC_DCHECK(!used_for_audio_);
+  used_for_video_ = true;
+#endif
+
+  if (!IsPayloadTypeValid(video_codec.plType))
+    return -1;
+
+  auto it = payload_type_map_.find(video_codec.plType);
+  if (it != payload_type_map_.end()) {
+    // We already use this payload type. Check if it's the same as we already
+    // have. If same, ignore sending an error.
+    if (PayloadIsCompatible(it->second, video_codec))
+      return 0;
+    RTC_LOG(LS_ERROR) << "Payload type already registered: "
+                      << static_cast<int>(video_codec.plType);
+    return -1;
+  }
+
+  const auto insert_status = payload_type_map_.emplace(
+      video_codec.plType, CreatePayloadType(video_codec));
+  RTC_DCHECK(insert_status.second);  // Insertion succeeded.
+
+  // Successful set of payload type, clear the value of last received payload
+  // type since it might mean something else.
+  last_received_payload_type_ = -1;
+  return 0;
+}
+
+int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
+    const int8_t payload_type) {
+  rtc::CritScope cs(&crit_sect_);
+  payload_type_map_.erase(payload_type);
+  return 0;
+}
+
+// There can't be several codecs with the same rate, frequency and channels
+// for audio codecs, but there can for video.
+// Always called from within a critical section.
+void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
+    const SdpAudioFormat& audio_format) {
+  for (auto iterator = payload_type_map_.begin();
+       iterator != payload_type_map_.end(); ++iterator) {
+    if (PayloadIsCompatible(iterator->second, audio_format)) {
+      // Remove old setting.
+      payload_type_map_.erase(iterator);
+      break;
+    }
+  }
+}
+
+int RTPPayloadRegistry::GetPayloadTypeFrequency(uint8_t payload_type) const {
+  const auto payload = PayloadTypeToPayload(payload_type);
+  if (!payload) {
+    return -1;
+  }
+  rtc::CritScope cs(&crit_sect_);
+  return payload->typeSpecific.is_audio()
+             ? payload->typeSpecific.audio_payload().format.clockrate_hz
+             : kVideoPayloadTypeFrequency;
+}
+
+absl::optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload(
+    uint8_t payload_type) const {
+  rtc::CritScope cs(&crit_sect_);
+  const auto it = payload_type_map_.find(payload_type);
+  return it == payload_type_map_.end()
+             ? absl::nullopt
+             : absl::optional<RtpUtility::Payload>(it->second);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc b/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc
new file mode 100644
index 0000000..e7362c7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_payload_registry_unittest.cc
@@ -0,0 +1,201 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+
+#include <memory>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+using ::testing::Eq;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::_;
+
+TEST(RtpPayloadRegistryTest,
+     RegistersAndRemembersVideoPayloadsUntilDeregistered) {
+  RTPPayloadRegistry rtp_payload_registry;
+  const uint8_t payload_type = 97;
+  VideoCodec video_codec;
+  video_codec.codecType = kVideoCodecVP8;
+  video_codec.plType = payload_type;
+
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(video_codec));
+
+  const auto retrieved_payload =
+      rtp_payload_registry.PayloadTypeToPayload(payload_type);
+  EXPECT_TRUE(retrieved_payload);
+
+  // We should get back the corresponding payload that we registered.
+  EXPECT_STREQ("VP8", retrieved_payload->name);
+  EXPECT_TRUE(retrieved_payload->typeSpecific.is_video());
+  EXPECT_EQ(kVideoCodecVP8,
+            retrieved_payload->typeSpecific.video_payload().videoCodecType);
+
+  // Now forget about it and verify it's gone.
+  EXPECT_EQ(0, rtp_payload_registry.DeRegisterReceivePayload(payload_type));
+  EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type));
+}
+
+TEST(RtpPayloadRegistryTest,
+     RegistersAndRemembersAudioPayloadsUntilDeregistered) {
+  RTPPayloadRegistry rtp_payload_registry;
+  constexpr int payload_type = 97;
+  const SdpAudioFormat audio_format("name", 44000, 1);
+  bool new_payload_created = false;
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type, audio_format, &new_payload_created));
+
+  EXPECT_TRUE(new_payload_created) << "A new payload WAS created.";
+
+  const auto retrieved_payload =
+      rtp_payload_registry.PayloadTypeToPayload(payload_type);
+  EXPECT_TRUE(retrieved_payload);
+
+  // We should get back the corresponding payload that we registered.
+  EXPECT_STREQ("name", retrieved_payload->name);
+  EXPECT_TRUE(retrieved_payload->typeSpecific.is_audio());
+  EXPECT_EQ(audio_format,
+            retrieved_payload->typeSpecific.audio_payload().format);
+
+  // Now forget about it and verify it's gone.
+  EXPECT_EQ(0, rtp_payload_registry.DeRegisterReceivePayload(payload_type));
+  EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type));
+}
+
+TEST(RtpPayloadRegistryTest,
+     DoesNotAcceptSamePayloadTypeTwiceExceptIfPayloadIsCompatible) {
+  constexpr int payload_type = 97;
+  RTPPayloadRegistry rtp_payload_registry;
+
+  bool ignored = false;
+  const SdpAudioFormat audio_format("name", 44000, 1);
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type, audio_format, &ignored));
+
+  const SdpAudioFormat audio_format_2("name", 44001, 1);  // Not compatible.
+  EXPECT_EQ(-1, rtp_payload_registry.RegisterReceivePayload(
+                    payload_type, audio_format_2, &ignored))
+      << "Adding incompatible codec with same payload type = bad.";
+
+  // Change payload type.
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type - 1, audio_format_2, &ignored))
+      << "With a different payload type is fine though.";
+
+  // Ensure both payloads are preserved.
+  const auto retrieved_payload1 =
+      rtp_payload_registry.PayloadTypeToPayload(payload_type);
+  EXPECT_TRUE(retrieved_payload1);
+  EXPECT_STREQ("name", retrieved_payload1->name);
+  EXPECT_TRUE(retrieved_payload1->typeSpecific.is_audio());
+  EXPECT_EQ(audio_format,
+            retrieved_payload1->typeSpecific.audio_payload().format);
+
+  const auto retrieved_payload2 =
+      rtp_payload_registry.PayloadTypeToPayload(payload_type - 1);
+  EXPECT_TRUE(retrieved_payload2);
+  EXPECT_STREQ("name", retrieved_payload2->name);
+  EXPECT_TRUE(retrieved_payload2->typeSpecific.is_audio());
+  EXPECT_EQ(audio_format_2,
+            retrieved_payload2->typeSpecific.audio_payload().format);
+
+  // Ok, update the rate for one of the codecs. If either the incoming rate or
+  // the stored rate is zero it's not really an error to register the same
+  // codec twice, and in that case roughly the following happens.
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type, audio_format, &ignored));
+}
+
+TEST(RtpPayloadRegistryTest,
+     RemovesCompatibleCodecsOnRegistryIfCodecsMustBeUnique) {
+  constexpr int payload_type = 97;
+  RTPPayloadRegistry rtp_payload_registry;
+
+  bool ignored = false;
+  const SdpAudioFormat audio_format("name", 44000, 1);
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type, audio_format, &ignored));
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type - 1, audio_format, &ignored));
+
+  EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type))
+      << "The first payload should be "
+         "deregistered because the only thing that differs is payload type.";
+  EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type - 1))
+      << "The second payload should still be registered though.";
+
+  // Now ensure non-compatible codecs aren't removed. Make |audio_format_2|
+  // incompatible by changing the frequency.
+  const SdpAudioFormat audio_format_2("name", 44001, 1);
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type + 1, audio_format_2, &ignored));
+
+  EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type - 1))
+      << "Not compatible; both payloads should be kept.";
+  EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type + 1))
+      << "Not compatible; both payloads should be kept.";
+}
+
+TEST(RtpPayloadRegistryTest,
+     LastReceivedCodecTypesAreResetWhenRegisteringNewPayloadTypes) {
+  RTPPayloadRegistry rtp_payload_registry;
+  rtp_payload_registry.set_last_received_payload_type(17);
+  EXPECT_EQ(17, rtp_payload_registry.last_received_payload_type());
+
+  bool ignored;
+  constexpr int payload_type = 34;
+  const SdpAudioFormat audio_format("name", 44000, 1);
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type, audio_format, &ignored));
+
+  EXPECT_EQ(-1, rtp_payload_registry.last_received_payload_type());
+}
+
+class ParameterizedRtpPayloadRegistryTest
+    : public ::testing::TestWithParam<int> {};
+
+TEST_P(ParameterizedRtpPayloadRegistryTest,
+       FailsToRegisterKnownPayloadsWeAreNotInterestedIn) {
+  RTPPayloadRegistry rtp_payload_registry;
+
+  bool ignored;
+  const int payload_type = GetParam();
+  const SdpAudioFormat audio_format("whatever", 1900, 1);
+  EXPECT_EQ(-1, rtp_payload_registry.RegisterReceivePayload(
+                    payload_type, audio_format, &ignored));
+}
+
+INSTANTIATE_TEST_CASE_P(TestKnownBadPayloadTypes,
+                        ParameterizedRtpPayloadRegistryTest,
+                        testing::Values(64, 72, 73, 74, 75, 76, 77, 78, 79));
+
+class RtpPayloadRegistryGenericTest : public ::testing::TestWithParam<int> {};
+
+TEST_P(RtpPayloadRegistryGenericTest, RegisterGenericReceivePayloadType) {
+  RTPPayloadRegistry rtp_payload_registry;
+
+  bool ignored;
+  const int payload_type = GetParam();
+  const SdpAudioFormat audio_format("generic-codec", 1900, 1);  // Dummy values.
+  EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
+                   payload_type, audio_format, &ignored));
+}
+
+INSTANTIATE_TEST_CASE_P(TestDynamicRange,
+                        RtpPayloadRegistryGenericTest,
+                        testing::Range(96, 127 + 1));
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_receiver_audio.cc b/modules/rtp_rtcp/source/rtp_receiver_audio.cc
new file mode 100644
index 0000000..ac57138
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_audio.cc
@@ -0,0 +1,241 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_receiver_audio.h"
+
+#include <assert.h>  // assert
+#include <math.h>    // pow()
+#include <string.h>  // memcpy()
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "rtc_base/logging.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+RTPReceiverStrategy* RTPReceiverStrategy::CreateAudioStrategy(
+    RtpData* data_callback) {
+  return new RTPReceiverAudio(data_callback);
+}
+
+RTPReceiverAudio::RTPReceiverAudio(RtpData* data_callback)
+    : RTPReceiverStrategy(data_callback),
+      TelephoneEventHandler(),
+      telephone_event_forward_to_decoder_(false),
+      telephone_event_payload_type_(-1),
+      cng_nb_payload_type_(-1),
+      cng_wb_payload_type_(-1),
+      cng_swb_payload_type_(-1),
+      cng_fb_payload_type_(-1) {}
+
+RTPReceiverAudio::~RTPReceiverAudio() = default;
+
+// Outband TelephoneEvent(DTMF) detection
+void RTPReceiverAudio::SetTelephoneEventForwardToDecoder(
+    bool forward_to_decoder) {
+  rtc::CritScope lock(&crit_sect_);
+  telephone_event_forward_to_decoder_ = forward_to_decoder;
+}
+
+// Is forwarding of outband telephone events turned on/off?
+bool RTPReceiverAudio::TelephoneEventForwardToDecoder() const {
+  rtc::CritScope lock(&crit_sect_);
+  return telephone_event_forward_to_decoder_;
+}
+
+bool RTPReceiverAudio::TelephoneEventPayloadType(int8_t payload_type) const {
+  rtc::CritScope lock(&crit_sect_);
+  return telephone_event_payload_type_ == payload_type;
+}
+
+TelephoneEventHandler* RTPReceiverAudio::GetTelephoneEventHandler() {
+  return this;
+}
+
+bool RTPReceiverAudio::CNGPayloadType(int8_t payload_type) {
+  rtc::CritScope lock(&crit_sect_);
+  return payload_type == cng_nb_payload_type_ ||
+         payload_type == cng_wb_payload_type_ ||
+         payload_type == cng_swb_payload_type_ ||
+         payload_type == cng_fb_payload_type_;
+}
+
+// -   Sample based or frame based codecs based on RFC 3551
+// -
+// -   NOTE! There is one error in the RFC, stating G.722 uses 8 bits/samples.
+// -   The correct rate is 4 bits/sample.
+// -
+// -   name of                              sampling              default
+// -   encoding  sample/frame  bits/sample      rate  ms/frame  ms/packet
+// -
+// -   Sample based audio codecs
+// -   DVI4      sample        4                var.                   20
+// -   G722      sample        4              16,000                   20
+// -   G726-40   sample        5               8,000                   20
+// -   G726-32   sample        4               8,000                   20
+// -   G726-24   sample        3               8,000                   20
+// -   G726-16   sample        2               8,000                   20
+// -   L8        sample        8                var.                   20
+// -   L16       sample        16               var.                   20
+// -   PCMA      sample        8                var.                   20
+// -   PCMU      sample        8                var.                   20
+// -
+// -   Frame based audio codecs
+// -   G723      frame         N/A             8,000        30         30
+// -   G728      frame         N/A             8,000       2.5         20
+// -   G729      frame         N/A             8,000        10         20
+// -   G729D     frame         N/A             8,000        10         20
+// -   G729E     frame         N/A             8,000        10         20
+// -   GSM       frame         N/A             8,000        20         20
+// -   GSM-EFR   frame         N/A             8,000        20         20
+// -   LPC       frame         N/A             8,000        20         20
+// -   MPA       frame         N/A              var.      var.
+// -
+// -   G7221     frame         N/A
+int32_t RTPReceiverAudio::OnNewPayloadTypeCreated(
+    int payload_type,
+    const SdpAudioFormat& audio_format) {
+  rtc::CritScope lock(&crit_sect_);
+
+  if (RtpUtility::StringCompare(audio_format.name.c_str(), "telephone-event",
+                                15)) {
+    telephone_event_payload_type_ = payload_type;
+  }
+  if (RtpUtility::StringCompare(audio_format.name.c_str(), "cn", 2)) {
+    // We support comfort noise at four different frequencies.
+    if (audio_format.clockrate_hz == 8000) {
+      cng_nb_payload_type_ = payload_type;
+    } else if (audio_format.clockrate_hz == 16000) {
+      cng_wb_payload_type_ = payload_type;
+    } else if (audio_format.clockrate_hz == 32000) {
+      cng_swb_payload_type_ = payload_type;
+    } else if (audio_format.clockrate_hz == 48000) {
+      cng_fb_payload_type_ = payload_type;
+    } else {
+      assert(false);
+      return -1;
+    }
+  }
+  return 0;
+}
+
+int32_t RTPReceiverAudio::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
+                                         const PayloadUnion& specific_payload,
+                                         const uint8_t* payload,
+                                         size_t payload_length,
+                                         int64_t timestamp_ms) {
+  if (first_packet_received_()) {
+    RTC_LOG(LS_INFO) << "Received first audio RTP packet";
+  }
+
+  return ParseAudioCodecSpecific(rtp_header, payload, payload_length,
+                                 specific_payload.audio_payload());
+}
+
+RTPAliveType RTPReceiverAudio::ProcessDeadOrAlive(
+    uint16_t last_payload_length) const {
+  // Our CNG is 9 bytes; if it's a likely CNG the receiver needs to check
+  // kRtpNoRtp against NetEq speech_type kOutputPLCtoCNG.
+  if (last_payload_length < 10) {  // our CNG is 9 bytes
+    return kRtpNoRtp;
+  } else {
+    return kRtpDead;
+  }
+}
+
+void RTPReceiverAudio::CheckPayloadChanged(int8_t payload_type,
+                                           PayloadUnion* /* specific_payload */,
+                                           bool* should_discard_changes) {
+  *should_discard_changes =
+      TelephoneEventPayloadType(payload_type) || CNGPayloadType(payload_type);
+}
+
+// We are not allowed to have any critsects when calling data_callback.
+int32_t RTPReceiverAudio::ParseAudioCodecSpecific(
+    WebRtcRTPHeader* rtp_header,
+    const uint8_t* payload_data,
+    size_t payload_length,
+    const AudioPayload& audio_specific) {
+  RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength);
+  const size_t payload_data_length =
+      payload_length - rtp_header->header.paddingLength;
+  if (payload_data_length == 0) {
+    rtp_header->frameType = kEmptyFrame;
+    return data_callback_->OnReceivedPayloadData(nullptr, 0, rtp_header);
+  }
+
+  bool telephone_event_packet =
+      TelephoneEventPayloadType(rtp_header->header.payloadType);
+  if (telephone_event_packet) {
+    rtc::CritScope lock(&crit_sect_);
+
+    // RFC 4733 2.3
+    // 0                   1                   2                   3
+    // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    // |     event     |E|R| volume    |          duration             |
+    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //
+    if (payload_data_length % 4 != 0) {
+      return -1;
+    }
+    size_t number_of_events = payload_data_length / 4;
+
+    // sanity
+    if (number_of_events >= MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS) {
+      number_of_events = MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS;
+    }
+    for (size_t n = 0; n < number_of_events; ++n) {
+      RTC_DCHECK_GE(payload_data_length, (4 * n) + 2);
+      bool end = (payload_data[(4 * n) + 1] & 0x80) ? true : false;
+
+      std::set<uint8_t>::iterator event =
+          telephone_event_reported_.find(payload_data[4 * n]);
+
+      if (event != telephone_event_reported_.end()) {
+        // we have already seen this event
+        if (end) {
+          telephone_event_reported_.erase(payload_data[4 * n]);
+        }
+      } else {
+        if (end) {
+          // don't add if it's a end of a tone
+        } else {
+          telephone_event_reported_.insert(payload_data[4 * n]);
+        }
+      }
+    }
+
+    // RFC 4733 2.5.1.3 & 2.5.2.3 Long-Duration Events
+    // should not be a problem since we don't care about the duration
+
+    // RFC 4733 See 2.5.1.5. & 2.5.2.4.  Multiple Events in a Packet
+  }
+
+  {
+    rtc::CritScope lock(&crit_sect_);
+
+    // check if it's a DTMF event, hence something we can playout
+    if (telephone_event_packet) {
+      if (!telephone_event_forward_to_decoder_) {
+        // don't forward event to decoder
+        return 0;
+      }
+      std::set<uint8_t>::iterator first = telephone_event_reported_.begin();
+      if (first != telephone_event_reported_.end() && *first > 15) {
+        // don't forward non DTMF events
+        return 0;
+      }
+    }
+  }
+
+  return data_callback_->OnReceivedPayloadData(payload_data,
+                                               payload_data_length, rtp_header);
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_receiver_audio.h b/modules/rtp_rtcp/source/rtp_receiver_audio.h
new file mode 100644
index 0000000..d88acfd
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_audio.h
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_
+
+#include <set>
+
+#include "modules/rtp_rtcp/include/rtp_receiver.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/onetimeevent.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+// Handles audio RTP packets. This class is thread-safe.
+class RTPReceiverAudio : public RTPReceiverStrategy,
+                         public TelephoneEventHandler {
+ public:
+  explicit RTPReceiverAudio(RtpData* data_callback);
+  ~RTPReceiverAudio() override;
+
+  // The following three methods implement the TelephoneEventHandler interface.
+  // Forward DTMFs to decoder for playout.
+  void SetTelephoneEventForwardToDecoder(bool forward_to_decoder) override;
+
+  // Is forwarding of outband telephone events turned on/off?
+  bool TelephoneEventForwardToDecoder() const override;
+
+  // Is TelephoneEvent configured with |payload_type|.
+  bool TelephoneEventPayloadType(const int8_t payload_type) const override;
+
+  TelephoneEventHandler* GetTelephoneEventHandler() override;
+
+  // Returns true if CNG is configured with |payload_type|.
+  bool CNGPayloadType(const int8_t payload_type);
+
+  int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
+                         const PayloadUnion& specific_payload,
+                         const uint8_t* packet,
+                         size_t payload_length,
+                         int64_t timestamp_ms) override;
+
+  RTPAliveType ProcessDeadOrAlive(uint16_t last_payload_length) const override;
+
+  int32_t OnNewPayloadTypeCreated(int payload_type,
+                                  const SdpAudioFormat& audio_format) override;
+
+  // We need to look out for special payload types here and sometimes reset
+  // statistics. In addition we sometimes need to tweak the frequency.
+  void CheckPayloadChanged(int8_t payload_type,
+                           PayloadUnion* specific_payload,
+                           bool* should_discard_changes) override;
+
+ private:
+  int32_t ParseAudioCodecSpecific(WebRtcRTPHeader* rtp_header,
+                                  const uint8_t* payload_data,
+                                  size_t payload_length,
+                                  const AudioPayload& audio_specific);
+
+  bool telephone_event_forward_to_decoder_;
+  int8_t telephone_event_payload_type_;
+  std::set<uint8_t> telephone_event_reported_;
+
+  int8_t cng_nb_payload_type_;
+  int8_t cng_wb_payload_type_;
+  int8_t cng_swb_payload_type_;
+  int8_t cng_fb_payload_type_;
+
+  ThreadUnsafeOneTimeEvent first_packet_received_;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_
diff --git a/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/modules/rtp_rtcp/source/rtp_receiver_impl.cc
new file mode 100644
index 0000000..ac18688
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_impl.cc
@@ -0,0 +1,367 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_receiver_impl.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <set>
+#include <vector>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/audio_coding/codecs/audio_format_conversion.h"
+#include "modules/include/module_common_types.h"
+#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+bool InOrderPacket(absl::optional<uint16_t> latest_sequence_number,
+                   uint16_t current_sequence_number) {
+  if (!latest_sequence_number)
+    return true;
+
+  // We need to distinguish between a late or retransmitted packet,
+  // and a sequence number discontinuity.
+  if (IsNewerSequenceNumber(current_sequence_number, *latest_sequence_number)) {
+    return true;
+  } else {
+    // If we have a restart of the remote side this packet is still in order.
+    return !IsNewerSequenceNumber(
+        current_sequence_number,
+        *latest_sequence_number - kDefaultMaxReorderingThreshold);
+  }
+}
+
+}  // namespace
+
+using RtpUtility::Payload;
+
+// Only return the sources in the last 10 seconds.
+const int64_t kGetSourcesTimeoutMs = 10000;
+
+RtpReceiver* RtpReceiver::CreateVideoReceiver(
+    Clock* clock,
+    RtpData* incoming_payload_callback,
+    RTPPayloadRegistry* rtp_payload_registry) {
+  RTC_DCHECK(incoming_payload_callback != nullptr);
+  return new RtpReceiverImpl(
+      clock, rtp_payload_registry,
+      RTPReceiverStrategy::CreateVideoStrategy(incoming_payload_callback));
+}
+
+RtpReceiver* RtpReceiver::CreateAudioReceiver(
+    Clock* clock,
+    RtpData* incoming_payload_callback,
+    RTPPayloadRegistry* rtp_payload_registry) {
+  RTC_DCHECK(incoming_payload_callback != nullptr);
+  return new RtpReceiverImpl(
+      clock, rtp_payload_registry,
+      RTPReceiverStrategy::CreateAudioStrategy(incoming_payload_callback));
+}
+
+int32_t RtpReceiver::RegisterReceivePayload(const CodecInst& audio_codec) {
+  return RegisterReceivePayload(audio_codec.pltype,
+                                CodecInstToSdp(audio_codec));
+}
+
+RtpReceiverImpl::RtpReceiverImpl(Clock* clock,
+                                 RTPPayloadRegistry* rtp_payload_registry,
+                                 RTPReceiverStrategy* rtp_media_receiver)
+    : clock_(clock),
+      rtp_payload_registry_(rtp_payload_registry),
+      rtp_media_receiver_(rtp_media_receiver),
+      ssrc_(0),
+      num_csrcs_(0),
+      current_remote_csrc_(),
+      last_received_timestamp_(0),
+      last_received_frame_time_ms_(-1) {
+  memset(current_remote_csrc_, 0, sizeof(current_remote_csrc_));
+}
+
+RtpReceiverImpl::~RtpReceiverImpl() {}
+
+int32_t RtpReceiverImpl::RegisterReceivePayload(
+    int payload_type,
+    const SdpAudioFormat& audio_format) {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+
+  // TODO(phoglund): Try to streamline handling of the RED codec and some other
+  // cases which makes it necessary to keep track of whether we created a
+  // payload or not.
+  bool created_new_payload = false;
+  int32_t result = rtp_payload_registry_->RegisterReceivePayload(
+      payload_type, audio_format, &created_new_payload);
+  if (created_new_payload) {
+    if (rtp_media_receiver_->OnNewPayloadTypeCreated(payload_type,
+                                                     audio_format) != 0) {
+      RTC_LOG(LS_ERROR) << "Failed to register payload: " << audio_format.name
+                        << "/" << payload_type;
+      return -1;
+    }
+  }
+  return result;
+}
+
+int32_t RtpReceiverImpl::RegisterReceivePayload(const VideoCodec& video_codec) {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+  return rtp_payload_registry_->RegisterReceivePayload(video_codec);
+}
+
+int32_t RtpReceiverImpl::DeRegisterReceivePayload(const int8_t payload_type) {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+  return rtp_payload_registry_->DeRegisterReceivePayload(payload_type);
+}
+
+uint32_t RtpReceiverImpl::SSRC() const {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+  return ssrc_;
+}
+
+// Get remote CSRC.
+int32_t RtpReceiverImpl::CSRCs(uint32_t array_of_csrcs[kRtpCsrcSize]) const {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+
+  assert(num_csrcs_ <= kRtpCsrcSize);
+
+  if (num_csrcs_ > 0) {
+    memcpy(array_of_csrcs, current_remote_csrc_, sizeof(uint32_t) * num_csrcs_);
+  }
+  return num_csrcs_;
+}
+
+bool RtpReceiverImpl::IncomingRtpPacket(const RTPHeader& rtp_header,
+                                        const uint8_t* payload,
+                                        size_t payload_length,
+                                        PayloadUnion payload_specific) {
+  // Trigger our callbacks.
+  CheckSSRCChanged(rtp_header);
+
+  if (CheckPayloadChanged(rtp_header, &payload_specific) == -1) {
+    if (payload_length == 0) {
+      // OK, keep-alive packet.
+      return true;
+    }
+    RTC_LOG(LS_WARNING) << "Receiving invalid payload type.";
+    return false;
+  }
+
+  WebRtcRTPHeader webrtc_rtp_header{};
+  webrtc_rtp_header.header = rtp_header;
+  CheckCSRC(webrtc_rtp_header);
+
+  auto audio_level =
+      rtp_header.extension.hasAudioLevel
+          ? absl::optional<uint8_t>(rtp_header.extension.audioLevel)
+          : absl::nullopt;
+  UpdateSources(audio_level);
+
+  int32_t ret_val = rtp_media_receiver_->ParseRtpPacket(
+      &webrtc_rtp_header, payload_specific, payload, payload_length,
+      clock_->TimeInMilliseconds());
+
+  if (ret_val < 0) {
+    return false;
+  }
+
+  {
+    rtc::CritScope lock(&critical_section_rtp_receiver_);
+
+    // TODO(nisse): Do not rely on InOrderPacket for recovered packets, when
+    // packet is passed as RtpPacketReceived and that information is available.
+    // We should ideally never record timestamps for retransmitted or recovered
+    // packets.
+    if (InOrderPacket(last_received_sequence_number_,
+                      rtp_header.sequenceNumber)) {
+      last_received_sequence_number_.emplace(rtp_header.sequenceNumber);
+      last_received_timestamp_ = rtp_header.timestamp;
+      last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
+    }
+  }
+
+  return true;
+}
+
+TelephoneEventHandler* RtpReceiverImpl::GetTelephoneEventHandler() {
+  return rtp_media_receiver_->GetTelephoneEventHandler();
+}
+
+std::vector<RtpSource> RtpReceiverImpl::GetSources() const {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  std::vector<RtpSource> sources;
+
+  RTC_DCHECK(std::is_sorted(ssrc_sources_.begin(), ssrc_sources_.end(),
+                            [](const RtpSource& lhs, const RtpSource& rhs) {
+                              return lhs.timestamp_ms() < rhs.timestamp_ms();
+                            }));
+  RTC_DCHECK(std::is_sorted(csrc_sources_.begin(), csrc_sources_.end(),
+                            [](const RtpSource& lhs, const RtpSource& rhs) {
+                              return lhs.timestamp_ms() < rhs.timestamp_ms();
+                            }));
+
+  std::set<uint32_t> selected_ssrcs;
+  for (auto rit = ssrc_sources_.rbegin(); rit != ssrc_sources_.rend(); ++rit) {
+    if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) {
+      break;
+    }
+    if (selected_ssrcs.insert(rit->source_id()).second) {
+      sources.push_back(*rit);
+    }
+  }
+
+  for (auto rit = csrc_sources_.rbegin(); rit != csrc_sources_.rend(); ++rit) {
+    if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) {
+      break;
+    }
+    sources.push_back(*rit);
+  }
+  return sources;
+}
+
+bool RtpReceiverImpl::GetLatestTimestamps(uint32_t* timestamp,
+                                          int64_t* receive_time_ms) const {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+  if (!last_received_sequence_number_)
+    return false;
+
+  *timestamp = last_received_timestamp_;
+  *receive_time_ms = last_received_frame_time_ms_;
+
+  return true;
+}
+
+// TODO(nisse): Delete.
+// Implementation note: must not hold critsect when called.
+void RtpReceiverImpl::CheckSSRCChanged(const RTPHeader& rtp_header) {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+  ssrc_ = rtp_header.ssrc;
+}
+
+// Implementation note: must not hold critsect when called.
+// TODO(phoglund): Move as much as possible of this code path into the media
+// specific receivers. Basically this method goes through a lot of trouble to
+// compute something which is only used by the media specific parts later. If
+// this code path moves we can get rid of some of the rtp_receiver ->
+// media_specific interface (such as CheckPayloadChange, possibly get/set
+// last known payload).
+int32_t RtpReceiverImpl::CheckPayloadChanged(const RTPHeader& rtp_header,
+                                             PayloadUnion* specific_payload) {
+  int8_t payload_type = rtp_header.payloadType;
+
+  {
+    rtc::CritScope lock(&critical_section_rtp_receiver_);
+
+    int8_t last_received_payload_type =
+        rtp_payload_registry_->last_received_payload_type();
+    // TODO(holmer): Remove this code when RED parsing has been broken out from
+    // RtpReceiverAudio.
+    if (payload_type != last_received_payload_type) {
+      bool should_discard_changes = false;
+
+      rtp_media_receiver_->CheckPayloadChanged(payload_type, specific_payload,
+                                               &should_discard_changes);
+
+      if (should_discard_changes) {
+        return 0;
+      }
+
+      const auto payload =
+          rtp_payload_registry_->PayloadTypeToPayload(payload_type);
+      if (!payload) {
+        // Not a registered payload type.
+        return -1;
+      }
+      rtp_payload_registry_->set_last_received_payload_type(payload_type);
+    }
+  }  // End critsect.
+
+  return 0;
+}
+
+// Implementation note: must not hold critsect when called.
+void RtpReceiverImpl::CheckCSRC(const WebRtcRTPHeader& rtp_header) {
+  const uint8_t num_csrcs = rtp_header.header.numCSRCs;
+  if (num_csrcs > kRtpCsrcSize) {
+    // Ignore.
+    return;
+  }
+  {
+    rtc::CritScope lock(&critical_section_rtp_receiver_);
+
+    // Copy new.
+    memcpy(current_remote_csrc_, rtp_header.header.arrOfCSRCs,
+           num_csrcs * sizeof(uint32_t));
+
+    num_csrcs_ = num_csrcs;
+  }  // End critsect.
+}
+
+void RtpReceiverImpl::UpdateSources(
+    const absl::optional<uint8_t>& ssrc_audio_level) {
+  rtc::CritScope lock(&critical_section_rtp_receiver_);
+  int64_t now_ms = clock_->TimeInMilliseconds();
+
+  for (size_t i = 0; i < num_csrcs_; ++i) {
+    auto map_it = iterator_by_csrc_.find(current_remote_csrc_[i]);
+    if (map_it == iterator_by_csrc_.end()) {
+      // If it is a new CSRC, append a new object to the end of the list.
+      csrc_sources_.emplace_back(now_ms, current_remote_csrc_[i],
+                                 RtpSourceType::CSRC);
+    } else {
+      // If it is an existing CSRC, move the object to the end of the list.
+      map_it->second->update_timestamp_ms(now_ms);
+      csrc_sources_.splice(csrc_sources_.end(), csrc_sources_, map_it->second);
+    }
+    // Update the unordered_map.
+    iterator_by_csrc_[current_remote_csrc_[i]] = std::prev(csrc_sources_.end());
+  }
+
+  // If this is the first packet or the SSRC is changed, insert a new
+  // contributing source that uses the SSRC.
+  if (ssrc_sources_.empty() || ssrc_sources_.rbegin()->source_id() != ssrc_) {
+    ssrc_sources_.emplace_back(now_ms, ssrc_, RtpSourceType::SSRC);
+  } else {
+    ssrc_sources_.rbegin()->update_timestamp_ms(now_ms);
+  }
+
+  ssrc_sources_.back().set_audio_level(ssrc_audio_level);
+
+  RemoveOutdatedSources(now_ms);
+}
+
+void RtpReceiverImpl::RemoveOutdatedSources(int64_t now_ms) {
+  std::list<RtpSource>::iterator it;
+  for (it = csrc_sources_.begin(); it != csrc_sources_.end(); ++it) {
+    if ((now_ms - it->timestamp_ms()) <= kGetSourcesTimeoutMs) {
+      break;
+    }
+    iterator_by_csrc_.erase(it->source_id());
+  }
+  csrc_sources_.erase(csrc_sources_.begin(), it);
+
+  std::vector<RtpSource>::iterator vec_it;
+  for (vec_it = ssrc_sources_.begin(); vec_it != ssrc_sources_.end();
+       ++vec_it) {
+    if ((now_ms - vec_it->timestamp_ms()) <= kGetSourcesTimeoutMs) {
+      break;
+    }
+  }
+  ssrc_sources_.erase(ssrc_sources_.begin(), vec_it);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_receiver_impl.h b/modules/rtp_rtcp/source/rtp_receiver_impl.h
new file mode 100644
index 0000000..ec218d3
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_impl.h
@@ -0,0 +1,106 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_
+
+#include <list>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "modules/rtp_rtcp/include/rtp_receiver.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
+#include "rtc_base/criticalsection.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class RtpReceiverImpl : public RtpReceiver {
+ public:
+  // Callbacks passed in here may not be NULL (use Null Object callbacks if you
+  // want callbacks to do nothing). This class takes ownership of the media
+  // receiver but nothing else.
+  RtpReceiverImpl(Clock* clock,
+                  RTPPayloadRegistry* rtp_payload_registry,
+                  RTPReceiverStrategy* rtp_media_receiver);
+
+  ~RtpReceiverImpl() override;
+
+  int32_t RegisterReceivePayload(int payload_type,
+                                 const SdpAudioFormat& audio_format) override;
+  int32_t RegisterReceivePayload(const VideoCodec& video_codec) override;
+
+  int32_t DeRegisterReceivePayload(const int8_t payload_type) override;
+
+  bool IncomingRtpPacket(const RTPHeader& rtp_header,
+                         const uint8_t* payload,
+                         size_t payload_length,
+                         PayloadUnion payload_specific) override;
+
+  bool GetLatestTimestamps(uint32_t* timestamp,
+                           int64_t* receive_time_ms) const override;
+
+  uint32_t SSRC() const override;
+
+  int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const override;
+
+  TelephoneEventHandler* GetTelephoneEventHandler() override;
+
+  std::vector<RtpSource> GetSources() const override;
+
+  const std::vector<RtpSource>& ssrc_sources_for_testing() const {
+    return ssrc_sources_;
+  }
+
+  const std::list<RtpSource>& csrc_sources_for_testing() const {
+    return csrc_sources_;
+  }
+
+ private:
+  void CheckSSRCChanged(const RTPHeader& rtp_header);
+  void CheckCSRC(const WebRtcRTPHeader& rtp_header);
+  int32_t CheckPayloadChanged(const RTPHeader& rtp_header,
+                              PayloadUnion* payload);
+
+  void UpdateSources(const absl::optional<uint8_t>& ssrc_audio_level);
+  void RemoveOutdatedSources(int64_t now_ms);
+
+  Clock* clock_;
+  rtc::CriticalSection critical_section_rtp_receiver_;
+
+  RTPPayloadRegistry* const rtp_payload_registry_
+      RTC_PT_GUARDED_BY(critical_section_rtp_receiver_);
+  const std::unique_ptr<RTPReceiverStrategy> rtp_media_receiver_;
+
+  // SSRCs.
+  uint32_t ssrc_ RTC_GUARDED_BY(critical_section_rtp_receiver_);
+  uint8_t num_csrcs_ RTC_GUARDED_BY(critical_section_rtp_receiver_);
+  uint32_t current_remote_csrc_[kRtpCsrcSize] RTC_GUARDED_BY(
+      critical_section_rtp_receiver_);
+
+  // Sequence number and timestamps for the latest in-order packet.
+  absl::optional<uint16_t> last_received_sequence_number_
+      RTC_GUARDED_BY(critical_section_rtp_receiver_);
+  uint32_t last_received_timestamp_
+      RTC_GUARDED_BY(critical_section_rtp_receiver_);
+  int64_t last_received_frame_time_ms_
+      RTC_GUARDED_BY(critical_section_rtp_receiver_);
+
+  std::unordered_map<uint32_t, std::list<RtpSource>::iterator>
+      iterator_by_csrc_;
+  // The RtpSource objects are sorted chronologically.
+  std::list<RtpSource> csrc_sources_;
+  std::vector<RtpSource> ssrc_sources_;
+};
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_
diff --git a/modules/rtp_rtcp/source/rtp_receiver_strategy.cc b/modules/rtp_rtcp/source/rtp_receiver_strategy.cc
new file mode 100644
index 0000000..bcce3e3
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_strategy.cc
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
+
+#include <stdlib.h>
+
+namespace webrtc {
+
+RTPReceiverStrategy::RTPReceiverStrategy(RtpData* data_callback)
+    : data_callback_(data_callback) {}
+
+RTPReceiverStrategy::~RTPReceiverStrategy() = default;
+
+void RTPReceiverStrategy::CheckPayloadChanged(int8_t payload_type,
+                                              PayloadUnion* specific_payload,
+                                              bool* should_discard_changes) {
+  // Default: Keep changes.
+  *should_discard_changes = false;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_receiver_strategy.h b/modules/rtp_rtcp/source/rtp_receiver_strategy.h
new file mode 100644
index 0000000..8b13f18
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_strategy.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/criticalsection.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+struct CodecInst;
+
+class TelephoneEventHandler;
+
+// This strategy deals with media-specific RTP packet processing.
+// This class is not thread-safe and must be protected by its caller.
+class RTPReceiverStrategy {
+ public:
+  static RTPReceiverStrategy* CreateVideoStrategy(RtpData* data_callback);
+  static RTPReceiverStrategy* CreateAudioStrategy(RtpData* data_callback);
+
+  virtual ~RTPReceiverStrategy();
+
+  // Parses the RTP packet and calls the data callback with the payload data.
+  // Implementations are encouraged to use the provided packet buffer and RTP
+  // header as arguments to the callback; implementations are also allowed to
+  // make changes in the data as necessary. The specific_payload argument
+  // provides audio or video-specific data.
+  virtual int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
+                                 const PayloadUnion& specific_payload,
+                                 const uint8_t* payload,
+                                 size_t payload_length,
+                                 int64_t timestamp_ms) = 0;
+
+  virtual TelephoneEventHandler* GetTelephoneEventHandler() = 0;
+
+  // Computes the current dead-or-alive state.
+  virtual RTPAliveType ProcessDeadOrAlive(
+      uint16_t last_payload_length) const = 0;
+
+  // Notifies the strategy that we have created a new non-RED audio payload type
+  // in the payload registry.
+  virtual int32_t OnNewPayloadTypeCreated(
+      int payload_type,
+      const SdpAudioFormat& audio_format) = 0;
+
+  // Checks if the payload type has changed, and returns whether we should
+  // reset statistics and/or discard this packet.
+  virtual void CheckPayloadChanged(int8_t payload_type,
+                                   PayloadUnion* specific_payload,
+                                   bool* should_discard_changes);
+
+ protected:
+  // The data callback is where we should send received payload data.
+  // See ParseRtpPacket. This class does not claim ownership of the callback.
+  // Implementations must NOT hold any critical sections while calling the
+  // callback.
+  //
+  // Note: Implementations may call the callback for other reasons than calls
+  // to ParseRtpPacket, for instance if the implementation somehow recovers a
+  // packet.
+  explicit RTPReceiverStrategy(RtpData* data_callback);
+
+  rtc::CriticalSection crit_sect_;
+  RtpData* data_callback_;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_
diff --git a/modules/rtp_rtcp/source/rtp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtp_receiver_unittest.cc
new file mode 100644
index 0000000..e8dccf4
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_unittest.cc
@@ -0,0 +1,471 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include <memory>
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
+#include "modules/rtp_rtcp/include/rtp_receiver.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "modules/rtp_rtcp/source/rtp_receiver_impl.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::NiceMock;
+using ::testing::UnorderedElementsAre;
+
+const uint32_t kTestRate = 64000u;
+const uint8_t kTestPayload[] = {'t', 'e', 's', 't'};
+const uint8_t kPcmuPayloadType = 96;
+const int64_t kGetSourcesTimeoutMs = 10000;
+const uint32_t kSsrc1 = 123;
+const uint32_t kSsrc2 = 124;
+const uint32_t kCsrc1 = 111;
+const uint32_t kCsrc2 = 222;
+
+static uint32_t rtp_timestamp(int64_t time_ms) {
+  return static_cast<uint32_t>(time_ms * kTestRate / 1000);
+}
+
+}  // namespace
+
+class RtpReceiverTest : public ::testing::Test {
+ protected:
+  RtpReceiverTest()
+      : fake_clock_(123456),
+        rtp_receiver_(
+            RtpReceiver::CreateAudioReceiver(&fake_clock_,
+                                             &mock_rtp_data_,
+                                             &rtp_payload_registry_)) {
+    rtp_receiver_->RegisterReceivePayload(kPcmuPayloadType,
+                                          SdpAudioFormat("PCMU", 8000, 1));
+  }
+  ~RtpReceiverTest() {}
+
+  bool FindSourceByIdAndType(const std::vector<RtpSource>& sources,
+                             uint32_t source_id,
+                             RtpSourceType type,
+                             RtpSource* source) {
+    for (size_t i = 0; i < sources.size(); ++i) {
+      if (sources[i].source_id() == source_id &&
+          sources[i].source_type() == type) {
+        (*source) = sources[i];
+        return true;
+      }
+    }
+    return false;
+  }
+
+  SimulatedClock fake_clock_;
+  NiceMock<MockRtpData> mock_rtp_data_;
+  RTPPayloadRegistry rtp_payload_registry_;
+  std::unique_ptr<RtpReceiver> rtp_receiver_;
+};
+
+TEST_F(RtpReceiverTest, GetSources) {
+  int64_t now_ms = fake_clock_.TimeInMilliseconds();
+
+  RTPHeader header;
+  header.payloadType = kPcmuPayloadType;
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(now_ms);
+  header.numCSRCs = 2;
+  header.arrOfCSRCs[0] = kCsrc1;
+  header.arrOfCSRCs[1] = kCsrc2;
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  auto sources = rtp_receiver_->GetSources();
+  // One SSRC source and two CSRC sources.
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC),
+                           RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC),
+                           RtpSource(now_ms, kCsrc2, RtpSourceType::CSRC)));
+
+  // Advance the fake clock and the method is expected to return the
+  // contributing source object with same source id and updated timestamp.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  now_ms = fake_clock_.TimeInMilliseconds();
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC),
+                           RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC),
+                           RtpSource(now_ms, kCsrc2, RtpSourceType::CSRC)));
+
+  // Test the edge case that the sources are still there just before the
+  // timeout.
+  int64_t prev_time_ms = fake_clock_.TimeInMilliseconds();
+  fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs);
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources,
+              UnorderedElementsAre(
+                  RtpSource(prev_time_ms, kSsrc1, RtpSourceType::SSRC),
+                  RtpSource(prev_time_ms, kCsrc1, RtpSourceType::CSRC),
+                  RtpSource(prev_time_ms, kCsrc2, RtpSourceType::CSRC)));
+
+  // Time out.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  sources = rtp_receiver_->GetSources();
+  // All the sources should be out of date.
+  ASSERT_EQ(0u, sources.size());
+}
+
+// Test the case that the SSRC is changed.
+TEST_F(RtpReceiverTest, GetSourcesChangeSSRC) {
+  int64_t prev_time_ms = -1;
+  int64_t now_ms = fake_clock_.TimeInMilliseconds();
+
+  RTPHeader header;
+  header.payloadType = kPcmuPayloadType;
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(now_ms);
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  auto sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC)));
+
+  // The SSRC is changed and the old SSRC is expected to be returned.
+  fake_clock_.AdvanceTimeMilliseconds(100);
+  prev_time_ms = now_ms;
+  now_ms = fake_clock_.TimeInMilliseconds();
+  header.ssrc = kSsrc2;
+  header.timestamp = rtp_timestamp(now_ms);
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(prev_time_ms, kSsrc1, RtpSourceType::SSRC),
+                           RtpSource(now_ms, kSsrc2, RtpSourceType::SSRC)));
+
+  // The SSRC is changed again and happen to be changed back to 1. No
+  // duplication is expected.
+  fake_clock_.AdvanceTimeMilliseconds(100);
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(now_ms);
+  prev_time_ms = now_ms;
+  now_ms = fake_clock_.TimeInMilliseconds();
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(prev_time_ms, kSsrc2, RtpSourceType::SSRC),
+                           RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC)));
+
+  // Old SSRC source timeout.
+  fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs);
+  now_ms = fake_clock_.TimeInMilliseconds();
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC)));
+}
+
+TEST_F(RtpReceiverTest, GetSourcesRemoveOutdatedSource) {
+  int64_t now_ms = fake_clock_.TimeInMilliseconds();
+
+  RTPHeader header;
+  header.payloadType = kPcmuPayloadType;
+  header.timestamp = rtp_timestamp(now_ms);
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+  header.numCSRCs = 1;
+  size_t kSourceListSize = 20;
+
+  for (size_t i = 0; i < kSourceListSize; ++i) {
+    header.ssrc = i;
+    header.arrOfCSRCs[0] = (i + 1);
+    EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+        header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  }
+
+  RtpSource source(0, 0, RtpSourceType::SSRC);
+  auto sources = rtp_receiver_->GetSources();
+  // Expect |kSourceListSize| SSRC sources and |kSourceListSize| CSRC sources.
+  ASSERT_EQ(2 * kSourceListSize, sources.size());
+  for (size_t i = 0; i < kSourceListSize; ++i) {
+    // The SSRC source IDs are expected to be 19, 18, 17 ... 0
+    ASSERT_TRUE(
+        FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source));
+    EXPECT_EQ(now_ms, source.timestamp_ms());
+
+    // The CSRC source IDs are expected to be 20, 19, 18 ... 1
+    ASSERT_TRUE(
+        FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source));
+    EXPECT_EQ(now_ms, source.timestamp_ms());
+  }
+
+  fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs);
+  for (size_t i = 0; i < kSourceListSize; ++i) {
+    // The SSRC source IDs are expected to be 19, 18, 17 ... 0
+    ASSERT_TRUE(
+        FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source));
+    EXPECT_EQ(now_ms, source.timestamp_ms());
+
+    // The CSRC source IDs are expected to be 20, 19, 18 ... 1
+    ASSERT_TRUE(
+        FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source));
+    EXPECT_EQ(now_ms, source.timestamp_ms());
+  }
+
+  // Timeout. All the existing objects are out of date and are expected to be
+  // removed.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  header.ssrc = kSsrc1;
+  header.arrOfCSRCs[0] = kCsrc1;
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  auto* rtp_receiver_impl = static_cast<RtpReceiverImpl*>(rtp_receiver_.get());
+  auto ssrc_sources = rtp_receiver_impl->ssrc_sources_for_testing();
+  ASSERT_EQ(1u, ssrc_sources.size());
+  EXPECT_EQ(kSsrc1, ssrc_sources.begin()->source_id());
+  EXPECT_EQ(RtpSourceType::SSRC, ssrc_sources.begin()->source_type());
+  EXPECT_EQ(fake_clock_.TimeInMilliseconds(),
+            ssrc_sources.begin()->timestamp_ms());
+
+  auto csrc_sources = rtp_receiver_impl->csrc_sources_for_testing();
+  ASSERT_EQ(1u, csrc_sources.size());
+  EXPECT_EQ(kCsrc1, csrc_sources.begin()->source_id());
+  EXPECT_EQ(RtpSourceType::CSRC, csrc_sources.begin()->source_type());
+  EXPECT_EQ(fake_clock_.TimeInMilliseconds(),
+            csrc_sources.begin()->timestamp_ms());
+}
+
+// The audio level from the RTPHeader extension should be stored in the
+// RtpSource with the matching SSRC.
+TEST_F(RtpReceiverTest, GetSourcesContainsAudioLevelExtension) {
+  RTPHeader header;
+  int64_t time1_ms = fake_clock_.TimeInMilliseconds();
+  header.payloadType = kPcmuPayloadType;
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(time1_ms);
+  header.extension.hasAudioLevel = true;
+  header.extension.audioLevel = 10;
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  auto sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(RtpSource(
+                           time1_ms, kSsrc1, RtpSourceType::SSRC, 10)));
+
+  // Receive a packet from a different SSRC with a different level and check
+  // that they are both remembered.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  int64_t time2_ms = fake_clock_.TimeInMilliseconds();
+  header.ssrc = kSsrc2;
+  header.timestamp = rtp_timestamp(time2_ms);
+  header.extension.hasAudioLevel = true;
+  header.extension.audioLevel = 20;
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources,
+              UnorderedElementsAre(
+                  RtpSource(time1_ms, kSsrc1, RtpSourceType::SSRC, 10),
+                  RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20)));
+
+  // Receive a packet from the first SSRC again and check that the level is
+  // updated.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  int64_t time3_ms = fake_clock_.TimeInMilliseconds();
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(time3_ms);
+  header.extension.hasAudioLevel = true;
+  header.extension.audioLevel = 30;
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources,
+              UnorderedElementsAre(
+                  RtpSource(time3_ms, kSsrc1, RtpSourceType::SSRC, 30),
+                  RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20)));
+}
+
+TEST_F(RtpReceiverTest,
+       MissingAudioLevelHeaderExtensionClearsRtpSourceAudioLevel) {
+  RTPHeader header;
+  int64_t time1_ms = fake_clock_.TimeInMilliseconds();
+  header.payloadType = kPcmuPayloadType;
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(time1_ms);
+  header.extension.hasAudioLevel = true;
+  header.extension.audioLevel = 10;
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  auto sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(RtpSource(
+                           time1_ms, kSsrc1, RtpSourceType::SSRC, 10)));
+
+  // Receive a second packet without the audio level header extension and check
+  // that the audio level is cleared.
+  fake_clock_.AdvanceTimeMilliseconds(1);
+  int64_t time2_ms = fake_clock_.TimeInMilliseconds();
+  header.timestamp = rtp_timestamp(time2_ms);
+  header.extension.hasAudioLevel = false;
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  sources = rtp_receiver_->GetSources();
+  EXPECT_THAT(sources, UnorderedElementsAre(
+                           RtpSource(time2_ms, kSsrc1, RtpSourceType::SSRC)));
+}
+
+TEST_F(RtpReceiverTest, UpdatesTimestampsIfAndOnlyIfPacketArrivesInOrder) {
+  RTPHeader header;
+  int64_t time1_ms = fake_clock_.TimeInMilliseconds();
+  header.payloadType = kPcmuPayloadType;
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(time1_ms);
+  header.extension.hasAudioLevel = true;
+  header.extension.audioLevel = 10;
+  header.sequenceNumber = 0xfff0;
+
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+  uint32_t latest_timestamp;
+  int64_t latest_receive_time_ms;
+
+  // No packet received yet.
+  EXPECT_FALSE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                  &latest_receive_time_ms));
+  // Initial packet
+  const uint32_t timestamp_1 = header.timestamp;
+  const int64_t receive_time_1 = fake_clock_.TimeInMilliseconds();
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_1);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_1);
+
+  // Late packet, timestamp not recorded.
+  fake_clock_.AdvanceTimeMilliseconds(10);
+  header.timestamp -= 900;
+  header.sequenceNumber -= 2;
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_1);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_1);
+
+  // New packet, still late, no wraparound.
+  fake_clock_.AdvanceTimeMilliseconds(10);
+  header.timestamp += 1800;
+  header.sequenceNumber += 1;
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_1);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_1);
+
+  // New packet, new timestamp recorded
+  fake_clock_.AdvanceTimeMilliseconds(10);
+  header.timestamp += 900;
+  header.sequenceNumber += 2;
+  const uint32_t timestamp_2 = header.timestamp;
+  const int64_t receive_time_2 = fake_clock_.TimeInMilliseconds();
+  const uint16_t seqno_2 = header.sequenceNumber;
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_2);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_2);
+
+  // New packet, timestamp wraps around
+  fake_clock_.AdvanceTimeMilliseconds(10);
+  header.timestamp += 900;
+  header.sequenceNumber += 20;
+  const uint32_t timestamp_3 = header.timestamp;
+  const int64_t receive_time_3 = fake_clock_.TimeInMilliseconds();
+  EXPECT_LT(header.sequenceNumber, seqno_2);  // Wrap-around
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_3);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_3);
+}
+
+TEST_F(RtpReceiverTest, UpdatesTimestampsWhenStreamResets) {
+  RTPHeader header;
+  int64_t time1_ms = fake_clock_.TimeInMilliseconds();
+  header.payloadType = kPcmuPayloadType;
+  header.ssrc = kSsrc1;
+  header.timestamp = rtp_timestamp(time1_ms);
+  header.extension.hasAudioLevel = true;
+  header.extension.audioLevel = 10;
+  header.sequenceNumber = 0xfff0;
+
+  const PayloadUnion payload_specific{
+      AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
+  uint32_t latest_timestamp;
+  int64_t latest_receive_time_ms;
+
+  // No packet received yet.
+  EXPECT_FALSE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                  &latest_receive_time_ms));
+  // Initial packet
+  const uint32_t timestamp_1 = header.timestamp;
+  const int64_t receive_time_1 = fake_clock_.TimeInMilliseconds();
+  const uint16_t seqno_1 = header.sequenceNumber;
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_1);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_1);
+
+  // Packet with far in the past seqno, but unlikely to be a wrap-around.
+  // Treated as a seqno discontinuity, and timestamp is recorded.
+  fake_clock_.AdvanceTimeMilliseconds(10);
+  header.timestamp += 900;
+  header.sequenceNumber = 0x9000;
+
+  const uint32_t timestamp_2 = header.timestamp;
+  const int64_t receive_time_2 = fake_clock_.TimeInMilliseconds();
+  const uint16_t seqno_2 = header.sequenceNumber;
+  EXPECT_LT(seqno_1 - seqno_2, 0x8000);  // In the past.
+
+  EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+      header, kTestPayload, sizeof(kTestPayload), payload_specific));
+  EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
+                                                 &latest_receive_time_ms));
+  EXPECT_EQ(latest_timestamp, timestamp_2);
+  EXPECT_EQ(latest_receive_time_ms, receive_time_2);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_receiver_video.cc b/modules/rtp_rtcp/source/rtp_receiver_video.cc
new file mode 100644
index 0000000..5e6bf3e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_video.cc
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_receiver_video.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <memory>
+
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
+#include "modules/rtp_rtcp/source/rtp_format.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+
+RTPReceiverStrategy* RTPReceiverStrategy::CreateVideoStrategy(
+    RtpData* data_callback) {
+  return new RTPReceiverVideo(data_callback);
+}
+
+RTPReceiverVideo::RTPReceiverVideo(RtpData* data_callback)
+    : RTPReceiverStrategy(data_callback) {}
+
+RTPReceiverVideo::~RTPReceiverVideo() {}
+
+int32_t RTPReceiverVideo::OnNewPayloadTypeCreated(
+    int payload_type,
+    const SdpAudioFormat& audio_format) {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
+                                         const PayloadUnion& specific_payload,
+                                         const uint8_t* payload,
+                                         size_t payload_length,
+                                         int64_t timestamp_ms) {
+  rtp_header->video_header().codec =
+      specific_payload.video_payload().videoCodecType;
+
+  RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength);
+  const size_t payload_data_length =
+      payload_length - rtp_header->header.paddingLength;
+
+  if (payload == NULL || payload_data_length == 0) {
+    return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0
+                                                                           : -1;
+  }
+
+  if (first_packet_received_()) {
+    RTC_LOG(LS_INFO) << "Received first video RTP packet";
+  }
+
+  // We are not allowed to hold a critical section when calling below functions.
+  std::unique_ptr<RtpDepacketizer> depacketizer(
+      RtpDepacketizer::Create(rtp_header->video_header().codec));
+  if (depacketizer.get() == NULL) {
+    RTC_LOG(LS_ERROR) << "Failed to create depacketizer.";
+    return -1;
+  }
+
+  RtpDepacketizer::ParsedPayload parsed_payload;
+  if (!depacketizer->Parse(&parsed_payload, payload, payload_data_length))
+    return -1;
+
+  rtp_header->frameType = parsed_payload.frame_type;
+  rtp_header->video_header() = parsed_payload.video_header();
+  rtp_header->video_header().rotation = kVideoRotation_0;
+  rtp_header->video_header().content_type = VideoContentType::UNSPECIFIED;
+  rtp_header->video_header().video_timing.flags = VideoSendTiming::kInvalid;
+
+  // Retrieve the video rotation information.
+  if (rtp_header->header.extension.hasVideoRotation) {
+    rtp_header->video_header().rotation =
+        rtp_header->header.extension.videoRotation;
+  }
+
+  if (rtp_header->header.extension.hasVideoContentType) {
+    rtp_header->video_header().content_type =
+        rtp_header->header.extension.videoContentType;
+  }
+
+  if (rtp_header->header.extension.has_video_timing) {
+    rtp_header->video_header().video_timing =
+        rtp_header->header.extension.video_timing;
+  }
+
+  rtp_header->video_header().playout_delay =
+      rtp_header->header.extension.playout_delay;
+
+  return data_callback_->OnReceivedPayloadData(parsed_payload.payload,
+                                               parsed_payload.payload_length,
+                                               rtp_header) == 0
+             ? 0
+             : -1;
+}
+
+TelephoneEventHandler* RTPReceiverVideo::GetTelephoneEventHandler() {
+  return nullptr;
+}
+
+RTPAliveType RTPReceiverVideo::ProcessDeadOrAlive(
+    uint16_t last_payload_length) const {
+  return kRtpDead;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_receiver_video.h b/modules/rtp_rtcp/source/rtp_receiver_video.h
new file mode 100644
index 0000000..d9404d1
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_receiver_video.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/onetimeevent.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class RTPReceiverVideo : public RTPReceiverStrategy {
+ public:
+  explicit RTPReceiverVideo(RtpData* data_callback);
+
+  ~RTPReceiverVideo() override;
+
+  int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
+                         const PayloadUnion& specific_payload,
+                         const uint8_t* packet,
+                         size_t packet_length,
+                         int64_t timestamp) override;
+
+  TelephoneEventHandler* GetTelephoneEventHandler() override;
+
+  RTPAliveType ProcessDeadOrAlive(uint16_t last_payload_length) const override;
+
+  int32_t OnNewPayloadTypeCreated(int payload_type,
+                                  const SdpAudioFormat& audio_format) override;
+
+  void SetPacketOverHead(uint16_t packet_over_head);
+
+ private:
+  OneTimeEvent first_packet_received_;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_config.h b/modules/rtp_rtcp/source/rtp_rtcp_config.h
new file mode 100644
index 0000000..a24bcdf
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_rtcp_config.h
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_RTCP_CONFIG_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_RTCP_CONFIG_H_
+
+// Configuration file for RTP utilities (RTPSender, RTPReceiver ...)
+namespace webrtc {
+enum { NACK_BYTECOUNT_SIZE = 60 };  // size of our NACK history
+// A sanity for the NACK list parsing at the send-side.
+enum { kSendSideNackListSizeSanity = 20000 };
+enum { kDefaultMaxReorderingThreshold = 50 };  // In sequence numbers.
+enum { kRtcpMaxNackFields = 253 };
+
+enum { RTCP_SEND_BEFORE_KEY_FRAME_MS = 100 };
+enum { RTCP_MAX_REPORT_BLOCKS = 31 };  // RFC 3550 page 37
+enum {
+  kRtcpAppCode_DATA_SIZE = 32 * 4
+};  // multiple of 4, this is not a limitation of the size
+enum { RTCP_NUMBER_OF_SR = 60 };
+
+enum { MAX_NUMBER_OF_TEMPORAL_ID = 8 };              // RFC
+enum { MAX_NUMBER_OF_DEPENDENCY_QUALITY_ID = 128 };  // RFC
+enum { MAX_NUMBER_OF_REMB_FEEDBACK_SSRCS = 255 };
+
+enum { BW_HISTORY_SIZE = 35 };
+
+#define MIN_AUDIO_BW_MANAGEMENT_BITRATE 6
+#define MIN_VIDEO_BW_MANAGEMENT_BITRATE 30
+
+enum { RTP_MAX_BURST_SLEEP_TIME = 500 };
+enum { RTP_AUDIO_LEVEL_UNIQUE_ID = 0xbede };
+enum { RTP_MAX_PACKETS_PER_FRAME = 512 };  // must be multiple of 32
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_RTCP_CONFIG_H_
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
new file mode 100644
index 0000000..fe8dbf3
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -0,0 +1,919 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <set>
+#include <string>
+
+#include "api/rtpparameters.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+#ifdef _WIN32
+// Disable warning C4355: 'this' : used in base member initializer list.
+#pragma warning(disable : 4355)
+#endif
+
+namespace webrtc {
+namespace {
+const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5;
+const int64_t kRtpRtcpRttProcessTimeMs = 1000;
+const int64_t kRtpRtcpBitrateProcessTimeMs = 10;
+const int64_t kDefaultExpectedRetransmissionTimeMs = 125;
+}  // namespace
+
+RTPExtensionType StringToRtpExtensionType(const std::string& extension) {
+  if (extension == RtpExtension::kTimestampOffsetUri)
+    return kRtpExtensionTransmissionTimeOffset;
+  if (extension == RtpExtension::kAudioLevelUri)
+    return kRtpExtensionAudioLevel;
+  if (extension == RtpExtension::kAbsSendTimeUri)
+    return kRtpExtensionAbsoluteSendTime;
+  if (extension == RtpExtension::kVideoRotationUri)
+    return kRtpExtensionVideoRotation;
+  if (extension == RtpExtension::kTransportSequenceNumberUri)
+    return kRtpExtensionTransportSequenceNumber;
+  if (extension == RtpExtension::kPlayoutDelayUri)
+    return kRtpExtensionPlayoutDelay;
+  if (extension == RtpExtension::kVideoContentTypeUri)
+    return kRtpExtensionVideoContentType;
+  if (extension == RtpExtension::kVideoTimingUri)
+    return kRtpExtensionVideoTiming;
+  if (extension == RtpExtension::kMidUri)
+    return kRtpExtensionMid;
+  RTC_NOTREACHED() << "Looking up unsupported RTP extension.";
+  return kRtpExtensionNone;
+}
+
+RtpRtcp::Configuration::Configuration() = default;
+
+RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
+  if (configuration.clock) {
+    return new ModuleRtpRtcpImpl(configuration);
+  } else {
+    // No clock implementation provided, use default clock.
+    RtpRtcp::Configuration configuration_copy;
+    memcpy(&configuration_copy, &configuration, sizeof(RtpRtcp::Configuration));
+    configuration_copy.clock = Clock::GetRealTimeClock();
+    return new ModuleRtpRtcpImpl(configuration_copy);
+  }
+}
+
+// Deprecated.
+int32_t RtpRtcp::SetFecParameters(const FecProtectionParams* delta_params,
+                                  const FecProtectionParams* key_params) {
+  RTC_DCHECK(delta_params);
+  RTC_DCHECK(key_params);
+  return SetFecParameters(*delta_params, *key_params) ? 0 : -1;
+}
+
+ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
+    : rtcp_sender_(configuration.audio,
+                   configuration.clock,
+                   configuration.receive_statistics,
+                   configuration.rtcp_packet_type_counter_observer,
+                   configuration.event_log,
+                   configuration.outgoing_transport,
+                   configuration.rtcp_interval_config),
+      rtcp_receiver_(configuration.clock,
+                     configuration.receiver_only,
+                     configuration.rtcp_packet_type_counter_observer,
+                     configuration.bandwidth_callback,
+                     configuration.intra_frame_callback,
+                     configuration.transport_feedback_callback,
+                     configuration.bitrate_allocation_observer,
+                     this),
+      clock_(configuration.clock),
+      audio_(configuration.audio),
+      keepalive_config_(configuration.keepalive_config),
+      last_bitrate_process_time_(clock_->TimeInMilliseconds()),
+      last_rtt_process_time_(clock_->TimeInMilliseconds()),
+      next_process_time_(clock_->TimeInMilliseconds() +
+                         kRtpRtcpMaxIdleTimeProcessMs),
+      next_keepalive_time_(-1),
+      packet_overhead_(28),  // IPV4 UDP.
+      nack_last_time_sent_full_(0),
+      nack_last_time_sent_full_prev_(0),
+      nack_last_seq_number_sent_(0),
+      key_frame_req_method_(kKeyFrameReqPliRtcp),
+      remote_bitrate_(configuration.remote_bitrate_estimator),
+      rtt_stats_(configuration.rtt_stats),
+      rtt_ms_(0) {
+  if (!configuration.receiver_only) {
+    rtp_sender_.reset(new RTPSender(
+        configuration.audio, configuration.clock,
+        configuration.outgoing_transport, configuration.paced_sender,
+        configuration.flexfec_sender,
+        configuration.transport_sequence_number_allocator,
+        configuration.transport_feedback_callback,
+        configuration.send_bitrate_observer,
+        configuration.send_frame_count_observer,
+        configuration.send_side_delay_observer, configuration.event_log,
+        configuration.send_packet_observer,
+        configuration.retransmission_rate_limiter,
+        configuration.overhead_observer,
+        configuration.populate_network2_timestamp));
+    // Make sure rtcp sender use same timestamp offset as rtp sender.
+    rtcp_sender_.SetTimestampOffset(rtp_sender_->TimestampOffset());
+
+    if (keepalive_config_.timeout_interval_ms != -1) {
+      next_keepalive_time_ =
+          clock_->TimeInMilliseconds() + keepalive_config_.timeout_interval_ms;
+    }
+  }
+
+  // Set default packet size limit.
+  // TODO(nisse): Kind-of duplicates
+  // webrtc::VideoSendStream::Config::Rtp::kDefaultMaxPacketSize.
+  const size_t kTcpOverIpv4HeaderSize = 40;
+  SetMaxRtpPacketSize(IP_PACKET_SIZE - kTcpOverIpv4HeaderSize);
+}
+
+ModuleRtpRtcpImpl::~ModuleRtpRtcpImpl() = default;
+
+// Returns the number of milliseconds until the module want a worker thread
+// to call Process.
+int64_t ModuleRtpRtcpImpl::TimeUntilNextProcess() {
+  return std::max<int64_t>(0,
+                           next_process_time_ - clock_->TimeInMilliseconds());
+}
+
+// Process any pending tasks such as timeouts (non time critical events).
+void ModuleRtpRtcpImpl::Process() {
+  const int64_t now = clock_->TimeInMilliseconds();
+  next_process_time_ = now + kRtpRtcpMaxIdleTimeProcessMs;
+
+  if (rtp_sender_) {
+    if (now >= last_bitrate_process_time_ + kRtpRtcpBitrateProcessTimeMs) {
+      rtp_sender_->ProcessBitrate();
+      last_bitrate_process_time_ = now;
+      next_process_time_ =
+          std::min(next_process_time_, now + kRtpRtcpBitrateProcessTimeMs);
+    }
+    if (keepalive_config_.timeout_interval_ms > 0 &&
+        now >= next_keepalive_time_) {
+      int64_t last_send_time_ms = rtp_sender_->LastTimestampTimeMs();
+      // If no packet has been sent, |last_send_time_ms| will be 0, and so the
+      // keep-alive will be triggered as expected.
+      if (now >= last_send_time_ms + keepalive_config_.timeout_interval_ms) {
+        rtp_sender_->SendKeepAlive(keepalive_config_.payload_type);
+        next_keepalive_time_ = now + keepalive_config_.timeout_interval_ms;
+      } else {
+        next_keepalive_time_ =
+            last_send_time_ms + keepalive_config_.timeout_interval_ms;
+      }
+      next_process_time_ = std::min(next_process_time_, next_keepalive_time_);
+    }
+  }
+
+  bool process_rtt = now >= last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs;
+  if (rtcp_sender_.Sending()) {
+    // Process RTT if we have received a report block and we haven't
+    // processed RTT for at least |kRtpRtcpRttProcessTimeMs| milliseconds.
+    if (rtcp_receiver_.LastReceivedReportBlockMs() > last_rtt_process_time_ &&
+        process_rtt) {
+      std::vector<RTCPReportBlock> receive_blocks;
+      rtcp_receiver_.StatisticsReceived(&receive_blocks);
+      int64_t max_rtt = 0;
+      for (std::vector<RTCPReportBlock>::iterator it = receive_blocks.begin();
+           it != receive_blocks.end(); ++it) {
+        int64_t rtt = 0;
+        rtcp_receiver_.RTT(it->sender_ssrc, &rtt, NULL, NULL, NULL);
+        max_rtt = (rtt > max_rtt) ? rtt : max_rtt;
+      }
+      // Report the rtt.
+      if (rtt_stats_ && max_rtt != 0)
+        rtt_stats_->OnRttUpdate(max_rtt);
+    }
+
+    // Verify receiver reports are delivered and the reported sequence number
+    // is increasing.
+    int64_t rtcp_interval = RtcpReportInterval();
+    if (rtcp_receiver_.RtcpRrTimeout(rtcp_interval)) {
+      RTC_LOG_F(LS_WARNING) << "Timeout: No RTCP RR received.";
+    } else if (rtcp_receiver_.RtcpRrSequenceNumberTimeout(rtcp_interval)) {
+      RTC_LOG_F(LS_WARNING) << "Timeout: No increase in RTCP RR extended "
+                               "highest sequence number.";
+    }
+
+    if (remote_bitrate_ && rtcp_sender_.TMMBR()) {
+      unsigned int target_bitrate = 0;
+      std::vector<unsigned int> ssrcs;
+      if (remote_bitrate_->LatestEstimate(&ssrcs, &target_bitrate)) {
+        if (!ssrcs.empty()) {
+          target_bitrate = target_bitrate / ssrcs.size();
+        }
+        rtcp_sender_.SetTargetBitrate(target_bitrate);
+      }
+    }
+  } else {
+    // Report rtt from receiver.
+    if (process_rtt) {
+      int64_t rtt_ms;
+      if (rtt_stats_ && rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)) {
+        rtt_stats_->OnRttUpdate(rtt_ms);
+      }
+    }
+  }
+
+  // Get processed rtt.
+  if (process_rtt) {
+    last_rtt_process_time_ = now;
+    next_process_time_ = std::min(
+        next_process_time_, last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs);
+    if (rtt_stats_) {
+      // Make sure we have a valid RTT before setting.
+      int64_t last_rtt = rtt_stats_->LastProcessedRtt();
+      if (last_rtt >= 0)
+        set_rtt_ms(last_rtt);
+    }
+  }
+
+  if (rtcp_sender_.TimeToSendRTCPReport())
+    rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);
+
+  if (TMMBR() && rtcp_receiver_.UpdateTmmbrTimers()) {
+    rtcp_receiver_.NotifyTmmbrUpdated();
+  }
+}
+
+void ModuleRtpRtcpImpl::SetRtxSendStatus(int mode) {
+  rtp_sender_->SetRtxStatus(mode);
+}
+
+int ModuleRtpRtcpImpl::RtxSendStatus() const {
+  return rtp_sender_ ? rtp_sender_->RtxStatus() : kRtxOff;
+}
+
+void ModuleRtpRtcpImpl::SetRtxSsrc(uint32_t ssrc) {
+  rtp_sender_->SetRtxSsrc(ssrc);
+}
+
+void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type,
+                                              int associated_payload_type) {
+  rtp_sender_->SetRtxPayloadType(payload_type, associated_payload_type);
+}
+
+absl::optional<uint32_t> ModuleRtpRtcpImpl::FlexfecSsrc() const {
+  if (rtp_sender_)
+    return rtp_sender_->FlexfecSsrc();
+  return absl::nullopt;
+}
+
+void ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet,
+                                           const size_t length) {
+  rtcp_receiver_.IncomingPacket(rtcp_packet, length);
+}
+
+int32_t ModuleRtpRtcpImpl::RegisterSendPayload(const CodecInst& voice_codec) {
+  return rtp_sender_->RegisterPayload(
+      voice_codec.plname, voice_codec.pltype, voice_codec.plfreq,
+      voice_codec.channels, (voice_codec.rate < 0) ? 0 : voice_codec.rate);
+}
+
+void ModuleRtpRtcpImpl::RegisterVideoSendPayload(int payload_type,
+                                                 const char* payload_name) {
+  RTC_CHECK_EQ(
+      0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, 0, 0));
+}
+
+int32_t ModuleRtpRtcpImpl::DeRegisterSendPayload(const int8_t payload_type) {
+  return rtp_sender_->DeRegisterSendPayload(payload_type);
+}
+
+uint32_t ModuleRtpRtcpImpl::StartTimestamp() const {
+  return rtp_sender_->TimestampOffset();
+}
+
+// Configure start timestamp, default is a random number.
+void ModuleRtpRtcpImpl::SetStartTimestamp(const uint32_t timestamp) {
+  rtcp_sender_.SetTimestampOffset(timestamp);
+  rtp_sender_->SetTimestampOffset(timestamp);
+}
+
+uint16_t ModuleRtpRtcpImpl::SequenceNumber() const {
+  return rtp_sender_->SequenceNumber();
+}
+
+// Set SequenceNumber, default is a random number.
+void ModuleRtpRtcpImpl::SetSequenceNumber(const uint16_t seq_num) {
+  rtp_sender_->SetSequenceNumber(seq_num);
+}
+
+void ModuleRtpRtcpImpl::SetRtpState(const RtpState& rtp_state) {
+  rtp_sender_->SetRtpState(rtp_state);
+  rtcp_sender_.SetTimestampOffset(rtp_state.start_timestamp);
+}
+
+void ModuleRtpRtcpImpl::SetRtxState(const RtpState& rtp_state) {
+  rtp_sender_->SetRtxRtpState(rtp_state);
+}
+
+RtpState ModuleRtpRtcpImpl::GetRtpState() const {
+  return rtp_sender_->GetRtpState();
+}
+
+RtpState ModuleRtpRtcpImpl::GetRtxState() const {
+  return rtp_sender_->GetRtxRtpState();
+}
+
+uint32_t ModuleRtpRtcpImpl::SSRC() const {
+  return rtcp_sender_.SSRC();
+}
+
+void ModuleRtpRtcpImpl::SetSSRC(const uint32_t ssrc) {
+  if (rtp_sender_) {
+    rtp_sender_->SetSSRC(ssrc);
+  }
+  rtcp_sender_.SetSSRC(ssrc);
+  SetRtcpReceiverSsrcs(ssrc);
+}
+
+void ModuleRtpRtcpImpl::SetMid(const std::string& mid) {
+  if (rtp_sender_) {
+    rtp_sender_->SetMid(mid);
+  }
+  // TODO(bugs.webrtc.org/4050): If we end up supporting the MID SDES item for
+  // RTCP, this will need to be passed down to the RTCPSender also.
+}
+
+void ModuleRtpRtcpImpl::SetCsrcs(const std::vector<uint32_t>& csrcs) {
+  rtcp_sender_.SetCsrcs(csrcs);
+  rtp_sender_->SetCsrcs(csrcs);
+}
+
+// TODO(pbos): Handle media and RTX streams separately (separate RTCP
+// feedbacks).
+RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() {
+  RTCPSender::FeedbackState state;
+  // This is called also when receiver_only is true. Hence below
+  // checks that rtp_sender_ exists.
+  if (rtp_sender_) {
+    StreamDataCounters rtp_stats;
+    StreamDataCounters rtx_stats;
+    rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats);
+    state.packets_sent =
+        rtp_stats.transmitted.packets + rtx_stats.transmitted.packets;
+    state.media_bytes_sent = rtp_stats.transmitted.payload_bytes +
+                             rtx_stats.transmitted.payload_bytes;
+    state.send_bitrate = rtp_sender_->BitrateSent();
+  }
+  state.module = this;
+
+  LastReceivedNTP(&state.last_rr_ntp_secs, &state.last_rr_ntp_frac,
+                  &state.remote_sr);
+
+  state.last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
+
+  return state;
+}
+
+// TODO(nisse): This method shouldn't be called for a receive-only
+// stream. Delete rtp_sender_ check as soon as all applications are
+// updated.
+int32_t ModuleRtpRtcpImpl::SetSendingStatus(const bool sending) {
+  if (rtcp_sender_.Sending() != sending) {
+    // Sends RTCP BYE when going from true to false
+    if (rtcp_sender_.SetSendingStatus(GetFeedbackState(), sending) != 0) {
+      RTC_LOG(LS_WARNING) << "Failed to send RTCP BYE";
+    }
+    if (sending && rtp_sender_) {
+      // Update Rtcp receiver config, to track Rtx config changes from
+      // the SetRtxStatus and SetRtxSsrc methods.
+      SetRtcpReceiverSsrcs(rtp_sender_->SSRC());
+    }
+  }
+  return 0;
+}
+
+bool ModuleRtpRtcpImpl::Sending() const {
+  return rtcp_sender_.Sending();
+}
+
+// TODO(nisse): This method shouldn't be called for a receive-only
+// stream. Delete rtp_sender_ check as soon as all applications are
+// updated.
+void ModuleRtpRtcpImpl::SetSendingMediaStatus(const bool sending) {
+  if (rtp_sender_) {
+    rtp_sender_->SetSendingMediaStatus(sending);
+  } else {
+    RTC_DCHECK(!sending);
+  }
+}
+
+bool ModuleRtpRtcpImpl::SendingMedia() const {
+  return rtp_sender_ ? rtp_sender_->SendingMedia() : false;
+}
+
+bool ModuleRtpRtcpImpl::SendOutgoingData(
+    FrameType frame_type,
+    int8_t payload_type,
+    uint32_t time_stamp,
+    int64_t capture_time_ms,
+    const uint8_t* payload_data,
+    size_t payload_size,
+    const RTPFragmentationHeader* fragmentation,
+    const RTPVideoHeader* rtp_video_header,
+    uint32_t* transport_frame_id_out) {
+  rtcp_sender_.SetLastRtpTime(time_stamp, capture_time_ms);
+  // Make sure an RTCP report isn't queued behind a key frame.
+  if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) {
+    rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);
+  }
+  int64_t expected_retransmission_time_ms = rtt_ms();
+  if (expected_retransmission_time_ms == 0) {
+    // No rtt available (|kRtpRtcpRttProcessTimeMs| not yet passed?), so try to
+    // poll avg_rtt_ms directly from rtcp receiver.
+    if (rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), nullptr,
+                           &expected_retransmission_time_ms, nullptr,
+                           nullptr) == -1) {
+      expected_retransmission_time_ms = kDefaultExpectedRetransmissionTimeMs;
+    }
+  }
+  return rtp_sender_->SendOutgoingData(
+      frame_type, payload_type, time_stamp, capture_time_ms, payload_data,
+      payload_size, fragmentation, rtp_video_header, transport_frame_id_out,
+      expected_retransmission_time_ms);
+}
+
+bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
+                                         uint16_t sequence_number,
+                                         int64_t capture_time_ms,
+                                         bool retransmission,
+                                         const PacedPacketInfo& pacing_info) {
+  return rtp_sender_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms,
+                                       retransmission, pacing_info);
+}
+
+size_t ModuleRtpRtcpImpl::TimeToSendPadding(
+    size_t bytes,
+    const PacedPacketInfo& pacing_info) {
+  return rtp_sender_->TimeToSendPadding(bytes, pacing_info);
+}
+
+size_t ModuleRtpRtcpImpl::MaxRtpPacketSize() const {
+  return rtp_sender_->MaxRtpPacketSize();
+}
+
+void ModuleRtpRtcpImpl::SetMaxRtpPacketSize(size_t rtp_packet_size) {
+  RTC_DCHECK_LE(rtp_packet_size, IP_PACKET_SIZE)
+      << "rtp packet size too large: " << rtp_packet_size;
+  RTC_DCHECK_GT(rtp_packet_size, packet_overhead_)
+      << "rtp packet size too small: " << rtp_packet_size;
+
+  rtcp_sender_.SetMaxRtpPacketSize(rtp_packet_size);
+  if (rtp_sender_)
+    rtp_sender_->SetMaxRtpPacketSize(rtp_packet_size);
+}
+
+RtcpMode ModuleRtpRtcpImpl::RTCP() const {
+  return rtcp_sender_.Status();
+}
+
+// Configure RTCP status i.e on/off.
+void ModuleRtpRtcpImpl::SetRTCPStatus(const RtcpMode method) {
+  rtcp_sender_.SetRTCPStatus(method);
+}
+
+int32_t ModuleRtpRtcpImpl::SetCNAME(const char* c_name) {
+  return rtcp_sender_.SetCNAME(c_name);
+}
+
+int32_t ModuleRtpRtcpImpl::AddMixedCNAME(uint32_t ssrc, const char* c_name) {
+  return rtcp_sender_.AddMixedCNAME(ssrc, c_name);
+}
+
+int32_t ModuleRtpRtcpImpl::RemoveMixedCNAME(const uint32_t ssrc) {
+  return rtcp_sender_.RemoveMixedCNAME(ssrc);
+}
+
+int32_t ModuleRtpRtcpImpl::RemoteCNAME(const uint32_t remote_ssrc,
+                                       char c_name[RTCP_CNAME_SIZE]) const {
+  return rtcp_receiver_.CNAME(remote_ssrc, c_name);
+}
+
+int32_t ModuleRtpRtcpImpl::RemoteNTP(uint32_t* received_ntpsecs,
+                                     uint32_t* received_ntpfrac,
+                                     uint32_t* rtcp_arrival_time_secs,
+                                     uint32_t* rtcp_arrival_time_frac,
+                                     uint32_t* rtcp_timestamp) const {
+  return rtcp_receiver_.NTP(received_ntpsecs, received_ntpfrac,
+                            rtcp_arrival_time_secs, rtcp_arrival_time_frac,
+                            rtcp_timestamp)
+             ? 0
+             : -1;
+}
+
+// Get RoundTripTime.
+int32_t ModuleRtpRtcpImpl::RTT(const uint32_t remote_ssrc,
+                               int64_t* rtt,
+                               int64_t* avg_rtt,
+                               int64_t* min_rtt,
+                               int64_t* max_rtt) const {
+  int32_t ret = rtcp_receiver_.RTT(remote_ssrc, rtt, avg_rtt, min_rtt, max_rtt);
+  if (rtt && *rtt == 0) {
+    // Try to get RTT from RtcpRttStats class.
+    *rtt = rtt_ms();
+  }
+  return ret;
+}
+
+// Force a send of an RTCP packet.
+// Normal SR and RR are triggered via the process function.
+int32_t ModuleRtpRtcpImpl::SendRTCP(RTCPPacketType packet_type) {
+  return rtcp_sender_.SendRTCP(GetFeedbackState(), packet_type);
+}
+
+// Force a send of an RTCP packet.
+// Normal SR and RR are triggered via the process function.
+int32_t ModuleRtpRtcpImpl::SendCompoundRTCP(
+    const std::set<RTCPPacketType>& packet_types) {
+  return rtcp_sender_.SendCompoundRTCP(GetFeedbackState(), packet_types);
+}
+
+int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData(
+    const uint8_t sub_type,
+    const uint32_t name,
+    const uint8_t* data,
+    const uint16_t length) {
+  return rtcp_sender_.SetApplicationSpecificData(sub_type, name, data, length);
+}
+
+// (XR) VOIP metric.
+int32_t ModuleRtpRtcpImpl::SetRTCPVoIPMetrics(
+    const RTCPVoIPMetric* voip_metric) {
+  return rtcp_sender_.SetRTCPVoIPMetrics(voip_metric);
+}
+
+void ModuleRtpRtcpImpl::SetRtcpXrRrtrStatus(bool enable) {
+  rtcp_receiver_.SetRtcpXrRrtrStatus(enable);
+  rtcp_sender_.SendRtcpXrReceiverReferenceTime(enable);
+}
+
+bool ModuleRtpRtcpImpl::RtcpXrRrtrStatus() const {
+  return rtcp_sender_.RtcpXrReceiverReferenceTime();
+}
+
+// TODO(asapersson): Replace this method with the one below.
+int32_t ModuleRtpRtcpImpl::DataCountersRTP(size_t* bytes_sent,
+                                           uint32_t* packets_sent) const {
+  StreamDataCounters rtp_stats;
+  StreamDataCounters rtx_stats;
+  rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats);
+
+  if (bytes_sent) {
+    *bytes_sent = rtp_stats.transmitted.payload_bytes +
+                  rtp_stats.transmitted.padding_bytes +
+                  rtp_stats.transmitted.header_bytes +
+                  rtx_stats.transmitted.payload_bytes +
+                  rtx_stats.transmitted.padding_bytes +
+                  rtx_stats.transmitted.header_bytes;
+  }
+  if (packets_sent) {
+    *packets_sent =
+        rtp_stats.transmitted.packets + rtx_stats.transmitted.packets;
+  }
+  return 0;
+}
+
+void ModuleRtpRtcpImpl::GetSendStreamDataCounters(
+    StreamDataCounters* rtp_counters,
+    StreamDataCounters* rtx_counters) const {
+  rtp_sender_->GetDataCounters(rtp_counters, rtx_counters);
+}
+
+void ModuleRtpRtcpImpl::GetRtpPacketLossStats(
+    bool outgoing,
+    uint32_t ssrc,
+    struct RtpPacketLossStats* loss_stats) const {
+  if (!loss_stats)
+    return;
+  const PacketLossStats* stats_source = NULL;
+  if (outgoing) {
+    if (SSRC() == ssrc) {
+      stats_source = &send_loss_stats_;
+    }
+  } else {
+    if (rtcp_receiver_.RemoteSSRC() == ssrc) {
+      stats_source = &receive_loss_stats_;
+    }
+  }
+  if (stats_source) {
+    loss_stats->single_packet_loss_count = stats_source->GetSingleLossCount();
+    loss_stats->multiple_packet_loss_event_count =
+        stats_source->GetMultipleLossEventCount();
+    loss_stats->multiple_packet_loss_packet_count =
+        stats_source->GetMultipleLossPacketCount();
+  }
+}
+
+// Received RTCP report.
+int32_t ModuleRtpRtcpImpl::RemoteRTCPStat(
+    std::vector<RTCPReportBlock>* receive_blocks) const {
+  return rtcp_receiver_.StatisticsReceived(receive_blocks);
+}
+
+// (REMB) Receiver Estimated Max Bitrate.
+void ModuleRtpRtcpImpl::SetRemb(int64_t bitrate_bps,
+                                std::vector<uint32_t> ssrcs) {
+  rtcp_sender_.SetRemb(bitrate_bps, std::move(ssrcs));
+}
+
+void ModuleRtpRtcpImpl::UnsetRemb() {
+  rtcp_sender_.UnsetRemb();
+}
+
+int32_t ModuleRtpRtcpImpl::RegisterSendRtpHeaderExtension(
+    const RTPExtensionType type,
+    const uint8_t id) {
+  return rtp_sender_->RegisterRtpHeaderExtension(type, id);
+}
+
+int32_t ModuleRtpRtcpImpl::DeregisterSendRtpHeaderExtension(
+    const RTPExtensionType type) {
+  return rtp_sender_->DeregisterRtpHeaderExtension(type);
+}
+
+bool ModuleRtpRtcpImpl::HasBweExtensions() const {
+  return rtp_sender_->IsRtpHeaderExtensionRegistered(
+             kRtpExtensionTransportSequenceNumber) ||
+         rtp_sender_->IsRtpHeaderExtensionRegistered(
+             kRtpExtensionAbsoluteSendTime) ||
+         rtp_sender_->IsRtpHeaderExtensionRegistered(
+             kRtpExtensionTransmissionTimeOffset);
+}
+
+// (TMMBR) Temporary Max Media Bit Rate.
+bool ModuleRtpRtcpImpl::TMMBR() const {
+  return rtcp_sender_.TMMBR();
+}
+
+void ModuleRtpRtcpImpl::SetTMMBRStatus(const bool enable) {
+  rtcp_sender_.SetTMMBRStatus(enable);
+}
+
+void ModuleRtpRtcpImpl::SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) {
+  rtcp_sender_.SetTmmbn(std::move(bounding_set));
+}
+
+// Returns the currently configured retransmission mode.
+int ModuleRtpRtcpImpl::SelectiveRetransmissions() const {
+  return rtp_sender_->SelectiveRetransmissions();
+}
+
+// Enable or disable a retransmission mode, which decides which packets will
+// be retransmitted if NACKed.
+int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) {
+  return rtp_sender_->SetSelectiveRetransmissions(settings);
+}
+
+// Send a Negative acknowledgment packet.
+int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
+                                    const uint16_t size) {
+  for (int i = 0; i < size; ++i) {
+    receive_loss_stats_.AddLostPacket(nack_list[i]);
+  }
+  uint16_t nack_length = size;
+  uint16_t start_id = 0;
+  int64_t now = clock_->TimeInMilliseconds();
+  if (TimeToSendFullNackList(now)) {
+    nack_last_time_sent_full_ = now;
+    nack_last_time_sent_full_prev_ = now;
+  } else {
+    // Only send extended list.
+    if (nack_last_seq_number_sent_ == nack_list[size - 1]) {
+      // Last sequence number is the same, do not send list.
+      return 0;
+    }
+    // Send new sequence numbers.
+    for (int i = 0; i < size; ++i) {
+      if (nack_last_seq_number_sent_ == nack_list[i]) {
+        start_id = i + 1;
+        break;
+      }
+    }
+    nack_length = size - start_id;
+  }
+
+  // Our RTCP NACK implementation is limited to kRtcpMaxNackFields sequence
+  // numbers per RTCP packet.
+  if (nack_length > kRtcpMaxNackFields) {
+    nack_length = kRtcpMaxNackFields;
+  }
+  nack_last_seq_number_sent_ = nack_list[start_id + nack_length - 1];
+
+  return rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpNack, nack_length,
+                               &nack_list[start_id]);
+}
+
+void ModuleRtpRtcpImpl::SendNack(
+    const std::vector<uint16_t>& sequence_numbers) {
+  rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpNack, sequence_numbers.size(),
+                        sequence_numbers.data());
+}
+
+bool ModuleRtpRtcpImpl::TimeToSendFullNackList(int64_t now) const {
+  // Use RTT from RtcpRttStats class if provided.
+  int64_t rtt = rtt_ms();
+  if (rtt == 0) {
+    rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL);
+  }
+
+  const int64_t kStartUpRttMs = 100;
+  int64_t wait_time = 5 + ((rtt * 3) >> 1);  // 5 + RTT * 1.5.
+  if (rtt == 0) {
+    wait_time = kStartUpRttMs;
+  }
+
+  // Send a full NACK list once within every |wait_time|.
+  if (rtt_stats_) {
+    return now - nack_last_time_sent_full_ > wait_time;
+  }
+  return now - nack_last_time_sent_full_prev_ > wait_time;
+}
+
+// Store the sent packets, needed to answer to Negative acknowledgment requests.
+void ModuleRtpRtcpImpl::SetStorePacketsStatus(const bool enable,
+                                              const uint16_t number_to_store) {
+  rtp_sender_->SetStorePacketsStatus(enable, number_to_store);
+}
+
+bool ModuleRtpRtcpImpl::StorePackets() const {
+  return rtp_sender_->StorePackets();
+}
+
+void ModuleRtpRtcpImpl::RegisterRtcpStatisticsCallback(
+    RtcpStatisticsCallback* callback) {
+  rtcp_receiver_.RegisterRtcpStatisticsCallback(callback);
+}
+
+RtcpStatisticsCallback* ModuleRtpRtcpImpl::GetRtcpStatisticsCallback() {
+  return rtcp_receiver_.GetRtcpStatisticsCallback();
+}
+
+bool ModuleRtpRtcpImpl::SendFeedbackPacket(
+    const rtcp::TransportFeedback& packet) {
+  return rtcp_sender_.SendFeedbackPacket(packet);
+}
+
+// Send a TelephoneEvent tone using RFC 2833 (4733).
+int32_t ModuleRtpRtcpImpl::SendTelephoneEventOutband(const uint8_t key,
+                                                     const uint16_t time_ms,
+                                                     const uint8_t level) {
+  return rtp_sender_->SendTelephoneEvent(key, time_ms, level);
+}
+
+int32_t ModuleRtpRtcpImpl::SetAudioLevel(const uint8_t level_d_bov) {
+  return rtp_sender_->SetAudioLevel(level_d_bov);
+}
+
+int32_t ModuleRtpRtcpImpl::SetKeyFrameRequestMethod(
+    const KeyFrameRequestMethod method) {
+  key_frame_req_method_ = method;
+  return 0;
+}
+
+int32_t ModuleRtpRtcpImpl::RequestKeyFrame() {
+  switch (key_frame_req_method_) {
+    case kKeyFrameReqPliRtcp:
+      return SendRTCP(kRtcpPli);
+    case kKeyFrameReqFirRtcp:
+      return SendRTCP(kRtcpFir);
+  }
+  return -1;
+}
+
+void ModuleRtpRtcpImpl::SetUlpfecConfig(int red_payload_type,
+                                        int ulpfec_payload_type) {
+  rtp_sender_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
+}
+
+bool ModuleRtpRtcpImpl::SetFecParameters(
+    const FecProtectionParams& delta_params,
+    const FecProtectionParams& key_params) {
+  return rtp_sender_->SetFecParameters(delta_params, key_params);
+}
+
+void ModuleRtpRtcpImpl::SetRemoteSSRC(const uint32_t ssrc) {
+  // Inform about the incoming SSRC.
+  rtcp_sender_.SetRemoteSSRC(ssrc);
+  rtcp_receiver_.SetRemoteSSRC(ssrc);
+}
+
+void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate,
+                                    uint32_t* video_rate,
+                                    uint32_t* fec_rate,
+                                    uint32_t* nack_rate) const {
+  *total_rate = rtp_sender_->BitrateSent();
+  *video_rate = rtp_sender_->VideoBitrateSent();
+  *fec_rate = rtp_sender_->FecOverheadRate();
+  *nack_rate = rtp_sender_->NackOverheadRate();
+}
+
+void ModuleRtpRtcpImpl::OnRequestSendReport() {
+  SendRTCP(kRtcpSr);
+}
+
+void ModuleRtpRtcpImpl::OnReceivedNack(
+    const std::vector<uint16_t>& nack_sequence_numbers) {
+  if (!rtp_sender_)
+    return;
+
+  for (uint16_t nack_sequence_number : nack_sequence_numbers) {
+    send_loss_stats_.AddLostPacket(nack_sequence_number);
+  }
+  if (!rtp_sender_->StorePackets() || nack_sequence_numbers.size() == 0) {
+    return;
+  }
+  // Use RTT from RtcpRttStats class if provided.
+  int64_t rtt = rtt_ms();
+  if (rtt == 0) {
+    rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL);
+  }
+  rtp_sender_->OnReceivedNack(nack_sequence_numbers, rtt);
+}
+
+void ModuleRtpRtcpImpl::OnReceivedRtcpReportBlocks(
+    const ReportBlockList& report_blocks) {
+  if (rtp_sender_)
+    rtp_sender_->OnReceivedRtcpReportBlocks(report_blocks);
+}
+
+bool ModuleRtpRtcpImpl::LastReceivedNTP(
+    uint32_t* rtcp_arrival_time_secs,  // When we got the last report.
+    uint32_t* rtcp_arrival_time_frac,
+    uint32_t* remote_sr) const {
+  // Remote SR: NTP inside the last received (mid 16 bits from sec and frac).
+  uint32_t ntp_secs = 0;
+  uint32_t ntp_frac = 0;
+
+  if (!rtcp_receiver_.NTP(&ntp_secs, &ntp_frac, rtcp_arrival_time_secs,
+                          rtcp_arrival_time_frac, NULL)) {
+    return false;
+  }
+  *remote_sr =
+      ((ntp_secs & 0x0000ffff) << 16) + ((ntp_frac & 0xffff0000) >> 16);
+  return true;
+}
+
+// Called from RTCPsender.
+std::vector<rtcp::TmmbItem> ModuleRtpRtcpImpl::BoundingSet(bool* tmmbr_owner) {
+  return rtcp_receiver_.BoundingSet(tmmbr_owner);
+}
+
+int64_t ModuleRtpRtcpImpl::RtcpReportInterval() {
+  if (audio_)
+    return rtcp_sender_.RtcpAudioReportInverval();
+  else
+    return rtcp_sender_.RtcpVideoReportInverval();
+}
+
+void ModuleRtpRtcpImpl::SetRtcpReceiverSsrcs(uint32_t main_ssrc) {
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(main_ssrc);
+  if (RtxSendStatus() != kRtxOff)
+    ssrcs.insert(rtp_sender_->RtxSsrc());
+  absl::optional<uint32_t> flexfec_ssrc = FlexfecSsrc();
+  if (flexfec_ssrc)
+    ssrcs.insert(*flexfec_ssrc);
+  rtcp_receiver_.SetSsrcs(main_ssrc, ssrcs);
+}
+
+void ModuleRtpRtcpImpl::set_rtt_ms(int64_t rtt_ms) {
+  rtc::CritScope cs(&critical_section_rtt_);
+  rtt_ms_ = rtt_ms;
+  if (rtp_sender_)
+    rtp_sender_->SetRtt(rtt_ms);
+}
+
+int64_t ModuleRtpRtcpImpl::rtt_ms() const {
+  rtc::CritScope cs(&critical_section_rtt_);
+  return rtt_ms_;
+}
+
+void ModuleRtpRtcpImpl::RegisterSendChannelRtpStatisticsCallback(
+    StreamDataCountersCallback* callback) {
+  rtp_sender_->RegisterRtpStatisticsCallback(callback);
+}
+
+StreamDataCountersCallback*
+ModuleRtpRtcpImpl::GetSendChannelRtpStatisticsCallback() const {
+  return rtp_sender_->GetRtpStatisticsCallback();
+}
+
+void ModuleRtpRtcpImpl::SetVideoBitrateAllocation(
+    const VideoBitrateAllocation& bitrate) {
+  rtcp_sender_.SetVideoBitrateAllocation(bitrate);
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
new file mode 100644
index 0000000..9f53416
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -0,0 +1,360 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/video/video_bitrate_allocation.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/packet_loss_stats.h"
+#include "modules/rtp_rtcp/source/rtcp_receiver.h"
+#include "modules/rtp_rtcp/source/rtcp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/gtest_prod_util.h"
+
+namespace webrtc {
+
+class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
+ public:
+  explicit ModuleRtpRtcpImpl(const RtpRtcp::Configuration& configuration);
+  ~ModuleRtpRtcpImpl() override;
+
+  // Returns the number of milliseconds until the module want a worker thread to
+  // call Process.
+  int64_t TimeUntilNextProcess() override;
+
+  // Process any pending tasks such as timeouts.
+  void Process() override;
+
+  // Receiver part.
+
+  // Called when we receive an RTCP packet.
+  void IncomingRtcpPacket(const uint8_t* incoming_packet,
+                          size_t incoming_packet_length) override;
+
+  void SetRemoteSSRC(uint32_t ssrc) override;
+
+  // Sender part.
+
+  int32_t RegisterSendPayload(const CodecInst& voice_codec) override;
+
+  void RegisterVideoSendPayload(int payload_type,
+                                const char* payload_name) override;
+
+  int32_t DeRegisterSendPayload(int8_t payload_type) override;
+
+  // Register RTP header extension.
+  int32_t RegisterSendRtpHeaderExtension(RTPExtensionType type,
+                                         uint8_t id) override;
+
+  int32_t DeregisterSendRtpHeaderExtension(RTPExtensionType type) override;
+
+  bool HasBweExtensions() const override;
+
+  // Get start timestamp.
+  uint32_t StartTimestamp() const override;
+
+  // Configure start timestamp, default is a random number.
+  void SetStartTimestamp(uint32_t timestamp) override;
+
+  uint16_t SequenceNumber() const override;
+
+  // Set SequenceNumber, default is a random number.
+  void SetSequenceNumber(uint16_t seq) override;
+
+  void SetRtpState(const RtpState& rtp_state) override;
+  void SetRtxState(const RtpState& rtp_state) override;
+  RtpState GetRtpState() const override;
+  RtpState GetRtxState() const override;
+
+  uint32_t SSRC() const override;
+
+  // Configure SSRC, default is a random number.
+  void SetSSRC(uint32_t ssrc) override;
+
+  void SetMid(const std::string& mid) override;
+
+  void SetCsrcs(const std::vector<uint32_t>& csrcs) override;
+
+  RTCPSender::FeedbackState GetFeedbackState();
+
+  void SetRtxSendStatus(int mode) override;
+  int RtxSendStatus() const override;
+
+  void SetRtxSsrc(uint32_t ssrc) override;
+
+  void SetRtxSendPayloadType(int payload_type,
+                             int associated_payload_type) override;
+
+  absl::optional<uint32_t> FlexfecSsrc() const override;
+
+  // Sends kRtcpByeCode when going from true to false.
+  int32_t SetSendingStatus(bool sending) override;
+
+  bool Sending() const override;
+
+  // Drops or relays media packets.
+  void SetSendingMediaStatus(bool sending) override;
+
+  bool SendingMedia() const override;
+
+  // Used by the codec module to deliver a video or audio frame for
+  // packetization.
+  bool SendOutgoingData(FrameType frame_type,
+                        int8_t payload_type,
+                        uint32_t time_stamp,
+                        int64_t capture_time_ms,
+                        const uint8_t* payload_data,
+                        size_t payload_size,
+                        const RTPFragmentationHeader* fragmentation,
+                        const RTPVideoHeader* rtp_video_header,
+                        uint32_t* transport_frame_id_out) override;
+
+  bool TimeToSendPacket(uint32_t ssrc,
+                        uint16_t sequence_number,
+                        int64_t capture_time_ms,
+                        bool retransmission,
+                        const PacedPacketInfo& pacing_info) override;
+
+  // Returns the number of padding bytes actually sent, which can be more or
+  // less than |bytes|.
+  size_t TimeToSendPadding(size_t bytes,
+                           const PacedPacketInfo& pacing_info) override;
+
+  // RTCP part.
+
+  // Get RTCP status.
+  RtcpMode RTCP() const override;
+
+  // Configure RTCP status i.e on/off.
+  void SetRTCPStatus(RtcpMode method) override;
+
+  // Set RTCP CName.
+  int32_t SetCNAME(const char* c_name) override;
+
+  // Get remote CName.
+  int32_t RemoteCNAME(uint32_t remote_ssrc,
+                      char c_name[RTCP_CNAME_SIZE]) const override;
+
+  // Get remote NTP.
+  int32_t RemoteNTP(uint32_t* received_ntp_secs,
+                    uint32_t* received_ntp_frac,
+                    uint32_t* rtcp_arrival_time_secs,
+                    uint32_t* rtcp_arrival_time_frac,
+                    uint32_t* rtcp_timestamp) const override;
+
+  int32_t AddMixedCNAME(uint32_t ssrc, const char* c_name) override;
+
+  int32_t RemoveMixedCNAME(uint32_t ssrc) override;
+
+  // Get RoundTripTime.
+  int32_t RTT(uint32_t remote_ssrc,
+              int64_t* rtt,
+              int64_t* avg_rtt,
+              int64_t* min_rtt,
+              int64_t* max_rtt) const override;
+
+  // Force a send of an RTCP packet.
+  // Normal SR and RR are triggered via the process function.
+  int32_t SendRTCP(RTCPPacketType rtcpPacketType) override;
+
+  int32_t SendCompoundRTCP(
+      const std::set<RTCPPacketType>& rtcpPacketTypes) override;
+
+  // Statistics of the amount of data sent and received.
+  int32_t DataCountersRTP(size_t* bytes_sent,
+                          uint32_t* packets_sent) const override;
+
+  void GetSendStreamDataCounters(
+      StreamDataCounters* rtp_counters,
+      StreamDataCounters* rtx_counters) const override;
+
+  void GetRtpPacketLossStats(
+      bool outgoing,
+      uint32_t ssrc,
+      struct RtpPacketLossStats* loss_stats) const override;
+
+  // Get received RTCP report, report block.
+  int32_t RemoteRTCPStat(
+      std::vector<RTCPReportBlock>* receive_blocks) const override;
+
+  // (REMB) Receiver Estimated Max Bitrate.
+  void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) override;
+  void UnsetRemb() override;
+
+  // (TMMBR) Temporary Max Media Bit Rate.
+  bool TMMBR() const override;
+
+  void SetTMMBRStatus(bool enable) override;
+
+  void SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) override;
+
+  size_t MaxRtpPacketSize() const override;
+
+  void SetMaxRtpPacketSize(size_t max_packet_size) override;
+
+  // (NACK) Negative acknowledgment part.
+
+  int SelectiveRetransmissions() const override;
+
+  int SetSelectiveRetransmissions(uint8_t settings) override;
+
+  // Send a Negative acknowledgment packet.
+  // TODO(philipel): Deprecate SendNACK and use SendNack instead.
+  int32_t SendNACK(const uint16_t* nack_list, uint16_t size) override;
+
+  void SendNack(const std::vector<uint16_t>& sequence_numbers) override;
+
+  // Store the sent packets, needed to answer to a negative acknowledgment
+  // requests.
+  void SetStorePacketsStatus(bool enable, uint16_t number_to_store) override;
+
+  bool StorePackets() const override;
+
+  // Called on receipt of RTCP report block from remote side.
+  void RegisterRtcpStatisticsCallback(
+      RtcpStatisticsCallback* callback) override;
+  RtcpStatisticsCallback* GetRtcpStatisticsCallback() override;
+
+  bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override;
+  // (APP) Application specific data.
+  int32_t SetRTCPApplicationSpecificData(uint8_t sub_type,
+                                         uint32_t name,
+                                         const uint8_t* data,
+                                         uint16_t length) override;
+
+  // (XR) VOIP metric.
+  int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) override;
+
+  // (XR) Receiver reference time report.
+  void SetRtcpXrRrtrStatus(bool enable) override;
+
+  bool RtcpXrRrtrStatus() const override;
+
+  // Audio part.
+
+  // Send a TelephoneEvent tone using RFC 2833 (4733).
+  int32_t SendTelephoneEventOutband(uint8_t key,
+                                    uint16_t time_ms,
+                                    uint8_t level) override;
+
+  // Store the audio level in d_bov for header-extension-for-audio-level-
+  // indication.
+  int32_t SetAudioLevel(uint8_t level_d_bov) override;
+
+  // Video part.
+
+  // Set method for requesting a new key frame.
+  int32_t SetKeyFrameRequestMethod(KeyFrameRequestMethod method) override;
+
+  // Send a request for a keyframe.
+  int32_t RequestKeyFrame() override;
+
+  void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) override;
+
+  bool SetFecParameters(const FecProtectionParams& delta_params,
+                        const FecProtectionParams& key_params) override;
+
+  bool LastReceivedNTP(uint32_t* NTPsecs,
+                       uint32_t* NTPfrac,
+                       uint32_t* remote_sr) const;
+
+  std::vector<rtcp::TmmbItem> BoundingSet(bool* tmmbr_owner);
+
+  void BitrateSent(uint32_t* total_rate,
+                   uint32_t* video_rate,
+                   uint32_t* fec_rate,
+                   uint32_t* nackRate) const override;
+
+  void RegisterSendChannelRtpStatisticsCallback(
+      StreamDataCountersCallback* callback) override;
+  StreamDataCountersCallback* GetSendChannelRtpStatisticsCallback()
+      const override;
+
+  void OnReceivedNack(
+      const std::vector<uint16_t>& nack_sequence_numbers) override;
+  void OnReceivedRtcpReportBlocks(
+      const ReportBlockList& report_blocks) override;
+  void OnRequestSendReport() override;
+
+  void SetVideoBitrateAllocation(
+      const VideoBitrateAllocation& bitrate) override;
+
+ protected:
+  bool UpdateRTCPReceiveInformationTimers();
+
+  RTPSender* rtp_sender() { return rtp_sender_.get(); }
+  const RTPSender* rtp_sender() const { return rtp_sender_.get(); }
+
+  RTCPSender* rtcp_sender() { return &rtcp_sender_; }
+  const RTCPSender* rtcp_sender() const { return &rtcp_sender_; }
+
+  RTCPReceiver* rtcp_receiver() { return &rtcp_receiver_; }
+  const RTCPReceiver* rtcp_receiver() const { return &rtcp_receiver_; }
+
+  const Clock* clock() const { return clock_; }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(RtpRtcpImplTest, Rtt);
+  FRIEND_TEST_ALL_PREFIXES(RtpRtcpImplTest, RttForReceiverOnly);
+  int64_t RtcpReportInterval();
+  void SetRtcpReceiverSsrcs(uint32_t main_ssrc);
+
+  void set_rtt_ms(int64_t rtt_ms);
+  int64_t rtt_ms() const;
+
+  bool TimeToSendFullNackList(int64_t now) const;
+
+  std::unique_ptr<RTPSender> rtp_sender_;
+  RTCPSender rtcp_sender_;
+  RTCPReceiver rtcp_receiver_;
+
+  const Clock* const clock_;
+
+  const bool audio_;
+
+  const RtpKeepAliveConfig keepalive_config_;
+  int64_t last_bitrate_process_time_;
+  int64_t last_rtt_process_time_;
+  int64_t next_process_time_;
+  int64_t next_keepalive_time_;
+  uint16_t packet_overhead_;
+
+  // Send side
+  int64_t nack_last_time_sent_full_;
+  uint32_t nack_last_time_sent_full_prev_;
+  uint16_t nack_last_seq_number_sent_;
+
+  KeyFrameRequestMethod key_frame_req_method_;
+
+  RemoteBitrateEstimator* remote_bitrate_;
+
+  RtcpRttStats* const rtt_stats_;
+
+  PacketLossStats send_loss_stats_;
+  PacketLossStats receive_loss_stats_;
+
+  // The processed RTT from RtcpRttStats.
+  rtc::CriticalSection critical_section_rtt_;
+  int64_t rtt_ms_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_RTCP_IMPL_H_
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
new file mode 100644
index 0000000..5071eee
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -0,0 +1,702 @@
+/*
+ *  Copyright (c) 2013 The WebRTC 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.
+ */
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include "api/video_codecs/video_codec.h"
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h"
+#include "rtc_base/rate_limiter.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/rtcp_packet_parser.h"
+
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+namespace webrtc {
+namespace {
+const uint32_t kSenderSsrc = 0x12345;
+const uint32_t kReceiverSsrc = 0x23456;
+const int64_t kOneWayNetworkDelayMs = 100;
+const uint8_t kBaseLayerTid = 0;
+const uint8_t kHigherLayerTid = 1;
+const uint16_t kSequenceNumber = 100;
+const int64_t kMaxRttMs = 1000;
+
+class RtcpRttStatsTestImpl : public RtcpRttStats {
+ public:
+  RtcpRttStatsTestImpl() : rtt_ms_(0) {}
+  ~RtcpRttStatsTestImpl() override = default;
+
+  void OnRttUpdate(int64_t rtt_ms) override { rtt_ms_ = rtt_ms; }
+  int64_t LastProcessedRtt() const override { return rtt_ms_; }
+  int64_t rtt_ms_;
+};
+
+class SendTransport : public Transport, public RtpData {
+ public:
+  SendTransport()
+      : receiver_(nullptr),
+        clock_(nullptr),
+        delay_ms_(0),
+        rtp_packets_sent_(0),
+        rtcp_packets_sent_(0),
+        keepalive_payload_type_(0),
+        num_keepalive_sent_(0) {}
+
+  void SetRtpRtcpModule(ModuleRtpRtcpImpl* receiver) { receiver_ = receiver; }
+  void SimulateNetworkDelay(int64_t delay_ms, SimulatedClock* clock) {
+    clock_ = clock;
+    delay_ms_ = delay_ms;
+  }
+  bool SendRtp(const uint8_t* data,
+               size_t len,
+               const PacketOptions& options) override {
+    RTPHeader header;
+    std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
+    EXPECT_TRUE(parser->Parse(static_cast<const uint8_t*>(data), len, &header));
+    ++rtp_packets_sent_;
+    if (header.payloadType == keepalive_payload_type_)
+      ++num_keepalive_sent_;
+    last_rtp_header_ = header;
+    return true;
+  }
+  bool SendRtcp(const uint8_t* data, size_t len) override {
+    test::RtcpPacketParser parser;
+    parser.Parse(data, len);
+    last_nack_list_ = parser.nack()->packet_ids();
+
+    if (clock_) {
+      clock_->AdvanceTimeMilliseconds(delay_ms_);
+    }
+    EXPECT_TRUE(receiver_);
+    receiver_->IncomingRtcpPacket(data, len);
+    ++rtcp_packets_sent_;
+    return true;
+  }
+  int32_t OnReceivedPayloadData(const uint8_t* payload_data,
+                                size_t payload_size,
+                                const WebRtcRTPHeader* rtp_header) override {
+    return 0;
+  }
+  void SetKeepalivePayloadType(uint8_t payload_type) {
+    keepalive_payload_type_ = payload_type;
+  }
+  size_t NumKeepaliveSent() { return num_keepalive_sent_; }
+  size_t NumRtcpSent() { return rtcp_packets_sent_; }
+  ModuleRtpRtcpImpl* receiver_;
+  SimulatedClock* clock_;
+  int64_t delay_ms_;
+  int rtp_packets_sent_;
+  size_t rtcp_packets_sent_;
+  RTPHeader last_rtp_header_;
+  std::vector<uint16_t> last_nack_list_;
+  uint8_t keepalive_payload_type_;
+  size_t num_keepalive_sent_;
+};
+
+class RtpRtcpModule : public RtcpPacketTypeCounterObserver {
+ public:
+  explicit RtpRtcpModule(SimulatedClock* clock)
+      : receive_statistics_(ReceiveStatistics::Create(clock)),
+        remote_ssrc_(0),
+        retransmission_rate_limiter_(clock, kMaxRttMs),
+        clock_(clock) {
+    CreateModuleImpl();
+    transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock);
+  }
+
+  RtcpPacketTypeCounter packets_sent_;
+  RtcpPacketTypeCounter packets_received_;
+  std::unique_ptr<ReceiveStatistics> receive_statistics_;
+  SendTransport transport_;
+  RtcpRttStatsTestImpl rtt_stats_;
+  std::unique_ptr<ModuleRtpRtcpImpl> impl_;
+  uint32_t remote_ssrc_;
+  RateLimiter retransmission_rate_limiter_;
+  RtpKeepAliveConfig keepalive_config_;
+  RtcpIntervalConfig rtcp_interval_config_;
+
+  void SetRemoteSsrc(uint32_t ssrc) {
+    remote_ssrc_ = ssrc;
+    impl_->SetRemoteSSRC(ssrc);
+  }
+
+  void RtcpPacketTypesCounterUpdated(
+      uint32_t ssrc,
+      const RtcpPacketTypeCounter& packet_counter) override {
+    counter_map_[ssrc] = packet_counter;
+  }
+
+  RtcpPacketTypeCounter RtcpSent() {
+    // RTCP counters for remote SSRC.
+    return counter_map_[remote_ssrc_];
+  }
+
+  RtcpPacketTypeCounter RtcpReceived() {
+    // Received RTCP stats for (own) local SSRC.
+    return counter_map_[impl_->SSRC()];
+  }
+  int RtpSent() { return transport_.rtp_packets_sent_; }
+  uint16_t LastRtpSequenceNumber() {
+    return transport_.last_rtp_header_.sequenceNumber;
+  }
+  std::vector<uint16_t> LastNackListSent() {
+    return transport_.last_nack_list_;
+  }
+  void SetKeepaliveConfigAndReset(const RtpKeepAliveConfig& config) {
+    keepalive_config_ = config;
+    // Need to create a new module impl, since it's configured at creation.
+    CreateModuleImpl();
+    transport_.SetKeepalivePayloadType(config.payload_type);
+  }
+  void SetRtcpIntervalConfigAndReset(const RtcpIntervalConfig& config) {
+    rtcp_interval_config_ = config;
+    CreateModuleImpl();
+  }
+
+ private:
+  void CreateModuleImpl() {
+    RtpRtcp::Configuration config;
+    config.audio = false;
+    config.clock = clock_;
+    config.outgoing_transport = &transport_;
+    config.receive_statistics = receive_statistics_.get();
+    config.rtcp_packet_type_counter_observer = this;
+    config.rtt_stats = &rtt_stats_;
+    config.retransmission_rate_limiter = &retransmission_rate_limiter_;
+    config.keepalive_config = keepalive_config_;
+    config.rtcp_interval_config = rtcp_interval_config_;
+
+    impl_.reset(new ModuleRtpRtcpImpl(config));
+    impl_->SetRTCPStatus(RtcpMode::kCompound);
+  }
+
+  SimulatedClock* const clock_;
+  std::map<uint32_t, RtcpPacketTypeCounter> counter_map_;
+};
+}  // namespace
+
+class RtpRtcpImplTest : public ::testing::Test {
+ protected:
+  RtpRtcpImplTest()
+      : clock_(133590000000000), sender_(&clock_), receiver_(&clock_) {}
+
+  void SetUp() override {
+    // Send module.
+    sender_.impl_->SetSSRC(kSenderSsrc);
+    EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true));
+    sender_.impl_->SetSendingMediaStatus(true);
+    sender_.SetRemoteSsrc(kReceiverSsrc);
+    sender_.impl_->SetSequenceNumber(kSequenceNumber);
+    sender_.impl_->SetStorePacketsStatus(true, 100);
+
+    memset(&codec_, 0, sizeof(VideoCodec));
+    codec_.plType = 100;
+    codec_.width = 320;
+    codec_.height = 180;
+    sender_.impl_->RegisterVideoSendPayload(codec_.plType, "VP8");
+
+    // Receive module.
+    EXPECT_EQ(0, receiver_.impl_->SetSendingStatus(false));
+    receiver_.impl_->SetSendingMediaStatus(false);
+    receiver_.impl_->SetSSRC(kReceiverSsrc);
+    receiver_.SetRemoteSsrc(kSenderSsrc);
+    // Transport settings.
+    sender_.transport_.SetRtpRtcpModule(receiver_.impl_.get());
+    receiver_.transport_.SetRtpRtcpModule(sender_.impl_.get());
+  }
+
+  SimulatedClock clock_;
+  RtpRtcpModule sender_;
+  RtpRtcpModule receiver_;
+  VideoCodec codec_;
+
+  void SendFrame(const RtpRtcpModule* module, uint8_t tid) {
+    RTPVideoHeaderVP8 vp8_header = {};
+    vp8_header.temporalIdx = tid;
+    RTPVideoHeader rtp_video_header;
+    rtp_video_header.width = codec_.width;
+    rtp_video_header.height = codec_.height;
+    rtp_video_header.rotation = kVideoRotation_0;
+    rtp_video_header.content_type = VideoContentType::UNSPECIFIED;
+    rtp_video_header.playout_delay = {-1, -1};
+    rtp_video_header.is_first_packet_in_frame = true;
+    rtp_video_header.simulcastIdx = 0;
+    rtp_video_header.codec = kVideoCodecVP8;
+    rtp_video_header.vp8() = vp8_header;
+    rtp_video_header.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false};
+
+    const uint8_t payload[100] = {0};
+    EXPECT_EQ(true, module->impl_->SendOutgoingData(
+                        kVideoFrameKey, codec_.plType, 0, 0, payload,
+                        sizeof(payload), nullptr, &rtp_video_header, nullptr));
+  }
+
+  void IncomingRtcpNack(const RtpRtcpModule* module, uint16_t sequence_number) {
+    bool sender = module->impl_->SSRC() == kSenderSsrc;
+    rtcp::Nack nack;
+    uint16_t list[1];
+    list[0] = sequence_number;
+    const uint16_t kListLength = sizeof(list) / sizeof(list[0]);
+    nack.SetSenderSsrc(sender ? kReceiverSsrc : kSenderSsrc);
+    nack.SetMediaSsrc(sender ? kSenderSsrc : kReceiverSsrc);
+    nack.SetPacketIds(list, kListLength);
+    rtc::Buffer packet = nack.Build();
+    module->impl_->IncomingRtcpPacket(packet.data(), packet.size());
+  }
+};
+
+TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_BaseLayer) {
+  sender_.impl_->SetSelectiveRetransmissions(kRetransmitBaseLayer);
+  EXPECT_EQ(kRetransmitBaseLayer, sender_.impl_->SelectiveRetransmissions());
+
+  // Send frames.
+  EXPECT_EQ(0, sender_.RtpSent());
+  SendFrame(&sender_, kBaseLayerTid);    // kSequenceNumber
+  SendFrame(&sender_, kHigherLayerTid);  // kSequenceNumber + 1
+  SendFrame(&sender_, kNoTemporalIdx);   // kSequenceNumber + 2
+  EXPECT_EQ(3, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+
+  // Min required delay until retransmit = 5 + RTT ms (RTT = 0).
+  clock_.AdvanceTimeMilliseconds(5);
+
+  // Frame with kBaseLayerTid re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber);
+  EXPECT_EQ(4, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber());
+  // Frame with kHigherLayerTid not re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 1);
+  EXPECT_EQ(4, sender_.RtpSent());
+  // Frame with kNoTemporalIdx re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 2);
+  EXPECT_EQ(5, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+}
+
+TEST_F(RtpRtcpImplTest, SetSelectiveRetransmissions_HigherLayers) {
+  const uint8_t kSetting = kRetransmitBaseLayer + kRetransmitHigherLayers;
+  sender_.impl_->SetSelectiveRetransmissions(kSetting);
+  EXPECT_EQ(kSetting, sender_.impl_->SelectiveRetransmissions());
+
+  // Send frames.
+  EXPECT_EQ(0, sender_.RtpSent());
+  SendFrame(&sender_, kBaseLayerTid);    // kSequenceNumber
+  SendFrame(&sender_, kHigherLayerTid);  // kSequenceNumber + 1
+  SendFrame(&sender_, kNoTemporalIdx);   // kSequenceNumber + 2
+  EXPECT_EQ(3, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+
+  // Min required delay until retransmit = 5 + RTT ms (RTT = 0).
+  clock_.AdvanceTimeMilliseconds(5);
+
+  // Frame with kBaseLayerTid re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber);
+  EXPECT_EQ(4, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber, sender_.LastRtpSequenceNumber());
+  // Frame with kHigherLayerTid re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 1);
+  EXPECT_EQ(5, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 1, sender_.LastRtpSequenceNumber());
+  // Frame with kNoTemporalIdx re-sent.
+  IncomingRtcpNack(&sender_, kSequenceNumber + 2);
+  EXPECT_EQ(6, sender_.RtpSent());
+  EXPECT_EQ(kSequenceNumber + 2, sender_.LastRtpSequenceNumber());
+}
+
+TEST_F(RtpRtcpImplTest, Rtt) {
+  RTPHeader header;
+  header.timestamp = 1;
+  header.sequenceNumber = 123;
+  header.ssrc = kSenderSsrc;
+  header.headerLength = 12;
+  receiver_.receive_statistics_->IncomingPacket(header, 100, false);
+
+  // Send Frame before sending an SR.
+  SendFrame(&sender_, kBaseLayerTid);
+  // Sender module should send an SR.
+  EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport));
+
+  // Receiver module should send a RR with a response to the last received SR.
+  clock_.AdvanceTimeMilliseconds(1000);
+  EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport));
+
+  // Verify RTT.
+  int64_t rtt;
+  int64_t avg_rtt;
+  int64_t min_rtt;
+  int64_t max_rtt;
+  EXPECT_EQ(
+      0, sender_.impl_->RTT(kReceiverSsrc, &rtt, &avg_rtt, &min_rtt, &max_rtt));
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, rtt, 1);
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, avg_rtt, 1);
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, min_rtt, 1);
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, max_rtt, 1);
+
+  // No RTT from other ssrc.
+  EXPECT_EQ(-1, sender_.impl_->RTT(kReceiverSsrc + 1, &rtt, &avg_rtt, &min_rtt,
+                                   &max_rtt));
+
+  // Verify RTT from rtt_stats config.
+  EXPECT_EQ(0, sender_.rtt_stats_.LastProcessedRtt());
+  EXPECT_EQ(0, sender_.impl_->rtt_ms());
+  sender_.impl_->Process();
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, sender_.rtt_stats_.LastProcessedRtt(),
+              1);
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, sender_.impl_->rtt_ms(), 1);
+}
+
+TEST_F(RtpRtcpImplTest, SetRtcpXrRrtrStatus) {
+  EXPECT_FALSE(receiver_.impl_->RtcpXrRrtrStatus());
+  receiver_.impl_->SetRtcpXrRrtrStatus(true);
+  EXPECT_TRUE(receiver_.impl_->RtcpXrRrtrStatus());
+}
+
+TEST_F(RtpRtcpImplTest, RttForReceiverOnly) {
+  receiver_.impl_->SetRtcpXrRrtrStatus(true);
+
+  // Receiver module should send a Receiver time reference report (RTRR).
+  EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpReport));
+
+  // Sender module should send a response to the last received RTRR (DLRR).
+  clock_.AdvanceTimeMilliseconds(1000);
+  // Send Frame before sending a SR.
+  SendFrame(&sender_, kBaseLayerTid);
+  EXPECT_EQ(0, sender_.impl_->SendRTCP(kRtcpReport));
+
+  // Verify RTT.
+  EXPECT_EQ(0, receiver_.rtt_stats_.LastProcessedRtt());
+  EXPECT_EQ(0, receiver_.impl_->rtt_ms());
+  receiver_.impl_->Process();
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs,
+              receiver_.rtt_stats_.LastProcessedRtt(), 1);
+  EXPECT_NEAR(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms(), 1);
+}
+
+TEST_F(RtpRtcpImplTest, NoSrBeforeMedia) {
+  // Ignore fake transport delays in this test.
+  sender_.transport_.SimulateNetworkDelay(0, &clock_);
+  receiver_.transport_.SimulateNetworkDelay(0, &clock_);
+
+  sender_.impl_->Process();
+  EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms);
+
+  // Verify no SR is sent before media has been sent, RR should still be sent
+  // from the receiving module though.
+  clock_.AdvanceTimeMilliseconds(2000);
+  int64_t current_time = clock_.TimeInMilliseconds();
+  sender_.impl_->Process();
+  receiver_.impl_->Process();
+  EXPECT_EQ(-1, sender_.RtcpSent().first_packet_time_ms);
+  EXPECT_EQ(receiver_.RtcpSent().first_packet_time_ms, current_time);
+
+  SendFrame(&sender_, kBaseLayerTid);
+  EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, current_time);
+}
+
+TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_Nack) {
+  EXPECT_EQ(-1, receiver_.RtcpSent().first_packet_time_ms);
+  EXPECT_EQ(-1, sender_.RtcpReceived().first_packet_time_ms);
+  EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets);
+  EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets);
+
+  // Receive module sends a NACK.
+  const uint16_t kNackLength = 1;
+  uint16_t nack_list[kNackLength] = {123};
+  EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets);
+  EXPECT_GT(receiver_.RtcpSent().first_packet_time_ms, -1);
+
+  // Send module receives the NACK.
+  EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets);
+  EXPECT_GT(sender_.RtcpReceived().first_packet_time_ms, -1);
+}
+
+TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) {
+  EXPECT_EQ(0U, sender_.RtcpReceived().fir_packets);
+  EXPECT_EQ(0U, receiver_.RtcpSent().fir_packets);
+  // Receive module sends a FIR.
+  EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir));
+  EXPECT_EQ(1U, receiver_.RtcpSent().fir_packets);
+  // Send module receives the FIR.
+  EXPECT_EQ(1U, sender_.RtcpReceived().fir_packets);
+
+  // Receive module sends a FIR and PLI.
+  std::set<RTCPPacketType> packet_types;
+  packet_types.insert(kRtcpFir);
+  packet_types.insert(kRtcpPli);
+  EXPECT_EQ(0, receiver_.impl_->SendCompoundRTCP(packet_types));
+  EXPECT_EQ(2U, receiver_.RtcpSent().fir_packets);
+  EXPECT_EQ(1U, receiver_.RtcpSent().pli_packets);
+  // Send module receives the FIR and PLI.
+  EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
+  EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets);
+}
+
+TEST_F(RtpRtcpImplTest, AddStreamDataCounters) {
+  StreamDataCounters rtp;
+  const int64_t kStartTimeMs = 1;
+  rtp.first_packet_time_ms = kStartTimeMs;
+  rtp.transmitted.packets = 1;
+  rtp.transmitted.payload_bytes = 1;
+  rtp.transmitted.header_bytes = 2;
+  rtp.transmitted.padding_bytes = 3;
+  EXPECT_EQ(rtp.transmitted.TotalBytes(), rtp.transmitted.payload_bytes +
+                                              rtp.transmitted.header_bytes +
+                                              rtp.transmitted.padding_bytes);
+
+  StreamDataCounters rtp2;
+  rtp2.first_packet_time_ms = -1;
+  rtp2.transmitted.packets = 10;
+  rtp2.transmitted.payload_bytes = 10;
+  rtp2.retransmitted.header_bytes = 4;
+  rtp2.retransmitted.payload_bytes = 5;
+  rtp2.retransmitted.padding_bytes = 6;
+  rtp2.retransmitted.packets = 7;
+  rtp2.fec.packets = 8;
+
+  StreamDataCounters sum = rtp;
+  sum.Add(rtp2);
+  EXPECT_EQ(kStartTimeMs, sum.first_packet_time_ms);
+  EXPECT_EQ(11U, sum.transmitted.packets);
+  EXPECT_EQ(11U, sum.transmitted.payload_bytes);
+  EXPECT_EQ(2U, sum.transmitted.header_bytes);
+  EXPECT_EQ(3U, sum.transmitted.padding_bytes);
+  EXPECT_EQ(4U, sum.retransmitted.header_bytes);
+  EXPECT_EQ(5U, sum.retransmitted.payload_bytes);
+  EXPECT_EQ(6U, sum.retransmitted.padding_bytes);
+  EXPECT_EQ(7U, sum.retransmitted.packets);
+  EXPECT_EQ(8U, sum.fec.packets);
+  EXPECT_EQ(sum.transmitted.TotalBytes(),
+            rtp.transmitted.TotalBytes() + rtp2.transmitted.TotalBytes());
+
+  StreamDataCounters rtp3;
+  rtp3.first_packet_time_ms = kStartTimeMs + 10;
+  sum.Add(rtp3);
+  EXPECT_EQ(kStartTimeMs, sum.first_packet_time_ms);  // Holds oldest time.
+}
+
+TEST_F(RtpRtcpImplTest, SendsInitialNackList) {
+  // Send module sends a NACK.
+  const uint16_t kNackLength = 1;
+  uint16_t nack_list[kNackLength] = {123};
+  EXPECT_EQ(0U, sender_.RtcpSent().nack_packets);
+  // Send Frame before sending a compound RTCP that starts with SR.
+  SendFrame(&sender_, kBaseLayerTid);
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
+  EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123));
+}
+
+TEST_F(RtpRtcpImplTest, SendsExtendedNackList) {
+  // Send module sends a NACK.
+  const uint16_t kNackLength = 1;
+  uint16_t nack_list[kNackLength] = {123};
+  EXPECT_EQ(0U, sender_.RtcpSent().nack_packets);
+  // Send Frame before sending a compound RTCP that starts with SR.
+  SendFrame(&sender_, kBaseLayerTid);
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
+  EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123));
+
+  // Same list not re-send.
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
+  EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123));
+
+  // Only extended list sent.
+  const uint16_t kNackExtLength = 2;
+  uint16_t nack_list_ext[kNackExtLength] = {123, 124};
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list_ext, kNackExtLength));
+  EXPECT_EQ(2U, sender_.RtcpSent().nack_packets);
+  EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(124));
+}
+
+TEST_F(RtpRtcpImplTest, ReSendsNackListAfterRttMs) {
+  sender_.transport_.SimulateNetworkDelay(0, &clock_);
+  // Send module sends a NACK.
+  const uint16_t kNackLength = 2;
+  uint16_t nack_list[kNackLength] = {123, 125};
+  EXPECT_EQ(0U, sender_.RtcpSent().nack_packets);
+  // Send Frame before sending a compound RTCP that starts with SR.
+  SendFrame(&sender_, kBaseLayerTid);
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
+  EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125));
+
+  // Same list not re-send, rtt interval has not passed.
+  const int kStartupRttMs = 100;
+  clock_.AdvanceTimeMilliseconds(kStartupRttMs);
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, sender_.RtcpSent().nack_packets);
+
+  // Rtt interval passed, full list sent.
+  clock_.AdvanceTimeMilliseconds(1);
+  EXPECT_EQ(0, sender_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(2U, sender_.RtcpSent().nack_packets);
+  EXPECT_THAT(sender_.LastNackListSent(), ElementsAre(123, 125));
+}
+
+TEST_F(RtpRtcpImplTest, UniqueNackRequests) {
+  receiver_.transport_.SimulateNetworkDelay(0, &clock_);
+  EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets);
+  EXPECT_EQ(0U, receiver_.RtcpSent().nack_requests);
+  EXPECT_EQ(0U, receiver_.RtcpSent().unique_nack_requests);
+  EXPECT_EQ(0, receiver_.RtcpSent().UniqueNackRequestsInPercent());
+
+  // Receive module sends NACK request.
+  const uint16_t kNackLength = 4;
+  uint16_t nack_list[kNackLength] = {10, 11, 13, 18};
+  EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength));
+  EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets);
+  EXPECT_EQ(4U, receiver_.RtcpSent().nack_requests);
+  EXPECT_EQ(4U, receiver_.RtcpSent().unique_nack_requests);
+  EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(10, 11, 13, 18));
+
+  // Send module receives the request.
+  EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets);
+  EXPECT_EQ(4U, sender_.RtcpReceived().nack_requests);
+  EXPECT_EQ(4U, sender_.RtcpReceived().unique_nack_requests);
+  EXPECT_EQ(100, sender_.RtcpReceived().UniqueNackRequestsInPercent());
+
+  // Receive module sends new request with duplicated packets.
+  const int kStartupRttMs = 100;
+  clock_.AdvanceTimeMilliseconds(kStartupRttMs + 1);
+  const uint16_t kNackLength2 = 4;
+  uint16_t nack_list2[kNackLength2] = {11, 18, 20, 21};
+  EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list2, kNackLength2));
+  EXPECT_EQ(2U, receiver_.RtcpSent().nack_packets);
+  EXPECT_EQ(8U, receiver_.RtcpSent().nack_requests);
+  EXPECT_EQ(6U, receiver_.RtcpSent().unique_nack_requests);
+  EXPECT_THAT(receiver_.LastNackListSent(), ElementsAre(11, 18, 20, 21));
+
+  // Send module receives the request.
+  EXPECT_EQ(2U, sender_.RtcpReceived().nack_packets);
+  EXPECT_EQ(8U, sender_.RtcpReceived().nack_requests);
+  EXPECT_EQ(6U, sender_.RtcpReceived().unique_nack_requests);
+  EXPECT_EQ(75, sender_.RtcpReceived().UniqueNackRequestsInPercent());
+}
+
+TEST_F(RtpRtcpImplTest, SendsKeepaliveAfterTimout) {
+  const int kTimeoutMs = 1500;
+
+  RtpKeepAliveConfig config;
+  config.timeout_interval_ms = kTimeoutMs;
+
+  // Recreate sender impl with new configuration, and redo setup.
+  sender_.SetKeepaliveConfigAndReset(config);
+  SetUp();
+
+  // Initial process call.
+  sender_.impl_->Process();
+  EXPECT_EQ(0U, sender_.transport_.NumKeepaliveSent());
+
+  // After one time, a single keep-alive packet should be sent.
+  clock_.AdvanceTimeMilliseconds(kTimeoutMs);
+  sender_.impl_->Process();
+  EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent());
+
+  // Process for the same timestamp again, no new packet should be sent.
+  sender_.impl_->Process();
+  EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent());
+
+  // Move ahead to the last ms before a keep-alive is expected, no action.
+  clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1);
+  sender_.impl_->Process();
+  EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent());
+
+  // Move the final ms, timeout relative last KA. Should create new keep-alive.
+  clock_.AdvanceTimeMilliseconds(1);
+  sender_.impl_->Process();
+  EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent());
+
+  // Move ahead to the last ms before Christmas.
+  clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1);
+  sender_.impl_->Process();
+  EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent());
+
+  // Send actual payload data, no keep-alive expected.
+  SendFrame(&sender_, 0);
+  sender_.impl_->Process();
+  EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent());
+
+  // Move ahead as far as possible again, timeout now relative payload. No KA.
+  clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1);
+  sender_.impl_->Process();
+  EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent());
+
+  // Timeout relative payload, send new keep-alive.
+  clock_.AdvanceTimeMilliseconds(1);
+  sender_.impl_->Process();
+  EXPECT_EQ(3U, sender_.transport_.NumKeepaliveSent());
+}
+
+TEST_F(RtpRtcpImplTest, ConfigurableRtcpReportInterval) {
+  const int kVideoReportInterval = 3000;
+
+  RtcpIntervalConfig config;
+  config.video_interval_ms = kVideoReportInterval;
+
+  // Recreate sender impl with new configuration, and redo setup.
+  sender_.SetRtcpIntervalConfigAndReset(config);
+  SetUp();
+
+  SendFrame(&sender_, kBaseLayerTid);
+
+  // Initial state
+  sender_.impl_->Process();
+  EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, -1);
+  EXPECT_EQ(0u, sender_.transport_.NumRtcpSent());
+
+  // Move ahead to the last ms before a rtcp is expected, no action.
+  clock_.AdvanceTimeMilliseconds(kVideoReportInterval / 2 - 1);
+  sender_.impl_->Process();
+  EXPECT_EQ(sender_.RtcpSent().first_packet_time_ms, -1);
+  EXPECT_EQ(sender_.transport_.NumRtcpSent(), 0u);
+
+  // Move ahead to the first rtcp. Send RTCP.
+  clock_.AdvanceTimeMilliseconds(1);
+  sender_.impl_->Process();
+  EXPECT_GT(sender_.RtcpSent().first_packet_time_ms, -1);
+  EXPECT_EQ(sender_.transport_.NumRtcpSent(), 1u);
+
+  SendFrame(&sender_, kBaseLayerTid);
+
+  // Move ahead to the last possible second before second rtcp is expected.
+  clock_.AdvanceTimeMilliseconds(kVideoReportInterval * 1 / 2 - 1);
+  sender_.impl_->Process();
+  EXPECT_EQ(sender_.transport_.NumRtcpSent(), 1u);
+
+  // Move ahead into the range of second rtcp, the second rtcp may be sent.
+  clock_.AdvanceTimeMilliseconds(1);
+  sender_.impl_->Process();
+  EXPECT_GE(sender_.transport_.NumRtcpSent(), 1u);
+
+  clock_.AdvanceTimeMilliseconds(kVideoReportInterval / 2);
+  sender_.impl_->Process();
+  EXPECT_GE(sender_.transport_.NumRtcpSent(), 1u);
+
+  // Move out the range of second rtcp, the second rtcp must have been sent.
+  clock_.AdvanceTimeMilliseconds(kVideoReportInterval / 2);
+  sender_.impl_->Process();
+  EXPECT_EQ(sender_.transport_.NumRtcpSent(), 2u);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
new file mode 100644
index 0000000..e0347f0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -0,0 +1,1374 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "modules/rtp_rtcp/source/rtp_sender_audio.h"
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
+#include "modules/rtp_rtcp/source/time_util.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_minmax.h"
+#include "rtc_base/rate_limiter.h"
+#include "rtc_base/timeutils.h"
+#include "rtc_base/trace_event.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+
+namespace {
+// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
+constexpr size_t kMaxPaddingLength = 224;
+constexpr size_t kMinAudioPaddingLength = 50;
+constexpr int kSendSideDelayWindowMs = 1000;
+constexpr size_t kRtpHeaderLength = 12;
+constexpr uint16_t kMaxInitRtpSeqNumber = 32767;  // 2^15 -1.
+constexpr uint32_t kTimestampTicksPerMs = 90;
+constexpr int kBitrateStatisticsWindowMs = 1000;
+
+constexpr size_t kMinFlexfecPacketsToStoreForPacing = 50;
+
+template <typename Extension>
+constexpr RtpExtensionSize CreateExtensionSize() {
+  return {Extension::kId, Extension::kValueSizeBytes};
+}
+
+// Size info for header extensions that might be used in padding or FEC packets.
+constexpr RtpExtensionSize kFecOrPaddingExtensionSizes[] = {
+    CreateExtensionSize<AbsoluteSendTime>(),
+    CreateExtensionSize<TransmissionOffset>(),
+    CreateExtensionSize<TransportSequenceNumber>(),
+    CreateExtensionSize<PlayoutDelayLimits>(),
+    {RtpMid::kId, RtpMid::kMaxValueSizeBytes},
+};
+
+// Size info for header extensions that might be used in video packets.
+constexpr RtpExtensionSize kVideoExtensionSizes[] = {
+    CreateExtensionSize<AbsoluteSendTime>(),
+    CreateExtensionSize<TransmissionOffset>(),
+    CreateExtensionSize<TransportSequenceNumber>(),
+    CreateExtensionSize<PlayoutDelayLimits>(),
+    CreateExtensionSize<VideoOrientation>(),
+    CreateExtensionSize<VideoContentTypeExtension>(),
+    CreateExtensionSize<VideoTimingExtension>(),
+    {RtpMid::kId, RtpMid::kMaxValueSizeBytes},
+};
+
+const char* FrameTypeToString(FrameType frame_type) {
+  switch (frame_type) {
+    case kEmptyFrame:
+      return "empty";
+    case kAudioFrameSpeech:
+      return "audio_speech";
+    case kAudioFrameCN:
+      return "audio_cn";
+    case kVideoFrameKey:
+      return "video_key";
+    case kVideoFrameDelta:
+      return "video_delta";
+  }
+  return "";
+}
+
+void CountPacket(RtpPacketCounter* counter, const RtpPacketToSend& packet) {
+  ++counter->packets;
+  counter->header_bytes += packet.headers_size();
+  counter->padding_bytes += packet.padding_size();
+  counter->payload_bytes += packet.payload_size();
+}
+
+}  // namespace
+
+RTPSender::RTPSender(
+    bool audio,
+    Clock* clock,
+    Transport* transport,
+    RtpPacketSender* paced_sender,
+    FlexfecSender* flexfec_sender,
+    TransportSequenceNumberAllocator* sequence_number_allocator,
+    TransportFeedbackObserver* transport_feedback_observer,
+    BitrateStatisticsObserver* bitrate_callback,
+    FrameCountObserver* frame_count_observer,
+    SendSideDelayObserver* send_side_delay_observer,
+    RtcEventLog* event_log,
+    SendPacketObserver* send_packet_observer,
+    RateLimiter* retransmission_rate_limiter,
+    OverheadObserver* overhead_observer,
+    bool populate_network2_timestamp)
+    : clock_(clock),
+      // TODO(holmer): Remove this conversion?
+      clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()),
+      random_(clock_->TimeInMicroseconds()),
+      audio_configured_(audio),
+      audio_(audio ? new RTPSenderAudio(clock, this) : nullptr),
+      video_(audio ? nullptr : new RTPSenderVideo(clock, this, flexfec_sender)),
+      paced_sender_(paced_sender),
+      transport_sequence_number_allocator_(sequence_number_allocator),
+      transport_feedback_observer_(transport_feedback_observer),
+      last_capture_time_ms_sent_(0),
+      transport_(transport),
+      sending_media_(true),                   // Default to sending media.
+      max_packet_size_(IP_PACKET_SIZE - 28),  // Default is IP-v4/UDP.
+      last_payload_type_(-1),
+      payload_type_map_(),
+      rtp_header_extension_map_(),
+      packet_history_(clock),
+      flexfec_packet_history_(clock),
+      // Statistics
+      rtp_stats_callback_(nullptr),
+      total_bitrate_sent_(kBitrateStatisticsWindowMs,
+                          RateStatistics::kBpsScale),
+      nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
+      frame_count_observer_(frame_count_observer),
+      send_side_delay_observer_(send_side_delay_observer),
+      event_log_(event_log),
+      send_packet_observer_(send_packet_observer),
+      bitrate_callback_(bitrate_callback),
+      // RTP variables
+      remote_ssrc_(0),
+      sequence_number_forced_(false),
+      last_rtp_timestamp_(0),
+      capture_time_ms_(0),
+      last_timestamp_time_ms_(0),
+      media_has_been_sent_(false),
+      last_packet_marker_bit_(false),
+      csrcs_(),
+      rtx_(kRtxOff),
+      rtp_overhead_bytes_per_packet_(0),
+      retransmission_rate_limiter_(retransmission_rate_limiter),
+      overhead_observer_(overhead_observer),
+      populate_network2_timestamp_(populate_network2_timestamp),
+      send_side_bwe_with_overhead_(
+          webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")) {
+  // This random initialization is not intended to be cryptographic strong.
+  timestamp_offset_ = random_.Rand<uint32_t>();
+  // Random start, 16 bits. Can't be 0.
+  sequence_number_rtx_ = random_.Rand(1, kMaxInitRtpSeqNumber);
+  sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
+
+  // Store FlexFEC packets in the packet history data structure, so they can
+  // be found when paced.
+  if (flexfec_sender) {
+    flexfec_packet_history_.SetStorePacketsStatus(
+        RtpPacketHistory::StorageMode::kStore,
+        kMinFlexfecPacketsToStoreForPacing);
+  }
+}
+
+RTPSender::~RTPSender() {
+  // TODO(tommi): Use a thread checker to ensure the object is created and
+  // deleted on the same thread.  At the moment this isn't possible due to
+  // voe::ChannelOwner in voice engine.  To reproduce, run:
+  // voe_auto_test --automated --gtest_filter=*MixManyChannelsForStressOpus
+
+  // TODO(tommi,holmer): We don't grab locks in the dtor before accessing member
+  // variables but we grab them in all other methods. (what's the design?)
+  // Start documenting what thread we're on in what method so that it's easier
+  // to understand performance attributes and possibly remove locks.
+  while (!payload_type_map_.empty()) {
+    std::map<int8_t, RtpUtility::Payload*>::iterator it =
+        payload_type_map_.begin();
+    delete it->second;
+    payload_type_map_.erase(it);
+  }
+}
+
+rtc::ArrayView<const RtpExtensionSize> RTPSender::FecExtensionSizes() {
+  return rtc::MakeArrayView(kFecOrPaddingExtensionSizes,
+                            arraysize(kFecOrPaddingExtensionSizes));
+}
+
+rtc::ArrayView<const RtpExtensionSize> RTPSender::VideoExtensionSizes() {
+  return rtc::MakeArrayView(kVideoExtensionSizes,
+                            arraysize(kVideoExtensionSizes));
+}
+
+uint16_t RTPSender::ActualSendBitrateKbit() const {
+  rtc::CritScope cs(&statistics_crit_);
+  return static_cast<uint16_t>(
+      total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) /
+      1000);
+}
+
+uint32_t RTPSender::VideoBitrateSent() const {
+  if (video_) {
+    return video_->VideoBitrateSent();
+  }
+  return 0;
+}
+
+uint32_t RTPSender::FecOverheadRate() const {
+  if (video_) {
+    return video_->FecOverheadRate();
+  }
+  return 0;
+}
+
+uint32_t RTPSender::NackOverheadRate() const {
+  rtc::CritScope cs(&statistics_crit_);
+  return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+}
+
+int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
+                                              uint8_t id) {
+  rtc::CritScope lock(&send_critsect_);
+  return rtp_header_extension_map_.RegisterByType(id, type) ? 0 : -1;
+}
+
+bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) const {
+  rtc::CritScope lock(&send_critsect_);
+  return rtp_header_extension_map_.IsRegistered(type);
+}
+
+int32_t RTPSender::DeregisterRtpHeaderExtension(RTPExtensionType type) {
+  rtc::CritScope lock(&send_critsect_);
+  return rtp_header_extension_map_.Deregister(type);
+}
+
+int32_t RTPSender::RegisterPayload(
+    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
+    int8_t payload_number,
+    uint32_t frequency,
+    size_t channels,
+    uint32_t rate) {
+  RTC_DCHECK_LT(strlen(payload_name), RTP_PAYLOAD_NAME_SIZE);
+  rtc::CritScope lock(&send_critsect_);
+
+  std::map<int8_t, RtpUtility::Payload*>::iterator it =
+      payload_type_map_.find(payload_number);
+
+  if (payload_type_map_.end() != it) {
+    // We already use this payload type.
+    RtpUtility::Payload* payload = it->second;
+    RTC_DCHECK(payload);
+
+    // Check if it's the same as we already have.
+    if (RtpUtility::StringCompare(payload->name, payload_name,
+                                  RTP_PAYLOAD_NAME_SIZE - 1)) {
+      if (audio_configured_ && payload->typeSpecific.is_audio()) {
+        auto& p = payload->typeSpecific.audio_payload();
+        if (rtc::SafeEq(p.format.clockrate_hz, frequency) &&
+            (p.rate == rate || p.rate == 0 || rate == 0)) {
+          p.rate = rate;
+          // Ensure that we update the rate if new or old is zero.
+          return 0;
+        }
+      }
+      if (!audio_configured_ && !payload->typeSpecific.is_audio()) {
+        return 0;
+      }
+    }
+    return -1;
+  }
+  int32_t ret_val = 0;
+  RtpUtility::Payload* payload = nullptr;
+  if (audio_configured_) {
+    // TODO(mflodman): Change to CreateAudioPayload and make static.
+    ret_val = audio_->RegisterAudioPayload(payload_name, payload_number,
+                                           frequency, channels, rate, &payload);
+  } else {
+    payload = video_->CreateVideoPayload(payload_name, payload_number);
+  }
+  if (payload) {
+    payload_type_map_[payload_number] = payload;
+  }
+  return ret_val;
+}
+
+int32_t RTPSender::DeRegisterSendPayload(int8_t payload_type) {
+  rtc::CritScope lock(&send_critsect_);
+
+  std::map<int8_t, RtpUtility::Payload*>::iterator it =
+      payload_type_map_.find(payload_type);
+
+  if (payload_type_map_.end() == it) {
+    return -1;
+  }
+  RtpUtility::Payload* payload = it->second;
+  delete payload;
+  payload_type_map_.erase(it);
+  return 0;
+}
+
+void RTPSender::SetMaxRtpPacketSize(size_t max_packet_size) {
+  RTC_DCHECK_GE(max_packet_size, 100);
+  RTC_DCHECK_LE(max_packet_size, IP_PACKET_SIZE);
+  rtc::CritScope lock(&send_critsect_);
+  max_packet_size_ = max_packet_size;
+}
+
+size_t RTPSender::MaxRtpPacketSize() const {
+  return max_packet_size_;
+}
+
+void RTPSender::SetRtxStatus(int mode) {
+  rtc::CritScope lock(&send_critsect_);
+  rtx_ = mode;
+}
+
+int RTPSender::RtxStatus() const {
+  rtc::CritScope lock(&send_critsect_);
+  return rtx_;
+}
+
+void RTPSender::SetRtxSsrc(uint32_t ssrc) {
+  rtc::CritScope lock(&send_critsect_);
+  ssrc_rtx_.emplace(ssrc);
+}
+
+uint32_t RTPSender::RtxSsrc() const {
+  rtc::CritScope lock(&send_critsect_);
+  RTC_DCHECK(ssrc_rtx_);
+  return *ssrc_rtx_;
+}
+
+void RTPSender::SetRtxPayloadType(int payload_type,
+                                  int associated_payload_type) {
+  rtc::CritScope lock(&send_critsect_);
+  RTC_DCHECK_LE(payload_type, 127);
+  RTC_DCHECK_LE(associated_payload_type, 127);
+  if (payload_type < 0) {
+    RTC_LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type << ".";
+    return;
+  }
+
+  rtx_payload_type_map_[associated_payload_type] = payload_type;
+}
+
+int32_t RTPSender::CheckPayloadType(int8_t payload_type,
+                                    VideoCodecType* video_type) {
+  rtc::CritScope lock(&send_critsect_);
+
+  if (payload_type < 0) {
+    RTC_LOG(LS_ERROR) << "Invalid payload_type " << payload_type << ".";
+    return -1;
+  }
+  if (last_payload_type_ == payload_type) {
+    if (!audio_configured_) {
+      *video_type = video_->VideoCodecType();
+    }
+    return 0;
+  }
+  std::map<int8_t, RtpUtility::Payload*>::iterator it =
+      payload_type_map_.find(payload_type);
+  if (it == payload_type_map_.end()) {
+    RTC_LOG(LS_WARNING) << "Payload type " << static_cast<int>(payload_type)
+                        << " not registered.";
+    return -1;
+  }
+  RtpUtility::Payload* payload = it->second;
+  RTC_DCHECK(payload);
+  if (payload->typeSpecific.is_video() && !audio_configured_) {
+    video_->SetVideoCodecType(
+        payload->typeSpecific.video_payload().videoCodecType);
+    *video_type = payload->typeSpecific.video_payload().videoCodecType;
+  }
+  return 0;
+}
+
+bool RTPSender::SendOutgoingData(FrameType frame_type,
+                                 int8_t payload_type,
+                                 uint32_t capture_timestamp,
+                                 int64_t capture_time_ms,
+                                 const uint8_t* payload_data,
+                                 size_t payload_size,
+                                 const RTPFragmentationHeader* fragmentation,
+                                 const RTPVideoHeader* rtp_header,
+                                 uint32_t* transport_frame_id_out,
+                                 int64_t expected_retransmission_time_ms) {
+  uint32_t ssrc;
+  uint16_t sequence_number;
+  uint32_t rtp_timestamp;
+  {
+    // Drop this packet if we're not sending media packets.
+    rtc::CritScope lock(&send_critsect_);
+    RTC_DCHECK(ssrc_);
+
+    ssrc = *ssrc_;
+    sequence_number = sequence_number_;
+    rtp_timestamp = timestamp_offset_ + capture_timestamp;
+    if (transport_frame_id_out)
+      *transport_frame_id_out = rtp_timestamp;
+    if (!sending_media_)
+      return true;
+  }
+  VideoCodecType video_type = kVideoCodecGeneric;
+  if (CheckPayloadType(payload_type, &video_type) != 0) {
+    RTC_LOG(LS_ERROR) << "Don't send data with unknown payload type: "
+                      << static_cast<int>(payload_type) << ".";
+    return false;
+  }
+
+  switch (frame_type) {
+    case kAudioFrameSpeech:
+    case kAudioFrameCN:
+      RTC_CHECK(audio_configured_);
+      break;
+    case kVideoFrameKey:
+    case kVideoFrameDelta:
+      RTC_CHECK(!audio_configured_);
+      break;
+    case kEmptyFrame:
+      break;
+  }
+
+  bool result;
+  if (audio_configured_) {
+    TRACE_EVENT_ASYNC_STEP1("webrtc", "Audio", rtp_timestamp, "Send", "type",
+                            FrameTypeToString(frame_type));
+    // The only known way to produce of RTPFragmentationHeader for audio is
+    // to use the AudioCodingModule directly.
+    RTC_DCHECK(fragmentation == nullptr);
+    result = audio_->SendAudio(frame_type, payload_type, rtp_timestamp,
+                               payload_data, payload_size);
+  } else {
+    TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", capture_time_ms, "Send", "type",
+                            FrameTypeToString(frame_type));
+    if (frame_type == kEmptyFrame)
+      return true;
+
+    if (rtp_header) {
+      playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay,
+                                          sequence_number);
+    }
+
+    result = video_->SendVideo(video_type, frame_type, payload_type,
+                               rtp_timestamp, capture_time_ms, payload_data,
+                               payload_size, fragmentation, rtp_header,
+                               expected_retransmission_time_ms);
+  }
+
+  rtc::CritScope cs(&statistics_crit_);
+  // Note: This is currently only counting for video.
+  if (frame_type == kVideoFrameKey) {
+    ++frame_counts_.key_frames;
+  } else if (frame_type == kVideoFrameDelta) {
+    ++frame_counts_.delta_frames;
+  }
+  if (frame_count_observer_) {
+    frame_count_observer_->FrameCountUpdated(frame_counts_, ssrc);
+  }
+
+  return result;
+}
+
+size_t RTPSender::TrySendRedundantPayloads(size_t bytes_to_send,
+                                           const PacedPacketInfo& pacing_info) {
+  {
+    rtc::CritScope lock(&send_critsect_);
+    if (!sending_media_)
+      return 0;
+    if ((rtx_ & kRtxRedundantPayloads) == 0)
+      return 0;
+  }
+
+  int bytes_left = static_cast<int>(bytes_to_send);
+  while (bytes_left > 0) {
+    std::unique_ptr<RtpPacketToSend> packet =
+        packet_history_.GetBestFittingPacket(bytes_left);
+    if (!packet)
+      break;
+    size_t payload_size = packet->payload_size();
+    if (!PrepareAndSendPacket(std::move(packet), true, false, pacing_info))
+      break;
+    bytes_left -= payload_size;
+  }
+  return bytes_to_send - bytes_left;
+}
+
+size_t RTPSender::SendPadData(size_t bytes,
+                              const PacedPacketInfo& pacing_info) {
+  size_t padding_bytes_in_packet;
+  size_t max_payload_size = max_packet_size_ - RtpHeaderLength();
+
+  if (audio_configured_) {
+    // Allow smaller padding packets for audio.
+    padding_bytes_in_packet = rtc::SafeClamp<size_t>(
+        bytes, kMinAudioPaddingLength,
+        rtc::SafeMin(max_payload_size, kMaxPaddingLength));
+  } else {
+    // Always send full padding packets. This is accounted for by the
+    // RtpPacketSender, which will make sure we don't send too much padding even
+    // if a single packet is larger than requested.
+    // We do this to avoid frequently sending small packets on higher bitrates.
+    padding_bytes_in_packet =
+        rtc::SafeMin<size_t>(max_payload_size, kMaxPaddingLength);
+  }
+  size_t bytes_sent = 0;
+  while (bytes_sent < bytes) {
+    int64_t now_ms = clock_->TimeInMilliseconds();
+    uint32_t ssrc;
+    uint32_t timestamp;
+    int64_t capture_time_ms;
+    uint16_t sequence_number;
+    int payload_type;
+    bool over_rtx;
+    {
+      rtc::CritScope lock(&send_critsect_);
+      if (!sending_media_)
+        break;
+      timestamp = last_rtp_timestamp_;
+      capture_time_ms = capture_time_ms_;
+      if (rtx_ == kRtxOff) {
+        if (last_payload_type_ == -1)
+          break;
+        // Without RTX we can't send padding in the middle of frames.
+        // For audio marker bits doesn't mark the end of a frame and frames
+        // are usually a single packet, so for now we don't apply this rule
+        // for audio.
+        if (!audio_configured_ && !last_packet_marker_bit_) {
+          break;
+        }
+        if (!ssrc_) {
+          RTC_LOG(LS_ERROR) << "SSRC unset.";
+          return 0;
+        }
+
+        RTC_DCHECK(ssrc_);
+        ssrc = *ssrc_;
+
+        sequence_number = sequence_number_;
+        ++sequence_number_;
+        payload_type = last_payload_type_;
+        over_rtx = false;
+      } else {
+        // Without abs-send-time or transport sequence number a media packet
+        // must be sent before padding so that the timestamps used for
+        // estimation are correct.
+        if (!media_has_been_sent_ &&
+            !(rtp_header_extension_map_.IsRegistered(AbsoluteSendTime::kId) ||
+              (rtp_header_extension_map_.IsRegistered(
+                   TransportSequenceNumber::kId) &&
+               transport_sequence_number_allocator_))) {
+          break;
+        }
+        // Only change change the timestamp of padding packets sent over RTX.
+        // Padding only packets over RTP has to be sent as part of a media
+        // frame (and therefore the same timestamp).
+        if (last_timestamp_time_ms_ > 0) {
+          timestamp +=
+              (now_ms - last_timestamp_time_ms_) * kTimestampTicksPerMs;
+          capture_time_ms += (now_ms - last_timestamp_time_ms_);
+        }
+        if (!ssrc_rtx_) {
+          RTC_LOG(LS_ERROR) << "RTX SSRC unset.";
+          return 0;
+        }
+        RTC_DCHECK(ssrc_rtx_);
+        ssrc = *ssrc_rtx_;
+        sequence_number = sequence_number_rtx_;
+        ++sequence_number_rtx_;
+        payload_type = rtx_payload_type_map_.begin()->second;
+        over_rtx = true;
+      }
+    }
+
+    RtpPacketToSend padding_packet(&rtp_header_extension_map_);
+    padding_packet.SetPayloadType(payload_type);
+    padding_packet.SetMarker(false);
+    padding_packet.SetSequenceNumber(sequence_number);
+    padding_packet.SetTimestamp(timestamp);
+    padding_packet.SetSsrc(ssrc);
+
+    if (capture_time_ms > 0) {
+      padding_packet.SetExtension<TransmissionOffset>(
+          (now_ms - capture_time_ms) * kTimestampTicksPerMs);
+    }
+    padding_packet.SetExtension<AbsoluteSendTime>(
+        AbsoluteSendTime::MsTo24Bits(now_ms));
+    PacketOptions options;
+    // Padding packets are never retransmissions.
+    options.is_retransmit = false;
+    bool has_transport_seq_num =
+        UpdateTransportSequenceNumber(&padding_packet, &options.packet_id);
+    padding_packet.SetPadding(padding_bytes_in_packet, &random_);
+
+    if (has_transport_seq_num) {
+      AddPacketToTransportFeedback(options.packet_id, padding_packet,
+                                   pacing_info);
+    }
+
+    if (!SendPacketToNetwork(padding_packet, options, pacing_info))
+      break;
+
+    bytes_sent += padding_bytes_in_packet;
+    UpdateRtpStats(padding_packet, over_rtx, false);
+  }
+
+  return bytes_sent;
+}
+
+void RTPSender::SetStorePacketsStatus(bool enable, uint16_t number_to_store) {
+  RtpPacketHistory::StorageMode mode =
+      enable ? RtpPacketHistory::StorageMode::kStore
+             : RtpPacketHistory::StorageMode::kDisabled;
+  packet_history_.SetStorePacketsStatus(mode, number_to_store);
+}
+
+bool RTPSender::StorePackets() const {
+  return packet_history_.GetStorageMode() !=
+         RtpPacketHistory::StorageMode::kDisabled;
+}
+
+int32_t RTPSender::ReSendPacket(uint16_t packet_id) {
+  // Try to find packet in RTP packet history. Also verify RTT here, so that we
+  // don't retransmit too often.
+  absl::optional<RtpPacketHistory::PacketState> stored_packet =
+      packet_history_.GetPacketState(packet_id, true);
+  if (!stored_packet) {
+    // Packet not found.
+    return 0;
+  }
+
+  const int32_t packet_size = static_cast<int32_t>(stored_packet->payload_size);
+
+  RTC_DCHECK(retransmission_rate_limiter_);
+  // Check if we're overusing retransmission bitrate.
+  // TODO(sprang): Add histograms for nack success or failure reasons.
+  if (!retransmission_rate_limiter_->TryUseRate(packet_size)) {
+    return -1;
+  }
+
+  if (paced_sender_) {
+    // Convert from TickTime to Clock since capture_time_ms is based on
+    // TickTime.
+    int64_t corrected_capture_tims_ms =
+        stored_packet->capture_time_ms + clock_delta_ms_;
+    paced_sender_->InsertPacket(
+        RtpPacketSender::kNormalPriority, stored_packet->ssrc,
+        stored_packet->rtp_sequence_number, corrected_capture_tims_ms,
+        stored_packet->payload_size, true);
+
+    return packet_size;
+  }
+
+  std::unique_ptr<RtpPacketToSend> packet =
+      packet_history_.GetPacketAndSetSendTime(packet_id, true);
+  if (!packet) {
+    // Packet could theoretically time out between the first check and this one.
+    return 0;
+  }
+
+  const bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
+  if (!PrepareAndSendPacket(std::move(packet), rtx, true, PacedPacketInfo()))
+    return -1;
+
+  return packet_size;
+}
+
+bool RTPSender::SendPacketToNetwork(const RtpPacketToSend& packet,
+                                    const PacketOptions& options,
+                                    const PacedPacketInfo& pacing_info) {
+  int bytes_sent = -1;
+  if (transport_) {
+    UpdateRtpOverhead(packet);
+    bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options)
+                     ? static_cast<int>(packet.size())
+                     : -1;
+    if (event_log_ && bytes_sent > 0) {
+      event_log_->Log(absl::make_unique<RtcEventRtpPacketOutgoing>(
+          packet, pacing_info.probe_cluster_id));
+    }
+  }
+  // TODO(pwestin): Add a separate bitrate for sent bitrate after pacer.
+  if (bytes_sent <= 0) {
+    RTC_LOG(LS_WARNING) << "Transport failed to send packet.";
+    return false;
+  }
+  return true;
+}
+
+int RTPSender::SelectiveRetransmissions() const {
+  if (!video_)
+    return -1;
+  return video_->SelectiveRetransmissions();
+}
+
+int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
+  if (!video_)
+    return -1;
+  video_->SetSelectiveRetransmissions(settings);
+  return 0;
+}
+
+void RTPSender::OnReceivedNack(
+    const std::vector<uint16_t>& nack_sequence_numbers,
+    int64_t avg_rtt) {
+  packet_history_.SetRtt(5 + avg_rtt);
+  for (uint16_t seq_no : nack_sequence_numbers) {
+    const int32_t bytes_sent = ReSendPacket(seq_no);
+    if (bytes_sent < 0) {
+      // Failed to send one Sequence number. Give up the rest in this nack.
+      RTC_LOG(LS_WARNING) << "Failed resending RTP packet " << seq_no
+                          << ", Discard rest of packets.";
+      break;
+    }
+  }
+}
+
+void RTPSender::OnReceivedRtcpReportBlocks(
+    const ReportBlockList& report_blocks) {
+  playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks);
+}
+
+// Called from pacer when we can send the packet.
+bool RTPSender::TimeToSendPacket(uint32_t ssrc,
+                                 uint16_t sequence_number,
+                                 int64_t capture_time_ms,
+                                 bool retransmission,
+                                 const PacedPacketInfo& pacing_info) {
+  if (!SendingMedia())
+    return true;
+
+  std::unique_ptr<RtpPacketToSend> packet;
+  // No need to verify RTT here, it has already been checked before putting the
+  // packet into the pacer. But _do_ update the send time.
+  if (ssrc == SSRC()) {
+    packet = packet_history_.GetPacketAndSetSendTime(sequence_number, false);
+  } else if (ssrc == FlexfecSsrc()) {
+    packet =
+        flexfec_packet_history_.GetPacketAndSetSendTime(sequence_number, false);
+  }
+
+  if (!packet) {
+    // Packet cannot be found.
+    return true;
+  }
+
+  return PrepareAndSendPacket(
+      std::move(packet),
+      retransmission && (RtxStatus() & kRtxRetransmitted) > 0, retransmission,
+      pacing_info);
+}
+
+bool RTPSender::PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
+                                     bool send_over_rtx,
+                                     bool is_retransmit,
+                                     const PacedPacketInfo& pacing_info) {
+  RTC_DCHECK(packet);
+  int64_t capture_time_ms = packet->capture_time_ms();
+  RtpPacketToSend* packet_to_send = packet.get();
+
+  std::unique_ptr<RtpPacketToSend> packet_rtx;
+  if (send_over_rtx) {
+    packet_rtx = BuildRtxPacket(*packet);
+    if (!packet_rtx)
+      return false;
+    packet_to_send = packet_rtx.get();
+  }
+
+  // Bug webrtc:7859. While FEC is invoked from rtp_sender_video, and not after
+  // the pacer, these modifications of the header below are happening after the
+  // FEC protection packets are calculated. This will corrupt recovered packets
+  // at the same place. It's not an issue for extensions, which are present in
+  // all the packets (their content just may be incorrect on recovered packets).
+  // In case of VideoTimingExtension, since it's present not in every packet,
+  // data after rtp header may be corrupted if these packets are protected by
+  // the FEC.
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t diff_ms = now_ms - capture_time_ms;
+  packet_to_send->SetExtension<TransmissionOffset>(kTimestampTicksPerMs *
+                                                   diff_ms);
+  packet_to_send->SetExtension<AbsoluteSendTime>(
+      AbsoluteSendTime::MsTo24Bits(now_ms));
+
+  if (packet_to_send->HasExtension<VideoTimingExtension>()) {
+    if (populate_network2_timestamp_) {
+      packet_to_send->set_network2_time_ms(now_ms);
+    } else {
+      packet_to_send->set_pacer_exit_time_ms(now_ms);
+    }
+  }
+
+  PacketOptions options;
+  // If we are sending over RTX, it also means this is a retransmission.
+  // E.g. RTPSender::TrySendRedundantPayloads calls PrepareAndSendPacket with
+  // send_over_rtx = true but is_retransmit = false.
+  options.is_retransmit = is_retransmit || send_over_rtx;
+  if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id)) {
+    AddPacketToTransportFeedback(options.packet_id, *packet_to_send,
+                                 pacing_info);
+  }
+  options.application_data.assign(packet_to_send->application_data().begin(),
+                                  packet_to_send->application_data().end());
+
+  if (!is_retransmit && !send_over_rtx) {
+    UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
+    UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
+                       packet->Ssrc());
+  }
+
+  if (!SendPacketToNetwork(*packet_to_send, options, pacing_info))
+    return false;
+
+  {
+    rtc::CritScope lock(&send_critsect_);
+    media_has_been_sent_ = true;
+  }
+  UpdateRtpStats(*packet_to_send, send_over_rtx, is_retransmit);
+  return true;
+}
+
+void RTPSender::UpdateRtpStats(const RtpPacketToSend& packet,
+                               bool is_rtx,
+                               bool is_retransmit) {
+  int64_t now_ms = clock_->TimeInMilliseconds();
+
+  rtc::CritScope lock(&statistics_crit_);
+  StreamDataCounters* counters = is_rtx ? &rtx_rtp_stats_ : &rtp_stats_;
+
+  total_bitrate_sent_.Update(packet.size(), now_ms);
+
+  if (counters->first_packet_time_ms == -1)
+    counters->first_packet_time_ms = now_ms;
+
+  if (IsFecPacket(packet))
+    CountPacket(&counters->fec, packet);
+
+  if (is_retransmit) {
+    CountPacket(&counters->retransmitted, packet);
+    nack_bitrate_sent_.Update(packet.size(), now_ms);
+  }
+  CountPacket(&counters->transmitted, packet);
+
+  if (rtp_stats_callback_)
+    rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc());
+}
+
+bool RTPSender::IsFecPacket(const RtpPacketToSend& packet) const {
+  if (!video_)
+    return false;
+
+  // FlexFEC.
+  if (packet.Ssrc() == FlexfecSsrc())
+    return true;
+
+  // RED+ULPFEC.
+  int pt_red;
+  int pt_fec;
+  video_->GetUlpfecConfig(&pt_red, &pt_fec);
+  return static_cast<int>(packet.PayloadType()) == pt_red &&
+         static_cast<int>(packet.payload()[0]) == pt_fec;
+}
+
+size_t RTPSender::TimeToSendPadding(size_t bytes,
+                                    const PacedPacketInfo& pacing_info) {
+  if (bytes == 0)
+    return 0;
+  size_t bytes_sent = TrySendRedundantPayloads(bytes, pacing_info);
+  if (bytes_sent < bytes)
+    bytes_sent += SendPadData(bytes - bytes_sent, pacing_info);
+  return bytes_sent;
+}
+
+bool RTPSender::SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
+                              StorageType storage,
+                              RtpPacketSender::Priority priority) {
+  RTC_DCHECK(packet);
+  int64_t now_ms = clock_->TimeInMilliseconds();
+
+  // |capture_time_ms| <= 0 is considered invalid.
+  // TODO(holmer): This should be changed all over Video Engine so that negative
+  // time is consider invalid, while 0 is considered a valid time.
+  if (packet->capture_time_ms() > 0) {
+    packet->SetExtension<TransmissionOffset>(
+        kTimestampTicksPerMs * (now_ms - packet->capture_time_ms()));
+  }
+  packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::MsTo24Bits(now_ms));
+
+  if (video_) {
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
+                                    ActualSendBitrateKbit(), packet->Ssrc());
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms,
+                                    FecOverheadRate() / 1000, packet->Ssrc());
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
+                                    NackOverheadRate() / 1000, packet->Ssrc());
+  } else {
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioTotBitrate_kbps", now_ms,
+                                    ActualSendBitrateKbit(), packet->Ssrc());
+    BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioNackBitrate_kbps", now_ms,
+                                    NackOverheadRate() / 1000, packet->Ssrc());
+  }
+
+  uint32_t ssrc = packet->Ssrc();
+  absl::optional<uint32_t> flexfec_ssrc = FlexfecSsrc();
+  if (paced_sender_) {
+    uint16_t seq_no = packet->SequenceNumber();
+    // Correct offset between implementations of millisecond time stamps in
+    // TickTime and Clock.
+    int64_t corrected_time_ms = packet->capture_time_ms() + clock_delta_ms_;
+    size_t payload_length = packet->payload_size();
+    if (ssrc == flexfec_ssrc) {
+      // Store FlexFEC packets in the history here, so they can be found
+      // when the pacer calls TimeToSendPacket.
+      flexfec_packet_history_.PutRtpPacket(std::move(packet), storage,
+                                           absl::nullopt);
+    } else {
+      packet_history_.PutRtpPacket(std::move(packet), storage, absl::nullopt);
+    }
+
+    paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms,
+                                payload_length, false);
+    if (last_capture_time_ms_sent_ == 0 ||
+        corrected_time_ms > last_capture_time_ms_sent_) {
+      last_capture_time_ms_sent_ = corrected_time_ms;
+    }
+    return true;
+  }
+
+  PacketOptions options;
+  options.is_retransmit = false;
+  if (UpdateTransportSequenceNumber(packet.get(), &options.packet_id)) {
+    AddPacketToTransportFeedback(options.packet_id, *packet.get(),
+                                 PacedPacketInfo());
+  }
+  options.application_data.assign(packet->application_data().begin(),
+                                  packet->application_data().end());
+
+  UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
+  UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
+                     packet->Ssrc());
+
+  bool sent = SendPacketToNetwork(*packet, options, PacedPacketInfo());
+
+  if (sent) {
+    {
+      rtc::CritScope lock(&send_critsect_);
+      media_has_been_sent_ = true;
+    }
+    UpdateRtpStats(*packet, false, false);
+  }
+
+  // To support retransmissions, we store the media packet as sent in the
+  // packet history (even if send failed).
+  if (storage == kAllowRetransmission) {
+    RTC_DCHECK_EQ(ssrc, SSRC());
+    packet_history_.PutRtpPacket(std::move(packet), storage, now_ms);
+  }
+
+  return sent;
+}
+
+void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
+  if (!send_side_delay_observer_ || capture_time_ms <= 0)
+    return;
+
+  uint32_t ssrc;
+  int64_t avg_delay_ms = 0;
+  int max_delay_ms = 0;
+  {
+    rtc::CritScope lock(&send_critsect_);
+    if (!ssrc_)
+      return;
+    ssrc = *ssrc_;
+  }
+  {
+    rtc::CritScope cs(&statistics_crit_);
+    // TODO(holmer): Compute this iteratively instead.
+    send_delays_[now_ms] = now_ms - capture_time_ms;
+    send_delays_.erase(
+        send_delays_.begin(),
+        send_delays_.lower_bound(now_ms - kSendSideDelayWindowMs));
+    int num_delays = 0;
+    for (auto it = send_delays_.upper_bound(now_ms - kSendSideDelayWindowMs);
+         it != send_delays_.end(); ++it) {
+      max_delay_ms = std::max(max_delay_ms, it->second);
+      avg_delay_ms += it->second;
+      ++num_delays;
+    }
+    if (num_delays == 0)
+      return;
+    avg_delay_ms = (avg_delay_ms + num_delays / 2) / num_delays;
+  }
+  send_side_delay_observer_->SendSideDelayUpdated(
+      rtc::dchecked_cast<int>(avg_delay_ms), max_delay_ms, ssrc);
+}
+
+void RTPSender::UpdateOnSendPacket(int packet_id,
+                                   int64_t capture_time_ms,
+                                   uint32_t ssrc) {
+  if (!send_packet_observer_ || capture_time_ms <= 0 || packet_id == -1)
+    return;
+
+  send_packet_observer_->OnSendPacket(packet_id, capture_time_ms, ssrc);
+}
+
+void RTPSender::ProcessBitrate() {
+  if (!bitrate_callback_)
+    return;
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  uint32_t ssrc;
+  {
+    rtc::CritScope lock(&send_critsect_);
+    if (!ssrc_)
+      return;
+    ssrc = *ssrc_;
+  }
+
+  rtc::CritScope lock(&statistics_crit_);
+  bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
+                            nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc);
+}
+
+size_t RTPSender::RtpHeaderLength() const {
+  rtc::CritScope lock(&send_critsect_);
+  size_t rtp_header_length = kRtpHeaderLength;
+  rtp_header_length += sizeof(uint32_t) * csrcs_.size();
+  rtp_header_length += rtp_header_extension_map_.GetTotalLengthInBytes(
+      kFecOrPaddingExtensionSizes);
+  return rtp_header_length;
+}
+
+uint16_t RTPSender::AllocateSequenceNumber(uint16_t packets_to_send) {
+  rtc::CritScope lock(&send_critsect_);
+  uint16_t first_allocated_sequence_number = sequence_number_;
+  sequence_number_ += packets_to_send;
+  return first_allocated_sequence_number;
+}
+
+void RTPSender::GetDataCounters(StreamDataCounters* rtp_stats,
+                                StreamDataCounters* rtx_stats) const {
+  rtc::CritScope lock(&statistics_crit_);
+  *rtp_stats = rtp_stats_;
+  *rtx_stats = rtx_rtp_stats_;
+}
+
+std::unique_ptr<RtpPacketToSend> RTPSender::AllocatePacket() const {
+  rtc::CritScope lock(&send_critsect_);
+  std::unique_ptr<RtpPacketToSend> packet(
+      new RtpPacketToSend(&rtp_header_extension_map_, max_packet_size_));
+  RTC_DCHECK(ssrc_);
+  packet->SetSsrc(*ssrc_);
+  packet->SetCsrcs(csrcs_);
+  // Reserve extensions, if registered, RtpSender set in SendToNetwork.
+  packet->ReserveExtension<AbsoluteSendTime>();
+  packet->ReserveExtension<TransmissionOffset>();
+  packet->ReserveExtension<TransportSequenceNumber>();
+  if (playout_delay_oracle_.send_playout_delay()) {
+    packet->SetExtension<PlayoutDelayLimits>(
+        playout_delay_oracle_.playout_delay());
+  }
+  if (!mid_.empty()) {
+    // This is a no-op if the MID header extension is not registered.
+    packet->SetExtension<RtpMid>(mid_);
+  }
+  return packet;
+}
+
+bool RTPSender::AssignSequenceNumber(RtpPacketToSend* packet) {
+  rtc::CritScope lock(&send_critsect_);
+  if (!sending_media_)
+    return false;
+  RTC_DCHECK(packet->Ssrc() == ssrc_);
+  packet->SetSequenceNumber(sequence_number_++);
+
+  // Remember marker bit to determine if padding can be inserted with
+  // sequence number following |packet|.
+  last_packet_marker_bit_ = packet->Marker();
+  // Remember payload type to use in the padding packet if rtx is disabled.
+  last_payload_type_ = packet->PayloadType();
+  // Save timestamps to generate timestamp field and extensions for the padding.
+  last_rtp_timestamp_ = packet->Timestamp();
+  last_timestamp_time_ms_ = clock_->TimeInMilliseconds();
+  capture_time_ms_ = packet->capture_time_ms();
+  return true;
+}
+
+bool RTPSender::UpdateTransportSequenceNumber(RtpPacketToSend* packet,
+                                              int* packet_id) const {
+  RTC_DCHECK(packet);
+  RTC_DCHECK(packet_id);
+  rtc::CritScope lock(&send_critsect_);
+  if (!rtp_header_extension_map_.IsRegistered(TransportSequenceNumber::kId))
+    return false;
+
+  if (!transport_sequence_number_allocator_)
+    return false;
+
+  *packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber();
+
+  if (!packet->SetExtension<TransportSequenceNumber>(*packet_id))
+    return false;
+
+  return true;
+}
+
+void RTPSender::SetSendingMediaStatus(bool enabled) {
+  rtc::CritScope lock(&send_critsect_);
+  sending_media_ = enabled;
+}
+
+bool RTPSender::SendingMedia() const {
+  rtc::CritScope lock(&send_critsect_);
+  return sending_media_;
+}
+
+void RTPSender::SetTimestampOffset(uint32_t timestamp) {
+  rtc::CritScope lock(&send_critsect_);
+  timestamp_offset_ = timestamp;
+}
+
+uint32_t RTPSender::TimestampOffset() const {
+  rtc::CritScope lock(&send_critsect_);
+  return timestamp_offset_;
+}
+
+void RTPSender::SetSSRC(uint32_t ssrc) {
+  // This is configured via the API.
+  rtc::CritScope lock(&send_critsect_);
+
+  if (ssrc_ == ssrc) {
+    return;  // Since it's same ssrc, don't reset anything.
+  }
+  ssrc_.emplace(ssrc);
+  if (!sequence_number_forced_) {
+    sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
+  }
+}
+
+uint32_t RTPSender::SSRC() const {
+  rtc::CritScope lock(&send_critsect_);
+  RTC_DCHECK(ssrc_);
+  return *ssrc_;
+}
+
+void RTPSender::SetMid(const std::string& mid) {
+  // This is configured via the API.
+  rtc::CritScope lock(&send_critsect_);
+  mid_ = mid;
+}
+
+absl::optional<uint32_t> RTPSender::FlexfecSsrc() const {
+  if (video_) {
+    return video_->FlexfecSsrc();
+  }
+  return absl::nullopt;
+}
+
+void RTPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
+  RTC_DCHECK_LE(csrcs.size(), kRtpCsrcSize);
+  rtc::CritScope lock(&send_critsect_);
+  csrcs_ = csrcs;
+}
+
+void RTPSender::SetSequenceNumber(uint16_t seq) {
+  rtc::CritScope lock(&send_critsect_);
+  sequence_number_forced_ = true;
+  sequence_number_ = seq;
+}
+
+uint16_t RTPSender::SequenceNumber() const {
+  rtc::CritScope lock(&send_critsect_);
+  return sequence_number_;
+}
+
+// Audio.
+int32_t RTPSender::SendTelephoneEvent(uint8_t key,
+                                      uint16_t time_ms,
+                                      uint8_t level) {
+  if (!audio_configured_) {
+    return -1;
+  }
+  return audio_->SendTelephoneEvent(key, time_ms, level);
+}
+
+int32_t RTPSender::SetAudioLevel(uint8_t level_d_bov) {
+  return audio_->SetAudioLevel(level_d_bov);
+}
+
+void RTPSender::SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) {
+  RTC_DCHECK(!audio_configured_);
+  video_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
+}
+
+bool RTPSender::SetFecParameters(const FecProtectionParams& delta_params,
+                                 const FecProtectionParams& key_params) {
+  if (audio_configured_) {
+    return false;
+  }
+  video_->SetFecParameters(delta_params, key_params);
+  return true;
+}
+
+std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
+    const RtpPacketToSend& packet) {
+  // TODO(danilchap): Create rtx packet with extra capacity for SRTP
+  // when transport interface would be updated to take buffer class.
+  std::unique_ptr<RtpPacketToSend> rtx_packet(new RtpPacketToSend(
+      &rtp_header_extension_map_, packet.size() + kRtxHeaderSize));
+  // Add original RTP header.
+  rtx_packet->CopyHeaderFrom(packet);
+  {
+    rtc::CritScope lock(&send_critsect_);
+    if (!sending_media_)
+      return nullptr;
+
+    RTC_DCHECK(ssrc_rtx_);
+
+    // Replace payload type.
+    auto kv = rtx_payload_type_map_.find(packet.PayloadType());
+    if (kv == rtx_payload_type_map_.end())
+      return nullptr;
+    rtx_packet->SetPayloadType(kv->second);
+
+    // Replace sequence number.
+    rtx_packet->SetSequenceNumber(sequence_number_rtx_++);
+
+    // Replace SSRC.
+    rtx_packet->SetSsrc(*ssrc_rtx_);
+
+    // Possibly include the MID header extension.
+    if (!mid_.empty()) {
+      // This is a no-op if the MID header extension is not registered.
+      rtx_packet->SetExtension<RtpMid>(mid_);
+    }
+  }
+
+  uint8_t* rtx_payload =
+      rtx_packet->AllocatePayload(packet.payload_size() + kRtxHeaderSize);
+  RTC_DCHECK(rtx_payload);
+  // Add OSN (original sequence number).
+  ByteWriter<uint16_t>::WriteBigEndian(rtx_payload, packet.SequenceNumber());
+
+  // Add original payload data.
+  auto payload = packet.payload();
+  memcpy(rtx_payload + kRtxHeaderSize, payload.data(), payload.size());
+
+  // Add original application data.
+  rtx_packet->set_application_data(packet.application_data());
+
+  return rtx_packet;
+}
+
+void RTPSender::RegisterRtpStatisticsCallback(
+    StreamDataCountersCallback* callback) {
+  rtc::CritScope cs(&statistics_crit_);
+  rtp_stats_callback_ = callback;
+}
+
+StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
+  rtc::CritScope cs(&statistics_crit_);
+  return rtp_stats_callback_;
+}
+
+uint32_t RTPSender::BitrateSent() const {
+  rtc::CritScope cs(&statistics_crit_);
+  return total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+}
+
+void RTPSender::SetRtpState(const RtpState& rtp_state) {
+  rtc::CritScope lock(&send_critsect_);
+  sequence_number_ = rtp_state.sequence_number;
+  sequence_number_forced_ = true;
+  timestamp_offset_ = rtp_state.start_timestamp;
+  last_rtp_timestamp_ = rtp_state.timestamp;
+  capture_time_ms_ = rtp_state.capture_time_ms;
+  last_timestamp_time_ms_ = rtp_state.last_timestamp_time_ms;
+  media_has_been_sent_ = rtp_state.media_has_been_sent;
+}
+
+RtpState RTPSender::GetRtpState() const {
+  rtc::CritScope lock(&send_critsect_);
+
+  RtpState state;
+  state.sequence_number = sequence_number_;
+  state.start_timestamp = timestamp_offset_;
+  state.timestamp = last_rtp_timestamp_;
+  state.capture_time_ms = capture_time_ms_;
+  state.last_timestamp_time_ms = last_timestamp_time_ms_;
+  state.media_has_been_sent = media_has_been_sent_;
+
+  return state;
+}
+
+void RTPSender::SetRtxRtpState(const RtpState& rtp_state) {
+  rtc::CritScope lock(&send_critsect_);
+  sequence_number_rtx_ = rtp_state.sequence_number;
+}
+
+RtpState RTPSender::GetRtxRtpState() const {
+  rtc::CritScope lock(&send_critsect_);
+
+  RtpState state;
+  state.sequence_number = sequence_number_rtx_;
+  state.start_timestamp = timestamp_offset_;
+
+  return state;
+}
+
+void RTPSender::AddPacketToTransportFeedback(
+    uint16_t packet_id,
+    const RtpPacketToSend& packet,
+    const PacedPacketInfo& pacing_info) {
+  size_t packet_size = packet.payload_size() + packet.padding_size();
+  if (send_side_bwe_with_overhead_) {
+    packet_size = packet.size();
+  }
+
+  if (transport_feedback_observer_) {
+    transport_feedback_observer_->AddPacket(SSRC(), packet_id, packet_size,
+                                            pacing_info);
+  }
+}
+
+void RTPSender::UpdateRtpOverhead(const RtpPacketToSend& packet) {
+  if (!overhead_observer_)
+    return;
+  size_t overhead_bytes_per_packet;
+  {
+    rtc::CritScope lock(&send_critsect_);
+    if (rtp_overhead_bytes_per_packet_ == packet.headers_size()) {
+      return;
+    }
+    rtp_overhead_bytes_per_packet_ = packet.headers_size();
+    overhead_bytes_per_packet = rtp_overhead_bytes_per_packet_;
+  }
+  overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet);
+}
+
+int64_t RTPSender::LastTimestampTimeMs() const {
+  rtc::CritScope lock(&send_critsect_);
+  return last_timestamp_time_ms_;
+}
+
+void RTPSender::SendKeepAlive(uint8_t payload_type) {
+  std::unique_ptr<RtpPacketToSend> packet = AllocatePacket();
+  packet->SetPayloadType(payload_type);
+  // Set marker bit and timestamps in the same manner as plain padding packets.
+  packet->SetMarker(false);
+  {
+    rtc::CritScope lock(&send_critsect_);
+    packet->SetTimestamp(last_rtp_timestamp_);
+    packet->set_capture_time_ms(capture_time_ms_);
+  }
+  AssignSequenceNumber(packet.get());
+  SendToNetwork(std::move(packet), StorageType::kDontRetransmit,
+                RtpPacketSender::Priority::kLowPriority);
+}
+
+void RTPSender::SetRtt(int64_t rtt_ms) {
+  packet_history_.SetRtt(rtt_ms);
+  flexfec_packet_history_.SetRtt(rtt_ms);
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
new file mode 100644
index 0000000..5ff4a0f
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -0,0 +1,346 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/call/transport.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/playout_delay_oracle.h"
+#include "modules/rtp_rtcp/source/rtp_packet_history.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/deprecation.h"
+#include "rtc_base/random.h"
+#include "rtc_base/rate_statistics.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class OverheadObserver;
+class RateLimiter;
+class RtcEventLog;
+class RtpPacketToSend;
+class RTPSenderAudio;
+class RTPSenderVideo;
+
+class RTPSender {
+ public:
+  RTPSender(bool audio,
+            Clock* clock,
+            Transport* transport,
+            RtpPacketSender* paced_sender,
+            // TODO(brandtr): Remove |flexfec_sender| when that is hooked up
+            // to PacedSender instead.
+            FlexfecSender* flexfec_sender,
+            TransportSequenceNumberAllocator* sequence_number_allocator,
+            TransportFeedbackObserver* transport_feedback_callback,
+            BitrateStatisticsObserver* bitrate_callback,
+            FrameCountObserver* frame_count_observer,
+            SendSideDelayObserver* send_side_delay_observer,
+            RtcEventLog* event_log,
+            SendPacketObserver* send_packet_observer,
+            RateLimiter* nack_rate_limiter,
+            OverheadObserver* overhead_observer,
+            bool populate_network2_timestamp);
+
+  ~RTPSender();
+
+  void ProcessBitrate();
+
+  uint16_t ActualSendBitrateKbit() const;
+
+  uint32_t VideoBitrateSent() const;
+  uint32_t FecOverheadRate() const;
+  uint32_t NackOverheadRate() const;
+
+  int32_t RegisterPayload(const char* payload_name,
+                          const int8_t payload_type,
+                          const uint32_t frequency,
+                          const size_t channels,
+                          const uint32_t rate);
+
+  int32_t DeRegisterSendPayload(const int8_t payload_type);
+
+  void SetSendingMediaStatus(bool enabled);
+  bool SendingMedia() const;
+
+  void GetDataCounters(StreamDataCounters* rtp_stats,
+                       StreamDataCounters* rtx_stats) const;
+
+  uint32_t TimestampOffset() const;
+  void SetTimestampOffset(uint32_t timestamp);
+
+  void SetSSRC(uint32_t ssrc);
+
+  void SetMid(const std::string& mid);
+
+  uint16_t SequenceNumber() const;
+  void SetSequenceNumber(uint16_t seq);
+
+  void SetCsrcs(const std::vector<uint32_t>& csrcs);
+
+  void SetMaxRtpPacketSize(size_t max_packet_size);
+
+  bool SendOutgoingData(FrameType frame_type,
+                        int8_t payload_type,
+                        uint32_t timestamp,
+                        int64_t capture_time_ms,
+                        const uint8_t* payload_data,
+                        size_t payload_size,
+                        const RTPFragmentationHeader* fragmentation,
+                        const RTPVideoHeader* rtp_header,
+                        uint32_t* transport_frame_id_out,
+                        int64_t expected_retransmission_time_ms);
+
+  // RTP header extension
+  int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id);
+  bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) const;
+  int32_t DeregisterRtpHeaderExtension(RTPExtensionType type);
+
+  bool TimeToSendPacket(uint32_t ssrc,
+                        uint16_t sequence_number,
+                        int64_t capture_time_ms,
+                        bool retransmission,
+                        const PacedPacketInfo& pacing_info);
+  size_t TimeToSendPadding(size_t bytes, const PacedPacketInfo& pacing_info);
+
+  // NACK.
+  int SelectiveRetransmissions() const;
+  int SetSelectiveRetransmissions(uint8_t settings);
+  void OnReceivedNack(const std::vector<uint16_t>& nack_sequence_numbers,
+                      int64_t avg_rtt);
+
+  void SetStorePacketsStatus(bool enable, uint16_t number_to_store);
+
+  bool StorePackets() const;
+
+  int32_t ReSendPacket(uint16_t packet_id);
+
+  // Feedback to decide when to stop sending the playout delay and MID header
+  // extensions.
+  void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks);
+
+  // RTX.
+  void SetRtxStatus(int mode);
+  int RtxStatus() const;
+
+  uint32_t RtxSsrc() const;
+  void SetRtxSsrc(uint32_t ssrc);
+
+  void SetRtxPayloadType(int payload_type, int associated_payload_type);
+
+  // Size info for header extensions used by FEC packets.
+  static rtc::ArrayView<const RtpExtensionSize> FecExtensionSizes();
+
+  // Size info for header extensions used by video packets.
+  static rtc::ArrayView<const RtpExtensionSize> VideoExtensionSizes();
+
+  // Create empty packet, fills ssrc, csrcs and reserve place for header
+  // extensions RtpSender updates before sending.
+  std::unique_ptr<RtpPacketToSend> AllocatePacket() const;
+  // Allocate sequence number for provided packet.
+  // Save packet's fields to generate padding that doesn't break media stream.
+  // Return false if sending was turned off.
+  bool AssignSequenceNumber(RtpPacketToSend* packet);
+
+  // Used for padding and FEC packets only.
+  size_t RtpHeaderLength() const;
+  uint16_t AllocateSequenceNumber(uint16_t packets_to_send);
+  // Including RTP headers.
+  size_t MaxRtpPacketSize() const;
+
+  uint32_t SSRC() const;
+
+  absl::optional<uint32_t> FlexfecSsrc() const;
+
+  bool SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
+                     StorageType storage,
+                     RtpPacketSender::Priority priority);
+
+  // Audio.
+
+  // Send a DTMF tone using RFC 2833 (4733).
+  int32_t SendTelephoneEvent(uint8_t key, uint16_t time_ms, uint8_t level);
+
+  // Store the audio level in d_bov for
+  // header-extension-for-audio-level-indication.
+  int32_t SetAudioLevel(uint8_t level_d_bov);
+
+  uint32_t MaxConfiguredBitrateVideo() const;
+
+  // ULPFEC.
+  void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
+
+  bool SetFecParameters(const FecProtectionParams& delta_params,
+                        const FecProtectionParams& key_params);
+
+  // Called on update of RTP statistics.
+  void RegisterRtpStatisticsCallback(StreamDataCountersCallback* callback);
+  StreamDataCountersCallback* GetRtpStatisticsCallback() const;
+
+  uint32_t BitrateSent() const;
+
+  void SetRtpState(const RtpState& rtp_state);
+  RtpState GetRtpState() const;
+  void SetRtxRtpState(const RtpState& rtp_state);
+  RtpState GetRtxRtpState() const;
+
+  int64_t LastTimestampTimeMs() const;
+  void SendKeepAlive(uint8_t payload_type);
+
+  void SetRtt(int64_t rtt_ms);
+
+ protected:
+  int32_t CheckPayloadType(int8_t payload_type, VideoCodecType* video_type);
+
+ private:
+  // Maps capture time in milliseconds to send-side delay in milliseconds.
+  // Send-side delay is the difference between transmission time and capture
+  // time.
+  typedef std::map<int64_t, int> SendDelayMap;
+
+  size_t SendPadData(size_t bytes, const PacedPacketInfo& pacing_info);
+
+  bool PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
+                            bool send_over_rtx,
+                            bool is_retransmit,
+                            const PacedPacketInfo& pacing_info);
+
+  // Return the number of bytes sent.  Note that both of these functions may
+  // return a larger value that their argument.
+  size_t TrySendRedundantPayloads(size_t bytes,
+                                  const PacedPacketInfo& pacing_info);
+
+  std::unique_ptr<RtpPacketToSend> BuildRtxPacket(
+      const RtpPacketToSend& packet);
+
+  bool SendPacketToNetwork(const RtpPacketToSend& packet,
+                           const PacketOptions& options,
+                           const PacedPacketInfo& pacing_info);
+
+  void UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms);
+  void UpdateOnSendPacket(int packet_id,
+                          int64_t capture_time_ms,
+                          uint32_t ssrc);
+
+  bool UpdateTransportSequenceNumber(RtpPacketToSend* packet,
+                                     int* packet_id) const;
+
+  void UpdateRtpStats(const RtpPacketToSend& packet,
+                      bool is_rtx,
+                      bool is_retransmit);
+  bool IsFecPacket(const RtpPacketToSend& packet) const;
+
+  void AddPacketToTransportFeedback(uint16_t packet_id,
+                                    const RtpPacketToSend& packet,
+                                    const PacedPacketInfo& pacing_info);
+
+  void UpdateRtpOverhead(const RtpPacketToSend& packet);
+
+  Clock* const clock_;
+  const int64_t clock_delta_ms_;
+  Random random_ RTC_GUARDED_BY(send_critsect_);
+
+  const bool audio_configured_;
+  const std::unique_ptr<RTPSenderAudio> audio_;
+  const std::unique_ptr<RTPSenderVideo> video_;
+
+  RtpPacketSender* const paced_sender_;
+  TransportSequenceNumberAllocator* const transport_sequence_number_allocator_;
+  TransportFeedbackObserver* const transport_feedback_observer_;
+  int64_t last_capture_time_ms_sent_;
+  rtc::CriticalSection send_critsect_;
+
+  Transport* transport_;
+  bool sending_media_ RTC_GUARDED_BY(send_critsect_);
+
+  size_t max_packet_size_;
+
+  int8_t last_payload_type_ RTC_GUARDED_BY(send_critsect_);
+  std::map<int8_t, RtpUtility::Payload*> payload_type_map_;
+
+  RtpHeaderExtensionMap rtp_header_extension_map_
+      RTC_GUARDED_BY(send_critsect_);
+
+  // Tracks the current request for playout delay limits from application
+  // and decides whether the current RTP frame should include the playout
+  // delay extension on header.
+  PlayoutDelayOracle playout_delay_oracle_;
+
+  RtpPacketHistory packet_history_;
+  // TODO(brandtr): Remove |flexfec_packet_history_| when the FlexfecSender
+  // is hooked up to the PacedSender.
+  RtpPacketHistory flexfec_packet_history_;
+
+  // Statistics
+  rtc::CriticalSection statistics_crit_;
+  SendDelayMap send_delays_ RTC_GUARDED_BY(statistics_crit_);
+  FrameCounts frame_counts_ RTC_GUARDED_BY(statistics_crit_);
+  StreamDataCounters rtp_stats_ RTC_GUARDED_BY(statistics_crit_);
+  StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(statistics_crit_);
+  StreamDataCountersCallback* rtp_stats_callback_
+      RTC_GUARDED_BY(statistics_crit_);
+  RateStatistics total_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_);
+  RateStatistics nack_bitrate_sent_ RTC_GUARDED_BY(statistics_crit_);
+  FrameCountObserver* const frame_count_observer_;
+  SendSideDelayObserver* const send_side_delay_observer_;
+  RtcEventLog* const event_log_;
+  SendPacketObserver* const send_packet_observer_;
+  BitrateStatisticsObserver* const bitrate_callback_;
+
+  // RTP variables
+  uint32_t timestamp_offset_ RTC_GUARDED_BY(send_critsect_);
+  uint32_t remote_ssrc_ RTC_GUARDED_BY(send_critsect_);
+  bool sequence_number_forced_ RTC_GUARDED_BY(send_critsect_);
+  uint16_t sequence_number_ RTC_GUARDED_BY(send_critsect_);
+  uint16_t sequence_number_rtx_ RTC_GUARDED_BY(send_critsect_);
+  // Must be explicitly set by the application, use of absl::optional
+  // only to keep track of correct use.
+  absl::optional<uint32_t> ssrc_ RTC_GUARDED_BY(send_critsect_);
+  // MID value to send in the MID header extension.
+  std::string mid_ RTC_GUARDED_BY(send_critsect_);
+  uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(send_critsect_);
+  int64_t capture_time_ms_ RTC_GUARDED_BY(send_critsect_);
+  int64_t last_timestamp_time_ms_ RTC_GUARDED_BY(send_critsect_);
+  bool media_has_been_sent_ RTC_GUARDED_BY(send_critsect_);
+  bool last_packet_marker_bit_ RTC_GUARDED_BY(send_critsect_);
+  std::vector<uint32_t> csrcs_ RTC_GUARDED_BY(send_critsect_);
+  int rtx_ RTC_GUARDED_BY(send_critsect_);
+  absl::optional<uint32_t> ssrc_rtx_ RTC_GUARDED_BY(send_critsect_);
+  // Mapping rtx_payload_type_map_[associated] = rtx.
+  std::map<int8_t, int8_t> rtx_payload_type_map_ RTC_GUARDED_BY(send_critsect_);
+  size_t rtp_overhead_bytes_per_packet_ RTC_GUARDED_BY(send_critsect_);
+
+  RateLimiter* const retransmission_rate_limiter_;
+  OverheadObserver* overhead_observer_;
+  const bool populate_network2_timestamp_;
+
+  const bool send_side_bwe_with_overhead_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.cc b/modules/rtp_rtcp/source/rtp_sender_audio.cc
new file mode 100644
index 0000000..bf86a39
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_audio.cc
@@ -0,0 +1,331 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_sender_audio.h"
+
+#include <string.h>
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/timeutils.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+
+RTPSenderAudio::RTPSenderAudio(Clock* clock, RTPSender* rtp_sender)
+    : clock_(clock), rtp_sender_(rtp_sender) {}
+
+RTPSenderAudio::~RTPSenderAudio() {}
+
+int32_t RTPSenderAudio::RegisterAudioPayload(
+    const char payloadName[RTP_PAYLOAD_NAME_SIZE],
+    const int8_t payload_type,
+    const uint32_t frequency,
+    const size_t channels,
+    const uint32_t rate,
+    RtpUtility::Payload** payload) {
+  if (RtpUtility::StringCompare(payloadName, "cn", 2)) {
+    rtc::CritScope cs(&send_audio_critsect_);
+    //  we can have multiple CNG payload types
+    switch (frequency) {
+      case 8000:
+        cngnb_payload_type_ = payload_type;
+        break;
+      case 16000:
+        cngwb_payload_type_ = payload_type;
+        break;
+      case 32000:
+        cngswb_payload_type_ = payload_type;
+        break;
+      case 48000:
+        cngfb_payload_type_ = payload_type;
+        break;
+      default:
+        return -1;
+    }
+  } else if (RtpUtility::StringCompare(payloadName, "telephone-event", 15)) {
+    rtc::CritScope cs(&send_audio_critsect_);
+    // Don't add it to the list
+    // we dont want to allow send with a DTMF payloadtype
+    dtmf_payload_type_ = payload_type;
+    dtmf_payload_freq_ = frequency;
+    return 0;
+  }
+  *payload = new RtpUtility::Payload(
+      payloadName,
+      PayloadUnion(AudioPayload{
+          SdpAudioFormat(payloadName, frequency, channels), rate}));
+  return 0;
+}
+
+bool RTPSenderAudio::MarkerBit(FrameType frame_type, int8_t payload_type) {
+  rtc::CritScope cs(&send_audio_critsect_);
+  // for audio true for first packet in a speech burst
+  bool marker_bit = false;
+  if (last_payload_type_ != payload_type) {
+    if (payload_type != -1 && (cngnb_payload_type_ == payload_type ||
+                               cngwb_payload_type_ == payload_type ||
+                               cngswb_payload_type_ == payload_type ||
+                               cngfb_payload_type_ == payload_type)) {
+      // Only set a marker bit when we change payload type to a non CNG
+      return false;
+    }
+
+    // payload_type differ
+    if (last_payload_type_ == -1) {
+      if (frame_type != kAudioFrameCN) {
+        // first packet and NOT CNG
+        return true;
+      } else {
+        // first packet and CNG
+        inband_vad_active_ = true;
+        return false;
+      }
+    }
+
+    // not first packet AND
+    // not CNG AND
+    // payload_type changed
+
+    // set a marker bit when we change payload type
+    marker_bit = true;
+  }
+
+  // For G.723 G.729, AMR etc we can have inband VAD
+  if (frame_type == kAudioFrameCN) {
+    inband_vad_active_ = true;
+  } else if (inband_vad_active_) {
+    inband_vad_active_ = false;
+    marker_bit = true;
+  }
+  return marker_bit;
+}
+
+bool RTPSenderAudio::SendAudio(FrameType frame_type,
+                               int8_t payload_type,
+                               uint32_t rtp_timestamp,
+                               const uint8_t* payload_data,
+                               size_t payload_size) {
+  // From RFC 4733:
+  // A source has wide latitude as to how often it sends event updates. A
+  // natural interval is the spacing between non-event audio packets. [...]
+  // Alternatively, a source MAY decide to use a different spacing for event
+  // updates, with a value of 50 ms RECOMMENDED.
+  constexpr int kDtmfIntervalTimeMs = 50;
+  uint8_t audio_level_dbov = 0;
+  uint32_t dtmf_payload_freq = 0;
+  {
+    rtc::CritScope cs(&send_audio_critsect_);
+    audio_level_dbov = audio_level_dbov_;
+    dtmf_payload_freq = dtmf_payload_freq_;
+  }
+
+  // Check if we have pending DTMFs to send
+  if (!dtmf_event_is_on_ && dtmf_queue_.PendingDtmf()) {
+    if ((clock_->TimeInMilliseconds() - dtmf_time_last_sent_) >
+        kDtmfIntervalTimeMs) {
+      // New tone to play
+      dtmf_timestamp_ = rtp_timestamp;
+      if (dtmf_queue_.NextDtmf(&dtmf_current_event_)) {
+        dtmf_event_first_packet_sent_ = false;
+        dtmf_length_samples_ =
+            dtmf_current_event_.duration_ms * (dtmf_payload_freq / 1000);
+        dtmf_event_is_on_ = true;
+      }
+    }
+  }
+
+  // A source MAY send events and coded audio packets for the same time
+  // but we don't support it
+  if (dtmf_event_is_on_) {
+    if (frame_type == kEmptyFrame) {
+      // kEmptyFrame is used to drive the DTMF when in CN mode
+      // it can be triggered more frequently than we want to send the
+      // DTMF packets.
+      const unsigned int dtmf_interval_time_rtp =
+          dtmf_payload_freq * kDtmfIntervalTimeMs / 1000;
+      if ((rtp_timestamp - dtmf_timestamp_last_sent_) <
+          dtmf_interval_time_rtp) {
+        // not time to send yet
+        return true;
+      }
+    }
+    dtmf_timestamp_last_sent_ = rtp_timestamp;
+    uint32_t dtmf_duration_samples = rtp_timestamp - dtmf_timestamp_;
+    bool ended = false;
+    bool send = true;
+
+    if (dtmf_length_samples_ > dtmf_duration_samples) {
+      if (dtmf_duration_samples <= 0) {
+        // Skip send packet at start, since we shouldn't use duration 0
+        send = false;
+      }
+    } else {
+      ended = true;
+      dtmf_event_is_on_ = false;
+      dtmf_time_last_sent_ = clock_->TimeInMilliseconds();
+    }
+    if (send) {
+      if (dtmf_duration_samples > 0xffff) {
+        // RFC 4733 2.5.2.3 Long-Duration Events
+        SendTelephoneEventPacket(ended, dtmf_timestamp_,
+                                 static_cast<uint16_t>(0xffff), false);
+
+        // set new timestap for this segment
+        dtmf_timestamp_ = rtp_timestamp;
+        dtmf_duration_samples -= 0xffff;
+        dtmf_length_samples_ -= 0xffff;
+
+        return SendTelephoneEventPacket(
+            ended, dtmf_timestamp_,
+            static_cast<uint16_t>(dtmf_duration_samples), false);
+      } else {
+        if (!SendTelephoneEventPacket(ended, dtmf_timestamp_,
+                                      dtmf_duration_samples,
+                                      !dtmf_event_first_packet_sent_)) {
+          return false;
+        }
+        dtmf_event_first_packet_sent_ = true;
+        return true;
+      }
+    }
+    return true;
+  }
+  if (payload_size == 0 || payload_data == NULL) {
+    if (frame_type == kEmptyFrame) {
+      // we don't send empty audio RTP packets
+      // no error since we use it to drive DTMF when we use VAD
+      return true;
+    }
+    return false;
+  }
+
+  std::unique_ptr<RtpPacketToSend> packet = rtp_sender_->AllocatePacket();
+  packet->SetMarker(MarkerBit(frame_type, payload_type));
+  packet->SetPayloadType(payload_type);
+  packet->SetTimestamp(rtp_timestamp);
+  packet->set_capture_time_ms(clock_->TimeInMilliseconds());
+  // Update audio level extension, if included.
+  packet->SetExtension<AudioLevel>(frame_type == kAudioFrameSpeech,
+                                   audio_level_dbov);
+
+  uint8_t* payload = packet->AllocatePayload(payload_size);
+  if (!payload)  // Too large payload buffer.
+    return false;
+  memcpy(payload, payload_data, payload_size);
+
+  if (!rtp_sender_->AssignSequenceNumber(packet.get()))
+    return false;
+
+  {
+    rtc::CritScope cs(&send_audio_critsect_);
+    last_payload_type_ = payload_type;
+  }
+  TRACE_EVENT_ASYNC_END2("webrtc", "Audio", rtp_timestamp, "timestamp",
+                         packet->Timestamp(), "seqnum",
+                         packet->SequenceNumber());
+  bool send_result = rtp_sender_->SendToNetwork(
+      std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority);
+  if (first_packet_sent_()) {
+    RTC_LOG(LS_INFO) << "First audio RTP packet sent to pacer";
+  }
+  return send_result;
+}
+
+// Audio level magnitude and voice activity flag are set for each RTP packet
+int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dbov) {
+  if (level_dbov > 127) {
+    return -1;
+  }
+  rtc::CritScope cs(&send_audio_critsect_);
+  audio_level_dbov_ = level_dbov;
+  return 0;
+}
+
+// Send a TelephoneEvent tone using RFC 2833 (4733)
+int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key,
+                                           uint16_t time_ms,
+                                           uint8_t level) {
+  DtmfQueue::Event event;
+  {
+    rtc::CritScope lock(&send_audio_critsect_);
+    if (dtmf_payload_type_ < 0) {
+      // TelephoneEvent payloadtype not configured
+      return -1;
+    }
+    event.payload_type = dtmf_payload_type_;
+  }
+  event.key = key;
+  event.duration_ms = time_ms;
+  event.level = level;
+  return dtmf_queue_.AddDtmf(event) ? 0 : -1;
+}
+
+bool RTPSenderAudio::SendTelephoneEventPacket(bool ended,
+                                              uint32_t dtmf_timestamp,
+                                              uint16_t duration,
+                                              bool marker_bit) {
+  uint8_t send_count = 1;
+  bool result = true;
+
+  if (ended) {
+    // resend last packet in an event 3 times
+    send_count = 3;
+  }
+  do {
+    // Send DTMF data.
+    constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
+    constexpr size_t kDtmfSize = 4;
+    std::unique_ptr<RtpPacketToSend> packet(
+        new RtpPacketToSend(kNoExtensions, kRtpHeaderSize + kDtmfSize));
+    packet->SetPayloadType(dtmf_current_event_.payload_type);
+    packet->SetMarker(marker_bit);
+    packet->SetSsrc(rtp_sender_->SSRC());
+    packet->SetTimestamp(dtmf_timestamp);
+    packet->set_capture_time_ms(clock_->TimeInMilliseconds());
+    if (!rtp_sender_->AssignSequenceNumber(packet.get()))
+      return false;
+
+    // Create DTMF data.
+    uint8_t* dtmfbuffer = packet->AllocatePayload(kDtmfSize);
+    RTC_DCHECK(dtmfbuffer);
+    /*    From RFC 2833:
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |     event     |E|R| volume    |          duration             |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    */
+    // R bit always cleared
+    uint8_t R = 0x00;
+    uint8_t volume = dtmf_current_event_.level;
+
+    // First packet un-ended
+    uint8_t E = ended ? 0x80 : 0x00;
+
+    // First byte is Event number, equals key number
+    dtmfbuffer[0] = dtmf_current_event_.key;
+    dtmfbuffer[1] = E | R | volume;
+    ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 2, duration);
+
+    result = rtp_sender_->SendToNetwork(std::move(packet), kAllowRetransmission,
+                                        RtpPacketSender::kHighPriority);
+    send_count--;
+  } while (send_count > 0 && result);
+
+  return result;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_audio.h b/modules/rtp_rtcp/source/rtp_sender_audio.h
new file mode 100644
index 0000000..16648cd
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_audio.h
@@ -0,0 +1,97 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_SENDER_AUDIO_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_AUDIO_H_
+
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/source/dtmf_queue.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/onetimeevent.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class RTPSenderAudio {
+ public:
+  RTPSenderAudio(Clock* clock, RTPSender* rtp_sender);
+  ~RTPSenderAudio();
+
+  int32_t RegisterAudioPayload(const char payloadName[RTP_PAYLOAD_NAME_SIZE],
+                               int8_t payload_type,
+                               uint32_t frequency,
+                               size_t channels,
+                               uint32_t rate,
+                               RtpUtility::Payload** payload);
+
+  bool SendAudio(FrameType frame_type,
+                 int8_t payload_type,
+                 uint32_t capture_timestamp,
+                 const uint8_t* payload_data,
+                 size_t payload_size);
+
+  // Store the audio level in dBov for
+  // header-extension-for-audio-level-indication.
+  // Valid range is [0,100]. Actual value is negative.
+  int32_t SetAudioLevel(uint8_t level_dbov);
+
+  // Send a DTMF tone using RFC 2833 (4733)
+  int32_t SendTelephoneEvent(uint8_t key, uint16_t time_ms, uint8_t level);
+
+ protected:
+  bool SendTelephoneEventPacket(
+      bool ended,
+      uint32_t dtmf_timestamp,
+      uint16_t duration,
+      bool marker_bit);  // set on first packet in talk burst
+
+  bool MarkerBit(FrameType frame_type, int8_t payload_type);
+
+ private:
+  Clock* const clock_ = nullptr;
+  RTPSender* const rtp_sender_ = nullptr;
+
+  rtc::CriticalSection send_audio_critsect_;
+
+  // DTMF.
+  bool dtmf_event_is_on_ = false;
+  bool dtmf_event_first_packet_sent_ = false;
+  int8_t dtmf_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1;
+  uint32_t dtmf_payload_freq_ RTC_GUARDED_BY(send_audio_critsect_) = 8000;
+  uint32_t dtmf_timestamp_ = 0;
+  uint32_t dtmf_length_samples_ = 0;
+  int64_t dtmf_time_last_sent_ = 0;
+  uint32_t dtmf_timestamp_last_sent_ = 0;
+  DtmfQueue::Event dtmf_current_event_;
+  DtmfQueue dtmf_queue_;
+
+  // VAD detection, used for marker bit.
+  bool inband_vad_active_ RTC_GUARDED_BY(send_audio_critsect_) = false;
+  int8_t cngnb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1;
+  int8_t cngwb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1;
+  int8_t cngswb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1;
+  int8_t cngfb_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1;
+  int8_t last_payload_type_ RTC_GUARDED_BY(send_audio_critsect_) = -1;
+
+  // Audio level indication.
+  // (https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/)
+  uint8_t audio_level_dbov_ RTC_GUARDED_BY(send_audio_critsect_) = 0;
+  OneTimeEvent first_packet_sent_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSenderAudio);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_AUDIO_H_
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
new file mode 100644
index 0000000..1d0ddaf
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -0,0 +1,2085 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <memory>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "api/video/video_timing.h"
+#include "logging/rtc_event_log/events/rtc_event.h"
+#include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/rate_limiter.h"
+#include "test/field_trial.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/mock_transport.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+namespace {
+const int kTransmissionTimeOffsetExtensionId = 1;
+const int kAbsoluteSendTimeExtensionId = 14;
+const int kTransportSequenceNumberExtensionId = 13;
+const int kVideoTimingExtensionId = 12;
+const int kMidExtensionId = 11;
+const int kPayload = 100;
+const int kRtxPayload = 98;
+const uint32_t kTimestamp = 10;
+const uint16_t kSeqNum = 33;
+const uint32_t kSsrc = 725242;
+const int kMaxPacketLength = 1500;
+const uint8_t kAudioLevel = 0x5a;
+const uint16_t kTransportSequenceNumber = 0xaabbu;
+const uint8_t kAudioLevelExtensionId = 9;
+const int kAudioPayload = 103;
+const uint64_t kStartTime = 123456789;
+const size_t kMaxPaddingSize = 224u;
+const int kVideoRotationExtensionId = 5;
+const size_t kGenericHeaderLength = 1;
+const uint8_t kPayloadData[] = {47, 11, 32, 93, 89};
+const int64_t kDefaultExpectedRetransmissionTimeMs = 125;
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Invoke;
+
+uint64_t ConvertMsToAbsSendTime(int64_t time_ms) {
+  return (((time_ms << 18) + 500) / 1000) & 0x00ffffff;
+}
+
+class LoopbackTransportTest : public webrtc::Transport {
+ public:
+  LoopbackTransportTest() : total_bytes_sent_(0) {
+    receivers_extensions_.Register(kRtpExtensionTransmissionTimeOffset,
+                                   kTransmissionTimeOffsetExtensionId);
+    receivers_extensions_.Register(kRtpExtensionAbsoluteSendTime,
+                                   kAbsoluteSendTimeExtensionId);
+    receivers_extensions_.Register(kRtpExtensionTransportSequenceNumber,
+                                   kTransportSequenceNumberExtensionId);
+    receivers_extensions_.Register(kRtpExtensionVideoRotation,
+                                   kVideoRotationExtensionId);
+    receivers_extensions_.Register(kRtpExtensionAudioLevel,
+                                   kAudioLevelExtensionId);
+    receivers_extensions_.Register(kRtpExtensionVideoTiming,
+                                   kVideoTimingExtensionId);
+    receivers_extensions_.Register(kRtpExtensionMid, kMidExtensionId);
+  }
+
+  bool SendRtp(const uint8_t* data,
+               size_t len,
+               const PacketOptions& options) override {
+    last_options_ = options;
+    total_bytes_sent_ += len;
+    sent_packets_.push_back(RtpPacketReceived(&receivers_extensions_));
+    EXPECT_TRUE(sent_packets_.back().Parse(data, len));
+    return true;
+  }
+  bool SendRtcp(const uint8_t* data, size_t len) override { return false; }
+  const RtpPacketReceived& last_sent_packet() { return sent_packets_.back(); }
+  int packets_sent() { return sent_packets_.size(); }
+
+  size_t total_bytes_sent_;
+  PacketOptions last_options_;
+  std::vector<RtpPacketReceived> sent_packets_;
+
+ private:
+  RtpHeaderExtensionMap receivers_extensions_;
+};
+
+MATCHER_P(SameRtcEventTypeAs, value, "") {
+  return value == arg->GetType();
+}
+
+}  // namespace
+
+class MockRtpPacketSender : public RtpPacketSender {
+ public:
+  MockRtpPacketSender() {}
+  virtual ~MockRtpPacketSender() {}
+
+  MOCK_METHOD6(InsertPacket,
+               void(Priority priority,
+                    uint32_t ssrc,
+                    uint16_t sequence_number,
+                    int64_t capture_time_ms,
+                    size_t bytes,
+                    bool retransmission));
+};
+
+class MockTransportSequenceNumberAllocator
+    : public TransportSequenceNumberAllocator {
+ public:
+  MOCK_METHOD0(AllocateSequenceNumber, uint16_t());
+};
+
+class MockSendPacketObserver : public SendPacketObserver {
+ public:
+  MOCK_METHOD3(OnSendPacket, void(uint16_t, int64_t, uint32_t));
+};
+
+class MockTransportFeedbackObserver : public TransportFeedbackObserver {
+ public:
+  MOCK_METHOD4(AddPacket,
+               void(uint32_t, uint16_t, size_t, const PacedPacketInfo&));
+  MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&));
+  MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>());
+};
+
+class MockOverheadObserver : public OverheadObserver {
+ public:
+  MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet));
+};
+
+class RtpSenderTest : public ::testing::TestWithParam<bool> {
+ protected:
+  RtpSenderTest()
+      : fake_clock_(kStartTime),
+        mock_rtc_event_log_(),
+        mock_paced_sender_(),
+        retransmission_rate_limiter_(&fake_clock_, 1000),
+        rtp_sender_(),
+        payload_(kPayload),
+        transport_(),
+        kMarkerBit(true),
+        field_trials_(GetParam() ? "WebRTC-SendSideBwe-WithOverhead/Enabled/"
+                                 : "") {}
+
+  void SetUp() override { SetUpRtpSender(true, false); }
+
+  void SetUpRtpSender(bool pacer, bool populate_network2) {
+    rtp_sender_.reset(new RTPSender(
+        false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr,
+        nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+        &mock_rtc_event_log_, &send_packet_observer_,
+        &retransmission_rate_limiter_, nullptr, populate_network2));
+    rtp_sender_->SetSequenceNumber(kSeqNum);
+    rtp_sender_->SetTimestampOffset(0);
+    rtp_sender_->SetSSRC(kSsrc);
+  }
+
+  SimulatedClock fake_clock_;
+  testing::NiceMock<MockRtcEventLog> mock_rtc_event_log_;
+  MockRtpPacketSender mock_paced_sender_;
+  testing::StrictMock<MockTransportSequenceNumberAllocator> seq_num_allocator_;
+  testing::StrictMock<MockSendPacketObserver> send_packet_observer_;
+  testing::StrictMock<MockTransportFeedbackObserver> feedback_observer_;
+  RateLimiter retransmission_rate_limiter_;
+  std::unique_ptr<RTPSender> rtp_sender_;
+  int payload_;
+  LoopbackTransportTest transport_;
+  const bool kMarkerBit;
+  test::ScopedFieldTrials field_trials_;
+
+  void VerifyRTPHeaderCommon(const RTPHeader& rtp_header) {
+    VerifyRTPHeaderCommon(rtp_header, kMarkerBit, 0);
+  }
+
+  void VerifyRTPHeaderCommon(const RTPHeader& rtp_header, bool marker_bit) {
+    VerifyRTPHeaderCommon(rtp_header, marker_bit, 0);
+  }
+
+  void VerifyRTPHeaderCommon(const RTPHeader& rtp_header,
+                             bool marker_bit,
+                             uint8_t number_of_csrcs) {
+    EXPECT_EQ(marker_bit, rtp_header.markerBit);
+    EXPECT_EQ(payload_, rtp_header.payloadType);
+    EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber);
+    EXPECT_EQ(kTimestamp, rtp_header.timestamp);
+    EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.ssrc);
+    EXPECT_EQ(number_of_csrcs, rtp_header.numCSRCs);
+    EXPECT_EQ(0U, rtp_header.paddingLength);
+  }
+
+  std::unique_ptr<RtpPacketToSend> BuildRtpPacket(int payload_type,
+                                                  bool marker_bit,
+                                                  uint32_t timestamp,
+                                                  int64_t capture_time_ms) {
+    auto packet = rtp_sender_->AllocatePacket();
+    packet->SetPayloadType(payload_type);
+    packet->SetMarker(marker_bit);
+    packet->SetTimestamp(timestamp);
+    packet->set_capture_time_ms(capture_time_ms);
+    EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+    return packet;
+  }
+
+  void SendPacket(int64_t capture_time_ms, int payload_length) {
+    uint32_t timestamp = capture_time_ms * 90;
+    auto packet =
+        BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms);
+    packet->AllocatePayload(payload_length);
+
+    // Packet should be stored in a send bucket.
+    EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                           kAllowRetransmission,
+                                           RtpPacketSender::kNormalPriority));
+  }
+
+  void SendGenericPayload() {
+    const uint32_t kTimestamp = 1234;
+    const uint8_t kPayloadType = 127;
+    const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
+    char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+    EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
+                                              0, 1500));
+
+    EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+        kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData,
+        sizeof(kPayloadData), nullptr, nullptr, nullptr,
+        kDefaultExpectedRetransmissionTimeMs));
+  }
+};
+
+// TODO(pbos): Move tests over from WithoutPacer to RtpSenderTest as this is our
+// default code path.
+class RtpSenderTestWithoutPacer : public RtpSenderTest {
+ public:
+  void SetUp() override { SetUpRtpSender(false, false); }
+};
+
+class TestRtpSenderVideo : public RTPSenderVideo {
+ public:
+  TestRtpSenderVideo(Clock* clock,
+                     RTPSender* rtp_sender,
+                     FlexfecSender* flexfec_sender)
+      : RTPSenderVideo(clock, rtp_sender, flexfec_sender) {}
+  ~TestRtpSenderVideo() override {}
+
+  StorageType GetStorageType(const RTPVideoHeader& header,
+                             int32_t retransmission_settings,
+                             int64_t expected_retransmission_time_ms) {
+    return RTPSenderVideo::GetStorageType(GetTemporalId(header),
+                                          retransmission_settings,
+                                          expected_retransmission_time_ms);
+  }
+};
+
+class RtpSenderVideoTest : public RtpSenderTest {
+ protected:
+  void SetUp() override {
+    // TODO(pbos): Set up to use pacer.
+    SetUpRtpSender(false, false);
+    rtp_sender_video_.reset(
+        new TestRtpSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr));
+  }
+  std::unique_ptr<TestRtpSenderVideo> rtp_sender_video_;
+};
+
+TEST_P(RtpSenderTestWithoutPacer, AllocatePacketSetCsrc) {
+  // Configure rtp_sender with csrc.
+  std::vector<uint32_t> csrcs;
+  csrcs.push_back(0x23456789);
+  rtp_sender_->SetCsrcs(csrcs);
+
+  auto packet = rtp_sender_->AllocatePacket();
+
+  ASSERT_TRUE(packet);
+  EXPECT_EQ(rtp_sender_->SSRC(), packet->Ssrc());
+  EXPECT_EQ(csrcs, packet->Csrcs());
+}
+
+TEST_P(RtpSenderTestWithoutPacer, AllocatePacketReserveExtensions) {
+  // Configure rtp_sender with extensions.
+  ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransmissionTimeOffset,
+                   kTransmissionTimeOffsetExtensionId));
+  ASSERT_EQ(
+      0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
+                                                 kAbsoluteSendTimeExtensionId));
+  ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
+                                                       kAudioLevelExtensionId));
+  ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+  ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  auto packet = rtp_sender_->AllocatePacket();
+
+  ASSERT_TRUE(packet);
+  // Preallocate BWE extensions RtpSender set itself.
+  EXPECT_TRUE(packet->HasExtension<TransmissionOffset>());
+  EXPECT_TRUE(packet->HasExtension<AbsoluteSendTime>());
+  EXPECT_TRUE(packet->HasExtension<TransportSequenceNumber>());
+  // Do not allocate media specific extensions.
+  EXPECT_FALSE(packet->HasExtension<AudioLevel>());
+  EXPECT_FALSE(packet->HasExtension<VideoOrientation>());
+}
+
+TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberAdvanceSequenceNumber) {
+  auto packet = rtp_sender_->AllocatePacket();
+  ASSERT_TRUE(packet);
+  const uint16_t sequence_number = rtp_sender_->SequenceNumber();
+
+  EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+
+  EXPECT_EQ(sequence_number, packet->SequenceNumber());
+  EXPECT_EQ(sequence_number + 1, rtp_sender_->SequenceNumber());
+}
+
+TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberFailsOnNotSending) {
+  auto packet = rtp_sender_->AllocatePacket();
+  ASSERT_TRUE(packet);
+
+  rtp_sender_->SetSendingMediaStatus(false);
+  EXPECT_FALSE(rtp_sender_->AssignSequenceNumber(packet.get()));
+}
+
+TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberMayAllowPaddingOnVideo) {
+  constexpr size_t kPaddingSize = 100;
+  auto packet = rtp_sender_->AllocatePacket();
+  ASSERT_TRUE(packet);
+
+  ASSERT_FALSE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo()));
+  packet->SetMarker(false);
+  ASSERT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+  // Packet without marker bit doesn't allow padding on video stream.
+  EXPECT_FALSE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo()));
+
+  packet->SetMarker(true);
+  ASSERT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+  // Packet with marker bit allows send padding.
+  EXPECT_TRUE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, AssignSequenceNumberAllowsPaddingOnAudio) {
+  MockTransport transport;
+  const bool kEnableAudio = true;
+  rtp_sender_.reset(new RTPSender(
+      kEnableAudio, &fake_clock_, &transport, &mock_paced_sender_, nullptr,
+      nullptr, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+      nullptr, &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetTimestampOffset(0);
+  rtp_sender_->SetSSRC(kSsrc);
+
+  std::unique_ptr<RtpPacketToSend> audio_packet = rtp_sender_->AllocatePacket();
+  // Padding on audio stream allowed regardless of marker in the last packet.
+  audio_packet->SetMarker(false);
+  audio_packet->SetPayloadType(kPayload);
+  rtp_sender_->AssignSequenceNumber(audio_packet.get());
+
+  const size_t kPaddingSize = 59;
+  EXPECT_CALL(transport, SendRtp(_, kPaddingSize + kRtpHeaderSize, _))
+      .WillOnce(testing::Return(true));
+  EXPECT_EQ(kPaddingSize,
+            rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo()));
+
+  // Requested padding size is too small, will send a larger one.
+  const size_t kMinPaddingSize = 50;
+  EXPECT_CALL(transport, SendRtp(_, kMinPaddingSize + kRtpHeaderSize, _))
+      .WillOnce(testing::Return(true));
+  EXPECT_EQ(kMinPaddingSize, rtp_sender_->TimeToSendPadding(kMinPaddingSize - 5,
+                                                            PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberSetPaddingTimestamps) {
+  constexpr size_t kPaddingSize = 100;
+  auto packet = rtp_sender_->AllocatePacket();
+  ASSERT_TRUE(packet);
+  packet->SetMarker(true);
+  packet->SetTimestamp(kTimestamp);
+
+  ASSERT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+  ASSERT_TRUE(rtp_sender_->TimeToSendPadding(kPaddingSize, PacedPacketInfo()));
+
+  ASSERT_EQ(1u, transport_.sent_packets_.size());
+  // Verify padding packet timestamp.
+  EXPECT_EQ(kTimestamp, transport_.last_sent_packet().Timestamp());
+}
+
+TEST_P(RtpSenderTestWithoutPacer,
+       TransportFeedbackObserverGetsCorrectByteCount) {
+  constexpr int kRtpOverheadBytesPerPacket = 12 + 8;
+  testing::NiceMock<MockOverheadObserver> mock_overhead_observer;
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
+      &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+      nullptr, &retransmission_rate_limiter_, &mock_overhead_observer, false));
+  rtp_sender_->SetSSRC(kSsrc);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+  EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+      .WillOnce(testing::Return(kTransportSequenceNumber));
+
+  const size_t expected_bytes =
+      GetParam() ? sizeof(kPayloadData) + kGenericHeaderLength +
+                       kRtpOverheadBytesPerPacket
+                 : sizeof(kPayloadData) + kGenericHeaderLength;
+
+  EXPECT_CALL(feedback_observer_,
+              AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber,
+                        expected_bytes, PacedPacketInfo()))
+      .Times(1);
+  EXPECT_CALL(mock_overhead_observer,
+              OnOverheadChanged(kRtpOverheadBytesPerPacket))
+      .Times(1);
+  SendGenericPayload();
+}
+
+TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
+      &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+      &send_packet_observer_, &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kSsrc);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+
+  EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+      .WillOnce(testing::Return(kTransportSequenceNumber));
+  EXPECT_CALL(send_packet_observer_,
+              OnSendPacket(kTransportSequenceNumber, _, _))
+      .Times(1);
+
+  EXPECT_CALL(feedback_observer_,
+              AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber, _,
+                        PacedPacketInfo()))
+      .Times(1);
+
+  SendGenericPayload();
+
+  const auto& packet = transport_.last_sent_packet();
+  uint16_t transport_seq_no;
+  ASSERT_TRUE(packet.GetExtension<TransportSequenceNumber>(&transport_seq_no));
+  EXPECT_EQ(kTransportSequenceNumber, transport_seq_no);
+  EXPECT_EQ(transport_.last_options_.packet_id, transport_seq_no);
+}
+
+TEST_P(RtpSenderTestWithoutPacer, PacketOptionsNoRetransmission) {
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
+      &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+      &send_packet_observer_, &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kSsrc);
+
+  SendGenericPayload();
+
+  EXPECT_FALSE(transport_.last_options_.is_retransmit);
+}
+
+TEST_P(RtpSenderTestWithoutPacer, NoAllocationIfNotRegistered) {
+  SendGenericPayload();
+}
+
+TEST_P(RtpSenderTestWithoutPacer, OnSendPacketUpdated) {
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+  EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+      .WillOnce(testing::Return(kTransportSequenceNumber));
+  EXPECT_CALL(send_packet_observer_,
+              OnSendPacket(kTransportSequenceNumber, _, _))
+      .Times(1);
+
+  SendGenericPayload();
+}
+
+TEST_P(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) {
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
+      &seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr,
+      &mock_rtc_event_log_, &send_packet_observer_,
+      &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetSSRC(kSsrc);
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _));
+  EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+      .WillOnce(testing::Return(kTransportSequenceNumber));
+  EXPECT_CALL(send_packet_observer_,
+              OnSendPacket(kTransportSequenceNumber, _, _))
+      .Times(1);
+  EXPECT_CALL(feedback_observer_,
+              AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber, _,
+                        PacedPacketInfo()))
+      .Times(1);
+
+  SendGenericPayload();
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+                                fake_clock_.TimeInMilliseconds(), false,
+                                PacedPacketInfo());
+
+  const auto& packet = transport_.last_sent_packet();
+  uint16_t transport_seq_no;
+  EXPECT_TRUE(packet.GetExtension<TransportSequenceNumber>(&transport_seq_no));
+  EXPECT_EQ(kTransportSequenceNumber, transport_seq_no);
+  EXPECT_EQ(transport_.last_options_.packet_id, transport_seq_no);
+}
+
+TEST_P(RtpSenderTest, WritesPacerExitToTimingExtension) {
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoTiming, kVideoTimingExtensionId));
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  auto packet = rtp_sender_->AllocatePacket();
+  packet->SetPayloadType(kPayload);
+  packet->SetMarker(true);
+  packet->SetTimestamp(kTimestamp);
+  packet->set_capture_time_ms(capture_time_ms);
+  const VideoSendTiming kVideoTiming = {0u, 0u, 0u, 0u, 0u, 0u, true};
+  packet->SetExtension<VideoTimingExtension>(kVideoTiming);
+  EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+  size_t packet_size = packet->size();
+
+  const int kStoredTimeInMs = 100;
+  {
+    EXPECT_CALL(
+        mock_paced_sender_,
+        InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _));
+    EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                           kAllowRetransmission,
+                                           RtpPacketSender::kNormalPriority));
+  }
+  fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+                                PacedPacketInfo());
+  EXPECT_EQ(1, transport_.packets_sent());
+  EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
+
+  VideoSendTiming video_timing;
+  EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
+      &video_timing));
+  EXPECT_EQ(kStoredTimeInMs, video_timing.pacer_exit_delta_ms);
+}
+
+TEST_P(RtpSenderTest, WritesNetwork2ToTimingExtension) {
+  SetUpRtpSender(true, true);
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoTiming, kVideoTimingExtensionId));
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  auto packet = rtp_sender_->AllocatePacket();
+  packet->SetPayloadType(kPayload);
+  packet->SetMarker(true);
+  packet->SetTimestamp(kTimestamp);
+  packet->set_capture_time_ms(capture_time_ms);
+  const uint16_t kPacerExitMs = 1234u;
+  const VideoSendTiming kVideoTiming = {0u, 0u, 0u, kPacerExitMs, 0u, 0u, true};
+  packet->SetExtension<VideoTimingExtension>(kVideoTiming);
+  EXPECT_TRUE(rtp_sender_->AssignSequenceNumber(packet.get()));
+  size_t packet_size = packet->size();
+
+  const int kStoredTimeInMs = 100;
+  {
+    EXPECT_CALL(
+        mock_paced_sender_,
+        InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _));
+    EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                           kAllowRetransmission,
+                                           RtpPacketSender::kNormalPriority));
+  }
+  fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+                                PacedPacketInfo());
+  EXPECT_EQ(1, transport_.packets_sent());
+  EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
+
+  VideoSendTiming video_timing;
+  EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
+      &video_timing));
+  EXPECT_EQ(kStoredTimeInMs, video_timing.network2_timestamp_delta_ms);
+  EXPECT_EQ(kPacerExitMs, video_timing.pacer_exit_delta_ms);
+}
+
+TEST_P(RtpSenderTest, TrafficSmoothingWithExtensions) {
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
+                                               kSsrc, kSeqNum, _, _, _));
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)));
+
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransmissionTimeOffset,
+                   kTransmissionTimeOffsetExtensionId));
+  EXPECT_EQ(
+      0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
+                                                 kAbsoluteSendTimeExtensionId));
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  auto packet =
+      BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms);
+  size_t packet_size = packet->size();
+
+  // Packet should be stored in a send bucket.
+  EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                         kAllowRetransmission,
+                                         RtpPacketSender::kNormalPriority));
+
+  EXPECT_EQ(0, transport_.packets_sent());
+
+  const int kStoredTimeInMs = 100;
+  fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+                                PacedPacketInfo());
+
+  // Process send bucket. Packet should now be sent.
+  EXPECT_EQ(1, transport_.packets_sent());
+  EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
+
+  webrtc::RTPHeader rtp_header;
+  transport_.last_sent_packet().GetHeader(&rtp_header);
+
+  // Verify transmission time offset.
+  EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset);
+  uint64_t expected_send_time =
+      ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds());
+  EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
+}
+
+TEST_P(RtpSenderTest, TrafficSmoothingRetransmits) {
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
+                                               kSsrc, kSeqNum, _, _, _));
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)));
+
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransmissionTimeOffset,
+                   kTransmissionTimeOffsetExtensionId));
+  EXPECT_EQ(
+      0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
+                                                 kAbsoluteSendTimeExtensionId));
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  auto packet =
+      BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms);
+  size_t packet_size = packet->size();
+
+  // Packet should be stored in a send bucket.
+  EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                         kAllowRetransmission,
+                                         RtpPacketSender::kNormalPriority));
+
+  EXPECT_EQ(0, transport_.packets_sent());
+
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
+                                               kSsrc, kSeqNum, _, _, _));
+
+  const int kStoredTimeInMs = 100;
+  fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+
+  EXPECT_EQ(static_cast<int>(packet_size), rtp_sender_->ReSendPacket(kSeqNum));
+  EXPECT_EQ(0, transport_.packets_sent());
+
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+                                PacedPacketInfo());
+
+  // Process send bucket. Packet should now be sent.
+  EXPECT_EQ(1, transport_.packets_sent());
+  EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
+
+  webrtc::RTPHeader rtp_header;
+  transport_.last_sent_packet().GetHeader(&rtp_header);
+
+  // Verify transmission time offset.
+  EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset);
+  uint64_t expected_send_time =
+      ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds());
+  EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
+}
+
+// This test sends 1 regular video packet, then 4 padding packets, and then
+// 1 more regular packet.
+TEST_P(RtpSenderTest, SendPadding) {
+  // Make all (non-padding) packets go to send queue.
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
+                                               kSsrc, kSeqNum, _, _, _));
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(1 + 4 + 1);
+
+  uint16_t seq_num = kSeqNum;
+  uint32_t timestamp = kTimestamp;
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  size_t rtp_header_len = kRtpHeaderSize;
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransmissionTimeOffset,
+                   kTransmissionTimeOffsetExtensionId));
+  rtp_header_len += 4;  // 4 bytes extension.
+  EXPECT_EQ(
+      0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
+                                                 kAbsoluteSendTimeExtensionId));
+  rtp_header_len += 4;  // 4 bytes extension.
+  rtp_header_len += 4;  // 4 extra bytes common to all extension headers.
+
+  webrtc::RTPHeader rtp_header;
+
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  auto packet =
+      BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms);
+  const uint32_t media_packet_timestamp = timestamp;
+  size_t packet_size = packet->size();
+
+  // Packet should be stored in a send bucket.
+  EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                         kAllowRetransmission,
+                                         RtpPacketSender::kNormalPriority));
+
+  int total_packets_sent = 0;
+  EXPECT_EQ(total_packets_sent, transport_.packets_sent());
+
+  const int kStoredTimeInMs = 100;
+  fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+  rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false,
+                                PacedPacketInfo());
+  // Packet should now be sent. This test doesn't verify the regular video
+  // packet, since it is tested in another test.
+  EXPECT_EQ(++total_packets_sent, transport_.packets_sent());
+  timestamp += 90 * kStoredTimeInMs;
+
+  // Send padding 4 times, waiting 50 ms between each.
+  for (int i = 0; i < 4; ++i) {
+    const int kPaddingPeriodMs = 50;
+    const size_t kPaddingBytes = 100;
+    const size_t kMaxPaddingLength = 224;  // Value taken from rtp_sender.cc.
+    // Padding will be forced to full packets.
+    EXPECT_EQ(kMaxPaddingLength,
+              rtp_sender_->TimeToSendPadding(kPaddingBytes, PacedPacketInfo()));
+
+    // Process send bucket. Padding should now be sent.
+    EXPECT_EQ(++total_packets_sent, transport_.packets_sent());
+    EXPECT_EQ(kMaxPaddingLength + rtp_header_len,
+              transport_.last_sent_packet().size());
+
+    transport_.last_sent_packet().GetHeader(&rtp_header);
+    EXPECT_EQ(kMaxPaddingLength, rtp_header.paddingLength);
+
+    // Verify sequence number and timestamp. The timestamp should be the same
+    // as the last media packet.
+    EXPECT_EQ(seq_num++, rtp_header.sequenceNumber);
+    EXPECT_EQ(media_packet_timestamp, rtp_header.timestamp);
+    // Verify transmission time offset.
+    int offset = timestamp - media_packet_timestamp;
+    EXPECT_EQ(offset, rtp_header.extension.transmissionTimeOffset);
+    uint64_t expected_send_time =
+        ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds());
+    EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
+    fake_clock_.AdvanceTimeMilliseconds(kPaddingPeriodMs);
+    timestamp += 90 * kPaddingPeriodMs;
+  }
+
+  // Send a regular video packet again.
+  capture_time_ms = fake_clock_.TimeInMilliseconds();
+  packet = BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms);
+  packet_size = packet->size();
+
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
+                                               kSsrc, seq_num, _, _, _));
+
+  // Packet should be stored in a send bucket.
+  EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+                                         kAllowRetransmission,
+                                         RtpPacketSender::kNormalPriority));
+
+  rtp_sender_->TimeToSendPacket(kSsrc, seq_num, capture_time_ms, false,
+                                PacedPacketInfo());
+  // Process send bucket.
+  EXPECT_EQ(++total_packets_sent, transport_.packets_sent());
+  EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
+  transport_.last_sent_packet().GetHeader(&rtp_header);
+
+  // Verify sequence number and timestamp.
+  EXPECT_EQ(seq_num, rtp_header.sequenceNumber);
+  EXPECT_EQ(timestamp, rtp_header.timestamp);
+  // Verify transmission time offset. This packet is sent without delay.
+  EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset);
+  uint64_t expected_send_time =
+      ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds());
+  EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
+}
+
+TEST_P(RtpSenderTest, OnSendPacketUpdated) {
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+
+  EXPECT_CALL(send_packet_observer_,
+              OnSendPacket(kTransportSequenceNumber, _, _))
+      .Times(1);
+  EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+      .WillOnce(testing::Return(kTransportSequenceNumber));
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
+      .Times(1);
+
+  SendGenericPayload();  // Packet passed to pacer.
+  const bool kIsRetransmit = false;
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+                                fake_clock_.TimeInMilliseconds(), kIsRetransmit,
+                                PacedPacketInfo());
+  EXPECT_EQ(1, transport_.packets_sent());
+}
+
+TEST_P(RtpSenderTest, OnSendPacketNotUpdatedForRetransmits) {
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+
+  EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0);
+  EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+      .WillOnce(testing::Return(kTransportSequenceNumber));
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
+      .Times(1);
+
+  SendGenericPayload();  // Packet passed to pacer.
+  const bool kIsRetransmit = true;
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+                                fake_clock_.TimeInMilliseconds(), kIsRetransmit,
+                                PacedPacketInfo());
+  EXPECT_EQ(1, transport_.packets_sent());
+  EXPECT_TRUE(transport_.last_options_.is_retransmit);
+}
+
+TEST_P(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) {
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
+      nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr,
+      nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_,
+      nullptr, false));
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetSSRC(kSsrc);
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+
+  EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0);
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
+      .Times(1);
+
+  SendGenericPayload();  // Packet passed to pacer.
+  const bool kIsRetransmit = false;
+  rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+                                fake_clock_.TimeInMilliseconds(), kIsRetransmit,
+                                PacedPacketInfo());
+  EXPECT_EQ(1, transport_.packets_sent());
+}
+
+TEST_P(RtpSenderTest, SendRedundantPayloads) {
+  MockTransport transport;
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr,
+      nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr,
+      &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetSSRC(kSsrc);
+  rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
+
+  uint16_t seq_num = kSeqNum;
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+  int32_t rtp_header_len = kRtpHeaderSize;
+  EXPECT_EQ(
+      0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
+                                                 kAbsoluteSendTimeExtensionId));
+  rtp_header_len += 4;  // 4 bytes extension.
+  rtp_header_len += 4;  // 4 extra bytes common to all extension headers.
+
+  rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
+  rtp_sender_->SetRtxSsrc(1234);
+
+  const size_t kNumPayloadSizes = 10;
+  const size_t kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700,
+                                                  750, 800, 850, 900, 950};
+  // Expect all packets go through the pacer.
+  EXPECT_CALL(mock_paced_sender_,
+              InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _))
+      .Times(kNumPayloadSizes);
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(kNumPayloadSizes);
+
+  // Send 10 packets of increasing size.
+  for (size_t i = 0; i < kNumPayloadSizes; ++i) {
+    int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+    EXPECT_CALL(transport, SendRtp(_, _, _)).WillOnce(testing::Return(true));
+    SendPacket(capture_time_ms, kPayloadSizes[i]);
+    rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false,
+                                  PacedPacketInfo());
+    fake_clock_.AdvanceTimeMilliseconds(33);
+  }
+
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(::testing::AtLeast(4));
+
+  // The amount of padding to send it too small to send a payload packet.
+  EXPECT_CALL(transport, SendRtp(_, kMaxPaddingSize + rtp_header_len, _))
+      .WillOnce(testing::Return(true));
+  EXPECT_EQ(kMaxPaddingSize,
+            rtp_sender_->TimeToSendPadding(49, PacedPacketInfo()));
+
+  PacketOptions options;
+  EXPECT_CALL(transport,
+              SendRtp(_, kPayloadSizes[0] + rtp_header_len + kRtxHeaderSize, _))
+      .WillOnce(
+          testing::DoAll(testing::SaveArg<2>(&options), testing::Return(true)));
+  EXPECT_EQ(kPayloadSizes[0],
+            rtp_sender_->TimeToSendPadding(500, PacedPacketInfo()));
+  EXPECT_TRUE(options.is_retransmit);
+
+  EXPECT_CALL(transport, SendRtp(_,
+                                 kPayloadSizes[kNumPayloadSizes - 1] +
+                                     rtp_header_len + kRtxHeaderSize,
+                                 _))
+      .WillOnce(testing::Return(true));
+
+  options.is_retransmit = false;
+  EXPECT_CALL(transport, SendRtp(_, kMaxPaddingSize + rtp_header_len, _))
+      .WillOnce(
+          testing::DoAll(testing::SaveArg<2>(&options), testing::Return(true)));
+  EXPECT_EQ(kPayloadSizes[kNumPayloadSizes - 1] + kMaxPaddingSize,
+            rtp_sender_->TimeToSendPadding(999, PacedPacketInfo()));
+  EXPECT_FALSE(options.is_retransmit);
+}
+
+TEST_P(RtpSenderTestWithoutPacer, SendGenericVideo) {
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+  const uint8_t payload_type = 127;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+
+  // Send keyframe
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  auto sent_payload = transport_.last_sent_packet().payload();
+  uint8_t generic_header = sent_payload[0];
+  EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit);
+  EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit);
+  EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload));
+
+  // Send delta frame
+  payload[0] = 13;
+  payload[1] = 42;
+  payload[4] = 13;
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  sent_payload = transport_.last_sent_packet().payload();
+  generic_header = sent_payload[0];
+  EXPECT_FALSE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit);
+  EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit);
+  EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload));
+}
+
+TEST_P(RtpSenderTest, SendFlexfecPackets) {
+  constexpr int kMediaPayloadType = 127;
+  constexpr int kFlexfecPayloadType = 118;
+  constexpr uint32_t kMediaSsrc = 1234;
+  constexpr uint32_t kFlexfecSsrc = 5678;
+  const char kNoMid[] = "";
+  const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
+  FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
+                               kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes,
+                               nullptr /* rtp_state */, &fake_clock_);
+
+  // Reset |rtp_sender_| to use FlexFEC.
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
+      &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+      &mock_rtc_event_log_, &send_packet_observer_,
+      &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kMediaSsrc);
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+
+  // Parameters selected to generate a single FEC packet per media packet.
+  FecProtectionParams params;
+  params.fec_rate = 15;
+  params.max_fec_frames = 1;
+  params.fec_mask_type = kFecMaskRandom;
+  rtp_sender_->SetFecParameters(params, params);
+
+  EXPECT_CALL(mock_paced_sender_,
+              InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum,
+                           _, _, false));
+  uint16_t flexfec_seq_num;
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+                                               kFlexfecSsrc, _, _, _, false))
+      .WillOnce(testing::SaveArg<2>(&flexfec_seq_num));
+  SendGenericPayload();
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(2);
+  EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kMediaSsrc, kSeqNum,
+                                            fake_clock_.TimeInMilliseconds(),
+                                            false, PacedPacketInfo()));
+  EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kFlexfecSsrc, flexfec_seq_num,
+                                            fake_clock_.TimeInMilliseconds(),
+                                            false, PacedPacketInfo()));
+  ASSERT_EQ(2, transport_.packets_sent());
+  const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
+  EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
+  EXPECT_EQ(kSeqNum, media_packet.SequenceNumber());
+  EXPECT_EQ(kMediaSsrc, media_packet.Ssrc());
+  const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[1];
+  EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType());
+  EXPECT_EQ(flexfec_seq_num, flexfec_packet.SequenceNumber());
+  EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc());
+}
+
+// TODO(ilnik): because of webrtc:7859. Once FEC moved below pacer, this test
+// should be removed.
+TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) {
+  constexpr int kMediaPayloadType = 127;
+  constexpr int kFlexfecPayloadType = 118;
+  constexpr uint32_t kMediaSsrc = 1234;
+  constexpr uint32_t kFlexfecSsrc = 5678;
+  const char kNoMid[] = "";
+  const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
+
+  FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
+                               kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes,
+                               nullptr /* rtp_state */, &fake_clock_);
+
+  // Reset |rtp_sender_| to use FlexFEC.
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
+      &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+      &mock_rtc_event_log_, &send_packet_observer_,
+      &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kMediaSsrc);
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+
+  // Need extension to be registered for timing frames to be sent.
+  ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoTiming, kVideoTimingExtensionId));
+
+  // Parameters selected to generate a single FEC packet per media packet.
+  FecProtectionParams params;
+  params.fec_rate = 15;
+  params.max_fec_frames = 1;
+  params.fec_mask_type = kFecMaskRandom;
+  rtp_sender_->SetFecParameters(params, params);
+
+  EXPECT_CALL(mock_paced_sender_,
+              InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc, kSeqNum,
+                           _, _, false));
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+                                               kFlexfecSsrc, _, _, _, false))
+      .Times(0);  // Not called because packet should not be protected.
+
+  const uint32_t kTimestamp = 1234;
+  const uint8_t kPayloadType = 127;
+  const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+  EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
+                                            0, 1500));
+  RTPVideoHeader video_header;
+  memset(&video_header, 0, sizeof(RTPVideoHeader));
+  video_header.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
+  EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData,
+      sizeof(kPayloadData), nullptr, &video_header, nullptr,
+      kDefaultExpectedRetransmissionTimeMs));
+
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(1);
+  EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kMediaSsrc, kSeqNum,
+                                            fake_clock_.TimeInMilliseconds(),
+                                            false, PacedPacketInfo()));
+  ASSERT_EQ(1, transport_.packets_sent());
+  const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
+  EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
+  EXPECT_EQ(kSeqNum, media_packet.SequenceNumber());
+  EXPECT_EQ(kMediaSsrc, media_packet.Ssrc());
+
+  // Now try to send not a timing frame.
+  uint16_t flexfec_seq_num;
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+                                               kFlexfecSsrc, _, _, _, false))
+      .WillOnce(testing::SaveArg<2>(&flexfec_seq_num));
+  EXPECT_CALL(mock_paced_sender_,
+              InsertPacket(RtpPacketSender::kLowPriority, kMediaSsrc,
+                           kSeqNum + 1, _, _, false));
+  video_header.video_timing.flags = VideoSendTiming::kInvalid;
+  EXPECT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameKey, kPayloadType, kTimestamp + 1, kCaptureTimeMs + 1,
+      kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr,
+      kDefaultExpectedRetransmissionTimeMs));
+
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(2);
+  EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kMediaSsrc, kSeqNum + 1,
+                                            fake_clock_.TimeInMilliseconds(),
+                                            false, PacedPacketInfo()));
+  EXPECT_TRUE(rtp_sender_->TimeToSendPacket(kFlexfecSsrc, flexfec_seq_num,
+                                            fake_clock_.TimeInMilliseconds(),
+                                            false, PacedPacketInfo()));
+  ASSERT_EQ(3, transport_.packets_sent());
+  const RtpPacketReceived& media_packet2 = transport_.sent_packets_[1];
+  EXPECT_EQ(kMediaPayloadType, media_packet2.PayloadType());
+  EXPECT_EQ(kSeqNum + 1, media_packet2.SequenceNumber());
+  EXPECT_EQ(kMediaSsrc, media_packet2.Ssrc());
+  const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[2];
+  EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType());
+  EXPECT_EQ(flexfec_seq_num, flexfec_packet.SequenceNumber());
+  EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc());
+}
+
+TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
+  constexpr int kMediaPayloadType = 127;
+  constexpr int kFlexfecPayloadType = 118;
+  constexpr uint32_t kMediaSsrc = 1234;
+  constexpr uint32_t kFlexfecSsrc = 5678;
+  const char kNoMid[] = "";
+  const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
+  FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
+                               kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes,
+                               nullptr /* rtp_state */, &fake_clock_);
+
+  // Reset |rtp_sender_| to use FlexFEC.
+  rtp_sender_.reset(
+      new RTPSender(false, &fake_clock_, &transport_, nullptr, &flexfec_sender,
+                    &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+                    &mock_rtc_event_log_, &send_packet_observer_,
+                    &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kMediaSsrc);
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+
+  // Parameters selected to generate a single FEC packet per media packet.
+  FecProtectionParams params;
+  params.fec_rate = 15;
+  params.max_fec_frames = 1;
+  params.fec_mask_type = kFecMaskRandom;
+  rtp_sender_->SetFecParameters(params, params);
+
+  EXPECT_CALL(mock_rtc_event_log_,
+              LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+      .Times(2);
+  SendGenericPayload();
+  ASSERT_EQ(2, transport_.packets_sent());
+  const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
+  EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
+  EXPECT_EQ(kMediaSsrc, media_packet.Ssrc());
+  const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[1];
+  EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType());
+  EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc());
+}
+
+// Test that the MID header extension is included on sent packets when
+// configured.
+TEST_P(RtpSenderTestWithoutPacer, MidIncludedOnSentPackets) {
+  const char kMid[] = "mid";
+
+  // Register MID header extension and set the MID for the RTPSender.
+  rtp_sender_->SetSendingMediaStatus(false);
+  rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionMid, kMidExtensionId);
+  rtp_sender_->SetMid(kMid);
+  rtp_sender_->SetSendingMediaStatus(true);
+
+  // Send a couple packets.
+  SendGenericPayload();
+  SendGenericPayload();
+
+  // Expect both packets to have the MID set.
+  ASSERT_EQ(2u, transport_.sent_packets_.size());
+  for (const RtpPacketReceived& packet : transport_.sent_packets_) {
+    std::string mid;
+    ASSERT_TRUE(packet.GetExtension<RtpMid>(&mid));
+    EXPECT_EQ(kMid, mid);
+  }
+}
+
+TEST_P(RtpSenderTest, FecOverheadRate) {
+  constexpr int kFlexfecPayloadType = 118;
+  constexpr uint32_t kMediaSsrc = 1234;
+  constexpr uint32_t kFlexfecSsrc = 5678;
+  const char kNoMid[] = "";
+  const std::vector<RtpExtension> kNoRtpExtensions;
+  const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
+  FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
+                               kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes,
+                               nullptr /* rtp_state */, &fake_clock_);
+
+  // Reset |rtp_sender_| to use FlexFEC.
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
+      &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
+      &mock_rtc_event_log_, &send_packet_observer_,
+      &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kMediaSsrc);
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+
+  // Parameters selected to generate a single FEC packet per media packet.
+  FecProtectionParams params;
+  params.fec_rate = 15;
+  params.max_fec_frames = 1;
+  params.fec_mask_type = kFecMaskRandom;
+  rtp_sender_->SetFecParameters(params, params);
+
+  constexpr size_t kNumMediaPackets = 10;
+  constexpr size_t kNumFecPackets = kNumMediaPackets;
+  constexpr int64_t kTimeBetweenPacketsMs = 10;
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, false))
+      .Times(kNumMediaPackets + kNumFecPackets);
+  for (size_t i = 0; i < kNumMediaPackets; ++i) {
+    SendGenericPayload();
+    fake_clock_.AdvanceTimeMilliseconds(kTimeBetweenPacketsMs);
+  }
+  constexpr size_t kRtpHeaderLength = 12;
+  constexpr size_t kFlexfecHeaderLength = 20;
+  constexpr size_t kGenericCodecHeaderLength = 1;
+  constexpr size_t kPayloadLength = sizeof(kPayloadData);
+  constexpr size_t kPacketLength = kRtpHeaderLength + kFlexfecHeaderLength +
+                                   kGenericCodecHeaderLength + kPayloadLength;
+  EXPECT_NEAR(kNumFecPackets * kPacketLength * 8 /
+                  (kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f),
+              rtp_sender_->FecOverheadRate(), 500);
+}
+
+TEST_P(RtpSenderTest, FrameCountCallbacks) {
+  class TestCallback : public FrameCountObserver {
+   public:
+    TestCallback() : FrameCountObserver(), num_calls_(0), ssrc_(0) {}
+    ~TestCallback() override = default;
+
+    void FrameCountUpdated(const FrameCounts& frame_counts,
+                           uint32_t ssrc) override {
+      ++num_calls_;
+      ssrc_ = ssrc;
+      frame_counts_ = frame_counts;
+    }
+
+    uint32_t num_calls_;
+    uint32_t ssrc_;
+    FrameCounts frame_counts_;
+  } callback;
+
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr,
+      nullptr, nullptr, &callback, nullptr, nullptr, nullptr,
+      &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kSsrc);
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+  const uint8_t payload_type = 127;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+  rtp_sender_->SetStorePacketsStatus(true, 1);
+  uint32_t ssrc = rtp_sender_->SSRC();
+
+  EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _))
+      .Times(::testing::AtLeast(2));
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  EXPECT_EQ(1U, callback.num_calls_);
+  EXPECT_EQ(ssrc, callback.ssrc_);
+  EXPECT_EQ(1, callback.frame_counts_.key_frames);
+  EXPECT_EQ(0, callback.frame_counts_.delta_frames);
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  EXPECT_EQ(2U, callback.num_calls_);
+  EXPECT_EQ(ssrc, callback.ssrc_);
+  EXPECT_EQ(1, callback.frame_counts_.key_frames);
+  EXPECT_EQ(1, callback.frame_counts_.delta_frames);
+
+  rtp_sender_.reset();
+}
+
+TEST_P(RtpSenderTest, BitrateCallbacks) {
+  class TestCallback : public BitrateStatisticsObserver {
+   public:
+    TestCallback()
+        : BitrateStatisticsObserver(),
+          num_calls_(0),
+          ssrc_(0),
+          total_bitrate_(0),
+          retransmit_bitrate_(0) {}
+    ~TestCallback() override = default;
+
+    void Notify(uint32_t total_bitrate,
+                uint32_t retransmit_bitrate,
+                uint32_t ssrc) override {
+      ++num_calls_;
+      ssrc_ = ssrc;
+      total_bitrate_ = total_bitrate;
+      retransmit_bitrate_ = retransmit_bitrate;
+    }
+
+    uint32_t num_calls_;
+    uint32_t ssrc_;
+    uint32_t total_bitrate_;
+    uint32_t retransmit_bitrate_;
+  } callback;
+  rtp_sender_.reset(
+      new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
+                    nullptr, &callback, nullptr, nullptr, nullptr, nullptr,
+                    &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSSRC(kSsrc);
+
+  // Simulate kNumPackets sent with kPacketInterval ms intervals, with the
+  // number of packets selected so that we fill (but don't overflow) the one
+  // second averaging window.
+  const uint32_t kWindowSizeMs = 1000;
+  const uint32_t kPacketInterval = 20;
+  const uint32_t kNumPackets =
+      (kWindowSizeMs - kPacketInterval) / kPacketInterval;
+  // Overhead = 12 bytes RTP header + 1 byte generic header.
+  const uint32_t kPacketOverhead = 13;
+
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+  const uint8_t payload_type = 127;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+  rtp_sender_->SetStorePacketsStatus(true, 1);
+  uint32_t ssrc = rtp_sender_->SSRC();
+
+  // Initial process call so we get a new time window.
+  rtp_sender_->ProcessBitrate();
+
+  // Send a few frames.
+  for (uint32_t i = 0; i < kNumPackets; ++i) {
+    ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+        kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
+        nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+    fake_clock_.AdvanceTimeMilliseconds(kPacketInterval);
+  }
+
+  rtp_sender_->ProcessBitrate();
+
+  // We get one call for every stats updated, thus two calls since both the
+  // stream stats and the retransmit stats are updated once.
+  EXPECT_EQ(2u, callback.num_calls_);
+  EXPECT_EQ(ssrc, callback.ssrc_);
+  const uint32_t kTotalPacketSize = kPacketOverhead + sizeof(payload);
+  // Bitrate measured over delta between last and first timestamp, plus one.
+  const uint32_t kExpectedWindowMs = kNumPackets * kPacketInterval + 1;
+  const uint32_t kExpectedBitsAccumulated = kTotalPacketSize * kNumPackets * 8;
+  const uint32_t kExpectedRateBps =
+      (kExpectedBitsAccumulated * 1000 + (kExpectedWindowMs / 2)) /
+      kExpectedWindowMs;
+  EXPECT_EQ(kExpectedRateBps, callback.total_bitrate_);
+
+  rtp_sender_.reset();
+}
+
+class RtpSenderAudioTest : public RtpSenderTest {
+ protected:
+  RtpSenderAudioTest() {}
+
+  void SetUp() override {
+    payload_ = kAudioPayload;
+    rtp_sender_.reset(
+        new RTPSender(true, &fake_clock_, &transport_, nullptr, nullptr,
+                      nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+                      nullptr, &retransmission_rate_limiter_, nullptr, false));
+    rtp_sender_->SetSSRC(kSsrc);
+    rtp_sender_->SetSequenceNumber(kSeqNum);
+  }
+};
+
+TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacks) {
+  class TestCallback : public StreamDataCountersCallback {
+   public:
+    TestCallback() : StreamDataCountersCallback(), ssrc_(0), counters_() {}
+    ~TestCallback() override = default;
+
+    void DataCountersUpdated(const StreamDataCounters& counters,
+                             uint32_t ssrc) override {
+      ssrc_ = ssrc;
+      counters_ = counters;
+    }
+
+    uint32_t ssrc_;
+    StreamDataCounters counters_;
+
+    void MatchPacketCounter(const RtpPacketCounter& expected,
+                            const RtpPacketCounter& actual) {
+      EXPECT_EQ(expected.payload_bytes, actual.payload_bytes);
+      EXPECT_EQ(expected.header_bytes, actual.header_bytes);
+      EXPECT_EQ(expected.padding_bytes, actual.padding_bytes);
+      EXPECT_EQ(expected.packets, actual.packets);
+    }
+
+    void Matches(uint32_t ssrc, const StreamDataCounters& counters) {
+      EXPECT_EQ(ssrc, ssrc_);
+      MatchPacketCounter(counters.transmitted, counters_.transmitted);
+      MatchPacketCounter(counters.retransmitted, counters_.retransmitted);
+      EXPECT_EQ(counters.fec.packets, counters_.fec.packets);
+    }
+  } callback;
+
+  const uint8_t kRedPayloadType = 96;
+  const uint8_t kUlpfecPayloadType = 97;
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+  const uint8_t payload_type = 127;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+  rtp_sender_->SetStorePacketsStatus(true, 1);
+  uint32_t ssrc = rtp_sender_->SSRC();
+
+  rtp_sender_->RegisterRtpStatisticsCallback(&callback);
+
+  // Send a frame.
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+  StreamDataCounters expected;
+  expected.transmitted.payload_bytes = 6;
+  expected.transmitted.header_bytes = 12;
+  expected.transmitted.padding_bytes = 0;
+  expected.transmitted.packets = 1;
+  expected.retransmitted.payload_bytes = 0;
+  expected.retransmitted.header_bytes = 0;
+  expected.retransmitted.padding_bytes = 0;
+  expected.retransmitted.packets = 0;
+  expected.fec.packets = 0;
+  callback.Matches(ssrc, expected);
+
+  // Retransmit a frame.
+  uint16_t seqno = rtp_sender_->SequenceNumber() - 1;
+  rtp_sender_->ReSendPacket(seqno);
+  expected.transmitted.payload_bytes = 12;
+  expected.transmitted.header_bytes = 24;
+  expected.transmitted.packets = 2;
+  expected.retransmitted.payload_bytes = 6;
+  expected.retransmitted.header_bytes = 12;
+  expected.retransmitted.padding_bytes = 0;
+  expected.retransmitted.packets = 1;
+  callback.Matches(ssrc, expected);
+
+  // Send padding.
+  rtp_sender_->TimeToSendPadding(kMaxPaddingSize, PacedPacketInfo());
+  expected.transmitted.payload_bytes = 12;
+  expected.transmitted.header_bytes = 36;
+  expected.transmitted.padding_bytes = kMaxPaddingSize;
+  expected.transmitted.packets = 3;
+  callback.Matches(ssrc, expected);
+
+  // Send ULPFEC.
+  rtp_sender_->SetUlpfecConfig(kRedPayloadType, kUlpfecPayloadType);
+  FecProtectionParams fec_params;
+  fec_params.fec_mask_type = kFecMaskRandom;
+  fec_params.fec_rate = 1;
+  fec_params.max_fec_frames = 1;
+  rtp_sender_->SetFecParameters(fec_params, fec_params);
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+  expected.transmitted.payload_bytes = 40;
+  expected.transmitted.header_bytes = 60;
+  expected.transmitted.packets = 5;
+  expected.fec.packets = 1;
+  callback.Matches(ssrc, expected);
+
+  rtp_sender_->RegisterRtpStatisticsCallback(nullptr);
+}
+
+TEST_P(RtpSenderAudioTest, SendAudio) {
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME";
+  const uint8_t payload_type = 127;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  auto sent_payload = transport_.last_sent_packet().payload();
+  EXPECT_THAT(sent_payload, ElementsAreArray(payload));
+}
+
+TEST_P(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) {
+  EXPECT_EQ(0, rtp_sender_->SetAudioLevel(kAudioLevel));
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
+                                                       kAudioLevelExtensionId));
+
+  char payload_name[RTP_PAYLOAD_NAME_SIZE] = "PAYLOAD_NAME";
+  const uint8_t payload_type = 127;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 48000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  auto sent_payload = transport_.last_sent_packet().payload();
+  EXPECT_THAT(sent_payload, ElementsAreArray(payload));
+  // Verify AudioLevel extension.
+  bool voice_activity;
+  uint8_t audio_level;
+  EXPECT_TRUE(transport_.last_sent_packet().GetExtension<AudioLevel>(
+      &voice_activity, &audio_level));
+  EXPECT_EQ(kAudioLevel, audio_level);
+  EXPECT_FALSE(voice_activity);
+}
+
+// As RFC4733, named telephone events are carried as part of the audio stream
+// and must use the same sequence number and timestamp base as the regular
+// audio channel.
+// This test checks the marker bit for the first packet and the consequent
+// packets of the same telephone event. Since it is specifically for DTMF
+// events, ignoring audio packets and sending kEmptyFrame instead of those.
+TEST_P(RtpSenderAudioTest, CheckMarkerBitForTelephoneEvents) {
+  const char* kDtmfPayloadName = "telephone-event";
+  const uint32_t kPayloadFrequency = 8000;
+  const uint8_t kPayloadType = 126;
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(kDtmfPayloadName, kPayloadType,
+                                            kPayloadFrequency, 0, 0));
+  // For Telephone events, payload is not added to the registered payload list,
+  // it will register only the payload used for audio stream.
+  // Registering the payload again for audio stream with different payload name.
+  const char* kPayloadName = "payload_name";
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(kPayloadName, kPayloadType,
+                                            kPayloadFrequency, 1, 0));
+  int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+  // DTMF event key=9, duration=500 and attenuationdB=10
+  rtp_sender_->SendTelephoneEvent(9, 500, 10);
+  // During start, it takes the starting timestamp as last sent timestamp.
+  // The duration is calculated as the difference of current and last sent
+  // timestamp. So for first call it will skip since the duration is zero.
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kEmptyFrame, kPayloadType, capture_time_ms, 0, nullptr, 0, nullptr,
+      nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+  // DTMF Sample Length is (Frequency/1000) * Duration.
+  // So in this case, it is (8000/1000) * 500 = 4000.
+  // Sending it as two packets.
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kEmptyFrame, kPayloadType, capture_time_ms + 2000, 0, nullptr, 0, nullptr,
+      nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  // Marker Bit should be set to 1 for first packet.
+  EXPECT_TRUE(transport_.last_sent_packet().Marker());
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kEmptyFrame, kPayloadType, capture_time_ms + 4000, 0, nullptr, 0, nullptr,
+      nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+  // Marker Bit should be set to 0 for rest of the packets.
+  EXPECT_FALSE(transport_.last_sent_packet().Marker());
+}
+
+TEST_P(RtpSenderTestWithoutPacer, BytesReportedCorrectly) {
+  const char* kPayloadName = "GENERIC";
+  const uint8_t kPayloadType = 127;
+  rtp_sender_->SetSSRC(1234);
+  rtp_sender_->SetRtxSsrc(4321);
+  rtp_sender_->SetRtxPayloadType(kPayloadType - 1, kPayloadType);
+  rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
+
+  ASSERT_EQ(0, rtp_sender_->RegisterPayload(kPayloadName, kPayloadType, 90000,
+                                            0, 1500));
+  uint8_t payload[] = {47, 11, 32, 93, 89};
+
+  ASSERT_TRUE(rtp_sender_->SendOutgoingData(
+      kVideoFrameKey, kPayloadType, 1234, 4321, payload, sizeof(payload),
+      nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs));
+
+  // Will send 2 full-size padding packets.
+  rtp_sender_->TimeToSendPadding(1, PacedPacketInfo());
+  rtp_sender_->TimeToSendPadding(1, PacedPacketInfo());
+
+  StreamDataCounters rtp_stats;
+  StreamDataCounters rtx_stats;
+  rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats);
+
+  // Payload + 1-byte generic header.
+  EXPECT_GT(rtp_stats.first_packet_time_ms, -1);
+  EXPECT_EQ(rtp_stats.transmitted.payload_bytes, sizeof(payload) + 1);
+  EXPECT_EQ(rtp_stats.transmitted.header_bytes, 12u);
+  EXPECT_EQ(rtp_stats.transmitted.padding_bytes, 0u);
+  EXPECT_EQ(rtx_stats.transmitted.payload_bytes, 0u);
+  EXPECT_EQ(rtx_stats.transmitted.header_bytes, 24u);
+  EXPECT_EQ(rtx_stats.transmitted.padding_bytes, 2 * kMaxPaddingSize);
+
+  EXPECT_EQ(rtp_stats.transmitted.TotalBytes(),
+            rtp_stats.transmitted.payload_bytes +
+                rtp_stats.transmitted.header_bytes +
+                rtp_stats.transmitted.padding_bytes);
+  EXPECT_EQ(rtx_stats.transmitted.TotalBytes(),
+            rtx_stats.transmitted.payload_bytes +
+                rtx_stats.transmitted.header_bytes +
+                rtx_stats.transmitted.padding_bytes);
+
+  EXPECT_EQ(
+      transport_.total_bytes_sent_,
+      rtp_stats.transmitted.TotalBytes() + rtx_stats.transmitted.TotalBytes());
+}
+
+TEST_P(RtpSenderTestWithoutPacer, RespectsNackBitrateLimit) {
+  const int32_t kPacketSize = 1400;
+  const int32_t kNumPackets = 30;
+
+  retransmission_rate_limiter_.SetMaxRate(kPacketSize * kNumPackets * 8);
+
+  rtp_sender_->SetStorePacketsStatus(true, kNumPackets);
+  const uint16_t kStartSequenceNumber = rtp_sender_->SequenceNumber();
+  std::vector<uint16_t> sequence_numbers;
+  for (int32_t i = 0; i < kNumPackets; ++i) {
+    sequence_numbers.push_back(kStartSequenceNumber + i);
+    fake_clock_.AdvanceTimeMilliseconds(1);
+    SendPacket(fake_clock_.TimeInMilliseconds(), kPacketSize);
+  }
+  EXPECT_EQ(kNumPackets, transport_.packets_sent());
+
+  fake_clock_.AdvanceTimeMilliseconds(1000 - kNumPackets);
+
+  // Resending should work - brings the bandwidth up to the limit.
+  // NACK bitrate is capped to the same bitrate as the encoder, since the max
+  // protection overhead is 50% (see MediaOptimization::SetTargetRates).
+  rtp_sender_->OnReceivedNack(sequence_numbers, 0);
+  EXPECT_EQ(kNumPackets * 2, transport_.packets_sent());
+
+  // Must be at least 5ms in between retransmission attempts.
+  fake_clock_.AdvanceTimeMilliseconds(5);
+
+  // Resending should not work, bandwidth exceeded.
+  rtp_sender_->OnReceivedNack(sequence_numbers, 0);
+  EXPECT_EQ(kNumPackets * 2, transport_.packets_sent());
+}
+
+TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) {
+  uint8_t kFrame[kMaxPacketLength];
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  RTPVideoHeader hdr;
+  hdr.rotation = kVideoRotation_0;
+  rtp_sender_video_->SendVideo(kVideoCodecGeneric, kVideoFrameKey, kPayload,
+                               kTimestamp, 0, kFrame, sizeof(kFrame), nullptr,
+                               &hdr, kDefaultExpectedRetransmissionTimeMs);
+
+  VideoRotation rotation;
+  EXPECT_TRUE(
+      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+  EXPECT_EQ(kVideoRotation_0, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) {
+  uint8_t kFrame[kMaxPacketLength];
+  const int64_t kPacketizationTimeMs = 100;
+  const int64_t kEncodeStartDeltaMs = 10;
+  const int64_t kEncodeFinishDeltaMs = 50;
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoTiming, kVideoTimingExtensionId));
+
+  const int64_t kCaptureTimestamp = fake_clock_.TimeInMilliseconds();
+
+  RTPVideoHeader hdr;
+  hdr.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
+  hdr.video_timing.encode_start_delta_ms = kEncodeStartDeltaMs;
+  hdr.video_timing.encode_finish_delta_ms = kEncodeFinishDeltaMs;
+
+  fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs);
+  rtp_sender_video_->SendVideo(kVideoCodecGeneric, kVideoFrameKey, kPayload,
+                               kTimestamp, kCaptureTimestamp, kFrame,
+                               sizeof(kFrame), nullptr, &hdr,
+                               kDefaultExpectedRetransmissionTimeMs);
+  VideoSendTiming timing;
+  EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>(
+      &timing));
+  EXPECT_EQ(kPacketizationTimeMs, timing.packetization_finish_delta_ms);
+  EXPECT_EQ(kEncodeStartDeltaMs, timing.encode_start_delta_ms);
+  EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms);
+}
+
+TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) {
+  uint8_t kFrame[kMaxPacketLength];
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  RTPVideoHeader hdr;
+  hdr.rotation = kVideoRotation_90;
+  EXPECT_TRUE(rtp_sender_video_->SendVideo(
+      kVideoCodecGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
+      sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  hdr.rotation = kVideoRotation_0;
+  EXPECT_TRUE(rtp_sender_video_->SendVideo(
+      kVideoCodecGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame,
+      sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  VideoRotation rotation;
+  EXPECT_TRUE(
+      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+  EXPECT_EQ(kVideoRotation_0, rotation);
+}
+
+TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) {
+  uint8_t kFrame[kMaxPacketLength];
+  EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionVideoRotation, kVideoRotationExtensionId));
+
+  RTPVideoHeader hdr;
+  hdr.rotation = kVideoRotation_90;
+  EXPECT_TRUE(rtp_sender_video_->SendVideo(
+      kVideoCodecGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame,
+      sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  EXPECT_TRUE(rtp_sender_video_->SendVideo(
+      kVideoCodecGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame,
+      sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs));
+
+  VideoRotation rotation;
+  EXPECT_TRUE(
+      transport_.last_sent_packet().GetExtension<VideoOrientation>(&rotation));
+  EXPECT_EQ(kVideoRotation_90, rotation);
+}
+
+// Make sure rotation is parsed correctly when the Camera (C) and Flip (F) bits
+// are set in the CVO byte.
+TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) {
+  // Test extracting rotation when Camera (C) and Flip (F) bits are zero.
+  EXPECT_EQ(kVideoRotation_0, ConvertCVOByteToVideoRotation(0));
+  EXPECT_EQ(kVideoRotation_90, ConvertCVOByteToVideoRotation(1));
+  EXPECT_EQ(kVideoRotation_180, ConvertCVOByteToVideoRotation(2));
+  EXPECT_EQ(kVideoRotation_270, ConvertCVOByteToVideoRotation(3));
+  // Test extracting rotation when Camera (C) and Flip (F) bits are set.
+  const int flip_bit = 1 << 2;
+  const int camera_bit = 1 << 3;
+  EXPECT_EQ(kVideoRotation_0,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 0));
+  EXPECT_EQ(kVideoRotation_90,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 1));
+  EXPECT_EQ(kVideoRotation_180,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 2));
+  EXPECT_EQ(kVideoRotation_270,
+            ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecGeneric;
+
+  EXPECT_EQ(kDontRetransmit,
+            rtp_sender_video_->GetStorageType(
+                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitBaseLayer,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitHigherLayers,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(
+                header, kConditionallyRetransmitHigherLayers,
+                kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitAllPackets,
+                                      kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecH264;
+  header.h264().packetization_mode = H264PacketizationMode::NonInterleaved;
+
+  EXPECT_EQ(kDontRetransmit,
+            rtp_sender_video_->GetStorageType(
+                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitBaseLayer,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitHigherLayers,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(
+                header, kConditionallyRetransmitHigherLayers,
+                kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitAllPackets,
+                                      kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+  header.vp8().temporalIdx = 0;
+
+  EXPECT_EQ(kDontRetransmit,
+            rtp_sender_video_->GetStorageType(
+                header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitBaseLayer,
+                                      kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
+                                 header, kRetransmitHigherLayers,
+                                 kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(
+                header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+                kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
+                                 header, kConditionallyRetransmitHigherLayers,
+                                 kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(
+      kAllowRetransmission,
+      rtp_sender_video_->GetStorageType(
+          header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers,
+          kDefaultExpectedRetransmissionTimeMs));
+  EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                      header, kRetransmitAllPackets,
+                                      kDefaultExpectedRetransmissionTimeMs));
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+
+  for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
+    header.vp8().temporalIdx = tid;
+
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
+                                   header, kRetransmitOff,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
+                                   header, kRetransmitBaseLayer,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                        header, kRetransmitHigherLayers,
+                                        kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission,
+              rtp_sender_video_->GetStorageType(
+                  header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+                  kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                        header, kRetransmitAllPackets,
+                                        kDefaultExpectedRetransmissionTimeMs));
+  }
+}
+
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) {
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP9;
+
+  for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) {
+    header.vp9().temporal_idx = tid;
+
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
+                                   header, kRetransmitOff,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType(
+                                   header, kRetransmitBaseLayer,
+                                   kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                        header, kRetransmitHigherLayers,
+                                        kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission,
+              rtp_sender_video_->GetStorageType(
+                  header, kRetransmitHigherLayers | kRetransmitBaseLayer,
+                  kDefaultExpectedRetransmissionTimeMs));
+    EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType(
+                                        header, kRetransmitAllPackets,
+                                        kDefaultExpectedRetransmissionTimeMs));
+  }
+}
+
+TEST_P(RtpSenderVideoTest, ConditionalRetransmit) {
+  const int64_t kFrameIntervalMs = 33;
+  const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
+  const uint8_t kSettings =
+      kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
+
+  // Insert VP8 frames for all temporal layers, but stop before the final index.
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+
+  // Fill averaging window to prevent rounding errors.
+  constexpr int kNumRepetitions =
+      (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
+      kFrameIntervalMs;
+  constexpr int kPattern[] = {0, 2, 1, 2};
+  for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
+    header.vp8().temporalIdx = kPattern[i % arraysize(kPattern)];
+    rtp_sender_video_->GetStorageType(header, kSettings, kRttMs);
+    fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+  }
+
+  // Since we're at the start of the pattern, the next expected frame in TL0 is
+  // right now. We will wait at most one expected retransmission time before
+  // acknowledging that it did not arrive, which means this frame and the next
+  // will not be retransmitted.
+  header.vp8().temporalIdx = 1;
+  EXPECT_EQ(StorageType::kDontRetransmit,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+  EXPECT_EQ(StorageType::kDontRetransmit,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // The TL0 frame did not arrive. So allow retransmission.
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // Insert a frame for TL2. We just had frame in TL1, so the next one there is
+  // in three frames away. TL0 is still too far in the past. So, allow
+  // retransmission.
+  header.vp8().temporalIdx = 2;
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // Another TL2, next in TL1 is two frames away. Allow again.
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+  fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+
+  // Yet another TL2, next in TL1 is now only one frame away, so don't store
+  // for retransmission.
+  EXPECT_EQ(StorageType::kDontRetransmit,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+}
+
+TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) {
+  const int64_t kFrameIntervalMs = 200;
+  const int64_t kRttMs = (kFrameIntervalMs * 3) / 2;
+  const int32_t kSettings =
+      kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers;
+
+  // Insert VP8 frames for all temporal layers, but stop before the final index.
+  RTPVideoHeader header;
+  header.codec = kVideoCodecVP8;
+
+  // Fill averaging window to prevent rounding errors.
+  constexpr int kNumRepetitions =
+      (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) /
+      kFrameIntervalMs;
+  constexpr int kPattern[] = {0, 2, 2, 2};
+  for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) {
+    header.vp8().temporalIdx = kPattern[i % arraysize(kPattern)];
+
+    rtp_sender_video_->GetStorageType(header, kSettings, kRttMs);
+    fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+  }
+
+  // Since we're at the start of the pattern, the next expected frame will be
+  // right now in TL0. Put it in TL1 instead. Regular rules would dictate that
+  // we don't store for retransmission because we expect a frame in a lower
+  // layer, but that last frame in TL1 was a long time ago in absolute terms,
+  // so allow retransmission anyway.
+  header.vp8().temporalIdx = 1;
+  EXPECT_EQ(StorageType::kAllowRetransmission,
+            rtp_sender_video_->GetStorageType(header, kSettings, kRttMs));
+}
+
+TEST_P(RtpSenderTest, OnOverheadChanged) {
+  MockOverheadObserver mock_overhead_observer;
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
+      nullptr, nullptr, nullptr, nullptr, nullptr,
+      &retransmission_rate_limiter_, &mock_overhead_observer, false));
+  rtp_sender_->SetSSRC(kSsrc);
+
+  // RTP overhead is 12B.
+  EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(12)).Times(1);
+  SendGenericPayload();
+
+  rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
+                                          kTransmissionTimeOffsetExtensionId);
+
+  // TransmissionTimeOffset extension has a size of 8B.
+  // 12B + 8B = 20B
+  EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(20)).Times(1);
+  SendGenericPayload();
+}
+
+TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) {
+  MockOverheadObserver mock_overhead_observer;
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
+      nullptr, nullptr, nullptr, nullptr, nullptr,
+      &retransmission_rate_limiter_, &mock_overhead_observer, false));
+  rtp_sender_->SetSSRC(kSsrc);
+
+  EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1);
+  SendGenericPayload();
+  SendGenericPayload();
+}
+
+TEST_P(RtpSenderTest, SendsKeepAlive) {
+  MockTransport transport;
+  rtp_sender_.reset(
+      new RTPSender(false, &fake_clock_, &transport, nullptr, nullptr, nullptr,
+                    nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
+                    nullptr, &retransmission_rate_limiter_, nullptr, false));
+  rtp_sender_->SetSequenceNumber(kSeqNum);
+  rtp_sender_->SetTimestampOffset(0);
+  rtp_sender_->SetSSRC(kSsrc);
+
+  const uint8_t kKeepalivePayloadType = 20;
+  RTC_CHECK_NE(kKeepalivePayloadType, kPayload);
+
+  EXPECT_CALL(transport, SendRtp(_, _, _))
+      .WillOnce(
+          Invoke([&kKeepalivePayloadType](const uint8_t* packet, size_t len,
+                                          const PacketOptions& options) {
+            webrtc::RTPHeader rtp_header;
+            RtpUtility::RtpHeaderParser parser(packet, len);
+            EXPECT_TRUE(parser.Parse(&rtp_header, nullptr));
+            EXPECT_FALSE(rtp_header.markerBit);
+            EXPECT_EQ(0U, rtp_header.paddingLength);
+            EXPECT_EQ(kKeepalivePayloadType, rtp_header.payloadType);
+            EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber);
+            EXPECT_EQ(kSsrc, rtp_header.ssrc);
+            EXPECT_EQ(0u, len - rtp_header.headerLength);
+            return true;
+          }));
+
+  rtp_sender_->SendKeepAlive(kKeepalivePayloadType);
+  EXPECT_EQ(kSeqNum + 1, rtp_sender_->SequenceNumber());
+}
+
+INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
+                        RtpSenderTest,
+                        ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
+                        RtpSenderTestWithoutPacer,
+                        ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
+                        RtpSenderVideoTest,
+                        ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead,
+                        RtpSenderAudioTest,
+                        ::testing::Bool());
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc
new file mode 100644
index 0000000..a7f3df0
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -0,0 +1,526 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_sender_video.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <limits>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
+#include "modules/rtp_rtcp/source/rtp_format_vp8.h"
+#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+
+namespace {
+constexpr size_t kRedForFecHeaderLength = 1;
+constexpr int64_t kMaxUnretransmittableFrameIntervalMs = 33 * 4;
+
+void BuildRedPayload(const RtpPacketToSend& media_packet,
+                     RtpPacketToSend* red_packet) {
+  uint8_t* red_payload = red_packet->AllocatePayload(
+      kRedForFecHeaderLength + media_packet.payload_size());
+  RTC_DCHECK(red_payload);
+  red_payload[0] = media_packet.PayloadType();
+
+  auto media_payload = media_packet.payload();
+  memcpy(&red_payload[kRedForFecHeaderLength], media_payload.data(),
+         media_payload.size());
+}
+}  // namespace
+
+RTPSenderVideo::RTPSenderVideo(Clock* clock,
+                               RTPSender* rtp_sender,
+                               FlexfecSender* flexfec_sender)
+    : rtp_sender_(rtp_sender),
+      clock_(clock),
+      video_type_(kVideoCodecGeneric),
+      retransmission_settings_(kRetransmitBaseLayer |
+                               kConditionallyRetransmitHigherLayers),
+      last_rotation_(kVideoRotation_0),
+      red_payload_type_(-1),
+      ulpfec_payload_type_(-1),
+      flexfec_sender_(flexfec_sender),
+      delta_fec_params_{0, 1, kFecMaskRandom},
+      key_fec_params_{0, 1, kFecMaskRandom},
+      fec_bitrate_(1000, RateStatistics::kBpsScale),
+      video_bitrate_(1000, RateStatistics::kBpsScale) {}
+
+RTPSenderVideo::~RTPSenderVideo() {}
+
+void RTPSenderVideo::SetVideoCodecType(enum VideoCodecType video_type) {
+  video_type_ = video_type;
+}
+
+VideoCodecType RTPSenderVideo::VideoCodecType() const {
+  return video_type_;
+}
+
+// Static.
+RtpUtility::Payload* RTPSenderVideo::CreateVideoPayload(
+    const char payload_name[RTP_PAYLOAD_NAME_SIZE],
+    int8_t payload_type) {
+  enum VideoCodecType video_type = kVideoCodecGeneric;
+  if (RtpUtility::StringCompare(payload_name, "VP8", 3)) {
+    video_type = kVideoCodecVP8;
+  } else if (RtpUtility::StringCompare(payload_name, "VP9", 3)) {
+    video_type = kVideoCodecVP9;
+  } else if (RtpUtility::StringCompare(payload_name, "H264", 4)) {
+    video_type = kVideoCodecH264;
+  } else if (RtpUtility::StringCompare(payload_name, "I420", 4)) {
+    video_type = kVideoCodecGeneric;
+  } else if (RtpUtility::StringCompare(payload_name, "stereo", 6)) {
+    video_type = kVideoCodecGeneric;
+  } else {
+    video_type = kVideoCodecGeneric;
+  }
+  VideoPayload vp;
+  vp.videoCodecType = video_type;
+  return new RtpUtility::Payload(payload_name, PayloadUnion(vp));
+}
+
+void RTPSenderVideo::SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet,
+                                     StorageType storage) {
+  // Remember some values about the packet before sending it away.
+  size_t packet_size = packet->size();
+  uint16_t seq_num = packet->SequenceNumber();
+  if (!rtp_sender_->SendToNetwork(std::move(packet), storage,
+                                  RtpPacketSender::kLowPriority)) {
+    RTC_LOG(LS_WARNING) << "Failed to send video packet " << seq_num;
+    return;
+  }
+  rtc::CritScope cs(&stats_crit_);
+  video_bitrate_.Update(packet_size, clock_->TimeInMilliseconds());
+}
+
+void RTPSenderVideo::SendVideoPacketAsRedMaybeWithUlpfec(
+    std::unique_ptr<RtpPacketToSend> media_packet,
+    StorageType media_packet_storage,
+    bool protect_media_packet) {
+  uint16_t media_seq_num = media_packet->SequenceNumber();
+
+  std::unique_ptr<RtpPacketToSend> red_packet(
+      new RtpPacketToSend(*media_packet));
+  BuildRedPayload(*media_packet, red_packet.get());
+
+  std::vector<std::unique_ptr<RedPacket>> fec_packets;
+  StorageType fec_storage = kDontRetransmit;
+  {
+    // Only protect while creating RED and FEC packets, not when sending.
+    rtc::CritScope cs(&crit_);
+    red_packet->SetPayloadType(red_payload_type_);
+    if (ulpfec_enabled()) {
+      if (protect_media_packet) {
+        ulpfec_generator_.AddRtpPacketAndGenerateFec(
+            media_packet->data(), media_packet->payload_size(),
+            media_packet->headers_size());
+      }
+      uint16_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets();
+      if (num_fec_packets > 0) {
+        uint16_t first_fec_sequence_number =
+            rtp_sender_->AllocateSequenceNumber(num_fec_packets);
+        fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed(
+            red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number);
+        RTC_DCHECK_EQ(num_fec_packets, fec_packets.size());
+        if (retransmission_settings_ & kRetransmitFECPackets)
+          fec_storage = kAllowRetransmission;
+      }
+    }
+  }
+  // Send |red_packet| instead of |packet| for allocated sequence number.
+  size_t red_packet_size = red_packet->size();
+  if (rtp_sender_->SendToNetwork(std::move(red_packet), media_packet_storage,
+                                 RtpPacketSender::kLowPriority)) {
+    rtc::CritScope cs(&stats_crit_);
+    video_bitrate_.Update(red_packet_size, clock_->TimeInMilliseconds());
+  } else {
+    RTC_LOG(LS_WARNING) << "Failed to send RED packet " << media_seq_num;
+  }
+  for (const auto& fec_packet : fec_packets) {
+    // TODO(danilchap): Make ulpfec_generator_ generate RtpPacketToSend to avoid
+    // reparsing them.
+    std::unique_ptr<RtpPacketToSend> rtp_packet(
+        new RtpPacketToSend(*media_packet));
+    RTC_CHECK(rtp_packet->Parse(fec_packet->data(), fec_packet->length()));
+    rtp_packet->set_capture_time_ms(media_packet->capture_time_ms());
+    uint16_t fec_sequence_number = rtp_packet->SequenceNumber();
+    if (rtp_sender_->SendToNetwork(std::move(rtp_packet), fec_storage,
+                                   RtpPacketSender::kLowPriority)) {
+      rtc::CritScope cs(&stats_crit_);
+      fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds());
+    } else {
+      RTC_LOG(LS_WARNING) << "Failed to send ULPFEC packet "
+                          << fec_sequence_number;
+    }
+  }
+}
+
+void RTPSenderVideo::SendVideoPacketWithFlexfec(
+    std::unique_ptr<RtpPacketToSend> media_packet,
+    StorageType media_packet_storage,
+    bool protect_media_packet) {
+  RTC_DCHECK(flexfec_sender_);
+
+  if (protect_media_packet)
+    flexfec_sender_->AddRtpPacketAndGenerateFec(*media_packet);
+
+  SendVideoPacket(std::move(media_packet), media_packet_storage);
+
+  if (flexfec_sender_->FecAvailable()) {
+    std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
+        flexfec_sender_->GetFecPackets();
+    for (auto& fec_packet : fec_packets) {
+      size_t packet_length = fec_packet->size();
+      uint16_t seq_num = fec_packet->SequenceNumber();
+      if (rtp_sender_->SendToNetwork(std::move(fec_packet), kDontRetransmit,
+                                     RtpPacketSender::kLowPriority)) {
+        rtc::CritScope cs(&stats_crit_);
+        fec_bitrate_.Update(packet_length, clock_->TimeInMilliseconds());
+      } else {
+        RTC_LOG(LS_WARNING) << "Failed to send FlexFEC packet " << seq_num;
+      }
+    }
+  }
+}
+
+void RTPSenderVideo::SetUlpfecConfig(int red_payload_type,
+                                     int ulpfec_payload_type) {
+  // Sanity check. Per the definition of UlpfecConfig (see config.h),
+  // a payload type of -1 means that the corresponding feature is
+  // turned off.
+  RTC_DCHECK_GE(red_payload_type, -1);
+  RTC_DCHECK_LE(red_payload_type, 127);
+  RTC_DCHECK_GE(ulpfec_payload_type, -1);
+  RTC_DCHECK_LE(ulpfec_payload_type, 127);
+
+  rtc::CritScope cs(&crit_);
+  red_payload_type_ = red_payload_type;
+  ulpfec_payload_type_ = ulpfec_payload_type;
+
+  // Must not enable ULPFEC without RED.
+  RTC_DCHECK(!(red_enabled() ^ ulpfec_enabled()));
+
+  // Reset FEC parameters.
+  delta_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
+  key_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
+}
+
+void RTPSenderVideo::GetUlpfecConfig(int* red_payload_type,
+                                     int* ulpfec_payload_type) const {
+  rtc::CritScope cs(&crit_);
+  *red_payload_type = red_payload_type_;
+  *ulpfec_payload_type = ulpfec_payload_type_;
+}
+
+size_t RTPSenderVideo::CalculateFecPacketOverhead() const {
+  if (flexfec_enabled())
+    return flexfec_sender_->MaxPacketOverhead();
+
+  size_t overhead = 0;
+  if (red_enabled()) {
+    // The RED overhead is due to a small header.
+    overhead += kRedForFecHeaderLength;
+  }
+  if (ulpfec_enabled()) {
+    // For ULPFEC, the overhead is the FEC headers plus RED for FEC header
+    // (see above) plus anything in RTP header beyond the 12 bytes base header
+    // (CSRC list, extensions...)
+    // This reason for the header extensions to be included here is that
+    // from an FEC viewpoint, they are part of the payload to be protected.
+    // (The base RTP header is already protected by the FEC header.)
+    overhead += ulpfec_generator_.MaxPacketOverhead() +
+                (rtp_sender_->RtpHeaderLength() - kRtpHeaderSize);
+  }
+  return overhead;
+}
+
+void RTPSenderVideo::SetFecParameters(const FecProtectionParams& delta_params,
+                                      const FecProtectionParams& key_params) {
+  rtc::CritScope cs(&crit_);
+  delta_fec_params_ = delta_params;
+  key_fec_params_ = key_params;
+}
+
+absl::optional<uint32_t> RTPSenderVideo::FlexfecSsrc() const {
+  if (flexfec_sender_) {
+    return flexfec_sender_->ssrc();
+  }
+  return absl::nullopt;
+}
+
+bool RTPSenderVideo::SendVideo(enum VideoCodecType video_type,
+                               FrameType frame_type,
+                               int8_t payload_type,
+                               uint32_t rtp_timestamp,
+                               int64_t capture_time_ms,
+                               const uint8_t* payload_data,
+                               size_t payload_size,
+                               const RTPFragmentationHeader* fragmentation,
+                               const RTPVideoHeader* video_header,
+                               int64_t expected_retransmission_time_ms) {
+  if (payload_size == 0)
+    return false;
+
+  // Create header that will be reused in all packets.
+  std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket();
+  rtp_header->SetPayloadType(payload_type);
+  rtp_header->SetTimestamp(rtp_timestamp);
+  rtp_header->set_capture_time_ms(capture_time_ms);
+  auto last_packet = absl::make_unique<RtpPacketToSend>(*rtp_header);
+
+  size_t fec_packet_overhead;
+  bool red_enabled;
+  int32_t retransmission_settings;
+  {
+    rtc::CritScope cs(&crit_);
+    // According to
+    // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
+    // ts_126114v120700p.pdf Section 7.4.5:
+    // The MTSI client shall add the payload bytes as defined in this clause
+    // onto the last RTP packet in each group of packets which make up a key
+    // frame (I-frame or IDR frame in H.264 (AVC), or an IRAP picture in H.265
+    // (HEVC)). The MTSI client may also add the payload bytes onto the last RTP
+    // packet in each group of packets which make up another type of frame
+    // (e.g. a P-Frame) only if the current value is different from the previous
+    // value sent.
+    if (video_header) {
+      // Set rotation when key frame or when changed (to follow standard).
+      // Or when different from 0 (to follow current receiver implementation).
+      VideoRotation current_rotation = video_header->rotation;
+      if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ ||
+          current_rotation != kVideoRotation_0)
+        last_packet->SetExtension<VideoOrientation>(current_rotation);
+      last_rotation_ = current_rotation;
+      // Report content type only for key frames.
+      if (frame_type == kVideoFrameKey &&
+          video_header->content_type != VideoContentType::UNSPECIFIED) {
+        last_packet->SetExtension<VideoContentTypeExtension>(
+            video_header->content_type);
+      }
+      if (video_header->video_timing.flags != VideoSendTiming::kInvalid) {
+        last_packet->SetExtension<VideoTimingExtension>(
+            video_header->video_timing);
+      }
+    }
+
+    // FEC settings.
+    const FecProtectionParams& fec_params =
+        frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
+    if (flexfec_enabled())
+      flexfec_sender_->SetFecParameters(fec_params);
+    if (ulpfec_enabled())
+      ulpfec_generator_.SetFecParameters(fec_params);
+
+    fec_packet_overhead = CalculateFecPacketOverhead();
+    red_enabled = this->red_enabled();
+    retransmission_settings = retransmission_settings_;
+  }
+
+  size_t packet_capacity = rtp_sender_->MaxRtpPacketSize() -
+                           fec_packet_overhead -
+                           (rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0);
+  RTC_DCHECK_LE(packet_capacity, rtp_header->capacity());
+  RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size());
+  RTC_DCHECK_GT(packet_capacity, last_packet->headers_size());
+  size_t max_data_payload_length = packet_capacity - rtp_header->headers_size();
+  RTC_DCHECK_GE(last_packet->headers_size(), rtp_header->headers_size());
+  size_t last_packet_reduction_len =
+      last_packet->headers_size() - rtp_header->headers_size();
+
+  std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create(
+      video_type, max_data_payload_length, last_packet_reduction_len,
+      video_header, frame_type));
+
+  const uint8_t temporal_id =
+      video_header ? GetTemporalId(*video_header) : kNoTemporalIdx;
+  StorageType storage = GetStorageType(temporal_id, retransmission_settings,
+                                       expected_retransmission_time_ms);
+  size_t num_packets =
+      packetizer->SetPayloadData(payload_data, payload_size, fragmentation);
+
+  if (num_packets == 0)
+    return false;
+
+  bool first_frame = first_frame_sent_();
+  for (size_t i = 0; i < num_packets; ++i) {
+    bool last = (i + 1) == num_packets;
+    auto packet = last ? std::move(last_packet)
+                       : absl::make_unique<RtpPacketToSend>(*rtp_header);
+    if (!packetizer->NextPacket(packet.get()))
+      return false;
+    RTC_DCHECK_LE(packet->payload_size(),
+                  last ? max_data_payload_length - last_packet_reduction_len
+                       : max_data_payload_length);
+    if (!rtp_sender_->AssignSequenceNumber(packet.get()))
+      return false;
+
+    // No FEC protection for upper temporal layers, if used.
+    bool protect_packet = temporal_id == 0 || temporal_id == kNoTemporalIdx;
+
+    // Put packetization finish timestamp into extension.
+    if (packet->HasExtension<VideoTimingExtension>()) {
+      packet->set_packetization_finish_time_ms(clock_->TimeInMilliseconds());
+      // TODO(ilnik): Due to webrtc:7859, packets with timing extensions are not
+      // protected by FEC. It reduces FEC efficiency a bit. When FEC is moved
+      // below the pacer, it can be re-enabled for these packets.
+      // NOTE: Any RTP stream processor in the network, modifying 'network'
+      // timestamps in the timing frames extension have to be an end-point for
+      // FEC, otherwise recovered by FEC packets will be corrupted.
+      protect_packet = false;
+    }
+
+    if (flexfec_enabled()) {
+      // TODO(brandtr): Remove the FlexFEC code path when FlexfecSender
+      // is wired up to PacedSender instead.
+      SendVideoPacketWithFlexfec(std::move(packet), storage, protect_packet);
+    } else if (red_enabled) {
+      SendVideoPacketAsRedMaybeWithUlpfec(std::move(packet), storage,
+                                          protect_packet);
+    } else {
+      SendVideoPacket(std::move(packet), storage);
+    }
+
+    if (first_frame) {
+      if (i == 0) {
+        RTC_LOG(LS_INFO)
+            << "Sent first RTP packet of the first video frame (pre-pacer)";
+      }
+      if (last) {
+        RTC_LOG(LS_INFO)
+            << "Sent last RTP packet of the first video frame (pre-pacer)";
+      }
+    }
+  }
+
+  TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms, "timestamp",
+                         rtp_timestamp);
+  return true;
+}
+
+uint32_t RTPSenderVideo::VideoBitrateSent() const {
+  rtc::CritScope cs(&stats_crit_);
+  return video_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+}
+
+uint32_t RTPSenderVideo::FecOverheadRate() const {
+  rtc::CritScope cs(&stats_crit_);
+  return fec_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
+}
+
+int RTPSenderVideo::SelectiveRetransmissions() const {
+  rtc::CritScope cs(&crit_);
+  return retransmission_settings_;
+}
+
+void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) {
+  rtc::CritScope cs(&crit_);
+  retransmission_settings_ = settings;
+}
+
+StorageType RTPSenderVideo::GetStorageType(
+    uint8_t temporal_id,
+    int32_t retransmission_settings,
+    int64_t expected_retransmission_time_ms) {
+  if (retransmission_settings == kRetransmitOff)
+    return StorageType::kDontRetransmit;
+  if (retransmission_settings == kRetransmitAllPackets)
+    return StorageType::kAllowRetransmission;
+
+  rtc::CritScope cs(&stats_crit_);
+  // Media packet storage.
+  if ((retransmission_settings & kConditionallyRetransmitHigherLayers) &&
+      UpdateConditionalRetransmit(temporal_id,
+                                  expected_retransmission_time_ms)) {
+    retransmission_settings |= kRetransmitHigherLayers;
+  }
+
+  if (temporal_id == kNoTemporalIdx)
+    return kAllowRetransmission;
+
+  if ((retransmission_settings & kRetransmitBaseLayer) && temporal_id == 0)
+    return kAllowRetransmission;
+
+  if ((retransmission_settings & kRetransmitHigherLayers) && temporal_id > 0)
+    return kAllowRetransmission;
+
+  return kDontRetransmit;
+}
+
+uint8_t RTPSenderVideo::GetTemporalId(const RTPVideoHeader& header) {
+  switch (header.codec) {
+    case kVideoCodecVP8:
+      return header.vp8().temporalIdx;
+    case kVideoCodecVP9:
+      return header.vp9().temporal_idx;
+    default:
+      return kNoTemporalIdx;
+  }
+}
+
+bool RTPSenderVideo::UpdateConditionalRetransmit(
+    uint8_t temporal_id,
+    int64_t expected_retransmission_time_ms) {
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  // Update stats for any temporal layer.
+  TemporalLayerStats* current_layer_stats =
+      &frame_stats_by_temporal_layer_[temporal_id];
+  current_layer_stats->frame_rate_fp1000s.Update(1, now_ms);
+  int64_t tl_frame_interval = now_ms - current_layer_stats->last_frame_time_ms;
+  current_layer_stats->last_frame_time_ms = now_ms;
+
+  // Conditional retransmit only applies to upper layers.
+  if (temporal_id != kNoTemporalIdx && temporal_id > 0) {
+    if (tl_frame_interval >= kMaxUnretransmittableFrameIntervalMs) {
+      // Too long since a retransmittable frame in this layer, enable NACK
+      // protection.
+      return true;
+    } else {
+      // Estimate when the next frame of any lower layer will be sent.
+      const int64_t kUndefined = std::numeric_limits<int64_t>::max();
+      int64_t expected_next_frame_time = kUndefined;
+      for (int i = temporal_id - 1; i >= 0; --i) {
+        TemporalLayerStats* stats = &frame_stats_by_temporal_layer_[i];
+        absl::optional<uint32_t> rate = stats->frame_rate_fp1000s.Rate(now_ms);
+        if (rate) {
+          int64_t tl_next = stats->last_frame_time_ms + 1000000 / *rate;
+          if (tl_next - now_ms > -expected_retransmission_time_ms &&
+              tl_next < expected_next_frame_time) {
+            expected_next_frame_time = tl_next;
+          }
+        }
+      }
+
+      if (expected_next_frame_time == kUndefined ||
+          expected_next_frame_time - now_ms > expected_retransmission_time_ms) {
+        // The next frame in a lower layer is expected at a later time (or
+        // unable to tell due to lack of data) than a retransmission is
+        // estimated to be able to arrive, so allow this packet to be nacked.
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_video.h b/modules/rtp_rtcp/source/rtp_sender_video.h
new file mode 100644
index 0000000..08724c7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -0,0 +1,166 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
+
+#include <map>
+#include <memory>
+
+#include "absl/types/optional.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "modules/rtp_rtcp/source/ulpfec_generator.h"
+#include "rtc_base/criticalsection.h"
+#include "rtc_base/onetimeevent.h"
+#include "rtc_base/rate_statistics.h"
+#include "rtc_base/sequenced_task_checker.h"
+#include "rtc_base/thread_annotations.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+class RtpPacketizer;
+class RtpPacketToSend;
+
+class RTPSenderVideo {
+ public:
+  static constexpr int64_t kTLRateWindowSizeMs = 2500;
+
+  RTPSenderVideo(Clock* clock,
+                 RTPSender* rtpSender,
+                 FlexfecSender* flexfec_sender);
+  virtual ~RTPSenderVideo();
+
+  virtual enum VideoCodecType VideoCodecType() const;
+
+  static RtpUtility::Payload* CreateVideoPayload(
+      const char payload_name[RTP_PAYLOAD_NAME_SIZE],
+      int8_t payload_type);
+
+  bool SendVideo(enum VideoCodecType video_type,
+                 FrameType frame_type,
+                 int8_t payload_type,
+                 uint32_t capture_timestamp,
+                 int64_t capture_time_ms,
+                 const uint8_t* payload_data,
+                 size_t payload_size,
+                 const RTPFragmentationHeader* fragmentation,
+                 const RTPVideoHeader* video_header,
+                 int64_t expected_retransmission_time_ms);
+
+  void SetVideoCodecType(enum VideoCodecType type);
+
+  // ULPFEC.
+  void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
+  void GetUlpfecConfig(int* red_payload_type, int* ulpfec_payload_type) const;
+
+  // FlexFEC/ULPFEC.
+  void SetFecParameters(const FecProtectionParams& delta_params,
+                        const FecProtectionParams& key_params);
+
+  // FlexFEC.
+  absl::optional<uint32_t> FlexfecSsrc() const;
+
+  uint32_t VideoBitrateSent() const;
+  uint32_t FecOverheadRate() const;
+
+  int SelectiveRetransmissions() const;
+  void SetSelectiveRetransmissions(uint8_t settings);
+
+ protected:
+  static uint8_t GetTemporalId(const RTPVideoHeader& header);
+  StorageType GetStorageType(uint8_t temporal_id,
+                             int32_t retransmission_settings,
+                             int64_t expected_retransmission_time_ms);
+
+ private:
+  struct TemporalLayerStats {
+    TemporalLayerStats()
+        : frame_rate_fp1000s(kTLRateWindowSizeMs, 1000 * 1000),
+          last_frame_time_ms(0) {}
+    // Frame rate, in frames per 1000 seconds. This essentially turns the fps
+    // value into a fixed point value with three decimals. Improves precision at
+    // low frame rates.
+    RateStatistics frame_rate_fp1000s;
+    int64_t last_frame_time_ms;
+  };
+
+  size_t CalculateFecPacketOverhead() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
+  void SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet,
+                       StorageType storage);
+
+  void SendVideoPacketAsRedMaybeWithUlpfec(
+      std::unique_ptr<RtpPacketToSend> media_packet,
+      StorageType media_packet_storage,
+      bool protect_media_packet);
+
+  // TODO(brandtr): Remove the FlexFEC functions when FlexfecSender has been
+  // moved to PacedSender.
+  void SendVideoPacketWithFlexfec(std::unique_ptr<RtpPacketToSend> media_packet,
+                                  StorageType media_packet_storage,
+                                  bool protect_media_packet);
+
+  bool red_enabled() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) {
+    return red_payload_type_ >= 0;
+  }
+
+  bool ulpfec_enabled() const RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) {
+    return ulpfec_payload_type_ >= 0;
+  }
+
+  bool flexfec_enabled() const { return flexfec_sender_ != nullptr; }
+
+  bool UpdateConditionalRetransmit(uint8_t temporal_id,
+                                   int64_t expected_retransmission_time_ms)
+      RTC_EXCLUSIVE_LOCKS_REQUIRED(stats_crit_);
+
+  RTPSender* const rtp_sender_;
+  Clock* const clock_;
+
+  // Should never be held when calling out of this class.
+  rtc::CriticalSection crit_;
+
+  enum VideoCodecType video_type_;
+  int32_t retransmission_settings_ RTC_GUARDED_BY(crit_);
+  VideoRotation last_rotation_ RTC_GUARDED_BY(crit_);
+
+  // RED/ULPFEC.
+  int red_payload_type_ RTC_GUARDED_BY(crit_);
+  int ulpfec_payload_type_ RTC_GUARDED_BY(crit_);
+  UlpfecGenerator ulpfec_generator_ RTC_GUARDED_BY(crit_);
+
+  // FlexFEC.
+  FlexfecSender* const flexfec_sender_;
+
+  // FEC parameters, applicable to either ULPFEC or FlexFEC.
+  FecProtectionParams delta_fec_params_ RTC_GUARDED_BY(crit_);
+  FecProtectionParams key_fec_params_ RTC_GUARDED_BY(crit_);
+
+  rtc::CriticalSection stats_crit_;
+  // Bitrate used for FEC payload, RED headers, RTP headers for FEC packets
+  // and any padding overhead.
+  RateStatistics fec_bitrate_ RTC_GUARDED_BY(stats_crit_);
+  // Bitrate used for video payload and RTP headers.
+  RateStatistics video_bitrate_ RTC_GUARDED_BY(stats_crit_);
+
+  std::map<int, TemporalLayerStats> frame_stats_by_temporal_layer_
+      RTC_GUARDED_BY(stats_crit_);
+
+  OneTimeEvent first_frame_sent_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_SENDER_VIDEO_H_
diff --git a/modules/rtp_rtcp/source/rtp_utility.cc b/modules/rtp_rtcp/source/rtp_utility.cc
new file mode 100644
index 0000000..d150ce2
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_utility.cc
@@ -0,0 +1,486 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+
+#include "modules/rtp_rtcp/include/rtp_cvo.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/stringutils.h"
+
+namespace webrtc {
+
+namespace RtpUtility {
+
+enum {
+  kRtcpExpectedVersion = 2,
+  kRtcpMinHeaderLength = 4,
+  kRtcpMinParseLength = 8,
+
+  kRtpExpectedVersion = 2,
+  kRtpMinParseLength = 12
+};
+
+/*
+ * Misc utility routines
+ */
+
+bool StringCompare(const char* str1, const char* str2, const uint32_t length) {
+  return _strnicmp(str1, str2, length) == 0;
+}
+
+size_t Word32Align(size_t size) {
+  uint32_t remainder = size % 4;
+  if (remainder != 0)
+    return size + 4 - remainder;
+  return size;
+}
+
+RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData,
+                                 const size_t rtpDataLength)
+    : _ptrRTPDataBegin(rtpData),
+      _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {}
+
+RtpHeaderParser::~RtpHeaderParser() {}
+
+bool RtpHeaderParser::RTCP() const {
+  // 72 to 76 is reserved for RTP
+  // 77 to 79 is not reserver but  they are not assigned we will block them
+  // for RTCP 200 SR  == marker bit + 72
+  // for RTCP 204 APP == marker bit + 76
+  /*
+   *       RTCP
+   *
+   * FIR      full INTRA-frame request             192     [RFC2032]   supported
+   * NACK     negative acknowledgement             193     [RFC2032]
+   * IJ       Extended inter-arrival jitter report 195 [RFC-ietf-avt-rtp-toff
+   * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
+   * SR       sender report                        200     [RFC3551]   supported
+   * RR       receiver report                      201     [RFC3551]   supported
+   * SDES     source description                   202     [RFC3551]   supported
+   * BYE      goodbye                              203     [RFC3551]   supported
+   * APP      application-defined                  204     [RFC3551]   ignored
+   * RTPFB    Transport layer FB message           205     [RFC4585]   supported
+   * PSFB     Payload-specific FB message          206     [RFC4585]   supported
+   * XR       extended report                      207     [RFC3611]   supported
+   */
+
+  /* 205       RFC 5104
+   * FMT 1      NACK       supported
+   * FMT 2      reserved
+   * FMT 3      TMMBR      supported
+   * FMT 4      TMMBN      supported
+   */
+
+  /* 206      RFC 5104
+   * FMT 1:     Picture Loss Indication (PLI)                      supported
+   * FMT 2:     Slice Lost Indication (SLI)
+   * FMT 3:     Reference Picture Selection Indication (RPSI)
+   * FMT 4:     Full Intra Request (FIR) Command                   supported
+   * FMT 5:     Temporal-Spatial Trade-off Request (TSTR)
+   * FMT 6:     Temporal-Spatial Trade-off Notification (TSTN)
+   * FMT 7:     Video Back Channel Message (VBCM)
+   * FMT 15:    Application layer FB message
+   */
+
+  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
+  if (length < kRtcpMinHeaderLength) {
+    return false;
+  }
+
+  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
+  if (V != kRtcpExpectedVersion) {
+    return false;
+  }
+
+  const uint8_t payloadType = _ptrRTPDataBegin[1];
+  switch (payloadType) {
+    case 192:
+      return true;
+    case 193:
+      // not supported
+      // pass through and check for a potential RTP packet
+      return false;
+    case 195:
+    case 200:
+    case 201:
+    case 202:
+    case 203:
+    case 204:
+    case 205:
+    case 206:
+    case 207:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool RtpHeaderParser::ParseRtcp(RTPHeader* header) const {
+  assert(header != NULL);
+
+  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
+  if (length < kRtcpMinParseLength) {
+    return false;
+  }
+
+  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
+  if (V != kRtcpExpectedVersion) {
+    return false;
+  }
+
+  const uint8_t PT = _ptrRTPDataBegin[1];
+  const size_t len = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
+  const uint8_t* ptr = &_ptrRTPDataBegin[4];
+
+  uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
+  ptr += 4;
+
+  header->payloadType = PT;
+  header->ssrc = SSRC;
+  header->headerLength = 4 + (len << 2);
+
+  return true;
+}
+
+bool RtpHeaderParser::Parse(
+    RTPHeader* header,
+    const RtpHeaderExtensionMap* ptrExtensionMap) const {
+  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
+  if (length < kRtpMinParseLength) {
+    return false;
+  }
+
+  // Version
+  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
+  // Padding
+  const bool P = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
+  // eXtension
+  const bool X = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
+  const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
+  const bool M = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
+
+  const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;
+
+  const uint16_t sequenceNumber =
+      (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
+
+  const uint8_t* ptr = &_ptrRTPDataBegin[4];
+
+  uint32_t RTPTimestamp = ByteReader<uint32_t>::ReadBigEndian(ptr);
+  ptr += 4;
+
+  uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
+  ptr += 4;
+
+  if (V != kRtpExpectedVersion) {
+    return false;
+  }
+
+  const size_t CSRCocts = CC * 4;
+
+  if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
+    return false;
+  }
+
+  header->markerBit = M;
+  header->payloadType = PT;
+  header->sequenceNumber = sequenceNumber;
+  header->timestamp = RTPTimestamp;
+  header->ssrc = SSRC;
+  header->numCSRCs = CC;
+  header->paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;
+
+  for (uint8_t i = 0; i < CC; ++i) {
+    uint32_t CSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
+    ptr += 4;
+    header->arrOfCSRCs[i] = CSRC;
+  }
+
+  header->headerLength = 12 + CSRCocts;
+
+  // If in effect, MAY be omitted for those packets for which the offset
+  // is zero.
+  header->extension.hasTransmissionTimeOffset = false;
+  header->extension.transmissionTimeOffset = 0;
+
+  // May not be present in packet.
+  header->extension.hasAbsoluteSendTime = false;
+  header->extension.absoluteSendTime = 0;
+
+  // May not be present in packet.
+  header->extension.hasAudioLevel = false;
+  header->extension.voiceActivity = false;
+  header->extension.audioLevel = 0;
+
+  // May not be present in packet.
+  header->extension.hasVideoRotation = false;
+  header->extension.videoRotation = kVideoRotation_0;
+
+  // May not be present in packet.
+  header->extension.playout_delay.min_ms = -1;
+  header->extension.playout_delay.max_ms = -1;
+
+  // May not be present in packet.
+  header->extension.hasVideoContentType = false;
+  header->extension.videoContentType = VideoContentType::UNSPECIFIED;
+
+  header->extension.has_video_timing = false;
+  header->extension.video_timing = {0u, 0u, 0u, 0u, 0u, 0u, false};
+
+  if (X) {
+    /* RTP header extension, RFC 3550.
+     0                   1                   2                   3
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |      defined by profile       |           length              |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                        header extension                       |
+    |                             ....                              |
+    */
+    const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
+    if (remain < 4) {
+      return false;
+    }
+
+    header->headerLength += 4;
+
+    uint16_t definedByProfile = ByteReader<uint16_t>::ReadBigEndian(ptr);
+    ptr += 2;
+
+    // in 32 bit words
+    size_t XLen = ByteReader<uint16_t>::ReadBigEndian(ptr);
+    ptr += 2;
+    XLen *= 4;  // in bytes
+
+    if (static_cast<size_t>(remain) < (4 + XLen)) {
+      return false;
+    }
+    static constexpr uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
+    if (definedByProfile == kRtpOneByteHeaderExtensionId) {
+      const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen;
+      ParseOneByteExtensionHeader(header, ptrExtensionMap,
+                                  ptrRTPDataExtensionEnd, ptr);
+    }
+    header->headerLength += XLen;
+  }
+  if (header->headerLength + header->paddingLength >
+      static_cast<size_t>(length))
+    return false;
+  return true;
+}
+
+void RtpHeaderParser::ParseOneByteExtensionHeader(
+    RTPHeader* header,
+    const RtpHeaderExtensionMap* ptrExtensionMap,
+    const uint8_t* ptrRTPDataExtensionEnd,
+    const uint8_t* ptr) const {
+  if (!ptrExtensionMap) {
+    return;
+  }
+
+  while (ptrRTPDataExtensionEnd - ptr > 0) {
+    //  0
+    //  0 1 2 3 4 5 6 7
+    // +-+-+-+-+-+-+-+-+
+    // |  ID   |  len  |
+    // +-+-+-+-+-+-+-+-+
+
+    // Note that 'len' is the header extension element length, which is the
+    // number of bytes - 1.
+    const int id = (*ptr & 0xf0) >> 4;
+    const int len = (*ptr & 0x0f);
+    ptr++;
+
+    if (id == 0) {
+      // Padding byte, skip ignoring len.
+      continue;
+    }
+
+    if (id == 15) {
+      RTC_LOG(LS_VERBOSE)
+          << "RTP extension header 15 encountered. Terminate parsing.";
+      return;
+    }
+
+    if (ptrRTPDataExtensionEnd - ptr < (len + 1)) {
+      RTC_LOG(LS_WARNING) << "Incorrect one-byte extension len: " << (len + 1)
+                          << ", bytes left in buffer: "
+                          << (ptrRTPDataExtensionEnd - ptr);
+      return;
+    }
+
+    RTPExtensionType type = ptrExtensionMap->GetType(id);
+    if (type == RtpHeaderExtensionMap::kInvalidType) {
+      // If we encounter an unknown extension, just skip over it.
+      RTC_LOG(LS_WARNING) << "Failed to find extension id: " << id;
+    } else {
+      switch (type) {
+        case kRtpExtensionTransmissionTimeOffset: {
+          if (len != 2) {
+            RTC_LOG(LS_WARNING)
+                << "Incorrect transmission time offset len: " << len;
+            return;
+          }
+          //  0                   1                   2                   3
+          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          // |  ID   | len=2 |              transmission offset              |
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+          header->extension.transmissionTimeOffset =
+              ByteReader<int32_t, 3>::ReadBigEndian(ptr);
+          header->extension.hasTransmissionTimeOffset = true;
+          break;
+        }
+        case kRtpExtensionAudioLevel: {
+          if (len != 0) {
+            RTC_LOG(LS_WARNING) << "Incorrect audio level len: " << len;
+            return;
+          }
+          //  0                   1
+          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          // |  ID   | len=0 |V|   level     |
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          //
+          header->extension.audioLevel = ptr[0] & 0x7f;
+          header->extension.voiceActivity = (ptr[0] & 0x80) != 0;
+          header->extension.hasAudioLevel = true;
+          break;
+        }
+        case kRtpExtensionAbsoluteSendTime: {
+          if (len != 2) {
+            RTC_LOG(LS_WARNING) << "Incorrect absolute send time len: " << len;
+            return;
+          }
+          //  0                   1                   2                   3
+          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          // |  ID   | len=2 |              absolute send time               |
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+          header->extension.absoluteSendTime =
+              ByteReader<uint32_t, 3>::ReadBigEndian(ptr);
+          header->extension.hasAbsoluteSendTime = true;
+          break;
+        }
+        case kRtpExtensionVideoRotation: {
+          if (len != 0) {
+            RTC_LOG(LS_WARNING)
+                << "Incorrect coordination of video coordination len: " << len;
+            return;
+          }
+          //  0                   1
+          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          // |  ID   | len=0 |0 0 0 0 C F R R|
+          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          header->extension.hasVideoRotation = true;
+          header->extension.videoRotation =
+              ConvertCVOByteToVideoRotation(ptr[0]);
+          break;
+        }
+        case kRtpExtensionTransportSequenceNumber: {
+          if (len != 1) {
+            RTC_LOG(LS_WARNING)
+                << "Incorrect transport sequence number len: " << len;
+            return;
+          }
+          //   0                   1                   2
+          //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          //  |  ID   | L=1   |transport wide sequence number |
+          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+          uint16_t sequence_number = ptr[0] << 8;
+          sequence_number += ptr[1];
+          header->extension.transportSequenceNumber = sequence_number;
+          header->extension.hasTransportSequenceNumber = true;
+          break;
+        }
+        case kRtpExtensionPlayoutDelay: {
+          if (len != 2) {
+            RTC_LOG(LS_WARNING) << "Incorrect playout delay len: " << len;
+            return;
+          }
+          //   0                   1                   2                   3
+          //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          //  |  ID   | len=2 |   MIN delay           |   MAX delay           |
+          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+          int min_playout_delay = (ptr[0] << 4) | ((ptr[1] >> 4) & 0xf);
+          int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2];
+          header->extension.playout_delay.min_ms =
+              min_playout_delay * PlayoutDelayLimits::kGranularityMs;
+          header->extension.playout_delay.max_ms =
+              max_playout_delay * PlayoutDelayLimits::kGranularityMs;
+          break;
+        }
+        case kRtpExtensionVideoContentType: {
+          if (len != 0) {
+            RTC_LOG(LS_WARNING) << "Incorrect video content type len: " << len;
+            return;
+          }
+          //    0                   1
+          //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+          //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+          //   |  ID   | len=0 | Content type  |
+          //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+          if (videocontenttypehelpers::IsValidContentType(ptr[0])) {
+            header->extension.hasVideoContentType = true;
+            header->extension.videoContentType =
+                static_cast<VideoContentType>(ptr[0]);
+          }
+          break;
+        }
+        case kRtpExtensionVideoTiming: {
+          if (len != VideoTimingExtension::kValueSizeBytes - 1) {
+            RTC_LOG(LS_WARNING) << "Incorrect video timing len: " << len;
+            return;
+          }
+          header->extension.has_video_timing = true;
+          VideoTimingExtension::Parse(rtc::MakeArrayView(ptr, len + 1),
+                                      &header->extension.video_timing);
+          break;
+        }
+        case kRtpExtensionRtpStreamId: {
+          header->extension.stream_id.Set(rtc::MakeArrayView(ptr, len + 1));
+          break;
+        }
+        case kRtpExtensionRepairedRtpStreamId: {
+          header->extension.repaired_stream_id.Set(
+              rtc::MakeArrayView(ptr, len + 1));
+          break;
+        }
+        case kRtpExtensionMid: {
+          header->extension.mid.Set(rtc::MakeArrayView(ptr, len + 1));
+          break;
+        }
+        case kRtpExtensionGenericFrameDescriptor:
+          RTC_LOG(WARNING)
+              << "RtpGenericFrameDescriptor unsupported by rtp header parser.";
+          break;
+        case kRtpExtensionNone:
+        case kRtpExtensionNumberOfExtensions: {
+          RTC_NOTREACHED() << "Invalid extension type: " << type;
+          return;
+        }
+      }
+    }
+    ptr += (len + 1);
+  }
+}
+
+}  // namespace RtpUtility
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_utility.h b/modules/rtp_rtcp/source/rtp_utility.h
new file mode 100644
index 0000000..51732df
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_utility.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_UTILITY_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_UTILITY_H_
+
+#include <cstring>
+#include <map>
+
+#include "modules/rtp_rtcp/include/receive_statistics.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
+#include "rtc_base/deprecation.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+const uint8_t kRtpMarkerBitMask = 0x80;
+
+namespace RtpUtility {
+
+struct Payload {
+  Payload(const char* name, const PayloadUnion& pu) : typeSpecific(pu) {
+    std::strncpy(this->name, name, sizeof(this->name) - 1);
+    this->name[sizeof(this->name) - 1] = '\0';
+  }
+  char name[RTP_PAYLOAD_NAME_SIZE];
+  PayloadUnion typeSpecific;
+};
+
+bool StringCompare(const char* str1, const char* str2, const uint32_t length);
+
+// Round up to the nearest size that is a multiple of 4.
+size_t Word32Align(size_t size);
+
+class RtpHeaderParser {
+ public:
+  RtpHeaderParser(const uint8_t* rtpData, size_t rtpDataLength);
+  ~RtpHeaderParser();
+
+  bool RTCP() const;
+  bool ParseRtcp(RTPHeader* header) const;
+  bool Parse(RTPHeader* parsedPacket,
+             const RtpHeaderExtensionMap* ptrExtensionMap = nullptr) const;
+
+ private:
+  void ParseOneByteExtensionHeader(RTPHeader* parsedPacket,
+                                   const RtpHeaderExtensionMap* ptrExtensionMap,
+                                   const uint8_t* ptrRTPDataExtensionEnd,
+                                   const uint8_t* ptr) const;
+
+  const uint8_t* const _ptrRTPDataBegin;
+  const uint8_t* const _ptrRTPDataEnd;
+};
+}  // namespace RtpUtility
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_UTILITY_H_
diff --git a/modules/rtp_rtcp/source/rtp_utility_unittest.cc b/modules/rtp_rtcp/source/rtp_utility_unittest.cc
new file mode 100644
index 0000000..e1bcfb7
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_utility_unittest.cc
@@ -0,0 +1,272 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAreArray;
+using ::testing::make_tuple;
+
+const int8_t kPayloadType = 100;
+const uint32_t kSsrc = 0x12345678;
+const uint16_t kSeqNum = 88;
+const uint32_t kTimestamp = 0x65431278;
+
+}  // namespace
+
+TEST(RtpHeaderParser, ParseMinimum) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+    0x80, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,   // kTimestamp.
+    0x12, 0x34, 0x56, 0x78};  // kSsrc.
+  // clang-format on
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, nullptr));
+
+  EXPECT_EQ(kPayloadType, header.payloadType);
+  EXPECT_EQ(kSeqNum, header.sequenceNumber);
+  EXPECT_EQ(kTimestamp, header.timestamp);
+  EXPECT_EQ(kSsrc, header.ssrc);
+  EXPECT_EQ(0u, header.paddingLength);
+  EXPECT_EQ(sizeof(kPacket), header.headerLength);
+}
+
+TEST(RtpHeaderParser, ParseWithExtension) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+    0x90, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+    0x12, 0x34, 0x56, 0x78,  // kSsrc.
+    0xbe, 0xde, 0x00, 0x01,  // Extension block of size 1 x 32bit words.
+    0x12, 0x01, 0x56, 0xce};
+  // clang-format on
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<TransmissionOffset>(1);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+
+  EXPECT_EQ(kPayloadType, header.payloadType);
+  EXPECT_EQ(kSeqNum, header.sequenceNumber);
+  EXPECT_EQ(kTimestamp, header.timestamp);
+  EXPECT_EQ(kSsrc, header.ssrc);
+
+  ASSERT_TRUE(header.extension.hasTransmissionTimeOffset);
+  EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset);
+}
+
+TEST(RtpHeaderParser, ParseWithInvalidSizedExtension) {
+  const size_t kPayloadSize = 7;
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x02,  // Extension block of size 2 x 32bit words.
+      0x16,  // (6+1)-bytes, but Transmission Offset expected to be 3-bytes.
+             'e',  'x',  't',
+       'd',  'a',  't',  'a',
+       'p',  'a',  'y',  'l',  'o',  'a',  'd'
+  };
+  // clang-format on
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<TransmissionOffset>(1);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+
+  // Extension should be ignored.
+  EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
+  // But shouldn't prevent reading payload.
+  EXPECT_THAT(sizeof(kPacket) - kPayloadSize, header.headerLength);
+}
+
+TEST(RtpHeaderParser, ParseWithExtensionPadding) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x02,  // Extension of size 1x32bit word.
+      0x02,  // A byte of (invalid) padding.
+      0x12, 0x1a, 0xda, 0x03,  // TransmissionOffset extension.
+      0x0f, 0x00, 0x03,  // More invalid padding bytes: id=0, but len > 0.
+  };
+  // clang-format on
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<TransmissionOffset>(1);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+
+  // Parse should skip padding and read extension.
+  EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
+  EXPECT_EQ(0x1ada03, header.extension.transmissionTimeOffset);
+  EXPECT_EQ(sizeof(kPacket), header.headerLength);
+}
+
+TEST(RtpHeaderParser, ParseWithOverSizedExtension) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x01,  // Extension of size 1x32bit word.
+      0x00,  // Add a byte of padding.
+            0x12,  // Extension id 1 size (2+1).
+                  0xda, 0x1a  // Only 2 bytes of extension payload.
+  };
+  // clang-format on
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<TransmissionOffset>(1);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+
+  // Parse should ignore extension.
+  EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
+  EXPECT_EQ(sizeof(kPacket), header.headerLength);
+}
+
+TEST(RtpHeaderParser, ParseAll8Extensions) {
+  const uint8_t kAudioLevel = 0x5a;
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x08,  // Extension of size 8x32bit words.
+      0x40, 0x80|kAudioLevel,  // AudioLevel.
+      0x22, 0x01, 0x56, 0xce,  // TransmissionOffset.
+      0x62, 0x12, 0x34, 0x56,  // AbsoluteSendTime.
+      0x81, 0xce, 0xab,        // TransportSequenceNumber.
+      0xa0, 0x03,              // VideoRotation.
+      0xb2, 0x12, 0x48, 0x76,  // PlayoutDelayLimits.
+      0xc2, 'r', 't', 'x',     // RtpStreamId
+      0xd5, 's', 't', 'r', 'e', 'a', 'm',  // RepairedRtpStreamId
+      0x00, 0x00,              // Padding to 32bit boundary.
+  };
+  // clang-format on
+  ASSERT_EQ(sizeof(kPacket) % 4, 0u);
+
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<TransmissionOffset>(2);
+  extensions.Register<AudioLevel>(4);
+  extensions.Register<AbsoluteSendTime>(6);
+  extensions.Register<TransportSequenceNumber>(8);
+  extensions.Register<VideoOrientation>(0xa);
+  extensions.Register<PlayoutDelayLimits>(0xb);
+  extensions.Register<RtpStreamId>(0xc);
+  extensions.Register<RepairedRtpStreamId>(0xd);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+
+  EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
+  EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset);
+
+  EXPECT_TRUE(header.extension.hasAudioLevel);
+  EXPECT_TRUE(header.extension.voiceActivity);
+  EXPECT_EQ(kAudioLevel, header.extension.audioLevel);
+
+  EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
+  EXPECT_EQ(0x123456U, header.extension.absoluteSendTime);
+
+  EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
+  EXPECT_EQ(0xceab, header.extension.transportSequenceNumber);
+
+  EXPECT_TRUE(header.extension.hasVideoRotation);
+  EXPECT_EQ(kVideoRotation_270, header.extension.videoRotation);
+
+  EXPECT_EQ(0x124 * PlayoutDelayLimits::kGranularityMs,
+            header.extension.playout_delay.min_ms);
+  EXPECT_EQ(0x876 * PlayoutDelayLimits::kGranularityMs,
+            header.extension.playout_delay.max_ms);
+  EXPECT_EQ(header.extension.stream_id, StreamId("rtx"));
+  EXPECT_EQ(header.extension.repaired_stream_id, StreamId("stream"));
+}
+
+TEST(RtpHeaderParser, ParseMalformedRsidExtensions) {
+  // clang-format off
+  const uint8_t kPacket[] = {
+      0x90, kPayloadType, 0x00, kSeqNum,
+      0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+      0x12, 0x34, 0x56, 0x78,  // kSsrc.
+      0xbe, 0xde, 0x00, 0x03,  // Extension of size 3x32bit words.
+      0xc2, '\0', 't', 'x',    // empty RtpStreamId
+      0xd5, 's', 't', 'r', '\0', 'a', 'm',  // RepairedRtpStreamId
+      0x00,                    // Padding to 32bit boundary.
+  };
+  // clang-format on
+  ASSERT_EQ(sizeof(kPacket) % 4, 0u);
+
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<RtpStreamId>(0xc);
+  extensions.Register<RepairedRtpStreamId>(0xd);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+  EXPECT_TRUE(header.extension.stream_id.empty());
+  EXPECT_EQ(header.extension.repaired_stream_id, StreamId("str"));
+}
+
+TEST(RtpHeaderParser, ParseWithCsrcsExtensionAndPadding) {
+  const uint8_t kPacketPaddingSize = 8;
+  const uint32_t kCsrcs[] = {0x34567890, 0x32435465};
+  const size_t kPayloadSize = 7;
+  // clang-format off
+  const uint8_t kPacket[] = {
+    0xb2, kPayloadType, 0x00, kSeqNum,
+    0x65, 0x43, 0x12, 0x78,  // kTimestamp.
+    0x12, 0x34, 0x56, 0x78,  // kSsrc.
+    0x34, 0x56, 0x78, 0x90,  // kCsrcs[0].
+    0x32, 0x43, 0x54, 0x65,  // kCsrcs[1].
+    0xbe, 0xde, 0x00, 0x01,  // Extension.
+    0x12, 0x00, 0x56, 0xce,  // TransmissionTimeOffset with id = 1.
+    'p', 'a', 'y', 'l', 'o', 'a', 'd',
+    'p', 'a', 'd', 'd', 'i', 'n', 'g', kPacketPaddingSize};
+  // clang-format on
+  RtpHeaderExtensionMap extensions;
+  extensions.Register<TransmissionOffset>(1);
+  RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
+  RTPHeader header;
+
+  EXPECT_TRUE(parser.Parse(&header, &extensions));
+
+  EXPECT_EQ(kPayloadType, header.payloadType);
+  EXPECT_EQ(kSeqNum, header.sequenceNumber);
+  EXPECT_EQ(kTimestamp, header.timestamp);
+  EXPECT_EQ(kSsrc, header.ssrc);
+  EXPECT_THAT(make_tuple(header.arrOfCSRCs, header.numCSRCs),
+              ElementsAreArray(kCsrcs));
+  EXPECT_EQ(kPacketPaddingSize, header.paddingLength);
+  EXPECT_THAT(sizeof(kPacket) - kPayloadSize - kPacketPaddingSize,
+              header.headerLength);
+  EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
+  EXPECT_EQ(0x56ce, header.extension.transmissionTimeOffset);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_video_header.cc b/modules/rtp_rtcp/source/rtp_video_header.cc
new file mode 100644
index 0000000..020a52e
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_video_header.cc
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/rtp_video_header.h"
+
+namespace webrtc {
+
+RTPVideoHeader::RTPVideoHeader()
+    : width(),
+      height(),
+      rotation(),
+      playout_delay(),
+      content_type(),
+      video_timing(),
+      is_first_packet_in_frame(),
+      simulcastIdx(),
+      codec() {}
+RTPVideoHeader::RTPVideoHeader(const RTPVideoHeader& other) = default;
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_video_header.h b/modules/rtp_rtcp/source/rtp_video_header.h
new file mode 100644
index 0000000..49e2d29
--- /dev/null
+++ b/modules/rtp_rtcp/source/rtp_video_header.h
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_RTP_VIDEO_HEADER_H_
+#define MODULES_RTP_RTCP_SOURCE_RTP_VIDEO_HEADER_H_
+
+#include "absl/types/variant.h"
+#include "api/video/video_content_type.h"
+#include "api/video/video_rotation.h"
+#include "api/video/video_timing.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/video_coding/codecs/h264/include/h264_globals.h"
+#include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
+#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
+
+namespace webrtc {
+using RTPVideoTypeHeader =
+    absl::variant<RTPVideoHeaderVP8, RTPVideoHeaderVP9, RTPVideoHeaderH264>;
+
+struct RTPVideoHeader {
+  RTPVideoHeader();
+  RTPVideoHeader(const RTPVideoHeader& other);
+
+  // TODO(philipel): Remove when downstream projects have been updated.
+  RTPVideoHeaderVP8& vp8() {
+    if (!absl::holds_alternative<RTPVideoHeaderVP8>(video_type_header))
+      video_type_header.emplace<RTPVideoHeaderVP8>();
+
+    return absl::get<RTPVideoHeaderVP8>(video_type_header);
+  }
+  // TODO(philipel): Remove when downstream projects have been updated.
+  const RTPVideoHeaderVP8& vp8() const {
+    if (!absl::holds_alternative<RTPVideoHeaderVP8>(video_type_header))
+      video_type_header.emplace<RTPVideoHeaderVP8>();
+
+    return absl::get<RTPVideoHeaderVP8>(video_type_header);
+  }
+  // TODO(philipel): Remove when downstream projects have been updated.
+  RTPVideoHeaderVP9& vp9() {
+    if (!absl::holds_alternative<RTPVideoHeaderVP9>(video_type_header))
+      video_type_header.emplace<RTPVideoHeaderVP9>();
+
+    return absl::get<RTPVideoHeaderVP9>(video_type_header);
+  }
+  // TODO(philipel): Remove when downstream projects have been updated.
+  const RTPVideoHeaderVP9& vp9() const {
+    if (!absl::holds_alternative<RTPVideoHeaderVP9>(video_type_header))
+      video_type_header.emplace<RTPVideoHeaderVP9>();
+
+    return absl::get<RTPVideoHeaderVP9>(video_type_header);
+  }
+  // TODO(philipel): Remove when downstream projects have been updated.
+  RTPVideoHeaderH264& h264() {
+    if (!absl::holds_alternative<RTPVideoHeaderH264>(video_type_header))
+      video_type_header.emplace<RTPVideoHeaderH264>();
+
+    return absl::get<RTPVideoHeaderH264>(video_type_header);
+  }
+  // TODO(philipel): Remove when downstream projects have been updated.
+  const RTPVideoHeaderH264& h264() const {
+    if (!absl::holds_alternative<RTPVideoHeaderH264>(video_type_header))
+      video_type_header.emplace<RTPVideoHeaderH264>();
+
+    return absl::get<RTPVideoHeaderH264>(video_type_header);
+  }
+
+  uint16_t width;
+  uint16_t height;
+  VideoRotation rotation;
+  PlayoutDelay playout_delay;
+  VideoContentType content_type;
+  VideoSendTiming video_timing;
+  bool is_first_packet_in_frame;
+  uint8_t simulcastIdx;
+  VideoCodecType codec;
+  // TODO(philipel): remove mutable when downstream projects have been updated.
+  mutable RTPVideoTypeHeader video_type_header;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_RTP_VIDEO_HEADER_H_
diff --git a/modules/rtp_rtcp/source/time_util.cc b/modules/rtp_rtcp/source/time_util.cc
new file mode 100644
index 0000000..6ac280a
--- /dev/null
+++ b/modules/rtp_rtcp/source/time_util.cc
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/time_util.h"
+
+#include <algorithm>
+
+#include "rtc_base/timeutils.h"
+
+namespace webrtc {
+namespace {
+// TODO(danilchap): Make generic, optimize and move to base.
+inline int64_t DivideRoundToNearest(int64_t x, uint32_t y) {
+  // Callers ensure x is positive and x + y / 2 doesn't overflow.
+  return (x + y / 2) / y;
+}
+
+int64_t NtpOffsetUs() {
+  constexpr int64_t kNtpJan1970Sec = 2208988800;
+  int64_t clock_time = rtc::TimeMicros();
+  int64_t utc_time = rtc::TimeUTCMicros();
+  return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
+}
+
+}  // namespace
+
+NtpTime TimeMicrosToNtp(int64_t time_us) {
+  // Calculate the offset once.
+  static int64_t ntp_offset_us = NtpOffsetUs();
+
+  int64_t time_ntp_us = time_us + ntp_offset_us;
+  RTC_DCHECK_GE(time_ntp_us, 0);  // Time before year 1900 is unsupported.
+
+  // TODO(danilchap): Convert both seconds and fraction together using int128
+  // when that type is easily available.
+  // Currently conversion is done separetly for seconds and fraction of a second
+  // to avoid overflow.
+
+  // Convert seconds to uint32 through uint64 for well-defined cast.
+  // Wrap around (will happen in 2036) is expected for ntp time.
+  uint32_t ntp_seconds =
+      static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
+
+  // Scale fractions of the second to ntp resolution.
+  constexpr int64_t kNtpInSecond = 1LL << 32;
+  int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
+  uint32_t ntp_fractions =
+      us_fractions * kNtpInSecond / rtc::kNumMicrosecsPerSec;
+  return NtpTime(ntp_seconds, ntp_fractions);
+}
+
+uint32_t SaturatedUsToCompactNtp(int64_t us) {
+  constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF;
+  constexpr int kCompactNtpInSecond = 0x10000;
+  if (us <= 0)
+    return 0;
+  if (us >= kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond)
+    return kMaxCompactNtp;
+  // To convert to compact ntp need to divide by 1e6 to get seconds,
+  // then multiply by 0x10000 to get the final result.
+  // To avoid float operations, multiplication and division swapped.
+  return DivideRoundToNearest(us * kCompactNtpInSecond,
+                              rtc::kNumMicrosecsPerSec);
+}
+
+int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval) {
+  // Interval to convert expected to be positive, e.g. rtt or delay.
+  // Because interval can be derived from non-monotonic ntp clock,
+  // it might become negative that is indistinguishable from very large values.
+  // Since very large rtt/delay are less likely than non-monotonic ntp clock,
+  // those values consider to be negative and convert to minimum value of 1ms.
+  if (compact_ntp_interval > 0x80000000)
+    return 1;
+  // Convert to 64bit value to avoid multiplication overflow.
+  int64_t value = static_cast<int64_t>(compact_ntp_interval);
+  // To convert to milliseconds need to divide by 2^16 to get seconds,
+  // then multiply by 1000 to get milliseconds. To avoid float operations,
+  // multiplication and division swapped.
+  int64_t ms = DivideRoundToNearest(value * 1000, 1 << 16);
+  // Rtt value 0 considered too good to be true and increases to 1.
+  return std::max<int64_t>(ms, 1);
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/time_util.h b/modules/rtp_rtcp/source/time_util.h
new file mode 100644
index 0000000..672722c
--- /dev/null
+++ b/modules/rtp_rtcp/source/time_util.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_
+#define MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_
+
+#include <stdint.h>
+
+#include "system_wrappers/include/ntp_time.h"
+
+namespace webrtc {
+
+// Converts time obtained using rtc::TimeMicros to ntp format.
+// TimeMicrosToNtp guarantees difference of the returned values matches
+// difference of the passed values.
+// As a result TimeMicrosToNtp(rtc::TimeMicros()) doesn't guarantee to match
+// system time.
+NtpTime TimeMicrosToNtp(int64_t time_us);
+
+// Converts NTP timestamp to RTP timestamp.
+inline uint32_t NtpToRtp(NtpTime ntp, uint32_t freq) {
+  uint32_t tmp = (static_cast<uint64_t>(ntp.fractions()) * freq) >> 32;
+  return ntp.seconds() * freq + tmp;
+}
+
+// Helper function for compact ntp representation:
+// RFC 3550, Section 4. Time Format.
+// Wallclock time is represented using the timestamp format of
+// the Network Time Protocol (NTP).
+// ...
+// In some fields where a more compact representation is
+// appropriate, only the middle 32 bits are used; that is, the low 16
+// bits of the integer part and the high 16 bits of the fractional part.
+inline uint32_t CompactNtp(NtpTime ntp) {
+  return (ntp.seconds() << 16) | (ntp.fractions() >> 16);
+}
+
+// Converts interval in microseconds to compact ntp (1/2^16 seconds) resolution.
+// Negative values converted to 0, Overlarge values converted to max uint32_t.
+uint32_t SaturatedUsToCompactNtp(int64_t us);
+
+// Converts interval between compact ntp timestamps to milliseconds.
+// This interval can be up to ~9.1 hours (2^15 seconds).
+// Values close to 2^16 seconds consider negative and result in minimum rtt = 1.
+int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval);
+
+}  // namespace webrtc
+#endif  // MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_
diff --git a/modules/rtp_rtcp/source/time_util_unittest.cc b/modules/rtp_rtcp/source/time_util_unittest.cc
new file mode 100644
index 0000000..0ff4f7b
--- /dev/null
+++ b/modules/rtp_rtcp/source/time_util_unittest.cc
@@ -0,0 +1,117 @@
+/*
+ *  Copyright (c) 2015 The WebRTC 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.
+ */
+#include "modules/rtp_rtcp/source/time_util.h"
+
+#include "rtc_base/fakeclock.h"
+#include "rtc_base/timeutils.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(TimeUtilTest, TimeMicrosToNtpDoesntChangeBetweenRuns) {
+  rtc::ScopedFakeClock clock;
+  // TimeMicrosToNtp is not pure: it behave differently between different
+  // execution of the program, but should behave same during same execution.
+  const int64_t time_us = 12345;
+  clock.SetTimeMicros(2);
+  NtpTime time_ntp = TimeMicrosToNtp(time_us);
+  clock.SetTimeMicros(time_us);
+  EXPECT_EQ(TimeMicrosToNtp(time_us), time_ntp);
+  clock.SetTimeMicros(1000000);
+  EXPECT_EQ(TimeMicrosToNtp(time_us), time_ntp);
+}
+
+TEST(TimeUtilTest, TimeMicrosToNtpKeepsIntervals) {
+  rtc::ScopedFakeClock clock;
+  NtpTime time_ntp1 = TimeMicrosToNtp(rtc::TimeMicros());
+  clock.AdvanceTimeMicros(20000);
+  NtpTime time_ntp2 = TimeMicrosToNtp(rtc::TimeMicros());
+  EXPECT_EQ(time_ntp2.ToMs() - time_ntp1.ToMs(), 20);
+}
+
+TEST(TimeUtilTest, CompactNtp) {
+  const uint32_t kNtpSec = 0x12345678;
+  const uint32_t kNtpFrac = 0x23456789;
+  const NtpTime kNtp(kNtpSec, kNtpFrac);
+  const uint32_t kNtpMid = 0x56782345;
+  EXPECT_EQ(kNtpMid, CompactNtp(kNtp));
+}
+
+TEST(TimeUtilTest, CompactNtpRttToMs) {
+  const NtpTime ntp1(0x12345, 0x23456);
+  const NtpTime ntp2(0x12654, 0x64335);
+  int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
+  uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
+
+  int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
+
+  EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1);
+}
+
+TEST(TimeUtilTest, CompactNtpRttToMsWithWrap) {
+  const NtpTime ntp1(0x1ffff, 0x23456);
+  const NtpTime ntp2(0x20000, 0x64335);
+  int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
+
+  // While ntp2 > ntp1, there compact ntp presentation happen to be opposite.
+  // That shouldn't be a problem as long as unsigned arithmetic is used.
+  ASSERT_GT(ntp2.ToMs(), ntp1.ToMs());
+  ASSERT_LT(CompactNtp(ntp2), CompactNtp(ntp1));
+
+  uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
+  int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
+
+  EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1);
+}
+
+TEST(TimeUtilTest, CompactNtpRttToMsLarge) {
+  const NtpTime ntp1(0x10000, 0x00006);
+  const NtpTime ntp2(0x17fff, 0xffff5);
+  int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
+  // Ntp difference close to 2^15 seconds should convert correctly too.
+  ASSERT_NEAR(ms_diff, ((1 << 15) - 1) * 1000, 1);
+  uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
+  int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
+
+  EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1);
+}
+
+TEST(TimeUtilTest, CompactNtpRttToMsNegative) {
+  const NtpTime ntp1(0x20000, 0x23456);
+  const NtpTime ntp2(0x1ffff, 0x64335);
+  int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
+  ASSERT_GT(0, ms_diff);
+  // Ntp difference close to 2^16 seconds should be treated as negative.
+  uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
+  int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
+  EXPECT_EQ(1, ntp_to_ms_diff);
+}
+
+TEST(TimeUtilTest, SaturatedUsToCompactNtp) {
+  // Converts negative to zero.
+  EXPECT_EQ(SaturatedUsToCompactNtp(-1), 0u);
+  EXPECT_EQ(SaturatedUsToCompactNtp(0), 0u);
+  // Converts values just above and just below max uint32_t.
+  EXPECT_EQ(SaturatedUsToCompactNtp(65536000000), 0xffffffff);
+  EXPECT_EQ(SaturatedUsToCompactNtp(65535999985), 0xffffffff);
+  EXPECT_EQ(SaturatedUsToCompactNtp(65535999970), 0xfffffffe);
+  // Converts half-seconds.
+  EXPECT_EQ(SaturatedUsToCompactNtp(500000), 0x8000u);
+  EXPECT_EQ(SaturatedUsToCompactNtp(1000000), 0x10000u);
+  EXPECT_EQ(SaturatedUsToCompactNtp(1500000), 0x18000u);
+  // Convert us -> compact_ntp -> ms. Compact ntp precision is ~15us.
+  EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(1516)), 2);
+  EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(15000)), 15);
+  EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5485)), 5);
+  EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5515)), 6);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/tmmbr_help.cc b/modules/rtp_rtcp/source/tmmbr_help.cc
new file mode 100644
index 0000000..8aa4530
--- /dev/null
+++ b/modules/rtp_rtcp/source/tmmbr_help.cc
@@ -0,0 +1,182 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/tmmbr_help.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+std::vector<rtcp::TmmbItem> TMMBRHelp::FindBoundingSet(
+    std::vector<rtcp::TmmbItem> candidates) {
+  // Filter out candidates with 0 bitrate.
+  for (auto it = candidates.begin(); it != candidates.end();) {
+    if (!it->bitrate_bps())
+      it = candidates.erase(it);
+    else
+      ++it;
+  }
+
+  if (candidates.size() <= 1)
+    return candidates;
+
+  size_t num_candidates = candidates.size();
+
+  // 1. Sort by increasing packet overhead.
+  std::sort(candidates.begin(), candidates.end(),
+            [](const rtcp::TmmbItem& lhs, const rtcp::TmmbItem& rhs) {
+              return lhs.packet_overhead() < rhs.packet_overhead();
+            });
+
+  // 2. For tuples with same overhead, keep the one with the lowest bitrate.
+  for (auto it = candidates.begin(); it != candidates.end();) {
+    RTC_DCHECK(it->bitrate_bps());
+    auto current_min = it;
+    auto next_it = it + 1;
+    // Use fact candidates are sorted by overhead, so candidates with same
+    // overhead are adjusted.
+    while (next_it != candidates.end() &&
+           next_it->packet_overhead() == current_min->packet_overhead()) {
+      if (next_it->bitrate_bps() < current_min->bitrate_bps()) {
+        current_min->set_bitrate_bps(0);
+        current_min = next_it;
+      } else {
+        next_it->set_bitrate_bps(0);
+      }
+      ++next_it;
+      --num_candidates;
+    }
+    it = next_it;
+  }
+
+  // 3. Select and remove tuple with lowest bitrate.
+  // (If more than 1, choose the one with highest overhead).
+  auto min_bitrate_it = candidates.end();
+  for (auto it = candidates.begin(); it != candidates.end(); ++it) {
+    if (it->bitrate_bps()) {
+      min_bitrate_it = it;
+      break;
+    }
+  }
+
+  for (auto it = min_bitrate_it; it != candidates.end(); ++it) {
+    if (it->bitrate_bps() &&
+        it->bitrate_bps() <= min_bitrate_it->bitrate_bps()) {
+      // Get min bitrate.
+      min_bitrate_it = it;
+    }
+  }
+
+  std::vector<rtcp::TmmbItem> bounding_set;
+  bounding_set.reserve(num_candidates);
+  std::vector<float> intersection(num_candidates);
+  std::vector<float> max_packet_rate(num_candidates);
+
+  // First member of selected list.
+  bounding_set.push_back(*min_bitrate_it);
+  intersection[0] = 0;
+  // Calculate its maximum packet rate (where its line crosses x-axis).
+  uint16_t packet_overhead = bounding_set.back().packet_overhead();
+  if (packet_overhead == 0) {
+    // Avoid division by zero.
+    max_packet_rate[0] = std::numeric_limits<float>::max();
+  } else {
+    max_packet_rate[0] =
+        bounding_set.back().bitrate_bps() / static_cast<float>(packet_overhead);
+  }
+  // Remove from candidate list.
+  min_bitrate_it->set_bitrate_bps(0);
+  --num_candidates;
+
+  // 4. Discard from candidate list all tuple with lower overhead
+  // (next tuple must be steeper).
+  for (auto it = candidates.begin(); it != candidates.end(); ++it) {
+    if (it->bitrate_bps() &&
+        it->packet_overhead() < bounding_set.front().packet_overhead()) {
+      it->set_bitrate_bps(0);
+      --num_candidates;
+    }
+  }
+
+  bool get_new_candidate = true;
+  rtcp::TmmbItem cur_candidate;
+  while (num_candidates > 0) {
+    if (get_new_candidate) {
+      // 5. Remove first remaining tuple from candidate list.
+      for (auto it = candidates.begin(); it != candidates.end(); ++it) {
+        if (it->bitrate_bps()) {
+          cur_candidate = *it;
+          it->set_bitrate_bps(0);
+          break;
+        }
+      }
+    }
+
+    // 6. Calculate packet rate and intersection of the current
+    // line with line of last tuple in selected list.
+    RTC_DCHECK_NE(cur_candidate.packet_overhead(),
+                  bounding_set.back().packet_overhead());
+    float packet_rate = static_cast<float>(cur_candidate.bitrate_bps() -
+                                           bounding_set.back().bitrate_bps()) /
+                        (cur_candidate.packet_overhead() -
+                         bounding_set.back().packet_overhead());
+
+    // 7. If the packet rate is equal or lower than intersection of
+    //    last tuple in selected list,
+    //    remove last tuple in selected list & go back to step 6.
+    if (packet_rate <= intersection[bounding_set.size() - 1]) {
+      // Remove last tuple and goto step 6.
+      bounding_set.pop_back();
+      get_new_candidate = false;
+    } else {
+      // 8. If packet rate is lower than maximum packet rate of
+      // last tuple in selected list, add current tuple to selected
+      // list.
+      if (packet_rate < max_packet_rate[bounding_set.size() - 1]) {
+        bounding_set.push_back(cur_candidate);
+        intersection[bounding_set.size() - 1] = packet_rate;
+        uint16_t packet_overhead = bounding_set.back().packet_overhead();
+        RTC_DCHECK_NE(packet_overhead, 0);
+        max_packet_rate[bounding_set.size() - 1] =
+            bounding_set.back().bitrate_bps() /
+            static_cast<float>(packet_overhead);
+      }
+      --num_candidates;
+      get_new_candidate = true;
+    }
+
+    // 9. Go back to step 5 if any tuple remains in candidate list.
+  }
+  RTC_DCHECK(!bounding_set.empty());
+  return bounding_set;
+}
+
+bool TMMBRHelp::IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
+                        uint32_t ssrc) {
+  for (const rtcp::TmmbItem& item : bounding) {
+    if (item.ssrc() == ssrc) {
+      return true;
+    }
+  }
+  return false;
+}
+
+uint64_t TMMBRHelp::CalcMinBitrateBps(
+    const std::vector<rtcp::TmmbItem>& candidates) {
+  RTC_DCHECK(!candidates.empty());
+  uint64_t min_bitrate_bps = std::numeric_limits<uint64_t>::max();
+  for (const rtcp::TmmbItem& item : candidates)
+    if (item.bitrate_bps() < min_bitrate_bps)
+      min_bitrate_bps = item.bitrate_bps();
+  return min_bitrate_bps;
+}
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/tmmbr_help.h b/modules/rtp_rtcp/source/tmmbr_help.h
new file mode 100644
index 0000000..46ce845
--- /dev/null
+++ b/modules/rtp_rtcp/source/tmmbr_help.h
@@ -0,0 +1,33 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_TMMBR_HELP_H_
+#define MODULES_RTP_RTCP_SOURCE_TMMBR_HELP_H_
+
+#include <vector>
+#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class TMMBRHelp {
+ public:
+  static std::vector<rtcp::TmmbItem> FindBoundingSet(
+      std::vector<rtcp::TmmbItem> candidates);
+
+  static bool IsOwner(const std::vector<rtcp::TmmbItem>& bounding,
+                      uint32_t ssrc);
+
+  static uint64_t CalcMinBitrateBps(
+      const std::vector<rtcp::TmmbItem>& candidates);
+};
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_TMMBR_HELP_H_
diff --git a/modules/rtp_rtcp/source/ulpfec_generator.cc b/modules/rtp_rtcp/source/ulpfec_generator.cc
new file mode 100644
index 0000000..e5777ed
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_generator.cc
@@ -0,0 +1,254 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/ulpfec_generator.h"
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/rtp_utility.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr size_t kRedForFecHeaderLength = 1;
+
+// This controls the maximum amount of excess overhead (actual - target)
+// allowed in order to trigger EncodeFec(), before |params_.max_fec_frames|
+// is reached. Overhead here is defined as relative to number of media packets.
+constexpr int kMaxExcessOverhead = 50;  // Q8.
+
+// This is the minimum number of media packets required (above some protection
+// level) in order to trigger EncodeFec(), before |params_.max_fec_frames| is
+// reached.
+constexpr size_t kMinMediaPackets = 4;
+
+// Threshold on the received FEC protection level, above which we enforce at
+// least |kMinMediaPackets| packets for the FEC code. Below this
+// threshold |kMinMediaPackets| is set to default value of 1.
+//
+// The range is between 0 and 255, where 255 corresponds to 100% overhead
+// (relative to the number of protected media packets).
+constexpr uint8_t kHighProtectionThreshold = 80;
+
+// This threshold is used to adapt the |kMinMediaPackets| threshold, based
+// on the average number of packets per frame seen so far. When there are few
+// packets per frame (as given by this threshold), at least
+// |kMinMediaPackets| + 1 packets are sent to the FEC code.
+constexpr float kMinMediaPacketsAdaptationThreshold = 2.0f;
+
+// At construction time, we don't know the SSRC that is used for the generated
+// FEC packets, but we still need to give it to the ForwardErrorCorrection ctor
+// to be used in the decoding.
+// TODO(brandtr): Get rid of this awkwardness by splitting
+// ForwardErrorCorrection in two objects -- one encoder and one decoder.
+constexpr uint32_t kUnknownSsrc = 0;
+
+}  // namespace
+
+RedPacket::RedPacket(size_t length)
+    : data_(new uint8_t[length]), length_(length), header_length_(0) {}
+
+RedPacket::~RedPacket() = default;
+
+void RedPacket::CreateHeader(const uint8_t* rtp_header,
+                             size_t header_length,
+                             int red_payload_type,
+                             int payload_type) {
+  RTC_DCHECK_LE(header_length + kRedForFecHeaderLength, length_);
+  memcpy(data_.get(), rtp_header, header_length);
+  // Replace payload type.
+  data_[1] &= 0x80;
+  data_[1] += red_payload_type;
+  // Add RED header
+  // f-bit always 0
+  data_[header_length] = static_cast<uint8_t>(payload_type);
+  header_length_ = header_length + kRedForFecHeaderLength;
+}
+
+void RedPacket::SetSeqNum(int seq_num) {
+  RTC_DCHECK_GE(seq_num, 0);
+  RTC_DCHECK_LT(seq_num, 1 << 16);
+
+  ByteWriter<uint16_t>::WriteBigEndian(&data_[2], seq_num);
+}
+
+void RedPacket::AssignPayload(const uint8_t* payload, size_t length) {
+  RTC_DCHECK_LE(header_length_ + length, length_);
+  memcpy(data_.get() + header_length_, payload, length);
+}
+
+void RedPacket::ClearMarkerBit() {
+  data_[1] &= 0x7F;
+}
+
+uint8_t* RedPacket::data() const {
+  return data_.get();
+}
+
+size_t RedPacket::length() const {
+  return length_;
+}
+
+UlpfecGenerator::UlpfecGenerator()
+    : UlpfecGenerator(ForwardErrorCorrection::CreateUlpfec(kUnknownSsrc)) {}
+
+UlpfecGenerator::UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec)
+    : fec_(std::move(fec)),
+      last_media_packet_rtp_header_length_(0),
+      num_protected_frames_(0),
+      min_num_media_packets_(1) {
+  memset(&params_, 0, sizeof(params_));
+  memset(&new_params_, 0, sizeof(new_params_));
+}
+
+UlpfecGenerator::~UlpfecGenerator() = default;
+
+void UlpfecGenerator::SetFecParameters(const FecProtectionParams& params) {
+  RTC_DCHECK_GE(params.fec_rate, 0);
+  RTC_DCHECK_LE(params.fec_rate, 255);
+  // Store the new params and apply them for the next set of FEC packets being
+  // produced.
+  new_params_ = params;
+  if (params.fec_rate > kHighProtectionThreshold) {
+    min_num_media_packets_ = kMinMediaPackets;
+  } else {
+    min_num_media_packets_ = 1;
+  }
+}
+
+int UlpfecGenerator::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
+                                                size_t payload_length,
+                                                size_t rtp_header_length) {
+  RTC_DCHECK(generated_fec_packets_.empty());
+  if (media_packets_.empty()) {
+    params_ = new_params_;
+  }
+  bool complete_frame = false;
+  const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
+  if (media_packets_.size() < kUlpfecMaxMediaPackets) {
+    // Our packet masks can only protect up to |kUlpfecMaxMediaPackets| packets.
+    std::unique_ptr<ForwardErrorCorrection::Packet> packet(
+        new ForwardErrorCorrection::Packet());
+    packet->length = payload_length + rtp_header_length;
+    memcpy(packet->data, data_buffer, packet->length);
+    media_packets_.push_back(std::move(packet));
+    // Keep track of the RTP header length, so we can copy the RTP header
+    // from |packet| to newly generated ULPFEC+RED packets.
+    RTC_DCHECK_GE(rtp_header_length, kRtpHeaderSize);
+    last_media_packet_rtp_header_length_ = rtp_header_length;
+  }
+  if (marker_bit) {
+    ++num_protected_frames_;
+    complete_frame = true;
+  }
+  // Produce FEC over at most |params_.max_fec_frames| frames, or as soon as:
+  // (1) the excess overhead (actual overhead - requested/target overhead) is
+  // less than |kMaxExcessOverhead|, and
+  // (2) at least |min_num_media_packets_| media packets is reached.
+  if (complete_frame &&
+      (num_protected_frames_ == params_.max_fec_frames ||
+       (ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
+    // We are not using Unequal Protection feature of the parity erasure code.
+    constexpr int kNumImportantPackets = 0;
+    constexpr bool kUseUnequalProtection = false;
+    int ret = fec_->EncodeFec(media_packets_, params_.fec_rate,
+                              kNumImportantPackets, kUseUnequalProtection,
+                              params_.fec_mask_type, &generated_fec_packets_);
+    if (generated_fec_packets_.empty()) {
+      ResetState();
+    }
+    return ret;
+  }
+  return 0;
+}
+
+bool UlpfecGenerator::ExcessOverheadBelowMax() const {
+  return ((Overhead() - params_.fec_rate) < kMaxExcessOverhead);
+}
+
+bool UlpfecGenerator::MinimumMediaPacketsReached() const {
+  float average_num_packets_per_frame =
+      static_cast<float>(media_packets_.size()) / num_protected_frames_;
+  int num_media_packets = static_cast<int>(media_packets_.size());
+  if (average_num_packets_per_frame < kMinMediaPacketsAdaptationThreshold) {
+    return num_media_packets >= min_num_media_packets_;
+  } else {
+    // For larger rates (more packets/frame), increase the threshold.
+    // TODO(brandtr): Investigate what impact this adaptation has.
+    return num_media_packets >= min_num_media_packets_ + 1;
+  }
+}
+
+bool UlpfecGenerator::FecAvailable() const {
+  return !generated_fec_packets_.empty();
+}
+
+size_t UlpfecGenerator::NumAvailableFecPackets() const {
+  return generated_fec_packets_.size();
+}
+
+size_t UlpfecGenerator::MaxPacketOverhead() const {
+  return fec_->MaxPacketOverhead();
+}
+
+std::vector<std::unique_ptr<RedPacket>> UlpfecGenerator::GetUlpfecPacketsAsRed(
+    int red_payload_type,
+    int ulpfec_payload_type,
+    uint16_t first_seq_num) {
+  std::vector<std::unique_ptr<RedPacket>> red_packets;
+  red_packets.reserve(generated_fec_packets_.size());
+  RTC_DCHECK(!media_packets_.empty());
+  ForwardErrorCorrection::Packet* last_media_packet =
+      media_packets_.back().get();
+  uint16_t seq_num = first_seq_num;
+  for (const auto* fec_packet : generated_fec_packets_) {
+    // Wrap FEC packet (including FEC headers) in a RED packet. Since the
+    // FEC packets in |generated_fec_packets_| don't have RTP headers, we
+    // reuse the header from the last media packet.
+    RTC_DCHECK_GT(last_media_packet_rtp_header_length_, 0);
+    std::unique_ptr<RedPacket> red_packet(
+        new RedPacket(last_media_packet_rtp_header_length_ +
+                      kRedForFecHeaderLength + fec_packet->length));
+    red_packet->CreateHeader(last_media_packet->data,
+                             last_media_packet_rtp_header_length_,
+                             red_payload_type, ulpfec_payload_type);
+    red_packet->SetSeqNum(seq_num++);
+    red_packet->ClearMarkerBit();
+    red_packet->AssignPayload(fec_packet->data, fec_packet->length);
+    red_packets.push_back(std::move(red_packet));
+  }
+
+  ResetState();
+
+  return red_packets;
+}
+
+int UlpfecGenerator::Overhead() const {
+  RTC_DCHECK(!media_packets_.empty());
+  int num_fec_packets =
+      fec_->NumFecPackets(media_packets_.size(), params_.fec_rate);
+  // Return the overhead in Q8.
+  return (num_fec_packets << 8) / media_packets_.size();
+}
+
+void UlpfecGenerator::ResetState() {
+  media_packets_.clear();
+  last_media_packet_rtp_header_length_ = 0;
+  generated_fec_packets_.clear();
+  num_protected_frames_ = 0;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/ulpfec_generator.h b/modules/rtp_rtcp/source/ulpfec_generator.h
new file mode 100644
index 0000000..efc753f
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_generator.h
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_ULPFEC_GENERATOR_H_
+#define MODULES_RTP_RTCP_SOURCE_ULPFEC_GENERATOR_H_
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+namespace webrtc {
+
+class FlexfecSender;
+
+class RedPacket {
+ public:
+  explicit RedPacket(size_t length);
+  ~RedPacket();
+
+  void CreateHeader(const uint8_t* rtp_header,
+                    size_t header_length,
+                    int red_payload_type,
+                    int payload_type);
+  void SetSeqNum(int seq_num);
+  void AssignPayload(const uint8_t* payload, size_t length);
+  void ClearMarkerBit();
+  uint8_t* data() const;
+  size_t length() const;
+
+ private:
+  std::unique_ptr<uint8_t[]> data_;
+  size_t length_;
+  size_t header_length_;
+};
+
+class UlpfecGenerator {
+  friend class FlexfecSender;
+
+ public:
+  UlpfecGenerator();
+  ~UlpfecGenerator();
+
+  void SetFecParameters(const FecProtectionParams& params);
+
+  // Adds a media packet to the internal buffer. When enough media packets
+  // have been added, the FEC packets are generated and stored internally.
+  // These FEC packets are then obtained by calling GetFecPacketsAsRed().
+  int AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
+                                 size_t payload_length,
+                                 size_t rtp_header_length);
+
+  // Returns true if there are generated FEC packets available.
+  bool FecAvailable() const;
+
+  size_t NumAvailableFecPackets() const;
+
+  // Returns the overhead, per packet, for FEC (and possibly RED).
+  size_t MaxPacketOverhead() const;
+
+  // Returns generated FEC packets with RED headers added.
+  std::vector<std::unique_ptr<RedPacket>> GetUlpfecPacketsAsRed(
+      int red_payload_type,
+      int ulpfec_payload_type,
+      uint16_t first_seq_num);
+
+ private:
+  explicit UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec);
+
+  // Overhead is defined as relative to the number of media packets, and not
+  // relative to total number of packets. This definition is inherited from the
+  // protection factor produced by video_coding module and how the FEC
+  // generation is implemented.
+  int Overhead() const;
+
+  // Returns true if the excess overhead (actual - target) for the FEC is below
+  // the amount |kMaxExcessOverhead|. This effects the lower protection level
+  // cases and low number of media packets/frame. The target overhead is given
+  // by |params_.fec_rate|, and is only achievable in the limit of large number
+  // of media packets.
+  bool ExcessOverheadBelowMax() const;
+
+  // Returns true if the number of added media packets is at least
+  // |min_num_media_packets_|. This condition tries to capture the effect
+  // that, for the same amount of protection/overhead, longer codes
+  // (e.g. (2k,2m) vs (k,m)) are generally more effective at recovering losses.
+  bool MinimumMediaPacketsReached() const;
+
+  void ResetState();
+
+  std::unique_ptr<ForwardErrorCorrection> fec_;
+  ForwardErrorCorrection::PacketList media_packets_;
+  size_t last_media_packet_rtp_header_length_;
+  std::list<ForwardErrorCorrection::Packet*> generated_fec_packets_;
+  int num_protected_frames_;
+  int min_num_media_packets_;
+  FecProtectionParams params_;
+  FecProtectionParams new_params_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_ULPFEC_GENERATOR_H_
diff --git a/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc b/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc
new file mode 100644
index 0000000..39ead62
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_generator_unittest.cc
@@ -0,0 +1,206 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <list>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/ulpfec_generator.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+using test::fec::AugmentedPacket;
+using test::fec::AugmentedPacketGenerator;
+
+constexpr int kFecPayloadType = 96;
+constexpr int kRedPayloadType = 97;
+constexpr uint32_t kMediaSsrc = 835424;
+}  // namespace
+
+void VerifyHeader(uint16_t seq_num,
+                  uint32_t timestamp,
+                  int red_payload_type,
+                  int fec_payload_type,
+                  RedPacket* packet,
+                  bool marker_bit) {
+  EXPECT_GT(packet->length(), kRtpHeaderSize);
+  EXPECT_TRUE(packet->data() != NULL);
+  uint8_t* data = packet->data();
+  // Marker bit not set.
+  EXPECT_EQ(marker_bit ? 0x80 : 0, data[1] & 0x80);
+  EXPECT_EQ(red_payload_type, data[1] & 0x7F);
+  EXPECT_EQ(seq_num, (data[2] << 8) + data[3]);
+  uint32_t parsed_timestamp =
+      (data[4] << 24) + (data[5] << 16) + (data[6] << 8) + data[7];
+  EXPECT_EQ(timestamp, parsed_timestamp);
+  EXPECT_EQ(static_cast<uint8_t>(fec_payload_type), data[kRtpHeaderSize]);
+}
+
+class UlpfecGeneratorTest : public ::testing::Test {
+ protected:
+  UlpfecGeneratorTest() : packet_generator_(kMediaSsrc) {}
+
+  UlpfecGenerator ulpfec_generator_;
+  AugmentedPacketGenerator packet_generator_;
+};
+
+// Verifies bug found via fuzzing, where a gap in the packet sequence caused us
+// to move past the end of the current FEC packet mask byte without moving to
+// the next byte. That likely caused us to repeatedly read from the same byte,
+// and if that byte didn't protect packets we would generate empty FEC.
+TEST_F(UlpfecGeneratorTest, NoEmptyFecWithSeqNumGaps) {
+  struct Packet {
+    size_t header_size;
+    size_t payload_size;
+    uint16_t seq_num;
+    bool marker_bit;
+  };
+  std::vector<Packet> protected_packets;
+  protected_packets.push_back({15, 3, 41, 0});
+  protected_packets.push_back({14, 1, 43, 0});
+  protected_packets.push_back({19, 0, 48, 0});
+  protected_packets.push_back({19, 0, 50, 0});
+  protected_packets.push_back({14, 3, 51, 0});
+  protected_packets.push_back({13, 8, 52, 0});
+  protected_packets.push_back({19, 2, 53, 0});
+  protected_packets.push_back({12, 3, 54, 0});
+  protected_packets.push_back({21, 0, 55, 0});
+  protected_packets.push_back({13, 3, 57, 1});
+  FecProtectionParams params = {117, 3, kFecMaskBursty};
+  ulpfec_generator_.SetFecParameters(params);
+  uint8_t packet[28] = {0};
+  for (Packet p : protected_packets) {
+    if (p.marker_bit) {
+      packet[1] |= 0x80;
+    } else {
+      packet[1] &= ~0x80;
+    }
+    ByteWriter<uint16_t>::WriteBigEndian(&packet[2], p.seq_num);
+    ulpfec_generator_.AddRtpPacketAndGenerateFec(packet, p.payload_size,
+                                                 p.header_size);
+    size_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets();
+    if (num_fec_packets > 0) {
+      std::vector<std::unique_ptr<RedPacket>> fec_packets =
+          ulpfec_generator_.GetUlpfecPacketsAsRed(kRedPayloadType,
+                                                  kFecPayloadType, 100);
+      EXPECT_EQ(num_fec_packets, fec_packets.size());
+    }
+  }
+}
+
+TEST_F(UlpfecGeneratorTest, OneFrameFec) {
+  // The number of media packets (|kNumPackets|), number of frames (one for
+  // this test), and the protection factor (|params->fec_rate|) are set to make
+  // sure the conditions for generating FEC are satisfied. This means:
+  // (1) protection factor is high enough so that actual overhead over 1 frame
+  // of packets is within |kMaxExcessOverhead|, and (2) the total number of
+  // media packets for 1 frame is at least |minimum_media_packets_fec_|.
+  constexpr size_t kNumPackets = 4;
+  FecProtectionParams params = {15, 3, kFecMaskRandom};
+  packet_generator_.NewFrame(kNumPackets);
+  ulpfec_generator_.SetFecParameters(params);  // Expecting one FEC packet.
+  uint32_t last_timestamp = 0;
+  for (size_t i = 0; i < kNumPackets; ++i) {
+    std::unique_ptr<AugmentedPacket> packet =
+        packet_generator_.NextPacket(i, 10);
+    EXPECT_EQ(0, ulpfec_generator_.AddRtpPacketAndGenerateFec(
+                     packet->data, packet->length, kRtpHeaderSize));
+    last_timestamp = packet->header.header.timestamp;
+  }
+  EXPECT_TRUE(ulpfec_generator_.FecAvailable());
+  const uint16_t seq_num = packet_generator_.NextPacketSeqNum();
+  std::vector<std::unique_ptr<RedPacket>> red_packets =
+      ulpfec_generator_.GetUlpfecPacketsAsRed(kRedPayloadType, kFecPayloadType,
+                                              seq_num);
+  EXPECT_FALSE(ulpfec_generator_.FecAvailable());
+  ASSERT_EQ(1u, red_packets.size());
+  VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType,
+               red_packets.front().get(), false);
+}
+
+TEST_F(UlpfecGeneratorTest, TwoFrameFec) {
+  // The number of media packets/frame (|kNumPackets|), the number of frames
+  // (|kNumFrames|), and the protection factor (|params->fec_rate|) are set to
+  // make sure the conditions for generating FEC are satisfied. This means:
+  // (1) protection factor is high enough so that actual overhead over
+  // |kNumFrames| is within |kMaxExcessOverhead|, and (2) the total number of
+  // media packets for |kNumFrames| frames is at least
+  // |minimum_media_packets_fec_|.
+  constexpr size_t kNumPackets = 2;
+  constexpr size_t kNumFrames = 2;
+
+  FecProtectionParams params = {15, 3, kFecMaskRandom};
+  ulpfec_generator_.SetFecParameters(params);  // Expecting one FEC packet.
+  uint32_t last_timestamp = 0;
+  for (size_t i = 0; i < kNumFrames; ++i) {
+    packet_generator_.NewFrame(kNumPackets);
+    for (size_t j = 0; j < kNumPackets; ++j) {
+      std::unique_ptr<AugmentedPacket> packet =
+          packet_generator_.NextPacket(i * kNumPackets + j, 10);
+      EXPECT_EQ(0, ulpfec_generator_.AddRtpPacketAndGenerateFec(
+                       packet->data, packet->length, kRtpHeaderSize));
+      last_timestamp = packet->header.header.timestamp;
+    }
+  }
+  EXPECT_TRUE(ulpfec_generator_.FecAvailable());
+  const uint16_t seq_num = packet_generator_.NextPacketSeqNum();
+  std::vector<std::unique_ptr<RedPacket>> red_packets =
+      ulpfec_generator_.GetUlpfecPacketsAsRed(kRedPayloadType, kFecPayloadType,
+                                              seq_num);
+  EXPECT_FALSE(ulpfec_generator_.FecAvailable());
+  ASSERT_EQ(1u, red_packets.size());
+  VerifyHeader(seq_num, last_timestamp, kRedPayloadType, kFecPayloadType,
+               red_packets.front().get(), false);
+}
+
+TEST_F(UlpfecGeneratorTest, MixedMediaRtpHeaderLengths) {
+  constexpr size_t kShortRtpHeaderLength = 12;
+  constexpr size_t kLongRtpHeaderLength = 16;
+
+  // Only one frame required to generate FEC.
+  FecProtectionParams params = {127, 1, kFecMaskRandom};
+  ulpfec_generator_.SetFecParameters(params);
+
+  // Fill up internal buffer with media packets with short RTP header length.
+  packet_generator_.NewFrame(kUlpfecMaxMediaPackets + 1);
+  for (size_t i = 0; i < kUlpfecMaxMediaPackets; ++i) {
+    std::unique_ptr<AugmentedPacket> packet =
+        packet_generator_.NextPacket(i, 10);
+    EXPECT_EQ(0, ulpfec_generator_.AddRtpPacketAndGenerateFec(
+                     packet->data, packet->length, kShortRtpHeaderLength));
+    EXPECT_FALSE(ulpfec_generator_.FecAvailable());
+  }
+
+  // Kick off FEC generation with media packet with long RTP header length.
+  // Since the internal buffer is full, this packet will not be protected.
+  std::unique_ptr<AugmentedPacket> packet =
+      packet_generator_.NextPacket(kUlpfecMaxMediaPackets, 10);
+  EXPECT_EQ(0, ulpfec_generator_.AddRtpPacketAndGenerateFec(
+                   packet->data, packet->length, kLongRtpHeaderLength));
+  EXPECT_TRUE(ulpfec_generator_.FecAvailable());
+
+  // Ensure that the RED header is placed correctly, i.e. the correct
+  // RTP header length was used in the RED packet creation.
+  const uint16_t seq_num = packet_generator_.NextPacketSeqNum();
+  std::vector<std::unique_ptr<RedPacket>> red_packets =
+      ulpfec_generator_.GetUlpfecPacketsAsRed(kRedPayloadType, kFecPayloadType,
+                                              seq_num);
+  for (const auto& red_packet : red_packets) {
+    EXPECT_EQ(kFecPayloadType, red_packet->data()[kShortRtpHeaderLength]);
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc b/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc
new file mode 100644
index 0000000..c54d3cd
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_header_reader_writer.cc
@@ -0,0 +1,131 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maximum number of media packets that can be protected in one batch.
+constexpr size_t kMaxMediaPackets = 48;
+
+// Maximum number of FEC packets stored inside ForwardErrorCorrection.
+constexpr size_t kMaxFecPackets = kMaxMediaPackets;
+
+// FEC Level 0 header size in bytes.
+constexpr size_t kFecLevel0HeaderSize = 10;
+
+// FEC Level 1 (ULP) header size in bytes (L bit is set).
+constexpr size_t kFecLevel1HeaderSizeLBitSet = 2 + kUlpfecPacketMaskSizeLBitSet;
+
+// FEC Level 1 (ULP) header size in bytes (L bit is cleared).
+constexpr size_t kFecLevel1HeaderSizeLBitClear =
+    2 + kUlpfecPacketMaskSizeLBitClear;
+
+constexpr size_t kPacketMaskOffset = kFecLevel0HeaderSize + 2;
+
+size_t UlpfecHeaderSize(size_t packet_mask_size) {
+  RTC_DCHECK_LE(packet_mask_size, kUlpfecPacketMaskSizeLBitSet);
+  if (packet_mask_size <= kUlpfecPacketMaskSizeLBitClear) {
+    return kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitClear;
+  } else {
+    return kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitSet;
+  }
+}
+
+}  // namespace
+
+UlpfecHeaderReader::UlpfecHeaderReader()
+    : FecHeaderReader(kMaxMediaPackets, kMaxFecPackets) {}
+
+UlpfecHeaderReader::~UlpfecHeaderReader() = default;
+
+bool UlpfecHeaderReader::ReadFecHeader(
+    ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const {
+  bool l_bit = (fec_packet->pkt->data[0] & 0x40) != 0u;
+  size_t packet_mask_size =
+      l_bit ? kUlpfecPacketMaskSizeLBitSet : kUlpfecPacketMaskSizeLBitClear;
+  fec_packet->fec_header_size = UlpfecHeaderSize(packet_mask_size);
+  uint16_t seq_num_base =
+      ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[2]);
+  fec_packet->protected_ssrc = fec_packet->ssrc;  // Due to RED.
+  fec_packet->seq_num_base = seq_num_base;
+  fec_packet->packet_mask_offset = kPacketMaskOffset;
+  fec_packet->packet_mask_size = packet_mask_size;
+  fec_packet->protection_length =
+      ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[10]);
+
+  // Store length recovery field in temporary location in header.
+  // This makes the header "compatible" with the corresponding
+  // FlexFEC location of the length recovery field, thus simplifying
+  // the XORing operations.
+  memcpy(&fec_packet->pkt->data[2], &fec_packet->pkt->data[8], 2);
+
+  return true;
+}
+
+UlpfecHeaderWriter::UlpfecHeaderWriter()
+    : FecHeaderWriter(kMaxMediaPackets,
+                      kMaxFecPackets,
+                      kFecLevel0HeaderSize + kFecLevel1HeaderSizeLBitSet) {}
+
+UlpfecHeaderWriter::~UlpfecHeaderWriter() = default;
+
+// TODO(brandtr): Consider updating this implementation (which actually
+// returns a bound on the sequence number spread), if logic is added to
+// UlpfecHeaderWriter::FinalizeFecHeader to truncate packet masks which end
+// in a string of zeroes. (Similar to how it is done in the FlexFEC case.)
+size_t UlpfecHeaderWriter::MinPacketMaskSize(const uint8_t* packet_mask,
+                                             size_t packet_mask_size) const {
+  return packet_mask_size;
+}
+
+size_t UlpfecHeaderWriter::FecHeaderSize(size_t packet_mask_size) const {
+  return UlpfecHeaderSize(packet_mask_size);
+}
+
+void UlpfecHeaderWriter::FinalizeFecHeader(
+    uint32_t /* media_ssrc */,
+    uint16_t seq_num_base,
+    const uint8_t* packet_mask,
+    size_t packet_mask_size,
+    ForwardErrorCorrection::Packet* fec_packet) const {
+  // Set E bit to zero.
+  fec_packet->data[0] &= 0x7f;
+  // Set L bit based on packet mask size. (Note that the packet mask
+  // can only take on two discrete values.)
+  bool l_bit = (packet_mask_size == kUlpfecPacketMaskSizeLBitSet);
+  if (l_bit) {
+    fec_packet->data[0] |= 0x40;  // Set the L bit.
+  } else {
+    RTC_DCHECK_EQ(packet_mask_size, kUlpfecPacketMaskSizeLBitClear);
+    fec_packet->data[0] &= 0xbf;  // Clear the L bit.
+  }
+  // Copy length recovery field from temporary location.
+  memcpy(&fec_packet->data[8], &fec_packet->data[2], 2);
+  // Write sequence number base.
+  ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2], seq_num_base);
+  // Protection length is set to entire packet. (This is not
+  // required in general.)
+  const size_t fec_header_size = FecHeaderSize(packet_mask_size);
+  ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[10],
+                                       fec_packet->length - fec_header_size);
+  // Copy the packet mask.
+  memcpy(&fec_packet->data[12], packet_mask, packet_mask_size);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h b/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h
new file mode 100644
index 0000000..fc83afd
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_ULPFEC_HEADER_READER_WRITER_H_
+#define MODULES_RTP_RTCP_SOURCE_ULPFEC_HEADER_READER_WRITER_H_
+
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+
+namespace webrtc {
+
+// FEC Level 0 Header, 10 bytes.
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |E|L|P|X|  CC   |M| PT recovery |            SN base            |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |                          TS recovery                          |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |        length recovery        |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// FEC Level 1 Header, 4 bytes (L = 0) or 8 bytes (L = 1).
+//    0                   1                   2                   3
+//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |       Protection Length       |             mask              |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//   |              mask cont. (present only when L = 1)             |
+//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+class UlpfecHeaderReader : public FecHeaderReader {
+ public:
+  UlpfecHeaderReader();
+  ~UlpfecHeaderReader() override;
+
+  bool ReadFecHeader(
+      ForwardErrorCorrection::ReceivedFecPacket* fec_packet) const override;
+};
+
+class UlpfecHeaderWriter : public FecHeaderWriter {
+ public:
+  UlpfecHeaderWriter();
+  ~UlpfecHeaderWriter() override;
+
+  size_t MinPacketMaskSize(const uint8_t* packet_mask,
+                           size_t packet_mask_size) const override;
+
+  size_t FecHeaderSize(size_t packet_mask_row_size) const override;
+
+  void FinalizeFecHeader(
+      uint32_t media_ssrc,  // Unused by ULPFEC.
+      uint16_t seq_num_base,
+      const uint8_t* packet_mask,
+      size_t packet_mask_size,
+      ForwardErrorCorrection::Packet* fec_packet) const override;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_ULPFEC_HEADER_READER_WRITER_H_
diff --git a/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc b/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc
new file mode 100644
index 0000000..a1d1bd5
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_header_reader_writer_unittest.cc
@@ -0,0 +1,243 @@
+/*
+ *  Copyright (c) 2016 The WebRTC 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.
+ */
+
+#include <string.h>
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
+#include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/random.h"
+#include "rtc_base/scoped_ref_ptr.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using Packet = ForwardErrorCorrection::Packet;
+using ReceivedFecPacket = ForwardErrorCorrection::ReceivedFecPacket;
+
+constexpr uint32_t kMediaSsrc = 1254983;
+constexpr uint16_t kMediaStartSeqNum = 825;
+constexpr size_t kMediaPacketLength = 1234;
+
+constexpr size_t kUlpfecHeaderSizeLBitClear = 14;
+constexpr size_t kUlpfecHeaderSizeLBitSet = 18;
+constexpr size_t kUlpfecPacketMaskOffset = 12;
+
+std::unique_ptr<uint8_t[]> GeneratePacketMask(size_t packet_mask_size,
+                                              uint64_t seed) {
+  Random random(seed);
+  std::unique_ptr<uint8_t[]> packet_mask(new uint8_t[packet_mask_size]);
+  for (size_t i = 0; i < packet_mask_size; ++i) {
+    packet_mask[i] = random.Rand<uint8_t>();
+  }
+  return packet_mask;
+}
+
+std::unique_ptr<Packet> WriteHeader(const uint8_t* packet_mask,
+                                    size_t packet_mask_size) {
+  UlpfecHeaderWriter writer;
+  std::unique_ptr<Packet> written_packet(new Packet());
+  written_packet->length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet->length; ++i) {
+    written_packet->data[i] = i;  // Actual content doesn't matter.
+  }
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask,
+                           packet_mask_size, written_packet.get());
+  return written_packet;
+}
+
+std::unique_ptr<ReceivedFecPacket> ReadHeader(const Packet& written_packet) {
+  UlpfecHeaderReader reader;
+  std::unique_ptr<ReceivedFecPacket> read_packet(new ReceivedFecPacket());
+  read_packet->ssrc = kMediaSsrc;
+  read_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet->pkt->data, written_packet.data, written_packet.length);
+  read_packet->pkt->length = written_packet.length;
+  EXPECT_TRUE(reader.ReadFecHeader(read_packet.get()));
+  return read_packet;
+}
+
+void VerifyHeaders(size_t expected_fec_header_size,
+                   const uint8_t* expected_packet_mask,
+                   size_t expected_packet_mask_size,
+                   const Packet& written_packet,
+                   const ReceivedFecPacket& read_packet) {
+  EXPECT_EQ(kMediaSsrc, read_packet.ssrc);
+  EXPECT_EQ(expected_fec_header_size, read_packet.fec_header_size);
+  EXPECT_EQ(kMediaSsrc, read_packet.protected_ssrc);
+  EXPECT_EQ(kMediaStartSeqNum, read_packet.seq_num_base);
+  EXPECT_EQ(kUlpfecPacketMaskOffset, read_packet.packet_mask_offset);
+  ASSERT_EQ(expected_packet_mask_size, read_packet.packet_mask_size);
+  EXPECT_EQ(written_packet.length - expected_fec_header_size,
+            read_packet.protection_length);
+  EXPECT_EQ(0, memcmp(expected_packet_mask,
+                      &read_packet.pkt->data[read_packet.packet_mask_offset],
+                      read_packet.packet_mask_size));
+  // Verify that the call to ReadFecHeader did not tamper with the payload.
+  EXPECT_EQ(0, memcmp(&written_packet.data[expected_fec_header_size],
+                      &read_packet.pkt->data[expected_fec_header_size],
+                      written_packet.length - expected_fec_header_size));
+}
+
+}  // namespace
+
+TEST(UlpfecHeaderReaderTest, ReadsSmallHeader) {
+  const uint8_t packet[] = {
+      0x00, 0x12, 0xab, 0xcd,  // L bit clear, "random" payload type and SN base
+      0x12, 0x34, 0x56, 0x78,  // "random" TS recovery
+      0xab, 0xcd, 0x11, 0x22,  // "random" length recovery and protection length
+      0x33, 0x44,              // "random" packet mask
+      0x00, 0x00, 0x00, 0x00   // payload
+  };
+  const size_t packet_length = sizeof(packet);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet.pkt->data, packet, packet_length);
+  read_packet.pkt->length = packet_length;
+
+  UlpfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  EXPECT_EQ(14U, read_packet.fec_header_size);
+  EXPECT_EQ(0xabcdU, read_packet.seq_num_base);
+  EXPECT_EQ(12U, read_packet.packet_mask_offset);
+  EXPECT_EQ(2U, read_packet.packet_mask_size);
+  EXPECT_EQ(0x1122U, read_packet.protection_length);
+}
+
+TEST(UlpfecHeaderReaderTest, ReadsLargeHeader) {
+  const uint8_t packet[] = {
+      0x40, 0x12, 0xab, 0xcd,  // L bit set, "random" payload type and SN base
+      0x12, 0x34, 0x56, 0x78,  // "random" TS recovery
+      0xab, 0xcd, 0x11, 0x22,  // "random" length recovery and protection length
+      0x33, 0x44, 0x55, 0x66,  // "random" packet mask
+      0x77, 0x88,              //
+      0x00, 0x00, 0x00, 0x00   // payload
+  };
+  const size_t packet_length = sizeof(packet);
+  ReceivedFecPacket read_packet;
+  read_packet.pkt = rtc::scoped_refptr<Packet>(new Packet());
+  memcpy(read_packet.pkt->data, packet, packet_length);
+  read_packet.pkt->length = packet_length;
+
+  UlpfecHeaderReader reader;
+  EXPECT_TRUE(reader.ReadFecHeader(&read_packet));
+
+  EXPECT_EQ(18U, read_packet.fec_header_size);
+  EXPECT_EQ(0xabcdU, read_packet.seq_num_base);
+  EXPECT_EQ(12U, read_packet.packet_mask_offset);
+  EXPECT_EQ(6U, read_packet.packet_mask_size);
+  EXPECT_EQ(0x1122U, read_packet.protection_length);
+}
+
+TEST(UlpfecHeaderWriterTest, FinalizesSmallHeader) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  Packet written_packet;
+  written_packet.length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet.length; ++i) {
+    written_packet.data[i] = i;
+  }
+
+  UlpfecHeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask.get(),
+                           packet_mask_size, &written_packet);
+
+  const uint8_t* packet = written_packet.data;
+  EXPECT_EQ(0x00, packet[0] & 0x80);  // E bit.
+  EXPECT_EQ(0x00, packet[0] & 0x40);  // L bit.
+  EXPECT_EQ(kMediaStartSeqNum, ByteReader<uint16_t>::ReadBigEndian(packet + 2));
+  EXPECT_EQ(
+      static_cast<uint16_t>(kMediaPacketLength - kUlpfecHeaderSizeLBitClear),
+      ByteReader<uint16_t>::ReadBigEndian(packet + 10));
+  EXPECT_EQ(0, memcmp(packet + kUlpfecPacketMaskOffset, packet_mask.get(),
+                      packet_mask_size));
+}
+
+TEST(UlpfecHeaderWriterTest, FinalizesLargeHeader) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+  Packet written_packet;
+  written_packet.length = kMediaPacketLength;
+  for (size_t i = 0; i < written_packet.length; ++i) {
+    written_packet.data[i] = i;
+  }
+
+  UlpfecHeaderWriter writer;
+  writer.FinalizeFecHeader(kMediaSsrc, kMediaStartSeqNum, packet_mask.get(),
+                           packet_mask_size, &written_packet);
+
+  const uint8_t* packet = written_packet.data;
+  EXPECT_EQ(0x00, packet[0] & 0x80);  // E bit.
+  EXPECT_EQ(0x40, packet[0] & 0x40);  // L bit.
+  EXPECT_EQ(kMediaStartSeqNum, ByteReader<uint16_t>::ReadBigEndian(packet + 2));
+  EXPECT_EQ(
+      static_cast<uint16_t>(kMediaPacketLength - kUlpfecHeaderSizeLBitSet),
+      ByteReader<uint16_t>::ReadBigEndian(packet + 10));
+  EXPECT_EQ(0, memcmp(packet + kUlpfecPacketMaskOffset, packet_mask.get(),
+                      packet_mask_size));
+}
+
+TEST(UlpfecHeaderWriterTest, CalculateSmallHeaderSize) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+
+  UlpfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kUlpfecPacketMaskSizeLBitClear, min_packet_mask_size);
+  EXPECT_EQ(kUlpfecHeaderSizeLBitClear,
+            writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(UlpfecHeaderWriterTest, CalculateLargeHeaderSize) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+
+  UlpfecHeaderWriter writer;
+  size_t min_packet_mask_size =
+      writer.MinPacketMaskSize(packet_mask.get(), packet_mask_size);
+
+  EXPECT_EQ(kUlpfecPacketMaskSizeLBitSet, min_packet_mask_size);
+  EXPECT_EQ(kUlpfecHeaderSizeLBitSet,
+            writer.FecHeaderSize(min_packet_mask_size));
+}
+
+TEST(UlpfecHeaderReaderWriterTest, WriteAndReadSmallHeader) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitClear;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyHeaders(kUlpfecHeaderSizeLBitClear, packet_mask.get(), packet_mask_size,
+                *written_packet, *read_packet);
+}
+
+TEST(UlpfecHeaderReaderWriterTest, WriteAndReadLargeHeader) {
+  const size_t packet_mask_size = kUlpfecPacketMaskSizeLBitSet;
+  auto packet_mask = GeneratePacketMask(packet_mask_size, 0xabcd);
+
+  auto written_packet = WriteHeader(packet_mask.get(), packet_mask_size);
+  auto read_packet = ReadHeader(*written_packet);
+
+  VerifyHeaders(kUlpfecHeaderSizeLBitSet, packet_mask.get(), packet_mask_size,
+                *written_packet, *read_packet);
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc b/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc
new file mode 100644
index 0000000..3afd612
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_receiver_impl.cc
@@ -0,0 +1,271 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include "modules/rtp_rtcp/source/ulpfec_receiver_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/rtp_receiver_video.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/clock.h"
+
+namespace webrtc {
+
+UlpfecReceiver* UlpfecReceiver::Create(uint32_t ssrc,
+                                       RecoveredPacketReceiver* callback) {
+  return new UlpfecReceiverImpl(ssrc, callback);
+}
+
+UlpfecReceiverImpl::UlpfecReceiverImpl(uint32_t ssrc,
+                                       RecoveredPacketReceiver* callback)
+    : ssrc_(ssrc),
+      recovered_packet_callback_(callback),
+      fec_(ForwardErrorCorrection::CreateUlpfec(ssrc_)) {}
+
+UlpfecReceiverImpl::~UlpfecReceiverImpl() {
+  received_packets_.clear();
+  fec_->ResetState(&recovered_packets_);
+}
+
+FecPacketCounter UlpfecReceiverImpl::GetPacketCounter() const {
+  rtc::CritScope cs(&crit_sect_);
+  return packet_counter_;
+}
+
+//     0                   1                    2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3  4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |F|   block PT  |  timestamp offset         |   block length    |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+// RFC 2198          RTP Payload for Redundant Audio Data    September 1997
+//
+//    The bits in the header are specified as follows:
+//
+//    F: 1 bit First bit in header indicates whether another header block
+//        follows.  If 1 further header blocks follow, if 0 this is the
+//        last header block.
+//        If 0 there is only 1 byte RED header
+//
+//    block PT: 7 bits RTP payload type for this block.
+//
+//    timestamp offset:  14 bits Unsigned offset of timestamp of this block
+//        relative to timestamp given in RTP header.  The use of an unsigned
+//        offset implies that redundant data must be sent after the primary
+//        data, and is hence a time to be subtracted from the current
+//        timestamp to determine the timestamp of the data for which this
+//        block is the redundancy.
+//
+//    block length:  10 bits Length in bytes of the corresponding data
+//        block excluding header.
+
+int32_t UlpfecReceiverImpl::AddReceivedRedPacket(
+    const RTPHeader& header,
+    const uint8_t* incoming_rtp_packet,
+    size_t packet_length,
+    uint8_t ulpfec_payload_type) {
+  if (header.ssrc != ssrc_) {
+    RTC_LOG(LS_WARNING)
+        << "Received RED packet with different SSRC than expected; dropping.";
+    return -1;
+  }
+  if (packet_length > IP_PACKET_SIZE) {
+    RTC_LOG(LS_WARNING) << "Received RED packet with length exceeds maximum IP "
+                           "packet size; dropping.";
+    return -1;
+  }
+  rtc::CritScope cs(&crit_sect_);
+
+  uint8_t red_header_length = 1;
+  size_t payload_data_length = packet_length - header.headerLength;
+
+  if (payload_data_length == 0) {
+    RTC_LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
+    return -1;
+  }
+
+  // Remove RED header of incoming packet and store as a virtual RTP packet.
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
+      new ForwardErrorCorrection::ReceivedPacket());
+  received_packet->pkt = new ForwardErrorCorrection::Packet();
+
+  // Get payload type from RED header and sequence number from RTP header.
+  uint8_t payload_type = incoming_rtp_packet[header.headerLength] & 0x7f;
+  received_packet->is_fec = payload_type == ulpfec_payload_type;
+  received_packet->ssrc = header.ssrc;
+  received_packet->seq_num = header.sequenceNumber;
+
+  uint16_t block_length = 0;
+  if (incoming_rtp_packet[header.headerLength] & 0x80) {
+    // f bit set in RED header, i.e. there are more than one RED header blocks.
+    red_header_length = 4;
+    if (payload_data_length < red_header_length + 1u) {
+      RTC_LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
+      return -1;
+    }
+
+    uint16_t timestamp_offset = incoming_rtp_packet[header.headerLength + 1]
+                                << 8;
+    timestamp_offset += incoming_rtp_packet[header.headerLength + 2];
+    timestamp_offset = timestamp_offset >> 2;
+    if (timestamp_offset != 0) {
+      RTC_LOG(LS_WARNING) << "Corrupt payload found.";
+      return -1;
+    }
+
+    block_length = (0x3 & incoming_rtp_packet[header.headerLength + 2]) << 8;
+    block_length += incoming_rtp_packet[header.headerLength + 3];
+
+    // Check next RED header block.
+    if (incoming_rtp_packet[header.headerLength + 4] & 0x80) {
+      RTC_LOG(LS_WARNING) << "More than 2 blocks in packet not supported.";
+      return -1;
+    }
+    // Check that the packet is long enough to contain data in the following
+    // block.
+    if (block_length > payload_data_length - (red_header_length + 1)) {
+      RTC_LOG(LS_WARNING) << "Block length longer than packet.";
+      return -1;
+    }
+  }
+  ++packet_counter_.num_packets;
+  if (packet_counter_.first_packet_time_ms == -1) {
+    packet_counter_.first_packet_time_ms =
+        Clock::GetRealTimeClock()->TimeInMilliseconds();
+  }
+
+  std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
+      second_received_packet;
+  if (block_length > 0) {
+    // Handle block length, split into two packets.
+    red_header_length = 5;
+
+    // Copy RTP header.
+    memcpy(received_packet->pkt->data, incoming_rtp_packet,
+           header.headerLength);
+
+    // Set payload type.
+    received_packet->pkt->data[1] &= 0x80;          // Reset RED payload type.
+    received_packet->pkt->data[1] += payload_type;  // Set media payload type.
+
+    // Copy payload data.
+    memcpy(received_packet->pkt->data + header.headerLength,
+           incoming_rtp_packet + header.headerLength + red_header_length,
+           block_length);
+    received_packet->pkt->length = block_length;
+
+    second_received_packet.reset(new ForwardErrorCorrection::ReceivedPacket);
+    second_received_packet->pkt = new ForwardErrorCorrection::Packet;
+
+    second_received_packet->is_fec = true;
+    second_received_packet->ssrc = header.ssrc;
+    second_received_packet->seq_num = header.sequenceNumber;
+    ++packet_counter_.num_fec_packets;
+
+    // Copy FEC payload data.
+    memcpy(second_received_packet->pkt->data,
+           incoming_rtp_packet + header.headerLength + red_header_length +
+               block_length,
+           payload_data_length - red_header_length - block_length);
+
+    second_received_packet->pkt->length =
+        payload_data_length - red_header_length - block_length;
+
+  } else if (received_packet->is_fec) {
+    ++packet_counter_.num_fec_packets;
+
+    // everything behind the RED header
+    memcpy(received_packet->pkt->data,
+           incoming_rtp_packet + header.headerLength + red_header_length,
+           payload_data_length - red_header_length);
+    received_packet->pkt->length = payload_data_length - red_header_length;
+    received_packet->ssrc =
+        ByteReader<uint32_t>::ReadBigEndian(&incoming_rtp_packet[8]);
+
+  } else {
+    // Copy RTP header.
+    memcpy(received_packet->pkt->data, incoming_rtp_packet,
+           header.headerLength);
+
+    // Set payload type.
+    received_packet->pkt->data[1] &= 0x80;          // Reset RED payload type.
+    received_packet->pkt->data[1] += payload_type;  // Set media payload type.
+
+    // Copy payload data.
+    memcpy(received_packet->pkt->data + header.headerLength,
+           incoming_rtp_packet + header.headerLength + red_header_length,
+           payload_data_length - red_header_length);
+    received_packet->pkt->length =
+        header.headerLength + payload_data_length - red_header_length;
+  }
+
+  if (received_packet->pkt->length == 0) {
+    return 0;
+  }
+
+  received_packets_.push_back(std::move(received_packet));
+  if (second_received_packet) {
+    received_packets_.push_back(std::move(second_received_packet));
+  }
+  return 0;
+}
+
+// TODO(nisse): Drop always-zero return value.
+int32_t UlpfecReceiverImpl::ProcessReceivedFec() {
+  crit_sect_.Enter();
+
+  // If we iterate over |received_packets_| and it contains a packet that cause
+  // us to recurse back to this function (for example a RED packet encapsulating
+  // a RED packet), then we will recurse forever. To avoid this we swap
+  // |received_packets_| with an empty vector so that the next recursive call
+  // wont iterate over the same packet again. This also solves the problem of
+  // not modifying the vector we are currently iterating over (packets are added
+  // in AddReceivedRedPacket).
+  std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
+      received_packets;
+  received_packets.swap(received_packets_);
+
+  for (const auto& received_packet : received_packets) {
+    // Send received media packet to VCM.
+    if (!received_packet->is_fec) {
+      ForwardErrorCorrection::Packet* packet = received_packet->pkt;
+      crit_sect_.Leave();
+      recovered_packet_callback_->OnRecoveredPacket(packet->data,
+                                                    packet->length);
+      crit_sect_.Enter();
+    }
+    fec_->DecodeFec(*received_packet, &recovered_packets_);
+  }
+
+  // Send any recovered media packets to VCM.
+  for (const auto& recovered_packet : recovered_packets_) {
+    if (recovered_packet->returned) {
+      // Already sent to the VCM and the jitter buffer.
+      continue;
+    }
+    ForwardErrorCorrection::Packet* packet = recovered_packet->pkt;
+    ++packet_counter_.num_recovered_packets;
+    // Set this flag first; in case the recovered packet carries a RED
+    // header, OnRecoveredPacket will recurse back here.
+    recovered_packet->returned = true;
+    crit_sect_.Leave();
+    recovered_packet_callback_->OnRecoveredPacket(packet->data, packet->length);
+    crit_sect_.Enter();
+  }
+
+  crit_sect_.Leave();
+  return 0;
+}
+
+}  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/ulpfec_receiver_impl.h b/modules/rtp_rtcp/source/ulpfec_receiver_impl.h
new file mode 100644
index 0000000..7dbc7dd
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_receiver_impl.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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 MODULES_RTP_RTCP_SOURCE_ULPFEC_RECEIVER_IMPL_H_
+#define MODULES_RTP_RTCP_SOURCE_ULPFEC_RECEIVER_IMPL_H_
+
+#include <memory>
+#include <vector>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/include/ulpfec_receiver.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "rtc_base/criticalsection.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class UlpfecReceiverImpl : public UlpfecReceiver {
+ public:
+  explicit UlpfecReceiverImpl(uint32_t ssrc, RecoveredPacketReceiver* callback);
+  ~UlpfecReceiverImpl() override;
+
+  int32_t AddReceivedRedPacket(const RTPHeader& rtp_header,
+                               const uint8_t* incoming_rtp_packet,
+                               size_t packet_length,
+                               uint8_t ulpfec_payload_type) override;
+
+  int32_t ProcessReceivedFec() override;
+
+  FecPacketCounter GetPacketCounter() const override;
+
+ private:
+  const uint32_t ssrc_;
+
+  rtc::CriticalSection crit_sect_;
+  RecoveredPacketReceiver* recovered_packet_callback_;
+  std::unique_ptr<ForwardErrorCorrection> fec_;
+  // TODO(nisse): The AddReceivedRedPacket method adds one or two packets to
+  // this list at a time, after which it is emptied by ProcessReceivedFec. It
+  // will make things simpler to merge AddReceivedRedPacket and
+  // ProcessReceivedFec into a single method, and we can then delete this list.
+  std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
+      received_packets_;
+  ForwardErrorCorrection::RecoveredPacketList recovered_packets_;
+  FecPacketCounter packet_counter_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_RTP_RTCP_SOURCE_ULPFEC_RECEIVER_IMPL_H_
diff --git a/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc b/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc
new file mode 100644
index 0000000..e050f80
--- /dev/null
+++ b/modules/rtp_rtcp/source/ulpfec_receiver_unittest.cc
@@ -0,0 +1,479 @@
+/*
+ *  Copyright (c) 2012 The WebRTC 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.
+ */
+
+#include <string.h>
+
+#include <list>
+#include <memory>
+
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "modules/rtp_rtcp/include/ulpfec_receiver.h"
+#include "modules/rtp_rtcp/mocks/mock_recovered_packet_receiver.h"
+#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/fec_test_helper.h"
+#include "modules/rtp_rtcp/source/forward_error_correction.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+using ::testing::_;
+using ::testing::Args;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+
+using test::fec::AugmentedPacket;
+using Packet = ForwardErrorCorrection::Packet;
+using test::fec::UlpfecPacketGenerator;
+
+constexpr int kFecPayloadType = 96;
+constexpr uint32_t kMediaSsrc = 835424;
+
+class NullRecoveredPacketReceiver : public RecoveredPacketReceiver {
+ public:
+  void OnRecoveredPacket(const uint8_t* packet, size_t length) override {}
+};
+
+}  // namespace
+
+class UlpfecReceiverTest : public ::testing::Test {
+ protected:
+  UlpfecReceiverTest()
+      : fec_(ForwardErrorCorrection::CreateUlpfec(kMediaSsrc)),
+        receiver_fec_(
+            UlpfecReceiver::Create(kMediaSsrc, &recovered_packet_receiver_)),
+        packet_generator_(kMediaSsrc) {}
+
+  // Generates |num_fec_packets| FEC packets, given |media_packets|.
+  void EncodeFec(const ForwardErrorCorrection::PacketList& media_packets,
+                 size_t num_fec_packets,
+                 std::list<ForwardErrorCorrection::Packet*>* fec_packets);
+
+  // Generates |num_media_packets| corresponding to a single frame.
+  void PacketizeFrame(size_t num_media_packets,
+                      size_t frame_offset,
+                      std::list<AugmentedPacket*>* augmented_packets,
+                      ForwardErrorCorrection::PacketList* packets);
+
+  // Build a media packet using |packet_generator_| and add it
+  // to the receiver.
+  void BuildAndAddRedMediaPacket(AugmentedPacket* packet);
+
+  // Build a FEC packet using |packet_generator_| and add it
+  // to the receiver.
+  void BuildAndAddRedFecPacket(Packet* packet);
+
+  // Ensure that |recovered_packet_receiver_| will be called correctly
+  // and that the recovered packet will be identical to the lost packet.
+  void VerifyReconstructedMediaPacket(const AugmentedPacket& packet,
+                                      size_t times);
+
+  void InjectGarbagePacketLength(size_t fec_garbage_offset);
+
+  static void SurvivesMaliciousPacket(const uint8_t* data,
+                                      size_t length,
+                                      uint8_t ulpfec_payload_type);
+
+  MockRecoveredPacketReceiver recovered_packet_receiver_;
+  std::unique_ptr<ForwardErrorCorrection> fec_;
+  std::unique_ptr<UlpfecReceiver> receiver_fec_;
+  UlpfecPacketGenerator packet_generator_;
+};
+
+void UlpfecReceiverTest::EncodeFec(
+    const ForwardErrorCorrection::PacketList& media_packets,
+    size_t num_fec_packets,
+    std::list<ForwardErrorCorrection::Packet*>* fec_packets) {
+  const uint8_t protection_factor =
+      num_fec_packets * 255 / media_packets.size();
+  // Unequal protection is turned off, and the number of important
+  // packets is thus irrelevant.
+  constexpr int kNumImportantPackets = 0;
+  constexpr bool kUseUnequalProtection = false;
+  constexpr FecMaskType kFecMaskType = kFecMaskBursty;
+  EXPECT_EQ(
+      0, fec_->EncodeFec(media_packets, protection_factor, kNumImportantPackets,
+                         kUseUnequalProtection, kFecMaskType, fec_packets));
+  ASSERT_EQ(num_fec_packets, fec_packets->size());
+}
+
+void UlpfecReceiverTest::PacketizeFrame(
+    size_t num_media_packets,
+    size_t frame_offset,
+    std::list<AugmentedPacket*>* augmented_packets,
+    ForwardErrorCorrection::PacketList* packets) {
+  packet_generator_.NewFrame(num_media_packets);
+  for (size_t i = 0; i < num_media_packets; ++i) {
+    std::unique_ptr<AugmentedPacket> next_packet(
+        packet_generator_.NextPacket(frame_offset + i, kRtpHeaderSize + 10));
+    augmented_packets->push_back(next_packet.get());
+    packets->push_back(std::move(next_packet));
+  }
+}
+
+void UlpfecReceiverTest::BuildAndAddRedMediaPacket(AugmentedPacket* packet) {
+  std::unique_ptr<AugmentedPacket> red_packet(
+      packet_generator_.BuildMediaRedPacket(*packet));
+  EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
+                   red_packet->header.header, red_packet->data,
+                   red_packet->length, kFecPayloadType));
+}
+
+void UlpfecReceiverTest::BuildAndAddRedFecPacket(Packet* packet) {
+  std::unique_ptr<AugmentedPacket> red_packet(
+      packet_generator_.BuildUlpfecRedPacket(*packet));
+  EXPECT_EQ(0, receiver_fec_->AddReceivedRedPacket(
+                   red_packet->header.header, red_packet->data,
+                   red_packet->length, kFecPayloadType));
+}
+
+void UlpfecReceiverTest::VerifyReconstructedMediaPacket(
+    const AugmentedPacket& packet,
+    size_t times) {
+  // Verify that the content of the reconstructed packet is equal to the
+  // content of |packet|, and that the same content is received |times| number
+  // of times in a row.
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, packet.length))
+      .With(Args<0, 1>(ElementsAreArray(packet.data, packet.length)))
+      .Times(times);
+}
+
+void UlpfecReceiverTest::InjectGarbagePacketLength(size_t fec_garbage_offset) {
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _));
+
+  const size_t kNumFecPackets = 1;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets, kNumFecPackets, &fec_packets);
+  ByteWriter<uint16_t>::WriteBigEndian(
+      &fec_packets.front()->data[fec_garbage_offset], 0x4711);
+
+  // Inject first media packet, then first FEC packet, skipping the second media
+  // packet to cause a recovery from the FEC packet.
+  BuildAndAddRedMediaPacket(augmented_media_packets.front());
+  BuildAndAddRedFecPacket(fec_packets.front());
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+
+  FecPacketCounter counter = receiver_fec_->GetPacketCounter();
+  EXPECT_EQ(2U, counter.num_packets);
+  EXPECT_EQ(1U, counter.num_fec_packets);
+  EXPECT_EQ(0U, counter.num_recovered_packets);
+}
+
+void UlpfecReceiverTest::SurvivesMaliciousPacket(const uint8_t* data,
+                                                 size_t length,
+                                                 uint8_t ulpfec_payload_type) {
+  RTPHeader header;
+  std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
+  ASSERT_TRUE(parser->Parse(data, length, &header));
+
+  NullRecoveredPacketReceiver null_callback;
+  std::unique_ptr<UlpfecReceiver> receiver_fec(
+      UlpfecReceiver::Create(kMediaSsrc, &null_callback));
+
+  receiver_fec->AddReceivedRedPacket(header, data, length, ulpfec_payload_type);
+}
+
+TEST_F(UlpfecReceiverTest, TwoMediaOneFec) {
+  constexpr size_t kNumFecPackets = 1u;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets, kNumFecPackets, &fec_packets);
+
+  FecPacketCounter counter = receiver_fec_->GetPacketCounter();
+  EXPECT_EQ(0u, counter.num_packets);
+  EXPECT_EQ(-1, counter.first_packet_time_ms);
+
+  // Recovery
+  auto it = augmented_media_packets.begin();
+  BuildAndAddRedMediaPacket(*it);
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  counter = receiver_fec_->GetPacketCounter();
+  EXPECT_EQ(1u, counter.num_packets);
+  EXPECT_EQ(0u, counter.num_fec_packets);
+  EXPECT_EQ(0u, counter.num_recovered_packets);
+  const int64_t first_packet_time_ms = counter.first_packet_time_ms;
+  EXPECT_NE(-1, first_packet_time_ms);
+
+  // Drop one media packet.
+  auto fec_it = fec_packets.begin();
+  BuildAndAddRedFecPacket(*fec_it);
+  ++it;
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+
+  counter = receiver_fec_->GetPacketCounter();
+  EXPECT_EQ(2u, counter.num_packets);
+  EXPECT_EQ(1u, counter.num_fec_packets);
+  EXPECT_EQ(1u, counter.num_recovered_packets);
+  EXPECT_EQ(first_packet_time_ms, counter.first_packet_time_ms);
+}
+
+TEST_F(UlpfecReceiverTest, InjectGarbageFecHeaderLengthRecovery) {
+  // Byte offset 8 is the 'length recovery' field of the FEC header.
+  InjectGarbagePacketLength(8);
+}
+
+TEST_F(UlpfecReceiverTest, InjectGarbageFecLevelHeaderProtectionLength) {
+  // Byte offset 10 is the 'protection length' field in the first FEC level
+  // header.
+  InjectGarbagePacketLength(10);
+}
+
+TEST_F(UlpfecReceiverTest, TwoMediaTwoFec) {
+  const size_t kNumFecPackets = 2;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  PacketizeFrame(2, 0, &augmented_media_packets, &media_packets);
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets, kNumFecPackets, &fec_packets);
+
+  // Recovery
+  // Drop both media packets.
+  auto it = augmented_media_packets.begin();
+  auto fec_it = fec_packets.begin();
+  BuildAndAddRedFecPacket(*fec_it);
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  ++fec_it;
+  BuildAndAddRedFecPacket(*fec_it);
+  ++it;
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, TwoFramesOneFec) {
+  const size_t kNumFecPackets = 1;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
+  PacketizeFrame(1, 1, &augmented_media_packets, &media_packets);
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets, kNumFecPackets, &fec_packets);
+
+  // Recovery
+  auto it = augmented_media_packets.begin();
+  BuildAndAddRedMediaPacket(augmented_media_packets.front());
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  // Drop one media packet.
+  BuildAndAddRedFecPacket(fec_packets.front());
+  ++it;
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, OneCompleteOneUnrecoverableFrame) {
+  const size_t kNumFecPackets = 1;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  PacketizeFrame(1, 0, &augmented_media_packets, &media_packets);
+  PacketizeFrame(2, 1, &augmented_media_packets, &media_packets);
+
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets, kNumFecPackets, &fec_packets);
+
+  // Recovery
+  auto it = augmented_media_packets.begin();
+  BuildAndAddRedMediaPacket(*it);  // First frame: one packet.
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  ++it;
+  BuildAndAddRedMediaPacket(*it);  // First packet of second frame.
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, MaxFramesOneFec) {
+  const size_t kNumFecPackets = 1;
+  const size_t kNumMediaPackets = 48;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  for (size_t i = 0; i < kNumMediaPackets; ++i) {
+    PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
+  }
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets, kNumFecPackets, &fec_packets);
+
+  // Recovery
+  auto it = augmented_media_packets.begin();
+  ++it;  // Drop first packet.
+  for (; it != augmented_media_packets.end(); ++it) {
+    BuildAndAddRedMediaPacket(*it);
+    VerifyReconstructedMediaPacket(**it, 1);
+    EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  }
+  BuildAndAddRedFecPacket(fec_packets.front());
+  it = augmented_media_packets.begin();
+  VerifyReconstructedMediaPacket(**it, 1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, TooManyFrames) {
+  const size_t kNumFecPackets = 1;
+  const size_t kNumMediaPackets = 49;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  for (size_t i = 0; i < kNumMediaPackets; ++i) {
+    PacketizeFrame(1, i, &augmented_media_packets, &media_packets);
+  }
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EXPECT_EQ(-1, fec_->EncodeFec(media_packets,
+                                kNumFecPackets * 255 / kNumMediaPackets, 0,
+                                false, kFecMaskBursty, &fec_packets));
+}
+
+TEST_F(UlpfecReceiverTest, PacketNotDroppedTooEarly) {
+  // 1 frame with 2 media packets and one FEC packet. One media packet missing.
+  // Delay the FEC packet.
+  Packet* delayed_fec = nullptr;
+  const size_t kNumFecPacketsBatch1 = 1;
+  const size_t kNumMediaPacketsBatch1 = 2;
+  std::list<AugmentedPacket*> augmented_media_packets_batch1;
+  ForwardErrorCorrection::PacketList media_packets_batch1;
+  PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
+                 &media_packets_batch1);
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
+
+  BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  delayed_fec = fec_packets.front();
+
+  // Fill the FEC decoder. No packets should be dropped.
+  const size_t kNumMediaPacketsBatch2 = 46;
+  std::list<AugmentedPacket*> augmented_media_packets_batch2;
+  ForwardErrorCorrection::PacketList media_packets_batch2;
+  for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
+    PacketizeFrame(1, i, &augmented_media_packets_batch2,
+                   &media_packets_batch2);
+  }
+  for (auto it = augmented_media_packets_batch2.begin();
+       it != augmented_media_packets_batch2.end(); ++it) {
+    BuildAndAddRedMediaPacket(*it);
+    EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
+    EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  }
+
+  // Add the delayed FEC packet. One packet should be reconstructed.
+  BuildAndAddRedFecPacket(delayed_fec);
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, PacketDroppedWhenTooOld) {
+  // 1 frame with 2 media packets and one FEC packet. One media packet missing.
+  // Delay the FEC packet.
+  Packet* delayed_fec = nullptr;
+  const size_t kNumFecPacketsBatch1 = 1;
+  const size_t kNumMediaPacketsBatch1 = 2;
+  std::list<AugmentedPacket*> augmented_media_packets_batch1;
+  ForwardErrorCorrection::PacketList media_packets_batch1;
+  PacketizeFrame(kNumMediaPacketsBatch1, 0, &augmented_media_packets_batch1,
+                 &media_packets_batch1);
+  std::list<ForwardErrorCorrection::Packet*> fec_packets;
+  EncodeFec(media_packets_batch1, kNumFecPacketsBatch1, &fec_packets);
+
+  BuildAndAddRedMediaPacket(augmented_media_packets_batch1.front());
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  delayed_fec = fec_packets.front();
+
+  // Fill the FEC decoder and force the last packet to be dropped.
+  const size_t kNumMediaPacketsBatch2 = 48;
+  std::list<AugmentedPacket*> augmented_media_packets_batch2;
+  ForwardErrorCorrection::PacketList media_packets_batch2;
+  for (size_t i = 0; i < kNumMediaPacketsBatch2; ++i) {
+    PacketizeFrame(1, i, &augmented_media_packets_batch2,
+                   &media_packets_batch2);
+  }
+  for (auto it = augmented_media_packets_batch2.begin();
+       it != augmented_media_packets_batch2.end(); ++it) {
+    BuildAndAddRedMediaPacket(*it);
+    EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
+    EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+  }
+
+  // Add the delayed FEC packet. No packet should be reconstructed since the
+  // first media packet of that frame has been dropped due to being too old.
+  BuildAndAddRedFecPacket(delayed_fec);
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, OldFecPacketDropped) {
+  // 49 frames with 2 media packets and one FEC packet. All media packets
+  // missing.
+  const size_t kNumMediaPackets = 49 * 2;
+  std::list<AugmentedPacket*> augmented_media_packets;
+  ForwardErrorCorrection::PacketList media_packets;
+  for (size_t i = 0; i < kNumMediaPackets / 2; ++i) {
+    std::list<AugmentedPacket*> frame_augmented_media_packets;
+    ForwardErrorCorrection::PacketList frame_media_packets;
+    std::list<ForwardErrorCorrection::Packet*> fec_packets;
+    PacketizeFrame(2, 0, &frame_augmented_media_packets, &frame_media_packets);
+    EncodeFec(frame_media_packets, 1, &fec_packets);
+    for (auto it = fec_packets.begin(); it != fec_packets.end(); ++it) {
+      // Only FEC packets inserted. No packets recoverable at this time.
+      BuildAndAddRedFecPacket(*it);
+      EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(0);
+      EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+    }
+    // Move unique_ptr's to media_packets for lifetime management.
+    media_packets.insert(media_packets.end(),
+                         std::make_move_iterator(frame_media_packets.begin()),
+                         std::make_move_iterator(frame_media_packets.end()));
+    augmented_media_packets.insert(augmented_media_packets.end(),
+                                   frame_augmented_media_packets.begin(),
+                                   frame_augmented_media_packets.end());
+  }
+  // Insert the oldest media packet. The corresponding FEC packet is too old
+  // and should have been dropped. Only the media packet we inserted will be
+  // returned.
+  BuildAndAddRedMediaPacket(augmented_media_packets.front());
+  EXPECT_CALL(recovered_packet_receiver_, OnRecoveredPacket(_, _)).Times(1);
+  EXPECT_EQ(0, receiver_fec_->ProcessReceivedFec());
+}
+
+TEST_F(UlpfecReceiverTest, TruncatedPacketWithFBitSet) {
+  const uint8_t kTruncatedPacket[] = {0x80, 0x2a, 0x68, 0x71, 0x29, 0xa1, 0x27,
+                                      0x3a, 0x29, 0x12, 0x2a, 0x98, 0xe0, 0x29};
+
+  SurvivesMaliciousPacket(kTruncatedPacket, sizeof(kTruncatedPacket), 100);
+}
+
+TEST_F(UlpfecReceiverTest,
+       TruncatedPacketWithFBitSetEndingAfterFirstRedHeader) {
+  const uint8_t kPacket[] = {
+      0x89, 0x27, 0x3a, 0x83, 0x27, 0x3a, 0x3a, 0xf3, 0x67, 0xbe, 0x2a,
+      0xa9, 0x27, 0x54, 0x3a, 0x3a, 0x2a, 0x67, 0x3a, 0xf3, 0x67, 0xbe,
+      0x2a, 0x27, 0xe6, 0xf6, 0x03, 0x3e, 0x29, 0x27, 0x21, 0x27, 0x2a,
+      0x29, 0x21, 0x4b, 0x29, 0x3a, 0x28, 0x29, 0xbf, 0x29, 0x2a, 0x26,
+      0x29, 0xae, 0x27, 0xa6, 0xf6, 0x00, 0x03, 0x3e};
+  SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
+}
+
+TEST_F(UlpfecReceiverTest, TruncatedPacketWithoutDataPastFirstBlock) {
+  const uint8_t kPacket[] = {
+      0x82, 0x38, 0x92, 0x38, 0x92, 0x38, 0xde, 0x2a, 0x11, 0xc8, 0xa3, 0xc4,
+      0x82, 0x38, 0x2a, 0x21, 0x2a, 0x28, 0x92, 0x38, 0x92, 0x00, 0x00, 0x0a,
+      0x3a, 0xc8, 0xa3, 0x3a, 0x27, 0xc4, 0x2a, 0x21, 0x2a, 0x28};
+  SurvivesMaliciousPacket(kPacket, sizeof(kPacket), 100);
+}
+
+}  // namespace webrtc
diff --git a/modules/video_coding/codecs/h264/include/h264_globals.h b/modules/video_coding/codecs/h264/include/h264_globals.h
index bfeba67..e321500 100644
--- a/modules/video_coding/codecs/h264/include/h264_globals.h
+++ b/modules/video_coding/codecs/h264/include/h264_globals.h
@@ -16,6 +16,8 @@
 
 #include <string>
 
+#include "rtc_base/checks.h"
+
 namespace webrtc {
 
 // The packetization types that we support: single, aggregated, and fragmented.
diff --git a/modules/video_coding/codecs/vp8/include/vp8_common_types.h b/modules/video_coding/codecs/vp8/include/vp8_common_types.h
deleted file mode 100644
index dff70ac..0000000
--- a/modules/video_coding/codecs/vp8/include/vp8_common_types.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *  Copyright (c) 2011 The WebRTC 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 MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_COMMON_TYPES_H_
-#define MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_COMMON_TYPES_H_
-
-#include "common_types.h"  // NOLINT(build/include)
-
-namespace webrtc {
-
-// Ratio allocation between temporal streams:
-// Values as required for the VP8 codec (accumulating).
-static const float
-    kVp8LayerRateAlloction[kMaxSimulcastStreams][kMaxTemporalStreams] = {
-        {1.0f, 1.0f, 1.0f, 1.0f},  // 1 layer
-        {0.6f, 1.0f, 1.0f, 1.0f},  // 2 layers {60%, 40%}
-        {0.4f, 0.6f, 1.0f, 1.0f},  // 3 layers {40%, 20%, 40%}
-        {0.25f, 0.4f, 0.6f, 1.0f}  // 4 layers {25%, 15%, 20%, 40%}
-};
-
-}  // namespace webrtc
-#endif  // MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_COMMON_TYPES_H_
diff --git a/modules/video_coding/codecs/vp9/include/vp9.h b/modules/video_coding/codecs/vp9/include/vp9.h
index 39dc138..8091cac 100644
--- a/modules/video_coding/codecs/vp9/include/vp9.h
+++ b/modules/video_coding/codecs/vp9/include/vp9.h
@@ -13,22 +13,31 @@
 #define MODULES_VIDEO_CODING_CODECS_VP9_INCLUDE_VP9_H_
 
 #include <memory>
+#include <vector>
 
+#include "api/video_codecs/sdp_video_format.h"
+#include "media/base/codec.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 
 namespace webrtc {
 
+// Returns a vector with all supported internal VP9 profiles that we can
+// negotiate in SDP, in order of preference.
+std::vector<SdpVideoFormat> SupportedVP9Codecs();
+
 class VP9Encoder : public VideoEncoder {
  public:
-  static bool IsSupported();
+  // Deprecated. Returns default implementation using VP9 Profile 0.
+  // TODO(emircan): Remove once this is no longer used.
   static std::unique_ptr<VP9Encoder> Create();
+  // Parses VP9 Profile from |codec| and returns the appropriate implementation.
+  static std::unique_ptr<VP9Encoder> Create(const cricket::VideoCodec& codec);
 
   ~VP9Encoder() override {}
 };
 
 class VP9Decoder : public VideoDecoder {
  public:
-  static bool IsSupported();
   static std::unique_ptr<VP9Decoder> Create();
 
   ~VP9Decoder() override {}
diff --git a/modules/video_coding/codecs/vp9/include/vp9_globals.h b/modules/video_coding/codecs/vp9/include/vp9_globals.h
index 918e411..aa532a6 100644
--- a/modules/video_coding/codecs/vp9/include/vp9_globals.h
+++ b/modules/video_coding/codecs/vp9/include/vp9_globals.h
@@ -79,10 +79,9 @@
         pid_diff[2][0] = 2;
 
         temporal_idx[3] = 2;
-        temporal_up_switch[3] = false;
-        num_ref_pics[3] = 2;
+        temporal_up_switch[3] = true;
+        num_ref_pics[3] = 1;
         pid_diff[3][0] = 1;
-        pid_diff[3][1] = 2;
         break;
       case kTemporalStructureMode4:
         num_frames_in_gof = 8;
@@ -182,12 +181,12 @@
   bool beginning_of_frame;   // True if this packet is the first in a VP9 layer
                              // frame.
   bool end_of_frame;  // True if this packet is the last in a VP9 layer frame.
-  bool ss_data_available;   // True if SS data is available in this payload
-                            // descriptor.
+  bool ss_data_available;  // True if SS data is available in this payload
+                           // descriptor.
   bool non_ref_for_inter_layer_pred;  // True for frame which is not used as
                                       // reference for inter-layer prediction.
-  int16_t picture_id;       // PictureID index, 15 bits;
-                            // kNoPictureId if PictureID does not exist.
+  int16_t picture_id;                 // PictureID index, 15 bits;
+                       // kNoPictureId if PictureID does not exist.
   int16_t max_picture_id;   // Maximum picture ID index; either 0x7F or 0x7FFF;
   int16_t tl0_pic_idx;      // TL0PIC_IDX, 8 bits;
                             // kNoTl0PicIdx means no value provided.
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 35c9da8..982d5c4 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -60,7 +60,7 @@
   }
 }
 
-source_set("protobuf_utils") {
+rtc_source_set("protobuf_utils") {
   visibility = [ "*" ]
   sources = [
     "protobuf_utils.h",
@@ -72,7 +72,7 @@
   }
 }
 
-source_set("compile_assert_c") {
+rtc_source_set("compile_assert_c") {
   sources = [
     "compile_assert_c.h",
   ]
@@ -104,7 +104,6 @@
 rtc_source_set("macromagic") {
   sources = [
     "arraysize.h",
-    "basictypes.h",
     "constructormagic.h",
     "format_macros.h",
     "stringize_macros.h",
@@ -124,6 +123,9 @@
     "ptr_util.h",
     "scoped_ref_ptr.h",
   ]
+  deps = [
+    "//third_party/abseil-cpp/absl/memory",
+  ]
 }
 
 rtc_source_set("refcount") {
@@ -218,6 +220,7 @@
       "logging.cc",
       "logging.h",
     ]
+    deps += [ "system:inline" ]
 
     # logging.h needs the deprecation header while downstream projects are
     # removing code that depends on logging implementation details.
@@ -254,6 +257,7 @@
   deps = [
     ":safe_compare",
     "..:typedefs",
+    "system:inline",
   ]
 }
 
@@ -367,6 +371,7 @@
   data_deps = []
   deps = [
     ":atomicops",
+    ":base64",
     ":checks",
     ":criticalsection",
     ":logging",
@@ -384,11 +389,10 @@
     ":timeutils",
     ":type_traits",
     "../:typedefs",
+    "system:arch",
   ]
 
   sources = [
-    "base64.cc",
-    "base64.h",
     "bind.h",
     "bitbuffer.cc",
     "bitbuffer.h",
@@ -416,6 +420,8 @@
     "numerics/histogram_percentile_counter.h",
     "numerics/mod_ops.h",
     "numerics/moving_max_counter.h",
+    "numerics/sample_counter.cc",
+    "numerics/sample_counter.h",
     "onetimeevent.h",
     "pathutils.cc",
     "pathutils.h",
@@ -443,7 +449,7 @@
   deps += [
     "..:webrtc_common",
     "../api:array_view",
-    "../api:optional",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 
   if (is_android) {
@@ -455,7 +461,11 @@
   }
 
   if (is_win) {
-    sources += [ "file_win.cc" ]
+    sources += [
+      "file_win.cc",
+      "win/windows_version.cc",
+      "win/windows_version.h",
+    ]
     data_deps += [ "//build/win:runtime_libs" ]
   }
 
@@ -482,6 +492,14 @@
   }
 }
 
+rtc_source_set("base64") {
+  visibility = [ "*" ]
+  sources = [
+    "base64.cc",
+    "base64.h",
+  ]
+}
+
 rtc_source_set("rtc_task_queue") {
   visibility = [ "*" ]
   deps = []
@@ -515,6 +533,7 @@
   deps = [
     ":macromagic",
     ":ptr_util",
+    "//third_party/abseil-cpp/absl/memory",
   ]
 }
 
@@ -642,22 +661,12 @@
     ":checks",
     ":rtc_base_approved",
     ":safe_compare",
-    "../api:optional",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
-config("rtc_base_warnings_config") {
-  if (is_win && is_clang) {
-    cflags = [
-      # Disable warnings failing when compiling with Clang on Windows.
-      # https://bugs.chromium.org/p/webrtc/issues/detail?id=5366
-      "-Wno-sign-compare",
-      "-Wno-missing-braces",
-    ]
-  }
-}
-
 rtc_source_set("rtc_json") {
+  testonly = true
   defines = []
   sources = [
     "json.cc",
@@ -714,11 +723,13 @@
   libs = []
   defines = []
   deps = [
+    ":base64",
     ":checks",
     ":stringutils",
     "..:webrtc_common",
     "../api:array_view",
-    "../api:optional",
+    "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
   public_deps = [
     ":rtc_base_approved",
@@ -782,8 +793,8 @@
     "openssl.h",
     "openssladapter.cc",
     "openssladapter.h",
-    "opensslcommon.cc",
-    "opensslcommon.h",
+    "opensslcertificate.cc",
+    "opensslcertificate.h",
     "openssldigest.cc",
     "openssldigest.h",
     "opensslidentity.cc",
@@ -792,6 +803,8 @@
     "opensslsessioncache.h",
     "opensslstreamadapter.cc",
     "opensslstreamadapter.h",
+    "opensslutility.cc",
+    "opensslutility.h",
     "physicalsocketserver.cc",
     "physicalsocketserver.h",
     "proxyinfo.cc",
@@ -819,6 +832,8 @@
     "socketstream.h",
     "ssladapter.cc",
     "ssladapter.h",
+    "sslcertificate.cc",
+    "sslcertificate.h",
     "sslfingerprint.cc",
     "sslfingerprint.h",
     "sslidentity.cc",
@@ -836,14 +851,6 @@
     ":rtc_base_objc",
   ]
 
-  # TODO(henrike): issue 3307, make rtc_base build with the Chromium default
-  # compiler settings.
-  suppressed_configs += [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
-  if (!is_win) {
-    cflags += [ "-Wno-uninitialized" ]
-  }
-
   if (build_with_chromium) {
     if (is_win) {
       sources += [ "../../webrtc_overrides/rtc_base/win32socketinit.cc" ]
@@ -851,7 +858,6 @@
     include_dirs = [ "../../boringssl/src/include" ]
     public_configs += [ ":rtc_base_chromium_config" ]
   } else {
-    configs += [ ":rtc_base_warnings_config" ]
     sources += [
       "callback.h",
       "logsinks.cc",
@@ -861,8 +867,6 @@
       "optionsfile.h",
       "rollingaccumulator.h",
       "sslroots.h",
-      "transformadapter.cc",
-      "transformadapter.h",
     ]
 
     if (is_win) {
@@ -881,6 +885,10 @@
     configs += [ ":external_ssl_library" ]
   }
 
+  if (rtc_builtin_ssl_root_certificates) {
+    defines += [ "WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES" ]
+  }
+
   if (is_android) {
     sources += [
       "ifaddrs-android.cc",
@@ -942,12 +950,6 @@
       "secur32.lib",
     ]
 
-    cflags += [
-      # Suppress warnings about WIN32_LEAN_AND_MEAN.
-      "/wd4005",
-      "/wd4703",
-    ]
-
     defines += [ "_CRT_NONSTDC_NO_DEPRECATE" ]
   }
 
@@ -978,16 +980,6 @@
   defines = [ "GTEST_RELATIVE_PATH" ]
 }
 
-config("rtc_base_tests_utils_warnings_config") {
-  if (is_win && is_clang) {
-    cflags = [
-      # See https://bugs.chromium.org/p/webrtc/issues/detail?id=6270
-      "-Wno-reorder",
-      "-Wno-sign-compare",
-    ]
-  }
-}
-
 rtc_source_set("rtc_base_tests_utils") {
   testonly = true
   sources = [
@@ -1021,25 +1013,26 @@
     "sigslottester.h",
     "sigslottester.h.pump",
     "testbase64.h",
+    "testcertificateverifier.h",
     "testclient.cc",
     "testclient.h",
     "testechoserver.cc",
     "testechoserver.h",
     "testutils.cc",
     "testutils.h",
-    "timedelta.h",
     "virtualsocketserver.cc",
     "virtualsocketserver.h",
   ]
-  configs += [ ":rtc_base_tests_utils_warnings_config" ]
   public_configs = [ ":rtc_base_tests_utils_exported_config" ]
   deps = [
     ":checks",
     ":rtc_base",
     ":stringutils",
+    "../api/units:time_delta",
     "../test:field_trial",
     "../test:test_support",
     "system:fallthrough",
+    "//third_party/abseil-cpp/absl/memory",
   ]
   public_deps = [
     "//testing/gtest",
@@ -1073,6 +1066,7 @@
       ":rtc_base_approved",
       ":rtc_base_tests_utils",
       "../system_wrappers:field_trial_default",
+      "../system_wrappers:metrics_default",
       "../test:field_trial",
       "../test:fileutils",
       "../test:test_support",
@@ -1104,6 +1098,7 @@
       "../test:fileutils",
       "../test:test_support",
       "//testing/gtest",
+      "//third_party/abseil-cpp/absl/memory",
     ]
     if (is_win) {
       sources += [ "win32socketserver_unittest.cc" ]
@@ -1118,7 +1113,6 @@
     sources = [
       "atomicops_unittest.cc",
       "base64_unittest.cc",
-      "basictypes_unittest.cc",
       "bind_unittest.cc",
       "bitbuffer_unittest.cc",
       "bitrateallocationstrategy_unittest.cc",
@@ -1138,6 +1132,7 @@
       "numerics/moving_max_counter_unittest.cc",
       "numerics/safe_compare_unittest.cc",
       "numerics/safe_minmax_unittest.cc",
+      "numerics/sample_counter_unittest.cc",
       "onetimeevent_unittest.cc",
       "pathutils_unittest.cc",
       "platform_file_unittest.cc",
@@ -1161,7 +1156,11 @@
       "virtualsocket_unittest.cc",
       "zero_memory_unittest.cc",
     ]
+    if (is_win) {
+      sources += [ "win/windows_version_unittest.cc" ]
+    }
     deps = [
+      ":base64",
       ":checks",
       ":rate_limiter",
       ":rtc_base",
@@ -1178,6 +1177,7 @@
       "../test:fileutils",
       "../test:test_support",
       "memory:unittests",
+      "//third_party/abseil-cpp/absl/memory",
     ]
   }
 
@@ -1248,13 +1248,9 @@
     ]
   }
 
-  config("rtc_base_unittests_config") {
-    if (is_clang) {
-      cflags = [ "-Wno-unused-const-variable" ]
-    }
-  }
   rtc_source_set("rtc_base_unittests") {
     testonly = true
+    defines = []
 
     sources = [
       "callback_unittest.cc",
@@ -1292,8 +1288,8 @@
     if (is_posix || is_fuchsia) {
       sources += [
         "openssladapter_unittest.cc",
-        "opensslcommon_unittest.cc",
         "opensslsessioncache_unittest.cc",
+        "opensslutility_unittest.cc",
         "ssladapter_unittest.cc",
         "sslidentity_unittest.cc",
         "sslstreamadapter_unittest.cc",
@@ -1305,14 +1301,14 @@
       ":rtc_base_tests_utils",
       ":stringutils",
       "../api:array_view",
-      "../api:optional",
       "../test:fileutils",
       "../test:test_support",
+      "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
     public_deps = [
       ":rtc_base",
     ]
-    configs += [ ":rtc_base_unittests_config" ]
     if (build_with_chromium) {
       include_dirs = [ "../../boringssl/src/include" ]
     }
@@ -1321,6 +1317,9 @@
     } else {
       configs += [ ":external_ssl_library" ]
     }
+    if (rtc_builtin_ssl_root_certificates) {
+      defines += [ "WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES" ]
+    }
   }
 }
 
@@ -1328,6 +1327,7 @@
   rtc_android_library("base_java") {
     java_files = [
       "java/src/org/webrtc/ContextUtils.java",
+      "java/src/org/webrtc/Loggable.java",
       "java/src/org/webrtc/Logging.java",
       "java/src/org/webrtc/Size.java",
       "java/src/org/webrtc/ThreadUtils.java",
diff --git a/rtc_base/OWNERS b/rtc_base/OWNERS
index f46838c..6355075 100644
--- a/rtc_base/OWNERS
+++ b/rtc_base/OWNERS
@@ -1,4 +1,3 @@
-deadbeef@webrtc.org
 hta@webrtc.org
 juberti@webrtc.org
 kwiberg@webrtc.org
diff --git a/rtc_base/arraysize.h b/rtc_base/arraysize.h
index f7845b5..bf8e6d8 100644
--- a/rtc_base/arraysize.h
+++ b/rtc_base/arraysize.h
@@ -24,7 +24,8 @@
 // This template function declaration is used in defining arraysize.
 // Note that the function doesn't need an implementation, as we only
 // use its type.
-template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
 
 #define arraysize(array) (sizeof(ArraySizeHelper(array)))
 
diff --git a/rtc_base/asyncinvoker-inl.h b/rtc_base/asyncinvoker-inl.h
index 0d546b1..3ae2430 100644
--- a/rtc_base/asyncinvoker-inl.h
+++ b/rtc_base/asyncinvoker-inl.h
@@ -48,12 +48,10 @@
 template <class FunctorT>
 class FireAndForgetAsyncClosure : public AsyncClosure {
  public:
-  explicit FireAndForgetAsyncClosure(AsyncInvoker* invoker,
-                                     FunctorT&& functor)
+  explicit FireAndForgetAsyncClosure(AsyncInvoker* invoker, FunctorT&& functor)
       : AsyncClosure(invoker), functor_(std::forward<FunctorT>(functor)) {}
-  virtual void Execute() {
-    functor_();
-  }
+  virtual void Execute() { functor_(); }
+
  private:
   typename std::decay<FunctorT>::type functor_;
 };
diff --git a/rtc_base/asyncinvoker.cc b/rtc_base/asyncinvoker.cc
index 7033c1a..e255fb9 100644
--- a/rtc_base/asyncinvoker.cc
+++ b/rtc_base/asyncinvoker.cc
@@ -106,8 +106,7 @@
                                         &GuardedAsyncInvoker::ThreadDestroyed);
 }
 
-GuardedAsyncInvoker::~GuardedAsyncInvoker() {
-}
+GuardedAsyncInvoker::~GuardedAsyncInvoker() {}
 
 bool GuardedAsyncInvoker::Flush(uint32_t id) {
   CritScope cs(&crit_);
diff --git a/rtc_base/asyncpacketsocket.h b/rtc_base/asyncpacketsocket.h
index ca59afb..820fe94 100644
--- a/rtc_base/asyncpacketsocket.h
+++ b/rtc_base/asyncpacketsocket.h
@@ -28,9 +28,9 @@
   ~PacketTimeUpdateParams();
 
   int rtp_sendtime_extension_id = -1;  // extension header id present in packet.
-  std::vector<char> srtp_auth_key;  // Authentication key.
-  int srtp_auth_tag_len = -1;       // Authentication tag length.
-  int64_t srtp_packet_index = -1;   // Required for Rtp Packet authentication.
+  std::vector<char> srtp_auth_key;     // Authentication key.
+  int srtp_auth_tag_len = -1;          // Authentication tag length.
+  int64_t srtp_packet_index = -1;  // Required for Rtp Packet authentication.
 };
 
 // This structure holds meta information for the packet which is about to send
@@ -57,7 +57,7 @@
   PacketTime(int64_t timestamp, int64_t not_before)
       : timestamp(timestamp), not_before(not_before) {}
 
-  int64_t timestamp;   // Receive time after socket delivers the data.
+  int64_t timestamp;  // Receive time after socket delivers the data.
 
   // Earliest possible time the data could have arrived, indicating the
   // potential error in the |timestamp| value, in case the system, is busy. For
@@ -93,8 +93,10 @@
   virtual SocketAddress GetRemoteAddress() const = 0;
 
   // Send a packet.
-  virtual int Send(const void *pv, size_t cb, const PacketOptions& options) = 0;
-  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
+  virtual int Send(const void* pv, size_t cb, const PacketOptions& options) = 0;
+  virtual int SendTo(const void* pv,
+                     size_t cb,
+                     const SocketAddress& addr,
                      const PacketOptions& options) = 0;
 
   // Close the socket.
@@ -114,9 +116,12 @@
 
   // Emitted each time a packet is read. Used only for UDP and
   // connected TCP sockets.
-  sigslot::signal5<AsyncPacketSocket*, const char*, size_t,
+  sigslot::signal5<AsyncPacketSocket*,
+                   const char*,
+                   size_t,
                    const SocketAddress&,
-                   const PacketTime&> SignalReadPacket;
+                   const PacketTime&>
+      SignalReadPacket;
 
   // Emitted each time a packet is sent.
   sigslot::signal2<AsyncPacketSocket*, const SentPacket&> SignalSentPacket;
diff --git a/rtc_base/asyncresolverinterface.cc b/rtc_base/asyncresolverinterface.cc
index 62dd36a..b2880f2 100644
--- a/rtc_base/asyncresolverinterface.cc
+++ b/rtc_base/asyncresolverinterface.cc
@@ -12,8 +12,7 @@
 
 namespace rtc {
 
-AsyncResolverInterface::AsyncResolverInterface() {
-}
+AsyncResolverInterface::AsyncResolverInterface() {}
 
 AsyncResolverInterface::~AsyncResolverInterface() = default;
 
diff --git a/rtc_base/asyncsocket.cc b/rtc_base/asyncsocket.cc
index b28b2f9..acd5415 100644
--- a/rtc_base/asyncsocket.cc
+++ b/rtc_base/asyncsocket.cc
@@ -13,11 +13,9 @@
 
 namespace rtc {
 
-AsyncSocket::AsyncSocket() {
-}
+AsyncSocket::AsyncSocket() {}
 
-AsyncSocket::~AsyncSocket() {
-}
+AsyncSocket::~AsyncSocket() {}
 
 AsyncSocketAdapter::AsyncSocketAdapter(AsyncSocket* socket) : socket_(nullptr) {
   Attach(socket);
diff --git a/rtc_base/asyncsocket.h b/rtc_base/asyncsocket.h
index c018c23..bf9c282 100644
--- a/rtc_base/asyncsocket.h
+++ b/rtc_base/asyncsocket.h
@@ -31,11 +31,10 @@
   // For example SignalReadEvent::connect will be called in AsyncUDPSocket ctor
   // but at the same time the SocketDispatcher maybe signaling the read event.
   // ready to read
-  sigslot::signal1<AsyncSocket*,
-                   sigslot::multi_threaded_local> SignalReadEvent;
+  sigslot::signal1<AsyncSocket*, sigslot::multi_threaded_local> SignalReadEvent;
   // ready to write
-  sigslot::signal1<AsyncSocket*,
-                   sigslot::multi_threaded_local> SignalWriteEvent;
+  sigslot::signal1<AsyncSocket*, sigslot::multi_threaded_local>
+      SignalWriteEvent;
   sigslot::signal1<AsyncSocket*> SignalConnectEvent;     // connected
   sigslot::signal2<AsyncSocket*, int> SignalCloseEvent;  // closed
 };
diff --git a/rtc_base/asynctcpsocket.cc b/rtc_base/asynctcpsocket.cc
index 058d945..3d68a2a 100644
--- a/rtc_base/asynctcpsocket.cc
+++ b/rtc_base/asynctcpsocket.cc
@@ -56,7 +56,8 @@
   return owned_socket.release();
 }
 
-AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket, bool listen,
+AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket,
+                                       bool listen,
                                        size_t max_packet_size)
     : socket_(socket),
       listen_(listen),
@@ -68,8 +69,8 @@
   }
 
   RTC_DCHECK(socket_.get() != nullptr);
-  socket_->SignalConnectEvent.connect(
-      this, &AsyncTCPSocketBase::OnConnectEvent);
+  socket_->SignalConnectEvent.connect(this,
+                                      &AsyncTCPSocketBase::OnConnectEvent);
   socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
   socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
   socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
@@ -129,7 +130,8 @@
   return socket_->SetError(error);
 }
 
-int AsyncTCPSocketBase::SendTo(const void *pv, size_t cb,
+int AsyncTCPSocketBase::SendTo(const void* pv,
+                               size_t cb,
                                const SocketAddress& addr,
                                const rtc::PacketOptions& options) {
   const SocketAddress& remote_address = GetRemoteAddress();
@@ -141,7 +143,7 @@
   return -1;
 }
 
-int AsyncTCPSocketBase::SendRaw(const void * pv, size_t cb) {
+int AsyncTCPSocketBase::SendRaw(const void* pv, size_t cb) {
   if (outbuf_.size() + cb > max_outsize_) {
     socket_->SetError(EMSGSIZE);
     return -1;
@@ -263,19 +265,19 @@
 // Binds and connects |socket| and creates AsyncTCPSocket for
 // it. Takes ownership of |socket|. Returns null if bind() or
 // connect() fail (|socket| is destroyed in that case).
-AsyncTCPSocket* AsyncTCPSocket::Create(
-    AsyncSocket* socket,
-    const SocketAddress& bind_address,
-    const SocketAddress& remote_address) {
-  return new AsyncTCPSocket(AsyncTCPSocketBase::ConnectSocket(
-      socket, bind_address, remote_address), false);
+AsyncTCPSocket* AsyncTCPSocket::Create(AsyncSocket* socket,
+                                       const SocketAddress& bind_address,
+                                       const SocketAddress& remote_address) {
+  return new AsyncTCPSocket(
+      AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address),
+      false);
 }
 
 AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
-    : AsyncTCPSocketBase(socket, listen, kBufSize) {
-}
+    : AsyncTCPSocketBase(socket, listen, kBufSize) {}
 
-int AsyncTCPSocket::Send(const void *pv, size_t cb,
+int AsyncTCPSocket::Send(const void* pv,
+                         size_t cb,
                          const rtc::PacketOptions& options) {
   if (cb > kBufSize) {
     SetError(EMSGSIZE);
@@ -306,7 +308,7 @@
   return static_cast<int>(cb);
 }
 
-void AsyncTCPSocket::ProcessInput(char * data, size_t* len) {
+void AsyncTCPSocket::ProcessInput(char* data, size_t* len) {
   SocketAddress remote_addr(GetRemoteAddress());
 
   while (true) {
diff --git a/rtc_base/asynctcpsocket.h b/rtc_base/asynctcpsocket.h
index 0a548d0..943e010 100644
--- a/rtc_base/asynctcpsocket.h
+++ b/rtc_base/asynctcpsocket.h
@@ -29,8 +29,9 @@
   ~AsyncTCPSocketBase() override;
 
   // Pure virtual methods to send and recv data.
-  int Send(const void *pv, size_t cb,
-                   const rtc::PacketOptions& options) override = 0;
+  int Send(const void* pv,
+           size_t cb,
+           const rtc::PacketOptions& options) override = 0;
   virtual void ProcessInput(char* data, size_t* len) = 0;
   // Signals incoming connection.
   virtual void HandleIncomingConnection(AsyncSocket* socket) = 0;
diff --git a/rtc_base/asynctcpsocket_unittest.cc b/rtc_base/asynctcpsocket_unittest.cc
index 7081411..e8fd96c 100644
--- a/rtc_base/asynctcpsocket_unittest.cc
+++ b/rtc_base/asynctcpsocket_unittest.cc
@@ -17,9 +17,7 @@
 
 namespace rtc {
 
-class AsyncTCPSocketTest
-    : public testing::Test,
-      public sigslot::has_slots<> {
+class AsyncTCPSocketTest : public testing::Test, public sigslot::has_slots<> {
  public:
   AsyncTCPSocketTest()
       : vss_(new rtc::VirtualSocketServer()),
@@ -30,9 +28,7 @@
                                            &AsyncTCPSocketTest::OnReadyToSend);
   }
 
-  void OnReadyToSend(rtc::AsyncPacketSocket* socket) {
-    ready_to_send_ = true;
-  }
+  void OnReadyToSend(rtc::AsyncPacketSocket* socket) { ready_to_send_ = true; }
 
  protected:
   std::unique_ptr<VirtualSocketServer> vss_;
diff --git a/rtc_base/asyncudpsocket.cc b/rtc_base/asyncudpsocket.cc
index d8e60b9..ba5fa88 100644
--- a/rtc_base/asyncudpsocket.cc
+++ b/rtc_base/asyncudpsocket.cc
@@ -16,9 +16,8 @@
 
 static const int BUF_SIZE = 64 * 1024;
 
-AsyncUDPSocket* AsyncUDPSocket::Create(
-    AsyncSocket* socket,
-    const SocketAddress& bind_address) {
+AsyncUDPSocket* AsyncUDPSocket::Create(AsyncSocket* socket,
+                                       const SocketAddress& bind_address) {
   std::unique_ptr<AsyncSocket> owned_socket(socket);
   if (socket->Bind(bind_address) < 0) {
     RTC_LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
@@ -36,8 +35,7 @@
   return Create(socket, bind_address);
 }
 
-AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket)
-    : socket_(socket) {
+AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket) : socket_(socket) {
   size_ = BUF_SIZE;
   buf_ = new char[size_];
 
@@ -47,7 +45,7 @@
 }
 
 AsyncUDPSocket::~AsyncUDPSocket() {
-  delete [] buf_;
+  delete[] buf_;
 }
 
 SocketAddress AsyncUDPSocket::GetLocalAddress() const {
@@ -58,7 +56,8 @@
   return socket_->GetRemoteAddress();
 }
 
-int AsyncUDPSocket::Send(const void *pv, size_t cb,
+int AsyncUDPSocket::Send(const void* pv,
+                         size_t cb,
                          const rtc::PacketOptions& options) {
   rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
                               options.info_signaled_after_sent);
@@ -68,7 +67,8 @@
   return ret;
 }
 
-int AsyncUDPSocket::SendTo(const void *pv, size_t cb,
+int AsyncUDPSocket::SendTo(const void* pv,
+                           size_t cb,
                            const SocketAddress& addr,
                            const rtc::PacketOptions& options) {
   rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
@@ -117,8 +117,7 @@
     // TODO: Do something better like forwarding the error to the user.
     SocketAddress local_addr = socket_->GetLocalAddress();
     RTC_LOG(LS_INFO) << "AsyncUDPSocket[" << local_addr.ToSensitiveString()
-                     << "] receive failed with error "
-                     << socket_->GetError();
+                     << "] receive failed with error " << socket_->GetError();
     return;
   }
 
diff --git a/rtc_base/asyncudpsocket_unittest.cc b/rtc_base/asyncudpsocket_unittest.cc
index af7cc20..33b3d13 100644
--- a/rtc_base/asyncudpsocket_unittest.cc
+++ b/rtc_base/asyncudpsocket_unittest.cc
@@ -18,9 +18,7 @@
 
 namespace rtc {
 
-class AsyncUdpSocketTest
-    : public testing::Test,
-      public sigslot::has_slots<> {
+class AsyncUdpSocketTest : public testing::Test, public sigslot::has_slots<> {
  public:
   AsyncUdpSocketTest()
       : pss_(new rtc::PhysicalSocketServer),
@@ -32,9 +30,7 @@
                                            &AsyncUdpSocketTest::OnReadyToSend);
   }
 
-  void OnReadyToSend(rtc::AsyncPacketSocket* socket) {
-    ready_to_send_ = true;
-  }
+  void OnReadyToSend(rtc::AsyncPacketSocket* socket) { ready_to_send_ = true; }
 
  protected:
   std::unique_ptr<PhysicalSocketServer> pss_;
diff --git a/rtc_base/atomicops.h b/rtc_base/atomicops.h
index c0ff1a6..16fa603 100644
--- a/rtc_base/atomicops.h
+++ b/rtc_base/atomicops.h
@@ -12,12 +12,15 @@
 #define RTC_BASE_ATOMICOPS_H_
 
 #if defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
+
 // Include winsock2.h before including <windows.h> to maintain consistency with
-// win32.h.  We can't include win32.h directly here since it pulls in
-// headers such as basictypes.h which causes problems in Chromium where webrtc
-// exists as two separate projects, webrtc and libjingle.
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
 #include <winsock2.h>
 #include <windows.h>
+// clang-format on
 #endif  // defined(WEBRTC_WIN)
 
 namespace rtc {
@@ -31,16 +34,11 @@
   static int Decrement(volatile int* i) {
     return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
   }
-  static int AcquireLoad(volatile const int* i) {
-    return *i;
-  }
-  static void ReleaseStore(volatile int* i, int value) {
-    *i = value;
-  }
+  static int AcquireLoad(volatile const int* i) { return *i; }
+  static void ReleaseStore(volatile int* i, int value) { *i = value; }
   static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
     return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i),
-                                        new_value,
-                                        old_value);
+                                        new_value, old_value);
   }
   // Pointer variants.
   template <typename T>
@@ -53,12 +51,8 @@
         reinterpret_cast<PVOID volatile*>(ptr), new_value, old_value));
   }
 #else
-  static int Increment(volatile int* i) {
-    return __sync_add_and_fetch(i, 1);
-  }
-  static int Decrement(volatile int* i) {
-    return __sync_sub_and_fetch(i, 1);
-  }
+  static int Increment(volatile int* i) { return __sync_add_and_fetch(i, 1); }
+  static int Decrement(volatile int* i) { return __sync_sub_and_fetch(i, 1); }
   static int AcquireLoad(volatile const int* i) {
     return __atomic_load_n(i, __ATOMIC_ACQUIRE);
   }
@@ -80,8 +74,6 @@
 #endif
 };
 
-
-
-}
+}  // namespace rtc
 
 #endif  // RTC_BASE_ATOMICOPS_H_
diff --git a/rtc_base/base64.cc b/rtc_base/base64.cc
index 0ccec0e..6add993 100644
--- a/rtc_base/base64.cc
+++ b/rtc_base/base64.cc
@@ -17,8 +17,7 @@
 #include "rtc_base/base64.h"
 
 #include <string.h>
-
-#include "rtc_base/checks.h"
+#include <assert.h>
 
 using std::vector;
 
@@ -96,7 +95,7 @@
 void Base64::EncodeFromArray(const void* data,
                              size_t len,
                              std::string* result) {
-  RTC_DCHECK(nullptr != result);
+  assert(nullptr != result);
   result->clear();
   result->resize(((len + 2) / 3) * 4);
   const unsigned char* byte_data = static_cast<const unsigned char*>(data);
@@ -224,15 +223,15 @@
                                      DecodeFlags flags,
                                      T* result,
                                      size_t* data_used) {
-  RTC_DCHECK(nullptr != result);
-  RTC_DCHECK(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
+  assert(nullptr != result);
+  assert(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
 
   const DecodeFlags parse_flags = flags & DO_PARSE_MASK;
   const DecodeFlags pad_flags = flags & DO_PAD_MASK;
   const DecodeFlags term_flags = flags & DO_TERM_MASK;
-  RTC_DCHECK(0 != parse_flags);
-  RTC_DCHECK(0 != pad_flags);
-  RTC_DCHECK(0 != term_flags);
+  assert(0 != parse_flags);
+  assert(0 != pad_flags);
+  assert(0 != term_flags);
 
   result->clear();
   result->reserve(len);
diff --git a/rtc_base/base64_unittest.cc b/rtc_base/base64_unittest.cc
index 0f7c80d..f73b396 100644
--- a/rtc_base/base64_unittest.cc
+++ b/rtc_base/base64_unittest.cc
@@ -24,257 +24,257 @@
   const char* cyphertext;
 } base64_tests[] = {
 
-  // Basic bit patterns;
-  // values obtained with "echo -n '...' | uuencode -m test"
+    // Basic bit patterns;
+    // values obtained with "echo -n '...' | uuencode -m test"
 
-  { 1, "\000", "AA==" },
-  { 1, "\001", "AQ==" },
-  { 1, "\002", "Ag==" },
-  { 1, "\004", "BA==" },
-  { 1, "\010", "CA==" },
-  { 1, "\020", "EA==" },
-  { 1, "\040", "IA==" },
-  { 1, "\100", "QA==" },
-  { 1, "\200", "gA==" },
+    {1, "\000", "AA=="},
+    {1, "\001", "AQ=="},
+    {1, "\002", "Ag=="},
+    {1, "\004", "BA=="},
+    {1, "\010", "CA=="},
+    {1, "\020", "EA=="},
+    {1, "\040", "IA=="},
+    {1, "\100", "QA=="},
+    {1, "\200", "gA=="},
 
-  { 1, "\377", "/w==" },
-  { 1, "\376", "/g==" },
-  { 1, "\375", "/Q==" },
-  { 1, "\373", "+w==" },
-  { 1, "\367", "9w==" },
-  { 1, "\357", "7w==" },
-  { 1, "\337", "3w==" },
-  { 1, "\277", "vw==" },
-  { 1, "\177", "fw==" },
-  { 2, "\000\000", "AAA=" },
-  { 2, "\000\001", "AAE=" },
-  { 2, "\000\002", "AAI=" },
-  { 2, "\000\004", "AAQ=" },
-  { 2, "\000\010", "AAg=" },
-  { 2, "\000\020", "ABA=" },
-  { 2, "\000\040", "ACA=" },
-  { 2, "\000\100", "AEA=" },
-  { 2, "\000\200", "AIA=" },
-  { 2, "\001\000", "AQA=" },
-  { 2, "\002\000", "AgA=" },
-  { 2, "\004\000", "BAA=" },
-  { 2, "\010\000", "CAA=" },
-  { 2, "\020\000", "EAA=" },
-  { 2, "\040\000", "IAA=" },
-  { 2, "\100\000", "QAA=" },
-  { 2, "\200\000", "gAA=" },
+    {1, "\377", "/w=="},
+    {1, "\376", "/g=="},
+    {1, "\375", "/Q=="},
+    {1, "\373", "+w=="},
+    {1, "\367", "9w=="},
+    {1, "\357", "7w=="},
+    {1, "\337", "3w=="},
+    {1, "\277", "vw=="},
+    {1, "\177", "fw=="},
+    {2, "\000\000", "AAA="},
+    {2, "\000\001", "AAE="},
+    {2, "\000\002", "AAI="},
+    {2, "\000\004", "AAQ="},
+    {2, "\000\010", "AAg="},
+    {2, "\000\020", "ABA="},
+    {2, "\000\040", "ACA="},
+    {2, "\000\100", "AEA="},
+    {2, "\000\200", "AIA="},
+    {2, "\001\000", "AQA="},
+    {2, "\002\000", "AgA="},
+    {2, "\004\000", "BAA="},
+    {2, "\010\000", "CAA="},
+    {2, "\020\000", "EAA="},
+    {2, "\040\000", "IAA="},
+    {2, "\100\000", "QAA="},
+    {2, "\200\000", "gAA="},
 
-  { 2, "\377\377", "//8=" },
-  { 2, "\377\376", "//4=" },
-  { 2, "\377\375", "//0=" },
-  { 2, "\377\373", "//s=" },
-  { 2, "\377\367", "//c=" },
-  { 2, "\377\357", "/+8=" },
-  { 2, "\377\337", "/98=" },
-  { 2, "\377\277", "/78=" },
-  { 2, "\377\177", "/38=" },
-  { 2, "\376\377", "/v8=" },
-  { 2, "\375\377", "/f8=" },
-  { 2, "\373\377", "+/8=" },
-  { 2, "\367\377", "9/8=" },
-  { 2, "\357\377", "7/8=" },
-  { 2, "\337\377", "3/8=" },
-  { 2, "\277\377", "v/8=" },
-  { 2, "\177\377", "f/8=" },
+    {2, "\377\377", "//8="},
+    {2, "\377\376", "//4="},
+    {2, "\377\375", "//0="},
+    {2, "\377\373", "//s="},
+    {2, "\377\367", "//c="},
+    {2, "\377\357", "/+8="},
+    {2, "\377\337", "/98="},
+    {2, "\377\277", "/78="},
+    {2, "\377\177", "/38="},
+    {2, "\376\377", "/v8="},
+    {2, "\375\377", "/f8="},
+    {2, "\373\377", "+/8="},
+    {2, "\367\377", "9/8="},
+    {2, "\357\377", "7/8="},
+    {2, "\337\377", "3/8="},
+    {2, "\277\377", "v/8="},
+    {2, "\177\377", "f/8="},
 
-  { 3, "\000\000\000", "AAAA" },
-  { 3, "\000\000\001", "AAAB" },
-  { 3, "\000\000\002", "AAAC" },
-  { 3, "\000\000\004", "AAAE" },
-  { 3, "\000\000\010", "AAAI" },
-  { 3, "\000\000\020", "AAAQ" },
-  { 3, "\000\000\040", "AAAg" },
-  { 3, "\000\000\100", "AABA" },
-  { 3, "\000\000\200", "AACA" },
-  { 3, "\000\001\000", "AAEA" },
-  { 3, "\000\002\000", "AAIA" },
-  { 3, "\000\004\000", "AAQA" },
-  { 3, "\000\010\000", "AAgA" },
-  { 3, "\000\020\000", "ABAA" },
-  { 3, "\000\040\000", "ACAA" },
-  { 3, "\000\100\000", "AEAA" },
-  { 3, "\000\200\000", "AIAA" },
-  { 3, "\001\000\000", "AQAA" },
-  { 3, "\002\000\000", "AgAA" },
-  { 3, "\004\000\000", "BAAA" },
-  { 3, "\010\000\000", "CAAA" },
-  { 3, "\020\000\000", "EAAA" },
-  { 3, "\040\000\000", "IAAA" },
-  { 3, "\100\000\000", "QAAA" },
-  { 3, "\200\000\000", "gAAA" },
+    {3, "\000\000\000", "AAAA"},
+    {3, "\000\000\001", "AAAB"},
+    {3, "\000\000\002", "AAAC"},
+    {3, "\000\000\004", "AAAE"},
+    {3, "\000\000\010", "AAAI"},
+    {3, "\000\000\020", "AAAQ"},
+    {3, "\000\000\040", "AAAg"},
+    {3, "\000\000\100", "AABA"},
+    {3, "\000\000\200", "AACA"},
+    {3, "\000\001\000", "AAEA"},
+    {3, "\000\002\000", "AAIA"},
+    {3, "\000\004\000", "AAQA"},
+    {3, "\000\010\000", "AAgA"},
+    {3, "\000\020\000", "ABAA"},
+    {3, "\000\040\000", "ACAA"},
+    {3, "\000\100\000", "AEAA"},
+    {3, "\000\200\000", "AIAA"},
+    {3, "\001\000\000", "AQAA"},
+    {3, "\002\000\000", "AgAA"},
+    {3, "\004\000\000", "BAAA"},
+    {3, "\010\000\000", "CAAA"},
+    {3, "\020\000\000", "EAAA"},
+    {3, "\040\000\000", "IAAA"},
+    {3, "\100\000\000", "QAAA"},
+    {3, "\200\000\000", "gAAA"},
 
-  { 3, "\377\377\377", "////" },
-  { 3, "\377\377\376", "///+" },
-  { 3, "\377\377\375", "///9" },
-  { 3, "\377\377\373", "///7" },
-  { 3, "\377\377\367", "///3" },
-  { 3, "\377\377\357", "///v" },
-  { 3, "\377\377\337", "///f" },
-  { 3, "\377\377\277", "//+/" },
-  { 3, "\377\377\177", "//9/" },
-  { 3, "\377\376\377", "//7/" },
-  { 3, "\377\375\377", "//3/" },
-  { 3, "\377\373\377", "//v/" },
-  { 3, "\377\367\377", "//f/" },
-  { 3, "\377\357\377", "/+//" },
-  { 3, "\377\337\377", "/9//" },
-  { 3, "\377\277\377", "/7//" },
-  { 3, "\377\177\377", "/3//" },
-  { 3, "\376\377\377", "/v//" },
-  { 3, "\375\377\377", "/f//" },
-  { 3, "\373\377\377", "+///" },
-  { 3, "\367\377\377", "9///" },
-  { 3, "\357\377\377", "7///" },
-  { 3, "\337\377\377", "3///" },
-  { 3, "\277\377\377", "v///" },
-  { 3, "\177\377\377", "f///" },
+    {3, "\377\377\377", "////"},
+    {3, "\377\377\376", "///+"},
+    {3, "\377\377\375", "///9"},
+    {3, "\377\377\373", "///7"},
+    {3, "\377\377\367", "///3"},
+    {3, "\377\377\357", "///v"},
+    {3, "\377\377\337", "///f"},
+    {3, "\377\377\277", "//+/"},
+    {3, "\377\377\177", "//9/"},
+    {3, "\377\376\377", "//7/"},
+    {3, "\377\375\377", "//3/"},
+    {3, "\377\373\377", "//v/"},
+    {3, "\377\367\377", "//f/"},
+    {3, "\377\357\377", "/+//"},
+    {3, "\377\337\377", "/9//"},
+    {3, "\377\277\377", "/7//"},
+    {3, "\377\177\377", "/3//"},
+    {3, "\376\377\377", "/v//"},
+    {3, "\375\377\377", "/f//"},
+    {3, "\373\377\377", "+///"},
+    {3, "\367\377\377", "9///"},
+    {3, "\357\377\377", "7///"},
+    {3, "\337\377\377", "3///"},
+    {3, "\277\377\377", "v///"},
+    {3, "\177\377\377", "f///"},
 
-  // Random numbers: values obtained with
-  //
-  //  #! /bin/bash
-  //  dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
-  //  od -N $1 -t o1 /tmp/bar.random
-  //  uuencode -m test < /tmp/bar.random
-  //
-  // where $1 is the number of bytes (2, 3)
+    // Random numbers: values obtained with
+    //
+    //  #! /bin/bash
+    //  dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
+    //  od -N $1 -t o1 /tmp/bar.random
+    //  uuencode -m test < /tmp/bar.random
+    //
+    // where $1 is the number of bytes (2, 3)
 
-  { 2, "\243\361", "o/E=" },
-  { 2, "\024\167", "FHc=" },
-  { 2, "\313\252", "y6o=" },
-  { 2, "\046\041", "JiE=" },
-  { 2, "\145\236", "ZZ4=" },
-  { 2, "\254\325", "rNU=" },
-  { 2, "\061\330", "Mdg=" },
-  { 2, "\245\032", "pRo=" },
-  { 2, "\006\000", "BgA=" },
-  { 2, "\375\131", "/Vk=" },
-  { 2, "\303\210", "w4g=" },
-  { 2, "\040\037", "IB8=" },
-  { 2, "\261\372", "sfo=" },
-  { 2, "\335\014", "3Qw=" },
-  { 2, "\233\217", "m48=" },
-  { 2, "\373\056", "+y4=" },
-  { 2, "\247\232", "p5o=" },
-  { 2, "\107\053", "Rys=" },
-  { 2, "\204\077", "hD8=" },
-  { 2, "\276\211", "vok=" },
-  { 2, "\313\110", "y0g=" },
-  { 2, "\363\376", "8/4=" },
-  { 2, "\251\234", "qZw=" },
-  { 2, "\103\262", "Q7I=" },
-  { 2, "\142\312", "Yso=" },
-  { 2, "\067\211", "N4k=" },
-  { 2, "\220\001", "kAE=" },
-  { 2, "\152\240", "aqA=" },
-  { 2, "\367\061", "9zE=" },
-  { 2, "\133\255", "W60=" },
-  { 2, "\176\035", "fh0=" },
-  { 2, "\032\231", "Gpk=" },
+    {2, "\243\361", "o/E="},
+    {2, "\024\167", "FHc="},
+    {2, "\313\252", "y6o="},
+    {2, "\046\041", "JiE="},
+    {2, "\145\236", "ZZ4="},
+    {2, "\254\325", "rNU="},
+    {2, "\061\330", "Mdg="},
+    {2, "\245\032", "pRo="},
+    {2, "\006\000", "BgA="},
+    {2, "\375\131", "/Vk="},
+    {2, "\303\210", "w4g="},
+    {2, "\040\037", "IB8="},
+    {2, "\261\372", "sfo="},
+    {2, "\335\014", "3Qw="},
+    {2, "\233\217", "m48="},
+    {2, "\373\056", "+y4="},
+    {2, "\247\232", "p5o="},
+    {2, "\107\053", "Rys="},
+    {2, "\204\077", "hD8="},
+    {2, "\276\211", "vok="},
+    {2, "\313\110", "y0g="},
+    {2, "\363\376", "8/4="},
+    {2, "\251\234", "qZw="},
+    {2, "\103\262", "Q7I="},
+    {2, "\142\312", "Yso="},
+    {2, "\067\211", "N4k="},
+    {2, "\220\001", "kAE="},
+    {2, "\152\240", "aqA="},
+    {2, "\367\061", "9zE="},
+    {2, "\133\255", "W60="},
+    {2, "\176\035", "fh0="},
+    {2, "\032\231", "Gpk="},
 
-  { 3, "\013\007\144", "Cwdk" },
-  { 3, "\030\112\106", "GEpG" },
-  { 3, "\047\325\046", "J9Um" },
-  { 3, "\310\160\022", "yHAS" },
-  { 3, "\131\100\237", "WUCf" },
-  { 3, "\064\342\134", "NOJc" },
-  { 3, "\010\177\004", "CH8E" },
-  { 3, "\345\147\205", "5WeF" },
-  { 3, "\300\343\360", "wOPw" },
-  { 3, "\061\240\201", "MaCB" },
-  { 3, "\225\333\044", "ldsk" },
-  { 3, "\215\137\352", "jV/q" },
-  { 3, "\371\147\160", "+Wdw" },
-  { 3, "\030\320\051", "GNAp" },
-  { 3, "\044\174\241", "JHyh" },
-  { 3, "\260\127\037", "sFcf" },
-  { 3, "\111\045\033", "SSUb" },
-  { 3, "\202\114\107", "gkxH" },
-  { 3, "\057\371\042", "L/ki" },
-  { 3, "\223\247\244", "k6ek" },
-  { 3, "\047\216\144", "J45k" },
-  { 3, "\203\070\327", "gzjX" },
-  { 3, "\247\140\072", "p2A6" },
-  { 3, "\124\115\116", "VE1O" },
-  { 3, "\157\162\050", "b3Io" },
-  { 3, "\357\223\004", "75ME" },
-  { 3, "\052\117\156", "Kk9u" },
-  { 3, "\347\154\000", "52wA" },
-  { 3, "\303\012\142", "wwpi" },
-  { 3, "\060\035\362", "MB3y" },
-  { 3, "\130\226\361", "WJbx" },
-  { 3, "\173\013\071", "ews5" },
-  { 3, "\336\004\027", "3gQX" },
-  { 3, "\357\366\234", "7/ac" },
-  { 3, "\353\304\111", "68RJ" },
-  { 3, "\024\264\131", "FLRZ" },
-  { 3, "\075\114\251", "PUyp" },
-  { 3, "\315\031\225", "zRmV" },
-  { 3, "\154\201\276", "bIG+" },
-  { 3, "\200\066\072", "gDY6" },
-  { 3, "\142\350\267", "Yui3" },
-  { 3, "\033\000\166", "GwB2" },
-  { 3, "\210\055\077", "iC0/" },
-  { 3, "\341\037\124", "4R9U" },
-  { 3, "\161\103\152", "cUNq" },
-  { 3, "\270\142\131", "uGJZ" },
-  { 3, "\337\076\074", "3z48" },
-  { 3, "\375\106\362", "/Uby" },
-  { 3, "\227\301\127", "l8FX" },
-  { 3, "\340\002\234", "4AKc" },
-  { 3, "\121\064\033", "UTQb" },
-  { 3, "\157\134\143", "b1xj" },
-  { 3, "\247\055\327", "py3X" },
-  { 3, "\340\142\005", "4GIF" },
-  { 3, "\060\260\143", "MLBj" },
-  { 3, "\075\203\170", "PYN4" },
-  { 3, "\143\160\016", "Y3AO" },
-  { 3, "\313\013\063", "ywsz" },
-  { 3, "\174\236\135", "fJ5d" },
-  { 3, "\103\047\026", "QycW" },
-  { 3, "\365\005\343", "9QXj" },
-  { 3, "\271\160\223", "uXCT" },
-  { 3, "\362\255\172", "8q16" },
-  { 3, "\113\012\015", "SwoN" },
+    {3, "\013\007\144", "Cwdk"},
+    {3, "\030\112\106", "GEpG"},
+    {3, "\047\325\046", "J9Um"},
+    {3, "\310\160\022", "yHAS"},
+    {3, "\131\100\237", "WUCf"},
+    {3, "\064\342\134", "NOJc"},
+    {3, "\010\177\004", "CH8E"},
+    {3, "\345\147\205", "5WeF"},
+    {3, "\300\343\360", "wOPw"},
+    {3, "\061\240\201", "MaCB"},
+    {3, "\225\333\044", "ldsk"},
+    {3, "\215\137\352", "jV/q"},
+    {3, "\371\147\160", "+Wdw"},
+    {3, "\030\320\051", "GNAp"},
+    {3, "\044\174\241", "JHyh"},
+    {3, "\260\127\037", "sFcf"},
+    {3, "\111\045\033", "SSUb"},
+    {3, "\202\114\107", "gkxH"},
+    {3, "\057\371\042", "L/ki"},
+    {3, "\223\247\244", "k6ek"},
+    {3, "\047\216\144", "J45k"},
+    {3, "\203\070\327", "gzjX"},
+    {3, "\247\140\072", "p2A6"},
+    {3, "\124\115\116", "VE1O"},
+    {3, "\157\162\050", "b3Io"},
+    {3, "\357\223\004", "75ME"},
+    {3, "\052\117\156", "Kk9u"},
+    {3, "\347\154\000", "52wA"},
+    {3, "\303\012\142", "wwpi"},
+    {3, "\060\035\362", "MB3y"},
+    {3, "\130\226\361", "WJbx"},
+    {3, "\173\013\071", "ews5"},
+    {3, "\336\004\027", "3gQX"},
+    {3, "\357\366\234", "7/ac"},
+    {3, "\353\304\111", "68RJ"},
+    {3, "\024\264\131", "FLRZ"},
+    {3, "\075\114\251", "PUyp"},
+    {3, "\315\031\225", "zRmV"},
+    {3, "\154\201\276", "bIG+"},
+    {3, "\200\066\072", "gDY6"},
+    {3, "\142\350\267", "Yui3"},
+    {3, "\033\000\166", "GwB2"},
+    {3, "\210\055\077", "iC0/"},
+    {3, "\341\037\124", "4R9U"},
+    {3, "\161\103\152", "cUNq"},
+    {3, "\270\142\131", "uGJZ"},
+    {3, "\337\076\074", "3z48"},
+    {3, "\375\106\362", "/Uby"},
+    {3, "\227\301\127", "l8FX"},
+    {3, "\340\002\234", "4AKc"},
+    {3, "\121\064\033", "UTQb"},
+    {3, "\157\134\143", "b1xj"},
+    {3, "\247\055\327", "py3X"},
+    {3, "\340\142\005", "4GIF"},
+    {3, "\060\260\143", "MLBj"},
+    {3, "\075\203\170", "PYN4"},
+    {3, "\143\160\016", "Y3AO"},
+    {3, "\313\013\063", "ywsz"},
+    {3, "\174\236\135", "fJ5d"},
+    {3, "\103\047\026", "QycW"},
+    {3, "\365\005\343", "9QXj"},
+    {3, "\271\160\223", "uXCT"},
+    {3, "\362\255\172", "8q16"},
+    {3, "\113\012\015", "SwoN"},
 
-  // various lengths, generated by this python script:
-  //
-  // from string import lowercase as lc
-  // for i in range(27):
-  //   print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
-  //                                     lc[:i].encode('base64').strip())
+    // various lengths, generated by this python script:
+    //
+    // from string import lowercase as lc
+    // for i in range(27):
+    //   print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
+    //                                     lc[:i].encode('base64').strip())
 
-  {  0, "abcdefghijklmnopqrstuvwxyz", "" },
-  {  1, "abcdefghijklmnopqrstuvwxyz", "YQ==" },
-  {  2, "abcdefghijklmnopqrstuvwxyz", "YWI=" },
-  {  3, "abcdefghijklmnopqrstuvwxyz", "YWJj" },
-  {  4, "abcdefghijklmnopqrstuvwxyz", "YWJjZA==" },
-  {  5, "abcdefghijklmnopqrstuvwxyz", "YWJjZGU=" },
-  {  6, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVm" },
-  {  7, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZw==" },
-  {  8, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2g=" },
-  {  9, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hp" },
-  { 10, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpag==" },
-  { 11, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpams=" },
-  { 12, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamts" },
-  { 13, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbQ==" },
-  { 14, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW4=" },
-  { 15, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5v" },
-  { 16, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcA==" },
-  { 17, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHE=" },
-  { 18, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFy" },
-  { 19, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFycw==" },
-  { 20, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q=" },
-  { 21, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1" },
-  { 22, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg==" },
-  { 23, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc=" },
-  { 24, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4" },
-  { 25, "abcdefghijklmnopqrstuvwxy",  "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ==" },
-  { 26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" },
+    {0, "abcdefghijklmnopqrstuvwxyz", ""},
+    {1, "abcdefghijklmnopqrstuvwxyz", "YQ=="},
+    {2, "abcdefghijklmnopqrstuvwxyz", "YWI="},
+    {3, "abcdefghijklmnopqrstuvwxyz", "YWJj"},
+    {4, "abcdefghijklmnopqrstuvwxyz", "YWJjZA=="},
+    {5, "abcdefghijklmnopqrstuvwxyz", "YWJjZGU="},
+    {6, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVm"},
+    {7, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZw=="},
+    {8, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2g="},
+    {9, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hp"},
+    {10, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpag=="},
+    {11, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpams="},
+    {12, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamts"},
+    {13, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbQ=="},
+    {14, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW4="},
+    {15, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5v"},
+    {16, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcA=="},
+    {17, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHE="},
+    {18, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFy"},
+    {19, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFycw=="},
+    {20, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q="},
+    {21, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1"},
+    {22, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg=="},
+    {23, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc="},
+    {24, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"},
+    {25, "abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="},
+    {26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="},
 };
 #if 0
 static struct {
@@ -328,15 +328,19 @@
     }                                                          \
   }
 
-size_t Base64Escape(const unsigned char *src, size_t szsrc, char *dest,
+size_t Base64Escape(const unsigned char* src,
+                    size_t szsrc,
+                    char* dest,
                     size_t szdest) {
   std::string escaped;
-  Base64::EncodeFromArray((const char *)src, szsrc, &escaped);
+  Base64::EncodeFromArray((const char*)src, szsrc, &escaped);
   memcpy(dest, escaped.data(), min(escaped.size(), szdest));
   return escaped.size();
 }
 
-size_t Base64Unescape(const char *src, size_t szsrc, char *dest,
+size_t Base64Unescape(const char* src,
+                      size_t szsrc,
+                      char* dest,
                       size_t szdest) {
   std::string unescaped;
   EXPECT_TRUE(
@@ -345,7 +349,7 @@
   return unescaped.size();
 }
 
-size_t Base64Unescape(const char *src, size_t szsrc, std::string *s) {
+size_t Base64Unescape(const char* src, size_t szsrc, std::string* s) {
   EXPECT_TRUE(Base64::DecodeFromArray(src, szsrc, Base64::DO_LAX, s, nullptr));
   return s->size();
 }
@@ -356,7 +360,7 @@
   size_t i;
 
   // Check the short strings; this tests the math (and boundaries)
-  for( i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i ) {
+  for (i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i) {
     char encode_buffer[100];
     size_t encode_length;
     char decode_buffer[100];
@@ -366,16 +370,15 @@
     RTC_LOG(LS_VERBOSE) << "B64: " << base64_tests[i].cyphertext;
 
     const unsigned char* unsigned_plaintext =
-      reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext);
+        reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext);
 
     cypher_length = strlen(base64_tests[i].cyphertext);
 
     // The basic escape function:
     memset(encode_buffer, 0, sizeof(encode_buffer));
-    encode_length = Base64Escape(unsigned_plaintext,
-                                 base64_tests[i].plain_length,
-                                 encode_buffer,
-                                 sizeof(encode_buffer));
+    encode_length =
+        Base64Escape(unsigned_plaintext, base64_tests[i].plain_length,
+                     encode_buffer, sizeof(encode_buffer));
     //    Is it of the expected length?
     EXPECT_EQ(encode_length, cypher_length);
 
@@ -384,10 +387,9 @@
 
     // If we encode it into a buffer of exactly the right length...
     memset(encode_buffer, 0, sizeof(encode_buffer));
-    encode_length = Base64Escape(unsigned_plaintext,
-                                 base64_tests[i].plain_length,
-                                 encode_buffer,
-                                 cypher_length);
+    encode_length =
+        Base64Escape(unsigned_plaintext, base64_tests[i].plain_length,
+                     encode_buffer, cypher_length);
     //    Is it still of the expected length?
     EXPECT_EQ(encode_length, cypher_length);
 
@@ -396,16 +398,15 @@
 
     // If we decode it back:
     memset(decode_buffer, 0, sizeof(decode_buffer));
-    decode_length = Base64Unescape(encode_buffer,
-                                   cypher_length,
-                                   decode_buffer,
+    decode_length = Base64Unescape(encode_buffer, cypher_length, decode_buffer,
                                    sizeof(decode_buffer));
 
     //    Is it of the expected length?
     EXPECT_EQ(decode_length, base64_tests[i].plain_length);
 
     //    Is it the expected decoded value?
-    EXPECT_EQ(0,  memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
+    EXPECT_EQ(0,
+              memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
 
     // Our decoder treats the padding '=' characters at the end as
     // optional.  If encode_buffer has any, run some additional
@@ -413,16 +414,17 @@
     char* first_equals = strchr(encode_buffer, '=');
     if (first_equals) {
       // How many equals signs does the string start with?
-      int equals = (*(first_equals+1) == '=') ? 2 : 1;
+      int equals = (*(first_equals + 1) == '=') ? 2 : 1;
 
       // Try chopping off the equals sign(s) entirely.  The decoder
       // should still be okay with this.
       std::string decoded2("this junk should also be ignored");
       *first_equals = '\0';
-      EXPECT_NE(0U, Base64Unescape(encode_buffer, first_equals-encode_buffer,
-                           &decoded2));
+      EXPECT_NE(0U, Base64Unescape(encode_buffer, first_equals - encode_buffer,
+                                   &decoded2));
       EXPECT_EQ(decoded2.size(), base64_tests[i].plain_length);
-      EXPECT_EQ_ARRAY(decoded2.size(), decoded2.data(), base64_tests[i].plaintext, i);
+      EXPECT_EQ_ARRAY(decoded2.size(), decoded2.data(),
+                      base64_tests[i].plaintext, i);
 
       size_t len;
 
@@ -445,453 +447,901 @@
 // here's a weird case: a giant base64 encoded stream which broke our base64
 // decoding.  Let's test it explicitly.
 const char SpecificTest[] =
-  "/9j/4AAQSkZJRgABAgEASABIAAD/4Q0HRXhpZgAATU0AKgAAAAgADAEOAAIAAAAgAAAAngEPAAI\n"
-  "AAAAFAAAAvgEQAAIAAAAJAAAAwwESAAMAAAABAAEAAAEaAAUAAAABAAAAzAEbAAUAAAABAAAA1A\n"
-  "EoAAMAAAABAAIAAAExAAIAAAAUAAAA3AEyAAIAAAAUAAAA8AE8AAIAAAAQAAABBAITAAMAAAABA\n"
-  "AIAAIdpAAQAAAABAAABFAAAAsQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAFNPTlkA\n"
-  "RFNDLVAyMDAAAAAASAAAAAEAAABIAAAAAUFkb2JlIFBob3Rvc2hvcCA3LjAAMjAwNzowMTozMCA\n"
-  "yMzoxMDowNABNYWMgT1MgWCAxMC40LjgAAByCmgAFAAAAAQAAAmqCnQAFAAAAAQAAAnKIIgADAA\n"
-  "AAAQACAACIJwADAAAAAQBkAACQAAAHAAAABDAyMjCQAwACAAAAFAAAAnqQBAACAAAAFAAAAo6RA\n"
-  "QAHAAAABAECAwCRAgAFAAAAAQAAAqKSBAAKAAAAAQAAAqqSBQAFAAAAAQAAArKSBwADAAAAAQAF\n"
-  "AACSCAADAAAAAQAAAACSCQADAAAAAQAPAACSCgAFAAAAAQAAArqgAAAHAAAABDAxMDCgAQADAAA\n"
-  "AAf//AACgAgAEAAAAAQAAAGSgAwAEAAAAAQAAAGSjAAAHAAAAAQMAAACjAQAHAAAAAQEAAACkAQ\n"
-  "ADAAAAAQAAAACkAgADAAAAAQAAAACkAwADAAAAAQAAAACkBgADAAAAAQAAAACkCAADAAAAAQAAA\n"
-  "ACkCQADAAAAAQAAAACkCgADAAAAAQAAAAAAAAAAAAAACgAAAZAAAAAcAAAACjIwMDc6MDE6MjAg\n"
-  "MjM6MDU6NTIAMjAwNzowMToyMCAyMzowNTo1MgAAAAAIAAAAAQAAAAAAAAAKAAAAMAAAABAAAAB\n"
-  "PAAAACgAAAAYBAwADAAAAAQAGAAABGgAFAAAAAQAAAxIBGwAFAAAAAQAAAxoBKAADAAAAAQACAA\n"
-  "ACAQAEAAAAAQAAAyICAgAEAAAAAQAACd0AAAAAAAAASAAAAAEAAABIAAAAAf/Y/+AAEEpGSUYAA\n"
-  "QIBAEgASAAA/+0ADEFkb2JlX0NNAAL/7gAOQWRvYmUAZIAAAAAB/9sAhAAMCAgICQgMCQkMEQsK\n"
-  "CxEVDwwMDxUYExMVExMYEQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQ0LCw0\n"
-  "ODRAODhAUDg4OFBQODg4OFBEMDAwMDBERDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA\n"
-  "wMDAz/wAARCABkAGQDASIAAhEBAxEB/90ABAAH/8QBPwAAAQUBAQEBAQEAAAAAAAAAAwABAgQFB\n"
-  "gcICQoLAQABBQEBAQEBAQAAAAAAAAABAAIDBAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEAAhED\n"
-  "BCESMQVBUWETInGBMgYUkaGxQiMkFVLBYjM0coLRQwclklPw4fFjczUWorKDJkSTVGRFwqN0Nhf\n"
-  "SVeJl8rOEw9N14/NGJ5SkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9xEAAg\n"
-  "IBAgQEAwQFBgcHBgU1AQACEQMhMRIEQVFhcSITBTKBkRShsUIjwVLR8DMkYuFygpJDUxVjczTxJ\n"
-  "QYWorKDByY1wtJEk1SjF2RFVTZ0ZeLys4TD03Xj80aUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm\n"
-  "9ic3R1dnd4eXp7fH/9oADAMBAAIRAxEAPwDy7bKNTUXNLz9EaJPDWMjxH4ozhtpYwaACT8ShaaW\n"
-  "bW0uEc9/JFfjj0Q4Hk/PRDxwX7y47W9z/AN9Cv4+O3ILK2DcRqT2CaSvEbcl1Jbz37KG1dBldLo\n"
-  "qaS4l9xGjG9v6yoDAdYIaIjUk+AREgo4y5sapirb8Yl0NHHdKvBNm4yA1o5Pc+SPEFvCWqB3HZF\n"
-  "Hj2SbWQ/afGFP0bHP8ATY0uc4w1o1JPkkimGiS2KvqlnmBkOZQTyydzgPMM9v8A0lp4v1Nx9gF1\n"
-  "tpdqJaGtH/S3I0i3lISXW/8AMqnd/O2bfg2eUkqVYf/Q8zuncO4Bj7lZ+n7f5Mj5KsJcY8NUZ4d\n"
-  "uEDVo1HkeU0rg3Om4H2rabCWUN7DQuK1n5FWKW4uCwG92gDRJBS6exhxmMboQI+Cv4WFTQ42Bs2\n"
-  "fvnkkqEmy2YxoMMbpVzaz6jt+RbpHZs8lzkHqrasKkYOKP0jgDfZ4N/wDM1tNrcWfSPmRyq9uNV\n"
-  "DnFg2s97i7UkjxKVrq0eVz3spZsja+ASDzwsh9jnOk/JFzb3XZD3v1c4yT8UACTCniKDUnKz5Nj\n"
-  "G33XV1DV73BrT8dF23SejV4zg9g33cOsPb+SxVvqv9ViwNy8vS0iWs/daf8A0Y5dpTi1sADGxCR\n"
-  "K1o0YBEmInlXWYbDBcDLdPJXa8f71Yrx2jnUoAqLnfZK5hJaW2vdwEk5a/wD/0fN6Ia/e76IiVf\n"
-  "xavUL7CPpnT4LNbYXAVjuQt/AqDmNYO/Kjnoy4hr5J8SwMhrRMaeSvbsxrfUazcOw4UX0Cisem2\n"
-  "SBoD4+Kz8nC6llbSLCRrubJA8kwUWbUDa29X1PMa7aQWjuDC0MXMdbDbhI7eazBiUfZ6GOYRe1s\n"
-  "WvGgJ8Vbw2+m4Bx9s6JpNHuuGo1FF53r/SHYua61gLse0lzXeBP5rkvqx0o5vVWz7WY49QkiQSP\n"
-  "oN/tLoevW/ogxv0HA7tJ0AnhT+pdDGYVl/wCdcTPkGn2NU0JWNWvlgAbHV6fEqdu2gR/r2WlWwt\n"
-  "AA5VXAEsLXTqJafArQY5rRr9LiPBJiZsZCI1pJjxCi0j4oncSICSkWwzwkjeaSch//0vO7sP7Lm\n"
-  "enO9ogtd5FbPT3Q5pCpZVc4ld3Lmn3O8j9EI2BYdunKjOobMQIyI+rusc2wx4d0eutwGnHh/uQc\n"
-  "Ha7ladj6mVANGvcqOgz0Go7HJ12/GEHcwvB/dPY6ImbbaMaASGuIBjkN7qofs9Ubg9g7OI9p/t/\n"
-  "RTSmhTHr0v6eSz6UgCPP2/wAVu9Ex2V49dVY2iACB4BZeVXQ/AJ3gzGnnOi2+kACpru8flUsNmt\n"
-  "zHRf6xfWCnoeAfTh2ZaQKazx/Ke7+QxcKz61fWA2uuObaC4zGhaPJrXBL64ZFmR124O09ENraPK\n"
-  "N3/AH5GqxIrZVUyp2K2vfdkENsDnxuex9m4Ox9n82xSgNd9D+p/XR1npgseR9ppOy4Dx/NfH/CL\n"
-  "oQJGunmvMv8AFq3KHVcq3HkYQbD2nuSf0I/rMavSg6TLjLigQhJ7Z58v9QkmlsTOqSCn/9PzL7R\n"
-  "d6Qq3n0wZ2zotXpT9xLfFYvkr/S7jXeB8E0jRkhKpC3q8LcJ/kmCrTnkuAPCq4do9Q/ytVbuAeY\n"
-  "Gg5lQybQK+82GBqEQUA1kOHPYf3LLsoyN36G5w8iUfHxepbXE2l0cApALgLHzBq9UxhTXU5hMC1\n"
-  "ktnSCup6S4Ctk+C5XqVGcaHPfuiuHkeTTuWz0+9zaKiH6CC0/yXBSQ2a/MxojV57634rq+v2PLY\n"
-  "be1r2nsYG13/AFKxbfCBMcr0brGAzrGEwCG31ncx0SfBzf7S4+zoHUWWsJq3hz9oLfcBH77R9H+\n"
-  "0pA13u/qPgDp/Q6ri39JlfpXkDx+h/msWn1L6wdO6bSbcrIbU2Q0xLnSe21kuVejJspbVS5+4bd\n"
-  "ocBAkD/orG+tP1ar67Wy7GtZTm1SCXfRsb+a18fRe38x6SG3/44H1Z3f0y2I+l6DoSXD/8xPrDs\n"
-  "3enVu3bdnqN3R+//USSVo//1PLohhce+gRWS0Nsby3lRgFkKxQyW7SgUh3em5Tbq2uB9wWw1wey\n"
-  "J1XGV2XYdm5k7e4WzidXY9oMwo5RZ4T6Hd1ixwfp96PWbAJBVTHzK7O6Ky5oJB1HZMqmUEFlkGy\n"
-  "xpa4zI1Hkq31dy7bMN9BAc3HeWAnnbyxEycmuup1jiAGglZ31PyrmZ9tQg1WtNj54EHR3/S2qTH\n"
-  "1Yc5GgD1FFtzPdWGkd2AyflogZmRmsz6PSrbXbdo+txOrP337f3fzVo15DK2uyrTtqpBOnBKx6b\n"
-  "7MjJsz7tHWOAYP3WD6LU6cqGjFCNl1MmvLcxv6YtDTLSAqP27LrdtYHXFnJZI+Tp3MWg68OpDPv\n"
-  "UMUM2lkQBoouKQ6swjE9Nml+1sz1PW+z6xt27zuj+skrX2ZvqR5z8kkuOfdPt43/1fMm/grFG6f\n"
-  "Lss9JA7JG7tnZs/SfJUrfS3foJ9TvHCopJsV8nWx/t24bJn8Fo/5TjWJXMJIS+i+G36TsZ/7Q9P\n"
-  "8ATfzfeOFofVSZv2/zvt+O3X/v65dJPjt/BiyfN1/wn0zre79nVej/ADG8ep4x2/6Srjd6TdviF\n"
-  "52ko8m6/Ht9X1KnftEo+POwxzK8mSTF46vrH6T1/OEl5Okkl//Z/+0uHFBob3Rvc2hvcCAzLjAA\n"
-  "OEJJTQQEAAAAAAArHAIAAAIAAhwCeAAfICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAA\n"
-  "4QklNBCUAAAAAABD7Caa9B0wqNp2P4sxXqayFOEJJTQPqAAAAAB2wPD94bWwgdmVyc2lvbj0iMS\n"
-  "4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUgQ\n"
-  "29tcHV0ZXIvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Q\n"
-  "cm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk\n"
-  "+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1Ib3Jpem9udGFsUmVzPC9rZXk+Cgk8ZGljdD\n"
-  "4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+Y\n"
-  "29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50\n"
-  "LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5jb20\n"
-  "uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUhvcml6b250YWxSZXM8L2tleT4KCQkJCTxyZWFsPj\n"
-  "cyPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJC\n"
-  "QkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCQk8a2V5PmNv\n"
-  "bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRhdGU+MjAwNy0wMS0zMFQ\n"
-  "yMjowODo0MVo8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbG\n"
-  "FnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY3Q+CgkJPC9hcnJheT4KC\n"
-  "TwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwv\n"
-  "a2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4\n"
-  "KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS\n"
-  "5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KC\n"
-  "QkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJ\n"
-  "CQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5\n"
-  "jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW\n"
-  "5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCTxkY\n"
-  "XRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQu\n"
-  "dGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJPC9kaWN\n"
-  "0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0Ll\n"
-  "BNU2NhbGluZzwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZ\n"
-  "WF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4K\n"
-  "CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5Pgo\n"
-  "JCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1TY2FsaW5nPC\n"
-  "9rZXk+CgkJCQk8cmVhbD4xPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0L\n"
-  "mNsaWVudDwva2V5PgoJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJp\n"
-  "bmc+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGR\n"
-  "hdGU+MjAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC\n"
-  "50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY\n"
-  "3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQu\n"
-  "UE1WZXJ0aWNhbFJlczwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V\n"
-  "0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cm\n"
-  "luZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFyc\n"
-  "mF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1WZXJ0\n"
-  "aWNhbFJlczwva2V5PgoJCQkJPHJlYWw+NzI8L3JlYWw+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcml\n"
-  "udC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbm\n"
-  "FnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZ\n"
-  "Xk+CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT4KCQkJCTxrZXk+Y29tLmFw\n"
-  "cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI\n"
-  "+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUG\n"
-  "FnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGluZzwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwb\n"
-  "GUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGlu\n"
-  "Z21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF\n"
-  "5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2\n"
-  "VGb3JtYXQuUE1WZXJ0aWNhbFNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjE8L3JlYWw+CgkJCQk8a\n"
-  "2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5h\n"
-  "cHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnR\n"
-  "pY2tldC5tb2REYXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT\n"
-  "4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpb\n"
-  "nRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5j\n"
-  "b20uYXBwbGUucHJpbnQuc3ViVGlja2V0LnBhcGVyX2luZm9fdGlja2V0PC9rZXk+Cgk8ZGljdD4\n"
-  "KCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlUmVjdDwva2\n"
-  "V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5P\n"
-  "goJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJPGtleT5j\n"
-  "b20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGl\n"
-  "jdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlUm\n"
-  "VjdDwva2V5PgoJCQkJCTxhcnJheT4KCQkJCQkJPHJlYWw+MC4wPC9yZWFsPgoJCQkJCQk8cmVhb\n"
-  "D4wLjA8L3JlYWw+CgkJCQkJCTxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+NTc2PC9yZWFs\n"
-  "PgoJCQkJCTwvYXJyYXk+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDw\n"
-  "va2V5PgoJCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQ\n"
-  "kJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+M\n"
-  "jAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj\n"
-  "a2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2RpY3Q\n"
-  "+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYX\n"
-  "QuUE1BZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5wc\n"
-  "mludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21h\n"
-  "bmFnZXI8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTw\n"
-  "va2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYW\n"
-  "dlRm9ybWF0LlBNQWRqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+CgkJCQkJCTxyZ\n"
-  "WFsPi0xODwvcmVhbD4KCQkJCQkJPHJlYWw+LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3Jl\n"
-  "YWw+CgkJCQkJCTxyZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+Y29tLmF\n"
-  "wcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcm\n"
-  "ludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQub\n"
-  "W9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJ\n"
-  "CTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWd\n"
-  "lcj4wPC9pbnRlZ2VyPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5Pm\n"
-  "NvbS5hcHBsZS5wcmludC5QYXBlckluZm8uUE1QYXBlck5hbWU8L2tleT4KCQk8ZGljdD4KCQkJP\n"
-  "GtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20u\n"
-  "YXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcml\n"
-  "udC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZX\n"
-  "k+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVBhcGVyTmFtZTwva2V5PgoJCQkJCTxzdHJpb\n"
-  "mc+bmEtbGV0dGVyPC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNs\n"
-  "aWVudDwva2V5PgoJCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LnBtLlBvc3RTY3JpcHQ8L3N\n"
-  "0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQ\n"
-  "kJCTxkYXRlPjIwMDMtMDctMDFUMTc6NDk6MzZaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxlL\n"
-  "nByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgoJ\n"
-  "CQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC5\n"
-  "QYXBlckluZm8uUE1VbmFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb2\n"
-  "0uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUuc\n"
-  "HJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNr\n"
-  "ZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmF\n"
-  "wcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYWdlUmVjdDwva2V5PgoJCQkJCTxhcn\n"
-  "JheT4KCQkJCQkJPHJlYWw+MC4wPC9yZWFsPgoJCQkJCQk8cmVhbD4wLjA8L3JlYWw+CgkJCQkJC\n"
-  "TxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+NTc2PC9yZWFsPgoJCQkJCTwvYXJyYXk+CgkJ\n"
-  "CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbmc\n"
-  "+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLn\n"
-  "ByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+MjAwNy0wMS0zMFQyMjowODo0M\n"
-  "Vo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5\n"
-  "PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9\n"
-  "kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYXBlcl\n"
-  "JlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b\n"
-  "3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5n\n"
-  "PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJ\n"
-  "heT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYW\n"
-  "RqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+CgkJCQkJCTxyZWFsPi0xODwvcmVhb\n"
-  "D4KCQkJCQkJPHJlYWw+LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3JlYWw+CgkJCQkJCTxy\n"
-  "ZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnR\n"
-  "pY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZX\n"
-  "I8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5P\n"
-  "goJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFw\n"
-  "cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4wPC9pbnRlZ2V\n"
-  "yPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcm\n"
-  "ludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tL\n"
-  "mFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnBy\n"
-  "aW50LnBtLlBvc3RTY3JpcHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V\n"
-  "0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcH\n"
-  "BsZS5wcmludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJCQkJPHN0cmluZz5VU\n"
-  "yBMZXR0ZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50\n"
-  "PC9rZXk+CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5\n"
-  "nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPG\n"
-  "RhdGU+MjAwMy0wNy0wMVQxNzo0OTozNlo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpb\n"
-  "nQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+CgkJCQk8\n"
-  "L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2t\n"
-  "ldC5BUElWZXJzaW9uPC9rZXk+CgkJPHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJCTxrZXk+Y29tLm\n"
-  "FwcGxlLnByaW50LnRpY2tldC5wcml2YXRlTG9jazwva2V5PgoJCTxmYWxzZS8+CgkJPGtleT5jb\n"
-  "20uYXBwbGUucHJpbnQudGlja2V0LnR5cGU8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmlu\n"
-  "dC5QYXBlckluZm9UaWNrZXQ8L3N0cmluZz4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW5\n"
-  "0LnRpY2tldC5BUElWZXJzaW9uPC9rZXk+Cgk8c3RyaW5nPjAwLjIwPC9zdHJpbmc+Cgk8a2V5Pm\n"
-  "NvbS5hcHBsZS5wcmludC50aWNrZXQucHJpdmF0ZUxvY2s8L2tleT4KCTxmYWxzZS8+Cgk8a2V5P\n"
-  "mNvbS5hcHBsZS5wcmludC50aWNrZXQudHlwZTwva2V5PgoJPHN0cmluZz5jb20uYXBwbGUucHJp\n"
-  "bnQuUGFnZUZvcm1hdFRpY2tldDwvc3RyaW5nPgo8L2RpY3Q+CjwvcGxpc3Q+CjhCSU0D6QAAAAA\n"
-  "AeAADAAAASABIAAAAAALeAkD/7v/uAwYCUgNnBSgD/AACAAAASABIAAAAAALYAigAAQAAAGQAAA\n"
-  "ABAAMDAwAAAAF//wABAAEAAAAAAAAAAAAAAABoCAAZAZAAAAAAACAAAAAAAAAAAAAAAAAAAAAAA\n"
-  "AAAAAAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQABAEgAAAABAAE4QklNBCYAAAAAAA4AAAAAAAAA\n"
-  "AAAAP4AAADhCSU0EDQAAAAAABAAAAB44QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAA\n"
-  "AAAABADhCSU0ECgAAAAAAAQAAOEJJTScQAAAAAAAKAAEAAAAAAAAAAThCSU0D9QAAAAAASAAvZm\n"
-  "YAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAA\n"
-  "QAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP//\n"
-  "//////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA///\n"
-  "//////////////////////////wPoAAA4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQ\n"
-  "QeAAAAAAAEAAAAADhCSU0EGgAAAAADRQAAAAYAAAAAAAAAAAAAAGQAAABkAAAACABEAFMAQwAwA\n"
-  "DIAMwAyADUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAGQAAABkAAAAAAAAAAAA\n"
-  "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHN\n"
-  "PYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAA\n"
-  "AAQnRvbWxvbmcAAABkAAAAAFJnaHRsb25nAAAAZAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABA\n"
-  "AAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAG\n"
-  "b3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQA\n"
-  "AAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAA\n"
-  "BUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAAZAAAAABSZ2h0bG9uZ\n"
-  "wAAAGQAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAEA\n"
-  "AAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxUZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleHR\n"
-  "URVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAPRVNsaWNlSG9yekFsaWduAAAAB2RlZmF1bH\n"
-  "QAAAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0QWxpZ24AAAAHZGVmYXVsdAAAAAtiZ0Nvb\n"
-  "G9yVHlwZWVudW0AAAARRVNsaWNlQkdDb2xvclR5cGUAAAAATm9uZQAAAAl0b3BPdXRzZXRsb25n\n"
-  "AAAAAAAAAApsZWZ0T3V0c2V0bG9uZwAAAAAAAAAMYm90dG9tT3V0c2V0bG9uZwAAAAAAAAALcml\n"
-  "naHRPdXRzZXRsb25nAAAAAAA4QklNBBEAAAAAAAEBADhCSU0EFAAAAAAABAAAAAE4QklNBAwAAA\n"
-  "AACfkAAAABAAAAZAAAAGQAAAEsAAB1MAAACd0AGAAB/9j/4AAQSkZJRgABAgEASABIAAD/7QAMQ\n"
-  "WRvYmVfQ00AAv/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUT\n"
-  "ExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4\n"
-  "ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAGQAZA\n"
-  "MBIgACEQEDEQH/3QAEAAf/xAE/AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBA\n"
-  "QEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYEy\n"
-  "BhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80Y\n"
-  "nlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcGBT\n"
-  "UBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kSTV\n"
-  "KMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/\n"
-  "2gAMAwEAAhEDEQA/APLtso1NRc0vP0Rok8NYyPEfijOG2ljBoAJPxKFppZtbS4Rz38kV+OPRDge\n"
-  "T89EPHBfvLjtb3P8A30K/j47cgsrYNxGpPYJpK8RtyXUlvPfsobV0GV0uippLiX3EaMb2/rKgMB\n"
-  "1ghoiNST4BESCjjLmxqmKtvxiXQ0cd0q8E2bjIDWjk9z5I8QW8JaoHcdkUePZJtZD9p8YU/Rsc/\n"
-  "wBNjS5zjDWjUk+SSKYaJLYq+qWeYGQ5lBPLJ3OA8wz2/wDSWni/U3H2AXW2l2oloa0f9LcjSLeU\n"
-  "hJdb/wAyqd387Zt+DZ5SSpVh/9DzO6dw7gGPuVn6ft/kyPkqwlxjw1Rnh24QNWjUeR5TSuDc6bg\n"
-  "fatpsJZQ3sNC4rWfkVYpbi4LAb3aANEkFLp7GHGYxuhAj4K/hYVNDjYGzZ++eSSoSbLZjGgwxul\n"
-  "XNrPqO35FukdmzyXOQeqtqwqRg4o/SOAN9ng3/AMzW02txZ9I+ZHKr241UOcWDaz3uLtSSPEpWu\n"
-  "rR5XPeylmyNr4BIPPCyH2Oc6T8kXNvddkPe/VzjJPxQAJMKeIoNScrPk2MbfddXUNXvcGtPx0Xb\n"
-  "dJ6NXjOD2Dfdw6w9v5LFW+q/1WLA3Ly9LSJaz91p/wDRjl2lOLWwAMbEJErWjRgESYieVdZhsMF\n"
-  "wMt08ldrx/vVivHaOdSgCoud9krmElpba93ASTlr/AP/R83ohr97voiJV/Fq9QvsI+mdPgs1thc\n"
-  "BWO5C38CoOY1g78qOejLiGvknxLAyGtExp5K9uzGt9RrNw7DhRfQKKx6bZIGgPj4rPycLqWVtIs\n"
-  "JGu5skDyTBRZtQNrb1fU8xrtpBaO4MLQxcx1sNuEjt5rMGJR9noY5hF7Wxa8aAnxVvDb6bgHH2z\n"
-  "omk0e64ajUUXnev9Idi5rrWAux7SXNd4E/muS+rHSjm9VbPtZjj1CSJBI+g3+0uh69b+iDG/QcD\n"
-  "u0nQCeFP6l0MZhWX/AJ1xM+QafY1TQlY1a+WABsdXp8Sp27aBH+vZaVbC0ADlVcASwtdOolp8Ct\n"
-  "BjmtGv0uI8EmJmxkIjWkmPEKLSPiidxIgJKRbDPCSN5pJyH//S87uw/suZ6c72iC13kVs9PdDmk\n"
-  "KllVziV3cuafc7yP0QjYFh26cqM6hsxAjIj6u6xzbDHh3R663AaceH+5BwdruVp2PqZUA0a9yo6\n"
-  "DPQajscnXb8YQdzC8H909joiZttoxoBIa4gGOQ3uqh+z1RuD2Ds4j2n+39FNKaFMevS/p5LPpSA\n"
-  "I8/b/ABW70THZXj11VjaIAIHgFl5VdD8AneDMaec6Lb6QAKmu7x+VSw2a3MdF/rF9YKeh4B9OHZ\n"
-  "lpAprPH8p7v5DFwrPrV9YDa645toLjMaFo8mtcEvrhkWZHXbg7T0Q2to8o3f8AfkarEitlVTKnY\n"
-  "ra992QQ2wOfG57H2bg7H2fzbFKA130P6n9dHWemCx5H2mk7LgPH818f8IuhAka6ea8y/wAWrcod\n"
-  "VyrceRhBsPae5J/Qj+sxq9KDpMuMuKBCEntnny/1CSaWxM6pIKf/0/MvtF3pCrefTBnbOi1elP3\n"
-  "Et8Vi+Sv9LuNd4HwTSNGSEqkLerwtwn+SYKtOeS4A8Krh2j1D/K1Vu4B5gaDmVDJtAr7zYYGoRB\n"
-  "QDWQ4c9h/csuyjI3fobnDyJR8fF6ltcTaXRwCkAuAsfMGr1TGFNdTmEwLWS2dIK6npLgK2T4Lle\n"
-  "pUZxoc9+6K4eR5NO5bPT73NoqIfoILT/JcFJDZr8zGiNXnvrfiur6/Y8tht7WvaexgbXf8AUrFt\n"
-  "8IExyvRusYDOsYTAIbfWdzHRJ8HN/tLj7OgdRZawmreHP2gt9wEfvtH0f7SkDXe7+o+AOn9DquL\n"
-  "f0mV+leQPH6H+axafUvrB07ptJtyshtTZDTEudJ7bWS5V6MmyltVLn7ht2hwECQP+isb60/Vqvr\n"
-  "tbLsa1lObVIJd9Gxv5rXx9F7fzHpIbf/jgfVnd/TLYj6XoOhJcP/zE+sOzd6dW7dt2eo3dH7/9R\n"
-  "JJWj//U8uiGFx76BFZLQ2xvLeVGAWQrFDJbtKBSHd6blNura4H3BbDXB7InVcZXZdh2bmTt7hbO\n"
-  "J1dj2gzCjlFnhPod3WLHB+n3o9ZsAkFVMfMrs7orLmgkHUdkyqZQQWWQbLGlrjMjUeSrfV3Ltsw\n"
-  "30EBzcd5YCedvLETJya66nWOIAaCVnfU/KuZn21CDVa02PngQdHf9LapMfVhzkaAPUUW3M91YaR\n"
-  "3YDJ+WiBmZGazPo9Kttdt2j63E6s/fft/d/NWjXkMra7KtO2qkE6cErHpvsyMmzPu0dY4Bg/dYP\n"
-  "otTpyoaMUI2XUya8tzG/pi0NMtICo/bsut21gdcWclkj5OncxaDrw6kM+9QxQzaWRAGii4pDqzC\n"
-  "MT02aX7WzPU9b7PrG3bvO6P6yStfZm+pHnPySS4590+3jf/V8yb+CsUbp8uyz0kDskbu2dmz9J8\n"
-  "lSt9Ld+gn1O8cKikmxXydbH+3bhsmfwWj/lONYlcwkhL6L4bfpOxn/tD0/wBN/N944Wh9VJm/b/\n"
-  "O+347df+/rl0k+O38GLJ83X/CfTOt7v2dV6P8AMbx6njHb/pKuN3pN2+IXnaSjybr8e31fUqd+0\n"
-  "Sj487DHMryZJMXjq+sfpPX84SXk6SSX/9kAOEJJTQQhAAAAAABVAAAAAQEAAAAPAEEAZABvAGIA\n"
-  "ZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAA\n"
-  "gADcALgAwAAAAAQA4QklNBAYAAAAAAAcABQAAAAEBAP/hFWdodHRwOi8vbnMuYWRvYmUuY29tL3\n"
-  "hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0n77u/JyBpZD0nVzVNME1wQ2VoaUh6cmVTek5UY3prY\n"
-  "zlkJz8+Cjw/YWRvYmUteGFwLWZpbHRlcnMgZXNjPSJDUiI/Pgo8eDp4YXBtZXRhIHhtbG5zOng9\n"
-  "J2Fkb2JlOm5zOm1ldGEvJyB4OnhhcHRrPSdYTVAgdG9vbGtpdCAyLjguMi0zMywgZnJhbWV3b3J\n"
-  "rIDEuNSc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi\n"
-  "1yZGYtc3ludGF4LW5zIycgeG1sbnM6aVg9J2h0dHA6Ly9ucy5hZG9iZS5jb20vaVgvMS4wLyc+C\n"
-  "gogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXVpZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC05\n"
-  "MWQ1NDAzZjkyZjknCiAgeG1sbnM6cGRmPSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz4\n"
-  "KICA8IS0tIHBkZjpTdWJqZWN0IGlzIGFsaWFzZWQgLS0+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCi\n"
-  "A8cmRmOkRlc2NyaXB0aW9uIGFib3V0PSd1dWlkOjIyZDAyYjBhLWIyNDktMTFkYi04YWY4LTkxZ\n"
-  "DU0MDNmOTJmOScKICB4bWxuczpwaG90b3Nob3A9J2h0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9z\n"
-  "aG9wLzEuMC8nPgogIDwhLS0gcGhvdG9zaG9wOkNhcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwvcmR\n"
-  "mOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMGEtYj\n"
-  "I0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcD0naHR0cDovL25zLmFkb2JlL\n"
-  "mNvbS94YXAvMS4wLyc+CiAgPCEtLSB4YXA6RGVzY3JpcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwv\n"
-  "cmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMGE\n"
-  "tYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYW\n"
-  "RvYmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwa\n"
-  "G90b3Nob3A6MjJkMDJiMDYtYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5PC94YXBNTTpEb2N1\n"
-  "bWVudElEPgogPC9yZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXV\n"
-  "pZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC05MWQ1NDAzZjkyZjknCiAgeG1sbnM6ZGM9J2h0dH\n"
-  "A6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJz4KICA8ZGM6ZGVzY3JpcHRpb24+CiAgIDxyZ\n"
-  "GY6QWx0PgogICAgPHJkZjpsaSB4bWw6bGFuZz0neC1kZWZhdWx0Jz4gICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgIDwvcmRmOkFsdD4KICA8L2RjOmRlc2NyaXB0aW9\n"
-  "uPgogPC9yZGY6RGVzY3JpcHRpb24+Cgo8L3JkZjpSREY+CjwveDp4YXBtZXRhPgogICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA\n"
-  "ogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
-  "ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
-  "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg\n"
-  "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
-  "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIC\n"
-  "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0ndyc/P\n"
-  "v/uAA5BZG9iZQBkQAAAAAH/2wCEAAQDAwMDAwQDAwQGBAMEBgcFBAQFBwgGBgcGBggKCAkJCQkI\n"
-  "CgoMDAwMDAoMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBAUFCAcIDwoKDxQODg4UFA4ODg4UEQwMDAw\n"
-  "MEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAGQAZAMBEQACEQEDEQ\n"
-  "H/3QAEAA3/xAGiAAAABwEBAQEBAAAAAAAAAAAEBQMCBgEABwgJCgsBAAICAwEBAQEBAAAAAAAAA\n"
-  "AEAAgMEBQYHCAkKCxAAAgEDAwIEAgYHAwQCBgJzAQIDEQQABSESMUFRBhNhInGBFDKRoQcVsUIj\n"
-  "wVLR4TMWYvAkcoLxJUM0U5KismNzwjVEJ5OjszYXVGR0w9LiCCaDCQoYGYSURUaktFbTVSga8uP\n"
-  "zxNTk9GV1hZWltcXV5fVmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9zhIWGh4iJiouMjY6PgpOUlZaX\n"
-  "mJmam5ydnp+So6SlpqeoqaqrrK2ur6EQACAgECAwUFBAUGBAgDA20BAAIRAwQhEjFBBVETYSIGc\n"
-  "YGRMqGx8BTB0eEjQhVSYnLxMyQ0Q4IWklMlomOywgdz0jXiRIMXVJMICQoYGSY2RRonZHRVN/Kj\n"
-  "s8MoKdPj84SUpLTE1OT0ZXWFlaW1xdXl9UZWZnaGlqa2xtbm9kdXZ3eHl6e3x9fn9zhIWGh4iJi\n"
-  "ouMjY6Pg5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6vr/2gAMAwEAAhEDEQA/APBnplwPAdR+GB\n"
-  "KY6dYtNG1w39yh4+xb+zIksgEfFaRSSoIx8f7RPRRkSWQimM+lRmwWVXFWYigHxUUVoMiJM+Fj0\n"
-  "tg0RBegLE0Wu+3c+GTBazFCGI7HtSp9slbFYYzyoBsegw2hY1Afl3wqqRqahk+0tDgKpgu4DAUU\n"
-  "+HY+GRS2ePiMKtUB3G+KGuONq//Q8OzpFbW5WnxMop4k9crG5ZnZNJkEOn21utVRYw7HxZtz+OR\n"
-  "vdsrZ2lRtci4aVxFEQA0neg/ZXxJpTITNNuOFss0vSotYNvZ2qGRkPKSTqiU8Sdqk5SZU5Ix8XJ\n"
-  "NNZ8k6bp8TtM73OputUtYq0Unux/hkRkJOzZLCAN2KR+VpbtSkCBaDnIzdlWu59u+XeJTjeASk8\n"
-  "+juZOESEAVqx8BvU/PJibScTrTy09560hkWOGFd2YgFnPQKD19zhOSkxw2l8Vm6XAiYb8gg+k5O\n"
-  "9mnhoon9H3cs5s7WF5pp29OGGMFndyaAKBuTiEEPQLD8h/NDmNdYlttNkYjlbFjcXCr3LLH8II8\n"
-  "C2WUGviZvon/OPWkm3RNSv72SYllMkKxQRV67CQMSKYQAxMkR/wBC56d61P0heel4cYuVOXWvTp\n"
-  "h4Qjjf/9Hw5qBYyISaqjBV+QpvkAzKcki4HomnIxck/wBhtlR2bhunvlDywddMUl4zW+kQ9FQ8X\n"
-  "nfuSewrtmPkycPvc/DhMhvyegXOrWWhmLQPKlsj6xIAiLCoZkY96nv7npmJvI2XOjQFMl0fyRqM\n"
-  "NoxvZvrGt33wlATwiMnVnY1LEdSfuyXF3KIDmUu88w2XlnTl8raAlb2ZFfVL0jdYRtQnxc7BfDC\n"
-  "OaJR7nm3me5tdOtjbMvp3ZRXkV6chVQRX79hmVjgZG+jgZ5jHGhzecXF5LPL6jEjstSSaDM51Ka\n"
-  "6MZ9S1C0sEBe8uZo4YCBXdjxGw60wEWyEqfUHkT8vLXRJFuLdTcaqfhlvWUErtukZ3ABPUjIXTE\n"
-  "m3rGmeV2Tk5UKz/AG/E/wAcgZKya20C3b02kjYtH8AqCygbkUH0nLYlgUb+gbWtPbpXt/n2ybB/\n"
-  "/9Lw4oaVxGd+PxH3qBkGaY3KyiSP01IkiUclH8sg+LKydm6INvZvKsFu+kWtvD8LRoFNRup6moO\n"
-  "aqd277HsGW+XPLmn6XM17FF6l7vW4fd2Zuu+RFls2tmUNrLJb7TSBertGQGqetDkxE0na0pvtHs\n"
-  "QkszWyiGAG5laYlnkeMVHJj8sA5rPk+SvMepTalqlxd3B5zTOXdj/MxqafLpm5xioh5nPK5kpRG\n"
-  "pkcKAST0A6k5NpfUP5K/ki1ssHmHzF+71KRQ8Nud/Qibb/kYw6/yjbrXISlSH07YaHbWyxx2kXE\n"
-  "KACB2zHJtLI7XSelBRvH2xCpvaaTDHXkOTVBPcUG2479RlsdmJVPRtvV+ylenQ0y62FP/9PxRpo\n"
-  "WG5FxKKxKFDA+GVS5NsebLdFsRePc3siVW4f4QR0QVAGYeSXR2unhtZ6s60K6jt+MMSFwtF2+xX\n"
-  "wr7eGUGLlRPQMsE2vxQm7itxKg3VCfT2+nb8cDYaCDtfOXmCCcROrQrUhkkCHYn6emRMqZxjbLd\n"
-  "F1+W/4xajHzjNCtQKMffETWUdngX5p+QZ9A8xS6hbo0ui37NNDPT7DOalHpsCD08Rmyw5ARTpdV\n"
-  "gIPEF35MeRn80ed4S5EdrpKm9kZ15K0iH92hB7Me/tmS60vt/QrCYyekiBdgSTXcjqV9q9MokFD\n"
-  "N7S3aFVVR8RoK9zldqndvAY6nffr/AGYQqLhjdpCoIAZW22HavU/LJBUP9WblX0xTw7fOmWsX/9\n"
-  "Tw7FdvMqWkQ3Z1qfED+mQIbI77PX/LFis9vBajZm2Y+x65rMh3t30Bsze400aVaIbSLk6r8CMRT\n"
-  "l/NmOcllnGDD9Y8uecNfEEiXrMgDGWAyGOOu5WlB+vMrHODTlxZCdjsyFdB006VpVtLasurQxBL\n"
-  "64WiLI4/aFT1ANOXemV5piR2b9NiljB4yyHy9CLOVI5GJhB+CvXY9R8xmINzs5HNZ+Z96BZpbxA\n"
-  "fVJo39UFefwopYgL4nMiMd2qZoIn/AJx00u3t/Lt7qpp9Yv5GLf5MUTERqfbvmzBeezjd9H+VlL\n"
-  "wSQzBqsvOGQD7L12rXsemPNxmXQSxxIPU2nFV4HYqR1xEUWj4ZAxBryr2G+J2VGDZlLrxUH6KZA\n"
-  "Fkqb15VFelfwy+2FP8A/9Xxlf6AdA182Yk9eFeLxSjoVfcfSMo4uIOfkweFOnpvlWYrLEwNFAA+\n"
-  "nMOYdrhFvQLeSO7coBXiK8iKiv07Zj8Ac4QtNrW1njUcKcT+yAR/xGmR4WcsStLpTuPU9IFaEsV\n"
-  "BP3k4m2AgBzSwyQNcIwNTE1aI3wnam9O2Ug7s5Ckk/NDndeVXa2H78MqqV6jmeBp9+ZWKXqDjZ4\n"
-  "+gvVvy30qCy0qzsLRBCnBI2VdgUTqPvOZ7y+Q7pz+bn5q6d+VflZxZlJ/NN4ypptk5qtB9qRwDX\n"
-  "gn/AAx2y2ItpfKFv+eH5qNeTajJ5ovVaVywSqvEtTUKqupAA6D2y0BNPtv/AJx//M5PzL8mJeXT\n"
-  "L+ndPf6rqarSpkAqsnEAAeoN6DpkJRYci9lROSgSUUH9o9K5Tw0ztfSHnXkOtK9q+PHwydq//9b\n"
-  "yxrVoZNBtNSA5zRMPXmH8j0CLXuBmHE+qneamHpEuqYeV7pzFVTRgQK5XMNmnlb1vyyY5QA1OwJ\n"
-  "+eUF2seTOLu5s7azVIVAkpVn/hhnIALG73Yz5jvb1dICqzpDNIqyFD8SxH7R28cxibZCiWOsdJs\n"
-  "PTM6XNstPhnkjIhcHuJBVfvOCiUSn0TfWrTTLjyw8guA/PifTO3xcxxA8a5ZAbimvJP0m3p/kFF\n"
-  "WxhmpWQJ9NW3zZPHz5vlb/nIDVbrWfzO1RJhxGnpDaRL/khA1T7ktmSOTAJhZaAUtLawsbayl8v\n"
-  "xWi3Gpay0cF3HPcFRJJHJMXVrcJ8UaAFG5LWjF8tAYW9H/wCcOo9bTzxrt/owkTyksZW5gkIKvI\n"
-  "7k26nvyReRJHyyBWT7dWQyOWlbnK2526e1O1MqIUFE84uPLkOdK9RXI0E2/wD/1/DA1bURZLY/W\n"
-  "ZDZqwb0eXw7dMgIi7bjllVXsz7yNcfWC0Vd3Ip92Y2UOz0cnsPlwyx8xQ/u24sMxCadoJp9LOXk\n"
-  "VX/uwRUE0BI8cokbLMyoKouHu2MaKGXw7fLDwgoGSkbHpaNZyLLHRSKcFFQQRvUdMlwUFOQyLzr\n"
-  "ztpCaba6fPau4ijv4OURY8AjVFKV7ZZiO+7Vnh6XvXkSWNbW2WTb92KDxIFMzwHlZc3zX+fuizW\n"
-  "f5p3ty8XGDU4YLmCQiisyII3+4rvl8UB5ffEghRGvOm7AbnvWvjk1fen/ONPldPKP5aWOpPCfr2\n"
-  "uE31y6q2wbaMEn+VAMDSdyzrzj+avlHyTp0l/r2rxWFuHWJuIeacu4qFCRgsajfBwsty89/6Gr/\n"
-  "ACa9an+JL/hSnrfoubhXwpXpjwhaL//Q8E1AqtcAZMs8l6i1nqMa1oSVP0VynKLDmaWdSfQXl69\n"
-  "jF1Jv8MhDb5rpB3AO7INRRLhhGp4R05FgaGvTMU8200xS70zVDMRp2pTIOvBmB3PgQP15kxIcnD\n"
-  "LH/EEz0rRvOJhldr9pQtCqyd6VrShGTqw5d4ARv9jHfOGl+ZJNMluLkyenaFbiRdqFYW5nrWuwO\n"
-  "MKB5MdSMRxnhlu9N8p6lLFpti63FUjCtFJTrDKvse2bEDZ4XJ9RZB+YPli2/Mjy5bxoUi1a0YS2\n"
-  "85UOwIXiy9jRu+TBppfOF1+V3m22vrdpNPM8cs/oo0VJlUqQPjValR3+IZNNvtLS9Yu9Mi0/TJr\n"
-  "kyp6QhWVVCIWRATsKBemwwFrDzT87fybs/wA1bW21PRb+DTvNlgGSRp6iC8i3KJJx+y6n7D0Pwm\n"
-  "hxBZXT55/6Fi/Nf0PW+qWXq+t6X1X67F6vD/ftK04V/wBl344U8b//0fBapxheVh9ocV+nviqY2\n"
-  "/qQJDew/bioWHiuQ8m0bbvaPKGtQ6jaxSo9JloCK75gZI0Xb4sgkHo8MouoAvP94BsRmGY7uWJU\n"
-  "gzbypOQpNOvIdK4Nw2WCE2tXulTkjEEbdafgclxMhFBas93dwyQzsWDghlJFONKHJCZtjOFBJfy\n"
-  "j1y9vPL9zpbIs0WkXL2sUjA8hDXlGCRXtt07ZuYvL5KJeo6bfajbkzWkcToR8dqshZ6in2fhNK/\n"
-  "PDTUlXmHVvMdr5o0v9H2kdrqGpfu7m0nkY87Uf7tkKAU4/s03ynLkEBbfihx7dGT6va67LbRMNR\n"
-  "aKOBuUTKgIBXoK1BOYR1M3aQ0mOt9yxUeZNdtJhFapLqMluSXkg5oxJrUMW5KevQ9MmNXXNqOiH\n"
-  "Rr/Hmv8A1r9I/oj95w+r+j9Yf1+NP5+nXtTD+dF8tkfkOlv/0vC3ph7f0/alcVTbS4A8QibuKb5\n"
-  "RI05EBYRFpdX3ly79a2qYCavH/EY7TCYyMD5PSdD8+wXUSn1ArDqOhBzFlipz4ZwWbaV5htbsgF\n"
-  "qg9crMXKErGyYwajFGzxyHlGSePbbwyqg5UZlCaxrFpaWU95LIqrEjMAT4Dp9OShGy1ZslBhv/A\n"
-  "Dj9rd/a+aL+xUK+m38L3d0HrxRo2HFtu5D8c27y8t30raarbWkU+u6g4gsNORn+EcUaSh2Pc0/4\n"
-  "lgtAjezzbT9SutY1i782al8Nxdyotqh6xWybIg+jc5q8s+I27bFDgFPQp9RE+nrag70+L6crrZu\n"
-  "4jajokdv6LW/Dii1Wo61PXKQN3KPK0L+h4/rnD/K5V78a5LhXxd3/0/DMXXtwxVNtL9Xkaf3f7N\n"
-  "etfbKMjdjtkZ9D6ufrlK0+HpX8coF9HJ26sXvfqXrf7i/U+uften/d/wCyrmQL6uOav0pvpP8Ai\n"
-  "b1F+rV59+vH6a5XLhcjH4nRmY/xpxHP0/UptWvT6Mx/RbmjxWK+aP8AFf1M/pCv1Kvxen9inavf\n"
-  "MrFwXtzcLUeLXq5Mv/I3nz1b0v8AjofuKVry9KrUpTanOlf9jmQ68va/zH9b/COn/o7/AI431mP\n"
-  "65SvLh+zWvbl9rMfNfC34K4kmj9T6lD6FKclp/DNYXZx5srsPrHor6nXvkgxTPS/U+rv6dPU5mt\n"
-  "fngFN5ulv+l/pL/Lp/scerHo//2Q==\n";
+    "/9j/4AAQSkZJRgABAgEASABIAAD/"
+    "4Q0HRXhpZgAATU0AKgAAAAgADAEOAAIAAAAgAAAAngEPAAI\n"
+    "AAAAFAAAAvgEQAAIAAAAJAAAAwwESAAMAAAABAAEAAAEaAAUAAAABAAAAzAEbAAUAAAABAAAA1"
+    "A\n"
+    "EoAAMAAAABAAIAAAExAAIAAAAUAAAA3AEyAAIAAAAUAAAA8AE8AAIAAAAQAAABBAITAAMAAAAB"
+    "A\n"
+    "AIAAIdpAAQAAAABAAABFAAAAsQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAFNPTlk"
+    "A\n"
+    "RFNDLVAyMDAAAAAASAAAAAEAAABIAAAAAUFkb2JlIFBob3Rvc2hvcCA3LjAAMjAwNzowMTozMC"
+    "A\n"
+    "yMzoxMDowNABNYWMgT1MgWCAxMC40LjgAAByCmgAFAAAAAQAAAmqCnQAFAAAAAQAAAnKIIgADA"
+    "A\n"
+    "AAAQACAACIJwADAAAAAQBkAACQAAAHAAAABDAyMjCQAwACAAAAFAAAAnqQBAACAAAAFAAAAo6R"
+    "A\n"
+    "QAHAAAABAECAwCRAgAFAAAAAQAAAqKSBAAKAAAAAQAAAqqSBQAFAAAAAQAAArKSBwADAAAAAQA"
+    "F\n"
+    "AACSCAADAAAAAQAAAACSCQADAAAAAQAPAACSCgAFAAAAAQAAArqgAAAHAAAABDAxMDCgAQADAA"
+    "A\n"
+    "AAf//"
+    "AACgAgAEAAAAAQAAAGSgAwAEAAAAAQAAAGSjAAAHAAAAAQMAAACjAQAHAAAAAQEAAACkAQ\n"
+    "ADAAAAAQAAAACkAgADAAAAAQAAAACkAwADAAAAAQAAAACkBgADAAAAAQAAAACkCAADAAAAAQAA"
+    "A\n"
+    "ACkCQADAAAAAQAAAACkCgADAAAAAQAAAAAAAAAAAAAACgAAAZAAAAAcAAAACjIwMDc6MDE6MjA"
+    "g\n"
+    "MjM6MDU6NTIAMjAwNzowMToyMCAyMzowNTo1MgAAAAAIAAAAAQAAAAAAAAAKAAAAMAAAABAAAA"
+    "B\n"
+    "PAAAACgAAAAYBAwADAAAAAQAGAAABGgAFAAAAAQAAAxIBGwAFAAAAAQAAAxoBKAADAAAAAQACA"
+    "A\n"
+    "ACAQAEAAAAAQAAAyICAgAEAAAAAQAACd0AAAAAAAAASAAAAAEAAABIAAAAAf/Y/"
+    "+AAEEpGSUYAA\n"
+    "QIBAEgASAAA/+0ADEFkb2JlX0NNAAL/7gAOQWRvYmUAZIAAAAAB/"
+    "9sAhAAMCAgICQgMCQkMEQsK\n"
+    "CxEVDwwMDxUYExMVExMYEQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQ0LCw"
+    "0\n"
+    "ODRAODhAUDg4OFBQODg4OFBEMDAwMDBERDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD"
+    "A\n"
+    "wMDAz/wAARCABkAGQDASIAAhEBAxEB/90ABAAH/"
+    "8QBPwAAAQUBAQEBAQEAAAAAAAAAAwABAgQFB\n"
+    "gcICQoLAQABBQEBAQEBAQAAAAAAAAABAAIDBAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEAAhE"
+    "D\n"
+    "BCESMQVBUWETInGBMgYUkaGxQiMkFVLBYjM0coLRQwclklPw4fFjczUWorKDJkSTVGRFwqN0Nh"
+    "f\n"
+    "SVeJl8rOEw9N14/"
+    "NGJ5SkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9xEAAg\n"
+    "IBAgQEAwQFBgcHBgU1AQACEQMhMRIEQVFhcSITBTKBkRShsUIjwVLR8DMkYuFygpJDUxVjczTx"
+    "J\n"
+    "QYWorKDByY1wtJEk1SjF2RFVTZ0ZeLys4TD03Xj80aUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtb"
+    "m\n"
+    "9ic3R1dnd4eXp7fH/"
+    "9oADAMBAAIRAxEAPwDy7bKNTUXNLz9EaJPDWMjxH4ozhtpYwaACT8ShaaW\n"
+    "bW0uEc9/JFfjj0Q4Hk/PRDxwX7y47W9z/"
+    "AN9Cv4+O3ILK2DcRqT2CaSvEbcl1Jbz37KG1dBldLo\n"
+    "qaS4l9xGjG9v6yoDAdYIaIjUk+AREgo4y5sapirb8Yl0NHHdKvBNm4yA1o5Pc+"
+    "SPEFvCWqB3HZF\n"
+    "Hj2SbWQ/"
+    "afGFP0bHP8ATY0uc4w1o1JPkkimGiS2KvqlnmBkOZQTyydzgPMM9v8A0lp4v1Nx9gF1\n"
+    "tpdqJaGtH/S3I0i3lISXW/8AMqnd/O2bfg2eUkqVYf/"
+    "Q8zuncO4Bj7lZ+n7f5Mj5KsJcY8NUZ4d\n"
+    "uEDVo1HkeU0rg3Om4H2rabCWUN7DQuK1n5FWKW4uCwG92gDRJBS6exhxmMboQI+"
+    "Cv4WFTQ42Bs2\n"
+    "fvnkkqEmy2YxoMMbpVzaz6jt+RbpHZs8lzkHqrasKkYOKP0jgDfZ4N/"
+    "wDM1tNrcWfSPmRyq9uNV\n"
+    "DnFg2s97i7UkjxKVrq0eVz3spZsja+ASDzwsh9jnOk/"
+    "JFzb3XZD3v1c4yT8UACTCniKDUnKz5Nj\n"
+    "G33XV1DV73BrT8dF23SejV4zg9g33cOsPb+SxVvqv9ViwNy8vS0iWs/"
+    "daf8A0Y5dpTi1sADGxCR\n"
+    "K1o0YBEmInlXWYbDBcDLdPJXa8f71Yrx2jnUoAqLnfZK5hJaW2vdwEk5a/wD/0fN6Ia/"
+    "e76IiVf\n"
+    "xavUL7CPpnT4LNbYXAVjuQt/AqDmNYO/"
+    "Kjnoy4hr5J8SwMhrRMaeSvbsxrfUazcOw4UX0Cisem2\n"
+    "SBoD4+"
+    "Kz8nC6llbSLCRrubJA8kwUWbUDa29X1PMa7aQWjuDC0MXMdbDbhI7eazBiUfZ6GOYRe1s\n"
+    "WvGgJ8Vbw2+m4Bx9s6JpNHuuGo1FF53r/"
+    "SHYua61gLse0lzXeBP5rkvqx0o5vVWz7WY49QkiQSP\n"
+    "oN/tLoevW/ogxv0HA7tJ0AnhT+pdDGYVl/wCdcTPkGn2NU0JWNWvlgAbHV6fEqdu2gR/"
+    "r2WlWwt\n"
+    "AA5VXAEsLXTqJafArQY5rRr9LiPBJiZsZCI1pJjxCi0j4oncSICSkWwzwkjeaSch//"
+    "0vO7sP7Lm\n"
+    "enO9ogtd5FbPT3Q5pCpZVc4ld3Lmn3O8j9EI2BYdunKjOobMQIyI+rusc2wx4d0eutwGnHh/"
+    "uQc\n"
+    "Ha7ladj6mVANGvcqOgz0Go7HJ12/GEHcwvB/dPY6ImbbaMaASGuIBjkN7qofs9Ubg9g7OI9p/"
+    "t/\n"
+    "RTSmhTHr0v6eSz6UgCPP2/wAVu9Ex2V49dVY2iACB4BZeVXQ/"
+    "AJ3gzGnnOi2+kACpru8flUsNmt\n"
+    "zHRf6xfWCnoeAfTh2ZaQKazx/"
+    "Ke7+QxcKz61fWA2uuObaC4zGhaPJrXBL64ZFmR124O09ENraPK\n"
+    "N3/AH5GqxIrZVUyp2K2vfdkENsDnxuex9m4Ox9n82xSgNd9D+p/XR1npgseR9ppOy4Dx/NfH/"
+    "CL\n"
+    "oQJGunmvMv8AFq3KHVcq3HkYQbD2nuSf0I/rMavSg6TLjLigQhJ7Z58v9QkmlsTOqSCn/"
+    "9PzL7R\n"
+    "d6Qq3n0wZ2zotXpT9xLfFYvkr/S7jXeB8E0jRkhKpC3q8LcJ/kmCrTnkuAPCq4do9Q/"
+    "ytVbuAeY\n"
+    "Gg5lQybQK+"
+    "82GBqEQUA1kOHPYf3LLsoyN36G5w8iUfHxepbXE2l0cApALgLHzBq9UxhTXU5hMC1\n"
+    "ktnSCup6S4Ctk+C5XqVGcaHPfuiuHkeTTuWz0+9zaKiH6CC0/yXBSQ2a/"
+    "MxojV57634rq+v2PLY\n"
+    "be1r2nsYG13/"
+    "AFKxbfCBMcr0brGAzrGEwCG31ncx0SfBzf7S4+zoHUWWsJq3hz9oLfcBH77R9H+\n"
+    "0pA13u/qPgDp/Q6ri39JlfpXkDx+h/"
+    "msWn1L6wdO6bSbcrIbU2Q0xLnSe21kuVejJspbVS5+4bd\n"
+    "ocBAkD/orG+tP1ar67Wy7GtZTm1SCXfRsb+a18fRe38x6SG3/44H1Z3f0y2I+l6DoSXD/"
+    "8xPrDs\n"
+    "3enVu3bdnqN3R+//USSVo//"
+    "1PLohhce+gRWS0Nsby3lRgFkKxQyW7SgUh3em5Tbq2uB9wWw1wey\n"
+    "J1XGV2XYdm5k7e4WzidXY9oMwo5RZ4T6Hd1ixwfp96PWbAJBVTHzK7O6Ky5oJB1HZMqmUEFlkG"
+    "y\n"
+    "xpa4zI1Hkq31dy7bMN9BAc3HeWAnnbyxEycmuup1jiAGglZ31PyrmZ9tQg1WtNj54EHR3/"
+    "S2qTH\n"
+    "1Yc5GgD1FFtzPdWGkd2AyflogZmRmsz6PSrbXbdo+"
+    "txOrP337f3fzVo15DK2uyrTtqpBOnBKx6b\n"
+    "7MjJsz7tHWOAYP3WD6LU6cqGjFCNl1MmvLcxv6YtDTLSAqP27LrdtYHXFnJZI+"
+    "Tp3MWg68OpDPv\n"
+    "UMUM2lkQBoouKQ6swjE9Nml+1sz1PW+z6xt27zuj+skrX2ZvqR5z8kkuOfdPt43/1fMm/"
+    "grFG6f\n"
+    "Lss9JA7JG7tnZs/SfJUrfS3foJ9TvHCopJsV8nWx/t24bJn8Fo/5TjWJXMJIS+i+G36TsZ/"
+    "7Q9P\n"
+    "8ATfzfeOFofVSZv2/zvt+O3X/v65dJPjt/BiyfN1/wn0zre79nVej/ADG8ep4x2/"
+    "6Srjd6TdviF\n"
+    "52ko8m6/Ht9X1KnftEo+POwxzK8mSTF46vrH6T1/OEl5Okkl//Z/"
+    "+0uHFBob3Rvc2hvcCAzLjAA\n"
+    "OEJJTQQEAAAAAAArHAIAAAIAAhwCeAAfICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA"
+    "A\n"
+    "4QklNBCUAAAAAABD7Caa9B0wqNp2P4sxXqayFOEJJTQPqAAAAAB2wPD94bWwgdmVyc2lvbj0iM"
+    "S\n"
+    "4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUg"
+    "Q\n"
+    "29tcHV0ZXIvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9"
+    "Q\n"
+    "cm9wZXJ0eUxpc3QtMS4wLmR0ZCI+"
+    "CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk\n"
+    "+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1Ib3Jpem9udGFsUmVzPC9rZXk+"
+    "Cgk8ZGljdD\n"
+    "4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+"
+    "Y\n"
+    "29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50\n"
+    "LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+"
+    "CgkJCTxkaWN0PgoJCQkJPGtleT5jb20\n"
+    "uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUhvcml6b250YWxSZXM8L2tleT4KCQkJCTxyZWFsP"
+    "j\n"
+    "cyPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJ"
+    "C\n"
+    "QkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+"
+    "CgkJCQk8a2V5PmNv\n"
+    "bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRhdGU+"
+    "MjAwNy0wMS0zMFQ\n"
+    "yMjowODo0MVo8L2RhdGU+"
+    "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbG\n"
+    "FnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY3Q+"
+    "CgkJPC9hcnJheT4KC\n"
+    "TwvZGljdD4KCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwv\n"
+    "a2V5PgoJPGRpY3Q+"
+    "CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4\n"
+    "KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvb"
+    "S\n"
+    "5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+"
+    "CgkJPGFycmF5PgoJCQk8ZGljdD4KC\n"
+    "QkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJ\n"
+    "CQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnRpY2tldC5\n"
+    "jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+"
+    "Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW\n"
+    "5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCTxk"
+    "Y\n"
+    "XRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQ"
+    "u\n"
+    "dGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+"
+    "MDwvaW50ZWdlcj4KCQkJPC9kaWN\n"
+    "0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+"
+    "Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0Ll\n"
+    "BNU2NhbGluZzwva2V5PgoJPGRpY3Q+"
+    "CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZ\n"
+    "WF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4"
+    "K\n"
+    "CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+"
+    "CgkJPGFycmF5Pgo\n"
+    "JCQk8ZGljdD4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1TY2FsaW5nPC\n"
+    "9rZXk+"
+    "CgkJCQk8cmVhbD4xPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0L\n"
+    "mNsaWVudDwva2V5PgoJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJ"
+    "p\n"
+    "bmc+"
+    "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGR\n"
+    "hdGU+MjAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+"
+    "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC\n"
+    "50aWNrZXQuc3RhdGVGbGFnPC9rZXk+"
+    "CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY\n"
+    "3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQu\n"
+    "UE1WZXJ0aWNhbFJlczwva2V5PgoJPGRpY3Q+"
+    "CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V\n"
+    "0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0c"
+    "m\n"
+    "luZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+"
+    "CgkJPGFyc\n"
+    "mF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1WZXJ0\n"
+    "aWNhbFJlczwva2V5PgoJCQkJPHJlYWw+NzI8L3JlYWw+"
+    "CgkJCQk8a2V5PmNvbS5hcHBsZS5wcml\n"
+    "udC50aWNrZXQuY2xpZW50PC9rZXk+"
+    "CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbm\n"
+    "FnZXI8L3N0cmluZz4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZ\n"
+    "Xk+CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT4KCQkJCTxrZXk+"
+    "Y29tLmFw\n"
+    "cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZX"
+    "I\n"
+    "+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuU"
+    "G\n"
+    "FnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGluZzwva2V5PgoJPGRpY3Q+"
+    "CgkJPGtleT5jb20uYXBwb\n"
+    "GUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGl"
+    "u\n"
+    "Z21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycm"
+    "F\n"
+    "5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2\n"
+    "VGb3JtYXQuUE1WZXJ0aWNhbFNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjE8L3JlYWw+"
+    "CgkJCQk8a\n"
+    "2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+"
+    "CgkJCQk8c3RyaW5nPmNvbS5h\n"
+    "cHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnR\n"
+    "pY2tldC5tb2REYXRlPC9rZXk+"
+    "CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT\n"
+    "4KCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpb\n"
+    "nRlZ2VyPjA8L2ludGVnZXI+"
+    "CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5j\n"
+    "b20uYXBwbGUucHJpbnQuc3ViVGlja2V0LnBhcGVyX2luZm9fdGlja2V0PC9rZXk+"
+    "Cgk8ZGljdD4\n"
+    "KCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlUmVjdDwva"
+    "2\n"
+    "V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5"
+    "P\n"
+    "goJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJPGtleT5"
+    "j\n"
+    "b20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+"
+    "CgkJCQk8ZGl\n"
+    "jdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlU"
+    "m\n"
+    "VjdDwva2V5PgoJCQkJCTxhcnJheT4KCQkJCQkJPHJlYWw+"
+    "MC4wPC9yZWFsPgoJCQkJCQk8cmVhb\n"
+    "D4wLjA8L3JlYWw+CgkJCQkJCTxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+"
+    "NTc2PC9yZWFs\n"
+    "PgoJCQkJCTwvYXJyYXk+"
+    "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDw\n"
+    "va2V5PgoJCQkJCTxzdHJpbmc+"
+    "Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQ\n"
+    "kJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+"
+    "M\n"
+    "jAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+"
+    "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj\n"
+    "a2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+"
+    "CgkJCQk8L2RpY3Q\n"
+    "+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYX\n"
+    "QuUE1BZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5w"
+    "c\n"
+    "mludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21"
+    "h\n"
+    "bmFnZXI8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheT"
+    "w\n"
+    "va2V5PgoJCQk8YXJyYXk+"
+    "CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYW\n"
+    "dlRm9ybWF0LlBNQWRqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+"
+    "CgkJCQkJCTxyZ\n"
+    "WFsPi0xODwvcmVhbD4KCQkJCQkJPHJlYWw+"
+    "LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3Jl\n"
+    "YWw+CgkJCQkJCTxyZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+"
+    "Y29tLmF\n"
+    "wcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wc"
+    "m\n"
+    "ludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQu"
+    "b\n"
+    "W9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQk"
+    "J\n"
+    "CTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWd\n"
+    "lcj4wPC9pbnRlZ2VyPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5P"
+    "m\n"
+    "NvbS5hcHBsZS5wcmludC5QYXBlckluZm8uUE1QYXBlck5hbWU8L2tleT4KCQk8ZGljdD4KCQkJ"
+    "P\n"
+    "GtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20"
+    "u\n"
+    "YXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcm"
+    "l\n"
+    "udC50aWNrZXQuaXRlbUFycmF5PC9rZXk+"
+    "CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZX\n"
+    "k+"
+    "Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVBhcGVyTmFtZTwva2V5PgoJCQkJCTxzdHJpb"
+    "\n"
+    "mc+bmEtbGV0dGVyPC9zdHJpbmc+"
+    "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNs\n"
+    "aWVudDwva2V5PgoJCQkJCTxzdHJpbmc+"
+    "Y29tLmFwcGxlLnByaW50LnBtLlBvc3RTY3JpcHQ8L3N\n"
+    "0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJC"
+    "Q\n"
+    "kJCTxkYXRlPjIwMDMtMDctMDFUMTc6NDk6MzZaPC9kYXRlPgoJCQkJCTxrZXk+"
+    "Y29tLmFwcGxlL\n"
+    "nByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgo"
+    "J\n"
+    "CQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC"
+    "5\n"
+    "QYXBlckluZm8uUE1VbmFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb"
+    "2\n"
+    "0uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUu"
+    "c\n"
+    "HJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWN"
+    "r\n"
+    "ZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+"
+    "Y29tLmF\n"
+    "wcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYWdlUmVjdDwva2V5PgoJCQkJCTxhc"
+    "n\n"
+    "JheT4KCQkJCQkJPHJlYWw+MC4wPC9yZWFsPgoJCQkJCQk8cmVhbD4wLjA8L3JlYWw+"
+    "CgkJCQkJC\n"
+    "TxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+NTc2PC9yZWFsPgoJCQkJCTwvYXJyYXk+"
+    "CgkJ\n"
+    "CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbm"
+    "c\n"
+    "+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLn\n"
+    "ByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+"
+    "MjAwNy0wMS0zMFQyMjowODo0M\n"
+    "Vo8L2RhdGU+"
+    "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5\n"
+    "PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+"
+    "CgkJPC9\n"
+    "kaWN0PgoJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYXBlcl\n"
+    "JlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0"
+    "b\n"
+    "3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5"
+    "n\n"
+    "PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+"
+    "CgkJCTxhcnJ\n"
+    "heT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYW\n"
+    "RqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+"
+    "CgkJCQkJCTxyZWFsPi0xODwvcmVhb\n"
+    "D4KCQkJCQkJPHJlYWw+LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3JlYWw+"
+    "CgkJCQkJCTxy\n"
+    "ZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnR\n"
+    "pY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZ"
+    "X\n"
+    "I8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5"
+    "P\n"
+    "goJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJCTxrZXk+"
+    "Y29tLmFw\n"
+    "cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4wPC9pbnRlZ2"
+    "V\n"
+    "yPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wc"
+    "m\n"
+    "ludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+"
+    "Y29tL\n"
+    "mFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+"
+    "Y29tLmFwcGxlLnBy\n"
+    "aW50LnBtLlBvc3RTY3JpcHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2"
+    "V\n"
+    "0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+"
+    "CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcH\n"
+    "BsZS5wcmludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+"
+    "CgkJCQkJPHN0cmluZz5VU\n"
+    "yBMZXR0ZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW5"
+    "0\n"
+    "PC9rZXk+"
+    "CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5\n"
+    "nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+"
+    "CgkJCQkJPG\n"
+    "RhdGU+MjAwMy0wNy0wMVQxNzo0OTozNlo8L2RhdGU+"
+    "CgkJCQkJPGtleT5jb20uYXBwbGUucHJpb\n"
+    "nQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+"
+    "CgkJCQk8\n"
+    "L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW50LnRpY2t\n"
+    "ldC5BUElWZXJzaW9uPC9rZXk+CgkJPHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJCTxrZXk+"
+    "Y29tLm\n"
+    "FwcGxlLnByaW50LnRpY2tldC5wcml2YXRlTG9jazwva2V5PgoJCTxmYWxzZS8+"
+    "CgkJPGtleT5jb\n"
+    "20uYXBwbGUucHJpbnQudGlja2V0LnR5cGU8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcml"
+    "u\n"
+    "dC5QYXBlckluZm9UaWNrZXQ8L3N0cmluZz4KCTwvZGljdD4KCTxrZXk+"
+    "Y29tLmFwcGxlLnByaW5\n"
+    "0LnRpY2tldC5BUElWZXJzaW9uPC9rZXk+Cgk8c3RyaW5nPjAwLjIwPC9zdHJpbmc+"
+    "Cgk8a2V5Pm\n"
+    "NvbS5hcHBsZS5wcmludC50aWNrZXQucHJpdmF0ZUxvY2s8L2tleT4KCTxmYWxzZS8+"
+    "Cgk8a2V5P\n"
+    "mNvbS5hcHBsZS5wcmludC50aWNrZXQudHlwZTwva2V5PgoJPHN0cmluZz5jb20uYXBwbGUucHJ"
+    "p\n"
+    "bnQuUGFnZUZvcm1hdFRpY2tldDwvc3RyaW5nPgo8L2RpY3Q+CjwvcGxpc3Q+"
+    "CjhCSU0D6QAAAAA\n"
+    "AeAADAAAASABIAAAAAALeAkD/7v/uAwYCUgNnBSgD/"
+    "AACAAAASABIAAAAAALYAigAAQAAAGQAAA\n"
+    "ABAAMDAwAAAAF//"
+    "wABAAEAAAAAAAAAAAAAAABoCAAZAZAAAAAAACAAAAAAAAAAAAAAAAAAAAAAA\n"
+    "AAAAAAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQABAEgAAAABAAE4QklNBCYAAAAAAA4AAAAAAAA"
+    "A\n"
+    "AAAAP4AAADhCSU0EDQAAAAAABAAAAB44QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAA"
+    "A\n"
+    "AAAABADhCSU0ECgAAAAAAAQAAOEJJTScQAAAAAAAKAAEAAAAAAAAAAThCSU0D9QAAAAAASAAvZ"
+    "m\n"
+    "YAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAA"
+    "A\n"
+    "QAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP/"
+    "/\n"
+    "//////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA//"
+    "/\n"
+    "//////////////////////////"
+    "wPoAAA4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQ\n"
+    "QeAAAAAAAEAAAAADhCSU0EGgAAAAADRQAAAAYAAAAAAAAAAAAAAGQAAABkAAAACABEAFMAQwAw"
+    "A\n"
+    "DIAMwAyADUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAGQAAABkAAAAAAAAAAA"
+    "A\n"
+    "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZH"
+    "N\n"
+    "PYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAA"
+    "A\n"
+    "AAQnRvbWxvbmcAAABkAAAAAFJnaHRsb25nAAAAZAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAAB"
+    "A\n"
+    "AAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAA"
+    "G\n"
+    "b3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQ"
+    "A\n"
+    "AAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAA"
+    "A\n"
+    "BUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAAZAAAAABSZ2h0bG9u"
+    "Z\n"
+    "wAAAGQAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAE"
+    "A\n"
+    "AAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxUZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleH"
+    "R\n"
+    "URVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAPRVNsaWNlSG9yekFsaWduAAAAB2RlZmF1b"
+    "H\n"
+    "QAAAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0QWxpZ24AAAAHZGVmYXVsdAAAAAtiZ0Nv"
+    "b\n"
+    "G9yVHlwZWVudW0AAAARRVNsaWNlQkdDb2xvclR5cGUAAAAATm9uZQAAAAl0b3BPdXRzZXRsb25"
+    "n\n"
+    "AAAAAAAAAApsZWZ0T3V0c2V0bG9uZwAAAAAAAAAMYm90dG9tT3V0c2V0bG9uZwAAAAAAAAALcm"
+    "l\n"
+    "naHRPdXRzZXRsb25nAAAAAAA4QklNBBEAAAAAAAEBADhCSU0EFAAAAAAABAAAAAE4QklNBAwAA"
+    "A\n"
+    "AACfkAAAABAAAAZAAAAGQAAAEsAAB1MAAACd0AGAAB/9j/4AAQSkZJRgABAgEASABIAAD/"
+    "7QAMQ\n"
+    "WRvYmVfQ00AAv/uAA5BZG9iZQBkgAAAAAH/"
+    "2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUT\n"
+    "ExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA"
+    "4\n"
+    "ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/"
+    "AABEIAGQAZA\n"
+    "MBIgACEQEDEQH/3QAEAAf/xAE/"
+    "AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBA\n"
+    "QEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYE"
+    "y\n"
+    "BhSRobFCIyQVUsFiMzRygtFDByWSU/"
+    "Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80Y\n"
+    "nlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+"
+    "f3EQACAgECBAQDBAUGBwcGBT\n"
+    "UBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kST"
+    "V\n"
+    "KMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f"
+    "/\n"
+    "2gAMAwEAAhEDEQA/"
+    "APLtso1NRc0vP0Rok8NYyPEfijOG2ljBoAJPxKFppZtbS4Rz38kV+OPRDge\n"
+    "T89EPHBfvLjtb3P8A30K/j47cgsrYNxGpPYJpK8RtyXUlvPfsobV0GV0uippLiX3EaMb2/"
+    "rKgMB\n"
+    "1ghoiNST4BESCjjLmxqmKtvxiXQ0cd0q8E2bjIDWjk9z5I8QW8JaoHcdkUePZJtZD9p8YU/"
+    "Rsc/\n"
+    "wBNjS5zjDWjUk+SSKYaJLYq+qWeYGQ5lBPLJ3OA8wz2/wDSWni/"
+    "U3H2AXW2l2oloa0f9LcjSLeU\n"
+    "hJdb/wAyqd387Zt+DZ5SSpVh/9DzO6dw7gGPuVn6ft/"
+    "kyPkqwlxjw1Rnh24QNWjUeR5TSuDc6bg\n"
+    "fatpsJZQ3sNC4rWfkVYpbi4LAb3aANEkFLp7GHGYxuhAj4K/"
+    "hYVNDjYGzZ++eSSoSbLZjGgwxul\n"
+    "XNrPqO35FukdmzyXOQeqtqwqRg4o/SOAN9ng3/"
+    "AMzW02txZ9I+ZHKr241UOcWDaz3uLtSSPEpWu\n"
+    "rR5XPeylmyNr4BIPPCyH2Oc6T8kXNvddkPe/"
+    "VzjJPxQAJMKeIoNScrPk2MbfddXUNXvcGtPx0Xb\n"
+    "dJ6NXjOD2Dfdw6w9v5LFW+q/1WLA3Ly9LSJaz91p/"
+    "wDRjl2lOLWwAMbEJErWjRgESYieVdZhsMF\n"
+    "wMt08ldrx/vVivHaOdSgCoud9krmElpba93ASTlr/AP/R83ohr97voiJV/"
+    "Fq9QvsI+mdPgs1thc\n"
+    "BWO5C38CoOY1g78qOejLiGvknxLAyGtExp5K9uzGt9RrNw7DhRfQKKx6bZIGgPj4rPycLqWVtI"
+    "s\n"
+    "JGu5skDyTBRZtQNrb1fU8xrtpBaO4MLQxcx1sNuEjt5rMGJR9noY5hF7Wxa8aAnxVvDb6bgHH2"
+    "z\n"
+    "omk0e64ajUUXnev9Idi5rrWAux7SXNd4E/muS+rHSjm9VbPtZjj1CSJBI+g3+0uh69b+iDG/"
+    "QcD\n"
+    "u0nQCeFP6l0MZhWX/"
+    "AJ1xM+QafY1TQlY1a+WABsdXp8Sp27aBH+vZaVbC0ADlVcASwtdOolp8Ct\n"
+    "BjmtGv0uI8EmJmxkIjWkmPEKLSPiidxIgJKRbDPCSN5pJyH//S87uw/"
+    "suZ6c72iC13kVs9PdDmk\n"
+    "KllVziV3cuafc7yP0QjYFh26cqM6hsxAjIj6u6xzbDHh3R663AaceH+"
+    "5BwdruVp2PqZUA0a9yo6\n"
+    "DPQajscnXb8YQdzC8H909joiZttoxoBIa4gGOQ3uqh+z1RuD2Ds4j2n+39FNKaFMevS/"
+    "p5LPpSA\n"
+    "I8/b/ABW70THZXj11VjaIAIHgFl5VdD8AneDMaec6Lb6QAKmu7x+VSw2a3MdF/"
+    "rF9YKeh4B9OHZ\n"
+    "lpAprPH8p7v5DFwrPrV9YDa645toLjMaFo8mtcEvrhkWZHXbg7T0Q2to8o3f8AfkarEitlVTKn"
+    "Y\n"
+    "ra992QQ2wOfG57H2bg7H2fzbFKA130P6n9dHWemCx5H2mk7LgPH818f8IuhAka6ea8y/"
+    "wAWrcod\n"
+    "VyrceRhBsPae5J/Qj+sxq9KDpMuMuKBCEntnny/1CSaWxM6pIKf/0/"
+    "MvtF3pCrefTBnbOi1elP3\n"
+    "Et8Vi+Sv9LuNd4HwTSNGSEqkLerwtwn+SYKtOeS4A8Krh2j1D/"
+    "K1Vu4B5gaDmVDJtAr7zYYGoRB\n"
+    "QDWQ4c9h/"
+    "csuyjI3fobnDyJR8fF6ltcTaXRwCkAuAsfMGr1TGFNdTmEwLWS2dIK6npLgK2T4Lle\n"
+    "pUZxoc9+6K4eR5NO5bPT73NoqIfoILT/JcFJDZr8zGiNXnvrfiur6/"
+    "Y8tht7WvaexgbXf8AUrFt\n"
+    "8IExyvRusYDOsYTAIbfWdzHRJ8HN/"
+    "tLj7OgdRZawmreHP2gt9wEfvtH0f7SkDXe7+o+AOn9DquL\n"
+    "f0mV+leQPH6H+axafUvrB07ptJtyshtTZDTEudJ7bWS5V6MmyltVLn7ht2hwECQP+isb60/"
+    "Vqvr\n"
+    "tbLsa1lObVIJd9Gxv5rXx9F7fzHpIbf/jgfVnd/TLYj6XoOhJcP/zE+sOzd6dW7dt2eo3dH7/"
+    "9R\n"
+    "JJWj//"
+    "U8uiGFx76BFZLQ2xvLeVGAWQrFDJbtKBSHd6blNura4H3BbDXB7InVcZXZdh2bmTt7hbO\n"
+    "J1dj2gzCjlFnhPod3WLHB+"
+    "n3o9ZsAkFVMfMrs7orLmgkHUdkyqZQQWWQbLGlrjMjUeSrfV3Ltsw\n"
+    "30EBzcd5YCedvLETJya66nWOIAaCVnfU/"
+    "KuZn21CDVa02PngQdHf9LapMfVhzkaAPUUW3M91YaR\n"
+    "3YDJ+WiBmZGazPo9Kttdt2j63E6s/fft/d/NWjXkMra7KtO2qkE6cErHpvsyMmzPu0dY4Bg/"
+    "dYP\n"
+    "otTpyoaMUI2XUya8tzG/pi0NMtICo/"
+    "bsut21gdcWclkj5OncxaDrw6kM+9QxQzaWRAGii4pDqzC\n"
+    "MT02aX7WzPU9b7PrG3bvO6P6yStfZm+pHnPySS4590+3jf/"
+    "V8yb+CsUbp8uyz0kDskbu2dmz9J8\n"
+    "lSt9Ld+gn1O8cKikmxXydbH+3bhsmfwWj/lONYlcwkhL6L4bfpOxn/tD0/wBN/N944Wh9VJm/"
+    "b/\n"
+    "O+347df+/rl0k+O38GLJ83X/CfTOt7v2dV6P8AMbx6njHb/"
+    "pKuN3pN2+IXnaSjybr8e31fUqd+0\n"
+    "Sj487DHMryZJMXjq+sfpPX84SXk6SSX/"
+    "9kAOEJJTQQhAAAAAABVAAAAAQEAAAAPAEEAZABvAGIA\n"
+    "ZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcA"
+    "A\n"
+    "gADcALgAwAAAAAQA4QklNBAYAAAAAAAcABQAAAAEBAP/"
+    "hFWdodHRwOi8vbnMuYWRvYmUuY29tL3\n"
+    "hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0n77u/"
+    "JyBpZD0nVzVNME1wQ2VoaUh6cmVTek5UY3prY\n"
+    "zlkJz8+Cjw/YWRvYmUteGFwLWZpbHRlcnMgZXNjPSJDUiI/"
+    "Pgo8eDp4YXBtZXRhIHhtbG5zOng9\n"
+    "J2Fkb2JlOm5zOm1ldGEvJyB4OnhhcHRrPSdYTVAgdG9vbGtpdCAyLjguMi0zMywgZnJhbWV3b3"
+    "J\n"
+    "rIDEuNSc+"
+    "CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi\n"
+    "1yZGYtc3ludGF4LW5zIycgeG1sbnM6aVg9J2h0dHA6Ly9ucy5hZG9iZS5jb20vaVgvMS4wLyc+"
+    "C\n"
+    "gogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXVpZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC0"
+    "5\n"
+    "MWQ1NDAzZjkyZjknCiAgeG1sbnM6cGRmPSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz"
+    "4\n"
+    "KICA8IS0tIHBkZjpTdWJqZWN0IGlzIGFsaWFzZWQgLS0+"
+    "CiA8L3JkZjpEZXNjcmlwdGlvbj4KCi\n"
+    "A8cmRmOkRlc2NyaXB0aW9uIGFib3V0PSd1dWlkOjIyZDAyYjBhLWIyNDktMTFkYi04YWY4LTkx"
+    "Z\n"
+    "DU0MDNmOTJmOScKICB4bWxuczpwaG90b3Nob3A9J2h0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9"
+    "z\n"
+    "aG9wLzEuMC8nPgogIDwhLS0gcGhvdG9zaG9wOkNhcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwvcm"
+    "R\n"
+    "mOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMGEtY"
+    "j\n"
+    "I0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcD0naHR0cDovL25zLmFkb2Jl"
+    "L\n"
+    "mNvbS94YXAvMS4wLyc+"
+    "CiAgPCEtLSB4YXA6RGVzY3JpcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwv\n"
+    "cmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMG"
+    "E\n"
+    "tYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuY"
+    "W\n"
+    "RvYmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpw"
+    "a\n"
+    "G90b3Nob3A6MjJkMDJiMDYtYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5PC94YXBNTTpEb2N"
+    "1\n"
+    "bWVudElEPgogPC9yZGY6RGVzY3JpcHRpb24+"
+    "CgogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXV\n"
+    "pZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC05MWQ1NDAzZjkyZjknCiAgeG1sbnM6ZGM9J2h0d"
+    "H\n"
+    "A6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJz4KICA8ZGM6ZGVzY3JpcHRpb24+"
+    "CiAgIDxyZ\n"
+    "GY6QWx0PgogICAgPHJkZjpsaSB4bWw6bGFuZz0neC1kZWZhdWx0Jz4gICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgPC9yZGY6bGk+"
+    "CiAgIDwvcmRmOkFsdD4KICA8L2RjOmRlc2NyaXB0aW9\n"
+    "uPgogPC9yZGY6RGVzY3JpcHRpb24+Cgo8L3JkZjpSREY+"
+    "CjwveDp4YXBtZXRhPgogICAgICAgIC\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "A\n"
+    "ogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg"
+    "I\n"
+    "CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICA"
+    "g\n"
+    "ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC"
+    "A\n"
+    "gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgI"
+    "C\n"
+    "AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0ndyc/"
+    "P\n"
+    "v/uAA5BZG9iZQBkQAAAAAH/"
+    "2wCEAAQDAwMDAwQDAwQGBAMEBgcFBAQFBwgGBgcGBggKCAkJCQkI\n"
+    "CgoMDAwMDAoMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBAUFCAcIDwoKDxQODg4UFA4ODg4UEQwMDA"
+    "w\n"
+    "MEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/"
+    "AABEIAGQAZAMBEQACEQEDEQ\n"
+    "H/3QAEAA3/"
+    "xAGiAAAABwEBAQEBAAAAAAAAAAAEBQMCBgEABwgJCgsBAAICAwEBAQEBAAAAAAAAA\n"
+    "AEAAgMEBQYHCAkKCxAAAgEDAwIEAgYHAwQCBgJzAQIDEQQABSESMUFRBhNhInGBFDKRoQcVsUI"
+    "j\n"
+    "wVLR4TMWYvAkcoLxJUM0U5KismNzwjVEJ5OjszYXVGR0w9LiCCaDCQoYGYSURUaktFbTVSga8u"
+    "P\n"
+    "zxNTk9GV1hZWltcXV5fVmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9zhIWGh4iJiouMjY6PgpOUlZa"
+    "X\n"
+    "mJmam5ydnp+"
+    "So6SlpqeoqaqrrK2ur6EQACAgECAwUFBAUGBAgDA20BAAIRAwQhEjFBBVETYSIGc\n"
+    "YGRMqGx8BTB0eEjQhVSYnLxMyQ0Q4IWklMlomOywgdz0jXiRIMXVJMICQoYGSY2RRonZHRVN/"
+    "Kj\n"
+    "s8MoKdPj84SUpLTE1OT0ZXWFlaW1xdXl9UZWZnaGlqa2xtbm9kdXZ3eHl6e3x9fn9zhIWGh4iJ"
+    "i\n"
+    "ouMjY6Pg5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6vr/2gAMAwEAAhEDEQA/"
+    "APBnplwPAdR+GB\n"
+    "KY6dYtNG1w39yh4+xb+zIksgEfFaRSSoIx8f7RPRRkSWQimM+lRmwWVXFWYigHxUUVoMiJM+"
+    "Fj0\n"
+    "tg0RBegLE0Wu+3c+GTBazFCGI7HtSp9slbFYYzyoBsegw2hY1Afl3wqqRqahk+"
+    "0tDgKpgu4DAUU\n"
+    "+HY+GRS2ePiMKtUB3G+KGuONq//"
+    "Q8OzpFbW5WnxMop4k9crG5ZnZNJkEOn21utVRYw7HxZtz+OR\n"
+    "vdsrZ2lRtci4aVxFEQA0neg/"
+    "ZXxJpTITNNuOFss0vSotYNvZ2qGRkPKSTqiU8Sdqk5SZU5Ix8XJ\n"
+    "NNZ8k6bp8TtM73OputUtYq0Unux/"
+    "hkRkJOzZLCAN2KR+VpbtSkCBaDnIzdlWu59u+XeJTjeASk8\n"
+    "+juZOESEAVqx8BvU/"
+    "PJibScTrTy09560hkWOGFd2YgFnPQKD19zhOSkxw2l8Vm6XAiYb8gg+k5O\n"
+    "9mnhoon9H3cs5s7WF5pp29OGGMFndyaAKBuTiEEPQLD8h/"
+    "NDmNdYlttNkYjlbFjcXCr3LLH8II8\n"
+    "C2WUGviZvon/OPWkm3RNSv72SYllMkKxQRV67CQMSKYQAxMkR/"
+    "wBC56d61P0heel4cYuVOXWvTp\n"
+    "h4Qjjf/9Hw5qBYyISaqjBV+QpvkAzKcki4HomnIxck/"
+    "wBhtlR2bhunvlDywddMUl4zW+kQ9FQ8X\n"
+    "nfuSewrtmPkycPvc/"
+    "DhMhvyegXOrWWhmLQPKlsj6xIAiLCoZkY96nv7npmJvI2XOjQFMl0fyRqM\n"
+    "NoxvZvrGt33wlATwiMnVnY1LEdSfuyXF3KIDmUu88w2XlnTl8raAlb2ZFfVL0jdYRtQnxc7BfD"
+    "C\n"
+    "OaJR7nm3me5tdOtjbMvp3ZRXkV6chVQRX79hmVjgZG+"
+    "jgZ5jHGhzecXF5LPL6jEjstSSaDM51Ka\n"
+    "6MZ9S1C0sEBe8uZo4YCBXdjxGw60wEWyEqfUHkT8vLXRJFuLdTcaqfhlvWUErtukZ3ABPUjIXT"
+    "E\n"
+    "m3rGmeV2Tk5UKz/AG/E/wAcgZKya20C3b02kjYtH8AqCygbkUH0nLYlgUb+gbWtPbpXt/"
+    "n2ybB/\n"
+    "/9Lw4oaVxGd+PxH3qBkGaY3KyiSP01IkiUclH8sg+LKydm6INvZvKsFu+"
+    "kWtvD8LRoFNRup6moO\n"
+    "aqd277HsGW+XPLmn6XM17FF6l7vW4fd2Zuu+"
+    "RFls2tmUNrLJb7TSBertGQGqetDkxE0na0pvtHs\n"
+    "QkszWyiGAG5laYlnkeMVHJj8sA5rPk+SvMepTalqlxd3B5zTOXdj/"
+    "MxqafLpm5xioh5nPK5kpRG\n"
+    "pkcKAST0A6k5NpfUP5K/ki1ssHmHzF+71KRQ8Nud/Qibb/kYw6/"
+    "yjbrXISlSH07YaHbWyxx2kXE\n"
+    "KACB2zHJtLI7XSelBRvH2xCpvaaTDHXkOTVBPcUG2479RlsdmJVPRtvV+ylenQ0y62FP/"
+    "9PxRpo\n"
+    "WG5FxKKxKFDA+GVS5NsebLdFsRePc3siVW4f4QR0QVAGYeSXR2unhtZ6s60K6jt+MMSFwtF2+"
+    "xX\n"
+    "wr7eGUGLlRPQMsE2vxQm7itxKg3VCfT2+"
+    "nb8cDYaCDtfOXmCCcROrQrUhkkCHYn6emRMqZxjbLd\n"
+    "F1+W/"
+    "4xajHzjNCtQKMffETWUdngX5p+QZ9A8xS6hbo0ui37NNDPT7DOalHpsCD08Rmyw5ARTpdV\n"
+    "gIPEF35MeRn80ed4S5EdrpKm9kZ15K0iH92hB7Me/tmS60vt/"
+    "QrCYyekiBdgSTXcjqV9q9MokFD\n"
+    "N7S3aFVVR8RoK9zldqndvAY6nffr/AGYQqLhjdpCoIAZW22HavU/LJBUP9WblX0xTw7fOmWsX/"
+    "9\n"
+    "Tw7FdvMqWkQ3Z1qfED+mQIbI77PX/"
+    "LFis9vBajZm2Y+x65rMh3t30Bsze400aVaIbSLk6r8CMRT\n"
+    "l/"
+    "NmOcllnGDD9Y8uecNfEEiXrMgDGWAyGOOu5WlB+"
+    "vMrHODTlxZCdjsyFdB006VpVtLasurQxBL\n"
+    "64WiLI4/"
+    "aFT1ANOXemV5piR2b9NiljB4yyHy9CLOVI5GJhB+CvXY9R8xmINzs5HNZ+Z96BZpbxA\n"
+    "fVJo39UFefwopYgL4nMiMd2qZoIn/AJx00u3t/"
+    "Lt7qpp9Yv5GLf5MUTERqfbvmzBeezjd9H+VlL\n"
+    "wSQzBqsvOGQD7L12rXsemPNxmXQSxxIPU2nFV4HYqR1xEUWj4ZAxBryr2G+"
+    "J2VGDZlLrxUH6KZA\n"
+    "Fkqb15VFelfwy+2FP8A/"
+    "9Xxlf6AdA182Yk9eFeLxSjoVfcfSMo4uIOfkweFOnpvlWYrLEwNFAA+\n"
+    "nMOYdrhFvQLeSO7coBXiK8iKiv07Zj8Ac4QtNrW1njUcKcT+yAR/"
+    "xGmR4WcsStLpTuPU9IFaEsV\n"
+    "BP3k4m2AgBzSwyQNcIwNTE1aI3wnam9O2Ug7s5Ckk/"
+    "NDndeVXa2H78MqqV6jmeBp9+ZWKXqDjZ4\n"
+    "+gvVvy30qCy0qzsLRBCnBI2VdgUTqPvOZ7y+Q7pz+bn5q6d+VflZxZlJ/"
+    "NN4ypptk5qtB9qRwDX\n"
+    "gn/AAx2y2ItpfKFv+eH5qNeTajJ5ovVaVywSqvEtTUKqupAA6D2y0BNPtv/AJx//"
+    "M5PzL8mJeXT\n"
+    "L+ndPf6rqarSpkAqsnEAAeoN6DpkJRYci9lROSgSUUH9o9K5Tw0ztfSHnXkOtK9q+PHwydq//"
+    "9b\n"
+    "yxrVoZNBtNSA5zRMPXmH8j0CLXuBmHE+"
+    "qneamHpEuqYeV7pzFVTRgQK5XMNmnlb1vyyY5QA1OwJ\n"
+    "+eUF2seTOLu5s7azVIVAkpVn/"
+    "hhnIALG73Yz5jvb1dICqzpDNIqyFD8SxH7R28cxibZCiWOsdJs\n"
+    "PTM6XNstPhnkjIhcHuJBVfvOCiUSn0TfWrTTLjyw8guA/PifTO3xcxxA8a5ZAbimvJP0m3p/"
+    "kFF\n"
+    "WxhmpWQJ9NW3zZPHz5vlb/nIDVbrWfzO1RJhxGnpDaRL/"
+    "khA1T7ktmSOTAJhZaAUtLawsbayl8v\n"
+    "xWi3Gpay0cF3HPcFRJJHJMXVrcJ8UaAFG5LWjF8tAYW9H/wCcOo9bTzxrt/"
+    "owkTyksZW5gkIKvI\n"
+    "7k26nvyReRJHyyBWT7dWQyOWlbnK2526e1O1MqIUFE84uPLkOdK9RXI0E2/wD/1/DA1bURZLY/"
+    "W\n"
+    "ZDZqwb0eXw7dMgIi7bjllVXsz7yNcfWC0Vd3Ip92Y2UOz0cnsPlwyx8xQ/"
+    "u24sMxCadoJp9LOXk\n"
+    "VX/"
+    "uwRUE0BI8cokbLMyoKouHu2MaKGXw7fLDwgoGSkbHpaNZyLLHRSKcFFQQRvUdMlwUFOQyLzr\n"
+    "ztpCaba6fPau4ijv4OURY8AjVFKV7ZZiO+7Vnh6XvXkSWNbW2WTb92KDxIFMzwHlZc3zX+"
+    "fuizW\n"
+    "f5p3ty8XGDU4YLmCQiisyII3+4rvl8UB5ffEghRGvOm7AbnvWvjk1fen/"
+    "ONPldPKP5aWOpPCfr2\n"
+    "uE31y6q2wbaMEn+VAMDSdyzrzj+avlHyTp0l/r2rxWFuHWJuIeacu4qFCRgsajfBwsty89/"
+    "6Gr/\n"
+    "ACa9an+JL/hSnrfoubhXwpXpjwhaL//"
+    "Q8E1AqtcAZMs8l6i1nqMa1oSVP0VynKLDmaWdSfQXl69\n"
+    "jF1Jv8MhDb5rpB3AO7INRRLhhGp4R05FgaGvTMU8200xS70zVDMRp2pTIOvBmB3PgQP15kxIcn"
+    "D\n"
+    "LH/"
+    "EEz0rRvOJhldr9pQtCqyd6VrShGTqw5d4ARv9jHfOGl+ZJNMluLkyenaFbiRdqFYW5nrWuwO\n"
+    "MKB5MdSMRxnhlu9N8p6lLFpti63FUjCtFJTrDKvse2bEDZ4XJ9RZB+YPli2/"
+    "Mjy5bxoUi1a0YS2\n"
+    "85UOwIXiy9jRu+TBppfOF1+V3m22vrdpNPM8cs/oo0VJlUqQPjValR3+IZNNvtLS9Yu9Mi0/"
+    "TJr\n"
+    "kyp6QhWVVCIWRATsKBemwwFrDzT87fybs/"
+    "wA1bW21PRb+DTvNlgGSRp6iC8i3KJJx+y6n7D0Pwm\n"
+    "hxBZXT55/6Fi/Nf0PW+qWXq+t6X1X67F6vD/ftK04V/wBl344U8b//"
+    "0fBapxheVh9ocV+nviqY2\n"
+    "/qQJDew/"
+    "bioWHiuQ8m0bbvaPKGtQ6jaxSo9JloCK75gZI0Xb4sgkHo8MouoAvP94BsRmGY7uWJU\n"
+    "gzbypOQpNOvIdK4Nw2WCE2tXulTkjEEbdafgclxMhFBas93dwyQzsWDghlJFONKHJCZtjOFBJf"
+    "y\n"
+    "j1y9vPL9zpbIs0WkXL2sUjA8hDXlGCRXtt07ZuYvL5KJeo6bfajbkzWkcToR8dqshZ6in2fhNK"
+    "/\n"
+    "PDTUlXmHVvMdr5o0v9H2kdrqGpfu7m0nkY87Uf7tkKAU4/"
+    "s03ynLkEBbfihx7dGT6va67LbRMNR\n"
+    "aKOBuUTKgIBXoK1BOYR1M3aQ0mOt9yxUeZNdtJhFapLqMluSXkg5oxJrUMW5KevQ9MmNXXNqOi"
+    "H\n"
+    "Rr/Hmv8A1r9I/oj95w+r+j9Yf1+NP5+nXtTD+dF8tkfkOlv/0vC3ph7f0/"
+    "alcVTbS4A8QibuKb5\n"
+    "RI05EBYRFpdX3ly79a2qYCavH/"
+    "EY7TCYyMD5PSdD8+wXUSn1ArDqOhBzFlipz4ZwWbaV5htbsgF\n"
+    "qg9crMXKErGyYwajFGzxyHlGSePbbwyqg5UZlCaxrFpaWU95LIqrEjMAT4Dp9OShGy1ZslBhv/"
+    "A\n"
+    "Dj9rd/a+aL+xUK+m38L3d0HrxRo2HFtu5D8c27y8t30raarbWkU+u6g4gsNORn+EcUaSh2Pc0/"
+    "4\n"
+    "lgtAjezzbT9SutY1i782al8Nxdyotqh6xWybIg+jc5q8s+I27bFDgFPQp9RE+nrag70+"
+    "L6crrZu\n"
+    "4jajokdv6LW/Dii1Wo61PXKQN3KPK0L+h4/rnD/K5V78a5LhXxd3/0/"
+    "DMXXtwxVNtL9Xkaf3f7N\n"
+    "etfbKMjdjtkZ9D6ufrlK0+HpX8coF9HJ26sXvfqXrf7i/U+uften/d/"
+    "wCyrmQL6uOav0pvpP8Ai\n"
+    "b1F+rV59+vH6a5XLhcjH4nRmY/xpxHP0/UptWvT6Mx/RbmjxWK+aP8AFf1M/"
+    "pCv1Kvxen9inavf\n"
+    "MrFwXtzcLUeLXq5Mv/I3nz1b0v8AjofuKVry9KrUpTanOlf9jmQ68va/zH9b/COn/o7/"
+    "AI431mP\n"
+    "65SvLh+zWvbl9rMfNfC34K4kmj9T6lD6FKclp/DNYXZx5srsPrHor6nXvkgxTPS/"
+    "U+rv6dPU5mt\n"
+    "fngFN5ulv+l/pL/Lp/scerHo//2Q==\n";
 
 static std::string gCommandLine;
 
@@ -901,87 +1351,85 @@
   char unescaped[64 * 1024];
 
   // unescape that massive blob above
-  size_t size = Base64Unescape(SpecificTest,
-                            sizeof(SpecificTest),
-                            unescaped,
-                            sizeof(unescaped));
+  size_t size = Base64Unescape(SpecificTest, sizeof(SpecificTest), unescaped,
+                               sizeof(unescaped));
 
   EXPECT_EQ(size, sizeof(testbase64));
   EXPECT_EQ(0, memcmp(testbase64, unescaped, sizeof(testbase64)));
 }
 
-bool DecodeTest(const char* encoded, size_t expect_unparsed,
-                const char* decoded, Base64::DecodeFlags flags)
-{
+bool DecodeTest(const char* encoded,
+                size_t expect_unparsed,
+                const char* decoded,
+                Base64::DecodeFlags flags) {
   std::string result;
   size_t consumed = 0, encoded_len = strlen(encoded);
-  bool success = Base64::DecodeFromArray(encoded, encoded_len, flags,
-                                         &result, &consumed);
+  bool success =
+      Base64::DecodeFromArray(encoded, encoded_len, flags, &result, &consumed);
   size_t unparsed = encoded_len - consumed;
-  EXPECT_EQ(expect_unparsed, unparsed) << "\"" << encoded
-                                       << "\" -> \"" << decoded
-                                       << "\"";
+  EXPECT_EQ(expect_unparsed, unparsed)
+      << "\"" << encoded << "\" -> \"" << decoded << "\"";
   EXPECT_STREQ(decoded, result.c_str());
   return success;
 }
 
-#define Flags(x,y,z) \
+#define Flags(x, y, z) \
   Base64::DO_PARSE_##x | Base64::DO_PAD_##y | Base64::DO_TERM_##z
 
 TEST(Base64, DecodeParseOptions) {
   // Trailing whitespace
-  EXPECT_TRUE (DecodeTest("YWJjZA== ", 1, "abcd", Flags(STRICT, YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA== ", 0, "abcd", Flags(WHITE,  YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA== ", 0, "abcd", Flags(ANY,    YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA== ", 1, "abcd", Flags(STRICT, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA== ", 0, "abcd", Flags(WHITE, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA== ", 0, "abcd", Flags(ANY, YES, CHAR)));
 
   // Embedded whitespace
   EXPECT_FALSE(DecodeTest("YWJjZA= =", 3, "abcd", Flags(STRICT, YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA= =", 0, "abcd", Flags(WHITE,  YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA= =", 0, "abcd", Flags(ANY,    YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA= =", 0, "abcd", Flags(WHITE, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA= =", 0, "abcd", Flags(ANY, YES, CHAR)));
 
   // Embedded non-base64 characters
   EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(STRICT, YES, CHAR)));
-  EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(WHITE,  YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA=*=", 0, "abcd", Flags(ANY,    YES, CHAR)));
+  EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(WHITE, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA=*=", 0, "abcd", Flags(ANY, YES, CHAR)));
 
   // Unexpected padding characters
-  EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a",    Flags(STRICT, YES, CHAR)));
-  EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a",    Flags(WHITE,  YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YW=JjZA==", 0, "abcd", Flags(ANY,    YES, CHAR)));
+  EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a", Flags(STRICT, YES, CHAR)));
+  EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a", Flags(WHITE, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YW=JjZA==", 0, "abcd", Flags(ANY, YES, CHAR)));
 }
 
 TEST(Base64, DecodePadOptions) {
   // Padding
-  EXPECT_TRUE (DecodeTest("YWJjZA==",  0, "abcd", Flags(STRICT, YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA==",  0, "abcd", Flags(STRICT, ANY, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA==",  2, "abcd", Flags(STRICT, NO,  CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA==", 0, "abcd", Flags(STRICT, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA==", 0, "abcd", Flags(STRICT, ANY, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA==", 2, "abcd", Flags(STRICT, NO, CHAR)));
 
   // Incomplete padding
-  EXPECT_FALSE(DecodeTest("YWJjZA=",   1, "abcd", Flags(STRICT, YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA=",   1, "abcd", Flags(STRICT, ANY, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA=",   1, "abcd", Flags(STRICT, NO,  CHAR)));
+  EXPECT_FALSE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, ANY, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, NO, CHAR)));
 
   // No padding
-  EXPECT_FALSE(DecodeTest("YWJjZA",    0, "abcd", Flags(STRICT, YES, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA",    0, "abcd", Flags(STRICT, ANY, CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJjZA",    0, "abcd", Flags(STRICT, NO,  CHAR)));
+  EXPECT_FALSE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, YES, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, ANY, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, NO, CHAR)));
 }
 
 TEST(Base64, DecodeTerminateOptions) {
   // Complete quantum
-  EXPECT_TRUE (DecodeTest("YWJj",      0, "abc",  Flags(STRICT, NO,  BUFFER)));
-  EXPECT_TRUE (DecodeTest("YWJj",      0, "abc",  Flags(STRICT, NO,  CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJj",      0, "abc",  Flags(STRICT, NO,  ANY)));
+  EXPECT_TRUE(DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, BUFFER)));
+  EXPECT_TRUE(DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, ANY)));
 
   // Complete quantum with trailing data
-  EXPECT_FALSE(DecodeTest("YWJj*",     1, "abc",  Flags(STRICT, NO,  BUFFER)));
-  EXPECT_TRUE (DecodeTest("YWJj*",     1, "abc",  Flags(STRICT, NO,  CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJj*",     1, "abc",  Flags(STRICT, NO,  ANY)));
+  EXPECT_FALSE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, BUFFER)));
+  EXPECT_TRUE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, ANY)));
 
   // Incomplete quantum
-  EXPECT_FALSE(DecodeTest("YWJ",       0, "ab",   Flags(STRICT, NO,  BUFFER)));
-  EXPECT_FALSE(DecodeTest("YWJ",       0, "ab",   Flags(STRICT, NO,  CHAR)));
-  EXPECT_TRUE (DecodeTest("YWJ",       0, "ab",   Flags(STRICT, NO,  ANY)));
+  EXPECT_FALSE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, BUFFER)));
+  EXPECT_FALSE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, CHAR)));
+  EXPECT_TRUE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, ANY)));
 }
 
 TEST(Base64, GetNextBase64Char) {
diff --git a/rtc_base/basictypes.h b/rtc_base/basictypes.h
deleted file mode 100644
index 42226e7..0000000
--- a/rtc_base/basictypes.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *  Copyright 2004 The WebRTC 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 RTC_BASE_BASICTYPES_H_
-#define RTC_BASE_BASICTYPES_H_
-
-#include <stddef.h>  // for NULL, size_t
-#include <stdint.h>  // for uintptr_t and (u)int_t types.
-
-// Detect compiler is for x86 or x64.
-#if defined(__x86_64__) || defined(_M_X64) || \
-    defined(__i386__) || defined(_M_IX86)
-#define CPU_X86 1
-#endif
-
-// Detect compiler is for arm.
-#if defined(__arm__) || defined(_M_ARM)
-#define CPU_ARM 1
-#endif
-
-#if defined(CPU_X86) && defined(CPU_ARM)
-#error CPU_X86 and CPU_ARM both defined.
-#endif
-
-#if !defined(RTC_ARCH_CPU_BIG_ENDIAN) && !defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
-// x86, arm or GCC provided __BYTE_ORDER__ macros
-#if defined(CPU_X86) || defined(CPU_ARM) ||                             \
-  (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-#define RTC_ARCH_CPU_LITTLE_ENDIAN
-#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#define RTC_ARCH_CPU_BIG_ENDIAN
-#else
-#error RTC_ARCH_CPU_BIG_ENDIAN or RTC_ARCH_CPU_LITTLE_ENDIAN should be defined.
-#endif
-#endif
-
-#if defined(RTC_ARCH_CPU_BIG_ENDIAN) && defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
-#error RTC_ARCH_CPU_BIG_ENDIAN and RTC_ARCH_CPU_LITTLE_ENDIAN both defined.
-#endif
-
-#if defined(WEBRTC_WIN)
-typedef int socklen_t;
-#endif
-
-// The following only works for C++
-#ifdef __cplusplus
-
-#ifndef ALIGNP
-#define ALIGNP(p, t)                                             \
-  (reinterpret_cast<uint8_t*>(((reinterpret_cast<uintptr_t>(p) + \
-  ((t) - 1)) & ~((t) - 1))))
-#endif
-
-#define RTC_IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1)))
-
-// Use these to declare and define a static local variable that gets leaked so
-// that its destructors are not called at exit.
-#define RTC_DEFINE_STATIC_LOCAL(type, name, arguments) \
-  static type& name = *new type arguments
-
-#endif  // __cplusplus
-
-#endif  // RTC_BASE_BASICTYPES_H_
diff --git a/rtc_base/basictypes_unittest.cc b/rtc_base/basictypes_unittest.cc
deleted file mode 100644
index a8b0533..0000000
--- a/rtc_base/basictypes_unittest.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Copyright 2012 The WebRTC 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.
- */
-
-#include "rtc_base/basictypes.h"
-
-#include "rtc_base/gunit.h"
-
-namespace rtc {
-
-TEST(BasicTypesTest, Endian) {
-  uint16_t v16 = 0x1234u;
-  uint8_t first_byte = *reinterpret_cast<uint8_t*>(&v16);
-#if defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
-  EXPECT_EQ(0x34u, first_byte);
-#elif defined(RTC_ARCH_CPU_BIG_ENDIAN)
-  EXPECT_EQ(0x12u, first_byte);
-#endif
-}
-
-TEST(BasicTypesTest, SizeOfConstants) {
-  EXPECT_EQ(8u, sizeof(INT64_C(0)));
-  EXPECT_EQ(8u, sizeof(UINT64_C(0)));
-  EXPECT_EQ(8u, sizeof(INT64_C(0x1234567887654321)));
-  EXPECT_EQ(8u, sizeof(UINT64_C(0x8765432112345678)));
-}
-
-// Test CPU_ macros
-#if !defined(CPU_ARM) && defined(__arm__)
-#error expected CPU_ARM to be defined.
-#endif
-#if !defined(CPU_X86) && (defined(WEBRTC_WIN) || defined(WEBRTC_MAC) && !defined(WEBRTC_IOS))
-#error expected CPU_X86 to be defined.
-#endif
-#if !defined(RTC_ARCH_CPU_LITTLE_ENDIAN) && \
-  (defined(WEBRTC_WIN) || defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) || defined(CPU_X86))
-#error expected RTC_ARCH_CPU_LITTLE_ENDIAN to be defined.
-#endif
-
-// TODO(fbarchard): Test all macros in basictypes.h
-
-}  // namespace rtc
diff --git a/rtc_base/bind.h b/rtc_base/bind.h
index b9f98b9..9f225f1 100644
--- a/rtc_base/bind.h
+++ b/rtc_base/bind.h
@@ -77,7 +77,10 @@
 // matches to the function prototype, but the parameters to bind have
 // references stripped. This trick allows the compiler to dictate the Bind
 // parameter types rather than deduce them.
-template <class T> struct identity { typedef T type; };
+template <class T>
+struct identity {
+  typedef T type;
+};
 
 // IsRefCounted<T>::value will be true for types that can be used in
 // rtc::scoped_refptr<T>, i.e. types that implements nullary functions AddRef()
@@ -88,8 +91,12 @@
   // This is a complex implementation detail done with SFINAE.
 
   // Define types such that sizeof(Yes) != sizeof(No).
-  struct Yes { char dummy[1]; };
-  struct No { char dummy[2]; };
+  struct Yes {
+    char dummy[1];
+  };
+  struct No {
+    char dummy[2];
+  };
   // Define two overloaded template functions with return types of different
   // size. This way, we can use sizeof() on the return type to determine which
   // function the compiler would have chosen. One function will be preferred
@@ -98,9 +105,10 @@
   // preferred function.
   template <typename R>
   static Yes test(R* r, decltype(r->AddRef(), r->Release(), 42));
-  template <typename C> static No test(...);
+  template <typename C>
+  static No test(...);
 
-public:
+ public:
   // Trick the compiler to tell if it's possible to call AddRef() and Release().
   static const bool value = sizeof(test<T>((T*)nullptr, 42)) == sizeof(Yes);
 };
diff --git a/rtc_base/bind_unittest.cc b/rtc_base/bind_unittest.cc
index 8703be4..ed0913f 100644
--- a/rtc_base/bind_unittest.cc
+++ b/rtc_base/bind_unittest.cc
@@ -24,10 +24,20 @@
 
 struct MethodBindTester {
   void NullaryVoid() { ++call_count; }
-  int NullaryInt() { ++call_count; return 1; }
-  int NullaryConst() const { ++call_count; return 2; }
+  int NullaryInt() {
+    ++call_count;
+    return 1;
+  }
+  int NullaryConst() const {
+    ++call_count;
+    return 2;
+  }
   void UnaryVoid(int dummy) { ++call_count; }
-  template <class T> T Identity(T value) { ++call_count; return value; }
+  template <class T>
+  T Identity(T value) {
+    ++call_count;
+    return value;
+  }
   int UnaryByPointer(int* value) const {
     ++call_count;
     return ++(*value);
@@ -36,7 +46,10 @@
     ++call_count;
     return ++const_cast<int&>(value);
   }
-  int Multiply(int a, int b) const { ++call_count; return a * b; }
+  int Multiply(int a, int b) const {
+    ++call_count;
+    return a * b;
+  }
   void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
     EXPECT_TRUE(object.get() != nullptr);
   }
@@ -44,13 +57,17 @@
   mutable int call_count;
 };
 
-struct A { int dummy; };
-struct B: public RefCountInterface { int dummy; };
-struct C: public A, B {};
+struct A {
+  int dummy;
+};
+struct B : public RefCountInterface {
+  int dummy;
+};
+struct C : public A, B {};
 struct D {
   int AddRef();
 };
-struct E: public D {
+struct E : public D {
   int Release();
 };
 struct F {
@@ -66,9 +83,15 @@
   int ref_count_;
 };
 
-int Return42() { return 42; }
-int Negate(int a) { return -a; }
-int Multiply(int a, int b) { return a * b; }
+int Return42() {
+  return 42;
+}
+int Negate(int a) {
+  return -a;
+}
+int Multiply(int a, int b) {
+  return a * b;
+}
 
 }  // namespace
 
@@ -76,7 +99,8 @@
 // compile time.
 #define EXPECT_IS_CAPTURED_AS_PTR(T)                              \
   static_assert(is_same<detail::PointerType<T>::type, T*>::value, \
-                "PointerType")
+                "PointerTyp"                                      \
+                "e")
 #define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T)                        \
   static_assert(                                                      \
       is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
@@ -206,7 +230,9 @@
 
 namespace {
 
-const int* Ref(const int& a) { return &a; }
+const int* Ref(const int& a) {
+  return &a;
+}
 
 }  // anonymous namespace
 
diff --git a/rtc_base/bitbuffer.cc b/rtc_base/bitbuffer.cc
index 86247af..025cfe1 100644
--- a/rtc_base/bitbuffer.cc
+++ b/rtc_base/bitbuffer.cc
@@ -200,8 +200,8 @@
   return true;
 }
 
-void BitBuffer::GetCurrentOffset(
-    size_t* out_byte_offset, size_t* out_bit_offset) {
+void BitBuffer::GetCurrentOffset(size_t* out_byte_offset,
+                                 size_t* out_bit_offset) {
   RTC_CHECK(out_byte_offset != nullptr);
   RTC_CHECK(out_bit_offset != nullptr);
   *out_byte_offset = byte_offset_;
@@ -219,8 +219,7 @@
 }
 
 BitBufferWriter::BitBufferWriter(uint8_t* bytes, size_t byte_count)
-    : BitBuffer(bytes, byte_count), writable_bytes_(bytes) {
-}
+    : BitBuffer(bytes, byte_count), writable_bytes_(bytes) {}
 
 bool BitBufferWriter::WriteUInt8(uint8_t val) {
   return WriteBits(val, sizeof(uint8_t) * 8);
@@ -251,8 +250,8 @@
   size_t remaining_bits_in_current_byte = 8 - bit_offset_;
   size_t bits_in_first_byte =
       std::min(bit_count, remaining_bits_in_current_byte);
-  *bytes = WritePartialByte(
-      HighestByte(val), bits_in_first_byte, *bytes, bit_offset_);
+  *bytes = WritePartialByte(HighestByte(val), bits_in_first_byte, *bytes,
+                            bit_offset_);
   if (bit_count <= remaining_bits_in_current_byte) {
     // Nothing left to write, so quit early.
     return ConsumeBits(total_bits);
diff --git a/rtc_base/bitbuffer.h b/rtc_base/bitbuffer.h
index 8519414..146577a 100644
--- a/rtc_base/bitbuffer.h
+++ b/rtc_base/bitbuffer.h
@@ -11,8 +11,8 @@
 #ifndef RTC_BASE_BITBUFFER_H_
 #define RTC_BASE_BITBUFFER_H_
 
-#include <stdint.h>  // For integer types.
 #include <stddef.h>  // For size_t.
+#include <stdint.h>  // For integer types.
 
 #include "rtc_base/constructormagic.h"
 
diff --git a/rtc_base/bitbuffer_unittest.cc b/rtc_base/bitbuffer_unittest.cc
index abf7232..a3f140f 100644
--- a/rtc_base/bitbuffer_unittest.cc
+++ b/rtc_base/bitbuffer_unittest.cc
@@ -165,8 +165,8 @@
   EXPECT_EQ(0u, bit_offset);
   EXPECT_FALSE(buffer.Seek(4, 1));
 
-  // Disable death test on Android because it relies on fork() and doesn't play
-  // nicely.
+// Disable death test on Android because it relies on fork() and doesn't play
+// nicely.
 #if GTEST_HAS_DEATH_TEST
 #if !defined(WEBRTC_ANDROID)
   // Passing a null out parameter is death.
diff --git a/rtc_base/buffer_unittest.cc b/rtc_base/buffer_unittest.cc
index e3b7d46..ae976f1 100644
--- a/rtc_base/buffer_unittest.cc
+++ b/rtc_base/buffer_unittest.cc
@@ -208,16 +208,16 @@
   EXPECT_EQ(buf.size(), 15u);
   EXPECT_EQ(buf.capacity(), 15u);
   EXPECT_FALSE(buf.empty());
-  const char *data = buf.data<char>();
+  const char* data = buf.data<char>();
   buf.Clear();
   EXPECT_EQ(buf.size(), 0u);
-  EXPECT_EQ(buf.capacity(), 15u);  // Hasn't shrunk.
-  EXPECT_EQ(buf.data<char>(), data); // No reallocation.
+  EXPECT_EQ(buf.capacity(), 15u);     // Hasn't shrunk.
+  EXPECT_EQ(buf.data<char>(), data);  // No reallocation.
   EXPECT_TRUE(buf.empty());
 }
 
 TEST(BufferTest, TestLambdaSetAppend) {
-  auto setter = [] (rtc::ArrayView<uint8_t> av) {
+  auto setter = [](rtc::ArrayView<uint8_t> av) {
     for (int i = 0; i != 15; ++i)
       av[i] = kTestData[i];
     return 15;
@@ -237,7 +237,7 @@
 }
 
 TEST(BufferTest, TestLambdaSetAppendSigned) {
-  auto setter = [] (rtc::ArrayView<int8_t> av) {
+  auto setter = [](rtc::ArrayView<int8_t> av) {
     for (int i = 0; i != 15; ++i)
       av[i] = kTestData[i];
     return 15;
@@ -257,7 +257,7 @@
 }
 
 TEST(BufferTest, TestLambdaAppendEmpty) {
-  auto setter = [] (rtc::ArrayView<uint8_t> av) {
+  auto setter = [](rtc::ArrayView<uint8_t> av) {
     for (int i = 0; i != 15; ++i)
       av[i] = kTestData[i];
     return 15;
@@ -275,7 +275,7 @@
 }
 
 TEST(BufferTest, TestLambdaAppendPartial) {
-  auto setter = [] (rtc::ArrayView<uint8_t> av) {
+  auto setter = [](rtc::ArrayView<uint8_t> av) {
     for (int i = 0; i != 7; ++i)
       av[i] = kTestData[i];
     return 7;
@@ -283,15 +283,15 @@
 
   Buffer buf;
   EXPECT_EQ(buf.AppendData(15, setter), 7u);
-  EXPECT_EQ(buf.size(), 7u);            // Size is exactly what we wrote.
-  EXPECT_GE(buf.capacity(), 7u);        // Capacity is valid.
-  EXPECT_NE(buf.data<char>(), nullptr); // Data is actually stored.
+  EXPECT_EQ(buf.size(), 7u);             // Size is exactly what we wrote.
+  EXPECT_GE(buf.capacity(), 7u);         // Capacity is valid.
+  EXPECT_NE(buf.data<char>(), nullptr);  // Data is actually stored.
   EXPECT_FALSE(buf.empty());
 }
 
 TEST(BufferTest, TestMutableLambdaSetAppend) {
   uint8_t magic_number = 17;
-  auto setter = [magic_number] (rtc::ArrayView<uint8_t> av) mutable {
+  auto setter = [magic_number](rtc::ArrayView<uint8_t> av) mutable {
     for (int i = 0; i != 15; ++i) {
       av[i] = magic_number;
       ++magic_number;
@@ -304,9 +304,9 @@
   Buffer buf;
   EXPECT_EQ(buf.SetData(15, setter), 15u);
   EXPECT_EQ(buf.AppendData(15, setter), 15u);
-  EXPECT_EQ(buf.size(), 30u);           // Size is exactly what we wrote.
-  EXPECT_GE(buf.capacity(), 30u);       // Capacity is valid.
-  EXPECT_NE(buf.data<char>(), nullptr); // Data is actually stored.
+  EXPECT_EQ(buf.size(), 30u);            // Size is exactly what we wrote.
+  EXPECT_GE(buf.capacity(), 30u);        // Capacity is valid.
+  EXPECT_NE(buf.data<char>(), nullptr);  // Data is actually stored.
   EXPECT_FALSE(buf.empty());
 
   for (uint8_t i = 0; i != buf.size(); ++i) {
diff --git a/rtc_base/bufferqueue.cc b/rtc_base/bufferqueue.cc
index 3b082a5..48ff2e6 100644
--- a/rtc_base/bufferqueue.cc
+++ b/rtc_base/bufferqueue.cc
@@ -15,8 +15,7 @@
 namespace rtc {
 
 BufferQueue::BufferQueue(size_t capacity, size_t default_size)
-    : capacity_(capacity), default_size_(default_size) {
-}
+    : capacity_(capacity), default_size_(default_size) {}
 
 BufferQueue::~BufferQueue() {
   CritScope cs(&crit_);
@@ -64,7 +63,8 @@
   return true;
 }
 
-bool BufferQueue::WriteBack(const void* buffer, size_t bytes,
+bool BufferQueue::WriteBack(const void* buffer,
+                            size_t bytes,
                             size_t* bytes_written) {
   CritScope cs(&crit_);
   if (queue_.size() == capacity_) {
diff --git a/rtc_base/bytebuffer.cc b/rtc_base/bytebuffer.cc
index f152d4f..94fc6ac 100644
--- a/rtc_base/bytebuffer.cc
+++ b/rtc_base/bytebuffer.cc
@@ -14,8 +14,6 @@
 
 #include <algorithm>
 
-#include "rtc_base/basictypes.h"
-
 namespace rtc {
 
 ByteBufferWriter::ByteBufferWriter() : ByteBufferWriterT() {}
@@ -36,7 +34,8 @@
   Construct(bytes, len);
 }
 
-ByteBufferReader::ByteBufferReader(const char* bytes, size_t len,
+ByteBufferReader::ByteBufferReader(const char* bytes,
+                                   size_t len,
                                    ByteOrder byte_order)
     : ByteBuffer(byte_order) {
   Construct(bytes, len);
@@ -65,13 +64,15 @@
 }
 
 bool ByteBufferReader::ReadUInt8(uint8_t* val) {
-  if (!val) return false;
+  if (!val)
+    return false;
 
   return ReadBytes(reinterpret_cast<char*>(val), 1);
 }
 
 bool ByteBufferReader::ReadUInt16(uint16_t* val) {
-  if (!val) return false;
+  if (!val)
+    return false;
 
   uint16_t v;
   if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
@@ -83,7 +84,8 @@
 }
 
 bool ByteBufferReader::ReadUInt24(uint32_t* val) {
-  if (!val) return false;
+  if (!val)
+    return false;
 
   uint32_t v = 0;
   char* read_into = reinterpret_cast<char*>(&v);
@@ -100,7 +102,8 @@
 }
 
 bool ByteBufferReader::ReadUInt32(uint32_t* val) {
-  if (!val) return false;
+  if (!val)
+    return false;
 
   uint32_t v;
   if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
@@ -112,7 +115,8 @@
 }
 
 bool ByteBufferReader::ReadUInt64(uint64_t* val) {
-  if (!val) return false;
+  if (!val)
+    return false;
 
   uint64_t v;
   if (!ReadBytes(reinterpret_cast<char*>(&v), 8)) {
@@ -147,7 +151,8 @@
 }
 
 bool ByteBufferReader::ReadString(std::string* val, size_t len) {
-  if (!val) return false;
+  if (!val)
+    return false;
 
   if (len > Length()) {
     return false;
diff --git a/rtc_base/bytebuffer.h b/rtc_base/bytebuffer.h
index 740bff2..9036bcd 100644
--- a/rtc_base/bytebuffer.h
+++ b/rtc_base/bytebuffer.h
@@ -13,7 +13,6 @@
 
 #include <string>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/buffer.h"
 #include "rtc_base/byteorder.h"
 #include "rtc_base/constructormagic.h"
diff --git a/rtc_base/bytebuffer_unittest.cc b/rtc_base/bytebuffer_unittest.cc
index 6140e9f..718f35c 100644
--- a/rtc_base/bytebuffer_unittest.cc
+++ b/rtc_base/bytebuffer_unittest.cc
@@ -79,8 +79,8 @@
 }
 
 TEST(ByteBufferTest, TestReadWriteBuffer) {
-  ByteBufferWriter::ByteOrder orders[2] = { ByteBufferWriter::ORDER_HOST,
-                                            ByteBufferWriter::ORDER_NETWORK };
+  ByteBufferWriter::ByteOrder orders[2] = {ByteBufferWriter::ORDER_HOST,
+                                           ByteBufferWriter::ORDER_NETWORK};
   for (size_t i = 0; i < arraysize(orders); i++) {
     ByteBufferWriter buffer(orders[i]);
     EXPECT_EQ(orders[i], buffer.Order());
diff --git a/rtc_base/byteorder.h b/rtc_base/byteorder.h
index 85f0cc5..86546a5 100644
--- a/rtc_base/byteorder.h
+++ b/rtc_base/byteorder.h
@@ -11,11 +11,13 @@
 #ifndef RTC_BASE_BYTEORDER_H_
 #define RTC_BASE_BYTEORDER_H_
 
+#include <stdint.h>
+
 #if defined(WEBRTC_POSIX) && !defined(__native_client__)
 #include <arpa/inet.h>
 #endif
 
-#include "rtc_base/basictypes.h"
+#include "rtc_base/system/arch.h"
 
 #if defined(WEBRTC_MAC)
 #include <libkern/OSByteOrder.h>
@@ -51,7 +53,7 @@
 #define be64toh(v) ntohll(v)
 #endif
 
-#if defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
+#if defined(WEBRTC_ARCH_LITTLE_ENDIAN)
 #define htole16(v) (v)
 #define htole32(v) (v)
 #define htole64(v) (v)
@@ -62,7 +64,7 @@
 #define htobe64(v) __builtin_bswap64(v)
 #define be64toh(v) __builtin_bswap64(v)
 #endif
-#elif defined(RTC_ARCH_CPU_BIG_ENDIAN)
+#elif defined(WEBRTC_ARCH_BIG_ENDIAN)
 #define htole16(v) __builtin_bswap16(v)
 #define htole32(v) __builtin_bswap32(v)
 #define htole64(v) __builtin_bswap64(v)
@@ -74,8 +76,8 @@
 #define be64toh(v) (v)
 #endif
 #else
-#error RTC_ARCH_CPU_BIG_ENDIAN or RTC_ARCH_CPU_LITTLE_ENDIAN must be defined.
-#endif  // defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
+#error WEBRTC_ARCH_BIG_ENDIAN or WEBRTC_ARCH_LITTLE_ENDIAN must be defined.
+#endif  // defined(WEBRTC_ARCH_LITTLE_ENDIAN)
 #elif defined(WEBRTC_POSIX)
 #include <endian.h>
 #endif
@@ -142,7 +144,7 @@
 
 // Check if the current host is big endian.
 inline bool IsHostBigEndian() {
-#if defined(RTC_ARCH_CPU_BIG_ENDIAN)
+#if defined(WEBRTC_ARCH_BIG_ENDIAN)
   return true;
 #else
   return false;
diff --git a/rtc_base/byteorder_unittest.cc b/rtc_base/byteorder_unittest.cc
index 30dc5fa..75509de 100644
--- a/rtc_base/byteorder_unittest.cc
+++ b/rtc_base/byteorder_unittest.cc
@@ -80,4 +80,3 @@
 }
 
 }  // namespace rtc
-
diff --git a/rtc_base/callback.h b/rtc_base/callback.h
index 0e035ad..65b7c9c 100644
--- a/rtc_base/callback.h
+++ b/rtc_base/callback.h
@@ -73,8 +73,9 @@
  public:
   // Default copy operations are appropriate for this class.
   Callback0() {}
-  template <class T> Callback0(const T& functor)
-      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  template <class T>
+  Callback0(const T& functor)
+      : helper_(new RefCountedObject<HelperImpl<T> >(functor)) {}
   R operator()() {
     if (empty())
       return R();
@@ -87,24 +88,23 @@
     virtual ~Helper() {}
     virtual R Run() = 0;
   };
-  template <class T> struct HelperImpl : Helper {
+  template <class T>
+  struct HelperImpl : Helper {
     explicit HelperImpl(const T& functor) : functor_(functor) {}
-    virtual R Run() {
-      return functor_();
-    }
+    virtual R Run() { return functor_(); }
     T functor_;
   };
   scoped_refptr<Helper> helper_;
 };
 
-template <class R,
-          class P1>
+template <class R, class P1>
 class Callback1 {
  public:
   // Default copy operations are appropriate for this class.
   Callback1() {}
-  template <class T> Callback1(const T& functor)
-      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  template <class T>
+  Callback1(const T& functor)
+      : helper_(new RefCountedObject<HelperImpl<T> >(functor)) {}
   R operator()(P1 p1) {
     if (empty())
       return R();
@@ -117,25 +117,23 @@
     virtual ~Helper() {}
     virtual R Run(P1 p1) = 0;
   };
-  template <class T> struct HelperImpl : Helper {
+  template <class T>
+  struct HelperImpl : Helper {
     explicit HelperImpl(const T& functor) : functor_(functor) {}
-    virtual R Run(P1 p1) {
-      return functor_(p1);
-    }
+    virtual R Run(P1 p1) { return functor_(p1); }
     T functor_;
   };
   scoped_refptr<Helper> helper_;
 };
 
-template <class R,
-          class P1,
-          class P2>
+template <class R, class P1, class P2>
 class Callback2 {
  public:
   // Default copy operations are appropriate for this class.
   Callback2() {}
-  template <class T> Callback2(const T& functor)
-      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  template <class T>
+  Callback2(const T& functor)
+      : helper_(new RefCountedObject<HelperImpl<T> >(functor)) {}
   R operator()(P1 p1, P2 p2) {
     if (empty())
       return R();
@@ -148,26 +146,23 @@
     virtual ~Helper() {}
     virtual R Run(P1 p1, P2 p2) = 0;
   };
-  template <class T> struct HelperImpl : Helper {
+  template <class T>
+  struct HelperImpl : Helper {
     explicit HelperImpl(const T& functor) : functor_(functor) {}
-    virtual R Run(P1 p1, P2 p2) {
-      return functor_(p1, p2);
-    }
+    virtual R Run(P1 p1, P2 p2) { return functor_(p1, p2); }
     T functor_;
   };
   scoped_refptr<Helper> helper_;
 };
 
-template <class R,
-          class P1,
-          class P2,
-          class P3>
+template <class R, class P1, class P2, class P3>
 class Callback3 {
  public:
   // Default copy operations are appropriate for this class.
   Callback3() {}
-  template <class T> Callback3(const T& functor)
-      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  template <class T>
+  Callback3(const T& functor)
+      : helper_(new RefCountedObject<HelperImpl<T> >(functor)) {}
   R operator()(P1 p1, P2 p2, P3 p3) {
     if (empty())
       return R();
@@ -180,27 +175,23 @@
     virtual ~Helper() {}
     virtual R Run(P1 p1, P2 p2, P3 p3) = 0;
   };
-  template <class T> struct HelperImpl : Helper {
+  template <class T>
+  struct HelperImpl : Helper {
     explicit HelperImpl(const T& functor) : functor_(functor) {}
-    virtual R Run(P1 p1, P2 p2, P3 p3) {
-      return functor_(p1, p2, p3);
-    }
+    virtual R Run(P1 p1, P2 p2, P3 p3) { return functor_(p1, p2, p3); }
     T functor_;
   };
   scoped_refptr<Helper> helper_;
 };
 
-template <class R,
-          class P1,
-          class P2,
-          class P3,
-          class P4>
+template <class R, class P1, class P2, class P3, class P4>
 class Callback4 {
  public:
   // Default copy operations are appropriate for this class.
   Callback4() {}
-  template <class T> Callback4(const T& functor)
-      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  template <class T>
+  Callback4(const T& functor)
+      : helper_(new RefCountedObject<HelperImpl<T> >(functor)) {}
   R operator()(P1 p1, P2 p2, P3 p3, P4 p4) {
     if (empty())
       return R();
@@ -213,7 +204,8 @@
     virtual ~Helper() {}
     virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) = 0;
   };
-  template <class T> struct HelperImpl : Helper {
+  template <class T>
+  struct HelperImpl : Helper {
     explicit HelperImpl(const T& functor) : functor_(functor) {}
     virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) {
       return functor_(p1, p2, p3, p4);
@@ -223,18 +215,14 @@
   scoped_refptr<Helper> helper_;
 };
 
-template <class R,
-          class P1,
-          class P2,
-          class P3,
-          class P4,
-          class P5>
+template <class R, class P1, class P2, class P3, class P4, class P5>
 class Callback5 {
  public:
   // Default copy operations are appropriate for this class.
   Callback5() {}
-  template <class T> Callback5(const T& functor)
-      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  template <class T>
+  Callback5(const T& functor)
+      : helper_(new RefCountedObject<HelperImpl<T> >(functor)) {}
   R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
     if (empty())
       return R();
@@ -247,7 +235,8 @@
     virtual ~Helper() {}
     virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) = 0;
   };
-  template <class T> struct HelperImpl : Helper {
+  template <class T>
+  struct HelperImpl : Helper {
     explicit HelperImpl(const T& functor) : functor_(functor) {}
     virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
       return functor_(p1, p2, p3, p4, p5);
diff --git a/rtc_base/callback_unittest.cc b/rtc_base/callback_unittest.cc
index 26bfd5d..ae86a4c 100644
--- a/rtc_base/callback_unittest.cc
+++ b/rtc_base/callback_unittest.cc
@@ -19,9 +19,15 @@
 namespace {
 
 void f() {}
-int g() { return 42; }
-int h(int x) { return x * x; }
-void i(int& x) { x *= x; }  // NOLINT: Testing refs
+int g() {
+  return 42;
+}
+int h(int x) {
+  return x * x;
+}
+void i(int& x) {
+  x *= x;
+}  // NOLINT: Testing refs
 
 struct BindTester {
   int a() { return 24; }
diff --git a/rtc_base/checks.cc b/rtc_base/checks.cc
index 820ca96..32ac8d6 100644
--- a/rtc_base/checks.cc
+++ b/rtc_base/checks.cc
@@ -35,83 +35,110 @@
 
 #include "rtc_base/checks.h"
 
-#if defined(_MSC_VER)
-// Warning C4722: destructor never returns, potential memory leak.
-// FatalMessage's dtor very intentionally aborts.
-#pragma warning(disable:4722)
-#endif
-
 namespace rtc {
-namespace {
+namespace webrtc_checks_impl {
 
-void VPrintError(const char* format, va_list args) {
-#if defined(WEBRTC_ANDROID)
-  __android_log_vprint(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, format, args);
-#else
-  vfprintf(stderr, format, args);
-#endif
+// Reads one argument from args, appends it to s and advances fmt.
+// Returns true iff an argument was sucessfully parsed.
+bool ParseArg(va_list* args,
+              const CheckArgType** fmt,
+              std::ostream& s) {  // no-presubmit-check TODO(webrtc:8982)
+  if (**fmt == CheckArgType::kEnd)
+    return false;
+
+  switch (**fmt) {
+    case CheckArgType::kInt:
+      s << va_arg(*args, int);
+      break;
+    case CheckArgType::kLong:
+      s << va_arg(*args, long);
+      break;
+    case CheckArgType::kLongLong:
+      s << va_arg(*args, long long);
+      break;
+    case CheckArgType::kUInt:
+      s << va_arg(*args, unsigned);
+      break;
+    case CheckArgType::kULong:
+      s << va_arg(*args, unsigned long);
+      break;
+    case CheckArgType::kULongLong:
+      s << va_arg(*args, unsigned long long);
+      break;
+    case CheckArgType::kDouble:
+      s << va_arg(*args, double);
+      break;
+    case CheckArgType::kLongDouble:
+      s << va_arg(*args, long double);
+      break;
+    case CheckArgType::kCharP:
+      s << va_arg(*args, const char*);
+      break;
+    case CheckArgType::kStdString:
+      s << *va_arg(*args, const std::string*);
+      break;
+    case CheckArgType::kVoidP:
+      s << reinterpret_cast<std::uintptr_t>(va_arg(*args, const void*));
+      break;
+    default:
+      s << "[Invalid CheckArgType:" << static_cast<int8_t>(**fmt) << "]";
+      return false;
+  }
+  (*fmt)++;
+  return true;
 }
 
-#if defined(__GNUC__)
-void PrintError(const char* format, ...)
-    __attribute__((__format__(__printf__, 1, 2)));
-#endif
-
-void PrintError(const char* format, ...) {
+RTC_NORETURN void FatalLog(const char* file,
+                           int line,
+                           const char* message,
+                           const CheckArgType* fmt,
+                           ...) {
   va_list args;
-  va_start(args, format);
-  VPrintError(format, args);
+  va_start(args, fmt);
+
+  std::ostringstream ss;  // no-presubmit-check TODO(webrtc:8982)
+  ss << "\n\n#\n# Fatal error in: " << file << ", line " << line
+     << "\n# last system error: " << LAST_SYSTEM_ERROR << "\n# Check failed: ";
+
+  if (*fmt == CheckArgType::kCheckOp) {
+    // This log message was generated by RTC_CHECK_OP, so we have to complete
+    // the error message using the operands that have been passed as the first
+    // two arguments.
+    fmt++;
+
+    std::ostringstream s1, s2;  // no-presubmit-check TODO(webrtc:8982)
+    if (ParseArg(&args, &fmt, s1) && ParseArg(&args, &fmt, s2))
+      ss << message << " (" << s1.str() << " vs. " << s2.str() << ")\n# ";
+  } else {
+    ss << message << "\n# ";
+  }
+
+  // Append all the user-supplied arguments to the message.
+  while (ParseArg(&args, &fmt, ss))
+    ;
+
   va_end(args);
-}
 
-}  // namespace
+  std::string s = ss.str();
+  const char* output = s.c_str();
 
-FatalMessage::FatalMessage(const char* file, int line) {
-  Init(file, line);
-}
+#if defined(WEBRTC_ANDROID)
+  __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
+#endif
 
-FatalMessage::FatalMessage(const char* file, int line, std::string* result) {
-  Init(file, line);
-  stream_ << "Check failed: " << *result << std::endl << "# ";
-  delete result;
-}
-
-NO_RETURN FatalMessage::~FatalMessage() {
   fflush(stdout);
-  fflush(stderr);
-  stream_ << std::endl << "#" << std::endl;
-  PrintError("%s", stream_.str().c_str());
+  fprintf(stderr, "%s", output);
   fflush(stderr);
   abort();
 }
 
-void FatalMessage::Init(const char* file, int line) {
-  stream_ << std::endl
-          << std::endl
-          << "#" << std::endl
-          << "# Fatal error in " << file << ", line " << line << std::endl
-          << "# last system error: " << LAST_SYSTEM_ERROR << std::endl
-          << "# ";
-}
-
-// MSVC doesn't like complex extern templates and DLLs.
-#if !defined(COMPILER_MSVC)
-// Explicit instantiations for commonly used comparisons.
-template std::string* MakeCheckOpString<int, int>(
-    const int&, const int&, const char* names);
-template std::string* MakeCheckOpString<unsigned long, unsigned long>(
-    const unsigned long&, const unsigned long&, const char* names);
-template std::string* MakeCheckOpString<unsigned long, unsigned int>(
-    const unsigned long&, const unsigned int&, const char* names);
-template std::string* MakeCheckOpString<unsigned int, unsigned long>(
-    const unsigned int&, const unsigned long&, const char* names);
-template std::string* MakeCheckOpString<std::string, std::string>(
-    const std::string&, const std::string&, const char* name);
-#endif
-
+}  // namespace webrtc_checks_impl
 }  // namespace rtc
 
 // Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
-NO_RETURN void rtc_FatalMessage(const char* file, int line, const char* msg) {
-  rtc::FatalMessage(file, line).stream() << msg;
+RTC_NORETURN void rtc_FatalMessage(const char* file, int line,
+                                   const char* msg) {
+  static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = {
+      rtc::webrtc_checks_impl::CheckArgType::kEnd};
+  FatalLog(file, line, msg, t);
 }
diff --git a/rtc_base/checks.h b/rtc_base/checks.h
index e9a19e6..a65088d 100644
--- a/rtc_base/checks.h
+++ b/rtc_base/checks.h
@@ -11,8 +11,6 @@
 #ifndef RTC_BASE_CHECKS_H_
 #define RTC_BASE_CHECKS_H_
 
-#include "typedefs.h"  // NOLINT(build/include)
-
 // If you for some reson need to know if DCHECKs are on, test the value of
 // RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be
 // defined, to either a true or a false value.)
@@ -22,10 +20,19 @@
 #define RTC_DCHECK_IS_ON 0
 #endif
 
+// Annotate a function that will not return control flow to the caller.
+#if defined(_MSC_VER)
+#define RTC_NORETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+#define RTC_NORETURN __attribute__ ((__noreturn__))
+#else
+#define RTC_NORETURN
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
-NO_RETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
+RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
 #ifdef __cplusplus
 }  // extern "C"
 #endif
@@ -33,10 +40,11 @@
 #ifdef __cplusplus
 // C++ version.
 
-#include <sstream>
+#include <sstream>  // no-presubmit-check TODO(webrtc:8982)
 #include <string>
 
 #include "rtc_base/numerics/safe_compare.h"
+#include "rtc_base/system/inline.h"
 
 // The macros here print a message to stderr and abort under various
 // conditions. All will accept additional stream messages. For example:
@@ -79,21 +87,209 @@
 // consolidation with system_wrappers/logging.h should happen first.
 
 namespace rtc {
+namespace webrtc_checks_impl {
+enum class CheckArgType : int8_t {
+  kEnd = 0,
+  kInt,
+  kLong,
+  kLongLong,
+  kUInt,
+  kULong,
+  kULongLong,
+  kDouble,
+  kLongDouble,
+  kCharP,
+  kStdString,
+  kVoidP,
 
-// Helper macro which avoids evaluating the arguments to a stream if
-// the condition doesn't hold.
-#define RTC_LAZY_STREAM(stream, condition)                                    \
-  !(condition) ? static_cast<void>(0) : rtc::FatalMessageVoidify() & (stream)
+  // kCheckOp doesn't represent an argument type. Instead, it is sent as the
+  // first argument from RTC_CHECK_OP to make FatalLog use the next two
+  // arguments to build the special CHECK_OP error message
+  // (the "a == b (1 vs. 2)" bit).
+  kCheckOp,
+};
+
+RTC_NORETURN void FatalLog(const char* file,
+                           int line,
+                           const char* message,
+                           const CheckArgType* fmt,
+                           ...);
+
+// Wrapper for log arguments. Only ever make values of this type with the
+// MakeVal() functions.
+template <CheckArgType N, typename T>
+struct Val {
+  static constexpr CheckArgType Type() { return N; }
+  T GetVal() const { return val; }
+  T val;
+};
+
+inline Val<CheckArgType::kInt, int> MakeVal(int x) {
+  return {x};
+}
+inline Val<CheckArgType::kLong, long> MakeVal(long x) {
+  return {x};
+}
+inline Val<CheckArgType::kLongLong, long long> MakeVal(long long x) {
+  return {x};
+}
+inline Val<CheckArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
+  return {x};
+}
+inline Val<CheckArgType::kULong, unsigned long> MakeVal(unsigned long x) {
+  return {x};
+}
+inline Val<CheckArgType::kULongLong, unsigned long long> MakeVal(
+    unsigned long long x) {
+  return {x};
+}
+
+inline Val<CheckArgType::kDouble, double> MakeVal(double x) {
+  return {x};
+}
+inline Val<CheckArgType::kLongDouble, long double> MakeVal(long double x) {
+  return {x};
+}
+
+inline Val<CheckArgType::kCharP, const char*> MakeVal(const char* x) {
+  return {x};
+}
+inline Val<CheckArgType::kStdString, const std::string*> MakeVal(
+    const std::string& x) {
+  return {&x};
+}
+
+inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) {
+  return {x};
+}
+
+// Ephemeral type that represents the result of the logging << operator.
+template <typename... Ts>
+class LogStreamer;
+
+// Base case: Before the first << argument.
+template <>
+class LogStreamer<> final {
+ public:
+  template <
+      typename U,
+      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
+      U arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
+                                                             this);
+  }
+
+  template <
+      typename U,
+      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
+      const U& arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
+                                                             this);
+  }
+
+  template <typename... Us>
+  RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
+                                                 const int line,
+                                                 const char* message,
+                                                 const Us&... args) {
+    static constexpr CheckArgType t[] = {Us::Type()..., CheckArgType::kEnd};
+    FatalLog(file, line, message, t, args.GetVal()...);
+  }
+
+  template <typename... Us>
+  RTC_NORETURN RTC_FORCE_INLINE static void CallCheckOp(const char* file,
+                                                        const int line,
+                                                        const char* message,
+                                                        const Us&... args) {
+    static constexpr CheckArgType t[] = {CheckArgType::kCheckOp, Us::Type()...,
+                                         CheckArgType::kEnd};
+    FatalLog(file, line, message, t, args.GetVal()...);
+  }
+};
+
+// Inductive case: We've already seen at least one << argument. The most recent
+// one had type `T`, and the earlier ones had types `Ts`.
+template <typename T, typename... Ts>
+class LogStreamer<T, Ts...> final {
+ public:
+  RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
+      : arg_(arg), prior_(prior) {}
+
+  template <
+      typename U,
+      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
+  operator<<(U arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
+        MakeVal(arg), this);
+  }
+
+  template <
+      typename U,
+      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
+  operator<<(const U& arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
+        MakeVal(arg), this);
+  }
+
+  template <typename... Us>
+  RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
+                                          const int line,
+                                          const char* message,
+                                          const Us&... args) const {
+    prior_->Call(file, line, message, arg_, args...);
+  }
+
+  template <typename... Us>
+  RTC_NORETURN RTC_FORCE_INLINE void CallCheckOp(const char* file,
+                                                 const int line,
+                                                 const char* message,
+                                                 const Us&... args) const {
+    prior_->CallCheckOp(file, line, message, arg_, args...);
+  }
+
+ private:
+  // The most recent argument.
+  T arg_;
+
+  // Earlier arguments.
+  const LogStreamer<Ts...>* prior_;
+};
+
+template <bool isCheckOp>
+class FatalLogCall final {
+ public:
+  FatalLogCall(const char* file, int line, const char* message)
+      : file_(file), line_(line), message_(message) {}
+
+  // This can be any binary operator with precedence lower than <<.
+  template <typename... Ts>
+  RTC_NORETURN RTC_FORCE_INLINE void operator&(
+      const LogStreamer<Ts...>& streamer) {
+    isCheckOp ? streamer.CallCheckOp(file_, line_, message_)
+              : streamer.Call(file_, line_, message_);
+  }
+
+ private:
+  const char* file_;
+  int line_;
+  const char* message_;
+};
+}  // namespace webrtc_checks_impl
 
 // The actual stream used isn't important. We reference |ignored| in the code
 // but don't evaluate it; this is to avoid "unused variable" warnings (we do so
 // in a particularly convoluted way with an extra ?: because that appears to be
 // the simplest construct that keeps Visual Studio from complaining about
 // condition being unused).
-#define RTC_EAT_STREAM_PARAMETERS(ignored) \
-  (true ? true : ((void)(ignored), true))  \
-      ? static_cast<void>(0)               \
-      : rtc::FatalMessageVoidify() & rtc::FatalMessage("", 0).stream()
+#define RTC_EAT_STREAM_PARAMETERS(ignored)                        \
+  (true ? true : ((void)(ignored), true))                         \
+      ? static_cast<void>(0)                                      \
+      : rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
+            rtc::webrtc_checks_impl::LogStreamer<>()
 
 // Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if
 // values of the same types as |a| and |b| can't be compared with the given
@@ -105,81 +301,21 @@
 // controlled by NDEBUG or anything else, so the check will be executed
 // regardless of compilation mode.
 //
-// We make sure RTC_CHECK et al. always evaluates their arguments, as
+// We make sure RTC_CHECK et al. always evaluates |condition|, as
 // doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
-#define RTC_CHECK(condition)                                      \
-  RTC_LAZY_STREAM(rtc::FatalMessage(__FILE__, __LINE__).stream(), \
-                  !(condition))                                   \
-      << "Check failed: " #condition << std::endl << "# "
+#define RTC_CHECK(condition)                                       \
+  while (!(condition))                                             \
+  rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
+                                               #condition) &       \
+      rtc::webrtc_checks_impl::LogStreamer<>()
 
 // Helper macro for binary operators.
 // Don't use this macro directly in your code, use RTC_CHECK_EQ et al below.
-//
-// TODO(akalin): Rewrite this so that constructs like if (...)
-// RTC_CHECK_EQ(...) else { ... } work properly.
-#define RTC_CHECK_OP(name, op, val1, val2)                                 \
-  if (std::string* _result =                                               \
-          rtc::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \
-    rtc::FatalMessage(__FILE__, __LINE__, _result).stream()
-
-// Build the error message string.  This is separate from the "Impl"
-// function template because it is not performance critical and so can
-// be out of line, while the "Impl" code should be inline.  Caller
-// takes ownership of the returned string.
-template<class t1, class t2>
-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
-  std::ostringstream ss;
-  ss << names << " (" << v1 << " vs. " << v2 << ")";
-  std::string* msg = new std::string(ss.str());
-  return msg;
-}
-
-// MSVC doesn't like complex extern templates and DLLs.
-#if !defined(COMPILER_MSVC)
-// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
-// in logging.cc.
-extern template std::string* MakeCheckOpString<int, int>(
-    const int&, const int&, const char* names);
-extern template
-std::string* MakeCheckOpString<unsigned long, unsigned long>(
-    const unsigned long&, const unsigned long&, const char* names);
-extern template
-std::string* MakeCheckOpString<unsigned long, unsigned int>(
-    const unsigned long&, const unsigned int&, const char* names);
-extern template
-std::string* MakeCheckOpString<unsigned int, unsigned long>(
-    const unsigned int&, const unsigned long&, const char* names);
-extern template
-std::string* MakeCheckOpString<std::string, std::string>(
-    const std::string&, const std::string&, const char* name);
-#endif
-
-// Helper functions for RTC_CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-#define DEFINE_RTC_CHECK_OP_IMPL(name)                                       \
-  template <class t1, class t2>                                              \
-  inline std::string* Check##name##Impl(const t1& v1, const t2& v2,          \
-                                        const char* names) {                 \
-    if (rtc::Safe##name(v1, v2))                                             \
-      return nullptr;                                                        \
-    else                                                                     \
-      return rtc::MakeCheckOpString(v1, v2, names);                          \
-  }                                                                          \
-  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
-    if (rtc::Safe##name(v1, v2))                                             \
-      return nullptr;                                                        \
-    else                                                                     \
-      return rtc::MakeCheckOpString(v1, v2, names);                          \
-  }
-DEFINE_RTC_CHECK_OP_IMPL(Eq)
-DEFINE_RTC_CHECK_OP_IMPL(Ne)
-DEFINE_RTC_CHECK_OP_IMPL(Le)
-DEFINE_RTC_CHECK_OP_IMPL(Lt)
-DEFINE_RTC_CHECK_OP_IMPL(Ge)
-DEFINE_RTC_CHECK_OP_IMPL(Gt)
-#undef DEFINE_RTC_CHECK_OP_IMPL
+#define RTC_CHECK_OP(name, op, val1, val2)                               \
+  while (!rtc::Safe##name((val1), (val2)))                               \
+  rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, __LINE__,        \
+                                              #val1 " " #op " " #val2) & \
+      rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2)
 
 #define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2)
 #define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2)
@@ -209,39 +345,14 @@
 #define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2)
 #endif
 
-// This is identical to LogMessageVoidify but in name.
-class FatalMessageVoidify {
- public:
-  FatalMessageVoidify() { }
-  // This has to be an operator with a precedence lower than << but
-  // higher than ?:
-  void operator&(std::ostream&) { }
-};
-
 #define RTC_UNREACHABLE_CODE_HIT false
 #define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
 
 // TODO(bugs.webrtc.org/8454): Add an RTC_ prefix or rename differently.
-#define FATAL() rtc::FatalMessage(__FILE__, __LINE__).stream()
-// TODO(ajm): Consider adding RTC_NOTIMPLEMENTED macro when
-// base/logging.h and system_wrappers/logging.h are consolidated such that we
-// can match the Chromium behavior.
-
-// Like a stripped-down LogMessage from logging.h, except that it aborts.
-class FatalMessage {
- public:
-  FatalMessage(const char* file, int line);
-  // Used for RTC_CHECK_EQ(), etc. Takes ownership of the given string.
-  FatalMessage(const char* file, int line, std::string* result);
-  NO_RETURN ~FatalMessage();
-
-  std::ostream& stream() { return stream_; }
-
- private:
-  void Init(const char* file, int line);
-
-  std::ostringstream stream_;
-};
+#define FATAL()                                                    \
+  rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
+                                               "FATAL()") &        \
+      rtc::webrtc_checks_impl::LogStreamer<>()
 
 // Performs the integer division a/b and returns the result. CHECKs that the
 // remainder is zero.
diff --git a/rtc_base/compile_assert_c.h b/rtc_base/compile_assert_c.h
index c83d314..db2e4a8 100644
--- a/rtc_base/compile_assert_c.h
+++ b/rtc_base/compile_assert_c.h
@@ -16,6 +16,10 @@
 // Example:
 //   RTC_COMPILE_ASSERT(sizeof(foo) < 128);
 // Note: In C++, use static_assert instead!
-#define RTC_COMPILE_ASSERT(expression) switch (0) {case 0: case expression:;}
+#define RTC_COMPILE_ASSERT(expression) \
+  switch (0) {                         \
+    case 0:                            \
+    case expression:;                  \
+  }
 
 #endif  // RTC_BASE_COMPILE_ASSERT_C_H_
diff --git a/rtc_base/constructormagic.h b/rtc_base/constructormagic.h
index 8a953aa..646a058 100644
--- a/rtc_base/constructormagic.h
+++ b/rtc_base/constructormagic.h
@@ -12,8 +12,7 @@
 #define RTC_BASE_CONSTRUCTORMAGIC_H_
 
 // Put this in the declarations for a class to be unassignable.
-#define RTC_DISALLOW_ASSIGN(TypeName) \
-  void operator=(const TypeName&) = delete
+#define RTC_DISALLOW_ASSIGN(TypeName) void operator=(const TypeName&) = delete
 
 // A macro to disallow the copy constructor and operator= functions. This should
 // be used in the declarations for a class.
diff --git a/rtc_base/copyonwritebuffer.cc b/rtc_base/copyonwritebuffer.cc
index 579dd46..8874ea9 100644
--- a/rtc_base/copyonwritebuffer.cc
+++ b/rtc_base/copyonwritebuffer.cc
@@ -17,12 +17,10 @@
 }
 
 CopyOnWriteBuffer::CopyOnWriteBuffer(const CopyOnWriteBuffer& buf)
-    : buffer_(buf.buffer_) {
-}
+    : buffer_(buf.buffer_) {}
 
 CopyOnWriteBuffer::CopyOnWriteBuffer(CopyOnWriteBuffer&& buf)
-    : buffer_(std::move(buf.buffer_)) {
-}
+    : buffer_(std::move(buf.buffer_)) {}
 
 CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size)
     : buffer_(size > 0 ? new RefCountedObject<Buffer>(size) : nullptr) {
@@ -31,8 +29,8 @@
 
 CopyOnWriteBuffer::CopyOnWriteBuffer(size_t size, size_t capacity)
     : buffer_(size > 0 || capacity > 0
-          ? new RefCountedObject<Buffer>(size, capacity)
-          : nullptr) {
+                  ? new RefCountedObject<Buffer>(size, capacity)
+                  : nullptr) {
   RTC_DCHECK(IsConsistent());
 }
 
@@ -43,8 +41,8 @@
   RTC_DCHECK(IsConsistent());
   RTC_DCHECK(buf.IsConsistent());
   return buffer_.get() == buf.buffer_.get() ||
-      (buffer_.get() && buf.buffer_.get() &&
-      *buffer_.get() == *buf.buffer_.get());
+         (buffer_.get() && buf.buffer_.get() &&
+          *buffer_.get() == *buf.buffer_.get());
 }
 
 void CopyOnWriteBuffer::SetSize(size_t size) {
@@ -59,10 +57,9 @@
 
   // Clone data if referenced.
   if (!buffer_->HasOneRef()) {
-    buffer_ = new RefCountedObject<Buffer>(
-        buffer_->data(),
-        std::min(buffer_->size(), size),
-        std::max(buffer_->capacity(), size));
+    buffer_ = new RefCountedObject<Buffer>(buffer_->data(),
+                                           std::min(buffer_->size(), size),
+                                           std::max(buffer_->capacity(), size));
   }
   buffer_->SetSize(size);
   RTC_DCHECK(IsConsistent());
@@ -103,10 +100,8 @@
   }
 
   buffer_ = new RefCountedObject<Buffer>(buffer_->data(), buffer_->size(),
-      new_capacity);
+                                         new_capacity);
   RTC_DCHECK(IsConsistent());
 }
 
-
-
 }  // namespace rtc
diff --git a/rtc_base/copyonwritebuffer.h b/rtc_base/copyonwritebuffer.h
index c4bba87..467baad 100644
--- a/rtc_base/copyonwritebuffer.h
+++ b/rtc_base/copyonwritebuffer.h
@@ -185,8 +185,8 @@
       return;
     }
 
-    CloneDataIfReferenced(std::max(buffer_->capacity(),
-        buffer_->size() + size));
+    CloneDataIfReferenced(
+        std::max(buffer_->capacity(), buffer_->size() + size));
     buffer_->AppendData(data, size);
     RTC_DCHECK(IsConsistent());
   }
@@ -229,9 +229,7 @@
   void CloneDataIfReferenced(size_t new_capacity);
 
   // Pre- and postcondition of all methods.
-  bool IsConsistent() const {
-    return (!buffer_ || buffer_->capacity() > 0);
-  }
+  bool IsConsistent() const { return (!buffer_ || buffer_->capacity() > 0); }
 
   // buffer_ is either null, or points to an rtc::Buffer with capacity > 0.
   scoped_refptr<RefCountedObject<Buffer>> buffer_;
diff --git a/rtc_base/cpu_time.cc b/rtc_base/cpu_time.cc
index 6c22880..f25b506 100644
--- a/rtc_base/cpu_time.cc
+++ b/rtc_base/cpu_time.cc
@@ -15,12 +15,12 @@
 #if defined(WEBRTC_LINUX)
 #include <time.h>
 #elif defined(WEBRTC_MAC)
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/times.h>
-#include <mach/thread_info.h>
-#include <mach/thread_act.h>
 #include <mach/mach_init.h>
+#include <mach/thread_act.h>
+#include <mach/thread_info.h>
+#include <sys/resource.h>
+#include <sys/times.h>
+#include <sys/types.h>
 #include <unistd.h>
 #elif defined(WEBRTC_WIN)
 #include <windows.h>
diff --git a/rtc_base/cpu_time_unittest.cc b/rtc_base/cpu_time_unittest.cc
index ba97378..f473069 100644
--- a/rtc_base/cpu_time_unittest.cc
+++ b/rtc_base/cpu_time_unittest.cc
@@ -86,10 +86,10 @@
             kAllowedErrorMillisecs * kNumNanosecsPerMillisec);
   // Total process time is at least twice working threads' CPU time.
   // Therefore process and thread times are correctly related.
-  EXPECT_GE(
-      process_duration_nanos,
-      kWorkingThreads * (kProcessingTimeMillisecs - kAllowedErrorMillisecs)
-      * kNumNanosecsPerMillisec);
+  EXPECT_GE(process_duration_nanos,
+            kWorkingThreads *
+                (kProcessingTimeMillisecs - kAllowedErrorMillisecs) *
+                kNumNanosecsPerMillisec);
 }
 
 TEST(CpuTimeTest, MAYBE_TEST(Sleeping)) {
diff --git a/rtc_base/crc32.cc b/rtc_base/crc32.cc
index c214f38..c70f5fe 100644
--- a/rtc_base/crc32.cc
+++ b/rtc_base/crc32.cc
@@ -49,4 +49,3 @@
 }
 
 }  // namespace rtc
-
diff --git a/rtc_base/crc32.h b/rtc_base/crc32.h
index a0ce432..79c765f 100644
--- a/rtc_base/crc32.h
+++ b/rtc_base/crc32.h
@@ -11,9 +11,10 @@
 #ifndef RTC_BASE_CRC32_H_
 #define RTC_BASE_CRC32_H_
 
-#include <string>
+#include <stddef.h>
+#include <stdint.h>
 
-#include "rtc_base/basictypes.h"
+#include <string>
 
 namespace rtc {
 
diff --git a/rtc_base/crc32_unittest.cc b/rtc_base/crc32_unittest.cc
index 576b424..752bc9f 100644
--- a/rtc_base/crc32_unittest.cc
+++ b/rtc_base/crc32_unittest.cc
@@ -18,7 +18,8 @@
 TEST(Crc32Test, TestBasic) {
   EXPECT_EQ(0U, ComputeCrc32(""));
   EXPECT_EQ(0x352441C2U, ComputeCrc32("abc"));
-  EXPECT_EQ(0x171A3F5FU,
+  EXPECT_EQ(
+      0x171A3F5FU,
       ComputeCrc32("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
 }
 
diff --git a/rtc_base/criticalsection.cc b/rtc_base/criticalsection.cc
index b2bbd03..c786a40 100644
--- a/rtc_base/criticalsection.cc
+++ b/rtc_base/criticalsection.cc
@@ -22,24 +22,24 @@
 #if defined(WEBRTC_WIN)
   InitializeCriticalSection(&crit_);
 #elif defined(WEBRTC_POSIX)
-# if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
+#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
   lock_queue_ = 0;
   owning_thread_ = 0;
   recursion_ = 0;
   semaphore_ = dispatch_semaphore_create(0);
-# else
+#else
   pthread_mutexattr_t mutex_attribute;
   pthread_mutexattr_init(&mutex_attribute);
   pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
   pthread_mutex_init(&mutex_, &mutex_attribute);
   pthread_mutexattr_destroy(&mutex_attribute);
-# endif
+#endif
   CS_DEBUG_CODE(thread_ = 0);
   CS_DEBUG_CODE(recursion_count_ = 0);
   RTC_UNUSED(thread_);
   RTC_UNUSED(recursion_count_);
 #else
-# error Unsupported platform.
+#error Unsupported platform.
 #endif
 }
 
@@ -47,13 +47,13 @@
 #if defined(WEBRTC_WIN)
   DeleteCriticalSection(&crit_);
 #elif defined(WEBRTC_POSIX)
-# if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
+#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
   dispatch_release(semaphore_);
-# else
-  pthread_mutex_destroy(&mutex_);
-# endif
 #else
-# error Unsupported platform.
+  pthread_mutex_destroy(&mutex_);
+#endif
+#else
+#error Unsupported platform.
 #endif
 }
 
@@ -61,7 +61,7 @@
 #if defined(WEBRTC_WIN)
   EnterCriticalSection(&crit_);
 #elif defined(WEBRTC_POSIX)
-# if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
+#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
   int spin = 3000;
   PlatformThreadRef self = CurrentThreadRef();
   bool have_lock = false;
@@ -98,11 +98,11 @@
   owning_thread_ = self;
   ++recursion_;
 
-# else
+#else
   pthread_mutex_lock(&mutex_);
-# endif
+#endif
 
-# if CS_DEBUG_CHECKS
+#if CS_DEBUG_CHECKS
   if (!recursion_count_) {
     RTC_DCHECK(!thread_);
     thread_ = CurrentThreadRef();
@@ -110,9 +110,9 @@
     RTC_DCHECK(CurrentThreadIsOwner());
   }
   ++recursion_count_;
-# endif
+#endif
 #else
-# error Unsupported platform.
+#error Unsupported platform.
 #endif
 }
 
@@ -120,7 +120,7 @@
 #if defined(WEBRTC_WIN)
   return TryEnterCriticalSection(&crit_) != FALSE;
 #elif defined(WEBRTC_POSIX)
-# if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
+#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
   if (!IsThreadRefEqual(owning_thread_, CurrentThreadRef())) {
     if (AtomicOps::CompareAndSwap(&lock_queue_, 0, 1) != 0)
       return false;
@@ -130,11 +130,11 @@
     AtomicOps::Increment(&lock_queue_);
   }
   ++recursion_;
-# else
+#else
   if (pthread_mutex_trylock(&mutex_) != 0)
     return false;
-# endif
-# if CS_DEBUG_CHECKS
+#endif
+#if CS_DEBUG_CHECKS
   if (!recursion_count_) {
     RTC_DCHECK(!thread_);
     thread_ = CurrentThreadRef();
@@ -142,10 +142,10 @@
     RTC_DCHECK(CurrentThreadIsOwner());
   }
   ++recursion_count_;
-# endif
+#endif
   return true;
 #else
-# error Unsupported platform.
+#error Unsupported platform.
 #endif
 }
 
@@ -154,13 +154,13 @@
 #if defined(WEBRTC_WIN)
   LeaveCriticalSection(&crit_);
 #elif defined(WEBRTC_POSIX)
-# if CS_DEBUG_CHECKS
+#if CS_DEBUG_CHECKS
   --recursion_count_;
   RTC_DCHECK(recursion_count_ >= 0);
   if (!recursion_count_)
     thread_ = 0;
-# endif
-# if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
+#endif
+#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
   RTC_DCHECK(IsThreadRefEqual(owning_thread_, CurrentThreadRef()));
   RTC_DCHECK_GE(recursion_, 0);
   --recursion_;
@@ -169,11 +169,11 @@
 
   if (AtomicOps::Decrement(&lock_queue_) > 0 && !recursion_)
     dispatch_semaphore_signal(semaphore_);
-# else
-  pthread_mutex_unlock(&mutex_);
-# endif
 #else
-# error Unsupported platform.
+  pthread_mutex_unlock(&mutex_);
+#endif
+#else
+#error Unsupported platform.
 #endif
 }
 
@@ -186,18 +186,22 @@
   return crit_.OwningThread ==
          reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
 #elif defined(WEBRTC_POSIX)
-# if CS_DEBUG_CHECKS
+#if CS_DEBUG_CHECKS
   return IsThreadRefEqual(thread_, CurrentThreadRef());
-# else
-  return true;
-# endif  // CS_DEBUG_CHECKS
 #else
-# error Unsupported platform.
+  return true;
+#endif  // CS_DEBUG_CHECKS
+#else
+#error Unsupported platform.
 #endif
 }
 
-CritScope::CritScope(const CriticalSection* cs) : cs_(cs) { cs_->Enter(); }
-CritScope::~CritScope() { cs_->Leave(); }
+CritScope::CritScope(const CriticalSection* cs) : cs_(cs) {
+  cs_->Enter();
+}
+CritScope::~CritScope() {
+  cs_->Leave();
+}
 
 TryCritScope::TryCritScope(const CriticalSection* cs)
     : cs_(cs), locked_(cs->TryEnter()) {
@@ -241,8 +245,7 @@
   lock_acquired = 0;
 }
 
-GlobalLockScope::GlobalLockScope(GlobalLockPod* lock)
-    : lock_(lock) {
+GlobalLockScope::GlobalLockScope(GlobalLockPod* lock) : lock_(lock) {
   lock_->Lock();
 }
 
diff --git a/rtc_base/criticalsection.h b/rtc_base/criticalsection.h
index 569e147..ce6fca1 100644
--- a/rtc_base/criticalsection.h
+++ b/rtc_base/criticalsection.h
@@ -18,13 +18,16 @@
 #include "typedefs.h"  // NOLINT(build/include)
 
 #if defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
+
 // Include winsock2.h before including <windows.h> to maintain consistency with
-// win32.h.  We can't include win32.h directly here since it pulls in
-// headers such as basictypes.h which causes problems in Chromium where webrtc
-// exists as two separate projects, webrtc and libjingle.
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
 #include <winsock2.h>
 #include <windows.h>
 #include <sal.h>  // must come after windows headers.
+// clang-format on
 #endif  // defined(WEBRTC_WIN)
 
 #if defined(WEBRTC_POSIX)
@@ -67,7 +70,7 @@
 #if defined(WEBRTC_WIN)
   mutable CRITICAL_SECTION crit_;
 #elif defined(WEBRTC_POSIX)
-# if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
+#if defined(WEBRTC_MAC) && !USE_NATIVE_MUTEX_ON_MAC
   // Number of times the lock has been locked + number of threads waiting.
   // TODO(tommi): We could use this number and subtract the recursion count
   // to find places where we have multiple threads contending on the same lock.
@@ -79,13 +82,13 @@
   mutable dispatch_semaphore_t semaphore_;
   // The thread that currently holds the lock. Required to handle recursion.
   mutable PlatformThreadRef owning_thread_;
-# else
+#else
   mutable pthread_mutex_t mutex_;
-# endif
+#endif
   mutable PlatformThreadRef thread_;  // Only used by RTC_DCHECKs.
   mutable int recursion_count_;       // Only used by RTC_DCHECKs.
 #else  // !defined(WEBRTC_WIN) && !defined(WEBRTC_POSIX)
-# error Unsupported platform.
+#error Unsupported platform.
 #endif
 };
 
@@ -114,9 +117,9 @@
 #if defined(WEBRTC_WIN)
   _Check_return_ bool locked() const;
 #elif defined(WEBRTC_POSIX)
-  bool locked() const __attribute__ ((__warn_unused_result__));
+  bool locked() const __attribute__((__warn_unused_result__));
 #else  // !defined(WEBRTC_WIN) && !defined(WEBRTC_POSIX)
-# error Unsupported platform.
+#error Unsupported platform.
 #endif
  private:
   const CriticalSection* const cs_;
@@ -153,6 +156,6 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(GlobalLockScope);
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_CRITICALSECTION_H_
+#endif  // RTC_BASE_CRITICALSECTION_H_
diff --git a/rtc_base/criticalsection_unittest.cc b/rtc_base/criticalsection_unittest.cc
index 6792504..db4f9e7 100644
--- a/rtc_base/criticalsection_unittest.cc
+++ b/rtc_base/criticalsection_unittest.cc
@@ -63,9 +63,8 @@
     }
   }
 
-  void Finalize() {
-    EXPECT_EQ(1, zero_count_);
-  }
+  void Finalize() { EXPECT_EQ(1, zero_count_); }
+
  private:
   int zero_count_;
 };
@@ -86,18 +85,14 @@
     return done_event_.Wait(kLongTime);
   }
 
-  void SetExpectedThreadCount(int count) {
-    threads_active_ = count;
-  }
+  void SetExpectedThreadCount(int count) { threads_active_ = count; }
 
   int shared_value() const { return shared_value_; }
 
  protected:
   // Derived classes must override OnMessage, and call BeforeStart and AfterEnd
   // at the beginning and the end of OnMessage respectively.
-  void BeforeStart() {
-    ASSERT_TRUE(start_event_.Wait(kLongTime));
-  }
+  void BeforeStart() { ASSERT_TRUE(start_event_.Wait(kLongTime)); }
 
   // Returns true if all threads have finished.
   bool AfterEnd() {
@@ -168,7 +163,7 @@
       values.push_back(Op::AtomicOp(&shared_value_));
     }
 
-    { // Add them all to the set.
+    {  // Add them all to the set.
       CritScope cs(&all_values_crit_);
       verifier_.Verify(values);
     }
@@ -255,8 +250,8 @@
 
 TEST(AtomicOpsTest, Decrement) {
   // Create and start lots of threads.
-  AtomicOpRunner<DecrementOp, UniqueValueVerifier> runner(
-      kOperationsToRun * kNumThreads);
+  AtomicOpRunner<DecrementOp, UniqueValueVerifier> runner(kOperationsToRun *
+                                                          kNumThreads);
   std::vector<std::unique_ptr<Thread>> threads;
   StartThreads(&threads, &runner);
   runner.SetExpectedThreadCount(kNumThreads);
@@ -305,8 +300,10 @@
 class PerfTestData {
  public:
   PerfTestData(int expected_count, Event* event)
-      : cache_line_barrier_1_(), cache_line_barrier_2_(),
-        expected_count_(expected_count), event_(event) {
+      : cache_line_barrier_1_(),
+        cache_line_barrier_2_(),
+        expected_count_(expected_count),
+        event_(event) {
     cache_line_barrier_1_[0]++;  // Avoid 'is not used'.
     cache_line_barrier_2_[0]++;  // Avoid 'is not used'.
   }
diff --git a/rtc_base/cryptstring.cc b/rtc_base/cryptstring.cc
index 421710c..2c7c0c7 100644
--- a/rtc_base/cryptstring.cc
+++ b/rtc_base/cryptstring.cc
@@ -34,15 +34,12 @@
   dest->clear();
 }
 
-CryptString::CryptString() : impl_(new EmptyCryptStringImpl()) {
-}
+CryptString::CryptString() : impl_(new EmptyCryptStringImpl()) {}
 
 CryptString::CryptString(const CryptString& other)
-    : impl_(other.impl_->Copy()) {
-}
+    : impl_(other.impl_->Copy()) {}
 
-CryptString::CryptString(const CryptStringImpl& impl) : impl_(impl.Copy()) {
-}
+CryptString::CryptString(const CryptStringImpl& impl) : impl_(impl.Copy()) {}
 
 CryptString::~CryptString() = default;
 
diff --git a/rtc_base/cryptstring.h b/rtc_base/cryptstring.h
index c210487..d0e36cb 100644
--- a/rtc_base/cryptstring.h
+++ b/rtc_base/cryptstring.h
@@ -23,10 +23,10 @@
  public:
   virtual ~CryptStringImpl() {}
   virtual size_t GetLength() const = 0;
-  virtual void CopyTo(char * dest, bool nullterminate) const = 0;
+  virtual void CopyTo(char* dest, bool nullterminate) const = 0;
   virtual std::string UrlEncode() const = 0;
-  virtual CryptStringImpl * Copy() const = 0;
-  virtual void CopyRawTo(std::vector<unsigned char> * dest) const = 0;
+  virtual CryptStringImpl* Copy() const = 0;
+  virtual void CopyRawTo(std::vector<unsigned char>* dest) const = 0;
 };
 
 class EmptyCryptStringImpl : public CryptStringImpl {
@@ -49,7 +49,7 @@
   CryptString(const CryptString& other);
   explicit CryptString(const CryptStringImpl& impl);
   ~CryptString();
-  CryptString & operator=(const CryptString & other) {
+  CryptString& operator=(const CryptString& other) {
     if (this != &other) {
       impl_.reset(other.impl_->Copy());
     }
@@ -57,7 +57,7 @@
   }
   void Clear() { impl_.reset(new EmptyCryptStringImpl()); }
   std::string UrlEncode() const { return impl_->UrlEncode(); }
-  void CopyRawTo(std::vector<unsigned char> * dest) const {
+  void CopyRawTo(std::vector<unsigned char>* dest) const {
     return impl_->CopyRawTo(dest);
   }
 
diff --git a/rtc_base/deprecation.h b/rtc_base/deprecation.h
index af776d5..f285ab0 100644
--- a/rtc_base/deprecation.h
+++ b/rtc_base/deprecation.h
@@ -37,7 +37,7 @@
 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=5368).
 #define RTC_DEPRECATED __declspec(deprecated)
 #elif defined(__GNUC__)
-#define RTC_DEPRECATED __attribute__ ((__deprecated__))
+#define RTC_DEPRECATED __attribute__((__deprecated__))
 #else
 #define RTC_DEPRECATED
 #endif
diff --git a/rtc_base/dscp.h b/rtc_base/dscp.h
index bdce466..3c39ca6 100644
--- a/rtc_base/dscp.h
+++ b/rtc_base/dscp.h
@@ -17,29 +17,29 @@
 enum DiffServCodePoint {
   DSCP_NO_CHANGE = -1,
   DSCP_DEFAULT = 0,  // Same as DSCP_CS0
-  DSCP_CS0  = 0,   // The default
-  DSCP_CS1  = 8,   // Bulk/background traffic
+  DSCP_CS0 = 0,      // The default
+  DSCP_CS1 = 8,      // Bulk/background traffic
   DSCP_AF11 = 10,
   DSCP_AF12 = 12,
   DSCP_AF13 = 14,
-  DSCP_CS2  = 16,
+  DSCP_CS2 = 16,
   DSCP_AF21 = 18,
   DSCP_AF22 = 20,
   DSCP_AF23 = 22,
-  DSCP_CS3  = 24,
+  DSCP_CS3 = 24,
   DSCP_AF31 = 26,
   DSCP_AF32 = 28,
   DSCP_AF33 = 30,
-  DSCP_CS4  = 32,
+  DSCP_CS4 = 32,
   DSCP_AF41 = 34,  // Video
   DSCP_AF42 = 36,  // Video
   DSCP_AF43 = 38,  // Video
-  DSCP_CS5  = 40,  // Video
-  DSCP_EF   = 46,  // Voice
-  DSCP_CS6  = 48,  // Voice
-  DSCP_CS7  = 56,  // Control messages
+  DSCP_CS5 = 40,   // Video
+  DSCP_EF = 46,    // Voice
+  DSCP_CS6 = 48,   // Voice
+  DSCP_CS7 = 56,   // Control messages
 };
 
 }  // namespace rtc
 
- #endif  // RTC_BASE_DSCP_H_
+#endif  // RTC_BASE_DSCP_H_
diff --git a/rtc_base/event.cc b/rtc_base/event.cc
index ff4faad..6c9639b 100644
--- a/rtc_base/event.cc
+++ b/rtc_base/event.cc
@@ -52,11 +52,33 @@
 
 #elif defined(WEBRTC_POSIX)
 
+// On MacOS, clock_gettime is available from version 10.12, and on
+// iOS, from version 10.0. So we can't use it yet.
+#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+#define USE_CLOCK_GETTIME 0
+#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
+// On Android, pthread_condattr_setclock is available from version 21. By
+// default, we target a new enough version for 64-bit platforms but not for
+// 32-bit platforms. For older versions, use
+// pthread_cond_timedwait_monotonic_np.
+#elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21)
+#define USE_CLOCK_GETTIME 1
+#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1
+#else
+#define USE_CLOCK_GETTIME 1
+#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
+#endif
+
 Event::Event(bool manual_reset, bool initially_signaled)
-    : is_manual_reset_(manual_reset),
-      event_status_(initially_signaled) {
+    : is_manual_reset_(manual_reset), event_status_(initially_signaled) {
   RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0);
-  RTC_CHECK(pthread_cond_init(&event_cond_, nullptr) == 0);
+  pthread_condattr_t cond_attr;
+  RTC_CHECK(pthread_condattr_init(&cond_attr) == 0);
+#if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
+  RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0);
+#endif
+  RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0);
+  pthread_condattr_destroy(&cond_attr);
 }
 
 Event::~Event() {
@@ -82,14 +104,17 @@
 
   struct timespec ts;
   if (milliseconds != kForever) {
-    // Converting from seconds and microseconds (1e-6) plus
-    // milliseconds (1e-3) to seconds and nanoseconds (1e-9).
-
+#if USE_CLOCK_GETTIME
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
     struct timeval tv;
     gettimeofday(&tv, nullptr);
+    ts.tv_sec = tv.tv_sec;
+    ts.tv_nsec = tv.tv_usec * 1000;
+#endif
 
-    ts.tv_sec = tv.tv_sec + (milliseconds / 1000);
-    ts.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;
+    ts.tv_sec += (milliseconds / 1000);
+    ts.tv_nsec += (milliseconds % 1000) * 1000000;
 
     // Handle overflow.
     if (ts.tv_nsec >= 1000000000) {
@@ -101,7 +126,12 @@
   pthread_mutex_lock(&event_mutex_);
   if (milliseconds != kForever) {
     while (!event_status_ && error == 0) {
+#if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
+      error =
+          pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_, &ts);
+#else
       error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
+#endif
     }
   } else {
     while (!event_status_ && error == 0)
diff --git a/rtc_base/event_tracer.cc b/rtc_base/event_tracer.cc
index 3461ec6..31f4271 100644
--- a/rtc_base/event_tracer.cc
+++ b/rtc_base/event_tracer.cc
@@ -63,15 +63,8 @@
                                 const unsigned long long* arg_values,
                                 unsigned char flags) {
   if (g_add_trace_event_ptr) {
-    g_add_trace_event_ptr(phase,
-                          category_enabled,
-                          name,
-                          id,
-                          num_args,
-                          arg_names,
-                          arg_types,
-                          arg_values,
-                          flags);
+    g_add_trace_event_ptr(phase, category_enabled, name, id, num_args,
+                          arg_names, arg_types, arg_values, flags);
   }
 }
 
@@ -128,8 +121,8 @@
         {name, category_enabled, phase, args, timestamp, 1, thread_id});
   }
 
-// The TraceEvent format is documented here:
-// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+  // The TraceEvent format is documented here:
+  // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
   void Log() {
     RTC_DCHECK(output_file_);
     static const int kLoggingIntervalMs = 100;
diff --git a/rtc_base/event_tracer.h b/rtc_base/event_tracer.h
index fc7ad04..4bbda57 100644
--- a/rtc_base/event_tracer.h
+++ b/rtc_base/event_tracer.h
@@ -45,27 +45,24 @@
 //
 // This method must be called before any WebRTC methods. Functions
 // provided should be thread-safe.
-void SetupEventTracer(
-    GetCategoryEnabledPtr get_category_enabled_ptr,
-    AddTraceEventPtr add_trace_event_ptr);
+void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
+                      AddTraceEventPtr add_trace_event_ptr);
 
 // This class defines interface for the event tracing system to call
 // internally. Do not call these methods directly.
 class EventTracer {
  public:
-  static const unsigned char* GetCategoryEnabled(
-      const char* name);
+  static const unsigned char* GetCategoryEnabled(const char* name);
 
-  static void AddTraceEvent(
-      char phase,
-      const unsigned char* category_enabled,
-      const char* name,
-      unsigned long long id,
-      int num_args,
-      const char** arg_names,
-      const unsigned char* arg_types,
-      const unsigned long long* arg_values,
-      unsigned char flags);
+  static void AddTraceEvent(char phase,
+                            const unsigned char* category_enabled,
+                            const char* name,
+                            unsigned long long id,
+                            int num_args,
+                            const char** arg_names,
+                            const unsigned char* arg_types,
+                            const unsigned long long* arg_values,
+                            unsigned char flags);
 };
 
 }  // namespace webrtc
diff --git a/rtc_base/event_tracer_unittest.cc b/rtc_base/event_tracer_unittest.cc
index 25b300b..27248e7 100644
--- a/rtc_base/event_tracer_unittest.cc
+++ b/rtc_base/event_tracer_unittest.cc
@@ -17,16 +17,11 @@
 
 class TestStatistics {
  public:
-  TestStatistics() : events_logged_(0) {
-  }
+  TestStatistics() : events_logged_(0) {}
 
-  void Reset() {
-    events_logged_ = 0;
-  }
+  void Reset() { events_logged_ = 0; }
 
-  void Increment() {
-    ++events_logged_;
-  }
+  void Increment() { ++events_logged_; }
 
   int Count() const { return events_logged_; }
 
@@ -62,18 +57,14 @@
 namespace webrtc {
 
 TEST(EventTracerTest, EventTracerDisabled) {
-  {
-    TRACE_EVENT0("test", "EventTracerDisabled");
-  }
+  { TRACE_EVENT0("test", "EventTracerDisabled"); }
   EXPECT_FALSE(TestStatistics::Get()->Count());
   TestStatistics::Get()->Reset();
 }
 
 TEST(EventTracerTest, ScopedTraceEvent) {
   SetupEventTracer(&GetCategoryEnabledHandler, &AddTraceEventHandler);
-  {
-    TRACE_EVENT0("test", "ScopedTraceEvent");
-  }
+  { TRACE_EVENT0("test", "ScopedTraceEvent"); }
   EXPECT_EQ(2, TestStatistics::Get()->Count());
   TestStatistics::Get()->Reset();
 }
diff --git a/rtc_base/event_unittest.cc b/rtc_base/event_unittest.cc
index 5bb6f77..050619e 100644
--- a/rtc_base/event_unittest.cc
+++ b/rtc_base/event_unittest.cc
@@ -41,7 +41,7 @@
 }
 
 class SignalerThread {
-public:
+ public:
   SignalerThread() : thread_(&ThreadFn, this, "EventPerf") {}
   void Start(Event* writer, Event* reader) {
     writer_ = writer;
@@ -52,9 +52,9 @@
     stop_event_.Set();
     thread_.Stop();
   }
-  static void ThreadFn(void *param) {
+  static void ThreadFn(void* param) {
     auto* me = static_cast<SignalerThread*>(param);
-    while(!me->stop_event_.Wait(0)) {
+    while (!me->stop_event_.Wait(0)) {
       me->writer_->Set();
       me->reader_->Wait(Event::kForever);
     }
diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn
index 1ba8827..a95e258 100644
--- a/rtc_base/experiments/BUILD.gn
+++ b/rtc_base/experiments/BUILD.gn
@@ -15,8 +15,25 @@
   ]
   deps = [
     "../:rtc_base_approved",
-    "../../api:optional",
     "../../system_wrappers:field_trial_api",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
+rtc_static_library("field_trial_parser") {
+  sources = [
+    "field_trial_parser.cc",
+    "field_trial_parser.h",
+    "field_trial_units.cc",
+    "field_trial_units.h",
+  ]
+  deps = [
+    "../:rtc_base_approved",
+    "../../api/units:data_rate",
+    "../../api/units:data_size",
+    "../../api/units:time_delta",
+    "../../system_wrappers:field_trial_api",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -27,8 +44,8 @@
   ]
   deps = [
     "../:rtc_base_approved",
-    "../../api:optional",
     "../../system_wrappers:field_trial_api",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -40,9 +57,9 @@
   deps = [
     "../:rtc_base_approved",
     "../..:webrtc_common",
-    "../../api:optional",
     "../../api/video_codecs:video_codecs_api",
     "../../system_wrappers:field_trial_api",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 }
 
@@ -52,13 +69,17 @@
 
     sources = [
       "congestion_controller_experiment_unittest.cc",
+      "field_trial_parser_unittest.cc",
+      "field_trial_units_unittest.cc",
       "quality_scaling_experiment_unittest.cc",
     ]
     deps = [
       ":congestion_controller_experiment",
+      ":field_trial_parser",
       ":quality_scaling_experiment",
       "../:rtc_base_tests_main",
       "../:rtc_base_tests_utils",
+      "../../system_wrappers:field_trial_api",
       "../../test:field_trial",
     ]
   }
diff --git a/rtc_base/experiments/alr_experiment.cc b/rtc_base/experiments/alr_experiment.cc
index c69caed..dff5ace 100644
--- a/rtc_base/experiments/alr_experiment.cc
+++ b/rtc_base/experiments/alr_experiment.cc
@@ -31,9 +31,9 @@
              .empty();
 }
 
-rtc::Optional<AlrExperimentSettings>
+absl::optional<AlrExperimentSettings>
 AlrExperimentSettings::CreateFromFieldTrial(const char* experiment_name) {
-  rtc::Optional<AlrExperimentSettings> ret;
+  absl::optional<AlrExperimentSettings> ret;
   std::string group_name = field_trial::FindFullName(experiment_name);
 
   const std::string kIgnoredSuffix = "_Dogfood";
diff --git a/rtc_base/experiments/alr_experiment.h b/rtc_base/experiments/alr_experiment.h
index a9c483d..4d9fd00 100644
--- a/rtc_base/experiments/alr_experiment.h
+++ b/rtc_base/experiments/alr_experiment.h
@@ -11,7 +11,7 @@
 #ifndef RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
 #define RTC_BASE_EXPERIMENTS_ALR_EXPERIMENT_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace webrtc {
 struct AlrExperimentSettings {
@@ -28,7 +28,7 @@
 
   static const char kScreenshareProbingBweExperimentName[];
   static const char kStrictPacingAndProbingExperimentName[];
-  static rtc::Optional<AlrExperimentSettings> CreateFromFieldTrial(
+  static absl::optional<AlrExperimentSettings> CreateFromFieldTrial(
       const char* experiment_name);
   static bool MaxOneFieldTrialEnabled();
 
diff --git a/rtc_base/experiments/congestion_controller_experiment.cc b/rtc_base/experiments/congestion_controller_experiment.cc
index 5733fea..2b7d776 100644
--- a/rtc_base/experiments/congestion_controller_experiment.cc
+++ b/rtc_base/experiments/congestion_controller_experiment.cc
@@ -16,42 +16,18 @@
 namespace webrtc {
 namespace {
 
-const char kBbrControllerExperiment[] = "WebRTC-BweCongestionController";
+const char kControllerExperiment[] = "WebRTC-BweCongestionController";
 }  // namespace
 
 bool CongestionControllerExperiment::BbrControllerEnabled() {
   std::string trial_string =
-      webrtc::field_trial::FindFullName(kBbrControllerExperiment);
+      webrtc::field_trial::FindFullName(kControllerExperiment);
   return trial_string.find("Enabled,BBR") == 0;
 }
 
-rtc::Optional<CongestionControllerExperiment::BbrExperimentConfig>
-CongestionControllerExperiment::GetBbrExperimentConfig() {
-  if (!BbrControllerEnabled())
-    return rtc::nullopt;
+bool CongestionControllerExperiment::InjectedControllerEnabled() {
   std::string trial_string =
-      webrtc::field_trial::FindFullName(kBbrControllerExperiment);
-  BbrExperimentConfig config;
-  if (sscanf(
-          trial_string.c_str(),
-          "Enabled,BBR,"
-          "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
-          "%lf,%lf,%lf,%lf,%lf,%lf",
-          &config.exit_startup_on_loss, &config.exit_startup_rtt_threshold_ms,
-          &config.fully_drain_queue, &config.initial_conservation_in_startup,
-          &config.num_startup_rtts, &config.probe_rtt_based_on_bdp,
-          &config.probe_rtt_disabled_if_app_limited,
-          &config.probe_rtt_skipped_if_similar_rtt, &config.rate_based_recovery,
-          &config.rate_based_startup, &config.slower_startup,
-          &config.encoder_rate_gain, &config.encoder_rate_gain_in_probe_rtt,
-          &config.max_ack_height_window_multiplier,
-          &config.max_aggregation_bytes_multiplier,
-          &config.probe_bw_pacing_gain_offset,
-          &config.probe_rtt_congestion_window_gain) == 17) {
-    return config;
-  } else {
-    return rtc::nullopt;
-  }
+      webrtc::field_trial::FindFullName(kControllerExperiment);
+  return trial_string.find("Enabled,Injected") == 0;
 }
-
 }  // namespace webrtc
diff --git a/rtc_base/experiments/congestion_controller_experiment.h b/rtc_base/experiments/congestion_controller_experiment.h
index 478d106..1f2d8ae 100644
--- a/rtc_base/experiments/congestion_controller_experiment.h
+++ b/rtc_base/experiments/congestion_controller_experiment.h
@@ -9,31 +9,12 @@
  */
 #ifndef RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
 #define RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
-#include <api/optional.h>
+
 namespace webrtc {
 class CongestionControllerExperiment {
  public:
-  struct BbrExperimentConfig {
-    int exit_startup_on_loss;
-    int exit_startup_rtt_threshold_ms;
-    int fully_drain_queue;
-    int initial_conservation_in_startup;
-    int num_startup_rtts;
-    int probe_rtt_based_on_bdp;
-    int probe_rtt_disabled_if_app_limited;
-    int probe_rtt_skipped_if_similar_rtt;
-    int rate_based_recovery;
-    int rate_based_startup;
-    int slower_startup;
-    double encoder_rate_gain;
-    double encoder_rate_gain_in_probe_rtt;
-    double max_ack_height_window_multiplier;
-    double max_aggregation_bytes_multiplier;
-    double probe_bw_pacing_gain_offset;
-    double probe_rtt_congestion_window_gain;
-  };
   static bool BbrControllerEnabled();
-  static rtc::Optional<BbrExperimentConfig> GetBbrExperimentConfig();
+  static bool InjectedControllerEnabled();
 };
 
 }  // namespace webrtc
diff --git a/rtc_base/experiments/congestion_controller_experiment_unittest.cc b/rtc_base/experiments/congestion_controller_experiment_unittest.cc
index b8e1fff..7f929e6 100644
--- a/rtc_base/experiments/congestion_controller_experiment_unittest.cc
+++ b/rtc_base/experiments/congestion_controller_experiment_unittest.cc
@@ -13,35 +13,6 @@
 #include "test/field_trial.h"
 
 namespace webrtc {
-namespace {
-void ExpectEquals(CongestionControllerExperiment::BbrExperimentConfig a,
-                  CongestionControllerExperiment::BbrExperimentConfig b) {
-  EXPECT_EQ(a.exit_startup_on_loss, b.exit_startup_on_loss);
-  EXPECT_EQ(a.exit_startup_rtt_threshold_ms, b.exit_startup_rtt_threshold_ms);
-  EXPECT_EQ(a.fully_drain_queue, b.fully_drain_queue);
-  EXPECT_EQ(a.initial_conservation_in_startup,
-            b.initial_conservation_in_startup);
-  EXPECT_EQ(a.num_startup_rtts, b.num_startup_rtts);
-  EXPECT_EQ(a.probe_rtt_based_on_bdp, b.probe_rtt_based_on_bdp);
-  EXPECT_EQ(a.probe_rtt_disabled_if_app_limited,
-            b.probe_rtt_disabled_if_app_limited);
-  EXPECT_EQ(a.probe_rtt_skipped_if_similar_rtt,
-            b.probe_rtt_skipped_if_similar_rtt);
-  EXPECT_EQ(a.rate_based_recovery, b.rate_based_recovery);
-  EXPECT_EQ(a.rate_based_startup, b.rate_based_startup);
-  EXPECT_EQ(a.slower_startup, b.slower_startup);
-  EXPECT_EQ(a.encoder_rate_gain, b.encoder_rate_gain);
-  EXPECT_EQ(a.encoder_rate_gain_in_probe_rtt, b.encoder_rate_gain_in_probe_rtt);
-  EXPECT_EQ(a.max_ack_height_window_multiplier,
-            b.max_ack_height_window_multiplier);
-  EXPECT_EQ(a.max_aggregation_bytes_multiplier,
-            b.max_aggregation_bytes_multiplier);
-  EXPECT_EQ(a.probe_bw_pacing_gain_offset, b.probe_bw_pacing_gain_offset);
-  EXPECT_EQ(a.probe_rtt_congestion_window_gain,
-            b.probe_rtt_congestion_window_gain);
-}
-}  // namespace
-
 TEST(CongestionControllerExperimentTest, BbrDisabledByDefault) {
   webrtc::test::ScopedFieldTrials field_trials("");
   EXPECT_FALSE(CongestionControllerExperiment::BbrControllerEnabled());
@@ -52,38 +23,4 @@
       "WebRTC-BweCongestionController/Enabled,BBR/");
   EXPECT_TRUE(CongestionControllerExperiment::BbrControllerEnabled());
 }
-
-TEST(CongestionControllerExperimentTest, BbrBadParametersFails) {
-  webrtc::test::ScopedFieldTrials field_trials(
-      "WebRTC-BweCongestionController/Enabled,BBR,"
-      "garbage,here/");
-  EXPECT_FALSE(CongestionControllerExperiment::GetBbrExperimentConfig());
-}
-
-TEST(CongestionControllerExperimentTest, BbrZeroParametersParsed) {
-  CongestionControllerExperiment::BbrExperimentConfig truth = {
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-  webrtc::test::ScopedFieldTrials field_trials(
-      "WebRTC-BweCongestionController/Enabled,BBR,"
-      "0,0,0,0,0,0,0,0,0,0,0,"
-      "0,0,0,0,0,0/");
-  auto config = CongestionControllerExperiment::GetBbrExperimentConfig();
-  EXPECT_TRUE(config);
-  if (config)
-    ExpectEquals(truth, *config);
-}
-
-TEST(CongestionControllerExperimentTest, BbrNonZeroParametersParsed) {
-  CongestionControllerExperiment::BbrExperimentConfig truth = {
-      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25};
-
-  webrtc::test::ScopedFieldTrials field_trials(
-      "WebRTC-BweCongestionController/Enabled,BBR,"
-      "1,1,1,1,1,1,1,1,1,1,1,"
-      "0.25,0.25,0.25,0.25,0.25,0.25/");
-  auto config = CongestionControllerExperiment::GetBbrExperimentConfig();
-  EXPECT_TRUE(config);
-  if (config)
-    ExpectEquals(truth, *config);
-}
 }  // namespace webrtc
diff --git a/rtc_base/experiments/field_trial_parser.cc b/rtc_base/experiments/field_trial_parser.cc
new file mode 100644
index 0000000..55299ad
--- /dev/null
+++ b/rtc_base/experiments/field_trial_parser.cc
@@ -0,0 +1,165 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+#include "rtc_base/experiments/field_trial_parser.h"
+
+#include <algorithm>
+#include <map>
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+
+int FindOrEnd(std::string str, size_t start, char delimiter) {
+  size_t pos = str.find(delimiter, start);
+  pos = (pos == std::string::npos) ? str.length() : pos;
+  return static_cast<int>(pos);
+}
+}  // namespace
+
+FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key)
+    : key_(key) {}
+FieldTrialParameterInterface::~FieldTrialParameterInterface() = default;
+std::string FieldTrialParameterInterface::Key() const {
+  return key_;
+}
+
+void ParseFieldTrial(
+    std::initializer_list<FieldTrialParameterInterface*> fields,
+    std::string trial_string) {
+  std::map<std::string, FieldTrialParameterInterface*> field_map;
+  for (FieldTrialParameterInterface* field : fields) {
+    field_map[field->Key()] = field;
+  }
+  size_t i = 0;
+  while (i < trial_string.length()) {
+    int val_end = FindOrEnd(trial_string, i, ',');
+    int colon_pos = FindOrEnd(trial_string, i, ':');
+    int key_end = std::min(val_end, colon_pos);
+    int val_begin = key_end + 1;
+    std::string key = trial_string.substr(i, key_end - i);
+    absl::optional<std::string> opt_value;
+    if (val_end >= val_begin)
+      opt_value = trial_string.substr(val_begin, val_end - val_begin);
+    i = val_end + 1;
+    auto field = field_map.find(key);
+    if (field != field_map.end()) {
+      if (!field->second->Parse(std::move(opt_value))) {
+        RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
+                            << "' in trial: \"" << trial_string << "\"";
+      }
+    } else {
+      RTC_LOG(LS_INFO) << "No field with key: '" << key
+                       << "' (found in trial: \"" << trial_string << "\")";
+    }
+  }
+}
+
+template <>
+absl::optional<bool> ParseTypedParameter<bool>(std::string str) {
+  if (str == "true" || str == "1") {
+    return true;
+  } else if (str == "false" || str == "0") {
+    return false;
+  }
+  return absl::nullopt;
+}
+
+template <>
+absl::optional<double> ParseTypedParameter<double>(std::string str) {
+  double value;
+  if (sscanf(str.c_str(), "%lf", &value) == 1) {
+    return value;
+  } else {
+    return absl::nullopt;
+  }
+}
+
+template <>
+absl::optional<int> ParseTypedParameter<int>(std::string str) {
+  int value;
+  if (sscanf(str.c_str(), "%i", &value) == 1) {
+    return value;
+  } else {
+    return absl::nullopt;
+  }
+}
+
+template <>
+absl::optional<std::string> ParseTypedParameter<std::string>(std::string str) {
+  return std::move(str);
+}
+
+FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {}
+
+FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value)
+    : FieldTrialParameterInterface(key), value_(default_value) {}
+
+bool FieldTrialFlag::Get() const {
+  return value_;
+}
+
+bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
+  // Only set the flag if there is no argument provided.
+  if (str_value) {
+    absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
+    if (!opt_value)
+      return false;
+    value_ = *opt_value;
+  } else {
+    value_ = true;
+  }
+  return true;
+}
+
+AbstractFieldTrialEnum::AbstractFieldTrialEnum(
+    std::string key,
+    int default_value,
+    std::map<std::string, int> mapping)
+    : FieldTrialParameterInterface(key),
+      value_(default_value),
+      enum_mapping_(mapping) {
+  for (auto& key_val : enum_mapping_)
+    valid_values_.insert(key_val.second);
+}
+AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
+    default;
+AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
+
+bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
+  if (str_value) {
+    auto it = enum_mapping_.find(*str_value);
+    if (it != enum_mapping_.end()) {
+      value_ = it->second;
+      return true;
+    }
+    absl::optional<int> value = ParseTypedParameter<int>(*str_value);
+    if (value.has_value() &&
+        (valid_values_.find(*value) != valid_values_.end())) {
+      value_ = *value;
+      return true;
+    }
+  }
+  return false;
+}
+
+template class FieldTrialParameter<bool>;
+template class FieldTrialParameter<double>;
+template class FieldTrialParameter<int>;
+template class FieldTrialParameter<std::string>;
+
+template class FieldTrialOptional<double>;
+template class FieldTrialOptional<int>;
+template class FieldTrialOptional<bool>;
+template class FieldTrialOptional<std::string>;
+
+}  // namespace webrtc
diff --git a/rtc_base/experiments/field_trial_parser.h b/rtc_base/experiments/field_trial_parser.h
new file mode 100644
index 0000000..a385ccf
--- /dev/null
+++ b/rtc_base/experiments/field_trial_parser.h
@@ -0,0 +1,189 @@
+/*
+ *  Copyright 2018 The WebRTC 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
+#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
+
+#include <stdint.h>
+#include <initializer_list>
+#include <map>
+#include <set>
+#include <string>
+#include "absl/types/optional.h"
+
+// Field trial parser functionality. Provides funcitonality to parse field trial
+// argument strings in key:value format. Each parameter is described using
+// key:value, parameters are separated with a ,. Values can't include the comma
+// character, since there's no quote facility. For most types, white space is
+// ignored. Parameters are declared with a given type for which an
+// implementation of ParseTypedParameter should be provided. The
+// ParseTypedParameter implementation is given whatever is between the : and the
+// ,. FieldTrialOptional will use nullopt if the key is provided without :.
+
+// Example string: "my_optional,my_int:3,my_string:hello"
+
+// For further description of usage and behavior, see the examples in the unit
+// tests.
+
+namespace webrtc {
+class FieldTrialParameterInterface {
+ public:
+  virtual ~FieldTrialParameterInterface();
+
+ protected:
+  explicit FieldTrialParameterInterface(std::string key);
+  friend void ParseFieldTrial(
+      std::initializer_list<FieldTrialParameterInterface*> fields,
+      std::string raw_string);
+  virtual bool Parse(absl::optional<std::string> str_value) = 0;
+  std::string Key() const;
+
+ private:
+  const std::string key_;
+};
+
+// ParseFieldTrial function parses the given string and fills the given fields
+// with extrated values if available.
+void ParseFieldTrial(
+    std::initializer_list<FieldTrialParameterInterface*> fields,
+    std::string raw_string);
+
+// Specialize this in code file for custom types. Should return absl::nullopt if
+// the given string cannot be properly parsed.
+template <typename T>
+absl::optional<T> ParseTypedParameter(std::string);
+
+// This class uses the ParseTypedParameter function to implement a parameter
+// implementation with an enforced default value.
+template <typename T>
+class FieldTrialParameter : public FieldTrialParameterInterface {
+ public:
+  FieldTrialParameter(std::string key, T default_value)
+      : FieldTrialParameterInterface(key), value_(default_value) {}
+  T Get() const { return value_; }
+  operator T() const { return Get(); }
+
+ protected:
+  bool Parse(absl::optional<std::string> str_value) override {
+    if (str_value) {
+      absl::optional<T> value = ParseTypedParameter<T>(*str_value);
+      if (value.has_value()) {
+        value_ = value.value();
+        return true;
+      }
+    }
+    return false;
+  }
+
+ private:
+  T value_;
+};
+
+class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
+ public:
+  AbstractFieldTrialEnum(std::string key,
+                         int default_value,
+                         std::map<std::string, int> mapping);
+  ~AbstractFieldTrialEnum() override;
+  AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
+
+ protected:
+  bool Parse(absl::optional<std::string> str_value) override;
+
+ protected:
+  int value_;
+  std::map<std::string, int> enum_mapping_;
+  std::set<int> valid_values_;
+};
+
+// The FieldTrialEnum class can be used to quickly define a parser for a
+// specific enum. It handles values provided as integers and as strings if a
+// mapping is provided.
+template <typename T>
+class FieldTrialEnum : public AbstractFieldTrialEnum {
+ public:
+  FieldTrialEnum(std::string key,
+                 T default_value,
+                 std::map<std::string, T> mapping)
+      : AbstractFieldTrialEnum(key,
+                               static_cast<int>(default_value),
+                               ToIntMap(mapping)) {}
+  T Get() const { return static_cast<T>(value_); }
+  operator T() const { return Get(); }
+
+ private:
+  static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
+    std::map<std::string, int> res;
+    for (const auto& it : mapping)
+      res[it.first] = static_cast<int>(it.second);
+    return res;
+  }
+};
+
+// This class uses the ParseTypedParameter function to implement an optional
+// parameter implementation that can default to absl::nullopt.
+template <typename T>
+class FieldTrialOptional : public FieldTrialParameterInterface {
+ public:
+  explicit FieldTrialOptional(std::string key)
+      : FieldTrialParameterInterface(key) {}
+  FieldTrialOptional(std::string key, absl::optional<T> default_value)
+      : FieldTrialParameterInterface(key), value_(default_value) {}
+  absl::optional<T> Get() const { return value_; }
+
+ protected:
+  bool Parse(absl::optional<std::string> str_value) override {
+    if (str_value) {
+      absl::optional<T> value = ParseTypedParameter<T>(*str_value);
+      if (!value.has_value())
+        return false;
+      value_ = value.value();
+    } else {
+      value_ = absl::nullopt;
+    }
+    return true;
+  }
+
+ private:
+  absl::optional<T> value_;
+};
+
+// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
+// are present. If key is missing, evaluates to false. If key is present, but no
+// explicit value is provided, the flag evaluates to true.
+class FieldTrialFlag : public FieldTrialParameterInterface {
+ public:
+  explicit FieldTrialFlag(std::string key);
+  FieldTrialFlag(std::string key, bool default_value);
+  bool Get() const;
+
+ protected:
+  bool Parse(absl::optional<std::string> str_value) override;
+
+ private:
+  bool value_;
+};
+
+// Accepts true, false, else parsed with sscanf %i, true if != 0.
+extern template class FieldTrialParameter<bool>;
+// Interpreted using sscanf %lf.
+extern template class FieldTrialParameter<double>;
+// Interpreted using sscanf %i.
+extern template class FieldTrialParameter<int>;
+// Using the given value as is.
+extern template class FieldTrialParameter<std::string>;
+
+extern template class FieldTrialOptional<double>;
+extern template class FieldTrialOptional<int>;
+extern template class FieldTrialOptional<bool>;
+extern template class FieldTrialOptional<std::string>;
+
+}  // namespace webrtc
+
+#endif  // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
diff --git a/rtc_base/experiments/field_trial_parser_unittest.cc b/rtc_base/experiments/field_trial_parser_unittest.cc
new file mode 100644
index 0000000..69f35bd
--- /dev/null
+++ b/rtc_base/experiments/field_trial_parser_unittest.cc
@@ -0,0 +1,125 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+#include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/gunit.h"
+#include "system_wrappers/include/field_trial.h"
+#include "test/field_trial.h"
+
+namespace webrtc {
+namespace {
+const char kDummyExperiment[] = "WebRTC-DummyExperiment";
+
+struct DummyExperiment {
+  FieldTrialFlag enabled = FieldTrialFlag("Enabled");
+  FieldTrialParameter<double> factor = FieldTrialParameter<double>("f", 0.5);
+  FieldTrialParameter<int> retries = FieldTrialParameter<int>("r", 5);
+  FieldTrialParameter<bool> ping = FieldTrialParameter<bool>("p", 0);
+  FieldTrialParameter<std::string> hash =
+      FieldTrialParameter<std::string>("h", "a80");
+
+  explicit DummyExperiment(std::string field_trial) {
+    ParseFieldTrial({&enabled, &factor, &retries, &ping, &hash}, field_trial);
+  }
+  DummyExperiment() {
+    std::string trial_string = field_trial::FindFullName(kDummyExperiment);
+    ParseFieldTrial({&enabled, &factor, &retries, &ping, &hash}, trial_string);
+  }
+};
+
+enum class CustomEnum {
+  kDefault = 0,
+  kRed = 1,
+  kBlue = 2,
+};
+}  // namespace
+
+TEST(FieldTrialParserTest, ParsesValidParameters) {
+  DummyExperiment exp("Enabled,f:-1.7,r:2,p:1,h:x7c");
+  EXPECT_TRUE(exp.enabled.Get());
+  EXPECT_EQ(exp.factor.Get(), -1.7);
+  EXPECT_EQ(exp.retries.Get(), 2);
+  EXPECT_EQ(exp.ping.Get(), true);
+  EXPECT_EQ(exp.hash.Get(), "x7c");
+}
+TEST(FieldTrialParserTest, InitializesFromFieldTrial) {
+  test::ScopedFieldTrials field_trials(
+      "WebRTC-OtherExperiment/Disabled/"
+      "WebRTC-DummyExperiment/Enabled,f:-1.7,r:2,p:1,h:x7c/"
+      "WebRTC-AnotherExperiment/Enabled,f:-3.1,otherstuff:beef/");
+  DummyExperiment exp;
+  EXPECT_TRUE(exp.enabled.Get());
+  EXPECT_EQ(exp.factor.Get(), -1.7);
+  EXPECT_EQ(exp.retries.Get(), 2);
+  EXPECT_EQ(exp.ping.Get(), true);
+  EXPECT_EQ(exp.hash.Get(), "x7c");
+}
+TEST(FieldTrialParserTest, UsesDefaults) {
+  DummyExperiment exp("");
+  EXPECT_FALSE(exp.enabled.Get());
+  EXPECT_EQ(exp.factor.Get(), 0.5);
+  EXPECT_EQ(exp.retries.Get(), 5);
+  EXPECT_EQ(exp.ping.Get(), false);
+  EXPECT_EQ(exp.hash.Get(), "a80");
+}
+TEST(FieldTrialParserTest, CanHandleMixedInput) {
+  DummyExperiment exp("p:true,h:,Enabled");
+  EXPECT_TRUE(exp.enabled.Get());
+  EXPECT_EQ(exp.factor.Get(), 0.5);
+  EXPECT_EQ(exp.retries.Get(), 5);
+  EXPECT_EQ(exp.ping.Get(), true);
+  EXPECT_EQ(exp.hash.Get(), "");
+}
+TEST(FieldTrialParserTest, IgnoresNewKey) {
+  DummyExperiment exp("Disabled,r:-11,foo");
+  EXPECT_FALSE(exp.enabled.Get());
+  EXPECT_EQ(exp.factor.Get(), 0.5);
+  EXPECT_EQ(exp.retries.Get(), -11);
+}
+TEST(FieldTrialParserTest, IgnoresInvalid) {
+  DummyExperiment exp("Enabled,f,p:,r:%,,:foo,h");
+  EXPECT_TRUE(exp.enabled.Get());
+  EXPECT_EQ(exp.factor.Get(), 0.5);
+  EXPECT_EQ(exp.retries.Get(), 5);
+  EXPECT_EQ(exp.ping.Get(), false);
+  EXPECT_EQ(exp.hash.Get(), "a80");
+}
+TEST(FieldTrialParserTest, ParsesOptionalParameters) {
+  FieldTrialOptional<int> max_count("c", absl::nullopt);
+  ParseFieldTrial({&max_count}, "");
+  EXPECT_FALSE(max_count.Get().has_value());
+  ParseFieldTrial({&max_count}, "c:10");
+  EXPECT_EQ(max_count.Get().value(), 10);
+  ParseFieldTrial({&max_count}, "c");
+  EXPECT_FALSE(max_count.Get().has_value());
+  ParseFieldTrial({&max_count}, "c:20");
+  EXPECT_EQ(max_count.Get().value(), 20);
+  ParseFieldTrial({&max_count}, "c:");
+  EXPECT_EQ(max_count.Get().value(), 20);
+  FieldTrialOptional<std::string> optional_string("s", std::string("ab"));
+  ParseFieldTrial({&optional_string}, "s:");
+  EXPECT_EQ(optional_string.Get().value(), "");
+  ParseFieldTrial({&optional_string}, "s");
+  EXPECT_FALSE(optional_string.Get().has_value());
+}
+TEST(FieldTrialParserTest, ParsesCustomEnumParameter) {
+  FieldTrialEnum<CustomEnum> my_enum("e", CustomEnum::kDefault,
+                                     {{"default", CustomEnum::kDefault},
+                                      {"red", CustomEnum::kRed},
+                                      {"blue", CustomEnum::kBlue}});
+  ParseFieldTrial({&my_enum}, "");
+  EXPECT_EQ(my_enum.Get(), CustomEnum::kDefault);
+  ParseFieldTrial({&my_enum}, "e:red");
+  EXPECT_EQ(my_enum.Get(), CustomEnum::kRed);
+  ParseFieldTrial({&my_enum}, "e:2");
+  EXPECT_EQ(my_enum.Get(), CustomEnum::kBlue);
+  ParseFieldTrial({&my_enum}, "e:5");
+  EXPECT_EQ(my_enum.Get(), CustomEnum::kBlue);
+}
+}  // namespace webrtc
diff --git a/rtc_base/experiments/field_trial_units.cc b/rtc_base/experiments/field_trial_units.cc
new file mode 100644
index 0000000..f53978b
--- /dev/null
+++ b/rtc_base/experiments/field_trial_units.cc
@@ -0,0 +1,92 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+#include "rtc_base/experiments/field_trial_units.h"
+
+#include <limits>
+#include <string>
+
+#include "absl/types/optional.h"
+
+// Large enough to fit "seconds", the longest supported unit name.
+#define RTC_TRIAL_UNIT_LENGTH_STR "7"
+#define RTC_TRIAL_UNIT_SIZE 8
+
+namespace webrtc {
+namespace {
+
+struct ValueWithUnit {
+  double value;
+  std::string unit;
+};
+
+absl::optional<ValueWithUnit> ParseValueWithUnit(std::string str) {
+  if (str == "inf") {
+    return ValueWithUnit{std::numeric_limits<double>::infinity(), ""};
+  } else if (str == "-inf") {
+    return ValueWithUnit{-std::numeric_limits<double>::infinity(), ""};
+  } else {
+    double double_val;
+    char unit_char[RTC_TRIAL_UNIT_SIZE];
+    unit_char[0] = 0;
+    if (sscanf(str.c_str(), "%lf%" RTC_TRIAL_UNIT_LENGTH_STR "s", &double_val,
+               unit_char) >= 1) {
+      return ValueWithUnit{double_val, unit_char};
+    }
+  }
+  return absl::nullopt;
+}
+}  // namespace
+
+template <>
+absl::optional<DataRate> ParseTypedParameter<DataRate>(std::string str) {
+  absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
+  if (result) {
+    if (result->unit.empty() || result->unit == "kbps") {
+      return DataRate::kbps(result->value);
+    } else if (result->unit == "bps") {
+      return DataRate::bps(result->value);
+    }
+  }
+  return absl::nullopt;
+}
+
+template <>
+absl::optional<DataSize> ParseTypedParameter<DataSize>(std::string str) {
+  absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
+  if (result) {
+    if (result->unit.empty() || result->unit == "bytes")
+      return DataSize::bytes(result->value);
+  }
+  return absl::nullopt;
+}
+
+template <>
+absl::optional<TimeDelta> ParseTypedParameter<TimeDelta>(std::string str) {
+  absl::optional<ValueWithUnit> result = ParseValueWithUnit(str);
+  if (result) {
+    if (result->unit == "s" || result->unit == "seconds") {
+      return TimeDelta::seconds(result->value);
+    } else if (result->unit == "us") {
+      return TimeDelta::us(result->value);
+    } else if (result->unit.empty() || result->unit == "ms") {
+      return TimeDelta::ms(result->value);
+    }
+  }
+  return absl::nullopt;
+}
+
+template class FieldTrialParameter<DataRate>;
+template class FieldTrialParameter<DataSize>;
+template class FieldTrialParameter<TimeDelta>;
+
+template class FieldTrialOptional<DataRate>;
+template class FieldTrialOptional<DataSize>;
+template class FieldTrialOptional<TimeDelta>;
+}  // namespace webrtc
diff --git a/rtc_base/experiments/field_trial_units.h b/rtc_base/experiments/field_trial_units.h
new file mode 100644
index 0000000..932c5cb
--- /dev/null
+++ b/rtc_base/experiments/field_trial_units.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2018 The WebRTC 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 RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
+#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
+
+#include "rtc_base/experiments/field_trial_parser.h"
+
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+
+namespace webrtc {
+extern template class FieldTrialParameter<DataRate>;
+extern template class FieldTrialParameter<DataSize>;
+extern template class FieldTrialParameter<TimeDelta>;
+
+extern template class FieldTrialOptional<DataRate>;
+extern template class FieldTrialOptional<DataSize>;
+extern template class FieldTrialOptional<TimeDelta>;
+}  // namespace webrtc
+
+#endif  // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_UNITS_H_
diff --git a/rtc_base/experiments/field_trial_units_unittest.cc b/rtc_base/experiments/field_trial_units_unittest.cc
new file mode 100644
index 0000000..1a2b75d
--- /dev/null
+++ b/rtc_base/experiments/field_trial_units_unittest.cc
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+#include <string>
+
+#include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/experiments/field_trial_units.h"
+#include "rtc_base/gunit.h"
+
+namespace webrtc {
+namespace {
+struct DummyExperiment {
+  FieldTrialParameter<DataRate> target_rate =
+      FieldTrialParameter<DataRate>("t", DataRate::kbps(100));
+  FieldTrialParameter<TimeDelta> period =
+      FieldTrialParameter<TimeDelta>("p", TimeDelta::ms(100));
+  FieldTrialOptional<DataSize> max_buffer =
+      FieldTrialOptional<DataSize>("b", absl::nullopt);
+
+  explicit DummyExperiment(std::string field_trial) {
+    ParseFieldTrial({&target_rate, &max_buffer, &period}, field_trial);
+  }
+};
+}  // namespace
+
+TEST(FieldTrialParserUnitsTest, FallsBackToDefaults) {
+  DummyExperiment exp("");
+  EXPECT_EQ(exp.target_rate.Get(), DataRate::kbps(100));
+  EXPECT_FALSE(exp.max_buffer.Get().has_value());
+  EXPECT_EQ(exp.period.Get(), TimeDelta::ms(100));
+}
+TEST(FieldTrialParserUnitsTest, ParsesUnitParameters) {
+  DummyExperiment exp("t:300kbps,b:5bytes,p:300ms");
+  EXPECT_EQ(exp.target_rate.Get(), DataRate::kbps(300));
+  EXPECT_EQ(*exp.max_buffer.Get(), DataSize::bytes(5));
+  EXPECT_EQ(exp.period.Get(), TimeDelta::ms(300));
+}
+TEST(FieldTrialParserUnitsTest, ParsesDefaultUnitParameters) {
+  DummyExperiment exp("t:300,b:5,p:300");
+  EXPECT_EQ(exp.target_rate.Get(), DataRate::kbps(300));
+  EXPECT_EQ(*exp.max_buffer.Get(), DataSize::bytes(5));
+  EXPECT_EQ(exp.period.Get(), TimeDelta::ms(300));
+}
+TEST(FieldTrialParserUnitsTest, ParsesInfinityParameter) {
+  DummyExperiment exp("t:inf,p:inf");
+  EXPECT_EQ(exp.target_rate.Get(), DataRate::Infinity());
+  EXPECT_EQ(exp.period.Get(), TimeDelta::PlusInfinity());
+}
+TEST(FieldTrialParserUnitsTest, ParsesOtherUnitParameters) {
+  DummyExperiment exp("t:300bps,p:0.3 seconds,b:8 bytes");
+  EXPECT_EQ(exp.target_rate.Get(), DataRate::bps(300));
+  EXPECT_EQ(*exp.max_buffer.Get(), DataSize::bytes(8));
+  EXPECT_EQ(exp.period.Get(), TimeDelta::ms(300));
+}
+
+}  // namespace webrtc
diff --git a/rtc_base/experiments/quality_scaling_experiment.cc b/rtc_base/experiments/quality_scaling_experiment.cc
index 8c99954..c13de3f 100644
--- a/rtc_base/experiments/quality_scaling_experiment.cc
+++ b/rtc_base/experiments/quality_scaling_experiment.cc
@@ -23,14 +23,14 @@
 constexpr int kMaxH264Qp = 51;
 constexpr int kMaxGenericQp = 255;
 
-rtc::Optional<VideoEncoder::QpThresholds> GetThresholds(int low,
-                                                        int high,
-                                                        int max) {
+absl::optional<VideoEncoder::QpThresholds> GetThresholds(int low,
+                                                         int high,
+                                                         int max) {
   if (low < kMinQp || high > max || high < low)
-    return rtc::nullopt;
+    return absl::nullopt;
 
   RTC_LOG(LS_INFO) << "QP thresholds: low: " << low << ", high: " << high;
-  return rtc::Optional<VideoEncoder::QpThresholds>(
+  return absl::optional<VideoEncoder::QpThresholds>(
       VideoEncoder::QpThresholds(low, high));
 }
 }  // namespace
@@ -39,11 +39,11 @@
   return webrtc::field_trial::IsEnabled(kFieldTrial);
 }
 
-rtc::Optional<QualityScalingExperiment::Settings>
+absl::optional<QualityScalingExperiment::Settings>
 QualityScalingExperiment::ParseSettings() {
   const std::string group = webrtc::field_trial::FindFullName(kFieldTrial);
   if (group.empty())
-    return rtc::nullopt;
+    return absl::nullopt;
 
   Settings s;
   if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%d",
@@ -51,16 +51,16 @@
              &s.h264_high, &s.generic_low, &s.generic_high, &s.alpha_high,
              &s.alpha_low, &s.drop) != 11) {
     RTC_LOG(LS_WARNING) << "Invalid number of parameters provided.";
-    return rtc::nullopt;
+    return absl::nullopt;
   }
   return s;
 }
 
-rtc::Optional<VideoEncoder::QpThresholds>
+absl::optional<VideoEncoder::QpThresholds>
 QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type) {
   const auto settings = ParseSettings();
   if (!settings)
-    return rtc::nullopt;
+    return absl::nullopt;
 
   switch (codec_type) {
     case kVideoCodecVP8:
@@ -73,7 +73,7 @@
       return GetThresholds(settings->generic_low, settings->generic_high,
                            kMaxGenericQp);
     default:
-      return rtc::nullopt;
+      return absl::nullopt;
   }
 }
 
diff --git a/rtc_base/experiments/quality_scaling_experiment.h b/rtc_base/experiments/quality_scaling_experiment.h
index 6f24d6b..80a25ef 100644
--- a/rtc_base/experiments/quality_scaling_experiment.h
+++ b/rtc_base/experiments/quality_scaling_experiment.h
@@ -10,7 +10,7 @@
 #ifndef RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
 #define RTC_BASE_EXPERIMENTS_QUALITY_SCALING_EXPERIMENT_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "api/video_codecs/video_encoder.h"
 #include "common_types.h"  // NOLINT(build/include)
 
@@ -44,10 +44,10 @@
   static bool Enabled();
 
   // Returns settings from field trial.
-  static rtc::Optional<Settings> ParseSettings();
+  static absl::optional<Settings> ParseSettings();
 
   // Returns QpThresholds for the |codec_type|.
-  static rtc::Optional<VideoEncoder::QpThresholds> GetQpThresholds(
+  static absl::optional<VideoEncoder::QpThresholds> GetQpThresholds(
       VideoCodecType codec_type);
 
   // Returns parsed values. If the parsing fails, default values are returned.
diff --git a/rtc_base/fakeclock.cc b/rtc_base/fakeclock.cc
index 721f699..ade9208 100644
--- a/rtc_base/fakeclock.cc
+++ b/rtc_base/fakeclock.cc
@@ -31,10 +31,10 @@
   MessageQueueManager::ProcessAllMessageQueues();
 }
 
-void FakeClock::AdvanceTime(TimeDelta delta) {
+void FakeClock::AdvanceTime(webrtc::TimeDelta delta) {
   {
     CritScope cs(&lock_);
-    time_ += delta.ToNanoseconds();
+    time_ += delta.ns();
   }
   MessageQueueManager::ProcessAllMessageQueues();
 }
diff --git a/rtc_base/fakeclock.h b/rtc_base/fakeclock.h
index 1b1ee71..2da8c61 100644
--- a/rtc_base/fakeclock.h
+++ b/rtc_base/fakeclock.h
@@ -11,8 +11,8 @@
 #ifndef RTC_BASE_FAKECLOCK_H_
 #define RTC_BASE_FAKECLOCK_H_
 
+#include "api/units/time_delta.h"
 #include "rtc_base/criticalsection.h"
-#include "rtc_base/timedelta.h"
 #include "rtc_base/timeutils.h"
 
 namespace rtc {
@@ -36,10 +36,11 @@
     SetTimeNanos(kNumNanosecsPerMicrosec * micros);
   }
 
-  void AdvanceTime(TimeDelta delta);
+  void AdvanceTime(webrtc::TimeDelta delta);
   void AdvanceTimeMicros(int64_t micros) {
-    AdvanceTime(rtc::TimeDelta::FromMicroseconds(micros));
+    AdvanceTime(webrtc::TimeDelta::us(micros));
   }
+
  private:
   CriticalSection lock_;
   int64_t time_ RTC_GUARDED_BY(lock_) = 0;
diff --git a/rtc_base/fakenetwork.h b/rtc_base/fakenetwork.h
index fd4eb61..8ed1164 100644
--- a/rtc_base/fakenetwork.h
+++ b/rtc_base/fakenetwork.h
@@ -28,8 +28,7 @@
 const int kFakeIPv6NetworkPrefixLength = 64;
 
 // Fake network manager that allows us to manually specify the IPs to use.
-class FakeNetworkManager : public NetworkManagerBase,
-                           public MessageHandler {
+class FakeNetworkManager : public NetworkManagerBase, public MessageHandler {
  public:
   FakeNetworkManager() {}
 
@@ -54,8 +53,7 @@
   }
 
   void RemoveInterface(const SocketAddress& iface) {
-    for (IfaceList::iterator it = ifaces_.begin();
-         it != ifaces_.end(); ++it) {
+    for (IfaceList::iterator it = ifaces_.begin(); it != ifaces_.end(); ++it) {
       if (it->first.EqualIPs(iface)) {
         ifaces_.erase(it);
         break;
@@ -79,9 +77,7 @@
   virtual void StopUpdating() { --start_count_; }
 
   // MessageHandler interface.
-  virtual void OnMessage(Message* msg) {
-    DoUpdateNetworks();
-  }
+  virtual void OnMessage(Message* msg) { DoUpdateNetworks(); }
 
   using NetworkManagerBase::set_enumeration_permission;
   using NetworkManagerBase::set_default_local_addresses;
@@ -91,8 +87,7 @@
     if (start_count_ == 0)
       return;
     std::vector<Network*> networks;
-    for (IfaceList::iterator it = ifaces_.begin();
-         it != ifaces_.end(); ++it) {
+    for (IfaceList::iterator it = ifaces_.begin(); it != ifaces_.end(); ++it) {
       int prefix_length = 0;
       if (it->first.ipaddr().family() == AF_INET) {
         prefix_length = kFakeIPv4NetworkPrefixLength;
diff --git a/rtc_base/fakesslidentity.cc b/rtc_base/fakesslidentity.cc
index 825c89b..80a3e78 100644
--- a/rtc_base/fakesslidentity.cc
+++ b/rtc_base/fakesslidentity.cc
@@ -14,9 +14,9 @@
 #include <string>
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/messagedigest.h"
-#include "rtc_base/ptr_util.h"
 
 namespace rtc {
 
@@ -77,13 +77,13 @@
 FakeSSLIdentity::FakeSSLIdentity(const std::vector<std::string>& pem_strings) {
   std::vector<std::unique_ptr<SSLCertificate>> certs;
   for (const std::string& pem_string : pem_strings) {
-    certs.push_back(MakeUnique<FakeSSLCertificate>(pem_string));
+    certs.push_back(absl::make_unique<FakeSSLCertificate>(pem_string));
   }
-  cert_chain_ = MakeUnique<SSLCertChain>(std::move(certs));
+  cert_chain_ = absl::make_unique<SSLCertChain>(std::move(certs));
 }
 
 FakeSSLIdentity::FakeSSLIdentity(const FakeSSLCertificate& cert)
-    : cert_chain_(MakeUnique<SSLCertChain>(&cert)) {}
+    : cert_chain_(absl::make_unique<SSLCertChain>(&cert)) {}
 
 FakeSSLIdentity::FakeSSLIdentity(const FakeSSLIdentity& o)
     : cert_chain_(o.cert_chain_->UniqueCopy()) {}
diff --git a/rtc_base/file.cc b/rtc_base/file.cc
index a6ee2aa..6202411 100644
--- a/rtc_base/file.cc
+++ b/rtc_base/file.cc
@@ -14,15 +14,6 @@
 
 namespace rtc {
 
-namespace {
-
-std::string NormalizePathname(Pathname&& path) {
-  path.Normalize();
-  return path.pathname();
-}
-
-}  // namespace
-
 File::File(PlatformFile file) : file_(file) {}
 
 File::File() : file_(kInvalidPlatformFileValue) {}
@@ -37,45 +28,15 @@
 }
 
 // static
-File File::Open(Pathname&& path) {
-  return Open(NormalizePathname(std::move(path)));
-}
-
-// static
-File File::Open(const Pathname& path) {
-  return Open(Pathname(path));
-}
-
-// static
 File File::Create(const std::string& path) {
   return File(CreatePlatformFile(path));
 }
 
 // static
-File File::Create(Pathname&& path) {
-  return Create(NormalizePathname(std::move(path)));
-}
-
-// static
-File File::Create(const Pathname& path) {
-  return Create(Pathname(path));
-}
-
-// static
 bool File::Remove(const std::string& path) {
   return RemoveFile(path);
 }
 
-// static
-bool File::Remove(Pathname&& path) {
-  return Remove(NormalizePathname(std::move(path)));
-}
-
-// static
-bool File::Remove(const Pathname& path) {
-  return Remove(Pathname(path));
-}
-
 File::File(File&& other) : file_(other.file_) {
   other.file_ = kInvalidPlatformFileValue;
 }
diff --git a/rtc_base/file.h b/rtc_base/file.h
index f87d9ce..75fd93d 100644
--- a/rtc_base/file.h
+++ b/rtc_base/file.h
@@ -16,7 +16,6 @@
 #include <string>
 
 #include "rtc_base/constructormagic.h"
-#include "rtc_base/pathutils.h"
 #include "rtc_base/platform_file.h"
 
 namespace rtc {
@@ -40,17 +39,11 @@
 
   // Open and Create give files with both reading and writing enabled.
   static File Open(const std::string& path);
-  static File Open(Pathname&& path);
-  static File Open(const Pathname& path);
   // If the file already exists it will be overwritten.
   static File Create(const std::string& path);
-  static File Create(Pathname&& path);
-  static File Create(const Pathname& path);
 
   // Remove a file in the file system.
   static bool Remove(const std::string& path);
-  static bool Remove(Pathname&& path);
-  static bool Remove(const Pathname& path);
 
   size_t Write(const uint8_t* data, size_t length);
   size_t Read(uint8_t* buffer, size_t length);
diff --git a/rtc_base/file_unittest.cc b/rtc_base/file_unittest.cc
index a8e39dd..5a72e5d 100644
--- a/rtc_base/file_unittest.cc
+++ b/rtc_base/file_unittest.cc
@@ -163,39 +163,13 @@
   EXPECT_TRUE(VerifyBuffer(out, 2, 0));
 }
 
-TEST_F(FileTest, OpenFromPathname) {
-  {
-    File file = File::Open(Pathname(path_));
-    ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-  }
-
-  {
-    Pathname path(path_);
-    File file = File::Open(path);
-    ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-  }
-}
-
-TEST_F(FileTest, CreateFromPathname) {
-  {
-    File file = File::Create(Pathname(path_));
-    ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-  }
-
-  {
-    Pathname path(path_);
-    File file = File::Create(path);
-    ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
-  }
-}
-
 TEST_F(FileTest, ShouldBeAbleToRemoveFile) {
   {
-    File file = File::Open(Pathname(path_));
+    File file = File::Open(path_);
     ASSERT_TRUE(file.IsOpen()) << "Error: " << LastError();
   }
 
-  ASSERT_TRUE(File::Remove(Pathname(path_))) << "Error: " << LastError();
+  ASSERT_TRUE(File::Remove(path_)) << "Error: " << LastError();
 }
 
 }  // namespace rtc
diff --git a/rtc_base/filerotatingstream.cc b/rtc_base/filerotatingstream.cc
index 4e3aa73..c9a663a 100644
--- a/rtc_base/filerotatingstream.cc
+++ b/rtc_base/filerotatingstream.cc
@@ -11,22 +11,22 @@
 #include "rtc_base/filerotatingstream.h"
 
 #include <algorithm>
-#include <iostream>
+#include <cstdio>
 #include <string>
 
 #include "rtc_base/checks.h"
 #include "rtc_base/fileutils.h"
 #include "rtc_base/pathutils.h"
+#include "rtc_base/strings/string_builder.h"
 
-// Note: We use std::cerr for logging in the write paths of this stream to avoid
+// Note: We use fprintf for logging in the write paths of this stream to avoid
 // infinite loops when logging.
 
 namespace rtc {
 
 FileRotatingStream::FileRotatingStream(const std::string& dir_path,
                                        const std::string& file_prefix)
-    : FileRotatingStream(dir_path, file_prefix, 0, 0, kRead) {
-}
+    : FileRotatingStream(dir_path, file_prefix, 0, 0, kRead) {}
 
 FileRotatingStream::FileRotatingStream(const std::string& dir_path,
                                        const std::string& file_prefix,
@@ -77,8 +77,7 @@
   }
 }
 
-FileRotatingStream::~FileRotatingStream() {
-}
+FileRotatingStream::~FileRotatingStream() {}
 
 StreamState FileRotatingStream::GetState() const {
   if (mode_ == kRead && current_file_index_ < file_names_.size()) {
@@ -149,7 +148,7 @@
     return SR_EOS;
   }
   if (!file_stream_) {
-    std::cerr << "Open() must be called before Write." << std::endl;
+    std::fprintf(stderr, "Open() must be called before Write.\n");
     return SR_ERROR;
   }
   // Write as much as will fit in to the current file.
@@ -213,7 +212,7 @@
       std::vector<std::string> matching_files = GetFilesWithPrefix();
       for (auto matching_file : matching_files) {
         if (!Filesystem::DeleteFile(matching_file)) {
-          std::cerr << "Failed to delete: " << matching_file << std::endl;
+          std::fprintf(stderr, "Failed to delete: %s\n", matching_file.c_str());
         }
       }
       return OpenCurrentFile();
@@ -225,8 +224,7 @@
 bool FileRotatingStream::DisableBuffering() {
   disable_buffering_ = true;
   if (!file_stream_) {
-    std::cerr << "Open() must be called before DisableBuffering()."
-              << std::endl;
+    std::fprintf(stderr, "Open() must be called before DisableBuffering().\n");
     return false;
   }
   return file_stream_->DisableBuffering();
@@ -257,8 +255,8 @@
   }
   int error = 0;
   if (!file_stream_->Open(file_path, mode, &error)) {
-    std::cerr << "Failed to open: " << file_path << "Error: " << error
-              << std::endl;
+    std::fprintf(stderr, "Failed to open: %s Error: %i\n", file_path.c_str(),
+                 error);
     file_stream_.reset();
     return false;
   }
@@ -286,7 +284,7 @@
   std::string file_to_delete = file_names_[rotation_index_];
   if (Filesystem::IsFile(file_to_delete)) {
     if (!Filesystem::DeleteFile(file_to_delete)) {
-      std::cerr << "Failed to delete: " << file_to_delete << std::endl;
+      std::fprintf(stderr, "Failed to delete: %s\n", file_to_delete.c_str());
     }
   }
   for (auto i = rotation_index_; i > 0; --i) {
@@ -294,8 +292,8 @@
     std::string unrotated_name = file_names_[i - 1];
     if (Filesystem::IsFile(unrotated_name)) {
       if (!Filesystem::MoveFile(unrotated_name, rotated_name)) {
-        std::cerr << "Failed to move: " << unrotated_name << " to "
-                  << rotated_name << std::endl;
+        std::fprintf(stderr, "Failed to move: %s to %s\n",
+                     unrotated_name.c_str(), rotated_name.c_str());
       }
     }
   }
@@ -327,21 +325,15 @@
 std::string FileRotatingStream::GetFilePath(size_t index,
                                             size_t num_files) const {
   RTC_DCHECK_LT(index, num_files);
-  std::ostringstream file_name;
-  // The format will be "_%<num_digits>zu". We want to zero pad the index so
-  // that it will sort nicely.
-  size_t max_digits = ((num_files - 1) / 10) + 1;
-  size_t num_digits = (index / 10) + 1;
-  RTC_DCHECK_LE(num_digits, max_digits);
-  size_t padding = max_digits - num_digits;
 
-  file_name << file_prefix_ << "_";
-  for (size_t i = 0; i < padding; ++i) {
-    file_name << "0";
-  }
-  file_name << index;
+  const size_t buffer_size = 32;
+  char file_postfix[buffer_size];
+  // We want to zero pad the index so that it will sort nicely.
+  const int max_digits = std::snprintf(nullptr, 0, "%zu", num_files - 1);
+  RTC_DCHECK_LT(1 + max_digits, buffer_size);
+  std::snprintf(file_postfix, buffer_size, "_%0*zu", max_digits, index);
 
-  Pathname file_path(dir_path_, file_name.str());
+  Pathname file_path(dir_path_, file_prefix_ + file_postfix);
   return file_path.pathname();
 }
 
@@ -349,8 +341,7 @@
     const std::string& dir_path)
     : FileRotatingStream(dir_path, kLogPrefix),
       max_total_log_size_(0),
-      num_rotations_(0) {
-}
+      num_rotations_(0) {}
 
 CallSessionFileRotatingStream::CallSessionFileRotatingStream(
     const std::string& dir_path,
diff --git a/rtc_base/filerotatingstream_unittest.cc b/rtc_base/filerotatingstream_unittest.cc
index 16db280..1905516 100644
--- a/rtc_base/filerotatingstream_unittest.cc
+++ b/rtc_base/filerotatingstream_unittest.cc
@@ -31,7 +31,7 @@
 
 }  // namespace
 
-#if defined (WEBRTC_ANDROID)
+#if defined(WEBRTC_ANDROID)
 // Fails on Android: https://bugs.chromium.org/p/webrtc/issues/detail?id=4364.
 #define MAYBE_FileRotatingStreamTest DISABLED_FileRotatingStreamTest
 #else
@@ -195,20 +195,20 @@
 // Tests that the returned file paths have the right folder and prefix.
 TEST_F(MAYBE_FileRotatingStreamTest, GetFilePath) {
   Init("FileRotatingStreamTestGetFilePath", kFilePrefix, kMaxFileSize, 20);
+  // dir_path_ includes a trailing delimiter.
+  const std::string prefix = dir_path_ + kFilePrefix;
   for (auto i = 0; i < 20; ++i) {
-    Pathname path(stream_->GetFilePath(i));
-    EXPECT_EQ(0, path.folder().compare(dir_path_));
-    EXPECT_EQ(0, path.filename().compare(0, strlen(kFilePrefix), kFilePrefix));
+    EXPECT_EQ(0, stream_->GetFilePath(i).compare(0, prefix.size(), prefix));
   }
 }
 
-#if defined (WEBRTC_ANDROID)
+#if defined(WEBRTC_ANDROID)
 // Fails on Android: https://bugs.chromium.org/p/webrtc/issues/detail?id=4364.
 #define MAYBE_CallSessionFileRotatingStreamTest \
-    DISABLED_CallSessionFileRotatingStreamTest
+  DISABLED_CallSessionFileRotatingStreamTest
 #else
 #define MAYBE_CallSessionFileRotatingStreamTest \
-    CallSessionFileRotatingStreamTest
+  CallSessionFileRotatingStreamTest
 #endif
 
 class MAYBE_CallSessionFileRotatingStreamTest : public ::testing::Test {
diff --git a/rtc_base/fileutils.cc b/rtc_base/fileutils.cc
index 40ec86f..7d83f97 100644
--- a/rtc_base/fileutils.cc
+++ b/rtc_base/fileutils.cc
@@ -35,7 +35,7 @@
 // to the first file in the directory, and can be advanecd with Next(). This
 // allows you to get information about each file.
 
-  // Constructor
+// Constructor
 DirectoryIterator::DirectoryIterator()
 #ifdef WEBRTC_WIN
     : handle_(INVALID_HANDLE_VALUE) {
@@ -45,7 +45,7 @@
 #endif
 }
 
-  // Destructor
+// Destructor
 DirectoryIterator::~DirectoryIterator() {
 #if defined(WEBRTC_WIN)
   if (handle_ != INVALID_HANDLE_VALUE)
@@ -56,10 +56,10 @@
 #endif
 }
 
-  // Starts traversing a directory.
-  // dir is the directory to traverse
-  // returns true if the directory exists and is valid
-bool DirectoryIterator::Iterate(const Pathname &dir) {
+// Starts traversing a directory.
+// dir is the directory to traverse
+// returns true if the directory exists and is valid
+bool DirectoryIterator::Iterate(const Pathname& dir) {
   directory_ = dir.pathname();
 #if defined(WEBRTC_WIN)
   if (handle_ != INVALID_HANDLE_VALUE)
@@ -84,8 +84,8 @@
   return true;
 }
 
-  // Advances to the next file
-  // returns true if there were more files in the directory.
+// Advances to the next file
+// returns true if there were more files in the directory.
 bool DirectoryIterator::Next() {
 #if defined(WEBRTC_WIN)
   return ::FindNextFile(handle_, &data_) == TRUE;
@@ -98,7 +98,7 @@
 #endif
 }
 
-  // returns true if the file currently pointed to is a directory
+// returns true if the file currently pointed to is a directory
 bool DirectoryIterator::IsDirectory() const {
 #if defined(WEBRTC_WIN)
   return (data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE;
@@ -107,7 +107,7 @@
 #endif
 }
 
-  // returns the name of the file currently pointed to
+// returns the name of the file currently pointed to
 std::string DirectoryIterator::Name() const {
 #if defined(WEBRTC_WIN)
   return ToUtf8(data_.cFileName);
@@ -117,17 +117,14 @@
 #endif
 }
 
-FilesystemInterface* Filesystem::default_filesystem_ = nullptr;
-
-FilesystemInterface *Filesystem::EnsureDefaultFilesystem() {
-  if (!default_filesystem_) {
+FilesystemInterface* Filesystem::GetFilesystem() {
 #if defined(WEBRTC_WIN)
-    default_filesystem_ = new Win32Filesystem();
+  static FilesystemInterface* const filesystem = new Win32Filesystem();
 #else
-    default_filesystem_ = new UnixFilesystem();
+  static FilesystemInterface* const filesystem = new UnixFilesystem();
 #endif
-  }
-  return default_filesystem_;
+
+  return filesystem;
 }
 
 }  // namespace rtc
diff --git a/rtc_base/fileutils.h b/rtc_base/fileutils.h
index b9e8a05..132fd88 100644
--- a/rtc_base/fileutils.h
+++ b/rtc_base/fileutils.h
@@ -42,6 +42,7 @@
 
 class DirectoryIterator {
   friend class Filesystem;
+
  public:
   // Constructor
   DirectoryIterator();
@@ -52,7 +53,7 @@
   // dir is the directory to traverse
   // returns true if the directory exists and is valid
   // The iterator will point to the first entry in the directory
-  virtual bool Iterate(const Pathname &path);
+  virtual bool Iterate(const Pathname& path);
 
   // Advances to the next file
   // returns true if there were more files in the directory.
@@ -70,8 +71,8 @@
   WIN32_FIND_DATA data_;
   HANDLE handle_;
 #else
-  DIR *dir_;
-  struct dirent *dirent_;
+  DIR* dir_;
+  struct dirent* dirent_;
   struct stat stat_;
 #endif
 };
@@ -83,12 +84,12 @@
   // This will attempt to delete the path located at filename.
   // It DCHECKs and returns false if the path points to a folder or a
   // non-existent file.
-  virtual bool DeleteFile(const Pathname &filename) = 0;
+  virtual bool DeleteFile(const Pathname& filename) = 0;
 
   // This moves a file from old_path to new_path, where "old_path" is a
   // plain file. This DCHECKs and returns false if old_path points to a
   // directory, and returns true if the function succeeds.
-  virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0;
+  virtual bool MoveFile(const Pathname& old_path, const Pathname& new_path) = 0;
 
   // Returns true if pathname refers to a directory
   virtual bool IsFolder(const Pathname& pathname) = 0;
@@ -102,46 +103,28 @@
 
 class Filesystem {
  public:
-  static FilesystemInterface *default_filesystem() {
-    RTC_DCHECK(default_filesystem_);
-    return default_filesystem_;
+  static bool DeleteFile(const Pathname& filename) {
+    return GetFilesystem()->DeleteFile(filename);
   }
 
-  static void set_default_filesystem(FilesystemInterface *filesystem) {
-    default_filesystem_ = filesystem;
-  }
-
-  static FilesystemInterface *swap_default_filesystem(
-      FilesystemInterface *filesystem) {
-    FilesystemInterface *cur = default_filesystem_;
-    default_filesystem_ = filesystem;
-    return cur;
-  }
-
-  static bool DeleteFile(const Pathname &filename) {
-    return EnsureDefaultFilesystem()->DeleteFile(filename);
-  }
-
-  static bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
-    return EnsureDefaultFilesystem()->MoveFile(old_path, new_path);
+  static bool MoveFile(const Pathname& old_path, const Pathname& new_path) {
+    return GetFilesystem()->MoveFile(old_path, new_path);
   }
 
   static bool IsFolder(const Pathname& pathname) {
-    return EnsureDefaultFilesystem()->IsFolder(pathname);
+    return GetFilesystem()->IsFolder(pathname);
   }
 
-  static bool IsFile(const Pathname &pathname) {
-    return EnsureDefaultFilesystem()->IsFile(pathname);
+  static bool IsFile(const Pathname& pathname) {
+    return GetFilesystem()->IsFile(pathname);
   }
 
   static bool GetFileSize(const Pathname& path, size_t* size) {
-    return EnsureDefaultFilesystem()->GetFileSize(path, size);
+    return GetFilesystem()->GetFileSize(path, size);
   }
 
  private:
-  static FilesystemInterface* default_filesystem_;
-
-  static FilesystemInterface *EnsureDefaultFilesystem();
+  static FilesystemInterface* GetFilesystem();
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
 };
 
diff --git a/rtc_base/firewallsocketserver.cc b/rtc_base/firewallsocketserver.cc
index 60f45ed..2a28124 100644
--- a/rtc_base/firewallsocketserver.cc
+++ b/rtc_base/firewallsocketserver.cc
@@ -21,8 +21,7 @@
 class FirewallSocket : public AsyncSocketAdapter {
  public:
   FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type)
-    : AsyncSocketAdapter(socket), server_(server), type_(type) {
-  }
+      : AsyncSocketAdapter(socket), server_(server), type_(type) {}
 
   int Bind(const SocketAddress& addr) override {
     if (!server_->IsBindableIp(addr.ipaddr())) {
@@ -117,9 +116,11 @@
 FirewallSocketServer::FirewallSocketServer(SocketServer* server,
                                            FirewallManager* manager,
                                            bool should_delete_server)
-    : server_(server), manager_(manager),
+    : server_(server),
+      manager_(manager),
       should_delete_server_(should_delete_server),
-      udp_sockets_enabled_(true), tcp_sockets_enabled_(true),
+      udp_sockets_enabled_(true),
+      tcp_sockets_enabled_(true),
       tcp_listen_enabled_(true) {
   if (manager_)
     manager_->AddServer(this);
@@ -135,7 +136,8 @@
   }
 }
 
-void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
+void FirewallSocketServer::AddRule(bool allow,
+                                   FirewallProtocol p,
                                    FirewallDirection d,
                                    const SocketAddress& addr) {
   SocketAddress any;
@@ -147,8 +149,8 @@
   }
 }
 
-
-void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
+void FirewallSocketServer::AddRule(bool allow,
+                                   FirewallProtocol p,
                                    const SocketAddress& src,
                                    const SocketAddress& dst) {
   Rule r;
@@ -196,18 +198,10 @@
          unbindable_ips_.end();
 }
 
-Socket* FirewallSocketServer::CreateSocket(int type) {
-  return CreateSocket(AF_INET, type);
-}
-
 Socket* FirewallSocketServer::CreateSocket(int family, int type) {
   return WrapSocket(server_->CreateAsyncSocket(family, type), type);
 }
 
-AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
-  return CreateAsyncSocket(AF_INET, type);
-}
-
 AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
   return WrapSocket(server_->CreateAsyncSocket(family, type), type);
 }
@@ -225,8 +219,7 @@
 }
 
 AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
-  if (!sock ||
-      (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
+  if (!sock || (type == SOCK_STREAM && !tcp_sockets_enabled_) ||
       (type == SOCK_DGRAM && !udp_sockets_enabled_)) {
     RTC_LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
     delete sock;
@@ -235,8 +228,7 @@
   return new FirewallSocket(this, sock, type);
 }
 
-FirewallManager::FirewallManager() {
-}
+FirewallManager::FirewallManager() {}
 
 FirewallManager::~FirewallManager() {
   RTC_DCHECK(servers_.empty());
@@ -253,19 +245,21 @@
                  servers_.end());
 }
 
-void FirewallManager::AddRule(bool allow, FirewallProtocol p,
-                              FirewallDirection d, const SocketAddress& addr) {
+void FirewallManager::AddRule(bool allow,
+                              FirewallProtocol p,
+                              FirewallDirection d,
+                              const SocketAddress& addr) {
   CritScope scope(&crit_);
-  for (std::vector<FirewallSocketServer*>::const_iterator it =
-      servers_.begin(); it != servers_.end(); ++it) {
+  for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
+       it != servers_.end(); ++it) {
     (*it)->AddRule(allow, p, d, addr);
   }
 }
 
 void FirewallManager::ClearRules() {
   CritScope scope(&crit_);
-  for (std::vector<FirewallSocketServer*>::const_iterator it =
-      servers_.begin(); it != servers_.end(); ++it) {
+  for (std::vector<FirewallSocketServer*>::const_iterator it = servers_.begin();
+       it != servers_.end(); ++it) {
     (*it)->ClearRules();
   }
 }
diff --git a/rtc_base/firewallsocketserver.h b/rtc_base/firewallsocketserver.h
index 9f04946..0e96823 100644
--- a/rtc_base/firewallsocketserver.h
+++ b/rtc_base/firewallsocketserver.h
@@ -48,15 +48,19 @@
   void set_tcp_listen_enabled(bool enabled) { tcp_listen_enabled_ = enabled; }
 
   // Rules govern the behavior of Connect/Accept/Send/Recv attempts.
-  void AddRule(bool allow, FirewallProtocol p = FP_ANY,
+  void AddRule(bool allow,
+               FirewallProtocol p = FP_ANY,
                FirewallDirection d = FD_ANY,
                const SocketAddress& addr = SocketAddress());
-  void AddRule(bool allow, FirewallProtocol p,
-               const SocketAddress& src, const SocketAddress& dst);
+  void AddRule(bool allow,
+               FirewallProtocol p,
+               const SocketAddress& src,
+               const SocketAddress& dst);
   void ClearRules();
 
   bool Check(FirewallProtocol p,
-             const SocketAddress& src, const SocketAddress& dst);
+             const SocketAddress& src,
+             const SocketAddress& dst);
 
   // Set the IP addresses for which Bind will fail. By default this list is
   // empty. This can be used to simulate a real OS that refuses to bind to
@@ -68,22 +72,19 @@
   void SetUnbindableIps(const std::vector<rtc::IPAddress>& unbindable_ips);
   bool IsBindableIp(const rtc::IPAddress& ip);
 
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
   void SetMessageQueue(MessageQueue* queue) override;
   bool Wait(int cms, bool process_io) override;
   void WakeUp() override;
 
-  Socket * WrapSocket(Socket * sock, int type);
-  AsyncSocket * WrapSocket(AsyncSocket * sock, int type);
+  Socket* WrapSocket(Socket* sock, int type);
+  AsyncSocket* WrapSocket(AsyncSocket* sock, int type);
 
  private:
-  SocketServer * server_;
-  FirewallManager * manager_;
+  SocketServer* server_;
+  FirewallManager* manager_;
   CriticalSection crit_;
   struct Rule {
     bool allow;
@@ -107,17 +108,18 @@
   FirewallManager();
   ~FirewallManager();
 
-  void AddServer(FirewallSocketServer * server);
-  void RemoveServer(FirewallSocketServer * server);
+  void AddServer(FirewallSocketServer* server);
+  void RemoveServer(FirewallSocketServer* server);
 
-  void AddRule(bool allow, FirewallProtocol p = FP_ANY,
+  void AddRule(bool allow,
+               FirewallProtocol p = FP_ANY,
                FirewallDirection d = FD_ANY,
                const SocketAddress& addr = SocketAddress());
   void ClearRules();
 
  private:
   CriticalSection crit_;
-  std::vector<FirewallSocketServer *> servers_;
+  std::vector<FirewallSocketServer*> servers_;
 };
 
 }  // namespace rtc
diff --git a/rtc_base/flags.cc b/rtc_base/flags.cc
index a2fb708..5b28794 100644
--- a/rtc_base/flags.cc
+++ b/rtc_base/flags.cc
@@ -18,11 +18,13 @@
 #include "rtc_base/stringutils.h"
 
 #if defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
 #include <windows.h>
-#include <shellapi.h>
+#include <shellapi.h> // must come after windows.h
+// clang-format on
 #endif
 
-
 namespace {
 bool FlagEq(const char* arg, const char* flag) {
   // Compare two flags for equality.
@@ -43,8 +45,12 @@
 // -----------------------------------------------------------------------------
 // Implementation of Flag
 
-Flag::Flag(const char* file, const char* name, const char* comment,
-           Type type, void* variable, FlagValue default__)
+Flag::Flag(const char* file,
+           const char* name,
+           const char* comment,
+           Type type,
+           void* variable,
+           FlagValue default__)
     : file_(file),
       name_(name),
       comment_(comment),
@@ -54,7 +60,6 @@
   FlagList::Register(this);
 }
 
-
 void Flag::SetToDefault() {
   // Note that we cannot simply do '*variable_ = default_;' since
   // flag variables are not really of type FlagValue and thus may
@@ -78,18 +83,20 @@
   FATAL() << "unreachable code";
 }
 
-
 static const char* Type2String(Flag::Type type) {
   switch (type) {
-    case Flag::BOOL: return "bool";
-    case Flag::INT: return "int";
-    case Flag::FLOAT: return "float";
-    case Flag::STRING: return "string";
+    case Flag::BOOL:
+      return "bool";
+    case Flag::INT:
+      return "int";
+    case Flag::FLOAT:
+      return "float";
+    case Flag::STRING:
+      return "string";
   }
   FATAL() << "unreachable code";
 }
 
-
 static void PrintFlagValue(Flag::Type type, FlagValue* p) {
   switch (type) {
     case Flag::BOOL:
@@ -108,10 +115,9 @@
   FATAL() << "unreachable code";
 }
 
-
 void Flag::Print(bool print_current_value) {
   printf("  --%s (%s)  type: %s  default: ", name_, comment_,
-          Type2String(type_));
+         Type2String(type_));
   PrintFlagValue(type_, &default_);
   if (print_current_value) {
     printf("  current value: ");
@@ -120,7 +126,6 @@
   printf("\n");
 }
 
-
 // -----------------------------------------------------------------------------
 // Implementation of FlagList
 
@@ -145,7 +150,6 @@
   }
 }
 
-
 Flag* FlagList::Lookup(const char* name) {
   Flag* f = list_;
   while (f != nullptr && !FlagEq(name, f->name()))
@@ -153,10 +157,11 @@
   return f;
 }
 
-
 void FlagList::SplitArgument(const char* arg,
-                             char* buffer, int buffer_size,
-                             const char** name, const char** value,
+                             char* buffer,
+                             int buffer_size,
+                             const char** name,
+                             const char** value,
                              bool* is_bool) {
   *name = nullptr;
   *value = nullptr;
@@ -191,8 +196,8 @@
   }
 }
 
-
-int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv,
+int FlagList::SetFlagsFromCommandLine(int* argc,
+                                      const char** argv,
                                       bool remove_flags) {
   // parse arguments
   for (int i = 1; i < *argc; /* see below */) {
@@ -219,14 +224,14 @@
         if (i < *argc) {
           value = argv[i++];
         } else {
-          fprintf(stderr, "Error: missing value for flag %s of type %s\n",
-            arg, Type2String(flag->type()));
+          fprintf(stderr, "Error: missing value for flag %s of type %s\n", arg,
+                  Type2String(flag->type()));
           return j;
         }
       }
 
       // set the flag
-      char empty[] = { '\0' };
+      char empty[] = {'\0'};
       char* endp = empty;
       switch (flag->type()) {
         case Flag::BOOL:
@@ -246,8 +251,8 @@
       // handle errors
       if ((flag->type() == Flag::BOOL && value != nullptr) ||
           (flag->type() != Flag::BOOL && is_bool) || *endp != '\0') {
-        fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
-          arg, Type2String(flag->type()));
+        fprintf(stderr, "Error: illegal value for flag %s of type %s\n", arg,
+                Type2String(flag->type()));
         return j;
       }
 
@@ -287,15 +292,15 @@
 WindowsCommandLineArguments::WindowsCommandLineArguments() {
   // start by getting the command line.
   LPTSTR command_line = ::GetCommandLine();
-   // now, convert it to a list of wide char strings.
-  LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_);
+  // now, convert it to a list of wide char strings.
+  LPWSTR* wide_argv = ::CommandLineToArgvW(command_line, &argc_);
   // now allocate an array big enough to hold that many string pointers.
   argv_ = new char*[argc_];
 
   // iterate over the returned wide strings;
-  for(int i = 0; i < argc_; ++i) {
+  for (int i = 0; i < argc_; ++i) {
     std::string s = rtc::ToUtf8(wide_argv[i], wcslen(wide_argv[i]));
-    char *buffer = new char[s.length() + 1];
+    char* buffer = new char[s.length() + 1];
     rtc::strcpyn(buffer, s.length() + 1, s.c_str());
 
     // make sure the argv array has the right string at this point.
@@ -306,7 +311,7 @@
 
 WindowsCommandLineArguments::~WindowsCommandLineArguments() {
   // need to free each string in the array, and then the array.
-  for(int i = 0; i < argc_; i++) {
+  for (int i = 0; i < argc_; i++) {
     delete[] argv_[i];
   }
 
diff --git a/rtc_base/flags.h b/rtc_base/flags.h
index 5a07b1a..33f6e5b 100644
--- a/rtc_base/flags.h
+++ b/rtc_base/flags.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 // Originally comes from shared/commandlineflags/flags.h
 
 // Flags are defined and declared using DEFINE_xxx and DECLARE_xxx macros,
@@ -65,23 +64,26 @@
   const char* s;
 };
 
-
 // Each flag can be accessed programmatically via a Flag object.
 class Flag {
  public:
   enum Type { BOOL, INT, FLOAT, STRING };
 
   // Internal use only.
-  Flag(const char* file, const char* name, const char* comment,
-       Type type, void* variable, FlagValue default_);
+  Flag(const char* file,
+       const char* name,
+       const char* comment,
+       Type type,
+       void* variable,
+       FlagValue default_);
 
   // General flag information
-  const char* file() const  { return file_; }
-  const char* name() const  { return name_; }
-  const char* comment() const  { return comment_; }
+  const char* file() const { return file_; }
+  const char* name() const { return name_; }
+  const char* comment() const { return comment_; }
 
   // Flag type
-  Type type() const  { return type_; }
+  Type type() const { return type_; }
 
   // Flag variables
   bool* bool_variable() const {
@@ -129,7 +131,7 @@
   void SetToDefault();
 
   // Iteration support
-  Flag* next() const  { return next_; }
+  Flag* next() const { return next_; }
 
   // Prints flag information. The current flag value is only printed
   // if print_current_value is set.
@@ -149,23 +151,20 @@
   friend class FlagList;  // accesses next_
 };
 
-
 // Internal use only.
-#define DEFINE_FLAG(type, c_type, name, default, comment) \
-  /* define and initialize the flag */                    \
-  c_type FLAG_##name = (default);                         \
-  /* register the flag */                                 \
-  static rtc::Flag Flag_##name(__FILE__, #name, (comment),      \
-                               rtc::Flag::type, &FLAG_##name,   \
+#define DEFINE_FLAG(type, c_type, name, default, comment)                   \
+  /* define and initialize the flag */                                      \
+  c_type FLAG_##name = (default);                                           \
+  /* register the flag */                                                   \
+  static rtc::Flag Flag_##name(__FILE__, #name, (comment), rtc::Flag::type, \
+                               &FLAG_##name,                                \
                                rtc::FlagValue::New_##type(default))
 
-
 // Internal use only.
-#define DECLARE_FLAG(c_type, name)              \
-  /* declare the external flag */               \
+#define DECLARE_FLAG(c_type, name) \
+  /* declare the external flag */  \
   extern c_type FLAG_##name
 
-
 // Use the following macros to define a new flag:
 #define DEFINE_bool(name, default, comment) \
   DEFINE_FLAG(BOOL, bool, name, default, comment)
@@ -176,13 +175,11 @@
 #define DEFINE_string(name, default, comment) \
   DEFINE_FLAG(STRING, const char*, name, default, comment)
 
-
 // Use the following macros to declare a flag defined elsewhere:
-#define DECLARE_bool(name)  DECLARE_FLAG(bool, name)
-#define DECLARE_int(name)  DECLARE_FLAG(int, name)
-#define DECLARE_float(name)  DECLARE_FLAG(double, name)
-#define DECLARE_string(name)  DECLARE_FLAG(const char*, name)
-
+#define DECLARE_bool(name) DECLARE_FLAG(bool, name)
+#define DECLARE_int(name) DECLARE_FLAG(int, name)
+#define DECLARE_float(name) DECLARE_FLAG(double, name)
+#define DECLARE_string(name) DECLARE_FLAG(const char*, name)
 
 // The global list of all flags.
 class FlagList {
@@ -190,7 +187,7 @@
   FlagList();
 
   // The null-terminated list of all flags. Traverse with Flag::next().
-  static Flag* list()  { return list_; }
+  static Flag* list() { return list_; }
 
   // If file != nullptr, prints information for all flags defined in file;
   // otherwise prints information for all flags in all files. The current flag
@@ -205,8 +202,10 @@
   // if the arg started with "-no" or "--no". The buffer may be used to NUL-
   // terminate the name, it must be large enough to hold any possible name.
   static void SplitArgument(const char* arg,
-                            char* buffer, int buffer_size,
-                            const char** name, const char** value,
+                            char* buffer,
+                            int buffer_size,
+                            const char** name,
+                            const char** value,
                             bool* is_bool);
 
   // Set the flag values by parsing the command line. If remove_flags
@@ -253,10 +252,11 @@
   ~WindowsCommandLineArguments();
 
   int argc() { return argc_; }
-  char **argv() { return argv_; }
+  char** argv() { return argv_; }
+
  private:
   int argc_;
-  char **argv_;
+  char** argv_;
 
  private:
   RTC_DISALLOW_COPY_AND_ASSIGN(WindowsCommandLineArguments);
diff --git a/rtc_base/function_view_unittest.cc b/rtc_base/function_view_unittest.cc
index 98f78d6..d0cfeb3 100644
--- a/rtc_base/function_view_unittest.cc
+++ b/rtc_base/function_view_unittest.cc
@@ -73,7 +73,7 @@
   EXPECT_FALSE(rtc::FunctionView<int()>(nullptr));
 
   // This calls the constructor for function pointers.
-  EXPECT_FALSE(rtc::FunctionView<int()>(reinterpret_cast<int(*)()>(0)));
+  EXPECT_FALSE(rtc::FunctionView<int()>(reinterpret_cast<int (*)()>(0)));
 }
 
 // Ensure that FunctionView handles move-only arguments and return values.
diff --git a/rtc_base/gtest_prod_util.h b/rtc_base/gtest_prod_util.h
index dc9679f..0661cd7 100644
--- a/rtc_base/gtest_prod_util.h
+++ b/rtc_base/gtest_prod_util.h
@@ -13,8 +13,8 @@
 
 // Define our own version of FRIEND_TEST here rather than including
 // gtest_prod.h to avoid depending on any part of GTest in production code.
-#define FRIEND_TEST_WEBRTC(test_case_name, test_name)\
-friend class test_case_name##_##test_name##_Test
+#define FRIEND_TEST_WEBRTC(test_case_name, test_name) \
+  friend class test_case_name##_##test_name##_Test
 
 // This file is a plain copy of Chromium's base/gtest_prod_util.h.
 //
@@ -30,9 +30,9 @@
 //   FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod);
 // };
 #define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
-  FRIEND_TEST_WEBRTC(test_case_name, test_name); \
+  FRIEND_TEST_WEBRTC(test_case_name, test_name);            \
   FRIEND_TEST_WEBRTC(test_case_name, DISABLED_##test_name); \
-  FRIEND_TEST_WEBRTC(test_case_name, FLAKY_##test_name); \
+  FRIEND_TEST_WEBRTC(test_case_name, FLAKY_##test_name);    \
   FRIEND_TEST_WEBRTC(test_case_name, FAILS_##test_name)
 
 #endif  // RTC_BASE_GTEST_PROD_UTIL_H_
diff --git a/rtc_base/gunit.h b/rtc_base/gunit.h
index 1d3019b..145b466 100644
--- a/rtc_base/gunit.h
+++ b/rtc_base/gunit.h
@@ -101,23 +101,23 @@
 // Wait until "ex" is true, or "timeout" expires, using fake clock where
 // messages are processed every millisecond.
 // TODO(pthatcher): Allow tests to control how many milliseconds to advance.
-#define SIMULATED_WAIT(ex, timeout, clock)                    \
-  for (int64_t start = rtc::TimeMillis();                     \
-       !(ex) && rtc::TimeMillis() < start + (timeout);) {     \
-    (clock).AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); \
+#define SIMULATED_WAIT(ex, timeout, clock)                \
+  for (int64_t start = rtc::TimeMillis();                 \
+       !(ex) && rtc::TimeMillis() < start + (timeout);) { \
+    (clock).AdvanceTime(webrtc::TimeDelta::ms(1));        \
   }
 
 // This returns the result of the test in res, so that we don't re-evaluate
 // the expression in the XXXX_WAIT macros below, since that causes problems
 // when the expression is only true the first time you check it.
-#define SIMULATED_WAIT_(ex, timeout, res, clock)                \
-  do {                                                          \
-    int64_t start = rtc::TimeMillis();                          \
-    res = (ex);                                                 \
-    while (!res && rtc::TimeMillis() < start + (timeout)) {     \
-      (clock).AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); \
-      res = (ex);                                               \
-    }                                                           \
+#define SIMULATED_WAIT_(ex, timeout, res, clock)            \
+  do {                                                      \
+    int64_t start = rtc::TimeMillis();                      \
+    res = (ex);                                             \
+    while (!res && rtc::TimeMillis() < start + (timeout)) { \
+      (clock).AdvanceTime(webrtc::TimeDelta::ms(1));        \
+      res = (ex);                                           \
+    }                                                       \
   } while (0)
 
 // The typical EXPECT_XXXX, but done until true or a timeout with a fake clock.
diff --git a/rtc_base/gunit_prod.h b/rtc_base/gunit_prod.h
index ae4157d..bf4f9a1 100644
--- a/rtc_base/gunit_prod.h
+++ b/rtc_base/gunit_prod.h
@@ -15,7 +15,7 @@
 // Android doesn't use gtest at all, so anything that relies on gtest should
 // check this define first.
 #define NO_GTEST
-#elif defined (GTEST_RELATIVE_PATH)
+#elif defined(GTEST_RELATIVE_PATH)
 #include "gtest/gtest_prod.h"
 #else
 #include "testing/base/gunit_prod.h"
diff --git a/rtc_base/helpers.cc b/rtc_base/helpers.cc
index 9cb9268..0260665 100644
--- a/rtc_base/helpers.cc
+++ b/rtc_base/helpers.cc
@@ -16,7 +16,6 @@
 #include <openssl/rand.h>
 
 #include "rtc_base/base64.h"
-#include "rtc_base/basictypes.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/timeutils.h"
@@ -48,10 +47,8 @@
 // A test random generator, for predictable output.
 class TestRandomGenerator : public RandomGenerator {
  public:
-  TestRandomGenerator() : seed_(7) {
-  }
-  ~TestRandomGenerator() override {
-  }
+  TestRandomGenerator() : seed_(7) {}
+  ~TestRandomGenerator() override {}
   bool Init(const void* seed, size_t len) override { return true; }
   bool Generate(void* buf, size_t len) override {
     for (size_t i = 0; i < len; ++i) {
@@ -85,8 +82,9 @@
 // This round about way of creating a global RNG is to safe-guard against
 // indeterminant static initialization order.
 std::unique_ptr<RandomGenerator>& GetGlobalRng() {
-  RTC_DEFINE_STATIC_LOCAL(std::unique_ptr<RandomGenerator>, global_rng,
-                          (new SecureRandomGenerator()));
+  static std::unique_ptr<RandomGenerator>& global_rng =
+      *new std::unique_ptr<RandomGenerator>(new SecureRandomGenerator());
+
   return global_rng;
 }
 
@@ -123,8 +121,9 @@
 }
 
 static bool CreateRandomString(size_t len,
-                        const char* table, int table_size,
-                        std::string* str) {
+                               const char* table,
+                               int table_size,
+                               std::string* str) {
   str->clear();
   // Avoid biased modulo division below.
   if (256 % table_size) {
@@ -147,10 +146,11 @@
   return CreateRandomString(len, kBase64, 64, str);
 }
 
-bool CreateRandomString(size_t len, const std::string& table,
+bool CreateRandomString(size_t len,
+                        const std::string& table,
                         std::string* str) {
-  return CreateRandomString(len, table.c_str(),
-                            static_cast<int>(table.size()), str);
+  return CreateRandomString(len, table.c_str(), static_cast<int>(table.size()),
+                            str);
 }
 
 bool CreateRandomData(size_t length, std::string* data) {
diff --git a/rtc_base/helpers.h b/rtc_base/helpers.h
index 0100794..d3b09cf 100644
--- a/rtc_base/helpers.h
+++ b/rtc_base/helpers.h
@@ -12,7 +12,6 @@
 #define RTC_BASE_HELPERS_H_
 
 #include <string>
-#include "rtc_base/basictypes.h"
 
 namespace rtc {
 
@@ -37,7 +36,8 @@
 // number generator failed.
 // For ease of implementation, the function requires that the table
 // size evenly divide 256; otherwise, it returns false.
-bool CreateRandomString(size_t length, const std::string& table,
+bool CreateRandomString(size_t length,
+                        const std::string& table,
                         std::string* str);
 
 // Generates (cryptographically) random data of the given length.
diff --git a/rtc_base/helpers_unittest.cc b/rtc_base/helpers_unittest.cc
index 9fa16a5..3e8729c 100644
--- a/rtc_base/helpers_unittest.cc
+++ b/rtc_base/helpers_unittest.cc
@@ -81,10 +81,12 @@
   std::string random;
   EXPECT_TRUE(CreateRandomData(kRandomDataLength, &random));
   EXPECT_EQ(kRandomDataLength, random.size());
-  Buffer expected("\xbd\x52\x2a\x4b\x97\x93\x2f\x1c"
+  Buffer expected(
+      "\xbd\x52\x2a\x4b\x97\x93\x2f\x1c"
       "\xc4\x72\xab\xa2\x88\x68\x3e\xcc"
       "\xa3\x8d\xaf\x13\x3b\xbc\x83\xbb"
-      "\x16\xf1\xcf\x56\x0c\xf5\x4a\x8b", kRandomDataLength);
+      "\x16\xf1\xcf\x56\x0c\xf5\x4a\x8b",
+      kRandomDataLength);
   EXPECT_EQ(0, memcmp(expected.data(), random.data(), kRandomDataLength));
 
   // Reset and make sure we get the same output.
diff --git a/rtc_base/httpbase.cc b/rtc_base/httpbase.cc
index ca85b57..3e2f376 100644
--- a/rtc_base/httpbase.cc
+++ b/rtc_base/httpbase.cc
@@ -36,9 +36,7 @@
   return (len == header_len) && (_strnicmp(str, header_str, header_len) == 0);
 }
 
-enum {
-  MSG_READ
-};
+enum { MSG_READ };
 
 //////////////////////////////////////////////////////////////////////
 // HttpParser
@@ -48,19 +46,18 @@
   reset();
 }
 
-HttpParser::~HttpParser() {
-}
+HttpParser::~HttpParser() {}
 
-void
-HttpParser::reset() {
+void HttpParser::reset() {
   state_ = ST_LEADER;
   chunked_ = false;
   data_size_ = SIZE_UNKNOWN;
 }
 
-HttpParser::ProcessResult
-HttpParser::Process(const char* buffer, size_t len, size_t* processed,
-                    HttpError* error) {
+HttpParser::ProcessResult HttpParser::Process(const char* buffer,
+                                              size_t len,
+                                              size_t* processed,
+                                              HttpError* error) {
   *processed = 0;
   *error = HE_NONE;
 
@@ -81,7 +78,7 @@
       const char* line = buffer + *processed;
       size_t len = (pos - *processed);
       *processed = pos + 1;
-      while ((len > 0) && isspace(static_cast<unsigned char>(line[len-1]))) {
+      while ((len > 0) && isspace(static_cast<unsigned char>(line[len - 1]))) {
         len -= 1;
       }
       ProcessResult result = ProcessLine(line, len, error);
@@ -99,14 +96,14 @@
     } else {
       size_t available = len - *processed;
       if (available <= 0) {
-        break; // no more data
+        break;  // no more data
       }
       if ((data_size_ != SIZE_UNKNOWN) && (available > data_size_)) {
         available = data_size_;
       }
       size_t read = 0;
-      ProcessResult result = ProcessData(buffer + *processed, available, read,
-                                         error);
+      ProcessResult result =
+          ProcessData(buffer + *processed, available, read, error);
       RTC_LOG(LS_VERBOSE) << "Processed data, result: " << result
                           << " read: " << read << " err: " << error;
 
@@ -123,104 +120,103 @@
   return PR_CONTINUE;
 }
 
-HttpParser::ProcessResult
-HttpParser::ProcessLine(const char* line, size_t len, HttpError* error) {
+HttpParser::ProcessResult HttpParser::ProcessLine(const char* line,
+                                                  size_t len,
+                                                  HttpError* error) {
   RTC_LOG_F(LS_VERBOSE) << " state: " << state_
                         << " line: " << std::string(line, len)
                         << " len: " << len << " err: " << error;
 
   switch (state_) {
-  case ST_LEADER:
-    state_ = ST_HEADERS;
-    return ProcessLeader(line, len, error);
+    case ST_LEADER:
+      state_ = ST_HEADERS;
+      return ProcessLeader(line, len, error);
 
-  case ST_HEADERS:
-    if (len > 0) {
-      const char* value = strchrn(line, len, ':');
-      if (!value) {
-        *error = HE_PROTOCOL;
-        return PR_COMPLETE;
-      }
-      size_t nlen = (value - line);
-      const char* eol = line + len;
-      do {
-        value += 1;
-      } while ((value < eol) && isspace(static_cast<unsigned char>(*value)));
-      size_t vlen = eol - value;
-      if (MatchHeader(line, nlen, HH_CONTENT_LENGTH)) {
-        // sscanf isn't safe with strings that aren't null-terminated, and there
-        // is no guarantee that |value| is.
-        // Create a local copy that is null-terminated.
-        std::string value_str(value, vlen);
-        unsigned int temp_size;
-        if (sscanf(value_str.c_str(), "%u", &temp_size) != 1) {
+    case ST_HEADERS:
+      if (len > 0) {
+        const char* value = strchrn(line, len, ':');
+        if (!value) {
           *error = HE_PROTOCOL;
           return PR_COMPLETE;
         }
-        data_size_ = static_cast<size_t>(temp_size);
-      } else if (MatchHeader(line, nlen, HH_TRANSFER_ENCODING)) {
-        if ((vlen == 7) && (_strnicmp(value, "chunked", 7) == 0)) {
-          chunked_ = true;
-        } else if ((vlen == 8) && (_strnicmp(value, "identity", 8) == 0)) {
-          chunked_ = false;
-        } else {
+        size_t nlen = (value - line);
+        const char* eol = line + len;
+        do {
+          value += 1;
+        } while ((value < eol) && isspace(static_cast<unsigned char>(*value)));
+        size_t vlen = eol - value;
+        if (MatchHeader(line, nlen, HH_CONTENT_LENGTH)) {
+          // sscanf isn't safe with strings that aren't null-terminated, and
+          // there is no guarantee that |value| is. Create a local copy that is
+          // null-terminated.
+          std::string value_str(value, vlen);
+          unsigned int temp_size;
+          if (sscanf(value_str.c_str(), "%u", &temp_size) != 1) {
+            *error = HE_PROTOCOL;
+            return PR_COMPLETE;
+          }
+          data_size_ = static_cast<size_t>(temp_size);
+        } else if (MatchHeader(line, nlen, HH_TRANSFER_ENCODING)) {
+          if ((vlen == 7) && (_strnicmp(value, "chunked", 7) == 0)) {
+            chunked_ = true;
+          } else if ((vlen == 8) && (_strnicmp(value, "identity", 8) == 0)) {
+            chunked_ = false;
+          } else {
+            *error = HE_PROTOCOL;
+            return PR_COMPLETE;
+          }
+        }
+        return ProcessHeader(line, nlen, value, vlen, error);
+      } else {
+        state_ = chunked_ ? ST_CHUNKSIZE : ST_DATA;
+        return ProcessHeaderComplete(chunked_, data_size_, error);
+      }
+      break;
+
+    case ST_CHUNKSIZE:
+      if (len > 0) {
+        char* ptr = nullptr;
+        data_size_ = strtoul(line, &ptr, 16);
+        if (ptr != line + len) {
           *error = HE_PROTOCOL;
           return PR_COMPLETE;
         }
-      }
-      return ProcessHeader(line, nlen, value, vlen, error);
-    } else {
-      state_ = chunked_ ? ST_CHUNKSIZE : ST_DATA;
-      return ProcessHeaderComplete(chunked_, data_size_, error);
-    }
-    break;
-
-  case ST_CHUNKSIZE:
-    if (len > 0) {
-      char* ptr = nullptr;
-      data_size_ = strtoul(line, &ptr, 16);
-      if (ptr != line + len) {
+        state_ = (data_size_ == 0) ? ST_TRAILERS : ST_DATA;
+      } else {
         *error = HE_PROTOCOL;
         return PR_COMPLETE;
       }
-      state_ = (data_size_ == 0) ? ST_TRAILERS : ST_DATA;
-    } else {
-      *error = HE_PROTOCOL;
-      return PR_COMPLETE;
-    }
-    break;
+      break;
 
-  case ST_CHUNKTERM:
-    if (len > 0) {
-      *error = HE_PROTOCOL;
-      return PR_COMPLETE;
-    } else {
-      state_ = chunked_ ? ST_CHUNKSIZE : ST_DATA;
-    }
-    break;
+    case ST_CHUNKTERM:
+      if (len > 0) {
+        *error = HE_PROTOCOL;
+        return PR_COMPLETE;
+      } else {
+        state_ = chunked_ ? ST_CHUNKSIZE : ST_DATA;
+      }
+      break;
 
-  case ST_TRAILERS:
-    if (len == 0) {
-      return PR_COMPLETE;
-    }
-    // *error = onHttpRecvTrailer();
-    break;
+    case ST_TRAILERS:
+      if (len == 0) {
+        return PR_COMPLETE;
+      }
+      // *error = onHttpRecvTrailer();
+      break;
 
-  default:
-    RTC_NOTREACHED();
-    break;
+    default:
+      RTC_NOTREACHED();
+      break;
   }
 
   return PR_CONTINUE;
 }
 
-bool
-HttpParser::is_valid_end_of_input() const {
+bool HttpParser::is_valid_end_of_input() const {
   return (state_ == ST_DATA) && (data_size_ == SIZE_UNKNOWN);
 }
 
-void
-HttpParser::complete(HttpError error) {
+void HttpParser::complete(HttpError error) {
   if (state_ < ST_COMPLETE) {
     state_ = ST_COMPLETE;
     OnComplete(error);
@@ -232,9 +228,9 @@
 //////////////////////////////////////////////////////////////////////
 
 class BlockingMemoryStream : public ExternalMemoryStream {
-public:
+ public:
   BlockingMemoryStream(char* buffer, size_t size)
-  : ExternalMemoryStream(buffer, size) { }
+      : ExternalMemoryStream(buffer, size) {}
 
   StreamResult DoReserve(size_t size, int* error) override {
     return (buffer_length_ >= size) ? SR_SUCCESS : SR_BLOCK;
@@ -242,8 +238,8 @@
 };
 
 class HttpBase::DocumentStream : public StreamInterface {
-public:
-  DocumentStream(HttpBase* base) : base_(base), error_(HE_DEFAULT) { }
+ public:
+  DocumentStream(HttpBase* base) : base_(base), error_(HE_DEFAULT) {}
 
   StreamState GetState() const override {
     if (nullptr == base_)
@@ -258,7 +254,8 @@
                     size_t* read,
                     int* error) override {
     if (!base_) {
-      if (error) *error = error_;
+      if (error)
+        *error = error_;
       return (HE_NONE == error_) ? SR_EOS : SR_ERROR;
     }
 
@@ -296,7 +293,8 @@
     StreamResult result = SR_BLOCK;
     if (complete) {
       HttpBase* base = Disconnect(http_error);
-      if (error) *error = error_;
+      if (error)
+        *error = error_;
       result = (HE_NONE == error_) ? SR_EOS : SR_ERROR;
       base->complete(http_error);
     }
@@ -306,7 +304,8 @@
     size_t position;
     stream->GetPosition(&position);
     if (position > 0) {
-      if (read) *read = position;
+      if (read)
+        *read = position;
       result = SR_SUCCESS;
     }
     return result;
@@ -316,7 +315,8 @@
                      size_t data_len,
                      size_t* written,
                      int* error) override {
-    if (error) *error = -1;
+    if (error)
+      *error = -1;
     return SR_ERROR;
   }
 
@@ -352,7 +352,7 @@
     return base;
   }
 
-private:
+ private:
   HttpBase* base_;
   HttpError error_;
 };
@@ -372,13 +372,11 @@
   RTC_DCHECK(HM_NONE == mode_);
 }
 
-bool
-HttpBase::isConnected() const {
+bool HttpBase::isConnected() const {
   return (http_stream_ != nullptr) && (http_stream_->GetState() == SS_OPEN);
 }
 
-bool
-HttpBase::attach(StreamInterface* stream) {
+bool HttpBase::attach(StreamInterface* stream) {
   if ((mode_ != HM_NONE) || (http_stream_ != nullptr) || (stream == nullptr)) {
     RTC_NOTREACHED();
     return false;
@@ -389,8 +387,7 @@
   return true;
 }
 
-StreamInterface*
-HttpBase::detach() {
+StreamInterface* HttpBase::detach() {
   RTC_DCHECK(HM_NONE == mode_);
   if (mode_ != HM_NONE) {
     return nullptr;
@@ -403,8 +400,7 @@
   return stream;
 }
 
-void
-HttpBase::send(HttpData* data) {
+void HttpBase::send(HttpData* data) {
   RTC_DCHECK(HM_NONE == mode_);
   if (mode_ != HM_NONE) {
     return;
@@ -423,8 +419,8 @@
   }
 
   std::string encoding;
-  if (data_->hasHeader(HH_TRANSFER_ENCODING, &encoding)
-      && (encoding == "chunked")) {
+  if (data_->hasHeader(HH_TRANSFER_ENCODING, &encoding) &&
+      (encoding == "chunked")) {
     chunk_data_ = true;
   }
 
@@ -440,8 +436,7 @@
   flush_data();
 }
 
-void
-HttpBase::recv(HttpData* data) {
+void HttpBase::recv(HttpData* data) {
   RTC_DCHECK(HM_NONE == mode_);
   if (mode_ != HM_NONE) {
     return;
@@ -463,8 +458,7 @@
   }
 }
 
-void
-HttpBase::abort(HttpError err) {
+void HttpBase::abort(HttpError err) {
   if (mode_ != HM_NONE) {
     if (http_stream_ != nullptr) {
       http_stream_->Close();
@@ -520,28 +514,27 @@
       // Attempt to buffer more data.
       size_t read;
       int read_error;
-      StreamResult read_result = http_stream_->Read(buffer_ + len_,
-                                                    sizeof(buffer_) - len_,
-                                                    &read, &read_error);
+      StreamResult read_result = http_stream_->Read(
+          buffer_ + len_, sizeof(buffer_) - len_, &read, &read_error);
       switch (read_result) {
-      case SR_SUCCESS:
-        RTC_DCHECK(len_ + read <= sizeof(buffer_));
-        len_ += read;
-        break;
-      case SR_BLOCK:
-        if (process_requires_more_data) {
-          // We're can't make progress until more data is available.
-          return false;
-        }
-        // Attempt to process the data already in our buffer.
-        break;
-      case SR_EOS:
-        // Clean close, with no error.
-        read_error = 0;
-        RTC_FALLTHROUGH();  // Fall through to HandleStreamClose.
-      case SR_ERROR:
-        *error = HandleStreamClose(read_error);
-        return true;
+        case SR_SUCCESS:
+          RTC_DCHECK(len_ + read <= sizeof(buffer_));
+          len_ += read;
+          break;
+        case SR_BLOCK:
+          if (process_requires_more_data) {
+            // We're can't make progress until more data is available.
+            return false;
+          }
+          // Attempt to process the data already in our buffer.
+          break;
+        case SR_EOS:
+          // Clean close, with no error.
+          read_error = 0;
+          RTC_FALLTHROUGH();  // Fall through to HandleStreamClose.
+        case SR_ERROR:
+          *error = HandleStreamClose(read_error);
+          return true;
       }
     } else if (process_requires_more_data) {
       // We have too much unprocessed data in our buffer.  This should only
@@ -558,22 +551,21 @@
     // necessary to call Process with an empty buffer, since the state machine
     // may have interrupted state transitions to complete.
     size_t processed;
-    ProcessResult process_result = Process(buffer_, len_, &processed,
-                                            error);
+    ProcessResult process_result = Process(buffer_, len_, &processed, error);
     RTC_DCHECK(processed <= len_);
     len_ -= processed;
     memmove(buffer_, buffer_ + processed, len_);
     switch (process_result) {
-    case PR_CONTINUE:
-      // We need more data to make progress.
-      process_requires_more_data = true;
-      break;
-    case PR_BLOCK:
-      // We're stalled on writing the processed data.
-      return false;
-    case PR_COMPLETE:
-      // *error already contains the correct code.
-      return true;
+      case PR_CONTINUE:
+        // We need more data to make progress.
+        process_requires_more_data = true;
+        break;
+      case PR_BLOCK:
+        // We're stalled on writing the processed data.
+        return false;
+      case PR_COMPLETE:
+        // *error already contains the correct code.
+        return true;
     }
   } while (++loop_count <= kMaxReadCount);
 
@@ -581,16 +573,14 @@
   return false;
 }
 
-void
-HttpBase::read_and_process_data() {
+void HttpBase::read_and_process_data() {
   HttpError error;
   if (DoReceiveLoop(&error)) {
     complete(error);
   }
 }
 
-void
-HttpBase::flush_data() {
+void HttpBase::flush_data() {
   RTC_DCHECK(HM_SEND == mode_);
 
   // When send_required is true, no more buffering can occur without a network
@@ -632,17 +622,16 @@
       } else {
         size_t read;
         int error;
-        StreamResult result = data_->document->Read(buffer_ + offset,
-                                                    sizeof(buffer_) - reserve,
-                                                    &read, &error);
+        StreamResult result = data_->document->Read(
+            buffer_ + offset, sizeof(buffer_) - reserve, &read, &error);
         if (result == SR_SUCCESS) {
           RTC_DCHECK(reserve + read <= sizeof(buffer_));
           if (chunk_data_) {
             // Prepend the chunk length in hex.
             // Note: sprintfn appends a null terminator, which is why we can't
             // combine it with the line terminator.
-            sprintfn(buffer_ + len_, kChunkDigits + 1, "%.*x",
-                     kChunkDigits, read);
+            sprintfn(buffer_ + len_, kChunkDigits + 1, "%.*x", kChunkDigits,
+                     read);
             // Add line terminator to the chunk length.
             memcpy(buffer_ + len_ + kChunkDigits, "\r\n", 2);
             // Add line terminator to the end of the chunk.
@@ -709,14 +698,13 @@
   RTC_NOTREACHED();
 }
 
-bool
-HttpBase::queue_headers() {
+bool HttpBase::queue_headers() {
   RTC_DCHECK(HM_SEND == mode_);
   while (header_ != data_->end()) {
-    size_t len = sprintfn(buffer_ + len_, sizeof(buffer_) - len_,
-                          "%.*s: %.*s\r\n",
-                          header_->first.size(), header_->first.data(),
-                          header_->second.size(), header_->second.data());
+    size_t len =
+        sprintfn(buffer_ + len_, sizeof(buffer_) - len_, "%.*s: %.*s\r\n",
+                 header_->first.size(), header_->first.data(),
+                 header_->second.size(), header_->second.data());
     if (len_ + len < sizeof(buffer_) - 3) {
       len_ += len;
       ++header_;
@@ -734,8 +722,7 @@
   return false;
 }
 
-void
-HttpBase::do_complete(HttpError err) {
+void HttpBase::do_complete(HttpError err) {
   RTC_DCHECK(mode_ != HM_NONE);
   HttpMode mode = mode_;
   mode_ = HM_NONE;
@@ -759,8 +746,9 @@
 // Stream Signals
 //
 
-void
-HttpBase::OnHttpStreamEvent(StreamInterface* stream, int events, int error) {
+void HttpBase::OnHttpStreamEvent(StreamInterface* stream,
+                                 int events,
+                                 int error) {
   RTC_DCHECK(stream == http_stream_);
   if ((events & SE_OPEN) && (mode_ == HM_CONNECT)) {
     do_complete();
@@ -794,8 +782,7 @@
   }
 }
 
-void
-HttpBase::OnDocumentEvent(StreamInterface* stream, int events, int error) {
+void HttpBase::OnDocumentEvent(StreamInterface* stream, int events, int error) {
   RTC_DCHECK(stream == data_->document.get());
   if ((events & SE_WRITE) && (mode_ == HM_RECV)) {
     read_and_process_data();
@@ -818,23 +805,26 @@
 // HttpParser Implementation
 //
 
-HttpParser::ProcessResult
-HttpBase::ProcessLeader(const char* line, size_t len, HttpError* error) {
+HttpParser::ProcessResult HttpBase::ProcessLeader(const char* line,
+                                                  size_t len,
+                                                  HttpError* error) {
   *error = data_->parseLeader(line, len);
   return (HE_NONE == *error) ? PR_CONTINUE : PR_COMPLETE;
 }
 
-HttpParser::ProcessResult
-HttpBase::ProcessHeader(const char* name, size_t nlen, const char* value,
-                        size_t vlen, HttpError* error) {
+HttpParser::ProcessResult HttpBase::ProcessHeader(const char* name,
+                                                  size_t nlen,
+                                                  const char* value,
+                                                  size_t vlen,
+                                                  HttpError* error) {
   std::string sname(name, nlen), svalue(value, vlen);
   data_->addHeader(sname, svalue);
   return PR_CONTINUE;
 }
 
-HttpParser::ProcessResult
-HttpBase::ProcessHeaderComplete(bool chunked, size_t& data_size,
-                                HttpError* error) {
+HttpParser::ProcessResult HttpBase::ProcessHeaderComplete(bool chunked,
+                                                          size_t& data_size,
+                                                          HttpError* error) {
   StreamInterface* old_docstream = doc_stream_;
   if (notify_) {
     *error = notify_->onHttpHeaderComplete(chunked, data_size);
@@ -854,35 +844,35 @@
   return PR_CONTINUE;
 }
 
-HttpParser::ProcessResult
-HttpBase::ProcessData(const char* data, size_t len, size_t& read,
-                      HttpError* error) {
+HttpParser::ProcessResult HttpBase::ProcessData(const char* data,
+                                                size_t len,
+                                                size_t& read,
+                                                HttpError* error) {
   if (ignore_data_ || !data_->document) {
     read = len;
     return PR_CONTINUE;
   }
   int write_error = 0;
   switch (data_->document->Write(data, len, &read, &write_error)) {
-  case SR_SUCCESS:
-    return PR_CONTINUE;
-  case SR_BLOCK:
-    return PR_BLOCK;
-  case SR_EOS:
-    RTC_LOG_F(LS_ERROR) << "Unexpected EOS";
-    *error = HE_STREAM;
-    return PR_COMPLETE;
-  case SR_ERROR:
-  default:
-    RTC_LOG_F(LS_ERROR) << "Write error: " << write_error;
-    *error = HE_STREAM;
-    return PR_COMPLETE;
+    case SR_SUCCESS:
+      return PR_CONTINUE;
+    case SR_BLOCK:
+      return PR_BLOCK;
+    case SR_EOS:
+      RTC_LOG_F(LS_ERROR) << "Unexpected EOS";
+      *error = HE_STREAM;
+      return PR_COMPLETE;
+    case SR_ERROR:
+    default:
+      RTC_LOG_F(LS_ERROR) << "Write error: " << write_error;
+      *error = HE_STREAM;
+      return PR_COMPLETE;
   }
 }
 
-void
-HttpBase::OnComplete(HttpError err) {
+void HttpBase::OnComplete(HttpError err) {
   RTC_LOG_F(LS_VERBOSE);
   do_complete(err);
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/httpbase.h b/rtc_base/httpbase.h
index 5ca0134..25a11ab 100644
--- a/rtc_base/httpbase.h
+++ b/rtc_base/httpbase.h
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 #ifndef RTC_BASE_HTTPBASE_H_
 #define RTC_BASE_HTTPBASE_H_
 
@@ -26,39 +25,51 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class HttpParser {
-public:
+ public:
   enum ProcessResult { PR_CONTINUE, PR_BLOCK, PR_COMPLETE };
   HttpParser();
   virtual ~HttpParser();
 
   void reset();
-  ProcessResult Process(const char* buffer, size_t len, size_t* processed,
+  ProcessResult Process(const char* buffer,
+                        size_t len,
+                        size_t* processed,
                         HttpError* error);
   bool is_valid_end_of_input() const;
   void complete(HttpError err);
 
   size_t GetDataRemaining() const { return data_size_; }
 
-protected:
+ protected:
   ProcessResult ProcessLine(const char* line, size_t len, HttpError* error);
 
   // HttpParser Interface
-  virtual ProcessResult ProcessLeader(const char* line, size_t len,
+  virtual ProcessResult ProcessLeader(const char* line,
+                                      size_t len,
                                       HttpError* error) = 0;
-  virtual ProcessResult ProcessHeader(const char* name, size_t nlen,
-                                      const char* value, size_t vlen,
+  virtual ProcessResult ProcessHeader(const char* name,
+                                      size_t nlen,
+                                      const char* value,
+                                      size_t vlen,
                                       HttpError* error) = 0;
-  virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size,
+  virtual ProcessResult ProcessHeaderComplete(bool chunked,
+                                              size_t& data_size,
                                               HttpError* error) = 0;
-  virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read,
+  virtual ProcessResult ProcessData(const char* data,
+                                    size_t len,
+                                    size_t& read,
                                     HttpError* error) = 0;
   virtual void OnComplete(HttpError err) = 0;
 
-private:
+ private:
   enum State {
-    ST_LEADER, ST_HEADERS,
-    ST_CHUNKSIZE, ST_CHUNKTERM, ST_TRAILERS,
-    ST_DATA, ST_COMPLETE
+    ST_LEADER,
+    ST_HEADERS,
+    ST_CHUNKSIZE,
+    ST_CHUNKTERM,
+    ST_TRAILERS,
+    ST_DATA,
+    ST_COMPLETE
   } state_;
   bool chunked_;
   size_t data_size_;
@@ -71,7 +82,7 @@
 enum HttpMode { HM_NONE, HM_CONNECT, HM_RECV, HM_SEND };
 
 class IHttpNotify {
-public:
+ public:
   virtual ~IHttpNotify() {}
   virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) = 0;
   virtual void onHttpComplete(HttpMode mode, HttpError err) = 0;
@@ -88,11 +99,8 @@
 // stream interface drives I/O via calls to Read().
 ///////////////////////////////////////////////////////////////////////////////
 
-class HttpBase
-: private HttpParser,
-  public sigslot::has_slots<>
-{
-public:
+class HttpBase : private HttpParser, public sigslot::has_slots<> {
+ public:
   HttpBase();
   ~HttpBase() override;
 
@@ -116,7 +124,7 @@
   // Further calls will return null.
   StreamInterface* GetDocumentStream();
 
-protected:
+ protected:
   // Do cleanup when the http stream closes (error may be 0 for a clean
   // shutdown), and return the error code to signal.
   HttpError HandleStreamClose(int error);
@@ -162,7 +170,7 @@
                             HttpError* error) override;
   void OnComplete(HttpError err) override;
 
-private:
+ private:
   class DocumentStream;
   friend class DocumentStream;
 
@@ -182,6 +190,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_HTTPBASE_H_
+#endif  // RTC_BASE_HTTPBASE_H_
diff --git a/rtc_base/httpbase_unittest.cc b/rtc_base/httpbase_unittest.cc
index 1b7ab7f..260fb9b 100644
--- a/rtc_base/httpbase_unittest.cc
+++ b/rtc_base/httpbase_unittest.cc
@@ -17,35 +17,35 @@
 namespace rtc {
 
 const char* const kHttpResponse =
-  "HTTP/1.1 200\r\n"
-  "Connection: Keep-Alive\r\n"
-  "Content-Type: text/plain\r\n"
-  "Proxy-Authorization: 42\r\n"
-  "Transfer-Encoding: chunked\r\n"
-  "\r\n"
-  "00000008\r\n"
-  "Goodbye!\r\n"
-  "0\r\n\r\n";
+    "HTTP/1.1 200\r\n"
+    "Connection: Keep-Alive\r\n"
+    "Content-Type: text/plain\r\n"
+    "Proxy-Authorization: 42\r\n"
+    "Transfer-Encoding: chunked\r\n"
+    "\r\n"
+    "00000008\r\n"
+    "Goodbye!\r\n"
+    "0\r\n\r\n";
 
 const char* const kHttpEmptyResponse =
-  "HTTP/1.1 200\r\n"
-  "Connection: Keep-Alive\r\n"
-  "Content-Length: 0\r\n"
-  "Proxy-Authorization: 42\r\n"
-  "\r\n";
+    "HTTP/1.1 200\r\n"
+    "Connection: Keep-Alive\r\n"
+    "Content-Length: 0\r\n"
+    "Proxy-Authorization: 42\r\n"
+    "\r\n";
 
 const char* const kHttpResponsePrefix =
-  "HTTP/1.1 200\r\n"
-  "Connection: Keep-Alive\r\n"
-  "Content-Type: text/plain\r\n"
-  "Proxy-Authorization: 42\r\n"
-  "Transfer-Encoding: chunked\r\n"
-  "\r\n"
-  "8\r\n"
-  "Goodbye!\r\n";
+    "HTTP/1.1 200\r\n"
+    "Connection: Keep-Alive\r\n"
+    "Content-Type: text/plain\r\n"
+    "Proxy-Authorization: 42\r\n"
+    "Transfer-Encoding: chunked\r\n"
+    "\r\n"
+    "8\r\n"
+    "Goodbye!\r\n";
 
 class HttpBaseTest : public testing::Test, public IHttpNotify {
-public:
+ public:
   enum EventType { E_HEADER_COMPLETE, E_COMPLETE, E_CLOSED };
   struct Event {
     EventType event;
@@ -64,7 +64,7 @@
 
   HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) override {
     RTC_LOG_F(LS_VERBOSE) << "chunked: " << chunked << " size: " << data_size;
-    Event e = { E_HEADER_COMPLETE, chunked, data_size, HM_NONE, HE_NONE};
+    Event e = {E_HEADER_COMPLETE, chunked, data_size, HM_NONE, HE_NONE};
     events.push_back(e);
     if (obtain_stream) {
       ObtainDocumentStream();
@@ -73,12 +73,12 @@
   }
   void onHttpComplete(HttpMode mode, HttpError err) override {
     RTC_LOG_F(LS_VERBOSE) << "mode: " << mode << " err: " << err;
-    Event e = { E_COMPLETE, false, 0, mode, err };
+    Event e = {E_COMPLETE, false, 0, mode, err};
     events.push_back(e);
   }
   void onHttpClosed(HttpError err) override {
     RTC_LOG_F(LS_VERBOSE) << "err: " << err;
-    Event e = { E_CLOSED, false, 0, HM_NONE, err };
+    Event e = {E_CLOSED, false, 0, HM_NONE, err};
     events.push_back(e);
   }
 
@@ -200,7 +200,7 @@
   EXPECT_EQ(SS_OPENING, http_stream->GetState());
 
   size_t read = 0;
-  char buffer[5] = { 0 };
+  char buffer[5] = {0};
   EXPECT_EQ(SR_BLOCK,
             http_stream->Read(buffer, sizeof(buffer), &read, nullptr));
   RTC_LOG_F(LS_VERBOSE) << "Exit";
@@ -230,7 +230,7 @@
   const size_t expected_length = strlen(expected_data);
   while (verified_length < expected_length) {
     size_t read = 0;
-    char buffer[5] = { 0 };
+    char buffer[5] = {0};
     size_t amt_to_read =
         std::min(expected_length - verified_length, sizeof(buffer));
     EXPECT_EQ(SR_SUCCESS,
@@ -247,7 +247,7 @@
 
   ASSERT_TRUE(nullptr != http_stream);
   size_t read = 0;
-  char buffer[5] = { 0 };
+  char buffer[5] = {0};
   EXPECT_EQ(SR_EOS, http_stream->Read(buffer, sizeof(buffer), &read, nullptr));
   EXPECT_EQ(SS_CLOSED, http_stream->GetState());
 
@@ -403,12 +403,10 @@
 }
 
 TEST_F(HttpBaseTest, DISABLED_AllowsCloseStreamBeforeDocumentIsComplete) {
-
   // TODO: Remove extra logging once test failure is understood
   LoggingSeverity old_sev = rtc::LogMessage::GetLogToDebug();
   rtc::LogMessage::LogToDebug(LS_VERBOSE);
 
-
   // Switch to pull mode
   ObtainDocumentStream();
   VerifyDocumentStreamIsOpening();
@@ -511,7 +509,7 @@
 
   // Future reads give an error
   int error = 0;
-  char buffer[5] = { 0 };
+  char buffer[5] = {0};
   EXPECT_EQ(SR_ERROR,
             http_stream->Read(buffer, sizeof(buffer), nullptr, &error));
   EXPECT_EQ(HE_DISCONNECTED, error);
@@ -522,4 +520,4 @@
   VerifyDocumentContents("");
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/httpcommon-inl.h b/rtc_base/httpcommon-inl.h
index 70263da..bb72357 100644
--- a/rtc_base/httpcommon-inl.h
+++ b/rtc_base/httpcommon-inl.h
@@ -21,13 +21,15 @@
 // Url
 ///////////////////////////////////////////////////////////////////////////////
 
-template<class CTYPE>
+template <class CTYPE>
 void Url<CTYPE>::do_set_url(const CTYPE* val, size_t len) {
   if (ascnicmp(val, "http://", 7) == 0) {
-    val += 7; len -= 7;
+    val += 7;
+    len -= 7;
     secure_ = false;
   } else if (ascnicmp(val, "https://", 8) == 0) {
-    val += 8; len -= 8;
+    val += 8;
+    len -= 8;
     secure_ = true;
   } else {
     clear();
@@ -42,7 +44,7 @@
   do_set_full_path(path, len - address_length);
 }
 
-template<class CTYPE>
+template <class CTYPE>
 void Url<CTYPE>::do_set_address(const CTYPE* val, size_t len) {
   if (const CTYPE* at = strchrn(val, len, static_cast<CTYPE>('@'))) {
     // Everything before the @ is a user:password combo, so skip it.
@@ -61,7 +63,7 @@
   }
 }
 
-template<class CTYPE>
+template <class CTYPE>
 void Url<CTYPE>::do_set_full_path(const CTYPE* val, size_t len) {
   const CTYPE* query = strchrn(val, len, static_cast<CTYPE>('?'));
   if (!query) {
@@ -78,7 +80,7 @@
   query_.assign(query, len - path_length);
 }
 
-template<class CTYPE>
+template <class CTYPE>
 void Url<CTYPE>::do_get_url(string* val) const {
   CTYPE protocol[9];
   asccpyn(protocol, arraysize(protocol), secure_ ? "https://" : "http://");
@@ -87,7 +89,7 @@
   do_get_full_path(val);
 }
 
-template<class CTYPE>
+template <class CTYPE>
 void Url<CTYPE>::do_get_address(string* val) const {
   val->append(host_);
   if (port_ != HttpDefaultPort(secure_)) {
@@ -98,13 +100,13 @@
   }
 }
 
-template<class CTYPE>
+template <class CTYPE>
 void Url<CTYPE>::do_get_full_path(string* val) const {
   val->append(path_);
   val->append(query_);
 }
 
-template<class CTYPE>
+template <class CTYPE>
 bool Url<CTYPE>::get_attribute(const string& name, string* value) const {
   if (query_.empty())
     return false;
@@ -114,7 +116,7 @@
     return false;
 
   pos += name.length() + 1;
-  if ((pos > query_.length()) || (static_cast<CTYPE>('=') != query_[pos-1]))
+  if ((pos > query_.length()) || (static_cast<CTYPE>('=') != query_[pos - 1]))
     return false;
 
   std::string::size_type end = query_.find(static_cast<CTYPE>('&'), pos);
diff --git a/rtc_base/httpcommon.cc b/rtc_base/httpcommon.cc
index f23cb63..5ac1e42 100644
--- a/rtc_base/httpcommon.cc
+++ b/rtc_base/httpcommon.cc
@@ -47,7 +47,10 @@
 //   int err = LibraryFunc();
 //   LOG(LS_ERROR) << "LibraryFunc returned: "
 //                 << GetErrorName(err, LIBRARY_ERRORS);
-struct ConstantToLabel { int value; const char * label; };
+struct ConstantToLabel {
+  int value;
+  const char* label;
+};
 
 const char* LookupLabel(int value, const ConstantToLabel entries[]) {
   for (int i = 0; entries[i].label; ++i) {
@@ -72,35 +75,36 @@
   return buffer;
 }
 
-#define KLABEL(x) { x, #x }
-#define LASTLABEL { 0, 0 }
+#define KLABEL(x) \
+  { x, #x }
+#define LASTLABEL \
+  { 0, 0 }
 
 const ConstantToLabel SECURITY_ERRORS[] = {
-  KLABEL(SEC_I_COMPLETE_AND_CONTINUE),
-  KLABEL(SEC_I_COMPLETE_NEEDED),
-  KLABEL(SEC_I_CONTEXT_EXPIRED),
-  KLABEL(SEC_I_CONTINUE_NEEDED),
-  KLABEL(SEC_I_INCOMPLETE_CREDENTIALS),
-  KLABEL(SEC_I_RENEGOTIATE),
-  KLABEL(SEC_E_CERT_EXPIRED),
-  KLABEL(SEC_E_INCOMPLETE_MESSAGE),
-  KLABEL(SEC_E_INSUFFICIENT_MEMORY),
-  KLABEL(SEC_E_INTERNAL_ERROR),
-  KLABEL(SEC_E_INVALID_HANDLE),
-  KLABEL(SEC_E_INVALID_TOKEN),
-  KLABEL(SEC_E_LOGON_DENIED),
-  KLABEL(SEC_E_NO_AUTHENTICATING_AUTHORITY),
-  KLABEL(SEC_E_NO_CREDENTIALS),
-  KLABEL(SEC_E_NOT_OWNER),
-  KLABEL(SEC_E_OK),
-  KLABEL(SEC_E_SECPKG_NOT_FOUND),
-  KLABEL(SEC_E_TARGET_UNKNOWN),
-  KLABEL(SEC_E_UNKNOWN_CREDENTIALS),
-  KLABEL(SEC_E_UNSUPPORTED_FUNCTION),
-  KLABEL(SEC_E_UNTRUSTED_ROOT),
-  KLABEL(SEC_E_WRONG_PRINCIPAL),
-  LASTLABEL
-};
+    KLABEL(SEC_I_COMPLETE_AND_CONTINUE),
+    KLABEL(SEC_I_COMPLETE_NEEDED),
+    KLABEL(SEC_I_CONTEXT_EXPIRED),
+    KLABEL(SEC_I_CONTINUE_NEEDED),
+    KLABEL(SEC_I_INCOMPLETE_CREDENTIALS),
+    KLABEL(SEC_I_RENEGOTIATE),
+    KLABEL(SEC_E_CERT_EXPIRED),
+    KLABEL(SEC_E_INCOMPLETE_MESSAGE),
+    KLABEL(SEC_E_INSUFFICIENT_MEMORY),
+    KLABEL(SEC_E_INTERNAL_ERROR),
+    KLABEL(SEC_E_INVALID_HANDLE),
+    KLABEL(SEC_E_INVALID_TOKEN),
+    KLABEL(SEC_E_LOGON_DENIED),
+    KLABEL(SEC_E_NO_AUTHENTICATING_AUTHORITY),
+    KLABEL(SEC_E_NO_CREDENTIALS),
+    KLABEL(SEC_E_NOT_OWNER),
+    KLABEL(SEC_E_OK),
+    KLABEL(SEC_E_SECPKG_NOT_FOUND),
+    KLABEL(SEC_E_TARGET_UNKNOWN),
+    KLABEL(SEC_E_UNKNOWN_CREDENTIALS),
+    KLABEL(SEC_E_UNSUPPORTED_FUNCTION),
+    KLABEL(SEC_E_UNTRUSTED_ROOT),
+    KLABEL(SEC_E_WRONG_PRINCIPAL),
+    LASTLABEL};
 #undef KLABEL
 #undef LASTLABEL
 #endif  // defined(WEBRTC_WIN)
@@ -110,9 +114,11 @@
 // Enum - TODO: expose globally later?
 //////////////////////////////////////////////////////////////////////
 
-bool find_string(size_t& index, const std::string& needle,
-                 const char* const haystack[], size_t max_index) {
-  for (index=0; index<max_index; ++index) {
+bool find_string(size_t& index,
+                 const std::string& needle,
+                 const char* const haystack[],
+                 size_t max_index) {
+  for (index = 0; index < max_index; ++index) {
     if (_stricmp(needle.c_str(), haystack[index]) == 0) {
       return true;
     }
@@ -120,7 +126,7 @@
   return false;
 }
 
-template<class E>
+template <class E>
 struct Enum {
   static const char** Names;
   static size_t Size;
@@ -137,60 +143,65 @@
   E val;
 
   inline operator E&() { return val; }
-  inline Enum& operator=(E rhs) { val = rhs; return *this; }
+  inline Enum& operator=(E rhs) {
+    val = rhs;
+    return *this;
+  }
 
   inline const char* name() const { return Name(val); }
   inline bool assign(const std::string& name) { return Parse(val, name); }
-  inline Enum& operator=(const std::string& rhs) { assign(rhs); return *this; }
+  inline Enum& operator=(const std::string& rhs) {
+    assign(rhs);
+    return *this;
+  }
 };
 
-#define ENUM(e,n) \
-  template<> const char** Enum<e>::Names = n; \
-  template<> size_t Enum<e>::Size = sizeof(n)/sizeof(n[0])
+#define ENUM(e, n)                 \
+  template <>                      \
+  const char** Enum<e>::Names = n; \
+  template <>                      \
+  size_t Enum<e>::Size = sizeof(n) / sizeof(n[0])
 
 //////////////////////////////////////////////////////////////////////
 // HttpCommon
 //////////////////////////////////////////////////////////////////////
 
-static const char* kHttpVersions[HVER_LAST+1] = {
-  "1.0", "1.1", "Unknown"
-};
+static const char* kHttpVersions[HVER_LAST + 1] = {"1.0", "1.1", "Unknown"};
 ENUM(HttpVersion, kHttpVersions);
 
-static const char* kHttpVerbs[HV_LAST+1] = {
-  "GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD"
-};
+static const char* kHttpVerbs[HV_LAST + 1] = {"GET",    "POST",    "PUT",
+                                              "DELETE", "CONNECT", "HEAD"};
 ENUM(HttpVerb, kHttpVerbs);
 
-static const char* kHttpHeaders[HH_LAST+1] = {
-  "Age",
-  "Cache-Control",
-  "Connection",
-  "Content-Disposition",
-  "Content-Length",
-  "Content-Range",
-  "Content-Type",
-  "Cookie",
-  "Date",
-  "ETag",
-  "Expires",
-  "Host",
-  "If-Modified-Since",
-  "If-None-Match",
-  "Keep-Alive",
-  "Last-Modified",
-  "Location",
-  "Proxy-Authenticate",
-  "Proxy-Authorization",
-  "Proxy-Connection",
-  "Range",
-  "Set-Cookie",
-  "TE",
-  "Trailers",
-  "Transfer-Encoding",
-  "Upgrade",
-  "User-Agent",
-  "WWW-Authenticate",
+static const char* kHttpHeaders[HH_LAST + 1] = {
+    "Age",
+    "Cache-Control",
+    "Connection",
+    "Content-Disposition",
+    "Content-Length",
+    "Content-Range",
+    "Content-Type",
+    "Cookie",
+    "Date",
+    "ETag",
+    "Expires",
+    "Host",
+    "If-Modified-Since",
+    "If-None-Match",
+    "Keep-Alive",
+    "Last-Modified",
+    "Location",
+    "Proxy-Authenticate",
+    "Proxy-Authorization",
+    "Proxy-Connection",
+    "Range",
+    "Set-Cookie",
+    "TE",
+    "Trailers",
+    "Transfer-Encoding",
+    "Upgrade",
+    "User-Agent",
+    "WWW-Authenticate",
 };
 ENUM(HttpHeader, kHttpHeaders);
 
@@ -219,56 +230,57 @@
 }
 
 bool HttpCodeHasBody(uint32_t code) {
-  return !HttpCodeIsInformational(code)
-         && (code != HC_NO_CONTENT) && (code != HC_NOT_MODIFIED);
+  return !HttpCodeIsInformational(code) && (code != HC_NO_CONTENT) &&
+         (code != HC_NOT_MODIFIED);
 }
 
 bool HttpCodeIsCacheable(uint32_t code) {
   switch (code) {
-  case HC_OK:
-  case HC_NON_AUTHORITATIVE:
-  case HC_PARTIAL_CONTENT:
-  case HC_MULTIPLE_CHOICES:
-  case HC_MOVED_PERMANENTLY:
-  case HC_GONE:
-    return true;
-  default:
-    return false;
+    case HC_OK:
+    case HC_NON_AUTHORITATIVE:
+    case HC_PARTIAL_CONTENT:
+    case HC_MULTIPLE_CHOICES:
+    case HC_MOVED_PERMANENTLY:
+    case HC_GONE:
+      return true;
+    default:
+      return false;
   }
 }
 
 bool HttpHeaderIsEndToEnd(HttpHeader header) {
   switch (header) {
-  case HH_CONNECTION:
-  case HH_KEEP_ALIVE:
-  case HH_PROXY_AUTHENTICATE:
-  case HH_PROXY_AUTHORIZATION:
-  case HH_PROXY_CONNECTION:  // Note part of RFC... this is non-standard header
-  case HH_TE:
-  case HH_TRAILERS:
-  case HH_TRANSFER_ENCODING:
-  case HH_UPGRADE:
-    return false;
-  default:
-    return true;
+    case HH_CONNECTION:
+    case HH_KEEP_ALIVE:
+    case HH_PROXY_AUTHENTICATE:
+    case HH_PROXY_AUTHORIZATION:
+    case HH_PROXY_CONNECTION:  // Note part of RFC... this is non-standard
+                               // header
+    case HH_TE:
+    case HH_TRAILERS:
+    case HH_TRANSFER_ENCODING:
+    case HH_UPGRADE:
+      return false;
+    default:
+      return true;
   }
 }
 
 bool HttpHeaderIsCollapsible(HttpHeader header) {
   switch (header) {
-  case HH_SET_COOKIE:
-  case HH_PROXY_AUTHENTICATE:
-  case HH_WWW_AUTHENTICATE:
-    return false;
-  default:
-    return true;
+    case HH_SET_COOKIE:
+    case HH_PROXY_AUTHENTICATE:
+    case HH_WWW_AUTHENTICATE:
+      return false;
+    default:
+      return true;
   }
 }
 
 bool HttpShouldKeepAlive(const HttpData& data) {
   std::string connection;
-  if ((data.hasHeader(HH_PROXY_CONNECTION, &connection)
-      || data.hasHeader(HH_CONNECTION, &connection))) {
+  if ((data.hasHeader(HH_PROXY_CONNECTION, &connection) ||
+       data.hasHeader(HH_CONNECTION, &connection))) {
     return (_stricmp(connection.c_str(), "Keep-Alive") == 0);
   }
   return (data.version >= HVER_1_1);
@@ -276,16 +288,16 @@
 
 namespace {
 
-inline bool IsEndOfAttributeName(size_t pos, size_t len, const char * data) {
+inline bool IsEndOfAttributeName(size_t pos, size_t len, const char* data) {
   if (pos >= len)
     return true;
   if (isspace(static_cast<unsigned char>(data[pos])))
     return true;
   // The reason for this complexity is that some attributes may contain trailing
   // equal signs (like base64 tokens in Negotiate auth headers)
-  if ((pos+1 < len) && (data[pos] == '=') &&
-      !isspace(static_cast<unsigned char>(data[pos+1])) &&
-      (data[pos+1] != '=')) {
+  if ((pos + 1 < len) && (data[pos] == '=') &&
+      !isspace(static_cast<unsigned char>(data[pos + 1])) &&
+      (data[pos + 1] != '=')) {
     return true;
   }
   return false;
@@ -293,7 +305,8 @@
 
 }  // anonymous namespace
 
-void HttpParseAttributes(const char * data, size_t len,
+void HttpParseAttributes(const char* data,
+                         size_t len,
                          HttpAttributeList& attributes) {
   size_t pos = 0;
   while (true) {
@@ -317,7 +330,7 @@
 
     // Attribute has value?
     if ((pos < len) && (data[pos] == '=')) {
-      ++pos; // Skip '='
+      ++pos;  // Skip '='
       // Check if quoted value
       if ((pos < len) && (data[pos] == '"')) {
         while (++pos < len) {
@@ -330,16 +343,16 @@
           attribute.second.append(1, data[pos]);
         }
       } else {
-        while ((pos < len) &&
-            !isspace(static_cast<unsigned char>(data[pos])) &&
-            (data[pos] != ',')) {
+        while ((pos < len) && !isspace(static_cast<unsigned char>(data[pos])) &&
+               (data[pos] != ',')) {
           attribute.second.append(1, data[pos++]);
         }
       }
     }
 
     attributes.push_back(attribute);
-    if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ','
+    if ((pos < len) && (data[pos] == ','))
+      ++pos;  // Skip ','
   }
 }
 
@@ -374,15 +387,13 @@
 
 bool HttpDateToSeconds(const std::string& date, time_t* seconds) {
   const char* const kTimeZones[] = {
-    "UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT",
-    "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M",
-    "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"
-  };
+      "UT",  "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST",
+      "PDT", "A",   "B",   "C",   "D",   "E",   "F",   "G",   "H",
+      "I",   "K",   "L",   "M",   "N",   "O",   "P",   "Q",   "R",
+      "S",   "T",   "U",   "V",   "W",   "X",   "Y"};
   const int kTimeZoneOffsets[] = {
-     0,  0, -5, -4, -6, -5, -7, -6, -8, -7,
-    -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12,
-     1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12
-  };
+      0,  0,  -5,  -4,  -6,  -5, -7, -6, -8, -7, -1, -2, -3, -4, -5, -6, -7,
+      -8, -9, -10, -11, -12, 1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12};
 
   RTC_DCHECK(nullptr != seconds);
   struct tm tval;
@@ -391,28 +402,48 @@
   memset(month, 0, sizeof(month));
   memset(zone, 0, sizeof(zone));
 
-  if (7 != sscanf(date.c_str(), "%*3s, %d %3s %d %d:%d:%d %5c",
-                  &tval.tm_mday, month, &tval.tm_year,
-                  &tval.tm_hour, &tval.tm_min, &tval.tm_sec, zone)) {
+  if (7 != sscanf(date.c_str(), "%*3s, %d %3s %d %d:%d:%d %5c", &tval.tm_mday,
+                  month, &tval.tm_year, &tval.tm_hour, &tval.tm_min,
+                  &tval.tm_sec, zone)) {
     return false;
   }
   switch (toupper(month[2])) {
-  case 'N': tval.tm_mon = (month[1] == 'A') ? 0 : 5; break;
-  case 'B': tval.tm_mon = 1; break;
-  case 'R': tval.tm_mon = (month[0] == 'M') ? 2 : 3; break;
-  case 'Y': tval.tm_mon = 4; break;
-  case 'L': tval.tm_mon = 6; break;
-  case 'G': tval.tm_mon = 7; break;
-  case 'P': tval.tm_mon = 8; break;
-  case 'T': tval.tm_mon = 9; break;
-  case 'V': tval.tm_mon = 10; break;
-  case 'C': tval.tm_mon = 11; break;
+    case 'N':
+      tval.tm_mon = (month[1] == 'A') ? 0 : 5;
+      break;
+    case 'B':
+      tval.tm_mon = 1;
+      break;
+    case 'R':
+      tval.tm_mon = (month[0] == 'M') ? 2 : 3;
+      break;
+    case 'Y':
+      tval.tm_mon = 4;
+      break;
+    case 'L':
+      tval.tm_mon = 6;
+      break;
+    case 'G':
+      tval.tm_mon = 7;
+      break;
+    case 'P':
+      tval.tm_mon = 8;
+      break;
+    case 'T':
+      tval.tm_mon = 9;
+      break;
+    case 'V':
+      tval.tm_mon = 10;
+      break;
+    case 'C':
+      tval.tm_mon = 11;
+      break;
   }
   tval.tm_year -= 1900;
   time_t gmt, non_gmt = mktime(&tval);
   if ((zone[0] == '+') || (zone[0] == '-')) {
-    if (!isdigit(zone[1]) || !isdigit(zone[2])
-        || !isdigit(zone[3]) || !isdigit(zone[4])) {
+    if (!isdigit(zone[1]) || !isdigit(zone[2]) || !isdigit(zone[3]) ||
+        !isdigit(zone[4])) {
       return false;
     }
     int hours = (zone[1] - '0') * 10 + (zone[2] - '0');
@@ -426,9 +457,10 @@
     }
     gmt = non_gmt + kTimeZoneOffsets[zindex] * 60 * 60;
   }
-  // TODO: Android should support timezone, see b/2441195
-#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID) || defined(BSD)
-  tm *tm_for_timezone = localtime(&gmt);
+// TODO: Android should support timezone, see b/2441195
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID) || \
+    defined(BSD)
+  tm* tm_for_timezone = localtime(&gmt);
   *seconds = gmt + tm_for_timezone->tm_gmtoff;
 #else
 #if defined(_MSC_VER) && _MSC_VER >= 1900
@@ -441,21 +473,19 @@
 }
 
 std::string HttpAddress(const SocketAddress& address, bool secure) {
-  return (address.port() == HttpDefaultPort(secure))
-          ? address.hostname() : address.ToString();
+  return (address.port() == HttpDefaultPort(secure)) ? address.hostname()
+                                                     : address.ToString();
 }
 
 //////////////////////////////////////////////////////////////////////
 // HttpData
 //////////////////////////////////////////////////////////////////////
 
-HttpData::HttpData() : version(HVER_1_1) {
-}
+HttpData::HttpData() : version(HVER_1_1) {}
 
 HttpData::~HttpData() = default;
 
-void
-HttpData::clear(bool release_document) {
+void HttpData::clear(bool release_document) {
   // Clear headers first, since releasing a document may have far-reaching
   // effects.
   headers_.clear();
@@ -464,19 +494,19 @@
   }
 }
 
-void
-HttpData::copy(const HttpData& src) {
+void HttpData::copy(const HttpData& src) {
   headers_ = src.headers_;
 }
 
-void
-HttpData::changeHeader(const std::string& name, const std::string& value,
-                       HeaderCombine combine) {
+void HttpData::changeHeader(const std::string& name,
+                            const std::string& value,
+                            HeaderCombine combine) {
   if (combine == HC_AUTO) {
     HttpHeader header;
     // Unrecognized headers are collapsible
     combine = !FromString(header, name) || HttpHeaderIsCollapsible(header)
-              ? HC_YES : HC_NO;
+                  ? HC_YES
+                  : HC_NO;
   } else if (combine == HC_REPLACE) {
     headers_.erase(name);
     combine = HC_NO;
@@ -505,8 +535,7 @@
   return header;
 }
 
-bool
-HttpData::hasHeader(const std::string& name, std::string* value) const {
+bool HttpData::hasHeader(const std::string& name, std::string* value) const {
   HeaderMap::const_iterator it = headers_.find(name);
   if (it == headers_.end()) {
     return false;
@@ -542,38 +571,34 @@
 // HttpRequestData
 //
 
-void
-HttpRequestData::clear(bool release_document) {
+void HttpRequestData::clear(bool release_document) {
   verb = HV_GET;
   path.clear();
   HttpData::clear(release_document);
 }
 
-void
-HttpRequestData::copy(const HttpRequestData& src) {
+void HttpRequestData::copy(const HttpRequestData& src) {
   verb = src.verb;
   path = src.path;
   HttpData::copy(src);
 }
 
-size_t
-HttpRequestData::formatLeader(char* buffer, size_t size) const {
+size_t HttpRequestData::formatLeader(char* buffer, size_t size) const {
   RTC_DCHECK(path.find(' ') == std::string::npos);
   return sprintfn(buffer, size, "%s %.*s HTTP/%s", ToString(verb), path.size(),
                   path.data(), ToString(version));
 }
 
-HttpError
-HttpRequestData::parseLeader(const char* line, size_t len) {
+HttpError HttpRequestData::parseLeader(const char* line, size_t len) {
   unsigned int vmajor, vminor;
   int vend, dstart, dend;
   // sscanf isn't safe with strings that aren't null-terminated, and there is
   // no guarantee that |line| is. Create a local copy that is null-terminated.
   std::string line_str(line, len);
   line = line_str.c_str();
-  if ((sscanf(line, "%*s%n %n%*s%n HTTP/%u.%u",
-              &vend, &dstart, &dend, &vmajor, &vminor) != 2)
-      || (vmajor != 1)) {
+  if ((sscanf(line, "%*s%n %n%*s%n HTTP/%u.%u", &vend, &dstart, &dend, &vmajor,
+              &vminor) != 2) ||
+      (vmajor != 1)) {
     return HE_PROTOCOL;
   }
   if (vminor == 0) {
@@ -585,7 +610,7 @@
   }
   std::string sverb(line, vend);
   if (!FromString(verb, sverb.c_str())) {
-    return HE_PROTOCOL; // !?! HC_METHOD_NOT_SUPPORTED?
+    return HE_PROTOCOL;  // !?! HC_METHOD_NOT_SUPPORTED?
   }
   path.assign(line + dstart, line + dend);
   return HE_NONE;
@@ -609,8 +634,7 @@
 }
 
 bool HttpRequestData::getRelativeUri(std::string* host,
-                                     std::string* path) const
-{
+                                     std::string* path) const {
   if (HV_CONNECT == verb)
     return false;
   Url<char> url(this->path);
@@ -629,15 +653,13 @@
 // HttpResponseData
 //
 
-void
-HttpResponseData::clear(bool release_document) {
+void HttpResponseData::clear(bool release_document) {
   scode = HC_INTERNAL_SERVER_ERROR;
   message.clear();
   HttpData::clear(release_document);
 }
 
-void
-HttpResponseData::copy(const HttpResponseData& src) {
+void HttpResponseData::copy(const HttpResponseData& src) {
   scode = src.scode;
   message = src.message;
   HttpData::copy(src);
@@ -671,18 +693,16 @@
   setHeader(HH_CONTENT_LENGTH, "0", false);
 }
 
-size_t
-HttpResponseData::formatLeader(char* buffer, size_t size) const {
+size_t HttpResponseData::formatLeader(char* buffer, size_t size) const {
   size_t len = sprintfn(buffer, size, "HTTP/%s %lu", ToString(version), scode);
   if (!message.empty()) {
-    len += sprintfn(buffer + len, size - len, " %.*s",
-                    message.size(), message.data());
+    len += sprintfn(buffer + len, size - len, " %.*s", message.size(),
+                    message.data());
   }
   return len;
 }
 
-HttpError
-HttpResponseData::parseLeader(const char* line, size_t len) {
+HttpError HttpResponseData::parseLeader(const char* line, size_t len) {
   size_t pos = 0;
   unsigned int vmajor, vminor, temp_scode;
   int temp_pos;
@@ -690,16 +710,15 @@
   // no guarantee that |line| is. Create a local copy that is null-terminated.
   std::string line_str(line, len);
   line = line_str.c_str();
-  if (sscanf(line, "HTTP %u%n",
-             &temp_scode, &temp_pos) == 1) {
+  if (sscanf(line, "HTTP %u%n", &temp_scode, &temp_pos) == 1) {
     // This server's response has no version. :( NOTE: This happens for every
     // response to requests made from Chrome plugins, regardless of the server's
     // behaviour.
     RTC_LOG(LS_VERBOSE) << "HTTP version missing from response";
     version = HVER_UNKNOWN;
-  } else if ((sscanf(line, "HTTP/%u.%u %u%n",
-                     &vmajor, &vminor, &temp_scode, &temp_pos) == 3)
-             && (vmajor == 1)) {
+  } else if ((sscanf(line, "HTTP/%u.%u %u%n", &vmajor, &vminor, &temp_scode,
+                     &temp_pos) == 3) &&
+             (vmajor == 1)) {
     // This server's response does have a version.
     if (vminor == 0) {
       version = HVER_1_0;
@@ -713,7 +732,8 @@
   }
   scode = temp_scode;
   pos = static_cast<size_t>(temp_pos);
-  while ((pos < len) && isspace(static_cast<unsigned char>(line[pos]))) ++pos;
+  while ((pos < len) && isspace(static_cast<unsigned char>(line[pos])))
+    ++pos;
   message.assign(line + pos, len - pos);
   return HE_NONE;
 }
@@ -725,7 +745,7 @@
 std::string quote(const std::string& str) {
   std::string result;
   result.push_back('"');
-  for (size_t i=0; i<str.size(); ++i) {
+  for (size_t i = 0; i < str.size(); ++i) {
     if ((str[i] == '"') || (str[i] == '\\'))
       result.push_back('\\');
     result.push_back(str[i]);
@@ -742,24 +762,29 @@
   bool specified_credentials;
 
   NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2)
-  : HttpAuthContext(auth), cred(c1), ctx(c2), steps(0),
-    specified_credentials(false)
-  { }
+      : HttpAuthContext(auth),
+        cred(c1),
+        ctx(c2),
+        steps(0),
+        specified_credentials(false) {}
 
   ~NegotiateAuthContext() override {
     DeleteSecurityContext(&ctx);
     FreeCredentialsHandle(&cred);
   }
 };
-#endif // WEBRTC_WIN
+#endif  // WEBRTC_WIN
 
-HttpAuthResult HttpAuthenticate(
-  const char * challenge, size_t len,
-  const SocketAddress& server,
-  const std::string& method, const std::string& uri,
-  const std::string& username, const CryptString& password,
-  HttpAuthContext *& context, std::string& response, std::string& auth_method)
-{
+HttpAuthResult HttpAuthenticate(const char* challenge,
+                                size_t len,
+                                const SocketAddress& server,
+                                const std::string& method,
+                                const std::string& uri,
+                                const std::string& username,
+                                const CryptString& password,
+                                HttpAuthContext*& context,
+                                std::string& response,
+                                std::string& auth_method) {
   HttpAttributeList args;
   HttpParseAttributes(challenge, len, args);
   HttpHasNthAttribute(args, 0, &auth_method, nullptr);
@@ -770,9 +795,9 @@
   // BASIC
   if (_stricmp(auth_method.c_str(), "basic") == 0) {
     if (context)
-      return HAR_CREDENTIALS; // Bad credentials
+      return HAR_CREDENTIALS;  // Bad credentials
     if (username.empty())
-      return HAR_CREDENTIALS; // Missing credentials
+      return HAR_CREDENTIALS;  // Missing credentials
 
     context = new HttpAuthContext(auth_method);
 
@@ -781,7 +806,7 @@
     // automatically.
     // std::string decoded = username + ":" + password;
     size_t len = username.size() + password.GetLength() + 2;
-    char * sensitive = new char[len];
+    char* sensitive = new char[len];
     size_t pos = strcpyn(sensitive, len, username.data(), username.size());
     pos += strcpyn(sensitive + pos, len - pos, ":");
     password.CopyTo(sensitive + pos, true);
@@ -791,16 +816,16 @@
     // TODO: create a sensitive-source version of Base64::encode
     response.append(Base64::Encode(sensitive));
     ExplicitZeroMemory(sensitive, len);
-    delete [] sensitive;
+    delete[] sensitive;
     return HAR_RESPONSE;
   }
 
   // DIGEST
   if (_stricmp(auth_method.c_str(), "digest") == 0) {
     if (context)
-      return HAR_CREDENTIALS; // Bad credentials
+      return HAR_CREDENTIALS;  // Bad credentials
     if (username.empty())
-      return HAR_CREDENTIALS; // Missing credentials
+      return HAR_CREDENTIALS;  // Missing credentials
 
     context = new HttpAuthContext(auth_method);
 
@@ -821,7 +846,7 @@
     // automatically.
     // std::string A1 = username + ":" + realm + ":" + password;
     size_t len = username.size() + realm.size() + password.GetLength() + 3;
-    char * sensitive = new char[len];  // A1
+    char* sensitive = new char[len];  // A1
     size_t pos = strcpyn(sensitive, len, username.data(), username.size());
     pos += strcpyn(sensitive + pos, len - pos, ":");
     pos += strcpyn(sensitive + pos, len - pos, realm.c_str());
@@ -838,7 +863,7 @@
     }
     std::string HA1 = MD5(sensitive);
     ExplicitZeroMemory(sensitive, len);
-    delete [] sensitive;
+    delete[] sensitive;
     std::string HA2 = MD5(A2);
     std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
 
@@ -850,7 +875,7 @@
     ss << ", uri=" << quote(uri);
     if (has_qop) {
       ss << ", qop=" << qop;
-      ss << ", nc="  << ncount;
+      ss << ", nc=" << ncount;
       ss << ", cnonce=" << quote(cnonce);
     }
     ss << ", response=\"" << dig_response << "\"";
@@ -870,7 +895,7 @@
     const size_t MAX_MESSAGE = 12000, MAX_SPN = 256;
     char out_buf[MAX_MESSAGE], spn[MAX_SPN];
 
-#if 0 // Requires funky windows versions
+#if 0  // Requires funky windows versions
     DWORD len = MAX_SPN;
     if (DsMakeSpn("HTTP", server.HostAsURIString().c_str(), nullptr,
                   server.port(),
@@ -883,25 +908,24 @@
 #endif
 
     SecBuffer out_sec;
-    out_sec.pvBuffer   = out_buf;
-    out_sec.cbBuffer   = sizeof(out_buf);
+    out_sec.pvBuffer = out_buf;
+    out_sec.cbBuffer = sizeof(out_buf);
     out_sec.BufferType = SECBUFFER_TOKEN;
 
     SecBufferDesc out_buf_desc;
     out_buf_desc.ulVersion = 0;
-    out_buf_desc.cBuffers  = 1;
-    out_buf_desc.pBuffers  = &out_sec;
+    out_buf_desc.cBuffers = 1;
+    out_buf_desc.pBuffers = &out_sec;
 
     const ULONG NEG_FLAGS_DEFAULT =
-      //ISC_REQ_ALLOCATE_MEMORY
-      ISC_REQ_CONFIDENTIALITY
-      //| ISC_REQ_EXTENDED_ERROR
-      //| ISC_REQ_INTEGRITY
-      | ISC_REQ_REPLAY_DETECT
-      | ISC_REQ_SEQUENCE_DETECT
-      //| ISC_REQ_STREAM
-      //| ISC_REQ_USE_SUPPLIED_CREDS
-      ;
+        // ISC_REQ_ALLOCATE_MEMORY
+        ISC_REQ_CONFIDENTIALITY
+        //| ISC_REQ_EXTENDED_ERROR
+        //| ISC_REQ_INTEGRITY
+        | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT
+        //| ISC_REQ_STREAM
+        //| ISC_REQ_USE_SUPPLIED_CREDS
+        ;
 
     ::TimeStamp lifetime;
     SECURITY_STATUS ret = S_OK;
@@ -912,7 +936,7 @@
 
     // uint32_t now = Time();
 
-    NegotiateAuthContext * neg = static_cast<NegotiateAuthContext *>(context);
+    NegotiateAuthContext* neg = static_cast<NegotiateAuthContext*>(context);
     if (neg) {
       const size_t max_steps = 10;
       if (++neg->steps >= max_steps) {
@@ -927,16 +951,18 @@
           Base64::Decode(challenge, Base64::DO_STRICT, &decoded_challenge,
                          nullptr)) {
         SecBuffer in_sec;
-        in_sec.pvBuffer   = const_cast<char *>(decoded_challenge.data());
-        in_sec.cbBuffer   = static_cast<unsigned long>(decoded_challenge.size());
+        in_sec.pvBuffer = const_cast<char*>(decoded_challenge.data());
+        in_sec.cbBuffer = static_cast<unsigned long>(decoded_challenge.size());
         in_sec.BufferType = SECBUFFER_TOKEN;
 
         SecBufferDesc in_buf_desc;
         in_buf_desc.ulVersion = 0;
-        in_buf_desc.cBuffers  = 1;
-        in_buf_desc.pBuffers  = &in_sec;
+        in_buf_desc.cBuffers = 1;
+        in_buf_desc.pBuffers = &in_sec;
 
-        ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
+        ret = InitializeSecurityContextA(
+            &neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP,
+            &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
         if (FAILED(ret)) {
           RTC_LOG(LS_ERROR) << "InitializeSecurityContext returned: "
                             << GetErrorName(ret, SECURITY_ERRORS);
@@ -954,11 +980,11 @@
 
     if (!neg) {
       unsigned char userbuf[256], passbuf[256], domainbuf[16];
-      SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0;
+      SEC_WINNT_AUTH_IDENTITY_A auth_id, *pauth_id = 0;
       if (specify_credentials) {
         memset(&auth_id, 0, sizeof(auth_id));
-        size_t len = password.GetLength()+1;
-        char * sensitive = new char[len];
+        size_t len = password.GetLength() + 1;
+        char* sensitive = new char[len];
         password.CopyTo(sensitive, true);
         std::string::size_type pos = username.find('\\');
         if (pos == std::string::npos) {
@@ -987,7 +1013,7 @@
           passbuf[auth_id.PasswordLength] = 0;
         }
         ExplicitZeroMemory(sensitive, len);
-        delete [] sensitive;
+        delete[] sensitive;
         auth_id.User = userbuf;
         auth_id.Domain = domainbuf;
         auth_id.Password = passbuf;
@@ -1009,10 +1035,12 @@
         return HAR_IGNORE;
       }
 
-      //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
+      // CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
 
       CtxtHandle ctx;
-      ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime);
+      ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0,
+                                       SECURITY_NATIVE_DREP, 0, 0, &ctx,
+                                       &out_buf_desc, &ret_flags, &lifetime);
       if (FAILED(ret)) {
         RTC_LOG(LS_ERROR) << "InitializeSecurityContext returned: "
                           << GetErrorName(ret, SECURITY_ERRORS);
@@ -1026,7 +1054,8 @@
       neg->steps = steps;
     }
 
-    if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
+    if ((ret == SEC_I_COMPLETE_NEEDED) ||
+        (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
       ret = CompleteAuthToken(&neg->ctx, &out_buf_desc);
       RTC_LOG(LS_VERBOSE) << "CompleteAuthToken returned: "
                           << GetErrorName(ret, SECURITY_ERRORS);
@@ -1042,11 +1071,11 @@
     return HAR_RESPONSE;
   }
 #endif
-#endif // WEBRTC_WIN
+#endif  // WEBRTC_WIN
 
   return HAR_IGNORE;
 }
 
 //////////////////////////////////////////////////////////////////////
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/httpcommon.h b/rtc_base/httpcommon.h
index 4dd1172..1b8768d 100644
--- a/rtc_base/httpcommon.h
+++ b/rtc_base/httpcommon.h
@@ -15,7 +15,7 @@
 #include <memory>
 #include <string>
 #include <vector>
-#include "rtc_base/basictypes.h"
+
 #include "rtc_base/checks.h"
 #include "rtc_base/stream.h"
 #include "rtc_base/stringutils.h"
@@ -54,29 +54,31 @@
   HC_SERVICE_UNAVAILABLE = 503,
 };
 
-enum HttpVersion {
-  HVER_1_0, HVER_1_1, HVER_UNKNOWN,
-  HVER_LAST = HVER_UNKNOWN
-};
+enum HttpVersion { HVER_1_0, HVER_1_1, HVER_UNKNOWN, HVER_LAST = HVER_UNKNOWN };
 
 enum HttpVerb {
-  HV_GET, HV_POST, HV_PUT, HV_DELETE, HV_CONNECT, HV_HEAD,
+  HV_GET,
+  HV_POST,
+  HV_PUT,
+  HV_DELETE,
+  HV_CONNECT,
+  HV_HEAD,
   HV_LAST = HV_HEAD
 };
 
 enum HttpError {
   HE_NONE,
-  HE_PROTOCOL,            // Received non-valid HTTP data
-  HE_DISCONNECTED,        // Connection closed unexpectedly
-  HE_OVERFLOW,            // Received too much data for internal buffers
-  HE_CONNECT_FAILED,      // The socket failed to connect.
-  HE_SOCKET_ERROR,        // An error occurred on a connected socket
-  HE_SHUTDOWN,            // Http object is being destroyed
-  HE_OPERATION_CANCELLED, // Connection aborted locally
-  HE_AUTH,                // Proxy Authentication Required
-  HE_CERTIFICATE_EXPIRED, // During SSL negotiation
-  HE_STREAM,              // Problem reading or writing to the document
-  HE_CACHE,               // Problem reading from cache
+  HE_PROTOCOL,             // Received non-valid HTTP data
+  HE_DISCONNECTED,         // Connection closed unexpectedly
+  HE_OVERFLOW,             // Received too much data for internal buffers
+  HE_CONNECT_FAILED,       // The socket failed to connect.
+  HE_SOCKET_ERROR,         // An error occurred on a connected socket
+  HE_SHUTDOWN,             // Http object is being destroyed
+  HE_OPERATION_CANCELLED,  // Connection aborted locally
+  HE_AUTH,                 // Proxy Authentication Required
+  HE_CERTIFICATE_EXPIRED,  // During SSL negotiation
+  HE_STREAM,               // Problem reading or writing to the document
+  HE_CACHE,                // Problem reading from cache
   HE_DEFAULT
 };
 
@@ -158,7 +160,8 @@
 
 typedef std::pair<std::string, std::string> HttpAttribute;
 typedef std::vector<HttpAttribute> HttpAttributeList;
-void HttpParseAttributes(const char * data, size_t len,
+void HttpParseAttributes(const char* data,
+                         size_t len,
                          HttpAttributeList& attributes);
 bool HttpHasAttribute(const HttpAttributeList& attributes,
                       const std::string& name,
@@ -192,9 +195,9 @@
 // Url
 //////////////////////////////////////////////////////////////////////
 
-template<class CTYPE>
+template <class CTYPE>
 class Url {
-public:
+ public:
   typedef typename Traits<CTYPE>::string string;
 
   // TODO: Implement Encode/Decode
@@ -218,25 +221,29 @@
     query_.clear();
   }
 
-  void set_url(const string& val) {
-    do_set_url(val.c_str(), val.size());
-  }
+  void set_url(const string& val) { do_set_url(val.c_str(), val.size()); }
   string url() const {
-    string val; do_get_url(&val); return val;
+    string val;
+    do_get_url(&val);
+    return val;
   }
 
   void set_address(const string& val) {
     do_set_address(val.c_str(), val.size());
   }
   string address() const {
-    string val; do_get_address(&val); return val;
+    string val;
+    do_get_address(&val);
+    return val;
   }
 
   void set_full_path(const string& val) {
     do_set_full_path(val.c_str(), val.size());
   }
   string full_path() const {
-    string val; do_get_full_path(&val); return val;
+    string val;
+    do_get_full_path(&val);
+    return val;
   }
 
   void set_host(const string& val) { host_ = val; }
@@ -266,7 +273,7 @@
 
   bool get_attribute(const string& name, string* value) const;
 
-private:
+ private:
   void do_set_url(const CTYPE* val, size_t len);
   void do_set_address(const CTYPE* val, size_t len);
   void do_set_full_path(const CTYPE* val, size_t len);
@@ -295,13 +302,16 @@
   HttpData();
 
   enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW };
-  void changeHeader(const std::string& name, const std::string& value,
+  void changeHeader(const std::string& name,
+                    const std::string& value,
                     HeaderCombine combine);
-  inline void addHeader(const std::string& name, const std::string& value,
+  inline void addHeader(const std::string& name,
+                        const std::string& value,
                         bool append = true) {
     changeHeader(name, value, append ? HC_AUTO : HC_NO);
   }
-  inline void setHeader(const std::string& name, const std::string& value,
+  inline void setHeader(const std::string& name,
+                        const std::string& value,
                         bool overwrite = true) {
     changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW);
   }
@@ -313,18 +323,10 @@
   // keep in mind, this may not do what you want in the face of multiple headers
   bool hasHeader(const std::string& name, std::string* value) const;
 
-  inline const_iterator begin() const {
-    return headers_.begin();
-  }
-  inline const_iterator end() const {
-    return headers_.end();
-  }
-  inline iterator begin() {
-    return headers_.begin();
-  }
-  inline iterator end() {
-    return headers_.end();
-  }
+  inline const_iterator begin() const { return headers_.begin(); }
+  inline const_iterator end() const { return headers_.end(); }
+  inline iterator begin() { return headers_.begin(); }
+  inline iterator end() { return headers_.end(); }
   inline const_iterator begin(const std::string& name) const {
     return headers_.lower_bound(name);
   }
@@ -339,21 +341,22 @@
   }
 
   // Convenience methods using HttpHeader
-  inline void changeHeader(HttpHeader header, const std::string& value,
+  inline void changeHeader(HttpHeader header,
+                           const std::string& value,
                            HeaderCombine combine) {
     changeHeader(ToString(header), value, combine);
   }
-  inline void addHeader(HttpHeader header, const std::string& value,
+  inline void addHeader(HttpHeader header,
+                        const std::string& value,
                         bool append = true) {
     addHeader(ToString(header), value, append);
   }
-  inline void setHeader(HttpHeader header, const std::string& value,
+  inline void setHeader(HttpHeader header,
+                        const std::string& value,
                         bool overwrite = true) {
     setHeader(ToString(header), value, overwrite);
   }
-  inline void clearHeader(HttpHeader header) {
-    clearHeader(ToString(header));
-  }
+  inline void clearHeader(HttpHeader header) { clearHeader(ToString(header)); }
   inline bool hasHeader(HttpHeader header, std::string* value) const {
     return hasHeader(ToString(header), value);
   }
@@ -376,12 +379,12 @@
   virtual size_t formatLeader(char* buffer, size_t size) const = 0;
   virtual HttpError parseLeader(const char* line, size_t len) = 0;
 
-protected:
- virtual ~HttpData();
+ protected:
+  virtual ~HttpData();
   void clear(bool release_document);
   void copy(const HttpData& src);
 
-private:
+ private:
   HeaderMap headers_;
 };
 
@@ -389,7 +392,7 @@
   HttpVerb verb;
   std::string path;
 
-  HttpRequestData() : verb(HV_GET) { }
+  HttpRequestData() : verb(HV_GET) {}
 
   void clear(bool release_document);
   void copy(const HttpRequestData& src);
@@ -405,7 +408,7 @@
   uint32_t scode;
   std::string message;
 
-  HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) { }
+  HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) {}
   void clear(bool release_document);
   void copy(const HttpResponseData& src);
 
@@ -433,8 +436,8 @@
 
 struct HttpAuthContext {
   std::string auth_method;
-  HttpAuthContext(const std::string& auth) : auth_method(auth) { }
-  virtual ~HttpAuthContext() { }
+  HttpAuthContext(const std::string& auth) : auth_method(auth) {}
+  virtual ~HttpAuthContext() {}
 };
 
 enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR };
@@ -443,15 +446,19 @@
 // Start by passing a null pointer, then pass the same pointer each additional
 // call.  When the authentication attempt is finished, delete the context.
 // TODO(bugs.webrtc.org/8905): Change "response" to "ZeroOnFreeBuffer".
-HttpAuthResult HttpAuthenticate(
-  const char * challenge, size_t len,
-  const SocketAddress& server,
-  const std::string& method, const std::string& uri,
-  const std::string& username, const CryptString& password,
-  HttpAuthContext *& context, std::string& response, std::string& auth_method);
+HttpAuthResult HttpAuthenticate(const char* challenge,
+                                size_t len,
+                                const SocketAddress& server,
+                                const std::string& method,
+                                const std::string& uri,
+                                const std::string& username,
+                                const CryptString& password,
+                                HttpAuthContext*& context,
+                                std::string& response,
+                                std::string& auth_method);
 
 //////////////////////////////////////////////////////////////////////
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_HTTPCOMMON_H_
+#endif  // RTC_BASE_HTTPCOMMON_H_
diff --git a/rtc_base/httpcommon_unittest.cc b/rtc_base/httpcommon_unittest.cc
index 997d6e3..ed7f242 100644
--- a/rtc_base/httpcommon_unittest.cc
+++ b/rtc_base/httpcommon_unittest.cc
@@ -122,8 +122,8 @@
 TEST(HttpResponseData, parseLeaderHttp1_0) {
   static const char kResponseString[] = "HTTP/1.0 200 OK";
   HttpResponseData response;
-  EXPECT_EQ(HE_NONE, response.parseLeader(kResponseString,
-                                          sizeof(kResponseString) - 1));
+  EXPECT_EQ(HE_NONE,
+            response.parseLeader(kResponseString, sizeof(kResponseString) - 1));
   EXPECT_EQ(HVER_1_0, response.version);
   EXPECT_EQ(200U, response.scode);
 }
@@ -131,8 +131,8 @@
 TEST(HttpResponseData, parseLeaderHttp1_1) {
   static const char kResponseString[] = "HTTP/1.1 200 OK";
   HttpResponseData response;
-  EXPECT_EQ(HE_NONE, response.parseLeader(kResponseString,
-                                          sizeof(kResponseString) - 1));
+  EXPECT_EQ(HE_NONE,
+            response.parseLeader(kResponseString, sizeof(kResponseString) - 1));
   EXPECT_EQ(HVER_1_1, response.version);
   EXPECT_EQ(200U, response.scode);
 }
@@ -140,8 +140,8 @@
 TEST(HttpResponseData, parseLeaderHttpUnknown) {
   static const char kResponseString[] = "HTTP 200 OK";
   HttpResponseData response;
-  EXPECT_EQ(HE_NONE, response.parseLeader(kResponseString,
-                                          sizeof(kResponseString) - 1));
+  EXPECT_EQ(HE_NONE,
+            response.parseLeader(kResponseString, sizeof(kResponseString) - 1));
   EXPECT_EQ(HVER_UNKNOWN, response.version);
   EXPECT_EQ(200U, response.scode);
 }
@@ -149,8 +149,8 @@
 TEST(HttpResponseData, parseLeaderHttpFailure) {
   static const char kResponseString[] = "HTTP/1.1 503 Service Unavailable";
   HttpResponseData response;
-  EXPECT_EQ(HE_NONE, response.parseLeader(kResponseString,
-                                          sizeof(kResponseString) - 1));
+  EXPECT_EQ(HE_NONE,
+            response.parseLeader(kResponseString, sizeof(kResponseString) - 1));
   EXPECT_EQ(HVER_1_1, response.version);
   EXPECT_EQ(503U, response.scode);
 }
@@ -158,8 +158,8 @@
 TEST(HttpResponseData, parseLeaderHttpInvalid) {
   static const char kResponseString[] = "Durrrrr, what's HTTP?";
   HttpResponseData response;
-  EXPECT_EQ(HE_PROTOCOL, response.parseLeader(kResponseString,
-                                              sizeof(kResponseString) - 1));
+  EXPECT_EQ(HE_PROTOCOL,
+            response.parseLeader(kResponseString, sizeof(kResponseString) - 1));
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/httpserver.cc b/rtc_base/httpserver.cc
index c36b432..0e536c3 100644
--- a/rtc_base/httpserver.cc
+++ b/rtc_base/httpserver.cc
@@ -25,24 +25,21 @@
 // HttpServer
 ///////////////////////////////////////////////////////////////////////////////
 
-HttpServer::HttpServer() : next_connection_id_(1), closing_(false) {
-}
+HttpServer::HttpServer() : next_connection_id_(1), closing_(false) {}
 
 HttpServer::~HttpServer() {
   if (closing_) {
     RTC_LOG(LS_WARNING) << "HttpServer::CloseAll has not completed";
   }
   for (ConnectionMap::iterator it = connections_.begin();
-       it != connections_.end();
-       ++it) {
+       it != connections_.end(); ++it) {
     StreamInterface* stream = it->second->EndProcess();
     delete stream;
     delete it->second;
   }
 }
 
-int
-HttpServer::HandleConnection(StreamInterface* stream) {
+int HttpServer::HandleConnection(StreamInterface* stream) {
   int connection_id = next_connection_id_++;
   RTC_DCHECK(connection_id != HTTP_INVALID_CONNECTION_ID);
   Connection* connection = new Connection(connection_id, this);
@@ -51,8 +48,7 @@
   return connection_id;
 }
 
-void
-HttpServer::Respond(HttpServerTransaction* transaction) {
+void HttpServer::Respond(HttpServerTransaction* transaction) {
   int connection_id = transaction->connection_id();
   if (Connection* connection = Find(connection_id)) {
     connection->Respond(transaction);
@@ -63,15 +59,13 @@
   }
 }
 
-void
-HttpServer::Close(int connection_id, bool force) {
+void HttpServer::Close(int connection_id, bool force) {
   if (Connection* connection = Find(connection_id)) {
     connection->InitiateClose(force);
   }
 }
 
-void
-HttpServer::CloseAll(bool force) {
+void HttpServer::CloseAll(bool force) {
   if (connections_.empty()) {
     SignalCloseAllComplete(this);
     return;
@@ -83,21 +77,19 @@
     connections.push_back(it->second);
   }
   for (std::list<Connection*>::const_iterator it = connections.begin();
-      it != connections.end(); ++it) {
+       it != connections.end(); ++it) {
     (*it)->InitiateClose(force);
   }
 }
 
-HttpServer::Connection*
-HttpServer::Find(int connection_id) {
+HttpServer::Connection* HttpServer::Find(int connection_id) {
   ConnectionMap::iterator it = connections_.find(connection_id);
   if (it == connections_.end())
     return nullptr;
   return it->second;
 }
 
-void
-HttpServer::Remove(int connection_id) {
+void HttpServer::Remove(int connection_id) {
   ConnectionMap::iterator it = connections_.find(connection_id);
   if (it == connections_.end()) {
     RTC_NOTREACHED();
@@ -130,8 +122,7 @@
   Thread::Current()->Dispose(current_);
 }
 
-void
-HttpServer::Connection::BeginProcess(StreamInterface* stream) {
+void HttpServer::Connection::BeginProcess(StreamInterface* stream) {
   base_.notify(this);
   base_.attach(stream);
   current_ = new HttpServerTransaction(connection_id_);
@@ -139,15 +130,13 @@
     base_.recv(&current_->request);
 }
 
-StreamInterface*
-HttpServer::Connection::EndProcess() {
+StreamInterface* HttpServer::Connection::EndProcess() {
   base_.notify(nullptr);
   base_.abort(HE_DISCONNECTED);
   return base_.detach();
 }
 
-void
-HttpServer::Connection::Respond(HttpServerTransaction* transaction) {
+void HttpServer::Connection::Respond(HttpServerTransaction* transaction) {
   RTC_DCHECK(current_ == nullptr);
   current_ = transaction;
   if (current_->response.begin() == current_->response.end()) {
@@ -155,14 +144,12 @@
   }
   bool keep_alive = HttpShouldKeepAlive(current_->request);
   current_->response.setHeader(HH_CONNECTION,
-                               keep_alive ? "Keep-Alive" : "Close",
-                               false);
+                               keep_alive ? "Keep-Alive" : "Close", false);
   close_ = !HttpShouldKeepAlive(current_->response);
   base_.send(&current_->response);
 }
 
-void
-HttpServer::Connection::InitiateClose(bool force) {
+void HttpServer::Connection::InitiateClose(bool force) {
   bool request_in_progress = (HM_SEND == base_.mode()) || (nullptr == current_);
   if (!signalling_ && (force || !request_in_progress)) {
     server_->Remove(connection_id_);
@@ -175,8 +162,8 @@
 // IHttpNotify Implementation
 //
 
-HttpError
-HttpServer::Connection::onHttpHeaderComplete(bool chunked, size_t& data_size) {
+HttpError HttpServer::Connection::onHttpHeaderComplete(bool chunked,
+                                                       size_t& data_size) {
   if (data_size == SIZE_UNKNOWN) {
     data_size = 0;
   }
@@ -189,8 +176,7 @@
   return HE_NONE;
 }
 
-void
-HttpServer::Connection::onHttpComplete(HttpMode mode, HttpError err) {
+void HttpServer::Connection::onHttpComplete(HttpMode mode, HttpError err) {
   if (mode == HM_SEND) {
     RTC_DCHECK(current_ != nullptr);
     signalling_ = true;
@@ -208,7 +194,7 @@
   } else if (mode == HM_RECV) {
     RTC_DCHECK(current_ != nullptr);
     // TODO: do we need this?
-    //request_.document_->rewind();
+    // request_.document_->rewind();
     HttpServerTransaction* transaction = current_;
     current_ = nullptr;
     server_->SignalHttpRequest(server_, transaction);
@@ -222,8 +208,7 @@
   }
 }
 
-void
-HttpServer::Connection::onHttpClosed(HttpError err) {
+void HttpServer::Connection::onHttpClosed(HttpError err) {
   server_->Remove(connection_id_);
 }
 
@@ -235,13 +220,11 @@
   SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed);
 }
 
-HttpListenServer::~HttpListenServer() {
-}
+HttpListenServer::~HttpListenServer() {}
 
 int HttpListenServer::Listen(const SocketAddress& address) {
-  AsyncSocket* sock =
-      Thread::Current()->socketserver()->CreateAsyncSocket(address.family(),
-                                                           SOCK_STREAM);
+  AsyncSocket* sock = Thread::Current()->socketserver()->CreateAsyncSocket(
+      address.family(), SOCK_STREAM);
   if (!sock) {
     return SOCKET_ERROR;
   }
diff --git a/rtc_base/httpserver.h b/rtc_base/httpserver.h
index 61442a9..e4d9444 100644
--- a/rtc_base/httpserver.h
+++ b/rtc_base/httpserver.h
@@ -29,16 +29,16 @@
 const int HTTP_INVALID_CONNECTION_ID = 0;
 
 struct HttpServerTransaction : public HttpTransaction {
-public:
-  HttpServerTransaction(int id) : connection_id_(id) { }
+ public:
+  HttpServerTransaction(int id) : connection_id_(id) {}
   int connection_id() const { return connection_id_; }
 
-private:
+ private:
   int connection_id_;
 };
 
 class HttpServer {
-public:
+ public:
   HttpServer();
   virtual ~HttpServer();
 
@@ -54,7 +54,7 @@
   // the document can be set to null.  Note that the transaction object is still
   // owened by the HttpServer at this point.
   sigslot::signal3<HttpServer*, HttpServerTransaction*, bool*>
-    SignalHttpRequestHeader;
+      SignalHttpRequestHeader;
 
   // An HTTP request has been made, and is available in the transaction object.
   // Populate the transaction's response, and then return the object via the
@@ -66,7 +66,7 @@
 
   // If you want to know when a request completes, listen to this event.
   sigslot::signal3<HttpServer*, HttpServerTransaction*, int>
-    SignalHttpRequestComplete;
+      SignalHttpRequestComplete;
 
   // Stop processing the connection indicated by connection_id.
   // Unless force is true, the server will complete sending a response that is
@@ -78,9 +78,9 @@
   // outstanding connections have closed.
   sigslot::signal1<HttpServer*> SignalCloseAllComplete;
 
-private:
+ private:
   class Connection : private IHttpNotify {
-  public:
+   public:
     Connection(int connection_id, HttpServer* server);
     ~Connection() override;
 
@@ -106,7 +106,7 @@
   void Remove(int connection_id);
 
   friend class Connection;
-  typedef std::map<int,Connection*> ConnectionMap;
+  typedef std::map<int, Connection*> ConnectionMap;
 
   ConnectionMap connections_;
   int next_connection_id_;
@@ -116,7 +116,7 @@
 //////////////////////////////////////////////////////////////////////
 
 class HttpListenServer : public HttpServer, public sigslot::has_slots<> {
-public:
+ public:
   HttpListenServer();
   ~HttpListenServer() override;
 
@@ -124,9 +124,10 @@
   bool GetAddress(SocketAddress* address) const;
   void StopListening();
 
-private:
+ private:
   void OnReadEvent(AsyncSocket* socket);
-  void OnConnectionClosed(HttpServer* server, int connection_id,
+  void OnConnectionClosed(HttpServer* server,
+                          int connection_id,
                           StreamInterface* stream);
 
   std::unique_ptr<AsyncSocket> listener_;
@@ -136,4 +137,4 @@
 
 }  // namespace rtc
 
-#endif // RTC_BASE_HTTPSERVER_H_
+#endif  // RTC_BASE_HTTPSERVER_H_
diff --git a/rtc_base/httpserver_unittest.cc b/rtc_base/httpserver_unittest.cc
index 5e86c88..0dde6c5 100644
--- a/rtc_base/httpserver_unittest.cc
+++ b/rtc_base/httpserver_unittest.cc
@@ -17,59 +17,56 @@
 namespace rtc {
 
 namespace {
-  const char* const kRequest =
+const char* const kRequest =
     "GET /index.html HTTP/1.1\r\n"
     "Host: localhost\r\n"
     "\r\n";
 
-  struct HttpServerMonitor : public sigslot::has_slots<> {
-    HttpServerTransaction* transaction;
-    bool server_closed, connection_closed;
+struct HttpServerMonitor : public sigslot::has_slots<> {
+  HttpServerTransaction* transaction;
+  bool server_closed, connection_closed;
 
-    HttpServerMonitor(HttpServer* server)
-        : transaction(nullptr), server_closed(false), connection_closed(false) {
-      server->SignalCloseAllComplete.connect(this,
-        &HttpServerMonitor::OnClosed);
-      server->SignalHttpRequest.connect(this, &HttpServerMonitor::OnRequest);
-      server->SignalHttpRequestComplete.connect(this,
-        &HttpServerMonitor::OnRequestComplete);
-      server->SignalConnectionClosed.connect(this,
-        &HttpServerMonitor::OnConnectionClosed);
-    }
-    void OnRequest(HttpServer*, HttpServerTransaction* t) {
-      ASSERT_FALSE(transaction);
-      transaction = t;
-      transaction->response.set_success();
-      transaction->response.setHeader(HH_CONNECTION, "Close");
-    }
-    void OnRequestComplete(HttpServer*, HttpServerTransaction* t, int) {
-      ASSERT_EQ(transaction, t);
-      transaction = nullptr;
-    }
-    void OnClosed(HttpServer*) {
-      server_closed = true;
-    }
-    void OnConnectionClosed(HttpServer*, int, StreamInterface* stream) {
-      connection_closed = true;
-      delete stream;
-    }
-  };
-
-  void CreateClientConnection(HttpServer& server,
-                              HttpServerMonitor& monitor,
-                              bool send_request) {
-    StreamSource* client = new StreamSource;
-    client->SetState(SS_OPEN);
-    server.HandleConnection(client);
-    EXPECT_FALSE(monitor.server_closed);
-    EXPECT_FALSE(monitor.transaction);
-
-    if (send_request) {
-      // Simulate a request
-      client->QueueString(kRequest);
-      EXPECT_FALSE(monitor.server_closed);
-    }
+  HttpServerMonitor(HttpServer* server)
+      : transaction(nullptr), server_closed(false), connection_closed(false) {
+    server->SignalCloseAllComplete.connect(this, &HttpServerMonitor::OnClosed);
+    server->SignalHttpRequest.connect(this, &HttpServerMonitor::OnRequest);
+    server->SignalHttpRequestComplete.connect(
+        this, &HttpServerMonitor::OnRequestComplete);
+    server->SignalConnectionClosed.connect(
+        this, &HttpServerMonitor::OnConnectionClosed);
   }
+  void OnRequest(HttpServer*, HttpServerTransaction* t) {
+    ASSERT_FALSE(transaction);
+    transaction = t;
+    transaction->response.set_success();
+    transaction->response.setHeader(HH_CONNECTION, "Close");
+  }
+  void OnRequestComplete(HttpServer*, HttpServerTransaction* t, int) {
+    ASSERT_EQ(transaction, t);
+    transaction = nullptr;
+  }
+  void OnClosed(HttpServer*) { server_closed = true; }
+  void OnConnectionClosed(HttpServer*, int, StreamInterface* stream) {
+    connection_closed = true;
+    delete stream;
+  }
+};
+
+void CreateClientConnection(HttpServer& server,
+                            HttpServerMonitor& monitor,
+                            bool send_request) {
+  StreamSource* client = new StreamSource;
+  client->SetState(SS_OPEN);
+  server.HandleConnection(client);
+  EXPECT_FALSE(monitor.server_closed);
+  EXPECT_FALSE(monitor.transaction);
+
+  if (send_request) {
+    // Simulate a request
+    client->QueueString(kRequest);
+    EXPECT_FALSE(monitor.server_closed);
+  }
+}
 }  // anonymous namespace
 
 TEST(HttpServer, DoesNotSignalCloseUnlessCloseAllIsCalled) {
@@ -127,4 +124,4 @@
   EXPECT_TRUE(monitor.connection_closed);
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/ifaddrs-android.cc b/rtc_base/ifaddrs-android.cc
index b713c02..cc6cdab 100644
--- a/rtc_base/ifaddrs-android.cc
+++ b/rtc_base/ifaddrs-android.cc
@@ -64,7 +64,9 @@
   return 0;
 }
 
-int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
+int set_addresses(struct ifaddrs* ifaddr,
+                  ifaddrmsg* msg,
+                  void* data,
                   size_t len) {
   if (msg->ifa_family == AF_INET) {
     sockaddr_in* sa = new sockaddr_in;
@@ -115,7 +117,9 @@
   return 0;
 }
 
-int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
+int populate_ifaddrs(struct ifaddrs* ifaddr,
+                     ifaddrmsg* msg,
+                     void* bytes,
                      size_t len) {
   if (set_ifname(ifaddr, msg->ifa_index) != 0) {
     return -1;
@@ -156,8 +160,8 @@
   while (amount_read > 0) {
     nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
     size_t header_size = static_cast<size_t>(amount_read);
-    for ( ; NLMSG_OK(header, header_size);
-          header = NLMSG_NEXT(header, header_size)) {
+    for (; NLMSG_OK(header, header_size);
+         header = NLMSG_NEXT(header, header_size)) {
       switch (header->nlmsg_type) {
         case NLMSG_DONE:
           // Success. Return.
@@ -175,7 +179,7 @@
           ssize_t payload_len = IFA_PAYLOAD(header);
           while (RTA_OK(rta, payload_len)) {
             if ((address_msg->ifa_family == AF_INET &&
-                    rta->rta_type == IFA_LOCAL) ||
+                 rta->rta_type == IFA_LOCAL) ||
                 (address_msg->ifa_family == AF_INET6 &&
                  rta->rta_type == IFA_ADDRESS)) {
               ifaddrs* newest = new ifaddrs;
diff --git a/rtc_base/ifaddrs-android.h b/rtc_base/ifaddrs-android.h
index 82b4cb3..1a5b662 100644
--- a/rtc_base/ifaddrs-android.h
+++ b/rtc_base/ifaddrs-android.h
@@ -14,7 +14,6 @@
 #include <stdio.h>
 #include <sys/socket.h>
 
-
 // Implementation of getifaddrs for Android.
 // Fills out a list of ifaddr structs (see below) which contain information
 // about every network interface available on the host.
diff --git a/rtc_base/ipaddress.cc b/rtc_base/ipaddress.cc
index e6a02c4..c52c9a4 100644
--- a/rtc_base/ipaddress.cc
+++ b/rtc_base/ipaddress.cc
@@ -9,9 +9,9 @@
  */
 
 #if defined(WEBRTC_POSIX)
-#include <sys/types.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #ifdef OPENBSD
 #include <netinet/in_systm.h>
 #endif
@@ -39,8 +39,8 @@
 namespace rtc {
 
 // Prefixes used for categorizing IPv6 addresses.
-static const in6_addr kV4MappedPrefix = {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                           0xFF, 0xFF, 0}}};
+static const in6_addr kV4MappedPrefix = {
+    {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0}}};
 static const in6_addr k6To4Prefix = {{{0x20, 0x02, 0}}};
 static const in6_addr kTeredoPrefix = {{{0x20, 0x01, 0x00, 0x00}}};
 static const in6_addr kV4CompatibilityPrefix = {{{0}}};
@@ -48,7 +48,8 @@
 static const in6_addr kPrivateNetworkPrefix = {{{0xFD}}};
 
 static bool IPIsHelper(const IPAddress& ip,
-                       const in6_addr& tomatch, int length);
+                       const in6_addr& tomatch,
+                       int length);
 static in_addr ExtractMappedAddress(const in6_addr& addr);
 
 uint32_t IPAddress::v4AddressAsHostOrderInteger() const {
@@ -73,8 +74,7 @@
   return 0;
 }
 
-
-bool IPAddress::operator==(const IPAddress &other) const {
+bool IPAddress::operator==(const IPAddress& other) const {
   if (family_ != other.family_) {
     return false;
   }
@@ -87,15 +87,15 @@
   return family_ == AF_UNSPEC;
 }
 
-bool IPAddress::operator!=(const IPAddress &other) const {
+bool IPAddress::operator!=(const IPAddress& other) const {
   return !((*this) == other);
 }
 
-bool IPAddress::operator >(const IPAddress &other) const {
+bool IPAddress::operator>(const IPAddress& other) const {
   return (*this) != other && !((*this) < other);
 }
 
-bool IPAddress::operator <(const IPAddress &other) const {
+bool IPAddress::operator<(const IPAddress& other) const {
   // IPv4 is 'less than' IPv6
   if (family_ != other.family_) {
     if (family_ == AF_UNSPEC) {
@@ -110,7 +110,7 @@
   switch (family_) {
     case AF_INET: {
       return NetworkToHost32(u_.ip4.s_addr) <
-          NetworkToHost32(other.u_.ip4.s_addr);
+             NetworkToHost32(other.u_.ip4.s_addr);
     }
     case AF_INET6: {
       return memcmp(&u_.ip6.s6_addr, &other.u_.ip6.s6_addr, 16) < 0;
@@ -195,17 +195,17 @@
   return IPAddress(v6addr);
 }
 
-bool InterfaceAddress::operator==(const InterfaceAddress &other) const {
+bool InterfaceAddress::operator==(const InterfaceAddress& other) const {
   return ipv6_flags_ == other.ipv6_flags() &&
-    static_cast<const IPAddress&>(*this) == other;
+         static_cast<const IPAddress&>(*this) == other;
 }
 
-bool InterfaceAddress::operator!=(const InterfaceAddress &other) const {
+bool InterfaceAddress::operator!=(const InterfaceAddress& other) const {
   return !((*this) == other);
 }
 
 const InterfaceAddress& InterfaceAddress::operator=(
-  const InterfaceAddress& other) {
+    const InterfaceAddress& other) {
   ipv6_flags_ = other.ipv6_flags_;
   static_cast<IPAddress&>(*this) = other;
   return *this;
@@ -223,8 +223,8 @@
 static bool IPIsPrivateNetworkV4(const IPAddress& ip) {
   uint32_t ip_in_host_order = ip.v4AddressAsHostOrderInteger();
   return ((ip_in_host_order >> 24) == 10) ||
-      ((ip_in_host_order >> 20) == ((172 << 4) | 1)) ||
-      ((ip_in_host_order >> 16) == ((192 << 8) | 168));
+         ((ip_in_host_order >> 20) == ((172 << 4) | 1)) ||
+         ((ip_in_host_order >> 16) == ((192 << 8) | 168));
 }
 
 static bool IPIsPrivateNetworkV6(const IPAddress& ip) {
@@ -283,8 +283,7 @@
   return true;
 }
 
-bool IPFromString(const std::string& str, int flags,
-                  InterfaceAddress* out) {
+bool IPFromString(const std::string& str, int flags, InterfaceAddress* out) {
   IPAddress ip;
   if (!IPFromString(str, &ip)) {
     return false;
@@ -416,9 +415,7 @@
       bits = (i * 32);
       break;
     }
-    default: {
-      return 0;
-    }
+    default: { return 0; }
   }
   if (word_to_count == 0) {
     return bits;
@@ -431,12 +428,18 @@
   // This could also be written word_to_count &= -word_to_count, but
   // MSVC emits warning C4146 when negating an unsigned number.
   word_to_count &= ~word_to_count + 1;  // Isolate lowest set bit.
-  if (word_to_count) zeroes--;
-  if (word_to_count & 0x0000FFFF) zeroes -= 16;
-  if (word_to_count & 0x00FF00FF) zeroes -= 8;
-  if (word_to_count & 0x0F0F0F0F) zeroes -= 4;
-  if (word_to_count & 0x33333333) zeroes -= 2;
-  if (word_to_count & 0x55555555) zeroes -= 1;
+  if (word_to_count)
+    zeroes--;
+  if (word_to_count & 0x0000FFFF)
+    zeroes -= 16;
+  if (word_to_count & 0x00FF00FF)
+    zeroes -= 8;
+  if (word_to_count & 0x0F0F0F0F)
+    zeroes -= 4;
+  if (word_to_count & 0x33333333)
+    zeroes -= 2;
+  if (word_to_count & 0x55555555)
+    zeroes -= 1;
 
   return bits + (32 - zeroes);
 }
diff --git a/rtc_base/ipaddress.h b/rtc_base/ipaddress.h
index c965cf1..614fd8f 100644
--- a/rtc_base/ipaddress.h
+++ b/rtc_base/ipaddress.h
@@ -12,10 +12,10 @@
 #define RTC_BASE_IPADDRESS_H_
 
 #if defined(WEBRTC_POSIX)
-#include <netinet/in.h>
-#include <sys/socket.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
 #endif
 #if defined(WEBRTC_WIN)
 #include <winsock2.h>
@@ -25,7 +25,6 @@
 #include <string>
 #include <vector>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/byteorder.h"
 #if defined(WEBRTC_WIN)
 #include "rtc_base/win32.h"
@@ -34,33 +33,29 @@
 namespace rtc {
 
 enum IPv6AddressFlag {
-  IPV6_ADDRESS_FLAG_NONE =           0x00,
+  IPV6_ADDRESS_FLAG_NONE = 0x00,
 
   // Temporary address is dynamic by nature and will not carry MAC
   // address.
-  IPV6_ADDRESS_FLAG_TEMPORARY =      1 << 0,
+  IPV6_ADDRESS_FLAG_TEMPORARY = 1 << 0,
 
   // Temporary address could become deprecated once the preferred
   // lifetime is reached. It is still valid but just shouldn't be used
   // to create new connection.
-  IPV6_ADDRESS_FLAG_DEPRECATED =     1 << 1,
+  IPV6_ADDRESS_FLAG_DEPRECATED = 1 << 1,
 };
 
 // Version-agnostic IP address class, wraps a union of in_addr and in6_addr.
 class IPAddress {
  public:
-  IPAddress() : family_(AF_UNSPEC) {
-    ::memset(&u_, 0, sizeof(u_));
-  }
+  IPAddress() : family_(AF_UNSPEC) { ::memset(&u_, 0, sizeof(u_)); }
 
   explicit IPAddress(const in_addr& ip4) : family_(AF_INET) {
     memset(&u_, 0, sizeof(u_));
     u_.ip4 = ip4;
   }
 
-  explicit IPAddress(const in6_addr& ip6) : family_(AF_INET6) {
-    u_.ip6 = ip6;
-  }
+  explicit IPAddress(const in6_addr& ip6) : family_(AF_INET6) { u_.ip6 = ip6; }
 
   explicit IPAddress(uint32_t ip_in_host_byte_order) : family_(AF_INET) {
     memset(&u_, 0, sizeof(u_));
@@ -73,7 +68,7 @@
 
   virtual ~IPAddress() {}
 
-  const IPAddress & operator=(const IPAddress& other) {
+  const IPAddress& operator=(const IPAddress& other) {
     family_ = other.family_;
     ::memcpy(&u_, &other.u_, sizeof(u_));
     return *this;
@@ -81,8 +76,8 @@
 
   bool operator==(const IPAddress& other) const;
   bool operator!=(const IPAddress& other) const;
-  bool operator <(const IPAddress& other) const;
-  bool operator >(const IPAddress& other) const;
+  bool operator<(const IPAddress& other) const;
+  bool operator>(const IPAddress& other) const;
 
 #ifdef UNIT_TEST
   inline std::ostream& operator<<(  // no-presubmit-check TODO(webrtc:8982)
@@ -136,12 +131,12 @@
       : IPAddress(ip), ipv6_flags_(IPV6_ADDRESS_FLAG_NONE) {}
 
   InterfaceAddress(IPAddress addr, int ipv6_flags)
-    : IPAddress(addr), ipv6_flags_(ipv6_flags) {}
+      : IPAddress(addr), ipv6_flags_(ipv6_flags) {}
 
   InterfaceAddress(const in6_addr& ip6, int ipv6_flags)
-    : IPAddress(ip6), ipv6_flags_(ipv6_flags) {}
+      : IPAddress(ip6), ipv6_flags_(ipv6_flags) {}
 
-  const InterfaceAddress & operator=(const InterfaceAddress& other);
+  const InterfaceAddress& operator=(const InterfaceAddress& other);
 
   bool operator==(const InterfaceAddress& other) const;
   bool operator!=(const InterfaceAddress& other) const;
@@ -156,8 +151,7 @@
 
 bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out);
 bool IPFromString(const std::string& str, IPAddress* out);
-bool IPFromString(const std::string& str, int flags,
-                  InterfaceAddress* out);
+bool IPFromString(const std::string& str, int flags, InterfaceAddress* out);
 bool IPIsAny(const IPAddress& ip);
 bool IPIsLoopback(const IPAddress& ip);
 bool IPIsLinkLocal(const IPAddress& ip);
diff --git a/rtc_base/ipaddress_unittest.cc b/rtc_base/ipaddress_unittest.cc
index 3698d3f..30312d0 100644
--- a/rtc_base/ipaddress_unittest.cc
+++ b/rtc_base/ipaddress_unittest.cc
@@ -17,31 +17,25 @@
 static const unsigned int kIPv6AddrSize = 16;
 static const unsigned int kIPv4RFC1918Addr = 0xC0A80701;
 static const unsigned int kIPv4PublicAddr = 0x01020304;
-static const unsigned int kIPv4LinkLocalAddr = 0xA9FE10C1; // 169.254.16.193
-static const in6_addr kIPv6LinkLocalAddr = {{{0xfe, 0x80, 0x00, 0x00,
-                                              0x00, 0x00, 0x00, 0x00,
-                                              0xbe, 0x30, 0x5b, 0xff,
-                                              0xfe, 0xe5, 0x00, 0xc3}}};
-static const in6_addr kIPv6PublicAddr = {{{0x24, 0x01, 0xfa, 0x00,
-                                           0x00, 0x04, 0x10, 0x00,
-                                           0xbe, 0x30, 0x5b, 0xff,
-                                           0xfe, 0xe5, 0x00, 0xc3}}};
-static const in6_addr kIPv6PublicAddr2 = {{{0x24, 0x01, 0x00, 0x00,
-                                            0x00, 0x00, 0x10, 0x00,
-                                            0xbe, 0x30, 0x5b, 0xff,
-                                            0xfe, 0xe5, 0x00, 0xc3}}};
-static const in6_addr kIPv4MappedAnyAddr = {{{0x00, 0x00, 0x00, 0x00,
-                                              0x00, 0x00, 0x00, 0x00,
-                                              0x00, 0x00, 0xff, 0xff,
-                                              0x00, 0x00, 0x00, 0x00}}};
-static const in6_addr kIPv4MappedRFC1918Addr = {{{0x00, 0x00, 0x00, 0x00,
-                                                  0x00, 0x00, 0x00, 0x00,
-                                                  0x00, 0x00, 0xff, 0xff,
-                                                  0xc0, 0xa8, 0x07, 0x01}}};
-static const in6_addr kIPv4MappedPublicAddr = {{{0x00, 0x00, 0x00, 0x00,
-                                                 0x00, 0x00, 0x00, 0x00,
-                                                 0x00, 0x00, 0xff, 0xff,
-                                                 0x01, 0x02, 0x03, 0x04}}};
+static const unsigned int kIPv4LinkLocalAddr = 0xA9FE10C1;  // 169.254.16.193
+static const in6_addr kIPv6LinkLocalAddr = {
+    {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+      0xfe, 0xe5, 0x00, 0xc3}}};
+static const in6_addr kIPv6PublicAddr = {
+    {{0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+      0xfe, 0xe5, 0x00, 0xc3}}};
+static const in6_addr kIPv6PublicAddr2 = {
+    {{0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+      0xfe, 0xe5, 0x00, 0xc3}}};
+static const in6_addr kIPv4MappedAnyAddr = {
+    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+      0x00, 0x00, 0x00, 0x00}}};
+static const in6_addr kIPv4MappedRFC1918Addr = {
+    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+      0xc0, 0xa8, 0x07, 0x01}}};
+static const in6_addr kIPv4MappedPublicAddr = {
+    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+      0x01, 0x02, 0x03, 0x04}}};
 
 static const std::string kIPv4AnyAddrString = "0.0.0.0";
 static const std::string kIPv4LoopbackAddrString = "127.0.0.1";
@@ -80,10 +74,8 @@
     "2401:fa00:4:1000:be30:5bff:fee5:c3:1";
 static const std::string kIPv6BrokenString3 =
     "[2401:fa00:4:1000:be30:5bff:fee5:c3]:1";
-static const std::string kIPv6BrokenString4 =
-    "2401::4::be30";
-static const std::string kIPv6BrokenString5 =
-    "2401:::4:fee5:be30";
+static const std::string kIPv6BrokenString4 = "2401::4::be30";
+static const std::string kIPv6BrokenString5 = "2401:::4:fee5:be30";
 static const std::string kIPv6BrokenString6 =
     "2401f:fa00:4:1000:be30:5bff:fee5:c3";
 static const std::string kIPv6BrokenString7 =
@@ -92,24 +84,18 @@
     "2401:fa000:4:1000:be30:5bff:fee5:c3";
 static const std::string kIPv6BrokenString9 =
     "2401:fal0:4:1000:be30:5bff:fee5:c3";
-static const std::string kIPv6BrokenString10 =
-    "::ffff:192.168.7.";
-static const std::string kIPv6BrokenString11 =
-    "::ffff:192.168.7.1.1.1";
-static const std::string kIPv6BrokenString12 =
-    "::fffe:192.168.7.1";
-static const std::string kIPv6BrokenString13 =
-    "::ffff:192.168.7.ff";
+static const std::string kIPv6BrokenString10 = "::ffff:192.168.7.";
+static const std::string kIPv6BrokenString11 = "::ffff:192.168.7.1.1.1";
+static const std::string kIPv6BrokenString12 = "::fffe:192.168.7.1";
+static const std::string kIPv6BrokenString13 = "::ffff:192.168.7.ff";
 static const std::string kIPv6BrokenString14 =
     "0x2401:fa00:4:1000:be30:5bff:fee5:c3";
 
-bool AreEqual(const IPAddress& addr,
-              const IPAddress& addr2) {
+bool AreEqual(const IPAddress& addr, const IPAddress& addr2) {
   if ((IPIsAny(addr) != IPIsAny(addr2)) ||
       (IPIsLoopback(addr) != IPIsLoopback(addr2)) ||
       (IPIsPrivate(addr) != IPIsPrivate(addr2)) ||
-      (HashIP(addr) != HashIP(addr2)) ||
-      (addr.Size() != addr2.Size()) ||
+      (HashIP(addr) != HashIP(addr2)) || (addr.Size() != addr2.Size()) ||
       (addr.family() != addr2.family()) ||
       (addr.ToString() != addr2.ToString())) {
     return false;
@@ -130,7 +116,7 @@
 }
 
 bool BrokenIPStringFails(const std::string& broken) {
-  IPAddress addr(0);   // Intentionally make it v4.
+  IPAddress addr(0);  // Intentionally make it v4.
   if (IPFromString(kIPv4BrokenString1, &addr)) {
     return false;
   }
@@ -140,7 +126,7 @@
 bool CheckMaskCount(const std::string& mask, int expected_length) {
   IPAddress addr;
   return IPFromString(mask, &addr) &&
-      (expected_length == CountIPMaskBits(addr));
+         (expected_length == CountIPMaskBits(addr));
 }
 
 bool TryInvalidMaskCount(const std::string& mask) {
@@ -154,7 +140,8 @@
   return true;
 }
 
-bool CheckTruncateIP(const std::string& initial, int truncate_length,
+bool CheckTruncateIP(const std::string& initial,
+                     int truncate_length,
                      const std::string& expected_result) {
   IPAddress addr, expected;
   IPFromString(initial, &addr);
@@ -390,14 +377,14 @@
 TEST(IPAddressTest, TestComparison) {
   // Defined in 'ascending' order.
   // v6 > v4, and intra-family sorting is purely numerical
-  IPAddress addr0;  // AF_UNSPEC
-  IPAddress addr1(INADDR_ANY);  // 0.0.0.0
-  IPAddress addr2(kIPv4PublicAddr);  // 1.2.3.4
-  IPAddress addr3(INADDR_LOOPBACK);  // 127.0.0.1
-  IPAddress addr4(kIPv4RFC1918Addr);  // 192.168.7.1.
-  IPAddress addr5(in6addr_any);  // ::
-  IPAddress addr6(in6addr_loopback);  // ::1
-  IPAddress addr7(kIPv6PublicAddr);  // 2401....
+  IPAddress addr0;                      // AF_UNSPEC
+  IPAddress addr1(INADDR_ANY);          // 0.0.0.0
+  IPAddress addr2(kIPv4PublicAddr);     // 1.2.3.4
+  IPAddress addr3(INADDR_LOOPBACK);     // 127.0.0.1
+  IPAddress addr4(kIPv4RFC1918Addr);    // 192.168.7.1.
+  IPAddress addr5(in6addr_any);         // ::
+  IPAddress addr6(in6addr_loopback);    // ::1
+  IPAddress addr7(kIPv6PublicAddr);     // 2401....
   IPAddress addr8(kIPv6LinkLocalAddr);  // fe80....
 
   EXPECT_TRUE(addr0 < addr1);
@@ -941,8 +928,7 @@
 
 TEST(IPAddressTest, TestInterfaceAddress) {
   in6_addr addr;
-  InterfaceAddress addr1(kIPv6PublicAddr,
-                         IPV6_ADDRESS_FLAG_TEMPORARY);
+  InterfaceAddress addr1(kIPv6PublicAddr, IPV6_ADDRESS_FLAG_TEMPORARY);
   EXPECT_EQ(addr1.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY);
   EXPECT_EQ(addr1.family(), AF_INET6);
 
@@ -961,18 +947,16 @@
   addr = addr3.ipv6_address();
   EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr));
 
-  InterfaceAddress addr4(kIPv6PublicAddr,
-                         IPV6_ADDRESS_FLAG_DEPRECATED);
+  InterfaceAddress addr4(kIPv6PublicAddr, IPV6_ADDRESS_FLAG_DEPRECATED);
   EXPECT_NE(addr1, addr4);
 
   // When you compare them as IPAddress, since operator==
   // is not virtual, it'll be equal.
-  IPAddress *paddr1 = &addr1;
-  IPAddress *paddr4 = &addr4;
+  IPAddress* paddr1 = &addr1;
+  IPAddress* paddr4 = &addr4;
   EXPECT_EQ(*paddr1, *paddr4);
 
-  InterfaceAddress addr5(kIPv6LinkLocalAddr,
-                         IPV6_ADDRESS_FLAG_TEMPORARY);
+  InterfaceAddress addr5(kIPv6LinkLocalAddr, IPV6_ADDRESS_FLAG_TEMPORARY);
   EXPECT_NE(addr1, addr5);
 }
 
diff --git a/rtc_base/java/src/org/webrtc/Loggable.java b/rtc_base/java/src/org/webrtc/Loggable.java
new file mode 100644
index 0000000..cd66aa1
--- /dev/null
+++ b/rtc_base/java/src/org/webrtc/Loggable.java
@@ -0,0 +1,22 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+package org.webrtc;
+
+import org.webrtc.Logging.Severity;
+
+/**
+ * Java interface for WebRTC logging. The default implementation uses webrtc.Logging.
+ *
+ * When injected, the Loggable will receive logging from both Java and native.
+ */
+public interface Loggable {
+  public void onLogMessage(String message, Severity severity, String tag);
+}
diff --git a/rtc_base/java/src/org/webrtc/Logging.java b/rtc_base/java/src/org/webrtc/Logging.java
index f143d2f..aafdbe8 100644
--- a/rtc_base/java/src/org/webrtc/Logging.java
+++ b/rtc_base/java/src/org/webrtc/Logging.java
@@ -15,21 +15,35 @@
 import java.util.EnumSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import javax.annotation.Nullable;
+import org.webrtc.Loggable;
 
 /**
- * Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but will switch to
- * native logging (rtc::LogMessage) if one of the following static functions are called from the
- * app:
+ * Java wrapper for WebRTC logging. Logging defaults to java.util.logging.Logger, but a custom
+ * logger implementing the Loggable interface can be injected along with a Severity. All subsequent
+ * log messages will then be redirected to the injected Loggable, except those with a severity lower
+ * than the specified severity, which will be discarded.
+ *
+ * It is also possible to switch to native logging (rtc::LogMessage) if one of the following static
+ * functions are called from the app:
  * - Logging.enableLogThreads
  * - Logging.enableLogTimeStamps
  * - Logging.enableLogToDebugOutput
  *
- * Using these APIs requires that the native library is loaded, using
- * PeerConnectionFactory.initialize.
+ * The priority goes:
+ * 1. Injected loggable
+ * 2. Native logging
+ * 3. Fallback logging.
+ * Only one method will be used at a time.
+ *
+ * Injecting a Loggable or using any of the enable... methods requires that the native library is
+ * loaded, using PeerConnectionFactory.initialize.
  */
 public class Logging {
   private static final Logger fallbackLogger = createFallbackLogger();
   private static volatile boolean loggingEnabled;
+  @Nullable private static Loggable loggable;
+  private static Severity loggableSeverity;
 
   private static Logger createFallbackLogger() {
     final Logger fallbackLogger = Logger.getLogger("org.webrtc.Logging");
@@ -37,6 +51,17 @@
     return fallbackLogger;
   }
 
+  static void injectLoggable(Loggable injectedLoggable, Severity severity) {
+    if (injectedLoggable != null) {
+      loggable = injectedLoggable;
+      loggableSeverity = severity;
+    }
+  }
+
+  static void deleteInjectedLoggable() {
+    loggable = null;
+  }
+
   // TODO(solenberg): Remove once dependent projects updated.
   @Deprecated
   public enum TraceLevel {
@@ -83,11 +108,29 @@
   // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
   @SuppressWarnings("NoSynchronizedMethodCheck")
   public static synchronized void enableLogToDebugOutput(Severity severity) {
+    if (loggable != null) {
+      throw new IllegalStateException(
+          "Logging to native debug output not supported while Loggable is injected. "
+          + "Delete the Loggable before calling this method.");
+    }
     nativeEnableLogToDebugOutput(severity.ordinal());
     loggingEnabled = true;
   }
 
   public static void log(Severity severity, String tag, String message) {
+    if (tag == null || message == null) {
+      throw new IllegalArgumentException("Logging tag or message may not be null.");
+    }
+    if (loggable != null) {
+      // Filter log messages below loggableSeverity.
+      if (severity.ordinal() < loggableSeverity.ordinal()) {
+        return;
+      }
+      loggable.onLogMessage(message, severity, tag);
+      return;
+    }
+
+    // Try native logging if no loggable is injected.
     if (loggingEnabled) {
       nativeLog(severity.ordinal(), tag, message);
       return;
diff --git a/rtc_base/json.cc b/rtc_base/json.cc
index b8071a9..cc40bd6 100644
--- a/rtc_base/json.cc
+++ b/rtc_base/json.cc
@@ -52,8 +52,8 @@
     char* end_ptr;
     errno = 0;
     val = strtol(c_str, &end_ptr, 10);  // NOLINT
-    ret = (end_ptr != c_str && *end_ptr == '\0' && !errno &&
-           val >= INT_MIN && val <= INT_MAX);
+    ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val >= INT_MIN &&
+           val <= INT_MAX);
     *out = val;
   }
   return ret;
@@ -72,8 +72,7 @@
     char* end_ptr;
     errno = 0;
     val = strtoul(c_str, &end_ptr, 10);  // NOLINT
-    ret = (end_ptr != c_str && *end_ptr == '\0' && !errno &&
-           val <= UINT_MAX);
+    ret = (end_ptr != c_str && *end_ptr == '\0' && !errno && val <= UINT_MAX);
     *out = val;
   }
   return ret;
@@ -120,10 +119,10 @@
 }
 
 namespace {
-template<typename T>
+template <typename T>
 bool JsonArrayToVector(const Json::Value& value,
                        bool (*getter)(const Json::Value& in, T* out),
-                       std::vector<T> *vec) {
+                       std::vector<T>* vec) {
   vec->clear();
   if (!value.isArray()) {
     return false;
@@ -151,8 +150,7 @@
   return JsonArrayToVector(in, GetValueFromJson, out);
 }
 
-bool JsonArrayToIntVector(const Json::Value& in,
-                          std::vector<int>* out) {
+bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out) {
   return JsonArrayToVector(in, GetIntFromJson, out);
 }
 
@@ -166,18 +164,16 @@
   return JsonArrayToVector(in, GetStringFromJson, out);
 }
 
-bool JsonArrayToBoolVector(const Json::Value& in,
-                           std::vector<bool>* out) {
+bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out) {
   return JsonArrayToVector(in, GetBoolFromJson, out);
 }
 
-bool JsonArrayToDoubleVector(const Json::Value& in,
-                             std::vector<double>* out) {
+bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out) {
   return JsonArrayToVector(in, GetDoubleFromJson, out);
 }
 
 namespace {
-template<typename T>
+template <typename T>
 Json::Value VectorToJsonArray(const std::vector<T>& vec) {
   Json::Value result(Json::arrayValue);
   for (size_t i = 0; i < vec.size(); ++i) {
@@ -211,8 +207,7 @@
   return VectorToJsonArray(in);
 }
 
-bool GetValueFromJsonArray(const Json::Value& in, size_t n,
-                           Json::Value* out) {
+bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out) {
   if (!in.isArray() || !in.isValidIndex(static_cast<int>(n))) {
     return false;
   }
@@ -221,37 +216,33 @@
   return true;
 }
 
-bool GetIntFromJsonArray(const Json::Value& in, size_t n,
-                         int* out) {
+bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out) {
   Json::Value x;
   return GetValueFromJsonArray(in, n, &x) && GetIntFromJson(x, out);
 }
 
-bool GetUIntFromJsonArray(const Json::Value& in, size_t n,
-                          unsigned int* out)  {
+bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out) {
   Json::Value x;
   return GetValueFromJsonArray(in, n, &x) && GetUIntFromJson(x, out);
 }
 
-bool GetStringFromJsonArray(const Json::Value& in, size_t n,
-                            std::string* out) {
+bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out) {
   Json::Value x;
   return GetValueFromJsonArray(in, n, &x) && GetStringFromJson(x, out);
 }
 
-bool GetBoolFromJsonArray(const Json::Value& in, size_t n,
-                          bool* out) {
+bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out) {
   Json::Value x;
   return GetValueFromJsonArray(in, n, &x) && GetBoolFromJson(x, out);
 }
 
-bool GetDoubleFromJsonArray(const Json::Value& in, size_t n,
-                            double* out) {
+bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out) {
   Json::Value x;
   return GetValueFromJsonArray(in, n, &x) && GetDoubleFromJson(x, out);
 }
 
-bool GetValueFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetValueFromJsonObject(const Json::Value& in,
+                            const std::string& k,
                             Json::Value* out) {
   if (!in.isObject() || !in.isMember(k)) {
     return false;
@@ -261,31 +252,36 @@
   return true;
 }
 
-bool GetIntFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetIntFromJsonObject(const Json::Value& in,
+                          const std::string& k,
                           int* out) {
   Json::Value x;
   return GetValueFromJsonObject(in, k, &x) && GetIntFromJson(x, out);
 }
 
-bool GetUIntFromJsonObject(const Json::Value& in, const std::string& k,
-                           unsigned int* out)  {
+bool GetUIntFromJsonObject(const Json::Value& in,
+                           const std::string& k,
+                           unsigned int* out) {
   Json::Value x;
   return GetValueFromJsonObject(in, k, &x) && GetUIntFromJson(x, out);
 }
 
-bool GetStringFromJsonObject(const Json::Value& in, const std::string& k,
-                             std::string* out)  {
+bool GetStringFromJsonObject(const Json::Value& in,
+                             const std::string& k,
+                             std::string* out) {
   Json::Value x;
   return GetValueFromJsonObject(in, k, &x) && GetStringFromJson(x, out);
 }
 
-bool GetBoolFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetBoolFromJsonObject(const Json::Value& in,
+                           const std::string& k,
                            bool* out) {
   Json::Value x;
   return GetValueFromJsonObject(in, k, &x) && GetBoolFromJson(x, out);
 }
 
-bool GetDoubleFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetDoubleFromJsonObject(const Json::Value& in,
+                             const std::string& k,
                              double* out) {
   Json::Value x;
   return GetValueFromJsonObject(in, k, &x) && GetDoubleFromJson(x, out);
diff --git a/rtc_base/json.h b/rtc_base/json.h
index 5db8bd6..b8e6d95 100644
--- a/rtc_base/json.h
+++ b/rtc_base/json.h
@@ -34,32 +34,23 @@
 bool GetDoubleFromJson(const Json::Value& in, double* out);
 
 // Pull values out of a JSON array.
-bool GetValueFromJsonArray(const Json::Value& in, size_t n,
-                           Json::Value* out);
-bool GetIntFromJsonArray(const Json::Value& in, size_t n,
-                         int* out);
-bool GetUIntFromJsonArray(const Json::Value& in, size_t n,
-                          unsigned int* out);
-bool GetStringFromJsonArray(const Json::Value& in, size_t n,
-                            std::string* out);
-bool GetBoolFromJsonArray(const Json::Value& in, size_t n,
-                          bool* out);
-bool GetDoubleFromJsonArray(const Json::Value& in, size_t n,
-                            double* out);
+bool GetValueFromJsonArray(const Json::Value& in, size_t n, Json::Value* out);
+bool GetIntFromJsonArray(const Json::Value& in, size_t n, int* out);
+bool GetUIntFromJsonArray(const Json::Value& in, size_t n, unsigned int* out);
+bool GetStringFromJsonArray(const Json::Value& in, size_t n, std::string* out);
+bool GetBoolFromJsonArray(const Json::Value& in, size_t n, bool* out);
+bool GetDoubleFromJsonArray(const Json::Value& in, size_t n, double* out);
 
 // Convert json arrays to std::vector
 bool JsonArrayToValueVector(const Json::Value& in,
                             std::vector<Json::Value>* out);
-bool JsonArrayToIntVector(const Json::Value& in,
-                          std::vector<int>* out);
+bool JsonArrayToIntVector(const Json::Value& in, std::vector<int>* out);
 bool JsonArrayToUIntVector(const Json::Value& in,
                            std::vector<unsigned int>* out);
 bool JsonArrayToStringVector(const Json::Value& in,
                              std::vector<std::string>* out);
-bool JsonArrayToBoolVector(const Json::Value& in,
-                           std::vector<bool>* out);
-bool JsonArrayToDoubleVector(const Json::Value& in,
-                             std::vector<double>* out);
+bool JsonArrayToBoolVector(const Json::Value& in, std::vector<bool>* out);
+bool JsonArrayToDoubleVector(const Json::Value& in, std::vector<double>* out);
 
 // Convert std::vector to json array
 Json::Value ValueVectorToJsonArray(const std::vector<Json::Value>& in);
@@ -70,17 +61,23 @@
 Json::Value DoubleVectorToJsonArray(const std::vector<double>& in);
 
 // Pull values out of a JSON object.
-bool GetValueFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetValueFromJsonObject(const Json::Value& in,
+                            const std::string& k,
                             Json::Value* out);
-bool GetIntFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetIntFromJsonObject(const Json::Value& in,
+                          const std::string& k,
                           int* out);
-bool GetUIntFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetUIntFromJsonObject(const Json::Value& in,
+                           const std::string& k,
                            unsigned int* out);
-bool GetStringFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetStringFromJsonObject(const Json::Value& in,
+                             const std::string& k,
                              std::string* out);
-bool GetBoolFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetBoolFromJsonObject(const Json::Value& in,
+                           const std::string& k,
                            bool* out);
-bool GetDoubleFromJsonObject(const Json::Value& in, const std::string& k,
+bool GetDoubleFromJsonObject(const Json::Value& in,
+                             const std::string& k,
                              double* out);
 
 // Writes out a Json value as a string.
diff --git a/rtc_base/keep_ref_until_done.h b/rtc_base/keep_ref_until_done.h
index 979415d..9ba0e87 100644
--- a/rtc_base/keep_ref_until_done.h
+++ b/rtc_base/keep_ref_until_done.h
@@ -39,5 +39,4 @@
 
 }  // namespace rtc
 
-
 #endif  // RTC_BASE_KEEP_REF_UNTIL_DONE_H_
diff --git a/rtc_base/logging.cc b/rtc_base/logging.cc
index ec8cd7f..c386600 100644
--- a/rtc_base/logging.cc
+++ b/rtc_base/logging.cc
@@ -9,9 +9,6 @@
  */
 
 #if defined(WEBRTC_WIN)
-#if !defined(WIN32_LEAN_AND_MEAN)
-#define WIN32_LEAN_AND_MEAN
-#endif
 #include <windows.h>
 #if _MSC_VER < 1900
 #define snprintf _snprintf
@@ -29,10 +26,11 @@
 static const int kMaxLogLineSize = 1024 - 60;
 #endif  // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
 
-#include <time.h>
 #include <limits.h>
+#include <time.h>
 
 #include <algorithm>
+#include <cstdarg>
 #include <iomanip>
 #include <ostream>
 #include <vector>
@@ -80,6 +78,12 @@
 CriticalSection g_log_crit;
 }  // namespace
 
+// Inefficient default implementation, override is recommended.
+void LogSink::OnLogMessage(const std::string& msg,
+                           LoggingSeverity severity,
+                           const char* tag) {
+  OnLogMessage(tag + (": " + msg));
+}
 
 /////////////////////////////////////////////////////////////////////////////
 // LogMessage
@@ -96,6 +100,9 @@
 // Boolean options default to false (0)
 bool LogMessage::thread_, LogMessage::timestamp_;
 
+LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
+    : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
+
 LogMessage::LogMessage(const char* file,
                        int line,
                        LoggingSeverity sev,
@@ -123,8 +130,14 @@
     print_stream_ << "[" << std::dec << id << "] ";
   }
 
-  if (file != nullptr)
-    print_stream_ << "(" << FilenameFromPath(file)  << ":" << line << "): ";
+  if (file != nullptr) {
+#if defined(WEBRTC_ANDROID)
+    tag_ = FilenameFromPath(file);
+    print_stream_ << "(line " << line << "): ";
+#else
+    print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
+#endif
+  }
 
   if (err_ctx != ERRCTX_NONE) {
     char tmp_buf[1024];
@@ -137,13 +150,13 @@
 #ifdef WEBRTC_WIN
       case ERRCTX_HRESULT: {
         char msgbuf[256];
-        DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM |
-                      FORMAT_MESSAGE_IGNORE_INSERTS;
+        DWORD flags =
+            FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
         if (DWORD len = FormatMessageA(
                 flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                 msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
           while ((len > 0) &&
-              isspace(static_cast<unsigned char>(msgbuf[len-1]))) {
+                 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
             msgbuf[--len] = 0;
           }
           tmp << " " << msgbuf;
@@ -170,11 +183,7 @@
                        int line,
                        LoggingSeverity sev,
                        const char* tag)
-    : LogMessage(file,
-                 line,
-                 sev,
-                 ERRCTX_NONE,
-                 0 /* err */) {
+    : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
   if (!is_noop_) {
     tag_ = tag;
     print_stream_ << tag << ": ";
@@ -185,7 +194,9 @@
 // DEPRECATED. Currently only used by downstream projects that use
 // implementation details of logging.h. Work is ongoing to remove those
 // dependencies.
-LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev,
+LogMessage::LogMessage(const char* file,
+                       int line,
+                       LoggingSeverity sev,
                        const std::string& tag)
     : LogMessage(file, line, sev) {
   if (!is_noop_)
@@ -215,11 +226,23 @@
   CritScope cs(&g_log_crit);
   for (auto& kv : streams_) {
     if (severity_ >= kv.second) {
+#if defined(WEBRTC_ANDROID)
+      kv.first->OnLogMessage(str, severity_, tag_);
+#else
       kv.first->OnLogMessage(str);
+#endif
     }
   }
 }
 
+void LogMessage::AddTag(const char* tag) {
+#ifdef WEBRTC_ANDROID
+  if (!is_noop_) {
+    tag_ = tag;
+  }
+#endif
+}
+
 std::ostream& LogMessage::stream() {
   return is_noop_ ? GetNoopStream() : print_stream_;
 }
@@ -308,7 +331,7 @@
     } else if (token == "thread") {
       LogThreads();
 
-    // Logging levels
+      // Logging levels
     } else if (token == "sensitive") {
       current_level = LS_SENSITIVE;
     } else if (token == "verbose") {
@@ -322,7 +345,7 @@
     } else if (token == "none") {
       current_level = LS_NONE;
 
-    // Logging targets
+      // Logging targets
     } else if (token == "debug") {
       debug_level = current_level;
     }
@@ -345,8 +368,9 @@
 void LogMessage::UpdateMinLogSeverity()
     RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_crit) {
   LoggingSeverity min_sev = g_dbg_sev;
-  for (auto& kv : streams_) {
-    min_sev = std::min(g_dbg_sev, kv.second);
+  for (const auto& kv : streams_) {
+    const LoggingSeverity sev = kv.second;
+    min_sev = std::min(min_sev, sev);
   }
   g_min_sev = min_sev;
 }
@@ -364,9 +388,8 @@
   // On the Mac, all stderr output goes to the Console log and causes clutter.
   // So in opt builds, don't log to stderr unless the user specifically sets
   // a preference to do so.
-  CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
-                                              "logToStdErr",
-                                              kCFStringEncodingUTF8);
+  CFStringRef key = CFStringCreateWithCString(
+      kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
   CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
   if (key != nullptr && domain != nullptr) {
     Boolean exists_and_is_valid;
@@ -471,6 +494,87 @@
   print_stream_ << std::endl;
 }
 
-//////////////////////////////////////////////////////////////////////
+namespace webrtc_logging_impl {
 
+void Log(const LogArgType* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+
+  LogMetadataErr meta;
+  const char* tag = nullptr;
+  switch (*fmt) {
+    case LogArgType::kLogMetadata: {
+      meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
+      break;
+    }
+    case LogArgType::kLogMetadataErr: {
+      meta = va_arg(args, LogMetadataErr);
+      break;
+    }
+#ifdef WEBRTC_ANDROID
+    case LogArgType::kLogMetadataTag: {
+      const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
+      meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
+      tag = tag_meta.tag;
+      break;
+    }
+#endif
+    default: {
+      RTC_NOTREACHED();
+      va_end(args);
+      return;
+    }
+  }
+  LogMessage log_message(meta.meta.File(), meta.meta.Line(),
+                         meta.meta.Severity(), meta.err_ctx, meta.err);
+  if (tag) {
+    log_message.AddTag(tag);
+  }
+
+  for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
+    switch (*fmt) {
+      case LogArgType::kInt:
+        log_message.stream() << va_arg(args, int);
+        break;
+      case LogArgType::kLong:
+        log_message.stream() << va_arg(args, long);
+        break;
+      case LogArgType::kLongLong:
+        log_message.stream() << va_arg(args, long long);
+        break;
+      case LogArgType::kUInt:
+        log_message.stream() << va_arg(args, unsigned);
+        break;
+      case LogArgType::kULong:
+        log_message.stream() << va_arg(args, unsigned long);
+        break;
+      case LogArgType::kULongLong:
+        log_message.stream() << va_arg(args, unsigned long long);
+        break;
+      case LogArgType::kDouble:
+        log_message.stream() << va_arg(args, double);
+        break;
+      case LogArgType::kLongDouble:
+        log_message.stream() << va_arg(args, long double);
+        break;
+      case LogArgType::kCharP:
+        log_message.stream() << va_arg(args, const char*);
+        break;
+      case LogArgType::kStdString:
+        log_message.stream() << *va_arg(args, const std::string*);
+        break;
+      case LogArgType::kVoidP:
+        log_message.stream() << va_arg(args, const void*);
+        break;
+      default:
+        RTC_NOTREACHED();
+        va_end(args);
+        return;
+    }
+  }
+
+  va_end(args);
+}
+
+}  // namespace webrtc_logging_impl
 }  // namespace rtc
diff --git a/rtc_base/logging.h b/rtc_base/logging.h
index efaadc5..b5af959 100644
--- a/rtc_base/logging.h
+++ b/rtc_base/logging.h
@@ -55,9 +55,9 @@
 #include <CoreServices/CoreServices.h>
 #endif
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/deprecation.h"
+#include "rtc_base/system/inline.h"
 #include "rtc_base/thread_annotations.h"
 
 #if !defined(NDEBUG) || defined(DLOG_ALWAYS_ON)
@@ -116,16 +116,279 @@
  public:
   LogSink() {}
   virtual ~LogSink() {}
+  virtual void OnLogMessage(const std::string& msg,
+                            LoggingSeverity severity,
+                            const char* tag);
   virtual void OnLogMessage(const std::string& message) = 0;
 };
 
+namespace webrtc_logging_impl {
+
+class LogMetadata {
+ public:
+  LogMetadata(const char* file, int line, LoggingSeverity severity)
+      : file_(file),
+        line_and_sev_(static_cast<uint32_t>(line) << 3 | severity) {}
+  LogMetadata() = default;
+
+  const char* File() const { return file_; }
+  int Line() const { return line_and_sev_ >> 3; }
+  LoggingSeverity Severity() const {
+    return static_cast<LoggingSeverity>(line_and_sev_ & 0x7);
+  }
+
+ private:
+  const char* file_;
+
+  // Line number and severity, the former in the most significant 29 bits, the
+  // latter in the least significant 3 bits. (This is an optimization; since
+  // both numbers are usually compile-time constants, this way we can load them
+  // both with a single instruction.)
+  uint32_t line_and_sev_;
+};
+static_assert(std::is_trivial<LogMetadata>::value, "");
+
+struct LogMetadataErr {
+  LogMetadata meta;
+  LogErrorContext err_ctx;
+  int err;
+};
+
+#ifdef WEBRTC_ANDROID
+struct LogMetadataTag {
+  LoggingSeverity severity;
+  const char* tag;
+};
+#endif
+
+enum class LogArgType : int8_t {
+  kEnd = 0,
+  kInt,
+  kLong,
+  kLongLong,
+  kUInt,
+  kULong,
+  kULongLong,
+  kDouble,
+  kLongDouble,
+  kCharP,
+  kStdString,
+  // TODO(kwiberg): Add absl::StringView.
+  kVoidP,
+  kLogMetadata,
+  kLogMetadataErr,
+#ifdef WEBRTC_ANDROID
+  kLogMetadataTag,
+#endif
+};
+
+// Wrapper for log arguments. Only ever make values of this type with the
+// MakeVal() functions.
+template <LogArgType N, typename T>
+struct Val {
+  static constexpr LogArgType Type() { return N; }
+  T GetVal() const { return val; }
+  T val;
+};
+
+// TODO(bugs.webrtc.org/9278): Get rid of this specialization when callers
+// don't need it anymore. No in-tree caller does, but some external callers
+// still do.
+template <>
+struct Val<LogArgType::kStdString, std::string> {
+  static constexpr LogArgType Type() { return LogArgType::kStdString; }
+  const std::string* GetVal() const { return &val; }
+  std::string val;
+};
+
+inline Val<LogArgType::kInt, int> MakeVal(int x) {
+  return {x};
+}
+inline Val<LogArgType::kLong, long> MakeVal(long x) {
+  return {x};
+}
+inline Val<LogArgType::kLongLong, long long> MakeVal(long long x) {
+  return {x};
+}
+inline Val<LogArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
+  return {x};
+}
+inline Val<LogArgType::kULong, unsigned long> MakeVal(unsigned long x) {
+  return {x};
+}
+inline Val<LogArgType::kULongLong, unsigned long long> MakeVal(
+    unsigned long long x) {
+  return {x};
+}
+
+inline Val<LogArgType::kDouble, double> MakeVal(double x) {
+  return {x};
+}
+inline Val<LogArgType::kLongDouble, long double> MakeVal(long double x) {
+  return {x};
+}
+
+inline Val<LogArgType::kCharP, const char*> MakeVal(const char* x) {
+  return {x};
+}
+inline Val<LogArgType::kStdString, const std::string*> MakeVal(
+    const std::string& x) {
+  return {&x};
+}
+// TODO(kwiberg): Add absl::string_view
+
+inline Val<LogArgType::kVoidP, const void*> MakeVal(const void* x) {
+  return {x};
+}
+
+inline Val<LogArgType::kLogMetadata, LogMetadata> MakeVal(
+    const LogMetadata& x) {
+  return {x};
+}
+inline Val<LogArgType::kLogMetadataErr, LogMetadataErr> MakeVal(
+    const LogMetadataErr& x) {
+  return {x};
+}
+
+#ifdef WEBRTC_ANDROID
+inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal(
+    const LogMetadataTag& x) {
+  return {x};
+}
+#endif
+
+// Handle arbitrary types other than the above by falling back to stringstream.
+// TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need
+// it anymore. No in-tree caller does, but some external callers still do.
+template <
+    typename T,
+    typename T1 =
+        typename std::remove_cv<typename std::remove_reference<T>::type>::type,
+    typename std::enable_if<
+        std::is_class<T1>::value && !std::is_same<T1, std::string>::value &&
+        !std::is_same<T1, LogMetadata>::value &&
+#ifdef WEBRTC_ANDROID
+        !std::is_same<T1, LogMetadataTag>::value &&
+#endif
+        !std::is_same<T1, LogMetadataErr>::value>::type* = nullptr>
+Val<LogArgType::kStdString, std::string> MakeVal(const T& x) {
+  std::ostringstream os;  // no-presubmit-check TODO(webrtc:8982)
+  os << x;
+  return {os.str()};
+}
+
+void Log(const LogArgType* fmt, ...);
+
+// Ephemeral type that represents the result of the logging << operator.
+template <typename... Ts>
+class LogStreamer;
+
+// Base case: Before the first << argument.
+template <>
+class LogStreamer<> final {
+ public:
+  template <
+      typename U,
+      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
+      U arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
+                                                             this);
+  }
+
+  template <
+      typename U,
+      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
+      const U& arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
+                                                             this);
+  }
+
+  template <typename... Us>
+  RTC_FORCE_INLINE static void Call(const Us&... args) {
+    static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd};
+    Log(t, args.GetVal()...);
+  }
+};
+
+// Inductive case: We've already seen at least one << argument. The most recent
+// one had type `T`, and the earlier ones had types `Ts`.
+template <typename T, typename... Ts>
+class LogStreamer<T, Ts...> final {
+ public:
+  RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
+      : arg_(arg), prior_(prior) {}
+
+  template <
+      typename U,
+      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
+  operator<<(U arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
+        MakeVal(arg), this);
+  }
+
+  template <
+      typename U,
+      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
+  RTC_FORCE_INLINE LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>
+  operator<<(const U& arg) const {
+    return LogStreamer<decltype(MakeVal(std::declval<U>())), T, Ts...>(
+        MakeVal(arg), this);
+  }
+
+  template <typename... Us>
+  RTC_FORCE_INLINE void Call(const Us&... args) const {
+    prior_->Call(arg_, args...);
+  }
+
+ private:
+  // The most recent argument.
+  T arg_;
+
+  // Earlier arguments.
+  const LogStreamer<Ts...>* prior_;
+};
+
+class LogCall final {
+ public:
+  // This can be any binary operator with precedence lower than <<.
+  template <typename... Ts>
+  RTC_FORCE_INLINE void operator&(const LogStreamer<Ts...>& streamer) {
+    streamer.Call();
+  }
+};
+
+// TODO(bugs.webrtc.org/9278): Remove this once it's no longer used.
+struct LogMessageVoidify {
+  void operator&(std::ostream&) {}  // no-presubmit-check TODO(webrtc:8982)
+};
+
+}  // namespace webrtc_logging_impl
+
+// Direct use of this class is deprecated; please use the logging macros
+// instead.
+// TODO(bugs.webrtc.org/9278): Move this class to an unnamed namespace in the
+// .cc file.
 class LogMessage {
  public:
+  LogMessage(const char* file, int line, LoggingSeverity sev);
+
+  // Same as the above, but using a compile-time constant for the logging
+  // severity. This saves space at the call site, since passing an empty struct
+  // is generally the same as not passing an argument at all.
+  template <LoggingSeverity S>
+  RTC_NO_INLINE LogMessage(const char* file,
+                           int line,
+                           std::integral_constant<LoggingSeverity, S>)
+      : LogMessage(file, line, S) {}
+
   LogMessage(const char* file,
              int line,
              LoggingSeverity sev,
-             LogErrorContext err_ctx = ERRCTX_NONE,
-             int err = 0);
+             LogErrorContext err_ctx,
+             int err);
 
 #if defined(WEBRTC_ANDROID)
   LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag);
@@ -135,12 +398,26 @@
   // Android code should use the 'const char*' version since tags are static
   // and we want to avoid allocating a std::string copy per log line.
   RTC_DEPRECATED
-  LogMessage(const char* file, int line, LoggingSeverity sev,
+  LogMessage(const char* file,
+             int line,
+             LoggingSeverity sev,
              const std::string& tag);
 
   ~LogMessage();
 
+  void AddTag(const char* tag);
+
   static bool Loggable(LoggingSeverity sev);
+
+  // Same as the above, but using a template argument instead of a function
+  // argument. (When the logging severity is statically known, passing it as a
+  // template argument instead of as a function argument saves space at the
+  // call site.)
+  template <LoggingSeverity S>
+  RTC_NO_INLINE static bool Loggable() {
+    return Loggable(S);
+  }
+
   std::ostream& stream();
 
   // Returns the time at which this function was called for the first time.
@@ -195,7 +472,7 @@
   // Updates min_sev_ appropriately when debug sinks change.
   static void UpdateMinLogSeverity();
 
-  // These write out the actual log messages.
+// These write out the actual log messages.
 #if defined(WEBRTC_ANDROID)
   static void OutputToDebug(const std::string& msg,
                             LoggingSeverity severity,
@@ -221,7 +498,7 @@
   LoggingSeverity severity_;
 
 #if defined(WEBRTC_ANDROID)
-  // The Android debug output tag.
+  // The default Android debug output tag.
   const char* tag_ = "libjingle";
 #endif
 
@@ -247,103 +524,97 @@
 // Logging Helpers
 //////////////////////////////////////////////////////////////////////
 
-// The following non-obvious technique for implementation of a
-// conditional log stream was stolen from google3/base/logging.h.
-
-// This class is used to explicitly ignore values in the conditional
-// logging macros.  This avoids compiler warnings like "value computed
-// is not used" and "statement has no effect".
-
-class LogMessageVoidify {
- public:
-  LogMessageVoidify() { }
-  // This has to be an operator with a precedence lower than << but
-  // higher than ?:
-  void operator&(std::ostream&) { }
-};
-
+// DEPRECATED.
+// TODO(bugs.webrtc.org/9278): Remove once there are no more users.
 #define RTC_LOG_SEVERITY_PRECONDITION(sev) \
-  !(rtc::LogMessage::Loggable(sev)) \
-    ? (void) 0 \
-    : rtc::LogMessageVoidify() &
+  !(rtc::LogMessage::Loggable(sev))        \
+      ? static_cast<void>(0)               \
+      : rtc::webrtc_logging_impl::LogMessageVoidify()&
 
-#define RTC_LOG(sev) \
-  RTC_LOG_SEVERITY_PRECONDITION(rtc::sev) \
-    rtc::LogMessage(__FILE__, __LINE__, rtc::sev).stream()
+#define RTC_LOG(sev)                                                   \
+  for (bool do_log = rtc::LogMessage::Loggable<rtc::sev>(); do_log;    \
+       do_log = false)                                                 \
+  rtc::webrtc_logging_impl::LogCall() &                                \
+      rtc::webrtc_logging_impl::LogStreamer<>()                        \
+          << rtc::webrtc_logging_impl::LogMetadata(__FILE__, __LINE__, \
+                                                   rtc::sev)
 
-// The _V version is for when a variable is passed in.  It doesn't do the
-// namespace concatenation.
-#define RTC_LOG_V(sev) \
-  RTC_LOG_SEVERITY_PRECONDITION(sev) \
-    rtc::LogMessage(__FILE__, __LINE__, sev).stream()
+// The _V version is for when a variable is passed in.
+#define RTC_LOG_V(sev)                                                       \
+  for (bool do_log = rtc::LogMessage::Loggable(sev); do_log; do_log = false) \
+  rtc::webrtc_logging_impl::LogCall() &                                      \
+      rtc::webrtc_logging_impl::LogStreamer<>()                              \
+          << rtc::webrtc_logging_impl::LogMetadata(__FILE__, __LINE__, sev)
 
 // The _F version prefixes the message with the current function name.
 #if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F)
 #define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": "
-#define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " \
-  << __PRETTY_FUNCTION__ << ": "
+#define RTC_LOG_T_F(sev) \
+  RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": "
 #else
 #define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": "
 #define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": "
 #endif
 
-#define RTC_LOG_CHECK_LEVEL(sev) \
-  rtc::LogCheckLevel(rtc::sev)
-#define RTC_LOG_CHECK_LEVEL_V(sev) \
-  rtc::LogCheckLevel(sev)
+#define RTC_LOG_CHECK_LEVEL(sev) rtc::LogCheckLevel(rtc::sev)
+#define RTC_LOG_CHECK_LEVEL_V(sev) rtc::LogCheckLevel(sev)
 
 inline bool LogCheckLevel(LoggingSeverity sev) {
   return (LogMessage::GetMinLogSeverity() <= sev);
 }
 
-#define RTC_LOG_E(sev, ctx, err, ...) \
-  RTC_LOG_SEVERITY_PRECONDITION(rtc::sev) \
-    rtc::LogMessage(__FILE__, __LINE__, rtc::sev, \
-                    rtc::ERRCTX_ ## ctx, err , ##__VA_ARGS__)   \
-        .stream()
+#define RTC_LOG_E(sev, ctx, err)                                    \
+  for (bool do_log = rtc::LogMessage::Loggable<rtc::sev>(); do_log; \
+       do_log = false)                                              \
+    rtc::webrtc_logging_impl::LogCall() &                           \
+        rtc::webrtc_logging_impl::LogStreamer<>()                   \
+            << rtc::webrtc_logging_impl::LogMetadataErr {           \
+      {__FILE__, __LINE__, rtc::sev}, rtc::ERRCTX_##ctx, (err)      \
+    }
 
 #define RTC_LOG_T(sev) RTC_LOG(sev) << this << ": "
 
-#define RTC_LOG_ERRNO_EX(sev, err) \
-  RTC_LOG_E(sev, ERRNO, err)
-#define RTC_LOG_ERRNO(sev) \
-  RTC_LOG_ERRNO_EX(sev, errno)
+#define RTC_LOG_ERRNO_EX(sev, err) RTC_LOG_E(sev, ERRNO, err)
+#define RTC_LOG_ERRNO(sev) RTC_LOG_ERRNO_EX(sev, errno)
 
 #if defined(WEBRTC_WIN)
-#define RTC_LOG_GLE_EX(sev, err) \
-  RTC_LOG_E(sev, HRESULT, err)
-#define RTC_LOG_GLE(sev) \
-  RTC_LOG_GLE_EX(sev, GetLastError())
-#define RTC_LOG_ERR_EX(sev, err) \
-  RTC_LOG_GLE_EX(sev, err)
-#define RTC_LOG_ERR(sev) \
-  RTC_LOG_GLE(sev)
+#define RTC_LOG_GLE_EX(sev, err) RTC_LOG_E(sev, HRESULT, err)
+#define RTC_LOG_GLE(sev) RTC_LOG_GLE_EX(sev, static_cast<int>(GetLastError()))
+#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_GLE_EX(sev, err)
+#define RTC_LOG_ERR(sev) RTC_LOG_GLE(sev)
 #elif defined(__native_client__) && __native_client__
-#define RTC_LOG_ERR_EX(sev, err) \
-  RTC_LOG(sev)
-#define RTC_LOG_ERR(sev) \
-  RTC_LOG(sev)
+#define RTC_LOG_ERR_EX(sev, err) RTC_LOG(sev)
+#define RTC_LOG_ERR(sev) RTC_LOG(sev)
 #elif defined(WEBRTC_POSIX)
-#define RTC_LOG_ERR_EX(sev, err) \
-  RTC_LOG_ERRNO_EX(sev, err)
-#define RTC_LOG_ERR(sev) \
-  RTC_LOG_ERRNO(sev)
+#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_ERRNO_EX(sev, err)
+#define RTC_LOG_ERR(sev) RTC_LOG_ERRNO(sev)
 #endif  // WEBRTC_WIN
 
-#if defined(WEBRTC_ANDROID)
-namespace internal {
-// Inline adapters provided for backwards compatibility for downstream projects.
-inline const char* AdaptString(const char* str) { return str; }
-inline const char* AdaptString(const std::string& str) { return str.c_str(); }
-}  // namespace internal
-#define RTC_LOG_TAG(sev, tag)        \
-  RTC_LOG_SEVERITY_PRECONDITION(sev) \
-  rtc::LogMessage(nullptr, 0, sev, rtc::internal::AdaptString(tag)).stream()
+#ifdef WEBRTC_ANDROID
+
+namespace webrtc_logging_impl {
+// TODO(kwiberg): Replace these with absl::string_view.
+inline const char* AdaptString(const char* str) {
+  return str;
+}
+inline const char* AdaptString(const std::string& str) {
+  return str.c_str();
+}
+}  // namespace webrtc_logging_impl
+
+#define RTC_LOG_TAG(sev, tag)                                                \
+  for (bool do_log = rtc::LogMessage::Loggable(sev); do_log; do_log = false) \
+    rtc::webrtc_logging_impl::LogCall() &                                    \
+        rtc::webrtc_logging_impl::LogStreamer<>()                            \
+            << rtc::webrtc_logging_impl::LogMetadataTag {                    \
+      sev, rtc::webrtc_logging_impl::AdaptString(tag)                        \
+    }
+
 #else
+
 // DEPRECATED. This macro is only intended for Android.
-#define RTC_LOG_TAG(sev, tag)        \
-  RTC_LOG_SEVERITY_PRECONDITION(sev) \
-  rtc::LogMessage(nullptr, 0, sev).stream()
+#define RTC_LOG_TAG(sev, tag) RTC_LOG_V(sev)
+
 #endif
 
 // The RTC_DLOG macros are equivalent to their RTC_LOG counterparts except that
@@ -353,14 +624,12 @@
 #define RTC_DLOG_V(sev) RTC_LOG_V(sev)
 #define RTC_DLOG_F(sev) RTC_LOG_F(sev)
 #else
-#define RTC_DLOG_EAT_STREAM_PARAMS(sev) \
-  (true ? true : ((void)(sev), true))   \
-      ? static_cast<void>(0)            \
-      : rtc::LogMessageVoidify() &      \
-            rtc::LogMessage(__FILE__, __LINE__, sev).stream()
-#define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS(rtc::sev)
-#define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS(sev)
-#define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS(rtc::sev)
+#define RTC_DLOG_EAT_STREAM_PARAMS() \
+  while (false)                      \
+  rtc::webrtc_logging_impl::LogStreamer<>()
+#define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS()
 #endif
 
 }  // namespace rtc
diff --git a/rtc_base/logging_unittest.cc b/rtc_base/logging_unittest.cc
index 1be0b24..af51212 100644
--- a/rtc_base/logging_unittest.cc
+++ b/rtc_base/logging_unittest.cc
@@ -19,20 +19,124 @@
 
 namespace rtc {
 
+namespace {
+
+class StringStream : public StreamInterface {
+ public:
+  explicit StringStream(std::string* str);
+  explicit StringStream(const std::string& str);
+
+  StreamState GetState() const override;
+  StreamResult Read(void* buffer,
+                    size_t buffer_len,
+                    size_t* read,
+                    int* error) override;
+  StreamResult Write(const void* data,
+                     size_t data_len,
+                     size_t* written,
+                     int* error) override;
+  void Close() override;
+  bool SetPosition(size_t position) override;
+  bool GetPosition(size_t* position) const override;
+  bool GetSize(size_t* size) const override;
+  bool GetAvailable(size_t* size) const override;
+  bool ReserveSize(size_t size) override;
+
+ private:
+  std::string& str_;
+  size_t read_pos_;
+  bool read_only_;
+};
+
+StringStream::StringStream(std::string* str)
+    : str_(*str), read_pos_(0), read_only_(false) {}
+
+StringStream::StringStream(const std::string& str)
+    : str_(const_cast<std::string&>(str)), read_pos_(0), read_only_(true) {}
+
+StreamState StringStream::GetState() const {
+  return SS_OPEN;
+}
+
+StreamResult StringStream::Read(void* buffer,
+                                size_t buffer_len,
+                                size_t* read,
+                                int* error) {
+  size_t available = std::min(buffer_len, str_.size() - read_pos_);
+  if (!available)
+    return SR_EOS;
+  memcpy(buffer, str_.data() + read_pos_, available);
+  read_pos_ += available;
+  if (read)
+    *read = available;
+  return SR_SUCCESS;
+}
+
+StreamResult StringStream::Write(const void* data,
+                                 size_t data_len,
+                                 size_t* written,
+                                 int* error) {
+  if (read_only_) {
+    if (error) {
+      *error = -1;
+    }
+    return SR_ERROR;
+  }
+  str_.append(static_cast<const char*>(data),
+              static_cast<const char*>(data) + data_len);
+  if (written)
+    *written = data_len;
+  return SR_SUCCESS;
+}
+
+void StringStream::Close() {}
+
+bool StringStream::SetPosition(size_t position) {
+  if (position > str_.size())
+    return false;
+  read_pos_ = position;
+  return true;
+}
+
+bool StringStream::GetPosition(size_t* position) const {
+  if (position)
+    *position = read_pos_;
+  return true;
+}
+
+bool StringStream::GetSize(size_t* size) const {
+  if (size)
+    *size = str_.size();
+  return true;
+}
+
+bool StringStream::GetAvailable(size_t* size) const {
+  if (size)
+    *size = str_.size() - read_pos_;
+  return true;
+}
+
+bool StringStream::ReserveSize(size_t size) {
+  if (read_only_)
+    return false;
+  str_.reserve(size);
+  return true;
+}
+
+}  // namespace
+
 template <typename Base>
-class LogSinkImpl
-    : public LogSink,
-      public Base {
+class LogSinkImpl : public LogSink, public Base {
  public:
   LogSinkImpl() {}
 
-  template<typename P>
+  template <typename P>
   explicit LogSinkImpl(P* p) : Base(p) {}
 
  private:
   void OnLogMessage(const std::string& message) override {
-    static_cast<Base*>(this)->WriteAll(
-        message.data(), message.size(), nullptr, nullptr);
+    static_cast<Base*>(this)->WriteAll(message.data(), message.size(), nullptr,
+                                       nullptr);
   }
 };
 
@@ -47,6 +151,9 @@
 
   const std::string& get_extra() const { return extra_; }
   bool is_noop() const { return is_noop_; }
+#if defined(WEBRTC_ANDROID)
+  const char* get_tag() const { return tag_; }
+#endif
 
   // Returns the contents of the internal log stream.
   // Note that parts of the stream won't (as is) be available until *after* the
@@ -87,6 +194,34 @@
   EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr));
 }
 
+#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+TEST(LogTest, Checks) {
+  EXPECT_DEATH(FATAL() << "message",
+               "\n\n#\n"
+               "# Fatal error in: \\S+, line \\w+\n"
+               "# last system error: \\w+\n"
+               "# Check failed: FATAL\\(\\)\n"
+               "# message");
+
+  int a = 1, b = 2;
+  EXPECT_DEATH(RTC_CHECK_EQ(a, b) << 1 << 2u,
+               "\n\n#\n"
+               "# Fatal error in: \\S+, line \\w+\n"
+               "# last system error: \\w+\n"
+               "# Check failed: a == b \\(1 vs. 2\\)\n"
+               "# 12");
+  RTC_CHECK_EQ(5, 5);
+
+  RTC_CHECK(true) << "Shouldn't crash" << 1;
+  EXPECT_DEATH(RTC_CHECK(false) << "Hi there!",
+               "\n\n#\n"
+               "# Fatal error in: \\S+, line \\w+\n"
+               "# last system error: \\w+\n"
+               "# Check failed: false\n"
+               "# Hi there!");
+}
+#endif
+
 // Test using multiple log streams. The INFO stream should get the INFO message,
 // the VERBOSE stream should get the INFO and the VERBOSE.
 // We should restore the correct global state at the end.
@@ -137,9 +272,6 @@
 
 // Ensure we don't crash when adding/removing streams while threads are going.
 // We should restore the correct global state at the end.
-// This test also makes sure that the 'noop' stream() singleton object, can be
-// safely used from mutiple threads since the threads log at LS_SENSITIVE
-// (by default 'noop' entries).
 TEST(LogTest, MultipleThreads) {
   int sev = LogMessage::GetLogToStream(nullptr);
 
@@ -148,7 +280,8 @@
   thread2.Start();
   thread3.Start();
 
-  LogSinkImpl<NullStream> stream1, stream2, stream3;
+  std::string s1, s2, s3;
+  LogSinkImpl<StringStream> stream1(&s1), stream2(&s2), stream3(&s3);
   for (int i = 0; i < 1000; ++i) {
     LogMessage::AddLogToStream(&stream1, LS_INFO);
     LogMessage::AddLogToStream(&stream2, LS_VERBOSE);
@@ -161,7 +294,6 @@
   EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr));
 }
 
-
 TEST(LogTest, WallClockStartTime) {
   uint32_t time = LogMessage::WallClockStartTime();
   // Expect the time to be in a sensible range, e.g. > 2012-01-01.
@@ -186,9 +318,28 @@
   log_msg.stream() << "<- Does this look right?";
 
   const std::string stream = log_msg.GetPrintStream();
+#if defined(WEBRTC_ANDROID)
+  const char* tag = log_msg.get_tag();
+  EXPECT_NE(nullptr, strstr(tag, "myfile.cc"));
+  EXPECT_NE(std::string::npos, stream.find("100"));
+#else
   EXPECT_NE(std::string::npos, stream.find("(myfile.cc:100)"));
+#endif
 }
 
+#if defined(WEBRTC_ANDROID)
+TEST(LogTest, CheckTagAddedToStringInDefaultOnLogMessageAndroid) {
+  std::string str;
+  LogSinkImpl<StringStream> stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+  EXPECT_EQ(LS_INFO, LogMessage::GetLogToStream(&stream));
+
+  RTC_LOG_TAG(LS_INFO, "my_tag") << "INFO";
+  EXPECT_NE(std::string::npos, str.find("INFO"));
+  EXPECT_NE(std::string::npos, str.find("my_tag"));
+}
+#endif
+
 TEST(LogTest, CheckNoopLogEntry) {
   if (LogMessage::GetLogToDebug() <= LS_SENSITIVE) {
     printf("CheckNoopLogEntry: skipping. Global severity is being overridden.");
diff --git a/rtc_base/logsinks.cc b/rtc_base/logsinks.cc
index 5f64f62..662b1f2 100644
--- a/rtc_base/logsinks.cc
+++ b/rtc_base/logsinks.cc
@@ -10,7 +10,7 @@
 
 #include "rtc_base/logsinks.h"
 
-#include <iostream>
+#include <cstdio>
 #include <string>
 
 #include "rtc_base/checks.h"
@@ -24,25 +24,35 @@
     : FileRotatingLogSink(new FileRotatingStream(log_dir_path,
                                                  log_prefix,
                                                  max_log_size,
-                                                 num_log_files)) {
-}
+                                                 num_log_files)) {}
 
 FileRotatingLogSink::FileRotatingLogSink(FileRotatingStream* stream)
     : stream_(stream) {
   RTC_DCHECK(stream);
 }
 
-FileRotatingLogSink::~FileRotatingLogSink() {
-}
+FileRotatingLogSink::~FileRotatingLogSink() {}
 
 void FileRotatingLogSink::OnLogMessage(const std::string& message) {
   if (stream_->GetState() != SS_OPEN) {
-    std::cerr << "Init() must be called before adding this sink." << std::endl;
+    std::fprintf(stderr, "Init() must be called before adding this sink.\n");
     return;
   }
   stream_->WriteAll(message.c_str(), message.size(), nullptr, nullptr);
 }
 
+void FileRotatingLogSink::OnLogMessage(const std::string& message,
+                                       LoggingSeverity sev,
+                                       const char* tag) {
+  if (stream_->GetState() != SS_OPEN) {
+    std::fprintf(stderr, "Init() must be called before adding this sink.\n");
+    return;
+  }
+  stream_->WriteAll(tag, strlen(tag), nullptr, nullptr);
+  stream_->WriteAll(": ", 2, nullptr, nullptr);
+  stream_->WriteAll(message.c_str(), message.size(), nullptr, nullptr);
+}
+
 bool FileRotatingLogSink::Init() {
   return stream_->Open();
 }
@@ -58,7 +68,6 @@
           new CallSessionFileRotatingStream(log_dir_path, max_total_log_size)) {
 }
 
-CallSessionFileRotatingLogSink::~CallSessionFileRotatingLogSink() {
-}
+CallSessionFileRotatingLogSink::~CallSessionFileRotatingLogSink() {}
 
 }  // namespace rtc
diff --git a/rtc_base/logsinks.h b/rtc_base/logsinks.h
index 315ef96..caf4a5f 100644
--- a/rtc_base/logsinks.h
+++ b/rtc_base/logsinks.h
@@ -35,6 +35,9 @@
   // Writes the message to the current file. It will spill over to the next
   // file if needed.
   void OnLogMessage(const std::string& message) override;
+  void OnLogMessage(const std::string& message,
+                    LoggingSeverity sev,
+                    const char* tag) override;
 
   // Deletes any existing files in the directory and creates a new log file.
   virtual bool Init();
diff --git a/rtc_base/macutils.cc b/rtc_base/macutils.cc
index d3f2919..2b8700f 100644
--- a/rtc_base/macutils.cc
+++ b/rtc_base/macutils.cc
@@ -10,7 +10,6 @@
 
 #include <cstring>
 #include <memory>
-#include <sstream>
 
 #include <sys/utsname.h>
 
@@ -26,10 +25,11 @@
     return false;
   }
   size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16),
-                                                    kCFStringEncodingUTF8) + 1;
+                                                    kCFStringEncodingUTF8) +
+                  1;
   std::unique_ptr<char[]> buffer(new char[maxlen]);
-  if (!buffer || !CFStringGetCString(str16, buffer.get(), maxlen,
-                                     kCFStringEncodingUTF8)) {
+  if (!buffer ||
+      !CFStringGetCString(str16, buffer.get(), maxlen, kCFStringEncodingUTF8)) {
     return false;
   }
   str8->assign(buffer.get());
@@ -42,8 +42,7 @@
   }
   *str16 = CFStringCreateWithBytes(kCFAllocatorDefault,
                                    reinterpret_cast<const UInt8*>(str8.data()),
-                                   str8.length(), kCFStringEncodingUTF8,
-                                   false);
+                                   str8.length(), kCFStringEncodingUTF8, false);
   return nullptr != *str16;
 }
 }  // namespace rtc
diff --git a/rtc_base/memory_usage.cc b/rtc_base/memory_usage.cc
index 41b27ed..a70c547 100644
--- a/rtc_base/memory_usage.cc
+++ b/rtc_base/memory_usage.cc
@@ -12,14 +12,17 @@
 
 #if defined(WEBRTC_LINUX)
 #include <unistd.h>
-#include <cstdlib>
 #include <cstdio>
+#include <cstdlib>
 #include <cstring>
 #elif defined(WEBRTC_MAC)
 #include <mach/mach.h>
 #elif defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
 #include <windows.h>
-#include <psapi.h>
+#include <psapi.h> // must come after windows.h
+// clang-format on
 #endif
 
 #include "rtc_base/logging.h"
diff --git a/rtc_base/memory_usage_unittest.cc b/rtc_base/memory_usage_unittest.cc
index 87cdcef..9c82f98 100644
--- a/rtc_base/memory_usage_unittest.cc
+++ b/rtc_base/memory_usage_unittest.cc
@@ -20,4 +20,3 @@
 }
 
 }  // namespace rtc
-
diff --git a/rtc_base/messagedigest.cc b/rtc_base/messagedigest.cc
index bf8d25d..9c10bcd 100644
--- a/rtc_base/messagedigest.cc
+++ b/rtc_base/messagedigest.cc
@@ -14,15 +14,14 @@
 
 #include <string.h>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/openssldigest.h"
 #include "rtc_base/stringencode.h"
 
 namespace rtc {
 
 // From RFC 4572.
-const char DIGEST_MD5[]     = "md5";
-const char DIGEST_SHA_1[]   = "sha-1";
+const char DIGEST_MD5[] = "md5";
+const char DIGEST_SHA_1[] = "sha-1";
 const char DIGEST_SHA_224[] = "sha-224";
 const char DIGEST_SHA_256[] = "sha-256";
 const char DIGEST_SHA_384[] = "sha-384";
@@ -45,35 +44,39 @@
   // consideration) MUST use one of the FIPS 180 algorithms (SHA-1,
   // SHA-224, SHA-256, SHA-384, or SHA-512) as their signature algorithm,
   // and thus also MUST use it to calculate certificate fingerprints."
-  return alg == DIGEST_SHA_1 ||
-         alg == DIGEST_SHA_224 ||
-         alg == DIGEST_SHA_256 ||
-         alg == DIGEST_SHA_384 ||
+  return alg == DIGEST_SHA_1 || alg == DIGEST_SHA_224 ||
+         alg == DIGEST_SHA_256 || alg == DIGEST_SHA_384 ||
          alg == DIGEST_SHA_512;
 }
 
-size_t ComputeDigest(MessageDigest* digest, const void* input, size_t in_len,
-                     void* output, size_t out_len) {
+size_t ComputeDigest(MessageDigest* digest,
+                     const void* input,
+                     size_t in_len,
+                     void* output,
+                     size_t out_len) {
   digest->Update(input, in_len);
   return digest->Finish(output, out_len);
 }
 
-size_t ComputeDigest(const std::string& alg, const void* input, size_t in_len,
-                     void* output, size_t out_len) {
+size_t ComputeDigest(const std::string& alg,
+                     const void* input,
+                     size_t in_len,
+                     void* output,
+                     size_t out_len) {
   std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
-  return (digest) ?
-      ComputeDigest(digest.get(), input, in_len, output, out_len) :
-      0;
+  return (digest) ? ComputeDigest(digest.get(), input, in_len, output, out_len)
+                  : 0;
 }
 
 std::string ComputeDigest(MessageDigest* digest, const std::string& input) {
   std::unique_ptr<char[]> output(new char[digest->Size()]);
-  ComputeDigest(digest, input.data(), input.size(),
-                output.get(), digest->Size());
+  ComputeDigest(digest, input.data(), input.size(), output.get(),
+                digest->Size());
   return hex_encode(output.get(), digest->Size());
 }
 
-bool ComputeDigest(const std::string& alg, const std::string& input,
+bool ComputeDigest(const std::string& alg,
+                   const std::string& input,
                    std::string* output) {
   std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
   if (!digest) {
@@ -91,9 +94,12 @@
 
 // Compute a RFC 2104 HMAC: H(K XOR opad, H(K XOR ipad, text))
 size_t ComputeHmac(MessageDigest* digest,
-                   const void* key, size_t key_len,
-                   const void* input, size_t in_len,
-                   void* output, size_t out_len) {
+                   const void* key,
+                   size_t key_len,
+                   const void* input,
+                   size_t in_len,
+                   void* output,
+                   size_t out_len) {
   // We only handle algorithms with a 64-byte blocksize.
   // TODO: Add BlockSize() method to MessageDigest.
   size_t block_len = kBlockSize;
@@ -128,27 +134,34 @@
   return digest->Finish(output, out_len);
 }
 
-size_t ComputeHmac(const std::string& alg, const void* key, size_t key_len,
-                   const void* input, size_t in_len,
-                   void* output, size_t out_len) {
+size_t ComputeHmac(const std::string& alg,
+                   const void* key,
+                   size_t key_len,
+                   const void* input,
+                   size_t in_len,
+                   void* output,
+                   size_t out_len) {
   std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
   if (!digest) {
     return 0;
   }
-  return ComputeHmac(digest.get(), key, key_len,
-                     input, in_len, output, out_len);
+  return ComputeHmac(digest.get(), key, key_len, input, in_len, output,
+                     out_len);
 }
 
-std::string ComputeHmac(MessageDigest* digest, const std::string& key,
+std::string ComputeHmac(MessageDigest* digest,
+                        const std::string& key,
                         const std::string& input) {
   std::unique_ptr<char[]> output(new char[digest->Size()]);
-  ComputeHmac(digest, key.data(), key.size(),
-              input.data(), input.size(), output.get(), digest->Size());
+  ComputeHmac(digest, key.data(), key.size(), input.data(), input.size(),
+              output.get(), digest->Size());
   return hex_encode(output.get(), digest->Size());
 }
 
-bool ComputeHmac(const std::string& alg, const std::string& key,
-                 const std::string& input, std::string* output) {
+bool ComputeHmac(const std::string& alg,
+                 const std::string& key,
+                 const std::string& input,
+                 std::string* output) {
   std::unique_ptr<MessageDigest> digest(MessageDigestFactory::Create(alg));
   if (!digest) {
     return false;
@@ -157,7 +170,8 @@
   return true;
 }
 
-std::string ComputeHmac(const std::string& alg, const std::string& key,
+std::string ComputeHmac(const std::string& alg,
+                        const std::string& key,
                         const std::string& input) {
   std::string output;
   ComputeHmac(alg, key, input, &output);
diff --git a/rtc_base/messagedigest.h b/rtc_base/messagedigest.h
index f80dd7a..fc82088 100644
--- a/rtc_base/messagedigest.h
+++ b/rtc_base/messagedigest.h
@@ -52,13 +52,19 @@
 // implementation, and outputs the hash to the buffer |output|, which is
 // |out_len| bytes long. Returns the number of bytes written to |output| if
 // successful, or 0 if |out_len| was too small.
-size_t ComputeDigest(MessageDigest* digest, const void* input, size_t in_len,
-                     void* output, size_t out_len);
+size_t ComputeDigest(MessageDigest* digest,
+                     const void* input,
+                     size_t in_len,
+                     void* output,
+                     size_t out_len);
 // Like the previous function, but creates a digest implementation based on
 // the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns 0 if there is no
 // digest with the given name.
-size_t ComputeDigest(const std::string& alg, const void* input, size_t in_len,
-                     void* output, size_t out_len);
+size_t ComputeDigest(const std::string& alg,
+                     const void* input,
+                     size_t in_len,
+                     void* output,
+                     size_t out_len);
 // Computes the hash of |input| using the |digest| hash implementation, and
 // returns it as a hex-encoded string.
 std::string ComputeDigest(MessageDigest* digest, const std::string& input);
@@ -67,7 +73,8 @@
 // there is no digest with the given name.
 std::string ComputeDigest(const std::string& alg, const std::string& input);
 // Like the previous function, but returns an explicit result code.
-bool ComputeDigest(const std::string& alg, const std::string& input,
+bool ComputeDigest(const std::string& alg,
+                   const std::string& input,
                    std::string* output);
 
 // Shorthand way to compute a hex-encoded hash using MD5.
@@ -82,27 +89,39 @@
 // the HMAC to the buffer |output|, which is |out_len| bytes long. Returns the
 // number of bytes written to |output| if successful, or 0 if |out_len| was too
 // small.
-size_t ComputeHmac(MessageDigest* digest, const void* key, size_t key_len,
-                   const void* input, size_t in_len,
-                   void* output, size_t out_len);
+size_t ComputeHmac(MessageDigest* digest,
+                   const void* key,
+                   size_t key_len,
+                   const void* input,
+                   size_t in_len,
+                   void* output,
+                   size_t out_len);
 // Like the previous function, but creates a digest implementation based on
 // the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns 0 if there is no
 // digest with the given name.
-size_t ComputeHmac(const std::string& alg, const void* key, size_t key_len,
-                   const void* input, size_t in_len,
-                   void* output, size_t out_len);
+size_t ComputeHmac(const std::string& alg,
+                   const void* key,
+                   size_t key_len,
+                   const void* input,
+                   size_t in_len,
+                   void* output,
+                   size_t out_len);
 // Computes the HMAC of |input| using the |digest| hash implementation and |key|
 // to key the HMAC, and returns it as a hex-encoded string.
-std::string ComputeHmac(MessageDigest* digest, const std::string& key,
+std::string ComputeHmac(MessageDigest* digest,
+                        const std::string& key,
                         const std::string& input);
 // Like the previous function, but creates a digest implementation based on
 // the desired digest name |alg|, e.g. DIGEST_SHA_1. Returns empty string if
 // there is no digest with the given name.
-std::string ComputeHmac(const std::string& alg, const std::string& key,
+std::string ComputeHmac(const std::string& alg,
+                        const std::string& key,
                         const std::string& input);
 // Like the previous function, but returns an explicit result code.
-bool ComputeHmac(const std::string& alg, const std::string& key,
-                 const std::string& input, std::string* output);
+bool ComputeHmac(const std::string& alg,
+                 const std::string& key,
+                 const std::string& input,
+                 std::string* output);
 
 }  // namespace rtc
 
diff --git a/rtc_base/messagedigest_unittest.cc b/rtc_base/messagedigest_unittest.cc
index 4d7c338..5524b18 100644
--- a/rtc_base/messagedigest_unittest.cc
+++ b/rtc_base/messagedigest_unittest.cc
@@ -17,42 +17,42 @@
 // Test vectors from RFC 1321.
 TEST(MessageDigestTest, TestMd5Digest) {
   // Test the string versions of the APIs.
-  EXPECT_EQ("d41d8cd98f00b204e9800998ecf8427e",
-      ComputeDigest(DIGEST_MD5, ""));
+  EXPECT_EQ("d41d8cd98f00b204e9800998ecf8427e", ComputeDigest(DIGEST_MD5, ""));
   EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72",
-      ComputeDigest(DIGEST_MD5, "abc"));
+            ComputeDigest(DIGEST_MD5, "abc"));
   EXPECT_EQ("c3fcd3d76192e4007dfb496cca67e13b",
-      ComputeDigest(DIGEST_MD5, "abcdefghijklmnopqrstuvwxyz"));
+            ComputeDigest(DIGEST_MD5, "abcdefghijklmnopqrstuvwxyz"));
 
   // Test the raw buffer versions of the APIs; also check output buffer size.
   char output[16];
   EXPECT_EQ(sizeof(output),
-      ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output)));
+            ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output)));
   EXPECT_EQ("900150983cd24fb0d6963f7d28e17f72",
-      hex_encode(output, sizeof(output)));
+            hex_encode(output, sizeof(output)));
   EXPECT_EQ(0U,
-      ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output) - 1));
+            ComputeDigest(DIGEST_MD5, "abc", 3, output, sizeof(output) - 1));
 }
 
 // Test vectors from RFC 3174.
 TEST(MessageDigestTest, TestSha1Digest) {
   // Test the string versions of the APIs.
   EXPECT_EQ("da39a3ee5e6b4b0d3255bfef95601890afd80709",
-      ComputeDigest(DIGEST_SHA_1, ""));
+            ComputeDigest(DIGEST_SHA_1, ""));
   EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d",
-      ComputeDigest(DIGEST_SHA_1, "abc"));
+            ComputeDigest(DIGEST_SHA_1, "abc"));
   EXPECT_EQ("84983e441c3bd26ebaae4aa1f95129e5e54670f1",
-      ComputeDigest(DIGEST_SHA_1,
-          "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
+            ComputeDigest(
+                DIGEST_SHA_1,
+                "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
 
   // Test the raw buffer versions of the APIs; also check output buffer size.
   char output[20];
   EXPECT_EQ(sizeof(output),
-      ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output)));
+            ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output)));
   EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d",
-      hex_encode(output, sizeof(output)));
+            hex_encode(output, sizeof(output)));
   EXPECT_EQ(0U,
-      ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output) - 1));
+            ComputeDigest(DIGEST_SHA_1, "abc", 3, output, sizeof(output) - 1));
 }
 
 // Test that we fail properly if a bad digest algorithm is specified.
@@ -66,80 +66,83 @@
 TEST(MessageDigestTest, TestMd5Hmac) {
   // Test the string versions of the APIs.
   EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d",
-      ComputeHmac(DIGEST_MD5, std::string(16, '\x0b'), "Hi There"));
+            ComputeHmac(DIGEST_MD5, std::string(16, '\x0b'), "Hi There"));
   EXPECT_EQ("750c783e6ab0b503eaa86e310a5db738",
-      ComputeHmac(DIGEST_MD5, "Jefe", "what do ya want for nothing?"));
+            ComputeHmac(DIGEST_MD5, "Jefe", "what do ya want for nothing?"));
   EXPECT_EQ("56be34521d144c88dbb8c733f0e8b3f6",
-      ComputeHmac(DIGEST_MD5, std::string(16, '\xaa'),
-          std::string(50, '\xdd')));
-  EXPECT_EQ("697eaf0aca3a3aea3a75164746ffaa79",
+            ComputeHmac(DIGEST_MD5, std::string(16, '\xaa'),
+                        std::string(50, '\xdd')));
+  EXPECT_EQ(
+      "697eaf0aca3a3aea3a75164746ffaa79",
       ComputeHmac(DIGEST_MD5,
-          "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-          "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
-          std::string(50, '\xcd')));
-  EXPECT_EQ("56461ef2342edc00f9bab995690efd4c",
-      ComputeHmac(DIGEST_MD5, std::string(16, '\x0c'),
-          "Test With Truncation"));
-  EXPECT_EQ("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
+                  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                  "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+                  std::string(50, '\xcd')));
+  EXPECT_EQ(
+      "56461ef2342edc00f9bab995690efd4c",
+      ComputeHmac(DIGEST_MD5, std::string(16, '\x0c'), "Test With Truncation"));
+  EXPECT_EQ(
+      "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
       ComputeHmac(DIGEST_MD5, std::string(80, '\xaa'),
-          "Test Using Larger Than Block-Size Key - Hash Key First"));
+                  "Test Using Larger Than Block-Size Key - Hash Key First"));
   EXPECT_EQ("6f630fad67cda0ee1fb1f562db3aa53e",
-      ComputeHmac(DIGEST_MD5, std::string(80, '\xaa'),
-          "Test Using Larger Than Block-Size Key and Larger "
-          "Than One Block-Size Data"));
+            ComputeHmac(DIGEST_MD5, std::string(80, '\xaa'),
+                        "Test Using Larger Than Block-Size Key and Larger "
+                        "Than One Block-Size Data"));
 
   // Test the raw buffer versions of the APIs; also check output buffer size.
   std::string key(16, '\x0b');
   std::string input("Hi There");
   char output[16];
   EXPECT_EQ(sizeof(output),
-      ComputeHmac(DIGEST_MD5, key.c_str(), key.size(),
-          input.c_str(), input.size(), output, sizeof(output)));
+            ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(),
+                        input.size(), output, sizeof(output)));
   EXPECT_EQ("9294727a3638bb1c13f48ef8158bfc9d",
-      hex_encode(output, sizeof(output)));
-  EXPECT_EQ(0U,
-      ComputeHmac(DIGEST_MD5, key.c_str(), key.size(),
-          input.c_str(), input.size(), output, sizeof(output) - 1));
+            hex_encode(output, sizeof(output)));
+  EXPECT_EQ(0U, ComputeHmac(DIGEST_MD5, key.c_str(), key.size(), input.c_str(),
+                            input.size(), output, sizeof(output) - 1));
 }
 
 // Test vectors from RFC 2202.
 TEST(MessageDigestTest, TestSha1Hmac) {
   // Test the string versions of the APIs.
   EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00",
-      ComputeHmac(DIGEST_SHA_1, std::string(20, '\x0b'), "Hi There"));
+            ComputeHmac(DIGEST_SHA_1, std::string(20, '\x0b'), "Hi There"));
   EXPECT_EQ("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
-      ComputeHmac(DIGEST_SHA_1, "Jefe", "what do ya want for nothing?"));
+            ComputeHmac(DIGEST_SHA_1, "Jefe", "what do ya want for nothing?"));
   EXPECT_EQ("125d7342b9ac11cd91a39af48aa17b4f63f175d3",
-      ComputeHmac(DIGEST_SHA_1, std::string(20, '\xaa'),
-          std::string(50, '\xdd')));
-  EXPECT_EQ("4c9007f4026250c6bc8414f9bf50c86c2d7235da",
+            ComputeHmac(DIGEST_SHA_1, std::string(20, '\xaa'),
+                        std::string(50, '\xdd')));
+  EXPECT_EQ(
+      "4c9007f4026250c6bc8414f9bf50c86c2d7235da",
       ComputeHmac(DIGEST_SHA_1,
-          "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-          "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
-          std::string(50, '\xcd')));
+                  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                  "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+                  std::string(50, '\xcd')));
   EXPECT_EQ("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
-      ComputeHmac(DIGEST_SHA_1, std::string(20, '\x0c'),
-          "Test With Truncation"));
-  EXPECT_EQ("aa4ae5e15272d00e95705637ce8a3b55ed402112",
+            ComputeHmac(DIGEST_SHA_1, std::string(20, '\x0c'),
+                        "Test With Truncation"));
+  EXPECT_EQ(
+      "aa4ae5e15272d00e95705637ce8a3b55ed402112",
       ComputeHmac(DIGEST_SHA_1, std::string(80, '\xaa'),
-          "Test Using Larger Than Block-Size Key - Hash Key First"));
+                  "Test Using Larger Than Block-Size Key - Hash Key First"));
   EXPECT_EQ("e8e99d0f45237d786d6bbaa7965c7808bbff1a91",
-      ComputeHmac(DIGEST_SHA_1, std::string(80, '\xaa'),
-          "Test Using Larger Than Block-Size Key and Larger "
-          "Than One Block-Size Data"));
+            ComputeHmac(DIGEST_SHA_1, std::string(80, '\xaa'),
+                        "Test Using Larger Than Block-Size Key and Larger "
+                        "Than One Block-Size Data"));
 
   // Test the raw buffer versions of the APIs; also check output buffer size.
   std::string key(20, '\x0b');
   std::string input("Hi There");
   char output[20];
   EXPECT_EQ(sizeof(output),
-      ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(),
-          input.c_str(), input.size(), output, sizeof(output)));
+            ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(),
+                        input.size(), output, sizeof(output)));
   EXPECT_EQ("b617318655057264e28bc0b6fb378c8ef146be00",
-      hex_encode(output, sizeof(output)));
+            hex_encode(output, sizeof(output)));
   EXPECT_EQ(0U,
-      ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(),
-          input.c_str(), input.size(), output, sizeof(output) - 1));
+            ComputeHmac(DIGEST_SHA_1, key.c_str(), key.size(), input.c_str(),
+                        input.size(), output, sizeof(output) - 1));
 }
 
 TEST(MessageDigestTest, TestBadHmac) {
diff --git a/rtc_base/messagehandler.cc b/rtc_base/messagehandler.cc
index 2f580cc..7376def 100644
--- a/rtc_base/messagehandler.cc
+++ b/rtc_base/messagehandler.cc
@@ -17,4 +17,4 @@
   MessageQueueManager::Clear(this);
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/messagehandler.h b/rtc_base/messagehandler.h
index ff953f7..df2d1ad 100644
--- a/rtc_base/messagehandler.h
+++ b/rtc_base/messagehandler.h
@@ -40,9 +40,7 @@
  public:
   explicit FunctorMessageHandler(FunctorT&& functor)
       : functor_(std::forward<FunctorT>(functor)) {}
-  virtual void OnMessage(Message* msg) {
-    result_ = functor_();
-  }
+  virtual void OnMessage(Message* msg) { result_ = functor_(); }
   const ReturnT& result() const { return result_; }
 
   // Returns moved result. Should not call result() or MoveResult() again
@@ -58,11 +56,8 @@
 template <class FunctorT>
 class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
  public:
-  explicit FunctorMessageHandler(const FunctorT& functor)
-      : functor_(functor) {}
-  virtual void OnMessage(Message* msg) {
-    functor_();
-  }
+  explicit FunctorMessageHandler(const FunctorT& functor) : functor_(functor) {}
+  virtual void OnMessage(Message* msg) { functor_(); }
   void result() const {}
   void MoveResult() {}
 
@@ -70,6 +65,6 @@
   FunctorT functor_;
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_MESSAGEHANDLER_H_
+#endif  // RTC_BASE_MESSAGEHANDLER_H_
diff --git a/rtc_base/messagequeue.cc b/rtc_base/messagequeue.cc
index 001d3ed..035ff07 100644
--- a/rtc_base/messagequeue.cc
+++ b/rtc_base/messagequeue.cc
@@ -20,7 +20,7 @@
 namespace rtc {
 namespace {
 
-const int kMaxMsgLatency = 150;  // 150 ms
+const int kMaxMsgLatency = 150;                // 150 ms
 const int kSlowDispatchLoggingThreshold = 50;  // 50 ms
 
 class RTC_SCOPED_LOCKABLE MarkProcessingCritScope {
@@ -64,26 +64,26 @@
 
 MessageQueueManager::MessageQueueManager() : processing_(0) {}
 
-MessageQueueManager::~MessageQueueManager() {
-}
+MessageQueueManager::~MessageQueueManager() {}
 
-void MessageQueueManager::Add(MessageQueue *message_queue) {
+void MessageQueueManager::Add(MessageQueue* message_queue) {
   return Instance()->AddInternal(message_queue);
 }
-void MessageQueueManager::AddInternal(MessageQueue *message_queue) {
+void MessageQueueManager::AddInternal(MessageQueue* message_queue) {
   CritScope cs(&crit_);
   // Prevent changes while the list of message queues is processed.
   RTC_DCHECK_EQ(processing_, 0);
   message_queues_.push_back(message_queue);
 }
 
-void MessageQueueManager::Remove(MessageQueue *message_queue) {
+void MessageQueueManager::Remove(MessageQueue* message_queue) {
   // If there isn't a message queue manager instance, then there isn't a queue
   // to remove.
-  if (!instance_) return;
+  if (!instance_)
+    return;
   return Instance()->RemoveInternal(message_queue);
 }
-void MessageQueueManager::RemoveInternal(MessageQueue *message_queue) {
+void MessageQueueManager::RemoveInternal(MessageQueue* message_queue) {
   // If this is the last MessageQueue, destroy the manager as well so that
   // we don't leak this object at program shutdown. As mentioned above, this is
   // not thread-safe, but this should only happen at program termination (when
@@ -93,7 +93,7 @@
     CritScope cs(&crit_);
     // Prevent changes while the list of message queues is processed.
     RTC_DCHECK_EQ(processing_, 0);
-    std::vector<MessageQueue *>::iterator iter;
+    std::vector<MessageQueue*>::iterator iter;
     iter = std::find(message_queues_.begin(), message_queues_.end(),
                      message_queue);
     if (iter != message_queues_.end()) {
@@ -107,18 +107,18 @@
   }
 }
 
-void MessageQueueManager::Clear(MessageHandler *handler) {
+void MessageQueueManager::Clear(MessageHandler* handler) {
   // If there isn't a message queue manager instance, then there aren't any
   // queues to remove this handler from.
-  if (!instance_) return;
+  if (!instance_)
+    return;
   return Instance()->ClearInternal(handler);
 }
-void MessageQueueManager::ClearInternal(MessageHandler *handler) {
+void MessageQueueManager::ClearInternal(MessageHandler* handler) {
   // Deleted objects may cause re-entrant calls to ClearInternal. This is
   // allowed as the list of message queues does not change while queues are
   // cleared.
   MarkProcessingCritScope cs(&crit_, &processing_);
-  std::vector<MessageQueue *>::iterator iter;
   for (MessageQueue* queue : message_queues_) {
     queue->Clear(handler);
   }
@@ -253,7 +253,7 @@
   AtomicOps::ReleaseStore(&stop_, 0);
 }
 
-bool MessageQueue::Peek(Message *pmsg, int cmsWait) {
+bool MessageQueue::Peek(Message* pmsg, int cmsWait) {
   if (fPeekKeep_) {
     *pmsg = msgPeek_;
     return true;
@@ -265,7 +265,7 @@
   return true;
 }
 
-bool MessageQueue::Get(Message *pmsg, int cmsWait, bool process_io) {
+bool MessageQueue::Get(Message* pmsg, int cmsWait, bool process_io) {
   // Return and clear peek if present
   // Always return the peek if it exists so there is Peek/Get symmetry
 
@@ -367,8 +367,7 @@
   return false;
 }
 
-void MessageQueue::ReceiveSends() {
-}
+void MessageQueue::ReceiveSends() {}
 
 void MessageQueue::Post(const Location& posted_from,
                         MessageHandler* phandler,
@@ -523,7 +522,7 @@
   dmsgq_.reheap();
 }
 
-void MessageQueue::Dispatch(Message *pmsg) {
+void MessageQueue::Dispatch(Message* pmsg) {
   TRACE_EVENT2("webrtc", "MessageQueue::Dispatch", "src_file_and_line",
                pmsg->posted_from.file_and_line(), "src_func",
                pmsg->posted_from.function_name());
diff --git a/rtc_base/messagequeue.h b/rtc_base/messagequeue.h
index 7055643..c156d15 100644
--- a/rtc_base/messagequeue.h
+++ b/rtc_base/messagequeue.h
@@ -20,7 +20,6 @@
 #include <utility>
 #include <vector>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/criticalsection.h"
 #include "rtc_base/location.h"
@@ -40,9 +39,9 @@
 
 class MessageQueueManager {
  public:
-  static void Add(MessageQueue *message_queue);
-  static void Remove(MessageQueue *message_queue);
-  static void Clear(MessageHandler *handler);
+  static void Add(MessageQueue* message_queue);
+  static void Remove(MessageQueue* message_queue);
+  static void Clear(MessageHandler* handler);
 
   // For testing purposes, we expose whether or not the MessageQueueManager
   // instance has been initialized. It has no other use relative to the rest of
@@ -61,9 +60,9 @@
   MessageQueueManager();
   ~MessageQueueManager();
 
-  void AddInternal(MessageQueue *message_queue);
-  void RemoveInternal(MessageQueue *message_queue);
-  void ClearInternal(MessageHandler *handler);
+  void AddInternal(MessageQueue* message_queue);
+  void RemoveInternal(MessageQueue* message_queue);
+  void ClearInternal(MessageHandler* handler);
   void ProcessAllMessageQueuesInternal();
 
   static MessageQueueManager* instance_;
@@ -89,9 +88,10 @@
 template <class T>
 class TypedMessageData : public MessageData {
  public:
-  explicit TypedMessageData(const T& data) : data_(data) { }
+  explicit TypedMessageData(const T& data) : data_(data) {}
   const T& data() const { return data_; }
   T& data() { return data_; }
+
  private:
   T data_;
 };
@@ -123,28 +123,30 @@
 template <class T>
 class ScopedRefMessageData : public MessageData {
  public:
-  explicit ScopedRefMessageData(T* data) : data_(data) { }
+  explicit ScopedRefMessageData(T* data) : data_(data) {}
   const scoped_refptr<T>& data() const { return data_; }
   scoped_refptr<T>& data() { return data_; }
+
  private:
   scoped_refptr<T> data_;
 };
 
-template<class T>
+template <class T>
 inline MessageData* WrapMessageData(const T& data) {
   return new TypedMessageData<T>(data);
 }
 
-template<class T>
+template <class T>
 inline const T& UseMessageData(MessageData* data) {
-  return static_cast< TypedMessageData<T>* >(data)->data();
+  return static_cast<TypedMessageData<T>*>(data)->data();
 }
 
-template<class T>
+template <class T>
 class DisposeData : public MessageData {
  public:
-  explicit DisposeData(T* data) : data_(data) { }
+  explicit DisposeData(T* data) : data_(data) {}
   virtual ~DisposeData() { delete data_; }
+
  private:
   T* data_;
 };
@@ -162,9 +164,9 @@
            (id == MQID_ANY || id == message_id);
   }
   Location posted_from;
-  MessageHandler *phandler;
+  MessageHandler* phandler;
   uint32_t message_id;
-  MessageData *pdata;
+  MessageData* pdata;
   int64_t ts_sensitive;
 };
 
@@ -181,9 +183,9 @@
                  const Message& msg)
       : cmsDelay_(delay), msTrigger_(trigger), num_(num), msg_(msg) {}
 
-  bool operator< (const DelayedMessage& dmsg) const {
-    return (dmsg.msTrigger_ < msTrigger_)
-           || ((dmsg.msTrigger_ == msTrigger_) && (dmsg.num_ < num_));
+  bool operator<(const DelayedMessage& dmsg) const {
+    return (dmsg.msTrigger_ < msTrigger_) ||
+           ((dmsg.msTrigger_ == msTrigger_) && (dmsg.num_ < num_));
   }
 
   int64_t cmsDelay_;  // for debugging
@@ -230,9 +232,10 @@
   //  1) A message is available (returns true)
   //  2) cmsWait seconds have elapsed (returns false)
   //  3) Stop() is called (returns false)
-  virtual bool Get(Message *pmsg, int cmsWait = kForever,
+  virtual bool Get(Message* pmsg,
+                   int cmsWait = kForever,
                    bool process_io = true);
-  virtual bool Peek(Message *pmsg, int cmsWait = 0);
+  virtual bool Peek(Message* pmsg, int cmsWait = 0);
   virtual void Post(const Location& posted_from,
                     MessageHandler* phandler,
                     uint32_t id = 0,
@@ -257,7 +260,7 @@
   virtual void Clear(MessageHandler* phandler,
                      uint32_t id = MQID_ANY,
                      MessageList* removed = nullptr);
-  virtual void Dispatch(Message *pmsg);
+  virtual void Dispatch(Message* pmsg);
   virtual void ReceiveSends();
 
   // Amount of time until the next message can be retrieved
@@ -270,7 +273,8 @@
   }
 
   // Internally posts a message which causes the doomed object to be deleted
-  template<class T> void Dispose(T* doomed) {
+  template <class T>
+  void Dispose(T* doomed) {
     if (doomed) {
       Post(RTC_FROM_HERE, nullptr, MQID_DISPOSE, new DisposeData<T>(doomed));
     }
diff --git a/rtc_base/messagequeue_unittest.cc b/rtc_base/messagequeue_unittest.cc
index 9e1ba63..1018a62 100644
--- a/rtc_base/messagequeue_unittest.cc
+++ b/rtc_base/messagequeue_unittest.cc
@@ -25,7 +25,7 @@
 
 using namespace rtc;
 
-class MessageQueueTest: public testing::Test, public MessageQueue {
+class MessageQueueTest : public testing::Test, public MessageQueue {
  public:
   MessageQueueTest() : MessageQueue(SocketServer::CreateDefault(), true) {}
   bool IsLocked_Worker() {
@@ -47,7 +47,7 @@
 
 struct DeletedLockChecker {
   DeletedLockChecker(MessageQueueTest* test, bool* was_locked, bool* deleted)
-      : test(test), was_locked(was_locked), deleted(deleted) { }
+      : test(test), was_locked(was_locked), deleted(deleted) {}
   ~DeletedLockChecker() {
     *deleted = true;
     *was_locked = test->IsLocked();
@@ -68,7 +68,7 @@
   q->PostAt(RTC_FROM_HERE, now - 1, nullptr, 2);
 
   Message msg;
-  for (size_t i=0; i<5; ++i) {
+  for (size_t i = 0; i < 5; ++i) {
     memset(&msg, 0, sizeof(msg));
     EXPECT_TRUE(q->Get(&msg, 0));
     EXPECT_EQ(i, msg.message_id);
@@ -100,7 +100,7 @@
 
 class DeletedMessageHandler : public MessageHandler {
  public:
-  explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) { }
+  explicit DeletedMessageHandler(bool* deleted) : deleted_(deleted) {}
   ~DeletedMessageHandler() override { *deleted_ = true; }
   void OnMessage(Message* msg) override {}
 
@@ -110,7 +110,7 @@
 
 TEST_F(MessageQueueTest, DiposeHandlerWithPostedMessagePending) {
   bool deleted = false;
-  DeletedMessageHandler *handler = new DeletedMessageHandler(&deleted);
+  DeletedMessageHandler* handler = new DeletedMessageHandler(&deleted);
   // First, post a dispose.
   Dispose(handler);
   // Now, post a message, which should *not* be returned by Get().
@@ -122,11 +122,14 @@
 
 struct UnwrapMainThreadScope {
   UnwrapMainThreadScope() : rewrap_(Thread::Current() != nullptr) {
-    if (rewrap_) ThreadManager::Instance()->UnwrapCurrentThread();
+    if (rewrap_)
+      ThreadManager::Instance()->UnwrapCurrentThread();
   }
   ~UnwrapMainThreadScope() {
-    if (rewrap_) ThreadManager::Instance()->WrapCurrentThread();
+    if (rewrap_)
+      ThreadManager::Instance()->WrapCurrentThread();
   }
+
  private:
   bool rewrap_;
 };
@@ -218,9 +221,7 @@
   MessageQueueManager::ProcessAllMessageQueues();
 }
 
-class RefCountedHandler
-  : public MessageHandler,
-    public rtc::RefCountInterface {
+class RefCountedHandler : public MessageHandler, public rtc::RefCountInterface {
  public:
   void OnMessage(Message* msg) override {}
 };
diff --git a/rtc_base/nat_unittest.cc b/rtc_base/nat_unittest.cc
index 68f0f1c..ee94427 100644
--- a/rtc_base/nat_unittest.cc
+++ b/rtc_base/nat_unittest.cc
@@ -12,6 +12,7 @@
 #include <memory>
 #include <string>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/asynctcpsocket.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/logging.h"
@@ -20,36 +21,38 @@
 #include "rtc_base/nethelpers.h"
 #include "rtc_base/network.h"
 #include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/testclient.h"
 #include "rtc_base/virtualsocketserver.h"
 
 using namespace rtc;
 
-bool CheckReceive(
-    TestClient* client, bool should_receive, const char* buf, size_t size) {
-  return (should_receive) ?
-      client->CheckNextPacket(buf, size, 0) :
-      client->CheckNoPacket();
+bool CheckReceive(TestClient* client,
+                  bool should_receive,
+                  const char* buf,
+                  size_t size) {
+  return (should_receive) ? client->CheckNextPacket(buf, size, 0)
+                          : client->CheckNoPacket();
 }
 
-TestClient* CreateTestClient(
-      SocketFactory* factory, const SocketAddress& local_addr) {
+TestClient* CreateTestClient(SocketFactory* factory,
+                             const SocketAddress& local_addr) {
   return new TestClient(
-      WrapUnique(AsyncUDPSocket::Create(factory, local_addr)));
+      absl::WrapUnique(AsyncUDPSocket::Create(factory, local_addr)));
 }
 
 TestClient* CreateTCPTestClient(AsyncSocket* socket) {
-  return new TestClient(MakeUnique<AsyncTCPSocket>(socket, false));
+  return new TestClient(absl::make_unique<AsyncTCPSocket>(socket, false));
 }
 
 // Tests that when sending from internal_addr to external_addrs through the
 // NAT type specified by nat_type, all external addrs receive the sent packet
 // and, if exp_same is true, all use the same mapped-address on the NAT.
-void TestSend(
-      SocketServer* internal, const SocketAddress& internal_addr,
-      SocketServer* external, const SocketAddress external_addrs[4],
-      NATType nat_type, bool exp_same) {
+void TestSend(SocketServer* internal,
+              const SocketAddress& internal_addr,
+              SocketServer* external,
+              const SocketAddress external_addrs[4],
+              NATType nat_type,
+              bool exp_same) {
   Thread th_int(internal);
   Thread th_ext(external);
 
@@ -57,9 +60,8 @@
   server_addr.SetPort(0);  // Auto-select a port
   NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr,
                                  external, external_addrs[0]);
-  NATSocketFactory* natsf = new NATSocketFactory(internal,
-                                                 nat->internal_udp_address(),
-                                                 nat->internal_tcp_address());
+  NATSocketFactory* natsf = new NATSocketFactory(
+      internal, nat->internal_udp_address(), nat->internal_tcp_address());
 
   TestClient* in = CreateTestClient(natsf, internal_addr);
   TestClient* out[4];
@@ -98,10 +100,13 @@
 
 // Tests that when sending from external_addrs to internal_addr, the packet
 // is delivered according to the specified filter_ip and filter_port rules.
-void TestRecv(
-      SocketServer* internal, const SocketAddress& internal_addr,
-      SocketServer* external, const SocketAddress external_addrs[4],
-      NATType nat_type, bool filter_ip, bool filter_port) {
+void TestRecv(SocketServer* internal,
+              const SocketAddress& internal_addr,
+              SocketServer* external,
+              const SocketAddress external_addrs[4],
+              NATType nat_type,
+              bool filter_ip,
+              bool filter_port) {
   Thread th_int(internal);
   Thread th_ext(external);
 
@@ -109,9 +114,8 @@
   server_addr.SetPort(0);  // Auto-select a port
   NATServer* nat = new NATServer(nat_type, internal, server_addr, server_addr,
                                  external, external_addrs[0]);
-  NATSocketFactory* natsf = new NATSocketFactory(internal,
-                                                 nat->internal_udp_address(),
-                                                 nat->internal_tcp_address());
+  NATSocketFactory* natsf = new NATSocketFactory(
+      internal, nat->internal_udp_address(), nat->internal_tcp_address());
 
   TestClient* in = CreateTestClient(natsf, internal_addr);
   TestClient* out[4];
@@ -148,31 +152,33 @@
 }
 
 // Tests that NATServer allocates bindings properly.
-void TestBindings(
-    SocketServer* internal, const SocketAddress& internal_addr,
-    SocketServer* external, const SocketAddress external_addrs[4]) {
-  TestSend(internal, internal_addr, external, external_addrs,
-           NAT_OPEN_CONE, true);
+void TestBindings(SocketServer* internal,
+                  const SocketAddress& internal_addr,
+                  SocketServer* external,
+                  const SocketAddress external_addrs[4]) {
+  TestSend(internal, internal_addr, external, external_addrs, NAT_OPEN_CONE,
+           true);
   TestSend(internal, internal_addr, external, external_addrs,
            NAT_ADDR_RESTRICTED, true);
   TestSend(internal, internal_addr, external, external_addrs,
            NAT_PORT_RESTRICTED, true);
-  TestSend(internal, internal_addr, external, external_addrs,
-           NAT_SYMMETRIC, false);
+  TestSend(internal, internal_addr, external, external_addrs, NAT_SYMMETRIC,
+           false);
 }
 
 // Tests that NATServer filters packets properly.
-void TestFilters(
-    SocketServer* internal, const SocketAddress& internal_addr,
-    SocketServer* external, const SocketAddress external_addrs[4]) {
-  TestRecv(internal, internal_addr, external, external_addrs,
-           NAT_OPEN_CONE, false, false);
+void TestFilters(SocketServer* internal,
+                 const SocketAddress& internal_addr,
+                 SocketServer* external,
+                 const SocketAddress external_addrs[4]) {
+  TestRecv(internal, internal_addr, external, external_addrs, NAT_OPEN_CONE,
+           false, false);
   TestRecv(internal, internal_addr, external, external_addrs,
            NAT_ADDR_RESTRICTED, true, false);
   TestRecv(internal, internal_addr, external, external_addrs,
            NAT_PORT_RESTRICTED, true, true);
-  TestRecv(internal, internal_addr, external, external_addrs,
-           NAT_SYMMETRIC, true, true);
+  TestRecv(internal, internal_addr, external, external_addrs, NAT_SYMMETRIC,
+           true, true);
 }
 
 bool TestConnectivity(const SocketAddress& src, const IPAddress& dst) {
@@ -224,7 +230,7 @@
   // Find an available IP with matching family. The test breaks if int_addr
   // can't talk to ip, so check for connectivity as well.
   for (std::vector<Network*>::iterator it = networks.begin();
-      it != networks.end(); ++it) {
+       it != networks.end(); ++it) {
     const IPAddress& ip = (*it)->GetBestIP();
     if (ip.family() == int_addr.family() && TestConnectivity(int_addr, ip)) {
       ext_addr2.SetIP(ip);
@@ -240,11 +246,8 @@
   RTC_LOG(LS_INFO) << "selected ip " << ext_addr2.ipaddr().ToString();
 
   SocketAddress ext_addrs[4] = {
-      SocketAddress(ext_addr1),
-      SocketAddress(ext_addr2),
-      SocketAddress(ext_addr1),
-      SocketAddress(ext_addr2)
-  };
+      SocketAddress(ext_addr1), SocketAddress(ext_addr2),
+      SocketAddress(ext_addr1), SocketAddress(ext_addr2)};
 
   std::unique_ptr<PhysicalSocketServer> int_pss(new PhysicalSocketServer());
   std::unique_ptr<PhysicalSocketServer> ext_pss(new PhysicalSocketServer());
@@ -328,16 +331,13 @@
     ext_thread_->Start();
   }
 
-  void OnConnectEvent(AsyncSocket* socket) {
-    connected_ = true;
-  }
+  void OnConnectEvent(AsyncSocket* socket) { connected_ = true; }
 
   void OnAcceptEvent(AsyncSocket* socket) {
     accepted_.reset(server_->Accept(nullptr));
   }
 
-  void OnCloseEvent(AsyncSocket* socket, int error) {
-  }
+  void OnCloseEvent(AsyncSocket* socket, int error) {}
 
   void ConnectEvents() {
     server_->SignalReadEvent.connect(this, &NatTcpTest::OnAcceptEvent);
@@ -359,11 +359,11 @@
 };
 
 TEST_F(NatTcpTest, DISABLED_TestConnectOut) {
-  server_.reset(ext_vss_->CreateAsyncSocket(SOCK_STREAM));
+  server_.reset(ext_vss_->CreateAsyncSocket(AF_INET, SOCK_STREAM));
   server_->Bind(ext_addr_);
   server_->Listen(5);
 
-  client_.reset(natsf_->CreateAsyncSocket(SOCK_STREAM));
+  client_.reset(natsf_->CreateAsyncSocket(AF_INET, SOCK_STREAM));
   EXPECT_GE(0, client_->Bind(int_addr_));
   EXPECT_GE(0, client_->Connect(server_->GetLocalAddress()));
 
diff --git a/rtc_base/natserver.cc b/rtc_base/natserver.cc
index bf983fe..8119376 100644
--- a/rtc_base/natserver.cc
+++ b/rtc_base/natserver.cc
@@ -18,8 +18,7 @@
 
 namespace rtc {
 
-RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {
-}
+RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {}
 
 size_t RouteCmp::operator()(const SocketAddressPair& r) const {
   size_t h = r.source().Hash();
@@ -28,8 +27,8 @@
   return h;
 }
 
-bool RouteCmp::operator()(
-      const SocketAddressPair& r1, const SocketAddressPair& r2) const {
+bool RouteCmp::operator()(const SocketAddressPair& r1,
+                          const SocketAddressPair& r2) const {
   if (r1.source() < r2.source())
     return true;
   if (r2.source() < r1.source())
@@ -42,8 +41,7 @@
 }
 
 AddrCmp::AddrCmp(NAT* nat)
-    : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {
-}
+    : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {}
 
 size_t AddrCmp::operator()(const SocketAddress& a) const {
   size_t h = 0;
@@ -54,8 +52,8 @@
   return h;
 }
 
-bool AddrCmp::operator()(
-      const SocketAddress& a1, const SocketAddress& a2) const {
+bool AddrCmp::operator()(const SocketAddress& a1,
+                         const SocketAddress& a2) const {
   if (use_ip && (a1.ipaddr() < a2.ipaddr()))
     return true;
   if (use_ip && (a2.ipaddr() < a1.ipaddr()))
@@ -109,15 +107,15 @@
       SignalReadEvent(this);
     }
   }
-
 };
 
 class NATProxyServer : public ProxyServer {
  public:
-  NATProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr,
-                 SocketFactory* ext_factory, const SocketAddress& ext_ip)
-      : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {
-  }
+  NATProxyServer(SocketFactory* int_factory,
+                 const SocketAddress& int_addr,
+                 SocketFactory* ext_factory,
+                 const SocketAddress& ext_ip)
+      : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {}
 
  protected:
   AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) override {
@@ -125,27 +123,27 @@
   }
 };
 
-NATServer::NATServer(
-    NATType type, SocketFactory* internal,
-    const SocketAddress& internal_udp_addr,
-    const SocketAddress& internal_tcp_addr,
-    SocketFactory* external, const SocketAddress& external_ip)
+NATServer::NATServer(NATType type,
+                     SocketFactory* internal,
+                     const SocketAddress& internal_udp_addr,
+                     const SocketAddress& internal_tcp_addr,
+                     SocketFactory* external,
+                     const SocketAddress& external_ip)
     : external_(external), external_ip_(external_ip.ipaddr(), 0) {
   nat_ = NAT::Create(type);
 
   udp_server_socket_ = AsyncUDPSocket::Create(internal, internal_udp_addr);
   udp_server_socket_->SignalReadPacket.connect(this,
                                                &NATServer::OnInternalUDPPacket);
-  tcp_proxy_server_ = new NATProxyServer(internal, internal_tcp_addr, external,
-                                         external_ip);
+  tcp_proxy_server_ =
+      new NATProxyServer(internal, internal_tcp_addr, external, external_ip);
 
   int_map_ = new InternalMap(RouteCmp(nat_));
   ext_map_ = new ExternalMap();
 }
 
 NATServer::~NATServer() {
-  for (InternalMap::iterator iter = int_map_->begin();
-       iter != int_map_->end();
+  for (InternalMap::iterator iter = int_map_->begin(); iter != int_map_->end();
        iter++)
     delete iter->second;
 
@@ -156,9 +154,11 @@
   delete ext_map_;
 }
 
-void NATServer::OnInternalUDPPacket(
-    AsyncPacketSocket* socket, const char* buf, size_t size,
-    const SocketAddress& addr, const PacketTime& packet_time) {
+void NATServer::OnInternalUDPPacket(AsyncPacketSocket* socket,
+                                    const char* buf,
+                                    size_t size,
+                                    const SocketAddress& addr,
+                                    const PacketTime& packet_time) {
   // Read the intended destination from the wire.
   SocketAddress dest_addr;
   size_t length = UnpackAddressFromNAT(buf, size, &dest_addr);
@@ -180,9 +180,11 @@
   iter->second->socket->SendTo(buf + length, size - length, dest_addr, options);
 }
 
-void NATServer::OnExternalUDPPacket(
-    AsyncPacketSocket* socket, const char* buf, size_t size,
-    const SocketAddress& remote_addr, const PacketTime& packet_time) {
+void NATServer::OnExternalUDPPacket(AsyncPacketSocket* socket,
+                                    const char* buf,
+                                    size_t size,
+                                    const SocketAddress& remote_addr,
+                                    const PacketTime& packet_time) {
   SocketAddress local_addr = socket->GetLocalAddress();
 
   // Find the translation for this addresses.
@@ -199,9 +201,8 @@
   // Forward this packet to the internal address.
   // First prepend the address in a quasi-STUN format.
   std::unique_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
-  size_t addrlength = PackAddressForNAT(real_buf.get(),
-                                        size + kNATEncodedIPv6AddressSize,
-                                        remote_addr);
+  size_t addrlength = PackAddressForNAT(
+      real_buf.get(), size + kNATEncodedIPv6AddressSize, remote_addr);
   // Copy the data part after the address.
   rtc::PacketOptions options;
   memcpy(real_buf.get() + addrlength, buf, size);
@@ -228,8 +229,9 @@
   return entry->WhitelistContains(ext_addr);
 }
 
-NATServer::TransEntry::TransEntry(
-    const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat)
+NATServer::TransEntry::TransEntry(const SocketAddressPair& r,
+                                  AsyncUDPSocket* s,
+                                  NAT* nat)
     : route(r), socket(s) {
   whitelist = new AddressSet(AddrCmp(nat));
 }
diff --git a/rtc_base/natserver.h b/rtc_base/natserver.h
index a7b4d62..f4cabcf 100644
--- a/rtc_base/natserver.h
+++ b/rtc_base/natserver.h
@@ -30,8 +30,8 @@
 struct RouteCmp {
   explicit RouteCmp(NAT* nat);
   size_t operator()(const SocketAddressPair& r) const;
-  bool operator()(
-      const SocketAddressPair& r1, const SocketAddressPair& r2) const;
+  bool operator()(const SocketAddressPair& r1,
+                  const SocketAddressPair& r2) const;
 
   bool symmetric;
 };
@@ -60,11 +60,12 @@
 
 class NATServer : public sigslot::has_slots<> {
  public:
-  NATServer(
-      NATType type, SocketFactory* internal,
-      const SocketAddress& internal_udp_addr,
-      const SocketAddress& internal_tcp_addr,
-      SocketFactory* external, const SocketAddress& external_ip);
+  NATServer(NATType type,
+            SocketFactory* internal,
+            const SocketAddress& internal_udp_addr,
+            const SocketAddress& internal_tcp_addr,
+            SocketFactory* external,
+            const SocketAddress& external_ip);
   ~NATServer() override;
 
   SocketAddress internal_udp_address() const {
@@ -76,11 +77,15 @@
   }
 
   // Packets received on one of the networks.
-  void OnInternalUDPPacket(AsyncPacketSocket* socket, const char* buf,
-                           size_t size, const SocketAddress& addr,
+  void OnInternalUDPPacket(AsyncPacketSocket* socket,
+                           const char* buf,
+                           size_t size,
+                           const SocketAddress& addr,
                            const PacketTime& packet_time);
-  void OnExternalUDPPacket(AsyncPacketSocket* socket, const char* buf,
-                           size_t size, const SocketAddress& remote_addr,
+  void OnExternalUDPPacket(AsyncPacketSocket* socket,
+                           const char* buf,
+                           size_t size,
+                           const SocketAddress& remote_addr,
                            const PacketTime& packet_time);
 
  private:
diff --git a/rtc_base/natsocketfactory.cc b/rtc_base/natsocketfactory.cc
index dd4c030..a707ce0 100644
--- a/rtc_base/natsocketfactory.cc
+++ b/rtc_base/natsocketfactory.cc
@@ -21,7 +21,8 @@
 // Packs the given socketaddress into the buffer in buf, in the quasi-STUN
 // format that the natserver uses.
 // Returns 0 if an invalid address is passed.
-size_t PackAddressForNAT(char* buf, size_t buf_size,
+size_t PackAddressForNAT(char* buf,
+                         size_t buf_size,
                          const SocketAddress& remote_addr) {
   const IPAddress& ip = remote_addr.ipaddr();
   int family = ip.family();
@@ -46,7 +47,8 @@
 // Decodes the remote address from a packet that has been encoded with the nat's
 // quasi-STUN format. Returns the length of the address (i.e., the offset into
 // data where the original packet starts).
-size_t UnpackAddressFromNAT(const char* buf, size_t buf_size,
+size_t UnpackAddressFromNAT(const char* buf,
+                            size_t buf_size,
                             SocketAddress* remote_addr) {
   RTC_DCHECK(buf_size >= 8);
   RTC_DCHECK(buf[0] == 0);
@@ -66,7 +68,6 @@
   return 0U;
 }
 
-
 // NATSocket
 class NATSocket : public AsyncSocket, public sigslot::has_slots<> {
  public:
@@ -138,9 +139,8 @@
     }
     // This array will be too large for IPv4 packets, but only by 12 bytes.
     std::unique_ptr<char[]> buf(new char[size + kNATEncodedIPv6AddressSize]);
-    size_t addrlength = PackAddressForNAT(buf.get(),
-                                          size + kNATEncodedIPv6AddressSize,
-                                          addr);
+    size_t addrlength =
+        PackAddressForNAT(buf.get(), size + kNATEncodedIPv6AddressSize, addr);
     size_t encoded_size = size + addrlength;
     memcpy(buf.get() + addrlength, data, size);
     int result = socket_->SendTo(buf.get(), encoded_size, server_addr_);
@@ -331,28 +331,23 @@
 NATSocketFactory::NATSocketFactory(SocketFactory* factory,
                                    const SocketAddress& nat_udp_addr,
                                    const SocketAddress& nat_tcp_addr)
-    : factory_(factory), nat_udp_addr_(nat_udp_addr),
-      nat_tcp_addr_(nat_tcp_addr) {
-}
-
-Socket* NATSocketFactory::CreateSocket(int type) {
-  return CreateSocket(AF_INET, type);
-}
+    : factory_(factory),
+      nat_udp_addr_(nat_udp_addr),
+      nat_tcp_addr_(nat_tcp_addr) {}
 
 Socket* NATSocketFactory::CreateSocket(int family, int type) {
   return new NATSocket(this, family, type);
 }
 
-AsyncSocket* NATSocketFactory::CreateAsyncSocket(int type) {
-  return CreateAsyncSocket(AF_INET, type);
-}
-
 AsyncSocket* NATSocketFactory::CreateAsyncSocket(int family, int type) {
   return new NATSocket(this, family, type);
 }
 
-AsyncSocket* NATSocketFactory::CreateInternalSocket(int family, int type,
-    const SocketAddress& local_addr, SocketAddress* nat_addr) {
+AsyncSocket* NATSocketFactory::CreateInternalSocket(
+    int family,
+    int type,
+    const SocketAddress& local_addr,
+    SocketAddress* nat_addr) {
   if (type == SOCK_STREAM) {
     *nat_addr = nat_tcp_addr_;
   } else {
@@ -371,7 +366,9 @@
 }
 
 NATSocketServer::Translator* NATSocketServer::AddTranslator(
-    const SocketAddress& ext_ip, const SocketAddress& int_ip, NATType type) {
+    const SocketAddress& ext_ip,
+    const SocketAddress& int_ip,
+    NATType type) {
   // Fail if a translator already exists with this extternal address.
   if (nats_.Get(ext_ip))
     return nullptr;
@@ -379,23 +376,14 @@
   return nats_.Add(ext_ip, new Translator(this, type, int_ip, server_, ext_ip));
 }
 
-void NATSocketServer::RemoveTranslator(
-    const SocketAddress& ext_ip) {
+void NATSocketServer::RemoveTranslator(const SocketAddress& ext_ip) {
   nats_.Remove(ext_ip);
 }
 
-Socket* NATSocketServer::CreateSocket(int type) {
-  return CreateSocket(AF_INET, type);
-}
-
 Socket* NATSocketServer::CreateSocket(int family, int type) {
   return new NATSocket(this, family, type);
 }
 
-AsyncSocket* NATSocketServer::CreateAsyncSocket(int type) {
-  return CreateAsyncSocket(AF_INET, type);
-}
-
 AsyncSocket* NATSocketServer::CreateAsyncSocket(int family, int type) {
   return new NATSocket(this, family, type);
 }
@@ -413,14 +401,17 @@
   server_->WakeUp();
 }
 
-AsyncSocket* NATSocketServer::CreateInternalSocket(int family, int type,
-    const SocketAddress& local_addr, SocketAddress* nat_addr) {
+AsyncSocket* NATSocketServer::CreateInternalSocket(
+    int family,
+    int type,
+    const SocketAddress& local_addr,
+    SocketAddress* nat_addr) {
   AsyncSocket* socket = nullptr;
   Translator* nat = nats_.FindClient(local_addr);
   if (nat) {
     socket = nat->internal_factory()->CreateAsyncSocket(family, type);
-    *nat_addr = (type == SOCK_STREAM) ?
-        nat->internal_tcp_address() : nat->internal_udp_address();
+    *nat_addr = (type == SOCK_STREAM) ? nat->internal_tcp_address()
+                                      : nat->internal_udp_address();
   } else {
     socket = server_->CreateAsyncSocket(family, type);
   }
@@ -428,9 +419,11 @@
 }
 
 // NATSocketServer::Translator
-NATSocketServer::Translator::Translator(
-    NATSocketServer* server, NATType type, const SocketAddress& int_ip,
-    SocketFactory* ext_factory, const SocketAddress& ext_ip)
+NATSocketServer::Translator::Translator(NATSocketServer* server,
+                                        NATType type,
+                                        const SocketAddress& int_ip,
+                                        SocketFactory* ext_factory,
+                                        const SocketAddress& ext_ip)
     : server_(server) {
   // Create a new private network, and a NATServer running on the private
   // network that bridges to the external network. Also tell the private
@@ -450,7 +443,9 @@
 }
 
 NATSocketServer::Translator* NATSocketServer::Translator::AddTranslator(
-    const SocketAddress& ext_ip, const SocketAddress& int_ip, NATType type) {
+    const SocketAddress& ext_ip,
+    const SocketAddress& int_ip,
+    NATType type) {
   // Fail if a translator already exists with this extternal address.
   if (nats_.Get(ext_ip))
     return nullptr;
@@ -465,8 +460,7 @@
   RemoveClient(ext_ip);
 }
 
-bool NATSocketServer::Translator::AddClient(
-    const SocketAddress& int_ip) {
+bool NATSocketServer::Translator::AddClient(const SocketAddress& int_ip) {
   // Fail if a client already exists with this internal address.
   if (clients_.find(int_ip) != clients_.end())
     return false;
@@ -475,8 +469,7 @@
   return true;
 }
 
-void NATSocketServer::Translator::RemoveClient(
-    const SocketAddress& int_ip) {
+void NATSocketServer::Translator::RemoveClient(const SocketAddress& int_ip) {
   std::set<SocketAddress>::iterator it = clients_.find(int_ip);
   if (it != clients_.end()) {
     clients_.erase(it);
@@ -486,8 +479,8 @@
 NATSocketServer::Translator* NATSocketServer::Translator::FindClient(
     const SocketAddress& int_ip) {
   // See if we have the requested IP, or any of our children do.
-  return (clients_.find(int_ip) != clients_.end()) ?
-      this : nats_.FindClient(int_ip);
+  return (clients_.find(int_ip) != clients_.end()) ? this
+                                                   : nats_.FindClient(int_ip);
 }
 
 // NATSocketServer::TranslatorMap
@@ -504,13 +497,13 @@
 }
 
 NATSocketServer::Translator* NATSocketServer::TranslatorMap::Add(
-    const SocketAddress& ext_ip, Translator* nat) {
+    const SocketAddress& ext_ip,
+    Translator* nat) {
   (*this)[ext_ip] = nat;
   return nat;
 }
 
-void NATSocketServer::TranslatorMap::Remove(
-    const SocketAddress& ext_ip) {
+void NATSocketServer::TranslatorMap::Remove(const SocketAddress& ext_ip) {
   TranslatorMap::iterator it = find(ext_ip);
   if (it != end()) {
     delete it->second;
diff --git a/rtc_base/natsocketfactory.h b/rtc_base/natsocketfactory.h
index 319545c..97961d4 100644
--- a/rtc_base/natsocketfactory.h
+++ b/rtc_base/natsocketfactory.h
@@ -11,10 +11,10 @@
 #ifndef RTC_BASE_NATSOCKETFACTORY_H_
 #define RTC_BASE_NATSOCKETFACTORY_H_
 
-#include <string>
 #include <map>
 #include <memory>
 #include <set>
+#include <string>
 
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/natserver.h"
@@ -30,8 +30,10 @@
 class NATInternalSocketFactory {
  public:
   virtual ~NATInternalSocketFactory() {}
-  virtual AsyncSocket* CreateInternalSocket(int family, int type,
-      const SocketAddress& local_addr, SocketAddress* nat_addr) = 0;
+  virtual AsyncSocket* CreateInternalSocket(int family,
+                                            int type,
+                                            const SocketAddress& local_addr,
+                                            SocketAddress* nat_addr) = 0;
 };
 
 // Creates sockets that will send all traffic through a NAT, using an existing
@@ -39,13 +41,12 @@
 // from a socket factory, given to the constructor.
 class NATSocketFactory : public SocketFactory, public NATInternalSocketFactory {
  public:
-  NATSocketFactory(SocketFactory* factory, const SocketAddress& nat_udp_addr,
+  NATSocketFactory(SocketFactory* factory,
+                   const SocketAddress& nat_udp_addr,
                    const SocketAddress& nat_tcp_addr);
 
   // SocketFactory implementation
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
   // NATInternalSocketFactory implementation
@@ -92,8 +93,10 @@
   // a specific NAT
   class Translator {
    public:
-    Translator(NATSocketServer* server, NATType type,
-               const SocketAddress& int_addr, SocketFactory* ext_factory,
+    Translator(NATSocketServer* server,
+               NATType type,
+               const SocketAddress& int_addr,
+               SocketFactory* ext_factory,
                const SocketAddress& ext_addr);
     ~Translator();
 
@@ -107,7 +110,8 @@
 
     Translator* GetTranslator(const SocketAddress& ext_ip);
     Translator* AddTranslator(const SocketAddress& ext_ip,
-                              const SocketAddress& int_ip, NATType type);
+                              const SocketAddress& int_ip,
+                              NATType type);
     void RemoveTranslator(const SocketAddress& ext_ip);
 
     bool AddClient(const SocketAddress& int_ip);
@@ -131,14 +135,12 @@
 
   Translator* GetTranslator(const SocketAddress& ext_ip);
   Translator* AddTranslator(const SocketAddress& ext_ip,
-                            const SocketAddress& int_ip, NATType type);
+                            const SocketAddress& int_ip,
+                            NATType type);
   void RemoveTranslator(const SocketAddress& ext_ip);
 
   // SocketServer implementation
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
   void SetMessageQueue(MessageQueue* queue) override;
@@ -159,9 +161,11 @@
 };
 
 // Free-standing NAT helper functions.
-size_t PackAddressForNAT(char* buf, size_t buf_size,
+size_t PackAddressForNAT(char* buf,
+                         size_t buf_size,
                          const SocketAddress& remote_addr);
-size_t UnpackAddressFromNAT(const char* buf, size_t buf_size,
+size_t UnpackAddressFromNAT(const char* buf,
+                            size_t buf_size,
                             SocketAddress* remote_addr);
 }  // namespace rtc
 
diff --git a/rtc_base/nattypes.cc b/rtc_base/nattypes.cc
index 29936ad..a7af57d 100644
--- a/rtc_base/nattypes.cc
+++ b/rtc_base/nattypes.cc
@@ -15,31 +15,31 @@
 namespace rtc {
 
 class SymmetricNAT : public NAT {
-public:
- bool IsSymmetric() override { return true; }
- bool FiltersIP() override { return true; }
- bool FiltersPort() override { return true; }
+ public:
+  bool IsSymmetric() override { return true; }
+  bool FiltersIP() override { return true; }
+  bool FiltersPort() override { return true; }
 };
 
 class OpenConeNAT : public NAT {
-public:
- bool IsSymmetric() override { return false; }
- bool FiltersIP() override { return false; }
- bool FiltersPort() override { return false; }
+ public:
+  bool IsSymmetric() override { return false; }
+  bool FiltersIP() override { return false; }
+  bool FiltersPort() override { return false; }
 };
 
 class AddressRestrictedNAT : public NAT {
-public:
- bool IsSymmetric() override { return false; }
- bool FiltersIP() override { return true; }
- bool FiltersPort() override { return false; }
+ public:
+  bool IsSymmetric() override { return false; }
+  bool FiltersIP() override { return true; }
+  bool FiltersPort() override { return false; }
 };
 
 class PortRestrictedNAT : public NAT {
-public:
- bool IsSymmetric() override { return false; }
- bool FiltersIP() override { return true; }
- bool FiltersPort() override { return true; }
+ public:
+  bool IsSymmetric() override { return false; }
+  bool FiltersIP() override { return true; }
+  bool FiltersPort() override { return true; }
 };
 
 NAT* NAT::Create(NATType type) {
@@ -58,4 +58,4 @@
   }
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/nattypes.h b/rtc_base/nattypes.h
index 64b36d3..1d816ac 100644
--- a/rtc_base/nattypes.h
+++ b/rtc_base/nattypes.h
@@ -23,8 +23,8 @@
 
 // Implements the rules for each specific type of NAT.
 class NAT {
-public:
-  virtual ~NAT() { }
+ public:
+  virtual ~NAT() {}
 
   // Determines whether this NAT uses both source and destination address when
   // checking whether a mapping already exists.
@@ -42,6 +42,6 @@
   static NAT* Create(NATType type);
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_NATTYPES_H_
+#endif  // RTC_BASE_NATTYPES_H_
diff --git a/rtc_base/nethelpers.cc b/rtc_base/nethelpers.cc
index c41e124..b1221c3 100644
--- a/rtc_base/nethelpers.cc
+++ b/rtc_base/nethelpers.cc
@@ -32,13 +32,14 @@
 
 namespace rtc {
 
-int ResolveHostname(const std::string& hostname, int family,
+int ResolveHostname(const std::string& hostname,
+                    int family,
                     std::vector<IPAddress>* addresses) {
 #ifdef __native_client__
   RTC_NOTREACHED();
   RTC_LOG(LS_WARNING) << "ResolveHostname() is not implemented for NaCl";
   return -1;
-#else  // __native_client__
+#else   // __native_client__
   if (!addresses) {
     return -1;
   }
@@ -83,8 +84,7 @@
 }
 
 // AsyncResolver
-AsyncResolver::AsyncResolver()
-    : SignalThread(), error_(-1) {}
+AsyncResolver::AsyncResolver() : SignalThread(), error_(-1) {}
 
 AsyncResolver::~AsyncResolver() = default;
 
@@ -117,15 +117,15 @@
 }
 
 void AsyncResolver::DoWork() {
-  error_ = ResolveHostname(addr_.hostname().c_str(), addr_.family(),
-                           &addresses_);
+  error_ =
+      ResolveHostname(addr_.hostname().c_str(), addr_.family(), &addresses_);
 }
 
 void AsyncResolver::OnWorkDone() {
   SignalDone(this);
 }
 
-const char* inet_ntop(int af, const void *src, char* dst, socklen_t size) {
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
 #if defined(WEBRTC_WIN)
   return win32_inet_ntop(af, src, dst, size);
 #else
@@ -133,7 +133,7 @@
 #endif
 }
 
-int inet_pton(int af, const char* src, void *dst) {
+int inet_pton(int af, const char* src, void* dst) {
 #if defined(WEBRTC_WIN)
   return win32_inet_pton(af, src, dst);
 #else
@@ -182,8 +182,8 @@
   do {
     protocols.reset(new char[protbuff_size]);
     protocol_infos = reinterpret_cast<LPWSAPROTOCOL_INFOW>(protocols.get());
-    ret = WSCEnumProtocols(requested_protocols, protocol_infos,
-                           &protbuff_size, &err);
+    ret = WSCEnumProtocols(requested_protocols, protocol_infos, &protbuff_size,
+                           &err);
   } while (ret == SOCKET_ERROR && err == WSAENOBUFS);
 
   if (ret == SOCKET_ERROR) {
diff --git a/rtc_base/nethelpers.h b/rtc_base/nethelpers.h
index e118b27..de14a06 100644
--- a/rtc_base/nethelpers.h
+++ b/rtc_base/nethelpers.h
@@ -27,8 +27,6 @@
 
 namespace rtc {
 
-class AsyncResolverTest;
-
 // AsyncResolver will perform async DNS resolution, signaling the result on
 // the SignalDone from AsyncResolverInterface when the operation completes.
 class AsyncResolver : public SignalThread, public AsyncResolverInterface {
@@ -56,8 +54,8 @@
 
 // rtc namespaced wrappers for inet_ntop and inet_pton so we can avoid
 // the windows-native versions of these.
-const char* inet_ntop(int af, const void *src, char* dst, socklen_t size);
-int inet_pton(int af, const char* src, void *dst);
+const char* inet_ntop(int af, const void* src, char* dst, socklen_t size);
+int inet_pton(int af, const char* src, void* dst);
 
 bool HasIPv4Enabled();
 bool HasIPv6Enabled();
diff --git a/rtc_base/network.cc b/rtc_base/network.cc
index 6daa7c3..0f42d6f 100644
--- a/rtc_base/network.cc
+++ b/rtc_base/network.cc
@@ -23,8 +23,8 @@
 #endif  // WEBRTC_POSIX
 
 #if defined(WEBRTC_WIN)
-#include "rtc_base/win32.h"
 #include <iphlpapi.h>
+#include "rtc_base/win32.h"
 #elif !defined(__native_client__)
 #include "rtc_base/ifaddrs_converter.h"
 #endif
@@ -40,6 +40,7 @@
 #include "rtc_base/socket.h"  // includes something that makes windows happy
 #include "rtc_base/stream.h"
 #include "rtc_base/stringencode.h"
+#include "rtc_base/stringutils.h"
 #include "rtc_base/thread.h"
 
 namespace rtc {
@@ -93,6 +94,7 @@
 
 std::string AdapterTypeToString(AdapterType type) {
   switch (type) {
+    case ADAPTER_TYPE_ANY:
     case ADAPTER_TYPE_UNKNOWN:
       return "Unknown";
     case ADAPTER_TYPE_ETHERNET:
@@ -120,6 +122,17 @@
       return kNetworkCostLow;
     case rtc::ADAPTER_TYPE_CELLULAR:
       return kNetworkCostHigh;
+    case rtc::ADAPTER_TYPE_ANY:
+      // Candidates gathered from the any-address/wildcard ports, as backups,
+      // are given the maximum cost so that if there are other candidates with
+      // known interface types, we would not select candidate pairs using these
+      // backup candidates if other selection criteria with higher precedence
+      // (network conditions over the route) are the same. Note that setting the
+      // cost to kNetworkCostUnknown would be problematic since
+      // ADAPTER_TYPE_CELLULAR would then have a higher cost. See
+      // P2PTransportChannel::SortConnectionsAndUpdateState for how we rank and
+      // select candidate pairs, where the network cost is among the criteria.
+      return kNetworkCostMax;
     case rtc::ADAPTER_TYPE_VPN:
       // The cost of a VPN should be computed using its underlying network type.
       RTC_NOTREACHED();
@@ -164,26 +177,53 @@
 const char kPublicIPv6Host[] = "2001:4860:4860::8888";
 const int kPublicPort = 53;  // DNS port.
 
-std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
+std::string MakeNetworkKey(const std::string& name,
+                           const IPAddress& prefix,
                            int prefix_length) {
   std::ostringstream ost;
   ost << name << "%" << prefix.ToString() << "/" << prefix_length;
   return ost.str();
 }
+// Test if the network name matches the type<number> pattern, e.g. eth0. The
+// matching is case-sensitive.
+bool MatchTypeNameWithIndexPattern(const std::string& network_name,
+                                   const std::string& type_name) {
+  if (network_name.find(type_name) != 0) {
+    return false;
+  }
+  return std::find_if(network_name.begin() + type_name.size(),
+                      network_name.end(),
+                      [](char c) { return !isdigit(c); }) == network_name.end();
+}
 
+// A cautious note that this method may not provide an accurate adapter type
+// based on the string matching. Incorrect type of adapters can affect the
+// result of the downstream network filtering, see e.g.
+// BasicPortAllocatorSession::GetNetworks when
+// PORTALLOCATOR_DISABLE_COSTLY_NETWORKS is turned on.
 AdapterType GetAdapterTypeFromName(const char* network_name) {
-  if (strncmp(network_name, "ipsec", 5) == 0 ||
-      strncmp(network_name, "tun", 3) == 0 ||
-      strncmp(network_name, "utun", 4) == 0 ||
-      strncmp(network_name, "tap", 3) == 0) {
+  if (MatchTypeNameWithIndexPattern(network_name, "lo")) {
+    // Note that we have a more robust way to determine if a network interface
+    // is a loopback interface by checking the flag IFF_LOOPBACK in ifa_flags of
+    // an ifaddr struct. See ConvertIfAddrs in this file.
+    return ADAPTER_TYPE_LOOPBACK;
+  }
+  if (MatchTypeNameWithIndexPattern(network_name, "eth")) {
+    return ADAPTER_TYPE_ETHERNET;
+  }
+
+  if (MatchTypeNameWithIndexPattern(network_name, "ipsec") ||
+      MatchTypeNameWithIndexPattern(network_name, "tun") ||
+      MatchTypeNameWithIndexPattern(network_name, "utun") ||
+      MatchTypeNameWithIndexPattern(network_name, "tap")) {
     return ADAPTER_TYPE_VPN;
   }
 #if defined(WEBRTC_IOS)
   // Cell networks are pdp_ipN on iOS.
-  if (strncmp(network_name, "pdp_ip", 6) == 0) {
+  if (MatchTypeNameWithIndexPattern(network_name, "pdp_ip")) {
     return ADAPTER_TYPE_CELLULAR;
   }
-  if (strncmp(network_name, "en", 2) == 0) {
+  if (MatchTypeNameWithIndexPattern(network_name, "en")) {
     // This may not be most accurate because sometimes Ethernet interface
     // name also starts with "en" but it is better than showing it as
     // "unknown" type.
@@ -191,11 +231,13 @@
     return ADAPTER_TYPE_WIFI;
   }
 #elif defined(WEBRTC_ANDROID)
-  if (strncmp(network_name, "rmnet", 5) == 0 ||
-      strncmp(network_name, "v4-rmnet", 8) == 0) {
+  if (MatchTypeNameWithIndexPattern(network_name, "rmnet") ||
+      MatchTypeNameWithIndexPattern(network_name, "rmnet_data") ||
+      MatchTypeNameWithIndexPattern(network_name, "v4-rmnet") ||
+      MatchTypeNameWithIndexPattern(network_name, "v4-rmnet_data")) {
     return ADAPTER_TYPE_CELLULAR;
   }
-  if (strncmp(network_name, "wlan", 4) == 0) {
+  if (MatchTypeNameWithIndexPattern(network_name, "wlan")) {
     return ADAPTER_TYPE_WIFI;
   }
 #endif
@@ -203,11 +245,9 @@
   return ADAPTER_TYPE_UNKNOWN;
 }
 
-NetworkManager::NetworkManager() {
-}
+NetworkManager::NetworkManager() {}
 
-NetworkManager::~NetworkManager() {
-}
+NetworkManager::~NetworkManager() {}
 
 NetworkManager::EnumerationPermission NetworkManager::enumeration_permission()
     const {
@@ -220,8 +260,7 @@
 
 NetworkManagerBase::NetworkManagerBase()
     : enumeration_permission_(NetworkManager::ENUMERATION_ALLOWED),
-      ipv6_enabled_(true) {
-}
+      ipv6_enabled_(true) {}
 
 NetworkManagerBase::~NetworkManagerBase() {
   for (const auto& kv : networks_map_) {
@@ -238,7 +277,7 @@
   if (!ipv4_any_address_network_) {
     const rtc::IPAddress ipv4_any_address(INADDR_ANY);
     ipv4_any_address_network_.reset(
-        new rtc::Network("any", "any", ipv4_any_address, 0));
+        new rtc::Network("any", "any", ipv4_any_address, 0, ADAPTER_TYPE_ANY));
     ipv4_any_address_network_->set_default_local_address_provider(this);
     ipv4_any_address_network_->AddIP(ipv4_any_address);
   }
@@ -247,8 +286,8 @@
   if (ipv6_enabled()) {
     if (!ipv6_any_address_network_) {
       const rtc::IPAddress ipv6_any_address(in6addr_any);
-      ipv6_any_address_network_.reset(
-          new rtc::Network("any", "any", ipv6_any_address, 0));
+      ipv6_any_address_network_.reset(new rtc::Network(
+          "any", "any", ipv6_any_address, 0, ADAPTER_TYPE_ANY));
       ipv6_any_address_network_->set_default_local_address_provider(this);
       ipv6_any_address_network_->AddIP(ipv6_any_address);
     }
@@ -279,8 +318,7 @@
   // First, build a set of network-keys to the ipaddresses.
   for (Network* network : list) {
     bool might_add_to_merged_list = false;
-    std::string key = MakeNetworkKey(network->name(),
-                                     network->prefix(),
+    std::string key = MakeNetworkKey(network->name(), network->prefix(),
                                      network->prefix_length());
     if (consolidated_address_list.find(key) ==
         consolidated_address_list.end()) {
@@ -431,8 +469,7 @@
       start_count_(0),
       ignore_non_default_routes_(false) {}
 
-BasicNetworkManager::~BasicNetworkManager() {
-}
+BasicNetworkManager::~BasicNetworkManager() {}
 
 void BasicNetworkManager::OnNetworksChanged() {
   RTC_LOG(LS_INFO) << "Network change was observed";
@@ -514,8 +551,8 @@
     }
     int prefix_length = CountIPMaskBits(mask);
     prefix = TruncateIP(ip, prefix_length);
-    std::string key = MakeNetworkKey(std::string(cursor->ifa_name),
-                                     prefix, prefix_length);
+    std::string key =
+        MakeNetworkKey(std::string(cursor->ifa_name), prefix, prefix_length);
     auto iter = current_networks.find(key);
     if (iter == current_networks.end()) {
       // TODO(phoglund): Need to recognize other types as well.
@@ -564,7 +601,8 @@
 #elif defined(WEBRTC_WIN)
 
 unsigned int GetPrefix(PIP_ADAPTER_PREFIX prefixlist,
-              const IPAddress& ip, IPAddress* prefix) {
+                       const IPAddress& ip,
+                       IPAddress* prefix) {
   IPAddress current_prefix;
   IPAddress best_prefix;
   unsigned int best_length = 0;
@@ -583,10 +621,10 @@
         break;
       }
       case AF_INET6: {
-          sockaddr_in6* v6_addr =
-              reinterpret_cast<sockaddr_in6*>(prefixlist->Address.lpSockaddr);
-          current_prefix = IPAddress(v6_addr->sin6_addr);
-          break;
+        sockaddr_in6* v6_addr =
+            reinterpret_cast<sockaddr_in6*>(prefixlist->Address.lpSockaddr);
+        current_prefix = IPAddress(v6_addr->sin6_addr);
+        break;
       }
       default: {
         prefixlist = prefixlist->Next;
@@ -618,8 +656,7 @@
   do {
     adapter_info.reset(new char[buffer_size]);
     adapter_addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
-    ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags,
-                               0, adapter_addrs,
+    ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags, 0, adapter_addrs,
                                reinterpret_cast<PULONG>(&buffer_size));
   } while (ret == ERROR_BUFFER_OVERFLOW);
   if (ret != ERROR_SUCCESS) {
@@ -669,9 +706,7 @@
               continue;
             }
           }
-          default: {
-            continue;
-          }
+          default: { continue; }
         }
 
         IPAddress prefix;
@@ -680,9 +715,29 @@
         auto existing_network = current_networks.find(key);
         if (existing_network == current_networks.end()) {
           AdapterType adapter_type = ADAPTER_TYPE_UNKNOWN;
-          if (adapter_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
-            // TODO(phoglund): Need to recognize other types as well.
-            adapter_type = ADAPTER_TYPE_LOOPBACK;
+          switch (adapter_addrs->IfType) {
+            case IF_TYPE_SOFTWARE_LOOPBACK:
+              adapter_type = ADAPTER_TYPE_LOOPBACK;
+              break;
+            case IF_TYPE_ETHERNET_CSMACD:
+            case IF_TYPE_ETHERNET_3MBIT:
+            case IF_TYPE_IEEE80212:
+            case IF_TYPE_FASTETHER:
+            case IF_TYPE_FASTETHER_FX:
+            case IF_TYPE_GIGABITETHERNET:
+              adapter_type = ADAPTER_TYPE_ETHERNET;
+              break;
+            case IF_TYPE_IEEE80211:
+              adapter_type = ADAPTER_TYPE_WIFI;
+              break;
+            case IF_TYPE_WWANPP:
+            case IF_TYPE_WWANPP2:
+              adapter_type = ADAPTER_TYPE_CELLULAR;
+              break;
+            default:
+              // TODO(phoglund): Need to recognize other types as well.
+              adapter_type = ADAPTER_TYPE_UNKNOWN;
+              break;
           }
           std::unique_ptr<Network> network(new Network(
               name, description, prefix, prefix_length, adapter_type));
@@ -722,12 +777,9 @@
     while (fs.ReadLine(&line) == SR_SUCCESS) {
       char iface_name[256];
       unsigned int iface_ip, iface_gw, iface_mask, iface_flags;
-      if (sscanf(line.c_str(),
-                 "%255s %8X %8X %4X %*d %*u %*d %8X",
-                 iface_name, &iface_ip, &iface_gw,
-                 &iface_flags, &iface_mask) == 5 &&
-          network_name == iface_name &&
-          iface_mask == 0 &&
+      if (sscanf(line.c_str(), "%255s %8X %8X %4X %*d %*u %*d %8X", iface_name,
+                 &iface_ip, &iface_gw, &iface_flags, &iface_mask) == 5 &&
+          network_name == iface_name && iface_mask == 0 &&
           (iface_flags & (RTF_UP | RTF_HOST)) == RTF_UP) {
         return true;
       }
@@ -834,7 +886,7 @@
       UpdateNetworksContinually();
       break;
     }
-    case kSignalNetworksMessage:  {
+    case kSignalNetworksMessage: {
       SignalNetworksChanged();
       break;
     }
@@ -858,8 +910,8 @@
   if (socket->Connect(SocketAddress(
           family == AF_INET ? kPublicIPv4Host : kPublicIPv6Host, kPublicPort)) <
       0) {
-    if (socket->GetError() != ENETUNREACH
-        && socket->GetError() != EHOSTUNREACH) {
+    if (socket->GetError() != ENETUNREACH &&
+        socket->GetError() != EHOSTUNREACH) {
       // Ignore the expected case of "host/net unreachable" - which happens if
       // the network is V4- or V6-only.
       RTC_LOG(LS_INFO) << "Connect failed with " << socket->GetError();
@@ -1013,7 +1065,7 @@
   if (IsVpn()) {
     ss << "/" << AdapterTypeToString(underlying_type_for_vpn_);
   }
-  ss << "]";
+  ss << ":id=" << id_ << "]";
   return ss.str();
 }
 
diff --git a/rtc_base/network.h b/rtc_base/network.h
index 49f500c..03a0978 100644
--- a/rtc_base/network.h
+++ b/rtc_base/network.h
@@ -44,7 +44,8 @@
 // Makes a string key for this network. Used in the network manager's maps.
 // Network objects are keyed on interface name, network prefix and the
 // length of that prefix.
-std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
+std::string MakeNetworkKey(const std::string& name,
+                           const IPAddress& prefix,
                            int prefix_length);
 
 // Utility function that attempts to determine an adapter type by an interface
@@ -352,7 +353,7 @@
   // detected. Passing true to already_changed skips this check.
   bool SetIPs(const std::vector<InterfaceAddress>& ips, bool already_changed);
   // Get the list of IP Addresses associated with this network.
-  const std::vector<InterfaceAddress>& GetIPs() const { return ips_;}
+  const std::vector<InterfaceAddress>& GetIPs() const { return ips_; }
   // Clear the network's list of addresses.
   void ClearIPs() { ips_.clear(); }
 
diff --git a/rtc_base/network_constants.h b/rtc_base/network_constants.h
index b4c8bea..efb2c83 100644
--- a/rtc_base/network_constants.h
+++ b/rtc_base/network_constants.h
@@ -28,7 +28,13 @@
   ADAPTER_TYPE_WIFI = 1 << 1,
   ADAPTER_TYPE_CELLULAR = 1 << 2,
   ADAPTER_TYPE_VPN = 1 << 3,
-  ADAPTER_TYPE_LOOPBACK = 1 << 4
+  ADAPTER_TYPE_LOOPBACK = 1 << 4,
+  // ADAPTER_TYPE_ANY is used for a network, which only contains a single "any
+  // address" IP address (INADDR_ANY for IPv4 or in6addr_any for IPv6), and can
+  // use any/all network interfaces. Whereas ADAPTER_TYPE_UNKNOWN is used
+  // when the network uses a specific interface/IP, but its interface type can
+  // not be determined or not fit in this enum.
+  ADAPTER_TYPE_ANY = 1 << 5,
 };
 
 }  // namespace rtc
diff --git a/rtc_base/network_unittest.cc b/rtc_base/network_unittest.cc
index f4dcc6c..cf1cecc 100644
--- a/rtc_base/network_unittest.cc
+++ b/rtc_base/network_unittest.cc
@@ -19,8 +19,8 @@
 #include "rtc_base/nethelpers.h"
 #include "rtc_base/networkmonitor.h"
 #if defined(WEBRTC_POSIX)
-#include <sys/types.h>
 #include <net/if.h>
+#include <sys/types.h>
 #include "rtc_base/ifaddrs_converter.h"
 #endif  // defined(WEBRTC_POSIX)
 #include "rtc_base/gunit.h"
@@ -61,15 +61,25 @@
   }
 };
 
+bool SameNameAndPrefix(const rtc::Network& a, const rtc::Network& b) {
+  if (a.name() != b.name()) {
+    RTC_LOG(INFO) << "Different interface names.";
+    return false;
+  }
+  if (a.prefix_length() != b.prefix_length() || a.prefix() != b.prefix()) {
+    RTC_LOG(INFO) << "Different IP prefixes.";
+    return false;
+  }
+  return true;
+}
+
 }  // namespace
 
-class NetworkTest : public testing::Test, public sigslot::has_slots<>  {
+class NetworkTest : public testing::Test, public sigslot::has_slots<> {
  public:
   NetworkTest() : callback_called_(false) {}
 
-  void OnNetworksChanged() {
-    callback_called_ = true;
-  }
+  void OnNetworksChanged() { callback_called_ = true; }
 
   NetworkManager::Stats MergeNetworkList(
       BasicNetworkManager& network_manager,
@@ -86,7 +96,8 @@
   }
 
   NetworkManager::NetworkList GetNetworks(
-      const BasicNetworkManager& network_manager, bool include_ignored) {
+      const BasicNetworkManager& network_manager,
+      bool include_ignored) {
     NetworkManager::NetworkList list;
     network_manager.CreateNetworks(include_ignored, &list);
     return list;
@@ -125,8 +136,8 @@
 
   struct sockaddr_in6* CreateIpv6Addr(const std::string& ip_string,
                                       uint32_t scope_id) {
-    struct sockaddr_in6* ipv6_addr = static_cast<struct sockaddr_in6*>(
-        malloc(sizeof(struct sockaddr_in6)));
+    struct sockaddr_in6* ipv6_addr =
+        static_cast<struct sockaddr_in6*>(malloc(sizeof(struct sockaddr_in6)));
     memset(ipv6_addr, 0, sizeof(struct sockaddr_in6));
     ipv6_addr->sin6_family = AF_INET6;
     ipv6_addr->sin6_scope_id = scope_id;
@@ -213,10 +224,10 @@
 
 // TODO(phoglund): Remove when ignore list goes away.
 TEST_F(NetworkTest, TestIgnoreList) {
-  Network ignore_me("ignore_me", "Ignore me please!",
-                    IPAddress(0x12345600U), 24);
-  Network include_me("include_me", "Include me please!",
-                     IPAddress(0x12345600U), 24);
+  Network ignore_me("ignore_me", "Ignore me please!", IPAddress(0x12345600U),
+                    24);
+  Network include_me("include_me", "Include me please!", IPAddress(0x12345600U),
+                     24);
   BasicNetworkManager network_manager;
   EXPECT_FALSE(IsIgnoredNetwork(network_manager, ignore_me));
   EXPECT_FALSE(IsIgnoredNetwork(network_manager, include_me));
@@ -233,9 +244,7 @@
   NetworkManager::NetworkList result = GetNetworks(manager, true);
   // We should be able to bind to any addresses we find.
   NetworkManager::NetworkList::iterator it;
-  for (it = result.begin();
-       it != result.end();
-       ++it) {
+  for (it = result.begin(); it != result.end(); ++it) {
     sockaddr_storage storage;
     memset(&storage, 0, sizeof(storage));
     IPAddress ip = (*it)->GetBestIP();
@@ -246,8 +255,7 @@
     if (fd > 0) {
       size_t ipsize = bindaddress.ToSockAddrStorage(&storage);
       EXPECT_GE(ipsize, 0U);
-      int success = ::bind(fd,
-                           reinterpret_cast<sockaddr*>(&storage),
+      int success = ::bind(fd, reinterpret_cast<sockaddr*>(&storage),
                            static_cast<int>(ipsize));
 #if defined(WEBRTC_WIN)
       if (success)
@@ -268,8 +276,8 @@
 // ALLOWED.
 TEST_F(NetworkTest, TestUpdateNetworks) {
   BasicNetworkManager manager;
-  manager.SignalNetworksChanged.connect(
-      static_cast<NetworkTest*>(this), &NetworkTest::OnNetworksChanged);
+  manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
+                                        &NetworkTest::OnNetworksChanged);
   EXPECT_EQ(NetworkManager::ENUMERATION_ALLOWED,
             manager.enumeration_permission());
   manager.StartUpdating();
@@ -320,7 +328,7 @@
 
   manager.GetNetworks(&list);
   EXPECT_EQ(1U, list.size());
-  EXPECT_EQ(ipv4_network1.ToString(), list[0]->ToString());
+  EXPECT_TRUE(SameNameAndPrefix(ipv4_network1, *list[0]));
   Network* net1 = list[0];
   uint16_t net_id1 = net1->id();
   EXPECT_EQ(1, net_id1);
@@ -336,7 +344,7 @@
 
   manager.GetNetworks(&list);
   EXPECT_EQ(1U, list.size());
-  EXPECT_EQ(ipv4_network2.ToString(), list[0]->ToString());
+  EXPECT_TRUE(SameNameAndPrefix(ipv4_network2, *list[0]));
   Network* net2 = list[0];
   uint16_t net_id2 = net2->id();
   // Network id will increase.
@@ -416,8 +424,8 @@
 // Test that the basic network merging case works.
 TEST_F(NetworkTest, TestIPv6MergeNetworkList) {
   BasicNetworkManager manager;
-  manager.SignalNetworksChanged.connect(
-      static_cast<NetworkTest*>(this), &NetworkTest::OnNetworksChanged);
+  manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
+                                        &NetworkTest::OnNetworksChanged);
   NetworkManager::NetworkList original_list;
   SetupNetworks(&original_list);
   bool changed = false;
@@ -441,8 +449,8 @@
 // objects remain in the result list.
 TEST_F(NetworkTest, TestNoChangeMerge) {
   BasicNetworkManager manager;
-  manager.SignalNetworksChanged.connect(
-      static_cast<NetworkTest*>(this), &NetworkTest::OnNetworksChanged);
+  manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
+                                        &NetworkTest::OnNetworksChanged);
   NetworkManager::NetworkList original_list;
   SetupNetworks(&original_list);
   bool changed = false;
@@ -476,17 +484,16 @@
 // IP changed.
 TEST_F(NetworkTest, MergeWithChangedIP) {
   BasicNetworkManager manager;
-  manager.SignalNetworksChanged.connect(
-      static_cast<NetworkTest*>(this), &NetworkTest::OnNetworksChanged);
+  manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
+                                        &NetworkTest::OnNetworksChanged);
   NetworkManager::NetworkList original_list;
   SetupNetworks(&original_list);
   // Make a network that we're going to change.
   IPAddress ip;
   EXPECT_TRUE(IPFromString("2401:fa01:4:1000:be30:faa:fee:faa", &ip));
   IPAddress prefix = TruncateIP(ip, 64);
-  Network* network_to_change = new Network("test_eth0",
-                                          "Test Network Adapter 1",
-                                          prefix, 64);
+  Network* network_to_change =
+      new Network("test_eth0", "Test Network Adapter 1", prefix, 64);
   Network* changed_network = new Network(*network_to_change);
   network_to_change->AddIP(ip);
   IPAddress changed_ip;
@@ -505,8 +512,7 @@
   manager.GetNetworks(&list);
   EXPECT_EQ(original_list.size(), list.size());
   // Make sure the original network is still in the merged list.
-  EXPECT_NE(list.end(),
-            std::find(list.begin(), list.end(), network_to_change));
+  EXPECT_NE(list.end(), std::find(list.begin(), list.end(), network_to_change));
   EXPECT_EQ(changed_ip, network_to_change->GetIPs().at(0));
 }
 
@@ -514,8 +520,8 @@
 // with additional IPs (not just a replacement).
 TEST_F(NetworkTest, TestMultipleIPMergeNetworkList) {
   BasicNetworkManager manager;
-  manager.SignalNetworksChanged.connect(
-      static_cast<NetworkTest*>(this), &NetworkTest::OnNetworksChanged);
+  manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
+                                        &NetworkTest::OnNetworksChanged);
   NetworkManager::NetworkList original_list;
   SetupNetworks(&original_list);
   bool changed = false;
@@ -544,7 +550,7 @@
   int matchcount = 0;
   for (NetworkManager::NetworkList::iterator it = list.begin();
        it != list.end(); ++it) {
-    if ((*it)->ToString() == original_list[2]->ToString()) {
+    if (SameNameAndPrefix(**it, *original_list[2])) {
       ++matchcount;
       EXPECT_EQ(1, matchcount);
       // This should be the same network object as before.
@@ -569,8 +575,8 @@
 // Test that merge correctly distinguishes multiple networks on an interface.
 TEST_F(NetworkTest, TestMultiplePublicNetworksOnOneInterfaceMerge) {
   BasicNetworkManager manager;
-  manager.SignalNetworksChanged.connect(
-      static_cast<NetworkTest*>(this), &NetworkTest::OnNetworksChanged);
+  manager.SignalNetworksChanged.connect(static_cast<NetworkTest*>(this),
+                                        &NetworkTest::OnNetworksChanged);
   NetworkManager::NetworkList original_list;
   SetupNetworks(&original_list);
   bool changed = false;
@@ -837,6 +843,18 @@
   ClearNetworks(manager);
   ReleaseIfAddrs(addr_list);
 
+  strcpy(if_name, "lo0");
+  addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager);
+  EXPECT_EQ(ADAPTER_TYPE_LOOPBACK, GetAdapterType(manager));
+  ClearNetworks(manager);
+  ReleaseIfAddrs(addr_list);
+
+  strcpy(if_name, "eth0");
+  addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager);
+  EXPECT_EQ(ADAPTER_TYPE_ETHERNET, GetAdapterType(manager));
+  ClearNetworks(manager);
+  ReleaseIfAddrs(addr_list);
+
 #if defined(WEBRTC_IOS)
   strcpy(if_name, "pdp_ip0");
   addr_list = InstallIpv6Network(if_name, ipv6_address1, ipv6_mask, manager);
@@ -1014,8 +1032,8 @@
   ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_DEPRECATED, &ip));
 
   // Create a network with this prefix.
-  Network ipv6_network(
-      "test_eth0", "Test NetworkAdapter", TruncateIP(ip, 64), 64);
+  Network ipv6_network("test_eth0", "Test NetworkAdapter", TruncateIP(ip, 64),
+                       64);
 
   // When there is no address added, it should return an unspecified
   // address.
diff --git a/rtc_base/nullsocketserver.cc b/rtc_base/nullsocketserver.cc
index 68b67fa..c890c6f 100644
--- a/rtc_base/nullsocketserver.cc
+++ b/rtc_base/nullsocketserver.cc
@@ -25,21 +25,11 @@
   event_.Set();
 }
 
-rtc::Socket* NullSocketServer::CreateSocket(int /* type */) {
-  RTC_NOTREACHED();
-  return nullptr;
-}
-
 rtc::Socket* NullSocketServer::CreateSocket(int /* family */, int /* type */) {
   RTC_NOTREACHED();
   return nullptr;
 }
 
-rtc::AsyncSocket* NullSocketServer::CreateAsyncSocket(int /* type */) {
-  RTC_NOTREACHED();
-  return nullptr;
-}
-
 rtc::AsyncSocket* NullSocketServer::CreateAsyncSocket(int /* family */,
                                                       int /* type */) {
   RTC_NOTREACHED();
diff --git a/rtc_base/nullsocketserver.h b/rtc_base/nullsocketserver.h
index 7715c5c..408bcd1 100644
--- a/rtc_base/nullsocketserver.h
+++ b/rtc_base/nullsocketserver.h
@@ -24,9 +24,7 @@
   bool Wait(int cms, bool process_io) override;
   void WakeUp() override;
 
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
  private:
diff --git a/rtc_base/nullsocketserver_unittest.cc b/rtc_base/nullsocketserver_unittest.cc
index e3d9952..f1d65ea 100644
--- a/rtc_base/nullsocketserver_unittest.cc
+++ b/rtc_base/nullsocketserver_unittest.cc
@@ -15,9 +15,7 @@
 
 static const uint32_t kTimeout = 5000U;
 
-class NullSocketServerTest
-    : public testing::Test,
-      public MessageHandler {
+class NullSocketServerTest : public testing::Test, public MessageHandler {
  protected:
   void OnMessage(Message* message) override { ss_.WakeUp(); }
 
diff --git a/rtc_base/numerics/histogram_percentile_counter.cc b/rtc_base/numerics/histogram_percentile_counter.cc
index 87ebd53..4bc8cb0 100644
--- a/rtc_base/numerics/histogram_percentile_counter.cc
+++ b/rtc_base/numerics/histogram_percentile_counter.cc
@@ -48,12 +48,12 @@
   Add(value, 1);
 }
 
-rtc::Optional<uint32_t> HistogramPercentileCounter::GetPercentile(
+absl::optional<uint32_t> HistogramPercentileCounter::GetPercentile(
     float fraction) {
   RTC_CHECK_LE(fraction, 1.0);
   RTC_CHECK_GE(fraction, 0.0);
   if (total_elements_ == 0)
-    return rtc::nullopt;
+    return absl::nullopt;
   size_t elements_to_skip = static_cast<size_t>(
       std::max(0.0f, std::ceil(total_elements_ * fraction) - 1));
   if (elements_to_skip >= total_elements_)
@@ -73,7 +73,7 @@
     }
   }
   RTC_NOTREACHED();
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
 }  // namespace rtc
diff --git a/rtc_base/numerics/histogram_percentile_counter.h b/rtc_base/numerics/histogram_percentile_counter.h
index 4ad2e53..7e5743f 100644
--- a/rtc_base/numerics/histogram_percentile_counter.h
+++ b/rtc_base/numerics/histogram_percentile_counter.h
@@ -15,7 +15,7 @@
 #include <map>
 #include <vector>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace rtc {
 // Calculates percentiles on the stream of data. Use |Add| methods to add new
@@ -30,7 +30,7 @@
   void Add(uint32_t value, size_t count);
   void Add(const HistogramPercentileCounter& other);
   // Argument should be from 0 to 1.
-  rtc::Optional<uint32_t> GetPercentile(float fraction);
+  absl::optional<uint32_t> GetPercentile(float fraction);
 
  private:
   std::vector<size_t> histogram_low_;
diff --git a/rtc_base/numerics/moving_max_counter.h b/rtc_base/numerics/moving_max_counter.h
index 4595cf3..6c6286d 100644
--- a/rtc_base/numerics/moving_max_counter.h
+++ b/rtc_base/numerics/moving_max_counter.h
@@ -17,7 +17,7 @@
 #include <limits>
 #include <utility>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/constructormagic.h"
 
@@ -40,7 +40,7 @@
   // Advances the current time, and returns the maximum sample in the time
   // window ending at the current time. The new current time must be at least as
   // large as the old current time.
-  rtc::Optional<T> Max(int64_t current_time_ms);
+  absl::optional<T> Max(int64_t current_time_ms);
   void Reset();
 
  private:
@@ -83,9 +83,9 @@
 }
 
 template <class T>
-rtc::Optional<T> MovingMaxCounter<T>::Max(int64_t current_time_ms) {
+absl::optional<T> MovingMaxCounter<T>::Max(int64_t current_time_ms) {
   RollWindow(current_time_ms);
-  rtc::Optional<T> res;
+  absl::optional<T> res;
   if (!samples_.empty()) {
     res.emplace(samples_.front().second);
   }
diff --git a/rtc_base/numerics/sample_counter.cc b/rtc_base/numerics/sample_counter.cc
new file mode 100644
index 0000000..d9244c3
--- /dev/null
+++ b/rtc_base/numerics/sample_counter.cc
@@ -0,0 +1,82 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+#include <limits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/numerics/sample_counter.h"
+
+namespace rtc {
+
+SampleCounter::SampleCounter() = default;
+SampleCounter::~SampleCounter() = default;
+
+void SampleCounter::Add(int sample) {
+  if (sum_ > 0) {
+    RTC_DCHECK_LE(sample, std::numeric_limits<int64_t>::max() - sum_);
+  } else {
+    RTC_DCHECK_GE(sample, std::numeric_limits<int64_t>::min() - sum_);
+  }
+  sum_ += sample;
+  // Prevent overflow in squaring.
+  RTC_DCHECK_GT(sample, std::numeric_limits<int32_t>::min());
+  RTC_DCHECK_LE(int64_t{sample} * sample,
+                std::numeric_limits<int64_t>::max() - sum_squared_);
+  sum_squared_ += int64_t{sample} * sample;
+  ++num_samples_;
+  if (!max_ || sample > *max_) {
+    max_ = sample;
+  }
+}
+
+void SampleCounter::Add(const SampleCounter& other) {
+  if (sum_ > 0) {
+    RTC_DCHECK_LE(other.sum_, std::numeric_limits<int64_t>::max() - sum_);
+  } else {
+    RTC_DCHECK_GE(other.sum_, std::numeric_limits<int64_t>::min() - sum_);
+  }
+  sum_ += other.sum_;
+  RTC_DCHECK_LE(other.sum_squared_,
+                std::numeric_limits<int64_t>::max() - sum_squared_);
+  sum_squared_ += other.sum_squared_;
+  RTC_DCHECK_LE(other.num_samples_,
+                std::numeric_limits<int64_t>::max() - num_samples_);
+  num_samples_ += other.num_samples_;
+  if (other.max_ && (!max_ || *max_ < *other.max_))
+    max_ = other.max_;
+}
+
+absl::optional<int> SampleCounter::Avg(int64_t min_required_samples) const {
+  RTC_DCHECK_GT(min_required_samples, 0);
+  if (num_samples_ < min_required_samples)
+    return absl::nullopt;
+  return rtc::dchecked_cast<int>(sum_ / num_samples_);
+}
+
+absl::optional<int64_t> SampleCounter::Variance(
+    int64_t min_required_samples) const {
+  RTC_DCHECK_GT(min_required_samples, 0);
+  if (num_samples_ < min_required_samples)
+    return absl::nullopt;
+  // E[(x-mean)^2] = E[x^2] - mean^2
+  int64_t mean = sum_ / num_samples_;
+  return sum_squared_ / num_samples_ - mean * mean;
+}
+
+absl::optional<int> SampleCounter::Max() const {
+  return max_;
+}
+
+void SampleCounter::Reset() {
+  *this = {};
+}
+
+}  // namespace rtc
diff --git a/rtc_base/numerics/sample_counter.h b/rtc_base/numerics/sample_counter.h
new file mode 100644
index 0000000..643754e
--- /dev/null
+++ b/rtc_base/numerics/sample_counter.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 RTC_BASE_NUMERICS_SAMPLE_COUNTER_H_
+#define RTC_BASE_NUMERICS_SAMPLE_COUNTER_H_
+
+#include "absl/types/optional.h"
+
+namespace rtc {
+
+// Simple utility class for counting basic statistics (max./avg./variance) on
+// stream of samples.
+class SampleCounter {
+ public:
+  SampleCounter();
+  ~SampleCounter();
+  void Add(int sample);
+  absl::optional<int> Avg(int64_t min_required_samples) const;
+  absl::optional<int64_t> Variance(int64_t min_required_samples) const;
+  absl::optional<int> Max() const;
+  void Reset();
+  // Adds all the samples from the |other| SampleCounter as if they were all
+  // individually added using |Add(int)| method.
+  void Add(const SampleCounter& other);
+
+ private:
+  int64_t sum_ = 0;
+  int64_t sum_squared_ = 0;
+  int64_t num_samples_ = 0;
+  absl::optional<int> max_;
+};
+
+}  // namespace rtc
+#endif  // RTC_BASE_NUMERICS_SAMPLE_COUNTER_H_
diff --git a/rtc_base/numerics/sample_counter_unittest.cc b/rtc_base/numerics/sample_counter_unittest.cc
new file mode 100644
index 0000000..898f00c
--- /dev/null
+++ b/rtc_base/numerics/sample_counter_unittest.cc
@@ -0,0 +1,53 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+
+#include "rtc_base/numerics/sample_counter.h"
+
+#include <utility>
+#include <vector>
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using testing::Eq;
+
+namespace rtc {
+
+TEST(SampleCounterTest, ProcessesNoSamples) {
+  constexpr int kMinSamples = 1;
+  SampleCounter counter;
+  EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt));
+  EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt));
+  EXPECT_THAT(counter.Max(), Eq(absl::nullopt));
+}
+
+TEST(SampleCounterTest, NotEnoughSamples) {
+  constexpr int kMinSamples = 6;
+  SampleCounter counter;
+  for (int value : {1, 2, 3, 4, 5}) {
+    counter.Add(value);
+  }
+  EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt));
+  EXPECT_THAT(counter.Avg(kMinSamples), Eq(absl::nullopt));
+  EXPECT_THAT(counter.Max(), Eq(5));
+}
+
+TEST(SampleCounterTest, EnoughSamples) {
+  constexpr int kMinSamples = 5;
+  SampleCounter counter;
+  for (int value : {1, 2, 3, 4, 5}) {
+    counter.Add(value);
+  }
+  EXPECT_THAT(counter.Avg(kMinSamples), Eq(3));
+  EXPECT_THAT(counter.Variance(kMinSamples), Eq(2));
+  EXPECT_THAT(counter.Max(), Eq(5));
+}
+
+}  // namespace rtc
diff --git a/rtc_base/numerics/sequence_number_util.h b/rtc_base/numerics/sequence_number_util.h
index 9e4b844..c55513a 100644
--- a/rtc_base/numerics/sequence_number_util.h
+++ b/rtc_base/numerics/sequence_number_util.h
@@ -14,7 +14,7 @@
 #include <limits>
 #include <type_traits>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/numerics/mod_ops.h"
 #include "rtc_base/numerics/safe_compare.h"
 
@@ -120,7 +120,7 @@
 
  private:
   uint64_t last_unwrapped_;
-  rtc::Optional<T> last_value_;
+  absl::optional<T> last_value_;
 };
 
 }  // namespace webrtc
diff --git a/rtc_base/openssladapter.cc b/rtc_base/openssladapter.cc
index 03b3ca8..05de6d0 100644
--- a/rtc_base/openssladapter.cc
+++ b/rtc_base/openssladapter.cc
@@ -23,37 +23,34 @@
 #include <openssl/x509v3.h>
 #include "rtc_base/openssl.h"
 
-#include "rtc_base/arraysize.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/opensslcommon.h"
-#include "rtc_base/ptr_util.h"
-#include "rtc_base/sslroots.h"
+#include "rtc_base/opensslutility.h"
 #include "rtc_base/stringencode.h"
 #include "rtc_base/stringutils.h"
 #include "rtc_base/thread.h"
 
 #ifndef OPENSSL_IS_BORINGSSL
 
-// TODO: Use a nicer abstraction for mutex.
+// TODO(benwright): Use a nicer abstraction for mutex.
 
 #if defined(WEBRTC_WIN)
-  #define MUTEX_TYPE HANDLE
+#define MUTEX_TYPE HANDLE
 #define MUTEX_SETUP(x) (x) = CreateMutex(nullptr, FALSE, nullptr)
 #define MUTEX_CLEANUP(x) CloseHandle(x)
 #define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
 #define MUTEX_UNLOCK(x) ReleaseMutex(x)
 #define THREAD_ID GetCurrentThreadId()
 #elif defined(WEBRTC_POSIX)
-  #define MUTEX_TYPE pthread_mutex_t
-  #define MUTEX_SETUP(x) pthread_mutex_init(&(x), nullptr)
-  #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
-  #define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
-  #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
-  #define THREAD_ID pthread_self()
+#define MUTEX_TYPE pthread_mutex_t
+#define MUTEX_SETUP(x) pthread_mutex_init(&(x), nullptr)
+#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
+#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
+#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+#define THREAD_ID pthread_self()
 #else
-  #error You must define mutex operations appropriate for your platform!
+#error You must define mutex operations appropriate for your platform!
 #endif
 
 struct CRYPTO_dynlock_value {
@@ -69,7 +66,7 @@
 static int socket_write(BIO* h, const char* buf, int num);
 static int socket_read(BIO* h, char* buf, int size);
 static int socket_puts(BIO* h, const char* str);
-static long socket_ctrl(BIO* h, int cmd, long arg1, void* arg2);
+static long socket_ctrl(BIO* h, int cmd, long arg1, void* arg2);  // NOLINT
 static int socket_new(BIO* h);
 static int socket_free(BIO* data);
 
@@ -141,22 +138,22 @@
   return socket_write(b, str, rtc::checked_cast<int>(strlen(str)));
 }
 
-static long socket_ctrl(BIO* b, int cmd, long num, void* ptr) {
+static long socket_ctrl(BIO* b, int cmd, long num, void* ptr) {  // NOLINT
   switch (cmd) {
-  case BIO_CTRL_RESET:
-    return 0;
-  case BIO_CTRL_EOF: {
-    rtc::AsyncSocket* socket = static_cast<rtc::AsyncSocket*>(ptr);
-    // 1 means socket closed.
-    return (socket->GetState() == rtc::AsyncSocket::CS_CLOSED) ? 1 : 0;
-  }
-  case BIO_CTRL_WPENDING:
-  case BIO_CTRL_PENDING:
-    return 0;
-  case BIO_CTRL_FLUSH:
-    return 1;
-  default:
-    return 0;
+    case BIO_CTRL_RESET:
+      return 0;
+    case BIO_CTRL_EOF: {
+      rtc::AsyncSocket* socket = static_cast<rtc::AsyncSocket*>(ptr);
+      // 1 means socket closed.
+      return (socket->GetState() == rtc::AsyncSocket::CS_CLOSED) ? 1 : 0;
+    }
+    case BIO_CTRL_WPENDING:
+    case BIO_CTRL_PENDING:
+      return 0;
+    case BIO_CTRL_FLUSH:
+      return 1;
+    default:
+      return 0;
   }
 }
 
@@ -181,9 +178,7 @@
 
 namespace rtc {
 
-VerificationCallback OpenSSLAdapter::custom_verify_callback_ = nullptr;
-
-bool OpenSSLAdapter::InitializeSSL(VerificationCallback callback) {
+bool OpenSSLAdapter::InitializeSSL() {
   if (!SSL_library_init())
     return false;
 #if !defined(ADDRESS_SANITIZER) || !defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
@@ -193,7 +188,6 @@
   ERR_load_BIO_strings();
   OpenSSL_add_all_algorithms();
   RAND_poll();
-  custom_verify_callback_ = callback;
   return true;
 }
 
@@ -202,9 +196,11 @@
 }
 
 OpenSSLAdapter::OpenSSLAdapter(AsyncSocket* socket,
-                               OpenSSLSessionCache* ssl_session_cache)
+                               OpenSSLSessionCache* ssl_session_cache,
+                               SSLCertificateVerifier* ssl_cert_verifier)
     : SSLAdapter(socket),
       ssl_session_cache_(ssl_session_cache),
+      ssl_cert_verifier_(ssl_cert_verifier),
       state_(SSL_NONE),
       role_(SSL_CLIENT),
       ssl_read_needs_write_(false),
@@ -214,7 +210,7 @@
       ssl_ctx_(nullptr),
       ssl_mode_(SSL_MODE_TLS),
       ignore_bad_cert_(false),
-      custom_verification_succeeded_(false) {
+      custom_cert_verifier_status_(false) {
   // If a factory is used, take a reference on the factory's SSL_CTX.
   // Otherwise, we'll create our own later.
   // Either way, we'll release our reference via SSL_CTX_free() in Cleanup().
@@ -248,6 +244,12 @@
   ssl_mode_ = mode;
 }
 
+void OpenSSLAdapter::SetCertVerifier(
+    SSLCertificateVerifier* ssl_cert_verifier) {
+  RTC_DCHECK(!ssl_ctx_);
+  ssl_cert_verifier_ = ssl_cert_verifier;
+}
+
 void OpenSSLAdapter::SetIdentity(SSLIdentity* identity) {
   RTC_DCHECK(!identity_);
   identity_.reset(static_cast<OpenSSLIdentity*>(identity));
@@ -307,6 +309,7 @@
     RTC_DCHECK(!ssl_ctx_);
     ssl_ctx_ = CreateContext(ssl_mode_, false);
   }
+
   if (!ssl_ctx_) {
     err = -1;
     goto ssl_error;
@@ -341,7 +344,7 @@
   // appear Send handles partial writes properly, though maybe we never notice
   // since we never send more than 16KB at once..
   SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE |
-                     SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+                         SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 
   // Enable SNI, if a hostname is supplied.
   if (!ssl_host_name_.empty()) {
@@ -374,7 +377,7 @@
     if (!tls_alpn_string.empty()) {
       SSL_set_alpn_protos(
           ssl_, reinterpret_cast<const unsigned char*>(tls_alpn_string.data()),
-          tls_alpn_string.size());
+          rtc::dchecked_cast<unsigned>(tls_alpn_string.size()));
     }
   }
 
@@ -410,18 +413,18 @@
 
   int code = (role_ == SSL_CLIENT) ? SSL_connect(ssl_) : SSL_accept(ssl_);
   switch (SSL_get_error(ssl_, code)) {
-  case SSL_ERROR_NONE:
-    if (!SSLPostConnectionCheck(ssl_, ssl_host_name_)) {
-      RTC_LOG(LS_ERROR) << "TLS post connection check failed";
-      // make sure we close the socket
-      Cleanup();
-      // The connect failed so return -1 to shut down the socket
-      return -1;
-    }
+    case SSL_ERROR_NONE:
+      if (!SSLPostConnectionCheck(ssl_, ssl_host_name_)) {
+        RTC_LOG(LS_ERROR) << "TLS post connection check failed";
+        // make sure we close the socket
+        Cleanup();
+        // The connect failed so return -1 to shut down the socket
+        return -1;
+      }
 
-    state_ = SSL_CONNECTED;
-    AsyncSocketAdapter::OnConnectEvent(this);
-#if 0  // TODO: worry about this
+      state_ = SSL_CONNECTED;
+      AsyncSocketAdapter::OnConnectEvent(this);
+#if 0  // TODO(benwright): worry about this
     // Don't let ourselves go away during the callbacks
     PRefPtr<OpenSSLAdapter> lock(this);
     RTC_LOG(LS_INFO) << " -- onStreamReadable";
@@ -429,26 +432,26 @@
     RTC_LOG(LS_INFO) << " -- onStreamWriteable";
     AsyncSocketAdapter::OnWriteEvent(this);
 #endif
-    break;
+      break;
 
-  case SSL_ERROR_WANT_READ:
-    RTC_LOG(LS_VERBOSE) << " -- error want read";
-    struct timeval timeout;
-    if (DTLSv1_get_timeout(ssl_, &timeout)) {
-      int delay = timeout.tv_sec * 1000 + timeout.tv_usec/1000;
+    case SSL_ERROR_WANT_READ:
+      RTC_LOG(LS_VERBOSE) << " -- error want read";
+      struct timeval timeout;
+      if (DTLSv1_get_timeout(ssl_, &timeout)) {
+        int delay = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
 
-      Thread::Current()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_TIMEOUT,
-                                     0);
-    }
-    break;
+        Thread::Current()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_TIMEOUT,
+                                       0);
+      }
+      break;
 
-  case SSL_ERROR_WANT_WRITE:
-    break;
+    case SSL_ERROR_WANT_WRITE:
+      break;
 
-  case SSL_ERROR_ZERO_RETURN:
-  default:
-    RTC_LOG(LS_WARNING) << "ContinueSSL -- error " << code;
-    return (code != 0) ? code : -1;
+    case SSL_ERROR_ZERO_RETURN:
+    default:
+      RTC_LOG(LS_WARNING) << "ContinueSSL -- error " << code;
+      return (code != 0) ? code : -1;
   }
 
   return 0;
@@ -469,7 +472,7 @@
   state_ = SSL_NONE;
   ssl_read_needs_write_ = false;
   ssl_write_needs_read_ = false;
-  custom_verification_succeeded_ = false;
+  custom_cert_verifier_status_ = false;
   pending_data_.Clear();
 
   if (ssl_) {
@@ -531,20 +534,20 @@
 
 int OpenSSLAdapter::Send(const void* pv, size_t cb) {
   switch (state_) {
-  case SSL_NONE:
-    return AsyncSocketAdapter::Send(pv, cb);
+    case SSL_NONE:
+      return AsyncSocketAdapter::Send(pv, cb);
 
-  case SSL_WAIT:
-  case SSL_CONNECTING:
-    SetError(ENOTCONN);
-    return SOCKET_ERROR;
+    case SSL_WAIT:
+    case SSL_CONNECTING:
+      SetError(ENOTCONN);
+      return SOCKET_ERROR;
 
-  case SSL_CONNECTED:
-    break;
+    case SSL_CONNECTED:
+      break;
 
-  case SSL_ERROR:
-  default:
-    return SOCKET_ERROR;
+    case SSL_ERROR:
+    default:
+      return SOCKET_ERROR;
   }
 
   int ret;
@@ -590,7 +593,7 @@
     pending_data_.SetData(static_cast<const uint8_t*>(pv), cb);
     // Since we're taking responsibility for sending this data, return its full
     // size. The user of this class can consider it sent.
-    return cb;
+    return rtc::dchecked_cast<int>(cb);
   }
 
   return ret;
@@ -611,20 +614,20 @@
 
 int OpenSSLAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) {
   switch (state_) {
-  case SSL_NONE:
-    return AsyncSocketAdapter::Recv(pv, cb, timestamp);
+    case SSL_NONE:
+      return AsyncSocketAdapter::Recv(pv, cb, timestamp);
 
-  case SSL_WAIT:
-  case SSL_CONNECTING:
-    SetError(ENOTCONN);
-    return SOCKET_ERROR;
+    case SSL_WAIT:
+    case SSL_CONNECTING:
+      SetError(ENOTCONN);
+      return SOCKET_ERROR;
 
-  case SSL_CONNECTED:
-    break;
+    case SSL_CONNECTED:
+      break;
 
-  case SSL_ERROR:
-  default:
-    return SOCKET_ERROR;
+    case SSL_ERROR:
+    default:
+      return SOCKET_ERROR;
   }
 
   // Don't trust OpenSSL with zero byte reads
@@ -685,11 +688,11 @@
 }
 
 Socket::ConnState OpenSSLAdapter::GetState() const {
-  //if (signal_close_)
+  // if (signal_close_)
   //  return CS_CONNECTED;
   ConnState state = socket_->GetState();
-  if ((state == CS_CONNECTED)
-      && ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING)))
+  if ((state == CS_CONNECTED) &&
+      ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING)))
     state = CS_CONNECTING;
   return state;
 }
@@ -737,8 +740,8 @@
     return;
 
   // Don't let ourselves go away during the callbacks
-  //PRefPtr<OpenSSLAdapter> lock(this); // TODO: fix this
-  if (ssl_write_needs_read_)  {
+  // PRefPtr<OpenSSLAdapter> lock(this); // TODO(benwright): fix this
+  if (ssl_write_needs_read_) {
     AsyncSocketAdapter::OnWriteEvent(socket);
   }
 
@@ -762,9 +765,9 @@
     return;
 
   // Don't let ourselves go away during the callbacks
-  //PRefPtr<OpenSSLAdapter> lock(this); // TODO: fix this
+  // PRefPtr<OpenSSLAdapter> lock(this); // TODO(benwright): fix this
 
-  if (ssl_read_needs_write_)  {
+  if (ssl_read_needs_write_) {
     AsyncSocketAdapter::OnReadEvent(socket);
   }
 
@@ -787,12 +790,12 @@
 }
 
 bool OpenSSLAdapter::SSLPostConnectionCheck(SSL* ssl, const std::string& host) {
-  bool is_valid_cert_name = openssl::VerifyPeerCertMatchesHost(ssl, host) &&
-                            (SSL_get_verify_result(ssl) == X509_V_OK ||
-                             custom_verification_succeeded_);
+  bool is_valid_cert_name =
+      openssl::VerifyPeerCertMatchesHost(ssl, host) &&
+      (SSL_get_verify_result(ssl) == X509_V_OK || custom_cert_verifier_status_);
 
   if (!is_valid_cert_name && ignore_bad_cert_) {
-    RTC_DLOG(LS_WARNING) << "Other TLS post connection checks failed."
+    RTC_DLOG(LS_WARNING) << "Other TLS post connection checks failed. "
                             "ignore_bad_cert_ set to true. Overriding name "
                             "verification failure!";
     is_valid_cert_name = true;
@@ -847,22 +850,22 @@
                       << X509_verify_cert_error_string(err);
   }
 #endif
-
   // Get our stream pointer from the store
   SSL* ssl = reinterpret_cast<SSL*>(
-                X509_STORE_CTX_get_ex_data(store,
-                  SSL_get_ex_data_X509_STORE_CTX_idx()));
+      X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()));
 
   OpenSSLAdapter* stream =
-    reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl));
+      reinterpret_cast<OpenSSLAdapter*>(SSL_get_app_data(ssl));
 
-  if (!ok && custom_verify_callback_) {
-    void* cert =
-        reinterpret_cast<void*>(X509_STORE_CTX_get_current_cert(store));
-    if (custom_verify_callback_(cert)) {
-      stream->custom_verification_succeeded_ = true;
-      RTC_LOG(LS_INFO) << "validated certificate using custom callback";
+  if (!ok && stream->ssl_cert_verifier_ != nullptr) {
+    RTC_LOG(LS_INFO) << "Invoking SSL Verify Callback.";
+    const OpenSSLCertificate cert(X509_STORE_CTX_get_current_cert(store));
+    if (stream->ssl_cert_verifier_->Verify(cert)) {
+      stream->custom_cert_verifier_status_ = true;
+      RTC_LOG(LS_INFO) << "Validated certificate using custom callback";
       ok = true;
+    } else {
+      RTC_LOG(LS_INFO) << "Failed to verify certificate using custom callback";
     }
   }
 
@@ -884,27 +887,6 @@
   return 1;  // We've taken ownership of the session; OpenSSL shouldn't free it.
 }
 
-bool OpenSSLAdapter::ConfigureTrustedRootCertificates(SSL_CTX* ctx) {
-  // Add the root cert that we care about to the SSL context
-  int count_of_added_certs = 0;
-  for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) {
-    const unsigned char* cert_buffer = kSSLCertCertificateList[i];
-    size_t cert_buffer_len = kSSLCertCertificateSizeList[i];
-    X509* cert =
-        d2i_X509(nullptr, &cert_buffer, checked_cast<long>(cert_buffer_len));
-    if (cert) {
-      int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert);
-      if (return_value == 0) {
-        RTC_LOG(LS_WARNING) << "Unable to add certificate.";
-      } else {
-        count_of_added_certs++;
-      }
-      X509_free(cert);
-    }
-  }
-  return count_of_added_certs > 0;
-}
-
 SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) {
   // Use (D)TLS 1.2.
   // Note: BoringSSL supports a range of versions by setting max/min version
@@ -924,10 +906,15 @@
                         << "(error=" << error << ')';
     return nullptr;
   }
-  if (!ConfigureTrustedRootCertificates(ctx)) {
+
+#ifdef WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+  if (!openssl::LoadBuiltinSSLRootCertificates(ctx)) {
+    RTC_LOG(LS_ERROR) << "SSL_CTX creation failed: Failed to load any trusted "
+                         "ssl root certificates.";
     SSL_CTX_free(ctx);
     return nullptr;
   }
+#endif  // WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
 
 #if !defined(NDEBUG)
   SSL_CTX_set_info_callback(ctx, SSLInfoCallback);
@@ -980,6 +967,7 @@
 //////////////////////////////////////////////////////////////////////
 
 OpenSSLAdapterFactory::OpenSSLAdapterFactory() = default;
+
 OpenSSLAdapterFactory::~OpenSSLAdapterFactory() = default;
 
 void OpenSSLAdapterFactory::SetMode(SSLMode mode) {
@@ -987,18 +975,25 @@
   ssl_mode_ = mode;
 }
 
+void OpenSSLAdapterFactory::SetCertVerifier(
+    SSLCertificateVerifier* ssl_cert_verifier) {
+  RTC_DCHECK(!ssl_session_cache_);
+  ssl_cert_verifier_ = ssl_cert_verifier;
+}
+
 OpenSSLAdapter* OpenSSLAdapterFactory::CreateAdapter(AsyncSocket* socket) {
   if (ssl_session_cache_ == nullptr) {
-    SSL_CTX* ssl_ctx =
-        OpenSSLAdapter::CreateContext(ssl_mode_, /* enable_cache = */ true);
+    SSL_CTX* ssl_ctx = OpenSSLAdapter::CreateContext(ssl_mode_, true);
     if (ssl_ctx == nullptr) {
       return nullptr;
     }
     // The OpenSSLSessionCache will upref the ssl_ctx.
-    ssl_session_cache_ = MakeUnique<OpenSSLSessionCache>(ssl_mode_, ssl_ctx);
+    ssl_session_cache_ =
+        absl::make_unique<OpenSSLSessionCache>(ssl_mode_, ssl_ctx);
     SSL_CTX_free(ssl_ctx);
   }
-  return new OpenSSLAdapter(socket, ssl_session_cache_.get());
+  return new OpenSSLAdapter(socket, ssl_session_cache_.get(),
+                            ssl_cert_verifier_);
 }
 
 }  // namespace rtc
diff --git a/rtc_base/openssladapter.h b/rtc_base/openssladapter.h
index 5f5eb80..50a7c08 100644
--- a/rtc_base/openssladapter.h
+++ b/rtc_base/openssladapter.h
@@ -18,9 +18,11 @@
 #include <string>
 #include <vector>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/buffer.h"
 #include "rtc_base/messagehandler.h"
 #include "rtc_base/messagequeue.h"
+#include "rtc_base/opensslcertificate.h"
 #include "rtc_base/opensslidentity.h"
 #include "rtc_base/opensslsessioncache.h"
 #include "rtc_base/ssladapter.h"
@@ -29,18 +31,25 @@
 
 class OpenSSLAdapter : public SSLAdapter, public MessageHandler {
  public:
-  static bool InitializeSSL(VerificationCallback callback);
+  static bool InitializeSSL();
   static bool CleanupSSL();
 
+  // Creating an OpenSSLAdapter requires a socket to bind to, an optional
+  // session cache if you wish to improve performance by caching sessions for
+  // hostnames you have previously connected to and an optional
+  // SSLCertificateVerifier which can override any existing trusted roots to
+  // validate a peer certificate. The cache and verifier are effectively
+  // immutable after the the SSL connection starts.
   explicit OpenSSLAdapter(AsyncSocket* socket,
-                          OpenSSLSessionCache* ssl_session_cache = nullptr);
+                          OpenSSLSessionCache* ssl_session_cache = nullptr,
+                          SSLCertificateVerifier* ssl_cert_verifier = nullptr);
   ~OpenSSLAdapter() override;
 
   void SetIgnoreBadCert(bool ignore) override;
   void SetAlpnProtocols(const std::vector<std::string>& protos) override;
   void SetEllipticCurves(const std::vector<std::string>& curves) override;
-
   void SetMode(SSLMode mode) override;
+  void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) override;
   void SetIdentity(SSLIdentity* identity) override;
   void SetRole(SSLRole role) override;
   AsyncSocket* Accept(SocketAddress* paddr) override;
@@ -53,11 +62,9 @@
                SocketAddress* paddr,
                int64_t* timestamp) override;
   int Close() override;
-
   // Note that the socket returns ST_CONNECTING while SSL is being negotiated.
   ConnState GetState() const override;
   bool IsResumedSession() override;
-
   // Creates a new SSL_CTX object, configured for client-to-server usage
   // with SSLMode |mode|, and if |enable_cache| is true, with support for
   // storing successful sessions so that they can be later resumed.
@@ -74,7 +81,11 @@
 
  private:
   enum SSLState {
-    SSL_NONE, SSL_WAIT, SSL_CONNECTING, SSL_CONNECTED, SSL_ERROR
+    SSL_NONE,
+    SSL_WAIT,
+    SSL_CONNECTING,
+    SSL_CONNECTED,
+    SSL_ERROR
   };
 
   enum { MSG_TIMEOUT };
@@ -87,9 +98,7 @@
   // Return value and arguments have the same meanings as for Send; |error| is
   // an output parameter filled with the result of SSL_get_error.
   int DoSslWrite(const void* pv, size_t cb, int* error);
-
   void OnMessage(Message* msg) override;
-
   bool SSLPostConnectionCheck(SSL* ssl, const std::string& host);
 
 #if !defined(NDEBUG)
@@ -97,7 +106,6 @@
   static void SSLInfoCallback(const SSL* ssl, int where, int ret);
 #endif
   static int SSLVerifyCallback(int ok, X509_STORE_CTX* store);
-  static VerificationCallback custom_verify_callback_;
   friend class OpenSSLStreamAdapter;  // for custom_verify_callback_;
 
   // If the SSL_CTX was created with |enable_cache| set to true, this callback
@@ -105,30 +113,30 @@
   // to allow its SSL_SESSION* to be cached for later resumption.
   static int NewSSLSessionCallback(SSL* ssl, SSL_SESSION* session);
 
-  static bool ConfigureTrustedRootCertificates(SSL_CTX* ctx);
-
-  // Parent object that maintains shared state.
-  // Can be null if state sharing is not needed.
+  // Optional SSL Shared session cache to improve performance.
   OpenSSLSessionCache* ssl_session_cache_ = nullptr;
-
+  // Optional SSL Certificate verifier which can be set by a third party.
+  SSLCertificateVerifier* ssl_cert_verifier_ = nullptr;
+  // The current connection state of the (d)TLS connection.
   SSLState state_;
   std::unique_ptr<OpenSSLIdentity> identity_;
+  // Indicates whethere this is a client or a server.
   SSLRole role_;
   bool ssl_read_needs_write_;
   bool ssl_write_needs_read_;
   // If true, socket will retain SSL configuration after Close.
   // TODO(juberti): Remove this unused flag.
   bool restartable_;
-
   // This buffer is used if SSL_write fails with SSL_ERROR_WANT_WRITE, which
   // means we need to keep retrying with *the same exact data* until it
   // succeeds. Afterwards it will be cleared.
   Buffer pending_data_;
-
   SSL* ssl_;
+  // Holds the SSL context, which may be shared if an session cache is provided.
   SSL_CTX* ssl_ctx_;
+  // Hostname of server that is being connected, used for SNI.
   std::string ssl_host_name_;
-  // Do DTLS or not
+  // Set the adapter to DTLS or TLS mode before creating the context.
   SSLMode ssl_mode_;
   // If true, the server certificate need not match the configured hostname.
   bool ignore_bad_cert_;
@@ -136,14 +144,10 @@
   std::vector<std::string> alpn_protocols_;
   // List of elliptic curves to be used in the TLS elliptic curves extension.
   std::vector<std::string> elliptic_curves_;
-
-  bool custom_verification_succeeded_;
+  // Holds the result of the call to run of the ssl_cert_verify_->Verify()
+  bool custom_cert_verifier_status_;
 };
 
-std::string TransformAlpnProtocols(const std::vector<std::string>& protos);
-
-/////////////////////////////////////////////////////////////////////////////
-
 // The OpenSSLAdapterFactory is responsbile for creating multiple new
 // OpenSSLAdapters with a shared SSL_CTX and a shared SSL_SESSION cache. The
 // SSL_SESSION cache allows existing SSL_SESSIONS to be reused instead of
@@ -156,6 +160,10 @@
   // the first adapter is created with the factory. If it is called after it
   // will DCHECK.
   void SetMode(SSLMode mode) override;
+  // Set a custom certificate verifier to be passed down to each instance
+  // created with this factory. This should only ever be set before the first
+  // call to the factory and cannot be changed after the fact.
+  void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) override;
   // Constructs a new socket using the shared OpenSSLSessionCache. This means
   // existing SSLSessions already in the cache will be reused instead of
   // re-created for improved performance.
@@ -166,11 +174,16 @@
   SSLMode ssl_mode_ = SSL_MODE_TLS;
   // Holds a cache of existing SSL Sessions.
   std::unique_ptr<OpenSSLSessionCache> ssl_session_cache_;
+  // Provides an optional custom callback for verifying SSL certificates, this
+  // in currently only used for TLS-TURN connections.
+  SSLCertificateVerifier* ssl_cert_verifier_ = nullptr;
   // TODO(benwright): Remove this when context is moved to OpenSSLCommon.
   // Hold a friend class to the OpenSSLAdapter to retrieve the context.
   friend class OpenSSLAdapter;
 };
 
+std::string TransformAlpnProtocols(const std::vector<std::string>& protos);
+
 }  // namespace rtc
 
 #endif  // RTC_BASE_OPENSSLADAPTER_H_
diff --git a/rtc_base/openssladapter_unittest.cc b/rtc_base/openssladapter_unittest.cc
index d043353..4db00e5 100644
--- a/rtc_base/openssladapter_unittest.cc
+++ b/rtc_base/openssladapter_unittest.cc
@@ -12,10 +12,46 @@
 #include <string>
 #include <vector>
 
+#include "absl/memory/memory.h"
+#include "rtc_base/asyncsocket.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/openssladapter.h"
+#include "test/gmock.h"
 
 namespace rtc {
+namespace {
+
+class MockAsyncSocket : public AsyncSocket {
+ public:
+  virtual ~MockAsyncSocket() = default;
+  MOCK_METHOD1(Accept, AsyncSocket*(SocketAddress*));
+  MOCK_CONST_METHOD0(GetLocalAddress, SocketAddress());
+  MOCK_CONST_METHOD0(GetRemoteAddress, SocketAddress());
+  MOCK_METHOD1(Bind, int(const SocketAddress&));
+  MOCK_METHOD1(Connect, int(const SocketAddress&));
+  MOCK_METHOD2(Send, int(const void*, size_t));
+  MOCK_METHOD3(SendTo, int(const void*, size_t, const SocketAddress&));
+  MOCK_METHOD3(Recv, int(void*, size_t, int64_t*));
+  MOCK_METHOD4(RecvFrom, int(void*, size_t, SocketAddress*, int64_t*));
+  MOCK_METHOD1(Listen, int(int));
+  MOCK_METHOD0(Close, int());
+  MOCK_CONST_METHOD0(GetError, int());
+  MOCK_METHOD1(SetError, void(int));
+  MOCK_CONST_METHOD0(GetState, ConnState());
+  MOCK_METHOD2(GetOption, int(Option, int*));
+  MOCK_METHOD2(SetOption, int(Option, int));
+};
+
+class MockCertVerifier : public SSLCertificateVerifier {
+ public:
+  virtual ~MockCertVerifier() = default;
+  MOCK_METHOD1(Verify, bool(const SSLCertificate&));
+};
+
+}  // namespace
+
+using ::testing::_;
+using ::testing::Return;
 
 TEST(OpenSSLAdapterTest, TestTransformAlpnProtocols) {
   EXPECT_EQ("", TransformAlpnProtocols(std::vector<std::string>()));
@@ -38,4 +74,36 @@
   EXPECT_EQ(expected_response.str(), TransformAlpnProtocols(alpn_protos));
 }
 
+// Verifies that SSLStart works when OpenSSLAdapter is started in standalone
+// mode.
+TEST(OpenSSLAdapterTest, TestBeginSSLBeforeConnection) {
+  AsyncSocket* async_socket = new MockAsyncSocket();
+  OpenSSLAdapter adapter(async_socket);
+  EXPECT_EQ(adapter.StartSSL("webrtc.org", false), 0);
+}
+
+// Verifies that the adapter factory can create new adapters.
+TEST(OpenSSLAdapterFactoryTest, CreateSingleOpenSSLAdapter) {
+  OpenSSLAdapterFactory adapter_factory;
+  AsyncSocket* async_socket = new MockAsyncSocket();
+  auto simple_adapter = std::unique_ptr<OpenSSLAdapter>(
+      adapter_factory.CreateAdapter(async_socket));
+  EXPECT_NE(simple_adapter, nullptr);
+}
+
+// Verifies that setting a custom verifier still allows for adapters to be
+// created.
+TEST(OpenSSLAdapterFactoryTest, CreateWorksWithCustomVerifier) {
+  MockCertVerifier* mock_verifier = new MockCertVerifier();
+  EXPECT_CALL(*mock_verifier, Verify(_)).WillRepeatedly(Return(true));
+  auto cert_verifier = std::unique_ptr<SSLCertificateVerifier>(mock_verifier);
+
+  OpenSSLAdapterFactory adapter_factory;
+  adapter_factory.SetCertVerifier(cert_verifier.get());
+  AsyncSocket* async_socket = new MockAsyncSocket();
+  auto simple_adapter = std::unique_ptr<OpenSSLAdapter>(
+      adapter_factory.CreateAdapter(async_socket));
+  EXPECT_NE(simple_adapter, nullptr);
+}
+
 }  // namespace rtc
diff --git a/rtc_base/opensslcertificate.cc b/rtc_base/opensslcertificate.cc
new file mode 100644
index 0000000..15fc303
--- /dev/null
+++ b/rtc_base/opensslcertificate.cc
@@ -0,0 +1,321 @@
+/*
+ *  Copyright 2004 The WebRTC 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.
+ */
+
+#include "rtc_base/opensslcertificate.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#if defined(WEBRTC_WIN)
+// Must be included first before openssl headers.
+#include "rtc_base/win32.h"  // NOLINT
+#endif                       // WEBRTC_WIN
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/helpers.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/openssl.h"
+#include "rtc_base/openssldigest.h"
+#include "rtc_base/opensslidentity.h"
+#include "rtc_base/opensslutility.h"
+#ifdef WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+#include "rtc_base/sslroots.h"
+#endif
+
+namespace rtc {
+
+//////////////////////////////////////////////////////////////////////
+// OpenSSLCertificate
+//////////////////////////////////////////////////////////////////////
+
+// We could have exposed a myriad of parameters for the crypto stuff,
+// but keeping it simple seems best.
+
+// Random bits for certificate serial number
+static const int SERIAL_RAND_BITS = 64;
+
+// Generate a self-signed certificate, with the public key from the
+// given key pair. Caller is responsible for freeing the returned object.
+static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
+  RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;
+  X509* x509 = nullptr;
+  BIGNUM* serial_number = nullptr;
+  X509_NAME* name = nullptr;
+  time_t epoch_off = 0;  // Time offset since epoch.
+
+  if ((x509 = X509_new()) == nullptr)
+    goto error;
+
+  if (!X509_set_pubkey(x509, pkey))
+    goto error;
+
+  // serial number
+  // temporary reference to serial number inside x509 struct
+  ASN1_INTEGER* asn1_serial_number;
+  if ((serial_number = BN_new()) == nullptr ||
+      !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
+      (asn1_serial_number = X509_get_serialNumber(x509)) == nullptr ||
+      !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
+    goto error;
+
+  if (!X509_set_version(x509, 2L))  // version 3
+    goto error;
+
+  // There are a lot of possible components for the name entries. In
+  // our P2P SSL mode however, the certificates are pre-exchanged
+  // (through the secure XMPP channel), and so the certificate
+  // identification is arbitrary. It can't be empty, so we set some
+  // arbitrary common_name. Note that this certificate goes out in
+  // clear during SSL negotiation, so there may be a privacy issue in
+  // putting anything recognizable here.
+  if ((name = X509_NAME_new()) == nullptr ||
+      !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
+                                  (unsigned char*)params.common_name.c_str(),
+                                  -1, -1, 0) ||
+      !X509_set_subject_name(x509, name) || !X509_set_issuer_name(x509, name))
+    goto error;
+
+  if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) ||
+      !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off))
+    goto error;
+
+  if (!X509_sign(x509, pkey, EVP_sha256()))
+    goto error;
+
+  BN_free(serial_number);
+  X509_NAME_free(name);
+  RTC_LOG(LS_INFO) << "Returning certificate";
+  return x509;
+
+error:
+  BN_free(serial_number);
+  X509_NAME_free(name);
+  X509_free(x509);
+  return nullptr;
+}
+
+#if !defined(NDEBUG)
+// Print a certificate to the log, for debugging.
+static void PrintCert(X509* x509) {
+  BIO* temp_memory_bio = BIO_new(BIO_s_mem());
+  if (!temp_memory_bio) {
+    RTC_DLOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
+    return;
+  }
+  X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
+  BIO_write(temp_memory_bio, "\0", 1);
+  char* buffer;
+  BIO_get_mem_data(temp_memory_bio, &buffer);
+  RTC_DLOG(LS_VERBOSE) << buffer;
+  BIO_free(temp_memory_bio);
+}
+#endif
+
+OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) {
+  AddReference();
+}
+
+OpenSSLCertificate* OpenSSLCertificate::Generate(
+    OpenSSLKeyPair* key_pair,
+    const SSLIdentityParams& params) {
+  SSLIdentityParams actual_params(params);
+  if (actual_params.common_name.empty()) {
+    // Use a random string, arbitrarily 8chars long.
+    actual_params.common_name = CreateRandomString(8);
+  }
+  X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
+  if (!x509) {
+    openssl::LogSSLErrors("Generating certificate");
+    return nullptr;
+  }
+#if !defined(NDEBUG)
+  PrintCert(x509);
+#endif
+  OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
+  X509_free(x509);
+  return ret;
+}
+
+OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
+    const std::string& pem_string) {
+  BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
+  if (!bio)
+    return nullptr;
+  BIO_set_mem_eof_return(bio, 0);
+  X509* x509 =
+      PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
+  BIO_free(bio);  // Frees the BIO, but not the pointed-to string.
+
+  if (!x509)
+    return nullptr;
+
+  OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
+  X509_free(x509);
+  return ret;
+}
+
+// NOTE: This implementation only functions correctly after InitializeSSL
+// and before CleanupSSL.
+bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
+    std::string* algorithm) const {
+  int nid = X509_get_signature_nid(x509_);
+  switch (nid) {
+    case NID_md5WithRSA:
+    case NID_md5WithRSAEncryption:
+      *algorithm = DIGEST_MD5;
+      break;
+    case NID_ecdsa_with_SHA1:
+    case NID_dsaWithSHA1:
+    case NID_dsaWithSHA1_2:
+    case NID_sha1WithRSA:
+    case NID_sha1WithRSAEncryption:
+      *algorithm = DIGEST_SHA_1;
+      break;
+    case NID_ecdsa_with_SHA224:
+    case NID_sha224WithRSAEncryption:
+    case NID_dsa_with_SHA224:
+      *algorithm = DIGEST_SHA_224;
+      break;
+    case NID_ecdsa_with_SHA256:
+    case NID_sha256WithRSAEncryption:
+    case NID_dsa_with_SHA256:
+      *algorithm = DIGEST_SHA_256;
+      break;
+    case NID_ecdsa_with_SHA384:
+    case NID_sha384WithRSAEncryption:
+      *algorithm = DIGEST_SHA_384;
+      break;
+    case NID_ecdsa_with_SHA512:
+    case NID_sha512WithRSAEncryption:
+      *algorithm = DIGEST_SHA_512;
+      break;
+    default:
+      // Unknown algorithm.  There are several unhandled options that are less
+      // common and more complex.
+      RTC_LOG(LS_ERROR) << "Unknown signature algorithm NID: " << nid;
+      algorithm->clear();
+      return false;
+  }
+  return true;
+}
+
+bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
+                                       unsigned char* digest,
+                                       size_t size,
+                                       size_t* length) const {
+  return ComputeDigest(x509_, algorithm, digest, size, length);
+}
+
+bool OpenSSLCertificate::ComputeDigest(const X509* x509,
+                                       const std::string& algorithm,
+                                       unsigned char* digest,
+                                       size_t size,
+                                       size_t* length) {
+  const EVP_MD* md;
+  unsigned int n;
+
+  if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
+    return false;
+
+  if (size < static_cast<size_t>(EVP_MD_size(md)))
+    return false;
+
+  X509_digest(x509, md, digest, &n);
+
+  *length = n;
+
+  return true;
+}
+
+OpenSSLCertificate::~OpenSSLCertificate() {
+  X509_free(x509_);
+}
+
+OpenSSLCertificate* OpenSSLCertificate::GetReference() const {
+  return new OpenSSLCertificate(x509_);
+}
+
+std::string OpenSSLCertificate::ToPEMString() const {
+  BIO* bio = BIO_new(BIO_s_mem());
+  if (!bio) {
+    FATAL() << "unreachable code";
+  }
+  if (!PEM_write_bio_X509(bio, x509_)) {
+    BIO_free(bio);
+    FATAL() << "unreachable code";
+  }
+  BIO_write(bio, "\0", 1);
+  char* buffer;
+  BIO_get_mem_data(bio, &buffer);
+  std::string ret(buffer);
+  BIO_free(bio);
+  return ret;
+}
+
+void OpenSSLCertificate::ToDER(Buffer* der_buffer) const {
+  // In case of failure, make sure to leave the buffer empty.
+  der_buffer->SetSize(0);
+
+  // Calculates the DER representation of the certificate, from scratch.
+  BIO* bio = BIO_new(BIO_s_mem());
+  if (!bio) {
+    FATAL() << "unreachable code";
+  }
+  if (!i2d_X509_bio(bio, x509_)) {
+    BIO_free(bio);
+    FATAL() << "unreachable code";
+  }
+  char* data;
+  size_t length = BIO_get_mem_data(bio, &data);
+  der_buffer->SetData(data, length);
+  BIO_free(bio);
+}
+
+void OpenSSLCertificate::AddReference() const {
+  RTC_DCHECK(x509_ != nullptr);
+  X509_up_ref(x509_);
+}
+
+bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const {
+  return X509_cmp(x509_, other.x509_) == 0;
+}
+
+bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const {
+  return !(*this == other);
+}
+
+// Documented in sslidentity.h.
+int64_t OpenSSLCertificate::CertificateExpirationTime() const {
+  ASN1_TIME* expire_time = X509_get_notAfter(x509_);
+  bool long_format;
+
+  if (expire_time->type == V_ASN1_UTCTIME) {
+    long_format = false;
+  } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) {
+    long_format = true;
+  } else {
+    return -1;
+  }
+
+  return ASN1TimeToSec(expire_time->data, expire_time->length, long_format);
+}
+
+}  // namespace rtc
diff --git a/rtc_base/opensslcertificate.h b/rtc_base/opensslcertificate.h
new file mode 100644
index 0000000..c730ffd
--- /dev/null
+++ b/rtc_base/opensslcertificate.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright 2004 The WebRTC 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 RTC_BASE_OPENSSLCERTIFICATE_H_
+#define RTC_BASE_OPENSSLCERTIFICATE_H_
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <memory>
+#include <string>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/sslcertificate.h"
+#include "rtc_base/sslidentity.h"
+
+typedef struct ssl_ctx_st SSL_CTX;
+
+namespace rtc {
+
+class OpenSSLKeyPair;
+
+// OpenSSLCertificate encapsulates an OpenSSL X509* certificate object,
+// which is also reference counted inside the OpenSSL library.
+class OpenSSLCertificate : public SSLCertificate {
+ public:
+  // X509 object has its reference count incremented. So the caller and
+  // OpenSSLCertificate share ownership.
+  explicit OpenSSLCertificate(X509* x509);
+
+  static OpenSSLCertificate* Generate(OpenSSLKeyPair* key_pair,
+                                      const SSLIdentityParams& params);
+  static OpenSSLCertificate* FromPEMString(const std::string& pem_string);
+
+  ~OpenSSLCertificate() override;
+
+  OpenSSLCertificate* GetReference() const override;
+
+  X509* x509() const { return x509_; }
+
+  std::string ToPEMString() const override;
+  void ToDER(Buffer* der_buffer) const override;
+  bool operator==(const OpenSSLCertificate& other) const;
+  bool operator!=(const OpenSSLCertificate& other) const;
+
+  // Compute the digest of the certificate given algorithm
+  bool ComputeDigest(const std::string& algorithm,
+                     unsigned char* digest,
+                     size_t size,
+                     size_t* length) const override;
+
+  // Compute the digest of a certificate as an X509 *
+  static bool ComputeDigest(const X509* x509,
+                            const std::string& algorithm,
+                            unsigned char* digest,
+                            size_t size,
+                            size_t* length);
+
+  bool GetSignatureDigestAlgorithm(std::string* algorithm) const override;
+
+  int64_t CertificateExpirationTime() const override;
+
+ private:
+  void AddReference() const;
+
+  X509* x509_;  // NOT OWNED
+  RTC_DISALLOW_COPY_AND_ASSIGN(OpenSSLCertificate);
+};
+
+}  // namespace rtc
+
+#endif  // RTC_BASE_OPENSSLCERTIFICATE_H_
diff --git a/rtc_base/opensslcommon.cc b/rtc_base/opensslcommon.cc
deleted file mode 100644
index 5213392..0000000
--- a/rtc_base/opensslcommon.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  Copyright 2018 The WebRTC 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.
- */
-
-#include "rtc_base/opensslcommon.h"
-
-#if defined(WEBRTC_POSIX)
-#include <unistd.h>
-#endif
-
-#if defined(WEBRTC_WIN)
-// Must be included first before openssl headers.
-#include "rtc_base/win32.h"  // NOLINT
-#endif                       // WEBRTC_WIN
-
-#include <openssl/bio.h>
-#include <openssl/crypto.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/openssl.h"
-
-namespace rtc {
-namespace openssl {
-
-// Holds various helper methods.
-namespace {
-void LogCertificates(SSL* ssl, X509* certificate) {
-// Logging certificates is extremely verbose. So it is disabled by default.
-#ifdef LOG_CERTIFICATES
-  BIO* mem = BIO_new(BIO_s_mem());
-  if (mem == nullptr) {
-    RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory.";
-    return;
-  }
-
-  RTC_DLOG(LS_INFO) << "Certificate from server:";
-  X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
-  BIO_write(mem, "\0", 1);
-
-  char* buffer = nullptr;
-  BIO_get_mem_data(mem, &buffer);
-  if (buffer != nullptr) {
-    RTC_DLOG(LS_INFO) << buffer;
-  } else {
-    RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer.";
-  }
-  BIO_free(mem);
-
-  const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
-  if (cipher_name != nullptr) {
-    RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name;
-  } else {
-    RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name.";
-  }
-#endif
-}
-}  // namespace
-
-bool VerifyPeerCertMatchesHost(SSL* ssl, const std::string& host) {
-  if (host.empty()) {
-    RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate.";
-    return false;
-  }
-
-  if (ssl == nullptr) {
-    RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate.";
-    return false;
-  }
-
-  X509* certificate = SSL_get_peer_certificate(ssl);
-  if (certificate == nullptr) {
-    RTC_DLOG(LS_ERROR)
-        << "SSL_get_peer_certificate failed. This should never happen.";
-    return false;
-  }
-
-  LogCertificates(ssl, certificate);
-
-  bool is_valid_cert_name =
-      X509_check_host(certificate, host.c_str(), host.size(), 0, nullptr) == 1;
-  X509_free(certificate);
-  return is_valid_cert_name;
-}
-
-}  // namespace openssl
-}  // namespace rtc
diff --git a/rtc_base/opensslcommon.h b/rtc_base/opensslcommon.h
deleted file mode 100644
index c05165b..0000000
--- a/rtc_base/opensslcommon.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *  Copyright 2018 The WebRTC 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 RTC_BASE_OPENSSLCOMMON_H_
-#define RTC_BASE_OPENSSLCOMMON_H_
-
-#include <string>
-
-typedef struct ssl_st SSL;
-
-namespace rtc {
-// The openssl namespace holds static helper methods. All methods related
-// to OpenSSL that are commonly used and don't require global state should be
-// placed here.
-namespace openssl {
-// Verifies that the hostname provided matches that in the peer certificate
-// attached to this SSL state.
-bool VerifyPeerCertMatchesHost(SSL* ssl, const std::string& host);
-}  // namespace openssl
-}  // namespace rtc
-
-#endif  // RTC_BASE_OPENSSLCOMMON_H_
diff --git a/rtc_base/opensslcommon_unittest.cc b/rtc_base/opensslcommon_unittest.cc
deleted file mode 100644
index 322a7b9..0000000
--- a/rtc_base/opensslcommon_unittest.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *  Copyright 2018 The WebRTC 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.
- */
-
-#include <string>
-#include <vector>
-
-#if defined(WEBRTC_POSIX)
-#include <unistd.h>
-#endif
-
-#if defined(WEBRTC_WIN)
-// Must be included first before openssl headers.
-#include "rtc_base/win32.h"  // NOLINT
-#endif                       // WEBRTC_WIN
-
-#include <openssl/bio.h>
-#include <openssl/crypto.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
-#include "rtc_base/arraysize.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/numerics/safe_conversions.h"
-#include "rtc_base/openssl.h"
-#include "rtc_base/opensslcommon.h"
-#include "rtc_base/sslroots.h"
-#include "test/gmock.h"
-
-namespace rtc {
-namespace {
-// Fake Self-Signed SSL Certifiacte with CN: *.webrtc.org.
-// This is only to be used for testing (it isn't signed by a CA anyway).
-const unsigned char kFakeSSLCertificate[] = {
-    0x30, 0x82, 0x02, 0x68, 0x30, 0x82, 0x02, 0x12, 0xA0, 0x03, 0x02, 0x01,
-    0x02, 0x02, 0x09, 0x00, 0xC8, 0x83, 0x59, 0x4D, 0x90, 0xC3, 0x5F, 0xC8,
-    0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
-    0x0B, 0x05, 0x00, 0x30, 0x81, 0x8D, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
-    0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0B, 0x30, 0x09, 0x06,
-    0x03, 0x55, 0x04, 0x08, 0x0C, 0x02, 0x57, 0x41, 0x31, 0x2C, 0x30, 0x2A,
-    0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x23, 0x46, 0x61, 0x6B, 0x65, 0x20,
-    0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
-    0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x54,
-    0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03,
-    0x55, 0x04, 0x0B, 0x0C, 0x23, 0x46, 0x61, 0x6B, 0x65, 0x20, 0x57, 0x65,
-    0x62, 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-    0x63, 0x61, 0x74, 0x65, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x54, 0x65, 0x73,
-    0x74, 0x69, 0x6E, 0x67, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
-    0x03, 0x0C, 0x0C, 0x2A, 0x2E, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2E,
-    0x6F, 0x72, 0x67, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x38, 0x30, 0x34, 0x30,
-    0x33, 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5A, 0x17, 0x0D, 0x31, 0x39,
-    0x30, 0x34, 0x30, 0x33, 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5A, 0x30,
-    0x81, 0x8D, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-    0x02, 0x55, 0x53, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-    0x0C, 0x02, 0x57, 0x41, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03, 0x55, 0x04,
-    0x0A, 0x0C, 0x23, 0x46, 0x61, 0x6B, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52,
-    0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
-    0x74, 0x65, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69,
-    0x6E, 0x67, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C,
-    0x23, 0x46, 0x61, 0x6B, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43,
-    0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
-    0x20, 0x46, 0x6F, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67,
-    0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0C, 0x2A,
-    0x2E, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2E, 0x6F, 0x72, 0x67, 0x30,
-    0x5C, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
-    0x01, 0x01, 0x05, 0x00, 0x03, 0x4B, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00,
-    0xAE, 0xAE, 0x85, 0x2A, 0x40, 0xD6, 0x99, 0x35, 0x09, 0x34, 0x1B, 0xC5,
-    0xAC, 0x6C, 0x79, 0xC7, 0xC3, 0xDE, 0x1B, 0xCF, 0x17, 0x8D, 0x6B, 0x84,
-    0xEC, 0x8B, 0x4E, 0x2B, 0xC1, 0x83, 0x43, 0xDF, 0x76, 0x0F, 0x5F, 0x5A,
-    0xA9, 0x7D, 0x94, 0xC0, 0x54, 0x5C, 0xFF, 0xBC, 0x7C, 0x86, 0xDC, 0x9A,
-    0xCE, 0xB9, 0xDF, 0xE6, 0x0B, 0xC4, 0x5B, 0x6E, 0x56, 0x9F, 0xBC, 0x40,
-    0xF5, 0xA0, 0x52, 0xA7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x53, 0x30,
-    0x51, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14,
-    0xB7, 0xC0, 0x9A, 0xA7, 0x22, 0xAF, 0xF8, 0x7D, 0xFF, 0x68, 0xDB, 0x80,
-    0xAC, 0x0A, 0xB6, 0xDC, 0x64, 0x89, 0xDB, 0xD4, 0x30, 0x1F, 0x06, 0x03,
-    0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xB7, 0xC0, 0x9A,
-    0xA7, 0x22, 0xAF, 0xF8, 0x7D, 0xFF, 0x68, 0xDB, 0x80, 0xAC, 0x0A, 0xB6,
-    0xDC, 0x64, 0x89, 0xDB, 0xD4, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13,
-    0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D,
-    0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05,
-    0x00, 0x03, 0x41, 0x00, 0x50, 0x6D, 0xCC, 0x62, 0xAE, 0xD1, 0x7C, 0x4D,
-    0xEF, 0x90, 0x1E, 0x9B, 0x72, 0x73, 0xE0, 0x56, 0x66, 0x32, 0x6A, 0x78,
-    0xE8, 0x0F, 0xAD, 0x21, 0x32, 0x54, 0xA5, 0xB3, 0xB8, 0x14, 0x54, 0xBC,
-    0x50, 0xF7, 0x7F, 0x73, 0xD6, 0x44, 0x1E, 0x82, 0xD9, 0x4B, 0x49, 0x48,
-    0x9E, 0x02, 0x8B, 0xFE, 0xC3, 0xFD, 0x5D, 0x15, 0x02, 0xE1, 0x78, 0xAC,
-    0x9A, 0xAE, 0xFC, 0xC7, 0x48, 0xC6, 0x48, 0x6B};
-
-// Simple testing helper method to create a fake SSL_SESSION with a testing
-// peer connection set.
-SSL_SESSION* CreateSSLSessionWithFakePeerCertificate(SSL_CTX* ssl_ctx) {
-  SSL_SESSION* ssl_session = SSL_SESSION_new(ssl_ctx);
-  const unsigned char* cert_buffer = kFakeSSLCertificate;
-  size_t cert_buffer_len = arraysize(kFakeSSLCertificate);
-  X509* ssl_peer_certificate = d2i_X509(
-      nullptr, &cert_buffer, checked_cast<long>(cert_buffer_len));  // NOLINT
-  EXPECT_NE(ssl_peer_certificate, nullptr);
-#ifdef OPENSSL_IS_BORINGSSL
-  ssl_session->x509_peer = ssl_peer_certificate;
-#else
-  ssl_session->peer = ssl_peer_certificate;
-#endif
-  return ssl_session;
-}
-}  // namespace
-
-TEST(OpenSSLCommonTest, VerifyPeerCertMatchesHostFailsOnNoPeerCertificate) {
-  SSL_CTX* ssl_ctx = SSL_CTX_new(DTLSv1_2_client_method());
-  SSL* ssl = SSL_new(ssl_ctx);
-
-  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "webrtc.org"));
-
-  SSL_free(ssl);
-  SSL_CTX_free(ssl_ctx);
-}
-
-TEST(OpenSSLCommonTest, VerifyPeerCertMatchesHostSucceedsOnCorrectHostname) {
-  SSL_CTX* ssl_ctx = SSL_CTX_new(DTLSv1_2_client_method());
-  SSL* ssl = SSL_new(ssl_ctx);
-  SSL_SESSION* ssl_session = CreateSSLSessionWithFakePeerCertificate(ssl_ctx);
-  SSL_set_session(ssl, ssl_session);
-
-  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "www.webrtc.org"));
-  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "alice.webrtc.org"));
-  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "bob.webrtc.org"));
-
-  SSL_SESSION_free(ssl_session);
-  SSL_free(ssl);
-  SSL_CTX_free(ssl_ctx);
-}
-
-TEST(OpenSSLCommonTest, VerifyPeerCertMatchesHostFailsOnInvalidHostname) {
-  SSL_CTX* ssl_ctx = SSL_CTX_new(DTLSv1_2_client_method());
-  SSL* ssl = SSL_new(ssl_ctx);
-  SSL_SESSION* ssl_session = CreateSSLSessionWithFakePeerCertificate(ssl_ctx);
-  SSL_set_session(ssl, ssl_session);
-
-  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "a.b.webrtc.org"));
-  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "notwebrtc.org"));
-  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "webrtc.org"));
-
-  SSL_SESSION_free(ssl_session);
-  SSL_free(ssl);
-  SSL_CTX_free(ssl_ctx);
-}
-
-}  // namespace rtc
diff --git a/rtc_base/openssldigest.cc b/rtc_base/openssldigest.cc
index 32cd4af..9b644c4 100644
--- a/rtc_base/openssldigest.cc
+++ b/rtc_base/openssldigest.cc
@@ -80,8 +80,7 @@
   return true;
 }
 
-bool OpenSSLDigest::GetDigestName(const EVP_MD* md,
-                                  std::string* algorithm) {
+bool OpenSSLDigest::GetDigestName(const EVP_MD* md, std::string* algorithm) {
   RTC_DCHECK(md != nullptr);
   RTC_DCHECK(algorithm != nullptr);
 
@@ -108,7 +107,7 @@
 
 bool OpenSSLDigest::GetDigestSize(const std::string& algorithm,
                                   size_t* length) {
-  const EVP_MD *md;
+  const EVP_MD* md;
   if (!GetDigestEVP(algorithm, &md))
     return false;
 
diff --git a/rtc_base/openssldigest.h b/rtc_base/openssldigest.h
index 2b65867..c4cd1e0 100644
--- a/rtc_base/openssldigest.h
+++ b/rtc_base/openssldigest.h
@@ -31,14 +31,11 @@
   size_t Finish(void* buf, size_t len) override;
 
   // Helper function to look up a digest's EVP by name.
-  static bool GetDigestEVP(const std::string &algorithm,
-                           const EVP_MD** md);
+  static bool GetDigestEVP(const std::string& algorithm, const EVP_MD** md);
   // Helper function to look up a digest's name by EVP.
-  static bool GetDigestName(const EVP_MD* md,
-                            std::string* algorithm);
+  static bool GetDigestName(const EVP_MD* md, std::string* algorithm);
   // Helper function to get the length of a digest.
-  static bool GetDigestSize(const std::string &algorithm,
-                            size_t* len);
+  static bool GetDigestSize(const std::string& algorithm, size_t* len);
 
  private:
   EVP_MD_CTX* ctx_ = nullptr;
diff --git a/rtc_base/opensslidentity.cc b/rtc_base/opensslidentity.cc
index 9f7c63b..a8c6919 100644
--- a/rtc_base/opensslidentity.cc
+++ b/rtc_base/opensslidentity.cc
@@ -11,11 +11,13 @@
 #include "rtc_base/opensslidentity.h"
 
 #include <memory>
+#include <utility>
+#include <vector>
 
 #if defined(WEBRTC_WIN)
 // Must be included first before openssl headers.
 #include "rtc_base/win32.h"  // NOLINT
-#endif  // WEBRTC_WIN
+#endif                       // WEBRTC_WIN
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
@@ -24,21 +26,20 @@
 #include <openssl/pem.h>
 #include <openssl/rsa.h>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/helpers.h"
 #include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
 #include "rtc_base/openssl.h"
 #include "rtc_base/openssldigest.h"
-#include "rtc_base/ptr_util.h"
+#include "rtc_base/opensslutility.h"
 
 namespace rtc {
 
 // We could have exposed a myriad of parameters for the crypto stuff,
 // but keeping it simple seems best.
 
-// Random bits for certificate serial number
-static const int SERIAL_RAND_BITS = 64;
-
 // Generate a key pair. Caller is responsible for freeing the returned object.
 static EVP_PKEY* MakeKey(const KeyParams& key_params) {
   RTC_LOG(LS_INFO) << "Making key pair";
@@ -93,81 +94,10 @@
   return pkey;
 }
 
-// Generate a self-signed certificate, with the public key from the
-// given key pair. Caller is responsible for freeing the returned object.
-static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
-  RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;
-  X509* x509 = nullptr;
-  BIGNUM* serial_number = nullptr;
-  X509_NAME* name = nullptr;
-  time_t epoch_off = 0;  // Time offset since epoch.
-
-  if ((x509 = X509_new()) == nullptr)
-    goto error;
-
-  if (!X509_set_pubkey(x509, pkey))
-    goto error;
-
-  // serial number
-  // temporary reference to serial number inside x509 struct
-  ASN1_INTEGER* asn1_serial_number;
-  if ((serial_number = BN_new()) == nullptr ||
-      !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
-      (asn1_serial_number = X509_get_serialNumber(x509)) == nullptr ||
-      !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
-    goto error;
-
-  if (!X509_set_version(x509, 2L))  // version 3
-    goto error;
-
-  // There are a lot of possible components for the name entries. In
-  // our P2P SSL mode however, the certificates are pre-exchanged
-  // (through the secure XMPP channel), and so the certificate
-  // identification is arbitrary. It can't be empty, so we set some
-  // arbitrary common_name. Note that this certificate goes out in
-  // clear during SSL negotiation, so there may be a privacy issue in
-  // putting anything recognizable here.
-  if ((name = X509_NAME_new()) == nullptr ||
-      !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
-                                  (unsigned char*)params.common_name.c_str(),
-                                  -1, -1, 0) ||
-      !X509_set_subject_name(x509, name) || !X509_set_issuer_name(x509, name))
-    goto error;
-
-  if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) ||
-      !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off))
-    goto error;
-
-  if (!X509_sign(x509, pkey, EVP_sha256()))
-    goto error;
-
-  BN_free(serial_number);
-  X509_NAME_free(name);
-  RTC_LOG(LS_INFO) << "Returning certificate";
-  return x509;
-
-error:
-  BN_free(serial_number);
-  X509_NAME_free(name);
-  X509_free(x509);
-  return nullptr;
-}
-
-// This dumps the SSL error stack to the log.
-static void LogSSLErrors(const std::string& prefix) {
-  char error_buf[200];
-  unsigned long err;
-
-  while ((err = ERR_get_error()) != 0) {
-    ERR_error_string_n(err, error_buf, sizeof(error_buf));
-    RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
-  }
-}
-
 OpenSSLKeyPair* OpenSSLKeyPair::Generate(const KeyParams& key_params) {
   EVP_PKEY* pkey = MakeKey(key_params);
   if (!pkey) {
-    LogSSLErrors("Generating key pair");
+    openssl::LogSSLErrors("Generating key pair");
     return nullptr;
   }
   return new OpenSSLKeyPair(pkey);
@@ -261,212 +191,6 @@
   return !(*this == other);
 }
 
-#if !defined(NDEBUG)
-// Print a certificate to the log, for debugging.
-static void PrintCert(X509* x509) {
-  BIO* temp_memory_bio = BIO_new(BIO_s_mem());
-  if (!temp_memory_bio) {
-    RTC_DLOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
-    return;
-  }
-  X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
-  BIO_write(temp_memory_bio, "\0", 1);
-  char* buffer;
-  BIO_get_mem_data(temp_memory_bio, &buffer);
-  RTC_DLOG(LS_VERBOSE) << buffer;
-  BIO_free(temp_memory_bio);
-}
-#endif
-
-OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) {
-  AddReference();
-}
-
-OpenSSLCertificate* OpenSSLCertificate::Generate(
-    OpenSSLKeyPair* key_pair,
-    const SSLIdentityParams& params) {
-  SSLIdentityParams actual_params(params);
-  if (actual_params.common_name.empty()) {
-    // Use a random string, arbitrarily 8chars long.
-    actual_params.common_name = CreateRandomString(8);
-  }
-  X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
-  if (!x509) {
-    LogSSLErrors("Generating certificate");
-    return nullptr;
-  }
-#if !defined(NDEBUG)
-  PrintCert(x509);
-#endif
-  OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
-  X509_free(x509);
-  return ret;
-}
-
-OpenSSLCertificate* OpenSSLCertificate::FromPEMString(
-    const std::string& pem_string) {
-  BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
-  if (!bio)
-    return nullptr;
-  BIO_set_mem_eof_return(bio, 0);
-  X509* x509 =
-      PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
-  BIO_free(bio);  // Frees the BIO, but not the pointed-to string.
-
-  if (!x509)
-    return nullptr;
-
-  OpenSSLCertificate* ret = new OpenSSLCertificate(x509);
-  X509_free(x509);
-  return ret;
-}
-
-// NOTE: This implementation only functions correctly after InitializeSSL
-// and before CleanupSSL.
-bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
-    std::string* algorithm) const {
-  int nid = X509_get_signature_nid(x509_);
-  switch (nid) {
-    case NID_md5WithRSA:
-    case NID_md5WithRSAEncryption:
-      *algorithm = DIGEST_MD5;
-      break;
-    case NID_ecdsa_with_SHA1:
-    case NID_dsaWithSHA1:
-    case NID_dsaWithSHA1_2:
-    case NID_sha1WithRSA:
-    case NID_sha1WithRSAEncryption:
-      *algorithm = DIGEST_SHA_1;
-      break;
-    case NID_ecdsa_with_SHA224:
-    case NID_sha224WithRSAEncryption:
-    case NID_dsa_with_SHA224:
-      *algorithm = DIGEST_SHA_224;
-      break;
-    case NID_ecdsa_with_SHA256:
-    case NID_sha256WithRSAEncryption:
-    case NID_dsa_with_SHA256:
-      *algorithm = DIGEST_SHA_256;
-      break;
-    case NID_ecdsa_with_SHA384:
-    case NID_sha384WithRSAEncryption:
-      *algorithm = DIGEST_SHA_384;
-      break;
-    case NID_ecdsa_with_SHA512:
-    case NID_sha512WithRSAEncryption:
-      *algorithm = DIGEST_SHA_512;
-      break;
-    default:
-      // Unknown algorithm.  There are several unhandled options that are less
-      // common and more complex.
-      RTC_LOG(LS_ERROR) << "Unknown signature algorithm NID: " << nid;
-      algorithm->clear();
-      return false;
-  }
-  return true;
-}
-
-bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
-                                       unsigned char* digest,
-                                       size_t size,
-                                       size_t* length) const {
-  return ComputeDigest(x509_, algorithm, digest, size, length);
-}
-
-bool OpenSSLCertificate::ComputeDigest(const X509* x509,
-                                       const std::string& algorithm,
-                                       unsigned char* digest,
-                                       size_t size,
-                                       size_t* length) {
-  const EVP_MD* md;
-  unsigned int n;
-
-  if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
-    return false;
-
-  if (size < static_cast<size_t>(EVP_MD_size(md)))
-    return false;
-
-  X509_digest(x509, md, digest, &n);
-
-  *length = n;
-
-  return true;
-}
-
-OpenSSLCertificate::~OpenSSLCertificate() {
-  X509_free(x509_);
-}
-
-OpenSSLCertificate* OpenSSLCertificate::GetReference() const {
-  return new OpenSSLCertificate(x509_);
-}
-
-std::string OpenSSLCertificate::ToPEMString() const {
-  BIO* bio = BIO_new(BIO_s_mem());
-  if (!bio) {
-    FATAL() << "unreachable code";
-  }
-  if (!PEM_write_bio_X509(bio, x509_)) {
-    BIO_free(bio);
-    FATAL() << "unreachable code";
-  }
-  BIO_write(bio, "\0", 1);
-  char* buffer;
-  BIO_get_mem_data(bio, &buffer);
-  std::string ret(buffer);
-  BIO_free(bio);
-  return ret;
-}
-
-void OpenSSLCertificate::ToDER(Buffer* der_buffer) const {
-  // In case of failure, make sure to leave the buffer empty.
-  der_buffer->SetSize(0);
-
-  // Calculates the DER representation of the certificate, from scratch.
-  BIO* bio = BIO_new(BIO_s_mem());
-  if (!bio) {
-    FATAL() << "unreachable code";
-  }
-  if (!i2d_X509_bio(bio, x509_)) {
-    BIO_free(bio);
-    FATAL() << "unreachable code";
-  }
-  char* data;
-  size_t length = BIO_get_mem_data(bio, &data);
-  der_buffer->SetData(data, length);
-  BIO_free(bio);
-}
-
-void OpenSSLCertificate::AddReference() const {
-  RTC_DCHECK(x509_ != nullptr);
-  X509_up_ref(x509_);
-}
-
-bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const {
-  return X509_cmp(x509_, other.x509_) == 0;
-}
-
-bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const {
-  return !(*this == other);
-}
-
-// Documented in sslidentity.h.
-int64_t OpenSSLCertificate::CertificateExpirationTime() const {
-  ASN1_TIME* expire_time = X509_get_notAfter(x509_);
-  bool long_format;
-
-  if (expire_time->type == V_ASN1_UTCTIME) {
-    long_format = false;
-  } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) {
-    long_format = true;
-  } else {
-    return -1;
-  }
-
-  return ASN1TimeToSec(expire_time->data, expire_time->length, long_format);
-}
-
 OpenSSLIdentity::OpenSSLIdentity(
     std::unique_ptr<OpenSSLKeyPair> key_pair,
     std::unique_ptr<OpenSSLCertificate> certificate)
@@ -543,8 +267,8 @@
 SSLIdentity* OpenSSLIdentity::FromPEMChainStrings(
     const std::string& private_key,
     const std::string& certificate_chain) {
-  BIO* bio =
-      BIO_new_mem_buf(certificate_chain.data(), certificate_chain.size());
+  BIO* bio = BIO_new_mem_buf(certificate_chain.data(),
+                             rtc::dchecked_cast<int>(certificate_chain.size()));
   if (!bio)
     return nullptr;
   BIO_set_mem_eof_return(bio, 0);
@@ -579,7 +303,7 @@
   }
 
   return new OpenSSLIdentity(std::move(key_pair),
-                             MakeUnique<SSLCertChain>(std::move(certs)));
+                             absl::make_unique<SSLCertChain>(std::move(certs)));
 }
 
 const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
@@ -591,8 +315,8 @@
 }
 
 OpenSSLIdentity* OpenSSLIdentity::GetReference() const {
-  return new OpenSSLIdentity(WrapUnique(key_pair_->GetReference()),
-                             WrapUnique(cert_chain_->Copy()));
+  return new OpenSSLIdentity(absl::WrapUnique(key_pair_->GetReference()),
+                             absl::WrapUnique(cert_chain_->Copy()));
 }
 
 bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
@@ -600,14 +324,14 @@
   const OpenSSLCertificate* cert = &certificate();
   if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
       SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
-    LogSSLErrors("Configuring key and certificate");
+    openssl::LogSSLErrors("Configuring key and certificate");
     return false;
   }
   // If a chain is available, use it.
   for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
     cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
     if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
-      LogSSLErrors("Configuring intermediate certificate");
+      openssl::LogSSLErrors("Configuring intermediate certificate");
       return false;
     }
   }
diff --git a/rtc_base/opensslidentity.h b/rtc_base/opensslidentity.h
index c1dc49f..3404427 100644
--- a/rtc_base/opensslidentity.h
+++ b/rtc_base/opensslidentity.h
@@ -19,6 +19,7 @@
 
 #include "rtc_base/checks.h"
 #include "rtc_base/constructormagic.h"
+#include "rtc_base/opensslcertificate.h"
 #include "rtc_base/sslidentity.h"
 
 typedef struct ssl_ctx_st SSL_CTX;
@@ -56,52 +57,6 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(OpenSSLKeyPair);
 };
 
-// OpenSSLCertificate encapsulates an OpenSSL X509* certificate object,
-// which is also reference counted inside the OpenSSL library.
-class OpenSSLCertificate : public SSLCertificate {
- public:
-  // Caller retains ownership of the X509 object.
-  explicit OpenSSLCertificate(X509* x509);
-
-  static OpenSSLCertificate* Generate(OpenSSLKeyPair* key_pair,
-                                      const SSLIdentityParams& params);
-  static OpenSSLCertificate* FromPEMString(const std::string& pem_string);
-
-  ~OpenSSLCertificate() override;
-
-  OpenSSLCertificate* GetReference() const override;
-
-  X509* x509() const { return x509_; }
-
-  std::string ToPEMString() const override;
-  void ToDER(Buffer* der_buffer) const override;
-  bool operator==(const OpenSSLCertificate& other) const;
-  bool operator!=(const OpenSSLCertificate& other) const;
-
-  // Compute the digest of the certificate given algorithm
-  bool ComputeDigest(const std::string& algorithm,
-                     unsigned char* digest,
-                     size_t size,
-                     size_t* length) const override;
-
-  // Compute the digest of a certificate as an X509 *
-  static bool ComputeDigest(const X509* x509,
-                            const std::string& algorithm,
-                            unsigned char* digest,
-                            size_t size,
-                            size_t* length);
-
-  bool GetSignatureDigestAlgorithm(std::string* algorithm) const override;
-
-  int64_t CertificateExpirationTime() const override;
-
- private:
-  void AddReference() const;
-
-  X509* x509_;
-  RTC_DISALLOW_COPY_AND_ASSIGN(OpenSSLCertificate);
-};
-
 // Holds a keypair and certificate together, and a method to generate
 // them consistently.
 class OpenSSLIdentity : public SSLIdentity {
diff --git a/rtc_base/opensslsessioncache.h b/rtc_base/opensslsessioncache.h
index ee5b525..c74b7bf 100644
--- a/rtc_base/opensslsessioncache.h
+++ b/rtc_base/opensslsessioncache.h
@@ -18,6 +18,10 @@
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/sslstreamadapter.h"
 
+#ifndef OPENSSL_IS_BORINGSSL
+typedef struct ssl_session_st SSL_SESSION;
+#endif
+
 namespace rtc {
 
 // The OpenSSLSessionCache maps hostnames to SSL_SESSIONS. This cache is
diff --git a/rtc_base/opensslstreamadapter.cc b/rtc_base/opensslstreamadapter.cc
index c0fb108..fd54a08 100644
--- a/rtc_base/opensslstreamadapter.cc
+++ b/rtc_base/opensslstreamadapter.cc
@@ -37,7 +37,7 @@
 #include "rtc_base/timeutils.h"
 
 namespace {
-  bool g_use_time_callback_for_testing = false;
+bool g_use_time_callback_for_testing = false;
 }
 
 namespace rtc {
@@ -77,8 +77,10 @@
   const char* rfc_name;
 };
 
-#define DEFINE_CIPHER_ENTRY_SSL3(name)  {SSL3_CK_##name, "TLS_"#name}
-#define DEFINE_CIPHER_ENTRY_TLS1(name)  {TLS1_CK_##name, "TLS_"#name}
+#define DEFINE_CIPHER_ENTRY_SSL3(name) \
+  { SSL3_CK_##name, "TLS_" #name }
+#define DEFINE_CIPHER_ENTRY_TLS1(name) \
+  { TLS1_CK_##name, "TLS_" #name }
 
 // The "SSL_CIPHER_standard_name" function is only available in OpenSSL when
 // compiled with tracing, so we need to define the mapping manually here.
@@ -452,7 +454,7 @@
   if (state_ != SSL_CONNECTED)
     return false;
 
-  const SRTP_PROTECTION_PROFILE *srtp_profile =
+  const SRTP_PROTECTION_PROFILE* srtp_profile =
       SSL_get_selected_srtp_profile(ssl_);
 
   if (!srtp_profile)
@@ -497,8 +499,7 @@
   ssl_max_version_ = version;
 }
 
-void OpenSSLStreamAdapter::SetInitialRetransmissionTimeout(
-    int timeout_ms) {
+void OpenSSLStreamAdapter::SetInitialRetransmissionTimeout(int timeout_ms) {
   RTC_DCHECK(ssl_ctx_ == nullptr);
   dtls_handshake_timeout_ms_ = timeout_ms;
 }
@@ -507,31 +508,33 @@
 // StreamInterface Implementation
 //
 
-StreamResult OpenSSLStreamAdapter::Write(const void* data, size_t data_len,
-                                         size_t* written, int* error) {
+StreamResult OpenSSLStreamAdapter::Write(const void* data,
+                                         size_t data_len,
+                                         size_t* written,
+                                         int* error) {
   RTC_LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Write(" << data_len << ")";
 
   switch (state_) {
-  case SSL_NONE:
-    // pass-through in clear text
-    return StreamAdapterInterface::Write(data, data_len, written, error);
+    case SSL_NONE:
+      // pass-through in clear text
+      return StreamAdapterInterface::Write(data, data_len, written, error);
 
-  case SSL_WAIT:
-  case SSL_CONNECTING:
-    return SR_BLOCK;
-
-  case SSL_CONNECTED:
-    if (waiting_to_verify_peer_certificate()) {
+    case SSL_WAIT:
+    case SSL_CONNECTING:
       return SR_BLOCK;
-    }
-    break;
 
-  case SSL_ERROR:
-  case SSL_CLOSED:
-  default:
-    if (error)
-      *error = ssl_error_code_;
-    return SR_ERROR;
+    case SSL_CONNECTED:
+      if (waiting_to_verify_peer_certificate()) {
+        return SR_BLOCK;
+      }
+      break;
+
+    case SSL_ERROR:
+    case SSL_CLOSED:
+    default:
+      if (error)
+        *error = ssl_error_code_;
+      return SR_ERROR;
   }
 
   // OpenSSL will return an error if we try to write zero bytes
@@ -546,33 +549,35 @@
   int code = SSL_write(ssl_, data, checked_cast<int>(data_len));
   int ssl_error = SSL_get_error(ssl_, code);
   switch (ssl_error) {
-  case SSL_ERROR_NONE:
-    RTC_LOG(LS_VERBOSE) << " -- success";
-    RTC_DCHECK_GT(code, 0);
-    RTC_DCHECK_LE(code, data_len);
-    if (written)
-      *written = code;
-    return SR_SUCCESS;
-  case SSL_ERROR_WANT_READ:
-    RTC_LOG(LS_VERBOSE) << " -- error want read";
-    ssl_write_needs_read_ = true;
-    return SR_BLOCK;
-  case SSL_ERROR_WANT_WRITE:
-    RTC_LOG(LS_VERBOSE) << " -- error want write";
-    return SR_BLOCK;
+    case SSL_ERROR_NONE:
+      RTC_LOG(LS_VERBOSE) << " -- success";
+      RTC_DCHECK_GT(code, 0);
+      RTC_DCHECK_LE(code, data_len);
+      if (written)
+        *written = code;
+      return SR_SUCCESS;
+    case SSL_ERROR_WANT_READ:
+      RTC_LOG(LS_VERBOSE) << " -- error want read";
+      ssl_write_needs_read_ = true;
+      return SR_BLOCK;
+    case SSL_ERROR_WANT_WRITE:
+      RTC_LOG(LS_VERBOSE) << " -- error want write";
+      return SR_BLOCK;
 
-  case SSL_ERROR_ZERO_RETURN:
-  default:
-    Error("SSL_write", (ssl_error ? ssl_error : -1), 0, false);
-    if (error)
-      *error = ssl_error_code_;
-    return SR_ERROR;
+    case SSL_ERROR_ZERO_RETURN:
+    default:
+      Error("SSL_write", (ssl_error ? ssl_error : -1), 0, false);
+      if (error)
+        *error = ssl_error_code_;
+      return SR_ERROR;
   }
   // not reached
 }
 
-StreamResult OpenSSLStreamAdapter::Read(void* data, size_t data_len,
-                                        size_t* read, int* error) {
+StreamResult OpenSSLStreamAdapter::Read(void* data,
+                                        size_t data_len,
+                                        size_t* read,
+                                        int* error) {
   RTC_LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::Read(" << data_len << ")";
   switch (state_) {
     case SSL_NONE:
@@ -699,7 +704,8 @@
   // not reached
 }
 
-void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, int events,
+void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream,
+                                   int events,
                                    int err) {
   int events_to_signal = 0;
   int signal_error = 0;
@@ -717,12 +723,12 @@
       }
     }
   }
-  if ((events & (SE_READ|SE_WRITE))) {
+  if ((events & (SE_READ | SE_WRITE))) {
     RTC_LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent"
                         << ((events & SE_READ) ? " SE_READ" : "")
                         << ((events & SE_WRITE) ? " SE_WRITE" : "");
     if (state_ == SSL_NONE) {
-      events_to_signal |= events & (SE_READ|SE_WRITE);
+      events_to_signal |= events & (SE_READ | SE_WRITE);
     } else if (state_ == SSL_CONNECTING) {
       if (int err = ContinueSSL()) {
         Error("ContinueSSL", err, 0, true);
@@ -791,7 +797,7 @@
   }
 
   SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE |
-               SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+                         SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 
 #if !defined(OPENSSL_IS_BORINGSSL)
   // Specify an ECDH group for ECDHE ciphers, otherwise OpenSSL cannot
@@ -849,9 +855,8 @@
 
         Thread::Current()->PostDelayed(RTC_FROM_HERE, delay, this, MSG_TIMEOUT,
                                        0);
-        }
       }
-      break;
+    } break;
 
     case SSL_ERROR_WANT_WRITE:
       RTC_LOG(LS_VERBOSE) << " -- error want write";
@@ -927,7 +932,6 @@
   Thread::Current()->Clear(this, MSG_TIMEOUT);
 }
 
-
 void OpenSSLStreamAdapter::OnMessage(Message* msg) {
   // Process our own messages and then pass others to the superclass
   if (MSG_TIMEOUT == msg->message_id) {
@@ -943,9 +947,8 @@
   SSL_CTX* ctx = nullptr;
 
 #ifdef OPENSSL_IS_BORINGSSL
-    ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
-        DTLS_method() : TLS_method());
-    // Version limiting for BoringSSL will be done below.
+  ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ? DTLS_method() : TLS_method());
+// Version limiting for BoringSSL will be done below.
 #else
   const SSL_METHOD* method;
   switch (ssl_max_version_) {
@@ -991,21 +994,21 @@
     return nullptr;
 
 #ifdef OPENSSL_IS_BORINGSSL
-  SSL_CTX_set_min_proto_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
-      DTLS1_VERSION : TLS1_VERSION);
+  SSL_CTX_set_min_proto_version(
+      ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION);
   switch (ssl_max_version_) {
     case SSL_PROTOCOL_TLS_10:
-      SSL_CTX_set_max_proto_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
-          DTLS1_VERSION : TLS1_VERSION);
+      SSL_CTX_set_max_proto_version(
+          ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_VERSION);
       break;
     case SSL_PROTOCOL_TLS_11:
-      SSL_CTX_set_max_proto_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
-          DTLS1_VERSION : TLS1_1_VERSION);
+      SSL_CTX_set_max_proto_version(
+          ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_VERSION : TLS1_1_VERSION);
       break;
     case SSL_PROTOCOL_TLS_12:
     default:
-      SSL_CTX_set_max_proto_version(ctx, ssl_mode_ == SSL_MODE_DTLS ?
-          DTLS1_2_VERSION : TLS1_2_VERSION);
+      SSL_CTX_set_max_proto_version(
+          ctx, ssl_mode_ == SSL_MODE_DTLS ? DTLS1_2_VERSION : TLS1_2_VERSION);
       break;
   }
   if (g_use_time_callback_for_testing) {
@@ -1108,10 +1111,9 @@
   stream->peer_cert_chain_.reset(new SSLCertChain(std::move(cert_chain)));
 #else
   // Record the peer's certificate.
-  X509* cert = SSL_get_peer_certificate(ssl);
+  X509* cert = X509_STORE_CTX_get0_cert(store);
   stream->peer_cert_chain_.reset(
       new SSLCertChain(new OpenSSLCertificate(cert)));
-  X509_free(cert);
 #endif
 
   // If the peer certificate digest isn't known yet, we'll wait to verify
@@ -1147,26 +1149,26 @@
 
 // TODO(torbjorng): Perhaps add more cipher suites to these lists.
 static const cipher_list OK_RSA_ciphers[] = {
-  CDEF(ECDHE_RSA_WITH_AES_128_CBC_SHA),
-  CDEF(ECDHE_RSA_WITH_AES_256_CBC_SHA),
-  CDEF(ECDHE_RSA_WITH_AES_128_GCM_SHA256),
+    CDEF(ECDHE_RSA_WITH_AES_128_CBC_SHA),
+    CDEF(ECDHE_RSA_WITH_AES_256_CBC_SHA),
+    CDEF(ECDHE_RSA_WITH_AES_128_GCM_SHA256),
 #ifdef TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA256
-  CDEF(ECDHE_RSA_WITH_AES_256_GCM_SHA256),
+    CDEF(ECDHE_RSA_WITH_AES_256_GCM_SHA256),
 #endif
 #ifdef TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
-  CDEF(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
+    CDEF(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 };
 
 static const cipher_list OK_ECDSA_ciphers[] = {
-  CDEF(ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
-  CDEF(ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
-  CDEF(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
+    CDEF(ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
+    CDEF(ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
+    CDEF(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
 #ifdef TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA256
-  CDEF(ECDHE_ECDSA_WITH_AES_256_GCM_SHA256),
+    CDEF(ECDHE_ECDSA_WITH_AES_256_GCM_SHA256),
 #endif
 #ifdef TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
-  CDEF(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
+    CDEF(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
 #endif
 };
 #undef CDEF
diff --git a/rtc_base/opensslstreamadapter.h b/rtc_base/opensslstreamadapter.h
index 7a6e099..61ffc3d 100644
--- a/rtc_base/opensslstreamadapter.h
+++ b/rtc_base/opensslstreamadapter.h
@@ -13,8 +13,8 @@
 
 #include <openssl/ossl_typ.h>
 
-#include <string>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "rtc_base/buffer.h"
@@ -125,14 +125,14 @@
     // Before calling one of the StartSSL methods, data flows
     // in clear text.
     SSL_NONE,
-    SSL_WAIT,  // waiting for the stream to open to start SSL negotiation
+    SSL_WAIT,        // waiting for the stream to open to start SSL negotiation
     SSL_CONNECTING,  // SSL negotiation in progress
-    SSL_CONNECTED,  // SSL stream successfully established
-    SSL_ERROR,  // some SSL error occurred, stream is closed
-    SSL_CLOSED  // Clean close
+    SSL_CONNECTED,   // SSL stream successfully established
+    SSL_ERROR,       // some SSL error occurred, stream is closed
+    SSL_CLOSED       // Clean close
   };
 
-  enum { MSG_TIMEOUT = MSG_MAX+1};
+  enum { MSG_TIMEOUT = MSG_MAX + 1 };
 
   // The following three methods return 0 on success and a negative
   // error code on failure. The error code may be from OpenSSL or -1
diff --git a/rtc_base/opensslutility.cc b/rtc_base/opensslutility.cc
new file mode 100644
index 0000000..2b4ffb6
--- /dev/null
+++ b/rtc_base/opensslutility.cc
@@ -0,0 +1,135 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+
+#include "rtc_base/opensslutility.h"
+
+#include <memory>
+
+#if defined(WEBRTC_POSIX)
+#include <unistd.h>
+#endif
+
+#if defined(WEBRTC_WIN)
+// Must be included first before openssl headers.
+#include "rtc_base/win32.h"  // NOLINT
+#endif                       // WEBRTC_WIN
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/openssl.h"
+#include "rtc_base/opensslcertificate.h"
+#ifdef WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+#include "rtc_base/sslroots.h"
+#endif  // WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+
+namespace rtc {
+namespace openssl {
+
+// Holds various helper methods.
+namespace {
+void LogCertificates(SSL* ssl, X509* certificate) {
+// Logging certificates is extremely verbose. So it is disabled by default.
+#ifdef LOG_CERTIFICATES
+  BIO* mem = BIO_new(BIO_s_mem());
+  if (mem == nullptr) {
+    RTC_DLOG(LS_ERROR) << "BIO_new() failed to allocate memory.";
+    return;
+  }
+
+  RTC_DLOG(LS_INFO) << "Certificate from server:";
+  X509_print_ex(mem, certificate, XN_FLAG_SEP_CPLUS_SPC, X509_FLAG_NO_HEADER);
+  BIO_write(mem, "\0", 1);
+
+  char* buffer = nullptr;
+  BIO_get_mem_data(mem, &buffer);
+  if (buffer != nullptr) {
+    RTC_DLOG(LS_INFO) << buffer;
+  } else {
+    RTC_DLOG(LS_ERROR) << "BIO_get_mem_data() failed to get buffer.";
+  }
+  BIO_free(mem);
+
+  const char* cipher_name = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
+  if (cipher_name != nullptr) {
+    RTC_DLOG(LS_INFO) << "Cipher: " << cipher_name;
+  } else {
+    RTC_DLOG(LS_ERROR) << "SSL_CIPHER_DESCRIPTION() failed to get cipher_name.";
+  }
+#endif
+}
+}  // namespace
+
+bool VerifyPeerCertMatchesHost(SSL* ssl, const std::string& host) {
+  if (host.empty()) {
+    RTC_DLOG(LS_ERROR) << "Hostname is empty. Cannot verify peer certificate.";
+    return false;
+  }
+
+  if (ssl == nullptr) {
+    RTC_DLOG(LS_ERROR) << "SSL is nullptr. Cannot verify peer certificate.";
+    return false;
+  }
+
+  X509* certificate = SSL_get_peer_certificate(ssl);
+  if (certificate == nullptr) {
+    RTC_DLOG(LS_ERROR)
+        << "SSL_get_peer_certificate failed. This should never happen.";
+    return false;
+  }
+
+  LogCertificates(ssl, certificate);
+
+  bool is_valid_cert_name =
+      X509_check_host(certificate, host.c_str(), host.size(), 0, nullptr) == 1;
+  X509_free(certificate);
+  return is_valid_cert_name;
+}
+
+void LogSSLErrors(const std::string& prefix) {
+  char error_buf[200];
+  unsigned long err;  // NOLINT
+
+  while ((err = ERR_get_error()) != 0) {
+    ERR_error_string_n(err, error_buf, sizeof(error_buf));
+    RTC_LOG(LS_ERROR) << prefix << ": " << error_buf << "\n";
+  }
+}
+
+#ifdef WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+bool LoadBuiltinSSLRootCertificates(SSL_CTX* ctx) {
+  int count_of_added_certs = 0;
+  for (size_t i = 0; i < arraysize(kSSLCertCertificateList); i++) {
+    const unsigned char* cert_buffer = kSSLCertCertificateList[i];
+    size_t cert_buffer_len = kSSLCertCertificateSizeList[i];
+    X509* cert = d2i_X509(nullptr, &cert_buffer,
+                          checked_cast<long>(cert_buffer_len));  // NOLINT
+    if (cert) {
+      int return_value = X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx), cert);
+      if (return_value == 0) {
+        RTC_LOG(LS_WARNING) << "Unable to add certificate.";
+      } else {
+        count_of_added_certs++;
+      }
+      X509_free(cert);
+    }
+  }
+  return count_of_added_certs > 0;
+}
+#endif  // WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+
+}  // namespace openssl
+}  // namespace rtc
diff --git a/rtc_base/opensslutility.h b/rtc_base/opensslutility.h
new file mode 100644
index 0000000..f579f50
--- /dev/null
+++ b/rtc_base/opensslutility.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 2018 The WebRTC 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 RTC_BASE_OPENSSLUTILITY_H_
+#define RTC_BASE_OPENSSLUTILITY_H_
+
+#include <openssl/ossl_typ.h>
+#include <string>
+#include "rtc_base/sslcertificate.h"
+
+namespace rtc {
+// The openssl namespace holds static helper methods. All methods related
+// to OpenSSL that are commonly used and don't require global state should be
+// placed here.
+namespace openssl {
+// Verifies that the hostname provided matches that in the peer certificate
+// attached to this SSL state.
+bool VerifyPeerCertMatchesHost(SSL* ssl, const std::string& host);
+
+// Logs all the errors in the OpenSSL errror queue from the current thread. A
+// prefix can be provided for context.
+void LogSSLErrors(const std::string& prefix);
+
+#ifdef WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+// Attempt to add the certificates from the loader into the SSL_CTX. False is
+// returned only if there are no certificates returned from the loader or none
+// of them can be added to the TrustStore for the provided context.
+bool LoadBuiltinSSLRootCertificates(SSL_CTX* ssl_ctx);
+#endif  // WEBRTC_BUILT_IN_SSL_ROOT_CERTIFICATES
+
+}  // namespace openssl
+}  // namespace rtc
+
+#endif  // RTC_BASE_OPENSSLUTILITY_H_
diff --git a/rtc_base/opensslutility_unittest.cc b/rtc_base/opensslutility_unittest.cc
new file mode 100644
index 0000000..2f952ae
--- /dev/null
+++ b/rtc_base/opensslutility_unittest.cc
@@ -0,0 +1,277 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+
+#include <string>
+#include <vector>
+
+#if defined(WEBRTC_POSIX)
+#include <unistd.h>
+#endif
+
+#if defined(WEBRTC_WIN)
+// Must be included first before openssl headers.
+#include "rtc_base/win32.h"  // NOLINT
+#endif                       // WEBRTC_WIN
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/gunit.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/openssl.h"
+#include "rtc_base/opensslutility.h"
+#include "rtc_base/sslroots.h"
+#include "test/gmock.h"
+
+namespace rtc {
+namespace {
+// Fake P-256 key for use with the test certificates below.
+const unsigned char kFakeSSLPrivateKey[] = {
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+    0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
+    0x07, 0x0f, 0x08, 0x72, 0x7a, 0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9,
+    0x4d, 0x89, 0x68, 0x77, 0x08, 0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e,
+    0xe8, 0xd1, 0xc9, 0xce, 0x0a, 0x8b, 0xb4, 0x6a, 0xa1, 0x44, 0x03, 0x42,
+    0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f,
+    0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
+    0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7,
+    0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2,
+    0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94,
+    0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1};
+
+// A self-signed certificate with CN *.webrtc.org and SANs foo.test, *.bar.test,
+// and test.webrtc.org.
+const unsigned char kFakeSSLCertificate[] = {
+    0x30, 0x82, 0x02, 0x9e, 0x30, 0x82, 0x02, 0x42, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x09, 0x00, 0xc8, 0x83, 0x59, 0x4d, 0x90, 0xc3, 0x5f, 0xc8,
+    0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+    0x05, 0x00, 0x30, 0x81, 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+    0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+    0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06,
+    0x03, 0x55, 0x04, 0x0a, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57,
+    0x65, 0x62, 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65,
+    0x73, 0x74, 0x69, 0x6e, 0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55,
+    0x04, 0x0b, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62,
+    0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74,
+    0x69, 0x6e, 0x67, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03,
+    0x0c, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f,
+    0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, 0x30, 0x33,
+    0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30,
+    0x34, 0x30, 0x33, 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x30, 0x81,
+    0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+    0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+    0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0a,
+    0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54,
+    0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e,
+    0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x23,
+    0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
+    0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x31,
+    0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0c, 0x2a, 0x2e,
+    0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59,
+    0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
+    0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
+    0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
+    0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46,
+    0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6,
+    0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c,
+    0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d,
+    0x4b, 0xcf, 0x72, 0x22, 0xc1, 0xa3, 0x81, 0x86, 0x30, 0x81, 0x83, 0x30,
+    0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0xc0,
+    0x9a, 0xa7, 0x22, 0xaf, 0xf8, 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a,
+    0xb6, 0xdc, 0x64, 0x89, 0xdb, 0xd4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+    0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb7, 0xc0, 0x9a, 0xa7, 0x22,
+    0xaf, 0xf8, 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, 0xb6, 0xdc, 0x64,
+    0x89, 0xdb, 0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+    0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x30, 0x06, 0x03,
+    0x55, 0x1d, 0x11, 0x04, 0x29, 0x30, 0x27, 0x82, 0x08, 0x66, 0x6f, 0x6f,
+    0x2e, 0x74, 0x65, 0x73, 0x74, 0x82, 0x0a, 0x2a, 0x2e, 0x62, 0x61, 0x72,
+    0x2e, 0x74, 0x65, 0x73, 0x74, 0x82, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x2e,
+    0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0c,
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00,
+    0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0x81, 0xcb, 0xe2, 0xf9,
+    0x04, 0xba, 0xf7, 0xfd, 0x3f, 0x0d, 0x56, 0x37, 0xdb, 0x65, 0x68, 0x07,
+    0x28, 0x8d, 0xc5, 0xe1, 0x73, 0xb7, 0xce, 0xa5, 0x20, 0x65, 0x15, 0xb2,
+    0xc6, 0x37, 0x8c, 0x5a, 0x02, 0x20, 0x24, 0x62, 0x74, 0xe8, 0xd9, 0x80,
+    0x78, 0x2a, 0xbb, 0x87, 0xff, 0x49, 0x99, 0xdb, 0x94, 0xab, 0x06, 0x91,
+    0xc0, 0x7a, 0xa4, 0x62, 0x61, 0x98, 0x97, 0x47, 0xb7, 0x64, 0x2b, 0x99,
+    0xc3, 0x71};
+
+// A self-signed SSL certificate with only the legacy CN field *.webrtc.org.
+const unsigned char kFakeSSLCertificateLegacy[] = {
+    0x30, 0x82, 0x02, 0x6a, 0x30, 0x82, 0x02, 0x0e, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x09, 0x00, 0xc8, 0x83, 0x59, 0x4d, 0x90, 0xc3, 0x5f, 0xc8,
+    0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+    0x05, 0x00, 0x30, 0x81, 0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+    0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+    0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06,
+    0x03, 0x55, 0x04, 0x0a, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57,
+    0x65, 0x62, 0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+    0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65,
+    0x73, 0x74, 0x69, 0x6e, 0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55,
+    0x04, 0x0b, 0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62,
+    0x52, 0x54, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+    0x61, 0x74, 0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74,
+    0x69, 0x6e, 0x67, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03,
+    0x0c, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f,
+    0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, 0x30, 0x33,
+    0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30,
+    0x34, 0x30, 0x33, 0x32, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x30, 0x81,
+    0x8d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+    0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+    0x02, 0x57, 0x41, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0a,
+    0x0c, 0x23, 0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54,
+    0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x65, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e,
+    0x67, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x23,
+    0x46, 0x61, 0x6b, 0x65, 0x20, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x20,
+    0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
+    0x46, 0x6f, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x31,
+    0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0c, 0x2a, 0x2e,
+    0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59,
+    0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
+    0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
+    0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
+    0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46,
+    0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6,
+    0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c,
+    0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d,
+    0x4b, 0xcf, 0x72, 0x22, 0xc1, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06,
+    0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0xc0, 0x9a, 0xa7,
+    0x22, 0xaf, 0xf8, 0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, 0xb6, 0xdc,
+    0x64, 0x89, 0xdb, 0xd4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+    0x18, 0x30, 0x16, 0x80, 0x14, 0xb7, 0xc0, 0x9a, 0xa7, 0x22, 0xaf, 0xf8,
+    0x7d, 0xff, 0x68, 0xdb, 0x80, 0xac, 0x0a, 0xb6, 0xdc, 0x64, 0x89, 0xdb,
+    0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+    0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x48, 0x00, 0x30,
+    0x45, 0x02, 0x21, 0x00, 0xae, 0x51, 0xbc, 0x0f, 0x28, 0x29, 0xd9, 0x35,
+    0x95, 0xcc, 0x68, 0xf1, 0xc6, 0x3e, 0xfe, 0x56, 0xfd, 0x7f, 0xd2, 0x03,
+    0x6d, 0x09, 0xc7, 0x9b, 0x83, 0x93, 0xd6, 0xd0, 0xfe, 0x45, 0x34, 0x7c,
+    0x02, 0x20, 0x6b, 0xaa, 0x95, 0x8c, 0xfc, 0x29, 0x5e, 0x5e, 0xc9, 0xf5,
+    0x84, 0x0b, 0xc7, 0x15, 0x86, 0xc3, 0xfc, 0x48, 0x55, 0xb5, 0x81, 0x94,
+    0x73, 0xbd, 0x18, 0xcd, 0x9d, 0x92, 0x47, 0xaa, 0xfd, 0x18};
+
+// Creates a client SSL that has completed handshaking with a server that uses
+// the specified certificate (which must have private key kFakeSSLPrivateKey).
+// The server is deallocated. This client will have a peer certificate available
+// and is thus suitable for testing VerifyPeerCertMatchesHost.
+SSL* CreateSSLWithPeerCertificate(const unsigned char* cert, size_t cert_len) {
+  X509* x509 =
+      d2i_X509(nullptr, &cert, checked_cast<long>(cert_len));  // NOLINT
+  RTC_CHECK(x509);
+
+  const unsigned char* key_ptr = kFakeSSLPrivateKey;
+  EVP_PKEY* key = d2i_PrivateKey(
+      EVP_PKEY_EC, nullptr, &key_ptr,
+      checked_cast<long>(arraysize(kFakeSSLPrivateKey)));  // NOLINT
+  RTC_CHECK(key);
+
+  SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
+  SSL* client = SSL_new(ctx);
+  SSL* server = SSL_new(ctx);
+  SSL_set_connect_state(client);
+  SSL_set_accept_state(server);
+
+  RTC_CHECK(SSL_use_certificate(server, x509));
+  RTC_CHECK(SSL_use_PrivateKey(server, key));
+
+  BIO* bio1;
+  BIO* bio2;
+  BIO_new_bio_pair(&bio1, 0, &bio2, 0);
+  // SSL_set_bio takes ownership of the BIOs.
+  SSL_set_bio(client, bio1, bio1);
+  SSL_set_bio(server, bio2, bio2);
+
+  for (;;) {
+    int client_ret = SSL_do_handshake(client);
+    int client_err = SSL_get_error(client, client_ret);
+    RTC_CHECK(client_err == SSL_ERROR_NONE ||
+              client_err == SSL_ERROR_WANT_READ ||
+              client_err == SSL_ERROR_WANT_WRITE);
+
+    int server_ret = SSL_do_handshake(server);
+    int server_err = SSL_get_error(server, server_ret);
+    RTC_CHECK(server_err == SSL_ERROR_NONE ||
+              server_err == SSL_ERROR_WANT_READ ||
+              server_err == SSL_ERROR_WANT_WRITE);
+
+    if (client_ret == 1 && server_ret == 1) {
+      break;
+    }
+  }
+
+  SSL_free(server);
+  SSL_CTX_free(ctx);
+  EVP_PKEY_free(key);
+  X509_free(x509);
+  return client;
+}
+}  // namespace
+
+TEST(OpenSSLUtilityTest, VerifyPeerCertMatchesHostFailsOnNoPeerCertificate) {
+  SSL_CTX* ssl_ctx = SSL_CTX_new(DTLSv1_2_client_method());
+  SSL* ssl = SSL_new(ssl_ctx);
+
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "webrtc.org"));
+
+  SSL_free(ssl);
+  SSL_CTX_free(ssl_ctx);
+}
+
+TEST(OpenSSLUtilityTest, VerifyPeerCertMatchesHost) {
+  SSL* ssl = CreateSSLWithPeerCertificate(kFakeSSLCertificate,
+                                          arraysize(kFakeSSLCertificate));
+
+  // Each of the names in the SAN list is valid.
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "foo.test"));
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "a.bar.test"));
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "b.bar.test"));
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "test.webrtc.org"));
+
+  // If the SAN list is present, the CN is not checked for hosts.
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "www.webrtc.org"));
+
+  // Additional cases around wildcards.
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "a.b.bar.test"));
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "notbar.test"));
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "bar.test"));
+
+  SSL_free(ssl);
+}
+
+TEST(OpenSSLUtilityTest, VerifyPeerCertMatchesHostLegacy) {
+  SSL* ssl = CreateSSLWithPeerCertificate(kFakeSSLCertificateLegacy,
+                                          arraysize(kFakeSSLCertificateLegacy));
+
+  // If there is no SAN list, WebRTC still implements the legacy mechanism which
+  // checks the CN, no longer supported by modern browsers.
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "www.webrtc.org"));
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "alice.webrtc.org"));
+  EXPECT_TRUE(openssl::VerifyPeerCertMatchesHost(ssl, "bob.webrtc.org"));
+
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "a.b.webrtc.org"));
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "notwebrtc.org"));
+  EXPECT_FALSE(openssl::VerifyPeerCertMatchesHost(ssl, "webrtc.org"));
+
+  SSL_free(ssl);
+}
+
+}  // namespace rtc
diff --git a/rtc_base/optionsfile.cc b/rtc_base/optionsfile.cc
index c3b6a6a..8d2d2e0 100644
--- a/rtc_base/optionsfile.cc
+++ b/rtc_base/optionsfile.cc
@@ -18,8 +18,7 @@
 
 namespace rtc {
 
-OptionsFile::OptionsFile(const std::string &path) : path_(path) {
-}
+OptionsFile::OptionsFile(const std::string& path) : path_(path) {}
 
 OptionsFile::~OptionsFile() = default;
 
@@ -75,8 +74,8 @@
   int error;
   for (OptionsMap::const_iterator i = options_.begin(); i != options_.end();
        ++i) {
-    res = stream.WriteAll(i->first.c_str(), i->first.length(), &written,
-        &error);
+    res =
+        stream.WriteAll(i->first.c_str(), i->first.length(), &written, &error);
     if (res != SR_SUCCESS) {
       break;
     }
@@ -85,7 +84,7 @@
       break;
     }
     res = stream.WriteAll(i->second.c_str(), i->second.length(), &written,
-        &error);
+                          &error);
     if (res != SR_SUCCESS) {
       break;
     }
@@ -102,7 +101,7 @@
   }
 }
 
-bool OptionsFile::IsLegalName(const std::string &name) {
+bool OptionsFile::IsLegalName(const std::string& name) {
   for (size_t pos = 0; pos < name.length(); ++pos) {
     if (name[pos] == '\n' || name[pos] == '\\' || name[pos] == '=') {
       // Illegal character.
@@ -113,7 +112,7 @@
   return true;
 }
 
-bool OptionsFile::IsLegalValue(const std::string &value) {
+bool OptionsFile::IsLegalValue(const std::string& value) {
   for (size_t pos = 0; pos < value.length(); ++pos) {
     if (value[pos] == '\n' || value[pos] == '\\') {
       // Illegal character.
@@ -125,7 +124,7 @@
 }
 
 bool OptionsFile::GetStringValue(const std::string& option,
-                                 std::string *out_val) const {
+                                 std::string* out_val) const {
   RTC_LOG(LS_VERBOSE) << "OptionsFile::GetStringValue " << option;
   if (!IsLegalName(option)) {
     return false;
@@ -138,8 +137,7 @@
   return true;
 }
 
-bool OptionsFile::GetIntValue(const std::string& option,
-                              int *out_val) const {
+bool OptionsFile::GetIntValue(const std::string& option, int* out_val) const {
   RTC_LOG(LS_VERBOSE) << "OptionsFile::GetIntValue " << option;
   if (!IsLegalName(option)) {
     return false;
@@ -162,8 +160,7 @@
   return true;
 }
 
-bool OptionsFile::SetIntValue(const std::string& option,
-                              int value) {
+bool OptionsFile::SetIntValue(const std::string& option, int value) {
   RTC_LOG(LS_VERBOSE) << "OptionsFile::SetIntValue " << option << ":" << value;
   if (!IsLegalName(option)) {
     return false;
diff --git a/rtc_base/optionsfile.h b/rtc_base/optionsfile.h
index 90976ac..55660ff 100644
--- a/rtc_base/optionsfile.h
+++ b/rtc_base/optionsfile.h
@@ -21,7 +21,7 @@
 // first-class options storage system.
 class OptionsFile {
  public:
-  OptionsFile(const std::string &path);
+  OptionsFile(const std::string& path);
   ~OptionsFile();
 
   // Loads the file from disk, overwriting the in-memory values.
@@ -38,8 +38,8 @@
  private:
   typedef std::map<std::string, std::string> OptionsMap;
 
-  static bool IsLegalName(const std::string &name);
-  static bool IsLegalValue(const std::string &value);
+  static bool IsLegalName(const std::string& name);
+  static bool IsLegalValue(const std::string& value);
 
   std::string path_;
   OptionsMap options_;
diff --git a/rtc_base/optionsfile_unittest.cc b/rtc_base/optionsfile_unittest.cc
index d2e3cbd..fc5bc82 100644
--- a/rtc_base/optionsfile_unittest.cc
+++ b/rtc_base/optionsfile_unittest.cc
@@ -26,16 +26,18 @@
 static const std::string kValueWithEquals = "baz=quux";
 static const std::string kValueWithNewline = "baz\nquux";
 static const std::string kEmptyString = "";
-static const char kOptionWithUtf8[] = {'O', 'p', 't', '\302', '\256', 'i', 'o',
-    'n', '\342', '\204', '\242', '\0'};  // Opt(R)io(TM).
-static const char kValueWithUtf8[] = {'V', 'a', 'l', '\302', '\256', 'v', 'e',
-    '\342', '\204', '\242', '\0'};  // Val(R)ue(TM).
+static const char kOptionWithUtf8[] = {'O',    'p', 't', '\302', '\256',
+                                       'i',    'o', 'n', '\342', '\204',
+                                       '\242', '\0'};  // Opt(R)io(TM).
+static const char kValueWithUtf8[] = {
+    'V', 'a',    'l',    '\302', '\256', 'v',
+    'e', '\342', '\204', '\242', '\0'};  // Val(R)ue(TM).
 static int kTestInt1 = 12345;
 static int kTestInt2 = 67890;
 static int kNegInt = -634;
 static int kZero = 0;
 
-#if defined (WEBRTC_ANDROID)
+#if defined(WEBRTC_ANDROID)
 // Fails on Android: https://bugs.chromium.org/p/webrtc/issues/detail?id=4364.
 #define MAYBE_OptionsFileTest DISABLED_OptionsFileTest
 #else
@@ -50,14 +52,10 @@
     OpenStore();
   }
 
-  ~MAYBE_OptionsFileTest() override {
-    webrtc::test::RemoveFile(test_file_);
-  }
+  ~MAYBE_OptionsFileTest() override { webrtc::test::RemoveFile(test_file_); }
 
  protected:
-  void OpenStore() {
-    store_.reset(new OptionsFile(test_file_));
-  }
+  void OpenStore() { store_.reset(new OptionsFile(test_file_)); }
 
   std::unique_ptr<OptionsFile> store_;
 
diff --git a/rtc_base/pathutils.cc b/rtc_base/pathutils.cc
index b85d14f..594deb7 100644
--- a/rtc_base/pathutils.cc
+++ b/rtc_base/pathutils.cc
@@ -69,24 +69,6 @@
 Pathname& Pathname::operator=(const Pathname&) = default;
 Pathname& Pathname::operator=(Pathname&&) = default;
 
-void Pathname::Normalize() {
-  for (size_t i=0; i<folder_.length(); ++i) {
-    if (IsFolderDelimiter(folder_[i])) {
-      folder_[i] = folder_delimiter_;
-    }
-  }
-}
-
-void Pathname::clear() {
-  folder_.clear();
-  basename_.clear();
-  extension_.clear();
-}
-
-bool Pathname::empty() const {
-  return folder_.empty() && basename_.empty() && extension_.empty();
-}
-
 std::string Pathname::pathname() const {
   std::string pathname(folder_);
   pathname.append(basename_);
@@ -116,22 +98,6 @@
   SetFilename(filename);
 }
 
-std::string Pathname::folder() const {
-  return folder_;
-}
-
-std::string Pathname::parent_folder() const {
-  std::string::size_type pos = std::string::npos;
-  if (folder_.size() >= 2) {
-    pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2);
-  }
-  if (pos != std::string::npos) {
-    return folder_.substr(0, pos + 1);
-  } else {
-    return EMPTY_STR;
-  }
-}
-
 void Pathname::SetFolder(const std::string& folder) {
   folder_.assign(folder);
   // Ensure folder ends in a path delimiter
diff --git a/rtc_base/pathutils.h b/rtc_base/pathutils.h
index b66cf18..9543be0 100644
--- a/rtc_base/pathutils.h
+++ b/rtc_base/pathutils.h
@@ -38,7 +38,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class Pathname {
-public:
+ public:
   // Folder delimiters are slash and backslash
   static bool IsFolderDelimiter(char ch);
   static char DefaultFolderDelimiter();
@@ -52,16 +52,6 @@
   Pathname& operator=(const Pathname&);
   Pathname& operator=(Pathname&&);
 
-  // Normalize changes all folder delimiters to folder_delimiter()
-  void Normalize();
-
-  // Reset to the empty pathname
-  void clear();
-
-  // Returns true if the pathname is empty.  Note: this->pathname().empty()
-  // is always false.
-  bool empty() const;
-
   // Returns the folder and filename components.  If the pathname is empty,
   // returns a string representing the current directory (as a relative path,
   // i.e., ".").
@@ -69,8 +59,6 @@
   void SetPathname(const std::string& pathname);
   void SetPathname(const std::string& folder, const std::string& filename);
 
-  std::string folder() const;
-  std::string parent_folder() const;
   // SetFolder and AppendFolder will append a folder delimiter, if needed.
   void SetFolder(const std::string& folder);
   void AppendFolder(const std::string& folder);
@@ -83,11 +71,11 @@
   std::string filename() const;
   bool SetFilename(const std::string& filename);
 
-private:
+ private:
   std::string folder_, basename_, extension_;
   char folder_delimiter_;
 };
 
 }  // namespace rtc
 
-#endif // RTC_BASE_PATHUTILS_H_
+#endif  // RTC_BASE_PATHUTILS_H_
diff --git a/rtc_base/pathutils_unittest.cc b/rtc_base/pathutils_unittest.cc
index cbd33ed..fae4f0a 100644
--- a/rtc_base/pathutils_unittest.cc
+++ b/rtc_base/pathutils_unittest.cc
@@ -16,29 +16,21 @@
       std::string(".") + rtc::Pathname::DefaultFolderDelimiter();
 
   rtc::Pathname path("/", "");
-  EXPECT_FALSE(path.empty());
-  EXPECT_FALSE(path.folder().empty());
   EXPECT_TRUE (path.filename().empty());
   EXPECT_FALSE(path.pathname().empty());
   EXPECT_EQ(std::string("/"), path.pathname());
 
   path.SetPathname("", "foo");
-  EXPECT_FALSE(path.empty());
-  EXPECT_TRUE (path.folder().empty());
   EXPECT_FALSE(path.filename().empty());
   EXPECT_FALSE(path.pathname().empty());
   EXPECT_EQ(std::string("foo"), path.pathname());
 
   path.SetPathname("", "");
-  EXPECT_TRUE (path.empty());
-  EXPECT_TRUE (path.folder().empty());
   EXPECT_TRUE (path.filename().empty());
   EXPECT_FALSE(path.pathname().empty());
   EXPECT_EQ(kCWD, path.pathname());
 
   path.SetPathname(kCWD, "");
-  EXPECT_FALSE(path.empty());
-  EXPECT_FALSE(path.folder().empty());
   EXPECT_TRUE (path.filename().empty());
   EXPECT_FALSE(path.pathname().empty());
   EXPECT_EQ(kCWD, path.pathname());
diff --git a/rtc_base/physicalsocketserver.cc b/rtc_base/physicalsocketserver.cc
index 0d5fc52..ca78499 100644
--- a/rtc_base/physicalsocketserver.cc
+++ b/rtc_base/physicalsocketserver.cc
@@ -10,7 +10,7 @@
 #include "rtc_base/physicalsocketserver.h"
 
 #if defined(_MSC_VER) && _MSC_VER < 1300
-#pragma warning(disable:4786)
+#pragma warning(disable : 4786)
 #endif
 
 #ifdef MEMORY_SANITIZER
@@ -18,21 +18,20 @@
 #endif
 
 #if defined(WEBRTC_POSIX)
-#include <string.h>
 #include <fcntl.h>
+#include <string.h>
 #if defined(WEBRTC_USE_EPOLL)
 // "poll" will be used to wait for the signal dispatcher.
 #include <poll.h>
 #endif
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/select.h>
-#include <unistd.h>
 #include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <unistd.h>
 #endif
 
 #if defined(WEBRTC_WIN)
-#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <winsock2.h>
 #include <ws2tcpip.h>
@@ -45,7 +44,6 @@
 #include <map>
 
 #include "rtc_base/arraysize.h"
-#include "rtc_base/basictypes.h"
 #include "rtc_base/byteorder.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
@@ -64,7 +62,7 @@
 
 #if defined(WEBRTC_POSIX)
 #include <netinet/tcp.h>  // for TCP_NODELAY
-#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h
+#define IP_MTU 14  // Until this is integrated from linux/in.h to netinet/in.h
 typedef void* SockOptArg;
 
 #endif  // WEBRTC_POSIX
@@ -113,40 +111,12 @@
 #endif
 }
 
-#if defined(WEBRTC_WIN)
-// Standard MTUs, from RFC 1191
-const uint16_t PACKET_MAXIMUMS[] = {
-    65535,  // Theoretical maximum, Hyperchannel
-    32000,  // Nothing
-    17914,  // 16Mb IBM Token Ring
-    8166,   // IEEE 802.4
-    // 4464,   // IEEE 802.5 (4Mb max)
-    4352,   // FDDI
-    // 2048,   // Wideband Network
-    2002,   // IEEE 802.5 (4Mb recommended)
-    // 1536,   // Expermental Ethernet Networks
-    // 1500,   // Ethernet, Point-to-Point (default)
-    1492,   // IEEE 802.3
-    1006,   // SLIP, ARPANET
-    // 576,    // X.25 Networks
-    // 544,    // DEC IP Portal
-    // 512,    // NETBIOS
-    508,    // IEEE 802/Source-Rt Bridge, ARCNET
-    296,    // Point-to-Point (low delay)
-    68,     // Official minimum
-    0,      // End of list marker
-};
-
-static const int IP_HEADER_SIZE = 20u;
-static const int IPV6_HEADER_SIZE = 40u;
-static const int ICMP_HEADER_SIZE = 8u;
-static const int ICMP_PING_TIMEOUT_MILLIS = 10000u;
-#endif
-
 PhysicalSocket::PhysicalSocket(PhysicalSocketServer* ss, SOCKET s)
-  : ss_(ss), s_(s), error_(0),
-    state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED),
-    resolver_(nullptr) {
+    : ss_(ss),
+      s_(s),
+      error_(0),
+      state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED),
+      resolver_(nullptr) {
 #if defined(WEBRTC_WIN)
   // EnsureWinsockInit() ensures that winsock is initialized. The default
   // version of this function doesn't do anything because winsock is
@@ -281,8 +251,7 @@
 }
 
 int PhysicalSocket::DoConnect(const SocketAddress& connect_addr) {
-  if ((s_ == INVALID_SOCKET) &&
-      !Create(connect_addr.family(), SOCK_STREAM)) {
+  if ((s_ == INVALID_SOCKET) && !Create(connect_addr.family(), SOCK_STREAM)) {
     return SOCKET_ERROR;
   }
   sockaddr_storage addr_storage;
@@ -347,8 +316,8 @@
 }
 
 int PhysicalSocket::Send(const void* pv, size_t cb) {
-  int sent = DoSend(s_, reinterpret_cast<const char *>(pv),
-      static_cast<int>(cb),
+  int sent = DoSend(
+      s_, reinterpret_cast<const char*>(pv), static_cast<int>(cb),
 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
       // Suppress SIGPIPE. Without this, attempting to send on a socket whose
       // other end is closed will result in a SIGPIPE signal being raised to
@@ -376,15 +345,15 @@
                            const SocketAddress& addr) {
   sockaddr_storage saddr;
   size_t len = addr.ToSockAddrStorage(&saddr);
-  int sent = DoSendTo(
-      s_, static_cast<const char *>(buffer), static_cast<int>(length),
+  int sent =
+      DoSendTo(s_, static_cast<const char*>(buffer), static_cast<int>(length),
 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
-      // Suppress SIGPIPE. See above for explanation.
-      MSG_NOSIGNAL,
+               // Suppress SIGPIPE. See above for explanation.
+               MSG_NOSIGNAL,
 #else
-      0,
+               0,
 #endif
-      reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len));
+               reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len));
   UpdateLastError();
   MaybeRemapSendError();
   // We have seen minidumps where this may be false.
@@ -397,8 +366,8 @@
 }
 
 int PhysicalSocket::Recv(void* buffer, size_t length, int64_t* timestamp) {
-  int received = ::recv(s_, static_cast<char*>(buffer),
-                        static_cast<int>(length), 0);
+  int received =
+      ::recv(s_, static_cast<char*>(buffer), static_cast<int>(length), 0);
   if ((received == 0) && (length != 0)) {
     // Note: on graceful shutdown, recv can return 0.  In this case, we
     // pretend it is blocking, and then signal close, so that simplifying
@@ -601,20 +570,24 @@
   return 0;
 }
 
-SocketDispatcher::SocketDispatcher(PhysicalSocketServer *ss)
+SocketDispatcher::SocketDispatcher(PhysicalSocketServer* ss)
 #if defined(WEBRTC_WIN)
-  : PhysicalSocket(ss), id_(0), signal_close_(false)
+    : PhysicalSocket(ss),
+      id_(0),
+      signal_close_(false)
 #else
-  : PhysicalSocket(ss)
+    : PhysicalSocket(ss)
 #endif
 {
 }
 
-SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer *ss)
+SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer* ss)
 #if defined(WEBRTC_WIN)
-  : PhysicalSocket(ss, s), id_(0), signal_close_(false)
+    : PhysicalSocket(ss, s),
+      id_(0),
+      signal_close_(false)
 #else
-  : PhysicalSocket(ss, s)
+    : PhysicalSocket(ss, s)
 #endif
 {
 }
@@ -625,7 +598,7 @@
 
 bool SocketDispatcher::Initialize() {
   RTC_DCHECK(s_ != INVALID_SOCKET);
-  // Must be a non-blocking
+// Must be a non-blocking
 #if defined(WEBRTC_WIN)
   u_long argp = 1;
   ioctlsocket(s_, FIONBIO, &argp);
@@ -658,7 +631,9 @@
     return false;
 
 #if defined(WEBRTC_WIN)
-  do { id_ = ++next_id_; } while (id_ == 0);
+  do {
+    id_ = ++next_id_;
+  } while (id_ == 0);
 #endif
   return true;
 }
@@ -742,7 +717,7 @@
   }
 }
 
-#endif // WEBRTC_POSIX
+#endif  // WEBRTC_POSIX
 
 uint32_t SocketDispatcher::GetRequestedEvents() {
   return enabled_events();
@@ -753,7 +728,7 @@
     state_ = CS_CONNECTED;
 
 #if defined(WEBRTC_WIN)
-  // We set CS_CLOSED from CheckSignalClose.
+// We set CS_CLOSED from CheckSignalClose.
 #elif defined(WEBRTC_POSIX)
   if ((ff & DE_CLOSE) != 0)
     state_ = CS_CLOSED;
@@ -833,7 +808,7 @@
 #endif
 }
 
-#endif // WEBRTC_POSIX
+#endif  // WEBRTC_POSIX
 
 #if defined(WEBRTC_USE_EPOLL)
 
@@ -946,7 +921,7 @@
   bool IsDescriptorClosed() override { return false; }
 
  private:
-  PhysicalSocketServer *ss_;
+  PhysicalSocketServer* ss_;
   int afd_[2];
   bool fSignaled_;
   CriticalSection crit_;
@@ -968,8 +943,8 @@
   // sort of user-defined void * parameter, so they can't access anything that
   // isn't global.)
   static PosixSignalHandler* Instance() {
-    RTC_DEFINE_STATIC_LOCAL(PosixSignalHandler, instance, ());
-    return &instance;
+    static PosixSignalHandler* const instance = new PosixSignalHandler();
+    return instance;
   }
 
   // Returns true if the given signal number is set.
@@ -991,9 +966,7 @@
   }
 
   // Returns the file descriptor to monitor for signal events.
-  int GetDescriptor() const {
-    return afd_[0];
-  }
+  int GetDescriptor() const { return afd_[0]; }
 
   // This is called directly from our real signal handler, so it must be
   // signal-handler-safe. That means it cannot assume anything about the
@@ -1030,8 +1003,7 @@
     if (fcntl(afd_[1], F_SETFL, O_NONBLOCK) < 0) {
       RTC_LOG_ERR(LS_WARNING) << "fcntl #2 failed";
     }
-    memset(const_cast<void *>(static_cast<volatile void *>(received_signal_)),
-           0,
+    memset(const_cast<void*>(static_cast<volatile void*>(received_signal_)), 0,
            sizeof(received_signal_));
   }
 
@@ -1069,13 +1041,11 @@
 
 class PosixSignalDispatcher : public Dispatcher {
  public:
-  PosixSignalDispatcher(PhysicalSocketServer *owner) : owner_(owner) {
+  PosixSignalDispatcher(PhysicalSocketServer* owner) : owner_(owner) {
     owner_->Add(this);
   }
 
-  ~PosixSignalDispatcher() override {
-    owner_->Remove(this);
-  }
+  ~PosixSignalDispatcher() override { owner_->Remove(this); }
 
   uint32_t GetRequestedEvents() override { return DE_READ; }
 
@@ -1120,23 +1090,19 @@
     handlers_[signum] = handler;
   }
 
-  void ClearHandler(int signum) {
-    handlers_.erase(signum);
-  }
+  void ClearHandler(int signum) { handlers_.erase(signum); }
 
-  bool HasHandlers() {
-    return !handlers_.empty();
-  }
+  bool HasHandlers() { return !handlers_.empty(); }
 
  private:
   typedef std::map<int, void (*)(int)> HandlerMap;
 
   HandlerMap handlers_;
   // Our owner.
-  PhysicalSocketServer *owner_;
+  PhysicalSocketServer* owner_;
 };
 
-#endif // WEBRTC_POSIX
+#endif  // WEBRTC_POSIX
 
 #if defined(WEBRTC_WIN)
 static uint32_t FlagsToEvents(uint32_t events) {
@@ -1154,7 +1120,7 @@
 
 class EventDispatcher : public Dispatcher {
  public:
-  EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) {
+  EventDispatcher(PhysicalSocketServer* ss) : ss_(ss) {
     hev_ = WSACreateEvent();
     if (hev_) {
       ss_->Add(this);
@@ -1195,10 +1161,8 @@
 // Sets the value of a boolean value to false when signaled.
 class Signaler : public EventDispatcher {
  public:
-  Signaler(PhysicalSocketServer* ss, bool* pf)
-      : EventDispatcher(ss), pf_(pf) {
-  }
-  ~Signaler() override { }
+  Signaler(PhysicalSocketServer* ss, bool* pf) : EventDispatcher(ss), pf_(pf) {}
+  ~Signaler() override {}
 
   void OnEvent(uint32_t ff, int err) override {
     if (pf_)
@@ -1206,11 +1170,10 @@
   }
 
  private:
-  bool *pf_;
+  bool* pf_;
 };
 
-PhysicalSocketServer::PhysicalSocketServer()
-    : fWait_(false) {
+PhysicalSocketServer::PhysicalSocketServer() : fWait_(false) {
 #if defined(WEBRTC_USE_EPOLL)
   // Since Linux 2.6.8, the size argument is ignored, but must be greater than
   // zero. Before that the size served as hint to the kernel for the amount of
@@ -1248,10 +1211,6 @@
   signal_wakeup_->Signal();
 }
 
-Socket* PhysicalSocketServer::CreateSocket(int type) {
-  return CreateSocket(AF_INET, type);
-}
-
 Socket* PhysicalSocketServer::CreateSocket(int family, int type) {
   PhysicalSocket* socket = new PhysicalSocket(this);
   if (socket->Create(family, type)) {
@@ -1262,10 +1221,6 @@
   }
 }
 
-AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) {
-  return CreateAsyncSocket(AF_INET, type);
-}
-
 AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int family, int type) {
   SocketDispatcher* dispatcher = new SocketDispatcher(this);
   if (dispatcher->Create(family, type)) {
@@ -1286,7 +1241,7 @@
   }
 }
 
-void PhysicalSocketServer::Add(Dispatcher *pdispatcher) {
+void PhysicalSocketServer::Add(Dispatcher* pdispatcher) {
   CritScope cs(&crit_);
   if (processing_dispatchers_) {
     // A dispatcher is being added while a "Wait" call is processing the
@@ -1305,7 +1260,7 @@
 #endif  // WEBRTC_USE_EPOLL
 }
 
-void PhysicalSocketServer::Remove(Dispatcher *pdispatcher) {
+void PhysicalSocketServer::Remove(Dispatcher* pdispatcher) {
   CritScope cs(&crit_);
   if (processing_dispatchers_) {
     // A dispatcher is being removed while a "Wait" call is processing the
@@ -1459,9 +1414,9 @@
   FD_ZERO(&fdsRead);
   fd_set fdsWrite;
   FD_ZERO(&fdsWrite);
-  // Explicitly unpoison these FDs on MemorySanitizer which doesn't handle the
-  // inline assembly in FD_ZERO.
-  // http://crbug.com/344505
+// Explicitly unpoison these FDs on MemorySanitizer which doesn't handle the
+// inline assembly in FD_ZERO.
+// http://crbug.com/344505
 #ifdef MEMORY_SANITIZER
   __msan_unpoison(&fdsRead, sizeof(fdsRead));
   __msan_unpoison(&fdsWrite, sizeof(fdsWrite));
@@ -1548,9 +1503,8 @@
       ptvWait->tv_usec = 0;
       struct timeval tvT;
       gettimeofday(&tvT, nullptr);
-      if ((tvStop.tv_sec > tvT.tv_sec)
-          || ((tvStop.tv_sec == tvT.tv_sec)
-              && (tvStop.tv_usec > tvT.tv_usec))) {
+      if ((tvStop.tv_sec > tvT.tv_sec) ||
+          ((tvStop.tv_sec == tvT.tv_sec) && (tvStop.tv_usec > tvT.tv_usec))) {
         ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec;
         ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec;
         if (ptvWait->tv_usec < 0) {
@@ -1840,7 +1794,7 @@
   fWait_ = true;
   while (fWait_) {
     std::vector<WSAEVENT> events;
-    std::vector<Dispatcher *> event_owners;
+    std::vector<Dispatcher*> event_owners;
 
     events.push_back(socket_ev_);
 
@@ -1859,8 +1813,7 @@
         if (disp->CheckSignalClose()) {
           // We just signalled close, don't poll this socket
         } else if (s != INVALID_SOCKET) {
-          WSAEventSelect(s,
-                         events[0],
+          WSAEventSelect(s, events[0],
                          FlagsToEvents(disp->GetRequestedEvents()));
         } else {
           events.push_back(disp->GetWSAEvent());
@@ -1884,11 +1837,9 @@
     }
 
     // Wait for one of the events to signal
-    DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()),
-                                        &events[0],
-                                        false,
-                                        static_cast<DWORD>(cmsNext),
-                                        false);
+    DWORD dw =
+        WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0],
+                                 false, static_cast<DWORD>(cmsNext), false);
 
     if (dw == WSA_WAIT_FAILED) {
       // Failed?
@@ -1904,7 +1855,7 @@
       CritScope cr(&crit_);
       int index = dw - WSA_WAIT_EVENT_0;
       if (index > 0) {
-        --index; // The first event is the socket event
+        --index;  // The first event is the socket event
         Dispatcher* disp = event_owners[index];
         // The dispatcher could have been removed while waiting for events.
         if (dispatchers_.find(disp) != dispatchers_.end()) {
@@ -1995,7 +1946,7 @@
       break;
     cmsElapsed = TimeSince(msStart);
     if ((cmsWait != kForever) && (cmsElapsed >= cmsWait)) {
-       break;
+      break;
     }
   }
 
diff --git a/rtc_base/physicalsocketserver.h b/rtc_base/physicalsocketserver.h
index f816774..ee4f936 100644
--- a/rtc_base/physicalsocketserver.h
+++ b/rtc_base/physicalsocketserver.h
@@ -26,17 +26,17 @@
 
 #if defined(WEBRTC_POSIX)
 typedef int SOCKET;
-#endif // WEBRTC_POSIX
+#endif  // WEBRTC_POSIX
 
 namespace rtc {
 
 // Event constants for the Dispatcher class.
 enum DispatcherEvent {
-  DE_READ    = 0x0001,
-  DE_WRITE   = 0x0002,
+  DE_READ = 0x0001,
+  DE_WRITE = 0x0002,
   DE_CONNECT = 0x0004,
-  DE_CLOSE   = 0x0008,
-  DE_ACCEPT  = 0x0010,
+  DE_CLOSE = 0x0008,
+  DE_ACCEPT = 0x0010,
 };
 
 class Signaler;
@@ -67,10 +67,7 @@
   ~PhysicalSocketServer() override;
 
   // SocketFactory:
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
   // Internal Factory for Accept (virtual so it can be overwritten in tests).
@@ -184,8 +181,12 @@
   virtual int DoSend(SOCKET socket, const char* buf, int len, int flags);
 
   // Make virtual so ::sendto can be overwritten in tests.
-  virtual int DoSendTo(SOCKET socket, const char* buf, int len, int flags,
-                       const struct sockaddr* dest_addr, socklen_t addrlen);
+  virtual int DoSendTo(SOCKET socket,
+                       const char* buf,
+                       int len,
+                       int flags,
+                       const struct sockaddr* dest_addr,
+                       socklen_t addrlen);
 
   void OnResolveResult(AsyncResolverInterface* resolver);
 
@@ -217,8 +218,8 @@
 
 class SocketDispatcher : public Dispatcher, public PhysicalSocket {
  public:
-  explicit SocketDispatcher(PhysicalSocketServer *ss);
-  SocketDispatcher(SOCKET s, PhysicalSocketServer *ss);
+  explicit SocketDispatcher(PhysicalSocketServer* ss);
+  SocketDispatcher(SOCKET s, PhysicalSocketServer* ss);
   ~SocketDispatcher() override;
 
   bool Initialize();
@@ -257,7 +258,7 @@
   int id_;
   bool signal_close_;
   int signal_err_;
-#endif // WEBRTC_WIN
+#endif  // WEBRTC_WIN
 #if defined(WEBRTC_USE_EPOLL)
   void MaybeUpdateDispatcher(uint8_t old_events);
 
@@ -265,6 +266,6 @@
 #endif
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_PHYSICALSOCKETSERVER_H_
+#endif  // RTC_BASE_PHYSICALSOCKETSERVER_H_
diff --git a/rtc_base/physicalsocketserver_unittest.cc b/rtc_base/physicalsocketserver_unittest.cc
index 81f1c9d..1e046c0 100644
--- a/rtc_base/physicalsocketserver_unittest.cc
+++ b/rtc_base/physicalsocketserver_unittest.cc
@@ -8,9 +8,9 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <memory>
 #include <signal.h>
 #include <stdarg.h>
+#include <memory>
 
 #include "rtc_base/gunit.h"
 #include "rtc_base/logging.h"
@@ -39,34 +39,25 @@
 class FakeSocketDispatcher : public SocketDispatcher {
  public:
   explicit FakeSocketDispatcher(PhysicalSocketServer* ss)
-    : SocketDispatcher(ss) {
-  }
+      : SocketDispatcher(ss) {}
 
   FakeSocketDispatcher(SOCKET s, PhysicalSocketServer* ss)
-    : SocketDispatcher(s, ss) {
-  }
+      : SocketDispatcher(s, ss) {}
 
  protected:
   SOCKET DoAccept(SOCKET socket, sockaddr* addr, socklen_t* addrlen) override;
   int DoSend(SOCKET socket, const char* buf, int len, int flags) override;
-  int DoSendTo(SOCKET socket, const char* buf, int len, int flags,
-               const struct sockaddr* dest_addr, socklen_t addrlen) override;
+  int DoSendTo(SOCKET socket,
+               const char* buf,
+               int len,
+               int flags,
+               const struct sockaddr* dest_addr,
+               socklen_t addrlen) override;
 };
 
 class FakePhysicalSocketServer : public PhysicalSocketServer {
  public:
-  explicit FakePhysicalSocketServer(PhysicalSocketTest* test)
-    : test_(test) {
-  }
-
-  AsyncSocket* CreateAsyncSocket(int type) override {
-    SocketDispatcher* dispatcher = new FakeSocketDispatcher(this);
-    if (!dispatcher->Create(type)) {
-      delete dispatcher;
-      return nullptr;
-    }
-    return dispatcher;
-  }
+  explicit FakePhysicalSocketServer(PhysicalSocketTest* test) : test_(test) {}
 
   AsyncSocket* CreateAsyncSocket(int family, int type) override {
     SocketDispatcher* dispatcher = new FakeSocketDispatcher(this);
@@ -120,10 +111,10 @@
 
  protected:
   PhysicalSocketTest()
-    : server_(new FakePhysicalSocketServer(this)),
-      thread_(server_.get()),
-      fail_accept_(false),
-      max_send_size_(-1) {}
+      : server_(new FakePhysicalSocketServer(this)),
+        thread_(server_.get()),
+        fail_accept_(false),
+        max_send_size_(-1) {}
 
   void ConnectInternalAcceptError(const IPAddress& loopback);
   void WritableAfterPartialWrite(const IPAddress& loopback);
@@ -146,8 +137,10 @@
   return SocketDispatcher::DoAccept(socket, addr, addrlen);
 }
 
-int FakeSocketDispatcher::DoSend(SOCKET socket, const char* buf, int len,
-    int flags) {
+int FakeSocketDispatcher::DoSend(SOCKET socket,
+                                 const char* buf,
+                                 int len,
+                                 int flags) {
   FakePhysicalSocketServer* ss =
       static_cast<FakePhysicalSocketServer*>(socketserver());
   if (ss->GetTest()->MaxSendSize() >= 0) {
@@ -157,8 +150,12 @@
   return SocketDispatcher::DoSend(socket, buf, len, flags);
 }
 
-int FakeSocketDispatcher::DoSendTo(SOCKET socket, const char* buf, int len,
-    int flags, const struct sockaddr* dest_addr, socklen_t addrlen) {
+int FakeSocketDispatcher::DoSendTo(SOCKET socket,
+                                   const char* buf,
+                                   int len,
+                                   int flags,
+                                   const struct sockaddr* dest_addr,
+                                   socklen_t addrlen) {
   FakePhysicalSocketServer* ss =
       static_cast<FakePhysicalSocketServer*>(socketserver());
   if (ss->GetTest()->MaxSendSize() >= 0) {
@@ -166,7 +163,7 @@
   }
 
   return SocketDispatcher::DoSendTo(socket, buf, len, flags, dest_addr,
-      addrlen);
+                                    addrlen);
 }
 
 TEST_F(PhysicalSocketTest, TestConnectIPv4) {
@@ -289,9 +286,11 @@
 
 // https://bugs.chromium.org/p/webrtc/issues/detail?id=6167
 #if defined(WEBRTC_WIN)
-#define MAYBE_TestWritableAfterPartialWriteIPv4 DISABLED_TestWritableAfterPartialWriteIPv4
+#define MAYBE_TestWritableAfterPartialWriteIPv4 \
+  DISABLED_TestWritableAfterPartialWriteIPv4
 #else
-#define MAYBE_TestWritableAfterPartialWriteIPv4 TestWritableAfterPartialWriteIPv4
+#define MAYBE_TestWritableAfterPartialWriteIPv4 \
+  TestWritableAfterPartialWriteIPv4
 #endif
 TEST_F(PhysicalSocketTest, MAYBE_TestWritableAfterPartialWriteIPv4) {
   MAYBE_SKIP_IPV4;
@@ -300,9 +299,11 @@
 
 // https://bugs.chromium.org/p/webrtc/issues/detail?id=6167
 #if defined(WEBRTC_WIN)
-#define MAYBE_TestWritableAfterPartialWriteIPv6 DISABLED_TestWritableAfterPartialWriteIPv6
+#define MAYBE_TestWritableAfterPartialWriteIPv6 \
+  DISABLED_TestWritableAfterPartialWriteIPv6
 #else
-#define MAYBE_TestWritableAfterPartialWriteIPv6 TestWritableAfterPartialWriteIPv6
+#define MAYBE_TestWritableAfterPartialWriteIPv6 \
+  TestWritableAfterPartialWriteIPv6
 #endif
 TEST_F(PhysicalSocketTest, MAYBE_TestWritableAfterPartialWriteIPv6) {
   MAYBE_SKIP_IPV6;
@@ -322,7 +323,6 @@
   SocketTest::TestConnectWithDnsLookupFailIPv6();
 }
 
-
 TEST_F(PhysicalSocketTest, TestConnectWithClosedSocketIPv4) {
   MAYBE_SKIP_IPV4;
   SocketTest::TestConnectWithClosedSocketIPv4();
@@ -472,8 +472,7 @@
 }
 
 // Network binder shouldn't be used if the socket is bound to the "any" IP.
-TEST_F(PhysicalSocketTest,
-       NetworkBinderIsNotUsedForAnyIp) {
+TEST_F(PhysicalSocketTest, NetworkBinderIsNotUsedForAnyIp) {
   MAYBE_SKIP_IPV4;
   FakeNetworkBinder fake_network_binder;
   server_->set_network_binder(&fake_network_binder);
@@ -538,7 +537,7 @@
   }
 
   static std::vector<int> signals_received_;
-  static Thread *signaled_thread_;
+  static Thread* signaled_thread_;
 
   std::unique_ptr<PhysicalSocketServer> ss_;
 };
diff --git a/rtc_base/platform_thread_types.h b/rtc_base/platform_thread_types.h
index 72aaa4b..0bc42eb 100644
--- a/rtc_base/platform_thread_types.h
+++ b/rtc_base/platform_thread_types.h
@@ -11,7 +11,12 @@
 #ifndef RTC_BASE_PLATFORM_THREAD_TYPES_H_
 #define RTC_BASE_PLATFORM_THREAD_TYPES_H_
 
+// clang-format off
+// clang formating would change include order.
 #if defined(WEBRTC_WIN)
+// Include winsock2.h before including <windows.h> to maintain consistency with
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
 #include <winsock2.h>
 #include <windows.h>
 #elif defined(WEBRTC_FUCHSIA)
@@ -21,6 +26,7 @@
 #include <pthread.h>
 #include <unistd.h>
 #endif
+// clang-format on
 
 namespace rtc {
 #if defined(WEBRTC_WIN)
diff --git a/rtc_base/platform_thread_unittest.cc b/rtc_base/platform_thread_unittest.cc
index d8c8995..1661b6a 100644
--- a/rtc_base/platform_thread_unittest.cc
+++ b/rtc_base/platform_thread_unittest.cc
@@ -125,4 +125,4 @@
   thread.Stop();
 }
 
-}  // rtc
+}  // namespace rtc
diff --git a/rtc_base/proxy_unittest.cc b/rtc_base/proxy_unittest.cc
index 7d7b6f8..d81b312 100644
--- a/rtc_base/proxy_unittest.cc
+++ b/rtc_base/proxy_unittest.cc
@@ -32,8 +32,8 @@
 class ProxyTest : public testing::Test {
  public:
   ProxyTest() : ss_(new rtc::VirtualSocketServer()), thread_(ss_.get()) {
-    socks_.reset(new rtc::SocksProxyServer(
-        ss_.get(), kSocksProxyIntAddr, ss_.get(), kSocksProxyExtAddr));
+    socks_.reset(new rtc::SocksProxyServer(ss_.get(), kSocksProxyIntAddr,
+                                           ss_.get(), kSocksProxyExtAddr));
     https_.reset(new rtc::HttpListenServer());
     https_->Listen(kHttpsProxyIntAddr);
   }
@@ -52,13 +52,11 @@
 TEST_F(ProxyTest, TestSocks5Connect) {
   rtc::AsyncSocket* socket =
       ss()->CreateAsyncSocket(kSocksProxyIntAddr.family(), SOCK_STREAM);
-  rtc::AsyncSocksProxySocket* proxy_socket =
-      new rtc::AsyncSocksProxySocket(socket, kSocksProxyIntAddr,
-                                           "", rtc::CryptString());
+  rtc::AsyncSocksProxySocket* proxy_socket = new rtc::AsyncSocksProxySocket(
+      socket, kSocksProxyIntAddr, "", rtc::CryptString());
   // TODO: IPv6-ize these tests when proxy supports IPv6.
 
-  rtc::TestEchoServer server(Thread::Current(),
-                                   SocketAddress(INADDR_ANY, 0));
+  rtc::TestEchoServer server(Thread::Current(), SocketAddress(INADDR_ANY, 0));
 
   std::unique_ptr<rtc::AsyncTCPSocket> packet_socket(
       rtc::AsyncTCPSocket::Create(proxy_socket, SocketAddress(INADDR_ANY, 0),
diff --git a/rtc_base/proxyinfo.cc b/rtc_base/proxyinfo.cc
index a165dca..c394487 100644
--- a/rtc_base/proxyinfo.cc
+++ b/rtc_base/proxyinfo.cc
@@ -12,13 +12,12 @@
 
 namespace rtc {
 
-const char * ProxyToString(ProxyType proxy) {
-  const char * const PROXY_NAMES[] = { "none", "https", "socks5", "unknown" };
+const char* ProxyToString(ProxyType proxy) {
+  const char* const PROXY_NAMES[] = {"none", "https", "socks5", "unknown"};
   return PROXY_NAMES[proxy];
 }
 
-ProxyInfo::ProxyInfo() : type(PROXY_NONE), autodetect(false) {
-}
+ProxyInfo::ProxyInfo() : type(PROXY_NONE), autodetect(false) {}
 ProxyInfo::~ProxyInfo() = default;
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/proxyinfo.h b/rtc_base/proxyinfo.h
index 5affcd8..1947669 100644
--- a/rtc_base/proxyinfo.h
+++ b/rtc_base/proxyinfo.h
@@ -17,13 +17,8 @@
 
 namespace rtc {
 
-enum ProxyType {
-  PROXY_NONE,
-  PROXY_HTTPS,
-  PROXY_SOCKS5,
-  PROXY_UNKNOWN
-};
-const char * ProxyToString(ProxyType proxy);
+enum ProxyType { PROXY_NONE, PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN };
+const char* ProxyToString(ProxyType proxy);
 
 struct ProxyInfo {
   ProxyType type;
@@ -38,6 +33,6 @@
   ~ProxyInfo();
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_PROXYINFO_H_
+#endif  // RTC_BASE_PROXYINFO_H_
diff --git a/rtc_base/proxyserver.cc b/rtc_base/proxyserver.cc
index 5ab7943..55cab80 100644
--- a/rtc_base/proxyserver.cc
+++ b/rtc_base/proxyserver.cc
@@ -18,12 +18,14 @@
 namespace rtc {
 
 // ProxyServer
-ProxyServer::ProxyServer(
-    SocketFactory* int_factory, const SocketAddress& int_addr,
-    SocketFactory* ext_factory, const SocketAddress& ext_ip)
-    : ext_factory_(ext_factory), ext_ip_(ext_ip.ipaddr(), 0),  // strip off port
-      server_socket_(int_factory->CreateAsyncSocket(int_addr.family(),
-                                                    SOCK_STREAM)) {
+ProxyServer::ProxyServer(SocketFactory* int_factory,
+                         const SocketAddress& int_addr,
+                         SocketFactory* ext_factory,
+                         const SocketAddress& ext_ip)
+    : ext_factory_(ext_factory),
+      ext_ip_(ext_ip.ipaddr(), 0),  // strip off port
+      server_socket_(
+          int_factory->CreateAsyncSocket(int_addr.family(), SOCK_STREAM)) {
   RTC_DCHECK(server_socket_.get() != nullptr);
   RTC_DCHECK(int_addr.family() == AF_INET || int_addr.family() == AF_INET6);
   server_socket_->Bind(int_addr);
@@ -32,8 +34,8 @@
 }
 
 ProxyServer::~ProxyServer() {
-  for (BindingList::iterator it = bindings_.begin();
-       it != bindings_.end(); ++it) {
+  for (BindingList::iterator it = bindings_.begin(); it != bindings_.end();
+       ++it) {
     delete (*it);
   }
 }
@@ -47,8 +49,8 @@
   RTC_DCHECK_EQ(socket, server_socket_.get());
   AsyncSocket* int_socket = socket->Accept(nullptr);
   AsyncProxyServerSocket* wrapped_socket = WrapSocket(int_socket);
-  AsyncSocket* ext_socket = ext_factory_->CreateAsyncSocket(ext_ip_.family(),
-                                                            SOCK_STREAM);
+  AsyncSocket* ext_socket =
+      ext_factory_->CreateAsyncSocket(ext_ip_.family(), SOCK_STREAM);
   if (ext_socket) {
     ext_socket->Bind(ext_ip_);
     bindings_.push_back(new ProxyBinding(wrapped_socket, ext_socket));
@@ -68,8 +70,11 @@
 // ProxyBinding
 ProxyBinding::ProxyBinding(AsyncProxyServerSocket* int_socket,
                            AsyncSocket* ext_socket)
-    : int_socket_(int_socket), ext_socket_(ext_socket), connected_(false),
-      out_buffer_(kBufferSize), in_buffer_(kBufferSize) {
+    : int_socket_(int_socket),
+      ext_socket_(ext_socket),
+      connected_(false),
+      out_buffer_(kBufferSize),
+      in_buffer_(kBufferSize) {
   int_socket_->SignalConnectRequest.connect(this,
                                             &ProxyBinding::OnConnectRequest);
   int_socket_->SignalReadEvent.connect(this, &ProxyBinding::OnInternalRead);
@@ -85,7 +90,7 @@
 ProxyBinding::~ProxyBinding() = default;
 
 void ProxyBinding::OnConnectRequest(AsyncProxyServerSocket* socket,
-                                   const SocketAddress& addr) {
+                                    const SocketAddress& addr) {
   RTC_DCHECK(!connected_);
   RTC_DCHECK(ext_socket_);
   ext_socket_->Connect(addr);
diff --git a/rtc_base/proxyserver.h b/rtc_base/proxyserver.h
index d90b091..37cadd0 100644
--- a/rtc_base/proxyserver.h
+++ b/rtc_base/proxyserver.h
@@ -62,8 +62,10 @@
 
 class ProxyServer : public sigslot::has_slots<> {
  public:
-  ProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr,
-              SocketFactory* ext_factory, const SocketAddress& ext_ip);
+  ProxyServer(SocketFactory* int_factory,
+              const SocketAddress& int_addr,
+              SocketFactory* ext_factory,
+              const SocketAddress& ext_ip);
   ~ProxyServer() override;
 
   // Returns the address to which the proxy server is bound
@@ -86,10 +88,12 @@
 // SocksProxyServer is a simple extension of ProxyServer to implement SOCKS.
 class SocksProxyServer : public ProxyServer {
  public:
-  SocksProxyServer(SocketFactory* int_factory, const SocketAddress& int_addr,
-                   SocketFactory* ext_factory, const SocketAddress& ext_ip)
-      : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {
-  }
+  SocksProxyServer(SocketFactory* int_factory,
+                   const SocketAddress& int_addr,
+                   SocketFactory* ext_factory,
+                   const SocketAddress& ext_ip)
+      : ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {}
+
  protected:
   AsyncProxyServerSocket* WrapSocket(AsyncSocket* socket) override;
   RTC_DISALLOW_COPY_AND_ASSIGN(SocksProxyServer);
diff --git a/rtc_base/ptr_util.h b/rtc_base/ptr_util.h
index 156df84..56d8da3 100644
--- a/rtc_base/ptr_util.h
+++ b/rtc_base/ptr_util.h
@@ -8,74 +8,30 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-// This implementation is borrowed from chromium.
+// This file contains rtc::MakeUnique and rtc::WrapUnique, which are backwards
+// compatibility aliases for absl::make_unique and absl::WrapUnique,
+// respectively. This file will go away soon; use the Abseil types directly in
+// new code.
 
 #ifndef RTC_BASE_PTR_UTIL_H_
 #define RTC_BASE_PTR_UTIL_H_
 
-#include <memory>
-#include <utility>
+#include "absl/memory/memory.h"
 
 namespace rtc {
 
-// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
-// Note that std::unique_ptr<T> has very different semantics from
-// std::unique_ptr<T[]>: do not use this helper for array allocations.
-template <typename T>
-std::unique_ptr<T> WrapUnique(T* ptr) {
-  return std::unique_ptr<T>(ptr);
-}
-
-namespace internal {
-
-template <typename T>
-struct MakeUniqueResult {
-  using Scalar = std::unique_ptr<T>;
-};
-
-template <typename T>
-struct MakeUniqueResult<T[]> {
-  using Array = std::unique_ptr<T[]>;
-};
-
-template <typename T, size_t N>
-struct MakeUniqueResult<T[N]> {
-  using Invalid = void;
-};
-
-}  // namespace internal
-
-// Helper to construct an object wrapped in a std::unique_ptr. This is an
-// implementation of C++14's std::make_unique that can be used in Chrome.
-//
-// MakeUnique<T>(args) should be preferred over WrapUnique(new T(args)): bare
-// calls to `new` should be treated with scrutiny.
-//
-// Usage:
-//   // ptr is a std::unique_ptr<std::string>
-//   auto ptr = MakeUnique<std::string>("hello world!");
-//
-//   // arr is a std::unique_ptr<int[]>
-//   auto arr = MakeUnique<int[]>(5);
-
-// Overload for non-array types. Arguments are forwarded to T's constructor.
 template <typename T, typename... Args>
-typename internal::MakeUniqueResult<T>::Scalar MakeUnique(Args&&... args) {
-  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+auto MakeUnique(Args&&... args)
+    -> decltype(absl::make_unique<T, Args...>(std::forward<Args>(args)...)) {
+  return absl::make_unique<T, Args...>(std::forward<Args>(args)...);
 }
 
-// Overload for array types of unknown bound, e.g. T[]. The array is allocated
-// with `new T[n]()` and value-initialized: note that this is distinct from
-// `new T[n]`, which default-initializes.
 template <typename T>
-typename internal::MakeUniqueResult<T>::Array MakeUnique(size_t size) {
-  return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
+auto MakeUnique(size_t n) -> decltype(absl::make_unique<T>(n)) {
+  return absl::make_unique<T>(n);
 }
 
-// Overload to reject array types of known bound, e.g. T[n].
-template <typename T, typename... Args>
-typename internal::MakeUniqueResult<T>::Invalid MakeUnique(Args&&... args) =
-    delete;
+using absl::WrapUnique;
 
 }  // namespace rtc
 
diff --git a/rtc_base/rate_limiter.cc b/rtc_base/rate_limiter.cc
index 34e0a40..0343f25 100644
--- a/rtc_base/rate_limiter.cc
+++ b/rtc_base/rate_limiter.cc
@@ -29,7 +29,7 @@
 bool RateLimiter::TryUseRate(size_t packet_size_bytes) {
   rtc::CritScope cs(&lock_);
   int64_t now_ms = clock_->TimeInMilliseconds();
-  rtc::Optional<uint32_t> current_rate = current_rate_.Rate(now_ms);
+  absl::optional<uint32_t> current_rate = current_rate_.Rate(now_ms);
   if (current_rate) {
     // If there is a current rate, check if adding bytes would cause maximum
     // bitrate target to be exceeded. If there is NOT a valid current rate,
diff --git a/rtc_base/rate_statistics.cc b/rtc_base/rate_statistics.cc
index e2d6b11..9b1ff8f 100644
--- a/rtc_base/rate_statistics.cc
+++ b/rtc_base/rate_statistics.cc
@@ -61,7 +61,7 @@
   ++num_samples_;
 }
 
-rtc::Optional<uint32_t> RateStatistics::Rate(int64_t now_ms) const {
+absl::optional<uint32_t> RateStatistics::Rate(int64_t now_ms) const {
   // Yeah, this const_cast ain't pretty, but the alternative is to declare most
   // of the members as mutable...
   const_cast<RateStatistics*>(this)->EraseOld(now_ms);
@@ -71,7 +71,7 @@
   int64_t active_window_size = now_ms - oldest_time_ + 1;
   if (num_samples_ == 0 || active_window_size <= 1 ||
       (num_samples_ <= 1 && active_window_size < current_window_size_ms_)) {
-    return rtc::nullopt;
+    return absl::nullopt;
   }
 
   float scale = scale_ / active_window_size;
diff --git a/rtc_base/rate_statistics.h b/rtc_base/rate_statistics.h
index aa28529..fe5ae82 100644
--- a/rtc_base/rate_statistics.h
+++ b/rtc_base/rate_statistics.h
@@ -13,7 +13,7 @@
 
 #include <memory>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
@@ -42,7 +42,7 @@
   // from a monotonic clock. Ie, it doesn't matter if this call moves the
   // window, since any subsequent call to Update or Rate would still have moved
   // the window as much or more.
-  rtc::Optional<uint32_t> Rate(int64_t now_ms) const;
+  absl::optional<uint32_t> Rate(int64_t now_ms) const;
 
   // Update the size of the averaging window. The maximum allowed value for
   // window_size_ms is max_window_size_ms as supplied in the constructor.
diff --git a/rtc_base/rate_statistics_unittest.cc b/rtc_base/rate_statistics_unittest.cc
index 51249b1..62f1486 100644
--- a/rtc_base/rate_statistics_unittest.cc
+++ b/rtc_base/rate_statistics_unittest.cc
@@ -53,7 +53,7 @@
     // Approximately 1200 kbps expected. Not exact since when packets
     // are removed we will jump 10 ms to the next packet.
     if (i > kInterval) {
-      rtc::Optional<uint32_t> rate = stats_.Rate(now_ms);
+      absl::optional<uint32_t> rate = stats_.Rate(now_ms);
       EXPECT_TRUE(static_cast<bool>(rate));
       uint32_t samples = i / kInterval + 1;
       uint64_t total_bits = samples * kPacketSize * 8;
@@ -78,7 +78,7 @@
   const uint32_t kExpectedBitrate = 8000000;
   // 1000 bytes per millisecond until plateau is reached.
   int prev_error = kExpectedBitrate;
-  rtc::Optional<uint32_t> bitrate;
+  absl::optional<uint32_t> bitrate;
   while (++now_ms < 10000) {
     stats_.Update(1000, now_ms);
     bitrate = stats_.Rate(now_ms);
@@ -102,7 +102,7 @@
   // Zero bytes per millisecond until 0 is reached.
   while (++now_ms < 20000) {
     stats_.Update(0, now_ms);
-    rtc::Optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
+    absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
     if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
       // New bitrate must be lower than previous one.
       EXPECT_LT(*new_bitrate, *bitrate);
@@ -130,7 +130,7 @@
   const uint32_t kExpectedBitrate = 8000000;
   // 1000 bytes per millisecond until the window has been filled.
   int prev_error = kExpectedBitrate;
-  rtc::Optional<uint32_t> bitrate;
+  absl::optional<uint32_t> bitrate;
   while (++now_ms < 10000) {
     stats_.Update(1000, now_ms);
     bitrate = stats_.Rate(now_ms);
@@ -213,7 +213,7 @@
 
   // Window size should be full, and the single data point should be accepted.
   ++now_ms;
-  rtc::Optional<uint32_t> bitrate = stats_.Rate(now_ms);
+  absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
   EXPECT_TRUE(static_cast<bool>(bitrate));
   EXPECT_EQ(1000 * 8u, *bitrate);
 
@@ -239,7 +239,7 @@
   stats_.Update(kWindowMs, now_ms);
   now_ms += kWindowMs - 1;
   stats_.Update(0, now_ms);
-  rtc::Optional<uint32_t> bitrate = stats_.Rate(now_ms);
+  absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
   EXPECT_TRUE(static_cast<bool>(bitrate));
   EXPECT_EQ(1000 * 8u, *bitrate);
 
@@ -262,7 +262,7 @@
 
   stats_.Update(0, now_ms);
   now_ms += kWindowMs - 1;
-  rtc::Optional<uint32_t> bitrate = stats_.Rate(now_ms);
+  absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
   EXPECT_TRUE(static_cast<bool>(bitrate));
   EXPECT_EQ(0u, *bitrate);
 
diff --git a/rtc_base/ratetracker.cc b/rtc_base/ratetracker.cc
index 68bd8a1..e31d266 100644
--- a/rtc_base/ratetracker.cc
+++ b/rtc_base/ratetracker.cc
@@ -79,13 +79,12 @@
   // Only count a portion of the first bucket according to how much of the
   // first bucket is within the current interval.
   size_t total_samples = ((sample_buckets_[start_bucket] *
-      (bucket_milliseconds_ - milliseconds_to_skip)) +
-      (bucket_milliseconds_ >> 1)) /
-      bucket_milliseconds_;
+                           (bucket_milliseconds_ - milliseconds_to_skip)) +
+                          (bucket_milliseconds_ >> 1)) /
+                         bucket_milliseconds_;
   // All other buckets in the interval are counted in their entirety.
   for (size_t i = NextBucketIndex(start_bucket);
-      i != NextBucketIndex(current_bucket_);
-      i = NextBucketIndex(i)) {
+       i != NextBucketIndex(current_bucket_); i = NextBucketIndex(i)) {
     total_samples += sample_buckets_[i];
   }
   // Convert to samples per second.
@@ -125,7 +124,8 @@
   }
   // Ensure that bucket_start_time_milliseconds_ is updated appropriately if
   // the entire buffer of samples has been expired.
-  bucket_start_time_milliseconds_ += bucket_milliseconds_ *
+  bucket_start_time_milliseconds_ +=
+      bucket_milliseconds_ *
       ((current_time - bucket_start_time_milliseconds_) / bucket_milliseconds_);
   // Add all samples in the bucket that includes the current time.
   sample_buckets_[current_bucket_] += sample_count;
diff --git a/rtc_base/ratetracker.h b/rtc_base/ratetracker.h
index 05eccff..ac9b88a 100644
--- a/rtc_base/ratetracker.h
+++ b/rtc_base/ratetracker.h
@@ -11,8 +11,8 @@
 #ifndef RTC_BASE_RATETRACKER_H_
 #define RTC_BASE_RATETRACKER_H_
 
+#include <stdint.h>
 #include <stdlib.h>
-#include "rtc_base/basictypes.h"
 
 namespace rtc {
 
diff --git a/rtc_base/ratetracker_unittest.cc b/rtc_base/ratetracker_unittest.cc
index cd288a3..58102df 100644
--- a/rtc_base/ratetracker_unittest.cc
+++ b/rtc_base/ratetracker_unittest.cc
@@ -13,7 +13,7 @@
 
 namespace rtc {
 namespace {
-  const uint32_t kBucketIntervalMs = 100;
+const uint32_t kBucketIntervalMs = 100;
 }  // namespace
 
 class RateTrackerForTest : public RateTracker {
@@ -107,7 +107,7 @@
   EXPECT_DOUBLE_EQ(9876.0 * 10.0, tracker.ComputeRate());
   EXPECT_EQ(1234U * 2 + 9876U * 55, tracker.TotalSampleCount());
   EXPECT_DOUBLE_EQ((1234.0 * 2.0 + 9876.0 * 55.0) / 7.5,
-      tracker.ComputeTotalRate());
+                   tracker.ComputeTotalRate());
 
   // Advance the clock by 500 ms. Since we sent nothing over this half-second,
   // the reported rate should be reduced by half.
@@ -116,7 +116,7 @@
   EXPECT_DOUBLE_EQ(9876.0 * 5.0, tracker.ComputeRate());
   EXPECT_EQ(1234U * 2 + 9876U * 55, tracker.TotalSampleCount());
   EXPECT_DOUBLE_EQ((1234.0 * 2.0 + 9876.0 * 55.0) / 8.0,
-      tracker.ComputeTotalRate());
+                   tracker.ComputeTotalRate());
 
   // Rate over the last half second should be zero.
   EXPECT_DOUBLE_EQ(0.0, tracker.ComputeRateForInterval(500));
diff --git a/rtc_base/refcounter.h b/rtc_base/refcounter.h
index baf72ae..3906529 100644
--- a/rtc_base/refcounter.h
+++ b/rtc_base/refcounter.h
@@ -28,8 +28,8 @@
   // the reference counter can be deleted.
   rtc::RefCountReleaseStatus DecRef() {
     return (rtc::AtomicOps::Decrement(&ref_count_) == 0)
-        ? rtc::RefCountReleaseStatus::kDroppedLastRef
-        : rtc::RefCountReleaseStatus::kOtherRefsRemained;
+               ? rtc::RefCountReleaseStatus::kDroppedLastRef
+               : rtc::RefCountReleaseStatus::kOtherRefsRemained;
   }
 
   // Return whether the reference count is one. If the reference count is used
diff --git a/rtc_base/rollingaccumulator.h b/rtc_base/rollingaccumulator.h
index e7d5b06..f6215c5 100644
--- a/rtc_base/rollingaccumulator.h
+++ b/rtc_base/rollingaccumulator.h
@@ -23,23 +23,17 @@
 // over N most recent samples.
 //
 // T is assumed to be an int, long, double or float.
-template<typename T>
+template <typename T>
 class RollingAccumulator {
  public:
-  explicit RollingAccumulator(size_t max_count)
-    : samples_(max_count) {
+  explicit RollingAccumulator(size_t max_count) : samples_(max_count) {
     Reset();
   }
-  ~RollingAccumulator() {
-  }
+  ~RollingAccumulator() {}
 
-  size_t max_count() const {
-    return samples_.size();
-  }
+  size_t max_count() const { return samples_.size(); }
 
-  size_t count() const {
-    return count_;
-  }
+  size_t count() const { return count_; }
 
   void Reset() {
     count_ = 0U;
@@ -84,9 +78,7 @@
     next_index_ = (next_index_ + 1) % max_count();
   }
 
-  T ComputeSum() const {
-    return static_cast<T>(sum_);
-  }
+  T ComputeSum() const { return static_cast<T>(sum_); }
 
   double ComputeMean() const {
     if (count_ == 0) {
@@ -97,8 +89,8 @@
 
   T ComputeMax() const {
     if (max_stale_) {
-      RTC_DCHECK(count_ > 0) <<
-                 "It shouldn't be possible for max_stale_ && count_ == 0";
+      RTC_DCHECK(count_ > 0)
+          << "It shouldn't be possible for max_stale_ && count_ == 0";
       max_ = samples_[next_index_];
       for (size_t i = 1u; i < count_; i++) {
         max_ = std::max(max_, samples_[(next_index_ + i) % max_count()]);
@@ -110,8 +102,8 @@
 
   T ComputeMin() const {
     if (min_stale_) {
-      RTC_DCHECK(count_ > 0) <<
-                 "It shouldn't be possible for min_stale_ && count_ == 0";
+      RTC_DCHECK(count_ > 0)
+          << "It shouldn't be possible for min_stale_ && count_ == 0";
       min_ = samples_[next_index_];
       for (size_t i = 1u; i < count_; i++) {
         min_ = std::min(min_, samples_[(next_index_ + i) % max_count()]);
diff --git a/rtc_base/rtccertificate.cc b/rtc_base/rtccertificate.cc
index 2887895..7f027ba 100644
--- a/rtc_base/rtccertificate.cc
+++ b/rtc_base/rtccertificate.cc
@@ -22,13 +22,11 @@
   return new RefCountedObject<RTCCertificate>(identity.release());
 }
 
-RTCCertificate::RTCCertificate(SSLIdentity* identity)
-    : identity_(identity) {
+RTCCertificate::RTCCertificate(SSLIdentity* identity) : identity_(identity) {
   RTC_DCHECK(identity_);
 }
 
-RTCCertificate::~RTCCertificate() {
-}
+RTCCertificate::~RTCCertificate() {}
 
 uint64_t RTCCertificate::Expires() const {
   int64_t expires = ssl_certificate().CertificateExpirationTime();
@@ -57,8 +55,8 @@
 
 scoped_refptr<RTCCertificate> RTCCertificate::FromPEM(
     const RTCCertificatePEM& pem) {
-  std::unique_ptr<SSLIdentity> identity(SSLIdentity::FromPEMStrings(
-      pem.private_key(), pem.certificate()));
+  std::unique_ptr<SSLIdentity> identity(
+      SSLIdentity::FromPEMStrings(pem.private_key(), pem.certificate()));
   if (!identity)
     return nullptr;
   return new RefCountedObject<RTCCertificate>(identity.release());
diff --git a/rtc_base/rtccertificate.h b/rtc_base/rtccertificate.h
index f13caba..d5422f8 100644
--- a/rtc_base/rtccertificate.h
+++ b/rtc_base/rtccertificate.h
@@ -29,11 +29,9 @@
 // the string representations used by OpenSSL.
 class RTCCertificatePEM {
  public:
-  RTCCertificatePEM(
-      const std::string& private_key,
-      const std::string& certificate)
-      : private_key_(private_key),
-        certificate_(certificate) {}
+  RTCCertificatePEM(const std::string& private_key,
+                    const std::string& certificate)
+      : private_key_(private_key), certificate_(certificate) {}
 
   const std::string& private_key() const { return private_key_; }
   const std::string& certificate() const { return certificate_; }
diff --git a/rtc_base/rtccertificate_unittest.cc b/rtc_base/rtccertificate_unittest.cc
index 7252a04..bb88d8a 100644
--- a/rtc_base/rtccertificate_unittest.cc
+++ b/rtc_base/rtccertificate_unittest.cc
@@ -47,9 +47,7 @@
   //   As a result, ExpiresSeconds and HasExpiredSeconds are used instead of
   // RTCCertificate::Expires and ::HasExpired for ms -> s conversion.
 
-  uint64_t NowSeconds() const {
-    return TimeNanos() / kNumNanosecsPerSec;
-  }
+  uint64_t NowSeconds() const { return TimeNanos() / kNumNanosecsPerSec; }
 
   uint64_t ExpiresSeconds(const scoped_refptr<RTCCertificate>& cert) const {
     uint64_t exp_ms = cert->Expires();
@@ -94,7 +92,7 @@
   EXPECT_FALSE(HasExpiredSeconds(certificate, now));
   // Even without specifying the expiration time we would expect it to be valid
   // for at least half an hour.
-  EXPECT_FALSE(HasExpiredSeconds(certificate, now + 30*60));
+  EXPECT_FALSE(HasExpiredSeconds(certificate, now + 30 * 60));
 }
 
 TEST_F(RTCCertificateTest, UsesExpiresAskedFor) {
diff --git a/rtc_base/rtccertificategenerator.cc b/rtc_base/rtccertificategenerator.cc
index cacff61..0b51c61 100644
--- a/rtc_base/rtccertificategenerator.cc
+++ b/rtc_base/rtccertificategenerator.cc
@@ -42,7 +42,7 @@
       Thread* signaling_thread,
       Thread* worker_thread,
       const KeyParams& key_params,
-      const Optional<uint64_t>& expires_ms,
+      const absl::optional<uint64_t>& expires_ms,
       const scoped_refptr<RTCCertificateGeneratorCallback>& callback)
       : signaling_thread_(signaling_thread),
         worker_thread_(worker_thread),
@@ -94,7 +94,7 @@
   Thread* const signaling_thread_;
   Thread* const worker_thread_;
   const KeyParams key_params_;
-  const Optional<uint64_t> expires_ms_;
+  const absl::optional<uint64_t> expires_ms_;
   const scoped_refptr<RTCCertificateGeneratorCallback> callback_;
   scoped_refptr<RTCCertificate> certificate_;
 };
@@ -102,10 +102,9 @@
 }  // namespace
 
 // static
-scoped_refptr<RTCCertificate>
-RTCCertificateGenerator::GenerateCertificate(
+scoped_refptr<RTCCertificate> RTCCertificateGenerator::GenerateCertificate(
     const KeyParams& key_params,
-    const Optional<uint64_t>& expires_ms) {
+    const absl::optional<uint64_t>& expires_ms) {
   if (!key_params.IsValid())
     return nullptr;
   SSLIdentity* identity;
@@ -122,8 +121,8 @@
     // |SSLIdentity::Generate| should stop relying on |time_t|.
     // See bugs.webrtc.org/5720.
     time_t cert_lifetime_s = static_cast<time_t>(expires_s);
-    identity = SSLIdentity::GenerateWithExpiration(
-        kIdentityName, key_params, cert_lifetime_s);
+    identity = SSLIdentity::GenerateWithExpiration(kIdentityName, key_params,
+                                                   cert_lifetime_s);
   }
   if (!identity)
     return nullptr;
@@ -131,17 +130,16 @@
   return RTCCertificate::Create(std::move(identity_sptr));
 }
 
-RTCCertificateGenerator::RTCCertificateGenerator(
-    Thread* signaling_thread, Thread* worker_thread)
-    : signaling_thread_(signaling_thread),
-      worker_thread_(worker_thread) {
+RTCCertificateGenerator::RTCCertificateGenerator(Thread* signaling_thread,
+                                                 Thread* worker_thread)
+    : signaling_thread_(signaling_thread), worker_thread_(worker_thread) {
   RTC_DCHECK(signaling_thread_);
   RTC_DCHECK(worker_thread_);
 }
 
 void RTCCertificateGenerator::GenerateCertificateAsync(
     const KeyParams& key_params,
-    const Optional<uint64_t>& expires_ms,
+    const absl::optional<uint64_t>& expires_ms,
     const scoped_refptr<RTCCertificateGeneratorCallback>& callback) {
   RTC_DCHECK(signaling_thread_->IsCurrent());
   RTC_DCHECK(callback);
diff --git a/rtc_base/rtccertificategenerator.h b/rtc_base/rtccertificategenerator.h
index 1f85466..a6c503a 100644
--- a/rtc_base/rtccertificategenerator.h
+++ b/rtc_base/rtccertificategenerator.h
@@ -11,7 +11,7 @@
 #ifndef RTC_BASE_RTCCERTIFICATEGENERATOR_H_
 #define RTC_BASE_RTCCERTIFICATEGENERATOR_H_
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/refcount.h"
 #include "rtc_base/rtccertificate.h"
 #include "rtc_base/scoped_ref_ptr.h"
@@ -23,8 +23,7 @@
 // See |RTCCertificateGeneratorInterface::GenerateCertificateAsync|.
 class RTCCertificateGeneratorCallback : public RefCountInterface {
  public:
-  virtual void OnSuccess(
-    const scoped_refptr<RTCCertificate>& certificate) = 0;
+  virtual void OnSuccess(const scoped_refptr<RTCCertificate>& certificate) = 0;
   virtual void OnFailure() = 0;
 
  protected:
@@ -44,7 +43,7 @@
   // its own restrictions on the expiration time.
   virtual void GenerateCertificateAsync(
       const KeyParams& key_params,
-      const Optional<uint64_t>& expires_ms,
+      const absl::optional<uint64_t>& expires_ms,
       const scoped_refptr<RTCCertificateGeneratorCallback>& callback) = 0;
 };
 
@@ -61,7 +60,7 @@
   // specified, a default expiration time is used.
   static scoped_refptr<RTCCertificate> GenerateCertificate(
       const KeyParams& key_params,
-      const Optional<uint64_t>& expires_ms);
+      const absl::optional<uint64_t>& expires_ms);
 
   RTCCertificateGenerator(Thread* signaling_thread, Thread* worker_thread);
   ~RTCCertificateGenerator() override {}
@@ -73,7 +72,7 @@
   // specified, a default expiration time is used.
   void GenerateCertificateAsync(
       const KeyParams& key_params,
-      const Optional<uint64_t>& expires_ms,
+      const absl::optional<uint64_t>& expires_ms,
       const scoped_refptr<RTCCertificateGeneratorCallback>& callback) override;
 
  private:
diff --git a/rtc_base/rtccertificategenerator_unittest.cc b/rtc_base/rtccertificategenerator_unittest.cc
index 9a0ad0c..3929128 100644
--- a/rtc_base/rtccertificategenerator_unittest.cc
+++ b/rtc_base/rtccertificategenerator_unittest.cc
@@ -12,7 +12,7 @@
 
 #include <memory>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/logging.h"
@@ -30,7 +30,7 @@
     RTC_CHECK(signaling_thread_);
     RTC_CHECK(worker_thread_->Start());
     generator_.reset(
-      new RTCCertificateGenerator(signaling_thread_, worker_thread_.get()));
+        new RTCCertificateGenerator(signaling_thread_, worker_thread_.get()));
   }
   ~RTCCertificateGeneratorFixture() override {}
 
@@ -67,8 +67,7 @@
   bool generate_async_completed_;
 };
 
-class RTCCertificateGeneratorTest
-    : public testing::Test {
+class RTCCertificateGeneratorTest : public testing::Test {
  public:
   RTCCertificateGeneratorTest()
       : fixture_(new RefCountedObject<RTCCertificateGeneratorFixture>()) {}
@@ -80,23 +79,19 @@
 };
 
 TEST_F(RTCCertificateGeneratorTest, GenerateECDSA) {
-  EXPECT_TRUE(RTCCertificateGenerator::GenerateCertificate(
-      KeyParams::ECDSA(),
-      Optional<uint64_t>()));
+  EXPECT_TRUE(RTCCertificateGenerator::GenerateCertificate(KeyParams::ECDSA(),
+                                                           absl::nullopt));
 }
 
 TEST_F(RTCCertificateGeneratorTest, GenerateRSA) {
-  EXPECT_TRUE(RTCCertificateGenerator::GenerateCertificate(
-      KeyParams::RSA(),
-      Optional<uint64_t>()));
+  EXPECT_TRUE(RTCCertificateGenerator::GenerateCertificate(KeyParams::RSA(),
+                                                           absl::nullopt));
 }
 
 TEST_F(RTCCertificateGeneratorTest, GenerateAsyncECDSA) {
   EXPECT_FALSE(fixture_->certificate());
-  fixture_->generator()->GenerateCertificateAsync(
-      KeyParams::ECDSA(),
-      Optional<uint64_t>(),
-      fixture_);
+  fixture_->generator()->GenerateCertificateAsync(KeyParams::ECDSA(),
+                                                  absl::nullopt, fixture_);
   // Until generation has completed, the certificate is null. Since this is an
   // async call, generation must not have completed until we process messages
   // posted to this thread (which is done by |EXPECT_TRUE_WAIT|).
@@ -115,15 +110,14 @@
 
   // Generate a certificate that expires immediately.
   scoped_refptr<RTCCertificate> cert_a =
-      RTCCertificateGenerator::GenerateCertificate(
-          KeyParams::ECDSA(), Optional<uint64_t>(0));
+      RTCCertificateGenerator::GenerateCertificate(KeyParams::ECDSA(), 0);
   EXPECT_TRUE(cert_a);
 
   // Generate a certificate that expires in one minute.
   const uint64_t kExpiresMs = 60000;
   scoped_refptr<RTCCertificate> cert_b =
-      RTCCertificateGenerator::GenerateCertificate(
-          KeyParams::ECDSA(), Optional<uint64_t>(kExpiresMs));
+      RTCCertificateGenerator::GenerateCertificate(KeyParams::ECDSA(),
+                                                   kExpiresMs);
   EXPECT_TRUE(cert_b);
 
   // Verify that |cert_b| expires approximately |kExpiresMs| after |cert_a|
@@ -131,20 +125,18 @@
   EXPECT_GT(cert_b->Expires(), cert_a->Expires());
   uint64_t expires_diff = cert_b->Expires() - cert_a->Expires();
   EXPECT_GE(expires_diff, kExpiresMs);
-  EXPECT_LE(expires_diff, kExpiresMs + 2*kGenerationTimeoutMs + 1000);
+  EXPECT_LE(expires_diff, kExpiresMs + 2 * kGenerationTimeoutMs + 1000);
 }
 
 TEST_F(RTCCertificateGeneratorTest, GenerateWithInvalidParamsShouldFail) {
   KeyParams invalid_params = KeyParams::RSA(0, 0);
   EXPECT_FALSE(invalid_params.IsValid());
 
-  EXPECT_FALSE(RTCCertificateGenerator::GenerateCertificate(
-      invalid_params, Optional<uint64_t>()));
+  EXPECT_FALSE(RTCCertificateGenerator::GenerateCertificate(invalid_params,
+                                                            absl::nullopt));
 
-  fixture_->generator()->GenerateCertificateAsync(
-      invalid_params,
-      Optional<uint64_t>(),
-      fixture_);
+  fixture_->generator()->GenerateCertificateAsync(invalid_params, absl::nullopt,
+                                                  fixture_);
   EXPECT_TRUE_WAIT(fixture_->GenerateAsyncCompleted(), kGenerationTimeoutMs);
   EXPECT_FALSE(fixture_->certificate());
 }
diff --git a/rtc_base/sanitizer_unittest.cc b/rtc_base/sanitizer_unittest.cc
index 21ef432..8dc6068 100644
--- a/rtc_base/sanitizer_unittest.cc
+++ b/rtc_base/sanitizer_unittest.cc
@@ -122,28 +122,20 @@
   Foo foo;
 };
 
-// Run the callback, and crash if it *doesn't* make an uninitialized memory
-// read. If MSan isn't on, just run the callback.
+// Run the callback, and expect a crash if it *doesn't* make an uninitialized
+// memory read. If MSan isn't on, just run the callback.
 template <typename F>
 void MsanExpectUninitializedRead(F&& f) {
 #if RTC_HAS_MSAN
-  // Allow uninitialized memory reads.
-  RTC_LOG(LS_INFO) << "__msan_set_expect_umr(1)";
-  __msan_set_expect_umr(1);
-#endif
+  EXPECT_DEATH(f(), "");
+#else
   f();
-#if RTC_HAS_MSAN
-  // Disallow uninitialized memory reads again, and verify that at least
-  // one uninitialized memory read happened while we weren't looking.
-  RTC_LOG(LS_INFO) << "__msan_set_expect_umr(0)";
-  __msan_set_expect_umr(0);
 #endif
 }
 
 }  // namespace
 
-// TODO(b/9116): Enable the test when the bug is fixed.
-TEST(SanitizerTest, DISABLED_MsanUninitialized) {
+TEST(SanitizerTest, MsanUninitialized) {
   Bar bar = MsanUninitialized<Bar>({});
   // Check that a read after initialization is OK.
   bar.ID = 1;
diff --git a/rtc_base/scoped_ref_ptr.h b/rtc_base/scoped_ref_ptr.h
index 8fefc73..a583aa9 100644
--- a/rtc_base/scoped_ref_ptr.h
+++ b/rtc_base/scoped_ref_ptr.h
@@ -118,8 +118,8 @@
     // AddRef first so that self assignment should work
     if (p)
       p->AddRef();
-    if (ptr_ )
-      ptr_ ->Release();
+    if (ptr_)
+      ptr_->Release();
     ptr_ = p;
     return *this;
   }
@@ -150,9 +150,7 @@
     *pp = p;
   }
 
-  void swap(scoped_refptr<T>& r) {
-    swap(&r.ptr_);
-  }
+  void swap(scoped_refptr<T>& r) { swap(&r.ptr_); }
 
  protected:
   T* ptr_;
diff --git a/rtc_base/sequenced_task_checker_unittest.cc b/rtc_base/sequenced_task_checker_unittest.cc
index 9199eb7..96e655b 100644
--- a/rtc_base/sequenced_task_checker_unittest.cc
+++ b/rtc_base/sequenced_task_checker_unittest.cc
@@ -26,13 +26,10 @@
 // attributes that are checked at compile-time.
 class CompileTimeTestForGuardedBy {
  public:
-  int CalledOnSequence() RTC_RUN_ON(sequence_checker_) {
-    return guarded_;
-  }
+  int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
 
   void CallMeFromSequence() {
-    RTC_DCHECK_RUN_ON(&sequence_checker_)
-        << "Should be called on sequence";
+    RTC_DCHECK_RUN_ON(&sequence_checker_) << "Should be called on sequence";
   }
 
  private:
@@ -40,7 +37,6 @@
   rtc::SequencedTaskChecker sequence_checker_;
 };
 
-
 // Calls SequencedTaskChecker::CalledSequentially on another thread.
 class CallCalledSequentiallyOnThread {
  public:
diff --git a/rtc_base/signalthread.cc b/rtc_base/signalthread.cc
index 48a677e..58f8761 100644
--- a/rtc_base/signalthread.cc
+++ b/rtc_base/signalthread.cc
@@ -10,8 +10,8 @@
 
 #include "rtc_base/signalthread.h"
 
+#include "absl/memory/memory.h"
 #include "rtc_base/checks.h"
-#include "rtc_base/ptr_util.h"
 
 namespace rtc {
 
@@ -20,10 +20,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SignalThread::SignalThread()
-    : main_(Thread::Current()),
-      worker_(this),
-      state_(kInit),
-      refcount_(1) {
+    : main_(Thread::Current()), worker_(this), state_(kInit), refcount_(1) {
   main_->SignalQueueDestroyed.connect(this,
                                       &SignalThread::OnMainThreadDestroyed);
   worker_.SetName("SignalThread", this);
@@ -94,7 +91,7 @@
   return worker_.ProcessMessages(0);
 }
 
-void SignalThread::OnMessage(Message *msg) {
+void SignalThread::OnMessage(Message* msg) {
   EnterExit ee(this);
   if (ST_MSG_WORKER_DONE == msg->message_id) {
     RTC_DCHECK(main_->IsCurrent());
@@ -126,7 +123,7 @@
 }
 
 SignalThread::Worker::Worker(SignalThread* parent)
-    : Thread(MakeUnique<NullSocketServer>(), /*do_init=*/false),
+    : Thread(absl::make_unique<NullSocketServer>(), /*do_init=*/false),
       parent_(parent) {
   DoInit();
 }
diff --git a/rtc_base/signalthread.h b/rtc_base/signalthread.h
index 8daaa08..9d140c0 100644
--- a/rtc_base/signalthread.h
+++ b/rtc_base/signalthread.h
@@ -38,9 +38,7 @@
 //   tasks in the context of the main thread.
 ///////////////////////////////////////////////////////////////////////////////
 
-class SignalThread
-    : public sigslot::has_slots<>,
-      protected MessageHandler {
+class SignalThread : public sigslot::has_slots<>, protected MessageHandler {
  public:
   SignalThread();
 
@@ -63,7 +61,7 @@
   void Release();
 
   // Context: Main Thread.  Signalled when work is complete.
-  sigslot::signal1<SignalThread *> SignalWorkDone;
+  sigslot::signal1<SignalThread*> SignalWorkDone;
 
   enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE };
 
@@ -73,7 +71,7 @@
   Thread* worker() { return &worker_; }
 
   // Context: Main Thread.  Subclass should override to do pre-work setup.
-  virtual void OnWorkStart() { }
+  virtual void OnWorkStart() {}
 
   // Context: Worker Thread.  Subclass should override to do work.
   virtual void DoWork() = 0;
@@ -84,10 +82,10 @@
 
   // Context: Worker Thread.  Subclass should override when extra work is
   // needed to abort the worker thread.
-  virtual void OnWorkStop() { }
+  virtual void OnWorkStop() {}
 
   // Context: Main Thread.  Subclass should override to do post-work cleanup.
-  virtual void OnWorkDone() { }
+  virtual void OnWorkDone() {}
 
   // Context: Any Thread.  If subclass overrides, be sure to call the base
   // implementation.  Do not use (message_id < ST_MSG_FIRST_AVAILABLE)
@@ -95,11 +93,11 @@
 
  private:
   enum State {
-    kInit,            // Initialized, but not started
-    kRunning,         // Started and doing work
-    kReleasing,       // Same as running, but to be deleted when work is done
-    kComplete,        // Work is done
-    kStopping,        // Work is being interrupted
+    kInit,       // Initialized, but not started
+    kRunning,    // Started and doing work
+    kReleasing,  // Same as running, but to be deleted when work is done
+    kComplete,   // Work is done
+    kStopping,   // Work is being interrupted
   };
 
   class Worker : public Thread {
diff --git a/rtc_base/sigslot.h b/rtc_base/sigslot.h
index 318aca3..15abdca 100644
--- a/rtc_base/sigslot.h
+++ b/rtc_base/sigslot.h
@@ -110,9 +110,6 @@
 #define _SIGSLOT_SINGLE_THREADED
 #elif defined(WEBRTC_WIN)
 #define _SIGSLOT_HAS_WIN32_THREADS
-#if !defined(WIN32_LEAN_AND_MEAN)
-#define WIN32_LEAN_AND_MEAN
-#endif
 #include "rtc_base/win32.h"
 #elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
 #define _SIGSLOT_HAS_POSIX_THREADS
diff --git a/rtc_base/sigslot_unittest.cc b/rtc_base/sigslot_unittest.cc
index 234bf45..114a59f 100644
--- a/rtc_base/sigslot_unittest.cc
+++ b/rtc_base/sigslot_unittest.cc
@@ -28,33 +28,32 @@
   sigslot::signal0<> signal_;
 };
 
-template<class slot_policy = sigslot::single_threaded,
-         class signal_policy = sigslot::single_threaded>
+template <class slot_policy = sigslot::single_threaded,
+          class signal_policy = sigslot::single_threaded>
 class SigslotReceiver : public sigslot::has_slots<slot_policy> {
  public:
   SigslotReceiver() : signal_(nullptr), signal_count_(0) {}
-  ~SigslotReceiver() {
-  }
+  ~SigslotReceiver() {}
 
   // Provide copy constructor so that tests can exercise the has_slots copy
   // constructor.
   SigslotReceiver(const SigslotReceiver&) = default;
 
   void Connect(sigslot::signal0<signal_policy>* signal) {
-    if (!signal) return;
+    if (!signal)
+      return;
     Disconnect();
     signal_ = signal;
     signal->connect(this,
                     &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
   }
   void Disconnect() {
-    if (!signal_) return;
+    if (!signal_)
+      return;
     signal_->disconnect(this);
     signal_ = nullptr;
   }
-  void OnSignal() {
-    ++signal_count_;
-  }
+  void OnSignal() { ++signal_count_; }
   int signal_count() { return signal_count_; }
 
  private:
@@ -62,8 +61,8 @@
   int signal_count_;
 };
 
-template<class slot_policy = sigslot::single_threaded,
-         class mt_signal_policy = sigslot::multi_threaded_local>
+template <class slot_policy = sigslot::single_threaded,
+          class mt_signal_policy = sigslot::multi_threaded_local>
 class SigslotSlotTest : public testing::Test {
  protected:
   SigslotSlotTest() {
@@ -71,12 +70,8 @@
     TemplateIsMT(&mt_policy);
   }
 
-  virtual void SetUp() {
-    Connect();
-  }
-  virtual void TearDown() {
-    Disconnect();
-  }
+  virtual void SetUp() { Connect(); }
+  virtual void TearDown() { Disconnect(); }
 
   void Disconnect() {
     st_receiver_.Disconnect();
@@ -99,12 +94,12 @@
 
 typedef SigslotSlotTest<> SigslotSTSlotTest;
 typedef SigslotSlotTest<sigslot::multi_threaded_local,
-                        sigslot::multi_threaded_local> SigslotMTSlotTest;
+                        sigslot::multi_threaded_local>
+    SigslotMTSlotTest;
 
 class multi_threaded_local_fake : public sigslot::multi_threaded_local {
  public:
-  multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {
-  }
+  multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {}
 
   void lock() { ++lock_count_; }
   void unlock() { ++unlock_count_; }
@@ -118,8 +113,8 @@
   int unlock_count_;
 };
 
-typedef SigslotSlotTest<multi_threaded_local_fake,
-                        multi_threaded_local_fake> SigslotMTLockBase;
+typedef SigslotSlotTest<multi_threaded_local_fake, multi_threaded_local_fake>
+    SigslotMTLockBase;
 
 class SigslotMTLockTest : public SigslotMTLockBase {
  protected:
@@ -329,9 +324,7 @@
   }
 
  private:
-  void Disconnect() {
-    signal_->disconnect_all();
-  }
+  void Disconnect() { signal_->disconnect_all(); }
 
   sigslot::signal<>* signal_;
 };
diff --git a/rtc_base/sigslottester.h b/rtc_base/sigslottester.h
old mode 100755
new mode 100644
index 04c6302..646ba22
--- a/rtc_base/sigslottester.h
+++ b/rtc_base/sigslottester.h
@@ -18,7 +18,6 @@
 // To generate sigslottester.h from sigslottester.h.pump, execute:
 // /home/build/google3/third_party/gtest/scripts/pump.py sigslottester.h.pump
 
-
 // SigslotTester(s) are utility classes to check if signals owned by an
 // object are being invoked at the right time and with the right arguments.
 // They are meant to be used in tests. Tests must provide "capture" pointers
@@ -70,10 +69,8 @@
 template <class A1, class C1>
 class SigslotTester1 : public sigslot::has_slots<> {
  public:
-  SigslotTester1(sigslot::signal1<A1>* signal,
-                C1* capture1)
-      : callback_count_(0),
-      capture1_(capture1) {
+  SigslotTester1(sigslot::signal1<A1>* signal, C1* capture1)
+      : callback_count_(0), capture1_(capture1) {
     signal->connect(this, &SigslotTester1::OnSignalCallback);
   }
 
@@ -94,10 +91,8 @@
 template <class A1, class A2, class C1, class C2>
 class SigslotTester2 : public sigslot::has_slots<> {
  public:
-  SigslotTester2(sigslot::signal2<A1, A2>* signal,
-                C1* capture1, C2* capture2)
-      : callback_count_(0),
-      capture1_(capture1), capture2_(capture2) {
+  SigslotTester2(sigslot::signal2<A1, A2>* signal, C1* capture1, C2* capture2)
+      : callback_count_(0), capture1_(capture1), capture2_(capture2) {
     signal->connect(this, &SigslotTester2::OnSignalCallback);
   }
 
@@ -121,9 +116,13 @@
 class SigslotTester3 : public sigslot::has_slots<> {
  public:
   SigslotTester3(sigslot::signal3<A1, A2, A3>* signal,
-                C1* capture1, C2* capture2, C3* capture3)
+                 C1* capture1,
+                 C2* capture2,
+                 C3* capture3)
       : callback_count_(0),
-      capture1_(capture1), capture2_(capture2), capture3_(capture3) {
+        capture1_(capture1),
+        capture2_(capture2),
+        capture3_(capture3) {
     signal->connect(this, &SigslotTester3::OnSignalCallback);
   }
 
@@ -145,15 +144,26 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(SigslotTester3);
 };
 
-template <class A1, class A2, class A3, class A4, class C1, class C2, class C3,
-    class C4>
+template <class A1,
+          class A2,
+          class A3,
+          class A4,
+          class C1,
+          class C2,
+          class C3,
+          class C4>
 class SigslotTester4 : public sigslot::has_slots<> {
  public:
   SigslotTester4(sigslot::signal4<A1, A2, A3, A4>* signal,
-                C1* capture1, C2* capture2, C3* capture3, C4* capture4)
+                 C1* capture1,
+                 C2* capture2,
+                 C3* capture3,
+                 C4* capture4)
       : callback_count_(0),
-      capture1_(capture1), capture2_(capture2), capture3_(capture3),
-          capture4_(capture4) {
+        capture1_(capture1),
+        capture2_(capture2),
+        capture3_(capture3),
+        capture4_(capture4) {
     signal->connect(this, &SigslotTester4::OnSignalCallback);
   }
 
@@ -177,16 +187,30 @@
   RTC_DISALLOW_COPY_AND_ASSIGN(SigslotTester4);
 };
 
-template <class A1, class A2, class A3, class A4, class A5, class C1, class C2,
-    class C3, class C4, class C5>
+template <class A1,
+          class A2,
+          class A3,
+          class A4,
+          class A5,
+          class C1,
+          class C2,
+          class C3,
+          class C4,
+          class C5>
 class SigslotTester5 : public sigslot::has_slots<> {
  public:
   SigslotTester5(sigslot::signal5<A1, A2, A3, A4, A5>* signal,
-                C1* capture1, C2* capture2, C3* capture3, C4* capture4,
-                    C5* capture5)
+                 C1* capture1,
+                 C2* capture2,
+                 C3* capture3,
+                 C4* capture4,
+                 C5* capture5)
       : callback_count_(0),
-      capture1_(capture1), capture2_(capture2), capture3_(capture3),
-          capture4_(capture4), capture5_(capture5) {
+        capture1_(capture1),
+        capture2_(capture2),
+        capture3_(capture3),
+        capture4_(capture4),
+        capture5_(capture5) {
     signal->connect(this, &SigslotTester5::OnSignalCallback);
   }
 
diff --git a/rtc_base/sigslottester_unittest.cc b/rtc_base/sigslottester_unittest.cc
old mode 100755
new mode 100644
diff --git a/rtc_base/socket.h b/rtc_base/socket.h
index ee2c73f..b8290bb 100644
--- a/rtc_base/socket.h
+++ b/rtc_base/socket.h
@@ -14,10 +14,10 @@
 #include <errno.h>
 
 #if defined(WEBRTC_POSIX)
-#include <sys/types.h>
-#include <sys/socket.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #define SOCKET_EACCES EACCES
 #endif
 
@@ -25,8 +25,7 @@
 #include "rtc_base/win32.h"
 #endif
 
-#include "api/optional.h"
-#include "rtc_base/basictypes.h"
+#include "absl/types/optional.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/socketaddress.h"
 
@@ -148,8 +147,8 @@
 
   PacketType packet_type = PacketType::kUnknown;
   PacketInfoProtocolType protocol = PacketInfoProtocolType::kUnknown;
-  // A unique id assigned by the network manager, and rtc::nullopt if not set.
-  rtc::Optional<uint16_t> network_id;
+  // A unique id assigned by the network manager, and absl::nullopt if not set.
+  absl::optional<uint16_t> network_id;
   size_t packet_size_bytes = 0;
   size_t turn_overhead_bytes = 0;
   SocketAddress local_socket_address;
@@ -184,8 +183,8 @@
 
   virtual int Bind(const SocketAddress& addr) = 0;
   virtual int Connect(const SocketAddress& addr) = 0;
-  virtual int Send(const void *pv, size_t cb) = 0;
-  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0;
+  virtual int Send(const void* pv, size_t cb) = 0;
+  virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) = 0;
   // |timestamp| is in units of microseconds.
   virtual int Recv(void* pv, size_t cb, int64_t* timestamp) = 0;
   virtual int RecvFrom(void* pv,
@@ -193,26 +192,22 @@
                        SocketAddress* paddr,
                        int64_t* timestamp) = 0;
   virtual int Listen(int backlog) = 0;
-  virtual Socket *Accept(SocketAddress *paddr) = 0;
+  virtual Socket* Accept(SocketAddress* paddr) = 0;
   virtual int Close() = 0;
   virtual int GetError() const = 0;
   virtual void SetError(int error) = 0;
   inline bool IsBlocking() const { return IsBlockingError(GetError()); }
 
-  enum ConnState {
-    CS_CLOSED,
-    CS_CONNECTING,
-    CS_CONNECTED
-  };
+  enum ConnState { CS_CLOSED, CS_CONNECTING, CS_CONNECTED };
   virtual ConnState GetState() const = 0;
 
   enum Option {
     OPT_DONTFRAGMENT,
-    OPT_RCVBUF,      // receive buffer size
-    OPT_SNDBUF,      // send buffer size
-    OPT_NODELAY,     // whether Nagle algorithm is enabled
-    OPT_IPV6_V6ONLY, // Whether the socket is IPv6 only.
-    OPT_DSCP,        // DSCP code
+    OPT_RCVBUF,                // receive buffer size
+    OPT_SNDBUF,                // send buffer size
+    OPT_NODELAY,               // whether Nagle algorithm is enabled
+    OPT_IPV6_V6ONLY,           // Whether the socket is IPv6 only.
+    OPT_DSCP,                  // DSCP code
     OPT_RTP_SENDTIME_EXTN_ID,  // This is a non-traditional socket option param.
                                // This is specific to libjingle and will be used
                                // if SendTime option is needed at socket level.
diff --git a/rtc_base/socket_unittest.cc b/rtc_base/socket_unittest.cc
index be958d3..cbc5eb5 100644
--- a/rtc_base/socket_unittest.cc
+++ b/rtc_base/socket_unittest.cc
@@ -12,12 +12,12 @@
 
 #include "rtc_base/socket_unittest.h"
 
+#include "absl/memory/memory.h"
 #include "rtc_base/arraysize.h"
 #include "rtc_base/asyncudpsocket.h"
 #include "rtc_base/buffer.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/nethelpers.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/socketserver.h"
 #include "rtc_base/testclient.h"
 #include "rtc_base/testutils.h"
@@ -291,7 +291,7 @@
   dns_addr.SetIP(host);
   EXPECT_EQ(0, client->Connect(dns_addr));
   // TODO: Bind when doing DNS lookup.
-  //EXPECT_NE(kEmptyAddr, client->GetLocalAddress());  // Implicit Bind
+  // EXPECT_NE(kEmptyAddr, client->GetLocalAddress());  // Implicit Bind
 
   // Client is connecting, outcome not yet determined.
   EXPECT_EQ(AsyncSocket::CS_CONNECTING, client->GetState());
@@ -444,9 +444,8 @@
 
   // Try to connect again, to an unresolved hostname.
   // Shouldn't break anything.
-  EXPECT_EQ(SOCKET_ERROR,
-            client->Connect(SocketAddress("localhost",
-                                          server->GetLocalAddress().port())));
+  EXPECT_EQ(SOCKET_ERROR, client->Connect(SocketAddress(
+                              "localhost", server->GetLocalAddress().port())));
   EXPECT_EQ(AsyncSocket::CS_CONNECTED, accepted->GetState());
   EXPECT_EQ(AsyncSocket::CS_CONNECTED, client->GetState());
   EXPECT_EQ(client->GetRemoteAddress(), server->GetLocalAddress());
@@ -694,8 +693,9 @@
   EXPECT_LT(0, accepted->Recv(buf, 1024, nullptr));
 }
 
-void SocketTest::TcpInternal(const IPAddress& loopback, size_t data_size,
-    ptrdiff_t max_send_size) {
+void SocketTest::TcpInternal(const IPAddress& loopback,
+                             size_t data_size,
+                             ptrdiff_t max_send_size) {
   StreamSink sink;
   SocketAddress accept_addr;
 
@@ -792,7 +792,7 @@
       }
       if (recved_size >= 0) {
         EXPECT_LE(static_cast<size_t>(recved_size),
-            sent_size - recv_buffer.size());
+                  sent_size - recv_buffer.size());
         recv_buffer.AppendData(recved_data.data(), recved_size);
       } else {
         ASSERT_TRUE(receiver->IsBlocking());
@@ -858,7 +858,8 @@
   // Fill the socket buffer.
   char buf[1024 * 16] = {0};
   int sends = 0;
-  while (++sends && accepted->Send(&buf, arraysize(buf)) != -1) {}
+  while (++sends && accepted->Send(&buf, arraysize(buf)) != -1) {
+  }
   EXPECT_TRUE(accepted->IsBlocking());
 
   // Wait until data is available.
@@ -892,8 +893,7 @@
 void SocketTest::UdpInternal(const IPAddress& loopback) {
   SocketAddress empty = EmptySocketAddressWithFamily(loopback.family());
   // Test basic bind and connect behavior.
-  AsyncSocket* socket =
-      ss_->CreateAsyncSocket(loopback.family(), SOCK_DGRAM);
+  AsyncSocket* socket = ss_->CreateAsyncSocket(loopback.family(), SOCK_DGRAM);
   EXPECT_EQ(AsyncSocket::CS_CLOSED, socket->GetState());
   EXPECT_EQ(0, socket->Bind(SocketAddress(loopback, 0)));
   SocketAddress addr1 = socket->GetLocalAddress();
@@ -905,9 +905,9 @@
 
   // Test send/receive behavior.
   std::unique_ptr<TestClient> client1(
-      new TestClient(WrapUnique(AsyncUDPSocket::Create(ss_, addr1))));
+      new TestClient(absl::WrapUnique(AsyncUDPSocket::Create(ss_, addr1))));
   std::unique_ptr<TestClient> client2(
-      new TestClient(WrapUnique(AsyncUDPSocket::Create(ss_, empty))));
+      new TestClient(absl::WrapUnique(AsyncUDPSocket::Create(ss_, empty))));
 
   SocketAddress addr2;
   EXPECT_EQ(3, client2->SendTo("foo", 3, addr1));
@@ -920,7 +920,7 @@
   // TODO: figure out what the intent is here
   for (int i = 0; i < 10; ++i) {
     client2.reset(
-        new TestClient(WrapUnique(AsyncUDPSocket::Create(ss_, empty))));
+        new TestClient(absl::WrapUnique(AsyncUDPSocket::Create(ss_, empty))));
 
     SocketAddress addr4;
     EXPECT_EQ(3, client2->SendTo("foo", 3, addr1));
@@ -941,13 +941,13 @@
   // RFC 5737 - The blocks 192.0.2.0/24 (TEST-NET-1) ... are provided for use in
   // documentation.
   // RFC 3849 - 2001:DB8::/32 as a documentation-only prefix.
-  std::string dest = (loopback.family() == AF_INET6) ?
-      "2001:db8::1" : "192.0.2.0";
+  std::string dest =
+      (loopback.family() == AF_INET6) ? "2001:db8::1" : "192.0.2.0";
   SocketAddress test_addr(dest, 2345);
 
   // Test send
   std::unique_ptr<TestClient> client(
-      new TestClient(WrapUnique(AsyncUDPSocket::Create(ss_, empty))));
+      new TestClient(absl::WrapUnique(AsyncUDPSocket::Create(ss_, empty))));
   int test_packet_size = 1200;
   std::unique_ptr<char[]> test_packet(new char[test_packet_size]);
   // Init the test packet just to avoid memcheck warning.
diff --git a/rtc_base/socket_unittest.h b/rtc_base/socket_unittest.h
index 55df219..db226c4 100644
--- a/rtc_base/socket_unittest.h
+++ b/rtc_base/socket_unittest.h
@@ -21,9 +21,10 @@
 // socketserver, and call the SocketTest test methods.
 class SocketTest : public testing::Test {
  protected:
-  SocketTest() : kIPv4Loopback(INADDR_LOOPBACK),
-                 kIPv6Loopback(in6addr_loopback),
-                 ss_(nullptr) {}
+  SocketTest()
+      : kIPv4Loopback(INADDR_LOOPBACK),
+        kIPv6Loopback(in6addr_loopback),
+        ss_(nullptr) {}
   void SetUp() override;
   void TestConnectIPv4();
   void TestConnectIPv6();
@@ -65,8 +66,9 @@
   const IPAddress kIPv6Loopback;
 
  protected:
-  void TcpInternal(const IPAddress& loopback, size_t data_size,
-      ptrdiff_t max_send_size);
+  void TcpInternal(const IPAddress& loopback,
+                   size_t data_size,
+                   ptrdiff_t max_send_size);
 
  private:
   void ConnectInternal(const IPAddress& loopback);
diff --git a/rtc_base/socketadapters.cc b/rtc_base/socketadapters.cc
index a300495..8095894 100644
--- a/rtc_base/socketadapters.cc
+++ b/rtc_base/socketadapters.cc
@@ -9,11 +9,11 @@
  */
 
 #if defined(_MSC_VER) && _MSC_VER < 1300
-#pragma warning(disable:4786)
+#pragma warning(disable : 4786)
 #endif
 
-#include <time.h>
 #include <errno.h>
+#include <time.h>
 
 #if defined(WEBRTC_WIN)
 #include <windows.h>
@@ -37,16 +37,18 @@
 namespace rtc {
 
 BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t size)
-    : AsyncSocketAdapter(socket), buffer_size_(size),
-      data_len_(0), buffering_(false) {
+    : AsyncSocketAdapter(socket),
+      buffer_size_(size),
+      data_len_(0),
+      buffering_(false) {
   buffer_ = new char[buffer_size_];
 }
 
 BufferedReadAdapter::~BufferedReadAdapter() {
-  delete [] buffer_;
+  delete[] buffer_;
 }
 
-int BufferedReadAdapter::Send(const void *pv, size_t cb) {
+int BufferedReadAdapter::Send(const void* pv, size_t cb) {
   if (buffering_) {
     // TODO: Spoof error better; Signal Writeable
     socket_->SetError(EWOULDBLOCK);
@@ -70,7 +72,7 @@
     if (data_len_ > 0) {
       memmove(buffer_, buffer_ + read, data_len_);
     }
-    pv = static_cast<char *>(pv) + read;
+    pv = static_cast<char*>(pv) + read;
     cb -= read;
   }
 
@@ -95,7 +97,7 @@
   buffering_ = on;
 }
 
-void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) {
+void BufferedReadAdapter::OnReadEvent(AsyncSocket* socket) {
   RTC_DCHECK(socket == socket_);
 
   if (!buffering_) {
@@ -124,8 +126,7 @@
 
 AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
                                                size_t buffer_size)
-    : BufferedReadAdapter(socket, buffer_size) {
-}
+    : BufferedReadAdapter(socket, buffer_size) {}
 
 AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
 
@@ -172,8 +173,7 @@
 };
 
 AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
-    : BufferedReadAdapter(socket, 1024) {
-}
+    : BufferedReadAdapter(socket, 1024) {}
 
 int AsyncSSLSocket::Connect(const SocketAddress& addr) {
   // Begin buffering before we connect, so that there isn't a race condition
@@ -182,7 +182,7 @@
   return BufferedReadAdapter::Connect(addr);
 }
 
-void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) {
+void AsyncSSLSocket::OnConnectEvent(AsyncSocket* socket) {
   RTC_DCHECK(socket == socket_);
   // TODO: we could buffer output too...
   const int res = DirectSend(kSslClientHello, sizeof(kSslClientHello));
@@ -214,7 +214,7 @@
 }
 
 AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
-     : BufferedReadAdapter(socket, 1024) {
+    : BufferedReadAdapter(socket, 1024) {
   BufferInput(true);
 }
 
@@ -249,10 +249,14 @@
                                              const SocketAddress& proxy,
                                              const std::string& username,
                                              const CryptString& password)
-  : BufferedReadAdapter(socket, 1024), proxy_(proxy), agent_(user_agent),
-    user_(username), pass_(password), force_connect_(false), state_(PS_ERROR),
-    context_(0) {
-}
+    : BufferedReadAdapter(socket, 1024),
+      proxy_(proxy),
+      agent_(user_agent),
+      user_(username),
+      pass_(password),
+      force_connect_(false),
+      state_(PS_ERROR),
+      context_(0) {}
 
 AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
   delete context_;
@@ -295,7 +299,7 @@
   }
 }
 
-void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) {
+void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket* socket) {
   RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
   if (!ShouldIssueConnect()) {
     state_ = PS_TUNNEL;
@@ -305,7 +309,7 @@
   SendRequest();
 }
 
-void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) {
+void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket* socket, int err) {
   RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
   if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
     state_ = PS_ERROR;
@@ -383,7 +387,7 @@
   RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
 }
 
-void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) {
+void AsyncHttpsProxySocket::ProcessLine(char* data, size_t len) {
   RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
 
   if (len == 0) {
@@ -404,15 +408,18 @@
       if (!unknown_mechanisms_.empty() && !report) {
         report = true;
         std::string msg(
-          "Unable to connect to the Google Talk service due to an incompatibility "
-          "with your proxy.\r\nPlease help us resolve this issue by submitting the "
-          "following information to us using our technical issue submission form "
-          "at:\r\n\r\n"
-          "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
-          "We apologize for the inconvenience.\r\n\r\n"
-          "Information to submit to Google: "
-          );
-        //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: ");
+            "Unable to connect to the Google Talk service due to an "
+            "incompatibility "
+            "with your proxy.\r\nPlease help us resolve this issue by "
+            "submitting the "
+            "following information to us using our technical issue submission "
+            "form "
+            "at:\r\n\r\n"
+            "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
+            "We apologize for the inconvenience.\r\n\r\n"
+            "Information to submit to Google: ");
+        // std::string msg("Please report the following information to
+        // foo@bar.com:\r\nUnknown methods: ");
         msg.append(unknown_mechanisms_);
 #if defined(WEBRTC_WIN)
         MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
@@ -433,50 +440,49 @@
       return;
     }
     switch (code) {
-    case 200:
-      // connection good!
-      state_ = PS_TUNNEL_HEADERS;
-      return;
+      case 200:
+        // connection good!
+        state_ = PS_TUNNEL_HEADERS;
+        return;
 #if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
 #error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
 #endif
-    case 407:  // HTTP_STATUS_PROXY_AUTH_REQ
-      state_ = PS_AUTHENTICATE;
-      return;
-    default:
-      defer_error_ = 0;
-      state_ = PS_ERROR_HEADERS;
-      return;
+      case 407:  // HTTP_STATUS_PROXY_AUTH_REQ
+        state_ = PS_AUTHENTICATE;
+        return;
+      default:
+        defer_error_ = 0;
+        state_ = PS_ERROR_HEADERS;
+        return;
     }
-  } else if ((state_ == PS_AUTHENTICATE)
-             && (_strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
+  } else if ((state_ == PS_AUTHENTICATE) &&
+             (_strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
     std::string response, auth_method;
-    switch (HttpAuthenticate(data + 19, len - 19,
-                             proxy_, "CONNECT", "/",
-                             user_, pass_, context_, response, auth_method)) {
-    case HAR_IGNORE:
-      RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
-      if (!unknown_mechanisms_.empty())
-        unknown_mechanisms_.append(", ");
-      unknown_mechanisms_.append(auth_method);
-      break;
-    case HAR_RESPONSE:
-      headers_ = "Proxy-Authorization: ";
-      headers_.append(response);
-      headers_.append("\r\n");
-      state_ = PS_SKIP_HEADERS;
-      unknown_mechanisms_.clear();
-      break;
-    case HAR_CREDENTIALS:
-      defer_error_ = SOCKET_EACCES;
-      state_ = PS_ERROR_HEADERS;
-      unknown_mechanisms_.clear();
-      break;
-    case HAR_ERROR:
-      defer_error_ = 0;
-      state_ = PS_ERROR_HEADERS;
-      unknown_mechanisms_.clear();
-      break;
+    switch (HttpAuthenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_,
+                             pass_, context_, response, auth_method)) {
+      case HAR_IGNORE:
+        RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
+        if (!unknown_mechanisms_.empty())
+          unknown_mechanisms_.append(", ");
+        unknown_mechanisms_.append(auth_method);
+        break;
+      case HAR_RESPONSE:
+        headers_ = "Proxy-Authorization: ";
+        headers_.append(response);
+        headers_.append("\r\n");
+        state_ = PS_SKIP_HEADERS;
+        unknown_mechanisms_.clear();
+        break;
+      case HAR_CREDENTIALS:
+        defer_error_ = SOCKET_EACCES;
+        state_ = PS_ERROR_HEADERS;
+        unknown_mechanisms_.clear();
+        break;
+      case HAR_ERROR:
+        defer_error_ = 0;
+        state_ = PS_ERROR_HEADERS;
+        unknown_mechanisms_.clear();
+        break;
     }
   } else if (_strnicmp(data, "Content-Length:", 15) == 0) {
     content_length_ = strtoul(data + 15, 0, 0);
@@ -515,9 +521,11 @@
                                              const SocketAddress& proxy,
                                              const std::string& username,
                                              const CryptString& password)
-    : BufferedReadAdapter(socket, 1024), state_(SS_ERROR), proxy_(proxy),
-      user_(username), pass_(password) {
-}
+    : BufferedReadAdapter(socket, 1024),
+      state_(SS_ERROR),
+      proxy_(proxy),
+      user_(username),
+      pass_(password) {}
 
 AsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
 
@@ -562,8 +570,7 @@
 
   if (state_ == SS_HELLO) {
     uint8_t ver, method;
-    if (!response.ReadUInt8(&ver) ||
-        !response.ReadUInt8(&method))
+    if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&method))
       return;
 
     if (ver != 5) {
@@ -581,8 +588,7 @@
     }
   } else if (state_ == SS_AUTH) {
     uint8_t ver, status;
-    if (!response.ReadUInt8(&ver) ||
-        !response.ReadUInt8(&status))
+    if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&status))
       return;
 
     if ((ver != 1) || (status != 0)) {
@@ -593,10 +599,8 @@
     SendConnect();
   } else if (state_ == SS_CONNECT) {
     uint8_t ver, rep, rsv, atyp;
-    if (!response.ReadUInt8(&ver) ||
-        !response.ReadUInt8(&rep) ||
-        !response.ReadUInt8(&rsv) ||
-        !response.ReadUInt8(&atyp))
+    if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&rep) ||
+        !response.ReadUInt8(&rsv) || !response.ReadUInt8(&atyp))
       return;
 
     if ((ver != 5) || (rep != 0)) {
@@ -607,22 +611,19 @@
     uint16_t port;
     if (atyp == 1) {
       uint32_t addr;
-      if (!response.ReadUInt32(&addr) ||
-          !response.ReadUInt16(&port))
+      if (!response.ReadUInt32(&addr) || !response.ReadUInt16(&port))
         return;
       RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
     } else if (atyp == 3) {
       uint8_t len;
       std::string addr;
-      if (!response.ReadUInt8(&len) ||
-          !response.ReadString(&addr, len) ||
+      if (!response.ReadUInt8(&len) || !response.ReadString(&addr, len) ||
           !response.ReadUInt16(&port))
         return;
       RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
     } else if (atyp == 4) {
       std::string addr;
-      if (!response.ReadString(&addr, 16) ||
-          !response.ReadUInt16(&port))
+      if (!response.ReadString(&addr, 16) || !response.ReadUInt16(&port))
         return;
       RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
     } else {
@@ -651,7 +652,7 @@
 
 void AsyncSocksProxySocket::SendHello() {
   ByteBufferWriter request;
-  request.WriteUInt8(5);    // Socks Version
+  request.WriteUInt8(5);  // Socks Version
   if (user_.empty()) {
     request.WriteUInt8(1);  // Authentication Mechanisms
     request.WriteUInt8(0);  // No authentication
@@ -666,30 +667,30 @@
 
 void AsyncSocksProxySocket::SendAuth() {
   ByteBufferWriterT<ZeroOnFreeBuffer<char>> request;
-  request.WriteUInt8(1);           // Negotiation Version
+  request.WriteUInt8(1);  // Negotiation Version
   request.WriteUInt8(static_cast<uint8_t>(user_.size()));
-  request.WriteString(user_);      // Username
+  request.WriteString(user_);  // Username
   request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
   size_t len = pass_.GetLength() + 1;
-  char * sensitive = new char[len];
+  char* sensitive = new char[len];
   pass_.CopyTo(sensitive, true);
   request.WriteBytes(sensitive, pass_.GetLength());  // Password
   ExplicitZeroMemory(sensitive, len);
-  delete [] sensitive;
+  delete[] sensitive;
   DirectSend(request.Data(), request.Length());
   state_ = SS_AUTH;
 }
 
 void AsyncSocksProxySocket::SendConnect() {
   ByteBufferWriter request;
-  request.WriteUInt8(5);              // Socks Version
-  request.WriteUInt8(1);              // CONNECT
-  request.WriteUInt8(0);              // Reserved
+  request.WriteUInt8(5);  // Socks Version
+  request.WriteUInt8(1);  // CONNECT
+  request.WriteUInt8(0);  // Reserved
   if (dest_.IsUnresolvedIP()) {
     std::string hostname = dest_.hostname();
-    request.WriteUInt8(3);            // DOMAINNAME
+    request.WriteUInt8(3);  // DOMAINNAME
     request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
-    request.WriteString(hostname);    // Destination Hostname
+    request.WriteString(hostname);  // Destination Hostname
   } else {
     request.WriteUInt8(1);            // IPV4
     request.WriteUInt32(dest_.ip());  // Destination IP
@@ -736,8 +737,7 @@
 
 void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
   uint8_t ver, num_methods;
-  if (!request->ReadUInt8(&ver) ||
-      !request->ReadUInt8(&num_methods)) {
+  if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
     Error(0);
     return;
   }
@@ -767,7 +767,7 @@
 
 void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
   ByteBufferWriter response;
-  response.WriteUInt8(5);  // Socks Version
+  response.WriteUInt8(5);       // Socks Version
   response.WriteUInt8(method);  // Auth method
   DirectSend(response);
 }
@@ -775,10 +775,8 @@
 void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
   uint8_t ver, user_len, pass_len;
   std::string user, pass;
-  if (!request->ReadUInt8(&ver) ||
-      !request->ReadUInt8(&user_len) ||
-      !request->ReadString(&user, user_len) ||
-      !request->ReadUInt8(&pass_len) ||
+  if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
+      !request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
       !request->ReadString(&pass, pass_len)) {
     Error(0);
     return;
@@ -800,20 +798,16 @@
   uint8_t ver, command, reserved, addr_type;
   uint32_t ip;
   uint16_t port;
-  if (!request->ReadUInt8(&ver) ||
-      !request->ReadUInt8(&command) ||
-      !request->ReadUInt8(&reserved) ||
-      !request->ReadUInt8(&addr_type) ||
-      !request->ReadUInt32(&ip) ||
-      !request->ReadUInt16(&port)) {
-      Error(0);
-      return;
+  if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
+      !request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
+      !request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
+    Error(0);
+    return;
   }
 
-  if (ver != 5 || command != 1 ||
-      reserved != 0 || addr_type != 1) {
-      Error(0);
-      return;
+  if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
+    Error(0);
+    return;
   }
 
   SignalConnectRequest(this, SocketAddress(ip, port));
@@ -826,10 +820,10 @@
     return;
 
   ByteBufferWriter response;
-  response.WriteUInt8(5);  // Socks version
+  response.WriteUInt8(5);              // Socks version
   response.WriteUInt8((result != 0));  // 0x01 is generic error
-  response.WriteUInt8(0);  // reserved
-  response.WriteUInt8(1);  // IPv4 address
+  response.WriteUInt8(0);              // reserved
+  response.WriteUInt8(1);              // IPv4 address
   response.WriteUInt32(addr.ip());
   response.WriteUInt16(addr.port());
   DirectSend(response);
diff --git a/rtc_base/socketadapters.h b/rtc_base/socketadapters.h
index c5d1bfc..ad88fe6 100644
--- a/rtc_base/socketadapters.h
+++ b/rtc_base/socketadapters.h
@@ -49,7 +49,7 @@
   void OnReadEvent(AsyncSocket* socket) override;
 
  private:
-  char * buffer_;
+  char* buffer_;
   size_t buffer_size_, data_len_;
   bool buffering_;
   RTC_DISALLOW_COPY_AND_ASSIGN(BufferedReadAdapter);
@@ -62,8 +62,8 @@
  public:
   AsyncProxyServerSocket(AsyncSocket* socket, size_t buffer_size);
   ~AsyncProxyServerSocket() override;
-  sigslot::signal2<AsyncProxyServerSocket*,
-                   const SocketAddress&>  SignalConnectRequest;
+  sigslot::signal2<AsyncProxyServerSocket*, const SocketAddress&>
+      SignalConnectRequest;
   virtual void SendConnectResult(int err, const SocketAddress& addr) = 0;
 };
 
@@ -99,9 +99,11 @@
 // Implements a socket adapter that speaks the HTTP/S proxy protocol.
 class AsyncHttpsProxySocket : public BufferedReadAdapter {
  public:
-  AsyncHttpsProxySocket(AsyncSocket* socket, const std::string& user_agent,
-    const SocketAddress& proxy,
-    const std::string& username, const CryptString& password);
+  AsyncHttpsProxySocket(AsyncSocket* socket,
+                        const std::string& user_agent,
+                        const SocketAddress& proxy,
+                        const std::string& username,
+                        const CryptString& password);
   ~AsyncHttpsProxySocket() override;
 
   // If connect is forced, the adapter will always issue an HTTP CONNECT to the
@@ -134,10 +136,18 @@
   int defer_error_;
   bool expect_close_;
   enum ProxyState {
-    PS_INIT, PS_LEADER, PS_AUTHENTICATE, PS_SKIP_HEADERS, PS_ERROR_HEADERS,
-    PS_TUNNEL_HEADERS, PS_SKIP_BODY, PS_TUNNEL, PS_WAIT_CLOSE, PS_ERROR
+    PS_INIT,
+    PS_LEADER,
+    PS_AUTHENTICATE,
+    PS_SKIP_HEADERS,
+    PS_ERROR_HEADERS,
+    PS_TUNNEL_HEADERS,
+    PS_SKIP_BODY,
+    PS_TUNNEL,
+    PS_WAIT_CLOSE,
+    PS_ERROR
   } state_;
-  HttpAuthContext * context_;
+  HttpAuthContext* context_;
   std::string unknown_mechanisms_;
   RTC_DISALLOW_COPY_AND_ASSIGN(AsyncHttpsProxySocket);
 };
@@ -147,8 +157,10 @@
 // Implements a socket adapter that speaks the SOCKS proxy protocol.
 class AsyncSocksProxySocket : public BufferedReadAdapter {
  public:
-  AsyncSocksProxySocket(AsyncSocket* socket, const SocketAddress& proxy,
-    const std::string& username, const CryptString& password);
+  AsyncSocksProxySocket(AsyncSocket* socket,
+                        const SocketAddress& proxy,
+                        const std::string& username,
+                        const CryptString& password);
   ~AsyncSocksProxySocket() override;
 
   int Connect(const SocketAddress& addr) override;
@@ -166,9 +178,7 @@
   void Error(int error);
 
  private:
-  enum State {
-    SS_INIT, SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR
-  };
+  enum State { SS_INIT, SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR };
   State state_;
   SocketAddress proxy_, dest_;
   std::string user_;
@@ -196,7 +206,12 @@
 
   static const int kBufferSize = 1024;
   enum State {
-    SS_HELLO, SS_AUTH, SS_CONNECT, SS_CONNECT_PENDING, SS_TUNNEL, SS_ERROR
+    SS_HELLO,
+    SS_AUTH,
+    SS_CONNECT,
+    SS_CONNECT_PENDING,
+    SS_TUNNEL,
+    SS_ERROR
   };
   State state_;
   RTC_DISALLOW_COPY_AND_ASSIGN(AsyncSocksProxyServerSocket);
diff --git a/rtc_base/socketaddress.cc b/rtc_base/socketaddress.cc
index a58c001..c91846d 100644
--- a/rtc_base/socketaddress.cc
+++ b/rtc_base/socketaddress.cc
@@ -12,9 +12,9 @@
 #include "rtc_base/numerics/safe_conversions.h"
 
 #if defined(WEBRTC_POSIX)
-#include <sys/types.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #if defined(OPENBSD)
 #include <netinet/in_systm.h>
 #endif
@@ -204,8 +204,8 @@
 }
 
 bool SocketAddress::IsLoopbackIP() const {
-  return IPIsLoopback(ip_) || (IPIsAny(ip_) &&
-                               0 == strcmp(hostname_.c_str(), "localhost"));
+  return IPIsLoopback(ip_) ||
+         (IPIsAny(ip_) && 0 == strcmp(hostname_.c_str(), "localhost"));
 }
 
 bool SocketAddress::IsPrivateIP() const {
@@ -234,7 +234,7 @@
 
 bool SocketAddress::EqualIPs(const SocketAddress& addr) const {
   return (ip_ == addr.ip_) &&
-      ((!IPIsAny(ip_) && !IPIsUnspec(ip_)) || (hostname_ == addr.hostname_));
+         ((!IPIsAny(ip_) && !IPIsUnspec(ip_)) || (hostname_ == addr.hostname_));
 }
 
 bool SocketAddress::EqualPorts(const SocketAddress& addr) const {
@@ -293,7 +293,7 @@
   return 0;
 }
 
-size_t SocketAddress::ToDualStackSockAddrStorage(sockaddr_storage *addr) const {
+size_t SocketAddress::ToDualStackSockAddrStorage(sockaddr_storage* addr) const {
   return ToSockAddrStorageHelper(addr, ip_.AsIPv6Address(), port_, scope_id_);
 }
 
diff --git a/rtc_base/socketaddress.h b/rtc_base/socketaddress.h
index 90919c2..7095be1 100644
--- a/rtc_base/socketaddress.h
+++ b/rtc_base/socketaddress.h
@@ -17,7 +17,6 @@
 #include <ostream>  // no-presubmit-check TODO(webrtc:8982)
 #endif              // UNIT_TEST
 #include <vector>
-#include "rtc_base/basictypes.h"
 #include "rtc_base/ipaddress.h"
 
 #undef SetPort
@@ -95,7 +94,7 @@
 
   const IPAddress& ipaddr() const;
 
-  int family() const {return ip_.family(); }
+  int family() const { return ip_.family(); }
 
   // Returns the port part of this address.
   uint16_t port() const;
@@ -105,7 +104,7 @@
   // interfaces having different scope-ids for their link-local addresses.
   // IPv4 address do not have scope_ids and sockaddr_in structures do not have
   // a field for them.
-  int scope_id() const {return scope_id_; }
+  int scope_id() const { return scope_id_; }
   void SetScopeID(int id) { scope_id_ = id; }
 
   // Returns the 'host' portion of the address (hostname or IP) in a form
@@ -155,13 +154,13 @@
   bool IsUnresolvedIP() const;
 
   // Determines whether this address is identical to the given one.
-  bool operator ==(const SocketAddress& addr) const;
-  inline bool operator !=(const SocketAddress& addr) const {
-    return !this->operator ==(addr);
+  bool operator==(const SocketAddress& addr) const;
+  inline bool operator!=(const SocketAddress& addr) const {
+    return !this->operator==(addr);
   }
 
   // Compares based on IP and then port.
-  bool operator <(const SocketAddress& addr) const;
+  bool operator<(const SocketAddress& addr) const;
 
   // Determines whether this address has the same IP as the one given.
   bool EqualIPs(const SocketAddress& addr) const;
diff --git a/rtc_base/socketaddress_unittest.cc b/rtc_base/socketaddress_unittest.cc
index fb195b6..b7a2d92 100644
--- a/rtc_base/socketaddress_unittest.cc
+++ b/rtc_base/socketaddress_unittest.cc
@@ -18,14 +18,12 @@
 
 namespace rtc {
 
-const in6_addr kTestV6Addr =  { { {0x20, 0x01, 0x0d, 0xb8,
-                                   0x10, 0x20, 0x30, 0x40,
-                                   0x50, 0x60, 0x70, 0x80,
-                                   0x90, 0xA0, 0xB0, 0xC0} } };
-const in6_addr kMappedV4Addr = { { {0x00, 0x00, 0x00, 0x00,
-                                    0x00, 0x00, 0x00, 0x00,
-                                    0x00, 0x00, 0xFF, 0xFF,
-                                    0x01, 0x02, 0x03, 0x04} } };
+const in6_addr kTestV6Addr = {
+    {{0x20, 0x01, 0x0d, 0xb8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
+      0x90, 0xA0, 0xB0, 0xC0}}};
+const in6_addr kMappedV4Addr = {
+    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
+      0x01, 0x02, 0x03, 0x04}}};
 const std::string kTestV6AddrString = "2001:db8:1020:3040:5060:7080:90a0:b0c0";
 const std::string kTestV6AddrAnonymizedString = "2001:db8:1020:x:x:x:x:x";
 const std::string kTestV6AddrFullString =
@@ -240,16 +238,14 @@
   EXPECT_FALSE(SocketAddressFromSockAddrStorage(addr_storage, nullptr));
 }
 
-bool AreEqual(const SocketAddress& addr1,
-              const SocketAddress& addr2) {
-  return addr1 == addr2 && addr2 == addr1 &&
-      !(addr1 != addr2) && !(addr2 != addr1);
+bool AreEqual(const SocketAddress& addr1, const SocketAddress& addr2) {
+  return addr1 == addr2 && addr2 == addr1 && !(addr1 != addr2) &&
+         !(addr2 != addr1);
 }
 
-bool AreUnequal(const SocketAddress& addr1,
-                const SocketAddress& addr2) {
-  return !(addr1 == addr2) && !(addr2 == addr1) &&
-      addr1 != addr2 && addr2 != addr1;
+bool AreUnequal(const SocketAddress& addr1, const SocketAddress& addr2) {
+  return !(addr1 == addr2) && !(addr2 == addr1) && addr1 != addr2 &&
+         addr2 != addr1;
 }
 
 TEST(SocketAddressTest, TestEqualityOperators) {
@@ -286,9 +282,7 @@
 }
 
 bool IsLessThan(const SocketAddress& addr1, const SocketAddress& addr2) {
-  return addr1 < addr2 &&
-      !(addr2 < addr1) &&
-      !(addr1 == addr2);
+  return addr1 < addr2 && !(addr2 < addr1) && !(addr1 == addr2);
 }
 
 TEST(SocketAddressTest, TestComparisonOperator) {
diff --git a/rtc_base/socketaddresspair.cc b/rtc_base/socketaddresspair.cc
index 3e4748f..914ffd9 100644
--- a/rtc_base/socketaddresspair.cc
+++ b/rtc_base/socketaddresspair.cc
@@ -12,17 +12,15 @@
 
 namespace rtc {
 
-SocketAddressPair::SocketAddressPair(
-    const SocketAddress& src, const SocketAddress& dest)
-    : src_(src), dest_(dest) {
-}
+SocketAddressPair::SocketAddressPair(const SocketAddress& src,
+                                     const SocketAddress& dest)
+    : src_(src), dest_(dest) {}
 
-
-bool SocketAddressPair::operator ==(const SocketAddressPair& p) const {
+bool SocketAddressPair::operator==(const SocketAddressPair& p) const {
   return (src_ == p.src_) && (dest_ == p.dest_);
 }
 
-bool SocketAddressPair::operator <(const SocketAddressPair& p) const {
+bool SocketAddressPair::operator<(const SocketAddressPair& p) const {
   if (src_ < p.src_)
     return true;
   if (p.src_ < src_)
@@ -38,4 +36,4 @@
   return src_.Hash() ^ dest_.Hash();
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/socketaddresspair.h b/rtc_base/socketaddresspair.h
index 8ff0ee6..5ff148a 100644
--- a/rtc_base/socketaddresspair.h
+++ b/rtc_base/socketaddresspair.h
@@ -19,23 +19,23 @@
 // identify a connection between two machines.  (For UDP, this "connection" is
 // not maintained explicitly in a socket.)
 class SocketAddressPair {
-public:
+ public:
   SocketAddressPair() {}
   SocketAddressPair(const SocketAddress& srs, const SocketAddress& dest);
 
   const SocketAddress& source() const { return src_; }
   const SocketAddress& destination() const { return dest_; }
 
-  bool operator ==(const SocketAddressPair& r) const;
-  bool operator <(const SocketAddressPair& r) const;
+  bool operator==(const SocketAddressPair& r) const;
+  bool operator<(const SocketAddressPair& r) const;
 
   size_t Hash() const;
 
-private:
+ private:
   SocketAddress src_;
   SocketAddress dest_;
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_SOCKETADDRESSPAIR_H_
+#endif  // RTC_BASE_SOCKETADDRESSPAIR_H_
diff --git a/rtc_base/socketfactory.h b/rtc_base/socketfactory.h
index 58bc0de..5a5cd04 100644
--- a/rtc_base/socketfactory.h
+++ b/rtc_base/socketfactory.h
@@ -17,22 +17,17 @@
 namespace rtc {
 
 class SocketFactory {
-public:
+ public:
   virtual ~SocketFactory() {}
 
   // Returns a new socket for blocking communication.  The type can be
   // SOCK_DGRAM and SOCK_STREAM.
-  // TODO: C++ inheritance rules mean that all users must have both
-  // CreateSocket(int) and CreateSocket(int,int). Will remove CreateSocket(int)
-  // (and CreateAsyncSocket(int) when all callers are changed.
-  virtual Socket* CreateSocket(int type) = 0;
   virtual Socket* CreateSocket(int family, int type) = 0;
   // Returns a new socket for nonblocking communication.  The type can be
   // SOCK_DGRAM and SOCK_STREAM.
-  virtual AsyncSocket* CreateAsyncSocket(int type) = 0;
   virtual AsyncSocket* CreateAsyncSocket(int family, int type) = 0;
 };
 
-} // namespace rtc
+}  // namespace rtc
 
-#endif // RTC_BASE_SOCKETFACTORY_H_
+#endif  // RTC_BASE_SOCKETFACTORY_H_
diff --git a/rtc_base/socketstream.cc b/rtc_base/socketstream.cc
index 8b4c513..2ea1cec 100644
--- a/rtc_base/socketstream.cc
+++ b/rtc_base/socketstream.cc
@@ -28,9 +28,9 @@
   socket_ = socket;
   if (socket_) {
     socket_->SignalConnectEvent.connect(this, &SocketStream::OnConnectEvent);
-    socket_->SignalReadEvent.connect(this,    &SocketStream::OnReadEvent);
-    socket_->SignalWriteEvent.connect(this,   &SocketStream::OnWriteEvent);
-    socket_->SignalCloseEvent.connect(this,   &SocketStream::OnCloseEvent);
+    socket_->SignalReadEvent.connect(this, &SocketStream::OnReadEvent);
+    socket_->SignalWriteEvent.connect(this, &SocketStream::OnWriteEvent);
+    socket_->SignalCloseEvent.connect(this, &SocketStream::OnCloseEvent);
   }
 }
 
@@ -59,8 +59,10 @@
   }
 }
 
-StreamResult SocketStream::Read(void* buffer, size_t buffer_len,
-                                size_t* read, int* error) {
+StreamResult SocketStream::Read(void* buffer,
+                                size_t buffer_len,
+                                size_t* read,
+                                int* error) {
   RTC_DCHECK(socket_ != nullptr);
   int result = socket_->Recv(buffer, buffer_len, nullptr);
   if (result < 0) {
@@ -78,8 +80,10 @@
   return SR_EOS;
 }
 
-StreamResult SocketStream::Write(const void* data, size_t data_len,
-                                 size_t* written, int* error) {
+StreamResult SocketStream::Write(const void* data,
+                                 size_t data_len,
+                                 size_t* written,
+                                 int* error) {
   RTC_DCHECK(socket_ != nullptr);
   int result = socket_->Send(data, data_len);
   if (result < 0) {
@@ -119,5 +123,4 @@
   SignalEvent(this, SE_CLOSE, err);
 }
 
-
 }  // namespace rtc
diff --git a/rtc_base/ssladapter.cc b/rtc_base/ssladapter.cc
index 8c62d3b..e091f00 100644
--- a/rtc_base/ssladapter.cc
+++ b/rtc_base/ssladapter.cc
@@ -26,8 +26,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-bool InitializeSSL(VerificationCallback callback) {
-  return OpenSSLAdapter::InitializeSSL(callback);
+bool InitializeSSL() {
+  return OpenSSLAdapter::InitializeSSL();
 }
 
 bool CleanupSSL() {
diff --git a/rtc_base/ssladapter.h b/rtc_base/ssladapter.h
index 6b84154..4843d26 100644
--- a/rtc_base/ssladapter.h
+++ b/rtc_base/ssladapter.h
@@ -11,7 +11,11 @@
 #ifndef RTC_BASE_SSLADAPTER_H_
 #define RTC_BASE_SSLADAPTER_H_
 
+#include <string>
+#include <vector>
+
 #include "rtc_base/asyncsocket.h"
+#include "rtc_base/sslcertificate.h"
 #include "rtc_base/sslstreamadapter.h"
 
 namespace rtc {
@@ -26,8 +30,13 @@
 class SSLAdapterFactory {
  public:
   virtual ~SSLAdapterFactory() {}
+
   // Specifies whether TLS or DTLS is to be used for the SSL adapters.
   virtual void SetMode(SSLMode mode) = 0;
+
+  // Specify a custom certificate verifier for SSL.
+  virtual void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) = 0;
+
   // Creates a new SSL adapter, but from a shared context.
   virtual SSLAdapter* CreateAdapter(AsyncSocket* socket) = 0;
 
@@ -54,6 +63,8 @@
 
   // Do DTLS or TLS (default is TLS, if unspecified)
   virtual void SetMode(SSLMode mode) = 0;
+  // Specify a custom certificate verifier for SSL.
+  virtual void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) = 0;
 
   // Set the certificate this socket will present to incoming clients.
   virtual void SetIdentity(SSLIdentity* identity) = 0;
@@ -82,11 +93,9 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-typedef bool (*VerificationCallback)(void* cert);
-
 // Call this on the main thread, before using SSL.
 // Call CleanupSSL when finished with SSL.
-bool InitializeSSL(VerificationCallback callback = nullptr);
+bool InitializeSSL();
 
 // Call to cleanup additional threads, and also the main thread.
 bool CleanupSSL();
diff --git a/rtc_base/ssladapter_unittest.cc b/rtc_base/ssladapter_unittest.cc
index c15ecfe..ec532b1 100644
--- a/rtc_base/ssladapter_unittest.cc
+++ b/rtc_base/ssladapter_unittest.cc
@@ -10,7 +10,9 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/ipaddress.h"
 #include "rtc_base/socketstream.h"
@@ -20,16 +22,20 @@
 #include "rtc_base/stream.h"
 #include "rtc_base/stringencode.h"
 #include "rtc_base/virtualsocketserver.h"
+#include "test/gmock.h"
+
+using ::testing::_;
+using ::testing::Return;
 
 static const int kTimeout = 5000;
 
 static rtc::AsyncSocket* CreateSocket(const rtc::SSLMode& ssl_mode) {
   rtc::SocketAddress address(rtc::IPAddress(INADDR_ANY), 0);
 
-  rtc::AsyncSocket* socket = rtc::Thread::Current()->
-      socketserver()->CreateAsyncSocket(
-      address.family(), (ssl_mode == rtc::SSL_MODE_DTLS) ?
-      SOCK_DGRAM : SOCK_STREAM);
+  rtc::AsyncSocket* socket =
+      rtc::Thread::Current()->socketserver()->CreateAsyncSocket(
+          address.family(),
+          (ssl_mode == rtc::SSL_MODE_DTLS) ? SOCK_DGRAM : SOCK_STREAM);
   socket->Bind(address);
 
   return socket;
@@ -39,6 +45,15 @@
   return (ssl_mode == rtc::SSL_MODE_DTLS) ? "DTLS" : "TLS";
 }
 
+// Simple mock for the certificate verifier.
+class MockCertVerifier : public rtc::SSLCertificateVerifier {
+ public:
+  virtual ~MockCertVerifier() = default;
+  MOCK_METHOD1(Verify, bool(const rtc::SSLCertificate&));
+};
+
+// TODO(benwright) - Move to using INSTANTIATE_TEST_CASE_P instead of using
+// duplicate test cases for simple parameter changes.
 class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
  public:
   explicit SSLAdapterTestDummyClient(const rtc::SSLMode& ssl_mode)
@@ -54,10 +69,18 @@
     // NEVER USE THIS IN PRODUCTION CODE!
     ssl_adapter_->SetIgnoreBadCert(true);
 
-    ssl_adapter_->SignalReadEvent.connect(this,
-        &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent);
-    ssl_adapter_->SignalCloseEvent.connect(this,
-        &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent);
+    ssl_adapter_->SignalReadEvent.connect(
+        this, &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent);
+    ssl_adapter_->SignalCloseEvent.connect(
+        this, &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent);
+  }
+
+  void SetIgnoreBadCert(bool ignore_bad_cert) {
+    ssl_adapter_->SetIgnoreBadCert(ignore_bad_cert);
+  }
+
+  void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) {
+    ssl_adapter_->SetCertVerifier(ssl_cert_verifier);
   }
 
   void SetAlpnProtocols(const std::vector<std::string>& protos) {
@@ -76,9 +99,7 @@
     return ssl_adapter_->GetState();
   }
 
-  const std::string& GetReceivedData() const {
-    return data_;
-  }
+  const std::string& GetReceivedData() const { return data_; }
 
   int Connect(const std::string& hostname, const rtc::SocketAddress& address) {
     RTC_LOG(LS_INFO) << "Initiating connection with " << address.ToString();
@@ -97,9 +118,7 @@
     return rv;
   }
 
-  int Close() {
-    return ssl_adapter_->Close();
-  }
+  int Close() { return ssl_adapter_->Close(); }
 
   int Send(const std::string& message) {
     RTC_LOG(LS_INFO) << "Client sending '" << message << "'";
@@ -149,8 +168,8 @@
     server_socket_.reset(CreateSocket(ssl_mode_));
 
     if (ssl_mode_ == rtc::SSL_MODE_TLS) {
-      server_socket_->SignalReadEvent.connect(this,
-          &SSLAdapterTestDummyServer::OnServerSocketReadEvent);
+      server_socket_->SignalReadEvent.connect(
+          this, &SSLAdapterTestDummyServer::OnServerSocketReadEvent);
 
       server_socket_->Listen(1);
     }
@@ -170,9 +189,7 @@
     return "example.com";
   }
 
-  const std::string& GetReceivedData() const {
-    return data_;
-  }
+  const std::string& GetReceivedData() const { return data_; }
 
   int Send(const std::string& message) {
     if (ssl_stream_adapter_ == nullptr ||
@@ -186,8 +203,8 @@
     size_t written;
     int error;
 
-    rtc::StreamResult r = ssl_stream_adapter_->Write(message.data(),
-        message.length(), &written, &error);
+    rtc::StreamResult r = ssl_stream_adapter_->Write(
+        message.data(), message.length(), &written, &error);
     if (r == rtc::SR_SUCCESS) {
       return written;
     } else {
@@ -257,12 +274,12 @@
     unsigned char digest[20];
     size_t digest_len = sizeof(digest);
     ssl_stream_adapter_->SetPeerCertificateDigest(rtc::DIGEST_SHA_1, digest,
-        digest_len);
+                                                  digest_len);
 
     ssl_stream_adapter_->StartSSL();
 
-    ssl_stream_adapter_->SignalEvent.connect(this,
-        &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent);
+    ssl_stream_adapter_->SignalEvent.connect(
+        this, &SSLAdapterTestDummyServer::OnSSLStreamAdapterEvent);
   }
 
   const rtc::SSLMode ssl_mode_;
@@ -275,8 +292,7 @@
   std::string data_;
 };
 
-class SSLAdapterTestBase : public testing::Test,
-                           public sigslot::has_slots<> {
+class SSLAdapterTestBase : public testing::Test, public sigslot::has_slots<> {
  public:
   explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode,
                               const rtc::KeyParams& key_params)
@@ -287,8 +303,14 @@
         client_(new SSLAdapterTestDummyClient(ssl_mode_)),
         handshake_wait_(kTimeout) {}
 
-  void SetHandshakeWait(int wait) {
-    handshake_wait_ = wait;
+  void SetHandshakeWait(int wait) { handshake_wait_ = wait; }
+
+  void SetIgnoreBadCert(bool ignore_bad_cert) {
+    client_->SetIgnoreBadCert(ignore_bad_cert);
+  }
+
+  void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) {
+    client_->SetCertVerifier(ssl_cert_verifier);
   }
 
   void SetAlpnProtocols(const std::vector<std::string>& protos) {
@@ -299,6 +321,16 @@
     client_->SetEllipticCurves(curves);
   }
 
+  void SetMockCertVerifier(bool return_value) {
+    auto mock_verifier = absl::make_unique<MockCertVerifier>();
+    EXPECT_CALL(*mock_verifier, Verify(_)).WillRepeatedly(Return(return_value));
+    cert_verifier_ =
+        std::unique_ptr<rtc::SSLCertificateVerifier>(std::move(mock_verifier));
+
+    SetIgnoreBadCert(false);
+    SetCertVerifier(cert_verifier_.get());
+  }
+
   void TestHandshake(bool expect_success) {
     int rv;
 
@@ -320,7 +352,7 @@
       // If expecting success, the client should end up in the CS_CONNECTED
       // state after handshake.
       EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CONNECTED, client_->GetState(),
-          handshake_wait_);
+                     handshake_wait_);
 
       RTC_LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_)
                        << " handshake complete.";
@@ -328,7 +360,7 @@
     } else {
       // On handshake failure the client should end up in the CS_CLOSED state.
       EXPECT_EQ_WAIT(rtc::AsyncSocket::CS_CLOSED, client_->GetState(),
-          handshake_wait_);
+                     handshake_wait_);
 
       RTC_LOG(LS_INFO) << GetSSLProtocolName(ssl_mode_) << " handshake failed.";
     }
@@ -359,6 +391,7 @@
   rtc::AutoSocketServerThread thread_;
   std::unique_ptr<SSLAdapterTestDummyServer> server_;
   std::unique_ptr<SSLAdapterTestDummyClient> client_;
+  std::unique_ptr<rtc::SSLCertificateVerifier> cert_verifier_;
 
   int handshake_wait_;
 };
@@ -394,9 +427,34 @@
   TestHandshake(true);
 }
 
+// Test that handshake works with a custom verifier that returns true. RSA.
+TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnectCustomCertVerifierSucceeds) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+}
+
+// Test that handshake fails with a custom verifier that returns false. RSA.
+TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnectCustomCertVerifierFails) {
+  SetMockCertVerifier(/*return_value=*/false);
+  TestHandshake(/*expect_success=*/false);
+}
+
 // Test that handshake works, using ECDSA
 TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnect) {
-  TestHandshake(true);
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+}
+
+// Test that handshake works with a custom verifier that returns true. ECDSA.
+TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnectCustomCertVerifierSucceeds) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+}
+
+// Test that handshake fails with a custom verifier that returns false. ECDSA.
+TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnectCustomCertVerifierFails) {
+  SetMockCertVerifier(/*return_value=*/false);
+  TestHandshake(/*expect_success=*/false);
 }
 
 // Test transfer between client and server, using RSA
@@ -405,6 +463,13 @@
   TestTransfer("Hello, world!");
 }
 
+// Test transfer between client and server, using RSA with custom cert verifier.
+TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransferCustomCertVerifier) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+  TestTransfer("Hello, world!");
+}
+
 TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransferWithBlockedSocket) {
   TestHandshake(true);
 
@@ -452,6 +517,14 @@
   TestTransfer("Hello, world!");
 }
 
+// Test transfer between client and server, using ECDSA with custom cert
+// verifier.
+TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransferCustomCertVerifier) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+  TestTransfer("Hello, world!");
+}
+
 // Test transfer using ALPN with protos as h2 and http/1.1
 TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSALPN) {
   std::vector<std::string> alpn_protos{"h2", "http/1.1"};
@@ -475,19 +548,61 @@
   TestHandshake(true);
 }
 
+// Test that handshake works with a custom verifier that returns true. DTLS_RSA.
+TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnectCustomCertVerifierSucceeds) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+}
+
+// Test that handshake fails with a custom verifier that returns false.
+// DTLS_RSA.
+TEST_F(SSLAdapterTestDTLS_RSA, TestTLSConnectCustomCertVerifierFails) {
+  SetMockCertVerifier(/*return_value=*/false);
+  TestHandshake(/*expect_success=*/false);
+}
+
 // Test that handshake works, using ECDSA
 TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnect) {
   TestHandshake(true);
 }
 
+// Test that handshake works with a custom verifier that returns true.
+// DTLS_ECDSA.
+TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnectCustomCertVerifierSucceeds) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+}
+
+// Test that handshake fails with a custom verifier that returns false.
+// DTLS_ECDSA.
+TEST_F(SSLAdapterTestDTLS_ECDSA, TestTLSConnectCustomCertVerifierFails) {
+  SetMockCertVerifier(/*return_value=*/false);
+  TestHandshake(/*expect_success=*/false);
+}
+
 // Test transfer between client and server, using RSA
 TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransfer) {
   TestHandshake(true);
   TestTransfer("Hello, world!");
 }
 
+// Test transfer between client and server, using RSA with custom cert verifier.
+TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransferCustomCertVerifier) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+  TestTransfer("Hello, world!");
+}
+
 // Test transfer between client and server, using ECDSA
 TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransfer) {
   TestHandshake(true);
   TestTransfer("Hello, world!");
 }
+
+// Test transfer between client and server, using ECDSA with custom cert
+// verifier.
+TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransferCustomCertVerifier) {
+  SetMockCertVerifier(/*return_value=*/true);
+  TestHandshake(/*expect_success=*/true);
+  TestTransfer("Hello, world!");
+}
diff --git a/rtc_base/sslcertificate.cc b/rtc_base/sslcertificate.cc
new file mode 100644
index 0000000..d99da60
--- /dev/null
+++ b/rtc_base/sslcertificate.cc
@@ -0,0 +1,142 @@
+/*
+ *  Copyright 2004 The WebRTC 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.
+ */
+
+#include "rtc_base/sslcertificate.h"
+
+#include <ctime>
+#include <string>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "rtc_base/base64.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/opensslcertificate.h"
+#include "rtc_base/sslfingerprint.h"
+
+namespace rtc {
+
+//////////////////////////////////////////////////////////////////////
+// SSLCertificateStats
+//////////////////////////////////////////////////////////////////////
+
+SSLCertificateStats::SSLCertificateStats(
+    std::string&& fingerprint,
+    std::string&& fingerprint_algorithm,
+    std::string&& base64_certificate,
+    std::unique_ptr<SSLCertificateStats>&& issuer)
+    : fingerprint(std::move(fingerprint)),
+      fingerprint_algorithm(std::move(fingerprint_algorithm)),
+      base64_certificate(std::move(base64_certificate)),
+      issuer(std::move(issuer)) {}
+
+SSLCertificateStats::~SSLCertificateStats() {}
+
+//////////////////////////////////////////////////////////////////////
+// SSLCertificate
+//////////////////////////////////////////////////////////////////////
+
+std::unique_ptr<SSLCertificateStats> SSLCertificate::GetStats() const {
+  // TODO(bemasc): Move this computation to a helper class that caches these
+  // values to reduce CPU use in |StatsCollector::GetStats|. This will require
+  // adding a fast |SSLCertificate::Equals| to detect certificate changes.
+  std::string digest_algorithm;
+  if (!GetSignatureDigestAlgorithm(&digest_algorithm))
+    return nullptr;
+
+  // |SSLFingerprint::Create| can fail if the algorithm returned by
+  // |SSLCertificate::GetSignatureDigestAlgorithm| is not supported by the
+  // implementation of |SSLCertificate::ComputeDigest|. This currently happens
+  // with MD5- and SHA-224-signed certificates when linked to libNSS.
+  std::unique_ptr<SSLFingerprint> ssl_fingerprint(
+      SSLFingerprint::Create(digest_algorithm, this));
+  if (!ssl_fingerprint)
+    return nullptr;
+  std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
+
+  Buffer der_buffer;
+  ToDER(&der_buffer);
+  std::string der_base64;
+  Base64::EncodeFromArray(der_buffer.data(), der_buffer.size(), &der_base64);
+
+  return absl::make_unique<SSLCertificateStats>(std::move(fingerprint),
+                                                std::move(digest_algorithm),
+                                                std::move(der_base64), nullptr);
+}
+
+std::unique_ptr<SSLCertificate> SSLCertificate::GetUniqueReference() const {
+  return absl::WrapUnique(GetReference());
+}
+
+//////////////////////////////////////////////////////////////////////
+// SSLCertChain
+//////////////////////////////////////////////////////////////////////
+
+SSLCertChain::SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs)
+    : certs_(std::move(certs)) {}
+
+SSLCertChain::SSLCertChain(const std::vector<SSLCertificate*>& certs) {
+  RTC_DCHECK(!certs.empty());
+  certs_.resize(certs.size());
+  std::transform(
+      certs.begin(), certs.end(), certs_.begin(),
+      [](const SSLCertificate* cert) -> std::unique_ptr<SSLCertificate> {
+        return cert->GetUniqueReference();
+      });
+}
+
+SSLCertChain::SSLCertChain(const SSLCertificate* cert) {
+  certs_.push_back(cert->GetUniqueReference());
+}
+
+SSLCertChain::SSLCertChain(SSLCertChain&& rhs) = default;
+
+SSLCertChain& SSLCertChain::operator=(SSLCertChain&&) = default;
+
+SSLCertChain::~SSLCertChain() {}
+
+SSLCertChain* SSLCertChain::Copy() const {
+  std::vector<std::unique_ptr<SSLCertificate>> new_certs(certs_.size());
+  std::transform(certs_.begin(), certs_.end(), new_certs.begin(),
+                 [](const std::unique_ptr<SSLCertificate>& cert)
+                     -> std::unique_ptr<SSLCertificate> {
+                   return cert->GetUniqueReference();
+                 });
+  return new SSLCertChain(std::move(new_certs));
+}
+
+std::unique_ptr<SSLCertChain> SSLCertChain::UniqueCopy() const {
+  return absl::WrapUnique(Copy());
+}
+
+std::unique_ptr<SSLCertificateStats> SSLCertChain::GetStats() const {
+  // We have a linked list of certificates, starting with the first element of
+  // |certs_| and ending with the last element of |certs_|. The "issuer" of a
+  // certificate is the next certificate in the chain. Stats are produced for
+  // each certificate in the list. Here, the "issuer" is the issuer's stats.
+  std::unique_ptr<SSLCertificateStats> issuer;
+  // The loop runs in reverse so that the |issuer| is known before the
+  // certificate issued by |issuer|.
+  for (ptrdiff_t i = certs_.size() - 1; i >= 0; --i) {
+    std::unique_ptr<SSLCertificateStats> new_stats = certs_[i]->GetStats();
+    if (new_stats) {
+      new_stats->issuer = std::move(issuer);
+    }
+    issuer = std::move(new_stats);
+  }
+  return issuer;
+}
+
+// static
+SSLCertificate* SSLCertificate::FromPEMString(const std::string& pem_string) {
+  return OpenSSLCertificate::FromPEMString(pem_string);
+}
+
+}  // namespace rtc
diff --git a/rtc_base/sslcertificate.h b/rtc_base/sslcertificate.h
new file mode 100644
index 0000000..29c4db5
--- /dev/null
+++ b/rtc_base/sslcertificate.h
@@ -0,0 +1,147 @@
+/*
+ *  Copyright 2018 The WebRTC 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.
+ */
+
+// Generic interface for SSL Certificates, used in both the SSLAdapter
+// for TLS TURN connections and the SSLStreamAdapter for DTLS Peer to Peer
+// Connections for SRTP Key negotiation and SCTP encryption.
+
+#ifndef RTC_BASE_SSLCERTIFICATE_H_
+#define RTC_BASE_SSLCERTIFICATE_H_
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "rtc_base/buffer.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/messagedigest.h"
+#include "rtc_base/timeutils.h"
+
+namespace rtc {
+
+struct SSLCertificateStats {
+  SSLCertificateStats(std::string&& fingerprint,
+                      std::string&& fingerprint_algorithm,
+                      std::string&& base64_certificate,
+                      std::unique_ptr<SSLCertificateStats>&& issuer);
+  ~SSLCertificateStats();
+  std::string fingerprint;
+  std::string fingerprint_algorithm;
+  std::string base64_certificate;
+  std::unique_ptr<SSLCertificateStats> issuer;
+};
+
+// Abstract interface overridden by SSL library specific
+// implementations.
+
+// A somewhat opaque type used to encapsulate a certificate.
+// Wraps the SSL library's notion of a certificate, with reference counting.
+// The SSLCertificate object is pretty much immutable once created.
+// (The OpenSSL implementation only does reference counting and
+// possibly caching of intermediate results.)
+class SSLCertificate {
+ public:
+  // Parses and builds a certificate from a PEM encoded string.
+  // Returns null on failure.
+  // The length of the string representation of the certificate is
+  // stored in *pem_length if it is non-null, and only if
+  // parsing was successful.
+  // Caller is responsible for freeing the returned object.
+  static SSLCertificate* FromPEMString(const std::string& pem_string);
+  virtual ~SSLCertificate() {}
+
+  // Returns a new SSLCertificate object instance wrapping the same
+  // underlying certificate, including its chain if present.  Caller is
+  // responsible for freeing the returned object. Use GetUniqueReference
+  // instead.
+  virtual SSLCertificate* GetReference() const = 0;
+
+  std::unique_ptr<SSLCertificate> GetUniqueReference() const;
+
+  // Returns a PEM encoded string representation of the certificate.
+  virtual std::string ToPEMString() const = 0;
+
+  // Provides a DER encoded binary representation of the certificate.
+  virtual void ToDER(Buffer* der_buffer) const = 0;
+
+  // Gets the name of the digest algorithm that was used to compute this
+  // certificate's signature.
+  virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const = 0;
+
+  // Compute the digest of the certificate given algorithm
+  virtual bool ComputeDigest(const std::string& algorithm,
+                             unsigned char* digest,
+                             size_t size,
+                             size_t* length) const = 0;
+
+  // Returns the time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC),
+  // or -1 if an expiration time could not be retrieved.
+  virtual int64_t CertificateExpirationTime() const = 0;
+
+  // Gets information (fingerprint, etc.) about this certificate. This is used
+  // for certificate stats, see
+  // https://w3c.github.io/webrtc-stats/#certificatestats-dict*.
+  std::unique_ptr<SSLCertificateStats> GetStats() const;
+};
+
+// SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves
+// primarily to ensure proper memory management (especially deletion) of the
+// SSLCertificate pointers.
+class SSLCertChain {
+ public:
+  explicit SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs);
+  // These constructors copy the provided SSLCertificate(s), so the caller
+  // retains ownership.
+  explicit SSLCertChain(const std::vector<SSLCertificate*>& certs);
+  explicit SSLCertChain(const SSLCertificate* cert);
+  // Allow move semantics for the object.
+  SSLCertChain(SSLCertChain&&);
+  SSLCertChain& operator=(SSLCertChain&&);
+
+  ~SSLCertChain();
+
+  // Vector access methods.
+  size_t GetSize() const { return certs_.size(); }
+
+  // Returns a temporary reference, only valid until the chain is destroyed.
+  const SSLCertificate& Get(size_t pos) const { return *(certs_[pos]); }
+
+  // Returns a new SSLCertChain object instance wrapping the same underlying
+  // certificate chain.  Caller is responsible for freeing the returned object.
+  SSLCertChain* Copy() const;
+  // Same as above, but returning a unique_ptr for convenience.
+  std::unique_ptr<SSLCertChain> UniqueCopy() const;
+
+  // Gets information (fingerprint, etc.) about this certificate chain. This is
+  // used for certificate stats, see
+  // https://w3c.github.io/webrtc-stats/#certificatestats-dict*.
+  std::unique_ptr<SSLCertificateStats> GetStats() const;
+
+ private:
+  std::vector<std::unique_ptr<SSLCertificate>> certs_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(SSLCertChain);
+};
+
+// SSLCertificateVerifier provides a simple interface to allow third parties to
+// define their own certificate verification code. It is completely independent
+// from the underlying SSL implementation.
+class SSLCertificateVerifier {
+ public:
+  virtual ~SSLCertificateVerifier() = default;
+  // Returns true if the certificate is valid, else false. It is up to the
+  // implementer to define what a valid certificate looks like.
+  virtual bool Verify(const SSLCertificate& certificate) = 0;
+};
+
+}  // namespace rtc
+
+#endif  // RTC_BASE_SSLCERTIFICATE_H_
diff --git a/rtc_base/sslfingerprint.cc b/rtc_base/sslfingerprint.cc
index dda46f1..b651a3d 100644
--- a/rtc_base/sslfingerprint.cc
+++ b/rtc_base/sslfingerprint.cc
@@ -20,8 +20,8 @@
 
 namespace rtc {
 
-SSLFingerprint* SSLFingerprint::Create(
-    const std::string& algorithm, const rtc::SSLIdentity* identity) {
+SSLFingerprint* SSLFingerprint::Create(const std::string& algorithm,
+                                       const rtc::SSLIdentity* identity) {
   if (!identity) {
     return nullptr;
   }
@@ -29,12 +29,12 @@
   return Create(algorithm, &(identity->certificate()));
 }
 
-SSLFingerprint* SSLFingerprint::Create(
-    const std::string& algorithm, const rtc::SSLCertificate* cert) {
+SSLFingerprint* SSLFingerprint::Create(const std::string& algorithm,
+                                       const rtc::SSLCertificate* cert) {
   uint8_t digest_val[64];
   size_t digest_len;
-  bool ret = cert->ComputeDigest(
-      algorithm, digest_val, sizeof(digest_val), &digest_len);
+  bool ret = cert->ComputeDigest(algorithm, digest_val, sizeof(digest_val),
+                                 &digest_len);
   if (!ret) {
     return nullptr;
   }
@@ -43,7 +43,8 @@
 }
 
 SSLFingerprint* SSLFingerprint::CreateFromRfc4572(
-    const std::string& algorithm, const std::string& fingerprint) {
+    const std::string& algorithm,
+    const std::string& fingerprint) {
   if (algorithm.empty() || !rtc::IsFips180DigestAlgorithm(algorithm))
     return nullptr;
 
@@ -52,10 +53,8 @@
 
   size_t value_len;
   char value[rtc::MessageDigest::kMaxSize];
-  value_len = rtc::hex_decode_with_delimiter(value, sizeof(value),
-                                                   fingerprint.c_str(),
-                                                   fingerprint.length(),
-                                                   ':');
+  value_len = rtc::hex_decode_with_delimiter(
+      value, sizeof(value), fingerprint.c_str(), fingerprint.length(), ':');
   if (!value_len)
     return nullptr;
 
@@ -91,15 +90,14 @@
     : algorithm(from.algorithm), digest(from.digest) {}
 
 bool SSLFingerprint::operator==(const SSLFingerprint& other) const {
-  return algorithm == other.algorithm &&
-         digest == other.digest;
+  return algorithm == other.algorithm && digest == other.digest;
 }
 
 std::string SSLFingerprint::GetRfc4572Fingerprint() const {
   std::string fingerprint =
       rtc::hex_encode_with_delimiter(digest.data<char>(), digest.size(), ':');
-  std::transform(fingerprint.begin(), fingerprint.end(),
-                 fingerprint.begin(), ::toupper);
+  std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(),
+                 ::toupper);
   return fingerprint;
 }
 
diff --git a/rtc_base/sslfingerprint.h b/rtc_base/sslfingerprint.h
index b5e9b72..b204bc7 100644
--- a/rtc_base/sslfingerprint.h
+++ b/rtc_base/sslfingerprint.h
@@ -13,7 +13,6 @@
 
 #include <string>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/copyonwritebuffer.h"
 #include "rtc_base/rtccertificate.h"
 #include "rtc_base/sslidentity.h"
diff --git a/rtc_base/sslidentity.cc b/rtc_base/sslidentity.cc
index 1514e52..94944f9 100644
--- a/rtc_base/sslidentity.cc
+++ b/rtc_base/sslidentity.cc
@@ -15,65 +15,23 @@
 #include <string>
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/base64.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/opensslidentity.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/sslfingerprint.h"
 
 namespace rtc {
 
+//////////////////////////////////////////////////////////////////////
+// KeyParams
+//////////////////////////////////////////////////////////////////////
+
 const char kPemTypeCertificate[] = "CERTIFICATE";
 const char kPemTypeRsaPrivateKey[] = "RSA PRIVATE KEY";
 const char kPemTypeEcPrivateKey[] = "EC PRIVATE KEY";
 
-SSLCertificateStats::SSLCertificateStats(
-    std::string&& fingerprint,
-    std::string&& fingerprint_algorithm,
-    std::string&& base64_certificate,
-    std::unique_ptr<SSLCertificateStats>&& issuer)
-    : fingerprint(std::move(fingerprint)),
-      fingerprint_algorithm(std::move(fingerprint_algorithm)),
-      base64_certificate(std::move(base64_certificate)),
-      issuer(std::move(issuer)) {
-}
-
-SSLCertificateStats::~SSLCertificateStats() {
-}
-
-std::unique_ptr<SSLCertificateStats> SSLCertificate::GetStats() const {
-  // TODO(bemasc): Move this computation to a helper class that caches these
-  // values to reduce CPU use in |StatsCollector::GetStats|. This will require
-  // adding a fast |SSLCertificate::Equals| to detect certificate changes.
-  std::string digest_algorithm;
-  if (!GetSignatureDigestAlgorithm(&digest_algorithm))
-    return nullptr;
-
-  // |SSLFingerprint::Create| can fail if the algorithm returned by
-  // |SSLCertificate::GetSignatureDigestAlgorithm| is not supported by the
-  // implementation of |SSLCertificate::ComputeDigest|. This currently happens
-  // with MD5- and SHA-224-signed certificates when linked to libNSS.
-  std::unique_ptr<SSLFingerprint> ssl_fingerprint(
-      SSLFingerprint::Create(digest_algorithm, this));
-  if (!ssl_fingerprint)
-    return nullptr;
-  std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
-
-  Buffer der_buffer;
-  ToDER(&der_buffer);
-  std::string der_base64;
-  Base64::EncodeFromArray(der_buffer.data(), der_buffer.size(), &der_base64);
-
-  return rtc::MakeUnique<SSLCertificateStats>(std::move(fingerprint),
-                                              std::move(digest_algorithm),
-                                              std::move(der_base64), nullptr);
-}
-
-std::unique_ptr<SSLCertificate> SSLCertificate::GetUniqueReference() const {
-  return WrapUnique(GetReference());
-}
-
 KeyParams::KeyParams(KeyType key_type) {
   if (key_type == KT_ECDSA) {
     type_ = KT_ECDSA;
@@ -127,6 +85,10 @@
   return static_cast<KeyType>(key_type_family);
 }
 
+//////////////////////////////////////////////////////////////////////
+// SSLIdentity
+//////////////////////////////////////////////////////////////////////
+
 bool SSLIdentity::PemToDer(const std::string& pem_type,
                            const std::string& pem_string,
                            std::string* der) {
@@ -146,9 +108,8 @@
 
   std::string inner = pem_string.substr(body + 1, trailer - (body + 1));
 
-  *der = Base64::Decode(inner, Base64::DO_PARSE_WHITE |
-                        Base64::DO_PAD_ANY |
-                        Base64::DO_TERM_BUFFER);
+  *der = Base64::Decode(inner, Base64::DO_PARSE_WHITE | Base64::DO_PAD_ANY |
+                                   Base64::DO_TERM_BUFFER);
   return true;
 }
 
@@ -177,62 +138,6 @@
   return result.str();
 }
 
-SSLCertChain::SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs)
-    : certs_(std::move(certs)) {}
-
-SSLCertChain::SSLCertChain(const std::vector<SSLCertificate*>& certs) {
-  RTC_DCHECK(!certs.empty());
-  certs_.resize(certs.size());
-  std::transform(
-      certs.begin(), certs.end(), certs_.begin(),
-      [](const SSLCertificate* cert) -> std::unique_ptr<SSLCertificate> {
-        return cert->GetUniqueReference();
-      });
-}
-
-SSLCertChain::SSLCertChain(const SSLCertificate* cert) {
-  certs_.push_back(cert->GetUniqueReference());
-}
-
-SSLCertChain::~SSLCertChain() {}
-
-SSLCertChain* SSLCertChain::Copy() const {
-  std::vector<std::unique_ptr<SSLCertificate>> new_certs(certs_.size());
-  std::transform(certs_.begin(), certs_.end(), new_certs.begin(),
-                 [](const std::unique_ptr<SSLCertificate>& cert)
-                     -> std::unique_ptr<SSLCertificate> {
-                   return cert->GetUniqueReference();
-                 });
-  return new SSLCertChain(std::move(new_certs));
-}
-
-std::unique_ptr<SSLCertChain> SSLCertChain::UniqueCopy() const {
-  return WrapUnique(Copy());
-}
-
-std::unique_ptr<SSLCertificateStats> SSLCertChain::GetStats() const {
-  // We have a linked list of certificates, starting with the first element of
-  // |certs_| and ending with the last element of |certs_|. The "issuer" of a
-  // certificate is the next certificate in the chain. Stats are produced for
-  // each certificate in the list. Here, the "issuer" is the issuer's stats.
-  std::unique_ptr<SSLCertificateStats> issuer;
-  // The loop runs in reverse so that the |issuer| is known before the
-  // certificate issued by |issuer|.
-  for (ptrdiff_t i = certs_.size() - 1; i >= 0; --i) {
-    std::unique_ptr<SSLCertificateStats> new_stats = certs_[i]->GetStats();
-    if (new_stats) {
-      new_stats->issuer = std::move(issuer);
-    }
-    issuer = std::move(new_stats);
-  }
-  return issuer;
-}
-
-// static
-SSLCertificate* SSLCertificate::FromPEMString(const std::string& pem_string) {
-  return OpenSSLCertificate::FromPEMString(pem_string);
-}
-
 // static
 SSLIdentity* SSLIdentity::GenerateWithExpiration(const std::string& common_name,
                                                  const KeyParams& key_params,
@@ -280,6 +185,10 @@
   return !(a == b);
 }
 
+//////////////////////////////////////////////////////////////////////
+// Helper Functions
+//////////////////////////////////////////////////////////////////////
+
 // Read |n| bytes from ASN1 number string at *|pp| and return the numeric value.
 // Update *|pp| and *|np| to reflect number of read bytes.
 static inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) {
diff --git a/rtc_base/sslidentity.h b/rtc_base/sslidentity.h
index d14610b..1379d73 100644
--- a/rtc_base/sslidentity.h
+++ b/rtc_base/sslidentity.h
@@ -21,113 +21,11 @@
 #include "rtc_base/buffer.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/messagedigest.h"
+#include "rtc_base/sslcertificate.h"
 #include "rtc_base/timeutils.h"
 
 namespace rtc {
 
-// Forward declaration due to circular dependency with SSLCertificate.
-class SSLCertChain;
-
-struct SSLCertificateStats {
-  SSLCertificateStats(std::string&& fingerprint,
-                      std::string&& fingerprint_algorithm,
-                      std::string&& base64_certificate,
-                      std::unique_ptr<SSLCertificateStats>&& issuer);
-  ~SSLCertificateStats();
-  std::string fingerprint;
-  std::string fingerprint_algorithm;
-  std::string base64_certificate;
-  std::unique_ptr<SSLCertificateStats> issuer;
-};
-
-// Abstract interface overridden by SSL library specific
-// implementations.
-
-// A somewhat opaque type used to encapsulate a certificate.
-// Wraps the SSL library's notion of a certificate, with reference counting.
-// The SSLCertificate object is pretty much immutable once created.
-// (The OpenSSL implementation only does reference counting and
-// possibly caching of intermediate results.)
-class SSLCertificate {
- public:
-  // Parses and builds a certificate from a PEM encoded string.
-  // Returns null on failure.
-  // The length of the string representation of the certificate is
-  // stored in *pem_length if it is non-null, and only if
-  // parsing was successful.
-  // Caller is responsible for freeing the returned object.
-  static SSLCertificate* FromPEMString(const std::string& pem_string);
-  virtual ~SSLCertificate() {}
-
-  // Returns a new SSLCertificate object instance wrapping the same
-  // underlying certificate, including its chain if present.  Caller is
-  // responsible for freeing the returned object. Use GetUniqueReference
-  // instead.
-  virtual SSLCertificate* GetReference() const = 0;
-
-  std::unique_ptr<SSLCertificate> GetUniqueReference() const;
-
-  // Returns a PEM encoded string representation of the certificate.
-  virtual std::string ToPEMString() const = 0;
-
-  // Provides a DER encoded binary representation of the certificate.
-  virtual void ToDER(Buffer* der_buffer) const = 0;
-
-  // Gets the name of the digest algorithm that was used to compute this
-  // certificate's signature.
-  virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const = 0;
-
-  // Compute the digest of the certificate given algorithm
-  virtual bool ComputeDigest(const std::string& algorithm,
-                             unsigned char* digest,
-                             size_t size,
-                             size_t* length) const = 0;
-
-  // Returns the time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC),
-  // or -1 if an expiration time could not be retrieved.
-  virtual int64_t CertificateExpirationTime() const = 0;
-
-  // Gets information (fingerprint, etc.) about this certificate. This is used
-  // for certificate stats, see
-  // https://w3c.github.io/webrtc-stats/#certificatestats-dict*.
-  std::unique_ptr<SSLCertificateStats> GetStats() const;
-};
-
-// SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves
-// primarily to ensure proper memory management (especially deletion) of the
-// SSLCertificate pointers.
-class SSLCertChain {
- public:
-  explicit SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs);
-  // These constructors copy the provided SSLCertificate(s), so the caller
-  // retains ownership.
-  explicit SSLCertChain(const std::vector<SSLCertificate*>& certs);
-  explicit SSLCertChain(const SSLCertificate* cert);
-  ~SSLCertChain();
-
-  // Vector access methods.
-  size_t GetSize() const { return certs_.size(); }
-
-  // Returns a temporary reference, only valid until the chain is destroyed.
-  const SSLCertificate& Get(size_t pos) const { return *(certs_[pos]); }
-
-  // Returns a new SSLCertChain object instance wrapping the same underlying
-  // certificate chain.  Caller is responsible for freeing the returned object.
-  SSLCertChain* Copy() const;
-  // Same as above, but returning a unique_ptr for convenience.
-  std::unique_ptr<SSLCertChain> UniqueCopy() const;
-
-  // Gets information (fingerprint, etc.) about this certificate chain. This is
-  // used for certificate stats, see
-  // https://w3c.github.io/webrtc-stats/#certificatestats-dict*.
-  std::unique_ptr<SSLCertificateStats> GetStats() const;
-
- private:
-  std::vector<std::unique_ptr<SSLCertificate>> certs_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(SSLCertChain);
-};
-
 // KT_LAST is intended for vector declarations and loops over all key types;
 // it does not represent any key type in itself.
 // KT_DEFAULT is used as the default KeyType for KeyParams.
diff --git a/rtc_base/sslidentity_unittest.cc b/rtc_base/sslidentity_unittest.cc
index e1dbe05..132e240 100644
--- a/rtc_base/sslidentity_unittest.cc
+++ b/rtc_base/sslidentity_unittest.cc
@@ -21,7 +21,8 @@
 
 using rtc::SSLIdentity;
 
-const char kTestCertificate[] = "-----BEGIN CERTIFICATE-----\n"
+const char kTestCertificate[] =
+    "-----BEGIN CERTIFICATE-----\n"
     "MIIB6TCCAVICAQYwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"
     "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"
     "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDAxMDE2MjIzMTAzWhcNMDMwMTE0\n"
@@ -35,36 +36,29 @@
     "itAE+OjGF+PFKbwX8Q==\n"
     "-----END CERTIFICATE-----\n";
 
-const unsigned char kTestCertSha1[] = {
-    0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D, 0x33,
-    0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6, 0xF6, 0x8A,
-    0x9E, 0x47, 0xA7, 0xCA};
+const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D,
+                                       0x33, 0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6,
+                                       0xF6, 0x8A, 0x9E, 0x47, 0xA7, 0xCA};
 const unsigned char kTestCertSha224[] = {
-    0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77,
-    0x38, 0x36, 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd,
-    0xae, 0x24, 0x21, 0x08, 0xcf, 0x6a, 0x44, 0x0d,
-    0x3f, 0x94, 0x2a, 0x5b};
+    0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77, 0x38, 0x36,
+    0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd, 0xae, 0x24, 0x21, 0x08,
+    0xcf, 0x6a, 0x44, 0x0d, 0x3f, 0x94, 0x2a, 0x5b};
 const unsigned char kTestCertSha256[] = {
-    0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24,
-    0x77, 0x0b, 0x8b, 0x2e, 0xa6, 0x2b, 0xe0, 0xf9,
-    0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7, 0x5c, 0xa1,
-    0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
+    0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24, 0x77, 0x0b, 0x8b,
+    0x2e, 0xa6, 0x2b, 0xe0, 0xf9, 0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7,
+    0x5c, 0xa1, 0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
 const unsigned char kTestCertSha384[] = {
-    0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf,
-    0x3b, 0xba, 0x36, 0xd8, 0x37, 0x4a, 0x9a, 0x75,
-    0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
-    0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc,
-    0x64, 0x47, 0xd6, 0xd8, 0xaa, 0xd9, 0x36, 0x60,
-    0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
+    0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf, 0x3b, 0xba, 0x36, 0xd8,
+    0x37, 0x4a, 0x9a, 0x75, 0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
+    0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc, 0x64, 0x47, 0xd6, 0xd8,
+    0xaa, 0xd9, 0x36, 0x60, 0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
 const unsigned char kTestCertSha512[] = {
-    0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3,
-    0xd8, 0x1d, 0xa4, 0x9d, 0x43, 0xc9, 0xee, 0x32,
-    0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f, 0x25, 0xdf,
-    0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b,
-    0x28, 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf,
-    0x61, 0x33, 0x0e, 0x14, 0xc3, 0x04, 0xaa, 0x07,
-    0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22, 0x35,
-    0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
+    0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3, 0xd8, 0x1d, 0xa4,
+    0x9d, 0x43, 0xc9, 0xee, 0x32, 0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f,
+    0x25, 0xdf, 0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b, 0x28,
+    0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf, 0x61, 0x33, 0x0e, 0x14,
+    0xc3, 0x04, 0xaa, 0x07, 0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22,
+    0x35, 0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
 
 // These PEM strings were created by generating an identity with
 // |SSLIdentity::Generate| and invoking |identity->PrivateKeyToPEMString()|,
@@ -112,8 +106,7 @@
 static const char kRSA_FINGERPRINT[] =
     "3C:E8:B2:70:09:CF:A9:09:5A:F4:EF:8F:8D:8A:32:FF:EA:04:91:BA:6E:D4:17:78:16"
     ":2A:EE:F9:9A:DD:E2:2B";
-static const char kRSA_FINGERPRINT_ALGORITHM[] =
-    "sha-256";
+static const char kRSA_FINGERPRINT_ALGORITHM[] = "sha-256";
 static const char kRSA_BASE64_CERTIFICATE[] =
     "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNVBAMMBXRlc3"
     "QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwGA1UEAwwFdGVzdDEwgZ8w"
@@ -147,8 +140,7 @@
 static const char kECDSA_FINGERPRINT[] =
     "9F:47:FA:88:76:3D:18:B8:00:A0:59:9D:C3:5D:34:0B:1F:B8:99:9E:68:DA:F3:A5:DA"
     ":50:33:A9:FF:4D:31:89";
-static const char kECDSA_FINGERPRINT_ALGORITHM[] =
-    "sha-256";
+static const char kECDSA_FINGERPRINT_ALGORITHM[] = "sha-256";
 static const char kECDSA_BASE64_CERTIFICATE[] =
     "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwFdGVzdDMwHh"
     "cNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQDDAV0ZXN0MzBZMBMGByqG"
@@ -171,19 +163,16 @@
   info.ders = ders;
   for (const std::string& der : ders) {
     info.pems.push_back(rtc::SSLIdentity::DerToPem(
-        "CERTIFICATE",
-        reinterpret_cast<const unsigned char*>(der.c_str()),
+        "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
         der.length()));
   }
   info.identity.reset(new rtc::FakeSSLIdentity(info.pems));
   // Strip header/footer and newline characters of PEM strings.
   for (size_t i = 0; i < info.pems.size(); ++i) {
-    rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27,
-                         "", 0, &info.pems[i]);
-    rtc::replace_substrs("-----END CERTIFICATE-----", 25,
-                         "", 0, &info.pems[i]);
-    rtc::replace_substrs("\n", 1,
-                         "", 0, &info.pems[i]);
+    rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27, "", 0,
+                         &info.pems[i]);
+    rtc::replace_substrs("-----END CERTIFICATE-----", 25, "", 0, &info.pems[i]);
+    rtc::replace_substrs("\n", 1, "", 0, &info.pems[i]);
   }
   // Fingerprints for the whole certificate chain, starting with leaf
   // certificate.
@@ -427,9 +416,11 @@
   std::string der;
   EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
 
-  EXPECT_EQ(kTestCertificate, SSLIdentity::DerToPem(
-      "CERTIFICATE",
-      reinterpret_cast<const unsigned char*>(der.data()), der.length()));
+  EXPECT_EQ(
+      kTestCertificate,
+      SSLIdentity::DerToPem("CERTIFICATE",
+                            reinterpret_cast<const unsigned char*>(der.data()),
+                            der.length()));
 }
 
 TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) {
@@ -498,6 +489,9 @@
       bool long_format;
       int64_t want;
     } static const data[] = {
+        // clang-format off
+        // clang formatting breaks this nice alignment
+
       // Valid examples.
       {"19700101000000Z",  true,  0},
       {"700101000000Z",    false, 0},
@@ -546,6 +540,8 @@
       {"500101000000Z",     false, -1},  // but too old for epoch
       {"691231235959Z",     false, -1},  // too old for epoch
       {"19611118043000Z",   false, -1},  // way too old for epoch
+
+        // clang-format off
     };
 
     unsigned char buf[20];
diff --git a/rtc_base/sslroots.h b/rtc_base/sslroots.h
index 7309a05..0dbd19b 100644
--- a/rtc_base/sslroots.h
+++ b/rtc_base/sslroots.h
@@ -18,6 +18,10 @@
 // > python tools/sslroots/generate_sslroots.py
 //    https://pki.google.com/roots.pem
 
+// clang-format off
+// Don't bother formatting generated code,
+// also it would breaks subject/issuer lines.
+
 /* subject:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */
 /* issuer :/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */
 
@@ -4277,4 +4281,6 @@
   1122,
 };
 
+// clang-format on
+
 #endif  // RTC_BASE_SSLROOTS_H_
diff --git a/rtc_base/sslstreamadapter.cc b/rtc_base/sslstreamadapter.cc
index d52dc45..746ebd5 100644
--- a/rtc_base/sslstreamadapter.cc
+++ b/rtc_base/sslstreamadapter.cc
@@ -25,16 +25,16 @@
 
 std::string SrtpCryptoSuiteToName(int crypto_suite) {
   switch (crypto_suite) {
-  case SRTP_AES128_CM_SHA1_32:
-    return CS_AES_CM_128_HMAC_SHA1_32;
-  case SRTP_AES128_CM_SHA1_80:
-    return CS_AES_CM_128_HMAC_SHA1_80;
-  case SRTP_AEAD_AES_128_GCM:
-    return CS_AEAD_AES_128_GCM;
-  case SRTP_AEAD_AES_256_GCM:
-    return CS_AEAD_AES_256_GCM;
-  default:
-    return std::string();
+    case SRTP_AES128_CM_SHA1_32:
+      return CS_AES_CM_128_HMAC_SHA1_32;
+    case SRTP_AES128_CM_SHA1_80:
+      return CS_AES_CM_128_HMAC_SHA1_80;
+    case SRTP_AEAD_AES_128_GCM:
+      return CS_AEAD_AES_128_GCM;
+    case SRTP_AEAD_AES_256_GCM:
+      return CS_AEAD_AES_256_GCM;
+    default:
+      return std::string();
   }
 }
 
@@ -50,30 +50,31 @@
   return SRTP_INVALID_CRYPTO_SUITE;
 }
 
-bool GetSrtpKeyAndSaltLengths(int crypto_suite, int *key_length,
-    int *salt_length) {
+bool GetSrtpKeyAndSaltLengths(int crypto_suite,
+                              int* key_length,
+                              int* salt_length) {
   switch (crypto_suite) {
-  case SRTP_AES128_CM_SHA1_32:
-  case SRTP_AES128_CM_SHA1_80:
-    // SRTP_AES128_CM_HMAC_SHA1_32 and SRTP_AES128_CM_HMAC_SHA1_80 are defined
-    // in RFC 5764 to use a 128 bits key and 112 bits salt for the cipher.
-    *key_length = 16;
-    *salt_length = 14;
-    break;
-  case SRTP_AEAD_AES_128_GCM:
-    // SRTP_AEAD_AES_128_GCM is defined in RFC 7714 to use a 128 bits key and
-    // a 96 bits salt for the cipher.
-    *key_length = 16;
-    *salt_length = 12;
-    break;
-  case SRTP_AEAD_AES_256_GCM:
-    // SRTP_AEAD_AES_256_GCM is defined in RFC 7714 to use a 256 bits key and
-    // a 96 bits salt for the cipher.
-    *key_length = 32;
-    *salt_length = 12;
-    break;
-  default:
-    return false;
+    case SRTP_AES128_CM_SHA1_32:
+    case SRTP_AES128_CM_SHA1_80:
+      // SRTP_AES128_CM_HMAC_SHA1_32 and SRTP_AES128_CM_HMAC_SHA1_80 are defined
+      // in RFC 5764 to use a 128 bits key and 112 bits salt for the cipher.
+      *key_length = 16;
+      *salt_length = 14;
+      break;
+    case SRTP_AEAD_AES_128_GCM:
+      // SRTP_AEAD_AES_128_GCM is defined in RFC 7714 to use a 128 bits key and
+      // a 96 bits salt for the cipher.
+      *key_length = 16;
+      *salt_length = 12;
+      break;
+    case SRTP_AEAD_AES_256_GCM:
+      // SRTP_AEAD_AES_256_GCM is defined in RFC 7714 to use a 256 bits key and
+      // a 96 bits salt for the cipher.
+      *key_length = 32;
+      *salt_length = 12;
+      break;
+    default:
+      return false;
   }
   return true;
 }
diff --git a/rtc_base/sslstreamadapter.h b/rtc_base/sslstreamadapter.h
index 827dc45..2d4e19f 100644
--- a/rtc_base/sslstreamadapter.h
+++ b/rtc_base/sslstreamadapter.h
@@ -22,6 +22,7 @@
 
 // Constants for SSL profile.
 const int TLS_NULL_WITH_NULL_NULL = 0;
+const int SSL_CIPHER_SUITE_MAX_VALUE = 0xFFFF;
 
 // Constants for SRTP profiles.
 const int SRTP_INVALID_CRYPTO_SUITE = 0;
@@ -37,6 +38,7 @@
 #ifndef SRTP_AEAD_AES_256_GCM
 const int SRTP_AEAD_AES_256_GCM = 0x0008;
 #endif
+const int SRTP_CRYPTO_SUITE_MAX_VALUE = 0xFFFF;
 
 // Names of SRTP profiles listed above.
 // 128-bit AES with 80-bit SHA-1 HMAC.
diff --git a/rtc_base/sslstreamadapter_unittest.cc b/rtc_base/sslstreamadapter_unittest.cc
index ce96274..3403bdb 100644
--- a/rtc_base/sslstreamadapter_unittest.cc
+++ b/rtc_base/sslstreamadapter_unittest.cc
@@ -8,7 +8,6 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
 #include <algorithm>
 #include <memory>
 #include <set>
@@ -135,22 +134,20 @@
                            public sigslot::has_slots<> {
  public:
   SSLDummyStreamBase(SSLStreamAdapterTestBase* test,
-                     const std::string &side,
+                     const std::string& side,
                      rtc::StreamInterface* in,
-                     rtc::StreamInterface* out) :
-      test_base_(test),
-      side_(side),
-      in_(in),
-      out_(out),
-      first_packet_(true) {
+                     rtc::StreamInterface* out)
+      : test_base_(test), side_(side), in_(in), out_(out), first_packet_(true) {
     in_->SignalEvent.connect(this, &SSLDummyStreamBase::OnEventIn);
     out_->SignalEvent.connect(this, &SSLDummyStreamBase::OnEventOut);
   }
 
   rtc::StreamState GetState() const override { return rtc::SS_OPEN; }
 
-  rtc::StreamResult Read(void* buffer, size_t buffer_len,
-                         size_t* read, int* error) override {
+  rtc::StreamResult Read(void* buffer,
+                         size_t buffer_len,
+                         size_t* read,
+                         int* error) override {
     rtc::StreamResult r;
 
     r = in_->Read(buffer, buffer_len, read, error);
@@ -189,13 +186,17 @@
   }
 
   // Write to the outgoing FifoBuffer
-  rtc::StreamResult WriteData(const void* data, size_t data_len,
-                              size_t* written, int* error) {
+  rtc::StreamResult WriteData(const void* data,
+                              size_t data_len,
+                              size_t* written,
+                              int* error) {
     return out_->Write(data, data_len, written, error);
   }
 
-  rtc::StreamResult Write(const void* data, size_t data_len,
-                          size_t* written, int* error) override;
+  rtc::StreamResult Write(const void* data,
+                          size_t data_len,
+                          size_t* written,
+                          int* error) override;
 
   void Close() override {
     RTC_LOG(LS_INFO) << "Closing outbound stream";
@@ -215,17 +216,14 @@
   SSLDummyStreamTLS(SSLStreamAdapterTestBase* test,
                     const std::string& side,
                     rtc::FifoBuffer* in,
-                    rtc::FifoBuffer* out) :
-      SSLDummyStreamBase(test, side, in, out) {
-  }
+                    rtc::FifoBuffer* out)
+      : SSLDummyStreamBase(test, side, in, out) {}
 };
 
-class BufferQueueStream : public rtc::BufferQueue,
-                          public rtc::StreamInterface {
+class BufferQueueStream : public rtc::BufferQueue, public rtc::StreamInterface {
  public:
   BufferQueueStream(size_t capacity, size_t default_size)
-      : rtc::BufferQueue(capacity, default_size) {
-  }
+      : rtc::BufferQueue(capacity, default_size) {}
 
   // Implementation of abstract StreamInterface methods.
 
@@ -233,8 +231,10 @@
   rtc::StreamState GetState() const override { return rtc::SS_OPEN; }
 
   // Reading a buffer queue stream will either succeed or block.
-  rtc::StreamResult Read(void* buffer, size_t buffer_len,
-                         size_t* read, int* error) override {
+  rtc::StreamResult Read(void* buffer,
+                         size_t buffer_len,
+                         size_t* read,
+                         int* error) override {
     if (!ReadFront(buffer, buffer_len, read)) {
       return rtc::SR_BLOCK;
     }
@@ -242,8 +242,10 @@
   }
 
   // Writing to a buffer queue stream will either succeed or block.
-  rtc::StreamResult Write(const void* data, size_t data_len,
-                          size_t* written, int* error) override {
+  rtc::StreamResult Write(const void* data,
+                          size_t data_len,
+                          size_t* written,
+                          int* error) override {
     if (!WriteBack(data, data_len, written)) {
       return rtc::SR_BLOCK;
     }
@@ -254,13 +256,9 @@
   void Close() override {}
 
  protected:
-  void NotifyReadableForTest() override {
-    PostEvent(rtc::SE_READ, 0);
-  }
+  void NotifyReadableForTest() override { PostEvent(rtc::SE_READ, 0); }
 
-  void NotifyWritableForTest() override {
-    PostEvent(rtc::SE_WRITE, 0);
-  }
+  void NotifyWritableForTest() override { PostEvent(rtc::SE_WRITE, 0); }
 };
 
 class SSLDummyStreamDTLS : public SSLDummyStreamBase {
@@ -268,9 +266,8 @@
   SSLDummyStreamDTLS(SSLStreamAdapterTestBase* test,
                      const std::string& side,
                      BufferQueueStream* in,
-                     BufferQueueStream* out) :
-      SSLDummyStreamBase(test, side, in, out) {
-  }
+                     BufferQueueStream* out)
+      : SSLDummyStreamBase(test, side, in, out) {}
 };
 
 static const int kFifoBufferSize = 4096;
@@ -372,7 +369,7 @@
     server_ssl_->SetIdentity(server_identity_);
   }
 
-  virtual void OnEvent(rtc::StreamInterface *stream, int sig, int err) {
+  virtual void OnEvent(rtc::StreamInterface* stream, int sig, int err) {
     RTC_LOG(LS_VERBOSE) << "SSLStreamAdapterTestBase::OnEvent sig=" << sig;
 
     if (sig & rtc::SE_READ) {
@@ -433,10 +430,8 @@
   }
 
   void TestHandshake(bool expect_success = true) {
-    server_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS :
-                         rtc::SSL_MODE_TLS);
-    client_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS :
-                         rtc::SSL_MODE_TLS);
+    server_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS);
+    client_ssl_->SetMode(dtls_ ? rtc::SSL_MODE_DTLS : rtc::SSL_MODE_TLS);
 
     if (!dtls_) {
       // Make sure we simulate a reliable network for TLS.
@@ -462,8 +457,8 @@
 
     // Now run the handshake
     if (expect_success) {
-      EXPECT_TRUE_WAIT((client_ssl_->GetState() == rtc::SS_OPEN)
-                       && (server_ssl_->GetState() == rtc::SS_OPEN),
+      EXPECT_TRUE_WAIT((client_ssl_->GetState() == rtc::SS_OPEN) &&
+                           (server_ssl_->GetState() == rtc::SS_OPEN),
                        handshake_wait_);
     } else {
       EXPECT_TRUE_WAIT(client_ssl_->GetState() == rtc::SS_CLOSED,
@@ -524,9 +519,11 @@
     }
   }
 
-  rtc::StreamResult DataWritten(SSLDummyStreamBase *from, const void *data,
-                                size_t data_len, size_t *written,
-                                int *error) {
+  rtc::StreamResult DataWritten(SSLDummyStreamBase* from,
+                                const void* data,
+                                size_t data_len,
+                                size_t* written,
+                                int* error) {
     // Randomly drop loss_ percent of packets
     if (rtc::CreateRandomId() % 100 < static_cast<uint32_t>(loss_)) {
       RTC_LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << data_len;
@@ -542,7 +539,7 @@
     // Optionally damage application data (type 23). Note that we don't damage
     // handshake packets and we damage the last byte to keep the header
     // intact but break the MAC.
-    if (damage_ && (*static_cast<const unsigned char *>(data) == 23)) {
+    if (damage_ && (*static_cast<const unsigned char*>(data) == 23)) {
       std::vector<char> buf(data_len);
 
       RTC_LOG(LS_VERBOSE) << "Damaging packet";
@@ -556,31 +553,19 @@
     return from->WriteData(data, data_len, written, error);
   }
 
-  void SetDelay(int delay) {
-    delay_ = delay;
-  }
+  void SetDelay(int delay) { delay_ = delay; }
   int GetDelay() { return delay_; }
 
-  void SetLoseFirstPacket(bool lose) {
-    lose_first_packet_ = lose;
-  }
+  void SetLoseFirstPacket(bool lose) { lose_first_packet_ = lose; }
   bool GetLoseFirstPacket() { return lose_first_packet_; }
 
-  void SetLoss(int percent) {
-    loss_ = percent;
-  }
+  void SetLoss(int percent) { loss_ = percent; }
 
-  void SetDamage() {
-    damage_ = true;
-  }
+  void SetDamage() { damage_ = true; }
 
-  void SetMtu(size_t mtu) {
-    mtu_ = mtu;
-  }
+  void SetMtu(size_t mtu) { mtu_ = mtu; }
 
-  void SetHandshakeWait(int wait) {
-    handshake_wait_ = wait;
-  }
+  void SetHandshakeWait(int wait) { handshake_wait_ = wait; }
 
   void SetDtlsSrtpCryptoSuites(const std::vector<int>& ciphers, bool client) {
     if (client)
@@ -620,28 +605,24 @@
       return server_ssl_->GetSslVersion();
   }
 
-  bool ExportKeyingMaterial(const char *label,
-                            const unsigned char *context,
+  bool ExportKeyingMaterial(const char* label,
+                            const unsigned char* context,
                             size_t context_len,
                             bool use_context,
                             bool client,
-                            unsigned char *result,
+                            unsigned char* result,
                             size_t result_len) {
     if (client)
-      return client_ssl_->ExportKeyingMaterial(label,
-                                               context, context_len,
-                                               use_context,
-                                               result, result_len);
+      return client_ssl_->ExportKeyingMaterial(label, context, context_len,
+                                               use_context, result, result_len);
     else
-      return server_ssl_->ExportKeyingMaterial(label,
-                                               context, context_len,
-                                               use_context,
-                                               result, result_len);
+      return server_ssl_->ExportKeyingMaterial(label, context, context_len,
+                                               use_context, result, result_len);
   }
 
   // To be implemented by subclasses.
   virtual void WriteData() = 0;
-  virtual void ReadData(rtc::StreamInterface *stream) = 0;
+  virtual void ReadData(rtc::StreamInterface* stream) = 0;
   virtual void TestTransfer(int size) = 0;
 
  protected:
@@ -649,12 +630,12 @@
   std::string client_private_key_pem_;
   rtc::KeyParams client_key_type_;
   rtc::KeyParams server_key_type_;
-  SSLDummyStreamBase *client_stream_;  // freed by client_ssl_ destructor
-  SSLDummyStreamBase *server_stream_;  // freed by server_ssl_ destructor
+  SSLDummyStreamBase* client_stream_;  // freed by client_ssl_ destructor
+  SSLDummyStreamBase* server_stream_;  // freed by server_ssl_ destructor
   std::unique_ptr<rtc::SSLStreamAdapter> client_ssl_;
   std::unique_ptr<rtc::SSLStreamAdapter> server_ssl_;
-  rtc::SSLIdentity *client_identity_;  // freed by client_ssl_ destructor
-  rtc::SSLIdentity *server_identity_;  // freed by server_ssl_ destructor
+  rtc::SSLIdentity* client_identity_;  // freed by client_ssl_ destructor
+  rtc::SSLIdentity* server_identity_;  // freed by server_ssl_ destructor
   int delay_;
   size_t mtu_;
   int loss_;
@@ -676,8 +657,7 @@
                                  ::testing::get<0>(GetParam()),
                                  ::testing::get<1>(GetParam())),
         client_buffer_(kFifoBufferSize),
-        server_buffer_(kFifoBufferSize) {
-  }
+        server_buffer_(kFifoBufferSize) {}
 
   void CreateStreams() override {
     client_stream_ =
@@ -712,8 +692,8 @@
     recv_stream_.GetSize(&received);
 
     EXPECT_EQ(static_cast<size_t>(size), received);
-    EXPECT_EQ(0, memcmp(send_stream_.GetBuffer(),
-                        recv_stream_.GetBuffer(), size));
+    EXPECT_EQ(0,
+              memcmp(send_stream_.GetBuffer(), recv_stream_.GetBuffer(), size));
   }
 
   void WriteData() override {
@@ -752,7 +732,7 @@
     }
   };
 
-  void ReadData(rtc::StreamInterface *stream) override {
+  void ReadData(rtc::StreamInterface* stream) override {
     char buffer[1600];
     size_t bread;
     int err2;
@@ -802,12 +782,13 @@
         sent_(0) {}
 
   SSLStreamAdapterTestDTLS(const std::string& cert_pem,
-                           const std::string& private_key_pem) :
-      SSLStreamAdapterTestBase(cert_pem, private_key_pem, true),
-      client_buffer_(kBufferCapacity, kDefaultBufferSize),
-      server_buffer_(kBufferCapacity, kDefaultBufferSize),
-      packet_size_(1000), count_(0), sent_(0) {
-  }
+                           const std::string& private_key_pem)
+      : SSLStreamAdapterTestBase(cert_pem, private_key_pem, true),
+        client_buffer_(kBufferCapacity, kDefaultBufferSize),
+        server_buffer_(kBufferCapacity, kDefaultBufferSize),
+        packet_size_(1000),
+        count_(0),
+        sent_(0) {}
 
   void CreateStreams() override {
     client_stream_ =
@@ -817,7 +798,7 @@
   }
 
   void WriteData() override {
-    unsigned char *packet = new unsigned char[1600];
+    unsigned char* packet = new unsigned char[1600];
 
     while (sent_ < count_) {
       unsigned int rand_state = sent_;
@@ -842,10 +823,10 @@
       }
     }
 
-    delete [] packet;
+    delete[] packet;
   }
 
-  void ReadData(rtc::StreamInterface *stream) override {
+  void ReadData(rtc::StreamInterface* stream) override {
     unsigned char buffer[2000];
     size_t bread;
     int err2;
@@ -893,7 +874,7 @@
       WAIT(false, 2000);
       EXPECT_EQ(0U, received_.size());
     } else if (loss_ == 0) {
-        EXPECT_EQ_WAIT(static_cast<size_t>(sent_), received_.size(), 1000);
+      EXPECT_EQ_WAIT(static_cast<size_t>(sent_), received_.size(), 1000);
     } else {
       RTC_LOG(LS_INFO) << "Sent " << sent_ << " packets; received "
                        << received_.size();
@@ -909,9 +890,10 @@
   std::set<int> received_;
 };
 
-
-rtc::StreamResult SSLDummyStreamBase::Write(const void* data, size_t data_len,
-                                              size_t* written, int* error) {
+rtc::StreamResult SSLDummyStreamBase::Write(const void* data,
+                                            size_t data_len,
+                                            size_t* written,
+                                            int* error) {
   RTC_LOG(LS_VERBOSE) << "Writing to loopback " << data_len;
 
   if (first_packet_) {
@@ -928,9 +910,8 @@
 
 class SSLStreamAdapterTestDTLSFromPEMStrings : public SSLStreamAdapterTestDTLS {
  public:
-  SSLStreamAdapterTestDTLSFromPEMStrings() :
-      SSLStreamAdapterTestDTLS(kCERT_PEM, kRSA_PRIVATE_KEY_PEM) {
-  }
+  SSLStreamAdapterTestDTLSFromPEMStrings()
+      : SSLStreamAdapterTestDTLS(kCERT_PEM, kRSA_PRIVATE_KEY_PEM) {}
 };
 
 // Test fixture for certificate chaining. Server will push more than one
@@ -1305,28 +1286,28 @@
   int key_len;
   int salt_len;
 
-  ASSERT_FALSE(rtc::GetSrtpKeyAndSaltLengths(
-      rtc::SRTP_INVALID_CRYPTO_SUITE, &key_len, &salt_len));
+  ASSERT_FALSE(rtc::GetSrtpKeyAndSaltLengths(rtc::SRTP_INVALID_CRYPTO_SUITE,
+                                             &key_len, &salt_len));
 
-  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(
-      rtc::SRTP_AES128_CM_SHA1_32, &key_len, &salt_len));
-  ASSERT_EQ(128/8, key_len);
-  ASSERT_EQ(112/8, salt_len);
+  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::SRTP_AES128_CM_SHA1_32,
+                                            &key_len, &salt_len));
+  ASSERT_EQ(128 / 8, key_len);
+  ASSERT_EQ(112 / 8, salt_len);
 
-  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(
-      rtc::SRTP_AES128_CM_SHA1_80, &key_len, &salt_len));
-  ASSERT_EQ(128/8, key_len);
-  ASSERT_EQ(112/8, salt_len);
+  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::SRTP_AES128_CM_SHA1_80,
+                                            &key_len, &salt_len));
+  ASSERT_EQ(128 / 8, key_len);
+  ASSERT_EQ(112 / 8, salt_len);
 
-  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(
-      rtc::SRTP_AEAD_AES_128_GCM, &key_len, &salt_len));
-  ASSERT_EQ(128/8, key_len);
-  ASSERT_EQ(96/8, salt_len);
+  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::SRTP_AEAD_AES_128_GCM,
+                                            &key_len, &salt_len));
+  ASSERT_EQ(128 / 8, key_len);
+  ASSERT_EQ(96 / 8, salt_len);
 
-  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(
-      rtc::SRTP_AEAD_AES_256_GCM, &key_len, &salt_len));
-  ASSERT_EQ(256/8, key_len);
-  ASSERT_EQ(96/8, salt_len);
+  ASSERT_TRUE(rtc::GetSrtpKeyAndSaltLengths(rtc::SRTP_AEAD_AES_256_GCM,
+                                            &key_len, &salt_len));
+  ASSERT_EQ(256 / 8, key_len);
+  ASSERT_EQ(96 / 8, salt_len);
 };
 
 // Test an exporter
@@ -1336,16 +1317,14 @@
   unsigned char server_out[20];
 
   bool result;
-  result = ExportKeyingMaterial(kExporterLabel,
-                                kExporterContext, kExporterContextLen,
-                                true, true,
-                                client_out, sizeof(client_out));
+  result = ExportKeyingMaterial(kExporterLabel, kExporterContext,
+                                kExporterContextLen, true, true, client_out,
+                                sizeof(client_out));
   ASSERT_TRUE(result);
 
-  result = ExportKeyingMaterial(kExporterLabel,
-                                kExporterContext, kExporterContextLen,
-                                true, false,
-                                server_out, sizeof(server_out));
+  result = ExportKeyingMaterial(kExporterLabel, kExporterContext,
+                                kExporterContextLen, true, false, server_out,
+                                sizeof(server_out));
   ASSERT_TRUE(result);
 
   ASSERT_TRUE(!memcmp(client_out, server_out, sizeof(client_out)));
diff --git a/rtc_base/stream.cc b/rtc_base/stream.cc
index d937353..b9691c5 100644
--- a/rtc_base/stream.cc
+++ b/rtc_base/stream.cc
@@ -11,14 +11,13 @@
 #if defined(WEBRTC_POSIX)
 #include <sys/file.h>
 #endif  // WEBRTC_POSIX
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include <algorithm>
 #include <string>
 
-#include "rtc_base/basictypes.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/messagequeue.h"
@@ -38,11 +37,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 // StreamInterface
 ///////////////////////////////////////////////////////////////////////////////
-StreamInterface::~StreamInterface() {
-}
+StreamInterface::~StreamInterface() {}
 
-StreamResult StreamInterface::WriteAll(const void* data, size_t data_len,
-                                       size_t* written, int* error) {
+StreamResult StreamInterface::WriteAll(const void* data,
+                                       size_t data_len,
+                                       size_t* written,
+                                       int* error) {
   StreamResult result = SR_SUCCESS;
   size_t total_written = 0, current_written;
   while (total_written < data_len) {
@@ -57,8 +57,10 @@
   return result;
 }
 
-StreamResult StreamInterface::ReadAll(void* buffer, size_t buffer_len,
-                                      size_t* read, int* error) {
+StreamResult StreamInterface::ReadAll(void* buffer,
+                                      size_t buffer_len,
+                                      size_t* read,
+                                      int* error) {
   StreamResult result = SR_SUCCESS;
   size_t total_read = 0, current_read;
   while (total_read < buffer_len) {
@@ -138,8 +140,7 @@
   return true;
 }
 
-StreamInterface::StreamInterface() {
-}
+StreamInterface::StreamInterface() {}
 
 void StreamInterface::OnMessage(Message* msg) {
   if (MSG_POST_EVENT == msg->message_id) {
@@ -238,90 +239,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// StreamTap
-///////////////////////////////////////////////////////////////////////////////
-
-StreamTap::StreamTap(StreamInterface* stream, StreamInterface* tap)
-    : StreamAdapterInterface(stream), tap_(), tap_result_(SR_SUCCESS),
-        tap_error_(0) {
-  AttachTap(tap);
-}
-
-StreamTap::~StreamTap() = default;
-
-void StreamTap::AttachTap(StreamInterface* tap) {
-  tap_.reset(tap);
-}
-
-StreamInterface* StreamTap::DetachTap() {
-  return tap_.release();
-}
-
-StreamResult StreamTap::GetTapResult(int* error) {
-  if (error) {
-    *error = tap_error_;
-  }
-  return tap_result_;
-}
-
-StreamResult StreamTap::Read(void* buffer, size_t buffer_len,
-                             size_t* read, int* error) {
-  size_t backup_read;
-  if (!read) {
-    read = &backup_read;
-  }
-  StreamResult res = StreamAdapterInterface::Read(buffer, buffer_len,
-                                                  read, error);
-  if ((res == SR_SUCCESS) && (tap_result_ == SR_SUCCESS)) {
-    tap_result_ = tap_->WriteAll(buffer, *read, nullptr, &tap_error_);
-  }
-  return res;
-}
-
-StreamResult StreamTap::Write(const void* data, size_t data_len,
-                              size_t* written, int* error) {
-  size_t backup_written;
-  if (!written) {
-    written = &backup_written;
-  }
-  StreamResult res = StreamAdapterInterface::Write(data, data_len,
-                                                   written, error);
-  if ((res == SR_SUCCESS) && (tap_result_ == SR_SUCCESS)) {
-    tap_result_ = tap_->WriteAll(data, *written, nullptr, &tap_error_);
-  }
-  return res;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// NullStream
-///////////////////////////////////////////////////////////////////////////////
-
-NullStream::NullStream() {
-}
-
-NullStream::~NullStream() {
-}
-
-StreamState NullStream::GetState() const {
-  return SS_OPEN;
-}
-
-StreamResult NullStream::Read(void* buffer, size_t buffer_len,
-                              size_t* read, int* error) {
-  if (error) *error = -1;
-  return SR_ERROR;
-}
-
-StreamResult NullStream::Write(const void* data, size_t data_len,
-                               size_t* written, int* error) {
-  if (written) *written = data_len;
-  return SR_SUCCESS;
-}
-
-void NullStream::Close() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // FileStream
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -331,7 +248,8 @@
   FileStream::Close();
 }
 
-bool FileStream::Open(const std::string& filename, const char* mode,
+bool FileStream::Open(const std::string& filename,
+                      const char* mode,
                       int* error) {
   Close();
 #if defined(WEBRTC_WIN)
@@ -353,8 +271,10 @@
   return (file_ != nullptr);
 }
 
-bool FileStream::OpenShare(const std::string& filename, const char* mode,
-                           int shflag, int* error) {
+bool FileStream::OpenShare(const std::string& filename,
+                           const char* mode,
+                           int shflag,
+                           int* error) {
   Close();
 #if defined(WEBRTC_WIN)
   std::wstring wfilename;
@@ -386,8 +306,10 @@
   return (file_ == nullptr) ? SS_CLOSED : SS_OPEN;
 }
 
-StreamResult FileStream::Read(void* buffer, size_t buffer_len,
-                              size_t* read, int* error) {
+StreamResult FileStream::Read(void* buffer,
+                              size_t buffer_len,
+                              size_t* read,
+                              int* error) {
   if (!file_)
     return SR_EOS;
   size_t result = fread(buffer, 1, buffer_len, file_);
@@ -403,8 +325,10 @@
   return SR_SUCCESS;
 }
 
-StreamResult FileStream::Write(const void* data, size_t data_len,
-                               size_t* written, int* error) {
+StreamResult FileStream::Write(const void* data,
+                               size_t data_len,
+                               size_t* written,
+                               int* error) {
   if (!file_)
     return SR_EOS;
   size_t result = fwrite(data, 1, data_len, file_);
@@ -496,8 +420,10 @@
   return SS_OPEN;
 }
 
-StreamResult MemoryStreamBase::Read(void* buffer, size_t bytes,
-                                    size_t* bytes_read, int* error) {
+StreamResult MemoryStreamBase::Read(void* buffer,
+                                    size_t bytes,
+                                    size_t* bytes_read,
+                                    int* error) {
   if (seek_position_ >= data_length_) {
     return SR_EOS;
   }
@@ -514,8 +440,10 @@
   return SR_SUCCESS;
 }
 
-StreamResult MemoryStreamBase::Write(const void* buffer, size_t bytes,
-                                     size_t* bytes_written, int* error) {
+StreamResult MemoryStreamBase::Write(const void* buffer,
+                                     size_t bytes,
+                                     size_t* bytes_written,
+                                     int* error) {
   size_t available = buffer_length_ - seek_position_;
   if (0 == available) {
     // Increase buffer size to the larger of:
@@ -584,26 +512,24 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-MemoryStream::MemoryStream() : buffer_alloc_(nullptr) {}
+MemoryStream::MemoryStream() {}
 
-MemoryStream::MemoryStream(const char* data) : buffer_alloc_(nullptr) {
+MemoryStream::MemoryStream(const char* data) {
   SetData(data, strlen(data));
 }
 
-MemoryStream::MemoryStream(const void* data, size_t length)
-    : buffer_alloc_(nullptr) {
+MemoryStream::MemoryStream(const void* data, size_t length) {
   SetData(data, length);
 }
 
 MemoryStream::~MemoryStream() {
-  delete [] buffer_alloc_;
+  delete[] buffer_;
 }
 
 void MemoryStream::SetData(const void* data, size_t length) {
   data_length_ = buffer_length_ = length;
-  delete [] buffer_alloc_;
-  buffer_alloc_ = new char[buffer_length_ + kAlignment];
-  buffer_ = reinterpret_cast<char*>(ALIGNP(buffer_alloc_, kAlignment));
+  delete[] buffer_;
+  buffer_ = new char[buffer_length_];
   memcpy(buffer_, data, data_length_);
   seek_position_ = 0;
 }
@@ -612,12 +538,9 @@
   if (buffer_length_ >= size)
     return SR_SUCCESS;
 
-  if (char* new_buffer_alloc = new char[size + kAlignment]) {
-    char* new_buffer = reinterpret_cast<char*>(
-        ALIGNP(new_buffer_alloc, kAlignment));
+  if (char* new_buffer = new char[size]) {
     memcpy(new_buffer, buffer_, data_length_);
-    delete [] buffer_alloc_;
-    buffer_alloc_ = new_buffer_alloc;
+    delete[] buffer_;
     buffer_ = new_buffer;
     buffer_length_ = size;
     return SR_SUCCESS;
@@ -631,15 +554,13 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-ExternalMemoryStream::ExternalMemoryStream() {
-}
+ExternalMemoryStream::ExternalMemoryStream() {}
 
 ExternalMemoryStream::ExternalMemoryStream(void* data, size_t length) {
   SetData(data, length);
 }
 
-ExternalMemoryStream::~ExternalMemoryStream() {
-}
+ExternalMemoryStream::~ExternalMemoryStream() {}
 
 void ExternalMemoryStream::SetData(void* data, size_t length) {
   data_length_ = buffer_length_ = length;
@@ -652,19 +573,26 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 FifoBuffer::FifoBuffer(size_t size)
-    : state_(SS_OPEN), buffer_(new char[size]), buffer_length_(size),
-      data_length_(0), read_position_(0), owner_(Thread::Current()) {
+    : state_(SS_OPEN),
+      buffer_(new char[size]),
+      buffer_length_(size),
+      data_length_(0),
+      read_position_(0),
+      owner_(Thread::Current()) {
   // all events are done on the owner_ thread
 }
 
 FifoBuffer::FifoBuffer(size_t size, Thread* owner)
-    : state_(SS_OPEN), buffer_(new char[size]), buffer_length_(size),
-      data_length_(0), read_position_(0), owner_(owner) {
+    : state_(SS_OPEN),
+      buffer_(new char[size]),
+      buffer_length_(size),
+      data_length_(0),
+      read_position_(0),
+      owner_(owner) {
   // all events are done on the owner_ thread
 }
 
-FifoBuffer::~FifoBuffer() {
-}
+FifoBuffer::~FifoBuffer() {}
 
 bool FifoBuffer::GetBuffered(size_t* size) const {
   CritScope cs(&crit_);
@@ -691,14 +619,18 @@
   return true;
 }
 
-StreamResult FifoBuffer::ReadOffset(void* buffer, size_t bytes,
-                                    size_t offset, size_t* bytes_read) {
+StreamResult FifoBuffer::ReadOffset(void* buffer,
+                                    size_t bytes,
+                                    size_t offset,
+                                    size_t* bytes_read) {
   CritScope cs(&crit_);
   return ReadOffsetLocked(buffer, bytes, offset, bytes_read);
 }
 
-StreamResult FifoBuffer::WriteOffset(const void* buffer, size_t bytes,
-                                     size_t offset, size_t* bytes_written) {
+StreamResult FifoBuffer::WriteOffset(const void* buffer,
+                                     size_t bytes,
+                                     size_t offset,
+                                     size_t* bytes_written) {
   CritScope cs(&crit_);
   return WriteOffsetLocked(buffer, bytes, offset, bytes_written);
 }
@@ -708,8 +640,10 @@
   return state_;
 }
 
-StreamResult FifoBuffer::Read(void* buffer, size_t bytes,
-                              size_t* bytes_read, int* error) {
+StreamResult FifoBuffer::Read(void* buffer,
+                              size_t bytes,
+                              size_t* bytes_read,
+                              int* error) {
   CritScope cs(&crit_);
   const bool was_writable = data_length_ < buffer_length_;
   size_t copy = 0;
@@ -732,8 +666,10 @@
   return result;
 }
 
-StreamResult FifoBuffer::Write(const void* buffer, size_t bytes,
-                               size_t* bytes_written, int* error) {
+StreamResult FifoBuffer::Write(const void* buffer,
+                               size_t bytes,
+                               size_t* bytes_written,
+                               int* error) {
   CritScope cs(&crit_);
 
   const bool was_readable = (data_length_ > 0);
@@ -762,8 +698,9 @@
 
 const void* FifoBuffer::GetReadData(size_t* size) {
   CritScope cs(&crit_);
-  *size = (read_position_ + data_length_ <= buffer_length_) ?
-      data_length_ : buffer_length_ - read_position_;
+  *size = (read_position_ + data_length_ <= buffer_length_)
+              ? data_length_
+              : buffer_length_ - read_position_;
   return &buffer_[read_position_];
 }
 
@@ -790,10 +727,11 @@
     read_position_ = 0;
   }
 
-  const size_t write_position = (read_position_ + data_length_)
-      % buffer_length_;
-  *size = (write_position > read_position_ || data_length_ == 0) ?
-      buffer_length_ - write_position : read_position_ - write_position;
+  const size_t write_position =
+      (read_position_ + data_length_) % buffer_length_;
+  *size = (write_position > read_position_ || data_length_ == 0)
+              ? buffer_length_ - write_position
+              : read_position_ - write_position;
   return &buffer_[write_position];
 }
 
@@ -848,8 +786,8 @@
   }
 
   const size_t available = buffer_length_ - data_length_ - offset;
-  const size_t write_position = (read_position_ + data_length_ + offset)
-      % buffer_length_;
+  const size_t write_position =
+      (read_position_ + data_length_ + offset) % buffer_length_;
   const size_t copy = std::min(bytes, available);
   const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
   const char* const p = static_cast<const char*>(buffer);
@@ -864,109 +802,6 @@
 
 
 ///////////////////////////////////////////////////////////////////////////////
-// StringStream - Reads/Writes to an external std::string
-///////////////////////////////////////////////////////////////////////////////
-
-StringStream::StringStream(std::string* str)
-    : str_(*str), read_pos_(0), read_only_(false) {
-}
-
-StringStream::StringStream(const std::string& str)
-    : str_(const_cast<std::string&>(str)), read_pos_(0), read_only_(true) {
-}
-
-StreamState StringStream::GetState() const {
-  return SS_OPEN;
-}
-
-StreamResult StringStream::Read(void* buffer, size_t buffer_len,
-                                      size_t* read, int* error) {
-  size_t available = std::min(buffer_len, str_.size() - read_pos_);
-  if (!available)
-    return SR_EOS;
-  memcpy(buffer, str_.data() + read_pos_, available);
-  read_pos_ += available;
-  if (read)
-    *read = available;
-  return SR_SUCCESS;
-}
-
-StreamResult StringStream::Write(const void* data, size_t data_len,
-                                      size_t* written, int* error) {
-  if (read_only_) {
-    if (error) {
-      *error = -1;
-    }
-    return SR_ERROR;
-  }
-  str_.append(static_cast<const char*>(data),
-              static_cast<const char*>(data) + data_len);
-  if (written)
-    *written = data_len;
-  return SR_SUCCESS;
-}
-
-void StringStream::Close() {
-}
-
-bool StringStream::SetPosition(size_t position) {
-  if (position > str_.size())
-    return false;
-  read_pos_ = position;
-  return true;
-}
-
-bool StringStream::GetPosition(size_t* position) const {
-  if (position)
-    *position = read_pos_;
-  return true;
-}
-
-bool StringStream::GetSize(size_t* size) const {
-  if (size)
-    *size = str_.size();
-  return true;
-}
-
-bool StringStream::GetAvailable(size_t* size) const {
-  if (size)
-    *size = str_.size() - read_pos_;
-  return true;
-}
-
-bool StringStream::ReserveSize(size_t size) {
-  if (read_only_)
-    return false;
-  str_.reserve(size);
-  return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// StreamReference
-///////////////////////////////////////////////////////////////////////////////
-
-StreamReference::StreamReference(StreamInterface* stream)
-    : StreamAdapterInterface(stream, false) {
-  // owner set to false so the destructor does not free the stream.
-  stream_ref_count_ = new StreamRefCount(stream);
-}
-
-StreamInterface* StreamReference::NewReference() {
-  stream_ref_count_->AddReference();
-  return new StreamReference(stream_ref_count_, stream());
-}
-
-StreamReference::~StreamReference() {
-  stream_ref_count_->Release();
-}
-
-StreamReference::StreamReference(StreamRefCount* stream_ref_count,
-                                 StreamInterface* stream)
-    : StreamAdapterInterface(stream, false),
-      stream_ref_count_(stream_ref_count) {
-}
-
-///////////////////////////////////////////////////////////////////////////////
 
 StreamResult Flow(StreamInterface* source,
                   char* buffer,
diff --git a/rtc_base/stream.h b/rtc_base/stream.h
index 77e4bd8..ee0f149 100644
--- a/rtc_base/stream.h
+++ b/rtc_base/stream.h
@@ -55,14 +55,12 @@
 
 struct StreamEventData : public MessageData {
   int events, error;
-  StreamEventData(int ev, int er) : events(ev), error(er) { }
+  StreamEventData(int ev, int er) : events(ev), error(er) {}
 };
 
 class StreamInterface : public MessageHandler {
  public:
-  enum {
-    MSG_POST_EVENT = 0xF1F1, MSG_MAX = MSG_POST_EVENT
-  };
+  enum { MSG_POST_EVENT = 0xF1F1, MSG_MAX = MSG_POST_EVENT };
 
   ~StreamInterface() override;
 
@@ -81,10 +79,14 @@
   //    block, or the stream is in SS_OPENING state.
   //  SR_EOS: the end-of-stream has been reached, or the stream is in the
   //    SS_CLOSED state.
-  virtual StreamResult Read(void* buffer, size_t buffer_len,
-                            size_t* read, int* error) = 0;
-  virtual StreamResult Write(const void* data, size_t data_len,
-                             size_t* written, int* error) = 0;
+  virtual StreamResult Read(void* buffer,
+                            size_t buffer_len,
+                            size_t* read,
+                            int* error) = 0;
+  virtual StreamResult Write(const void* data,
+                             size_t data_len,
+                             size_t* written,
+                             int* error) = 0;
   // Attempt to transition to the SS_CLOSED state.  SE_CLOSE will not be
   // signalled as a result of this call.
   virtual void Close() = 0;
@@ -158,7 +160,7 @@
   // NOTE: This interface is being considered experimentally at the moment.  It
   // would be used by JUDP and BandwidthStream as a way to circumvent certain
   // soft limits in writing.
-  //virtual bool ForceWrite(const void* data, size_t data_len, int* error) {
+  // virtual bool ForceWrite(const void* data, size_t data_len, int* error) {
   //  if (error) *error = -1;
   //  return false;
   //}
@@ -208,13 +210,17 @@
   // unlike Write, the argument 'written' is always set, and may be non-zero
   // on results other than SR_SUCCESS.  The remaining arguments have the
   // same semantics as Write.
-  StreamResult WriteAll(const void* data, size_t data_len,
-                        size_t* written, int* error);
+  StreamResult WriteAll(const void* data,
+                        size_t data_len,
+                        size_t* written,
+                        int* error);
 
   // Similar to ReadAll.  Calls Read until buffer_len bytes have been read, or
   // until a non-SR_SUCCESS result is returned.  'read' is always set.
-  StreamResult ReadAll(void* buffer, size_t buffer_len,
-                       size_t* read, int* error);
+  StreamResult ReadAll(void* buffer,
+                       size_t buffer_len,
+                       size_t* read,
+                       int* error);
 
   // ReadLine is a helper function which repeatedly calls Read until it hits
   // the end-of-line character, or something other than SR_SUCCESS.
@@ -310,60 +316,6 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
-// StreamTap is a non-modifying, pass-through adapter, which copies all data
-// in either direction to the tap.  Note that errors or blocking on writing to
-// the tap will prevent further tap writes from occurring.
-///////////////////////////////////////////////////////////////////////////////
-
-class StreamTap : public StreamAdapterInterface {
- public:
-  explicit StreamTap(StreamInterface* stream, StreamInterface* tap);
-  ~StreamTap() override;
-
-  void AttachTap(StreamInterface* tap);
-  StreamInterface* DetachTap();
-  StreamResult GetTapResult(int* error);
-
-  // StreamAdapterInterface Interface
-  StreamResult Read(void* buffer,
-                    size_t buffer_len,
-                    size_t* read,
-                    int* error) override;
-  StreamResult Write(const void* data,
-                     size_t data_len,
-                     size_t* written,
-                     int* error) override;
-
- private:
-  std::unique_ptr<StreamInterface> tap_;
-  StreamResult tap_result_;
-  int tap_error_;
-  RTC_DISALLOW_COPY_AND_ASSIGN(StreamTap);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// NullStream gives errors on read, and silently discards all written data.
-///////////////////////////////////////////////////////////////////////////////
-
-class NullStream : public StreamInterface {
- public:
-  NullStream();
-  ~NullStream() override;
-
-  // StreamInterface Interface
-  StreamState GetState() const override;
-  StreamResult Read(void* buffer,
-                    size_t buffer_len,
-                    size_t* read,
-                    int* error) override;
-  StreamResult Write(const void* data,
-                     size_t data_len,
-                     size_t* written,
-                     int* error) override;
-  void Close() override;
-};
-
-///////////////////////////////////////////////////////////////////////////////
 // FileStream is a simple implementation of a StreamInterface, which does not
 // support asynchronous notification.
 ///////////////////////////////////////////////////////////////////////////////
@@ -375,8 +327,10 @@
 
   // The semantics of filename and mode are the same as stdio's fopen
   virtual bool Open(const std::string& filename, const char* mode, int* error);
-  virtual bool OpenShare(const std::string& filename, const char* mode,
-                         int shflag, int* error);
+  virtual bool OpenShare(const std::string& filename,
+                         const char* mode,
+                         int shflag,
+                         int* error);
 
   // By default, reads and writes are buffered for efficiency.  Disabling
   // buffering causes writes to block until the bytes on disk are updated.
@@ -465,9 +419,6 @@
 
  protected:
   StreamResult DoReserve(size_t size, int* error) override;
-  // Memory Streams are aligned for efficiency.
-  static const int kAlignment = 16;
-  char* buffer_alloc_;
 };
 
 // ExternalMemoryStream adapts an external memory buffer, so writes which would
@@ -502,14 +453,18 @@
   // is specified in number of bytes.
   // This method doesn't adjust read position nor the number of available
   // bytes, user has to call ConsumeReadData() to do this.
-  StreamResult ReadOffset(void* buffer, size_t bytes, size_t offset,
+  StreamResult ReadOffset(void* buffer,
+                          size_t bytes,
+                          size_t offset,
                           size_t* bytes_read);
 
   // Write |buffer| with an offset from the current write position, offset is
   // specified in number of bytes.
   // This method doesn't adjust the number of buffered bytes, user has to call
   // ConsumeWriteBuffer() to do this.
-  StreamResult WriteOffset(const void* buffer, size_t bytes, size_t offset,
+  StreamResult WriteOffset(const void* buffer,
+                           size_t bytes,
+                           size_t offset,
                            size_t* bytes_written);
 
   // StreamInterface methods
@@ -564,97 +519,6 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
-// StringStream - Reads/Writes to an external std::string
-///////////////////////////////////////////////////////////////////////////////
-
-class StringStream : public StreamInterface {
- public:
-  explicit StringStream(std::string* str);
-  explicit StringStream(const std::string& str);
-
-  StreamState GetState() const override;
-  StreamResult Read(void* buffer,
-                    size_t buffer_len,
-                    size_t* read,
-                    int* error) override;
-  StreamResult Write(const void* data,
-                     size_t data_len,
-                     size_t* written,
-                     int* error) override;
-  void Close() override;
-  bool SetPosition(size_t position) override;
-  bool GetPosition(size_t* position) const override;
-  bool GetSize(size_t* size) const override;
-  bool GetAvailable(size_t* size) const override;
-  bool ReserveSize(size_t size) override;
-
- private:
-  std::string& str_;
-  size_t read_pos_;
-  bool read_only_;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// StreamReference - A reference counting stream adapter
-///////////////////////////////////////////////////////////////////////////////
-
-// Keep in mind that the streams and adapters defined in this file are
-// not thread-safe, so this has limited uses.
-
-// A StreamRefCount holds the reference count and a pointer to the
-// wrapped stream. It deletes the wrapped stream when there are no
-// more references. We can then have multiple StreamReference
-// instances pointing to one StreamRefCount, all wrapping the same
-// stream.
-
-class StreamReference : public StreamAdapterInterface {
-  class StreamRefCount;
- public:
-  // Constructor for the first reference to a stream
-  // Note: get more references through NewReference(). Use this
-  // constructor only once on a given stream.
-  explicit StreamReference(StreamInterface* stream);
-  StreamInterface* GetStream() { return stream(); }
-  StreamInterface* NewReference();
-  ~StreamReference() override;
-
- private:
-  class StreamRefCount {
-   public:
-    explicit StreamRefCount(StreamInterface* stream)
-        : stream_(stream), ref_count_(1) {
-    }
-    void AddReference() {
-      CritScope lock(&cs_);
-      ++ref_count_;
-    }
-    void Release() {
-      int ref_count;
-      {  // Atomic ops would have been a better fit here.
-        CritScope lock(&cs_);
-        ref_count = --ref_count_;
-      }
-      if (ref_count == 0) {
-        delete stream_;
-        delete this;
-      }
-    }
-   private:
-    StreamInterface* stream_;
-    int ref_count_;
-    CriticalSection cs_;
-    RTC_DISALLOW_COPY_AND_ASSIGN(StreamRefCount);
-  };
-
-  // Constructor for adding references
-  explicit StreamReference(StreamRefCount* stream_ref_count,
-                           StreamInterface* stream);
-
-  StreamRefCount* stream_ref_count_;
-  RTC_DISALLOW_COPY_AND_ASSIGN(StreamReference);
-};
-
-///////////////////////////////////////////////////////////////////////////////
 
 // Flow attempts to move bytes from source to sink via buffer of size
 // buffer_len.  The function returns SR_SUCCESS when source reaches
diff --git a/rtc_base/stream_unittest.cc b/rtc_base/stream_unittest.cc
index 8c305c5..11e0be0 100644
--- a/rtc_base/stream_unittest.cc
+++ b/rtc_base/stream_unittest.cc
@@ -19,7 +19,7 @@
 
 class TestStream : public StreamInterface {
  public:
-  TestStream() : pos_(0) { }
+  TestStream() : pos_(0) {}
 
   StreamState GetState() const override { return SS_OPEN; }
 
@@ -53,7 +53,8 @@
   }
 
   bool GetPosition(size_t* position) const override {
-    if (position) *position = pos_;
+    if (position)
+      *position = pos_;
     return true;
   }
 
@@ -65,8 +66,7 @@
   size_t pos_;
 };
 
-bool VerifyTestBuffer(unsigned char* buffer, size_t len,
-                      unsigned char value) {
+bool VerifyTestBuffer(unsigned char* buffer, size_t len, unsigned char value) {
   bool passed = true;
   for (size_t i = 0; i < len; ++i) {
     if (buffer[i] != value++) {
@@ -81,7 +81,7 @@
 
 void SeekTest(StreamInterface* stream, const unsigned char value) {
   size_t bytes;
-  unsigned char buffer[13] = { 0 };
+  unsigned char buffer[13] = {0};
   const size_t kBufSize = sizeof(buffer);
 
   EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, nullptr), SR_SUCCESS);
@@ -176,15 +176,15 @@
   EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, nullptr));
   EXPECT_EQ(kSize / 2, bytes);
   EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 4, &bytes, nullptr));
-  EXPECT_EQ(kSize / 4 , bytes);
+  EXPECT_EQ(kSize / 4, bytes);
   EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
   EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, nullptr));
   EXPECT_EQ(kSize / 2, bytes);
   EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, nullptr));
-  EXPECT_EQ(kSize / 2 , bytes);
+  EXPECT_EQ(kSize / 2, bytes);
   EXPECT_EQ(0, memcmp(in, out, kSize / 2));
   EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, nullptr));
-  EXPECT_EQ(kSize / 2 , bytes);
+  EXPECT_EQ(kSize / 2, bytes);
   EXPECT_EQ(0, memcmp(in, out, kSize / 2));
 
   // Use GetWriteBuffer to reset the read_position for the next tests
diff --git a/rtc_base/string_to_number.cc b/rtc_base/string_to_number.cc
index fe17f34..06ac9e9 100644
--- a/rtc_base/string_to_number.cc
+++ b/rtc_base/string_to_number.cc
@@ -18,7 +18,7 @@
 namespace rtc {
 namespace string_to_number_internal {
 
-rtc::Optional<signed_type> ParseSigned(const char* str, int base) {
+absl::optional<signed_type> ParseSigned(const char* str, int base) {
   RTC_DCHECK(str);
   if (isdigit(str[0]) || str[0] == '-') {
     char* end = nullptr;
@@ -28,10 +28,10 @@
       return value;
     }
   }
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
-rtc::Optional<unsigned_type> ParseUnsigned(const char* str, int base) {
+absl::optional<unsigned_type> ParseUnsigned(const char* str, int base) {
   RTC_DCHECK(str);
   if (isdigit(str[0]) || str[0] == '-') {
     // Explicitly discard negative values. std::strtoull parsing causes unsigned
@@ -45,7 +45,7 @@
       return value;
     }
   }
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
 }  // namespace string_to_number_internal
diff --git a/rtc_base/string_to_number.h b/rtc_base/string_to_number.h
index 4a8fb8f..9b4fa67 100644
--- a/rtc_base/string_to_number.h
+++ b/rtc_base/string_to_number.h
@@ -11,10 +11,10 @@
 #ifndef RTC_BASE_STRING_TO_NUMBER_H_
 #define RTC_BASE_STRING_TO_NUMBER_H_
 
-#include <string>
 #include <limits>
+#include <string>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 
 namespace rtc {
 
@@ -25,8 +25,8 @@
 // are disabled in WebRTC.
 //
 // Integers are parsed using one of the following functions:
-//   rtc::Optional<int-type> StringToNumber(const char* str, int base = 10);
-//   rtc::Optional<int-type> StringToNumber(const std::string& str,
+//   absl::optional<int-type> StringToNumber(const char* str, int base = 10);
+//   absl::optional<int-type> StringToNumber(const std::string& str,
 //                                          int base = 10);
 //
 // These functions parse a value from the beginning of a string into one of the
@@ -44,15 +44,15 @@
 namespace string_to_number_internal {
 // These must be (unsigned) long long, to match the signature of strto(u)ll.
 using unsigned_type = unsigned long long;  // NOLINT(runtime/int)
-using signed_type = long long;  // NOLINT(runtime/int)
+using signed_type = long long;             // NOLINT(runtime/int)
 
-rtc::Optional<signed_type> ParseSigned(const char* str, int base);
-rtc::Optional<unsigned_type> ParseUnsigned(const char* str, int base);
+absl::optional<signed_type> ParseSigned(const char* str, int base);
+absl::optional<unsigned_type> ParseUnsigned(const char* str, int base);
 }  // namespace string_to_number_internal
 
 template <typename T>
 typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value,
-                        rtc::Optional<T>>::type
+                        absl::optional<T>>::type
 StringToNumber(const char* str, int base = 10) {
   using string_to_number_internal::signed_type;
   static_assert(
@@ -61,31 +61,31 @@
           std::numeric_limits<T>::lowest() >=
               std::numeric_limits<signed_type>::lowest(),
       "StringToNumber only supports signed integers as large as long long int");
-  rtc::Optional<signed_type> value =
+  absl::optional<signed_type> value =
       string_to_number_internal::ParseSigned(str, base);
   if (value && *value >= std::numeric_limits<T>::lowest() &&
       *value <= std::numeric_limits<T>::max()) {
     return static_cast<T>(*value);
   }
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
 template <typename T>
 typename std::enable_if<std::is_integral<T>::value &&
                             std::is_unsigned<T>::value,
-                        rtc::Optional<T>>::type
+                        absl::optional<T>>::type
 StringToNumber(const char* str, int base = 10) {
   using string_to_number_internal::unsigned_type;
   static_assert(std::numeric_limits<T>::max() <=
                     std::numeric_limits<unsigned_type>::max(),
                 "StringToNumber only supports unsigned integers as large as "
                 "unsigned long long int");
-  rtc::Optional<unsigned_type> value =
+  absl::optional<unsigned_type> value =
       string_to_number_internal::ParseUnsigned(str, base);
   if (value && *value <= std::numeric_limits<T>::max()) {
     return static_cast<T>(*value);
   }
-  return rtc::nullopt;
+  return absl::nullopt;
 }
 
 // The std::string overloads only exists if there is a matching const char*
diff --git a/rtc_base/string_to_number_unittest.cc b/rtc_base/string_to_number_unittest.cc
index 538ee10..f7bf484 100644
--- a/rtc_base/string_to_number_unittest.cc
+++ b/rtc_base/string_to_number_unittest.cc
@@ -10,9 +10,9 @@
 
 #include "rtc_base/string_to_number.h"
 
+#include <limits>
 #include <string>
 #include <type_traits>
-#include <limits>
 
 #include "rtc_base/gunit.h"
 
@@ -68,10 +68,10 @@
       (min_value == 0) ? "-2" : (std::to_string(min_value) + "1");
   // Make the large value approximately ten times larger than the maximum.
   const std::string too_large_string = std::to_string(max_value) + "1";
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(too_low_string));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(too_low_string.c_str()));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(too_large_string));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(too_large_string.c_str()));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_low_string));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_low_string.c_str()));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_large_string));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(too_large_string.c_str()));
 }
 
 TYPED_TEST_P(BasicNumberTest, TestInvalidInputs) {
@@ -79,18 +79,18 @@
   const char kInvalidCharArray[] = "Invalid string containing 47";
   const char kPlusMinusCharArray[] = "+-100";
   const char kNumberFollowedByCruft[] = "640x480";
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(kInvalidCharArray));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(std::string(kInvalidCharArray)));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(kPlusMinusCharArray));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(std::string(kPlusMinusCharArray)));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(kNumberFollowedByCruft));
-  EXPECT_EQ(rtc::nullopt,
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(kInvalidCharArray));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(std::string(kInvalidCharArray)));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(kPlusMinusCharArray));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(std::string(kPlusMinusCharArray)));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(kNumberFollowedByCruft));
+  EXPECT_EQ(absl::nullopt,
             StringToNumber<T>(std::string(kNumberFollowedByCruft)));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(" 5"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(" - 5"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>("- 5"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>(" -5"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<T>("5 "));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(" 5"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(" - 5"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>("- 5"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>(" -5"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<T>("5 "));
 }
 
 REGISTER_TYPED_TEST_CASE_P(BasicNumberTest,
@@ -105,10 +105,10 @@
                               IntegerTypes);
 
 TEST(StringToNumberTest, TestSpecificValues) {
-  EXPECT_EQ(rtc::nullopt, StringToNumber<uint8_t>("256"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<uint8_t>("-256"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<int8_t>("256"));
-  EXPECT_EQ(rtc::nullopt, StringToNumber<int8_t>("-256"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<uint8_t>("256"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<uint8_t>("-256"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<int8_t>("256"));
+  EXPECT_EQ(absl::nullopt, StringToNumber<int8_t>("-256"));
 }
 
 }  // namespace rtc
diff --git a/rtc_base/stringencode.cc b/rtc_base/stringencode.cc
index f2a1508..8e7c6d7 100644
--- a/rtc_base/stringencode.cc
+++ b/rtc_base/stringencode.cc
@@ -22,8 +22,10 @@
 // String Encoding Utilities
 /////////////////////////////////////////////////////////////////////////////
 
-size_t url_decode(char * buffer, size_t buflen,
-                  const char * source, size_t srclen) {
+size_t url_decode(char* buffer,
+                  size_t buflen,
+                  const char* source,
+                  size_t srclen) {
   if (nullptr == buffer)
     return srclen + 1;
   if (buflen <= 0)
@@ -35,11 +37,9 @@
     unsigned char ch = source[srcpos++];
     if (ch == '+') {
       buffer[bufpos++] = ' ';
-    } else if ((ch == '%')
-               && (srcpos + 1 < srclen)
-               && hex_decode(source[srcpos], &h1)
-               && hex_decode(source[srcpos+1], &h2))
-    {
+    } else if ((ch == '%') && (srcpos + 1 < srclen) &&
+               hex_decode(source[srcpos], &h1) &&
+               hex_decode(source[srcpos + 1], &h2)) {
       buffer[bufpos++] = (h1 << 4) | h2;
       srcpos += 2;
     } else {
@@ -52,7 +52,7 @@
 
 size_t utf8_decode(const char* source, size_t srclen, unsigned long* value) {
   const unsigned char* s = reinterpret_cast<const unsigned char*>(source);
-  if ((s[0] & 0x80) == 0x00) {                    // Check s[0] == 0xxxxxxx
+  if ((s[0] & 0x80) == 0x00) {  // Check s[0] == 0xxxxxxx
     *value = s[0];
     return 1;
   }
@@ -62,7 +62,7 @@
   // Accumulate the trailer byte values in value16, and combine it with the
   // relevant bits from s[0], once we've determined the sequence length.
   unsigned long value16 = (s[1] & 0x3F);
-  if ((s[0] & 0xE0) == 0xC0) {                    // Check s[0] == 110xxxxx
+  if ((s[0] & 0xE0) == 0xC0) {  // Check s[0] == 110xxxxx
     *value = ((s[0] & 0x1F) << 6) | value16;
     return 2;
   }
@@ -70,7 +70,7 @@
     return 0;
   }
   value16 = (value16 << 6) | (s[2] & 0x3F);
-  if ((s[0] & 0xF0) == 0xE0) {                    // Check s[0] == 1110xxxx
+  if ((s[0] & 0xF0) == 0xE0) {  // Check s[0] == 1110xxxx
     *value = ((s[0] & 0x0F) << 12) | value16;
     return 3;
   }
@@ -78,7 +78,7 @@
     return 0;
   }
   value16 = (value16 << 6) | (s[3] & 0x3F);
-  if ((s[0] & 0xF8) == 0xF0) {                    // Check s[0] == 11110xxx
+  if ((s[0] & 0xF8) == 0xF0) {  // Check s[0] == 11110xxx
     *value = ((s[0] & 0x07) << 18) | value16;
     return 4;
   }
@@ -131,13 +131,17 @@
   return true;
 }
 
-size_t hex_encode(char* buffer, size_t buflen,
-                  const char* csource, size_t srclen) {
+size_t hex_encode(char* buffer,
+                  size_t buflen,
+                  const char* csource,
+                  size_t srclen) {
   return hex_encode_with_delimiter(buffer, buflen, csource, srclen, 0);
 }
 
-size_t hex_encode_with_delimiter(char* buffer, size_t buflen,
-                                 const char* csource, size_t srclen,
+size_t hex_encode_with_delimiter(char* buffer,
+                                 size_t buflen,
+                                 const char* csource,
+                                 size_t srclen,
                                  char delimiter) {
   RTC_DCHECK(buffer);  // TODO(kwiberg): estimate output size
   if (buflen == 0)
@@ -153,8 +157,8 @@
 
   while (srcpos < srclen) {
     unsigned char ch = bsource[srcpos++];
-    buffer[bufpos  ] = hex_encode((ch >> 4) & 0xF);
-    buffer[bufpos+1] = hex_encode((ch     ) & 0xF);
+    buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
+    buffer[bufpos + 1] = hex_encode((ch)&0xF);
     bufpos += 2;
 
     // Don't write a delimiter after the last byte.
@@ -177,23 +181,28 @@
   return hex_encode_with_delimiter(source, srclen, 0);
 }
 
-std::string hex_encode_with_delimiter(const char* source, size_t srclen,
+std::string hex_encode_with_delimiter(const char* source,
+                                      size_t srclen,
                                       char delimiter) {
   const size_t kBufferSize = srclen * 3;
   char* buffer = STACK_ARRAY(char, kBufferSize);
-  size_t length = hex_encode_with_delimiter(buffer, kBufferSize,
-                                            source, srclen, delimiter);
+  size_t length =
+      hex_encode_with_delimiter(buffer, kBufferSize, source, srclen, delimiter);
   RTC_DCHECK(srclen == 0 || length > 0);
   return std::string(buffer, length);
 }
 
-size_t hex_decode(char * cbuffer, size_t buflen,
-                  const char * source, size_t srclen) {
+size_t hex_decode(char* cbuffer,
+                  size_t buflen,
+                  const char* source,
+                  size_t srclen) {
   return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
 }
 
-size_t hex_decode_with_delimiter(char* cbuffer, size_t buflen,
-                                 const char* source, size_t srclen,
+size_t hex_decode_with_delimiter(char* cbuffer,
+                                 size_t buflen,
+                                 const char* source,
+                                 size_t srclen,
                                  char delimiter) {
   RTC_DCHECK(cbuffer);  // TODO(kwiberg): estimate output size
   if (buflen == 0)
@@ -234,13 +243,17 @@
 size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
   return hex_decode_with_delimiter(buffer, buflen, source, 0);
 }
-size_t hex_decode_with_delimiter(char* buffer, size_t buflen,
-                                 const std::string& source, char delimiter) {
-  return hex_decode_with_delimiter(buffer, buflen,
-                                   source.c_str(), source.length(), delimiter);
+size_t hex_decode_with_delimiter(char* buffer,
+                                 size_t buflen,
+                                 const std::string& source,
+                                 char delimiter) {
+  return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
+                                   source.length(), delimiter);
 }
 
-size_t transform(std::string& value, size_t maxlen, const std::string& source,
+size_t transform(std::string& value,
+                 size_t maxlen,
+                 const std::string& source,
                  Transform t) {
   char* buffer = STACK_ARRAY(char, maxlen + 1);
   size_t length = t(buffer, maxlen + 1, source.data(), source.length());
@@ -249,15 +262,17 @@
 }
 
 std::string s_transform(const std::string& source, Transform t) {
-  // Ask transformation function to approximate the destination size (returns upper bound)
+  // Ask transformation function to approximate the destination size (returns
+  // upper bound)
   size_t maxlen = t(nullptr, 0, source.data(), source.length());
-  char * buffer = STACK_ARRAY(char, maxlen);
+  char* buffer = STACK_ARRAY(char, maxlen);
   size_t len = t(buffer, maxlen, source.data(), source.length());
   std::string result(buffer, len);
   return result;
 }
 
-size_t tokenize(const std::string& source, char delimiter,
+size_t tokenize(const std::string& source,
+                char delimiter,
                 std::vector<std::string>* fields) {
   fields->clear();
   size_t last = 0;
@@ -290,9 +305,11 @@
   return fields->size();
 }
 
-size_t tokenize_append(const std::string& source, char delimiter,
+size_t tokenize_append(const std::string& source,
+                       char delimiter,
                        std::vector<std::string>* fields) {
-  if (!fields) return 0;
+  if (!fields)
+    return 0;
 
   std::vector<std::string> new_fields;
   tokenize(source, delimiter, &new_fields);
@@ -300,15 +317,20 @@
   return fields->size();
 }
 
-size_t tokenize(const std::string& source, char delimiter, char start_mark,
-                char end_mark, std::vector<std::string>* fields) {
-  if (!fields) return 0;
+size_t tokenize(const std::string& source,
+                char delimiter,
+                char start_mark,
+                char end_mark,
+                std::vector<std::string>* fields) {
+  if (!fields)
+    return 0;
   fields->clear();
 
   std::string remain_source = source;
   while (!remain_source.empty()) {
     size_t start_pos = remain_source.find(start_mark);
-    if (std::string::npos == start_pos) break;
+    if (std::string::npos == start_pos)
+      break;
     std::string pre_mark;
     if (start_pos > 0) {
       pre_mark = remain_source.substr(0, start_pos - 1);
@@ -316,7 +338,8 @@
 
     ++start_pos;
     size_t end_pos = remain_source.find(end_mark, start_pos);
-    if (std::string::npos == end_pos) break;
+    if (std::string::npos == end_pos)
+      break;
 
     // We have found the matching marks. First tokenize the pre-mask. Then add
     // the marked part as a single field. Finally, loop back for the post-mark.
@@ -371,7 +394,8 @@
   return joined_string;
 }
 
-size_t split(const std::string& source, char delimiter,
+size_t split(const std::string& source,
+             char delimiter,
              std::vector<std::string>* fields) {
   RTC_DCHECK(fields);
   fields->clear();
diff --git a/rtc_base/stringencode.h b/rtc_base/stringencode.h
index e5395b7..7042c4a 100644
--- a/rtc_base/stringencode.h
+++ b/rtc_base/stringencode.h
@@ -24,8 +24,10 @@
 //////////////////////////////////////////////////////////////////////
 
 // Note: in-place decoding (buffer == source) is allowed.
-size_t url_decode(char * buffer, size_t buflen,
-                  const char * source, size_t srclen);
+size_t url_decode(char* buffer,
+                  size_t buflen,
+                  const char* source,
+                  size_t srclen);
 
 // Convert an unsigned value from 0 to 15 to the hex character equivalent...
 char hex_encode(unsigned char val);
@@ -33,45 +35,60 @@
 bool hex_decode(char ch, unsigned char* val);
 
 // hex_encode shows the hex representation of binary data in ascii.
-size_t hex_encode(char* buffer, size_t buflen,
-                  const char* source, size_t srclen);
+size_t hex_encode(char* buffer,
+                  size_t buflen,
+                  const char* source,
+                  size_t srclen);
 
 // hex_encode, but separate each byte representation with a delimiter.
 // |delimiter| == 0 means no delimiter
 // If the buffer is too short, we return 0
-size_t hex_encode_with_delimiter(char* buffer, size_t buflen,
-                                 const char* source, size_t srclen,
+size_t hex_encode_with_delimiter(char* buffer,
+                                 size_t buflen,
+                                 const char* source,
+                                 size_t srclen,
                                  char delimiter);
 
 // Helper functions for hex_encode.
 std::string hex_encode(const std::string& str);
 std::string hex_encode(const char* source, size_t srclen);
-std::string hex_encode_with_delimiter(const char* source, size_t srclen,
+std::string hex_encode_with_delimiter(const char* source,
+                                      size_t srclen,
                                       char delimiter);
 
 // hex_decode converts ascii hex to binary.
-size_t hex_decode(char* buffer, size_t buflen,
-                  const char* source, size_t srclen);
+size_t hex_decode(char* buffer,
+                  size_t buflen,
+                  const char* source,
+                  size_t srclen);
 
 // hex_decode, assuming that there is a delimiter between every byte
 // pair.
 // |delimiter| == 0 means no delimiter
 // If the buffer is too short or the data is invalid, we return 0.
-size_t hex_decode_with_delimiter(char* buffer, size_t buflen,
-                                 const char* source, size_t srclen,
+size_t hex_decode_with_delimiter(char* buffer,
+                                 size_t buflen,
+                                 const char* source,
+                                 size_t srclen,
                                  char delimiter);
 
 // Helper functions for hex_decode.
 size_t hex_decode(char* buffer, size_t buflen, const std::string& source);
-size_t hex_decode_with_delimiter(char* buffer, size_t buflen,
-                                 const std::string& source, char delimiter);
+size_t hex_decode_with_delimiter(char* buffer,
+                                 size_t buflen,
+                                 const std::string& source,
+                                 char delimiter);
 
 // Apply any suitable string transform (including the ones above) to an STL
 // string.  Stack-allocated temporary space is used for the transformation,
 // so value and source may refer to the same string.
-typedef size_t (*Transform)(char * buffer, size_t buflen,
-                            const char * source, size_t srclen);
-size_t transform(std::string& value, size_t maxlen, const std::string& source,
+typedef size_t (*Transform)(char* buffer,
+                            size_t buflen,
+                            const char* source,
+                            size_t srclen);
+size_t transform(std::string& value,
+                 size_t maxlen,
+                 const std::string& source,
                  Transform t);
 
 // Return the result of applying transform t to source.
@@ -88,12 +105,14 @@
 
 // Splits the source string into multiple fields separated by delimiter,
 // with duplicates of delimiter creating empty fields.
-size_t split(const std::string& source, char delimiter,
+size_t split(const std::string& source,
+             char delimiter,
              std::vector<std::string>* fields);
 
 // Splits the source string into multiple fields separated by delimiter,
 // with duplicates of delimiter ignored.  Trailing delimiter ignored.
-size_t tokenize(const std::string& source, char delimiter,
+size_t tokenize(const std::string& source,
+                char delimiter,
                 std::vector<std::string>* fields);
 
 // Tokenize, including the empty tokens.
@@ -102,7 +121,8 @@
                                   std::vector<std::string>* fields);
 
 // Tokenize and append the tokens to fields. Return the new size of fields.
-size_t tokenize_append(const std::string& source, char delimiter,
+size_t tokenize_append(const std::string& source,
+                       char delimiter,
                        std::vector<std::string>* fields);
 
 // Splits the source string into multiple fields separated by delimiter, with
@@ -112,8 +132,11 @@
 // \"/Library/Application Support/media content.txt\"", delimiter is ' ', and
 // the start_mark and end_mark are '"', this method returns two fields:
 // "filename" and "/Library/Application Support/media content.txt".
-size_t tokenize(const std::string& source, char delimiter, char start_mark,
-                char end_mark, std::vector<std::string>* fields);
+size_t tokenize(const std::string& source,
+                char delimiter,
+                char start_mark,
+                char end_mark,
+                std::vector<std::string>* fields);
 
 // Extract the first token from source as separated by delimiter, with
 // duplicates of delimiter ignored. Return false if the delimiter could not be
@@ -126,7 +149,7 @@
 // Convert arbitrary values to/from a string.
 
 template <class T>
-static bool ToString(const T &t, std::string* s) {
+static bool ToString(const T& t, std::string* s) {
   RTC_DCHECK(s);
   std::ostringstream oss;
   oss << std::boolalpha << t;
@@ -144,19 +167,25 @@
 
 // Inline versions of the string conversion routines.
 
-template<typename T>
+template <typename T>
 static inline std::string ToString(const T& val) {
-  std::string str; ToString(val, &str); return str;
+  std::string str;
+  ToString(val, &str);
+  return str;
 }
 
-template<typename T>
+template <typename T>
 static inline T FromString(const std::string& str) {
-  T val; FromString(str, &val); return val;
+  T val;
+  FromString(str, &val);
+  return val;
 }
 
-template<typename T>
+template <typename T>
 static inline T FromString(const T& defaultValue, const std::string& str) {
-  T val(defaultValue); FromString(str, &val); return val;
+  T val(defaultValue);
+  FromString(str, &val);
+  return val;
 }
 
 //////////////////////////////////////////////////////////////////////
diff --git a/rtc_base/stringencode_unittest.cc b/rtc_base/stringencode_unittest.cc
index 63d8290..ffb90b2 100644
--- a/rtc_base/stringencode_unittest.cc
+++ b/rtc_base/stringencode_unittest.cc
@@ -43,23 +43,23 @@
 
 // Test that we can convert to/from hex with a colon delimiter.
 TEST_F(HexEncodeTest, TestWithDelimiter) {
-  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_),
-                                       data_, sizeof(data_), ':');
+  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_), data_,
+                                       sizeof(data_), ':');
   ASSERT_EQ(sizeof(data_) * 3 - 1, enc_res_);
   ASSERT_STREQ("80:81:82:83:84:85:86:87:88:89", encoded_);
-  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_),
-                                       encoded_, enc_res_, ':');
+  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), encoded_,
+                                       enc_res_, ':');
   ASSERT_EQ(sizeof(data_), dec_res_);
   ASSERT_EQ(0, memcmp(data_, decoded_, dec_res_));
 }
 
 // Test that encoding with one delimiter and decoding with another fails.
 TEST_F(HexEncodeTest, TestWithWrongDelimiter) {
-  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_),
-                                       data_, sizeof(data_), ':');
+  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_), data_,
+                                       sizeof(data_), ':');
   ASSERT_EQ(sizeof(data_) * 3 - 1, enc_res_);
-  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_),
-                                       encoded_, enc_res_, '/');
+  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), encoded_,
+                                       enc_res_, '/');
   ASSERT_EQ(0U, dec_res_);
 }
 
@@ -67,15 +67,15 @@
 TEST_F(HexEncodeTest, TestExpectedDelimiter) {
   enc_res_ = hex_encode(encoded_, sizeof(encoded_), data_, sizeof(data_));
   ASSERT_EQ(sizeof(data_) * 2, enc_res_);
-  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_),
-                                       encoded_, enc_res_, ':');
+  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), encoded_,
+                                       enc_res_, ':');
   ASSERT_EQ(0U, dec_res_);
 }
 
 // Test that encoding with a delimiter and decoding without one fails.
 TEST_F(HexEncodeTest, TestExpectedNoDelimiter) {
-  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_),
-                                       data_, sizeof(data_), ':');
+  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_), data_,
+                                       sizeof(data_), ':');
   ASSERT_EQ(sizeof(data_) * 3 - 1, enc_res_);
   dec_res_ = hex_decode(decoded_, sizeof(decoded_), encoded_, enc_res_);
   ASSERT_EQ(0U, dec_res_);
@@ -93,8 +93,8 @@
 TEST_F(HexEncodeTest, TestZeroLengthWithDelimiter) {
   enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(encoded_), "", 0, ':');
   ASSERT_EQ(0U, enc_res_);
-  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_),
-                                       encoded_, enc_res_, ':');
+  dec_res_ = hex_decode_with_delimiter(decoded_, sizeof(decoded_), encoded_,
+                                       enc_res_, ':');
   ASSERT_EQ(0U, dec_res_);
 }
 
@@ -118,15 +118,15 @@
 
 // Test that encoding into a too-small output buffer (without delimiter) fails.
 TEST_F(HexEncodeTest, TestEncodeTooShort) {
-  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(data_) * 2,
-                                       data_, sizeof(data_), 0);
+  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(data_) * 2, data_,
+                                       sizeof(data_), 0);
   ASSERT_EQ(0U, enc_res_);
 }
 
 // Test that encoding into a too-small output buffer (with delimiter) fails.
 TEST_F(HexEncodeTest, TestEncodeWithDelimiterTooShort) {
-  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(data_) * 3 - 1,
-                                       data_, sizeof(data_), ':');
+  enc_res_ = hex_encode_with_delimiter(encoded_, sizeof(data_) * 3 - 1, data_,
+                                       sizeof(data_), ':');
   ASSERT_EQ(0U, enc_res_);
 }
 
diff --git a/rtc_base/stringize_macros_unittest.cc b/rtc_base/stringize_macros_unittest.cc
index d1dea5e..78e6b55 100644
--- a/rtc_base/stringize_macros_unittest.cc
+++ b/rtc_base/stringize_macros_unittest.cc
@@ -18,15 +18,12 @@
 #define PREPROCESSOR_UTIL_UNITTEST_C "foo"
 
 TEST(StringizeTest, Ansi) {
-  EXPECT_STREQ(
-      "PREPROCESSOR_UTIL_UNITTEST_A",
-      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A));
-  EXPECT_STREQ(
-      "PREPROCESSOR_UTIL_UNITTEST_B(y)",
-      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y)));
-  EXPECT_STREQ(
-      "PREPROCESSOR_UTIL_UNITTEST_C",
-      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C));
+  EXPECT_STREQ("PREPROCESSOR_UTIL_UNITTEST_A",
+               STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ("PREPROCESSOR_UTIL_UNITTEST_B(y)",
+               STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ("PREPROCESSOR_UTIL_UNITTEST_C",
+               STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C));
 
   EXPECT_STREQ("FOO", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A));
   EXPECT_STREQ("myobj->FunctionCall(y)",
diff --git a/rtc_base/strings/audio_format_to_string.cc b/rtc_base/strings/audio_format_to_string.cc
index 2d0b53b..a149344 100644
--- a/rtc_base/strings/audio_format_to_string.cc
+++ b/rtc_base/strings/audio_format_to_string.cc
@@ -13,40 +13,40 @@
 #include "rtc_base/strings/string_builder.h"
 
 namespace rtc {
-  std::string ToString(const webrtc::SdpAudioFormat& saf) {
-    char sb_buf[1024];
-    rtc::SimpleStringBuilder sb(sb_buf);
-    sb << "{name: " << saf.name;
-    sb << ", clockrate_hz: " << saf.clockrate_hz;
-    sb << ", num_channels: " << saf.num_channels;
-    sb << ", parameters: {";
-    const char* sep = "";
-    for (const auto& kv : saf.parameters) {
-      sb << sep << kv.first << ": " << kv.second;
-      sep = ", ";
-    }
-    sb << "}}";
-    return sb.str();
+std::string ToString(const webrtc::SdpAudioFormat& saf) {
+  char sb_buf[1024];
+  rtc::SimpleStringBuilder sb(sb_buf);
+  sb << "{name: " << saf.name;
+  sb << ", clockrate_hz: " << saf.clockrate_hz;
+  sb << ", num_channels: " << saf.num_channels;
+  sb << ", parameters: {";
+  const char* sep = "";
+  for (const auto& kv : saf.parameters) {
+    sb << sep << kv.first << ": " << kv.second;
+    sep = ", ";
   }
-  std::string ToString(const webrtc::AudioCodecInfo& aci) {
-    char sb_buf[1024];
-    rtc::SimpleStringBuilder sb(sb_buf);
-    sb << "{sample_rate_hz: " << aci.sample_rate_hz;
-    sb << ", num_channels: " << aci.num_channels;
-    sb << ", default_bitrate_bps: " << aci.default_bitrate_bps;
-    sb << ", min_bitrate_bps: " << aci.min_bitrate_bps;
-    sb << ", max_bitrate_bps: " << aci.max_bitrate_bps;
-    sb << ", allow_comfort_noise: " << aci.allow_comfort_noise;
-    sb << ", supports_network_adaption: " << aci.supports_network_adaption;
-    sb << "}";
-    return sb.str();
-  }
-  std::string ToString(const webrtc::AudioCodecSpec& acs) {
-    char sb_buf[1024];
-    rtc::SimpleStringBuilder sb(sb_buf);
-    sb << "{format: " << ToString(acs.format);
-    sb << ", info: " << ToString(acs.info);
-    sb << "}";
-    return sb.str();
-  }
+  sb << "}}";
+  return sb.str();
+}
+std::string ToString(const webrtc::AudioCodecInfo& aci) {
+  char sb_buf[1024];
+  rtc::SimpleStringBuilder sb(sb_buf);
+  sb << "{sample_rate_hz: " << aci.sample_rate_hz;
+  sb << ", num_channels: " << aci.num_channels;
+  sb << ", default_bitrate_bps: " << aci.default_bitrate_bps;
+  sb << ", min_bitrate_bps: " << aci.min_bitrate_bps;
+  sb << ", max_bitrate_bps: " << aci.max_bitrate_bps;
+  sb << ", allow_comfort_noise: " << aci.allow_comfort_noise;
+  sb << ", supports_network_adaption: " << aci.supports_network_adaption;
+  sb << "}";
+  return sb.str();
+}
+std::string ToString(const webrtc::AudioCodecSpec& acs) {
+  char sb_buf[1024];
+  rtc::SimpleStringBuilder sb(sb_buf);
+  sb << "{format: " << ToString(acs.format);
+  sb << ", info: " << ToString(acs.info);
+  sb << "}";
+  return sb.str();
+}
 }  // namespace rtc
diff --git a/rtc_base/strings/audio_format_to_string.h b/rtc_base/strings/audio_format_to_string.h
index de0ce16..6a4535c 100644
--- a/rtc_base/strings/audio_format_to_string.h
+++ b/rtc_base/strings/audio_format_to_string.h
@@ -16,9 +16,9 @@
 #include "api/audio_codecs/audio_format.h"
 
 namespace rtc {
-  std::string ToString(const webrtc::SdpAudioFormat& saf);
-  std::string ToString(const webrtc::AudioCodecInfo& saf);
-  std::string ToString(const webrtc::AudioCodecSpec& acs);
+std::string ToString(const webrtc::SdpAudioFormat& saf);
+std::string ToString(const webrtc::AudioCodecInfo& saf);
+std::string ToString(const webrtc::AudioCodecSpec& acs);
 }  // namespace rtc
 
 #endif  // RTC_BASE_STRINGS_AUDIO_FORMAT_TO_STRING_H_
diff --git a/rtc_base/strings/string_builder.h b/rtc_base/strings/string_builder.h
index d095385..093954b 100644
--- a/rtc_base/strings/string_builder.h
+++ b/rtc_base/strings/string_builder.h
@@ -55,7 +55,7 @@
   // compatibility reasons.
   size_t size() const { return size_; }
 
-  // Allows appending a printf style formatted string.
+// Allows appending a printf style formatted string.
 #if defined(__GNUC__)
   __attribute__((__format__(__printf__, 2, 3)))
 #endif
diff --git a/rtc_base/stringutils.cc b/rtc_base/stringutils.cc
index 7664bb8..bef128c 100644
--- a/rtc_base/stringutils.cc
+++ b/rtc_base/stringutils.cc
@@ -10,8 +10,8 @@
 #include <algorithm>
 #include <cstdio>
 
-#include "rtc_base/stringutils.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/stringutils.h"
 
 namespace rtc {
 
@@ -33,8 +33,8 @@
         return true;
       }
       while (*target) {
-        if ((toupper(*pattern) == toupper(*target))
-            && string_match(target + 1, pattern + 1)) {
+        if ((toupper(*pattern) == toupper(*target)) &&
+            string_match(target + 1, pattern + 1)) {
           return true;
         }
         ++target;
@@ -52,25 +52,32 @@
 }
 
 #if defined(WEBRTC_WIN)
-int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
+int ascii_string_compare(const wchar_t* s1,
+                         const char* s2,
+                         size_t n,
                          CharacterTransformation transformation) {
   wchar_t c1, c2;
   while (true) {
-    if (n-- == 0) return 0;
+    if (n-- == 0)
+      return 0;
     c1 = transformation(*s1);
     // Double check that characters are not UTF-8
     RTC_DCHECK_LT(*s2, 128);
     // Note: *s2 gets implicitly promoted to wchar_t
     c2 = transformation(*s2);
-    if (c1 != c2) return (c1 < c2) ? -1 : 1;
-    if (!c1) return 0;
+    if (c1 != c2)
+      return (c1 < c2) ? -1 : 1;
+    if (!c1)
+      return 0;
     ++s1;
     ++s2;
   }
 }
 
-size_t asccpyn(wchar_t* buffer, size_t buflen,
-               const char* source, size_t srclen) {
+size_t asccpyn(wchar_t* buffer,
+               size_t buflen,
+               const char* source,
+               size_t srclen) {
   if (buflen <= 0)
     return 0;
 
@@ -91,11 +98,11 @@
 
 #endif  // WEBRTC_WIN
 
-void replace_substrs(const char *search,
+void replace_substrs(const char* search,
                      size_t search_len,
-                     const char *replace,
+                     const char* replace,
                      size_t replace_len,
-                     std::string *s) {
+                     std::string* s) {
   size_t pos = 0;
   while ((pos = s->find(search, pos, search_len)) != std::string::npos) {
     s->replace(pos, search_len, replace, replace_len);
@@ -103,11 +110,11 @@
   }
 }
 
-bool starts_with(const char *s1, const char *s2) {
+bool starts_with(const char* s1, const char* s2) {
   return strncmp(s1, s2, strlen(s2)) == 0;
 }
 
-bool ends_with(const char *s1, const char *s2) {
+bool ends_with(const char* s1, const char* s2) {
   size_t s1_length = strlen(s1);
   size_t s2_length = strlen(s2);
 
@@ -123,7 +130,7 @@
 
 std::string string_trim(const std::string& s) {
   std::string::size_type first = s.find_first_not_of(kWhitespace);
-  std::string::size_type last  = s.find_last_not_of(kWhitespace);
+  std::string::size_type last = s.find_last_not_of(kWhitespace);
 
   if (first == std::string::npos || last == std::string::npos) {
     return std::string("");
diff --git a/rtc_base/stringutils.h b/rtc_base/stringutils.h
index b42cfa5..d92ba02 100644
--- a/rtc_base/stringutils.h
+++ b/rtc_base/stringutils.h
@@ -37,7 +37,8 @@
 // Generic string/memory utilities
 ///////////////////////////////////////////////////////////////////////////////
 
-#define STACK_ARRAY(TYPE, LEN) static_cast<TYPE*>(::alloca((LEN)*sizeof(TYPE)))
+#define STACK_ARRAY(TYPE, LEN) \
+  static_cast<TYPE*>(::alloca((LEN) * sizeof(TYPE)))
 
 namespace rtc {
 
@@ -88,7 +89,7 @@
 
 const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
 
-template<class CTYPE>
+template <class CTYPE>
 struct Traits {
   // STL string type
   // typedef XXX string;
@@ -105,10 +106,10 @@
   return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str());
 }
 
-template<class CTYPE>
+template <class CTYPE>
 const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) {
-  for (size_t i=0; str[i]; ++i) {
-    for (size_t j=0; chs[j]; ++j) {
+  for (size_t i = 0; str[i]; ++i) {
+    for (size_t j = 0; chs[j]; ++j) {
       if (str[i] == chs[j]) {
         return str + i;
       }
@@ -117,9 +118,9 @@
   return 0;
 }
 
-template<class CTYPE>
+template <class CTYPE>
 const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) {
-  for (size_t i=0; i < slen && str[i]; ++i) {
+  for (size_t i = 0; i < slen && str[i]; ++i) {
     if (str[i] == ch) {
       return str + i;
     }
@@ -127,7 +128,7 @@
   return 0;
 }
 
-template<class CTYPE>
+template <class CTYPE>
 size_t strlenn(const CTYPE* buffer, size_t buflen) {
   size_t bufpos = 0;
   while (buffer[bufpos] && (bufpos < buflen)) {
@@ -139,9 +140,11 @@
 // Safe versions of strncpy, strncat, snprintf and vsnprintf that always
 // null-terminate.
 
-template<class CTYPE>
-size_t strcpyn(CTYPE* buffer, size_t buflen,
-               const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
+template <class CTYPE>
+size_t strcpyn(CTYPE* buffer,
+               size_t buflen,
+               const CTYPE* source,
+               size_t srclen = SIZE_UNKNOWN) {
   if (buflen <= 0)
     return 0;
 
@@ -155,9 +158,11 @@
   return srclen;
 }
 
-template<class CTYPE>
-size_t strcatn(CTYPE* buffer, size_t buflen,
-               const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
+template <class CTYPE>
+size_t strcatn(CTYPE* buffer,
+               size_t buflen,
+               const CTYPE* source,
+               size_t srclen = SIZE_UNKNOWN) {
   if (buflen <= 0)
     return 0;
 
@@ -167,8 +172,10 @@
 
 // Some compilers (clang specifically) require vsprintfn be defined before
 // sprintfn.
-template<class CTYPE>
-size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format,
+template <class CTYPE>
+size_t vsprintfn(CTYPE* buffer,
+                 size_t buflen,
+                 const CTYPE* format,
                  va_list args) {
   int len = vsnprintf(buffer, buflen, format, args);
   if ((len < 0) || (static_cast<size_t>(len) >= buflen)) {
@@ -178,9 +185,9 @@
   return len;
 }
 
-template<class CTYPE>
+template <class CTYPE>
 size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...);
-template<class CTYPE>
+template <class CTYPE>
 size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) {
   va_list args;
   va_start(args, format);
@@ -206,16 +213,22 @@
 inline int ascnicmp(const char* s1, const char* s2, size_t n) {
   return _strnicmp(s1, s2, n);
 }
-inline size_t asccpyn(char* buffer, size_t buflen,
-                      const char* source, size_t srclen = SIZE_UNKNOWN) {
+inline size_t asccpyn(char* buffer,
+                      size_t buflen,
+                      const char* source,
+                      size_t srclen = SIZE_UNKNOWN) {
   return strcpyn(buffer, buflen, source, srclen);
 }
 
 #if defined(WEBRTC_WIN)
 
-typedef wchar_t(*CharacterTransformation)(wchar_t);
-inline wchar_t identity(wchar_t c) { return c; }
-int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
+typedef wchar_t (*CharacterTransformation)(wchar_t);
+inline wchar_t identity(wchar_t c) {
+  return c;
+}
+int ascii_string_compare(const wchar_t* s1,
+                         const char* s2,
+                         size_t n,
                          CharacterTransformation transformation);
 
 inline int asccmp(const wchar_t* s1, const char* s2) {
@@ -230,8 +243,10 @@
 inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) {
   return ascii_string_compare(s1, s2, n, tolowercase);
 }
-size_t asccpyn(wchar_t* buffer, size_t buflen,
-               const char* source, size_t srclen = SIZE_UNKNOWN);
+size_t asccpyn(wchar_t* buffer,
+               size_t buflen,
+               const char* source,
+               size_t srclen = SIZE_UNKNOWN);
 
 #endif  // WEBRTC_WIN
 
@@ -239,7 +254,7 @@
 // Traits<char> specializations
 ///////////////////////////////////////////////////////////////////////////////
 
-template<>
+template <>
 struct Traits<char> {
   typedef std::string string;
   inline static const char* empty_str() { return ""; }
@@ -251,7 +266,7 @@
 
 #if defined(WEBRTC_WIN)
 
-template<>
+template <>
 struct Traits<wchar_t> {
   typedef std::wstring string;
   inline static const wchar_t* empty_str() { return L""; }
@@ -297,17 +312,17 @@
 #endif  // WEBRTC_WIN
 
 // Replaces all occurrences of "search" with "replace".
-void replace_substrs(const char *search,
+void replace_substrs(const char* search,
                      size_t search_len,
-                     const char *replace,
+                     const char* replace,
                      size_t replace_len,
-                     std::string *s);
+                     std::string* s);
 
 // True iff s1 starts with s2.
-bool starts_with(const char *s1, const char *s2);
+bool starts_with(const char* s1, const char* s2);
 
 // True iff s1 ends with s2.
-bool ends_with(const char *s1, const char *s2);
+bool ends_with(const char* s1, const char* s2);
 
 // Remove leading and trailing whitespaces.
 std::string string_trim(const std::string& s);
diff --git a/rtc_base/stringutils_unittest.cc b/rtc_base/stringutils_unittest.cc
index bb0e7b5..a6e6468 100644
--- a/rtc_base/stringutils_unittest.cc
+++ b/rtc_base/stringutils_unittest.cc
@@ -18,10 +18,10 @@
 TEST(string_matchTest, Matches) {
   EXPECT_TRUE(string_match("A.B.C.D", "a.b.c.d"));
   EXPECT_TRUE(string_match("www.TEST.GOOGLE.COM", "www.*.com"));
-  EXPECT_TRUE(string_match("127.0.0.1",  "12*.0.*1"));
+  EXPECT_TRUE(string_match("127.0.0.1", "12*.0.*1"));
   EXPECT_TRUE(string_match("127.1.0.21", "12*.0.*1"));
-  EXPECT_FALSE(string_match("127.0.0.0",  "12*.0.*1"));
-  EXPECT_FALSE(string_match("127.0.0.0",  "12*.0.*1"));
+  EXPECT_FALSE(string_match("127.0.0.0", "12*.0.*1"));
+  EXPECT_FALSE(string_match("127.0.0.0", "12*.0.*1"));
   EXPECT_FALSE(string_match("127.1.1.21", "12*.0.*1"));
 }
 
diff --git a/rtc_base/system/BUILD.gn b/rtc_base/system/BUILD.gn
index a3dc4c1..9d3fa2c 100644
--- a/rtc_base/system/BUILD.gn
+++ b/rtc_base/system/BUILD.gn
@@ -12,6 +12,12 @@
   import("//build/config/android/rules.gni")
 }
 
+rtc_source_set("arch") {
+  sources = [
+    "arch.h",
+  ]
+}
+
 rtc_source_set("asm_defines") {
   sources = [
     "asm_defines.h",
@@ -36,3 +42,21 @@
     "../..:webrtc_common",
   ]
 }
+
+rtc_source_set("ignore_warnings") {
+  sources = [
+    "ignore_warnings.h",
+  ]
+}
+
+rtc_source_set("inline") {
+  sources = [
+    "inline.h",
+  ]
+}
+
+rtc_source_set("unused") {
+  sources = [
+    "unused.h",
+  ]
+}
diff --git a/rtc_base/system/arch.h b/rtc_base/system/arch.h
new file mode 100644
index 0000000..a2a1180
--- /dev/null
+++ b/rtc_base/system/arch.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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.
+ */
+
+// This file contains platform-specific typedefs and defines.
+// Much of it is derived from Chromium's build/build_config.h.
+
+#ifndef RTC_BASE_SYSTEM_ARCH_H_
+#define RTC_BASE_SYSTEM_ARCH_H_
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+//   or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define WEBRTC_ARCH_X86_FAMILY
+#define WEBRTC_ARCH_X86_64
+#define WEBRTC_ARCH_64_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__aarch64__)
+#define WEBRTC_ARCH_ARM_FAMILY
+#define WEBRTC_ARCH_64_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(_M_IX86) || defined(__i386__)
+#define WEBRTC_ARCH_X86_FAMILY
+#define WEBRTC_ARCH_X86
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__ARMEL__)
+#define WEBRTC_ARCH_ARM_FAMILY
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__MIPSEL__)
+#define WEBRTC_ARCH_MIPS_FAMILY
+#if defined(__LP64__)
+#define WEBRTC_ARCH_64_BITS
+#else
+#define WEBRTC_ARCH_32_BITS
+#endif
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__pnacl__)
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#else
+#error Please add support for your architecture in typedefs.h
+#endif
+
+#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
+#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
+#endif
+
+#endif  // RTC_BASE_SYSTEM_ARCH_H_
diff --git a/rtc_base/system/asm_defines.h b/rtc_base/system/asm_defines.h
index e1c7453..a7f6aad 100644
--- a/rtc_base/system/asm_defines.h
+++ b/rtc_base/system/asm_defines.h
@@ -11,6 +11,10 @@
 #ifndef RTC_BASE_SYSTEM_ASM_DEFINES_H_
 #define RTC_BASE_SYSTEM_ASM_DEFINES_H_
 
+// clang-format off
+// clang formatting breaks everything here, e.g. concatenating directives,
+// due to absence of context via asm keyword.
+
 #if defined(__linux__) && defined(__ELF__)
 .section .note.GNU-stack,"",%progbits
 #endif
@@ -63,4 +67,6 @@
 
 .text
 
+// clang-format on
+
 #endif  // RTC_BASE_SYSTEM_ASM_DEFINES_H_
diff --git a/rtc_base/system/ignore_warnings.h b/rtc_base/system/ignore_warnings.h
new file mode 100644
index 0000000..e891c50
--- /dev/null
+++ b/rtc_base/system/ignore_warnings.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
+#define RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
+
+#ifdef __clang__
+#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \
+  _Pragma("clang diagnostic push")             \
+      _Pragma("clang diagnostic ignored \"-Wframe-larger-than=\"")
+#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("clang diagnostic pop")
+#elif __GNUC__
+#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \
+  _Pragma("GCC diagnostic push")               \
+      _Pragma("GCC diagnostic ignored \"-Wframe-larger-than=\"")
+#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("GCC diagnostic pop")
+#else
+#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
+#define RTC_POP_IGNORING_WFRAME_LARGER_THAN()
+#endif
+
+#endif  // RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
diff --git a/rtc_base/system/inline.h b/rtc_base/system/inline.h
new file mode 100644
index 0000000..f585d34
--- /dev/null
+++ b/rtc_base/system/inline.h
@@ -0,0 +1,31 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 RTC_BASE_SYSTEM_INLINE_H_
+#define RTC_BASE_SYSTEM_INLINE_H_
+
+#if defined(_MSC_VER)
+
+#define RTC_FORCE_INLINE __forceinline
+#define RTC_NO_INLINE __declspec(noinline)
+
+#elif defined(__GNUC__)
+
+#define RTC_FORCE_INLINE __attribute__((__always_inline__))
+#define RTC_NO_INLINE __attribute__((__noinline__))
+
+#else
+
+#define RTC_FORCE_INLINE
+#define RTC_NO_INLINE
+
+#endif
+
+#endif  // RTC_BASE_SYSTEM_INLINE_H_
diff --git a/rtc_base/system/unused.h b/rtc_base/system/unused.h
new file mode 100644
index 0000000..a0add4e
--- /dev/null
+++ b/rtc_base/system/unused.h
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2018 The WebRTC 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 RTC_BASE_SYSTEM_UNUSED_H_
+#define RTC_BASE_SYSTEM_UNUSED_H_
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() RTC_WARN_UNUSED_RESULT;
+// To explicitly ignore a result, cast to void.
+// TODO(kwiberg): Remove when we can use [[nodiscard]] from C++17.
+#if defined(__clang__)
+#define RTC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+#elif defined(__GNUC__)
+// gcc has a __warn_unused_result__ attribute, but you can't quiet it by
+// casting to void, so we don't use it.
+#define RTC_WARN_UNUSED_RESULT
+#else
+#define RTC_WARN_UNUSED_RESULT
+#endif
+
+// Prevent the compiler from warning about an unused variable. For example:
+//   int result = DoSomething();
+//   assert(result == 17);
+//   RTC_UNUSED(result);
+// Note: In most cases it is better to remove the unused variable rather than
+// suppressing the compiler warning.
+#ifndef RTC_UNUSED
+#define RTC_UNUSED(x) static_cast<void>(x)
+#endif  // RTC_UNUSED
+
+#endif  // RTC_BASE_SYSTEM_UNUSED_H_
diff --git a/rtc_base/task_queue.h b/rtc_base/task_queue.h
index 41d6a10..b8b307c 100644
--- a/rtc_base/task_queue.h
+++ b/rtc_base/task_queue.h
@@ -15,8 +15,8 @@
 #include <type_traits>
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/constructormagic.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/scoped_ref_ptr.h"
 #include "rtc_base/thread_annotations.h"
 
@@ -79,13 +79,14 @@
 // based parameters.
 template <class Closure>
 static std::unique_ptr<QueuedTask> NewClosure(Closure&& closure) {
-  return rtc::MakeUnique<ClosureTask<Closure>>(std::forward<Closure>(closure));
+  return absl::make_unique<ClosureTask<Closure>>(
+      std::forward<Closure>(closure));
 }
 
 template <class Closure, class Cleanup>
 static std::unique_ptr<QueuedTask> NewClosure(Closure&& closure,
                                               Cleanup&& cleanup) {
-  return rtc::MakeUnique<ClosureTaskWithCleanup<Closure, Cleanup>>(
+  return absl::make_unique<ClosureTaskWithCleanup<Closure, Cleanup>>(
       std::forward<Closure>(closure), std::forward<Cleanup>(cleanup));
 }
 
diff --git a/rtc_base/task_queue_gcd.cc b/rtc_base/task_queue_gcd.cc
index a13e088..c7731dd 100644
--- a/rtc_base/task_queue_gcd.cc
+++ b/rtc_base/task_queue_gcd.cc
@@ -39,7 +39,7 @@
       return DISPATCH_QUEUE_PRIORITY_LOW;
   }
 }
-}
+}  // namespace
 
 using internal::GetQueuePtrTls;
 using internal::AutoSetCurrentQueuePtr;
diff --git a/rtc_base/task_queue_unittest.cc b/rtc_base/task_queue_unittest.cc
index 51956d2..cdf0d59 100644
--- a/rtc_base/task_queue_unittest.cc
+++ b/rtc_base/task_queue_unittest.cc
@@ -166,8 +166,7 @@
   std::vector<std::unique_ptr<Event>> events;
   for (int i = 0; i < 100; ++i) {
     events.push_back(std::unique_ptr<Event>(new Event(false, false)));
-    queue.PostDelayedTask(
-        Bind(&CheckCurrent, events.back().get(), &queue), i);
+    queue.PostDelayedTask(Bind(&CheckCurrent, events.back().get(), &queue), i);
   }
 
   for (const auto& e : events)
@@ -191,9 +190,9 @@
   TaskQueue post_queue(kPostQueue);
   TaskQueue reply_queue(kReplyQueue);
 
-  post_queue.PostTaskAndReply(
-      Bind(&CheckCurrent, nullptr, &post_queue),
-      Bind(&CheckCurrent, &event, &reply_queue), &reply_queue);
+  post_queue.PostTaskAndReply(Bind(&CheckCurrent, nullptr, &post_queue),
+                              Bind(&CheckCurrent, &event, &reply_queue),
+                              &reply_queue);
   EXPECT_TRUE(event.Wait(1000));
 }
 
@@ -372,12 +371,10 @@
   EXPECT_TRUE(event.Wait(1000));
 }
 
-void TestPostTaskAndReply(TaskQueue* work_queue,
-                          Event* event) {
+void TestPostTaskAndReply(TaskQueue* work_queue, Event* event) {
   ASSERT_FALSE(work_queue->IsCurrent());
-  work_queue->PostTaskAndReply(
-      Bind(&CheckCurrent, nullptr, work_queue),
-      NewClosure([event]() { event->Set(); }));
+  work_queue->PostTaskAndReply(Bind(&CheckCurrent, nullptr, work_queue),
+                               NewClosure([event]() { event->Set(); }));
 }
 
 // Does a PostTaskAndReply from within a task to post and reply to the current
@@ -389,8 +386,7 @@
   TaskQueue queue(kQueueName);
   TaskQueue work_queue(kWorkQueueName);
 
-  queue.PostTask(
-      Bind(&TestPostTaskAndReply, &work_queue, &event));
+  queue.PostTask(Bind(&TestPostTaskAndReply, &work_queue, &event));
   EXPECT_TRUE(event.Wait(1000));
 }
 
diff --git a/rtc_base/task_queue_win.cc b/rtc_base/task_queue_win.cc
index cbf86a6..c1e7c46 100644
--- a/rtc_base/task_queue_win.cc
+++ b/rtc_base/task_queue_win.cc
@@ -10,14 +10,17 @@
 
 #include "rtc_base/task_queue.h"
 
+// clang-format off
+// clang formating would change include order.
+
 // Include winsock2.h before including <windows.h> to maintain consistency with
-// win32.h.  We can't include win32.h directly here since it pulls in
-// headers such as basictypes.h which causes problems in Chromium where webrtc
-// exists as two separate projects, webrtc and libjingle.
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
 #include <winsock2.h>
 #include <windows.h>
-#include <sal.h>  // Must come after windows headers.
+#include <sal.h>       // Must come after windows headers.
 #include <mmsystem.h>  // Must come after windows headers.
+// clang-format on
 #include <string.h>
 
 #include <algorithm>
@@ -360,7 +363,7 @@
 }
 
 void TaskQueue::Impl::ThreadState::RunThreadMain() {
-  HANDLE handles[2] = { *timer_.event_for_wait(), in_queue_ };
+  HANDLE handles[2] = {*timer_.event_for_wait(), in_queue_};
   while (true) {
     // Make sure we do an alertable wait as that's required to allow APCs to run
     // (e.g. required for InitializeQueueThread and stopping the thread in
@@ -374,8 +377,9 @@
         break;
     }
 
-    if (result == WAIT_OBJECT_0 || (!timer_tasks_.empty() &&
-        ::WaitForSingleObject(*timer_.event_for_wait(), 0) == WAIT_OBJECT_0)) {
+    if (result == WAIT_OBJECT_0 ||
+        (!timer_tasks_.empty() &&
+         ::WaitForSingleObject(*timer_.event_for_wait(), 0) == WAIT_OBJECT_0)) {
       // The multimedia timer was signaled.
       timer_.Cancel();
       RunDueTasks();
diff --git a/rtc_base/template_util.h b/rtc_base/template_util.h
index 04e5e37..3c04a86 100644
--- a/rtc_base/template_util.h
+++ b/rtc_base/template_util.h
@@ -19,34 +19,47 @@
 
 // Template definitions from tr1.
 
-template<class T, T v>
+template <class T, T v>
 struct integral_constant {
   static const T value = v;
   typedef T value_type;
   typedef integral_constant<T, v> type;
 };
 
-template <class T, T v> const T integral_constant<T, v>::value;
+template <class T, T v>
+const T integral_constant<T, v>::value;
 
 typedef integral_constant<bool, true> true_type;
 typedef integral_constant<bool, false> false_type;
 
-template <class T> struct is_pointer : false_type {};
-template <class T> struct is_pointer<T*> : true_type {};
+template <class T>
+struct is_pointer : false_type {};
+template <class T>
+struct is_pointer<T*> : true_type {};
 
-template <class T, class U> struct is_same : public false_type {};
-template <class T> struct is_same<T, T> : true_type {};
+template <class T, class U>
+struct is_same : public false_type {};
+template <class T>
+struct is_same<T, T> : true_type {};
 
-template<class> struct is_array : public false_type {};
-template<class T, size_t n> struct is_array<T[n]> : public true_type {};
-template<class T> struct is_array<T[]> : public true_type {};
+template <class>
+struct is_array : public false_type {};
+template <class T, size_t n>
+struct is_array<T[n]> : public true_type {};
+template <class T>
+struct is_array<T[]> : public true_type {};
 
-template <class T> struct is_non_const_reference : false_type {};
-template <class T> struct is_non_const_reference<T&> : true_type {};
-template <class T> struct is_non_const_reference<const T&> : false_type {};
+template <class T>
+struct is_non_const_reference : false_type {};
+template <class T>
+struct is_non_const_reference<T&> : true_type {};
+template <class T>
+struct is_non_const_reference<const T&> : false_type {};
 
-template <class T> struct is_void : false_type {};
-template <> struct is_void<void> : true_type {};
+template <class T>
+struct is_void : false_type {};
+template <>
+struct is_void<void> : true_type {};
 
 // Helper useful for converting a tuple to variadic template function
 // arguments.
@@ -95,7 +108,7 @@
 // is_class type_trait implementation.
 struct IsClassHelper {
   template <typename C>
-  static YesType Test(void(C::*)(void));
+  static YesType Test(void (C::*)(void));
 
   template <typename C>
   static NoType Test(...);
@@ -111,16 +124,14 @@
 struct is_convertible
     : integral_constant<bool,
                         sizeof(internal::ConvertHelper::Test<To>(
-                                   internal::ConvertHelper::Create<From>())) ==
-                        sizeof(internal::YesType)> {
-};
+                            internal::ConvertHelper::Create<From>())) ==
+                            sizeof(internal::YesType)> {};
 
 template <typename T>
 struct is_class
     : integral_constant<bool,
                         sizeof(internal::IsClassHelper::Test<T>(0)) ==
-                            sizeof(internal::YesType)> {
-};
+                            sizeof(internal::YesType)> {};
 
 }  // namespace rtc
 
diff --git a/rtc_base/testbase64.h b/rtc_base/testbase64.h
index dbbdec9..5dc94b6 100644
--- a/rtc_base/testbase64.h
+++ b/rtc_base/testbase64.h
@@ -14,7 +14,2098 @@
 /* This file was generated by googleclient/talk/binary2header.sh */
 
 static unsigned char testbase64[] = {
-0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xe1, 0x0d, 0x07, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xbe, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xc3, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xcc, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x3c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x04, 0x02, 0x13, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x02, 0xc4, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x53, 0x4f, 0x4e, 0x59, 0x00, 0x44, 0x53, 0x43, 0x2d, 0x50, 0x32, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, 0x37, 0x2e, 0x30, 0x00, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x33, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x31, 0x30, 0x3a, 0x30, 0x34, 0x00, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, 0x20, 0x31, 0x30, 0x2e, 0x34, 0x2e, 0x38, 0x00, 0x00, 0x1c, 0x82, 0x9a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x6a, 0x82, 0x9d, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x72, 0x88, 0x22, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x88, 0x27, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0x00, 0x00, 0x90, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x7a, 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xa2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xaa, 0x92, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xb2, 0x92, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x92, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x92, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xba, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa0, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x12, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x1a, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x22, 0x02, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, 0x00, 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, 0x0b, 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, 0x0e, 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, 0x3f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, 0x73, 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xc2, 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, 0x82, 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, 0xa2, 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, 0x17, 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, 0x4d, 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, 0x1f, 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, 0x69, 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, 0xd1, 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, 0x5b, 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, 0xd8, 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, 0x25, 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, 0x4b, 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, 0x60, 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, 0xb1, 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, 0x04, 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, 0xbc, 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, 0xfd, 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, 0x73, 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, 0x2a, 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, 0x80, 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, 0xf6, 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, 0x23, 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, 0xfc, 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, 0xf3, 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, 0xe4, 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, 0x10, 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, 0x1f, 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, 0xe4, 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, 0x05, 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, 0xe1, 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, 0x12, 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, 0x8e, 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, 0x6a, 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, 0xff, 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, 0xab, 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, 0x92, 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, 0x8d, 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, 0x24, 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, 0x50, 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, 0x1b, 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, 0xdb, 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, 0x3d, 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, 0xbd, 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, 0xa5, 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, 0x04, 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, 0x3c, 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, 0x02, 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, 0x12, 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, 0xef, 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, 0x4f, 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, 0x0e, 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, 0xf1, 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, 0x7d, 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, 0xd9, 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, 0x48, 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, 0x0d, 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, 0x0b, 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, 0x89, 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, 0x27, 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, 0x34, 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, 0xb9, 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, 0xae, 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, 0xf5, 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, 0xfe, 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, 0xfa, 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, 0x1a, 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, 0x57, 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, 0xc2, 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, 0x7c, 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, 0x66, 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, 0x9d, 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, 0x72, 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, 0xf6, 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, 0x65, 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, 0x23, 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, 0x23, 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, 0x1a, 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, 0x99, 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, 0x27, 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, 0x22, 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, 0xee, 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, 0xfe, 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, 0xcf, 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, 0xd9, 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, 0x55, 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, 0x90, 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, 0x45, 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, 0x69, 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, 0xeb, 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, 0x68, 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, 0x3b, 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, 0xab, 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, 0x10, 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, 0xf3, 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, 0xa6, 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, 0x1f, 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, 0x16, 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, 0x9e, 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, 0x8c, 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, 0x96, 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, 0xe9, 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, 0xc4, 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, 0x13, 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, 0x92, 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, 0x43, 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, 0x6d, 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, 0x1c, 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, 0xf2, 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, 0xa4, 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, 0xe6, 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, 0xb6, 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, 0xb8, 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, 0x1f, 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, 0xa2, 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, 0x6d, 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, 0x6d, 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, 0xc0, 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, 0xe3, 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, 0x2d, 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, 0xbb, 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, 0x7e, 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, 0xc1, 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, 0x2e, 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, 0x4b, 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, 0xfa, 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, 0xd5, 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, 0xf3, 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, 0xd8, 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, 0xb3, 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, 0xfd, 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, 0xfa, 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, 0x2b, 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, 0xab, 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, 0x57, 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, 0x63, 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, 0xc7, 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, 0x2b, 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, 0x50, 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, 0xab, 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, 0x58, 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, 0x88, 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, 0x83, 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, 0x4c, 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, 0x58, 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, 0xcf, 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, 0xdf, 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, 0xad, 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, 0x26, 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, 0x53, 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, 0xc6, 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, 0x76, 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, 0x83, 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, 0x06, 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, 0xd6, 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, 0xfa, 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, 0x39, 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, 0x1b, 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, 0xb3, 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, 0x1c, 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, 0x26, 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, 0xfa, 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, 0x4d, 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, 0xbe, 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, 0x06, 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, 0x55, 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, 0xae, 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, 0xfc, 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, 0xc7, 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, 0xfc, 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0xff, 0xed, 0x2e, 0x1c, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, 0x33, 0x2e, 0x30, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x1c, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x1c, 0x02, 0x78, 0x00, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfb, 0x09, 0xa6, 0xbd, 0x07, 0x4c, 0x2a, 0x36, 0x9d, 0x8f, 0xe2, 0xcc, 0x57, 0xa9, 0xac, 0x85, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xea, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xb0, 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54, 0x46, 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x2f, 0x2f, 0x44, 0x54, 0x44, 0x20, 0x50, 0x4c, 0x49, 0x53, 0x54, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x2f, 0x45, 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x54, 0x44, 0x73, 0x2f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x2d, 0x31, 0x2e, 0x30, 0x2e, 0x64, 0x74, 0x64, 0x22, 0x3e, 0x0a, 0x3c, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x32, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x32, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x73, 0x75, 0x62, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x61, 0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x37, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x6e, 0x61, 0x2d, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x54, 0x31, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x37, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, 0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x55, 0x53, 0x20, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x54, 0x31, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x3c, 0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0xde, 0x02, 0x40, 0xff, 0xee, 0xff, 0xee, 0x03, 0x06, 0x02, 0x52, 0x03, 0x67, 0x05, 0x28, 0x03, 0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd8, 0x02, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x01, 0x7f, 0xff, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x08, 0x00, 0x19, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x2f, 0x66, 0x66, 0x00, 0x01, 0x00, 0x6c, 0x66, 0x66, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2f, 0x66, 0x66, 0x00, 0x01, 0x00, 0xa1, 0x99, 0x9a, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x03, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x44, 0x00, 0x53, 0x00, 0x43, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x32, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6f, 0x6d, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x06, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x56, 0x6c, 0x4c, 0x73, 0x00, 0x00, 0x00, 0x01, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x49, 0x44, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0c, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x54, 0x79, 0x70, 0x65, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0a, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6d, 0x67, 0x20, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6f, 0x6d, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, 0x6c, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6c, 0x6c, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x73, 0x67, 0x65, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x61, 0x6c, 0x74, 0x54, 0x61, 0x67, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x63, 0x65, 0x6c, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x49, 0x73, 0x48, 0x54, 0x4d, 0x4c, 0x62, 0x6f, 0x6f, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x08, 0x63, 0x65, 0x6c, 0x6c, 0x54, 0x65, 0x78, 0x74, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x68, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x48, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x00, 0x09, 0x76, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x00, 0x0b, 0x62, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x11, 0x45, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x42, 0x47, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x09, 0x74, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6c, 0x65, 0x66, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x72, 0x69, 0x67, 0x68, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0x09, 0xdd, 0x00, 0x18, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, 0x00, 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, 0x0b, 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, 0x0e, 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, 0x3f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05, 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91, 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, 0x72, 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, 0x73, 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xc2, 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41, 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, 0x82, 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, 0xa2, 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, 0x17, 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, 0x4d, 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, 0x1f, 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, 0x69, 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, 0xd1, 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, 0x5b, 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, 0xd8, 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, 0x25, 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, 0x4b, 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, 0x60, 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, 0xb1, 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, 0x04, 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, 0xbc, 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, 0xfd, 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, 0x73, 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, 0x2a, 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, 0x80, 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, 0xf6, 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, 0x23, 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, 0xfc, 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, 0xf3, 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, 0xe4, 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, 0x10, 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, 0x1f, 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, 0xe4, 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, 0x05, 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, 0xe1, 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, 0x12, 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, 0x8e, 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, 0x6a, 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, 0xff, 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, 0xab, 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, 0x92, 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, 0x8d, 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, 0x24, 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, 0x50, 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, 0x1b, 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, 0xdb, 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, 0x3d, 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, 0xbd, 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, 0xa5, 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, 0x04, 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, 0x3c, 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, 0x02, 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, 0x12, 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, 0xef, 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, 0x4f, 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, 0x0e, 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, 0xf1, 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, 0x7d, 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, 0xd9, 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, 0x48, 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, 0x0d, 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, 0x0b, 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, 0x89, 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, 0x27, 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, 0x34, 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, 0xb9, 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, 0xae, 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, 0xf5, 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, 0xfe, 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, 0xfa, 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, 0x1a, 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, 0x57, 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, 0xc2, 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, 0x7c, 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, 0x66, 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, 0x9d, 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, 0x72, 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, 0xf6, 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, 0x65, 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, 0x23, 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, 0x23, 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, 0x1a, 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, 0x99, 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, 0x27, 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, 0x22, 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, 0xee, 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, 0xfe, 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, 0xcf, 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, 0xd9, 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, 0x55, 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, 0x90, 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, 0x45, 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, 0x69, 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, 0xeb, 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, 0x68, 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, 0x3b, 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, 0xab, 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, 0x10, 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, 0xf3, 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, 0xa6, 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, 0x1f, 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, 0x16, 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, 0x9e, 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, 0x8c, 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, 0x96, 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, 0xe9, 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, 0xc4, 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, 0x13, 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, 0x92, 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, 0x43, 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, 0x6d, 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, 0x1c, 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, 0xf2, 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, 0xa4, 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, 0xe6, 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, 0xb6, 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, 0xb8, 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, 0x1f, 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, 0xa2, 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, 0x6d, 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, 0x6d, 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, 0xc0, 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, 0xe3, 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, 0x2d, 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, 0xbb, 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, 0x7e, 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, 0xc1, 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, 0x2e, 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, 0x4b, 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, 0xfa, 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, 0xd5, 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, 0xf3, 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, 0xd8, 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, 0xb3, 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, 0xfd, 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, 0xfa, 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, 0x2b, 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, 0xab, 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, 0x57, 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, 0x63, 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, 0xc7, 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, 0x2b, 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, 0x50, 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, 0xab, 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, 0x58, 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, 0x88, 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, 0x83, 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, 0x4c, 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, 0x58, 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, 0xcf, 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, 0xdf, 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, 0xad, 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, 0x26, 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, 0x53, 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, 0xc6, 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, 0x76, 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, 0x83, 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, 0x06, 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, 0xd6, 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, 0xfa, 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, 0x39, 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, 0x1b, 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, 0xb3, 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, 0x1c, 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, 0x26, 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, 0xfa, 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, 0x4d, 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, 0xbe, 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, 0x06, 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, 0x55, 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, 0xae, 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, 0xfc, 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, 0xc7, 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, 0xfc, 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x00, 0x00, 0x13, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x20, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xff, 0xe1, 0x15, 0x67, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x00, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x27, 0xef, 0xbb, 0xbf, 0x27, 0x20, 0x69, 0x64, 0x3d, 0x27, 0x57, 0x35, 0x4d, 0x30, 0x4d, 0x70, 0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, 0x7a, 0x4e, 0x54, 0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x27, 0x3f, 0x3e, 0x0a, 0x3c, 0x3f, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2d, 0x78, 0x61, 0x70, 0x2d, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x20, 0x65, 0x73, 0x63, 0x3d, 0x22, 0x43, 0x52, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x27, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x27, 0x20, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x74, 0x6b, 0x3d, 0x27, 0x58, 0x4d, 0x50, 0x20, 0x74, 0x6f, 0x6f, 0x6c, 0x6b, 0x69, 0x74, 0x20, 0x32, 0x2e, 0x38, 0x2e, 0x32, 0x2d, 0x33, 0x33, 0x2c, 0x20, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x31, 0x2e, 0x35, 0x27, 0x3e, 0x0a, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x27, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x69, 0x58, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x58, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x64, 0x66, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x31, 0x2e, 0x33, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x70, 0x64, 0x66, 0x3a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x43, 0x61, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x61, 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x78, 0x61, 0x70, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x6d, 0x6d, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x64, 0x6f, 0x63, 0x69, 0x64, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x36, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x3c, 0x2f, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x64, 0x63, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x72, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x63, 0x2f, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x31, 0x2e, 0x31, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x78, 0x6d, 0x6c, 0x3a, 0x6c, 0x61, 0x6e, 0x67, 0x3d, 0x27, 0x78, 0x2d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x27, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x27, 0x77, 0x27, 0x3f, 0x3e, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64, 0x40, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x06, 0x04, 0x03, 0x04, 0x06, 0x07, 0x05, 0x04, 0x04, 0x05, 0x07, 0x08, 0x06, 0x06, 0x07, 0x06, 0x06, 0x08, 0x0a, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x04, 0x05, 0x05, 0x08, 0x07, 0x08, 0x0f, 0x0a, 0x0a, 0x0f, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x0d, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x02, 0x06, 0x01, 0x00, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x02, 0x06, 0x07, 0x03, 0x04, 0x02, 0x06, 0x02, 0x73, 0x01, 0x02, 0x03, 0x11, 0x04, 0x00, 0x05, 0x21, 0x12, 0x31, 0x41, 0x51, 0x06, 0x13, 0x61, 0x22, 0x71, 0x81, 0x14, 0x32, 0x91, 0xa1, 0x07, 0x15, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xe1, 0x33, 0x16, 0x62, 0xf0, 0x24, 0x72, 0x82, 0xf1, 0x25, 0x43, 0x34, 0x53, 0x92, 0xa2, 0xb2, 0x63, 0x73, 0xc2, 0x35, 0x44, 0x27, 0x93, 0xa3, 0xb3, 0x36, 0x17, 0x54, 0x64, 0x74, 0xc3, 0xd2, 0xe2, 0x08, 0x26, 0x83, 0x09, 0x0a, 0x18, 0x19, 0x84, 0x94, 0x45, 0x46, 0xa4, 0xb4, 0x56, 0xd3, 0x55, 0x28, 0x1a, 0xf2, 0xe3, 0xf3, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x05, 0x05, 0x04, 0x05, 0x06, 0x04, 0x08, 0x03, 0x03, 0x6d, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31, 0x41, 0x05, 0x51, 0x13, 0x61, 0x22, 0x06, 0x71, 0x81, 0x91, 0x32, 0xa1, 0xb1, 0xf0, 0x14, 0xc1, 0xd1, 0xe1, 0x23, 0x42, 0x15, 0x52, 0x62, 0x72, 0xf1, 0x33, 0x24, 0x34, 0x43, 0x82, 0x16, 0x92, 0x53, 0x25, 0xa2, 0x63, 0xb2, 0xc2, 0x07, 0x73, 0xd2, 0x35, 0xe2, 0x44, 0x83, 0x17, 0x54, 0x93, 0x08, 0x09, 0x0a, 0x18, 0x19, 0x26, 0x36, 0x45, 0x1a, 0x27, 0x64, 0x74, 0x55, 0x37, 0xf2, 0xa3, 0xb3, 0xc3, 0x28, 0x29, 0xd3, 0xe3, 0xf3, 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf0, 0x67, 0xa6, 0x5c, 0x0f, 0x01, 0xd4, 0x7e, 0x18, 0x12, 0x98, 0xe9, 0xd6, 0x2d, 0x34, 0x6d, 0x70, 0xdf, 0xdc, 0xa1, 0xe3, 0xec, 0x5b, 0xfb, 0x32, 0x24, 0xb2, 0x01, 0x1f, 0x15, 0xa4, 0x52, 0x4a, 0x82, 0x31, 0xf1, 0xfe, 0xd1, 0x3d, 0x14, 0x64, 0x49, 0x64, 0x22, 0x98, 0xcf, 0xa5, 0x46, 0x6c, 0x16, 0x55, 0x71, 0x56, 0x62, 0x28, 0x07, 0xc5, 0x45, 0x15, 0xa0, 0xc8, 0x89, 0x33, 0xe1, 0x63, 0xd2, 0xd8, 0x34, 0x44, 0x17, 0xa0, 0x2c, 0x4d, 0x16, 0xbb, 0xed, 0xdc, 0xf8, 0x64, 0xc1, 0x6b, 0x31, 0x42, 0x18, 0x8e, 0xc7, 0xb5, 0x2a, 0x7d, 0xb2, 0x56, 0xc5, 0x61, 0x8c, 0xf2, 0xa0, 0x1b, 0x1e, 0x83, 0x0d, 0xa1, 0x63, 0x50, 0x1f, 0x97, 0x7c, 0x2a, 0xa9, 0x1a, 0x9a, 0x86, 0x4f, 0xb4, 0xb4, 0x38, 0x0a, 0xa6, 0x0b, 0xb8, 0x0c, 0x05, 0x14, 0xf8, 0x76, 0x3e, 0x19, 0x14, 0xb6, 0x78, 0xf8, 0x8c, 0x2a, 0xd5, 0x01, 0xdc, 0x6f, 0x8a, 0x1a, 0xe3, 0x8d, 0xab, 0xff, 0xd0, 0xf0, 0xec, 0xe9, 0x15, 0xb5, 0xb9, 0x5a, 0x7c, 0x4c, 0xa2, 0x9e, 0x24, 0xf5, 0xca, 0xc6, 0xe5, 0x99, 0xd9, 0x34, 0x99, 0x04, 0x3a, 0x7d, 0xb5, 0xba, 0xd5, 0x51, 0x63, 0x0e, 0xc7, 0xc5, 0x9b, 0x73, 0xf8, 0xe4, 0x6f, 0x76, 0xca, 0xd9, 0xda, 0x54, 0x6d, 0x72, 0x2e, 0x1a, 0x57, 0x11, 0x44, 0x40, 0x0d, 0x27, 0x7a, 0x0f, 0xd9, 0x5f, 0x12, 0x69, 0x4c, 0x84, 0xcd, 0x36, 0xe3, 0x85, 0xb2, 0xcd, 0x2f, 0x4a, 0x8b, 0x58, 0x36, 0xf6, 0x76, 0xa8, 0x64, 0x64, 0x3c, 0xa4, 0x93, 0xaa, 0x25, 0x3c, 0x49, 0xda, 0xa4, 0xe5, 0x26, 0x54, 0xe4, 0x8c, 0x7c, 0x5c, 0x93, 0x4d, 0x67, 0xc9, 0x3a, 0x6e, 0x9f, 0x13, 0xb4, 0xce, 0xf7, 0x3a, 0x9b, 0xad, 0x52, 0xd6, 0x2a, 0xd1, 0x49, 0xee, 0xc7, 0xf8, 0x64, 0x46, 0x42, 0x4e, 0xcd, 0x92, 0xc2, 0x00, 0xdd, 0x8a, 0x47, 0xe5, 0x69, 0x6e, 0xd4, 0xa4, 0x08, 0x16, 0x83, 0x9c, 0x8c, 0xdd, 0x95, 0x6b, 0xb9, 0xf6, 0xef, 0x97, 0x78, 0x94, 0xe3, 0x78, 0x04, 0xa4, 0xf3, 0xe8, 0xee, 0x64, 0xe1, 0x12, 0x10, 0x05, 0x6a, 0xc7, 0xc0, 0x6f, 0x53, 0xf3, 0xc9, 0x89, 0xb4, 0x9c, 0x4e, 0xb4, 0xf2, 0xd3, 0xde, 0x7a, 0xd2, 0x19, 0x16, 0x38, 0x61, 0x5d, 0xd9, 0x88, 0x05, 0x9c, 0xf4, 0x0a, 0x0f, 0x5f, 0x73, 0x84, 0xe4, 0xa4, 0xc7, 0x0d, 0xa5, 0xf1, 0x59, 0xba, 0x5c, 0x08, 0x98, 0x6f, 0xc8, 0x20, 0xfa, 0x4e, 0x4e, 0xf6, 0x69, 0xe1, 0xa2, 0x89, 0xfd, 0x1f, 0x77, 0x2c, 0xe6, 0xce, 0xd6, 0x17, 0x9a, 0x69, 0xdb, 0xd3, 0x86, 0x18, 0xc1, 0x67, 0x77, 0x26, 0x80, 0x28, 0x1b, 0x93, 0x88, 0x41, 0x0f, 0x40, 0xb0, 0xfc, 0x87, 0xf3, 0x43, 0x98, 0xd7, 0x58, 0x96, 0xdb, 0x4d, 0x91, 0x88, 0xe5, 0x6c, 0x58, 0xdc, 0x5c, 0x2a, 0xf7, 0x2c, 0xb1, 0xfc, 0x20, 0x8f, 0x02, 0xd9, 0x65, 0x06, 0xbe, 0x26, 0x6f, 0xa2, 0x7f, 0xce, 0x3d, 0x69, 0x26, 0xdd, 0x13, 0x52, 0xbf, 0xbd, 0x92, 0x62, 0x59, 0x4c, 0x90, 0xac, 0x50, 0x45, 0x5e, 0xbb, 0x09, 0x03, 0x12, 0x29, 0x84, 0x00, 0xc4, 0xc9, 0x11, 0xff, 0x00, 0x42, 0xe7, 0xa7, 0x7a, 0xd4, 0xfd, 0x21, 0x79, 0xe9, 0x78, 0x71, 0x8b, 0x95, 0x39, 0x75, 0xaf, 0x4e, 0x98, 0x78, 0x42, 0x38, 0xdf, 0xff, 0xd1, 0xf0, 0xe6, 0xa0, 0x58, 0xc8, 0x84, 0x9a, 0xaa, 0x30, 0x55, 0xf9, 0x0a, 0x6f, 0x90, 0x0c, 0xca, 0x72, 0x48, 0xb8, 0x1e, 0x89, 0xa7, 0x23, 0x17, 0x24, 0xff, 0x00, 0x61, 0xb6, 0x54, 0x76, 0x6e, 0x1b, 0xa7, 0xbe, 0x50, 0xf2, 0xc1, 0xd7, 0x4c, 0x52, 0x5e, 0x33, 0x5b, 0xe9, 0x10, 0xf4, 0x54, 0x3c, 0x5e, 0x77, 0xee, 0x49, 0xec, 0x2b, 0xb6, 0x63, 0xe4, 0xc9, 0xc3, 0xef, 0x73, 0xf0, 0xe1, 0x32, 0x1b, 0xf2, 0x7a, 0x05, 0xce, 0xad, 0x65, 0xa1, 0x98, 0xb4, 0x0f, 0x2a, 0x5b, 0x23, 0xeb, 0x12, 0x00, 0x88, 0xb0, 0xa8, 0x66, 0x46, 0x3d, 0xea, 0x7b, 0xfb, 0x9e, 0x99, 0x89, 0xbc, 0x8d, 0x97, 0x3a, 0x34, 0x05, 0x32, 0x5d, 0x1f, 0xc9, 0x1a, 0x8c, 0x36, 0x8c, 0x6f, 0x66, 0xfa, 0xc6, 0xb7, 0x7d, 0xf0, 0x94, 0x04, 0xf0, 0x88, 0xc9, 0xd5, 0x9d, 0x8d, 0x4b, 0x11, 0xd4, 0x9f, 0xbb, 0x25, 0xc5, 0xdc, 0xa2, 0x03, 0x99, 0x4b, 0xbc, 0xf3, 0x0d, 0x97, 0x96, 0x74, 0xe5, 0xf2, 0xb6, 0x80, 0x95, 0xbd, 0x99, 0x15, 0xf5, 0x4b, 0xd2, 0x37, 0x58, 0x46, 0xd4, 0x27, 0xc5, 0xce, 0xc1, 0x7c, 0x30, 0x8e, 0x68, 0x94, 0x7b, 0x9e, 0x6d, 0xe6, 0x7b, 0x9b, 0x5d, 0x3a, 0xd8, 0xdb, 0x32, 0xfa, 0x77, 0x65, 0x15, 0xe4, 0x57, 0xa7, 0x21, 0x55, 0x04, 0x57, 0xef, 0xd8, 0x66, 0x56, 0x38, 0x19, 0x1b, 0xe8, 0xe0, 0x67, 0x98, 0xc7, 0x1a, 0x1c, 0xde, 0x71, 0x71, 0x79, 0x2c, 0xf2, 0xfa, 0x8c, 0x48, 0xec, 0xb5, 0x24, 0x9a, 0x0c, 0xce, 0x75, 0x29, 0xae, 0x8c, 0x67, 0xd4, 0xb5, 0x0b, 0x4b, 0x04, 0x05, 0xef, 0x2e, 0x66, 0x8e, 0x18, 0x08, 0x15, 0xdd, 0x8f, 0x11, 0xb0, 0xeb, 0x4c, 0x04, 0x5b, 0x21, 0x2a, 0x7d, 0x41, 0xe4, 0x4f, 0xcb, 0xcb, 0x5d, 0x12, 0x45, 0xb8, 0xb7, 0x53, 0x71, 0xaa, 0x9f, 0x86, 0x5b, 0xd6, 0x50, 0x4a, 0xed, 0xba, 0x46, 0x77, 0x00, 0x13, 0xd4, 0x8c, 0x85, 0xd3, 0x12, 0x6d, 0xeb, 0x1a, 0x67, 0x95, 0xd9, 0x39, 0x39, 0x50, 0xac, 0xff, 0x00, 0x6f, 0xc4, 0xff, 0x00, 0x1c, 0x81, 0x92, 0xb2, 0x6b, 0x6d, 0x02, 0xdd, 0xbd, 0x36, 0x92, 0x36, 0x2d, 0x1f, 0xc0, 0x2a, 0x0b, 0x28, 0x1b, 0x91, 0x41, 0xf4, 0x9c, 0xb6, 0x25, 0x81, 0x46, 0xfe, 0x81, 0xb5, 0xad, 0x3d, 0xba, 0x57, 0xb7, 0xf9, 0xf6, 0xc9, 0xb0, 0x7f, 0xff, 0xd2, 0xf0, 0xe2, 0x86, 0x95, 0xc4, 0x67, 0x7e, 0x3f, 0x11, 0xf7, 0xa8, 0x19, 0x06, 0x69, 0x8d, 0xca, 0xca, 0x24, 0x8f, 0xd3, 0x52, 0x24, 0x89, 0x47, 0x25, 0x1f, 0xcb, 0x20, 0xf8, 0xb2, 0xb2, 0x76, 0x6e, 0x88, 0x36, 0xf6, 0x6f, 0x2a, 0xc1, 0x6e, 0xfa, 0x45, 0xad, 0xbc, 0x3f, 0x0b, 0x46, 0x81, 0x4d, 0x46, 0xea, 0x7a, 0x9a, 0x83, 0x9a, 0xa9, 0xdd, 0xbb, 0xec, 0x7b, 0x06, 0x5b, 0xe5, 0xcf, 0x2e, 0x69, 0xfa, 0x5c, 0xcd, 0x7b, 0x14, 0x5e, 0xa5, 0xee, 0xf5, 0xb8, 0x7d, 0xdd, 0x99, 0xba, 0xef, 0x91, 0x16, 0x5b, 0x36, 0xb6, 0x65, 0x0d, 0xac, 0xb2, 0x5b, 0xed, 0x34, 0x81, 0x7a, 0xbb, 0x46, 0x40, 0x6a, 0x9e, 0xb4, 0x39, 0x31, 0x13, 0x49, 0xda, 0xd2, 0x9b, 0xed, 0x1e, 0xc4, 0x24, 0xb3, 0x35, 0xb2, 0x88, 0x60, 0x06, 0xe6, 0x56, 0x98, 0x96, 0x79, 0x1e, 0x31, 0x51, 0xc9, 0x8f, 0xcb, 0x00, 0xe6, 0xb3, 0xe4, 0xf9, 0x2b, 0xcc, 0x7a, 0x94, 0xda, 0x96, 0xa9, 0x71, 0x77, 0x70, 0x79, 0xcd, 0x33, 0x97, 0x76, 0x3f, 0xcc, 0xc6, 0xa6, 0x9f, 0x2e, 0x99, 0xb9, 0xc6, 0x2a, 0x21, 0xe6, 0x73, 0xca, 0xe6, 0x4a, 0x51, 0x1a, 0x99, 0x1c, 0x28, 0x04, 0x93, 0xd0, 0x0e, 0xa4, 0xe4, 0xda, 0x5f, 0x50, 0xfe, 0x4a, 0xfe, 0x48, 0xb5, 0xb2, 0xc1, 0xe6, 0x1f, 0x31, 0x7e, 0xef, 0x52, 0x91, 0x43, 0xc3, 0x6e, 0x77, 0xf4, 0x22, 0x6d, 0xbf, 0xe4, 0x63, 0x0e, 0xbf, 0xca, 0x36, 0xeb, 0x5c, 0x84, 0xa5, 0x48, 0x7d, 0x3b, 0x61, 0xa1, 0xdb, 0x5b, 0x2c, 0x71, 0xda, 0x45, 0xc4, 0x28, 0x00, 0x81, 0xdb, 0x31, 0xc9, 0xb4, 0xb2, 0x3b, 0x5d, 0x27, 0xa5, 0x05, 0x1b, 0xc7, 0xdb, 0x10, 0xa9, 0xbd, 0xa6, 0x93, 0x0c, 0x75, 0xe4, 0x39, 0x35, 0x41, 0x3d, 0xc5, 0x06, 0xdb, 0x8e, 0xfd, 0x46, 0x5b, 0x1d, 0x98, 0x95, 0x4f, 0x46, 0xdb, 0xd5, 0xfb, 0x29, 0x5e, 0x9d, 0x0d, 0x32, 0xeb, 0x61, 0x4f, 0xff, 0xd3, 0xf1, 0x46, 0x9a, 0x16, 0x1b, 0x91, 0x71, 0x28, 0xac, 0x4a, 0x14, 0x30, 0x3e, 0x19, 0x54, 0xb9, 0x36, 0xc7, 0x9b, 0x2d, 0xd1, 0x6c, 0x45, 0xe3, 0xdc, 0xde, 0xc8, 0x95, 0x5b, 0x87, 0xf8, 0x41, 0x1d, 0x10, 0x54, 0x01, 0x98, 0x79, 0x25, 0xd1, 0xda, 0xe9, 0xe1, 0xb5, 0x9e, 0xac, 0xeb, 0x42, 0xba, 0x8e, 0xdf, 0x8c, 0x31, 0x21, 0x70, 0xb4, 0x5d, 0xbe, 0xc5, 0x7c, 0x2b, 0xed, 0xe1, 0x94, 0x18, 0xb9, 0x51, 0x3d, 0x03, 0x2c, 0x13, 0x6b, 0xf1, 0x42, 0x6e, 0xe2, 0xb7, 0x12, 0xa0, 0xdd, 0x50, 0x9f, 0x4f, 0x6f, 0xa7, 0x6f, 0xc7, 0x03, 0x61, 0xa0, 0x83, 0xb5, 0xf3, 0x97, 0x98, 0x20, 0x9c, 0x44, 0xea, 0xd0, 0xad, 0x48, 0x64, 0x90, 0x21, 0xd8, 0x9f, 0xa7, 0xa6, 0x44, 0xca, 0x99, 0xc6, 0x36, 0xcb, 0x74, 0x5d, 0x7e, 0x5b, 0xfe, 0x31, 0x6a, 0x31, 0xf3, 0x8c, 0xd0, 0xad, 0x40, 0xa3, 0x1f, 0x7c, 0x44, 0xd6, 0x51, 0xd9, 0xe0, 0x5f, 0x9a, 0x7e, 0x41, 0x9f, 0x40, 0xf3, 0x14, 0xba, 0x85, 0xba, 0x34, 0xba, 0x2d, 0xfb, 0x34, 0xd0, 0xcf, 0x4f, 0xb0, 0xce, 0x6a, 0x51, 0xe9, 0xb0, 0x20, 0xf4, 0xf1, 0x19, 0xb2, 0xc3, 0x90, 0x11, 0x4e, 0x97, 0x55, 0x80, 0x83, 0xc4, 0x17, 0x7e, 0x4c, 0x79, 0x19, 0xfc, 0xd1, 0xe7, 0x78, 0x4b, 0x91, 0x1d, 0xae, 0x92, 0xa6, 0xf6, 0x46, 0x75, 0xe4, 0xad, 0x22, 0x1f, 0xdd, 0xa1, 0x07, 0xb3, 0x1e, 0xfe, 0xd9, 0x92, 0xeb, 0x4b, 0xed, 0xfd, 0x0a, 0xc2, 0x63, 0x27, 0xa4, 0x88, 0x17, 0x60, 0x49, 0x35, 0xdc, 0x8e, 0xa5, 0x7d, 0xab, 0xd3, 0x28, 0x90, 0x50, 0xcd, 0xed, 0x2d, 0xda, 0x15, 0x55, 0x51, 0xf1, 0x1a, 0x0a, 0xf7, 0x39, 0x5d, 0xaa, 0x77, 0x6f, 0x01, 0x8e, 0xa7, 0x7d, 0xfa, 0xff, 0x00, 0x66, 0x10, 0xa8, 0xb8, 0x63, 0x76, 0x90, 0xa8, 0x20, 0x06, 0x56, 0xdb, 0x61, 0xda, 0xbd, 0x4f, 0xcb, 0x24, 0x15, 0x0f, 0xf5, 0x66, 0xe5, 0x5f, 0x4c, 0x53, 0xc3, 0xb7, 0xce, 0x99, 0x6b, 0x17, 0xff, 0xd4, 0xf0, 0xec, 0x57, 0x6f, 0x32, 0xa5, 0xa4, 0x43, 0x76, 0x75, 0xa9, 0xf1, 0x03, 0xfa, 0x64, 0x08, 0x6c, 0x8e, 0xfb, 0x3d, 0x7f, 0xcb, 0x16, 0x2b, 0x3d, 0xbc, 0x16, 0xa3, 0x66, 0x6d, 0x98, 0xfb, 0x1e, 0xb9, 0xac, 0xc8, 0x77, 0xb7, 0x7d, 0x01, 0xb3, 0x37, 0xb8, 0xd3, 0x46, 0x95, 0x68, 0x86, 0xd2, 0x2e, 0x4e, 0xab, 0xf0, 0x23, 0x11, 0x4e, 0x5f, 0xcd, 0x98, 0xe7, 0x25, 0x96, 0x71, 0x83, 0x0f, 0xd6, 0x3c, 0xb9, 0xe7, 0x0d, 0x7c, 0x41, 0x22, 0x5e, 0xb3, 0x20, 0x0c, 0x65, 0x80, 0xc8, 0x63, 0x8e, 0xbb, 0x95, 0xa5, 0x07, 0xeb, 0xcc, 0xac, 0x73, 0x83, 0x4e, 0x5c, 0x59, 0x09, 0xd8, 0xec, 0xc8, 0x57, 0x41, 0xd3, 0x4e, 0x95, 0xa5, 0x5b, 0x4b, 0x6a, 0xcb, 0xab, 0x43, 0x10, 0x4b, 0xeb, 0x85, 0xa2, 0x2c, 0x8e, 0x3f, 0x68, 0x54, 0xf5, 0x00, 0xd3, 0x97, 0x7a, 0x65, 0x79, 0xa6, 0x24, 0x76, 0x6f, 0xd3, 0x62, 0x96, 0x30, 0x78, 0xcb, 0x21, 0xf2, 0xf4, 0x22, 0xce, 0x54, 0x8e, 0x46, 0x26, 0x10, 0x7e, 0x0a, 0xf5, 0xd8, 0xf5, 0x1f, 0x31, 0x98, 0x83, 0x73, 0xb3, 0x91, 0xcd, 0x67, 0xe6, 0x7d, 0xe8, 0x16, 0x69, 0x6f, 0x10, 0x1f, 0x54, 0x9a, 0x37, 0xf5, 0x41, 0x5e, 0x7f, 0x0a, 0x29, 0x62, 0x02, 0xf8, 0x9c, 0xc8, 0x8c, 0x77, 0x6a, 0x99, 0xa0, 0x89, 0xff, 0x00, 0x9c, 0x74, 0xd2, 0xed, 0xed, 0xfc, 0xbb, 0x7b, 0xaa, 0x9a, 0x7d, 0x62, 0xfe, 0x46, 0x2d, 0xfe, 0x4c, 0x51, 0x31, 0x11, 0xa9, 0xf6, 0xef, 0x9b, 0x30, 0x5e, 0x7b, 0x38, 0xdd, 0xf4, 0x7f, 0x95, 0x94, 0xbc, 0x12, 0x43, 0x30, 0x6a, 0xb2, 0xf3, 0x86, 0x40, 0x3e, 0xcb, 0xd7, 0x6a, 0xd7, 0xb1, 0xe9, 0x8f, 0x37, 0x19, 0x97, 0x41, 0x2c, 0x71, 0x20, 0xf5, 0x36, 0x9c, 0x55, 0x78, 0x1d, 0x8a, 0x91, 0xd7, 0x11, 0x14, 0x5a, 0x3e, 0x19, 0x03, 0x10, 0x6b, 0xca, 0xbd, 0x86, 0xf8, 0x9d, 0x95, 0x18, 0x36, 0x65, 0x2e, 0xbc, 0x54, 0x1f, 0xa2, 0x99, 0x00, 0x59, 0x2a, 0x6f, 0x5e, 0x55, 0x15, 0xe9, 0x5f, 0xc3, 0x2f, 0xb6, 0x14, 0xff, 0x00, 0xff, 0xd5, 0xf1, 0x95, 0xfe, 0x80, 0x74, 0x0d, 0x7c, 0xd9, 0x89, 0x3d, 0x78, 0x57, 0x8b, 0xc5, 0x28, 0xe8, 0x55, 0xf7, 0x1f, 0x48, 0xca, 0x38, 0xb8, 0x83, 0x9f, 0x93, 0x07, 0x85, 0x3a, 0x7a, 0x6f, 0x95, 0x66, 0x2b, 0x2c, 0x4c, 0x0d, 0x14, 0x00, 0x3e, 0x9c, 0xc3, 0x98, 0x76, 0xb8, 0x45, 0xbd, 0x02, 0xde, 0x48, 0xee, 0xdc, 0xa0, 0x15, 0xe2, 0x2b, 0xc8, 0x8a, 0x8a, 0xfd, 0x3b, 0x66, 0x3f, 0x00, 0x73, 0x84, 0x2d, 0x36, 0xb5, 0xb5, 0x9e, 0x35, 0x1c, 0x29, 0xc4, 0xfe, 0xc8, 0x04, 0x7f, 0xc4, 0x69, 0x91, 0xe1, 0x67, 0x2c, 0x4a, 0xd2, 0xe9, 0x4e, 0xe3, 0xd4, 0xf4, 0x81, 0x5a, 0x12, 0xc5, 0x41, 0x3f, 0x79, 0x38, 0x9b, 0x60, 0x20, 0x07, 0x34, 0xb0, 0xc9, 0x03, 0x5c, 0x23, 0x03, 0x53, 0x13, 0x56, 0x88, 0xdf, 0x09, 0xda, 0x9b, 0xd3, 0xb6, 0x52, 0x0e, 0xec, 0xe4, 0x29, 0x24, 0xfc, 0xd0, 0xe7, 0x75, 0xe5, 0x57, 0x6b, 0x61, 0xfb, 0xf0, 0xca, 0xaa, 0x57, 0xa8, 0xe6, 0x78, 0x1a, 0x7d, 0xf9, 0x95, 0x8a, 0x5e, 0xa0, 0xe3, 0x67, 0x8f, 0xa0, 0xbd, 0x5b, 0xf2, 0xdf, 0x4a, 0x82, 0xcb, 0x4a, 0xb3, 0xb0, 0xb4, 0x41, 0x0a, 0x70, 0x48, 0xd9, 0x57, 0x60, 0x51, 0x3a, 0x8f, 0xbc, 0xe6, 0x7b, 0xcb, 0xe4, 0x3b, 0xa7, 0x3f, 0x9b, 0x9f, 0x9a, 0xba, 0x77, 0xe5, 0x5f, 0x95, 0x9c, 0x59, 0x94, 0x9f, 0xcd, 0x37, 0x8c, 0xa9, 0xa6, 0xd9, 0x39, 0xaa, 0xd0, 0x7d, 0xa9, 0x1c, 0x03, 0x5e, 0x09, 0xff, 0x00, 0x0c, 0x76, 0xcb, 0x62, 0x2d, 0xa5, 0xf2, 0x85, 0xbf, 0xe7, 0x87, 0xe6, 0xa3, 0x5e, 0x4d, 0xa8, 0xc9, 0xe6, 0x8b, 0xd5, 0x69, 0x5c, 0xb0, 0x4a, 0xab, 0xc4, 0xb5, 0x35, 0x0a, 0xaa, 0xea, 0x40, 0x03, 0xa0, 0xf6, 0xcb, 0x40, 0x4d, 0x3e, 0xdb, 0xff, 0x00, 0x9c, 0x7f, 0xfc, 0xce, 0x4f, 0xcc, 0xbf, 0x26, 0x25, 0xe5, 0xd3, 0x2f, 0xe9, 0xdd, 0x3d, 0xfe, 0xab, 0xa9, 0xaa, 0xd2, 0xa6, 0x40, 0x2a, 0xb2, 0x71, 0x00, 0x01, 0xea, 0x0d, 0xe8, 0x3a, 0x64, 0x25, 0x16, 0x1c, 0x8b, 0xd9, 0x51, 0x39, 0x28, 0x12, 0x51, 0x41, 0xfd, 0xa3, 0xd2, 0xb9, 0x4f, 0x0d, 0x33, 0xb5, 0xf4, 0x87, 0x9d, 0x79, 0x0e, 0xb4, 0xaf, 0x6a, 0xf8, 0xf1, 0xf0, 0xc9, 0xda, 0xbf, 0xff, 0xd6, 0xf2, 0xc6, 0xb5, 0x68, 0x64, 0xd0, 0x6d, 0x35, 0x20, 0x39, 0xcd, 0x13, 0x0f, 0x5e, 0x61, 0xfc, 0x8f, 0x40, 0x8b, 0x5e, 0xe0, 0x66, 0x1c, 0x4f, 0xaa, 0x9d, 0xe6, 0xa6, 0x1e, 0x91, 0x2e, 0xa9, 0x87, 0x95, 0xee, 0x9c, 0xc5, 0x55, 0x34, 0x60, 0x40, 0xae, 0x57, 0x30, 0xd9, 0xa7, 0x95, 0xbd, 0x6f, 0xcb, 0x26, 0x39, 0x40, 0x0d, 0x4e, 0xc0, 0x9f, 0x9e, 0x50, 0x5d, 0xac, 0x79, 0x33, 0x8b, 0xbb, 0x9b, 0x3b, 0x6b, 0x35, 0x48, 0x54, 0x09, 0x29, 0x56, 0x7f, 0xe1, 0x86, 0x72, 0x00, 0x2c, 0x6e, 0xf7, 0x63, 0x3e, 0x63, 0xbd, 0xbd, 0x5d, 0x20, 0x2a, 0xb3, 0xa4, 0x33, 0x48, 0xab, 0x21, 0x43, 0xf1, 0x2c, 0x47, 0xed, 0x1d, 0xbc, 0x73, 0x18, 0x9b, 0x64, 0x28, 0x96, 0x3a, 0xc7, 0x49, 0xb0, 0xf4, 0xcc, 0xe9, 0x73, 0x6c, 0xb4, 0xf8, 0x67, 0x92, 0x32, 0x21, 0x70, 0x7b, 0x89, 0x05, 0x57, 0xef, 0x38, 0x28, 0x94, 0x4a, 0x7d, 0x13, 0x7d, 0x6a, 0xd3, 0x4c, 0xb8, 0xf2, 0xc3, 0xc8, 0x2e, 0x03, 0xf3, 0xe2, 0x7d, 0x33, 0xb7, 0xc5, 0xcc, 0x71, 0x03, 0xc6, 0xb9, 0x64, 0x06, 0xe2, 0x9a, 0xf2, 0x4f, 0xd2, 0x6d, 0xe9, 0xfe, 0x41, 0x45, 0x5b, 0x18, 0x66, 0xa5, 0x64, 0x09, 0xf4, 0xd5, 0xb7, 0xcd, 0x93, 0xc7, 0xcf, 0x9b, 0xe5, 0x6f, 0xf9, 0xc8, 0x0d, 0x56, 0xeb, 0x59, 0xfc, 0xce, 0xd5, 0x12, 0x61, 0xc4, 0x69, 0xe9, 0x0d, 0xa4, 0x4b, 0xfe, 0x48, 0x40, 0xd5, 0x3e, 0xe4, 0xb6, 0x64, 0x8e, 0x4c, 0x02, 0x61, 0x65, 0xa0, 0x14, 0xb4, 0xb6, 0xb0, 0xb1, 0xb6, 0xb2, 0x97, 0xcb, 0xf1, 0x5a, 0x2d, 0xc6, 0xa5, 0xac, 0xb4, 0x70, 0x5d, 0xc7, 0x3d, 0xc1, 0x51, 0x24, 0x91, 0xc9, 0x31, 0x75, 0x6b, 0x70, 0x9f, 0x14, 0x68, 0x01, 0x46, 0xe4, 0xb5, 0xa3, 0x17, 0xcb, 0x40, 0x61, 0x6f, 0x47, 0xff, 0x00, 0x9c, 0x3a, 0x8f, 0x5b, 0x4f, 0x3c, 0x6b, 0xb7, 0xfa, 0x30, 0x91, 0x3c, 0xa4, 0xb1, 0x95, 0xb9, 0x82, 0x42, 0x0a, 0xbc, 0x8e, 0xe4, 0xdb, 0xa9, 0xef, 0xc9, 0x17, 0x91, 0x24, 0x7c, 0xb2, 0x05, 0x64, 0xfb, 0x75, 0x64, 0x32, 0x39, 0x69, 0x5b, 0x9c, 0xad, 0xb9, 0xdb, 0xa7, 0xb5, 0x3b, 0x53, 0x2a, 0x21, 0x41, 0x44, 0xf3, 0x8b, 0x8f, 0x2e, 0x43, 0x9d, 0x2b, 0xd4, 0x57, 0x23, 0x41, 0x36, 0xff, 0x00, 0xff, 0xd7, 0xf0, 0xc0, 0xd5, 0xb5, 0x11, 0x64, 0xb6, 0x3f, 0x59, 0x90, 0xd9, 0xab, 0x06, 0xf4, 0x79, 0x7c, 0x3b, 0x74, 0xc8, 0x08, 0x8b, 0xb6, 0xe3, 0x96, 0x55, 0x57, 0xb3, 0x3e, 0xf2, 0x35, 0xc7, 0xd6, 0x0b, 0x45, 0x5d, 0xdc, 0x8a, 0x7d, 0xd9, 0x8d, 0x94, 0x3b, 0x3d, 0x1c, 0x9e, 0xc3, 0xe5, 0xc3, 0x2c, 0x7c, 0xc5, 0x0f, 0xee, 0xdb, 0x8b, 0x0c, 0xc4, 0x26, 0x9d, 0xa0, 0x9a, 0x7d, 0x2c, 0xe5, 0xe4, 0x55, 0x7f, 0xee, 0xc1, 0x15, 0x04, 0xd0, 0x12, 0x3c, 0x72, 0x89, 0x1b, 0x2c, 0xcc, 0xa8, 0x2a, 0x8b, 0x87, 0xbb, 0x63, 0x1a, 0x28, 0x65, 0xf0, 0xed, 0xf2, 0xc3, 0xc2, 0x0a, 0x06, 0x4a, 0x46, 0xc7, 0xa5, 0xa3, 0x59, 0xc8, 0xb2, 0xc7, 0x45, 0x22, 0x9c, 0x14, 0x54, 0x10, 0x46, 0xf5, 0x1d, 0x32, 0x5c, 0x14, 0x14, 0xe4, 0x32, 0x2f, 0x3a, 0xf3, 0xb6, 0x90, 0x9a, 0x6d, 0xae, 0x9f, 0x3d, 0xab, 0xb8, 0x8a, 0x3b, 0xf8, 0x39, 0x44, 0x58, 0xf0, 0x08, 0xd5, 0x14, 0xa5, 0x7b, 0x65, 0x98, 0x8e, 0xfb, 0xb5, 0x67, 0x87, 0xa5, 0xef, 0x5e, 0x44, 0x96, 0x35, 0xb5, 0xb6, 0x59, 0x36, 0xfd, 0xd8, 0xa0, 0xf1, 0x20, 0x53, 0x33, 0xc0, 0x79, 0x59, 0x73, 0x7c, 0xd7, 0xf9, 0xfb, 0xa2, 0xcd, 0x67, 0xf9, 0xa7, 0x7b, 0x72, 0xf1, 0x71, 0x83, 0x53, 0x86, 0x0b, 0x98, 0x24, 0x22, 0x8a, 0xcc, 0x88, 0x23, 0x7f, 0xb8, 0xae, 0xf9, 0x7c, 0x50, 0x1e, 0x5f, 0x7c, 0x48, 0x21, 0x44, 0x6b, 0xce, 0x9b, 0xb0, 0x1b, 0x9e, 0xf5, 0xaf, 0x8e, 0x4d, 0x5f, 0x7a, 0x7f, 0xce, 0x34, 0xf9, 0x5d, 0x3c, 0xa3, 0xf9, 0x69, 0x63, 0xa9, 0x3c, 0x27, 0xeb, 0xda, 0xe1, 0x37, 0xd7, 0x2e, 0xaa, 0xdb, 0x06, 0xda, 0x30, 0x49, 0xfe, 0x54, 0x03, 0x03, 0x49, 0xdc, 0xb3, 0xaf, 0x38, 0xfe, 0x6a, 0xf9, 0x47, 0xc9, 0x3a, 0x74, 0x97, 0xfa, 0xf6, 0xaf, 0x15, 0x85, 0xb8, 0x75, 0x89, 0xb8, 0x87, 0x9a, 0x72, 0xee, 0x2a, 0x14, 0x24, 0x60, 0xb1, 0xa8, 0xdf, 0x07, 0x0b, 0x2d, 0xcb, 0xcf, 0x7f, 0xe8, 0x6a, 0xff, 0x00, 0x26, 0xbd, 0x6a, 0x7f, 0x89, 0x2f, 0xf8, 0x52, 0x9e, 0xb7, 0xe8, 0xb9, 0xb8, 0x57, 0xc2, 0x95, 0xe9, 0x8f, 0x08, 0x5a, 0x2f, 0xff, 0xd0, 0xf0, 0x4d, 0x40, 0xaa, 0xd7, 0x00, 0x64, 0xcb, 0x3c, 0x97, 0xa8, 0xb5, 0x9e, 0xa3, 0x1a, 0xd6, 0x84, 0x95, 0x3f, 0x45, 0x72, 0x9c, 0xa2, 0xc3, 0x99, 0xa5, 0x9d, 0x49, 0xf4, 0x17, 0x97, 0xaf, 0x63, 0x17, 0x52, 0x6f, 0xf0, 0xc8, 0x43, 0x6f, 0x9a, 0xe9, 0x07, 0x70, 0x0e, 0xec, 0x83, 0x51, 0x44, 0xb8, 0x61, 0x1a, 0x9e, 0x11, 0xd3, 0x91, 0x60, 0x68, 0x6b, 0xd3, 0x31, 0x4f, 0x36, 0xd3, 0x4c, 0x52, 0xef, 0x4c, 0xd5, 0x0c, 0xc4, 0x69, 0xda, 0x94, 0xc8, 0x3a, 0xf0, 0x66, 0x07, 0x73, 0xe0, 0x40, 0xfd, 0x79, 0x93, 0x12, 0x1c, 0x9c, 0x32, 0xc7, 0xfc, 0x41, 0x33, 0xd2, 0xb4, 0x6f, 0x38, 0x98, 0x65, 0x76, 0xbf, 0x69, 0x42, 0xd0, 0xaa, 0xc9, 0xde, 0x95, 0xad, 0x28, 0x46, 0x4e, 0xac, 0x39, 0x77, 0x80, 0x11, 0xbf, 0xd8, 0xc7, 0x7c, 0xe1, 0xa5, 0xf9, 0x92, 0x4d, 0x32, 0x5b, 0x8b, 0x93, 0x27, 0xa7, 0x68, 0x56, 0xe2, 0x45, 0xda, 0x85, 0x61, 0x6e, 0x67, 0xad, 0x6b, 0xb0, 0x38, 0xc2, 0x81, 0xe4, 0xc7, 0x52, 0x31, 0x1c, 0x67, 0x86, 0x5b, 0xbd, 0x37, 0xca, 0x7a, 0x94, 0xb1, 0x69, 0xb6, 0x2e, 0xb7, 0x15, 0x48, 0xc2, 0xb4, 0x52, 0x53, 0xac, 0x32, 0xaf, 0xb1, 0xed, 0x9b, 0x10, 0x36, 0x78, 0x5c, 0x9f, 0x51, 0x64, 0x1f, 0x98, 0x3e, 0x58, 0xb6, 0xfc, 0xc8, 0xf2, 0xe5, 0xbc, 0x68, 0x52, 0x2d, 0x5a, 0xd1, 0x84, 0xb6, 0xf3, 0x95, 0x0e, 0xc0, 0x85, 0xe2, 0xcb, 0xd8, 0xd1, 0xbb, 0xe4, 0xc1, 0xa6, 0x97, 0xce, 0x17, 0x5f, 0x95, 0xde, 0x6d, 0xb6, 0xbe, 0xb7, 0x69, 0x34, 0xf3, 0x3c, 0x72, 0xcf, 0xe8, 0xa3, 0x45, 0x49, 0x95, 0x4a, 0x90, 0x3e, 0x35, 0x5a, 0x95, 0x1d, 0xfe, 0x21, 0x93, 0x4d, 0xbe, 0xd2, 0xd2, 0xf5, 0x8b, 0xbd, 0x32, 0x2d, 0x3f, 0x4c, 0x9a, 0xe4, 0xca, 0x9e, 0x90, 0x85, 0x65, 0x55, 0x08, 0x85, 0x91, 0x01, 0x3b, 0x0a, 0x05, 0xe9, 0xb0, 0xc0, 0x5a, 0xc3, 0xcd, 0x3f, 0x3b, 0x7f, 0x26, 0xec, 0xff, 0x00, 0x35, 0x6d, 0x6d, 0xb5, 0x3d, 0x16, 0xfe, 0x0d, 0x3b, 0xcd, 0x96, 0x01, 0x92, 0x46, 0x9e, 0xa2, 0x0b, 0xc8, 0xb7, 0x28, 0x92, 0x71, 0xfb, 0x2e, 0xa7, 0xec, 0x3d, 0x0f, 0xc2, 0x68, 0x71, 0x05, 0x95, 0xd3, 0xe7, 0x9f, 0xfa, 0x16, 0x2f, 0xcd, 0x7f, 0x43, 0xd6, 0xfa, 0xa5, 0x97, 0xab, 0xeb, 0x7a, 0x5f, 0x55, 0xfa, 0xec, 0x5e, 0xaf, 0x0f, 0xf7, 0xed, 0x2b, 0x4e, 0x15, 0xff, 0x00, 0x65, 0xdf, 0x8e, 0x14, 0xf1, 0xbf, 0xff, 0xd1, 0xf0, 0x5a, 0xa7, 0x18, 0x5e, 0x56, 0x1f, 0x68, 0x71, 0x5f, 0xa7, 0xbe, 0x2a, 0x98, 0xdb, 0xfa, 0x90, 0x24, 0x37, 0xb0, 0xfd, 0xb8, 0xa8, 0x58, 0x78, 0xae, 0x43, 0xc9, 0xb4, 0x6d, 0xbb, 0xda, 0x3c, 0xa1, 0xad, 0x43, 0xa8, 0xda, 0xc5, 0x2a, 0x3d, 0x26, 0x5a, 0x02, 0x2b, 0xbe, 0x60, 0x64, 0x8d, 0x17, 0x6f, 0x8b, 0x20, 0x90, 0x7a, 0x3c, 0x32, 0x8b, 0xa8, 0x02, 0xf3, 0xfd, 0xe0, 0x1b, 0x11, 0x98, 0x66, 0x3b, 0xb9, 0x62, 0x54, 0x83, 0x36, 0xf2, 0xa4, 0xe4, 0x29, 0x34, 0xeb, 0xc8, 0x74, 0xae, 0x0d, 0xc3, 0x65, 0x82, 0x13, 0x6b, 0x57, 0xba, 0x54, 0xe4, 0x8c, 0x41, 0x1b, 0x75, 0xa7, 0xe0, 0x72, 0x5c, 0x4c, 0x84, 0x50, 0x5a, 0xb3, 0xdd, 0xdd, 0xc3, 0x24, 0x33, 0xb1, 0x60, 0xe0, 0x86, 0x52, 0x45, 0x38, 0xd2, 0x87, 0x24, 0x26, 0x6d, 0x8c, 0xe1, 0x41, 0x25, 0xfc, 0xa3, 0xd7, 0x2f, 0x6f, 0x3c, 0xbf, 0x73, 0xa5, 0xb2, 0x2c, 0xd1, 0x69, 0x17, 0x2f, 0x6b, 0x14, 0x8c, 0x0f, 0x21, 0x0d, 0x79, 0x46, 0x09, 0x15, 0xed, 0xb7, 0x4e, 0xd9, 0xb9, 0x8b, 0xcb, 0xe4, 0xa2, 0x5e, 0xa3, 0xa6, 0xdf, 0x6a, 0x36, 0xe4, 0xcd, 0x69, 0x1c, 0x4e, 0x84, 0x7c, 0x76, 0xab, 0x21, 0x67, 0xa8, 0xa7, 0xd9, 0xf8, 0x4d, 0x2b, 0xf3, 0xc3, 0x4d, 0x49, 0x57, 0x98, 0x75, 0x6f, 0x31, 0xda, 0xf9, 0xa3, 0x4b, 0xfd, 0x1f, 0x69, 0x1d, 0xae, 0xa1, 0xa9, 0x7e, 0xee, 0xe6, 0xd2, 0x79, 0x18, 0xf3, 0xb5, 0x1f, 0xee, 0xd9, 0x0a, 0x01, 0x4e, 0x3f, 0xb3, 0x4d, 0xf2, 0x9c, 0xb9, 0x04, 0x05, 0xb7, 0xe2, 0x87, 0x1e, 0xdd, 0x19, 0x3e, 0xaf, 0x6b, 0xae, 0xcb, 0x6d, 0x13, 0x0d, 0x45, 0xa2, 0x8e, 0x06, 0xe5, 0x13, 0x2a, 0x02, 0x01, 0x5e, 0x82, 0xb5, 0x04, 0xe6, 0x11, 0xd4, 0xcd, 0xda, 0x43, 0x49, 0x8e, 0xb7, 0xdc, 0xb1, 0x51, 0xe6, 0x4d, 0x76, 0xd2, 0x61, 0x15, 0xaa, 0x4b, 0xa8, 0xc9, 0x6e, 0x49, 0x79, 0x20, 0xe6, 0x8c, 0x49, 0xad, 0x43, 0x16, 0xe4, 0xa7, 0xaf, 0x43, 0xd3, 0x26, 0x35, 0x75, 0xcd, 0xa8, 0xe8, 0x87, 0x46, 0xbf, 0xc7, 0x9a, 0xff, 0x00, 0xd6, 0xbf, 0x48, 0xfe, 0x88, 0xfd, 0xe7, 0x0f, 0xab, 0xfa, 0x3f, 0x58, 0x7f, 0x5f, 0x8d, 0x3f, 0x9f, 0xa7, 0x5e, 0xd4, 0xc3, 0xf9, 0xd1, 0x7c, 0xb6, 0x47, 0xe4, 0x3a, 0x5b, 0xff, 0xd2, 0xf0, 0xb7, 0xa6, 0x1e, 0xdf, 0xd3, 0xf6, 0xa5, 0x71, 0x54, 0xdb, 0x4b, 0x80, 0x3c, 0x42, 0x26, 0xee, 0x29, 0xbe, 0x51, 0x23, 0x4e, 0x44, 0x05, 0x84, 0x45, 0xa5, 0xd5, 0xf7, 0x97, 0x2e, 0xfd, 0x6b, 0x6a, 0x98, 0x09, 0xab, 0xc7, 0xfc, 0x46, 0x3b, 0x4c, 0x26, 0x32, 0x30, 0x3e, 0x4f, 0x49, 0xd0, 0xfc, 0xfb, 0x05, 0xd4, 0x4a, 0x7d, 0x40, 0xac, 0x3a, 0x8e, 0x84, 0x1c, 0xc5, 0x96, 0x2a, 0x73, 0xe1, 0x9c, 0x16, 0x6d, 0xa5, 0x79, 0x86, 0xd6, 0xec, 0x80, 0x5a, 0xa0, 0xf5, 0xca, 0xcc, 0x5c, 0xa1, 0x2b, 0x1b, 0x26, 0x30, 0x6a, 0x31, 0x46, 0xcf, 0x1c, 0x87, 0x94, 0x64, 0x9e, 0x3d, 0xb6, 0xf0, 0xca, 0xa8, 0x39, 0x51, 0x99, 0x42, 0x6b, 0x1a, 0xc5, 0xa5, 0xa5, 0x94, 0xf7, 0x92, 0xc8, 0xaa, 0xb1, 0x23, 0x30, 0x04, 0xf8, 0x0e, 0x9f, 0x4e, 0x4a, 0x11, 0xb2, 0xd5, 0x9b, 0x25, 0x06, 0x1b, 0xff, 0x00, 0x38, 0xfd, 0xad, 0xdf, 0xda, 0xf9, 0xa2, 0xfe, 0xc5, 0x42, 0xbe, 0x9b, 0x7f, 0x0b, 0xdd, 0xdd, 0x07, 0xaf, 0x14, 0x68, 0xd8, 0x71, 0x6d, 0xbb, 0x90, 0xfc, 0x73, 0x6e, 0xf2, 0xf2, 0xdd, 0xf4, 0xad, 0xa6, 0xab, 0x6d, 0x69, 0x14, 0xfa, 0xee, 0xa0, 0xe2, 0x0b, 0x0d, 0x39, 0x19, 0xfe, 0x11, 0xc5, 0x1a, 0x4a, 0x1d, 0x8f, 0x73, 0x4f, 0xf8, 0x96, 0x0b, 0x40, 0x8d, 0xec, 0xf3, 0x6d, 0x3f, 0x52, 0xba, 0xd6, 0x35, 0x8b, 0xbf, 0x36, 0x6a, 0x5f, 0x0d, 0xc5, 0xdc, 0xa8, 0xb6, 0xa8, 0x7a, 0xc5, 0x6c, 0x9b, 0x22, 0x0f, 0xa3, 0x73, 0x9a, 0xbc, 0xb3, 0xe2, 0x36, 0xed, 0xb1, 0x43, 0x80, 0x53, 0xd0, 0xa7, 0xd4, 0x44, 0xfa, 0x7a, 0xda, 0x83, 0xbd, 0x3e, 0x2f, 0xa7, 0x2b, 0xad, 0x9b, 0xb8, 0x8d, 0xa8, 0xe8, 0x91, 0xdb, 0xfa, 0x2d, 0x6f, 0xc3, 0x8a, 0x2d, 0x56, 0xa3, 0xad, 0x4f, 0x5c, 0xa4, 0x0d, 0xdc, 0xa3, 0xca, 0xd0, 0xbf, 0xa1, 0xe3, 0xfa, 0xe7, 0x0f, 0xf2, 0xb9, 0x57, 0xbf, 0x1a, 0xe4, 0xb8, 0x57, 0xc5, 0xdd, 0xff, 0xd3, 0xf0, 0xcc, 0x5d, 0x7b, 0x70, 0xc5, 0x53, 0x6d, 0x2f, 0xd5, 0xe4, 0x69, 0xfd, 0xdf, 0xec, 0xd7, 0xad, 0x7d, 0xb2, 0x8c, 0x8d, 0xd8, 0xed, 0x91, 0x9f, 0x43, 0xea, 0xe7, 0xeb, 0x94, 0xad, 0x3e, 0x1e, 0x95, 0xfc, 0x72, 0x81, 0x7d, 0x1c, 0x9d, 0xba, 0xb1, 0x7b, 0xdf, 0xa9, 0x7a, 0xdf, 0xee, 0x2f, 0xd4, 0xfa, 0xe7, 0xed, 0x7a, 0x7f, 0xdd, 0xff, 0x00, 0xb2, 0xae, 0x64, 0x0b, 0xea, 0xe3, 0x9a, 0xbf, 0x4a, 0x6f, 0xa4, 0xff, 0x00, 0x89, 0xbd, 0x45, 0xfa, 0xb5, 0x79, 0xf7, 0xeb, 0xc7, 0xe9, 0xae, 0x57, 0x2e, 0x17, 0x23, 0x1f, 0x89, 0xd1, 0x99, 0x8f, 0xf1, 0xa7, 0x11, 0xcf, 0xd3, 0xf5, 0x29, 0xb5, 0x6b, 0xd3, 0xe8, 0xcc, 0x7f, 0x45, 0xb9, 0xa3, 0xc5, 0x62, 0xbe, 0x68, 0xff, 0x00, 0x15, 0xfd, 0x4c, 0xfe, 0x90, 0xaf, 0xd4, 0xab, 0xf1, 0x7a, 0x7f, 0x62, 0x9d, 0xab, 0xdf, 0x32, 0xb1, 0x70, 0x5e, 0xdc, 0xdc, 0x2d, 0x47, 0x8b, 0x5e, 0xae, 0x4c, 0xbf, 0xf2, 0x37, 0x9f, 0x3d, 0x5b, 0xd2, 0xff, 0x00, 0x8e, 0x87, 0xee, 0x29, 0x5a, 0xf2, 0xf4, 0xaa, 0xd4, 0xa5, 0x36, 0xa7, 0x3a, 0x57, 0xfd, 0x8e, 0x64, 0x3a, 0xf2, 0xf6, 0xbf, 0xcc, 0x7f, 0x5b, 0xfc, 0x23, 0xa7, 0xfe, 0x8e, 0xff, 0x00, 0x8e, 0x37, 0xd6, 0x63, 0xfa, 0xe5, 0x2b, 0xcb, 0x87, 0xec, 0xd6, 0xbd, 0xb9, 0x7d, 0xac, 0xc7, 0xcd, 0x7c, 0x2d, 0xf8, 0x2b, 0x89, 0x26, 0x8f, 0xd4, 0xfa, 0x94, 0x3e, 0x85, 0x29, 0xc9, 0x69, 0xfc, 0x33, 0x58, 0x5d, 0x9c, 0x79, 0xb2, 0xbb, 0x0f, 0xac, 0x7a, 0x2b, 0xea, 0x75, 0xef, 0x92, 0x0c, 0x53, 0x3d, 0x2f, 0xd4, 0xfa, 0xbb, 0xfa, 0x74, 0xf5, 0x39, 0x9a, 0xd7, 0xe7, 0x80, 0x53, 0x79, 0xba, 0x5b, 0xfe, 0x97, 0xfa, 0x4b, 0xfc, 0xba, 0x7f, 0xb1, 0xc7, 0xab, 0x1e, 0x8f, 0xff, 0xd9
-};
+    0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
+    0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xe1, 0x0d, 0x07,
+    0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00,
+    0x00, 0x08, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20,
+    0x00, 0x00, 0x00, 0x9e, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0xbe, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
+    0x00, 0x00, 0x00, 0xc3, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0xcc, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0xd4, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14,
+    0x00, 0x00, 0x00, 0xdc, 0x01, 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14,
+    0x00, 0x00, 0x00, 0xf0, 0x01, 0x3c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10,
+    0x00, 0x00, 0x01, 0x04, 0x02, 0x13, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x02, 0x00, 0x00, 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x02, 0xc4, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x00, 0x53, 0x4f, 0x4e, 0x59, 0x00, 0x44, 0x53, 0x43,
+    0x2d, 0x50, 0x32, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00,
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x41, 0x64,
+    0x6f, 0x62, 0x65, 0x20, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f,
+    0x70, 0x20, 0x37, 0x2e, 0x30, 0x00, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30,
+    0x31, 0x3a, 0x33, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x31, 0x30, 0x3a, 0x30,
+    0x34, 0x00, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, 0x20, 0x31,
+    0x30, 0x2e, 0x34, 0x2e, 0x38, 0x00, 0x00, 0x1c, 0x82, 0x9a, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x6a, 0x82, 0x9d, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x72, 0x88, 0x22, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x88, 0x27, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0x00, 0x00, 0x90, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90, 0x03, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x7a, 0x90, 0x04, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x8e, 0x91, 0x01, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x00, 0x91, 0x02, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xa2, 0x92, 0x04, 0x00, 0x0a,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xaa, 0x92, 0x05, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xb2, 0x92, 0x07, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x92, 0x08, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x92, 0x0a, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xba, 0xa0, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x04,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa0, 0x03, 0x00, 0x04,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0xa3, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x09, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0a, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x1c,
+    0x00, 0x00, 0x00, 0x0a, 0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a,
+    0x32, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00,
+    0x32, 0x30, 0x30, 0x37, 0x3a, 0x30, 0x31, 0x3a, 0x32, 0x30, 0x20, 0x32,
+    0x33, 0x3a, 0x30, 0x35, 0x3a, 0x35, 0x32, 0x00, 0x00, 0x00, 0x00, 0x08,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+    0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4f,
+    0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x12, 0x01, 0x1b, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x1a, 0x01, 0x28, 0x00, 0x03,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x22, 0x02, 0x02, 0x00, 0x04,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0xdd, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48,
+    0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46,
+    0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00,
+    0xff, 0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d,
+    0x00, 0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00,
+    0x64, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c,
+    0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a,
+    0x0b, 0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15,
+    0x13, 0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e,
+    0x0e, 0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e,
+    0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11,
+    0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01,
+    0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01,
+    0x3f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05,
+    0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10,
+    0x00, 0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08,
+    0x05, 0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12,
+    0x31, 0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14,
+    0x91, 0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34,
+    0x72, 0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63,
+    0x73, 0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45,
+    0xc2, 0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84,
+    0xc3, 0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95,
+    0xc4, 0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66,
+    0x76, 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57,
+    0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00,
+    0x02, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07,
+    0x06, 0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04,
+    0x41, 0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1,
+    0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72,
+    0x82, 0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16,
+    0xa2, 0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3,
+    0x17, 0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3,
+    0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4,
+    0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86,
+    0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67,
+    0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
+    0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d,
+    0x4d, 0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1,
+    0x1f, 0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1,
+    0x69, 0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3,
+    0xd1, 0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b,
+    0x5b, 0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca,
+    0xd8, 0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75,
+    0x25, 0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a,
+    0x4b, 0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d,
+    0x60, 0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9,
+    0xb1, 0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf,
+    0x04, 0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05,
+    0xbc, 0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90,
+    0xfd, 0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e,
+    0x73, 0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6,
+    0x2a, 0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73,
+    0x80, 0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71,
+    0xf6, 0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7,
+    0x23, 0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd,
+    0xfc, 0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0,
+    0xf3, 0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf,
+    0xe4, 0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e,
+    0x10, 0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8,
+    0x1f, 0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67,
+    0xe4, 0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49,
+    0x05, 0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf,
+    0xe1, 0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a,
+    0x12, 0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa,
+    0x8e, 0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab,
+    0x6a, 0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d,
+    0xff, 0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72,
+    0xab, 0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4,
+    0x92, 0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c,
+    0x8d, 0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f,
+    0x24, 0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc,
+    0x50, 0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63,
+    0x1b, 0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45,
+    0xdb, 0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac,
+    0x3d, 0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc,
+    0xbd, 0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d,
+    0xa5, 0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18,
+    0x04, 0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd,
+    0x3c, 0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28,
+    0x02, 0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70,
+    0x12, 0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde,
+    0xef, 0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67,
+    0x4f, 0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a,
+    0x0e, 0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49,
+    0xf1, 0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b,
+    0x7d, 0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6,
+    0xd9, 0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b,
+    0x48, 0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4,
+    0x0d, 0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83,
+    0x0b, 0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1,
+    0x89, 0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0,
+    0x27, 0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69,
+    0x34, 0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8,
+    0xb9, 0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9,
+    0xae, 0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38,
+    0xf5, 0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6,
+    0xfe, 0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53,
+    0xfa, 0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4,
+    0x1a, 0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7,
+    0x57, 0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56,
+    0xc2, 0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a,
+    0x7c, 0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62,
+    0x66, 0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28,
+    0x9d, 0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92,
+    0x72, 0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce,
+    0xf6, 0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9,
+    0x65, 0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44,
+    0x23, 0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32,
+    0x23, 0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70,
+    0x1a, 0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa,
+    0x99, 0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7,
+    0x27, 0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a,
+    0x22, 0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d,
+    0xee, 0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69,
+    0xfe, 0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92,
+    0xcf, 0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31,
+    0xd9, 0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e,
+    0x55, 0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe,
+    0x90, 0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7,
+    0x45, 0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99,
+    0x69, 0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3,
+    0xeb, 0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1,
+    0x68, 0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8,
+    0x3b, 0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46,
+    0xab, 0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64,
+    0x10, 0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67,
+    0xf3, 0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67,
+    0xa6, 0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f,
+    0x1f, 0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00,
+    0x16, 0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6,
+    0x9e, 0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb,
+    0x8c, 0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26,
+    0x96, 0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d,
+    0xe9, 0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd,
+    0xc4, 0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c,
+    0x13, 0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f,
+    0x92, 0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d,
+    0x43, 0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32,
+    0x6d, 0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e,
+    0x1c, 0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70,
+    0xf2, 0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00,
+    0xa4, 0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4,
+    0xe6, 0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02,
+    0xb6, 0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2,
+    0xb8, 0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2,
+    0x1f, 0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31,
+    0xa2, 0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8,
+    0x6d, 0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1,
+    0x6d, 0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84,
+    0xc0, 0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2,
+    0xe3, 0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68,
+    0x2d, 0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77,
+    0xbb, 0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65,
+    0x7e, 0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa,
+    0xc1, 0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31,
+    0x2e, 0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5,
+    0x4b, 0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6,
+    0xfa, 0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6,
+    0xd5, 0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7,
+    0xf3, 0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32,
+    0xd8, 0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3,
+    0xb3, 0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf,
+    0xfd, 0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e,
+    0xfa, 0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64,
+    0x2b, 0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb,
+    0xab, 0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6,
+    0x57, 0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57,
+    0x63, 0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62,
+    0xc7, 0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3,
+    0x2b, 0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6,
+    0x50, 0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4,
+    0xab, 0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde,
+    0x58, 0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63,
+    0x88, 0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50,
+    0x83, 0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa,
+    0x4c, 0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd,
+    0x58, 0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac,
+    0xcf, 0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf,
+    0xdf, 0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2,
+    0xad, 0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23,
+    0x26, 0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b,
+    0x53, 0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc,
+    0xc6, 0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb,
+    0x76, 0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16,
+    0x83, 0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10,
+    0x06, 0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e,
+    0xd6, 0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3,
+    0xfa, 0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e,
+    0x39, 0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5,
+    0x1b, 0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9,
+    0xb3, 0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef,
+    0x1c, 0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b,
+    0x26, 0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12,
+    0xfa, 0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00,
+    0x4d, 0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3,
+    0xbe, 0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f,
+    0x06, 0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67,
+    0x55, 0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92,
+    0xae, 0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba,
+    0xfc, 0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0,
+    0xc7, 0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5,
+    0xfc, 0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0xff, 0xed, 0x2e,
+    0x1c, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20, 0x33,
+    0x2e, 0x30, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x04, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x2b, 0x1c, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x1c, 0x02,
+    0x78, 0x00, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x38,
+    0x42, 0x49, 0x4d, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfb,
+    0x09, 0xa6, 0xbd, 0x07, 0x4c, 0x2a, 0x36, 0x9d, 0x8f, 0xe2, 0xcc, 0x57,
+    0xa9, 0xac, 0x85, 0x38, 0x42, 0x49, 0x4d, 0x03, 0xea, 0x00, 0x00, 0x00,
+    0x00, 0x1d, 0xb0, 0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72,
+    0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x20, 0x65,
+    0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54, 0x46,
+    0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54,
+    0x59, 0x50, 0x45, 0x20, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x50, 0x55,
+    0x42, 0x4c, 0x49, 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x41, 0x70, 0x70,
+    0x6c, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x2f,
+    0x2f, 0x44, 0x54, 0x44, 0x20, 0x50, 0x4c, 0x49, 0x53, 0x54, 0x20, 0x31,
+    0x2e, 0x30, 0x2f, 0x2f, 0x45, 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74,
+    0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x54, 0x44, 0x73, 0x2f, 0x50,
+    0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x2d,
+    0x31, 0x2e, 0x30, 0x2e, 0x64, 0x74, 0x64, 0x22, 0x3e, 0x0a, 0x3c, 0x70,
+    0x6c, 0x69, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+    0x3d, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x3e, 0x0a, 0x3c, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e,
+    0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c,
+    0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c,
+    0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e,
+    0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79,
+    0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
+    0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69,
+    0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72,
+    0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c,
+    0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64,
+    0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65,
+    0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f,
+    0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x48, 0x6f, 0x72, 0x69, 0x7a,
+    0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65,
+    0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c,
+    0x3e, 0x37, 0x32, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+    0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69,
+    0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73,
+    0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f,
+    0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61,
+    0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33,
+    0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c,
+    0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69,
+    0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c,
+    0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61,
+    0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e,
+    0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69,
+    0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63,
+    0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72,
+    0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c,
+    0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72,
+    0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d,
+    0x61, 0x74, 0x2e, 0x50, 0x4d, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e,
+    0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65,
+    0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c,
+    0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64,
+    0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d,
+    0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a,
+    0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61,
+    0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f,
+    0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f,
+    0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69,
+    0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74,
+    0x2e, 0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f,
+    0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e,
+    0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74,
+    0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e,
+    0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74,
+    0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e,
+    0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e,
+    0x50, 0x4d, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61,
+    0x6c, 0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+    0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69,
+    0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73,
+    0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f,
+    0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61,
+    0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33,
+    0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c,
+    0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69,
+    0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c,
+    0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61,
+    0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e,
+    0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65,
+    0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69,
+    0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63,
+    0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72,
+    0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c,
+    0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72,
+    0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d,
+    0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61,
+    0x6c, 0x52, 0x65, 0x73, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x32, 0x3c,
+    0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72,
+    0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61,
+    0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e,
+    0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d,
+    0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e,
+    0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32,
+    0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32,
+    0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74,
+    0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73,
+    0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65,
+    0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65,
+    0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67,
+    0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79,
+    0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67,
+    0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65,
+    0x72, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e,
+    0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x69,
+    0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63,
+    0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69,
+    0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72,
+    0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c,
+    0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x61, 0x72,
+    0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d,
+    0x61, 0x74, 0x2e, 0x50, 0x4d, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61,
+    0x6c, 0x53, 0x63, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0x3c, 0x2f, 0x6b, 0x65,
+    0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c,
+    0x3e, 0x31, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74,
+    0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e,
+    0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74,
+    0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65,
+    0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74,
+    0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33, 0x30,
+    0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c, 0x2f,
+    0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65,
+    0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c,
+    0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69,
+    0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e,
+    0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f,
+    0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72,
+    0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74,
+    0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x73, 0x75, 0x62, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x61,
+    0x70, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c,
+    0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72,
+    0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75, 0x73, 0x74,
+    0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f,
+    0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65,
+    0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c,
+    0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61,
+    0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c,
+    0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65,
+    0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a,
+    0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63,
+    0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30,
+    0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30, 0x2e, 0x30, 0x3c,
+    0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33, 0x34, 0x3c, 0x2f,
+    0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36, 0x3c, 0x2f, 0x72,
+    0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f,
+    0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f,
+    0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73,
+    0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67,
+    0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72,
+    0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65,
+    0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61,
+    0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d, 0x33,
+    0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a, 0x3c,
+    0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61,
+    0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30, 0x3c,
+    0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x46,
+    0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d, 0x41, 0x64, 0x6a, 0x75,
+    0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65, 0x63,
+    0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64,
+    0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e,
+    0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67,
+    0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41,
+    0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50,
+    0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x50, 0x4d,
+    0x41, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65,
+    0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e,
+    0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c,
+    0x3e, 0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e,
+    0x2d, 0x31, 0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37,
+    0x37, 0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39,
+    0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65,
+    0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c,
+    0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74,
+    0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74,
+    0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d,
+    0x30, 0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a,
+    0x34, 0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74,
+    0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65,
+    0x72, 0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79,
+    0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50,
+    0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50,
+    0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65,
+    0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74,
+    0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70,
+    0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74,
+    0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72,
+    0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61,
+    0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x50, 0x61,
+    0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69,
+    0x6e, 0x67, 0x3e, 0x6e, 0x61, 0x2d, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72,
+    0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+    0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69,
+    0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64,
+    0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30,
+    0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x54, 0x31, 0x37, 0x3a,
+    0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65,
+    0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e,
+    0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+    0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73,
+    0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65,
+    0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74,
+    0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65,
+    0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64,
+    0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72,
+    0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63,
+    0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e,
+    0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64,
+    0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65,
+    0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74,
+    0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70,
+    0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74,
+    0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72,
+    0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61,
+    0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e,
+    0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x67, 0x65,
+    0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e,
+    0x30, 0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x30,
+    0x2e, 0x30, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x33,
+    0x34, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x37, 0x36,
+    0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+    0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x69, 0x6e, 0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69,
+    0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30,
+    0x31, 0x2d, 0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34,
+    0x31, 0x5a, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65,
+    0x46, 0x6c, 0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72,
+    0x3e, 0x30, 0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e,
+    0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e,
+    0x0a, 0x09, 0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e,
+    0x0a, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61,
+    0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e,
+    0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65,
+    0x72, 0x52, 0x65, 0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x3c,
+    0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74,
+    0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e,
+    0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41, 0x72, 0x72, 0x61, 0x79,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x3c, 0x61,
+    0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64,
+    0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72,
+    0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x64, 0x6a,
+    0x75, 0x73, 0x74, 0x65, 0x64, 0x50, 0x61, 0x70, 0x65, 0x72, 0x52, 0x65,
+    0x63, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31,
+    0x38, 0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x2d, 0x31, 0x38,
+    0x3c, 0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x37, 0x37, 0x34, 0x3c,
+    0x2f, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x72, 0x65, 0x61, 0x6c, 0x3e, 0x35, 0x39, 0x34, 0x3c, 0x2f,
+    0x72, 0x65, 0x61, 0x6c, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69,
+    0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c,
+    0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x69, 0x6e,
+    0x67, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74,
+    0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f,
+    0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64,
+    0x61, 0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x37, 0x2d, 0x30, 0x31, 0x2d,
+    0x33, 0x30, 0x54, 0x32, 0x32, 0x3a, 0x30, 0x38, 0x3a, 0x34, 0x31, 0x5a,
+    0x3c, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69,
+    0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c,
+    0x61, 0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x30,
+    0x3c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x70, 0x65,
+    0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64, 0x2e, 0x50, 0x4d,
+    0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e,
+    0x0a, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61,
+    0x74, 0x6f, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d,
+    0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
+    0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x63, 0x72, 0x69,
+    0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a,
+    0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x69, 0x74, 0x65, 0x6d, 0x41,
+    0x72, 0x72, 0x61, 0x79, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x09, 0x09, 0x3c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x50,
+    0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 0x70, 0x64,
+    0x2e, 0x50, 0x4d, 0x50, 0x61, 0x70, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x55, 0x53, 0x20, 0x4c,
+    0x65, 0x74, 0x74, 0x65, 0x72, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e,
+    0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b, 0x65, 0x79,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e,
+    0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e,
+    0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e,
+    0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x70, 0x6d, 0x2e, 0x50, 0x6f, 0x73,
+    0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72,
+    0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65,
+    0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x44, 0x61, 0x74, 0x65, 0x3c, 0x2f, 0x6b,
+    0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3c, 0x64, 0x61,
+    0x74, 0x65, 0x3e, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x30, 0x37, 0x2d, 0x30,
+    0x31, 0x54, 0x31, 0x37, 0x3a, 0x34, 0x39, 0x3a, 0x33, 0x36, 0x5a, 0x3c,
+    0x2f, 0x64, 0x61, 0x74, 0x65, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
+    0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70,
+    0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63,
+    0x6b, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x61,
+    0x67, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x09, 0x09,
+    0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x31, 0x3c,
+    0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09,
+    0x09, 0x3c, 0x2f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3e, 0x0a, 0x09, 0x09,
+    0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65,
+    0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+    0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x73, 0x74,
+    0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30, 0x3c, 0x2f,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b,
+    0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65,
+    0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65,
+    0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x63,
+    0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x66,
+    0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x09, 0x3c, 0x6b, 0x65,
+    0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e,
+    0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74,
+    0x2e, 0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
+    0x09, 0x09, 0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f,
+    0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e,
+    0x74, 0x2e, 0x50, 0x61, 0x70, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x54,
+    0x69, 0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e,
+    0x67, 0x3e, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a,
+    0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70,
+    0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69,
+    0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x50, 0x49, 0x56, 0x65, 0x72, 0x73,
+    0x69, 0x6f, 0x6e, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c,
+    0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x30, 0x30, 0x2e, 0x32, 0x30,
+    0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x0a, 0x09, 0x3c,
+    0x6b, 0x65, 0x79, 0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+    0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b,
+    0x65, 0x74, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4c, 0x6f,
+    0x63, 0x6b, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x66,
+    0x61, 0x6c, 0x73, 0x65, 0x2f, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79,
+    0x3e, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70,
+    0x72, 0x69, 0x6e, 0x74, 0x2e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x2e,
+    0x74, 0x79, 0x70, 0x65, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
+    0x3c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3e, 0x63, 0x6f, 0x6d, 0x2e,
+    0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x2e,
+    0x50, 0x61, 0x67, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x54, 0x69,
+    0x63, 0x6b, 0x65, 0x74, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+    0x3e, 0x0a, 0x3c, 0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x3c, 0x2f,
+    0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e, 0x0a, 0x38, 0x42, 0x49, 0x4d, 0x03,
+    0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0x48, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0xde, 0x02, 0x40, 0xff,
+    0xee, 0xff, 0xee, 0x03, 0x06, 0x02, 0x52, 0x03, 0x67, 0x05, 0x28, 0x03,
+    0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0x00,
+    0x00, 0x02, 0xd8, 0x02, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x01, 0x7f,
+    0xff, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x08, 0x00, 0x19, 0x01, 0x90, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x03,
+    0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x48, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x38,
+    0x42, 0x49, 0x4d, 0x04, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00,
+    0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x19, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0x38, 0x42, 0x49,
+    0x4d, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04,
+    0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x38, 0x42, 0x49,
+    0x4d, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03,
+    0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x2f, 0x66, 0x66, 0x00,
+    0x01, 0x00, 0x6c, 0x66, 0x66, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x2f, 0x66, 0x66, 0x00, 0x01, 0x00, 0xa1, 0x99, 0x9a, 0x00,
+    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x32, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00,
+    0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x42, 0x49, 0x4d, 0x03,
+    0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00,
+    0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+    0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe8, 0x00, 0x00, 0x38,
+    0x42, 0x49, 0x4d, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00,
+    0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x1e, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04,
+    0x1a, 0x00, 0x00, 0x00, 0x00, 0x03, 0x45, 0x00, 0x00, 0x00, 0x06, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00,
+    0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x44, 0x00, 0x53, 0x00,
+    0x43, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x32, 0x00, 0x35, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00,
+    0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x6e, 0x75, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+    0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x4f, 0x62, 0x6a, 0x63,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x63,
+    0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f,
+    0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74, 0x6f, 0x6d, 0x6c, 0x6f,
+    0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x52, 0x67,
+    0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+    0x00, 0x06, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x56, 0x6c, 0x4c, 0x73,
+    0x00, 0x00, 0x00, 0x01, 0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00,
+    0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x73, 0x6c, 0x69, 0x63, 0x65,
+    0x49, 0x44, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x44, 0x6c, 0x6f, 0x6e,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69,
+    0x67, 0x69, 0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0c, 0x45,
+    0x53, 0x6c, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x00,
+    0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x47, 0x65, 0x6e, 0x65, 0x72,
+    0x61, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x54, 0x79, 0x70, 0x65,
+    0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0a, 0x45, 0x53, 0x6c, 0x69,
+    0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6d,
+    0x67, 0x20, 0x00, 0x00, 0x00, 0x06, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73,
+    0x4f, 0x62, 0x6a, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x52, 0x63, 0x74, 0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x00, 0x00, 0x54, 0x6f, 0x70, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x6c, 0x6f,
+    0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x74,
+    0x6f, 0x6d, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+    0x00, 0x00, 0x52, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x6e, 0x67, 0x00, 0x00,
+    0x00, 0x64, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, 0x6c, 0x54, 0x45, 0x58,
+    0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e,
+    0x75, 0x6c, 0x6c, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x73, 0x67, 0x65, 0x54, 0x45, 0x58,
+    0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x61,
+    0x6c, 0x74, 0x54, 0x61, 0x67, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x63, 0x65, 0x6c, 0x6c, 0x54,
+    0x65, 0x78, 0x74, 0x49, 0x73, 0x48, 0x54, 0x4d, 0x4c, 0x62, 0x6f, 0x6f,
+    0x6c, 0x01, 0x00, 0x00, 0x00, 0x08, 0x63, 0x65, 0x6c, 0x6c, 0x54, 0x65,
+    0x78, 0x74, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x09, 0x68, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67,
+    0x6e, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c,
+    0x69, 0x63, 0x65, 0x48, 0x6f, 0x72, 0x7a, 0x41, 0x6c, 0x69, 0x67, 0x6e,
+    0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00,
+    0x00, 0x00, 0x09, 0x76, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e,
+    0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x0f, 0x45, 0x53, 0x6c, 0x69,
+    0x63, 0x65, 0x56, 0x65, 0x72, 0x74, 0x41, 0x6c, 0x69, 0x67, 0x6e, 0x00,
+    0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00,
+    0x00, 0x0b, 0x62, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79, 0x70,
+    0x65, 0x65, 0x6e, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x11, 0x45, 0x53, 0x6c,
+    0x69, 0x63, 0x65, 0x42, 0x47, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x79,
+    0x70, 0x65, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65, 0x00, 0x00,
+    0x00, 0x09, 0x74, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c,
+    0x6f, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6c,
+    0x65, 0x66, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x62, 0x6f, 0x74,
+    0x74, 0x6f, 0x6d, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x72, 0x69, 0x67,
+    0x68, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x65, 0x74, 0x6c, 0x6f, 0x6e, 0x67,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04, 0x11, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x38, 0x42, 0x49, 0x4d, 0x04,
+    0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x38,
+    0x42, 0x49, 0x4d, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf9, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00,
+    0x00, 0x01, 0x2c, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0x09, 0xdd, 0x00,
+    0x18, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49,
+    0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff,
+    0xed, 0x00, 0x0c, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x5f, 0x43, 0x4d, 0x00,
+    0x02, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x00, 0x64,
+    0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0c, 0x08,
+    0x08, 0x08, 0x09, 0x08, 0x0c, 0x09, 0x09, 0x0c, 0x11, 0x0b, 0x0a, 0x0b,
+    0x11, 0x15, 0x0f, 0x0c, 0x0c, 0x0f, 0x15, 0x18, 0x13, 0x13, 0x15, 0x13,
+    0x13, 0x18, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x01, 0x0d, 0x0b, 0x0b, 0x0d, 0x0e, 0x0d, 0x10, 0x0e, 0x0e,
+    0x10, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e, 0x0e, 0x0e, 0x14,
+    0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0, 0x00, 0x11, 0x08,
+    0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
+    0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x07, 0xff, 0xc4, 0x01, 0x3f,
+    0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
+    0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
+    0x01, 0x04, 0x01, 0x03, 0x02, 0x04, 0x02, 0x05, 0x07, 0x06, 0x08, 0x05,
+    0x03, 0x0c, 0x33, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21, 0x12, 0x31,
+    0x05, 0x41, 0x51, 0x61, 0x13, 0x22, 0x71, 0x81, 0x32, 0x06, 0x14, 0x91,
+    0xa1, 0xb1, 0x42, 0x23, 0x24, 0x15, 0x52, 0xc1, 0x62, 0x33, 0x34, 0x72,
+    0x82, 0xd1, 0x43, 0x07, 0x25, 0x92, 0x53, 0xf0, 0xe1, 0xf1, 0x63, 0x73,
+    0x35, 0x16, 0xa2, 0xb2, 0x83, 0x26, 0x44, 0x93, 0x54, 0x64, 0x45, 0xc2,
+    0xa3, 0x74, 0x36, 0x17, 0xd2, 0x55, 0xe2, 0x65, 0xf2, 0xb3, 0x84, 0xc3,
+    0xd3, 0x75, 0xe3, 0xf3, 0x46, 0x27, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4,
+    0xd4, 0xe4, 0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76,
+    0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67,
+    0x77, 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x11, 0x00, 0x02,
+    0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06,
+    0x05, 0x35, 0x01, 0x00, 0x02, 0x11, 0x03, 0x21, 0x31, 0x12, 0x04, 0x41,
+    0x51, 0x61, 0x71, 0x22, 0x13, 0x05, 0x32, 0x81, 0x91, 0x14, 0xa1, 0xb1,
+    0x42, 0x23, 0xc1, 0x52, 0xd1, 0xf0, 0x33, 0x24, 0x62, 0xe1, 0x72, 0x82,
+    0x92, 0x43, 0x53, 0x15, 0x63, 0x73, 0x34, 0xf1, 0x25, 0x06, 0x16, 0xa2,
+    0xb2, 0x83, 0x07, 0x26, 0x35, 0xc2, 0xd2, 0x44, 0x93, 0x54, 0xa3, 0x17,
+    0x64, 0x45, 0x55, 0x36, 0x74, 0x65, 0xe2, 0xf2, 0xb3, 0x84, 0xc3, 0xd3,
+    0x75, 0xe3, 0xf3, 0x46, 0x94, 0xa4, 0x85, 0xb4, 0x95, 0xc4, 0xd4, 0xe4,
+    0xf4, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x56, 0x66, 0x76, 0x86, 0x96,
+    0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+    0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00,
+    0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf2, 0xed, 0xb2, 0x8d, 0x4d,
+    0x45, 0xcd, 0x2f, 0x3f, 0x44, 0x68, 0x93, 0xc3, 0x58, 0xc8, 0xf1, 0x1f,
+    0x8a, 0x33, 0x86, 0xda, 0x58, 0xc1, 0xa0, 0x02, 0x4f, 0xc4, 0xa1, 0x69,
+    0xa5, 0x9b, 0x5b, 0x4b, 0x84, 0x73, 0xdf, 0xc9, 0x15, 0xf8, 0xe3, 0xd1,
+    0x0e, 0x07, 0x93, 0xf3, 0xd1, 0x0f, 0x1c, 0x17, 0xef, 0x2e, 0x3b, 0x5b,
+    0xdc, 0xff, 0x00, 0xdf, 0x42, 0xbf, 0x8f, 0x8e, 0xdc, 0x82, 0xca, 0xd8,
+    0x37, 0x11, 0xa9, 0x3d, 0x82, 0x69, 0x2b, 0xc4, 0x6d, 0xc9, 0x75, 0x25,
+    0xbc, 0xf7, 0xec, 0xa1, 0xb5, 0x74, 0x19, 0x5d, 0x2e, 0x8a, 0x9a, 0x4b,
+    0x89, 0x7d, 0xc4, 0x68, 0xc6, 0xf6, 0xfe, 0xb2, 0xa0, 0x30, 0x1d, 0x60,
+    0x86, 0x88, 0x8d, 0x49, 0x3e, 0x01, 0x11, 0x20, 0xa3, 0x8c, 0xb9, 0xb1,
+    0xaa, 0x62, 0xad, 0xbf, 0x18, 0x97, 0x43, 0x47, 0x1d, 0xd2, 0xaf, 0x04,
+    0xd9, 0xb8, 0xc8, 0x0d, 0x68, 0xe4, 0xf7, 0x3e, 0x48, 0xf1, 0x05, 0xbc,
+    0x25, 0xaa, 0x07, 0x71, 0xd9, 0x14, 0x78, 0xf6, 0x49, 0xb5, 0x90, 0xfd,
+    0xa7, 0xc6, 0x14, 0xfd, 0x1b, 0x1c, 0xff, 0x00, 0x4d, 0x8d, 0x2e, 0x73,
+    0x8c, 0x35, 0xa3, 0x52, 0x4f, 0x92, 0x48, 0xa6, 0x1a, 0x24, 0xb6, 0x2a,
+    0xfa, 0xa5, 0x9e, 0x60, 0x64, 0x39, 0x94, 0x13, 0xcb, 0x27, 0x73, 0x80,
+    0xf3, 0x0c, 0xf6, 0xff, 0x00, 0xd2, 0x5a, 0x78, 0xbf, 0x53, 0x71, 0xf6,
+    0x01, 0x75, 0xb6, 0x97, 0x6a, 0x25, 0xa1, 0xad, 0x1f, 0xf4, 0xb7, 0x23,
+    0x48, 0xb7, 0x94, 0x84, 0x97, 0x5b, 0xff, 0x00, 0x32, 0xa9, 0xdd, 0xfc,
+    0xed, 0x9b, 0x7e, 0x0d, 0x9e, 0x52, 0x4a, 0x95, 0x61, 0xff, 0xd0, 0xf3,
+    0x3b, 0xa7, 0x70, 0xee, 0x01, 0x8f, 0xb9, 0x59, 0xfa, 0x7e, 0xdf, 0xe4,
+    0xc8, 0xf9, 0x2a, 0xc2, 0x5c, 0x63, 0xc3, 0x54, 0x67, 0x87, 0x6e, 0x10,
+    0x35, 0x68, 0xd4, 0x79, 0x1e, 0x53, 0x4a, 0xe0, 0xdc, 0xe9, 0xb8, 0x1f,
+    0x6a, 0xda, 0x6c, 0x25, 0x94, 0x37, 0xb0, 0xd0, 0xb8, 0xad, 0x67, 0xe4,
+    0x55, 0x8a, 0x5b, 0x8b, 0x82, 0xc0, 0x6f, 0x76, 0x80, 0x34, 0x49, 0x05,
+    0x2e, 0x9e, 0xc6, 0x1c, 0x66, 0x31, 0xba, 0x10, 0x23, 0xe0, 0xaf, 0xe1,
+    0x61, 0x53, 0x43, 0x8d, 0x81, 0xb3, 0x67, 0xef, 0x9e, 0x49, 0x2a, 0x12,
+    0x6c, 0xb6, 0x63, 0x1a, 0x0c, 0x31, 0xba, 0x55, 0xcd, 0xac, 0xfa, 0x8e,
+    0xdf, 0x91, 0x6e, 0x91, 0xd9, 0xb3, 0xc9, 0x73, 0x90, 0x7a, 0xab, 0x6a,
+    0xc2, 0xa4, 0x60, 0xe2, 0x8f, 0xd2, 0x38, 0x03, 0x7d, 0x9e, 0x0d, 0xff,
+    0x00, 0xcc, 0xd6, 0xd3, 0x6b, 0x71, 0x67, 0xd2, 0x3e, 0x64, 0x72, 0xab,
+    0xdb, 0x8d, 0x54, 0x39, 0xc5, 0x83, 0x6b, 0x3d, 0xee, 0x2e, 0xd4, 0x92,
+    0x3c, 0x4a, 0x56, 0xba, 0xb4, 0x79, 0x5c, 0xf7, 0xb2, 0x96, 0x6c, 0x8d,
+    0xaf, 0x80, 0x48, 0x3c, 0xf0, 0xb2, 0x1f, 0x63, 0x9c, 0xe9, 0x3f, 0x24,
+    0x5c, 0xdb, 0xdd, 0x76, 0x43, 0xde, 0xfd, 0x5c, 0xe3, 0x24, 0xfc, 0x50,
+    0x00, 0x93, 0x0a, 0x78, 0x8a, 0x0d, 0x49, 0xca, 0xcf, 0x93, 0x63, 0x1b,
+    0x7d, 0xd7, 0x57, 0x50, 0xd5, 0xef, 0x70, 0x6b, 0x4f, 0xc7, 0x45, 0xdb,
+    0x74, 0x9e, 0x8d, 0x5e, 0x33, 0x83, 0xd8, 0x37, 0xdd, 0xc3, 0xac, 0x3d,
+    0xbf, 0x92, 0xc5, 0x5b, 0xea, 0xbf, 0xd5, 0x62, 0xc0, 0xdc, 0xbc, 0xbd,
+    0x2d, 0x22, 0x5a, 0xcf, 0xdd, 0x69, 0xff, 0x00, 0xd1, 0x8e, 0x5d, 0xa5,
+    0x38, 0xb5, 0xb0, 0x00, 0xc6, 0xc4, 0x24, 0x4a, 0xd6, 0x8d, 0x18, 0x04,
+    0x49, 0x88, 0x9e, 0x55, 0xd6, 0x61, 0xb0, 0xc1, 0x70, 0x32, 0xdd, 0x3c,
+    0x95, 0xda, 0xf1, 0xfe, 0xf5, 0x62, 0xbc, 0x76, 0x8e, 0x75, 0x28, 0x02,
+    0xa2, 0xe7, 0x7d, 0x92, 0xb9, 0x84, 0x96, 0x96, 0xda, 0xf7, 0x70, 0x12,
+    0x4e, 0x5a, 0xff, 0x00, 0xff, 0xd1, 0xf3, 0x7a, 0x21, 0xaf, 0xde, 0xef,
+    0xa2, 0x22, 0x55, 0xfc, 0x5a, 0xbd, 0x42, 0xfb, 0x08, 0xfa, 0x67, 0x4f,
+    0x82, 0xcd, 0x6d, 0x85, 0xc0, 0x56, 0x3b, 0x90, 0xb7, 0xf0, 0x2a, 0x0e,
+    0x63, 0x58, 0x3b, 0xf2, 0xa3, 0x9e, 0x8c, 0xb8, 0x86, 0xbe, 0x49, 0xf1,
+    0x2c, 0x0c, 0x86, 0xb4, 0x4c, 0x69, 0xe4, 0xaf, 0x6e, 0xcc, 0x6b, 0x7d,
+    0x46, 0xb3, 0x70, 0xec, 0x38, 0x51, 0x7d, 0x02, 0x8a, 0xc7, 0xa6, 0xd9,
+    0x20, 0x68, 0x0f, 0x8f, 0x8a, 0xcf, 0xc9, 0xc2, 0xea, 0x59, 0x5b, 0x48,
+    0xb0, 0x91, 0xae, 0xe6, 0xc9, 0x03, 0xc9, 0x30, 0x51, 0x66, 0xd4, 0x0d,
+    0xad, 0xbd, 0x5f, 0x53, 0xcc, 0x6b, 0xb6, 0x90, 0x5a, 0x3b, 0x83, 0x0b,
+    0x43, 0x17, 0x31, 0xd6, 0xc3, 0x6e, 0x12, 0x3b, 0x79, 0xac, 0xc1, 0x89,
+    0x47, 0xd9, 0xe8, 0x63, 0x98, 0x45, 0xed, 0x6c, 0x5a, 0xf1, 0xa0, 0x27,
+    0xc5, 0x5b, 0xc3, 0x6f, 0xa6, 0xe0, 0x1c, 0x7d, 0xb3, 0xa2, 0x69, 0x34,
+    0x7b, 0xae, 0x1a, 0x8d, 0x45, 0x17, 0x9d, 0xeb, 0xfd, 0x21, 0xd8, 0xb9,
+    0xae, 0xb5, 0x80, 0xbb, 0x1e, 0xd2, 0x5c, 0xd7, 0x78, 0x13, 0xf9, 0xae,
+    0x4b, 0xea, 0xc7, 0x4a, 0x39, 0xbd, 0x55, 0xb3, 0xed, 0x66, 0x38, 0xf5,
+    0x09, 0x22, 0x41, 0x23, 0xe8, 0x37, 0xfb, 0x4b, 0xa1, 0xeb, 0xd6, 0xfe,
+    0x88, 0x31, 0xbf, 0x41, 0xc0, 0xee, 0xd2, 0x74, 0x02, 0x78, 0x53, 0xfa,
+    0x97, 0x43, 0x19, 0x85, 0x65, 0xff, 0x00, 0x9d, 0x71, 0x33, 0xe4, 0x1a,
+    0x7d, 0x8d, 0x53, 0x42, 0x56, 0x35, 0x6b, 0xe5, 0x80, 0x06, 0xc7, 0x57,
+    0xa7, 0xc4, 0xa9, 0xdb, 0xb6, 0x81, 0x1f, 0xeb, 0xd9, 0x69, 0x56, 0xc2,
+    0xd0, 0x00, 0xe5, 0x55, 0xc0, 0x12, 0xc2, 0xd7, 0x4e, 0xa2, 0x5a, 0x7c,
+    0x0a, 0xd0, 0x63, 0x9a, 0xd1, 0xaf, 0xd2, 0xe2, 0x3c, 0x12, 0x62, 0x66,
+    0xc6, 0x42, 0x23, 0x5a, 0x49, 0x8f, 0x10, 0xa2, 0xd2, 0x3e, 0x28, 0x9d,
+    0xc4, 0x88, 0x09, 0x29, 0x16, 0xc3, 0x3c, 0x24, 0x8d, 0xe6, 0x92, 0x72,
+    0x1f, 0xff, 0xd2, 0xf3, 0xbb, 0xb0, 0xfe, 0xcb, 0x99, 0xe9, 0xce, 0xf6,
+    0x88, 0x2d, 0x77, 0x91, 0x5b, 0x3d, 0x3d, 0xd0, 0xe6, 0x90, 0xa9, 0x65,
+    0x57, 0x38, 0x95, 0xdd, 0xcb, 0x9a, 0x7d, 0xce, 0xf2, 0x3f, 0x44, 0x23,
+    0x60, 0x58, 0x76, 0xe9, 0xca, 0x8c, 0xea, 0x1b, 0x31, 0x02, 0x32, 0x23,
+    0xea, 0xee, 0xb1, 0xcd, 0xb0, 0xc7, 0x87, 0x74, 0x7a, 0xeb, 0x70, 0x1a,
+    0x71, 0xe1, 0xfe, 0xe4, 0x1c, 0x1d, 0xae, 0xe5, 0x69, 0xd8, 0xfa, 0x99,
+    0x50, 0x0d, 0x1a, 0xf7, 0x2a, 0x3a, 0x0c, 0xf4, 0x1a, 0x8e, 0xc7, 0x27,
+    0x5d, 0xbf, 0x18, 0x41, 0xdc, 0xc2, 0xf0, 0x7f, 0x74, 0xf6, 0x3a, 0x22,
+    0x66, 0xdb, 0x68, 0xc6, 0x80, 0x48, 0x6b, 0x88, 0x06, 0x39, 0x0d, 0xee,
+    0xaa, 0x1f, 0xb3, 0xd5, 0x1b, 0x83, 0xd8, 0x3b, 0x38, 0x8f, 0x69, 0xfe,
+    0xdf, 0xd1, 0x4d, 0x29, 0xa1, 0x4c, 0x7a, 0xf4, 0xbf, 0xa7, 0x92, 0xcf,
+    0xa5, 0x20, 0x08, 0xf3, 0xf6, 0xff, 0x00, 0x15, 0xbb, 0xd1, 0x31, 0xd9,
+    0x5e, 0x3d, 0x75, 0x56, 0x36, 0x88, 0x00, 0x81, 0xe0, 0x16, 0x5e, 0x55,
+    0x74, 0x3f, 0x00, 0x9d, 0xe0, 0xcc, 0x69, 0xe7, 0x3a, 0x2d, 0xbe, 0x90,
+    0x00, 0xa9, 0xae, 0xef, 0x1f, 0x95, 0x4b, 0x0d, 0x9a, 0xdc, 0xc7, 0x45,
+    0xfe, 0xb1, 0x7d, 0x60, 0xa7, 0xa1, 0xe0, 0x1f, 0x4e, 0x1d, 0x99, 0x69,
+    0x02, 0x9a, 0xcf, 0x1f, 0xca, 0x7b, 0xbf, 0x90, 0xc5, 0xc2, 0xb3, 0xeb,
+    0x57, 0xd6, 0x03, 0x6b, 0xae, 0x39, 0xb6, 0x82, 0xe3, 0x31, 0xa1, 0x68,
+    0xf2, 0x6b, 0x5c, 0x12, 0xfa, 0xe1, 0x91, 0x66, 0x47, 0x5d, 0xb8, 0x3b,
+    0x4f, 0x44, 0x36, 0xb6, 0x8f, 0x28, 0xdd, 0xff, 0x00, 0x7e, 0x46, 0xab,
+    0x12, 0x2b, 0x65, 0x55, 0x32, 0xa7, 0x62, 0xb6, 0xbd, 0xf7, 0x64, 0x10,
+    0xdb, 0x03, 0x9f, 0x1b, 0x9e, 0xc7, 0xd9, 0xb8, 0x3b, 0x1f, 0x67, 0xf3,
+    0x6c, 0x52, 0x80, 0xd7, 0x7d, 0x0f, 0xea, 0x7f, 0x5d, 0x1d, 0x67, 0xa6,
+    0x0b, 0x1e, 0x47, 0xda, 0x69, 0x3b, 0x2e, 0x03, 0xc7, 0xf3, 0x5f, 0x1f,
+    0xf0, 0x8b, 0xa1, 0x02, 0x46, 0xba, 0x79, 0xaf, 0x32, 0xff, 0x00, 0x16,
+    0xad, 0xca, 0x1d, 0x57, 0x2a, 0xdc, 0x79, 0x18, 0x41, 0xb0, 0xf6, 0x9e,
+    0xe4, 0x9f, 0xd0, 0x8f, 0xeb, 0x31, 0xab, 0xd2, 0x83, 0xa4, 0xcb, 0x8c,
+    0xb8, 0xa0, 0x42, 0x12, 0x7b, 0x67, 0x9f, 0x2f, 0xf5, 0x09, 0x26, 0x96,
+    0xc4, 0xce, 0xa9, 0x20, 0xa7, 0xff, 0xd3, 0xf3, 0x2f, 0xb4, 0x5d, 0xe9,
+    0x0a, 0xb7, 0x9f, 0x4c, 0x19, 0xdb, 0x3a, 0x2d, 0x5e, 0x94, 0xfd, 0xc4,
+    0xb7, 0xc5, 0x62, 0xf9, 0x2b, 0xfd, 0x2e, 0xe3, 0x5d, 0xe0, 0x7c, 0x13,
+    0x48, 0xd1, 0x92, 0x12, 0xa9, 0x0b, 0x7a, 0xbc, 0x2d, 0xc2, 0x7f, 0x92,
+    0x60, 0xab, 0x4e, 0x79, 0x2e, 0x00, 0xf0, 0xaa, 0xe1, 0xda, 0x3d, 0x43,
+    0xfc, 0xad, 0x55, 0xbb, 0x80, 0x79, 0x81, 0xa0, 0xe6, 0x54, 0x32, 0x6d,
+    0x02, 0xbe, 0xf3, 0x61, 0x81, 0xa8, 0x44, 0x14, 0x03, 0x59, 0x0e, 0x1c,
+    0xf6, 0x1f, 0xdc, 0xb2, 0xec, 0xa3, 0x23, 0x77, 0xe8, 0x6e, 0x70, 0xf2,
+    0x25, 0x1f, 0x1f, 0x17, 0xa9, 0x6d, 0x71, 0x36, 0x97, 0x47, 0x00, 0xa4,
+    0x02, 0xe0, 0x2c, 0x7c, 0xc1, 0xab, 0xd5, 0x31, 0x85, 0x35, 0xd4, 0xe6,
+    0x13, 0x02, 0xd6, 0x4b, 0x67, 0x48, 0x2b, 0xa9, 0xe9, 0x2e, 0x02, 0xb6,
+    0x4f, 0x82, 0xe5, 0x7a, 0x95, 0x19, 0xc6, 0x87, 0x3d, 0xfb, 0xa2, 0xb8,
+    0x79, 0x1e, 0x4d, 0x3b, 0x96, 0xcf, 0x4f, 0xbd, 0xcd, 0xa2, 0xa2, 0x1f,
+    0xa0, 0x82, 0xd3, 0xfc, 0x97, 0x05, 0x24, 0x36, 0x6b, 0xf3, 0x31, 0xa2,
+    0x35, 0x79, 0xef, 0xad, 0xf8, 0xae, 0xaf, 0xaf, 0xd8, 0xf2, 0xd8, 0x6d,
+    0xed, 0x6b, 0xda, 0x7b, 0x18, 0x1b, 0x5d, 0xff, 0x00, 0x52, 0xb1, 0x6d,
+    0xf0, 0x81, 0x31, 0xca, 0xf4, 0x6e, 0xb1, 0x80, 0xce, 0xb1, 0x84, 0xc0,
+    0x21, 0xb7, 0xd6, 0x77, 0x31, 0xd1, 0x27, 0xc1, 0xcd, 0xfe, 0xd2, 0xe3,
+    0xec, 0xe8, 0x1d, 0x45, 0x96, 0xb0, 0x9a, 0xb7, 0x87, 0x3f, 0x68, 0x2d,
+    0xf7, 0x01, 0x1f, 0xbe, 0xd1, 0xf4, 0x7f, 0xb4, 0xa4, 0x0d, 0x77, 0xbb,
+    0xfa, 0x8f, 0x80, 0x3a, 0x7f, 0x43, 0xaa, 0xe2, 0xdf, 0xd2, 0x65, 0x7e,
+    0x95, 0xe4, 0x0f, 0x1f, 0xa1, 0xfe, 0x6b, 0x16, 0x9f, 0x52, 0xfa, 0xc1,
+    0xd3, 0xba, 0x6d, 0x26, 0xdc, 0xac, 0x86, 0xd4, 0xd9, 0x0d, 0x31, 0x2e,
+    0x74, 0x9e, 0xdb, 0x59, 0x2e, 0x55, 0xe8, 0xc9, 0xb2, 0x96, 0xd5, 0x4b,
+    0x9f, 0xb8, 0x6d, 0xda, 0x1c, 0x04, 0x09, 0x03, 0xfe, 0x8a, 0xc6, 0xfa,
+    0xd3, 0xf5, 0x6a, 0xbe, 0xbb, 0x5b, 0x2e, 0xc6, 0xb5, 0x94, 0xe6, 0xd5,
+    0x20, 0x97, 0x7d, 0x1b, 0x1b, 0xf9, 0xad, 0x7c, 0x7d, 0x17, 0xb7, 0xf3,
+    0x1e, 0x92, 0x1b, 0x7f, 0xf8, 0xe0, 0x7d, 0x59, 0xdd, 0xfd, 0x32, 0xd8,
+    0x8f, 0xa5, 0xe8, 0x3a, 0x12, 0x5c, 0x3f, 0xfc, 0xc4, 0xfa, 0xc3, 0xb3,
+    0x77, 0xa7, 0x56, 0xed, 0xdb, 0x76, 0x7a, 0x8d, 0xdd, 0x1f, 0xbf, 0xfd,
+    0x44, 0x92, 0x56, 0x8f, 0xff, 0xd4, 0xf2, 0xe8, 0x86, 0x17, 0x1e, 0xfa,
+    0x04, 0x56, 0x4b, 0x43, 0x6c, 0x6f, 0x2d, 0xe5, 0x46, 0x01, 0x64, 0x2b,
+    0x14, 0x32, 0x5b, 0xb4, 0xa0, 0x52, 0x1d, 0xde, 0x9b, 0x94, 0xdb, 0xab,
+    0x6b, 0x81, 0xf7, 0x05, 0xb0, 0xd7, 0x07, 0xb2, 0x27, 0x55, 0xc6, 0x57,
+    0x65, 0xd8, 0x76, 0x6e, 0x64, 0xed, 0xee, 0x16, 0xce, 0x27, 0x57, 0x63,
+    0xda, 0x0c, 0xc2, 0x8e, 0x51, 0x67, 0x84, 0xfa, 0x1d, 0xdd, 0x62, 0xc7,
+    0x07, 0xe9, 0xf7, 0xa3, 0xd6, 0x6c, 0x02, 0x41, 0x55, 0x31, 0xf3, 0x2b,
+    0xb3, 0xba, 0x2b, 0x2e, 0x68, 0x24, 0x1d, 0x47, 0x64, 0xca, 0xa6, 0x50,
+    0x41, 0x65, 0x90, 0x6c, 0xb1, 0xa5, 0xae, 0x33, 0x23, 0x51, 0xe4, 0xab,
+    0x7d, 0x5d, 0xcb, 0xb6, 0xcc, 0x37, 0xd0, 0x40, 0x73, 0x71, 0xde, 0x58,
+    0x09, 0xe7, 0x6f, 0x2c, 0x44, 0xc9, 0xc9, 0xae, 0xba, 0x9d, 0x63, 0x88,
+    0x01, 0xa0, 0x95, 0x9d, 0xf5, 0x3f, 0x2a, 0xe6, 0x67, 0xdb, 0x50, 0x83,
+    0x55, 0xad, 0x36, 0x3e, 0x78, 0x10, 0x74, 0x77, 0xfd, 0x2d, 0xaa, 0x4c,
+    0x7d, 0x58, 0x73, 0x91, 0xa0, 0x0f, 0x51, 0x45, 0xb7, 0x33, 0xdd, 0x58,
+    0x69, 0x1d, 0xd8, 0x0c, 0x9f, 0x96, 0x88, 0x19, 0x99, 0x19, 0xac, 0xcf,
+    0xa3, 0xd2, 0xad, 0xb5, 0xdb, 0x76, 0x8f, 0xad, 0xc4, 0xea, 0xcf, 0xdf,
+    0x7e, 0xdf, 0xdd, 0xfc, 0xd5, 0xa3, 0x5e, 0x43, 0x2b, 0x6b, 0xb2, 0xad,
+    0x3b, 0x6a, 0xa4, 0x13, 0xa7, 0x04, 0xac, 0x7a, 0x6f, 0xb3, 0x23, 0x26,
+    0xcc, 0xfb, 0xb4, 0x75, 0x8e, 0x01, 0x83, 0xf7, 0x58, 0x3e, 0x8b, 0x53,
+    0xa7, 0x2a, 0x1a, 0x31, 0x42, 0x36, 0x5d, 0x4c, 0x9a, 0xf2, 0xdc, 0xc6,
+    0xfe, 0x98, 0xb4, 0x34, 0xcb, 0x48, 0x0a, 0x8f, 0xdb, 0xb2, 0xeb, 0x76,
+    0xd6, 0x07, 0x5c, 0x59, 0xc9, 0x64, 0x8f, 0x93, 0xa7, 0x73, 0x16, 0x83,
+    0xaf, 0x0e, 0xa4, 0x33, 0xef, 0x50, 0xc5, 0x0c, 0xda, 0x59, 0x10, 0x06,
+    0x8a, 0x2e, 0x29, 0x0e, 0xac, 0xc2, 0x31, 0x3d, 0x36, 0x69, 0x7e, 0xd6,
+    0xcc, 0xf5, 0x3d, 0x6f, 0xb3, 0xeb, 0x1b, 0x76, 0xef, 0x3b, 0xa3, 0xfa,
+    0xc9, 0x2b, 0x5f, 0x66, 0x6f, 0xa9, 0x1e, 0x73, 0xf2, 0x49, 0x2e, 0x39,
+    0xf7, 0x4f, 0xb7, 0x8d, 0xff, 0xd5, 0xf3, 0x26, 0xfe, 0x0a, 0xc5, 0x1b,
+    0xa7, 0xcb, 0xb2, 0xcf, 0x49, 0x03, 0xb2, 0x46, 0xee, 0xd9, 0xd9, 0xb3,
+    0xf4, 0x9f, 0x25, 0x4a, 0xdf, 0x4b, 0x77, 0xe8, 0x27, 0xd4, 0xef, 0x1c,
+    0x2a, 0x29, 0x26, 0xc5, 0x7c, 0x9d, 0x6c, 0x7f, 0xb7, 0x6e, 0x1b, 0x26,
+    0x7f, 0x05, 0xa3, 0xfe, 0x53, 0x8d, 0x62, 0x57, 0x30, 0x92, 0x12, 0xfa,
+    0x2f, 0x86, 0xdf, 0xa4, 0xec, 0x67, 0xfe, 0xd0, 0xf4, 0xff, 0x00, 0x4d,
+    0xfc, 0xdf, 0x78, 0xe1, 0x68, 0x7d, 0x54, 0x99, 0xbf, 0x6f, 0xf3, 0xbe,
+    0xdf, 0x8e, 0xdd, 0x7f, 0xef, 0xeb, 0x97, 0x49, 0x3e, 0x3b, 0x7f, 0x06,
+    0x2c, 0x9f, 0x37, 0x5f, 0xf0, 0x9f, 0x4c, 0xeb, 0x7b, 0xbf, 0x67, 0x55,
+    0xe8, 0xff, 0x00, 0x31, 0xbc, 0x7a, 0x9e, 0x31, 0xdb, 0xfe, 0x92, 0xae,
+    0x37, 0x7a, 0x4d, 0xdb, 0xe2, 0x17, 0x9d, 0xa4, 0xa3, 0xc9, 0xba, 0xfc,
+    0x7b, 0x7d, 0x5f, 0x52, 0xa7, 0x7e, 0xd1, 0x28, 0xf8, 0xf3, 0xb0, 0xc7,
+    0x32, 0xbc, 0x99, 0x24, 0xc5, 0xe3, 0xab, 0xeb, 0x1f, 0xa4, 0xf5, 0xfc,
+    0xe1, 0x25, 0xe4, 0xe9, 0x24, 0x97, 0xff, 0xd9, 0x00, 0x38, 0x42, 0x49,
+    0x4d, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
+    0x01, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f,
+    0x00, 0x62, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f,
+    0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70,
+    0x00, 0x00, 0x00, 0x13, 0x00, 0x41, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x62,
+    0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x74,
+    0x00, 0x6f, 0x00, 0x73, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x20,
+    0x00, 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x38,
+    0x42, 0x49, 0x4d, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xff, 0xe1, 0x15, 0x67, 0x68,
+    0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f,
+    0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31,
+    0x2e, 0x30, 0x2f, 0x00, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65,
+    0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x27, 0xef, 0xbb, 0xbf,
+    0x27, 0x20, 0x69, 0x64, 0x3d, 0x27, 0x57, 0x35, 0x4d, 0x30, 0x4d, 0x70,
+    0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, 0x7a, 0x4e, 0x54,
+    0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x27, 0x3f, 0x3e, 0x0a, 0x3c, 0x3f,
+    0x61, 0x64, 0x6f, 0x62, 0x65, 0x2d, 0x78, 0x61, 0x70, 0x2d, 0x66, 0x69,
+    0x6c, 0x74, 0x65, 0x72, 0x73, 0x20, 0x65, 0x73, 0x63, 0x3d, 0x22, 0x43,
+    0x52, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d,
+    0x65, 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d,
+    0x27, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65,
+    0x74, 0x61, 0x2f, 0x27, 0x20, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x74, 0x6b,
+    0x3d, 0x27, 0x58, 0x4d, 0x50, 0x20, 0x74, 0x6f, 0x6f, 0x6c, 0x6b, 0x69,
+    0x74, 0x20, 0x32, 0x2e, 0x38, 0x2e, 0x32, 0x2d, 0x33, 0x33, 0x2c, 0x20,
+    0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x31, 0x2e,
+    0x35, 0x27, 0x3e, 0x0a, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46,
+    0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, 0x27,
+    0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77,
+    0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30,
+    0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e,
+    0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x27, 0x20, 0x78, 0x6d, 0x6c,
+    0x6e, 0x73, 0x3a, 0x69, 0x58, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a,
+    0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63,
+    0x6f, 0x6d, 0x2f, 0x69, 0x58, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e,
+    0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63,
+    0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75,
+    0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30,
+    0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31,
+    0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35,
+    0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20,
+    0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x64, 0x66, 0x3d, 0x27, 0x68,
+    0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f,
+    0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x31,
+    0x2e, 0x33, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d,
+    0x20, 0x70, 0x64, 0x66, 0x3a, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
+    0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20,
+    0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44,
+    0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a,
+    0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72,
+    0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74,
+    0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32,
+    0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64,
+    0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34,
+    0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78,
+    0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68,
+    0x6f, 0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e,
+    0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+    0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x2f, 0x31, 0x2e,
+    0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x21, 0x2d, 0x2d, 0x20,
+    0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x43, 0x61,
+    0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x69,
+    0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a, 0x20, 0x3c, 0x2f,
+    0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+    0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a,
+    0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a,
+    0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34,
+    0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d,
+    0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39,
+    0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x61,
+    0x70, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73,
+    0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
+    0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20,
+    0x3c, 0x21, 0x2d, 0x2d, 0x20, 0x78, 0x61, 0x70, 0x3a, 0x44, 0x65, 0x73,
+    0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20,
+    0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x64, 0x20, 0x2d, 0x2d, 0x3e, 0x0a,
+    0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72,
+    0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72,
+    0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+    0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75,
+    0x69, 0x64, 0x3a, 0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d,
+    0x62, 0x32, 0x34, 0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61,
+    0x66, 0x38, 0x2d, 0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39,
+    0x32, 0x66, 0x39, 0x27, 0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73,
+    0x3a, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3d, 0x27, 0x68, 0x74, 0x74, 0x70,
+    0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e,
+    0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f,
+    0x6d, 0x6d, 0x2f, 0x27, 0x3e, 0x0a, 0x20, 0x20, 0x3c, 0x78, 0x61, 0x70,
+    0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x49,
+    0x44, 0x3e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x64, 0x6f, 0x63, 0x69,
+    0x64, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a,
+    0x32, 0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x36, 0x2d, 0x62, 0x32, 0x34,
+    0x39, 0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d,
+    0x39, 0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39,
+    0x3c, 0x2f, 0x78, 0x61, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75,
+    0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72,
+    0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+    0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44,
+    0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
+    0x62, 0x6f, 0x75, 0x74, 0x3d, 0x27, 0x75, 0x75, 0x69, 0x64, 0x3a, 0x32,
+    0x32, 0x64, 0x30, 0x32, 0x62, 0x30, 0x61, 0x2d, 0x62, 0x32, 0x34, 0x39,
+    0x2d, 0x31, 0x31, 0x64, 0x62, 0x2d, 0x38, 0x61, 0x66, 0x38, 0x2d, 0x39,
+    0x31, 0x64, 0x35, 0x34, 0x30, 0x33, 0x66, 0x39, 0x32, 0x66, 0x39, 0x27,
+    0x0a, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x64, 0x63, 0x3d,
+    0x27, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x72, 0x6c,
+    0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x63, 0x2f, 0x65, 0x6c, 0x65, 0x6d,
+    0x65, 0x6e, 0x74, 0x73, 0x2f, 0x31, 0x2e, 0x31, 0x2f, 0x27, 0x3e, 0x0a,
+    0x20, 0x20, 0x3c, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
+    0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72,
+    0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+    0x3c, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x78, 0x6d, 0x6c, 0x3a,
+    0x6c, 0x61, 0x6e, 0x67, 0x3d, 0x27, 0x78, 0x2d, 0x64, 0x65, 0x66, 0x61,
+    0x75, 0x6c, 0x74, 0x27, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x3e, 0x0a, 0x20, 0x20,
+    0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0x0a,
+    0x20, 0x20, 0x3c, 0x2f, 0x64, 0x63, 0x3a, 0x64, 0x65, 0x73, 0x63, 0x72,
+    0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x3c, 0x2f, 0x72,
+    0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+    0x6f, 0x6e, 0x3e, 0x0a, 0x0a, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52,
+    0x44, 0x46, 0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x61, 0x70, 0x6d,
+    0x65, 0x74, 0x61, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x3c, 0x3f, 0x78,
+    0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x27,
+    0x77, 0x27, 0x3f, 0x3e, 0xff, 0xee, 0x00, 0x0e, 0x41, 0x64, 0x6f, 0x62,
+    0x65, 0x00, 0x64, 0x40, 0x00, 0x00, 0x00, 0x01, 0xff, 0xdb, 0x00, 0x84,
+    0x00, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x06,
+    0x04, 0x03, 0x04, 0x06, 0x07, 0x05, 0x04, 0x04, 0x05, 0x07, 0x08, 0x06,
+    0x06, 0x07, 0x06, 0x06, 0x08, 0x0a, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08,
+    0x0a, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0a, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x01, 0x04, 0x05, 0x05, 0x08, 0x07, 0x08,
+    0x0f, 0x0a, 0x0a, 0x0f, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, 0x0e, 0x0e,
+    0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+    0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xc0,
+    0x00, 0x11, 0x08, 0x00, 0x64, 0x00, 0x64, 0x03, 0x01, 0x11, 0x00, 0x02,
+    0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdd, 0x00, 0x04, 0x00, 0x0d, 0xff,
+    0xc4, 0x01, 0xa2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x01, 0x01, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x02,
+    0x06, 0x01, 0x00, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x02, 0x02,
+    0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+    0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x02, 0x06, 0x07,
+    0x03, 0x04, 0x02, 0x06, 0x02, 0x73, 0x01, 0x02, 0x03, 0x11, 0x04, 0x00,
+    0x05, 0x21, 0x12, 0x31, 0x41, 0x51, 0x06, 0x13, 0x61, 0x22, 0x71, 0x81,
+    0x14, 0x32, 0x91, 0xa1, 0x07, 0x15, 0xb1, 0x42, 0x23, 0xc1, 0x52, 0xd1,
+    0xe1, 0x33, 0x16, 0x62, 0xf0, 0x24, 0x72, 0x82, 0xf1, 0x25, 0x43, 0x34,
+    0x53, 0x92, 0xa2, 0xb2, 0x63, 0x73, 0xc2, 0x35, 0x44, 0x27, 0x93, 0xa3,
+    0xb3, 0x36, 0x17, 0x54, 0x64, 0x74, 0xc3, 0xd2, 0xe2, 0x08, 0x26, 0x83,
+    0x09, 0x0a, 0x18, 0x19, 0x84, 0x94, 0x45, 0x46, 0xa4, 0xb4, 0x56, 0xd3,
+    0x55, 0x28, 0x1a, 0xf2, 0xe3, 0xf3, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75,
+    0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x66, 0x76, 0x86, 0x96,
+    0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87,
+    0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78,
+    0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x29, 0x39, 0x49, 0x59,
+    0x69, 0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a,
+    0x4a, 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
+    0x11, 0x00, 0x02, 0x02, 0x01, 0x02, 0x03, 0x05, 0x05, 0x04, 0x05, 0x06,
+    0x04, 0x08, 0x03, 0x03, 0x6d, 0x01, 0x00, 0x02, 0x11, 0x03, 0x04, 0x21,
+    0x12, 0x31, 0x41, 0x05, 0x51, 0x13, 0x61, 0x22, 0x06, 0x71, 0x81, 0x91,
+    0x32, 0xa1, 0xb1, 0xf0, 0x14, 0xc1, 0xd1, 0xe1, 0x23, 0x42, 0x15, 0x52,
+    0x62, 0x72, 0xf1, 0x33, 0x24, 0x34, 0x43, 0x82, 0x16, 0x92, 0x53, 0x25,
+    0xa2, 0x63, 0xb2, 0xc2, 0x07, 0x73, 0xd2, 0x35, 0xe2, 0x44, 0x83, 0x17,
+    0x54, 0x93, 0x08, 0x09, 0x0a, 0x18, 0x19, 0x26, 0x36, 0x45, 0x1a, 0x27,
+    0x64, 0x74, 0x55, 0x37, 0xf2, 0xa3, 0xb3, 0xc3, 0x28, 0x29, 0xd3, 0xe3,
+    0xf3, 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4, 0x65, 0x75, 0x85,
+    0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5, 0x46, 0x56, 0x66, 0x76, 0x86,
+    0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6, 0x47, 0x57, 0x67, 0x77, 0x87,
+    0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7, 0x38, 0x48, 0x58, 0x68, 0x78,
+    0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8, 0x39, 0x49, 0x59, 0x69,
+    0x79, 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9, 0x2a, 0x3a, 0x4a,
+    0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa, 0xff,
+    0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f,
+    0x00, 0xf0, 0x67, 0xa6, 0x5c, 0x0f, 0x01, 0xd4, 0x7e, 0x18, 0x12, 0x98,
+    0xe9, 0xd6, 0x2d, 0x34, 0x6d, 0x70, 0xdf, 0xdc, 0xa1, 0xe3, 0xec, 0x5b,
+    0xfb, 0x32, 0x24, 0xb2, 0x01, 0x1f, 0x15, 0xa4, 0x52, 0x4a, 0x82, 0x31,
+    0xf1, 0xfe, 0xd1, 0x3d, 0x14, 0x64, 0x49, 0x64, 0x22, 0x98, 0xcf, 0xa5,
+    0x46, 0x6c, 0x16, 0x55, 0x71, 0x56, 0x62, 0x28, 0x07, 0xc5, 0x45, 0x15,
+    0xa0, 0xc8, 0x89, 0x33, 0xe1, 0x63, 0xd2, 0xd8, 0x34, 0x44, 0x17, 0xa0,
+    0x2c, 0x4d, 0x16, 0xbb, 0xed, 0xdc, 0xf8, 0x64, 0xc1, 0x6b, 0x31, 0x42,
+    0x18, 0x8e, 0xc7, 0xb5, 0x2a, 0x7d, 0xb2, 0x56, 0xc5, 0x61, 0x8c, 0xf2,
+    0xa0, 0x1b, 0x1e, 0x83, 0x0d, 0xa1, 0x63, 0x50, 0x1f, 0x97, 0x7c, 0x2a,
+    0xa9, 0x1a, 0x9a, 0x86, 0x4f, 0xb4, 0xb4, 0x38, 0x0a, 0xa6, 0x0b, 0xb8,
+    0x0c, 0x05, 0x14, 0xf8, 0x76, 0x3e, 0x19, 0x14, 0xb6, 0x78, 0xf8, 0x8c,
+    0x2a, 0xd5, 0x01, 0xdc, 0x6f, 0x8a, 0x1a, 0xe3, 0x8d, 0xab, 0xff, 0xd0,
+    0xf0, 0xec, 0xe9, 0x15, 0xb5, 0xb9, 0x5a, 0x7c, 0x4c, 0xa2, 0x9e, 0x24,
+    0xf5, 0xca, 0xc6, 0xe5, 0x99, 0xd9, 0x34, 0x99, 0x04, 0x3a, 0x7d, 0xb5,
+    0xba, 0xd5, 0x51, 0x63, 0x0e, 0xc7, 0xc5, 0x9b, 0x73, 0xf8, 0xe4, 0x6f,
+    0x76, 0xca, 0xd9, 0xda, 0x54, 0x6d, 0x72, 0x2e, 0x1a, 0x57, 0x11, 0x44,
+    0x40, 0x0d, 0x27, 0x7a, 0x0f, 0xd9, 0x5f, 0x12, 0x69, 0x4c, 0x84, 0xcd,
+    0x36, 0xe3, 0x85, 0xb2, 0xcd, 0x2f, 0x4a, 0x8b, 0x58, 0x36, 0xf6, 0x76,
+    0xa8, 0x64, 0x64, 0x3c, 0xa4, 0x93, 0xaa, 0x25, 0x3c, 0x49, 0xda, 0xa4,
+    0xe5, 0x26, 0x54, 0xe4, 0x8c, 0x7c, 0x5c, 0x93, 0x4d, 0x67, 0xc9, 0x3a,
+    0x6e, 0x9f, 0x13, 0xb4, 0xce, 0xf7, 0x3a, 0x9b, 0xad, 0x52, 0xd6, 0x2a,
+    0xd1, 0x49, 0xee, 0xc7, 0xf8, 0x64, 0x46, 0x42, 0x4e, 0xcd, 0x92, 0xc2,
+    0x00, 0xdd, 0x8a, 0x47, 0xe5, 0x69, 0x6e, 0xd4, 0xa4, 0x08, 0x16, 0x83,
+    0x9c, 0x8c, 0xdd, 0x95, 0x6b, 0xb9, 0xf6, 0xef, 0x97, 0x78, 0x94, 0xe3,
+    0x78, 0x04, 0xa4, 0xf3, 0xe8, 0xee, 0x64, 0xe1, 0x12, 0x10, 0x05, 0x6a,
+    0xc7, 0xc0, 0x6f, 0x53, 0xf3, 0xc9, 0x89, 0xb4, 0x9c, 0x4e, 0xb4, 0xf2,
+    0xd3, 0xde, 0x7a, 0xd2, 0x19, 0x16, 0x38, 0x61, 0x5d, 0xd9, 0x88, 0x05,
+    0x9c, 0xf4, 0x0a, 0x0f, 0x5f, 0x73, 0x84, 0xe4, 0xa4, 0xc7, 0x0d, 0xa5,
+    0xf1, 0x59, 0xba, 0x5c, 0x08, 0x98, 0x6f, 0xc8, 0x20, 0xfa, 0x4e, 0x4e,
+    0xf6, 0x69, 0xe1, 0xa2, 0x89, 0xfd, 0x1f, 0x77, 0x2c, 0xe6, 0xce, 0xd6,
+    0x17, 0x9a, 0x69, 0xdb, 0xd3, 0x86, 0x18, 0xc1, 0x67, 0x77, 0x26, 0x80,
+    0x28, 0x1b, 0x93, 0x88, 0x41, 0x0f, 0x40, 0xb0, 0xfc, 0x87, 0xf3, 0x43,
+    0x98, 0xd7, 0x58, 0x96, 0xdb, 0x4d, 0x91, 0x88, 0xe5, 0x6c, 0x58, 0xdc,
+    0x5c, 0x2a, 0xf7, 0x2c, 0xb1, 0xfc, 0x20, 0x8f, 0x02, 0xd9, 0x65, 0x06,
+    0xbe, 0x26, 0x6f, 0xa2, 0x7f, 0xce, 0x3d, 0x69, 0x26, 0xdd, 0x13, 0x52,
+    0xbf, 0xbd, 0x92, 0x62, 0x59, 0x4c, 0x90, 0xac, 0x50, 0x45, 0x5e, 0xbb,
+    0x09, 0x03, 0x12, 0x29, 0x84, 0x00, 0xc4, 0xc9, 0x11, 0xff, 0x00, 0x42,
+    0xe7, 0xa7, 0x7a, 0xd4, 0xfd, 0x21, 0x79, 0xe9, 0x78, 0x71, 0x8b, 0x95,
+    0x39, 0x75, 0xaf, 0x4e, 0x98, 0x78, 0x42, 0x38, 0xdf, 0xff, 0xd1, 0xf0,
+    0xe6, 0xa0, 0x58, 0xc8, 0x84, 0x9a, 0xaa, 0x30, 0x55, 0xf9, 0x0a, 0x6f,
+    0x90, 0x0c, 0xca, 0x72, 0x48, 0xb8, 0x1e, 0x89, 0xa7, 0x23, 0x17, 0x24,
+    0xff, 0x00, 0x61, 0xb6, 0x54, 0x76, 0x6e, 0x1b, 0xa7, 0xbe, 0x50, 0xf2,
+    0xc1, 0xd7, 0x4c, 0x52, 0x5e, 0x33, 0x5b, 0xe9, 0x10, 0xf4, 0x54, 0x3c,
+    0x5e, 0x77, 0xee, 0x49, 0xec, 0x2b, 0xb6, 0x63, 0xe4, 0xc9, 0xc3, 0xef,
+    0x73, 0xf0, 0xe1, 0x32, 0x1b, 0xf2, 0x7a, 0x05, 0xce, 0xad, 0x65, 0xa1,
+    0x98, 0xb4, 0x0f, 0x2a, 0x5b, 0x23, 0xeb, 0x12, 0x00, 0x88, 0xb0, 0xa8,
+    0x66, 0x46, 0x3d, 0xea, 0x7b, 0xfb, 0x9e, 0x99, 0x89, 0xbc, 0x8d, 0x97,
+    0x3a, 0x34, 0x05, 0x32, 0x5d, 0x1f, 0xc9, 0x1a, 0x8c, 0x36, 0x8c, 0x6f,
+    0x66, 0xfa, 0xc6, 0xb7, 0x7d, 0xf0, 0x94, 0x04, 0xf0, 0x88, 0xc9, 0xd5,
+    0x9d, 0x8d, 0x4b, 0x11, 0xd4, 0x9f, 0xbb, 0x25, 0xc5, 0xdc, 0xa2, 0x03,
+    0x99, 0x4b, 0xbc, 0xf3, 0x0d, 0x97, 0x96, 0x74, 0xe5, 0xf2, 0xb6, 0x80,
+    0x95, 0xbd, 0x99, 0x15, 0xf5, 0x4b, 0xd2, 0x37, 0x58, 0x46, 0xd4, 0x27,
+    0xc5, 0xce, 0xc1, 0x7c, 0x30, 0x8e, 0x68, 0x94, 0x7b, 0x9e, 0x6d, 0xe6,
+    0x7b, 0x9b, 0x5d, 0x3a, 0xd8, 0xdb, 0x32, 0xfa, 0x77, 0x65, 0x15, 0xe4,
+    0x57, 0xa7, 0x21, 0x55, 0x04, 0x57, 0xef, 0xd8, 0x66, 0x56, 0x38, 0x19,
+    0x1b, 0xe8, 0xe0, 0x67, 0x98, 0xc7, 0x1a, 0x1c, 0xde, 0x71, 0x71, 0x79,
+    0x2c, 0xf2, 0xfa, 0x8c, 0x48, 0xec, 0xb5, 0x24, 0x9a, 0x0c, 0xce, 0x75,
+    0x29, 0xae, 0x8c, 0x67, 0xd4, 0xb5, 0x0b, 0x4b, 0x04, 0x05, 0xef, 0x2e,
+    0x66, 0x8e, 0x18, 0x08, 0x15, 0xdd, 0x8f, 0x11, 0xb0, 0xeb, 0x4c, 0x04,
+    0x5b, 0x21, 0x2a, 0x7d, 0x41, 0xe4, 0x4f, 0xcb, 0xcb, 0x5d, 0x12, 0x45,
+    0xb8, 0xb7, 0x53, 0x71, 0xaa, 0x9f, 0x86, 0x5b, 0xd6, 0x50, 0x4a, 0xed,
+    0xba, 0x46, 0x77, 0x00, 0x13, 0xd4, 0x8c, 0x85, 0xd3, 0x12, 0x6d, 0xeb,
+    0x1a, 0x67, 0x95, 0xd9, 0x39, 0x39, 0x50, 0xac, 0xff, 0x00, 0x6f, 0xc4,
+    0xff, 0x00, 0x1c, 0x81, 0x92, 0xb2, 0x6b, 0x6d, 0x02, 0xdd, 0xbd, 0x36,
+    0x92, 0x36, 0x2d, 0x1f, 0xc0, 0x2a, 0x0b, 0x28, 0x1b, 0x91, 0x41, 0xf4,
+    0x9c, 0xb6, 0x25, 0x81, 0x46, 0xfe, 0x81, 0xb5, 0xad, 0x3d, 0xba, 0x57,
+    0xb7, 0xf9, 0xf6, 0xc9, 0xb0, 0x7f, 0xff, 0xd2, 0xf0, 0xe2, 0x86, 0x95,
+    0xc4, 0x67, 0x7e, 0x3f, 0x11, 0xf7, 0xa8, 0x19, 0x06, 0x69, 0x8d, 0xca,
+    0xca, 0x24, 0x8f, 0xd3, 0x52, 0x24, 0x89, 0x47, 0x25, 0x1f, 0xcb, 0x20,
+    0xf8, 0xb2, 0xb2, 0x76, 0x6e, 0x88, 0x36, 0xf6, 0x6f, 0x2a, 0xc1, 0x6e,
+    0xfa, 0x45, 0xad, 0xbc, 0x3f, 0x0b, 0x46, 0x81, 0x4d, 0x46, 0xea, 0x7a,
+    0x9a, 0x83, 0x9a, 0xa9, 0xdd, 0xbb, 0xec, 0x7b, 0x06, 0x5b, 0xe5, 0xcf,
+    0x2e, 0x69, 0xfa, 0x5c, 0xcd, 0x7b, 0x14, 0x5e, 0xa5, 0xee, 0xf5, 0xb8,
+    0x7d, 0xdd, 0x99, 0xba, 0xef, 0x91, 0x16, 0x5b, 0x36, 0xb6, 0x65, 0x0d,
+    0xac, 0xb2, 0x5b, 0xed, 0x34, 0x81, 0x7a, 0xbb, 0x46, 0x40, 0x6a, 0x9e,
+    0xb4, 0x39, 0x31, 0x13, 0x49, 0xda, 0xd2, 0x9b, 0xed, 0x1e, 0xc4, 0x24,
+    0xb3, 0x35, 0xb2, 0x88, 0x60, 0x06, 0xe6, 0x56, 0x98, 0x96, 0x79, 0x1e,
+    0x31, 0x51, 0xc9, 0x8f, 0xcb, 0x00, 0xe6, 0xb3, 0xe4, 0xf9, 0x2b, 0xcc,
+    0x7a, 0x94, 0xda, 0x96, 0xa9, 0x71, 0x77, 0x70, 0x79, 0xcd, 0x33, 0x97,
+    0x76, 0x3f, 0xcc, 0xc6, 0xa6, 0x9f, 0x2e, 0x99, 0xb9, 0xc6, 0x2a, 0x21,
+    0xe6, 0x73, 0xca, 0xe6, 0x4a, 0x51, 0x1a, 0x99, 0x1c, 0x28, 0x04, 0x93,
+    0xd0, 0x0e, 0xa4, 0xe4, 0xda, 0x5f, 0x50, 0xfe, 0x4a, 0xfe, 0x48, 0xb5,
+    0xb2, 0xc1, 0xe6, 0x1f, 0x31, 0x7e, 0xef, 0x52, 0x91, 0x43, 0xc3, 0x6e,
+    0x77, 0xf4, 0x22, 0x6d, 0xbf, 0xe4, 0x63, 0x0e, 0xbf, 0xca, 0x36, 0xeb,
+    0x5c, 0x84, 0xa5, 0x48, 0x7d, 0x3b, 0x61, 0xa1, 0xdb, 0x5b, 0x2c, 0x71,
+    0xda, 0x45, 0xc4, 0x28, 0x00, 0x81, 0xdb, 0x31, 0xc9, 0xb4, 0xb2, 0x3b,
+    0x5d, 0x27, 0xa5, 0x05, 0x1b, 0xc7, 0xdb, 0x10, 0xa9, 0xbd, 0xa6, 0x93,
+    0x0c, 0x75, 0xe4, 0x39, 0x35, 0x41, 0x3d, 0xc5, 0x06, 0xdb, 0x8e, 0xfd,
+    0x46, 0x5b, 0x1d, 0x98, 0x95, 0x4f, 0x46, 0xdb, 0xd5, 0xfb, 0x29, 0x5e,
+    0x9d, 0x0d, 0x32, 0xeb, 0x61, 0x4f, 0xff, 0xd3, 0xf1, 0x46, 0x9a, 0x16,
+    0x1b, 0x91, 0x71, 0x28, 0xac, 0x4a, 0x14, 0x30, 0x3e, 0x19, 0x54, 0xb9,
+    0x36, 0xc7, 0x9b, 0x2d, 0xd1, 0x6c, 0x45, 0xe3, 0xdc, 0xde, 0xc8, 0x95,
+    0x5b, 0x87, 0xf8, 0x41, 0x1d, 0x10, 0x54, 0x01, 0x98, 0x79, 0x25, 0xd1,
+    0xda, 0xe9, 0xe1, 0xb5, 0x9e, 0xac, 0xeb, 0x42, 0xba, 0x8e, 0xdf, 0x8c,
+    0x31, 0x21, 0x70, 0xb4, 0x5d, 0xbe, 0xc5, 0x7c, 0x2b, 0xed, 0xe1, 0x94,
+    0x18, 0xb9, 0x51, 0x3d, 0x03, 0x2c, 0x13, 0x6b, 0xf1, 0x42, 0x6e, 0xe2,
+    0xb7, 0x12, 0xa0, 0xdd, 0x50, 0x9f, 0x4f, 0x6f, 0xa7, 0x6f, 0xc7, 0x03,
+    0x61, 0xa0, 0x83, 0xb5, 0xf3, 0x97, 0x98, 0x20, 0x9c, 0x44, 0xea, 0xd0,
+    0xad, 0x48, 0x64, 0x90, 0x21, 0xd8, 0x9f, 0xa7, 0xa6, 0x44, 0xca, 0x99,
+    0xc6, 0x36, 0xcb, 0x74, 0x5d, 0x7e, 0x5b, 0xfe, 0x31, 0x6a, 0x31, 0xf3,
+    0x8c, 0xd0, 0xad, 0x40, 0xa3, 0x1f, 0x7c, 0x44, 0xd6, 0x51, 0xd9, 0xe0,
+    0x5f, 0x9a, 0x7e, 0x41, 0x9f, 0x40, 0xf3, 0x14, 0xba, 0x85, 0xba, 0x34,
+    0xba, 0x2d, 0xfb, 0x34, 0xd0, 0xcf, 0x4f, 0xb0, 0xce, 0x6a, 0x51, 0xe9,
+    0xb0, 0x20, 0xf4, 0xf1, 0x19, 0xb2, 0xc3, 0x90, 0x11, 0x4e, 0x97, 0x55,
+    0x80, 0x83, 0xc4, 0x17, 0x7e, 0x4c, 0x79, 0x19, 0xfc, 0xd1, 0xe7, 0x78,
+    0x4b, 0x91, 0x1d, 0xae, 0x92, 0xa6, 0xf6, 0x46, 0x75, 0xe4, 0xad, 0x22,
+    0x1f, 0xdd, 0xa1, 0x07, 0xb3, 0x1e, 0xfe, 0xd9, 0x92, 0xeb, 0x4b, 0xed,
+    0xfd, 0x0a, 0xc2, 0x63, 0x27, 0xa4, 0x88, 0x17, 0x60, 0x49, 0x35, 0xdc,
+    0x8e, 0xa5, 0x7d, 0xab, 0xd3, 0x28, 0x90, 0x50, 0xcd, 0xed, 0x2d, 0xda,
+    0x15, 0x55, 0x51, 0xf1, 0x1a, 0x0a, 0xf7, 0x39, 0x5d, 0xaa, 0x77, 0x6f,
+    0x01, 0x8e, 0xa7, 0x7d, 0xfa, 0xff, 0x00, 0x66, 0x10, 0xa8, 0xb8, 0x63,
+    0x76, 0x90, 0xa8, 0x20, 0x06, 0x56, 0xdb, 0x61, 0xda, 0xbd, 0x4f, 0xcb,
+    0x24, 0x15, 0x0f, 0xf5, 0x66, 0xe5, 0x5f, 0x4c, 0x53, 0xc3, 0xb7, 0xce,
+    0x99, 0x6b, 0x17, 0xff, 0xd4, 0xf0, 0xec, 0x57, 0x6f, 0x32, 0xa5, 0xa4,
+    0x43, 0x76, 0x75, 0xa9, 0xf1, 0x03, 0xfa, 0x64, 0x08, 0x6c, 0x8e, 0xfb,
+    0x3d, 0x7f, 0xcb, 0x16, 0x2b, 0x3d, 0xbc, 0x16, 0xa3, 0x66, 0x6d, 0x98,
+    0xfb, 0x1e, 0xb9, 0xac, 0xc8, 0x77, 0xb7, 0x7d, 0x01, 0xb3, 0x37, 0xb8,
+    0xd3, 0x46, 0x95, 0x68, 0x86, 0xd2, 0x2e, 0x4e, 0xab, 0xf0, 0x23, 0x11,
+    0x4e, 0x5f, 0xcd, 0x98, 0xe7, 0x25, 0x96, 0x71, 0x83, 0x0f, 0xd6, 0x3c,
+    0xb9, 0xe7, 0x0d, 0x7c, 0x41, 0x22, 0x5e, 0xb3, 0x20, 0x0c, 0x65, 0x80,
+    0xc8, 0x63, 0x8e, 0xbb, 0x95, 0xa5, 0x07, 0xeb, 0xcc, 0xac, 0x73, 0x83,
+    0x4e, 0x5c, 0x59, 0x09, 0xd8, 0xec, 0xc8, 0x57, 0x41, 0xd3, 0x4e, 0x95,
+    0xa5, 0x5b, 0x4b, 0x6a, 0xcb, 0xab, 0x43, 0x10, 0x4b, 0xeb, 0x85, 0xa2,
+    0x2c, 0x8e, 0x3f, 0x68, 0x54, 0xf5, 0x00, 0xd3, 0x97, 0x7a, 0x65, 0x79,
+    0xa6, 0x24, 0x76, 0x6f, 0xd3, 0x62, 0x96, 0x30, 0x78, 0xcb, 0x21, 0xf2,
+    0xf4, 0x22, 0xce, 0x54, 0x8e, 0x46, 0x26, 0x10, 0x7e, 0x0a, 0xf5, 0xd8,
+    0xf5, 0x1f, 0x31, 0x98, 0x83, 0x73, 0xb3, 0x91, 0xcd, 0x67, 0xe6, 0x7d,
+    0xe8, 0x16, 0x69, 0x6f, 0x10, 0x1f, 0x54, 0x9a, 0x37, 0xf5, 0x41, 0x5e,
+    0x7f, 0x0a, 0x29, 0x62, 0x02, 0xf8, 0x9c, 0xc8, 0x8c, 0x77, 0x6a, 0x99,
+    0xa0, 0x89, 0xff, 0x00, 0x9c, 0x74, 0xd2, 0xed, 0xed, 0xfc, 0xbb, 0x7b,
+    0xaa, 0x9a, 0x7d, 0x62, 0xfe, 0x46, 0x2d, 0xfe, 0x4c, 0x51, 0x31, 0x11,
+    0xa9, 0xf6, 0xef, 0x9b, 0x30, 0x5e, 0x7b, 0x38, 0xdd, 0xf4, 0x7f, 0x95,
+    0x94, 0xbc, 0x12, 0x43, 0x30, 0x6a, 0xb2, 0xf3, 0x86, 0x40, 0x3e, 0xcb,
+    0xd7, 0x6a, 0xd7, 0xb1, 0xe9, 0x8f, 0x37, 0x19, 0x97, 0x41, 0x2c, 0x71,
+    0x20, 0xf5, 0x36, 0x9c, 0x55, 0x78, 0x1d, 0x8a, 0x91, 0xd7, 0x11, 0x14,
+    0x5a, 0x3e, 0x19, 0x03, 0x10, 0x6b, 0xca, 0xbd, 0x86, 0xf8, 0x9d, 0x95,
+    0x18, 0x36, 0x65, 0x2e, 0xbc, 0x54, 0x1f, 0xa2, 0x99, 0x00, 0x59, 0x2a,
+    0x6f, 0x5e, 0x55, 0x15, 0xe9, 0x5f, 0xc3, 0x2f, 0xb6, 0x14, 0xff, 0x00,
+    0xff, 0xd5, 0xf1, 0x95, 0xfe, 0x80, 0x74, 0x0d, 0x7c, 0xd9, 0x89, 0x3d,
+    0x78, 0x57, 0x8b, 0xc5, 0x28, 0xe8, 0x55, 0xf7, 0x1f, 0x48, 0xca, 0x38,
+    0xb8, 0x83, 0x9f, 0x93, 0x07, 0x85, 0x3a, 0x7a, 0x6f, 0x95, 0x66, 0x2b,
+    0x2c, 0x4c, 0x0d, 0x14, 0x00, 0x3e, 0x9c, 0xc3, 0x98, 0x76, 0xb8, 0x45,
+    0xbd, 0x02, 0xde, 0x48, 0xee, 0xdc, 0xa0, 0x15, 0xe2, 0x2b, 0xc8, 0x8a,
+    0x8a, 0xfd, 0x3b, 0x66, 0x3f, 0x00, 0x73, 0x84, 0x2d, 0x36, 0xb5, 0xb5,
+    0x9e, 0x35, 0x1c, 0x29, 0xc4, 0xfe, 0xc8, 0x04, 0x7f, 0xc4, 0x69, 0x91,
+    0xe1, 0x67, 0x2c, 0x4a, 0xd2, 0xe9, 0x4e, 0xe3, 0xd4, 0xf4, 0x81, 0x5a,
+    0x12, 0xc5, 0x41, 0x3f, 0x79, 0x38, 0x9b, 0x60, 0x20, 0x07, 0x34, 0xb0,
+    0xc9, 0x03, 0x5c, 0x23, 0x03, 0x53, 0x13, 0x56, 0x88, 0xdf, 0x09, 0xda,
+    0x9b, 0xd3, 0xb6, 0x52, 0x0e, 0xec, 0xe4, 0x29, 0x24, 0xfc, 0xd0, 0xe7,
+    0x75, 0xe5, 0x57, 0x6b, 0x61, 0xfb, 0xf0, 0xca, 0xaa, 0x57, 0xa8, 0xe6,
+    0x78, 0x1a, 0x7d, 0xf9, 0x95, 0x8a, 0x5e, 0xa0, 0xe3, 0x67, 0x8f, 0xa0,
+    0xbd, 0x5b, 0xf2, 0xdf, 0x4a, 0x82, 0xcb, 0x4a, 0xb3, 0xb0, 0xb4, 0x41,
+    0x0a, 0x70, 0x48, 0xd9, 0x57, 0x60, 0x51, 0x3a, 0x8f, 0xbc, 0xe6, 0x7b,
+    0xcb, 0xe4, 0x3b, 0xa7, 0x3f, 0x9b, 0x9f, 0x9a, 0xba, 0x77, 0xe5, 0x5f,
+    0x95, 0x9c, 0x59, 0x94, 0x9f, 0xcd, 0x37, 0x8c, 0xa9, 0xa6, 0xd9, 0x39,
+    0xaa, 0xd0, 0x7d, 0xa9, 0x1c, 0x03, 0x5e, 0x09, 0xff, 0x00, 0x0c, 0x76,
+    0xcb, 0x62, 0x2d, 0xa5, 0xf2, 0x85, 0xbf, 0xe7, 0x87, 0xe6, 0xa3, 0x5e,
+    0x4d, 0xa8, 0xc9, 0xe6, 0x8b, 0xd5, 0x69, 0x5c, 0xb0, 0x4a, 0xab, 0xc4,
+    0xb5, 0x35, 0x0a, 0xaa, 0xea, 0x40, 0x03, 0xa0, 0xf6, 0xcb, 0x40, 0x4d,
+    0x3e, 0xdb, 0xff, 0x00, 0x9c, 0x7f, 0xfc, 0xce, 0x4f, 0xcc, 0xbf, 0x26,
+    0x25, 0xe5, 0xd3, 0x2f, 0xe9, 0xdd, 0x3d, 0xfe, 0xab, 0xa9, 0xaa, 0xd2,
+    0xa6, 0x40, 0x2a, 0xb2, 0x71, 0x00, 0x01, 0xea, 0x0d, 0xe8, 0x3a, 0x64,
+    0x25, 0x16, 0x1c, 0x8b, 0xd9, 0x51, 0x39, 0x28, 0x12, 0x51, 0x41, 0xfd,
+    0xa3, 0xd2, 0xb9, 0x4f, 0x0d, 0x33, 0xb5, 0xf4, 0x87, 0x9d, 0x79, 0x0e,
+    0xb4, 0xaf, 0x6a, 0xf8, 0xf1, 0xf0, 0xc9, 0xda, 0xbf, 0xff, 0xd6, 0xf2,
+    0xc6, 0xb5, 0x68, 0x64, 0xd0, 0x6d, 0x35, 0x20, 0x39, 0xcd, 0x13, 0x0f,
+    0x5e, 0x61, 0xfc, 0x8f, 0x40, 0x8b, 0x5e, 0xe0, 0x66, 0x1c, 0x4f, 0xaa,
+    0x9d, 0xe6, 0xa6, 0x1e, 0x91, 0x2e, 0xa9, 0x87, 0x95, 0xee, 0x9c, 0xc5,
+    0x55, 0x34, 0x60, 0x40, 0xae, 0x57, 0x30, 0xd9, 0xa7, 0x95, 0xbd, 0x6f,
+    0xcb, 0x26, 0x39, 0x40, 0x0d, 0x4e, 0xc0, 0x9f, 0x9e, 0x50, 0x5d, 0xac,
+    0x79, 0x33, 0x8b, 0xbb, 0x9b, 0x3b, 0x6b, 0x35, 0x48, 0x54, 0x09, 0x29,
+    0x56, 0x7f, 0xe1, 0x86, 0x72, 0x00, 0x2c, 0x6e, 0xf7, 0x63, 0x3e, 0x63,
+    0xbd, 0xbd, 0x5d, 0x20, 0x2a, 0xb3, 0xa4, 0x33, 0x48, 0xab, 0x21, 0x43,
+    0xf1, 0x2c, 0x47, 0xed, 0x1d, 0xbc, 0x73, 0x18, 0x9b, 0x64, 0x28, 0x96,
+    0x3a, 0xc7, 0x49, 0xb0, 0xf4, 0xcc, 0xe9, 0x73, 0x6c, 0xb4, 0xf8, 0x67,
+    0x92, 0x32, 0x21, 0x70, 0x7b, 0x89, 0x05, 0x57, 0xef, 0x38, 0x28, 0x94,
+    0x4a, 0x7d, 0x13, 0x7d, 0x6a, 0xd3, 0x4c, 0xb8, 0xf2, 0xc3, 0xc8, 0x2e,
+    0x03, 0xf3, 0xe2, 0x7d, 0x33, 0xb7, 0xc5, 0xcc, 0x71, 0x03, 0xc6, 0xb9,
+    0x64, 0x06, 0xe2, 0x9a, 0xf2, 0x4f, 0xd2, 0x6d, 0xe9, 0xfe, 0x41, 0x45,
+    0x5b, 0x18, 0x66, 0xa5, 0x64, 0x09, 0xf4, 0xd5, 0xb7, 0xcd, 0x93, 0xc7,
+    0xcf, 0x9b, 0xe5, 0x6f, 0xf9, 0xc8, 0x0d, 0x56, 0xeb, 0x59, 0xfc, 0xce,
+    0xd5, 0x12, 0x61, 0xc4, 0x69, 0xe9, 0x0d, 0xa4, 0x4b, 0xfe, 0x48, 0x40,
+    0xd5, 0x3e, 0xe4, 0xb6, 0x64, 0x8e, 0x4c, 0x02, 0x61, 0x65, 0xa0, 0x14,
+    0xb4, 0xb6, 0xb0, 0xb1, 0xb6, 0xb2, 0x97, 0xcb, 0xf1, 0x5a, 0x2d, 0xc6,
+    0xa5, 0xac, 0xb4, 0x70, 0x5d, 0xc7, 0x3d, 0xc1, 0x51, 0x24, 0x91, 0xc9,
+    0x31, 0x75, 0x6b, 0x70, 0x9f, 0x14, 0x68, 0x01, 0x46, 0xe4, 0xb5, 0xa3,
+    0x17, 0xcb, 0x40, 0x61, 0x6f, 0x47, 0xff, 0x00, 0x9c, 0x3a, 0x8f, 0x5b,
+    0x4f, 0x3c, 0x6b, 0xb7, 0xfa, 0x30, 0x91, 0x3c, 0xa4, 0xb1, 0x95, 0xb9,
+    0x82, 0x42, 0x0a, 0xbc, 0x8e, 0xe4, 0xdb, 0xa9, 0xef, 0xc9, 0x17, 0x91,
+    0x24, 0x7c, 0xb2, 0x05, 0x64, 0xfb, 0x75, 0x64, 0x32, 0x39, 0x69, 0x5b,
+    0x9c, 0xad, 0xb9, 0xdb, 0xa7, 0xb5, 0x3b, 0x53, 0x2a, 0x21, 0x41, 0x44,
+    0xf3, 0x8b, 0x8f, 0x2e, 0x43, 0x9d, 0x2b, 0xd4, 0x57, 0x23, 0x41, 0x36,
+    0xff, 0x00, 0xff, 0xd7, 0xf0, 0xc0, 0xd5, 0xb5, 0x11, 0x64, 0xb6, 0x3f,
+    0x59, 0x90, 0xd9, 0xab, 0x06, 0xf4, 0x79, 0x7c, 0x3b, 0x74, 0xc8, 0x08,
+    0x8b, 0xb6, 0xe3, 0x96, 0x55, 0x57, 0xb3, 0x3e, 0xf2, 0x35, 0xc7, 0xd6,
+    0x0b, 0x45, 0x5d, 0xdc, 0x8a, 0x7d, 0xd9, 0x8d, 0x94, 0x3b, 0x3d, 0x1c,
+    0x9e, 0xc3, 0xe5, 0xc3, 0x2c, 0x7c, 0xc5, 0x0f, 0xee, 0xdb, 0x8b, 0x0c,
+    0xc4, 0x26, 0x9d, 0xa0, 0x9a, 0x7d, 0x2c, 0xe5, 0xe4, 0x55, 0x7f, 0xee,
+    0xc1, 0x15, 0x04, 0xd0, 0x12, 0x3c, 0x72, 0x89, 0x1b, 0x2c, 0xcc, 0xa8,
+    0x2a, 0x8b, 0x87, 0xbb, 0x63, 0x1a, 0x28, 0x65, 0xf0, 0xed, 0xf2, 0xc3,
+    0xc2, 0x0a, 0x06, 0x4a, 0x46, 0xc7, 0xa5, 0xa3, 0x59, 0xc8, 0xb2, 0xc7,
+    0x45, 0x22, 0x9c, 0x14, 0x54, 0x10, 0x46, 0xf5, 0x1d, 0x32, 0x5c, 0x14,
+    0x14, 0xe4, 0x32, 0x2f, 0x3a, 0xf3, 0xb6, 0x90, 0x9a, 0x6d, 0xae, 0x9f,
+    0x3d, 0xab, 0xb8, 0x8a, 0x3b, 0xf8, 0x39, 0x44, 0x58, 0xf0, 0x08, 0xd5,
+    0x14, 0xa5, 0x7b, 0x65, 0x98, 0x8e, 0xfb, 0xb5, 0x67, 0x87, 0xa5, 0xef,
+    0x5e, 0x44, 0x96, 0x35, 0xb5, 0xb6, 0x59, 0x36, 0xfd, 0xd8, 0xa0, 0xf1,
+    0x20, 0x53, 0x33, 0xc0, 0x79, 0x59, 0x73, 0x7c, 0xd7, 0xf9, 0xfb, 0xa2,
+    0xcd, 0x67, 0xf9, 0xa7, 0x7b, 0x72, 0xf1, 0x71, 0x83, 0x53, 0x86, 0x0b,
+    0x98, 0x24, 0x22, 0x8a, 0xcc, 0x88, 0x23, 0x7f, 0xb8, 0xae, 0xf9, 0x7c,
+    0x50, 0x1e, 0x5f, 0x7c, 0x48, 0x21, 0x44, 0x6b, 0xce, 0x9b, 0xb0, 0x1b,
+    0x9e, 0xf5, 0xaf, 0x8e, 0x4d, 0x5f, 0x7a, 0x7f, 0xce, 0x34, 0xf9, 0x5d,
+    0x3c, 0xa3, 0xf9, 0x69, 0x63, 0xa9, 0x3c, 0x27, 0xeb, 0xda, 0xe1, 0x37,
+    0xd7, 0x2e, 0xaa, 0xdb, 0x06, 0xda, 0x30, 0x49, 0xfe, 0x54, 0x03, 0x03,
+    0x49, 0xdc, 0xb3, 0xaf, 0x38, 0xfe, 0x6a, 0xf9, 0x47, 0xc9, 0x3a, 0x74,
+    0x97, 0xfa, 0xf6, 0xaf, 0x15, 0x85, 0xb8, 0x75, 0x89, 0xb8, 0x87, 0x9a,
+    0x72, 0xee, 0x2a, 0x14, 0x24, 0x60, 0xb1, 0xa8, 0xdf, 0x07, 0x0b, 0x2d,
+    0xcb, 0xcf, 0x7f, 0xe8, 0x6a, 0xff, 0x00, 0x26, 0xbd, 0x6a, 0x7f, 0x89,
+    0x2f, 0xf8, 0x52, 0x9e, 0xb7, 0xe8, 0xb9, 0xb8, 0x57, 0xc2, 0x95, 0xe9,
+    0x8f, 0x08, 0x5a, 0x2f, 0xff, 0xd0, 0xf0, 0x4d, 0x40, 0xaa, 0xd7, 0x00,
+    0x64, 0xcb, 0x3c, 0x97, 0xa8, 0xb5, 0x9e, 0xa3, 0x1a, 0xd6, 0x84, 0x95,
+    0x3f, 0x45, 0x72, 0x9c, 0xa2, 0xc3, 0x99, 0xa5, 0x9d, 0x49, 0xf4, 0x17,
+    0x97, 0xaf, 0x63, 0x17, 0x52, 0x6f, 0xf0, 0xc8, 0x43, 0x6f, 0x9a, 0xe9,
+    0x07, 0x70, 0x0e, 0xec, 0x83, 0x51, 0x44, 0xb8, 0x61, 0x1a, 0x9e, 0x11,
+    0xd3, 0x91, 0x60, 0x68, 0x6b, 0xd3, 0x31, 0x4f, 0x36, 0xd3, 0x4c, 0x52,
+    0xef, 0x4c, 0xd5, 0x0c, 0xc4, 0x69, 0xda, 0x94, 0xc8, 0x3a, 0xf0, 0x66,
+    0x07, 0x73, 0xe0, 0x40, 0xfd, 0x79, 0x93, 0x12, 0x1c, 0x9c, 0x32, 0xc7,
+    0xfc, 0x41, 0x33, 0xd2, 0xb4, 0x6f, 0x38, 0x98, 0x65, 0x76, 0xbf, 0x69,
+    0x42, 0xd0, 0xaa, 0xc9, 0xde, 0x95, 0xad, 0x28, 0x46, 0x4e, 0xac, 0x39,
+    0x77, 0x80, 0x11, 0xbf, 0xd8, 0xc7, 0x7c, 0xe1, 0xa5, 0xf9, 0x92, 0x4d,
+    0x32, 0x5b, 0x8b, 0x93, 0x27, 0xa7, 0x68, 0x56, 0xe2, 0x45, 0xda, 0x85,
+    0x61, 0x6e, 0x67, 0xad, 0x6b, 0xb0, 0x38, 0xc2, 0x81, 0xe4, 0xc7, 0x52,
+    0x31, 0x1c, 0x67, 0x86, 0x5b, 0xbd, 0x37, 0xca, 0x7a, 0x94, 0xb1, 0x69,
+    0xb6, 0x2e, 0xb7, 0x15, 0x48, 0xc2, 0xb4, 0x52, 0x53, 0xac, 0x32, 0xaf,
+    0xb1, 0xed, 0x9b, 0x10, 0x36, 0x78, 0x5c, 0x9f, 0x51, 0x64, 0x1f, 0x98,
+    0x3e, 0x58, 0xb6, 0xfc, 0xc8, 0xf2, 0xe5, 0xbc, 0x68, 0x52, 0x2d, 0x5a,
+    0xd1, 0x84, 0xb6, 0xf3, 0x95, 0x0e, 0xc0, 0x85, 0xe2, 0xcb, 0xd8, 0xd1,
+    0xbb, 0xe4, 0xc1, 0xa6, 0x97, 0xce, 0x17, 0x5f, 0x95, 0xde, 0x6d, 0xb6,
+    0xbe, 0xb7, 0x69, 0x34, 0xf3, 0x3c, 0x72, 0xcf, 0xe8, 0xa3, 0x45, 0x49,
+    0x95, 0x4a, 0x90, 0x3e, 0x35, 0x5a, 0x95, 0x1d, 0xfe, 0x21, 0x93, 0x4d,
+    0xbe, 0xd2, 0xd2, 0xf5, 0x8b, 0xbd, 0x32, 0x2d, 0x3f, 0x4c, 0x9a, 0xe4,
+    0xca, 0x9e, 0x90, 0x85, 0x65, 0x55, 0x08, 0x85, 0x91, 0x01, 0x3b, 0x0a,
+    0x05, 0xe9, 0xb0, 0xc0, 0x5a, 0xc3, 0xcd, 0x3f, 0x3b, 0x7f, 0x26, 0xec,
+    0xff, 0x00, 0x35, 0x6d, 0x6d, 0xb5, 0x3d, 0x16, 0xfe, 0x0d, 0x3b, 0xcd,
+    0x96, 0x01, 0x92, 0x46, 0x9e, 0xa2, 0x0b, 0xc8, 0xb7, 0x28, 0x92, 0x71,
+    0xfb, 0x2e, 0xa7, 0xec, 0x3d, 0x0f, 0xc2, 0x68, 0x71, 0x05, 0x95, 0xd3,
+    0xe7, 0x9f, 0xfa, 0x16, 0x2f, 0xcd, 0x7f, 0x43, 0xd6, 0xfa, 0xa5, 0x97,
+    0xab, 0xeb, 0x7a, 0x5f, 0x55, 0xfa, 0xec, 0x5e, 0xaf, 0x0f, 0xf7, 0xed,
+    0x2b, 0x4e, 0x15, 0xff, 0x00, 0x65, 0xdf, 0x8e, 0x14, 0xf1, 0xbf, 0xff,
+    0xd1, 0xf0, 0x5a, 0xa7, 0x18, 0x5e, 0x56, 0x1f, 0x68, 0x71, 0x5f, 0xa7,
+    0xbe, 0x2a, 0x98, 0xdb, 0xfa, 0x90, 0x24, 0x37, 0xb0, 0xfd, 0xb8, 0xa8,
+    0x58, 0x78, 0xae, 0x43, 0xc9, 0xb4, 0x6d, 0xbb, 0xda, 0x3c, 0xa1, 0xad,
+    0x43, 0xa8, 0xda, 0xc5, 0x2a, 0x3d, 0x26, 0x5a, 0x02, 0x2b, 0xbe, 0x60,
+    0x64, 0x8d, 0x17, 0x6f, 0x8b, 0x20, 0x90, 0x7a, 0x3c, 0x32, 0x8b, 0xa8,
+    0x02, 0xf3, 0xfd, 0xe0, 0x1b, 0x11, 0x98, 0x66, 0x3b, 0xb9, 0x62, 0x54,
+    0x83, 0x36, 0xf2, 0xa4, 0xe4, 0x29, 0x34, 0xeb, 0xc8, 0x74, 0xae, 0x0d,
+    0xc3, 0x65, 0x82, 0x13, 0x6b, 0x57, 0xba, 0x54, 0xe4, 0x8c, 0x41, 0x1b,
+    0x75, 0xa7, 0xe0, 0x72, 0x5c, 0x4c, 0x84, 0x50, 0x5a, 0xb3, 0xdd, 0xdd,
+    0xc3, 0x24, 0x33, 0xb1, 0x60, 0xe0, 0x86, 0x52, 0x45, 0x38, 0xd2, 0x87,
+    0x24, 0x26, 0x6d, 0x8c, 0xe1, 0x41, 0x25, 0xfc, 0xa3, 0xd7, 0x2f, 0x6f,
+    0x3c, 0xbf, 0x73, 0xa5, 0xb2, 0x2c, 0xd1, 0x69, 0x17, 0x2f, 0x6b, 0x14,
+    0x8c, 0x0f, 0x21, 0x0d, 0x79, 0x46, 0x09, 0x15, 0xed, 0xb7, 0x4e, 0xd9,
+    0xb9, 0x8b, 0xcb, 0xe4, 0xa2, 0x5e, 0xa3, 0xa6, 0xdf, 0x6a, 0x36, 0xe4,
+    0xcd, 0x69, 0x1c, 0x4e, 0x84, 0x7c, 0x76, 0xab, 0x21, 0x67, 0xa8, 0xa7,
+    0xd9, 0xf8, 0x4d, 0x2b, 0xf3, 0xc3, 0x4d, 0x49, 0x57, 0x98, 0x75, 0x6f,
+    0x31, 0xda, 0xf9, 0xa3, 0x4b, 0xfd, 0x1f, 0x69, 0x1d, 0xae, 0xa1, 0xa9,
+    0x7e, 0xee, 0xe6, 0xd2, 0x79, 0x18, 0xf3, 0xb5, 0x1f, 0xee, 0xd9, 0x0a,
+    0x01, 0x4e, 0x3f, 0xb3, 0x4d, 0xf2, 0x9c, 0xb9, 0x04, 0x05, 0xb7, 0xe2,
+    0x87, 0x1e, 0xdd, 0x19, 0x3e, 0xaf, 0x6b, 0xae, 0xcb, 0x6d, 0x13, 0x0d,
+    0x45, 0xa2, 0x8e, 0x06, 0xe5, 0x13, 0x2a, 0x02, 0x01, 0x5e, 0x82, 0xb5,
+    0x04, 0xe6, 0x11, 0xd4, 0xcd, 0xda, 0x43, 0x49, 0x8e, 0xb7, 0xdc, 0xb1,
+    0x51, 0xe6, 0x4d, 0x76, 0xd2, 0x61, 0x15, 0xaa, 0x4b, 0xa8, 0xc9, 0x6e,
+    0x49, 0x79, 0x20, 0xe6, 0x8c, 0x49, 0xad, 0x43, 0x16, 0xe4, 0xa7, 0xaf,
+    0x43, 0xd3, 0x26, 0x35, 0x75, 0xcd, 0xa8, 0xe8, 0x87, 0x46, 0xbf, 0xc7,
+    0x9a, 0xff, 0x00, 0xd6, 0xbf, 0x48, 0xfe, 0x88, 0xfd, 0xe7, 0x0f, 0xab,
+    0xfa, 0x3f, 0x58, 0x7f, 0x5f, 0x8d, 0x3f, 0x9f, 0xa7, 0x5e, 0xd4, 0xc3,
+    0xf9, 0xd1, 0x7c, 0xb6, 0x47, 0xe4, 0x3a, 0x5b, 0xff, 0xd2, 0xf0, 0xb7,
+    0xa6, 0x1e, 0xdf, 0xd3, 0xf6, 0xa5, 0x71, 0x54, 0xdb, 0x4b, 0x80, 0x3c,
+    0x42, 0x26, 0xee, 0x29, 0xbe, 0x51, 0x23, 0x4e, 0x44, 0x05, 0x84, 0x45,
+    0xa5, 0xd5, 0xf7, 0x97, 0x2e, 0xfd, 0x6b, 0x6a, 0x98, 0x09, 0xab, 0xc7,
+    0xfc, 0x46, 0x3b, 0x4c, 0x26, 0x32, 0x30, 0x3e, 0x4f, 0x49, 0xd0, 0xfc,
+    0xfb, 0x05, 0xd4, 0x4a, 0x7d, 0x40, 0xac, 0x3a, 0x8e, 0x84, 0x1c, 0xc5,
+    0x96, 0x2a, 0x73, 0xe1, 0x9c, 0x16, 0x6d, 0xa5, 0x79, 0x86, 0xd6, 0xec,
+    0x80, 0x5a, 0xa0, 0xf5, 0xca, 0xcc, 0x5c, 0xa1, 0x2b, 0x1b, 0x26, 0x30,
+    0x6a, 0x31, 0x46, 0xcf, 0x1c, 0x87, 0x94, 0x64, 0x9e, 0x3d, 0xb6, 0xf0,
+    0xca, 0xa8, 0x39, 0x51, 0x99, 0x42, 0x6b, 0x1a, 0xc5, 0xa5, 0xa5, 0x94,
+    0xf7, 0x92, 0xc8, 0xaa, 0xb1, 0x23, 0x30, 0x04, 0xf8, 0x0e, 0x9f, 0x4e,
+    0x4a, 0x11, 0xb2, 0xd5, 0x9b, 0x25, 0x06, 0x1b, 0xff, 0x00, 0x38, 0xfd,
+    0xad, 0xdf, 0xda, 0xf9, 0xa2, 0xfe, 0xc5, 0x42, 0xbe, 0x9b, 0x7f, 0x0b,
+    0xdd, 0xdd, 0x07, 0xaf, 0x14, 0x68, 0xd8, 0x71, 0x6d, 0xbb, 0x90, 0xfc,
+    0x73, 0x6e, 0xf2, 0xf2, 0xdd, 0xf4, 0xad, 0xa6, 0xab, 0x6d, 0x69, 0x14,
+    0xfa, 0xee, 0xa0, 0xe2, 0x0b, 0x0d, 0x39, 0x19, 0xfe, 0x11, 0xc5, 0x1a,
+    0x4a, 0x1d, 0x8f, 0x73, 0x4f, 0xf8, 0x96, 0x0b, 0x40, 0x8d, 0xec, 0xf3,
+    0x6d, 0x3f, 0x52, 0xba, 0xd6, 0x35, 0x8b, 0xbf, 0x36, 0x6a, 0x5f, 0x0d,
+    0xc5, 0xdc, 0xa8, 0xb6, 0xa8, 0x7a, 0xc5, 0x6c, 0x9b, 0x22, 0x0f, 0xa3,
+    0x73, 0x9a, 0xbc, 0xb3, 0xe2, 0x36, 0xed, 0xb1, 0x43, 0x80, 0x53, 0xd0,
+    0xa7, 0xd4, 0x44, 0xfa, 0x7a, 0xda, 0x83, 0xbd, 0x3e, 0x2f, 0xa7, 0x2b,
+    0xad, 0x9b, 0xb8, 0x8d, 0xa8, 0xe8, 0x91, 0xdb, 0xfa, 0x2d, 0x6f, 0xc3,
+    0x8a, 0x2d, 0x56, 0xa3, 0xad, 0x4f, 0x5c, 0xa4, 0x0d, 0xdc, 0xa3, 0xca,
+    0xd0, 0xbf, 0xa1, 0xe3, 0xfa, 0xe7, 0x0f, 0xf2, 0xb9, 0x57, 0xbf, 0x1a,
+    0xe4, 0xb8, 0x57, 0xc5, 0xdd, 0xff, 0xd3, 0xf0, 0xcc, 0x5d, 0x7b, 0x70,
+    0xc5, 0x53, 0x6d, 0x2f, 0xd5, 0xe4, 0x69, 0xfd, 0xdf, 0xec, 0xd7, 0xad,
+    0x7d, 0xb2, 0x8c, 0x8d, 0xd8, 0xed, 0x91, 0x9f, 0x43, 0xea, 0xe7, 0xeb,
+    0x94, 0xad, 0x3e, 0x1e, 0x95, 0xfc, 0x72, 0x81, 0x7d, 0x1c, 0x9d, 0xba,
+    0xb1, 0x7b, 0xdf, 0xa9, 0x7a, 0xdf, 0xee, 0x2f, 0xd4, 0xfa, 0xe7, 0xed,
+    0x7a, 0x7f, 0xdd, 0xff, 0x00, 0xb2, 0xae, 0x64, 0x0b, 0xea, 0xe3, 0x9a,
+    0xbf, 0x4a, 0x6f, 0xa4, 0xff, 0x00, 0x89, 0xbd, 0x45, 0xfa, 0xb5, 0x79,
+    0xf7, 0xeb, 0xc7, 0xe9, 0xae, 0x57, 0x2e, 0x17, 0x23, 0x1f, 0x89, 0xd1,
+    0x99, 0x8f, 0xf1, 0xa7, 0x11, 0xcf, 0xd3, 0xf5, 0x29, 0xb5, 0x6b, 0xd3,
+    0xe8, 0xcc, 0x7f, 0x45, 0xb9, 0xa3, 0xc5, 0x62, 0xbe, 0x68, 0xff, 0x00,
+    0x15, 0xfd, 0x4c, 0xfe, 0x90, 0xaf, 0xd4, 0xab, 0xf1, 0x7a, 0x7f, 0x62,
+    0x9d, 0xab, 0xdf, 0x32, 0xb1, 0x70, 0x5e, 0xdc, 0xdc, 0x2d, 0x47, 0x8b,
+    0x5e, 0xae, 0x4c, 0xbf, 0xf2, 0x37, 0x9f, 0x3d, 0x5b, 0xd2, 0xff, 0x00,
+    0x8e, 0x87, 0xee, 0x29, 0x5a, 0xf2, 0xf4, 0xaa, 0xd4, 0xa5, 0x36, 0xa7,
+    0x3a, 0x57, 0xfd, 0x8e, 0x64, 0x3a, 0xf2, 0xf6, 0xbf, 0xcc, 0x7f, 0x5b,
+    0xfc, 0x23, 0xa7, 0xfe, 0x8e, 0xff, 0x00, 0x8e, 0x37, 0xd6, 0x63, 0xfa,
+    0xe5, 0x2b, 0xcb, 0x87, 0xec, 0xd6, 0xbd, 0xb9, 0x7d, 0xac, 0xc7, 0xcd,
+    0x7c, 0x2d, 0xf8, 0x2b, 0x89, 0x26, 0x8f, 0xd4, 0xfa, 0x94, 0x3e, 0x85,
+    0x29, 0xc9, 0x69, 0xfc, 0x33, 0x58, 0x5d, 0x9c, 0x79, 0xb2, 0xbb, 0x0f,
+    0xac, 0x7a, 0x2b, 0xea, 0x75, 0xef, 0x92, 0x0c, 0x53, 0x3d, 0x2f, 0xd4,
+    0xfa, 0xbb, 0xfa, 0x74, 0xf5, 0x39, 0x9a, 0xd7, 0xe7, 0x80, 0x53, 0x79,
+    0xba, 0x5b, 0xfe, 0x97, 0xfa, 0x4b, 0xfc, 0xba, 0x7f, 0xb1, 0xc7, 0xab,
+    0x1e, 0x8f, 0xff, 0xd9};
 
 #endif  // RTC_BASE_TESTBASE64_H_
diff --git a/rtc_base/testcertificateverifier.h b/rtc_base/testcertificateverifier.h
new file mode 100644
index 0000000..8ad6e4d
--- /dev/null
+++ b/rtc_base/testcertificateverifier.h
@@ -0,0 +1,34 @@
+/*
+ *  Copyright 2018 The WebRTC 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 RTC_BASE_TESTCERTIFICATEVERIFIER_H_
+#define RTC_BASE_TESTCERTIFICATEVERIFIER_H_
+
+#include "rtc_base/sslcertificate.h"
+
+namespace rtc {
+
+class TestCertificateVerifier : public SSLCertificateVerifier {
+ public:
+  TestCertificateVerifier() = default;
+  ~TestCertificateVerifier() override = default;
+
+  bool Verify(const SSLCertificate& certificate) override {
+    call_count_++;
+    return verify_certificate_;
+  }
+
+  size_t call_count_ = 0;
+  bool verify_certificate_ = true;
+};
+
+}  // namespace rtc
+
+#endif  // RTC_BASE_TESTCERTIFICATEVERIFIER_H_
diff --git a/rtc_base/testclient.cc b/rtc_base/testclient.cc
index 585db77..7c151c7 100644
--- a/rtc_base/testclient.cc
+++ b/rtc_base/testclient.cc
@@ -10,8 +10,8 @@
 
 #include "rtc_base/testclient.h"
 
+#include "absl/memory/memory.h"
 #include "rtc_base/gunit.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/thread.h"
 #include "rtc_base/timeutils.h"
 
@@ -49,7 +49,8 @@
   return socket_->Send(buf, size, options);
 }
 
-int TestClient::SendTo(const char* buf, size_t size,
+int TestClient::SendTo(const char* buf,
+                       size_t size,
                        const SocketAddress& dest) {
   rtc::PacketOptions options;
   return socket_->SendTo(buf, size, dest, options);
@@ -89,7 +90,8 @@
   return packet;
 }
 
-bool TestClient::CheckNextPacket(const char* buf, size_t size,
+bool TestClient::CheckNextPacket(const char* buf,
+                                 size_t size,
                                  SocketAddress* addr) {
   bool res = false;
   std::unique_ptr<Packet> packet = NextPacket(kTimeoutMs);
@@ -138,11 +140,14 @@
   return socket_->SetOption(opt, value);
 }
 
-void TestClient::OnPacket(AsyncPacketSocket* socket, const char* buf,
-                          size_t size, const SocketAddress& remote_addr,
+void TestClient::OnPacket(AsyncPacketSocket* socket,
+                          const char* buf,
+                          size_t size,
+                          const SocketAddress& remote_addr,
                           const PacketTime& packet_time) {
   CritScope cs(&crit_);
-  packets_.push_back(MakeUnique<Packet>(remote_addr, buf, size, packet_time));
+  packets_.push_back(
+      absl::make_unique<Packet>(remote_addr, buf, size, packet_time));
 }
 
 void TestClient::OnReadyToSend(AsyncPacketSocket* socket) {
diff --git a/rtc_base/testclient.h b/rtc_base/testclient.h
index c0dbe65..a0d98b3 100644
--- a/rtc_base/testclient.h
+++ b/rtc_base/testclient.h
@@ -34,7 +34,7 @@
     virtual ~Packet();
 
     SocketAddress addr;
-    char*  buf;
+    char* buf;
     size_t size;
     PacketTime packet_time;
   };
@@ -93,7 +93,9 @@
   // Workaround for the fact that AsyncPacketSocket::GetConnState doesn't exist.
   Socket::ConnState GetState();
   // Slot for packets read on the socket.
-  void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t len,
+  void OnPacket(AsyncPacketSocket* socket,
+                const char* buf,
+                size_t len,
                 const SocketAddress& remote_addr,
                 const PacketTime& packet_time);
   void OnReadyToSend(AsyncPacketSocket* socket);
diff --git a/rtc_base/testclient_unittest.cc b/rtc_base/testclient_unittest.cc
index 1d1d3f2..b3a6c80 100644
--- a/rtc_base/testclient_unittest.cc
+++ b/rtc_base/testclient_unittest.cc
@@ -9,10 +9,10 @@
  */
 
 #include "rtc_base/testclient.h"
+#include "absl/memory/memory.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/nethelpers.h"
 #include "rtc_base/physicalsocketserver.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/testechoserver.h"
 #include "rtc_base/thread.h"
 
@@ -31,12 +31,12 @@
   }
 
 void TestUdpInternal(const SocketAddress& loopback) {
-  Thread *main = Thread::Current();
-  AsyncSocket* socket = main->socketserver()
-      ->CreateAsyncSocket(loopback.family(), SOCK_DGRAM);
+  Thread* main = Thread::Current();
+  AsyncSocket* socket =
+      main->socketserver()->CreateAsyncSocket(loopback.family(), SOCK_DGRAM);
   socket->Bind(loopback);
 
-  TestClient client(MakeUnique<AsyncUDPSocket>(socket));
+  TestClient client(absl::make_unique<AsyncUDPSocket>(socket));
   SocketAddress addr = client.address(), from;
   EXPECT_EQ(3, client.SendTo("foo", 3, addr));
   EXPECT_TRUE(client.CheckNextPacket("foo", 3, &from));
@@ -45,13 +45,13 @@
 }
 
 void TestTcpInternal(const SocketAddress& loopback) {
-  Thread *main = Thread::Current();
+  Thread* main = Thread::Current();
   TestEchoServer server(main, loopback);
 
-  AsyncSocket* socket = main->socketserver()
-      ->CreateAsyncSocket(loopback.family(), SOCK_STREAM);
-  std::unique_ptr<AsyncTCPSocket> tcp_socket =
-      WrapUnique(AsyncTCPSocket::Create(socket, loopback, server.address()));
+  AsyncSocket* socket =
+      main->socketserver()->CreateAsyncSocket(loopback.family(), SOCK_STREAM);
+  std::unique_ptr<AsyncTCPSocket> tcp_socket = absl::WrapUnique(
+      AsyncTCPSocket::Create(socket, loopback, server.address()));
   ASSERT_TRUE(tcp_socket != nullptr);
 
   TestClient client(std::move(tcp_socket));
diff --git a/rtc_base/testechoserver.h b/rtc_base/testechoserver.h
index 672dda0..5e714eb 100644
--- a/rtc_base/testechoserver.h
+++ b/rtc_base/testechoserver.h
@@ -40,7 +40,9 @@
       client_sockets_.push_back(packet_socket);
     }
   }
-  void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
+  void OnPacket(AsyncPacketSocket* socket,
+                const char* buf,
+                size_t size,
                 const SocketAddress& remote_addr,
                 const PacketTime& packet_time) {
     rtc::PacketOptions options;
diff --git a/rtc_base/testutils.h b/rtc_base/testutils.h
index b000384..2ab4a35 100644
--- a/rtc_base/testutils.h
+++ b/rtc_base/testutils.h
@@ -37,8 +37,8 @@
 // event.
 
 enum StreamSinkEvent {
-  SSE_OPEN  = SE_OPEN,
-  SSE_READ  = SE_READ,
+  SSE_OPEN = SE_OPEN,
+  SSE_READ = SE_READ,
   SSE_WRITE = SE_WRITE,
   SSE_CLOSE = SE_CLOSE,
   SSE_ERROR = 16
@@ -50,15 +50,17 @@
   ~StreamSink() override;
 
   void Monitor(StreamInterface* stream) {
-   stream->SignalEvent.connect(this, &StreamSink::OnEvent);
-   events_.erase(stream);
+    stream->SignalEvent.connect(this, &StreamSink::OnEvent);
+    events_.erase(stream);
   }
   void Unmonitor(StreamInterface* stream) {
-   stream->SignalEvent.disconnect(this);
-   // In case you forgot to unmonitor a previous object with this address
-   events_.erase(stream);
+    stream->SignalEvent.disconnect(this);
+    // In case you forgot to unmonitor a previous object with this address
+    events_.erase(stream);
   }
-  bool Check(StreamInterface* stream, StreamSinkEvent event, bool reset = true) {
+  bool Check(StreamInterface* stream,
+             StreamSinkEvent event,
+             bool reset = true) {
     return DoCheck(stream, event, reset);
   }
   int Events(StreamInterface* stream, bool reset = true) {
@@ -66,19 +68,19 @@
   }
 
   void Monitor(AsyncSocket* socket) {
-   socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent);
-   socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent);
-   socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent);
-   socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent);
-   // In case you forgot to unmonitor a previous object with this address
-   events_.erase(socket);
+    socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent);
+    socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent);
+    socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent);
+    socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent);
+    // In case you forgot to unmonitor a previous object with this address
+    events_.erase(socket);
   }
   void Unmonitor(AsyncSocket* socket) {
-   socket->SignalConnectEvent.disconnect(this);
-   socket->SignalReadEvent.disconnect(this);
-   socket->SignalWriteEvent.disconnect(this);
-   socket->SignalCloseEvent.disconnect(this);
-   events_.erase(socket);
+    socket->SignalConnectEvent.disconnect(this);
+    socket->SignalReadEvent.disconnect(this);
+    socket->SignalWriteEvent.disconnect(this);
+    socket->SignalCloseEvent.disconnect(this);
+    events_.erase(socket);
   }
   bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) {
     return DoCheck(socket, event, reset);
@@ -88,7 +90,7 @@
   }
 
  private:
-  typedef std::map<void*,int> EventMap;
+  typedef std::map<void*, int> EventMap;
 
   void OnEvent(StreamInterface* stream, int events, int error) {
     if (error) {
@@ -96,15 +98,9 @@
     }
     AddEvents(stream, events);
   }
-  void OnConnectEvent(AsyncSocket* socket) {
-    AddEvents(socket, SSE_OPEN);
-  }
-  void OnReadEvent(AsyncSocket* socket) {
-    AddEvents(socket, SSE_READ);
-  }
-  void OnWriteEvent(AsyncSocket* socket) {
-    AddEvents(socket, SSE_WRITE);
-  }
+  void OnConnectEvent(AsyncSocket* socket) { AddEvents(socket, SSE_OPEN); }
+  void OnReadEvent(AsyncSocket* socket) { AddEvents(socket, SSE_READ); }
+  void OnWriteEvent(AsyncSocket* socket) { AddEvents(socket, SSE_WRITE); }
   void OnCloseEvent(AsyncSocket* socket, int error) {
     AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR);
   }
@@ -147,25 +143,24 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class StreamSource : public StreamInterface {
-public:
- StreamSource();
- ~StreamSource() override;
+ public:
+  StreamSource();
+  ~StreamSource() override;
 
- void Clear() {
-   readable_data_.clear();
-   written_data_.clear();
-   state_ = SS_CLOSED;
-   read_block_ = 0;
-   write_block_ = SIZE_UNKNOWN;
+  void Clear() {
+    readable_data_.clear();
+    written_data_.clear();
+    state_ = SS_CLOSED;
+    read_block_ = 0;
+    write_block_ = SIZE_UNKNOWN;
   }
-  void QueueString(const char* data) {
-    QueueData(data, strlen(data));
-  }
+  void QueueString(const char* data) { QueueData(data, strlen(data)); }
 #if defined(__GNUC__)
   // Note: Implicit |this| argument counts as the first argument.
   __attribute__((__format__(__printf__, 2, 3)))
 #endif
-  void QueueStringF(const char* format, ...) {
+  void
+  QueueStringF(const char* format, ...) {
     va_list args;
     va_start(args, format);
     char buffer[1024];
diff --git a/rtc_base/thread.cc b/rtc_base/thread.cc
index bb7b591..373fa39 100644
--- a/rtc_base/thread.cc
+++ b/rtc_base/thread.cc
@@ -18,6 +18,12 @@
 #error "Either WEBRTC_WIN or WEBRTC_POSIX needs to be defined."
 #endif
 
+#if defined(WEBRTC_WIN)
+// Disable warning that we don't care about:
+// warning C4722: destructor never returns, potential memory leak
+#pragma warning(disable : 4722)
+#endif
+
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/nullsocketserver.h"
@@ -29,8 +35,8 @@
 namespace rtc {
 
 ThreadManager* ThreadManager::Instance() {
-  RTC_DEFINE_STATIC_LOCAL(ThreadManager, thread_manager, ());
-  return &thread_manager;
+  static ThreadManager* const thread_manager = new ThreadManager();
+  return thread_manager;
 }
 
 ThreadManager::~ThreadManager() {
@@ -61,8 +67,8 @@
 }
 #endif
 
-Thread *ThreadManager::CurrentThread() {
-  return static_cast<Thread *>(pthread_getspecific(key_));
+Thread* ThreadManager::CurrentThread() {
+  return static_cast<Thread*>(pthread_getspecific(key_));
 }
 
 void ThreadManager::SetCurrentThread(Thread* thread) {
@@ -77,20 +83,19 @@
 
 #if defined(WEBRTC_WIN)
 ThreadManager::ThreadManager()
-    : key_(TlsAlloc()), main_thread_ref_(CurrentThreadRef()) {
+    : key_(TlsAlloc()), main_thread_ref_(CurrentThreadRef()) {}
+
+Thread* ThreadManager::CurrentThread() {
+  return static_cast<Thread*>(TlsGetValue(key_));
 }
 
-Thread *ThreadManager::CurrentThread() {
-  return static_cast<Thread *>(TlsGetValue(key_));
-}
-
-void ThreadManager::SetCurrentThread(Thread *thread) {
+void ThreadManager::SetCurrentThread(Thread* thread) {
   RTC_DCHECK(!CurrentThread() || !thread);
   TlsSetValue(key_, thread);
 }
 #endif
 
-Thread *ThreadManager::WrapCurrentThread() {
+Thread* ThreadManager::WrapCurrentThread() {
   Thread* result = CurrentThread();
   if (nullptr == result) {
     result = new Thread(SocketServer::CreateDefault());
@@ -112,9 +117,8 @@
 }
 
 Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
-  : thread_(Thread::Current()),
-    previous_state_(thread_->SetAllowBlockingCalls(false)) {
-}
+    : thread_(Thread::Current()),
+      previous_state_(thread_->SetAllowBlockingCalls(false)) {}
 
 Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() {
   RTC_DCHECK(thread_->IsCurrent());
@@ -357,7 +361,7 @@
   AssertBlockingIsAllowedOnCurrentThread();
 
   AutoThread thread;
-  Thread *current_thread = Thread::Current();
+  Thread* current_thread = Thread::Current();
   RTC_DCHECK(current_thread != nullptr);  // AutoThread ensures this
 
   bool ready = false;
@@ -418,7 +422,7 @@
   while (PopSendMessageFromThread(source, &smsg)) {
     crit_.Leave();
 
-    smsg.msg.phandler->OnMessage(&smsg.msg);
+    Dispatch(&smsg.msg);
 
     crit_.Enter();
     *smsg.ready = true;
diff --git a/rtc_base/thread.h b/rtc_base/thread.h
index 568764e..0408a0d 100644
--- a/rtc_base/thread.h
+++ b/rtc_base/thread.h
@@ -56,7 +56,7 @@
   // shame to break it.  It is also conceivable on Win32 that we won't even
   // be able to get synchronization privileges, in which case the result
   // will have a null handle.
-  Thread *WrapCurrentThread();
+  Thread* WrapCurrentThread();
   void UnwrapCurrentThread();
 
   bool IsMainThread();
@@ -81,9 +81,9 @@
 
 struct _SendMessage {
   _SendMessage() {}
-  Thread *thread;
+  Thread* thread;
   Message msg;
-  bool *ready;
+  bool* ready;
 };
 
 class Runnable {
@@ -135,6 +135,7 @@
    public:
     ScopedDisallowBlockingCalls();
     ~ScopedDisallowBlockingCalls();
+
    private:
     Thread* const thread_;
     const bool previous_state_;
@@ -249,7 +250,7 @@
 #if defined(WEBRTC_WIN)
   static DWORD WINAPI PreRun(LPVOID context);
 #else
-  static void *PreRun(void *pv);
+  static void* PreRun(void* pv);
 #endif
 
   // ThreadManager calls this instead WrapCurrent() because
@@ -278,8 +279,8 @@
   std::list<_SendMessage> sendlist_;
   std::string name_;
 
-  // TODO(tommi): Add thread checks for proper use of control methods.
-  // Ideally we should be able to just use PlatformThread.
+// TODO(tommi): Add thread checks for proper use of control methods.
+// Ideally we should be able to just use PlatformThread.
 
 #if defined(WEBRTC_POSIX)
   pthread_t thread_ = 0;
diff --git a/rtc_base/thread_annotations_unittest.cc b/rtc_base/thread_annotations_unittest.cc
index d8a4af1..949f042 100644
--- a/rtc_base/thread_annotations_unittest.cc
+++ b/rtc_base/thread_annotations_unittest.cc
@@ -32,13 +32,9 @@
 
 class ThreadSafe {
  public:
-  ThreadSafe() {
-    pt_protected_by_lock_ = new int;
-  }
+  ThreadSafe() { pt_protected_by_lock_ = new int; }
 
-  ~ThreadSafe() {
-    delete pt_protected_by_lock_;
-  }
+  ~ThreadSafe() { delete pt_protected_by_lock_; }
 
   void LockInOrder() {
     beforelock_.EnterWrite();
diff --git a/rtc_base/thread_checker.h b/rtc_base/thread_checker.h
index cc03b8d..ad04508 100644
--- a/rtc_base/thread_checker.h
+++ b/rtc_base/thread_checker.h
@@ -32,9 +32,7 @@
 // right version for your build configuration.
 class ThreadCheckerDoNothing {
  public:
-  bool CalledOnValidThread() const {
-    return true;
-  }
+  bool CalledOnValidThread() const { return true; }
 
   void DetachFromThread() {}
 };
@@ -86,7 +84,7 @@
       RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
   ~AnnounceOnThread() RTC_UNLOCK_FUNCTION() {}
 
-  template<typename ThreadLikeObject>
+  template <typename ThreadLikeObject>
   static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
     return thread_like_object->IsCurrent();
   }
@@ -163,9 +161,10 @@
 // }
 
 // Document if a function expected to be called from same thread/task queue.
-#define RTC_RUN_ON(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
+#define RTC_RUN_ON(x) \
+  RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
 
-#define RTC_DCHECK_RUN_ON(thread_like_object) \
+#define RTC_DCHECK_RUN_ON(thread_like_object)                           \
   rtc::internal::AnnounceOnThread thread_announcer(thread_like_object); \
   RTC_DCHECK(rtc::internal::AnnounceOnThread::IsCurrent(thread_like_object))
 
diff --git a/rtc_base/thread_checker_impl.cc b/rtc_base/thread_checker_impl.cc
index 850f2ac..a9e87c6 100644
--- a/rtc_base/thread_checker_impl.cc
+++ b/rtc_base/thread_checker_impl.cc
@@ -14,11 +14,9 @@
 
 namespace rtc {
 
-ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_(CurrentThreadRef()) {
-}
+ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_(CurrentThreadRef()) {}
 
-ThreadCheckerImpl::~ThreadCheckerImpl() {
-}
+ThreadCheckerImpl::~ThreadCheckerImpl() {}
 
 bool ThreadCheckerImpl::CalledOnValidThread() const {
   const PlatformThreadRef current_thread = CurrentThreadRef();
diff --git a/rtc_base/thread_checker_unittest.cc b/rtc_base/thread_checker_unittest.cc
index ba5ac9e..9c0942f 100644
--- a/rtc_base/thread_checker_unittest.cc
+++ b/rtc_base/thread_checker_unittest.cc
@@ -38,9 +38,7 @@
   // Verifies that it was called on the same thread as the constructor.
   void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
 
-  void DetachFromThread() {
-    ThreadChecker::DetachFromThread();
-  }
+  void DetachFromThread() { ThreadChecker::DetachFromThread(); }
 
   static void MethodOnDifferentThreadImpl();
   static void DetachThenCallFromDifferentThreadImpl();
@@ -62,9 +60,7 @@
 
   // New method. Needed since Thread::Join is protected, and it is called by
   // the TEST.
-  void Join() {
-    Thread::Join();
-  }
+  void Join() { Thread::Join(); }
 
  private:
   ThreadCheckerClass* thread_checker_class_;
@@ -86,9 +82,7 @@
 
   // New method. Needed since Thread::Join is protected, and it is called by
   // the TEST.
-  void Join() {
-    Thread::Join();
-  }
+  void Join() { Thread::Join(); }
 
   bool has_been_deleted() const { return !thread_checker_class_; }
 
@@ -157,9 +151,7 @@
 
 #if ENABLE_THREAD_CHECKER
 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
-  ASSERT_DEATH({
-      ThreadCheckerClass::MethodOnDifferentThreadImpl();
-    }, "");
+  ASSERT_DEATH({ ThreadCheckerClass::MethodOnDifferentThreadImpl(); }, "");
 }
 #else
 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
@@ -186,9 +178,8 @@
 
 #if ENABLE_THREAD_CHECKER
 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
-  ASSERT_DEATH({
-    ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
-    }, "");
+  ASSERT_DEATH({ ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); },
+               "");
 }
 #else
 TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
@@ -204,12 +195,12 @@
   // specific T).
   // TODO(danilchap): Find a way to test they do not compile when thread
   // annotation checks enabled.
-  template<typename T>
+  template <typename T>
   void access_var_no_annotate() {
     var_thread_ = 42;
   }
 
-  template<typename T>
+  template <typename T>
   void access_fun_no_annotate() {
     function();
   }
diff --git a/rtc_base/thread_unittest.cc b/rtc_base/thread_unittest.cc
index 01022e9..74f62eb 100644
--- a/rtc_base/thread_unittest.cc
+++ b/rtc_base/thread_unittest.cc
@@ -51,8 +51,10 @@
 // Receives on a socket and sends by posting messages.
 class SocketClient : public TestGenerator, public sigslot::has_slots<> {
  public:
-  SocketClient(AsyncSocket* socket, const SocketAddress& addr,
-               Thread* post_thread, MessageHandler* phandler)
+  SocketClient(AsyncSocket* socket,
+               const SocketAddress& addr,
+               Thread* post_thread,
+               MessageHandler* phandler)
       : socket_(AsyncUDPSocket::Create(socket, addr)),
         post_thread_(post_thread),
         post_handler_(phandler) {
@@ -63,7 +65,9 @@
 
   SocketAddress address() const { return socket_->GetLocalAddress(); }
 
-  void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
+  void OnPacket(AsyncPacketSocket* socket,
+                const char* buf,
+                size_t size,
                 const SocketAddress& remote_addr,
                 const PacketTime& packet_time) {
     EXPECT_EQ(size, sizeof(uint32_t));
@@ -83,9 +87,7 @@
 // Receives messages and sends on a socket.
 class MessageClient : public MessageHandler, public TestGenerator {
  public:
-  MessageClient(Thread* pth, Socket* socket)
-      : socket_(socket) {
-  }
+  MessageClient(Thread* pth, Socket* socket) : socket_(socket) {}
 
   ~MessageClient() override { delete socket_; }
 
@@ -107,15 +109,10 @@
   ~CustomThread() override { Stop(); }
   bool Start() { return false; }
 
-  bool WrapCurrent() {
-    return Thread::WrapCurrent();
-  }
-  void UnwrapCurrent() {
-    Thread::UnwrapCurrent();
-  }
+  bool WrapCurrent() { return Thread::WrapCurrent(); }
+  void UnwrapCurrent() { Thread::UnwrapCurrent(); }
 };
 
-
 // A thread that does nothing when it runs and signals an event
 // when it is destroyed.
 class SignalWhenDestroyedThread : public Thread {
@@ -176,7 +173,11 @@
 class FunctorB {
  public:
   explicit FunctorB(AtomicBool* flag) : flag_(flag) {}
-  void operator()() { if (flag_) *flag_ = true; }
+  void operator()() {
+    if (flag_)
+      *flag_ = true;
+  }
+
  private:
   AtomicBool* flag_;
 };
@@ -191,7 +192,11 @@
   explicit FunctorD(AtomicBool* flag) : flag_(flag) {}
   FunctorD(FunctorD&&) = default;
   FunctorD& operator=(FunctorD&&) = default;
-  void operator()() { if (flag_) *flag_ = true; }
+  void operator()() {
+    if (flag_)
+      *flag_ = true;
+  }
+
  private:
   AtomicBool* flag_;
   RTC_DISALLOW_COPY_AND_ASSIGN(FunctorD);
@@ -431,9 +436,7 @@
 
  protected:
   enum { kWaitTimeout = 1000 };
-  AsyncInvokeTest()
-      : int_value_(0),
-        expected_thread_(nullptr) {}
+  AsyncInvokeTest() : int_value_(0), expected_thread_(nullptr) {}
 
   int int_value_;
   Thread* expected_thread_;
@@ -580,9 +583,7 @@
 
  protected:
   const static int kWaitTimeout = 1000;
-  GuardedAsyncInvokeTest()
-      : int_value_(0),
-        expected_thread_(nullptr) {}
+  GuardedAsyncInvokeTest() : int_value_(0), expected_thread_(nullptr) {}
 
   int int_value_;
   Thread* expected_thread_;
diff --git a/rtc_base/timedelta.h b/rtc_base/timedelta.h
deleted file mode 100644
index c8dcf03..0000000
--- a/rtc_base/timedelta.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *  Copyright 2016 The WebRTC 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 RTC_BASE_TIMEDELTA_H_
-#define RTC_BASE_TIMEDELTA_H_
-
-#include <stdint.h>
-
-#include "rtc_base/timeutils.h"
-
-// Convenience class to convert between different units of relative time.
-// Stores time to precision of nanoseconds, as int64_t internally.
-// Doesn't check for overflow/underflow.
-//
-// Based on TimeDelta in:
-// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time.h
-namespace rtc {
-
-class TimeDelta {
- public:
-  TimeDelta() : delta_(0) {}
-
-  // Converts units of time to TimeDeltas.
-  static constexpr TimeDelta FromSeconds(int64_t secs) {
-    return TimeDelta(secs * kNumNanosecsPerSec);
-  }
-  static constexpr TimeDelta FromMilliseconds(int64_t ms) {
-    return TimeDelta(ms * kNumNanosecsPerMillisec);
-  }
-  static constexpr TimeDelta FromMicroseconds(int64_t us) {
-    return TimeDelta(us * kNumNanosecsPerMicrosec);
-  }
-  static constexpr TimeDelta FromNanoseconds(int64_t ns) {
-    return TimeDelta(ns);
-  }
-
-  // Returns true if the time delta is zero.
-  bool is_zero() const { return delta_ == 0; }
-
-  // Converts TimeDelta to units of time.
-  int64_t ToSeconds() const { return delta_ / kNumNanosecsPerSec; }
-  int64_t ToMilliseconds() const { return delta_ / kNumNanosecsPerMillisec; }
-  int64_t ToMicroseconds() const { return delta_ / kNumNanosecsPerMicrosec; }
-  int64_t ToNanoseconds() const { return delta_; }
-
-  TimeDelta& operator=(TimeDelta other) {
-    delta_ = other.delta_;
-    return *this;
-  }
-
-  // Computations with other deltas.
-  TimeDelta operator+(TimeDelta other) const {
-    return TimeDelta(delta_ + other.delta_);
-  }
-  TimeDelta operator-(TimeDelta other) const {
-    return TimeDelta(delta_ + other.delta_);
-  }
-
-  TimeDelta& operator+=(TimeDelta other) { return *this = (*this + other); }
-  TimeDelta& operator-=(TimeDelta other) { return *this = (*this - other); }
-  TimeDelta operator-() const { return TimeDelta(-delta_); }
-
-  // Computations with numeric types.
-  template <typename T>
-  TimeDelta operator*(T a) const {
-    return TimeDelta(delta_ * a);
-  }
-  template <typename T>
-  TimeDelta operator/(T a) const {
-    return TimeDelta(delta_ / a);
-  }
-  template <typename T>
-  TimeDelta& operator*=(T a) {
-    return *this = (*this * a);
-  }
-  template <typename T>
-  TimeDelta& operator/=(T a) {
-    return *this = (*this / a);
-  }
-
-  TimeDelta operator%(TimeDelta a) const {
-    return TimeDelta(delta_ % a.delta_);
-  }
-
-  // Comparison operators.
-  constexpr bool operator==(TimeDelta other) const {
-    return delta_ == other.delta_;
-  }
-  constexpr bool operator!=(TimeDelta other) const {
-    return delta_ != other.delta_;
-  }
-  constexpr bool operator<(TimeDelta other) const {
-    return delta_ < other.delta_;
-  }
-  constexpr bool operator<=(TimeDelta other) const {
-    return delta_ <= other.delta_;
-  }
-  constexpr bool operator>(TimeDelta other) const {
-    return delta_ > other.delta_;
-  }
-  constexpr bool operator>=(TimeDelta other) const {
-    return delta_ >= other.delta_;
-  }
-
- private:
-  // Constructs a delta given the duration in nanoseconds. This is private
-  // to avoid confusion by callers with an integer constructor. Use
-  // FromSeconds, FromMilliseconds, etc. instead.
-  constexpr explicit TimeDelta(int64_t delta_ns) : delta_(delta_ns) {}
-
-  // Delta in nanoseconds.
-  int64_t delta_;
-};
-
-template <typename T>
-inline TimeDelta operator*(T a, TimeDelta td) {
-  return td * a;
-}
-
-}  // namespace rtc
-
-#endif  // RTC_BASE_TIMEDELTA_H_
diff --git a/rtc_base/timeutils.cc b/rtc_base/timeutils.cc
index 35c25c7..f65bd15 100644
--- a/rtc_base/timeutils.cc
+++ b/rtc_base/timeutils.cc
@@ -18,12 +18,13 @@
 #endif
 
 #if defined(WEBRTC_WIN)
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
+// clang-format off
+// clang formatting would put <windows.h> last,
+// which leads to compilation failure.
 #include <windows.h>
 #include <mmsystem.h>
 #include <sys/timeb.h>
+// clang-format on
 #endif
 
 #include "rtc_base/checks.h"
@@ -164,8 +165,8 @@
   int min = tm.tm_min;
   int sec = tm.tm_sec;
 
-  bool expiry_in_leap_year = (year % 4 == 0 &&
-                              (year % 100 != 0 || year % 400 == 0));
+  bool expiry_in_leap_year =
+      (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
 
   if (year < 1970)
     return -1;
@@ -188,13 +189,15 @@
 
   // We will have added one day too much above if expiration is during a leap
   // year, and expiration is in January or February.
-  if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based.
+  if (expiry_in_leap_year && month <= 2 - 1)  // |month| is zero based.
     day -= 1;
 
   // Combine all variables into seconds from 1970-01-01 00:00 (except |month|
   // which was accumulated into |day| above).
-  return (((static_cast<int64_t>
-            (year - 1970) * 365 + day) * 24 + hour) * 60 + min) * 60 + sec;
+  return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 +
+          min) *
+             60 +
+         sec;
 }
 
 int64_t TimeUTCMicros() {
@@ -214,4 +217,4 @@
 #endif
 }
 
-} // namespace rtc
+}  // namespace rtc
diff --git a/rtc_base/timeutils.h b/rtc_base/timeutils.h
index 5eb73c7..48b5c8d 100644
--- a/rtc_base/timeutils.h
+++ b/rtc_base/timeutils.h
@@ -80,7 +80,6 @@
 // Returns the current time in nanoseconds.
 int64_t TimeNanos();
 
-
 // Returns a future timestamp, 'elapsed' milliseconds from now.
 int64_t TimeAfter(int64_t elapsed);
 
diff --git a/rtc_base/timeutils_unittest.cc b/rtc_base/timeutils_unittest.cc
index 592b7f8..0e1949a 100644
--- a/rtc_base/timeutils_unittest.cc
+++ b/rtc_base/timeutils_unittest.cc
@@ -33,7 +33,7 @@
 
   // We can't depend on ts_later and ts_earlier to be exactly 500 apart
   // since time elapses between the calls to TimeMillis() and TimeAfter(500)
-  EXPECT_LE(500,  TimeDiff(ts_later, ts_earlier));
+  EXPECT_LE(500, TimeDiff(ts_later, ts_earlier));
   EXPECT_GE(-500, TimeDiff(ts_earlier, ts_later));
 
   // Time has elapsed since ts_earlier
@@ -125,7 +125,6 @@
   void TestTmToSeconds(int times) {
     static char mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
     for (int i = 0; i < times; i++) {
-
       // First generate something correct and check that TmToSeconds is happy.
       int year = rtc::CreateRandomId() % 400 + 1970;
 
@@ -206,96 +205,6 @@
   TestTmToSeconds(100000);
 }
 
-TEST(TimeDelta, FromAndTo) {
-  EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
-  EXPECT_TRUE(TimeDelta::FromMilliseconds(3) ==
-              TimeDelta::FromMicroseconds(3000));
-  EXPECT_TRUE(TimeDelta::FromMicroseconds(4) ==
-              TimeDelta::FromNanoseconds(4000));
-  EXPECT_EQ(13, TimeDelta::FromSeconds(13).ToSeconds());
-  EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).ToMilliseconds());
-  EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).ToMicroseconds());
-  EXPECT_EQ(13, TimeDelta::FromNanoseconds(13).ToNanoseconds());
-}
-
-TEST(TimeDelta, ComparisonOperators) {
-  EXPECT_LT(TimeDelta::FromSeconds(1), TimeDelta::FromSeconds(2));
-  EXPECT_EQ(TimeDelta::FromSeconds(3), TimeDelta::FromSeconds(3));
-  EXPECT_GT(TimeDelta::FromSeconds(5), TimeDelta::FromSeconds(4));
-}
-
-TEST(TimeDelta, NumericOperators) {
-  double d = 0.5;
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) * d);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) / d);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) *= d);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) /= d);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            d * TimeDelta::FromMilliseconds(1000));
-
-  float f = 0.5;
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) * f);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) / f);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) *= f);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) /= f);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            f * TimeDelta::FromMilliseconds(1000));
-
-  int i = 2;
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) * i);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) / i);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) *= i);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) /= i);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            i * TimeDelta::FromMilliseconds(1000));
-
-  int64_t i64 = 2;
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) * i64);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) / i64);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) *= i64);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) /= i64);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            i64 * TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) * 0.5);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) / 0.5);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) *= 0.5);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) /= 0.5);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            0.5 * TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) * 2);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) / 2);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000) *= 2);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000) /= 2);
-  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            2 * TimeDelta::FromMilliseconds(1000));
-}
-
 // Test that all the time functions exposed by TimeUtils get time from the
 // fake clock when it's set.
 TEST(FakeClock, TimeFunctionsUseFakeClock) {
@@ -329,14 +238,14 @@
 
 TEST(FakeClock, AdvanceTime) {
   FakeClock clock;
-  clock.AdvanceTime(TimeDelta::FromNanoseconds(1111u));
-  EXPECT_EQ(1111, clock.TimeNanos());
-  clock.AdvanceTime(TimeDelta::FromMicroseconds(2222u));
-  EXPECT_EQ(2223111, clock.TimeNanos());
-  clock.AdvanceTime(TimeDelta::FromMilliseconds(3333u));
-  EXPECT_EQ(3335223111, clock.TimeNanos());
-  clock.AdvanceTime(TimeDelta::FromSeconds(4444u));
-  EXPECT_EQ(4447335223111, clock.TimeNanos());
+  clock.AdvanceTime(webrtc::TimeDelta::us(1u));
+  EXPECT_EQ(1000, clock.TimeNanos());
+  clock.AdvanceTime(webrtc::TimeDelta::us(2222u));
+  EXPECT_EQ(2223000, clock.TimeNanos());
+  clock.AdvanceTime(webrtc::TimeDelta::ms(3333u));
+  EXPECT_EQ(3335223000, clock.TimeNanos());
+  clock.AdvanceTime(webrtc::TimeDelta::seconds(4444u));
+  EXPECT_EQ(4447335223000, clock.TimeNanos());
 }
 
 // When the clock is advanced, threads that are waiting in a socket select
@@ -367,7 +276,7 @@
 
   // Advance the fake clock, expecting the worker thread to wake up
   // and dispatch the message instantly.
-  clock.AdvanceTime(TimeDelta::FromSeconds(60u));
+  clock.AdvanceTime(webrtc::TimeDelta::seconds(60u));
   EXPECT_TRUE(message_handler_dispatched.Wait(0));
   worker->Stop();
 
diff --git a/rtc_base/trace_event.h b/rtc_base/trace_event.h
index 7a9f2dd..fee9a7f 100644
--- a/rtc_base/trace_event.h
+++ b/rtc_base/trace_event.h
@@ -168,35 +168,6 @@
     INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \
         arg2_name, arg2_val)
 
-// Same as TRACE_EVENT except that they are not included in official builds.
-#ifdef OFFICIAL_BUILD
-#define UNSHIPPED_TRACE_EVENT0(category, name) (void)0
-#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) (void)0
-#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \
-                               arg2_name, arg2_val) (void)0
-#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) (void)0
-#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
-    (void)0
-#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
-                                       arg2_name, arg2_val) (void)0
-#else
-#define UNSHIPPED_TRACE_EVENT0(category, name) \
-    TRACE_EVENT0(category, name)
-#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) \
-    TRACE_EVENT1(category, name, arg1_name, arg1_val)
-#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \
-                               arg2_name, arg2_val) \
-    TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val)
-#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) \
-    TRACE_EVENT_INSTANT0(category, name)
-#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
-    TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val)
-#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
-                                       arg2_name, arg2_val) \
-    TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
-                         arg2_name, arg2_val)
-#endif
-
 // Records a single event called "name" immediately, with 0, 1 or 2
 // associated arguments. If the category is not enabled, then this
 // does nothing.
diff --git a/rtc_base/transformadapter.cc b/rtc_base/transformadapter.cc
deleted file mode 100644
index 943a5b9..0000000
--- a/rtc_base/transformadapter.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- *  Copyright 2004 The WebRTC 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.
- */
-
-#include "rtc_base/transformadapter.h"
-
-#include <string.h>
-
-#include "rtc_base/checks.h"
-
-namespace rtc {
-
-///////////////////////////////////////////////////////////////////////////////
-
-TransformAdapter::TransformAdapter(StreamInterface * stream,
-                                   TransformInterface * transform,
-                                   bool direction_read)
-    : StreamAdapterInterface(stream), transform_(transform),
-      direction_read_(direction_read), state_(ST_PROCESSING), len_(0) {
-}
-
-TransformAdapter::~TransformAdapter() {
-  TransformAdapter::Close();
-  delete transform_;
-}
-
-StreamResult
-TransformAdapter::Read(void * buffer, size_t buffer_len,
-                       size_t * read, int * error) {
-  if (!direction_read_)
-    return SR_EOS;
-
-  while (state_ != ST_ERROR) {
-    if (state_ == ST_COMPLETE)
-      return SR_EOS;
-
-    // Buffer more data
-    if ((state_ == ST_PROCESSING) && (len_ < sizeof(buffer_))) {
-      size_t subread;
-      StreamResult result = StreamAdapterInterface::Read(
-                              buffer_ + len_,
-                              sizeof(buffer_) - len_,
-                              &subread,
-                              &error_);
-      if (result == SR_BLOCK) {
-        return SR_BLOCK;
-      } else if (result == SR_ERROR) {
-        state_ = ST_ERROR;
-        break;
-      } else if (result == SR_EOS) {
-        state_ = ST_FLUSHING;
-      } else {
-        len_ += subread;
-      }
-    }
-
-    // Process buffered data
-    size_t in_len = len_;
-    size_t out_len = buffer_len;
-    StreamResult result = transform_->Transform(buffer_, &in_len,
-                                                buffer, &out_len,
-                                                (state_ == ST_FLUSHING));
-    RTC_DCHECK(result != SR_BLOCK);
-    if (result == SR_EOS) {
-      // Note: Don't signal SR_EOS this iteration, unless out_len is zero
-      state_ = ST_COMPLETE;
-    } else if (result == SR_ERROR) {
-      state_ = ST_ERROR;
-      error_ = -1; // TODO: propagate error
-      break;
-    } else if ((out_len == 0) && (state_ == ST_FLUSHING)) {
-      // If there is no output AND no more input, then something is wrong
-      state_ = ST_ERROR;
-      error_ = -1; // TODO: better error code?
-      break;
-    }
-
-    len_ -= in_len;
-    if (len_ > 0)
-      memmove(buffer_, buffer_ + in_len, len_);
-
-    if (out_len == 0)
-      continue;
-
-    if (read)
-      *read = out_len;
-    return SR_SUCCESS;
-  }
-
-  if (error)
-    *error = error_;
-  return SR_ERROR;
-}
-
-StreamResult
-TransformAdapter::Write(const void * data, size_t data_len,
-                        size_t * written, int * error) {
-  if (direction_read_)
-    return SR_EOS;
-
-  size_t bytes_written = 0;
-  while (state_ != ST_ERROR) {
-    if (state_ == ST_COMPLETE)
-      return SR_EOS;
-
-    if (len_ < sizeof(buffer_)) {
-      // Process buffered data
-      size_t in_len = data_len;
-      size_t out_len = sizeof(buffer_) - len_;
-      StreamResult result = transform_->Transform(data, &in_len,
-                                                  buffer_ + len_, &out_len,
-                                                  (state_ == ST_FLUSHING));
-
-      RTC_DCHECK(result != SR_BLOCK);
-      if (result == SR_EOS) {
-        // Note: Don't signal SR_EOS this iteration, unless no data written
-        state_ = ST_COMPLETE;
-      } else if (result == SR_ERROR) {
-        RTC_NOTREACHED();  // When this happens, think about what should be done
-        state_ = ST_ERROR;
-        error_ = -1; // TODO: propagate error
-        break;
-      }
-
-      len_ = out_len;
-      bytes_written = in_len;
-    }
-
-    size_t pos = 0;
-    while (pos < len_) {
-      size_t subwritten;
-      StreamResult result = StreamAdapterInterface::Write(buffer_ + pos,
-                                                          len_ - pos,
-                                                          &subwritten,
-                                                          &error_);
-      if (result == SR_BLOCK) {
-        RTC_NOTREACHED();  // We should handle this
-        return SR_BLOCK;
-      } else if (result == SR_ERROR) {
-        state_ = ST_ERROR;
-        break;
-      } else if (result == SR_EOS) {
-        state_ = ST_COMPLETE;
-        break;
-      }
-
-      pos += subwritten;
-    }
-
-    len_ -= pos;
-    if (len_ > 0)
-      memmove(buffer_, buffer_ + pos, len_);
-
-    if (bytes_written == 0)
-      continue;
-
-    if (written)
-      *written = bytes_written;
-    return SR_SUCCESS;
-  }
-
-  if (error)
-    *error = error_;
-  return SR_ERROR;
-}
-
-void
-TransformAdapter::Close() {
-  if (!direction_read_ && (state_ == ST_PROCESSING)) {
-    state_ = ST_FLUSHING;
-    do {
-      Write(0, 0, nullptr, nullptr);
-    } while (state_ == ST_FLUSHING);
-  }
-  state_ = ST_COMPLETE;
-  StreamAdapterInterface::Close();
-}
-
-bool TransformAdapter::GetAvailable(size_t* size) const {
-  return false;
-}
-
-bool TransformAdapter::ReserveSize(size_t size) {
-  return true;
-}
-
-bool TransformAdapter::Rewind() {
-  return false;
-}
-
-} // namespace rtc
diff --git a/rtc_base/transformadapter.h b/rtc_base/transformadapter.h
deleted file mode 100644
index 5e8aa9a..0000000
--- a/rtc_base/transformadapter.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  Copyright 2004 The WebRTC 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 RTC_BASE_TRANSFORMADAPTER_H_
-#define RTC_BASE_TRANSFORMADAPTER_H_
-
-#include "rtc_base/stream.h"
-
-namespace rtc {
-///////////////////////////////////////////////////////////////////////////////
-
-class TransformInterface {
-public:
-  virtual ~TransformInterface() { }
-
-  // Transform should convert the in_len bytes of input into the out_len-sized
-  // output buffer.  If flush is true, there will be no more data following
-  // input.
-  // After the transformation, in_len contains the number of bytes consumed, and
-  // out_len contains the number of bytes ready in output.
-  // Note: Transform should not return SR_BLOCK, as there is no asynchronous
-  // notification available.
-  virtual StreamResult Transform(const void * input, size_t * in_len,
-                                 void * output, size_t * out_len,
-                                 bool flush) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-// TransformAdapter causes all data passed through to be transformed by the
-// supplied TransformInterface object, which may apply compression, encryption,
-// etc.
-
-class TransformAdapter : public StreamAdapterInterface {
-public:
-  // Note that the transformation is unidirectional, in the direction specified
-  // by the constructor.  Operations in the opposite direction result in SR_EOS.
-  TransformAdapter(StreamInterface * stream,
-                   TransformInterface * transform,
-                   bool direction_read);
-  ~TransformAdapter() override;
-
-  StreamResult Read(void* buffer,
-                    size_t buffer_len,
-                    size_t* read,
-                    int* error) override;
-  StreamResult Write(const void* data,
-                     size_t data_len,
-                     size_t* written,
-                     int* error) override;
-  void Close() override;
-
-  // Apriori, we can't tell what the transformation does to the stream length.
-  bool GetAvailable(size_t* size) const override;
-  bool ReserveSize(size_t size) override;
-
-  // Transformations might not be restartable
-  virtual bool Rewind();
-
-private:
-  enum State { ST_PROCESSING, ST_FLUSHING, ST_COMPLETE, ST_ERROR };
-  enum { BUFFER_SIZE = 1024 };
-
-  TransformInterface * transform_;
-  bool direction_read_;
-  State state_;
-  int error_;
-
-  char buffer_[BUFFER_SIZE];
-  size_t len_;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-} // namespace rtc
-
-#endif // RTC_BASE_TRANSFORMADAPTER_H_
diff --git a/rtc_base/type_traits.h b/rtc_base/type_traits.h
index 4f004cd..0cb899c 100644
--- a/rtc_base/type_traits.h
+++ b/rtc_base/type_traits.h
@@ -133,7 +133,7 @@
 static_assert(!IsIntlike<float>::value, "");
 static_assert(!IsIntlike<S>::value, "");
 
-}  // test_enum_intlike
+}  // namespace test_enum_intlike
 
 }  // namespace rtc
 
diff --git a/rtc_base/unittest_main.cc b/rtc_base/unittest_main.cc
index aa8a11b..0b5a39d 100644
--- a/rtc_base/unittest_main.cc
+++ b/rtc_base/unittest_main.cc
@@ -20,6 +20,7 @@
 #include "rtc_base/ssladapter.h"
 #include "rtc_base/sslstreamadapter.h"
 #include "system_wrappers/include/field_trial_default.h"
+#include "system_wrappers/include/metrics_default.h"
 #include "test/field_trial.h"
 #include "test/testsupport/fileutils.h"
 
@@ -37,7 +38,8 @@
     " will assign the group Enable to field trial WebRTC-FooFeature.");
 #if defined(WEBRTC_WIN)
 DEFINE_int(crt_break_alloc, -1, "memory allocation to break on");
-DEFINE_bool(default_error_handlers, false,
+DEFINE_bool(default_error_handlers,
+            false,
             "leave the default exception/dbg handler functions in place");
 
 void TestInvalidParameterHandler(const wchar_t* expression,
@@ -45,11 +47,10 @@
                                  const wchar_t* file,
                                  unsigned int line,
                                  uintptr_t pReserved) {
+  // In order to log `expression`, `function`, and `file` here, we would have
+  // to convert them to const char*. std::wcsrtombs can do that, but it's
+  // locale dependent.
   RTC_LOG(LS_ERROR) << "InvalidParameter Handler called.  Exiting.";
-  RTC_LOG(LS_ERROR) << expression << std::endl
-                    << function << std::endl
-                    << file << std::endl
-                    << line;
   exit(1);
 }
 void TestPureCallHandler() {
@@ -81,6 +82,7 @@
   // InitFieldTrialsFromString stores the char*, so the char array must outlive
   // the application.
   webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials);
+  webrtc::metrics::Enable();
 
 #if defined(WEBRTC_WIN)
   if (!FLAG_default_error_handlers) {
@@ -91,7 +93,7 @@
   }
 
 #if !defined(NDEBUG)  // Turn on memory leak checking on Windows.
-  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF |_CRTDBG_LEAK_CHECK_DF);
+  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
   if (FLAG_crt_break_alloc >= 0) {
     _crtBreakAlloc = FLAG_crt_break_alloc;
   }
diff --git a/rtc_base/unixfilesystem.cc b/rtc_base/unixfilesystem.cc
index a48aca1..023c34c 100644
--- a/rtc_base/unixfilesystem.cc
+++ b/rtc_base/unixfilesystem.cc
@@ -57,7 +57,7 @@
 
 UnixFilesystem::~UnixFilesystem() {}
 
-bool UnixFilesystem::DeleteFile(const Pathname &filename) {
+bool UnixFilesystem::DeleteFile(const Pathname& filename) {
   RTC_LOG(LS_INFO) << "Deleting file:" << filename.pathname();
 
   if (!IsFile(filename)) {
@@ -67,8 +67,8 @@
   return ::unlink(filename.pathname().c_str()) == 0;
 }
 
-bool UnixFilesystem::MoveFile(const Pathname &old_path,
-                              const Pathname &new_path) {
+bool UnixFilesystem::MoveFile(const Pathname& old_path,
+                              const Pathname& new_path) {
   if (!IsFile(old_path)) {
     RTC_DCHECK(IsFile(old_path));
     return false;
@@ -81,7 +81,7 @@
   return true;
 }
 
-bool UnixFilesystem::IsFolder(const Pathname &path) {
+bool UnixFilesystem::IsFolder(const Pathname& path) {
   struct stat st;
   if (stat(path.pathname().c_str(), &st) < 0)
     return false;
@@ -95,7 +95,7 @@
   return res == 0 && !S_ISDIR(st.st_mode);
 }
 
-bool UnixFilesystem::GetFileSize(const Pathname& pathname, size_t *size) {
+bool UnixFilesystem::GetFileSize(const Pathname& pathname, size_t* size) {
   struct stat st;
   if (::stat(pathname.pathname().c_str(), &st) != 0)
     return false;
diff --git a/rtc_base/virtualsocket_unittest.cc b/rtc_base/virtualsocket_unittest.cc
index a6a4ee1..d2bff54 100644
--- a/rtc_base/virtualsocket_unittest.cc
+++ b/rtc_base/virtualsocket_unittest.cc
@@ -16,11 +16,11 @@
 
 #include <memory>
 
+#include "absl/memory/memory.h"
 #include "rtc_base/arraysize.h"
 #include "rtc_base/fakeclock.h"
 #include "rtc_base/gunit.h"
 #include "rtc_base/logging.h"
-#include "rtc_base/ptr_util.h"
 #include "rtc_base/testclient.h"
 #include "rtc_base/testutils.h"
 #include "rtc_base/thread.h"
@@ -40,7 +40,7 @@
 struct Sender : public MessageHandler {
   Sender(Thread* th, AsyncSocket* s, uint32_t rt)
       : thread(th),
-        socket(MakeUnique<AsyncUDPSocket>(s)),
+        socket(absl::make_unique<AsyncUDPSocket>(s)),
         done(false),
         rate(rt),
         count(0) {
@@ -86,7 +86,7 @@
 struct Receiver : public MessageHandler, public sigslot::has_slots<> {
   Receiver(Thread* th, AsyncSocket* s, uint32_t bw)
       : thread(th),
-        socket(MakeUnique<AsyncUDPSocket>(s)),
+        socket(absl::make_unique<AsyncUDPSocket>(s)),
         bandwidth(bw),
         done(false),
         count(0),
@@ -100,7 +100,9 @@
 
   ~Receiver() override { thread->Clear(this); }
 
-  void OnReadPacket(AsyncPacketSocket* s, const char* data, size_t size,
+  void OnReadPacket(AsyncPacketSocket* s,
+                    const char* data,
+                    size_t size,
                     const SocketAddress& remote_addr,
                     const PacketTime& packet_time) {
     ASSERT_EQ(socket.get(), s);
@@ -182,8 +184,8 @@
     socket->Bind(EmptySocketAddressWithFamily(default_route.family()));
     SocketAddress client1_any_addr = socket->GetLocalAddress();
     EXPECT_TRUE(client1_any_addr.IsAnyIP());
-    auto client1 = MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket),
-                                          &fake_clock_);
+    auto client1 = absl::make_unique<TestClient>(
+        absl::make_unique<AsyncUDPSocket>(socket), &fake_clock_);
 
     // Create client2 bound to the default route.
     AsyncSocket* socket2 =
@@ -191,8 +193,8 @@
     socket2->Bind(SocketAddress(default_route, 0));
     SocketAddress client2_addr = socket2->GetLocalAddress();
     EXPECT_FALSE(client2_addr.IsAnyIP());
-    auto client2 = MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket2),
-                                          &fake_clock_);
+    auto client2 = absl::make_unique<TestClient>(
+        absl::make_unique<AsyncUDPSocket>(socket2), &fake_clock_);
 
     // Client1 sends to client2, client2 should see the default route as
     // client1's address.
@@ -215,12 +217,12 @@
     // Make sure VSS didn't switch families on us.
     EXPECT_EQ(server_addr.family(), initial_addr.family());
 
-    auto client1 = MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket),
-                                          &fake_clock_);
+    auto client1 = absl::make_unique<TestClient>(
+        absl::make_unique<AsyncUDPSocket>(socket), &fake_clock_);
     AsyncSocket* socket2 =
         ss_.CreateAsyncSocket(initial_addr.family(), SOCK_DGRAM);
-    auto client2 = MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket2),
-                                          &fake_clock_);
+    auto client2 = absl::make_unique<TestClient>(
+        absl::make_unique<AsyncUDPSocket>(socket2), &fake_clock_);
 
     SocketAddress client2_addr;
     EXPECT_EQ(3, client2->SendTo("foo", 3, server_addr));
@@ -233,8 +235,8 @@
 
     SocketAddress empty = EmptySocketAddressWithFamily(initial_addr.family());
     for (int i = 0; i < 10; i++) {
-      client2 = MakeUnique<TestClient>(
-          WrapUnique(AsyncUDPSocket::Create(&ss_, empty)), &fake_clock_);
+      client2 = absl::make_unique<TestClient>(
+          absl::WrapUnique(AsyncUDPSocket::Create(&ss_, empty)), &fake_clock_);
 
       SocketAddress next_client2_addr;
       EXPECT_EQ(3, client2->SendTo("foo", 3, server_addr));
@@ -259,15 +261,15 @@
         EmptySocketAddressWithFamily(initial_addr.family());
 
     // Create client
-    std::unique_ptr<AsyncSocket> client =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> client = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(client.get());
     EXPECT_EQ(client->GetState(), AsyncSocket::CS_CLOSED);
     EXPECT_TRUE(client->GetLocalAddress().IsNil());
 
     // Create server
-    std::unique_ptr<AsyncSocket> server =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> server = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(server.get());
     EXPECT_NE(0, server->Listen(5));  // Bind required
     EXPECT_EQ(0, server->Bind(initial_addr));
@@ -282,7 +284,7 @@
 
     // Attempt connect to listening socket
     EXPECT_EQ(0, client->Connect(server->GetLocalAddress()));
-    EXPECT_NE(client->GetLocalAddress(), kEmptyAddr);  // Implicit Bind
+    EXPECT_NE(client->GetLocalAddress(), kEmptyAddr);          // Implicit Bind
     EXPECT_NE(AF_UNSPEC, client->GetLocalAddress().family());  // Implicit Bind
     EXPECT_NE(client->GetLocalAddress(), server->GetLocalAddress());
 
@@ -300,7 +302,8 @@
 
     // Server has pending connection
     EXPECT_TRUE(sink.Check(server.get(), SSE_READ));
-    std::unique_ptr<Socket> accepted = WrapUnique(server->Accept(&accept_addr));
+    std::unique_ptr<Socket> accepted =
+        absl::WrapUnique(server->Accept(&accept_addr));
     EXPECT_TRUE(nullptr != accepted);
     EXPECT_NE(accept_addr, kEmptyAddr);
     EXPECT_EQ(accepted->GetRemoteAddress(), accept_addr);
@@ -327,13 +330,13 @@
         EmptySocketAddressWithFamily(initial_addr.family());
 
     // Create client
-    std::unique_ptr<AsyncSocket> client =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> client = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(client.get());
 
     // Create server
-    std::unique_ptr<AsyncSocket> server =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> server = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(server.get());
     EXPECT_EQ(0, server->Bind(initial_addr));
     EXPECT_EQ(server->GetLocalAddress().family(), initial_addr.family());
@@ -446,14 +449,14 @@
     const SocketAddress kEmptyAddr;
 
     // Create clients
-    std::unique_ptr<AsyncSocket> a =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> a = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(a.get());
     a->Bind(initial_addr);
     EXPECT_EQ(a->GetLocalAddress().family(), initial_addr.family());
 
-    std::unique_ptr<AsyncSocket> b =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> b = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(b.get());
     b->Bind(initial_addr);
     EXPECT_EQ(b->GetLocalAddress().family(), initial_addr.family());
@@ -496,14 +499,14 @@
     const SocketAddress kEmptyAddr;
 
     // Connect two sockets
-    std::unique_ptr<AsyncSocket> a =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> a = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(a.get());
     a->Bind(initial_addr);
     EXPECT_EQ(a->GetLocalAddress().family(), initial_addr.family());
 
-    std::unique_ptr<AsyncSocket> b =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> b = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     sink.Monitor(b.get());
     b->Bind(initial_addr);
     EXPECT_EQ(b->GetLocalAddress().family(), initial_addr.family());
@@ -618,10 +621,10 @@
     const SocketAddress kEmptyAddr;
 
     // Connect two sockets
-    std::unique_ptr<AsyncSocket> a =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
-    std::unique_ptr<AsyncSocket> b =
-        WrapUnique(ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> a = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> b = absl::WrapUnique(
+        ss_.CreateAsyncSocket(initial_addr.family(), SOCK_STREAM));
     a->Bind(initial_addr);
     EXPECT_EQ(a->GetLocalAddress().family(), initial_addr.family());
 
@@ -633,7 +636,7 @@
     ss_.ProcessMessagesUntilIdle();
 
     // First, deliver all packets in 0 ms.
-    char buffer[2] = { 0, 0 };
+    char buffer[2] = {0, 0};
     const char cNumPackets = 10;
     for (char i = 0; i < cNumPackets; ++i) {
       buffer[0] = '0' + i;
@@ -769,8 +772,8 @@
     const SocketAddress kEmptyAddr;
 
     // Client gets a IPv4 address
-    std::unique_ptr<AsyncSocket> client =
-        WrapUnique(ss_.CreateAsyncSocket(client_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> client = absl::WrapUnique(
+        ss_.CreateAsyncSocket(client_addr.family(), SOCK_STREAM));
     sink.Monitor(client.get());
     EXPECT_EQ(client->GetState(), AsyncSocket::CS_CLOSED);
     EXPECT_EQ(client->GetLocalAddress(), kEmptyAddr);
@@ -778,8 +781,8 @@
 
     // Server gets a non-mapped non-any IPv6 address.
     // IPv4 sockets should not be able to connect to this.
-    std::unique_ptr<AsyncSocket> server =
-        WrapUnique(ss_.CreateAsyncSocket(server_addr.family(), SOCK_STREAM));
+    std::unique_ptr<AsyncSocket> server = absl::WrapUnique(
+        ss_.CreateAsyncSocket(server_addr.family(), SOCK_STREAM));
     sink.Monitor(server.get());
     server->Bind(server_addr);
     server->Listen(5);
@@ -789,7 +792,7 @@
       ss_.ProcessMessagesUntilIdle();
       EXPECT_TRUE(sink.Check(server.get(), SSE_READ));
       std::unique_ptr<Socket> accepted =
-          WrapUnique(server->Accept(&accept_address));
+          absl::WrapUnique(server->Accept(&accept_address));
       EXPECT_TRUE(nullptr != accepted);
       EXPECT_NE(kEmptyAddr, accept_address);
       ss_.ProcessMessagesUntilIdle();
@@ -815,16 +818,16 @@
   void CrossFamilyDatagramTest(const SocketAddress& client_addr,
                                const SocketAddress& server_addr,
                                bool shouldSucceed) {
-    AsyncSocket* socket = ss_.CreateAsyncSocket(SOCK_DGRAM);
+    AsyncSocket* socket = ss_.CreateAsyncSocket(AF_INET, SOCK_DGRAM);
     socket->Bind(server_addr);
     SocketAddress bound_server_addr = socket->GetLocalAddress();
-    auto client1 = MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket),
-                                          &fake_clock_);
+    auto client1 = absl::make_unique<TestClient>(
+        absl::make_unique<AsyncUDPSocket>(socket), &fake_clock_);
 
-    AsyncSocket* socket2 = ss_.CreateAsyncSocket(SOCK_DGRAM);
+    AsyncSocket* socket2 = ss_.CreateAsyncSocket(AF_INET, SOCK_DGRAM);
     socket2->Bind(client_addr);
-    auto client2 = MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket2),
-                                          &fake_clock_);
+    auto client2 = absl::make_unique<TestClient>(
+        absl::make_unique<AsyncUDPSocket>(socket2), &fake_clock_);
     SocketAddress client2_addr;
 
     if (shouldSucceed) {
@@ -937,116 +940,100 @@
 // Works, receiving socket sees 127.0.0.2.
 TEST_F(VirtualSocketServerTest, CanConnectFromMappedIPv6ToIPv4Any) {
   CrossFamilyConnectionTest(SocketAddress("::ffff:127.0.0.2", 0),
-                            SocketAddress("0.0.0.0", 5000),
-                            true);
+                            SocketAddress("0.0.0.0", 5000), true);
 }
 
 // Fails.
 TEST_F(VirtualSocketServerTest, CantConnectFromUnMappedIPv6ToIPv4Any) {
   CrossFamilyConnectionTest(SocketAddress("::2", 0),
-                            SocketAddress("0.0.0.0", 5000),
-                            false);
+                            SocketAddress("0.0.0.0", 5000), false);
 }
 
 // Fails.
 TEST_F(VirtualSocketServerTest, CantConnectFromUnMappedIPv6ToMappedIPv6) {
   CrossFamilyConnectionTest(SocketAddress("::2", 0),
-                            SocketAddress("::ffff:127.0.0.1", 5000),
-                            false);
+                            SocketAddress("::ffff:127.0.0.1", 5000), false);
 }
 
 // Works. receiving socket sees ::ffff:127.0.0.2.
 TEST_F(VirtualSocketServerTest, CanConnectFromIPv4ToIPv6Any) {
   CrossFamilyConnectionTest(SocketAddress("127.0.0.2", 0),
-                            SocketAddress("::", 5000),
-                            true);
+                            SocketAddress("::", 5000), true);
 }
 
 // Fails.
 TEST_F(VirtualSocketServerTest, CantConnectFromIPv4ToUnMappedIPv6) {
   CrossFamilyConnectionTest(SocketAddress("127.0.0.2", 0),
-                            SocketAddress("::1", 5000),
-                            false);
+                            SocketAddress("::1", 5000), false);
 }
 
 // Works. Receiving socket sees ::ffff:127.0.0.1.
 TEST_F(VirtualSocketServerTest, CanConnectFromIPv4ToMappedIPv6) {
   CrossFamilyConnectionTest(SocketAddress("127.0.0.1", 0),
-                            SocketAddress("::ffff:127.0.0.2", 5000),
-                            true);
+                            SocketAddress("::ffff:127.0.0.2", 5000), true);
 }
 
 // Works, receiving socket sees a result from GetNextIP.
 TEST_F(VirtualSocketServerTest, CanConnectFromUnboundIPv6ToIPv4Any) {
   CrossFamilyConnectionTest(SocketAddress("::", 0),
-                            SocketAddress("0.0.0.0", 5000),
-                            true);
+                            SocketAddress("0.0.0.0", 5000), true);
 }
 
 // Works, receiving socket sees whatever GetNextIP gave the client.
 TEST_F(VirtualSocketServerTest, CanConnectFromUnboundIPv4ToIPv6Any) {
   CrossFamilyConnectionTest(SocketAddress("0.0.0.0", 0),
-                            SocketAddress("::", 5000),
-                            true);
+                            SocketAddress("::", 5000), true);
 }
 
 TEST_F(VirtualSocketServerTest, CanSendDatagramFromUnboundIPv4ToIPv6Any) {
   CrossFamilyDatagramTest(SocketAddress("0.0.0.0", 0),
-                          SocketAddress("::", 5000),
-                          true);
+                          SocketAddress("::", 5000), true);
 }
 
 TEST_F(VirtualSocketServerTest, CanSendDatagramFromMappedIPv6ToIPv4Any) {
   CrossFamilyDatagramTest(SocketAddress("::ffff:127.0.0.1", 0),
-                          SocketAddress("0.0.0.0", 5000),
-                          true);
+                          SocketAddress("0.0.0.0", 5000), true);
 }
 
 TEST_F(VirtualSocketServerTest, CantSendDatagramFromUnMappedIPv6ToIPv4Any) {
   CrossFamilyDatagramTest(SocketAddress("::2", 0),
-                          SocketAddress("0.0.0.0", 5000),
-                          false);
+                          SocketAddress("0.0.0.0", 5000), false);
 }
 
 TEST_F(VirtualSocketServerTest, CantSendDatagramFromUnMappedIPv6ToMappedIPv6) {
   CrossFamilyDatagramTest(SocketAddress("::2", 0),
-                          SocketAddress("::ffff:127.0.0.1", 5000),
-                          false);
+                          SocketAddress("::ffff:127.0.0.1", 5000), false);
 }
 
 TEST_F(VirtualSocketServerTest, CanSendDatagramFromIPv4ToIPv6Any) {
   CrossFamilyDatagramTest(SocketAddress("127.0.0.2", 0),
-                          SocketAddress("::", 5000),
-                          true);
+                          SocketAddress("::", 5000), true);
 }
 
 TEST_F(VirtualSocketServerTest, CantSendDatagramFromIPv4ToUnMappedIPv6) {
   CrossFamilyDatagramTest(SocketAddress("127.0.0.2", 0),
-                          SocketAddress("::1", 5000),
-                          false);
+                          SocketAddress("::1", 5000), false);
 }
 
 TEST_F(VirtualSocketServerTest, CanSendDatagramFromIPv4ToMappedIPv6) {
   CrossFamilyDatagramTest(SocketAddress("127.0.0.1", 0),
-                          SocketAddress("::ffff:127.0.0.2", 5000),
-                          true);
+                          SocketAddress("::ffff:127.0.0.2", 5000), true);
 }
 
 TEST_F(VirtualSocketServerTest, CanSendDatagramFromUnboundIPv6ToIPv4Any) {
   CrossFamilyDatagramTest(SocketAddress("::", 0),
-                          SocketAddress("0.0.0.0", 5000),
-                          true);
+                          SocketAddress("0.0.0.0", 5000), true);
 }
 
 TEST_F(VirtualSocketServerTest, SetSendingBlockedWithUdpSocket) {
   AsyncSocket* socket1 =
       ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_DGRAM);
-  std::unique_ptr<AsyncSocket> socket2 =
-      WrapUnique(ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_DGRAM));
+  std::unique_ptr<AsyncSocket> socket2 = absl::WrapUnique(
+      ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_DGRAM));
   socket1->Bind(kIPv4AnyAddress);
   socket2->Bind(kIPv4AnyAddress);
-  auto client1 =
-      MakeUnique<TestClient>(MakeUnique<AsyncUDPSocket>(socket1), &fake_clock_);
+  auto client1 = absl::make_unique<TestClient>(
+      absl::make_unique<AsyncUDPSocket>(socket1), &fake_clock_);
 
   ss_.SetSendingBlocked(true);
   EXPECT_EQ(-1, client1->SendTo("foo", 3, socket2->GetLocalAddress()));
@@ -1064,10 +1051,10 @@
   ss_.set_recv_buffer_capacity(kBufferSize);
 
   StreamSink sink;
-  std::unique_ptr<AsyncSocket> socket1 =
-      WrapUnique(ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_STREAM));
-  std::unique_ptr<AsyncSocket> socket2 =
-      WrapUnique(ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_STREAM));
+  std::unique_ptr<AsyncSocket> socket1 = absl::WrapUnique(
+      ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_STREAM));
+  std::unique_ptr<AsyncSocket> socket2 = absl::WrapUnique(
+      ss_.CreateAsyncSocket(kIPv4AnyAddress.family(), SOCK_STREAM));
   sink.Monitor(socket1.get());
   sink.Monitor(socket2.get());
   socket1->Bind(kIPv4AnyAddress);
@@ -1104,7 +1091,7 @@
 
 TEST_F(VirtualSocketServerTest, CreatesStandardDistribution) {
   const uint32_t kTestMean[] = {10, 100, 333, 1000};
-  const double kTestDev[] = { 0.25, 0.1, 0.01 };
+  const double kTestDev[] = {0.25, 0.1, 0.01};
   // TODO(deadbeef): The current code only works for 1000 data points or more.
   const uint32_t kTestSamples[] = {/*10, 100,*/ 1000};
   for (size_t midx = 0; midx < arraysize(kTestMean); ++midx) {
@@ -1114,8 +1101,7 @@
         const uint32_t kStdDev =
             static_cast<uint32_t>(kTestDev[didx] * kTestMean[midx]);
         VirtualSocketServer::Function* f =
-            VirtualSocketServer::CreateDistribution(kTestMean[midx],
-                                                    kStdDev,
+            VirtualSocketServer::CreateDistribution(kTestMean[midx], kStdDev,
                                                     kTestSamples[sidx]);
         ASSERT_TRUE(nullptr != f);
         ASSERT_EQ(kTestSamples[sidx], f->size());
@@ -1131,13 +1117,11 @@
         }
         const double stddev = sqrt(sum_sq_dev / f->size());
         EXPECT_NEAR(kTestMean[midx], mean, 0.1 * kTestMean[midx])
-          << "M=" << kTestMean[midx]
-          << " SD=" << kStdDev
-          << " N=" << kTestSamples[sidx];
+            << "M=" << kTestMean[midx] << " SD=" << kStdDev
+            << " N=" << kTestSamples[sidx];
         EXPECT_NEAR(kStdDev, stddev, 0.1 * kStdDev)
-          << "M=" << kTestMean[midx]
-          << " SD=" << kStdDev
-          << " N=" << kTestSamples[sidx];
+            << "M=" << kTestMean[midx] << " SD=" << kStdDev
+            << " N=" << kTestSamples[sidx];
         delete f;
       }
     }
diff --git a/rtc_base/virtualsocketserver.cc b/rtc_base/virtualsocketserver.cc
index fab5900..53dad46 100644
--- a/rtc_base/virtualsocketserver.cc
+++ b/rtc_base/virtualsocketserver.cc
@@ -28,15 +28,14 @@
 
 namespace rtc {
 #if defined(WEBRTC_WIN)
-const in_addr kInitialNextIPv4 = { { { 0x01, 0, 0, 0 } } };
+const in_addr kInitialNextIPv4 = {{{0x01, 0, 0, 0}}};
 #else
 // This value is entirely arbitrary, hence the lack of concern about endianness.
-const in_addr kInitialNextIPv4 = { 0x01000000 };
+const in_addr kInitialNextIPv4 = {0x01000000};
 #endif
 // Starts at ::2 so as to not cause confusion with ::1.
-const in6_addr kInitialNextIPv6 = { { {
-      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
-    } } };
+const in6_addr kInitialNextIPv6 = {
+    {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}}};
 
 const uint16_t kFirstEphemeralPort = 49152;
 const uint16_t kLastEphemeralPort = 65535;
@@ -65,15 +64,13 @@
 class Packet : public MessageData {
  public:
   Packet(const char* data, size_t size, const SocketAddress& from)
-        : size_(size), consumed_(0), from_(from) {
+      : size_(size), consumed_(0), from_(from) {
     RTC_DCHECK(nullptr != data);
     data_ = new char[size_];
     memcpy(data_, data, size_);
   }
 
-  ~Packet() override {
-    delete[] data_;
-  }
+  ~Packet() override { delete[] data_; }
 
   const char* data() const { return data_ + consumed_; }
   size_t size() const { return size_ - consumed_; }
@@ -92,7 +89,7 @@
 };
 
 struct MessageAddress : public MessageData {
-  explicit MessageAddress(const SocketAddress& a) : addr(a) { }
+  explicit MessageAddress(const SocketAddress& a) : addr(a) {}
   SocketAddress addr;
 };
 
@@ -236,15 +233,15 @@
 }
 
 int VirtualSocket::Send(const void* pv, size_t cb) {
-    if (CS_CONNECTED != state_) {
-      error_ = ENOTCONN;
-      return -1;
-    }
-    if (SOCK_DGRAM == type_) {
-      return SendUdp(pv, cb, remote_addr_);
-    } else {
-      return SendTcp(pv, cb);
-    }
+  if (CS_CONNECTED != state_) {
+    error_ = ENOTCONN;
+    return -1;
+  }
+  if (SOCK_DGRAM == type_) {
+    return SendUdp(pv, cb, remote_addr_);
+  } else {
+    return SendTcp(pv, cb);
+  }
 }
 
 int VirtualSocket::SendTo(const void* pv,
@@ -555,8 +552,7 @@
 IPAddress VirtualSocketServer::GetNextIP(int family) {
   if (family == AF_INET) {
     IPAddress next_ip(next_ipv4_);
-    next_ipv4_.s_addr =
-        HostToNetwork32(NetworkToHost32(next_ipv4_.s_addr) + 1);
+    next_ipv4_.s_addr = HostToNetwork32(NetworkToHost32(next_ipv4_.s_addr) + 1);
     return next_ip;
   } else if (family == AF_INET6) {
     IPAddress next_ip(next_ipv6_);
@@ -590,18 +586,10 @@
   }
 }
 
-Socket* VirtualSocketServer::CreateSocket(int type) {
-  return CreateSocket(AF_INET, type);
-}
-
 Socket* VirtualSocketServer::CreateSocket(int family, int type) {
   return CreateSocketInternal(family, type);
 }
 
-AsyncSocket* VirtualSocketServer::CreateAsyncSocket(int type) {
-  return CreateAsyncSocket(AF_INET, type);
-}
-
 AsyncSocket* VirtualSocketServer::CreateAsyncSocket(int family, int type) {
   return CreateSocketInternal(family, type);
 }
@@ -615,8 +603,8 @@
 void VirtualSocketServer::SetMessageQueue(MessageQueue* msg_queue) {
   msg_queue_ = msg_queue;
   if (msg_queue_) {
-    msg_queue_->SignalQueueDestroyed.connect(this,
-        &VirtualSocketServer::OnMessageQueueDestroyed);
+    msg_queue_->SignalQueueDestroyed.connect(
+        this, &VirtualSocketServer::OnMessageQueueDestroyed);
   }
 }
 
@@ -650,7 +638,7 @@
     if (fake_clock_) {
       // If using a fake clock, advance it in millisecond increments until the
       // queue is empty.
-      fake_clock_->AdvanceTime(rtc::TimeDelta::FromMilliseconds(1));
+      fake_clock_->AdvanceTime(webrtc::TimeDelta::ms(1));
     } else {
       // Otherwise, run a normal message loop.
       Message msg;
@@ -729,8 +717,7 @@
 }
 
 VirtualSocket* VirtualSocketServer::LookupBinding(const SocketAddress& addr) {
-  SocketAddress normalized(addr.ipaddr().Normalized(),
-                           addr.port());
+  SocketAddress normalized(addr.ipaddr().Normalized(), addr.port());
   AddressMap::iterator it = bindings_->find(normalized);
   if (it != bindings_->end()) {
     return it->second;
@@ -752,8 +739,7 @@
 
 int VirtualSocketServer::Unbind(const SocketAddress& addr,
                                 VirtualSocket* socket) {
-  SocketAddress normalized(addr.ipaddr().Normalized(),
-                           addr.port());
+  SocketAddress normalized(addr.ipaddr().Normalized(), addr.port());
   RTC_DCHECK((*bindings_)[normalized] == socket);
   bindings_->erase(bindings_->find(normalized));
   return 0;
@@ -764,22 +750,18 @@
                                         VirtualSocket* remote_socket) {
   // Add this socket pair to our routing table. This will allow
   // multiple clients to connect to the same server address.
-  SocketAddress local_normalized(local.ipaddr().Normalized(),
-                                 local.port());
-  SocketAddress remote_normalized(remote.ipaddr().Normalized(),
-                                  remote.port());
+  SocketAddress local_normalized(local.ipaddr().Normalized(), local.port());
+  SocketAddress remote_normalized(remote.ipaddr().Normalized(), remote.port());
   SocketAddressPair address_pair(local_normalized, remote_normalized);
-  connections_->insert(std::pair<SocketAddressPair,
-                       VirtualSocket*>(address_pair, remote_socket));
+  connections_->insert(std::pair<SocketAddressPair, VirtualSocket*>(
+      address_pair, remote_socket));
 }
 
 VirtualSocket* VirtualSocketServer::LookupConnection(
     const SocketAddress& local,
     const SocketAddress& remote) {
-  SocketAddress local_normalized(local.ipaddr().Normalized(),
-                                 local.port());
-  SocketAddress remote_normalized(remote.ipaddr().Normalized(),
-                                  remote.port());
+  SocketAddress local_normalized(local.ipaddr().Normalized(), local.port());
+  SocketAddress remote_normalized(remote.ipaddr().Normalized(), remote.port());
   SocketAddressPair address_pair(local_normalized, remote_normalized);
   ConnectionMap::iterator it = connections_->find(address_pair);
   return (connections_->end() != it) ? it->second : nullptr;
@@ -787,10 +769,8 @@
 
 void VirtualSocketServer::RemoveConnection(const SocketAddress& local,
                                            const SocketAddress& remote) {
-  SocketAddress local_normalized(local.ipaddr().Normalized(),
-                                local.port());
-  SocketAddress remote_normalized(remote.ipaddr().Normalized(),
-                                 remote.port());
+  SocketAddress local_normalized(local.ipaddr().Normalized(), local.port());
+  SocketAddress remote_normalized(remote.ipaddr().Normalized(), remote.port());
   SocketAddressPair address_pair(local_normalized, remote_normalized);
   connections_->erase(address_pair);
 }
@@ -834,7 +814,8 @@
 }
 
 int VirtualSocketServer::SendUdp(VirtualSocket* socket,
-                                 const char* data, size_t data_size,
+                                 const char* data,
+                                 size_t data_size,
                                  const SocketAddress& remote_addr) {
   ++sent_packets_;
   if (sending_blocked_) {
@@ -915,8 +896,8 @@
   // is read from the recv_buffer.
 
   // Lookup the local/remote pair in the connections table.
-  VirtualSocket* recipient = LookupConnection(socket->local_addr_,
-                                              socket->remote_addr_);
+  VirtualSocket* recipient =
+      LookupConnection(socket->local_addr_, socket->remote_addr_);
   if (!recipient) {
     RTC_LOG(LS_VERBOSE) << "Sending data to no one.";
     return;
@@ -1037,8 +1018,8 @@
 #endif  // <unused>
 
 void VirtualSocketServer::UpdateDelayDistribution() {
-  Function* dist = CreateDistribution(delay_mean_, delay_stddev_,
-                                      delay_samples_);
+  Function* dist =
+      CreateDistribution(delay_mean_, delay_stddev_, delay_samples_);
   // We take a lock just to make sure we don't leak memory.
   {
     CritScope cs(&delay_crit_);
@@ -1100,7 +1081,7 @@
 
 struct FunctionDomainCmp {
   bool operator()(const VirtualSocketServer::Point& p1,
-                   const VirtualSocketServer::Point& p2) {
+                  const VirtualSocketServer::Point& p2) {
     return p1.first < p2.first;
   }
   bool operator()(double v1, const VirtualSocketServer::Point& p2) {
@@ -1120,7 +1101,7 @@
     (*f)[i].second = v;
     v = v + dx * avgy;
   }
-  (*f)[f->size()-1].second = v;
+  (*f)[f->size() - 1].second = v;
   return f;
 }
 
diff --git a/rtc_base/virtualsocketserver.h b/rtc_base/virtualsocketserver.h
index e17caae..4fa7d77 100644
--- a/rtc_base/virtualsocketserver.h
+++ b/rtc_base/virtualsocketserver.h
@@ -103,10 +103,7 @@
   void SetSendingBlocked(bool blocked);
 
   // SocketFactory:
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
   // SocketServer:
@@ -186,14 +183,17 @@
                         const SocketAddress& server);
 
   // Connects the given socket to the socket at the given address
-  int Connect(VirtualSocket* socket, const SocketAddress& remote_addr,
+  int Connect(VirtualSocket* socket,
+              const SocketAddress& remote_addr,
               bool use_delay);
 
   // Sends a disconnect message to the socket at the given address
   bool Disconnect(VirtualSocket* socket);
 
   // Sends the given packet to the socket at the given address (if one exists).
-  int SendUdp(VirtualSocket* socket, const char* data, size_t data_size,
+  int SendUdp(VirtualSocket* socket,
+              const char* data,
+              size_t data_size,
               const SocketAddress& remote_addr);
 
   // Moves as much data as possible from the sender's buffer to the network
diff --git a/rtc_base/weak_ptr.cc b/rtc_base/weak_ptr.cc
index c76256a..ad98c24 100644
--- a/rtc_base/weak_ptr.cc
+++ b/rtc_base/weak_ptr.cc
@@ -51,8 +51,7 @@
   return flag_.get() && flag_->IsValid();
 }
 
-WeakReferenceOwner::WeakReferenceOwner() {
-}
+WeakReferenceOwner::WeakReferenceOwner() {}
 
 WeakReferenceOwner::~WeakReferenceOwner() {
   Invalidate();
diff --git a/rtc_base/weak_ptr_unittest.cc b/rtc_base/weak_ptr_unittest.cc
index 6b0b452..9541718 100644
--- a/rtc_base/weak_ptr_unittest.cc
+++ b/rtc_base/weak_ptr_unittest.cc
@@ -225,7 +225,7 @@
   // Test that it is OK to create a WeakPtr on one thread, but use it on
   // another. This tests that we do not trip runtime checks that ensure that a
   // WeakPtr is not used by multiple threads.
-  auto target = rtc::MakeUnique<TargetWithFactory>();
+  auto target = absl::make_unique<TargetWithFactory>();
   // Create weak ptr on main thread
   WeakPtr<Target> weak_ptr = target->factory.GetWeakPtr();
   rtc::TaskQueue queue("queue");
diff --git a/rtc_base/win/windows_version.cc b/rtc_base/win/windows_version.cc
new file mode 100644
index 0000000..9ccde4c
--- /dev/null
+++ b/rtc_base/win/windows_version.cc
@@ -0,0 +1,397 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "rtc_base/win/windows_version.h"
+
+#include <windows.h>
+#include <memory>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/stringutils.h"
+
+#if !defined(__clang__) && _MSC_FULL_VER < 191125507
+#error VS 2017 Update 3.2 or higher is required
+#endif
+
+#if !defined(NTDDI_WIN10_RS2)
+// Windows 10 Creators Update SDK is required to build Chrome. It is important
+// to install the 10.0.15063.468 version, released June 2017, because earlier
+// versions had bugs and could not build Chrome. See this link for details:
+// https://developercommunity.visualstudio.com/content/problem/42961/15063-sdk-is-broken-bitsh-indirectly-references-no.html
+#error Creators Update SDK (10.0.15063.468) required.
+#endif
+
+namespace {
+
+typedef BOOL(WINAPI* GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD);
+
+// Mask to pull WOW64 access flags out of REGSAM access.
+const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
+
+// Utility class to read, write and manipulate the Windows Registry.
+// Registry vocabulary primer: a "key" is like a folder, in which there
+// are "values", which are <name, data> pairs, with an associated data type.
+// Based on base::win::RegKey but only implements a small fraction of it.
+class RegKey {
+ public:
+  RegKey() : key_(nullptr), wow64access_(0) {}
+
+  RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
+      : key_(nullptr), wow64access_(0) {
+    if (rootkey) {
+      if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
+        Create(rootkey, subkey, access);
+      else
+        Open(rootkey, subkey, access);
+    } else {
+      RTC_DCHECK(!subkey);
+      wow64access_ = access & kWow64AccessMask;
+    }
+  }
+
+  ~RegKey() { Close(); }
+
+  LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+    DWORD disposition_value;
+    return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
+  }
+
+  LONG CreateWithDisposition(HKEY rootkey,
+                             const wchar_t* subkey,
+                             DWORD* disposition,
+                             REGSAM access) {
+    RTC_DCHECK(rootkey && subkey && access && disposition);
+    HKEY subhkey = NULL;
+    LONG result =
+        ::RegCreateKeyEx(rootkey, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
+                         access, NULL, &subhkey, disposition);
+    if (result == ERROR_SUCCESS) {
+      Close();
+      key_ = subhkey;
+      wow64access_ = access & kWow64AccessMask;
+    }
+
+    return result;
+  }
+
+  // Opens an existing reg key.
+  LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+    RTC_DCHECK(rootkey && subkey && access);
+    HKEY subhkey = NULL;
+
+    LONG result = ::RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
+    if (result == ERROR_SUCCESS) {
+      Close();
+      key_ = subhkey;
+      wow64access_ = access & kWow64AccessMask;
+    }
+
+    return result;
+  }
+
+  // Closes this reg key.
+  void Close() {
+    if (key_) {
+      ::RegCloseKey(key_);
+      key_ = nullptr;
+    }
+  }
+
+  // Reads a REG_DWORD (uint32_t) into |out_value|. If |name| is null or empty,
+  // reads the key's default value, if any.
+  LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const {
+    RTC_DCHECK(out_value);
+    DWORD type = REG_DWORD;
+    DWORD size = sizeof(DWORD);
+    DWORD local_value = 0;
+    LONG result = ReadValue(name, &local_value, &size, &type);
+    if (result == ERROR_SUCCESS) {
+      if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
+        *out_value = local_value;
+      else
+        result = ERROR_CANTREAD;
+    }
+
+    return result;
+  }
+
+  // Reads a string into |out_value|. If |name| is null or empty, reads
+  // the key's default value, if any.
+  LONG ReadValue(const wchar_t* name, std::wstring* out_value) const {
+    RTC_DCHECK(out_value);
+    const size_t kMaxStringLength = 1024;  // This is after expansion.
+    // Use the one of the other forms of ReadValue if 1024 is too small for you.
+    wchar_t raw_value[kMaxStringLength];
+    DWORD type = REG_SZ, size = sizeof(raw_value);
+    LONG result = ReadValue(name, raw_value, &size, &type);
+    if (result == ERROR_SUCCESS) {
+      if (type == REG_SZ) {
+        *out_value = raw_value;
+      } else if (type == REG_EXPAND_SZ) {
+        wchar_t expanded[kMaxStringLength];
+        size =
+            ::ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
+        // Success: returns the number of wchar_t's copied
+        // Fail: buffer too small, returns the size required
+        // Fail: other, returns 0
+        if (size == 0 || size > kMaxStringLength) {
+          result = ERROR_MORE_DATA;
+        } else {
+          *out_value = expanded;
+        }
+      } else {
+        // Not a string. Oops.
+        result = ERROR_CANTREAD;
+      }
+    }
+
+    return result;
+  }
+
+  LONG ReadValue(const wchar_t* name,
+                 void* data,
+                 DWORD* dsize,
+                 DWORD* dtype) const {
+    LONG result = RegQueryValueEx(key_, name, 0, dtype,
+                                  reinterpret_cast<LPBYTE>(data), dsize);
+    return result;
+  }
+
+ private:
+  HKEY key_;
+  REGSAM wow64access_;
+};
+
+}  // namespace
+
+namespace rtc {
+namespace rtc_win {
+namespace {
+
+// Helper to map a major.minor.x.build version (e.g. 6.1) to a Windows release.
+Version MajorMinorBuildToVersion(int major, int minor, int build) {
+  if ((major == 5) && (minor > 0)) {
+    // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
+    return (minor == 1) ? VERSION_XP : VERSION_SERVER_2003;
+  } else if (major == 6) {
+    switch (minor) {
+      case 0:
+        // Treat Windows Server 2008 the same as Windows Vista.
+        return VERSION_VISTA;
+      case 1:
+        // Treat Windows Server 2008 R2 the same as Windows 7.
+        return VERSION_WIN7;
+      case 2:
+        // Treat Windows Server 2012 the same as Windows 8.
+        return VERSION_WIN8;
+      default:
+        RTC_DCHECK_EQ(minor, 3);
+        return VERSION_WIN8_1;
+    }
+  } else if (major == 10) {
+    if (build < 10586) {
+      return VERSION_WIN10;
+    } else if (build < 14393) {
+      return VERSION_WIN10_TH2;
+    } else if (build < 15063) {
+      return VERSION_WIN10_RS1;
+    } else if (build < 16299) {
+      return VERSION_WIN10_RS2;
+    } else if (build < 17134) {
+      return VERSION_WIN10_RS3;
+    } else {
+      return VERSION_WIN10_RS4;
+    }
+  } else if (major > 6) {
+    RTC_NOTREACHED();
+    return VERSION_WIN_LAST;
+  }
+
+  return VERSION_PRE_XP;
+}
+
+// Returns the the "UBR" value from the registry. Introduced in Windows 10,
+// this undocumented value appears to be similar to a patch number.
+// Returns 0 if the value does not exist or it could not be read.
+int GetUBR() {
+  // The values under the CurrentVersion registry hive are mirrored under
+  // the corresponding Wow6432 hive.
+  static constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] =
+      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
+
+  RegKey key;
+  if (key.Open(HKEY_LOCAL_MACHINE, kRegKeyWindowsNTCurrentVersion,
+               KEY_QUERY_VALUE) != ERROR_SUCCESS) {
+    return 0;
+  }
+
+  DWORD ubr = 0;
+  key.ReadValueDW(L"UBR", &ubr);
+
+  return static_cast<int>(ubr);
+}
+
+}  // namespace
+
+// static
+OSInfo* OSInfo::GetInstance() {
+  // Note: we don't use the Singleton class because it depends on AtExitManager,
+  // and it's convenient for other modules to use this class without it. This
+  // pattern is copied from gurl.cc.
+  static OSInfo* info;
+  if (!info) {
+    OSInfo* new_info = new OSInfo();
+    if (InterlockedCompareExchangePointer(reinterpret_cast<PVOID*>(&info),
+                                          new_info, NULL)) {
+      delete new_info;
+    }
+  }
+  return info;
+}
+
+OSInfo::OSInfo()
+    : version_(VERSION_PRE_XP),
+      architecture_(OTHER_ARCHITECTURE),
+      wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
+  OSVERSIONINFOEX version_info = {sizeof version_info};
+  ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
+  version_number_.major = version_info.dwMajorVersion;
+  version_number_.minor = version_info.dwMinorVersion;
+  version_number_.build = version_info.dwBuildNumber;
+  version_number_.patch = GetUBR();
+  version_ = MajorMinorBuildToVersion(
+      version_number_.major, version_number_.minor, version_number_.build);
+  service_pack_.major = version_info.wServicePackMajor;
+  service_pack_.minor = version_info.wServicePackMinor;
+  service_pack_str_ = rtc::ToUtf8(version_info.szCSDVersion);
+
+  SYSTEM_INFO system_info = {};
+  ::GetNativeSystemInfo(&system_info);
+  switch (system_info.wProcessorArchitecture) {
+    case PROCESSOR_ARCHITECTURE_INTEL:
+      architecture_ = X86_ARCHITECTURE;
+      break;
+    case PROCESSOR_ARCHITECTURE_AMD64:
+      architecture_ = X64_ARCHITECTURE;
+      break;
+    case PROCESSOR_ARCHITECTURE_IA64:
+      architecture_ = IA64_ARCHITECTURE;
+      break;
+  }
+  processors_ = system_info.dwNumberOfProcessors;
+  allocation_granularity_ = system_info.dwAllocationGranularity;
+
+  GetProductInfoPtr get_product_info;
+  DWORD os_type;
+
+  if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
+    // Only present on Vista+.
+    get_product_info = reinterpret_cast<GetProductInfoPtr>(
+        ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetProductInfo"));
+
+    get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion,
+                     0, 0, &os_type);
+    switch (os_type) {
+      case PRODUCT_CLUSTER_SERVER:
+      case PRODUCT_DATACENTER_SERVER:
+      case PRODUCT_DATACENTER_SERVER_CORE:
+      case PRODUCT_ENTERPRISE_SERVER:
+      case PRODUCT_ENTERPRISE_SERVER_CORE:
+      case PRODUCT_ENTERPRISE_SERVER_IA64:
+      case PRODUCT_SMALLBUSINESS_SERVER:
+      case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
+      case PRODUCT_STANDARD_SERVER:
+      case PRODUCT_STANDARD_SERVER_CORE:
+      case PRODUCT_WEB_SERVER:
+        version_type_ = SUITE_SERVER;
+        break;
+      case PRODUCT_PROFESSIONAL:
+      case PRODUCT_ULTIMATE:
+        version_type_ = SUITE_PROFESSIONAL;
+        break;
+      case PRODUCT_ENTERPRISE:
+      case PRODUCT_ENTERPRISE_E:
+      case PRODUCT_ENTERPRISE_EVALUATION:
+      case PRODUCT_ENTERPRISE_N:
+      case PRODUCT_ENTERPRISE_N_EVALUATION:
+      case PRODUCT_ENTERPRISE_S:
+      case PRODUCT_ENTERPRISE_S_EVALUATION:
+      case PRODUCT_ENTERPRISE_S_N:
+      case PRODUCT_ENTERPRISE_S_N_EVALUATION:
+      case PRODUCT_BUSINESS:
+      case PRODUCT_BUSINESS_N:
+        version_type_ = SUITE_ENTERPRISE;
+        break;
+      case PRODUCT_EDUCATION:
+      case PRODUCT_EDUCATION_N:
+        version_type_ = SUITE_EDUCATION;
+        break;
+      case PRODUCT_HOME_BASIC:
+      case PRODUCT_HOME_PREMIUM:
+      case PRODUCT_STARTER:
+      default:
+        version_type_ = SUITE_HOME;
+        break;
+    }
+  } else if (version_info.dwMajorVersion == 5 &&
+             version_info.dwMinorVersion == 2) {
+    if (version_info.wProductType == VER_NT_WORKSTATION &&
+        system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+      version_type_ = SUITE_PROFESSIONAL;
+    } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER) {
+      version_type_ = SUITE_HOME;
+    } else {
+      version_type_ = SUITE_SERVER;
+    }
+  } else if (version_info.dwMajorVersion == 5 &&
+             version_info.dwMinorVersion == 1) {
+    if (version_info.wSuiteMask & VER_SUITE_PERSONAL)
+      version_type_ = SUITE_HOME;
+    else
+      version_type_ = SUITE_PROFESSIONAL;
+  } else {
+    // Windows is pre XP so we don't care but pick a safe default.
+    version_type_ = SUITE_HOME;
+  }
+}
+
+OSInfo::~OSInfo() {}
+
+std::string OSInfo::processor_model_name() {
+  if (processor_model_name_.empty()) {
+    const wchar_t kProcessorNameString[] =
+        L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
+    RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
+    std::wstring value;
+    key.ReadValue(L"ProcessorNameString", &value);
+    processor_model_name_ = rtc::ToUtf8(value);
+  }
+  return processor_model_name_;
+}
+
+// static
+OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
+  typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
+  IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
+  if (!is_wow64_process)
+    return WOW64_DISABLED;
+  BOOL is_wow64 = FALSE;
+  if (!(*is_wow64_process)(process_handle, &is_wow64))
+    return WOW64_UNKNOWN;
+  return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
+Version GetVersion() {
+  return OSInfo::GetInstance()->version();
+}
+
+}  // namespace rtc_win
+}  // namespace rtc
diff --git a/rtc_base/win/windows_version.h b/rtc_base/win/windows_version.h
new file mode 100644
index 0000000..39d333e
--- /dev/null
+++ b/rtc_base/win/windows_version.h
@@ -0,0 +1,149 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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 RTC_BASE_WIN_WINDOWS_VERSION_H_
+#define RTC_BASE_WIN_WINDOWS_VERSION_H_
+
+#include <stddef.h>
+#include <string>
+
+#include "rtc_base/constructormagic.h"
+
+typedef void* HANDLE;
+
+namespace rtc {
+namespace rtc_win {
+
+// The running version of Windows.  This is declared outside OSInfo for
+// syntactic sugar reasons; see the declaration of GetVersion() below.
+// NOTE: Keep these in order so callers can do things like
+// "if (rtc_win::GetVersion() >= rtc_win::VERSION_VISTA) ...".
+//
+// This enum is used in metrics histograms, so they shouldn't be reordered or
+// removed. New values can be added before VERSION_WIN_LAST.
+enum Version {
+  VERSION_PRE_XP = 0,  // Not supported.
+  VERSION_XP = 1,
+  VERSION_SERVER_2003 = 2,  // Also includes XP Pro x64 and Server 2003 R2.
+  VERSION_VISTA = 3,        // Also includes Windows Server 2008.
+  VERSION_WIN7 = 4,         // Also includes Windows Server 2008 R2.
+  VERSION_WIN8 = 5,         // Also includes Windows Server 2012.
+  VERSION_WIN8_1 = 6,       // Also includes Windows Server 2012 R2.
+  VERSION_WIN10 = 7,        // Threshold 1: Version 1507, Build 10240.
+  VERSION_WIN10_TH2 = 8,    // Threshold 2: Version 1511, Build 10586.
+  VERSION_WIN10_RS1 = 9,    // Redstone 1: Version 1607, Build 14393.
+  VERSION_WIN10_RS2 = 10,   // Redstone 2: Version 1703, Build 15063.
+  VERSION_WIN10_RS3 = 11,   // Redstone 3: Version 1709, Build 16299.
+  VERSION_WIN10_RS4 = 12,   // Redstone 4: Version 1803, Build 17134.
+  // On edit, update tools\metrics\histograms\enums.xml "WindowsVersion" and
+  // "GpuBlacklistFeatureTestResultsWindows2".
+  VERSION_WIN_LAST,  // Indicates error condition.
+};
+
+// A rough bucketing of the available types of versions of Windows. This is used
+// to distinguish enterprise enabled versions from home versions and potentially
+// server versions. Keep these values in the same order, since they are used as
+// is for metrics histogram ids.
+enum VersionType {
+  SUITE_HOME = 0,
+  SUITE_PROFESSIONAL,
+  SUITE_SERVER,
+  SUITE_ENTERPRISE,
+  SUITE_EDUCATION,
+  SUITE_LAST,
+};
+
+// A singleton that can be used to query various pieces of information about the
+// OS and process state. Note that this doesn't use the base Singleton class, so
+// it can be used without an AtExitManager.
+class OSInfo {
+ public:
+  struct VersionNumber {
+    int major;
+    int minor;
+    int build;
+    int patch;
+  };
+
+  struct ServicePack {
+    int major;
+    int minor;
+  };
+
+  // The processor architecture this copy of Windows natively uses.  For
+  // example, given an x64-capable processor, we have three possibilities:
+  //   32-bit Chrome running on 32-bit Windows:           X86_ARCHITECTURE
+  //   32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE
+  //   64-bit Chrome running on 64-bit Windows:           X64_ARCHITECTURE
+  enum WindowsArchitecture {
+    X86_ARCHITECTURE,
+    X64_ARCHITECTURE,
+    IA64_ARCHITECTURE,
+    OTHER_ARCHITECTURE,
+  };
+
+  // Whether a process is running under WOW64 (the wrapper that allows 32-bit
+  // processes to run on 64-bit versions of Windows).  This will return
+  // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
+  // Chrome on 64-bit Windows".  WOW64_UNKNOWN means "an error occurred", e.g.
+  // the process does not have sufficient access rights to determine this.
+  enum WOW64Status {
+    WOW64_DISABLED,
+    WOW64_ENABLED,
+    WOW64_UNKNOWN,
+  };
+
+  static OSInfo* GetInstance();
+
+  Version version() const { return version_; }
+  VersionNumber version_number() const { return version_number_; }
+  VersionType version_type() const { return version_type_; }
+  ServicePack service_pack() const { return service_pack_; }
+  std::string service_pack_str() const { return service_pack_str_; }
+  WindowsArchitecture architecture() const { return architecture_; }
+  int processors() const { return processors_; }
+  size_t allocation_granularity() const { return allocation_granularity_; }
+  WOW64Status wow64_status() const { return wow64_status_; }
+  std::string processor_model_name();
+
+  // Like wow64_status(), but for the supplied handle instead of the current
+  // process.  This doesn't touch member state, so you can bypass the singleton.
+  static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
+
+ private:
+  OSInfo();
+  ~OSInfo();
+
+  Version version_;
+  VersionNumber version_number_;
+  VersionType version_type_;
+  ServicePack service_pack_;
+
+  // A string, such as "Service Pack 3", that indicates the latest Service Pack
+  // installed on the system. If no Service Pack has been installed, the string
+  // is empty.
+  std::string service_pack_str_;
+  WindowsArchitecture architecture_;
+  int processors_;
+  size_t allocation_granularity_;
+  WOW64Status wow64_status_;
+  std::string processor_model_name_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(OSInfo);
+};
+
+// Because this is by far the most commonly-requested value from the above
+// singleton, we add a global-scope accessor here as syntactic sugar.
+Version GetVersion();
+
+}  // namespace rtc_win
+}  // namespace rtc
+
+#endif  // RTC_BASE_WIN_WINDOWS_VERSION_H_
diff --git a/rtc_base/win/windows_version_unittest.cc b/rtc_base/win/windows_version_unittest.cc
new file mode 100644
index 0000000..9e582e5
--- /dev/null
+++ b/rtc_base/win/windows_version_unittest.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2017 The WebRTC 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.
+ */
+
+#include "rtc_base/win/windows_version.h"
+
+#include "rtc_base/gunit.h"
+#include "rtc_base/logging.h"
+
+namespace rtc {
+namespace rtc_win {
+namespace {
+
+void MethodSupportedOnWin10AndLater() {
+  RTC_DLOG(INFO) << "MethodSupportedOnWin10AndLater";
+}
+
+void MethodNotSupportedOnWin10AndLater() {
+  RTC_DLOG(INFO) << "MethodNotSupportedOnWin10AndLater";
+}
+
+// Use global GetVersion() and use it in a way a user would typically use it
+// when checking for support of a certain API:
+// "if (rtc_win::GetVersion() < VERSION_WIN10) ...".
+TEST(WindowsVersion, GetVersionGlobalScopeAccessor) {
+  if (GetVersion() < VERSION_WIN10) {
+    MethodNotSupportedOnWin10AndLater();
+  } else {
+    MethodSupportedOnWin10AndLater();
+  }
+}
+
+TEST(WindowsVersion, ProcessorModelName) {
+  std::string name = OSInfo::GetInstance()->processor_model_name();
+  EXPECT_FALSE(name.empty());
+  RTC_DLOG(INFO) << "processor_model_name: " << name;
+}
+
+}  // namespace
+}  // namespace rtc_win
+}  // namespace rtc
diff --git a/rtc_base/win32.cc b/rtc_base/win32.cc
index cbf6fbb..d81d685 100644
--- a/rtc_base/win32.cc
+++ b/rtc_base/win32.cc
@@ -15,10 +15,10 @@
 #include <algorithm>
 
 #include "rtc_base/arraysize.h"
-#include "rtc_base/basictypes.h"
 #include "rtc_base/byteorder.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
+#include "rtc_base/stringutils.h"
 
 namespace rtc {
 
@@ -32,8 +32,10 @@
 // ip address). XP doesn't have its own inet_ntop, and
 // WSAAddressToString requires both IPv6 to be  installed and for Winsock
 // to be initialized.
-const char* win32_inet_ntop(int af, const void *src,
-                            char* dst, socklen_t size) {
+const char* win32_inet_ntop(int af,
+                            const void* src,
+                            char* dst,
+                            socklen_t size) {
   if (!src || !dst) {
     return nullptr;
   }
@@ -70,11 +72,9 @@
   }
   const struct in_addr* as_in_addr =
       reinterpret_cast<const struct in_addr*>(src);
-  rtc::sprintfn(dst, size, "%d.%d.%d.%d",
-                      as_in_addr->S_un.S_un_b.s_b1,
-                      as_in_addr->S_un.S_un_b.s_b2,
-                      as_in_addr->S_un.S_un_b.s_b3,
-                      as_in_addr->S_un.S_un_b.s_b4);
+  rtc::sprintfn(dst, size, "%d.%d.%d.%d", as_in_addr->S_un.S_un_b.s_b1,
+                as_in_addr->S_un.S_un_b.s_b2, as_in_addr->S_un.S_un_b.s_b3,
+                as_in_addr->S_un.S_un_b.s_b4);
   return dst;
 }
 
@@ -122,8 +122,8 @@
   // Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper.
   // These addresses have an initial run of either eight zero-bytes followed
   // by 0xFFFF, or an initial run of ten zero-bytes.
-  if (runpos[0] == 1 && (maxpos == 5 ||
-                         (maxpos == 4 && as_shorts[5] == 0xFFFF))) {
+  if (runpos[0] == 1 &&
+      (maxpos == 5 || (maxpos == 4 && as_shorts[5] == 0xFFFF))) {
     *cursor++ = ':';
     *cursor++ = ':';
     if (maxpos == 4) {
@@ -136,9 +136,8 @@
   } else {
     for (int i = 0; i < run_array_size; ++i) {
       if (runpos[i] == -1) {
-        cursor += rtc::sprintfn(cursor,
-                                      INET6_ADDRSTRLEN - (cursor - dst),
-                                      "%x", NetworkToHost16(as_shorts[i]));
+        cursor += rtc::sprintfn(cursor, INET6_ADDRSTRLEN - (cursor - dst), "%x",
+                                NetworkToHost16(as_shorts[i]));
         if (i != 7 && runpos[i + 1] != 1) {
           *cursor++ = ':';
         }
@@ -221,7 +220,7 @@
   // Addresses that start with "::" (i.e., a run of initial zeros) or
   // "::ffff:" can potentially be IPv4 mapped or compatibility addresses.
   // These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1").
-  if (*readcursor == ':' && *(readcursor+1) == ':' &&
+  if (*readcursor == ':' && *(readcursor + 1) == ':' &&
       *(readcursor + 2) != 0) {
     // Check for periods, which we'll take as a sign of v4 addresses.
     const char* addrstart = readcursor + 2;
@@ -326,8 +325,8 @@
   }
   wchar_t* wfilename = STACK_ARRAY(wchar_t, wlen);
   if (0 == ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(),
-                                 static_cast<int>(utf8.length() + 1),
-                                 wfilename, wlen)) {
+                                 static_cast<int>(utf8.length() + 1), wfilename,
+                                 wlen)) {
     return false;
   }
   // Replace forward slashes with backslashes
@@ -368,9 +367,12 @@
   OSVERSIONINFO info = {0};
   info.dwOSVersionInfoSize = sizeof(info);
   if (GetVersionEx(&info)) {
-    if (major) *major = info.dwMajorVersion;
-    if (minor) *minor = info.dwMinorVersion;
-    if (build) *build = info.dwBuildNumber;
+    if (major)
+      *major = info.dwMajorVersion;
+    if (minor)
+      *minor = info.dwMinorVersion;
+    if (build)
+      *build = info.dwBuildNumber;
     return true;
   }
   return false;
@@ -387,7 +389,6 @@
       TOKEN_MANDATORY_LABEL* til =
           reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buf);
       if (GetTokenInformation(token, TokenIntegrityLevel, til, size, &size)) {
-
         DWORD count = *GetSidSubAuthorityCount(til->Label.Sid);
         *level = *GetSidSubAuthority(til->Label.Sid, count - 1);
         ret = true;
diff --git a/rtc_base/win32.h b/rtc_base/win32.h
index 4e91687..a5fd541 100644
--- a/rtc_base/win32.h
+++ b/rtc_base/win32.h
@@ -15,24 +15,25 @@
 #error "Only #include this header in Windows builds"
 #endif
 
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-
 // Make sure we don't get min/max macros
 #ifndef NOMINMAX
 #define NOMINMAX
 #endif
 
-#include <winsock2.h>
+// clang-format off
+// clang formating would change include order.
+#include <winsock2.h> // must come first
 #include <windows.h>
+// clang-format on
+
+typedef int socklen_t;
 
 #ifndef SECURITY_MANDATORY_LABEL_AUTHORITY
 // Add defines that we use if we are compiling against older sdks
-#define SECURITY_MANDATORY_MEDIUM_RID               (0x00002000L)
+#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
 #define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(0x19)
 typedef struct _TOKEN_MANDATORY_LABEL {
-    SID_AND_ATTRIBUTES Label;
+  SID_AND_ATTRIBUTES Label;
 } TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
 #endif  // SECURITY_MANDATORY_LABEL_AUTHORITY
 
@@ -40,13 +41,10 @@
 
 #include <string>
 
-#include "rtc_base/basictypes.h"
-#include "rtc_base/stringutils.h"
-
 namespace rtc {
 
-const char* win32_inet_ntop(int af, const void *src, char* dst, socklen_t size);
-int win32_inet_pton(int af, const char* src, void *dst);
+const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size);
+int win32_inet_pton(int af, const char* src, void* dst);
 
 // Convert a Utf8 path representation to a non-length-limited Unicode pathname.
 bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename);
@@ -86,7 +84,7 @@
 inline bool IsCurrentProcessLowIntegrity() {
   int level;
   return (GetCurrentProcessIntegrityLevel(&level) &&
-      level < SECURITY_MANDATORY_MEDIUM_RID);
+          level < SECURITY_MANDATORY_MEDIUM_RID);
 }
 
 }  // namespace rtc
diff --git a/rtc_base/win32_unittest.cc b/rtc_base/win32_unittest.cc
index 5ee3ff4..5691be4 100644
--- a/rtc_base/win32_unittest.cc
+++ b/rtc_base/win32_unittest.cc
@@ -22,8 +22,7 @@
 
 class Win32Test : public testing::Test {
  public:
-  Win32Test() {
-  }
+  Win32Test() {}
 };
 
 TEST_F(Win32Test, IPv6AddressCompression) {
diff --git a/rtc_base/win32filesystem.cc b/rtc_base/win32filesystem.cc
index 8ca84c3..b500e5e 100644
--- a/rtc_base/win32filesystem.cc
+++ b/rtc_base/win32filesystem.cc
@@ -33,7 +33,7 @@
 
 namespace rtc {
 
-bool Win32Filesystem::DeleteFile(const Pathname &filename) {
+bool Win32Filesystem::DeleteFile(const Pathname& filename) {
   RTC_LOG(LS_INFO) << "Deleting file " << filename.pathname();
   if (!IsFile(filename)) {
     RTC_DCHECK(IsFile(filename));
@@ -42,8 +42,8 @@
   return ::DeleteFile(ToUtf16(filename.pathname()).c_str()) != 0;
 }
 
-bool Win32Filesystem::MoveFile(const Pathname &old_path,
-                               const Pathname &new_path) {
+bool Win32Filesystem::MoveFile(const Pathname& old_path,
+                               const Pathname& new_path) {
   if (!IsFile(old_path)) {
     RTC_DCHECK(IsFile(old_path));
     return false;
@@ -54,16 +54,16 @@
                     ToUtf16(new_path.pathname()).c_str()) != 0;
 }
 
-bool Win32Filesystem::IsFolder(const Pathname &path) {
+bool Win32Filesystem::IsFolder(const Pathname& path) {
   WIN32_FILE_ATTRIBUTE_DATA data = {0};
   if (0 == ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(),
                                  GetFileExInfoStandard, &data))
     return false;
   return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
-      FILE_ATTRIBUTE_DIRECTORY;
+         FILE_ATTRIBUTE_DIRECTORY;
 }
 
-bool Win32Filesystem::IsFile(const Pathname &path) {
+bool Win32Filesystem::IsFile(const Pathname& path) {
   WIN32_FILE_ATTRIBUTE_DATA data = {0};
   if (0 == ::GetFileAttributesEx(ToUtf16(path.pathname()).c_str(),
                                  GetFileExInfoStandard, &data))
@@ -71,11 +71,11 @@
   return (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
 }
 
-bool Win32Filesystem::GetFileSize(const Pathname &pathname, size_t *size) {
+bool Win32Filesystem::GetFileSize(const Pathname& pathname, size_t* size) {
   WIN32_FILE_ATTRIBUTE_DATA data = {0};
   if (::GetFileAttributesEx(ToUtf16(pathname.pathname()).c_str(),
                             GetFileExInfoStandard, &data) == 0)
-  return false;
+    return false;
   *size = data.nFileSizeLow;
   return true;
 }
diff --git a/rtc_base/win32socketinit.cc b/rtc_base/win32socketinit.cc
index 5bf6546..ea0aae6 100644
--- a/rtc_base/win32socketinit.cc
+++ b/rtc_base/win32socketinit.cc
@@ -34,9 +34,8 @@
     if (!err_)
       WSACleanup();
   }
-  int error() {
-    return err_;
-  }
+  int error() { return err_; }
+
  private:
   int err_;
 };
diff --git a/rtc_base/win32socketserver.cc b/rtc_base/win32socketserver.cc
index d79a1b3..cab751a 100644
--- a/rtc_base/win32socketserver.cc
+++ b/rtc_base/win32socketserver.cc
@@ -10,8 +10,8 @@
 
 #include "rtc_base/win32socketserver.h"
 
-#include <algorithm>
 #include <ws2tcpip.h>  // NOLINT
+#include <algorithm>
 
 #include "rtc_base/byteorder.h"
 #include "rtc_base/checks.h"
@@ -24,38 +24,9 @@
 // Win32Socket
 ///////////////////////////////////////////////////////////////////////////////
 
-// TODO: Move this to a common place where PhysicalSocketServer can
-// share it.
-// Standard MTUs
-static const uint16_t PACKET_MAXIMUMS[] = {
-    65535,  // Theoretical maximum, Hyperchannel
-    32000,  // Nothing
-    17914,  // 16Mb IBM Token Ring
-    8166,   // IEEE 802.4
-    // 4464   // IEEE 802.5 (4Mb max)
-    4352,   // FDDI
-    // 2048,  // Wideband Network
-    2002,   // IEEE 802.5 (4Mb recommended)
-    // 1536,  // Expermental Ethernet Networks
-    // 1500,  // Ethernet, Point-to-Point (default)
-    1492,   // IEEE 802.3
-    1006,   // SLIP, ARPANET
-    // 576,   // X.25 Networks
-    // 544,   // DEC IP Portal
-    // 512,   // NETBIOS
-    508,    // IEEE 802/Source-Rt Bridge, ARCNET
-    296,    // Point-to-Point (low delay)
-    68,     // Official minimum
-    0,      // End of list marker
-};
-
-static const int IP_HEADER_SIZE = 20u;
-static const int ICMP_HEADER_SIZE = 8u;
-static const int ICMP_PING_TIMEOUT_MILLIS = 10000u;
-
 // TODO: Enable for production builds also? Use FormatMessage?
 #if !defined(NDEBUG)
-LPCSTR WSAErrorToString(int error, LPCSTR *description_result) {
+LPCSTR WSAErrorToString(int error, LPCSTR* description_result) {
   LPCSTR string = "Unspecified";
   LPCSTR description = "Unspecified description";
   switch (error) {
@@ -136,8 +107,8 @@
 // Win32Socket::EventSink
 /////////////////////////////////////////////////////////////////////////////
 
-#define WM_SOCKETNOTIFY  (WM_USER + 50)
-#define WM_DNSNOTIFY     (WM_USER + 51)
+#define WM_SOCKETNOTIFY (WM_USER + 50)
+#define WM_DNSNOTIFY (WM_USER + 51)
 
 struct Win32Socket::DnsLookup {
   HANDLE handle;
@@ -147,7 +118,7 @@
 
 class Win32Socket::EventSink : public Win32Window {
  public:
-  explicit EventSink(Win32Socket * parent) : parent_(parent) { }
+  explicit EventSink(Win32Socket* parent) : parent_(parent) {}
 
   void Dispose();
 
@@ -161,7 +132,7 @@
   bool OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result);
   bool OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result);
 
-  Win32Socket * parent_;
+  Win32Socket* parent_;
 };
 
 void Win32Socket::EventSink::Dispose() {
@@ -173,20 +144,24 @@
   }
 }
 
-bool Win32Socket::EventSink::OnMessage(UINT uMsg, WPARAM wParam,
-                                       LPARAM lParam, LRESULT& result) {
+bool Win32Socket::EventSink::OnMessage(UINT uMsg,
+                                       WPARAM wParam,
+                                       LPARAM lParam,
+                                       LRESULT& result) {
   switch (uMsg) {
-  case WM_SOCKETNOTIFY:
-  case WM_TIMER:
-    return OnSocketNotify(uMsg, wParam, lParam, result);
-  case WM_DNSNOTIFY:
-    return OnDnsNotify(wParam, lParam, result);
+    case WM_SOCKETNOTIFY:
+    case WM_TIMER:
+      return OnSocketNotify(uMsg, wParam, lParam, result);
+    case WM_DNSNOTIFY:
+      return OnDnsNotify(wParam, lParam, result);
   }
   return false;
 }
 
-bool Win32Socket::EventSink::OnSocketNotify(UINT uMsg, WPARAM wParam,
-                                            LPARAM lParam, LRESULT& result) {
+bool Win32Socket::EventSink::OnSocketNotify(UINT uMsg,
+                                            WPARAM wParam,
+                                            LPARAM lParam,
+                                            LRESULT& result) {
   result = 0;
 
   int wsa_event = WSAGETSELECTEVENT(lParam);
@@ -203,7 +178,8 @@
   return true;
 }
 
-bool Win32Socket::EventSink::OnDnsNotify(WPARAM wParam, LPARAM lParam,
+bool Win32Socket::EventSink::OnDnsNotify(WPARAM wParam,
+                                         LPARAM lParam,
                                          LRESULT& result) {
   result = 0;
 
@@ -280,8 +256,8 @@
 SocketAddress Win32Socket::GetLocalAddress() const {
   sockaddr_storage addr = {0};
   socklen_t addrlen = sizeof(addr);
-  int result = ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr),
-                             &addrlen);
+  int result =
+      ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
   SocketAddress address;
   if (result >= 0) {
     SocketAddressFromSockAddrStorage(addr, &address);
@@ -295,8 +271,8 @@
 SocketAddress Win32Socket::GetRemoteAddress() const {
   sockaddr_storage addr = {0};
   socklen_t addrlen = sizeof(addr);
-  int result = ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr),
-                             &addrlen);
+  int result =
+      ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
   SocketAddress address;
   if (result >= 0) {
     SocketAddressFromSockAddrStorage(addr, &address);
@@ -314,8 +290,7 @@
 
   sockaddr_storage saddr;
   size_t len = addr.ToSockAddrStorage(&saddr);
-  int err = ::bind(socket_,
-                   reinterpret_cast<sockaddr*>(&saddr),
+  int err = ::bind(socket_, reinterpret_cast<sockaddr*>(&saddr),
                    static_cast<int>(len));
   UpdateLastError();
   return err;
@@ -332,7 +307,7 @@
   }
 
   RTC_LOG_F(LS_INFO) << "async dns lookup (" << addr.hostname() << ")";
-  DnsLookup * dns = new DnsLookup;
+  DnsLookup* dns = new DnsLookup;
   if (!sink_) {
     // Explicitly create the sink ourselves here; we can't rely on SetAsync
     // because we don't have a socket_ yet.
@@ -368,8 +343,7 @@
   sockaddr_storage saddr = {0};
   size_t len = addr.ToSockAddrStorage(&saddr);
   connect_time_ = Time();
-  int result = connect(socket_,
-                       reinterpret_cast<SOCKADDR*>(&saddr),
+  int result = connect(socket_, reinterpret_cast<SOCKADDR*>(&saddr),
                        static_cast<int>(len));
   if (result != SOCKET_ERROR) {
     state_ = CS_CONNECTED;
@@ -423,22 +397,20 @@
 }
 
 int Win32Socket::Send(const void* buffer, size_t length) {
-  int sent = ::send(socket_,
-                    reinterpret_cast<const char*>(buffer),
-                    static_cast<int>(length),
-                    0);
+  int sent = ::send(socket_, reinterpret_cast<const char*>(buffer),
+                    static_cast<int>(length), 0);
   UpdateLastError();
   return sent;
 }
 
-int Win32Socket::SendTo(const void* buffer, size_t length,
+int Win32Socket::SendTo(const void* buffer,
+                        size_t length,
                         const SocketAddress& addr) {
   sockaddr_storage saddr;
   size_t addr_len = addr.ToSockAddrStorage(&saddr);
-  int sent = ::sendto(socket_, reinterpret_cast<const char*>(buffer),
-                      static_cast<int>(length), 0,
-                      reinterpret_cast<sockaddr*>(&saddr),
-                      static_cast<int>(addr_len));
+  int sent = ::sendto(
+      socket_, reinterpret_cast<const char*>(buffer), static_cast<int>(length),
+      0, reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(addr_len));
   UpdateLastError();
   return sent;
 }
@@ -447,8 +419,8 @@
   if (timestamp) {
     *timestamp = -1;
   }
-  int received = ::recv(socket_, static_cast<char*>(buffer),
-                        static_cast<int>(length), 0);
+  int received =
+      ::recv(socket_, static_cast<char*>(buffer), static_cast<int>(length), 0);
   UpdateLastError();
   if (closing_ && received <= static_cast<int>(length))
     PostClosed();
@@ -464,9 +436,9 @@
   }
   sockaddr_storage saddr;
   socklen_t addr_len = sizeof(saddr);
-  int received = ::recvfrom(socket_, static_cast<char*>(buffer),
-                            static_cast<int>(length), 0,
-                            reinterpret_cast<sockaddr*>(&saddr), &addr_len);
+  int received =
+      ::recvfrom(socket_, static_cast<char*>(buffer), static_cast<int>(length),
+                 0, reinterpret_cast<sockaddr*>(&saddr), &addr_len);
   UpdateLastError();
   if (received != SOCKET_ERROR)
     SocketAddressFromSockAddrStorage(saddr, out_addr);
@@ -540,8 +512,8 @@
   }
 
   // start the async select
-  if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events)
-      == SOCKET_ERROR) {
+  if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events) ==
+      SOCKET_ERROR) {
     UpdateLastError();
     Close();
     return false;
@@ -562,8 +534,8 @@
 void Win32Socket::PostClosed() {
   // If we see that the buffer is indeed drained, then send the close.
   closing_ = false;
-  ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY,
-                socket_, WSAMAKESELECTREPLY(FD_CLOSE, close_error_));
+  ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY, socket_,
+                WSAMAKESELECTREPLY(FD_CLOSE, close_error_));
 }
 
 void Win32Socket::UpdateLastError() {
@@ -696,9 +668,7 @@
 const TCHAR Win32SocketServer::kWindowName[] = L"libjingle Message Window";
 
 Win32SocketServer::Win32SocketServer()
-    : wnd_(this),
-      posted_(false),
-      hdlg_(nullptr) {
+    : wnd_(this), posted_(false), hdlg_(nullptr) {
   if (s_wm_wakeup_id == 0)
     s_wm_wakeup_id = RegisterWindowMessage(L"WM_WAKEUP");
   if (!wnd_.Create(nullptr, kWindowName, 0, 0, 0, 0, 0, 0)) {
@@ -713,18 +683,10 @@
   }
 }
 
-Socket* Win32SocketServer::CreateSocket(int type) {
-  return CreateSocket(AF_INET, type);
-}
-
 Socket* Win32SocketServer::CreateSocket(int family, int type) {
   return CreateAsyncSocket(family, type);
 }
 
-AsyncSocket* Win32SocketServer::CreateAsyncSocket(int type) {
-  return CreateAsyncSocket(AF_INET, type);
-}
-
 AsyncSocket* Win32SocketServer::CreateAsyncSocket(int family, int type) {
   Win32Socket* socket = new Win32Socket;
   if (socket->CreateT(family, type)) {
@@ -755,7 +717,7 @@
       if (b == -1) {
         RTC_LOG_GLE(LS_ERROR) << "GetMessage failed.";
         return false;
-      } else if(b) {
+      } else if (b) {
         if (!hdlg_ || !IsDialogMessage(hdlg_, &msg)) {
           TranslateMessage(&msg);
           DispatchMessage(&msg);
@@ -821,8 +783,10 @@
   }
 }
 
-bool Win32SocketServer::MessageWindow::OnMessage(UINT wm, WPARAM wp,
-                                                 LPARAM lp, LRESULT& lr) {
+bool Win32SocketServer::MessageWindow::OnMessage(UINT wm,
+                                                 WPARAM wp,
+                                                 LPARAM lp,
+                                                 LRESULT& lr) {
   bool handled = false;
   if (wm == s_wm_wakeup_id || (wm == WM_TIMER && wp == 1)) {
     ss_->Pump();
diff --git a/rtc_base/win32socketserver.h b/rtc_base/win32socketserver.h
index ce29bc5..0b11d64 100644
--- a/rtc_base/win32socketserver.h
+++ b/rtc_base/win32socketserver.h
@@ -75,17 +75,17 @@
   SOCKET socket_;
   int error_;
   ConnState state_;
-  SocketAddress addr_;         // address that we connected to (see DoConnect)
+  SocketAddress addr_;  // address that we connected to (see DoConnect)
   uint32_t connect_time_;
   bool closing_;
   int close_error_;
 
   class EventSink;
   friend class EventSink;
-  EventSink * sink_;
+  EventSink* sink_;
 
   struct DnsLookup;
-  DnsLookup * dns_;
+  DnsLookup* dns_;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -97,15 +97,10 @@
   Win32SocketServer();
   ~Win32SocketServer() override;
 
-  void set_modeless_dialog(HWND hdlg) {
-    hdlg_ = hdlg;
-  }
+  void set_modeless_dialog(HWND hdlg) { hdlg_ = hdlg; }
 
   // SocketServer Interface
-  Socket* CreateSocket(int type) override;
   Socket* CreateSocket(int family, int type) override;
-
-  AsyncSocket* CreateAsyncSocket(int type) override;
   AsyncSocket* CreateAsyncSocket(int family, int type) override;
 
   void SetMessageQueue(MessageQueue* queue) override;
@@ -120,13 +115,14 @@
   class MessageWindow : public Win32Window {
    public:
     explicit MessageWindow(Win32SocketServer* ss) : ss_(ss) {}
+
    private:
     bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result) override;
     Win32SocketServer* ss_;
   };
 
   static const TCHAR kWindowName[];
-  MessageQueue *message_queue_;
+  MessageQueue* message_queue_;
   MessageWindow wnd_;
   CriticalSection cs_;
   bool posted_;
diff --git a/rtc_base/win32window.cc b/rtc_base/win32window.cc
index d71c68e..4290894 100644
--- a/rtc_base/win32window.cc
+++ b/rtc_base/win32window.cc
@@ -28,8 +28,14 @@
   RTC_DCHECK(nullptr == wnd_);
 }
 
-bool Win32Window::Create(HWND parent, const wchar_t* title, DWORD style,
-                         DWORD exstyle, int x, int y, int cx, int cy) {
+bool Win32Window::Create(HWND parent,
+                         const wchar_t* title,
+                         DWORD style,
+                         DWORD exstyle,
+                         int x,
+                         int y,
+                         int cx,
+                         int cy) {
   if (wnd_) {
     // Window already exists.
     return false;
@@ -37,7 +43,7 @@
 
   if (!window_class_) {
     if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
-                           GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                               GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                            reinterpret_cast<LPCWSTR>(&Win32Window::WndProc),
                            &instance_)) {
       RTC_LOG_GLE(LS_ERROR) << "GetModuleHandleEx failed";
@@ -74,15 +80,17 @@
   }
 }
 
-bool Win32Window::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
+bool Win32Window::OnMessage(UINT uMsg,
+                            WPARAM wParam,
+                            LPARAM lParam,
                             LRESULT& result) {
   switch (uMsg) {
-  case WM_CLOSE:
-    if (!OnClose()) {
-      result = 0;
-      return true;
-    }
-    break;
+    case WM_CLOSE:
+      if (!OnClose()) {
+        result = 0;
+        return true;
+      }
+      break;
   }
   return false;
 }
diff --git a/rtc_base/win32window.h b/rtc_base/win32window.h
index fa026d1..e96aa35 100644
--- a/rtc_base/win32window.h
+++ b/rtc_base/win32window.h
@@ -28,22 +28,32 @@
 
   HWND handle() const { return wnd_; }
 
-  bool Create(HWND parent, const wchar_t* title, DWORD style, DWORD exstyle,
-              int x, int y, int cx, int cy);
+  bool Create(HWND parent,
+              const wchar_t* title,
+              DWORD style,
+              DWORD exstyle,
+              int x,
+              int y,
+              int cx,
+              int cy);
   void Destroy();
 
   // Call this when your DLL unloads.
   static void Shutdown();
 
  protected:
-  virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
+  virtual bool OnMessage(UINT uMsg,
+                         WPARAM wParam,
+                         LPARAM lParam,
                          LRESULT& result);
 
   virtual bool OnClose();
   virtual void OnNcDestroy();
 
  private:
-  static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
+  static LRESULT CALLBACK WndProc(HWND hwnd,
+                                  UINT uMsg,
+                                  WPARAM wParam,
                                   LPARAM lParam);
 
   HWND wnd_;
diff --git a/script/sync-apm.sh b/script/sync-apm.sh
index de4f77f..ab645f9 100755
--- a/script/sync-apm.sh
+++ b/script/sync-apm.sh
@@ -23,6 +23,7 @@
 rsync "${OPTIONS[@]}" ${FROM}/modules/audio_coding ${TO}/modules
 rsync "${OPTIONS[@]}" ${FROM}/modules/audio_processing ${TO}/modules
 rsync "${OPTIONS[@]}" ${FROM}/modules/include ${TO}/modules
+rsync "${OPTIONS[@]}" ${FROM}/modules/rtp_rtcp ${TO}/modules
 
 # Add video codecs headers for common includes to work.
 mkdir -p ${TO}/modules/video_coding/codecs
@@ -38,8 +39,15 @@
 rsync "${OPTIONS[@]}" ${FROM}/modules/video_coding/codecs/vp9/include \
 	${TO}/modules/video_coding/codecs/vp9
 
+rsync "${OPTIONS[@]}" ${FROM}/third_party/abseil-cpp/absl ${TO}
+
+mkdir -p ${TO}/third_party
+rsync "${OPTIONS[@]}" ${FROM}/third_party/rnnoise \
+	${TO}/third_party
+
 rsync "${OPTIONS[@]}" --include="*.cc" --include="*.h" --include="audio" \
-	--include="video" --exclude="*" ${FROM}/api/* ${TO}/api
+	--include="video" --include="transport" --include="units" \
+	--exclude="*" ${FROM}/api/* ${TO}/api
 
 # Adjust include path to use libevent header on chroot
 sed -i 's/include "base\/third_party\/libevent\/event\.h"/include <event.h>/' \
diff --git a/system_wrappers/BUILD.gn b/system_wrappers/BUILD.gn
index af778fd..4c09164 100644
--- a/system_wrappers/BUILD.gn
+++ b/system_wrappers/BUILD.gn
@@ -40,10 +40,10 @@
     ":runtime_enabled_features_api",
     "..:webrtc_common",
     "../:typedefs",
-    "../api:optional",
     "../modules:module_api_public",
     "../rtc_base:checks",
     "../rtc_base/synchronization:rw_lock_wrapper",
+    "//third_party/abseil-cpp/absl/types:optional",
   ]
 
   if (is_posix || is_fuchsia) {
@@ -83,24 +83,14 @@
     defines += [ "WEBRTC_THREAD_RR" ]
   }
 
-  # TODO(jschuh): Bug 1348: fix this warning.
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
   if (is_win) {
     libs += [ "winmm.lib" ]
 
-    cflags = [ "/wd4334" ]  # Ignore warning on shift operator promotion.
-
     # Windows needs ../rtc_base:rtc_base due to include of
     # webrtc/rtc_base/win32.h in source/clock.cc.
     deps += [ "../rtc_base:rtc_base" ]
   }
 
-  if (is_win && is_clang) {
-    # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-    suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
-  }
-
   deps += [
     "../rtc_base:rtc_base_approved",
     "../rtc_base:rtc_numerics",
@@ -218,17 +208,9 @@
       "source/ntp_time_unittest.cc",
       "source/rtp_to_ntp_estimator_unittest.cc",
     ]
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
     if (is_posix || is_fuchsia) {
-      sources += [
-        "source/event_timer_posix_unittest.cc",
-      ]
-    }
-
-    if (!build_with_chromium && is_clang) {
-      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
-      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+      sources += [ "source/event_timer_posix_unittest.cc" ]
     }
 
     deps = [
diff --git a/system_wrappers/include/metrics.h b/system_wrappers/include/metrics.h
index 13f2483..99b8194 100644
--- a/system_wrappers/include/metrics.h
+++ b/system_wrappers/include/metrics.h
@@ -127,10 +127,13 @@
 
 // Histogram for enumerators (evenly spaced buckets).
 // |boundary| should be above the max enumerator sample.
+//
+// TODO(qingsi): Refactor the default implementation given by RtcHistogram,
+// which is already sparse, and remove the boundary argument from the macro.
 #define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
-  RTC_HISTOGRAM_COMMON_BLOCK_SLOW(                               \
+  RTC_HISTOGRAM_COMMON_BLOCK(                                    \
       name, sample,                                              \
-      webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
+      webrtc::metrics::SparseHistogramFactoryGetEnumeration(name, boundary))
 
 // Histogram for percentage (evenly spaced buckets).
 #define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
@@ -263,6 +266,11 @@
 Histogram* HistogramFactoryGetEnumeration(const std::string& name,
                                           int boundary);
 
+// Get sparse histogram for enumerators.
+// |boundary| should be above the max enumerator sample.
+Histogram* SparseHistogramFactoryGetEnumeration(const std::string& name,
+                                                int boundary);
+
 // Function for adding a |sample| to a histogram.
 void HistogramAdd(Histogram* histogram_pointer, int sample);
 
diff --git a/system_wrappers/include/rtp_to_ntp_estimator.h b/system_wrappers/include/rtp_to_ntp_estimator.h
index 7c0757c..62a79a5 100644
--- a/system_wrappers/include/rtp_to_ntp_estimator.h
+++ b/system_wrappers/include/rtp_to_ntp_estimator.h
@@ -13,7 +13,7 @@
 
 #include <list>
 
-#include "api/optional.h"
+#include "absl/types/optional.h"
 #include "modules/include/module_common_types_public.h"
 #include "rtc_base/numerics/moving_median_filter.h"
 #include "system_wrappers/include/ntp_time.h"
@@ -72,7 +72,7 @@
   bool Estimate(int64_t rtp_timestamp, int64_t* rtp_timestamp_ms) const;
 
   // Returns estimated rtp to ntp linear transform parameters.
-  const rtc::Optional<Parameters> params() const;
+  const absl::optional<Parameters> params() const;
 
   static const int kMaxInvalidSamples = 3;
 
diff --git a/system_wrappers/source/clock.cc b/system_wrappers/source/clock.cc
index 00cdff0..c9940fb 100644
--- a/system_wrappers/source/clock.cc
+++ b/system_wrappers/source/clock.cc
@@ -90,7 +90,7 @@
         num_timer_wraps_(0),
         ref_point_(GetSystemReferencePoint()) {}
 
-  virtual ~WindowsRealTimeClock() {}
+  ~WindowsRealTimeClock() override {}
 
  protected:
   struct ReferencePoint {
@@ -223,7 +223,7 @@
 #elif defined(WEBRTC_POSIX)
   static UnixRealTimeClock clock;
   return &clock;
-#else  // defined(WEBRTC_POSIX)
+#else   // defined(WEBRTC_POSIX)
   return nullptr;
 #endif  // !defined(WEBRTC_WIN) || defined(WEBRTC_POSIX)
 }
diff --git a/system_wrappers/source/event_timer_posix_unittest.cc b/system_wrappers/source/event_timer_posix_unittest.cc
index e0c5cbc..88fd90a 100644
--- a/system_wrappers/source/event_timer_posix_unittest.cc
+++ b/system_wrappers/source/event_timer_posix_unittest.cc
@@ -35,7 +35,7 @@
         main_event_(false, true),
         process_thread_id_(0),
         process_thread_(nullptr) {}
-  virtual ~EventTimerPosixTest() {}
+  ~EventTimerPosixTest() override {}
 
   rtc::PlatformThread* CreateThread() override {
     EXPECT_TRUE(process_thread_ == nullptr);
diff --git a/system_wrappers/source/event_timer_win.h b/system_wrappers/source/event_timer_win.h
index 5631a3f..0b4dff6 100644
--- a/system_wrappers/source/event_timer_win.h
+++ b/system_wrappers/source/event_timer_win.h
@@ -22,13 +22,13 @@
 class EventTimerWin : public EventTimerWrapper {
  public:
   EventTimerWin();
-  virtual ~EventTimerWin();
+  ~EventTimerWin() override;
 
-  virtual EventTypeWrapper Wait(unsigned long max_time);
-  virtual bool Set();
+  EventTypeWrapper Wait(unsigned long max_time) override;
+  bool Set() override;
 
-  virtual bool StartTimer(bool periodic, unsigned long time);
-  virtual bool StopTimer();
+  bool StartTimer(bool periodic, unsigned long time) override;
+  bool StopTimer() override;
 
  private:
   HANDLE event_;
diff --git a/system_wrappers/source/metrics_default.cc b/system_wrappers/source/metrics_default.cc
index fbb2956..7b62c81 100644
--- a/system_wrappers/source/metrics_default.cc
+++ b/system_wrappers/source/metrics_default.cc
@@ -247,6 +247,12 @@
   return map->GetEnumerationHistogram(name, boundary);
 }
 
+// Our default implementation reuses the non-sparse histogram.
+Histogram* SparseHistogramFactoryGetEnumeration(const std::string& name,
+                                                int boundary) {
+  return HistogramFactoryGetEnumeration(name, boundary);
+}
+
 // Fast path. Adds |sample| to cached |histogram_pointer|.
 void HistogramAdd(Histogram* histogram_pointer, int sample) {
   RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
diff --git a/system_wrappers/source/metrics_default_unittest.cc b/system_wrappers/source/metrics_default_unittest.cc
index fa253a9..7491a2f 100644
--- a/system_wrappers/source/metrics_default_unittest.cc
+++ b/system_wrappers/source/metrics_default_unittest.cc
@@ -54,7 +54,7 @@
   MetricsDefaultTest() {}
 
  protected:
-  virtual void SetUp() { metrics::Reset(); }
+  void SetUp() override { metrics::Reset(); }
 };
 
 TEST_F(MetricsDefaultTest, Reset) {
diff --git a/system_wrappers/source/metrics_unittest.cc b/system_wrappers/source/metrics_unittest.cc
index 53d43cd..4218ad7 100644
--- a/system_wrappers/source/metrics_unittest.cc
+++ b/system_wrappers/source/metrics_unittest.cc
@@ -29,7 +29,7 @@
   MetricsTest() {}
 
  protected:
-  virtual void SetUp() { metrics::Reset(); }
+  void SetUp() override { metrics::Reset(); }
 };
 
 TEST_F(MetricsTest, InitiallyNoSamples) {
diff --git a/system_wrappers/source/module.mk b/system_wrappers/source/module.mk
index 3b84a7d..15ea48a 100644
--- a/system_wrappers/source/module.mk
+++ b/system_wrappers/source/module.mk
@@ -10,6 +10,7 @@
 	system_wrappers/source/cpu_info.o \
 	system_wrappers/source/event.o \
 	system_wrappers/source/event_timer_posix.o \
+	system_wrappers/source/field_trial_default.o \
 	system_wrappers/source/rtp_to_ntp_estimator.o \
 	system_wrappers/source/sleep.o
 
diff --git a/system_wrappers/source/rtp_to_ntp_estimator.cc b/system_wrappers/source/rtp_to_ntp_estimator.cc
index 21f64ec..730c4f6 100644
--- a/system_wrappers/source/rtp_to_ntp_estimator.cc
+++ b/system_wrappers/source/rtp_to_ntp_estimator.cc
@@ -21,7 +21,6 @@
 // Number of parameters samples used to smooth.
 const size_t kNumSamplesToSmooth = 20;
 
-
 // Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps.
 bool CalculateFrequency(int64_t ntp_ms1,
                         uint32_t rtp_timestamp1,
@@ -194,9 +193,9 @@
   return true;
 }
 
-const rtc::Optional<RtpToNtpEstimator::Parameters> RtpToNtpEstimator::params()
+const absl::optional<RtpToNtpEstimator::Parameters> RtpToNtpEstimator::params()
     const {
-  rtc::Optional<Parameters> res;
+  absl::optional<Parameters> res;
   if (params_calculated_) {
     res.emplace(smoothing_filter_.GetFilteredValue());
   }
diff --git a/system_wrappers/source/runtime_enabled_features_default.cc b/system_wrappers/source/runtime_enabled_features_default.cc
index 31a3ff7..1d040a9 100644
--- a/system_wrappers/source/runtime_enabled_features_default.cc
+++ b/system_wrappers/source/runtime_enabled_features_default.cc
@@ -13,9 +13,7 @@
 #include "rtc_base/flags.h"
 
 namespace flags {
-DEFINE_bool(enable_dual_stream_mode,
-            false,
-            "Enables dual video stream mode.");
+DEFINE_bool(enable_dual_stream_mode, false, "Enables dual video stream mode.");
 }
 
 namespace webrtc {
diff --git a/third_party/module.mk b/third_party/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/third_party/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/third_party/rnnoise/BUILD.gn b/third_party/rnnoise/BUILD.gn
new file mode 100644
index 0000000..c669179
--- /dev/null
+++ b/third_party/rnnoise/BUILD.gn
@@ -0,0 +1,38 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/test.gni")
+
+group("rnnoise") {
+  deps = [
+    ":kiss_fft",
+    ":rnn_vad",
+  ]
+}
+
+source_set("kiss_fft") {
+  sources = [
+    "src/kiss_fft.cc",
+    "src/kiss_fft.h",
+  ]
+}
+
+source_set("rnn_vad") {
+  sources = [
+    "src/rnn_activations.h",
+    "src/rnn_vad_weights.cc",
+    "src/rnn_vad_weights.h",
+  ]
+}
+
+test("kiss_fft_unittest") {
+  sources = [
+    "src/kiss_fft_unittest.cc",
+  ]
+  deps = [
+    ":kiss_fft",
+    "//testing/gtest",
+    "//testing/gtest:gtest_main",
+  ]
+}
diff --git a/third_party/rnnoise/COPYING b/third_party/rnnoise/COPYING
new file mode 100644
index 0000000..01ea4b1
--- /dev/null
+++ b/third_party/rnnoise/COPYING
@@ -0,0 +1,31 @@
+Copyright (c) 2017, Mozilla
+Copyright (c) 2007-2017, Jean-Marc Valin
+Copyright (c) 2005-2017, Xiph.Org Foundation
+Copyright (c) 2003-2004, Mark Borgerding
+
+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 the Xiph.Org Foundation 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 FOUNDATION
+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/third_party/rnnoise/DEPS b/third_party/rnnoise/DEPS
new file mode 100644
index 0000000..fca61fc
--- /dev/null
+++ b/third_party/rnnoise/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+testing/gtest/include/gtest",
+]
diff --git a/third_party/rnnoise/OWNERS b/third_party/rnnoise/OWNERS
new file mode 100644
index 0000000..b3f35ec
--- /dev/null
+++ b/third_party/rnnoise/OWNERS
@@ -0,0 +1,2 @@
+alessiob@chromium.org
+aleloi@chromium.org
diff --git a/third_party/rnnoise/README.chromium b/third_party/rnnoise/README.chromium
new file mode 100644
index 0000000..8efe059
--- /dev/null
+++ b/third_party/rnnoise/README.chromium
@@ -0,0 +1,28 @@
+Name: Recurrent neural network for audio noise reduction
+Short Name: rnnoise
+URL: https://github.com/xiph/rnnoise
+Version: 91ef401
+Date: Oct 10, 2017
+Revision:
+License: BSD 3-Clause
+License File: COPYING
+Security Critical: no
+License Android Compatible:
+
+Description:
+RNNoise is a noise suppression library based on a recurrent neural network.
+The library is used for speech processing in WebRTC.
+
+Local Modifications:
+* Only retaining COPYING and from src/ the following files:
+ - kiss_fft.c, kiss_fft.h
+ - rnn.c
+ - rnn_data.c
+ - tansig_table.h
+* KissFFT: non-floating point parts removed, code clean, from C to C++,
+  class wrapper added
+* BUILD targets and KissFFT unit tests added
+* rnn_vad_weights.h: output layer sizes + weights scaling factor
+* removing unwanted extern from constants in rnn_vad_weights.h and using
+  constants to declare array sizes
+* Add braces around arrays in unit test.
\ No newline at end of file
diff --git a/third_party/rnnoise/module.mk b/third_party/rnnoise/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/third_party/rnnoise/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/third_party/rnnoise/src/kiss_fft.cc b/third_party/rnnoise/src/kiss_fft.cc
new file mode 100644
index 0000000..27b4900
--- /dev/null
+++ b/third_party/rnnoise/src/kiss_fft.cc
@@ -0,0 +1,443 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+  Lots of modifications by Jean-Marc Valin
+  Copyright (c) 2005-2007, Xiph.Org Foundation
+  Copyright (c) 2008,      Xiph.Org Foundation, CSIRO
+  Copyright (c) 2018,      The WebRTC 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.
+
+  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 OWNER 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.*/
+
+#include "third_party/rnnoise/src/kiss_fft.h"
+
+#include <cassert>
+#include <cmath>
+#include <utility>
+
+namespace rnnoise {
+namespace {
+
+void kf_bfly2(std::complex<float>* Fout, int m, int N) {
+  if (m == 1) {
+    for (int i = 0; i < N; i++) {
+      const std::complex<float> t = Fout[1];
+      Fout[1] = Fout[0] - t;
+      Fout[0] += t;
+      Fout += 2;
+    }
+  } else {
+    constexpr float tw = 0.7071067812f;
+    // We know that m==4 here because the radix-2 is just after a radix-4.
+    assert(m == 4);
+    for (int i = 0; i < N; i++) {
+      std::complex<float>* Fout2 = Fout + 4;
+      std::complex<float> t = Fout2[0];
+
+      *Fout2 = Fout[0] - t;
+      Fout[0] += t;
+
+      t.real((Fout2[1].real() + Fout2[1].imag()) * tw);
+      t.imag((Fout2[1].imag() - Fout2[1].real()) * tw);
+      Fout2[1] = Fout[1] - t;
+      Fout[1] += t;
+
+      t.real(Fout2[2].imag());
+      t.imag(-Fout2[2].real());
+      Fout2[2] = Fout[2] - t;
+      Fout[2] += t;
+
+      t.real((Fout2[3].imag() - Fout2[3].real()) * tw);
+      t.imag(-(Fout2[3].imag() + Fout2[3].real()) * tw);
+      Fout2[3] = Fout[3] - t;
+      Fout[3] += t;
+      Fout += 8;
+    }
+  }
+}
+
+void kf_bfly4(std::complex<float>* Fout,
+              const size_t fstride,
+              const KissFft::KissFftState* st,
+              int m,
+              int N,
+              int mm) {
+  assert(Fout);
+  assert(st);
+  if (m == 1) {
+    // Degenerate case where all the twiddles are 1.
+    for (int i = 0; i < N; i++) {
+      std::complex<float> scratch0 = Fout[0] - Fout[2];
+      Fout[0] += Fout[2];
+      std::complex<float> scratch1 = Fout[1] + Fout[3];
+      Fout[2] = Fout[0] - scratch1;
+      Fout[0] += scratch1;
+      scratch1 = Fout[1] - Fout[3];
+
+      Fout[1].real(scratch0.real() + scratch1.imag());
+      Fout[1].imag(scratch0.imag() - scratch1.real());
+      Fout[3].real(scratch0.real() - scratch1.imag());
+      Fout[3].imag(scratch0.imag() + scratch1.real());
+      Fout += 4;
+    }
+  } else {
+    std::complex<float> scratch[6];
+    const int m2 = 2 * m;
+    const int m3 = 3 * m;
+    std::complex<float>* Fout_beg = Fout;
+    for (int i = 0; i < N; i++) {
+      Fout = Fout_beg + i * mm;
+      const std::complex<float>* tw1;
+      const std::complex<float>* tw2;
+      const std::complex<float>* tw3;
+      tw3 = tw2 = tw1 = &st->twiddles[0];
+      assert(m % 4 == 0);  // |m| is guaranteed to be a multiple of 4.
+      for (int j = 0; j < m; j++) {
+        scratch[0] = Fout[m] * *tw1;
+        scratch[1] = Fout[m2] * *tw2;
+        scratch[2] = Fout[m3] * *tw3;
+
+        scratch[5] = Fout[0] - scratch[1];
+        Fout[0] += scratch[1];
+        scratch[3] = scratch[0] + scratch[2];
+        scratch[4] = scratch[0] - scratch[2];
+        Fout[m2] = Fout[0] - scratch[3];
+
+        tw1 += fstride;
+        tw2 += fstride * 2;
+        tw3 += fstride * 3;
+        Fout[0] += scratch[3];
+
+        Fout[m].real(scratch[5].real() + scratch[4].imag());
+        Fout[m].imag(scratch[5].imag() - scratch[4].real());
+        Fout[m3].real(scratch[5].real() - scratch[4].imag());
+        Fout[m3].imag(scratch[5].imag() + scratch[4].real());
+        ++Fout;
+      }
+    }
+  }
+}
+
+void kf_bfly3(std::complex<float>* Fout,
+              const size_t fstride,
+              const KissFft::KissFftState* st,
+              int m,
+              int N,
+              int mm) {
+  assert(Fout);
+  assert(st);
+  const size_t m2 = 2 * m;
+  const std::complex<float>*tw1, *tw2;
+  std::complex<float> scratch[5];
+  std::complex<float> epi3;
+
+  std::complex<float>* Fout_beg = Fout;
+  epi3 = st->twiddles[fstride * m];
+  for (int i = 0; i < N; i++) {
+    Fout = Fout_beg + i * mm;
+    tw1 = tw2 = &st->twiddles[0];
+    size_t k = m;
+    do {
+      scratch[1] = Fout[m] * *tw1;
+      scratch[2] = Fout[m2] * *tw2;
+
+      scratch[3] = scratch[1] + scratch[2];
+      scratch[0] = scratch[1] - scratch[2];
+      tw1 += fstride;
+      tw2 += fstride * 2;
+
+      Fout[m] = Fout[0] - 0.5f * scratch[3];
+
+      scratch[0] *= epi3.imag();
+
+      Fout[0] += scratch[3];
+
+      Fout[m2].real(Fout[m].real() + scratch[0].imag());
+      Fout[m2].imag(Fout[m].imag() - scratch[0].real());
+
+      Fout[m].real(Fout[m].real() - scratch[0].imag());
+      Fout[m].imag(Fout[m].imag() + scratch[0].real());
+
+      ++Fout;
+    } while (--k);
+  }
+}
+
+void kf_bfly5(std::complex<float>* Fout,
+              const size_t fstride,
+              const KissFft::KissFftState* st,
+              int m,
+              int N,
+              int mm) {
+  assert(Fout);
+  assert(st);
+  std::complex<float> scratch[13];
+  const std::complex<float>* tw;
+  std::complex<float> ya, yb;
+  std::complex<float>* const Fout_beg = Fout;
+
+  ya = st->twiddles[fstride * m];
+  yb = st->twiddles[fstride * 2 * m];
+  tw = &st->twiddles[0];
+
+  for (int i = 0; i < N; i++) {
+    Fout = Fout_beg + i * mm;
+    std::complex<float>* Fout0 = Fout;
+    std::complex<float>* Fout1 = Fout0 + m;
+    std::complex<float>* Fout2 = Fout0 + 2 * m;
+    std::complex<float>* Fout3 = Fout0 + 3 * m;
+    std::complex<float>* Fout4 = Fout0 + 4 * m;
+
+    // For non-custom modes, m is guaranteed to be a multiple of 4.
+    for (int u = 0; u < m; ++u) {
+      scratch[0] = *Fout0;
+
+      scratch[1] = *Fout1 * tw[u * fstride];
+      scratch[2] = *Fout2 * tw[2 * u * fstride];
+      scratch[3] = *Fout3 * tw[3 * u * fstride];
+      scratch[4] = *Fout4 * tw[4 * u * fstride];
+
+      scratch[7] = scratch[1] + scratch[4];
+      scratch[10] = scratch[1] - scratch[4];
+      scratch[8] = scratch[2] + scratch[3];
+      scratch[9] = scratch[2] - scratch[3];
+
+      Fout0->real(Fout0->real() + scratch[7].real() + scratch[8].real());
+      Fout0->imag(Fout0->imag() + scratch[7].imag() + scratch[8].imag());
+
+      scratch[5].real(scratch[0].real() + scratch[7].real() * ya.real() +
+                      scratch[8].real() * yb.real());
+      scratch[5].imag(scratch[0].imag() + scratch[7].imag() * ya.real() +
+                      scratch[8].imag() * yb.real());
+
+      scratch[6].real(scratch[10].imag() * ya.imag() +
+                      scratch[9].imag() * yb.imag());
+      scratch[6].imag(
+          -(scratch[10].real() * ya.imag() + scratch[9].real() * yb.imag()));
+
+      *Fout1 = scratch[5] - scratch[6];
+      *Fout4 = scratch[5] + scratch[6];
+
+      scratch[11].real(scratch[0].real() + scratch[7].real() * yb.real() +
+                       scratch[8].real() * ya.real());
+      scratch[11].imag(scratch[0].imag() + scratch[7].imag() * yb.real() +
+                       scratch[8].imag() * ya.real());
+      scratch[12].real(scratch[9].imag() * ya.imag() -
+                       scratch[10].imag() * yb.imag());
+      scratch[12].imag(scratch[10].real() * yb.imag() -
+                       scratch[9].real() * ya.imag());
+
+      *Fout2 = scratch[11] + scratch[12];
+      *Fout3 = scratch[11] - scratch[12];
+
+      ++Fout0;
+      ++Fout1;
+      ++Fout2;
+      ++Fout3;
+      ++Fout4;
+    }
+  }
+}
+
+void compute_bitrev_table(int base_index,
+                          const size_t stride,
+                          const int16_t* factors,
+                          const KissFft::KissFftState* st,
+                          const int16_t* bitrev_table_last,
+                          int16_t* bitrev_table) {
+  const int p = *factors++;  // The radix.
+  const int m = *factors++;  // Stage's fft length/p.
+  if (m == 1) {
+    for (int j = 0; j < p; j++) {
+      assert(bitrev_table <= bitrev_table_last);
+      *bitrev_table = base_index + j;
+      bitrev_table += stride;
+    }
+  } else {
+    for (int j = 0; j < p; j++) {
+      compute_bitrev_table(base_index, stride * p, factors, st,
+                           bitrev_table_last, bitrev_table);
+      bitrev_table += stride;
+      base_index += m;
+    }
+  }
+}
+
+// Populates |facbuf| with p1, m1, p2, m2, ... where p[i] * m[i] = m[i-1] and
+// m0 = n.
+bool kf_factor(int n, int16_t* facbuf) {
+  assert(facbuf);
+  int p = 4;
+  int stages = 0;
+  int nbak = n;
+
+  // Factor out powers of 4, powers of 2, then any remaining primes.
+  do {
+    while (n % p) {
+      switch (p) {
+        case 4:
+          p = 2;
+          break;
+        case 2:
+          p = 3;
+          break;
+        default:
+          p += 2;
+          break;
+      }
+      if (p > 32000 || p * p > n)
+        p = n;  // No more factors, skip to end.
+    }
+    n /= p;
+    if (p > 5)
+      return false;
+    facbuf[2 * stages] = p;
+    if (p == 2 && stages > 1) {
+      facbuf[2 * stages] = 4;
+      facbuf[2] = 2;
+    }
+    stages++;
+  } while (n > 1);
+  n = nbak;
+  // Reverse the order to get the radix 4 at the end, so we can use the
+  // fast degenerate case. It turns out that reversing the order also
+  // improves the noise behavior.
+  for (int i = 0; i < stages / 2; i++)
+    std::swap(facbuf[2 * i], facbuf[2 * (stages - i - 1)]);
+  for (int i = 0; i < stages; i++) {
+    n /= facbuf[2 * i];
+    facbuf[2 * i + 1] = n;
+  }
+  return true;
+}
+
+void compute_twiddles(const int nfft, std::complex<float>* twiddles) {
+  constexpr double pi = 3.14159265358979323846264338327;
+  assert(twiddles);
+  for (int i = 0; i < nfft; ++i) {
+    const double phase = (-2 * pi / nfft) * i;
+    twiddles[i].real(std::cos(phase));
+    twiddles[i].imag(std::sin(phase));
+  }
+}
+
+void fft_impl(const KissFft::KissFftState* st, std::complex<float>* fout) {
+  assert(st);
+  assert(fout);
+  int m2, m;
+  int p;
+  int L;
+  int fstride[KissFft::kMaxFactors];
+
+  fstride[0] = 1;
+  L = 0;
+  do {
+    p = st->factors[2 * L];
+    m = st->factors[2 * L + 1];
+    assert(static_cast<size_t>(L + 1) < KissFft::kMaxFactors);
+    fstride[L + 1] = fstride[L] * p;
+    L++;
+  } while (m != 1);
+  m = st->factors[2 * L - 1];
+  for (int i = L - 1; i >= 0; i--) {
+    if (i != 0)
+      m2 = st->factors[2 * i - 1];
+    else
+      m2 = 1;
+    switch (st->factors[2 * i]) {
+      case 2:
+        kf_bfly2(fout, m, fstride[i]);
+        break;
+      case 4:
+        kf_bfly4(fout, fstride[i], st, m, fstride[i], m2);
+        break;
+      case 3:
+        kf_bfly3(fout, fstride[i], st, m, fstride[i], m2);
+        break;
+      case 5:
+        kf_bfly5(fout, fstride[i], st, m, fstride[i], m2);
+        break;
+      default:
+        assert(0);
+        break;
+    }
+    m = m2;
+  }
+}
+
+}  // namespace
+
+KissFft::KissFftState::KissFftState(int num_fft_points)
+    : nfft(num_fft_points), scale(1.f / nfft) {
+  // Factorize |nfft|.
+  // TODO(alessiob): Handle kf_factor fails (invalid nfft).
+  if (!kf_factor(nfft, factors.data()))
+    assert(0);
+  // Twiddles.
+  twiddles.resize(nfft);
+  compute_twiddles(nfft, twiddles.data());
+  // Bit-reverse table.
+  bitrev.resize(nfft);
+  compute_bitrev_table(0, 1, factors.data(), this, &bitrev.back(),
+                       bitrev.data());
+}
+
+KissFft::KissFftState::~KissFftState() = default;
+
+KissFft::KissFft(const int nfft) : state_(nfft) {}
+
+KissFft::~KissFft() = default;
+
+void KissFft::ForwardFft(const size_t in_size,
+                         const std::complex<float>* in,
+                         const size_t out_size,
+                         std::complex<float>* out) {
+  assert(in);
+  assert(out);
+  assert(in != out);  // In-place FFT not supported.
+  assert(state_.nfft == static_cast<int>(in_size));
+  assert(state_.nfft == static_cast<int>(out_size));
+  // Bit-reverse the input.
+  for (int i = 0; i < state_.nfft; i++)
+    out[state_.bitrev[i]] = state_.scale * in[i];
+  fft_impl(&state_, out);
+}
+
+void KissFft::ReverseFft(const size_t in_size,
+                         const std::complex<float>* in,
+                         const size_t out_size,
+                         std::complex<float>* out) {
+  assert(in);
+  assert(out);
+  assert(in != out);  // In-place IFFT not supported.
+  assert(state_.nfft == static_cast<int>(in_size));
+  assert(state_.nfft == static_cast<int>(out_size));
+  // Bit-reverse the input.
+  for (int i = 0; i < state_.nfft; i++)
+    out[state_.bitrev[i]] = in[i];
+  for (int i = 0; i < state_.nfft; i++)
+    out[i].imag(-out[i].imag());
+  fft_impl(&state_, out);
+  for (int i = 0; i < state_.nfft; i++)
+    out[i].imag(-out[i].imag());
+}
+
+}  // namespace rnnoise
diff --git a/third_party/rnnoise/src/kiss_fft.h b/third_party/rnnoise/src/kiss_fft.h
new file mode 100644
index 0000000..b90f77d
--- /dev/null
+++ b/third_party/rnnoise/src/kiss_fft.h
@@ -0,0 +1,78 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+  Lots of modifications by Jean-Marc Valin
+  Copyright (c) 2005-2007, Xiph.Org Foundation
+  Copyright (c) 2008,      Xiph.Org Foundation, CSIRO
+  Copyright (c) 2018,      The WebRTC 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.
+
+  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 OWNER 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.*/
+
+#ifndef THIRD_PARTY_RNNOISE_SRC_KISS_FFT_H_
+#define THIRD_PARTY_RNNOISE_SRC_KISS_FFT_H_
+
+#include <array>
+#include <complex>
+#include <vector>
+
+namespace rnnoise {
+
+class KissFft {
+ public:
+  // Example: an FFT of length 128 has 4 factors as far as kissfft is concerned
+  // (namely, 4*4*4*2).
+  static const size_t kMaxFactors = 8;
+
+  class KissFftState {
+   public:
+    KissFftState(int num_fft_points);
+    KissFftState(const KissFftState&) = delete;
+    KissFftState& operator=(const KissFftState&) = delete;
+    ~KissFftState();
+
+    const int nfft;
+    const float scale;
+    std::array<int16_t, 2 * kMaxFactors> factors;
+    std::vector<int16_t> bitrev;
+    std::vector<std::complex<float>> twiddles;
+  };
+
+  explicit KissFft(const int nfft);
+  KissFft(const KissFft&) = delete;
+  KissFft& operator=(const KissFft&) = delete;
+  ~KissFft();
+  void ForwardFft(const size_t in_size,
+                  const std::complex<float>* in,
+                  const size_t out_size,
+                  std::complex<float>* out);
+  void ReverseFft(const size_t in_size,
+                  const std::complex<float>* in,
+                  const size_t out_size,
+                  std::complex<float>* out);
+
+ private:
+  KissFftState state_;
+};
+
+}  // namespace rnnoise
+
+#endif  // THIRD_PARTY_RNNOISE_SRC_KISS_FFT_H_
diff --git a/third_party/rnnoise/src/kiss_fft_unittest.cc b/third_party/rnnoise/src/kiss_fft_unittest.cc
new file mode 100644
index 0000000..3132445
--- /dev/null
+++ b/third_party/rnnoise/src/kiss_fft_unittest.cc
@@ -0,0 +1,145 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <array>
+#include <cmath>
+#include <limits>
+#include <tuple>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/rnnoise/src/kiss_fft.h"
+
+namespace rnnoise {
+namespace test {
+namespace {
+
+const double kPi = std::acos(-1.0);
+
+void FillFftInputBuffer(const size_t num_samples,
+                        const float* samples,
+                        std::complex<float>* input_buf) {
+  for (size_t i = 0; i < num_samples; ++i)
+    input_buf[i].real(samples[i]);
+}
+
+void CheckFftResult(const size_t num_fft_points,
+                    const float* expected_real,
+                    const float* expected_imag,
+                    const std::complex<float>* computed,
+                    const float tolerance) {
+  for (size_t i = 0; i < num_fft_points; ++i) {
+    SCOPED_TRACE(i);
+    EXPECT_NEAR(expected_real[i], computed[i].real(), tolerance);
+    EXPECT_NEAR(expected_imag[i], computed[i].imag(), tolerance);
+  }
+}
+
+}  // namespace
+
+class RnnVadTest
+    : public testing::Test,
+      public ::testing::WithParamInterface<std::tuple<size_t, float, float>> {};
+
+// Check that IFFT(FFT(x)) == x (tolerating round-off errors).
+TEST_P(RnnVadTest, KissFftForwardReverseCheckIdentity) {
+  const auto params = GetParam();
+  const float amplitude = std::get<0>(params);
+  const size_t num_fft = std::get<1>(params);
+  const float tolerance = std::get<2>(params);
+  std::vector<float> samples;
+  std::vector<float> zeros;
+  samples.resize(num_fft);
+  zeros.resize(num_fft);
+  for (size_t i = 0; i < num_fft; ++i) {
+    samples[i] = amplitude * std::sin(2.f * kPi * 10 * i / num_fft);
+    zeros[i] = 0.f;
+  }
+
+  KissFft fft(num_fft);
+  std::vector<std::complex<float>> fft_buf_1;
+  fft_buf_1.resize(num_fft);
+  std::vector<std::complex<float>> fft_buf_2;
+  fft_buf_2.resize(num_fft);
+
+  FillFftInputBuffer(samples.size(), samples.data(), fft_buf_1.data());
+  {
+    // TODO(alessiob): Underflow with non power of 2 frame sizes.
+    // FloatingPointExceptionObserver fpe_observer;
+
+    fft.ForwardFft(fft_buf_1.size(), fft_buf_1.data(), fft_buf_2.size(),
+                   fft_buf_2.data());
+    fft.ReverseFft(fft_buf_2.size(), fft_buf_2.data(), fft_buf_1.size(),
+                   fft_buf_1.data());
+  }
+  CheckFftResult(samples.size(), samples.data(), zeros.data(), fft_buf_1.data(),
+                 tolerance);
+}
+
+INSTANTIATE_TEST_CASE_P(FftPoints,
+                        RnnVadTest,
+                        ::testing::Values(std::make_tuple(1.f, 240, 3e-7f),
+                                          std::make_tuple(1.f, 256, 3e-7f),
+                                          std::make_tuple(1.f, 480, 3e-7f),
+                                          std::make_tuple(1.f, 512, 3e-7f),
+                                          std::make_tuple(1.f, 960, 4e-7f),
+                                          std::make_tuple(1.f, 1024, 3e-7f),
+                                          std::make_tuple(30.f, 240, 5e-6f),
+                                          std::make_tuple(30.f, 256, 5e-6f),
+                                          std::make_tuple(30.f, 480, 6e-6f),
+                                          std::make_tuple(30.f, 512, 6e-6f),
+                                          std::make_tuple(30.f, 960, 8e-6f),
+                                          std::make_tuple(30.f, 1024, 6e-6f)));
+
+TEST(RnnVadTest, KissFftBitExactness) {
+  constexpr std::array<float, 32> samples = {
+      {0.3524301946163177490234375f,  0.891803801059722900390625f,
+       0.07706542313098907470703125f, 0.699530780315399169921875f,
+       0.3789891898632049560546875f,  0.5438187122344970703125f,
+       0.332781612873077392578125f,   0.449340641498565673828125f,
+       0.105229437351226806640625f,   0.722373783588409423828125f,
+       0.13155306875705718994140625f, 0.340857982635498046875f,
+       0.970204889774322509765625f,   0.53061950206756591796875f,
+       0.91507828235626220703125f,    0.830274522304534912109375f,
+       0.74468600749969482421875f,    0.24320767819881439208984375f,
+       0.743998110294342041015625f,   0.17574800550937652587890625f,
+       0.1834825575351715087890625f,  0.63317775726318359375f,
+       0.11414264142513275146484375f, 0.1612723171710968017578125f,
+       0.80316197872161865234375f,    0.4979794919490814208984375f,
+       0.554282128810882568359375f,   0.67189347743988037109375f,
+       0.06660757958889007568359375f, 0.89568817615509033203125f,
+       0.29327380657196044921875f,    0.3472573757171630859375f}};
+  constexpr std::array<float, 17> expected_real = {
+      {0.4813065826892852783203125f, -0.0246877372264862060546875f,
+       0.04095232486724853515625f, -0.0401695556938648223876953125f,
+       0.00500857271254062652587890625f, 0.0160773508250713348388671875f,
+       -0.011385642923414707183837890625f, -0.008461721241474151611328125f,
+       0.01383177936077117919921875f, 0.0117270611226558685302734375f,
+       -0.0164460353553295135498046875f, 0.0585579685866832733154296875f,
+       0.02038039825856685638427734375f, -0.0209107734262943267822265625f,
+       0.01046995259821414947509765625f, -0.09019653499126434326171875f,
+       -0.0583711564540863037109375f}};
+  constexpr std::array<float, 17> expected_imag = {
+      {0.f, -0.010482530109584331512451171875f, 0.04762755334377288818359375f,
+       -0.0558677613735198974609375f, 0.007908363826572895050048828125f,
+       -0.0071932487189769744873046875f, 0.01322011835873126983642578125f,
+       -0.011227893643081188201904296875f, -0.0400779247283935546875f,
+       -0.0290451310575008392333984375f, 0.01519204117357730865478515625f,
+       -0.09711246192455291748046875f, -0.00136523949913680553436279296875f,
+       0.038602568209171295166015625f, -0.009693108499050140380859375f,
+       -0.0183933563530445098876953125f, 0.f}};
+
+  KissFft fft(32);
+  std::array<std::complex<float>, 32> fft_buf_in;
+  std::array<std::complex<float>, 32> fft_buf_out;
+  FillFftInputBuffer(samples.size(), samples.data(), fft_buf_in.data());
+  fft.ForwardFft(fft_buf_in.size(), fft_buf_in.data(), fft_buf_out.size(),
+                 fft_buf_out.data());
+  CheckFftResult(expected_real.size(), expected_real.data(),
+                 expected_imag.data(), fft_buf_out.data(),
+                 std::numeric_limits<float>::min());
+}
+
+}  // namespace test
+}  // namespace rnnoise
diff --git a/third_party/rnnoise/src/module.mk b/third_party/rnnoise/src/module.mk
new file mode 100644
index 0000000..37c23f4
--- /dev/null
+++ b/third_party/rnnoise/src/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2018 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include common.mk
diff --git a/third_party/rnnoise/src/rnn_activations.h b/third_party/rnnoise/src/rnn_activations.h
new file mode 100644
index 0000000..af81031
--- /dev/null
+++ b/third_party/rnnoise/src/rnn_activations.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+                 2012-2017 Jean-Marc Valin */
+/*
+   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.
+
+   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 FOUNDATION 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.
+*/
+
+#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_
+#define THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_
+
+#include <cmath>
+
+namespace rnnoise {
+
+inline float TansigApproximated(float x) {
+  static constexpr float kTansigTable[201] = {
+      0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, 0.197375f,
+      0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f,
+      0.446244f, 0.477700f, 0.507977f, 0.537050f, 0.564900f, 0.591519f,
+      0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f,
+      0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
+      0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f,
+      0.893698f, 0.901468f, 0.908698f, 0.915420f, 0.921669f, 0.927473f,
+      0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f,
+      0.957917f, 0.961090f, 0.964028f, 0.966747f, 0.969265f, 0.971594f,
+      0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
+      0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f,
+      0.989867f, 0.990642f, 0.991359f, 0.992020f, 0.992631f, 0.993196f,
+      0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f,
+      0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f,
+      0.997590f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
+      0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999000f,
+      0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f,
+      0.999428f, 0.999472f, 0.999513f, 0.999550f, 0.999585f, 0.999617f,
+      0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f,
+      0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
+      0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f,
+      0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f,
+      0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f,
+      0.999968f, 0.999970f, 0.999973f, 0.999975f, 0.999977f, 0.999978f,
+      0.999980f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
+      0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, 0.999992f,
+      0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f,
+      0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f,
+      0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f,
+      0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
+      0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+      0.999999f, 0.999999f, 0.999999f, 0.999999f, 1.000000f, 1.000000f,
+      1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+      1.000000f, 1.000000f, 1.000000f,
+  };
+
+  // Tests are reversed to catch NaNs.
+  if (!(x < 8.f))
+    return 1.f;
+  if (!(x > -8.f))
+    return -1.f;
+  float sign = 1.f;
+  if (x < 0.f) {
+    x = -x;
+    sign = -1.f;
+  }
+  // Look-up.
+  int i = static_cast<int>(std::floor(0.5f + 25 * x));
+  float y = kTansigTable[i];
+  // Map i back to x's scale (undo 25 factor).
+  x -= 0.04f * i;
+  y = y + x * (1.f - y * y) * (1.f - y * x);
+  return sign * y;
+}
+
+inline float SigmoidApproximated(const float x) {
+  return 0.5f + 0.5f * TansigApproximated(0.5f * x);
+}
+
+inline float RectifiedLinearUnit(const float x) {
+  return x < 0.f ? 0.f : x;
+}
+
+}  // namespace rnnoise
+
+#endif  // THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_
diff --git a/third_party/rnnoise/src/rnn_vad_weights.cc b/third_party/rnnoise/src/rnn_vad_weights.cc
new file mode 100644
index 0000000..40c184b
--- /dev/null
+++ b/third_party/rnnoise/src/rnn_vad_weights.cc
@@ -0,0 +1,401 @@
+#include "third_party/rnnoise/src/rnn_vad_weights.h"
+
+namespace rnnoise {
+
+const int8_t kInputDenseWeights[kInputLayerWeights] = {
+    -10,  0,    -3,   1,    -8,   -6,   3,    -13,  1,    0,    -3,   -7,
+    -5,   -3,   6,    -1,   -6,   0,    -6,   -4,   -1,   -2,   1,    1,
+    -7,   2,    21,   10,   -5,   -20,  24,   23,   37,   8,    -2,   33,
+    -6,   22,   13,   -2,   50,   8,    13,   1,    -15,  30,   -10,  30,
+    0,    3,    5,    27,   1,    4,    -3,   41,   56,   35,   -2,   49,
+    -13,  11,   13,   -2,   -47,  5,    -16,  -60,  -15,  77,   -17,  26,
+    -3,   14,   -21,  19,   -5,   -19,  -13,  0,    10,   14,   9,    31,
+    -13,  -41,  -10,  4,    22,   18,   -48,  -6,   -10,  62,   -3,   -18,
+    -14,  12,   26,   -28,  3,    14,   25,   -13,  -19,  6,    5,    36,
+    -3,   -65,  -12,  0,    31,   -7,   -9,   101,  -4,   26,   16,   17,
+    -12,  -12,  14,   -36,  -3,   5,    -15,  21,   2,    30,   -3,   38,
+    -4,   1,    -6,   7,    -7,   14,   38,   -22,  -30,  -3,   -7,   3,
+    -39,  -70,  -126, 25,   34,   94,   -67,  -22,  -33,  83,   -47,  -118,
+    4,    70,   33,   25,   62,   -128, -76,  -118, -113, 49,   -12,  -100,
+    -18,  -114, -33,  43,   32,   61,   40,   -9,   -106, 2,    36,   -100,
+    -40,  -5,   20,   -75,  61,   -51,  -9,   126,  -27,  -52,  5,    -24,
+    -21,  -126, -114, -12,  15,   106,  -2,   73,   -125, 50,   13,   -120,
+    35,   35,   4,    -61,  29,   -124, 6,    -53,  -69,  -125, 64,   -89,
+    36,   -107, -103, -7,   27,   121,  69,   77,   -35,  35,   95,   -125,
+    -49,  97,   -45,  -43,  -23,  23,   -28,  -65,  -118, 2,    8,    -126,
+    27,   -97,  92,   5,    55,   82,   17,   -57,  -115, 37,   8,    -106,
+    -46,  41,   -2,   21,   -44,  8,    -73,  -58,  -39,  34,   89,   -95,
+    95,   -117, 120,  -58,  31,   123,  1,    -32,  -109, -110, 60,   -120,
+    -43,  -74,  5,    91,   26,   21,   114,  82,   -83,  -126, 123,  22,
+    -16,  -67,  25,   -83,  46,   48,   -34,  -121, -124, -63,  -35,  -9,
+    31,   82,   123,  6,    -3,   117,  93,   -2,   -13,  -36,  124,  -112,
+    -6,   -102, -5,   -33,  -15,  44,   -69,  -127, -23,  -40,  -34,  -85,
+    68,   83,   -1,   40,   8,    84,   118,  -58,  -55,  -102, 123,  -55,
+    -14,  -123, 44,   -63,  -14,  21,   35,   16,   24,   -126, -13,  -114,
+    35,   20,   -36,  61,   -9,   97,   34,   19,   -32,  -109, 76,   -104,
+    99,   -119, 45,   -125, -51,  -28,  -8,   -69,  -8,   125,  -45,  -93,
+    113,  103,  -41,  -82,  52,   7,    126,  0,    -40,  104,  55,   -58,
+    17,   -124, -93,  -58,  8,    -45,  1,    56,   -123, 108,  -47,  -23,
+    115,  127,  17,   -68,  -13,  116,  -82,  -44,  45,   67,   -120, -101,
+    -15,  -125, 120,  -113, 17,   -48,  -73,  126,  -64,  -86,  -118, -19,
+    112,  -1,   -66,  -27,  -62,  121,  -86,  -58,  50,   89,   -38,  -75,
+    95,   -111, 12,   -113, 2,    -68,  2,    -94,  -121, 91,   -5,   0,
+    79,   43,   -7,   -18,  79,   35,   -38,  47,   1,    -45,  83,   -50,
+    102,  32,   55,   -96,  15,   -122, -69,  45,   -27,  91,   -62,  -30,
+    46,   -95,  22,   -72,  -97,  -1,   14,   -122, 28,   127,  61,   -126,
+    121,  9,    68,   -120, 49,   -60,  90,   3,    43,   68,   54,   34,
+    -10,  28,   21,   -24,  -54,  22,   -113, -12,  82,   -2,   -17,  -9,
+    127,  8,    116,  -92,  0,    -70,  -33,  123,  66,   116,  -74,  -4,
+    74,   -72,  -22,  -47,  1,    -83,  -60,  -124, 1,    122,  -57,  -43,
+    49,   40,   -126, -128, -8,   -29,  28,   -24,  -123, -121, -70,  -93,
+    -37,  -126, 11,   -125, -37,  11,   -31,  -51,  -124, 116,  -128, 8,
+    -25,  109,  75,   -12,  7,    8,    10,   117,  124,  -128, -128, 29,
+    -26,  101,  21,   -128, 87,   8,    -39,  23,   -128, 127,  -127, 74,
+    -55,  74,   112,  127,  4,    55,   44,   -92,  123,  34,   -93,  47,
+    -21,  -92,  17,   49,   -121, 92,   7,    -126, -125, 124,  -74,  3,
+    -59,  18,   -91,  3,    -9,   9,    56,   116,  7,    -29,  33,   87,
+    -21,  -128, -13,  57,   74,   9,    -29,  -61,  -97,  -21,  -95,  -12,
+    -114, 16,   82,   125,  -7,   10,   -24,  9,    77,   -128, -102, -25,
+    3,    -126, 10,   13,   -18,  51,   26,   127,  -79,  35,   51,   12,
+    -50,  -24,  1,    -7,   22,   81,   65,   120,  -30,  -38,  85,   122,
+    -4,   -106, -11,  27,   53,   41,   8,    -104, -66,  -38,  -124, 10,
+    12,   76,   117,  -109, 9,    11,   2,    -18,  3,    113,  -16,  -79,
+    -39,  -123, -20,  -128, 2,    13,   -33,  -58,  10,   84,   -104, 13,
+    64,   109,  1,    54,   -12,  28,   24,   63,   -126, 118,  -82,  46,
+    -12,  -15,  14,   -43,  60,   22,   -32,  -19,  -46,  91,   -107, 24,
+    -94,  26,   -47,  125,  6,    58,   -15,  -75,  -26,  -38,  -35,  103,
+    -16,  -17,  -13,  63,   -2,   45,   -45,  -73,  -23,  70,   -87,  51,
+    -17,  53,   76,   14,   -18,  -31,  -14,  103,  8,    21,   -28,  -33,
+    -20,  -47,  6,    39,   40,   -30,  7,    -76,  55,   31,   -20,  -21,
+    -59,  1,    25,   -11,  17,   5,    -13,  -39,  0,    -76,  50,   -33,
+    -29,  -50,  -16,  -11,  -12,  -1,   -46,  40,   -10,  65,   -19,  21,
+    -41,  -32,  -83,  -19,  -4,   49,   -60,  118,  -24,  -46,  9,    102,
+    -20,  8,    -19,  25,   31,   -3,   -37,  0,    25,   7,    29,   2,
+    -39,  127,  -64,  -20,  64,   115,  -30,  36,   100,  35,   122,  127,
+    127,  -127, 127,  -127, 19,   127,  -89,  -79,  -32,  39,   -127, 125,
+    -80,  126,  -127, 26,   8,    98,   -8,   -57,  -90,  -50,  126,  61,
+    127,  -126, 40,   -106, -68,  104,  -125, -119, 11,   10,   -127, 66,
+    -56,  -12,  -126, -104, 27,   75,   38,   -124, -126, -125, 84,   -123,
+    -45,  -114, -128, 127,  103,  -101, -124, 127,  -11,  -23,  -123, 92,
+    -123, 24,   126,  41,   -2,   -39,  -27,  -94,  40,   -112, -48,  127,
+    58,   14,   38,   -75,  -64,  73,   117,  100,  -119, -11,  6,    32,
+    -126, -14,  35,   121,  -10,  54,   -60,  89,   -3,   69,   -25,  -20,
+    43,   -86,  -34,  24,   27,   7,    -81,  -99,  -23,  -16,  -26,  13,
+    35,   -97,  80,   -29,  -13,  -121, -12,  -65,  -94,  70,   -89,  -126,
+    -95,  88,   33,   96,   29,   -90,  69,   114,  -78,  65,   90,   -47,
+    -47,  89,   1,    -12,  3,    8,    30,   5,    2,    -30,  -1,   6,
+    -7,   10,   -4,   46,   -27,  -40,  22,   -6,   -17,  45,   24,   -9,
+    23,   -14,  -63,  -26,  -12,  -57,  27,   25,   55,   -76,  -47,  21,
+    34,   33,   26,   17,   14,   6,    9,    26,   25,   -25,  -25,  -18};
+
+const int8_t kInputDenseBias[kInputLayerOutputSize] = {
+    38,  -6,  127,  127, 127,  -43, -127, 78,  127, 5,   127, 123,
+    127, 127, -128, -76, -126, 28,  127,  125, -30, 127, -89, -20};
+
+const int8_t kHiddenGruWeights[kHiddenLayerWeights] = {
+    -124, 23,   -123, -33,  -95,  -4,   8,    -84,  4,    101,  -119, 116,
+    -4,   123,  103,  -51,  29,   -124, -114, -49,  31,   9,    75,   -128,
+    0,    -49,  37,   -50,  46,   -21,  -63,  -104, 54,   82,   33,   21,
+    70,   127,  -9,   -79,  -39,  -23,  -127, 107,  122,  -96,  -46,  -18,
+    -39,  13,   -28,  -48,  14,   56,   -52,  49,   -1,   -121, 25,   -18,
+    -36,  -52,  -57,  -30,  54,   -124, -26,  -47,  10,   39,   12,   2,
+    9,    -127, -128, 102,  21,   11,   -64,  -71,  89,   -113, -111, 54,
+    31,   94,   121,  -40,  30,   40,   -109, 73,   -9,   108,  -92,  2,
+    -127, 116,  127,  127,  -122, 95,   127,  -37,  -127, 28,   89,   10,
+    24,   -104, -62,  -67,  -14,  38,   14,   -71,  22,   -41,  20,   -50,
+    39,   63,   86,   127,  -18,  79,   4,    -51,  2,    33,   117,  -113,
+    -78,  56,   -91,  37,   34,   -45,  -44,  -22,  21,   -16,  56,   30,
+    -84,  -79,  38,   -74,  127,  9,    -25,  2,    82,   61,   25,   -26,
+    26,   11,   117,  -65,  12,   -58,  42,   -62,  -93,  11,   11,   124,
+    -123, 80,   -125, 11,   -90,  42,   94,   4,    -109, -1,   85,   -52,
+    45,   -26,  -27,  77,   -5,   30,   90,   0,    95,   -7,   53,   29,
+    -82,  22,   -9,   74,   2,    -12,  -73,  114,  97,   -64,  122,  -77,
+    43,   91,   86,   126,  106,  72,   90,   -43,  46,   96,   -51,  21,
+    22,   68,   22,   41,   79,   75,   -46,  -105, 23,   -116, 127,  -123,
+    102,  57,   85,   10,   -29,  34,   125,  126,  124,  81,   -15,  54,
+    96,   -128, 39,   -124, 103,  74,   126,  127,  -50,  -71,  -122, -64,
+    93,   -75,  71,   105,  122,  123,  126,  122,  -127, 33,   -63,  -74,
+    124,  -71,  33,   41,   -56,  19,   6,    65,   41,   90,   -116, -3,
+    -46,  75,   -13,  98,   -74,  -42,  74,   -95,  -96,  81,   24,   32,
+    -19,  -123, 74,   55,   109,  115,  0,    32,   33,   12,   -20,  9,
+    127,  127,  -61,  79,   -48,  -54,  -49,  101,  -9,   27,   -106, 74,
+    119,  77,   87,   -126, -24,  127,  124,  31,   34,   127,  40,   3,
+    -90,  127,  23,   57,   -53,  127,  -69,  -88,  -33,  127,  19,   -46,
+    -9,   -125, 13,   -126, -113, 127,  -41,  46,   106,  -62,  3,    -10,
+    111,  49,   -34,  -24,  -20,  -112, 11,   101,  -50,  -34,  50,   65,
+    -64,  -106, 70,   -48,  60,   9,    -122, -45,  15,   -112, -26,  -4,
+    1,    39,   23,   58,   -45,  -80,  127,  82,   58,   30,   -94,  -119,
+    51,   -89,  95,   -107, 30,   127,  125,  58,   -52,  -42,  -38,  -20,
+    -122, 115,  39,   -26,  5,    73,   13,   -39,  43,   -23,  -20,  -125,
+    23,   35,   53,   -61,  -66,  72,   -20,  33,   8,    35,   4,    7,
+    18,   19,   16,   -45,  -50,  -71,  31,   -29,  -41,  -27,  10,   14,
+    27,   9,    -23,  98,   6,    -94,  92,   127,  -114, 59,   -26,  -100,
+    -62,  -127, -17,  -85,  -60,  126,  -42,  -6,   33,   -120, -26,  -126,
+    -127, -35,  -114, -31,  25,   -126, -100, -126, -64,  -46,  -31,  30,
+    25,   -74,  -111, -97,  -81,  -104, -114, -19,  -9,   -116, -69,  22,
+    30,   59,   8,    -51,  16,   -97,  18,   -4,   -89,  80,   -50,  3,
+    36,   -67,  56,   69,   -26,  107,  -10,  58,   -28,  -4,   -57,  -72,
+    -111, 0,    -75,  -119, 14,   -75,  -49,  -66,  -49,  8,    -121, 22,
+    -54,  121,  30,   54,   -26,  -126, -123, 56,   5,    48,   21,   -127,
+    -11,  23,   25,   -82,  6,    -25,  119,  78,   4,    -104, 27,   61,
+    -48,  37,   -13,  -52,  50,   -50,  44,   -1,   -22,  -43,  -59,  -78,
+    -67,  -32,  -26,  9,    -3,   40,   16,   19,   3,    -9,   20,   -6,
+    -37,  28,   39,   17,   -19,  -10,  1,    6,    -59,  74,   47,   3,
+    -119, 0,    -128, -107, -25,  -22,  -69,  -23,  -111, -42,  -93,  -120,
+    90,   -85,  -54,  -118, 76,   -79,  124,  101,  -77,  -75,  -17,  -71,
+    -114, 68,   55,   79,   -1,   -123, -20,  127,  -65,  -123, -128, -87,
+    123,  9,    -115, -14,  7,    -4,   127,  -79,  -115, 125,  -28,  89,
+    -83,  49,   89,   119,  -69,  -5,   12,   -49,  60,   57,   -24,  -99,
+    -110, 76,   -83,  125,  73,   81,   11,   8,    -45,  1,    83,   13,
+    -70,  -2,   97,   112,  -97,  53,   -9,   -94,  124,  44,   -49,  -24,
+    52,   76,   -110, -70,  -114, -12,  72,   -4,   -114, 43,   -43,  81,
+    102,  -84,  -27,  62,   -40,  52,   58,   124,  -35,  -51,  -123, -43,
+    56,   -75,  -34,  -35,  -106, 93,   -43,  14,   -16,  46,   62,   -97,
+    21,   30,   -53,  21,   -11,  -33,  -20,  -95,  4,    -126, 12,   45,
+    20,   108,  85,   11,   20,   -40,  99,   4,    -25,  -18,  -23,  -12,
+    -126, -55,  -20,  -44,  -51,  91,   -127, 127,  -44,  7,    127,  78,
+    38,   125,  -6,   -94,  -103, 73,   126,  -126, 18,   59,   -46,  106,
+    76,   116,  -31,  75,   -4,   92,   102,  32,   -31,  73,   42,   -21,
+    -28,  57,   127,  -8,   -107, 115,  124,  -94,  -4,   -128, 29,   -57,
+    70,   -82,  50,   -13,  -44,  38,   67,   -93,  6,    -39,  -46,  56,
+    68,   27,   61,   26,   18,   -72,  127,  22,   18,   -31,  127,  61,
+    -65,  -38,  1,    -67,  -1,   8,    -73,  46,   -116, -94,  58,   -49,
+    71,   -40,  -63,  -82,  -20,  -60,  93,   76,   69,   -106, 34,   -31,
+    4,    -25,  107,  -18,  45,   4,    -61,  126,  54,   -126, -125, 41,
+    19,   44,   32,   -98,  125,  -24,  125,  -96,  -125, 15,   87,   -4,
+    -90,  18,   -40,  28,   -69,  67,   22,   41,   39,   7,    -48,  -44,
+    12,   69,   -13,  2,    44,   -38,  111,  -7,   -126, -22,  -9,   74,
+    -128, -36,  -7,   -123, -15,  -79,  -91,  -37,  -127, -122, 104,  30,
+    7,    98,   -37,  111,  -116, -47,  127,  -45,  118,  -111, -123, -120,
+    -77,  -64,  -125, 124,  77,   111,  77,   18,   -113, 117,  -9,   67,
+    -77,  126,  49,   -20,  -124, 39,   41,   -124, -34,  114,  -87,  -126,
+    98,   -20,  59,   -17,  -24,  125,  107,  54,   35,   33,   -44,  12,
+    -29,  125,  -71,  -28,  -63,  -114, 28,   -17,  121,  -36,  127,  89,
+    -122, -49,  -18,  -48,  17,   24,   19,   -64,  -128, 13,   86,   45,
+    13,   -49,  55,   84,   48,   80,   -39,  99,   -127, 70,   -33,  30,
+    50,   126,  -65,  -117, -13,  -20,  -24,  127,  115,  -72,  -104, 63,
+    126,  -42,  57,   17,   46,   21,   119,  110,  -100, -60,  -112, 62,
+    -33,  28,   26,   -22,  -60,  -33,  -54,  78,   25,   32,   -114, 86,
+    44,   26,   43,   76,   121,  19,   97,   -2,   -3,   -73,  -68,  6,
+    -116, 6,    -43,  -97,  46,   -128, -120, -31,  -119, -29,  16,   16,
+    -126, -128, -126, -46,  -9,   -3,   92,   -31,  -76,  -126, -3,   -107,
+    -12,  -23,  -69,  5,    51,   27,   -42,  23,   -70,  -128, -29,  22,
+    29,   -126, -55,  50,   -71,  -3,   127,  44,   -27,  -70,  -63,  -66,
+    -70,  104,  86,   115,  29,   -92,  41,   -90,  44,   -11,  -28,  20,
+    -11,  -63,  -16,  43,   31,   17,   -73,  -31,  -1,   -17,  -11,  -39,
+    56,   18,   124,  72,   -14,  28,   69,   -121, -125, 34,   127,  63,
+    86,   -80,  -126, -125, -124, -47,  124,  77,   124,  -19,  23,   -7,
+    -50,  96,   -128, -93,  102,  -53,  -36,  -87,  119,  -125, 92,   -126,
+    118,  102,  72,   -2,   125,  10,   97,   124,  -125, 125,  71,   -20,
+    -47,  -116, -121, -4,   -9,   -32,  79,   -124, -36,  33,   -128, -74,
+    125,  23,   127,  -29,  -115, -32,  124,  -89,  32,   -107, 43,   -17,
+    24,   24,   18,   29,   -13,  -15,  -36,  62,   -91,  4,    -41,  95,
+    28,   -23,  6,    46,   84,   66,   77,   68,   -70,  -1,   -23,  -6,
+    65,   70,   -21,  9,    77,   -12,  2,    -118, 4,    9,    -108, 84,
+    52,   2,    52,   13,   -10,  58,   -110, 18,   66,   -95,  -23,  70,
+    31,   -3,   56,   56,   -3,   -7,   1,    -27,  -48,  -61,  41,   -4,
+    10,   -62,  32,   -7,   -24,  9,    -48,  -60,  -4,   79,   -20,  -38,
+    -76,  68,   -49,  -97,  0,    -15,  5,    -100, -49,  -95,  -99,  -115,
+    -9,   -40,  10,   104,  13,   56,   127,  -27,  -109, -94,  -118, -102,
+    -44,  -85,  52,   127,  -4,   14,   62,   121,  -122, -26,  -79,  -42,
+    -34,  1,    25,   -38,  -79,  -58,  -31,  -31,  -90,  -30,  -123, 32,
+    -56,  125,  66,   124,  -1,   3,    91,   -103, -7,   23,   78,   -18,
+    9,    69,   -69,  76,   -38,  -33,  -2,   -98,  18,   106,  84,   55,
+    87,   -47,  35,   -124, 64,   41,   -14,  46,   25,   -2,   120,  -21,
+    82,   19,   -79,  -37,  -3,   -8,   -16,  21,   19,   -5,   -28,  -112,
+    39,   -6,   -30,  53,   -69,  53,   46,   127,  123,  78,   20,   28,
+    -7,   73,   72,   17,   -40,  41,   111,  57,   32,   -95,  29,   28,
+    -39,  -65,  54,   -20,  -63,  29,   -67,  3,    44,   -57,  -47,  11,
+    61,   -22,  -44,  61,   48,   -100, 20,   125,  96,   -24,  -16,  3,
+    -69,  -126, 74,   -125, 9,    45,   -67,  -123, -59,  -72,  118,  69,
+    45,   50,   -57,  67,   13,   -66,  -106, 47,   62,   22,   -1,   -22,
+    -25,  -40,  -125, 3,    125,  32,   102,  -56,  -25,  -75,  -30,  122,
+    60,   -13,  36,   -73,  7,    -84,  124,  40,   -118, 17,   -87,  -118,
+    -8,   3,    -27,  111,  -40,  40,   -51,  127,  125,  -45,  -30,  -54,
+    46,   80,   -1,   -30,  101,  -17,  18,   26,   54,   7,    -12,  1,
+    -127, 123,  -122, -27,  -75,  64,   10,   25,   -15,  -44,  127,  -127,
+    5,    -84,  -81,  -7,   19,   -26,  126,  15,   116,  -126, 14,   -76,
+    44,   62,   -110, -124, 125,  -29,  -87,  -3,   -69,  82,   90,   57,
+    -123, 123,  100,  -19,  -51,  -32,  69,   37,   -57,  -128, -124, -72,
+    -13,  51,   -7,   -45,  -73,  5,    99,   -26,  -117, -96,  -109, 4,
+    -31,  -12,  0,    31,   -42,  -27,  12,   -81,  118,  39,   83,   14,
+    41,   -126, 107,  -82,  94,   -116, -122, -47,  -109, -84,  -128, -35,
+    -56,  66,   8,    -65,  19,   42,   -46,  -72,  -109, 41,   43,   -127,
+    -113, 58,   127,  42,   -75,  -1,   65,   117,  -55,  -113, -123, 124,
+    43,   -96,  -115, -19,  68,   15,   94,   3,    75,   0,    34,   9,
+    42,   110,  -48,  92,   -76,  99,   -17,  27,   32,   13,   125,  50,
+    -17,  56,   4,    53,   34,   -8,   99,   80,   -126, -21,  -65,  -11,
+    -46,  44,   -81,  -3,   -121, 123,  66,   -81,  -84,  119,  127,  84,
+    105,  45,   -66,  -42,  -23,  32,   -25,  12,   111,  127,  88,   125,
+    30,   24,   -127, -9,   -54,  127,  -116, -119, 88,   70,   94,   -120,
+    35,   -93,  15,   22,   -21,  25,   -110, -123, -45,  8,    -109, 125,
+    -122, -86,  -126, 8,    -14,  -120, -45,  -45,  69,   -125, -122, 6,
+    81,   86,   125,  95,   54,   77,   54,   -123, 126,  -85,  -117, 56,
+    11,   0,    -61,  -91,  -12,  -2,   -113, -3,   -15,  -122, -63,  -91,
+    10,   84,   -111, 125,  93,   21,   62,   -78,  -116, 13,   -57,  28,
+    -124, 126,  110,  12,   15,   95,   15,   -19,  -125, -97,  52,   -7,
+    101,  9,    20,   -125, -26,  -56,  72,   77,   12,   -126, 22,   -29,
+    47,   62,   95,   112,  69,   32,   97,   -83,  -8,   -5,   67,   -63,
+    -123, 79,   59,   0,    -6,   -17,  4,    -111, -52,  27,   65,   0};
+
+const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights] = {
+    65,   83,   35,   56,   24,   -34,  -28,  -2,   125,  19,   42,   -9,
+    124,  -53,  24,   -87,  11,   35,   -81,  -35,  -125, -31,  123,  -21,
+    33,   -91,  113,  -93,  45,   -6,   53,   38,   -92,  8,    -27,  87,
+    4,    43,   43,   10,   -128, -128, -46,  127,  -38,  -45,  25,   -87,
+    19,   5,    52,   -96,  -23,  -29,  121,  -126, -24,  -20,  -2,   69,
+    -50,  6,    71,   -81,  -125, 90,   -94,  1,    -38,  36,   89,   17,
+    -60,  71,   -48,  18,   -15,  44,   -18,  59,   11,   114,  -51,  32,
+    110,  1,    4,    109,  -24,  127,  27,   60,   88,   24,   45,   -59,
+    75,   -36,  8,    57,   -32,  -25,  13,   126,  -89,  -61,  -76,  127,
+    18,   -62,  -68,  23,   -113, 5,    126,  43,   -88,  26,   -78,  18,
+    75,   21,   9,    -74,  20,   41,   126,  -118, -15,  9,    116,  126,
+    -127, 34,   -6,   126,  -128, -53,  -54,  -55,  -121, 70,   127,  -12,
+    -68,  82,   -25,  104,  -126, 126,  -21,  -26,  124,  -75,  -127, -120,
+    13,   61,   -64,  -108, -63,  -65,  -44,  -35,  -61,  -39,  109,  -74,
+    113,  -3,   108,  -30,  125,  120,  39,   125,  -128, -95,  -99,  111,
+    9,    25,   114,  -75,  -92,  -54,  -12,  -32,  -38,  10,   31,   10,
+    63,   51,   40,   -99,  74,   4,    50,   -128, -36,  -35,  -11,  -28,
+    -126, -7,   66,   -58,  -126, -22,  -83,  -61,  -127, 49,   126,  -8,
+    7,    62,   36,   -11,  -32,  -44,  63,   116,  41,   65,   -127, 126,
+    63,   -30,  -96,  74,   -92,  127,  38,   -18,  -128, 68,   -5,   101,
+    -4,   85,   58,   79,   0,    -58,  8,    119,  -70,  -1,   -79,  -68,
+    114,  -28,  -90,  -6,   -112, 2,    127,  -8,   10,   55,   -59,  -126,
+    127,  125,  80,   72,   35,   -54,  95,   -124, -124, 79,   23,   -46,
+    -61,  -127, -100, 99,   -77,  8,    -87,  5,    -2,   49,   85,   7,
+    -71,  82,   53,   -41,  22,   -22,  -93,  -103, 6,    52,   -56,  14,
+    -8,   -111, 85,   16,   54,   32,   -118, -24,  61,   -53,  96,   -70,
+    -5,   -17,  -67,  -84,  -7,   -82,  -107, -96,  21,   -83,  -58,  50,
+    12,   -126, -1,   -28,  34,   -126, 115,  17,   91,   1,    -127, 72,
+    11,   126,  -81,  6,    96,   -8,   77,   15,   -6,   63,   -27,  20,
+    -123, -109, 85,   -79,  -17,  126,  -92,  2,    -61,  20,   14,   17,
+    121,  123,  30,   57,   120,  127,  57,   42,   117,  98,   67,   39,
+    -20,  -70,  100,  7,    125,  122,  40,   16,   -79,  125,  83,   41,
+    -106, -57,  24,   55,   27,   -66,  -111, -44,  -7,   -43,  -66,  121,
+    42,   -128, -45,  35,   15,   -127, 34,   -35,  -34,  -40,  -18,  -6,
+    63,   111,  31,   116,  127,  19,   24,   -71,  -39,  34,   11,   19,
+    -40,  27,   12,   106,  -10,  56,   -82,  -106, -2,   -50,  -52,  114,
+    -126, -34,  -43,  -68,  10,   76,   57,   -118, -128, 37,   -104, 76,
+    125,  3,    -76,  127,  -29,  84,   -94,  -15,  55,   125,  79,   127,
+    -57,  -125, 104,  -68,  126,  126,  -77,  51,   45,   33,   -109, 115,
+    -11,  1,    95,   -121, -5,   -9,   -126, -114, 39,   68,   -126, -107,
+    -51,  -42,  24,   -8,   51,   -27,  -43,  66,   -45,  62,   -98,  -109,
+    69,   67,   0,    -125, -128, 49,   31,   126,  -122, 2,    -55,  -67,
+    -126, -70,  -128, -125, -77,  25,   16,   -8,   -102, 11,   -75,  82,
+    38,   -5,   5,    19,   34,   47,   -127, -93,  21,   24,   -97,  -18,
+    31,   39,   34,   -20,  22,   123,  7,    -77,  -81,  -46,  -9,   1,
+    23,   39,   -127, -43,  -8,   -50,  10,   -21,  59,   -9,   -4,   -13,
+    -27,  44,   127,  52,   -47,  70,   -43,  52,   101,  -49,  27,   45,
+    49,   33,   -125, 55,   114,  20,   -1,   76,   -24,  -96,  105,  24,
+    126,  75,   -21,  -105, 13,   -42,  40,   126,  -30,  -39,  -95,  125,
+    -63,  11,   6,    125,  125,  -14,  5,    42,   -61,  -4,   49,   88,
+    6,    -107, -28,  19,   -29,  47,   126,  6,    -46,  -89,  -18,  91,
+    -20,  -6,   118,  -21,  -22,  39,   115,  11,   -42,  54,   73,   -55,
+    -77,  62,   -27,  -59,  -99,  -12,  -127, -40,  56,   -3,   -124, -91,
+    71,   -111, 6,    -19,  82,   -24,  -35,  102,  -42,  7,    -126, -126,
+    -125, 18,   98,   -52,  127,  105,  -52,  40,   -83,  126,  -122, 109,
+    5,    127,  48,   6,    5,    -125, 100,  -16,  29,   85,   -89,  8,
+    4,    41,   62,   -127, 62,   122,  85,   122,  -107, 8,    -125, 93,
+    -127, 127,  102,  19,   19,   -66,  41,   -42,  114,  127,  -48,  -117,
+    -29,  -6,   -73,  -102, -3,   -19,  0,    88,   42,   87,   -117, -20,
+    2,    122,  28,   63,   71,   66,   120,  93,   124,  -43,  49,   103,
+    31,   90,   -91,  -22,  -126, 26,   -24,  -21,  51,   -126, 87,   -103,
+    -69,  -10,  -66,  -23,  20,   97,   36,   25,   -127, 30,   -20,  -63,
+    30,   51,   -116, 23,   40,   -39,  36,   -83,  -77,  -25,  -50,  110,
+    14,   13,   -109, 125,  -65,  -55,  -87,  124,  -126, -32,  -72,  -108,
+    127,  127,  -125, -124, 61,   121,  102,  -128, -127, 16,   100,  127,
+    -124, -68,  72,   -93,  -128, 43,   -93,  -19,  -125, -97,  -113, -33,
+    83,   127,  -44,  127,  -75,  127,  16,   44,   50,   -122, 23,   118,
+    46,   19,   26,   -128, 10,   4,    99,   -14,  -82,  -13,  30,   125,
+    57,   65,   60,   -71,  35,   98,   28,   7,    1,    43,   89,   70,
+    75,   121,  -59,  82,   -126, -53,  -16,  -116, -65,  52,   -52,  0,
+    80,   35,   45,   -61,  46,   8,    107,  27,   -26,  -118, 90,   57,
+    -10,  7,    -15,  0,    -39,  -4,   12,   29,   -1,   116,  84,   79,
+    119,  125,  -59,  28,   -6,   -25,  -43,  2,    90,   79,   67,   103,
+    -82,  2,    -6,   125,  19,   73,   0,    -105, 112,  -17,  104,  107,
+    124,  106,  19,   56,   -44,  55,   -112, 6,    -39,  -83,  126,  -93,
+    -98,  57,   -120, -23,  -38,  2,    -31,  -48,  106,  127,  127,  69,
+    16,   110,  71,   104,  62,   -12,  -22,  42,   -37,  -94,  34,   -1,
+    -32,  -12,  -124, -47,  -13,  60,   -75,  -66,  58,   -127, -2,   64,
+    76,   -106, 73,   -49,  -31,  127,  126,  31,   16,   127,  -110, 107,
+    -16,  -53,  20,   69,   -14,  -125, 59,   -44,  15,   120,  125,  125,
+    43,   6,    19,   -58,  127,  127,  43,   16,   82,   97,   -127, 127,
+    -93,  -41,  88,   0,    77,   -15,  116,  16,   -124, -31,  -3,   95,
+    -40,  -126, -54,  -126, -83,  -8,   -59,  6,    67,   -29,  4,    124,
+    -10,  112,  -28,  -8,   85,   -21,  45,   84,   6,    -8,   11,   72,
+    32,   84,   -62,  77,   2,    -36,  75,   31,   -50,  116,  126,  119,
+    -88,  -55,  -14,  -37,  126,  40,   -108, -6,   -6,   57,   64,   -28,
+    -76,  30,   -117, -93,  31,   -92,  -44,  -64,  94,   58,   65,   114,
+    41,   47,   71,   42,   -26,  99,   -126, 57,   -5,   74,   -19,  -113,
+    -1,   67,   -21,  126,  1,    -3,   33,   60,   -82,  37,   -48,  89,
+    114,  -38,  127,  -114, 35,   58,   -5,   21,   -46,  121,  -123, -43,
+    127,  115,  123,  122,  -101, 126,  127,  81,   52,   89,   -127, 102,
+    42,   117,  -9,   -2,   125,  127,  110,  96,   120,  66,   70,   124,
+    55,   84,   -38,  -58,  119,  -127, -16,  -79,  123,  18,   -127, -50,
+    -38,  120,  -85,  1,    7,    -56,  108,  -77,  -2,   21,   37,   1,
+    13,   -105, -69,  28,   -87,  33,   -104, -51,  126,  41,   3,    -121,
+    28,   71,   58,   86,   -8,   127,  94,   -55,  125,  40,   -19,  127,
+    -33,  -87,  -23,  7,    -111, -68,  9,    84,   -119, 55,   -82,  78,
+    -37,  -20,  -9,   -23,  53,   -13,  15,   -46,  116,  126,  -127, 56,
+    -126, 125,  -7,   -1,   45,   26,   125,  121,  29,   47,   -86,  30,
+    10,   76,   -125, -7,   23,   92,   -12,  -39,  -18,  92,   -97,  -8,
+    -85,  -41,  49,   -50,  123,  -37,  -126, -30,  14,   79,   -49,  -65,
+    9,    -36,  -38,  -96,  85,   -24,  -13,  37,   -25,  -5,   -64,  -127,
+    55,   -60,  -18,  -61,  -63,  127,  56,   67,   15,   124,  72,   120,
+    127,  40,   -10,  114,  24,   -23,  46,   78,   -53,  125,  86,   124,
+    86,   0,    38,   93,   21,   127,  123,  75,   -72,  13,   48,   33,
+    83,   -51,  15,   -32,  -49,  -33,  120,  64,   7,    9,    65,   60,
+    21,   -21,  -61,  -53,  -113, 84,   -97,  101,  37,   -114, -27,  41,
+    73,   126,  -10,  59,   61,   -15,  70,   -13,  82,   -4,   69,   56,
+    94,   -91,  -50,  92,   -74,  -48,  53,   -7,   -107, 127,  28,   30,
+    -26,  -21,  -61,  77,   82,   64,   -91,  -125, 122,  -104, 127,  123,
+    122,  123,  76,   -126, 127,  -6,   -80,  7,    40,   -66,  -65,  54,
+    -2,   23,   96,   -64,  74,   2,    -53,  -12,  -123, 39,   60,   -20,
+    16,   -17,  -97,  23,   -4,   -53,  -122, 32,   -16,  -54,  -95,  43,
+    71,   -1,   -67,  -33,  41,   18,   72,   28,   -83,  31,   -100, -91,
+    -27,  10,   -128, -106, 2,    76,   -13,  42,   34,   112,  -19,  44,
+    40,   -9,   -11,  65,   92,   -43,  -125, 2,    47,   -32,  25,   122,
+    -29,  12,   101,  -8,   -126, -23,  43,   7,    125,  -20,  -124, 82,
+    -2,   13,   -73,  -106, 115,  31,   116,  -23,  -44,  -71,  84,   3,
+    47,   91,   127,  127,  -15,  95,   7,    93,   5,    113,  -50,  54,
+    11,   13,   -127, 17,   72,   43,   -23,  5,    -70,  20,   15,   -27,
+    99,   69,   -109, -122, -94,  16,   127,  0,    116,  104,  45,   108,
+    -34,  87,   72,   -14,  118,  46,   42,   109,  -26,  95,   93,   127,
+    60,   127,  -93,  -54,  -122, 34,   -105, 56,   55,   103,  125,  -71,
+    -50,  95,   -72,  127,  107,  21,   73,   126,  61,   127,  127,  24,
+    -62,  90,   73,   90,   -46,  -78,  -124, 72,   123,  -42,  50,   -107,
+    17,   -32,  -62,  -89,  124,  1,    80,   -2,   117,  119,  -65,  -127,
+    -95,  -121, -52,  103,  66,   75,   -3,   -62,  -127, 127,  -74,  124,
+    79,   49,   40,   105,  -67,  -71,  -70,  43,   127,  119,  -4,   66,
+    43,   23,   91,   -126, 15,   63,   -119, 112,  103,  15,   -99,  31,
+    -127, 69,   116,  -46,  -67,  2,    -126, -29,  30,   30,   -69,  -98,
+    -47,  -87,  -70,  -127, 23,   -73,  30,   -7,   94,   -52,  -65,  98,
+    -45,  97,   53,   23,   -9,   -22,  -52,  -47,  6,    -1,   -85,  -15,
+    -61,  -14,  68,   110,  -10,  -121, -25,  -35,  -15,  -94,  -123, 27,
+    75,   48,   -66,  -56,  -44,  93,   109,  67,   -36,  24,   70,   -126,
+    8,    -127, 126,  52,   11,   -32,  120,  -13,  -26,  -28,  -125, 127,
+    106,  -50,  124,  36,   -126, -12,  0,    -23,  76,   -71,  -126, -12,
+    -17,  -82,  12,   124,  57,   33,   4,    77,   -46,  71,   -34,  72,
+    125,  -128, 124,  -24,  -128, 75,   -120, 69,   -45,  55,   33,   127,
+    -33,  4,    -105, -41,  -59,  -91,  123,  44,   -127, 127,  -67,  52,
+    25,   -125, -65,  100,  -25,  123,  6,    11,   -123, -92,  -33,  126,
+    -17,  -4,   29,   33,   127,  96,   3,    87,   -48,  -18,  -70,  123,
+    58,   -127, -3,   -52,  -1,   -36,  -41,  127,  51,   -52,  -27,  46,
+    -83,  57,   9,    126,  127,  94,   79,   -37,  -127, -40,  67,   52,
+    82,   -66,  122,  -13,  -73,  127,  -8,   -80,  46,   -48,  4,    -54};
+
+const int8_t kHiddenGruBias[kHiddenLayerBiases] = {
+    124, 125, -57, -126, 53,  123, 127,  -75, 68,  102, -2, 116,
+    124, 127, 124, 125,  126, 123, -16,  48,  125, 126, 78, 85,
+    11,  126, -30, -30,  -64, -3,  -105, -29, -17, 69,  63, 2,
+    -32, -10, -62, 113,  -52, 112, -109, 112, 7,   -40, 73, 53,
+    62,  6,   -2,  0,    0,   100, -16,  26,  -24, 56,  26, -10,
+    -33, 41,  70,  109,  -29, 127, 34,   -66, 49,  53,  27, 62};
+
+const int8_t kOutputDenseWeights[kOutputLayerWeights] = {
+    127,  127,  127, 127,  127,  20,  127,  -126, -126, -54, 14,  125,
+    -126, -126, 127, -125, -126, 127, -127, -127, -57,  -30, 127, 80};
+
+const int8_t kOutputDenseBias[kOutputLayerOutputSize] = {-50};
+
+}  // namespace rnnoise
diff --git a/third_party/rnnoise/src/rnn_vad_weights.h b/third_party/rnnoise/src/rnn_vad_weights.h
new file mode 100644
index 0000000..d55e33d
--- /dev/null
+++ b/third_party/rnnoise/src/rnn_vad_weights.h
@@ -0,0 +1,37 @@
+#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_
+#define THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_
+
+#include <cstdint>
+#include <cstring>
+
+namespace rnnoise {
+
+// Weights scaling factor.
+const float kWeightsScale = 1.f / 256.f;
+
+// Input layer (dense).
+const size_t kInputLayerInputSize = 42;
+const size_t kInputLayerOutputSize = 24;
+const size_t kInputLayerWeights = kInputLayerInputSize * kInputLayerOutputSize;
+extern const int8_t kInputDenseWeights[kInputLayerWeights];
+extern const int8_t kInputDenseBias[kInputLayerOutputSize];
+
+// Hidden layer (GRU).
+const size_t kHiddenLayerOutputSize = 24;
+const size_t kHiddenLayerWeights =
+    3 * kInputLayerOutputSize * kHiddenLayerOutputSize;
+const size_t kHiddenLayerBiases = 3 * kHiddenLayerOutputSize;
+extern const int8_t kHiddenGruWeights[kHiddenLayerWeights];
+extern const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights];
+extern const int8_t kHiddenGruBias[kHiddenLayerBiases];
+
+// Output layer (dense).
+const size_t kOutputLayerOutputSize = 1;
+const size_t kOutputLayerWeights =
+    kHiddenLayerOutputSize * kOutputLayerOutputSize;
+extern const int8_t kOutputDenseWeights[kOutputLayerWeights];
+extern const int8_t kOutputDenseBias[kOutputLayerOutputSize];
+
+}  // namespace rnnoise
+
+#endif  // THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_
diff --git a/typedefs.h b/typedefs.h
index 073b180..dd10048 100644
--- a/typedefs.h
+++ b/typedefs.h
@@ -8,108 +8,14 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-// This file contains platform-specific typedefs and defines.
-// Much of it is derived from Chromium's build/build_config.h.
-
+// TODO(solenberg): Make the files including typedefs.h directly include the
+//                  files below they need.
 #ifndef TYPEDEFS_H_
 #define TYPEDEFS_H_
 
-// Processor architecture detection.  For more info on what's defined, see:
-//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
-//   http://www.agner.org/optimize/calling_conventions.pdf
-//   or with gcc, run: "echo | gcc -E -dM -"
-#if defined(_M_X64) || defined(__x86_64__)
-#define WEBRTC_ARCH_X86_FAMILY
-#define WEBRTC_ARCH_X86_64
-#define WEBRTC_ARCH_64_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__aarch64__)
-#define WEBRTC_ARCH_ARM_FAMILY
-#define WEBRTC_ARCH_64_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(_M_IX86) || defined(__i386__)
-#define WEBRTC_ARCH_X86_FAMILY
-#define WEBRTC_ARCH_X86
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__ARMEL__)
-#define WEBRTC_ARCH_ARM_FAMILY
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__MIPSEL__)
-#define WEBRTC_ARCH_MIPS_FAMILY
-#if defined(__LP64__)
-#define WEBRTC_ARCH_64_BITS
-#else
-#define WEBRTC_ARCH_32_BITS
-#endif
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__pnacl__)
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#else
-#error Please add support for your architecture in typedefs.h
-#endif
-
-#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
-#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
-#endif
-
-// TODO(zhongwei.yao): WEBRTC_CPU_DETECTION is only used in one place; we should
-// probably just remove it.
-#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__))
-#define WEBRTC_CPU_DETECTION
-#endif
-
 #include <stdint.h>
 
-// Annotate a function indicating the caller must examine the return value.
-// Use like:
-//   int foo() RTC_WARN_UNUSED_RESULT;
-// To explicitly ignore a result, cast to void.
-// TODO(kwiberg): Remove when we can use [[nodiscard]] from C++17.
-#if defined(__clang__)
-#define RTC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
-#elif defined(__GNUC__)
-// gcc has a __warn_unused_result__ attribute, but you can't quiet it by
-// casting to void, so we don't use it.
-#define RTC_WARN_UNUSED_RESULT
-#else
-#define RTC_WARN_UNUSED_RESULT
-#endif
-
-// Put after a variable that might not be used, to prevent compiler warnings:
-//   int result ATTRIBUTE_UNUSED = DoSomething();
-//   assert(result == 17);
-// Deprecated since it only works with GCC & clang. See RTC_UNUSED below.
-// TODO(terelius): Remove.
-#ifndef ATTRIBUTE_UNUSED
-#if defined(__GNUC__) || defined(__clang__)
-#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#else
-#define ATTRIBUTE_UNUSED
-#endif
-#endif
-
-#ifndef NO_RETURN
-// Annotate a function that will not return control flow to the caller.
-#if defined(_MSC_VER)
-#define NO_RETURN __declspec(noreturn)
-#elif defined(__GNUC__)
-#define NO_RETURN __attribute__ ((__noreturn__))
-#else
-#define NO_RETURN
-#endif
-#endif
-
-// Prevent the compiler from warning about an unused variable. For example:
-//   int result = DoSomething();
-//   assert(result == 17);
-//   RTC_UNUSED(result);
-// Note: In most cases it is better to remove the unused variable rather than
-// suppressing the compiler warning.
-#ifndef RTC_UNUSED
-#define RTC_UNUSED(x) static_cast<void>(x)
-#endif  // RTC_UNUSED
+#include "rtc_base/system/arch.h"
+#include "rtc_base/system/unused.h"
 
 #endif  // TYPEDEFS_H_
diff --git a/webrtc_apm.cc b/webrtc_apm.cc
index b770ab6..d36ccc2 100644
--- a/webrtc_apm.cc
+++ b/webrtc_apm.cc
@@ -146,24 +146,33 @@
 
 	aec3_config->echo_removal_control = {
 		{
+		config->echo_removal_control.gain_rampup.initial_gain,
 		config->echo_removal_control.gain_rampup.first_non_zero_gain,
 		config->echo_removal_control.gain_rampup.non_zero_gain_blocks,
 		config->echo_removal_control.gain_rampup.full_gain_blocks
 		},
-		static_cast<bool>(config->echo_removal_control.has_clock_drift)
+		static_cast<bool>(config->echo_removal_control.has_clock_drift),
+		static_cast<bool>(
+			config->echo_removal_control.linear_and_stable_echo_path)
 	};
 
-	aec3_config->echo_model = {
-		config->echo_model.noise_floor_hold,
-		config->echo_model.min_noise_floor_power,
-		config->echo_model.stationary_gate_slope,
-		config->echo_model.noise_gate_power,
-		config->echo_model.noise_gate_slope,
-		config->echo_model.render_pre_window_size,
-		config->echo_model.render_post_window_size,
-		config->echo_model.nonlinear_hold,
-		config->echo_model.nonlinear_release
-	};
+	webrtc::EchoCanceller3Config::EchoModel echo_model;
+
+	echo_model.noise_floor_hold = config->echo_model.noise_floor_hold;
+	echo_model.min_noise_floor_power =
+			config->echo_model.min_noise_floor_power;
+	echo_model.stationary_gate_slope =
+			config->echo_model.stationary_gate_slope;
+	echo_model.noise_gate_power = config->echo_model.noise_gate_power;
+	echo_model.noise_gate_slope = config->echo_model.noise_gate_slope;
+	echo_model.render_pre_window_size =
+			config->echo_model.render_pre_window_size;
+	echo_model.render_post_window_size =
+			config->echo_model.render_post_window_size;
+	echo_model.nonlinear_hold = config->echo_model.nonlinear_hold;
+	echo_model.nonlinear_release = config->echo_model.nonlinear_release;
+
+	aec3_config->echo_model = echo_model;
 
 
 	return 0;
diff --git a/webrtc_apm.h b/webrtc_apm.h
index 918c4ab..8e2e6cb 100644
--- a/webrtc_apm.h
+++ b/webrtc_apm.h
@@ -62,11 +62,13 @@
 	float mf;
 	float hf;
 	float default_len;
+	int reverb_based_on_render;
 	int echo_can_saturate;
 	int bounded_erl;
 };
 
 struct mask {
+	float m0;
 	float m1;
 	float m2;
 	float m3;
@@ -96,6 +98,7 @@
 struct render_levels {
 	float active_render_limit;
 	float poor_excitation_render_limit;
+	float poor_excitation_render_limit_ds8;
 };
 
 struct GainChanges {
@@ -113,10 +116,13 @@
 	struct GainChanges normal;
 	struct GainChanges saturation;
 	struct GainChanges nonlinear;
+	float max_inc_factor;
+	float max_dec_factor_lf;
 	float floor_first_increase;
 };
 
 struct GainRampup {
+	float initial_gain;
 	float first_non_zero_gain;
 	int non_zero_gain_blocks;
 	int full_gain_blocks;
@@ -125,6 +131,7 @@
 struct echo_removal_control {
 	struct GainRampup gain_rampup;
 	int has_clock_drift;
+	int linear_and_stable_echo_path;
 };
 
 struct echo_model {
@@ -135,12 +142,21 @@
 	float noise_gate_slope;
 	size_t render_pre_window_size;
 	size_t render_post_window_size;
+	size_t render_pre_window_size_init;
+	size_t render_post_window_size_init;
 	float nonlinear_hold;
 	float nonlinear_release;
 };
 
 struct suppressor {
 	size_t bands_with_reliable_coherence;
+	size_t nearend_average_blocks;
+	float mask_lf_enr_transparent;
+	float mask_lf_enr_suppress;
+	float mask_lf_emr_transparent;
+	float mask_hf_enr_transparent;
+	float mask_hf_enr_suppress;
+	float mask_hf_emr_transparent;
  };
 
 struct aec_config {